From ae85698a2bf674e99c744169e56f8cbf2874778a Mon Sep 17 00:00:00 2001 From: Tom Verbeure Date: Thu, 9 Aug 2018 22:15:26 -0700 Subject: [PATCH 001/951] MulSimple --- .../vexriscv/plugin/MulSimplePlugin.scala | 90 +++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 src/main/scala/vexriscv/plugin/MulSimplePlugin.scala diff --git a/src/main/scala/vexriscv/plugin/MulSimplePlugin.scala b/src/main/scala/vexriscv/plugin/MulSimplePlugin.scala new file mode 100644 index 00000000..41ed3916 --- /dev/null +++ b/src/main/scala/vexriscv/plugin/MulSimplePlugin.scala @@ -0,0 +1,90 @@ +package vexriscv.plugin +import vexriscv._ +import vexriscv.VexRiscv +import spinal.core._ + +class MulSimplePlugin extends Plugin[VexRiscv]{ + object MUL_OPA extends Stageable(SInt(33 bits)) + object MUL_OPB extends Stageable(SInt(33 bits)) + object MUL extends Stageable(Bits(64 bits)) + + object IS_MUL extends Stageable(Bool) + + override def setup(pipeline: VexRiscv): Unit = { + import Riscv._ + import pipeline.config._ + + + val actions = List[(Stageable[_ <: BaseType],Any)]( + SRC1_CTRL -> Src1CtrlEnum.RS, + SRC2_CTRL -> Src2CtrlEnum.RS, + REGFILE_WRITE_VALID -> True, + BYPASSABLE_EXECUTE_STAGE -> False, + BYPASSABLE_MEMORY_STAGE -> False, + RS1_USE -> True, + RS2_USE -> True, + IS_MUL -> True + ) + + val decoderService = pipeline.service(classOf[DecoderService]) + decoderService.addDefault(IS_MUL, False) + decoderService.add(List( + MULX -> actions + )) + + } + + override def build(pipeline: VexRiscv): Unit = { + import pipeline._ + import pipeline.config._ + + // Prepare signed inputs for the multiplier in the next stage. + // This will map them best to an FPGA DSP. + execute plug new Area { + import execute._ + val aSigned,bSigned = Bool + val a,b = Bits(32 bit) + + a := input(SRC1) + b := input(SRC2) + switch(input(INSTRUCTION)(13 downto 12)) { + is(B"01") { + aSigned := True + bSigned := True + } + is(B"10") { + aSigned := True + bSigned := False + } + default { + aSigned := False + bSigned := False + } + } + + insert(MUL_OPA) := ((aSigned ? a.msb | False) ## a).asSInt + insert(MUL_OPB) := ((bSigned ? b.msb | False) ## b).asSInt + } + + memory plug new Area { + import memory._ + + insert(MUL) := (input(MUL_OPA) * input(MUL_OPB))(63 downto 0).asBits + } + + writeBack plug new Area { + import writeBack._ + + when(arbitration.isValid && input(IS_MUL)){ + switch(input(INSTRUCTION)(13 downto 12)){ + is(B"00"){ + output(REGFILE_WRITE_DATA) := input(MUL)(31 downto 0) + } + is(B"01",B"10",B"11"){ + output(REGFILE_WRITE_DATA) := input(MUL)(63 downto 32) + } + } + } + } + } +} From b1b7da4f1004d700eaaddf05ea7cb1f8ffc89069 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 30 Nov 2018 17:37:17 +0100 Subject: [PATCH 002/951] Rename SimpleBus into PipelinedMemoryBus Move PipelinedMemoryBus into SpinalHDL lib --- build.sbt | 8 +- src/main/scala/vexriscv/demo/Murax.scala | 38 +- .../scala/vexriscv/demo/MuraxUtiles.scala | 55 +-- src/main/scala/vexriscv/demo/SimpleBus.scala | 324 ------------------ src/main/scala/vexriscv/ip/DataCache.scala | 8 +- .../scala/vexriscv/ip/InstructionCache.scala | 12 +- .../vexriscv/plugin/DBusSimplePlugin.scala | 10 +- .../vexriscv/plugin/IBusSimplePlugin.scala | 9 +- 8 files changed, 71 insertions(+), 393 deletions(-) delete mode 100644 src/main/scala/vexriscv/demo/SimpleBus.scala diff --git a/build.sbt b/build.sbt index d84c0a65..21851324 100644 --- a/build.sbt +++ b/build.sbt @@ -29,16 +29,16 @@ lazy val root = (project in file(".")). version := "1.0.0" )), libraryDependencies ++= Seq( - "com.github.spinalhdl" % "spinalhdl-core_2.11" % "1.2.2", - "com.github.spinalhdl" % "spinalhdl-lib_2.11" % "1.2.2", +// "com.github.spinalhdl" % "spinalhdl-core_2.11" % "1.2.2", +// "com.github.spinalhdl" % "spinalhdl-lib_2.11" % "1.2.2", "org.scalatest" % "scalatest_2.11" % "2.2.1", "org.yaml" % "snakeyaml" % "1.8" ), name := "VexRiscv" - )/*.dependsOn(spinalHdlSim,spinalHdlCore,spinalHdlLib) + ).dependsOn(spinalHdlSim,spinalHdlCore,spinalHdlLib) lazy val spinalHdlSim = ProjectRef(file("../SpinalHDL"), "SpinalHDL-sim") lazy val spinalHdlCore = ProjectRef(file("../SpinalHDL"), "SpinalHDL-core") -lazy val spinalHdlLib = ProjectRef(file("../SpinalHDL"), "SpinalHDL-lib")*/ +lazy val spinalHdlLib = ProjectRef(file("../SpinalHDL"), "SpinalHDL-lib") addCompilerPlugin("org.scala-lang.plugins" % "scala-continuations-plugin_2.11.6" % "1.0.2") diff --git a/src/main/scala/vexriscv/demo/Murax.scala b/src/main/scala/vexriscv/demo/Murax.scala index 675ef287..8b9c6aa0 100644 --- a/src/main/scala/vexriscv/demo/Murax.scala +++ b/src/main/scala/vexriscv/demo/Murax.scala @@ -4,8 +4,9 @@ import spinal.core._ import spinal.lib._ import spinal.lib.bus.amba3.apb._ import spinal.lib.bus.misc.SizeMapping +import spinal.lib.bus.simple.PipelinedMemoryBus import spinal.lib.com.jtag.Jtag -import spinal.lib.com.spi.ddr.SpiDdrMaster +import spinal.lib.com.spi.ddr.SpiXdrMaster import spinal.lib.com.uart._ import spinal.lib.io.{InOutWrapper, TriStateArray} import spinal.lib.misc.{InterruptCtrl, Prescaler, Timer} @@ -13,6 +14,7 @@ import spinal.lib.soc.pinsec.{PinsecTimerCtrl, PinsecTimerCtrlExternal} import vexriscv.plugin._ import vexriscv.{VexRiscv, VexRiscvConfig, plugin} import spinal.lib.com.spi.ddr._ +import spinal.lib.bus.simple._ import scala.collection.mutable.ArrayBuffer /** @@ -39,7 +41,7 @@ case class MuraxConfig(coreFrequency : HertzNumber, pipelineApbBridge : Boolean, gpioWidth : Int, uartCtrlConfig : UartCtrlMemoryMappedConfig, - xipConfig : SpiDdrMasterCtrl.MemoryMappingParameters, + xipConfig : SpiXdrMasterCtrl.MemoryMappingParameters, hardwareBreakpointCount : Int, cpuPlugins : ArrayBuffer[Plugin[VexRiscv]]){ require(pipelineApbBridge || pipelineMainBus, "At least pipelineMainBus or pipelineApbBridge should be enable to avoid wipe transactions") @@ -59,11 +61,11 @@ object MuraxConfig{ pipelineMainBus = false, pipelineApbBridge = true, gpioWidth = 32, - xipConfig = ifGen(withXip) (SpiDdrMasterCtrl.MemoryMappingParameters( - SpiDdrMasterCtrl.Parameters(8, 12, SpiDdrParameter(2, 2, 1)).addFullDuplex(0,1,false), + xipConfig = ifGen(withXip) (SpiXdrMasterCtrl.MemoryMappingParameters( + SpiXdrMasterCtrl.Parameters(8, 12, SpiXdrParameter(2, 2, 1)).addFullDuplex(0,1,false), cmdFifoDepth = 32, rspFifoDepth = 32, - xip = SpiDdrMasterCtrl.XipBusParameters(addressWidth = 24, dataWidth = 32) + xip = SpiXdrMasterCtrl.XipBusParameters(addressWidth = 24, dataWidth = 32) )), hardwareBreakpointCount = if(withXip) 3 else 0, cpuPlugins = ArrayBuffer( //DebugPlugin added by the toplevel @@ -163,7 +165,7 @@ case class Murax(config : MuraxConfig) extends Component{ val gpioA = master(TriStateArray(gpioWidth bits)) val uart = master(Uart()) - val xip = ifGen(genXip)(master(SpiDdrMaster(xipConfig.ctrl.spi))) + val xip = ifGen(genXip)(master(SpiXdrMaster(xipConfig.ctrl.spi))) } @@ -207,14 +209,14 @@ case class Murax(config : MuraxConfig) extends Component{ ) val system = new ClockingArea(systemClockDomain) { - val simpleBusConfig = SimpleBusConfig( + val pipelinedMemoryBusConfig = PipelinedMemoryBusConfig( addressWidth = 32, dataWidth = 32 ) //Arbiter of the cpu dBus/iBus to drive the mainBus //Priority to dBus, !! cmd transactions can change on the fly !! - val mainBusArbiter = new MuraxMasterArbiter(simpleBusConfig) + val mainBusArbiter = new MuraxMasterArbiter(pipelinedMemoryBusConfig) //Instanciate the CPU val cpu = new VexRiscv( @@ -252,23 +254,23 @@ case class Murax(config : MuraxConfig) extends Component{ //****** MainBus slaves ******** - val mainBusMapping = ArrayBuffer[(SimpleBus,SizeMapping)]() - val ram = new MuraxSimpleBusRam( + val mainBusMapping = ArrayBuffer[(PipelinedMemoryBus,SizeMapping)]() + val ram = new MuraxPipelinedMemoryBusRam( onChipRamSize = onChipRamSize, onChipRamHexFile = onChipRamHexFile, - simpleBusConfig = simpleBusConfig + pipelinedMemoryBusConfig = pipelinedMemoryBusConfig ) mainBusMapping += ram.io.bus -> (0x80000000l, onChipRamSize) - val apbBridge = new MuraxSimpleBusToApbBridge( + val apbBridge = new MuraxPipelinedMemoryBusToApbBridge( apb3Config = Apb3Config( addressWidth = 20, dataWidth = 32 ), pipelineBridge = pipelineApbBridge, - simpleBusConfig = simpleBusConfig + pipelinedMemoryBusConfig = pipelinedMemoryBusConfig ) - mainBusMapping += apbBridge.io.simpleBus -> (0xF0000000l, 1 MB) + mainBusMapping += apbBridge.io.pipelinedMemoryBus -> (0xF0000000l, 1 MB) @@ -288,15 +290,15 @@ case class Murax(config : MuraxConfig) extends Component{ apbMapping += timer.io.apb -> (0x20000, 4 kB) val xip = ifGen(genXip)(new Area{ - val ctrl = Apb3SpiDdrMasterCtrl(xipConfig) + val ctrl = Apb3SpiXdrMasterCtrl(xipConfig) ctrl.io.spi <> io.xip externalInterrupt setWhen(ctrl.io.interrupt) apbMapping += ctrl.io.apb -> (0x1F000, 4 kB) - val accessBus = new SimpleBus(SimpleBusConfig(24,32)) + val accessBus = new PipelinedMemoryBus(PipelinedMemoryBusConfig(24,32)) mainBusMapping += accessBus -> (0xE0000000l, 16 MB) - ctrl.io.xip.cmd.valid <> (accessBus.cmd.valid && !accessBus.cmd.wr) + ctrl.io.xip.cmd.valid <> (accessBus.cmd.valid && !accessBus.cmd.write) ctrl.io.xip.cmd.ready <> accessBus.cmd.ready ctrl.io.xip.cmd.payload <> accessBus.cmd.address @@ -316,7 +318,7 @@ case class Murax(config : MuraxConfig) extends Component{ ) val mainBusDecoder = new Area { - val logic = new MuraxSimpleBusDecoder( + val logic = new MuraxPipelinedMemoryBusDecoder( master = mainBusArbiter.io.masterBus, specification = mainBusMapping, pipelineMaster = pipelineMainBus diff --git a/src/main/scala/vexriscv/demo/MuraxUtiles.scala b/src/main/scala/vexriscv/demo/MuraxUtiles.scala index b940e8cf..9ada9f6d 100644 --- a/src/main/scala/vexriscv/demo/MuraxUtiles.scala +++ b/src/main/scala/vexriscv/demo/MuraxUtiles.scala @@ -7,17 +7,18 @@ 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(simpleBusConfig : SimpleBusConfig) extends Component{ +class MuraxMasterArbiter(pipelinedMemoryBusConfig : PipelinedMemoryBusConfig) extends Component{ val io = new Bundle{ val iBus = slave(IBusSimpleBus(false)) val dBus = slave(DBusSimpleBus()) - val masterBus = master(SimpleBus(simpleBusConfig)) + val masterBus = master(PipelinedMemoryBus(pipelinedMemoryBusConfig)) } io.masterBus.cmd.valid := io.iBus.cmd.valid || io.dBus.cmd.valid - io.masterBus.cmd.wr := io.dBus.cmd.valid && io.dBus.cmd.wr + 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.cmd.size.mux( @@ -31,7 +32,7 @@ class MuraxMasterArbiter(simpleBusConfig : SimpleBusConfig) extends Component{ val rspPending = RegInit(False) clearWhen(io.masterBus.rsp.valid) val rspTarget = RegInit(False) - when(io.masterBus.cmd.fire && !io.masterBus.cmd.wr){ + when(io.masterBus.cmd.fire && !io.masterBus.cmd.write){ rspTarget := io.dBus.cmd.valid rspPending := True } @@ -52,18 +53,18 @@ class MuraxMasterArbiter(simpleBusConfig : SimpleBusConfig) extends Component{ } -case class MuraxSimpleBusRam(onChipRamSize : BigInt, onChipRamHexFile : String, simpleBusConfig : SimpleBusConfig) extends Component{ +case class MuraxPipelinedMemoryBusRam(onChipRamSize : BigInt, onChipRamHexFile : String, pipelinedMemoryBusConfig : PipelinedMemoryBusConfig) extends Component{ val io = new Bundle{ - val bus = slave(SimpleBus(simpleBusConfig)) + 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.wr) init(False) + 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.wr, + write = io.bus.cmd.write, mask = io.bus.cmd.mask ) io.bus.cmd.ready := True @@ -95,42 +96,42 @@ case class Apb3Rom(onChipRamBinFile : String) extends Component{ io.apb.PREADY := True } -class MuraxSimpleBusToApbBridge(apb3Config: Apb3Config, pipelineBridge : Boolean, simpleBusConfig : SimpleBusConfig) extends Component{ - assert(apb3Config.dataWidth == simpleBusConfig.dataWidth) +class MuraxPipelinedMemoryBusToApbBridge(apb3Config: Apb3Config, pipelineBridge : Boolean, pipelinedMemoryBusConfig : PipelinedMemoryBusConfig) extends Component{ + assert(apb3Config.dataWidth == pipelinedMemoryBusConfig.dataWidth) val io = new Bundle { - val simpleBus = slave(SimpleBus(simpleBusConfig)) + val pipelinedMemoryBus = slave(PipelinedMemoryBus(pipelinedMemoryBusConfig)) val apb = master(Apb3(apb3Config)) } - val simpleBusStage = SimpleBus(simpleBusConfig) - simpleBusStage.cmd << (if(pipelineBridge) io.simpleBus.cmd.halfPipe() else io.simpleBus.cmd) - simpleBusStage.rsp >-> io.simpleBus.rsp + val pipelinedMemoryBusStage = PipelinedMemoryBus(pipelinedMemoryBusConfig) + pipelinedMemoryBusStage.cmd << (if(pipelineBridge) io.pipelinedMemoryBus.cmd.halfPipe() else io.pipelinedMemoryBus.cmd) + pipelinedMemoryBusStage.rsp >-> io.pipelinedMemoryBus.rsp val state = RegInit(False) - simpleBusStage.cmd.ready := False + pipelinedMemoryBusStage.cmd.ready := False - io.apb.PSEL(0) := simpleBusStage.cmd.valid + io.apb.PSEL(0) := pipelinedMemoryBusStage.cmd.valid io.apb.PENABLE := state - io.apb.PWRITE := simpleBusStage.cmd.wr - io.apb.PADDR := simpleBusStage.cmd.address.resized - io.apb.PWDATA := simpleBusStage.cmd.data + io.apb.PWRITE := pipelinedMemoryBusStage.cmd.write + io.apb.PADDR := pipelinedMemoryBusStage.cmd.address.resized + io.apb.PWDATA := pipelinedMemoryBusStage.cmd.data - simpleBusStage.rsp.valid := False - simpleBusStage.rsp.data := io.apb.PRDATA + pipelinedMemoryBusStage.rsp.valid := False + pipelinedMemoryBusStage.rsp.data := io.apb.PRDATA when(!state) { - state := simpleBusStage.cmd.valid + state := pipelinedMemoryBusStage.cmd.valid } otherwise { when(io.apb.PREADY){ state := False - simpleBusStage.rsp.valid := !simpleBusStage.cmd.wr - simpleBusStage.cmd.ready := True + pipelinedMemoryBusStage.rsp.valid := !pipelinedMemoryBusStage.cmd.write + pipelinedMemoryBusStage.cmd.ready := True } } } -class MuraxSimpleBusDecoder(master : SimpleBus, val specification : Seq[(SimpleBus,SizeMapping)], pipelineMaster : Boolean) extends Area{ - val masterPipelined = SimpleBus(master.config) +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 @@ -151,7 +152,7 @@ class MuraxSimpleBusDecoder(master : SimpleBus, val specification : Seq[(SimpleB 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.wr) + 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) diff --git a/src/main/scala/vexriscv/demo/SimpleBus.scala b/src/main/scala/vexriscv/demo/SimpleBus.scala deleted file mode 100644 index e8a74044..00000000 --- a/src/main/scala/vexriscv/demo/SimpleBus.scala +++ /dev/null @@ -1,324 +0,0 @@ -package vexriscv.demo - - -import spinal.core._ -import spinal.lib.bus.misc._ -import spinal.lib._ - -import scala.collection.mutable -import scala.collection.mutable.ArrayBuffer - -case class SimpleBusConfig(addressWidth : Int, dataWidth : Int) - -case class SimpleBusCmd(config : SimpleBusConfig) extends Bundle{ - val wr = Bool - val address = UInt(config.addressWidth bits) - val data = Bits(config.dataWidth bits) - val mask = Bits(4 bit) -} - -case class SimpleBusRsp(config : SimpleBusConfig) extends Bundle{ - val data = Bits(config.dataWidth bits) -} - -object SimpleBus{ - def apply(addressWidth : Int, dataWidth : Int) = new SimpleBus(SimpleBusConfig(addressWidth, dataWidth)) -} -case class SimpleBus(config : SimpleBusConfig) extends Bundle with IMasterSlave { - val cmd = Stream(SimpleBusCmd(config)) - val rsp = Flow(SimpleBusRsp(config)) - - override def asMaster(): Unit = { - master(cmd) - slave(rsp) - } - - def <<(m : SimpleBus) : Unit = { - val s = this - assert(m.config.addressWidth >= s.config.addressWidth) - assert(m.config.dataWidth == s.config.dataWidth) - s.cmd.valid := m.cmd.valid - s.cmd.wr := m.cmd.wr - s.cmd.address := m.cmd.address.resized - s.cmd.data := m.cmd.data - s.cmd.mask := m.cmd.mask - m.cmd.ready := s.cmd.ready - m.rsp.valid := s.rsp.valid - m.rsp.data := s.rsp.data - } - def >>(s : SimpleBus) : Unit = s << this - - def cmdM2sPipe(): SimpleBus = { - val ret = cloneOf(this) - this.cmd.m2sPipe() >> ret.cmd - this.rsp << ret.rsp - ret - } - - def cmdS2mPipe(): SimpleBus = { - val ret = cloneOf(this) - this.cmd.s2mPipe() >> ret.cmd - this.rsp << ret.rsp - ret - } - - def rspPipe(): SimpleBus = { - val ret = cloneOf(this) - this.cmd >> ret.cmd - this.rsp << ret.rsp.stage() - ret - } -} - - - - - -object SimpleBusArbiter{ - def apply(inputs : Seq[SimpleBus], pendingRspMax : Int, rspRouteQueue : Boolean, transactionLock : Boolean): SimpleBus = { - val c = SimpleBusArbiter(inputs.head.config, inputs.size, pendingRspMax, rspRouteQueue, transactionLock) - (inputs, c.io.inputs).zipped.foreach(_ <> _) - c.io.output - } -} - -case class SimpleBusArbiter(simpleBusConfig : SimpleBusConfig, portCount : Int, pendingRspMax : Int, rspRouteQueue : Boolean, transactionLock : Boolean = true) extends Component{ - val io = new Bundle{ - val inputs = Vec(slave(SimpleBus(simpleBusConfig)), portCount) - val output = master(SimpleBus(simpleBusConfig)) - } - val logic = if(portCount == 1) new Area{ - io.output << io.inputs(0) - } else new Area { - val arbiterFactory = StreamArbiterFactory.lowerFirst - if(transactionLock) arbiterFactory.transactionLock else arbiterFactory.noLock - val arbiter = arbiterFactory.build(SimpleBusCmd(simpleBusConfig), portCount) - (arbiter.io.inputs, io.inputs).zipped.foreach(_ <> _.cmd) - - val rspRouteOh = Bits(portCount bits) - - val rsp = if(!rspRouteQueue) new Area{ - assert(pendingRspMax == 1) - val pending = RegInit(False) clearWhen(io.output.rsp.valid) - val target = Reg(Bits(portCount bits)) - rspRouteOh := target - when(io.output.cmd.fire && !io.output.cmd.wr){ - target := arbiter.io.chosenOH - pending := True - } - io.output.cmd << arbiter.io.output.haltWhen(pending && !io.output.rsp.valid) - } else new Area{ - val (outputCmdFork, routeCmdFork) = StreamFork2(arbiter.io.output) - io.output.cmd << outputCmdFork - - val rspRoute = routeCmdFork.translateWith(arbiter.io.chosenOH).throwWhen(routeCmdFork.wr).queueLowLatency(size = pendingRspMax, latency = 1) - rspRoute.ready := io.output.rsp.valid - rspRouteOh := rspRoute.payload - } - - for ((input, id) <- io.inputs.zipWithIndex) { - input.rsp.valid := io.output.rsp.valid && rspRouteOh(id) - input.rsp.payload := io.output.rsp.payload - } - } -} - -class SimpleBusSlaveFactory(bus: SimpleBus) extends BusSlaveFactoryDelayed{ - bus.cmd.ready := True - - val readAtCmd = Flow(Bits(bus.config.dataWidth bits)) - val readAtRsp = readAtCmd.stage() - - val askWrite = (bus.cmd.valid && bus.cmd.wr).allowPruning() - val askRead = (bus.cmd.valid && !bus.cmd.wr).allowPruning() - val doWrite = (askWrite && bus.cmd.ready).allowPruning() - val doRead = (askRead && bus.cmd.ready).allowPruning() - - bus.rsp.valid := readAtRsp.valid - bus.rsp.data := readAtRsp.payload - - readAtCmd.valid := doRead - readAtCmd.payload := 0 - - def readAddress() : UInt = bus.cmd.address - def writeAddress() : UInt = bus.cmd.address - - override def readHalt(): Unit = bus.cmd.ready := False - override def writeHalt(): Unit = bus.cmd.ready := False - - override def build(): Unit = { - super.doNonStopWrite(bus.cmd.data) - - def doMappedElements(jobs : Seq[BusSlaveFactoryElement]) = super.doMappedElements( - jobs = jobs, - askWrite = askWrite, - askRead = askRead, - doWrite = doWrite, - doRead = doRead, - writeData = bus.cmd.data, - readData = readAtCmd.payload - ) - - switch(bus.cmd.address) { - for ((address, jobs) <- elementsPerAddress if address.isInstanceOf[SingleMapping]) { - is(address.asInstanceOf[SingleMapping].address) { - doMappedElements(jobs) - } - } - } - - for ((address, jobs) <- elementsPerAddress if !address.isInstanceOf[SingleMapping]) { - when(address.hit(bus.cmd.address)){ - doMappedElements(jobs) - } - } - } - - override def busDataWidth: Int = bus.config.dataWidth - override def wordAddressInc: Int = busDataWidth / 8 -} - -case class SimpleBusDecoder(busConfig : SimpleBusConfig, mappings : Seq[AddressMapping], pendingMax : Int = 3) extends Component{ - val io = new Bundle { - val input = slave(SimpleBus(busConfig)) - val outputs = Vec(master(SimpleBus(busConfig)), mappings.size) - } - val hasDefault = mappings.contains(DefaultMapping) - val logic = if(hasDefault && mappings.size == 1){ - io.outputs(0) <> io.input - } else new Area { - val hits = Vec(Bool, mappings.size) - for ((slaveBus, memorySpace, hit) <- (io.outputs, mappings, hits).zipped) yield { - hit := (memorySpace match { - case DefaultMapping => !hits.filterNot(_ == hit).orR - case _ => memorySpace.hit(io.input.cmd.address) - }) - slaveBus.cmd.valid := io.input.cmd.valid && hit - slaveBus.cmd.payload := io.input.cmd.payload.resized - } - val noHit = if (!hasDefault) !hits.orR else False - io.input.cmd.ready := (hits, io.outputs).zipped.map(_ && _.cmd.ready).orR || noHit - - val rspPendingCounter = Reg(UInt(log2Up(pendingMax + 1) bits)) init (0) - rspPendingCounter := rspPendingCounter + U(io.input.cmd.fire && !io.input.cmd.wr) - U(io.input.rsp.valid) - val rspHits = RegNextWhen(hits, io.input.cmd.fire) - val rspPending = rspPendingCounter =/= 0 - val rspNoHit = if (!hasDefault) !rspHits.orR else False - io.input.rsp.valid := io.outputs.map(_.rsp.valid).orR || (rspPending && rspNoHit) - io.input.rsp.payload := io.outputs.map(_.rsp.payload).read(OHToUInt(rspHits)) - - val cmdWait = (io.input.cmd.valid && rspPending && hits =/= rspHits) || rspPendingCounter === pendingMax - when(cmdWait) { - io.input.cmd.ready := False - io.outputs.foreach(_.cmd.valid := False) - } - } -} - -object SimpleBusConnectors{ - def direct(m : SimpleBus, s : SimpleBus) : Unit = m >> s -} - -case class SimpleBusInterconnect(){ - case class MasterModel(var connector : (SimpleBus,SimpleBus) => Unit = SimpleBusConnectors.direct) - case class SlaveModel(mapping : AddressMapping, var connector : (SimpleBus,SimpleBus) => Unit = SimpleBusConnectors.direct, var transactionLock : Boolean = true) - case class ConnectionModel(m : SimpleBus, s : SimpleBus, var connector : (SimpleBus,SimpleBus) => Unit = SimpleBusConnectors.direct) - - val masters = mutable.LinkedHashMap[SimpleBus, MasterModel]() - val slaves = mutable.LinkedHashMap[SimpleBus, SlaveModel]() - val connections = ArrayBuffer[ConnectionModel]() - var arbitrationPendingRspMaxDefault = 1 - var arbitrationRspRouteQueueDefault = false - - def perfConfig(): Unit ={ - arbitrationPendingRspMaxDefault = 7 - arbitrationRspRouteQueueDefault = true - } - - def areaConfig(): Unit ={ - arbitrationPendingRspMaxDefault = 1 - arbitrationRspRouteQueueDefault = false - } - - def setConnector(bus : SimpleBus)( connector : (SimpleBus,SimpleBus) => Unit): Unit = (masters.get(bus), slaves.get(bus)) match { - case (Some(m), _) => m.connector = connector - case (None, Some(s)) => s.connector = connector - } - - def setConnector(m : SimpleBus, s : SimpleBus)(connector : (SimpleBus,SimpleBus) => Unit): Unit = connections.find(e => e.m == m && e.s == s) match { - case Some(c) => c.connector = connector - } - - def addSlave(bus: SimpleBus,mapping: AddressMapping) : this.type = { - slaves(bus) = SlaveModel(mapping) - this - } - - def addSlaves(orders : (SimpleBus,AddressMapping)*) : this.type = { - orders.foreach(order => addSlave(order._1,order._2)) - this - } - - def noTransactionLockOn(slave : SimpleBus) : Unit = slaves(slave).transactionLock = false - def noTransactionLockOn(slaves : Seq[SimpleBus]) : Unit = slaves.foreach(noTransactionLockOn(_)) - - - def addMaster(bus : SimpleBus, accesses : Seq[SimpleBus]) : this.type = { - masters(bus) = MasterModel() - for(s <- accesses) connections += ConnectionModel(bus, s) - this - } - - def addMasters(specs : (SimpleBus,Seq[SimpleBus])*) : this.type = { - specs.foreach(spec => addMaster(spec._1,spec._2)) - this - } - - def build(): Unit ={ - def applyName(bus : Bundle,name : String, onThat : Nameable) : Unit = { - if(bus.component == Component.current) - onThat.setCompositeName(bus,name) - else if(bus.isNamed) - onThat.setCompositeName(bus.component,bus.getName() + "_" + name) - } - - val connectionsInput = mutable.HashMap[ConnectionModel,SimpleBus]() - val connectionsOutput = mutable.HashMap[ConnectionModel,SimpleBus]() - for((bus, model) <- masters){ - val busConnections = connections.filter(_.m == bus) - val busSlaves = busConnections.map(c => slaves(c.s)) - val decoder = new SimpleBusDecoder(bus.config, busSlaves.map(_.mapping)) - applyName(bus,"decoder",decoder) - model.connector(bus, decoder.io.input) - for((connection, decoderOutput) <- (busConnections, decoder.io.outputs).zipped) { - connectionsInput(connection) = decoderOutput - } - } - - for((bus, model) <- slaves){ - val busConnections = connections.filter(_.s == bus) - val busMasters = busConnections.map(c => masters(c.m)) - val arbiter = new SimpleBusArbiter(bus.config, busMasters.size, arbitrationPendingRspMaxDefault, arbitrationRspRouteQueueDefault, model.transactionLock) - applyName(bus,"arbiter",arbiter) - model.connector(arbiter.io.output, bus) - for((connection, arbiterInput) <- (busConnections, arbiter.io.inputs).zipped) { - connectionsOutput(connection) = arbiterInput - } - } - - for(connection <- connections){ - val m = connectionsInput(connection) - val s = connectionsOutput(connection) - if(m.config == s.config) { - connection.connector(m, s) - }else{ - val tmp = cloneOf(s) - m >> tmp //Adapte the bus kind. - connection.connector(tmp,s) - } - } - } - - //Will make SpinalHDL calling the build function at the end of the current component elaboration - Component.current.addPrePopTask(build) -} diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index 88538200..5e4f9b79 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -6,7 +6,7 @@ import spinal.lib._ import spinal.lib.bus.amba4.axi.{Axi4Config, Axi4Shared} import spinal.lib.bus.avalon.{AvalonMM, AvalonMMConfig} import spinal.lib.bus.wishbone.{Wishbone, WishboneConfig} -import vexriscv.demo.SimpleBus +import spinal.lib.bus.simple._ case class DataCacheConfig( cacheSize : Int, bytePerLine : Int, @@ -346,8 +346,8 @@ case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave - def toSimpleBus(): SimpleBus = { - val bus = SimpleBus(32,32) + def toPipelinedMemoryBus(): PipelinedMemoryBus = { + val bus = PipelinedMemoryBus(32,32) val counter = Reg(UInt(log2Up(p.burstSize) bits)) init(0) when(bus.cmd.fire){ counter := counter + 1 } @@ -355,7 +355,7 @@ case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave bus.cmd.valid := cmd.valid bus.cmd.address := (cmd.address(31 downto 2) | counter.resized) @@ U"00" - bus.cmd.wr := cmd.wr + bus.cmd.write := cmd.wr bus.cmd.mask := cmd.mask bus.cmd.data := cmd.data cmd.ready := bus.cmd.ready && (cmd.wr || counter === cmd.length) diff --git a/src/main/scala/vexriscv/ip/InstructionCache.scala b/src/main/scala/vexriscv/ip/InstructionCache.scala index 8ba3ba49..40cb700e 100644 --- a/src/main/scala/vexriscv/ip/InstructionCache.scala +++ b/src/main/scala/vexriscv/ip/InstructionCache.scala @@ -6,7 +6,7 @@ import spinal.lib._ import spinal.lib.bus.amba4.axi.{Axi4Config, Axi4ReadOnly} import spinal.lib.bus.avalon.{AvalonMM, AvalonMMConfig} import spinal.lib.bus.wishbone.{Wishbone, WishboneConfig} -import vexriscv.demo.{SimpleBus, SimpleBusConfig} +import spinal.lib.bus.simple._ case class InstructionCacheConfig( cacheSize : Int, @@ -46,7 +46,7 @@ case class InstructionCacheConfig( cacheSize : Int, constantBurstBehavior = true ) - def getSimpleBusConfig() = SimpleBusConfig( + def getPipelinedMemoryBusConfig() = PipelinedMemoryBusConfig( addressWidth = 32, dataWidth = 32 ) @@ -185,13 +185,13 @@ case class InstructionCacheMemBus(p : InstructionCacheConfig) extends Bundle wit } - def toSimpleBus(): SimpleBus = { - val simpleBusConfig = p.getSimpleBusConfig() - val bus = SimpleBus(simpleBusConfig) + def toPipelinedMemoryBus(): PipelinedMemoryBus = { + val pipelinedMemoryBusConfig = p.getPipelinedMemoryBusConfig() + val bus = PipelinedMemoryBus(pipelinedMemoryBusConfig) val counter = Counter(p.burstSize, bus.cmd.fire) bus.cmd.valid := cmd.valid bus.cmd.address := cmd.address(31 downto widthOf(counter.value) + 2) @@ counter @@ U"00" - bus.cmd.wr := False + bus.cmd.write := False bus.cmd.mask.assignDontCare() bus.cmd.data.assignDontCare() cmd.ready := counter.willOverflow diff --git a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala index 3f4479cd..eb4ce468 100644 --- a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala @@ -6,7 +6,7 @@ import spinal.lib._ import spinal.lib.bus.amba4.axi._ import spinal.lib.bus.avalon.{AvalonMM, AvalonMMConfig} import spinal.lib.bus.wishbone.{Wishbone, WishboneConfig} -import vexriscv.demo.SimpleBus +import spinal.lib.bus.simple._ import vexriscv.ip.DataCacheMemCmd @@ -176,11 +176,11 @@ case class DBusSimpleBus() extends Bundle with IMasterSlave{ rsp.error := False //TODO bus } - - def toSimpleBus() : SimpleBus = { - val bus = SimpleBus(32,32) + + def toPipelinedMemoryBus() : PipelinedMemoryBus = { + val bus = PipelinedMemoryBus(32,32) bus.cmd.valid := cmd.valid - bus.cmd.wr := cmd.wr + bus.cmd.write := cmd.wr bus.cmd.address := cmd.address.resized bus.cmd.data := cmd.data bus.cmd.mask := cmd.size.mux( diff --git a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala index 756d372f..636b1930 100644 --- a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala @@ -6,8 +6,7 @@ import spinal.lib._ import spinal.lib.bus.amba4.axi._ import spinal.lib.bus.avalon.{AvalonMM, AvalonMMConfig} import spinal.lib.bus.wishbone.{Wishbone, WishboneConfig} -import vexriscv.demo.SimpleBus - +import spinal.lib.bus.simple._ case class IBusSimpleCmd() extends Bundle{ @@ -136,11 +135,11 @@ case class IBusSimpleBus(interfaceKeepData : Boolean = false) extends Bundle wit bus } - def toSimpleBus(): SimpleBus = { - val bus = SimpleBus(32,32) + def toPipelinedMemoryBus(): PipelinedMemoryBus = { + val bus = PipelinedMemoryBus(32,32) bus.cmd.arbitrationFrom(cmd) bus.cmd.address := cmd.pc.resized - bus.cmd.wr := False + bus.cmd.write := False bus.cmd.mask.assignDontCare() bus.cmd.data.assignDontCare() rsp.valid := bus.rsp.valid From 58d7a4784d5c1a75923c44060400b8ef4e038de0 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 30 Nov 2018 17:39:33 +0100 Subject: [PATCH 003/951] move HexTools into SpinalHDL lib --- src/main/scala/spinal/lib/misc/HexTools.scala | 58 ------------------- 1 file changed, 58 deletions(-) delete mode 100644 src/main/scala/spinal/lib/misc/HexTools.scala diff --git a/src/main/scala/spinal/lib/misc/HexTools.scala b/src/main/scala/spinal/lib/misc/HexTools.scala deleted file mode 100644 index d35de536..00000000 --- a/src/main/scala/spinal/lib/misc/HexTools.scala +++ /dev/null @@ -1,58 +0,0 @@ -package spinal.lib.misc - -import spinal.core._ - -import scala.collection.mutable.ArrayBuffer - -object HexTools{ - def readHexFile(path : String, hexOffset : Int, callback : (Int, Int) => Unit) : Unit ={ - import scala.io.Source - def hToI(that : String, start : Int, size : Int) = Integer.parseInt(that.substring(start,start + size), 16) - - var offset = 0 - for (line <- Source.fromFile(path).getLines) { - if (line.charAt(0) == ':'){ - val byteCount = hToI(line, 1, 2) - val nextAddr = hToI(line, 3, 4) + offset - val key = hToI(line, 7, 2) - key match { - case 0 => - for(i <- 0 until byteCount){ - callback(nextAddr + i - hexOffset, hToI(line, 9 + i * 2, 2)) - } - case 2 => - offset = hToI(line, 9, 4) << 4 - case 4 => - offset = hToI(line, 9, 4) << 16 - case 3 => - case 5 => - case 1 => - } - } - } - } - - def readHexFile(path : String, hexOffset : Int): Array[BigInt] ={ - var onChipRomSize = 0 - readHexFile(path, hexOffset ,(address, _) => { - onChipRomSize = Math.max((address).toInt, onChipRomSize) + 1 - }) - - val initContent = Array.fill[BigInt]((onChipRomSize+3)/4)(0) - readHexFile(path, hexOffset,(address,data) => { - val addressWithoutOffset = (address).toInt - if(addressWithoutOffset < onChipRomSize) - initContent(addressWithoutOffset >> 2) |= BigInt(data) << ((addressWithoutOffset & 3)*8) - }) - initContent - } - - def initRam[T <: Data](ram : Mem[T], onChipRamHexFile : String, hexOffset : BigInt): Unit ={ - val initContent = Array.fill[BigInt](ram.wordCount)(0) - HexTools.readHexFile(onChipRamHexFile, 0,(address,data) => { - val addressWithoutOffset = (address - hexOffset).toInt - initContent(addressWithoutOffset >> 2) |= BigInt(data) << ((addressWithoutOffset & 3)*8) - }) - ram.initBigInt(initContent) - } -} \ No newline at end of file From 3d710451593aef7ba0eccc6bf782622f363698d9 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sat, 1 Dec 2018 18:24:33 +0100 Subject: [PATCH 004/951] DebugPlugin doesn't require memory/writeback stage anymore --- src/main/scala/vexriscv/plugin/DebugPlugin.scala | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/DebugPlugin.scala b/src/main/scala/vexriscv/plugin/DebugPlugin.scala index 7d28b24c..56f27952 100644 --- a/src/main/scala/vexriscv/plugin/DebugPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DebugPlugin.scala @@ -141,7 +141,7 @@ class DebugPlugin(val debugClockDomain : ClockDomain, hardwareBreakpointCount : val haltIt = RegInit(False) val stepIt = RegInit(False) - val isPipActive = RegNext(List(decode,execute, memory, writeBack).map(_.arbitration.isValid).orR) + val isPipActive = RegNext(stages.map(_.arbitration.isValid).orR) val isPipBusy = isPipActive || RegNext(isPipActive) val haltedByBreak = RegInit(False) @@ -152,8 +152,8 @@ class DebugPlugin(val debugClockDomain : ClockDomain, hardwareBreakpointCount : hardwareBreakpoints.foreach(_.valid init(False)) val busReadDataReg = Reg(Bits(32 bit)) - when(writeBack.arbitration.isValid) { - busReadDataReg := writeBack.output(REGFILE_WRITE_DATA) + when(stages.last.arbitration.isValid) { + busReadDataReg := stages.last.output(REGFILE_WRITE_DATA) } io.bus.cmd.ready := True io.bus.rsp.data := busReadDataReg @@ -199,7 +199,7 @@ class DebugPlugin(val debugClockDomain : ClockDomain, hardwareBreakpointCount : when(execute.arbitration.isValid && execute.input(DO_EBREAK)){ execute.arbitration.haltByOther := True busReadDataReg := execute.input(PC).asBits - when(List(memory, writeBack).map(_.arbitration.isValid).orR === False){ + when(stagesFromExecute.tail.map(_.arbitration.isValid).orR === False){ iBusFetcher.flushIt() iBusFetcher.haltIt() execute.arbitration.flushAll := True From ac1ed40b80f2f2aaec678bb4abb4f296f946c3ea Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sat, 1 Dec 2018 18:25:18 +0100 Subject: [PATCH 005/951] Move things into SpinalHDL lib --- src/main/scala/vexriscv/VexRiscv.scala | 2 ++ src/main/scala/vexriscv/demo/Murax.scala | 2 +- .../scala/vexriscv/demo/MuraxUtiles.scala | 32 ------------------- src/test/scala/vexriscv/MuraxSim.scala | 6 ++-- 4 files changed, 6 insertions(+), 36 deletions(-) diff --git a/src/main/scala/vexriscv/VexRiscv.scala b/src/main/scala/vexriscv/VexRiscv.scala index 01ce0ca3..9665a31c 100644 --- a/src/main/scala/vexriscv/VexRiscv.scala +++ b/src/main/scala/vexriscv/VexRiscv.scala @@ -22,6 +22,8 @@ case class VexRiscvConfig(){ var withWriteBackStage = true val plugins = ArrayBuffer[Plugin[VexRiscv]]() + def add(that : Plugin[VexRiscv]) : this.type = {plugins += that;this} + //Default Stageables object IS_RVC extends Stageable(Bool) object BYPASSABLE_EXECUTE_STAGE extends Stageable(Bool) diff --git a/src/main/scala/vexriscv/demo/Murax.scala b/src/main/scala/vexriscv/demo/Murax.scala index 8b9c6aa0..8a06cbc6 100644 --- a/src/main/scala/vexriscv/demo/Murax.scala +++ b/src/main/scala/vexriscv/demo/Murax.scala @@ -262,7 +262,7 @@ case class Murax(config : MuraxConfig) extends Component{ ) mainBusMapping += ram.io.bus -> (0x80000000l, onChipRamSize) - val apbBridge = new MuraxPipelinedMemoryBusToApbBridge( + val apbBridge = new PipelinedMemoryBusToApbBridge( apb3Config = Apb3Config( addressWidth = 20, dataWidth = 32 diff --git a/src/main/scala/vexriscv/demo/MuraxUtiles.scala b/src/main/scala/vexriscv/demo/MuraxUtiles.scala index 9ada9f6d..24224507 100644 --- a/src/main/scala/vexriscv/demo/MuraxUtiles.scala +++ b/src/main/scala/vexriscv/demo/MuraxUtiles.scala @@ -96,39 +96,7 @@ case class Apb3Rom(onChipRamBinFile : String) extends Component{ io.apb.PREADY := True } -class MuraxPipelinedMemoryBusToApbBridge(apb3Config: Apb3Config, pipelineBridge : Boolean, pipelinedMemoryBusConfig : PipelinedMemoryBusConfig) extends Component{ - assert(apb3Config.dataWidth == pipelinedMemoryBusConfig.dataWidth) - val io = new Bundle { - val pipelinedMemoryBus = slave(PipelinedMemoryBus(pipelinedMemoryBusConfig)) - val apb = master(Apb3(apb3Config)) - } - - val pipelinedMemoryBusStage = PipelinedMemoryBus(pipelinedMemoryBusConfig) - pipelinedMemoryBusStage.cmd << (if(pipelineBridge) io.pipelinedMemoryBus.cmd.halfPipe() else io.pipelinedMemoryBus.cmd) - pipelinedMemoryBusStage.rsp >-> io.pipelinedMemoryBus.rsp - - val state = RegInit(False) - pipelinedMemoryBusStage.cmd.ready := False - - io.apb.PSEL(0) := pipelinedMemoryBusStage.cmd.valid - io.apb.PENABLE := state - io.apb.PWRITE := pipelinedMemoryBusStage.cmd.write - io.apb.PADDR := pipelinedMemoryBusStage.cmd.address.resized - io.apb.PWDATA := pipelinedMemoryBusStage.cmd.data - - pipelinedMemoryBusStage.rsp.valid := False - pipelinedMemoryBusStage.rsp.data := io.apb.PRDATA - when(!state) { - state := pipelinedMemoryBusStage.cmd.valid - } otherwise { - when(io.apb.PREADY){ - state := False - pipelinedMemoryBusStage.rsp.valid := !pipelinedMemoryBusStage.cmd.write - pipelinedMemoryBusStage.cmd.ready := True - } - } -} class MuraxPipelinedMemoryBusDecoder(master : PipelinedMemoryBus, val specification : Seq[(PipelinedMemoryBus,SizeMapping)], pipelineMaster : Boolean) extends Area{ val masterPipelined = PipelinedMemoryBus(master.config) diff --git a/src/test/scala/vexriscv/MuraxSim.scala b/src/test/scala/vexriscv/MuraxSim.scala index 53c22b33..2cb78021 100644 --- a/src/test/scala/vexriscv/MuraxSim.scala +++ b/src/test/scala/vexriscv/MuraxSim.scala @@ -20,9 +20,9 @@ import scala.collection.mutable object MuraxSim { def main(args: Array[String]): Unit = { // def config = MuraxConfig.default.copy(onChipRamSize = 256 kB) - def config = MuraxConfig.default(withXip = true).copy(onChipRamSize = 4 kB, onChipRamHexFile = "src/main/ressource/hex/muraxDemo.hex") - val simSlowDown = true - SimConfig.allOptimisation.withWave.compile(new Murax(config)).doSimUntilVoid{dut => + def config = MuraxConfig.default(withXip = false).copy(onChipRamSize = 4 kB, onChipRamHexFile = "src/main/ressource/hex/muraxDemo.hex") + val simSlowDown = false + SimConfig.allOptimisation.compile(new Murax(config)).doSimUntilVoid{dut => val mainClkPeriod = (1e12/dut.config.coreFrequency.toDouble).toLong val jtagClkPeriod = mainClkPeriod*4 val uartBaudRate = 115200 From eca54585b01c67d8d3bd009f6afede3d9c300dc5 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 4 Dec 2018 16:57:24 +0100 Subject: [PATCH 006/951] Fix hardware breakpoint --- src/main/scala/vexriscv/plugin/DebugPlugin.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/plugin/DebugPlugin.scala b/src/main/scala/vexriscv/plugin/DebugPlugin.scala index 56f27952..4915eea6 100644 --- a/src/main/scala/vexriscv/plugin/DebugPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DebugPlugin.scala @@ -195,7 +195,7 @@ class DebugPlugin(val debugClockDomain : ClockDomain, hardwareBreakpointCount : } - decode.insert(DO_EBREAK) := !haltIt && (decode.input(IS_EBREAK) || hardwareBreakpoints.map(hb => hb.valid && hb.pc === (execute.input(PC) >> 1)).foldLeft(False)(_ || _)) + decode.insert(DO_EBREAK) := !haltIt && (decode.input(IS_EBREAK) || hardwareBreakpoints.map(hb => hb.valid && hb.pc === (decode.input(PC) >> 1)).foldLeft(False)(_ || _)) when(execute.arbitration.isValid && execute.input(DO_EBREAK)){ execute.arbitration.haltByOther := True busReadDataReg := execute.input(PC).asBits From 6334f430fe1bed302733c6ea6c44f8b514f3e2c6 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 4 Dec 2018 19:07:51 +0100 Subject: [PATCH 007/951] Update README.md Fix #44 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b67b0e3d..430d1625 100644 --- a/README.md +++ b/README.md @@ -159,7 +159,7 @@ You can find two example CPU instances in: - src/main/scala/vexriscv/GenFull.scala - src/main/scala/vexriscv/GenSmallest.scala -To generate the corresponding RTL as a VexRiscv.v file, run: +To generate the corresponding RTL as a VexRiscv.v file, run the following commands in the root directory of this repository: ```sh sbt "run-main vexriscv.demo.GenFull" From 68fdbe60ccab30b16d9b08fef37b13ac0f9d5cc1 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 7 Dec 2018 23:43:19 +0100 Subject: [PATCH 008/951] verilator regression fix missing fclose #46 --- src/test/cpp/regression/main.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index ab9fab62..016555dc 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -106,6 +106,7 @@ void loadHexImpl(string path,Memory* mem) { fseek(fp, 0, SEEK_SET); char* content = new char[size]; fread(content, 1, size, fp); + fclose(fp); int offset = 0; char* line = content; @@ -2104,15 +2105,19 @@ public: fseek(refFile, 0, SEEK_SET); char* ref = new char[refSize]; fread(ref, 1, refSize, refFile); + fclose(refFile); logTraces.flush(); + logTraces.close(); + FILE *logFile = fopen((name + ".logTrace").c_str(), "r"); fseek(logFile, 0, SEEK_END); uint32_t logSize = ftell(logFile); fseek(logFile, 0, SEEK_SET); char* log = new char[logSize]; fread(log, 1, logSize, logFile); + fclose(logFile); if(refSize > logSize || memcmp(log,ref,refSize)) fail(); @@ -2157,15 +2162,19 @@ public: fseek(refFile, 0, SEEK_SET); char* ref = new char[refSize]; fread(ref, 1, refSize, refFile); + fclose(refFile); out32.flush(); + out32.close(); + FILE *logFile = fopen((name + ".out32").c_str(), "r"); fseek(logFile, 0, SEEK_END); uint32_t logSize = ftell(logFile); fseek(logFile, 0, SEEK_SET); char* log = new char[logSize]; fread(log, 1, logSize, logFile); + fclose(logFile); if(refSize > logSize || memcmp(log,ref,refSize)) fail(); From 52419fd7ada23f546e33e0c4ff88997dc7773480 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 7 Dec 2018 23:47:49 +0100 Subject: [PATCH 009/951] Regression remove dplus stuff #46 --- src/test/cpp/regression/makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/cpp/regression/makefile b/src/test/cpp/regression/makefile index a5d56438..2e481c40 100644 --- a/src/test/cpp/regression/makefile +++ b/src/test/cpp/regression/makefile @@ -46,11 +46,11 @@ else endif -ifneq ($(shell dplus -VV | grep timerInterrupt ../../../../VexRiscv.v -w),) +ifneq (grep timerInterrupt ../../../../VexRiscv.v -w),) ADDCFLAGS += -CFLAGS -DTIMER_INTERRUPT endif -ifneq ($(shell dplus -VV | grep externalInterrupt ../../../../VexRiscv.v -w),) +ifneq (grep externalInterrupt ../../../../VexRiscv.v -w),) ADDCFLAGS += -CFLAGS -DEXTERNAL_INTERRUPT endif From 9330945623f58dead70abca50223a9565297862f Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 7 Dec 2018 23:50:13 +0100 Subject: [PATCH 010/951] fix regression makefile --- src/test/cpp/regression/makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/cpp/regression/makefile b/src/test/cpp/regression/makefile index 2e481c40..ba249518 100644 --- a/src/test/cpp/regression/makefile +++ b/src/test/cpp/regression/makefile @@ -46,11 +46,11 @@ else endif -ifneq (grep timerInterrupt ../../../../VexRiscv.v -w),) +ifneq ($(shell grep timerInterrupt ../../../../VexRiscv.v -w),) ADDCFLAGS += -CFLAGS -DTIMER_INTERRUPT endif -ifneq (grep externalInterrupt ../../../../VexRiscv.v -w),) +ifneq ($(shell grep externalInterrupt ../../../../VexRiscv.v -w),) ADDCFLAGS += -CFLAGS -DEXTERNAL_INTERRUPT endif From f121ce1ed557a07e7383892bde6a663cb839a990 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sat, 8 Dec 2018 14:10:18 +0100 Subject: [PATCH 011/951] add sanity asserts in regression #46 --- src/test/cpp/regression/main.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 016555dc..2d5bd2af 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -686,6 +686,10 @@ public: ws->iBusAccessPatch(address,data,&error); } virtual bool dRead(int32_t address, int32_t size, uint32_t *data){ + if(size < 1 || size > 4){ + cout << "dRead size=" << size << endl; + fail(); + } if(address & (size-1) != 0) cout << "Ref did a unaligned read" << endl; if((address & 0xF0000000) == 0xF0000000){ MemRead t = periphRead.front(); From cf80c63c22b2454452b4aabb0ac131f32656398b Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sat, 8 Dec 2018 15:16:17 +0100 Subject: [PATCH 012/951] fix travis --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 87447ea9..ee009743 100644 --- a/.travis.yml +++ b/.travis.yml @@ -45,7 +45,7 @@ before_install: - sudo make install - cd .. - - git clone https://github.com/SpinalHDL/SpinalHDL.git + - git clone https://github.com/SpinalHDL/SpinalHDL.git -b dev - cd VexRiscv #- curl -T README.md -udolu1990:$BINTRAY_KEY https://api.bintray.com/content/spinalhdl/VexRiscv/test/0.0.4/README.md From 1fbb81a4d91739f585e16b294ae4c888abf229d9 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sun, 9 Dec 2018 15:40:02 +0100 Subject: [PATCH 013/951] regression fix delete [] #46 --- src/test/cpp/regression/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 2d5bd2af..92a0a0c7 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -35,7 +35,7 @@ public: for(uint32_t i = 0;i < (1 << 12);i++) mem[i] = NULL; } ~Memory(){ - for(uint32_t i = 0;i < (1 << 12);i++) if(mem[i]) delete mem[i]; + for(uint32_t i = 0;i < (1 << 12);i++) if(mem[i]) delete [] mem[i]; } uint8_t* get(uint32_t address){ @@ -147,7 +147,7 @@ void loadHexImpl(string path,Memory* mem) { size--; } - delete content; + delete [] content; } From 281d61bbe18eef621d2b44fe985eb565f0b3152e Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sun, 9 Dec 2018 16:37:16 +0100 Subject: [PATCH 014/951] regression fix hex << dec #46 --- src/test/cpp/regression/main.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 92a0a0c7..3dcc6027 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -1064,13 +1064,13 @@ public: #ifdef TRACE_WITH_TIME currentTime << #endif - " PC " << hex << setw(8) << top->VexRiscv->writeBack_PC << " : reg[" << dec << setw(2) << (uint32_t)top->VexRiscv->writeBack_RegFilePlugin_regFileWrite_payload_address << "] = " << hex << setw(8) << top->VexRiscv->writeBack_RegFilePlugin_regFileWrite_payload_data << endl; + " PC " << hex << setw(8) << top->VexRiscv->writeBack_PC << " : reg[" << dec << setw(2) << (uint32_t)top->VexRiscv->writeBack_RegFilePlugin_regFileWrite_payload_address << "] = " << hex << setw(8) << top->VexRiscv->writeBack_RegFilePlugin_regFileWrite_payload_data << dec << endl; } else { regTraces << #ifdef TRACE_WITH_TIME currentTime << #endif - " PC " << hex << setw(8) << top->VexRiscv->writeBack_PC << endl; + " PC " << hex << setw(8) << top->VexRiscv->writeBack_PC << dec << endl; } if(riscvRefEnable) if(rfWriteValid != riscvRef.rfWriteValid || (rfWriteValid && (rfWriteAddress!= riscvRef.rfWriteAddress || rfWriteData!= riscvRef.rfWriteData))){ @@ -1118,7 +1118,7 @@ public: staticMutex.unlock(); } catch (const std::exception& e) { staticMutex.lock(); - cout << "FAIL " << name << " at PC=" << hex << setw(8) << top->VexRiscv->writeBack_PC << endl; //<< " seed : " << seed << + cout << "FAIL " << name << " at PC=" << hex << setw(8) << top->VexRiscv->writeBack_PC << dec << endl; //<< " seed : " << seed << cycles += instanceCycles; staticMutex.unlock(); failed = true; @@ -2147,7 +2147,7 @@ public: virtual void dBusAccess(uint32_t addr,bool wr, uint32_t size,uint32_t mask, uint32_t *data, bool *error) { Workspace::dBusAccess(addr,wr,size,mask,data,error); if(wr && addr == 0xF00FFF2C){ - out32 << hex << setw(8) << std::setfill('0') << *data; + out32 << hex << setw(8) << std::setfill('0') << *data << dec; if(++out32Counter % 4 == 0) out32 << "\n"; *error = 0; } From d9029c2efcc5a9a2c79a186fa1a017be5bb0356b Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 10 Dec 2018 01:44:47 +0100 Subject: [PATCH 015/951] Fix #46 by filling missing return statements --- src/test/cpp/regression/main.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 3dcc6027..84d1f2bb 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -323,7 +323,7 @@ public: case MCAUSE: return &mcause.raw; break; case MBADADDR: return &mbadaddr; break; case MEPC: return &mepc; break; - default: fail(); break; + default: fail(); return NULL; break; } } @@ -684,7 +684,9 @@ public: mem.read(address, 4, (uint8_t*)data); bool error; ws->iBusAccessPatch(address,data,&error); + return error; } + virtual bool dRead(int32_t address, int32_t size, uint32_t *data){ if(size < 1 || size > 4){ cout << "dRead size=" << size << endl; @@ -701,6 +703,7 @@ public: }else { mem.read(address, size, (uint8_t*)data); } + return false; } virtual void dWrite(int32_t address, int32_t size, uint32_t data){ if(address & (size-1) != 0) cout << "Ref did a unaligned write" << endl; From 76ebfb2243f11f473a943be26ad429ffc2276bb8 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 10 Dec 2018 13:15:03 +0100 Subject: [PATCH 016/951] Fix machine mode to supervisor delegation --- .../scala/vexriscv/plugin/CsrPlugin.scala | 62 +++++++++++++------ 1 file changed, 42 insertions(+), 20 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 6ad56a61..fb383e5f 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -501,34 +501,34 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception } case class InterruptSource(cond : Bool, id : Int) - case class InterruptModel(privilege : Int, privilegeCond : Bool, sources : ArrayBuffer[InterruptSource]) - val interruptModel = ArrayBuffer[InterruptModel]() - if(supervisorGen) interruptModel += InterruptModel(1, sstatus.SIE && privilege <= "01", ArrayBuffer( + case class InterruptPrivilege(privilege : Int, privilegeCond : Bool, sources : ArrayBuffer[InterruptSource]) + val interruptModel = ArrayBuffer[InterruptPrivilege]() + if(supervisorGen) interruptModel += InterruptPrivilege(1, sstatus.SIE && privilege <= "01", ArrayBuffer( InterruptSource(sip.STIP && sie.STIE, 5), InterruptSource(sip.SSIP && sie.SSIE, 1), InterruptSource(sip.SEIP && sie.SEIE, 9) )) - interruptModel += InterruptModel(3, mstatus.MIE , ArrayBuffer( + interruptModel += InterruptPrivilege(3, mstatus.MIE , ArrayBuffer( InterruptSource(mip.MTIP && mie.MTIE, 7), InterruptSource(mip.MSIP && mie.MSIE, 3), InterruptSource(mip.MEIP && mie.MEIE, 11) )) case class DelegatorModel(value : Bits, source : Int, target : Int) - def solveDelegators(delegators : Seq[DelegatorModel], id : Int, lowerBound : Int): UInt = { - val filtredDelegators = delegators.filter(_.target >= lowerBound) - val ret = U(lowerBound, 2 bits) - for(d <- filtredDelegators){ - when(!d.value(id)){ - ret := d.source - } - } - ret - } +// def solveDelegators(delegators : Seq[DelegatorModel], id : Int, lowerBound : Int): UInt = { +// val filtredDelegators = delegators.filter(_.target >= lowerBound) +// val ret = U(lowerBound, 2 bits) +// for(d <- filtredDelegators){ +// when(!d.value(id)){ +// ret := d.source +// } +// } +// ret +// } def solveDelegators(delegators : Seq[DelegatorModel], id : UInt, lowerBound : UInt): UInt = { - if(delegators.isEmpty) return CombInit(lowerBound) + if(delegators.isEmpty) return U"11" val ret = U(delegators.last.target, 2 bits) for(d <- delegators){ when(!d.value(id) || d.target < lowerBound){ @@ -536,6 +536,15 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception } } ret +// val ret = U"11" +// var continue = True +// for(d <- delegators){ +// continue = continue && d.value(id) +// when(continue){ +// ret := d.source +// } +// } +// ret.max(lowerBound) } val interruptDelegators = ArrayBuffer[DelegatorModel]() @@ -601,7 +610,6 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception when(exceptionValidsRegs.orR){ fetcher.haltIt() -// fetcher.flushIt() } } else null @@ -609,11 +617,10 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception + //Process interrupt request, code and privilege val interrupt = False val interruptCode = UInt(4 bits).assignDontCare().addTag(Verilator.public) - val interruptTargetPrivilege = UInt(2 bits).assignDontCare() - - + val interruptDelegatorHit = interruptDelegators.map(d => (d -> False)).toMap for(model <- interruptModel){ when(model.privilegeCond){ when(model.sources.map(_.cond).orR){ @@ -622,11 +629,25 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception for(source <- model.sources){ when(source.cond){ interruptCode := source.id - interruptTargetPrivilege := solveDelegators(interruptDelegators, source.id, model.privilege) + for(interruptDelegator <- interruptDelegators){ + interruptDelegatorHit(interruptDelegator) := (if(interruptDelegator.target < model.privilege){ + False + } else { + interruptDelegator.value(source.id) + }) + } } } } } + + val interruptTargetPrivilege = U(if(interruptDelegators.isEmpty) 3 else interruptDelegators.last.target, 2 bits) + for(interruptDelegator <- interruptDelegators){ + when(!interruptDelegatorHit(interruptDelegator)){ + interruptTargetPrivilege := interruptDelegator.source + } + } + interrupt.clearWhen(!allowInterrupts) val exception = if(exceptionPortCtrl != null) exceptionPortCtrl.exceptionValids.last && allowException else False @@ -678,6 +699,7 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception jumpInterface.payload := (if(!mtvecModeGen) mtvec.base @@ "00" else (mtvec.mode === 0 || hadException) ? (mtvec.base @@ "00") | ((mtvec.base + trapCause) @@ "00") ) beforeLastStage.arbitration.flushAll := True + privilege := targetPrivilege switch(targetPrivilege){ if(supervisorGen) is(1) { sstatus.SIE := False From 961abb3cf10bab123e62445d7c0ab5d13470eff7 Mon Sep 17 00:00:00 2001 From: Brett Foster Date: Sat, 22 Dec 2018 07:58:59 -0800 Subject: [PATCH 017/951] Avalon: Debug Clock Domain for JTAG This change ensures that the clock domain for the JTAG interface uses the debug plugin's domain. Otherwise, resetting the processor will put the jtag debugger in to reset as well. See SpinalHDL/VexRiscv#48 --- .../scala/vexriscv/demo/VexRiscvAvalonWithIntegratedJtag.scala | 2 +- .../scala/vexriscv/demo/VexRiscvAxi4WithIntegratedJtag.scala | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/demo/VexRiscvAvalonWithIntegratedJtag.scala b/src/main/scala/vexriscv/demo/VexRiscvAvalonWithIntegratedJtag.scala index e4793d2d..8908cad8 100644 --- a/src/main/scala/vexriscv/demo/VexRiscvAvalonWithIntegratedJtag.scala +++ b/src/main/scala/vexriscv/demo/VexRiscvAvalonWithIntegratedJtag.scala @@ -162,7 +162,7 @@ object VexRiscvAvalonWithIntegratedJtag{ .setName("dBusAvalon") .addTag(ClockDomainTag(ClockDomain.current)) } - case plugin: DebugPlugin => { + case plugin: DebugPlugin => plugin.debugClockDomain { plugin.io.bus.setAsDirectionLess() val jtag = slave(new Jtag()) .setName("jtag") diff --git a/src/main/scala/vexriscv/demo/VexRiscvAxi4WithIntegratedJtag.scala b/src/main/scala/vexriscv/demo/VexRiscvAxi4WithIntegratedJtag.scala index 9f339fb4..89476360 100644 --- a/src/main/scala/vexriscv/demo/VexRiscvAxi4WithIntegratedJtag.scala +++ b/src/main/scala/vexriscv/demo/VexRiscvAxi4WithIntegratedJtag.scala @@ -163,7 +163,7 @@ object VexRiscvAxi4WithIntegratedJtag{ .setName("dBusAxi") .addTag(ClockDomainTag(ClockDomain.current)) } - case plugin: DebugPlugin => { + case plugin: DebugPlugin => plugin.debugClockDomain { plugin.io.bus.setAsDirectionLess() val jtag = slave(new Jtag()) .setName("jtag") From d617bafb081daf9837d1479f635d0bc9d381ef1f Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 25 Dec 2018 00:15:23 +0100 Subject: [PATCH 018/951] Roll back VexRiscvAvalonForSim to use caches --- .../vexriscv/demo/VexRiscvAvalonForSim.scala | 79 ++++++++++--------- 1 file changed, 40 insertions(+), 39 deletions(-) diff --git a/src/main/scala/vexriscv/demo/VexRiscvAvalonForSim.scala b/src/main/scala/vexriscv/demo/VexRiscvAvalonForSim.scala index 1e926ee5..cbb76aed 100644 --- a/src/main/scala/vexriscv/demo/VexRiscvAvalonForSim.scala +++ b/src/main/scala/vexriscv/demo/VexRiscvAvalonForSim.scala @@ -26,7 +26,7 @@ object VexRiscvAvalonForSim{ //CPU configuration val cpuConfig = VexRiscvConfig( plugins = List( - new IBusSimplePlugin( + /* new IBusSimplePlugin( resetVector = 0x00000000l, cmdForkOnSecondStage = false, cmdForkPersistence = false, @@ -37,44 +37,44 @@ object VexRiscvAvalonForSim{ new DBusSimplePlugin( catchAddressMisaligned = false, catchAccessFault = false + ),*/ + new IBusCachedPlugin( + config = InstructionCacheConfig( + cacheSize = 4096, + bytePerLine =32, + wayCount = 1, + addressWidth = 32, + cpuDataWidth = 32, + memDataWidth = 32, + catchIllegalAccess = true, + catchAccessFault = true, + catchMemoryTranslationMiss = true, + asyncTagMemory = false, + twoCycleRam = true + ) + // askMemoryTranslation = true, + // memoryTranslatorPortConfig = MemoryTranslatorPortConfig( + // portTlbSize = 4 + // ) + ), + new DBusCachedPlugin( + config = new DataCacheConfig( + cacheSize = 4096, + bytePerLine = 32, + wayCount = 1, + addressWidth = 32, + cpuDataWidth = 32, + memDataWidth = 32, + catchAccessError = true, + catchIllegal = true, + catchUnaligned = true, + catchMemoryTranslationMiss = true + ), + memoryTranslatorPortConfig = null + // memoryTranslatorPortConfig = MemoryTranslatorPortConfig( + // portTlbSize = 6 + // ) ), -// new IBusCachedPlugin( -// config = InstructionCacheConfig( -// cacheSize = 4096, -// bytePerLine =32, -// wayCount = 1, -// addressWidth = 32, -// cpuDataWidth = 32, -// memDataWidth = 32, -// catchIllegalAccess = true, -// catchAccessFault = true, -// catchMemoryTranslationMiss = true, -// asyncTagMemory = false, -// twoCycleRam = true -// ) -// // askMemoryTranslation = true, -// // memoryTranslatorPortConfig = MemoryTranslatorPortConfig( -// // portTlbSize = 4 -// // ) -// ), -// new DBusCachedPlugin( -// config = new DataCacheConfig( -// cacheSize = 4096, -// bytePerLine = 32, -// wayCount = 1, -// addressWidth = 32, -// cpuDataWidth = 32, -// memDataWidth = 32, -// catchAccessError = true, -// catchIllegal = true, -// catchUnaligned = true, -// catchMemoryTranslationMiss = true -// ), -// memoryTranslatorPortConfig = null -// // memoryTranslatorPortConfig = MemoryTranslatorPortConfig( -// // portTlbSize = 6 -// // ) -// ), new StaticMemoryTranslatorPlugin( ioRange = _(31 downto 28) === 0xF ), @@ -165,7 +165,7 @@ object VexRiscvAvalonForSim{ .setName("dBusAvalon") .addTag(ClockDomainTag(ClockDomain.current)) } - case plugin: DebugPlugin => { + case plugin: DebugPlugin => plugin.debugClockDomain { plugin.io.bus.setAsDirectionLess() slave(plugin.io.bus.fromAvalon()) .setName("debugBusAvalon") @@ -194,3 +194,4 @@ object VexRiscvAvalonForSim{ QSysify(report.toplevel) } } + From 92065a1a10af5f910f55a01b280b2aef2a9d2460 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sun, 30 Dec 2018 15:51:46 +0100 Subject: [PATCH 019/951] Update to SpinalHDL 1.3.0 --- build.sbt | 16 +++++++--------- project/build.properties | 2 +- project/plugins.sbt | 2 +- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/build.sbt b/build.sbt index 21851324..3075bbab 100644 --- a/build.sbt +++ b/build.sbt @@ -25,22 +25,20 @@ lazy val root = (project in file(".")). settings( inThisBuild(List( organization := "com.github.spinalhdl", - scalaVersion := "2.11.6", + scalaVersion := "2.11.12", version := "1.0.0" )), libraryDependencies ++= Seq( -// "com.github.spinalhdl" % "spinalhdl-core_2.11" % "1.2.2", -// "com.github.spinalhdl" % "spinalhdl-lib_2.11" % "1.2.2", + "com.github.spinalhdl" % "spinalhdl-core_2.11" % "1.3.0", + "com.github.spinalhdl" % "spinalhdl-lib_2.11" % "1.3.0", "org.scalatest" % "scalatest_2.11" % "2.2.1", "org.yaml" % "snakeyaml" % "1.8" ), name := "VexRiscv" - ).dependsOn(spinalHdlSim,spinalHdlCore,spinalHdlLib) -lazy val spinalHdlSim = ProjectRef(file("../SpinalHDL"), "SpinalHDL-sim") -lazy val spinalHdlCore = ProjectRef(file("../SpinalHDL"), "SpinalHDL-core") -lazy val spinalHdlLib = ProjectRef(file("../SpinalHDL"), "SpinalHDL-lib") + )//.dependsOn(spinalHdlSim,spinalHdlCore,spinalHdlLib) +//lazy val spinalHdlSim = ProjectRef(file("../SpinalHDL"), "SpinalHDL-sim") +//lazy val spinalHdlCore = ProjectRef(file("../SpinalHDL"), "SpinalHDL-core") +//lazy val spinalHdlLib = ProjectRef(file("../SpinalHDL"), "SpinalHDL-lib") -addCompilerPlugin("org.scala-lang.plugins" % "scala-continuations-plugin_2.11.6" % "1.0.2") -scalacOptions += "-P:continuations:enable" fork := true \ No newline at end of file diff --git a/project/build.properties b/project/build.properties index c091b86c..72f90289 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=0.13.16 +sbt.version=1.2.7 diff --git a/project/plugins.sbt b/project/plugins.sbt index 9190bbb9..e5c42332 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,2 +1,2 @@ -addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "5.2.1") +addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "5.2.4") From dcdfa79024f5c6b88c04eadfd3140dc3733a33a1 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 3 Jan 2019 20:07:38 +0100 Subject: [PATCH 020/951] fix run-main into runMain --- README.md | 14 +++++++------- scripts/Murax/iCE40-hx8k_breakout_board/Makefile | 4 ++-- .../Murax/iCE40-hx8k_breakout_board_xip/Makefile | 4 ++-- scripts/Murax/iCE40HX8K-EVB/Makefile | 4 ++-- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 430d1625..ef6df531 100644 --- a/README.md +++ b/README.md @@ -162,13 +162,13 @@ You can find two example CPU instances in: To generate the corresponding RTL as a VexRiscv.v file, run the following commands in the root directory of this repository: ```sh -sbt "run-main vexriscv.demo.GenFull" +sbt "runMain vexriscv.demo.GenFull" ``` or ```sh -sbt "run-main vexriscv.demo.GenSmallest" +sbt "runMain vexriscv.demo.GenSmallest" ``` NOTES: @@ -204,7 +204,7 @@ Then you can use the https://github.com/SpinalHDL/openocd_riscv tool to create a ```sh #in the VexRiscv repository, to run the simulation on which one OpenOCD can connect itself => -sbt "run-main vexriscv.demo.GenFull" +sbt "runMain vexriscv.demo.GenFull" cd src/test/cpp/regression make run DEBUG_PLUGIN_EXTERNAL=yes @@ -254,7 +254,7 @@ the [Pinsec SOC](https://spinalhdl.github.io/SpinalDoc/spinal/lib/pinsec/hardwar To generate the Briey SoC Hardware: ```sh -sbt "run-main vexriscv.demo.Briey" +sbt "runMain vexriscv.demo.Briey" ``` To run the verilator simulation of the Briey SoC which can then be connected to OpenOCD/GDB, first get those dependencies: @@ -309,10 +309,10 @@ To generate the Murax SoC Hardware : ```sh # To generate the SoC without any content in the ram -sbt "run-main vexriscv.demo.Murax" +sbt "runMain vexriscv.demo.Murax" # To generate the SoC with a demo program already in ram -sbt "run-main vexriscv.demo.MuraxWithRamInit" +sbt "runMain vexriscv.demo.MuraxWithRamInit" ``` The demo program included by default with `MuraxWithRamInit` will blink the @@ -560,7 +560,7 @@ and is self-tested by the `src/test/cpp/custom/simd_add` application by running ```sh # Generate the CPU -sbt "run-main vexriscv.demo.GenCustomSimdAdd" +sbt "runMain vexriscv.demo.GenCustomSimdAdd" cd src/test/cpp/regression/ diff --git a/scripts/Murax/iCE40-hx8k_breakout_board/Makefile b/scripts/Murax/iCE40-hx8k_breakout_board/Makefile index 078af3b3..46896749 100644 --- a/scripts/Murax/iCE40-hx8k_breakout_board/Makefile +++ b/scripts/Murax/iCE40-hx8k_breakout_board/Makefile @@ -3,10 +3,10 @@ VERILOG = ../../../Murax.v toplevel.v generate : - (cd ../../..; sbt "run-main vexriscv.demo.MuraxWithRamInit") + (cd ../../..; sbt "runMain vexriscv.demo.MuraxWithRamInit") ../../../Murax.v : - (cd ../../..; sbt "run-main vexriscv.demo.MuraxWithRamInit") + (cd ../../..; sbt "runMain vexriscv.demo.MuraxWithRamInit") ../../../Murax.v*.bin: diff --git a/scripts/Murax/iCE40-hx8k_breakout_board_xip/Makefile b/scripts/Murax/iCE40-hx8k_breakout_board_xip/Makefile index ca74503a..88aa1a2f 100644 --- a/scripts/Murax/iCE40-hx8k_breakout_board_xip/Makefile +++ b/scripts/Murax/iCE40-hx8k_breakout_board_xip/Makefile @@ -3,10 +3,10 @@ VERILOG = ../../../Murax_iCE40_hx8k_breakout_board_xip.v generate : - #(cd ../../..; sbt "run-main vexriscv.demo.Murax_iCE40_hx8k_breakout_board_xip") + #(cd ../../..; sbt "runMain vexriscv.demo.Murax_iCE40_hx8k_breakout_board_xip") ../../../Murax_iCE40_hx8k_breakout_board_xip.v : - #(cd ../../..; sbt "run-main vexriscv.demo.Murax_iCE40_hx8k_breakout_board_xip") + #(cd ../../..; sbt "runMain vexriscv.demo.Murax_iCE40_hx8k_breakout_board_xip") ../../../Murax_iCE40_hx8k_breakout_board_xip.v*.bin: diff --git a/scripts/Murax/iCE40HX8K-EVB/Makefile b/scripts/Murax/iCE40HX8K-EVB/Makefile index e69f58cd..e90ed02e 100644 --- a/scripts/Murax/iCE40HX8K-EVB/Makefile +++ b/scripts/Murax/iCE40HX8K-EVB/Makefile @@ -3,10 +3,10 @@ VERILOG = ../../../Murax.v toplevel.v toplevel_pll.v generate : - (cd ../../..; sbt "run-main vexriscv.demo.MuraxWithRamInit") + (cd ../../..; sbt "runMain vexriscv.demo.MuraxWithRamInit") ../../../Murax.v : - (cd ../../..; sbt "run-main vexriscv.demo.MuraxWithRamInit") + (cd ../../..; sbt "runMain vexriscv.demo.MuraxWithRamInit") ../../../Murax.v*.bin: From f4f854ae4f8a953baaa04b981fd39b322dff5edb Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 14 Jan 2019 13:32:16 +0100 Subject: [PATCH 021/951] SpinalHDL 1.3.1 --- build.sbt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.sbt b/build.sbt index 3075bbab..3c2aae66 100644 --- a/build.sbt +++ b/build.sbt @@ -29,8 +29,8 @@ lazy val root = (project in file(".")). version := "1.0.0" )), libraryDependencies ++= Seq( - "com.github.spinalhdl" % "spinalhdl-core_2.11" % "1.3.0", - "com.github.spinalhdl" % "spinalhdl-lib_2.11" % "1.3.0", + "com.github.spinalhdl" % "spinalhdl-core_2.11" % "1.3.1", + "com.github.spinalhdl" % "spinalhdl-lib_2.11" % "1.3.1", "org.scalatest" % "scalatest_2.11" % "2.2.1", "org.yaml" % "snakeyaml" % "1.8" ), From b5caca54cd97e968f8b6c7494aa8aed7388a23c6 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 16 Jan 2019 15:25:50 +0100 Subject: [PATCH 022/951] restore all feature in TestsWorkspace --- src/main/scala/vexriscv/TestsWorkspace.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/TestsWorkspace.scala b/src/main/scala/vexriscv/TestsWorkspace.scala index 93d494f4..34d047d4 100644 --- a/src/main/scala/vexriscv/TestsWorkspace.scala +++ b/src/main/scala/vexriscv/TestsWorkspace.scala @@ -153,7 +153,7 @@ object TestsWorkspace { // wfiGenAsNop = true, // ucycleAccess = CsrAccess.NONE // )), -// new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))), + new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))), new BranchPlugin( earlyBranch = true, catchAddressMisaligned = true, From f4598fbd0a1df290d948e910e5a16910479ff67a Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 21 Jan 2019 23:46:18 +0100 Subject: [PATCH 023/951] Add tightly coupled interface to the i$ --- src/main/scala/vexriscv/Pipeline.scala | 7 + src/main/scala/vexriscv/Services.scala | 4 + src/main/scala/vexriscv/TestsWorkspace.scala | 121 +++++++----- .../scala/vexriscv/ip/InstructionCache.scala | 33 ++-- .../vexriscv/plugin/IBusCachedPlugin.scala | 187 +++++++++++------- src/test/cpp/regression/main.cpp | 48 +++++ src/test/cpp/regression/makefile | 8 +- .../vexriscv/TestIndividualFeatures.scala | 54 ++--- 8 files changed, 301 insertions(+), 161 deletions(-) diff --git a/src/main/scala/vexriscv/Pipeline.scala b/src/main/scala/vexriscv/Pipeline.scala index f0466c52..898094ee 100644 --- a/src/main/scala/vexriscv/Pipeline.scala +++ b/src/main/scala/vexriscv/Pipeline.scala @@ -30,6 +30,13 @@ trait Pipeline { filtered.length != 0 } + def serviceElse[T](clazz : Class[T], default : => T) : T = { + if(!serviceExist(clazz)) return default + val filtered = plugins.filter(o => clazz.isAssignableFrom(o.getClass)) + assert(filtered.length == 1) + filtered.head.asInstanceOf[T] + } + def update[T](that : PipelineConfig[T], value : T) : Unit = configs(that) = value def apply[T](that : PipelineConfig[T]) : T = configs(that).asInstanceOf[T] diff --git a/src/main/scala/vexriscv/Services.scala b/src/main/scala/vexriscv/Services.scala index 33adf070..6f7d641d 100644 --- a/src/main/scala/vexriscv/Services.scala +++ b/src/main/scala/vexriscv/Services.scala @@ -39,6 +39,10 @@ trait PrivilegeService{ def isUser(stage : Stage) : Bool } +case class PrivilegeServiceDefault() extends PrivilegeService{ + override def isUser(stage: Stage): Bool = False +} + trait InterruptionInhibitor{ def inhibateInterrupts() : Unit } diff --git a/src/main/scala/vexriscv/TestsWorkspace.scala b/src/main/scala/vexriscv/TestsWorkspace.scala index 34d047d4..75e59345 100644 --- a/src/main/scala/vexriscv/TestsWorkspace.scala +++ b/src/main/scala/vexriscv/TestsWorkspace.scala @@ -28,20 +28,20 @@ import spinal.lib.eda.altera.{InterruptReceiverTag, ResetEmitterTag} object TestsWorkspace { def main(args: Array[String]) { - SpinalConfig(mergeAsyncProcess = false, anonymSignalPrefix = "zz_").generateVerilog { - val configFull = VexRiscvConfig( + def configFull = { + val config = VexRiscvConfig( plugins = List( -// new IBusSimplePlugin( -// resetVector = 0x80000000l, -// cmdForkOnSecondStage = false, -// cmdForkPersistence = false, -// prediction = NONE, -// historyRamSizeLog2 = 10, -// catchAccessFault = false, -// compressedGen = false, -// busLatencyMin = 1, -// injectorStage = true -// ), + // new IBusSimplePlugin( + // resetVector = 0x80000000l, + // cmdForkOnSecondStage = false, + // cmdForkPersistence = false, + // prediction = NONE, + // historyRamSizeLog2 = 10, + // catchAccessFault = false, + // compressedGen = false, + // busLatencyMin = 1, + // injectorStage = true + // ), new IBusCachedPlugin( resetVector = 0x80000000l, compressedGen = false, @@ -65,11 +65,12 @@ object TestsWorkspace { portTlbSize = 4 ) ), -// new DBusSimplePlugin( -// catchAddressMisaligned = true, -// catchAccessFault = false, -// earlyInjection = false -// ), +// ).newTightlyCoupledPort(TightlyCoupledPortParameter("iBusTc", a => a(30 downto 28) === 0x0 && a(5))), + // new DBusSimplePlugin( + // catchAddressMisaligned = true, + // catchAccessFault = false, + // earlyInjection = false + // ), new DBusCachedPlugin( config = new DataCacheConfig( cacheSize = 4096, @@ -84,21 +85,21 @@ object TestsWorkspace { catchMemoryTranslationMiss = true, atomicEntriesCount = 2 ), -// memoryTranslatorPortConfig = null + // memoryTranslatorPortConfig = null memoryTranslatorPortConfig = MemoryTranslatorPortConfig( portTlbSize = 6 ) ), -// new StaticMemoryTranslatorPlugin( -// ioRange = _(31 downto 28) === 0xF -// ), + // new StaticMemoryTranslatorPlugin( + // ioRange = _(31 downto 28) === 0xF + // ), new MemoryTranslatorPlugin( tlbSize = 32, virtualRange = _(31 downto 28) === 0xC, ioRange = _(31 downto 28) === 0xF ), new DecoderSimplePlugin( - catchIllegalInstruction = false + catchIllegalInstruction = true ), new RegFilePlugin( regFileReadyKind = plugin.ASYNC, @@ -109,7 +110,7 @@ object TestsWorkspace { separatedAddSub = false ), new FullBarrelShifterPlugin(earlyInjection = true), - // new LightShifterPlugin, + // new LightShifterPlugin, new HazardSimplePlugin( bypassExecute = true, bypassMemory = true, @@ -119,8 +120,8 @@ object TestsWorkspace { pessimisticWriteRegFile = false, pessimisticAddressMatch = false ), - // new HazardSimplePlugin(false, true, false, true), - // new HazardSimplePlugin(false, false, false, false), + // new HazardSimplePlugin(false, true, false, true), + // new HazardSimplePlugin(false, false, false, false), new MulPlugin, new MulDivIterativePlugin( genMul = false, @@ -128,31 +129,31 @@ object TestsWorkspace { mulUnrollFactor = 32, divUnrollFactor = 1 ), -// new DivPlugin, + // new DivPlugin, new CsrPlugin(CsrPluginConfig.all(0x80000020l)), -// new CsrPlugin(//CsrPluginConfig.all2(0x80000020l).copy(ebreakGen = true)/* -// CsrPluginConfig( -// catchIllegalAccess = false, -// mvendorid = null, -// marchid = null, -// mimpid = null, -// mhartid = null, -// misaExtensionsInit = 0, -// misaAccess = CsrAccess.READ_ONLY, -// mtvecAccess = CsrAccess.WRITE_ONLY, -// mtvecInit = 0x80000020l, -// mepcAccess = CsrAccess.READ_WRITE, -// mscratchGen = true, -// mcauseAccess = CsrAccess.READ_ONLY, -// mbadaddrAccess = CsrAccess.READ_ONLY, -// mcycleAccess = CsrAccess.NONE, -// minstretAccess = CsrAccess.NONE, -// ecallGen = true, -// ebreakGen = true, -// wfiGenAsWait = false, -// wfiGenAsNop = true, -// ucycleAccess = CsrAccess.NONE -// )), + // new CsrPlugin(//CsrPluginConfig.all2(0x80000020l).copy(ebreakGen = true)/* + // CsrPluginConfig( + // catchIllegalAccess = false, + // mvendorid = null, + // marchid = null, + // mimpid = null, + // mhartid = null, + // misaExtensionsInit = 0, + // misaAccess = CsrAccess.READ_ONLY, + // mtvecAccess = CsrAccess.WRITE_ONLY, + // mtvecInit = 0x80000020l, + // mepcAccess = CsrAccess.READ_WRITE, + // mscratchGen = true, + // mcauseAccess = CsrAccess.READ_ONLY, + // mbadaddrAccess = CsrAccess.READ_ONLY, + // mcycleAccess = CsrAccess.NONE, + // minstretAccess = CsrAccess.NONE, + // ecallGen = true, + // ebreakGen = true, + // wfiGenAsWait = false, + // wfiGenAsNop = true, + // ucycleAccess = CsrAccess.NONE + // )), new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))), new BranchPlugin( earlyBranch = true, @@ -162,8 +163,28 @@ object TestsWorkspace { new YamlPlugin("cpu0.yaml") ) ) + config + } +// import spinal.core.sim._ +// SimConfig.withConfig(SpinalConfig(mergeAsyncProcess = false, anonymSignalPrefix = "zz_")).allOptimisation.compile(new VexRiscv(configFull)).doSimUntilVoid{ dut => +// dut.clockDomain.forkStimulus(10) +// dut.clockDomain.forkSimSpeedPrinter(4) +// var iBus : InstructionCacheMemBus = null +// +// dut.plugins.foreach{ +// case plugin: IBusCachedPlugin => iBus = plugin.iBus +// case _ => +// } +// dut.clockDomain.onSamplings{ +//// iBus.cmd.ready.randomize() +// iBus.rsp.data #= 0x13 +// } +// } + + SpinalConfig(mergeAsyncProcess = false, anonymSignalPrefix = "zz_").generateVerilog { + val toplevel = new VexRiscv(configFull) // val toplevel = new VexRiscv(configLight) diff --git a/src/main/scala/vexriscv/ip/InstructionCache.scala b/src/main/scala/vexriscv/ip/InstructionCache.scala index 40cb700e..26d1caa5 100644 --- a/src/main/scala/vexriscv/ip/InstructionCache.scala +++ b/src/main/scala/vexriscv/ip/InstructionCache.scala @@ -86,15 +86,17 @@ trait InstructionCacheCommons{ val pc : UInt val physicalAddress : UInt val data : Bits - val cacheMiss, error, mmuMiss, illegalAccess,isUser : Bool + val cacheMiss, error, mmuMiss, illegalAccess, isUser : Bool } case class InstructionCacheCpuFetch(p : InstructionCacheConfig) extends Bundle with IMasterSlave with InstructionCacheCommons { - val isValid = Bool - val isStuck = Bool - val isRemoved = Bool + val isValid = Bool() + val isStuck = Bool() + val isRemoved = Bool() val pc = UInt(p.addressWidth bits) - val data = Bits(p.cpuDataWidth bits) + val data = Bits(p.cpuDataWidth bits) + val dataBypassValid = Bool() + val dataBypass = Bits(p.cpuDataWidth bits) val mmuBus = MemoryTranslatorBus() val physicalAddress = UInt(p.addressWidth bits) val cacheMiss, error, mmuMiss, illegalAccess,isUser = ifGen(!p.twoCycleCache)(Bool) @@ -102,7 +104,7 @@ case class InstructionCacheCpuFetch(p : InstructionCacheConfig) extends Bundle w override def asMaster(): Unit = { out(isValid, isStuck, isRemoved, pc) inWithNull(error,mmuMiss,illegalAccess,data, cacheMiss,physicalAddress) - outWithNull(isUser) + outWithNull(isUser, dataBypass, dataBypassValid) slaveWithNull(mmuBus) } } @@ -381,21 +383,21 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{ } - val hit = if(!twoCycleRam) new Area{ + val hit = (!twoCycleRam) generate 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 + io.cpu.fetch.data := (io.cpu.fetch.dataBypassValid ? io.cpu.fetch.dataBypass | word) if(twoCycleCache){ io.cpu.decode.data := RegNextWhen(io.cpu.fetch.data,!io.cpu.decode.isStuck) } - } else null + } if(twoCycleRam && wayCount == 1){ - io.cpu.fetch.data := read.waysValues.head.data.subdivideIn(cpuDataWidth bits).read(io.cpu.fetch.pc(memWordToCpuWordRange)) + io.cpu.fetch.data := (io.cpu.fetch.dataBypassValid ? io.cpu.fetch.dataBypass | read.waysValues.head.data.subdivideIn(cpuDataWidth bits).read(io.cpu.fetch.pc(memWordToCpuWordRange))) } io.cpu.fetch.mmuBus.cmd.isValid := io.cpu.fetch.isValid @@ -405,7 +407,6 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{ io.cpu.fetch.physicalAddress := io.cpu.fetch.mmuBus.rsp.physicalAddress val resolution = ifGen(!twoCycleCache)( new Area{ -// def stage[T <: Data](that : T) = RegNextWhen(that,!io.cpu.decode.isStuck) val mmuRsp = io.cpu.fetch.mmuBus.rsp io.cpu.fetch.cacheMiss := !hit.valid @@ -432,17 +433,13 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{ val error = tags(id).error val data = fetchStage.read.waysValues.map(way => stage(way.data)).read(id) val word = data.subdivideIn(cpuDataWidth bits).read(io.cpu.decode.pc(memWordToCpuWordRange)) + when(stage(io.cpu.fetch.dataBypassValid)){ + word := stage(io.cpu.fetch.dataBypass) + } io.cpu.decode.data := word } io.cpu.decode.cacheMiss := !hit.valid -// when( io.cpu.decode.isValid && io.cpu.decode.cacheMiss){ -// io.cpu.prefetch.haltIt := True -// lineLoader.valid := True -// lineLoader.address := mmuRsp.physicalAddress //Could be optimise if mmu not used -// } -// when(io.cpu) - io.cpu.decode.error := hit.error io.cpu.decode.mmuMiss := mmuRsp.miss io.cpu.decode.illegalAccess := !mmuRsp.allowExecute || (io.cpu.decode.isUser && !mmuRsp.allowUser) diff --git a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala index 66348f4b..c34c32f2 100644 --- a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala @@ -5,10 +5,26 @@ import vexriscv.ip._ import spinal.core._ import spinal.lib._ +import scala.collection.mutable.ArrayBuffer + //class IBusCachedPlugin(config : InstructionCacheConfig, memoryTranslatorPortConfig : Any = null) extends Plugin[VexRiscv] { // var iBus : InstructionCacheMemBus = null // override def build(pipeline: VexRiscv): Unit = ??? //} + +case class TightlyCoupledBus() extends Bundle with IMasterSlave { + val enable = Bool() + val address = UInt(32 bits) + val data = Bits(32 bits) + + override def asMaster(): Unit = { + out(enable, address) + in(data) + } +} + +case class TightlyCoupledPortParameter(name : String, hit : UInt => Bool) +case class TightlyCoupledPort(p : TightlyCoupledPortParameter, var bus : TightlyCoupledBus) class IBusCachedPlugin(resetVector : BigInt = 0x80000000l, relaxedPcCalculation : Boolean = false, prediction : BranchPrediction = NONE, @@ -36,6 +52,15 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l, var privilegeService : PrivilegeService = null var redoBranch : Flow[UInt] = null var decodeExceptionPort : Flow[ExceptionCause] = null + val tightlyCoupledPorts = ArrayBuffer[TightlyCoupledPort]() + + + def newTightlyCoupledPort(p : TightlyCoupledPortParameter) = { + val port = TightlyCoupledPort(p, null) + tightlyCoupledPorts += port + this + } + object FLUSH_ALL extends Stageable(Bool) object IBUS_ACCESS_ERROR extends Stageable(Bool) @@ -66,8 +91,7 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l, if(pipeline.serviceExist(classOf[MemoryTranslator])) mmuBus = pipeline.service(classOf[MemoryTranslator]).newTranslationPort(MemoryTranslatorPort.PRIORITY_INSTRUCTION, memoryTranslatorPortConfig) - if(pipeline.serviceExist(classOf[PrivilegeService])) - privilegeService = pipeline.service(classOf[PrivilegeService]) + privilegeService = pipeline.serviceElse(classOf[PrivilegeService], PrivilegeServiceDefault()) if(pipeline.serviceExist(classOf[ReportService])){ val report = pipeline.service(classOf[ReportService]) @@ -98,21 +122,106 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l, val cache = new InstructionCache(IBusCachedPlugin.this.config) iBus = master(new InstructionCacheMemBus(IBusCachedPlugin.this.config)).setName("iBus") iBus <> cache.io.mem - iBus.cmd.address.allowOverride := cache.io.mem.cmd.address // - debugAddressOffset + iBus.cmd.address.allowOverride := cache.io.mem.cmd.address val stageOffset = if(relaxedPcCalculation) 1 else 0 def stages = iBusRsp.stages.drop(stageOffset) - //Connect prefetch cache side - cache.io.cpu.prefetch.isValid := stages(0).input.valid - cache.io.cpu.prefetch.pc := stages(0).input.payload - stages(0).halt setWhen(cache.io.cpu.prefetch.haltIt) + + tightlyCoupledPorts.foreach(p => p.bus = master(TightlyCoupledBus()).setName(p.p.name)) + + val s0 = new Area { + //address decoding + val tightlyCoupledHits = Vec(tightlyCoupledPorts.map(_.p.hit(stages(0).input.payload))) + val tightlyCoupledHit = tightlyCoupledHits.orR + + for((port, hit) <- (tightlyCoupledPorts, tightlyCoupledHits).zipped){ + port.bus.enable := stages(0).input.fire && hit + port.bus.address := stages(0).input.payload(31 downto 2) @@ U"00" + } + + //Connect prefetch cache side + cache.io.cpu.prefetch.isValid := stages(0).input.valid && !tightlyCoupledHit + cache.io.cpu.prefetch.pc := stages(0).input.payload + stages(0).halt setWhen (cache.io.cpu.prefetch.haltIt) - cache.io.cpu.fetch.isRemoved := flush - val iBusRspOutputHalt = False + cache.io.cpu.fetch.isRemoved := flush + } + + + val s1 = new Area { + val tightlyCoupledHits = RegNextWhen(s0.tightlyCoupledHits, stages(1).input.ready) + val tightlyCoupledHit = RegNextWhen(s0.tightlyCoupledHit, stages(1).input.ready) + + cache.io.cpu.fetch.dataBypassValid := tightlyCoupledHit + cache.io.cpu.fetch.dataBypass := (if(tightlyCoupledPorts.isEmpty) B(0) else MuxOH(tightlyCoupledHits, tightlyCoupledPorts.map(e => CombInit(e.bus.data)))) + + //Connect fetch cache side + cache.io.cpu.fetch.isValid := stages(1).input.valid && !tightlyCoupledHit + cache.io.cpu.fetch.isStuck := !stages(1).input.ready + cache.io.cpu.fetch.pc := stages(1).input.payload + + if (!twoCycleCache) { + cache.io.cpu.fetch.isUser := privilegeService.isUser(decode) + } + } + + val s2 = twoCycleCache generate new Area { + val tightlyCoupledHit = RegNextWhen(s1.tightlyCoupledHit, stages(2).input.ready) + cache.io.cpu.decode.isValid := stages(2).input.valid && !tightlyCoupledHit + cache.io.cpu.decode.isStuck := !stages(2).input.ready + cache.io.cpu.decode.pc := stages(2).input.payload + cache.io.cpu.decode.isUser := privilegeService.isUser(decode) + + if ((!twoCycleRam || wayCount == 1) && !compressedGen && !injectorStage) { + decode.insert(INSTRUCTION_ANTICIPATED) := Mux(decode.arbitration.isStuck, decode.input(INSTRUCTION), cache.io.cpu.fetch.data) + } + } + + val rsp = new Area { + val iBusRspOutputHalt = False + + val cacheRsp = if (twoCycleCache) cache.io.cpu.decode else cache.io.cpu.fetch + val cacheRspArbitration = stages(if (twoCycleCache) 2 else 1) + var issueDetected = False + val redoFetch = False //RegNext(False) init(False) + when(cacheRsp.isValid && cacheRsp.cacheMiss && !issueDetected) { + issueDetected \= True + redoFetch := iBusRsp.readyForError + } + + + //Refill / redo + assert(decodePcGen == compressedGen) + cache.io.cpu.fill.valid := redoFetch + cache.io.cpu.fill.payload := cacheRsp.physicalAddress + redoBranch.valid := redoFetch + redoBranch.payload := (if (decodePcGen) decode.input(PC) else cacheRsp.pc) + + if (catchSomething) { + val accessFault = if (catchAccessFault) cacheRsp.error else False + val mmuMiss = if (catchMemoryTranslationMiss) cacheRsp.mmuMiss else False + val illegalAccess = if (catchIllegalAccess) cacheRsp.illegalAccess else False + + decodeExceptionPort.valid := False + decodeExceptionPort.code := mmuMiss ? U(14) | 1 + decodeExceptionPort.badAddr := cacheRsp.pc + when(cacheRsp.isValid && (accessFault || mmuMiss || illegalAccess) && !issueDetected) { + issueDetected \= True + decodeExceptionPort.valid := iBusRsp.readyForError + } + } + + cacheRspArbitration.halt setWhen (issueDetected || iBusRspOutputHalt) + iBusRsp.output.valid := cacheRspArbitration.output.valid + cacheRspArbitration.output.ready := iBusRsp.output.ready + iBusRsp.output.rsp.inst := cacheRsp.data + iBusRsp.output.pc := cacheRspArbitration.output.payload + } + if (mmuBus != null) { cache.io.cpu.fetch.mmuBus <> mmuBus - (if(twoCycleCache) stages(1).halt else iBusRspOutputHalt) setWhen(mmuBus.cmd.isValid && !mmuBus.rsp.hit && !mmuBus.rsp.miss) + (if (twoCycleCache) stages(1).halt else rsp.iBusRspOutputHalt) setWhen (mmuBus.cmd.isValid && !mmuBus.rsp.hit && !mmuBus.rsp.miss) } else { cache.io.cpu.fetch.mmuBus.rsp.physicalAddress := cache.io.cpu.fetch.mmuBus.cmd.virtualAddress cache.io.cpu.fetch.mmuBus.rsp.allowExecute := True @@ -124,64 +233,6 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l, cache.io.cpu.fetch.mmuBus.rsp.hit := False } - //Connect fetch cache side - cache.io.cpu.fetch.isValid := stages(1).input.valid - cache.io.cpu.fetch.isStuck := !stages(1).input.ready - cache.io.cpu.fetch.pc := stages(1).input.payload - - - if(twoCycleCache){ - cache.io.cpu.decode.isValid := stages(2).input.valid - cache.io.cpu.decode.isStuck := !stages(2).input.ready - cache.io.cpu.decode.pc := stages(2).input.payload - cache.io.cpu.decode.isUser := (if (privilegeService != null) privilegeService.isUser(decode) else False) - - if((!twoCycleRam || wayCount == 1) && !compressedGen && !injectorStage){ - decode.insert(INSTRUCTION_ANTICIPATED) := Mux(decode.arbitration.isStuck, decode.input(INSTRUCTION), cache.io.cpu.fetch.data) - } - } else { - cache.io.cpu.fetch.isUser := (if (privilegeService != null) privilegeService.isUser(decode) else False) - } - - - -// val missHalt = cache.io.cpu.fetch.isValid && cache.io.cpu.fetch.cacheMiss - val cacheRsp = if(twoCycleCache) cache.io.cpu.decode else cache.io.cpu.fetch - val cacheRspArbitration = stages(if(twoCycleCache) 2 else 1) - var issueDetected = False - val redoFetch = False //RegNext(False) init(False) - when(cacheRsp.isValid && cacheRsp.cacheMiss && !issueDetected){ - issueDetected \= True - redoFetch := iBusRsp.readyForError - } - - - assert(decodePcGen == compressedGen) - cache.io.cpu.fill.valid := redoFetch - redoBranch.valid := redoFetch - redoBranch.payload := (if(decodePcGen) decode.input(PC) else cacheRsp.pc) - cache.io.cpu.fill.payload := cacheRsp.physicalAddress - - if(catchSomething){ - val accessFault = if (catchAccessFault) cacheRsp.error else False - val mmuMiss = if (catchMemoryTranslationMiss) cacheRsp.mmuMiss else False - val illegalAccess = if (catchIllegalAccess) cacheRsp.illegalAccess else False - - decodeExceptionPort.valid := False - decodeExceptionPort.code := mmuMiss ? U(14) | 1 - decodeExceptionPort.badAddr := cacheRsp.pc - when(cacheRsp.isValid && (accessFault || mmuMiss || illegalAccess) && !issueDetected){ - issueDetected \= True - decodeExceptionPort.valid := iBusRsp.readyForError - } - } - - cacheRspArbitration.halt setWhen(issueDetected || iBusRspOutputHalt) - iBusRsp.output.arbitrationFrom(cacheRspArbitration.output) - iBusRsp.output.rsp.inst := cacheRsp.data - iBusRsp.output.pc := cacheRspArbitration.output.payload - - val flushStage = if(memory != null) memory else execute flushStage plug new Area { import flushStage._ diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 84d1f2bb..a5c1b0d6 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -1192,6 +1192,43 @@ public: }; #endif + +#ifdef IBUS_TC + +class IBusTc : public SimElement{ +public: + + uint32_t nextData; + + Workspace *ws; + VVexRiscv* top; + IBusTc(Workspace* ws){ + this->ws = ws; + this->top = ws->top; + } + + virtual void onReset(){ + } + + virtual void preCycle(){ + if (top->iBusTc_enable) { + if((top->iBusTc_address & 0x70000000) != 0 || (top->iBusTc_address & 0x20) == 0){ + printf("IBusTc access out of range\n"); + ws->fail(); + } + bool error_next; + ws->iBusAccess(top->iBusTc_address, &nextData,&error_next); + } + } + + virtual void postCycle(){ + top->iBusTc_data = nextData; + } +}; + +#endif + + #ifdef IBUS_SIMPLE_AVALON struct IBusSimpleAvalonRsp{ @@ -1274,6 +1311,12 @@ public: bool error; top->iBus_rsp_valid = 0; if(pendingCount != 0 && (!ws->iStall || VL_RANDOM_I(7) < 100)){ + #ifdef IBUS_TC + if((address & 0x70000000) == 0 && (address & 0x20) != 0){ + printf("IBUS_CACHED access out of range\n"); + ws->fail(); + } + #endif ws->iBusAccess(address,&top->iBus_rsp_payload_data,&error); top->iBus_rsp_payload_error = error; pendingCount--; @@ -1960,6 +2003,11 @@ void Workspace::fillSimELements(){ #if defined(IBUS_CACHED_WISHBONE) || defined(IBUS_SIMPLE_WISHBONE) simElements.push_back(new IBusCachedWishbone(this)); #endif + + #ifdef IBUS_TC + simElements.push_back(new IBusTc(this)); + #endif + #ifdef DBUS_SIMPLE simElements.push_back(new DBusSimple(this)); #endif diff --git a/src/test/cpp/regression/makefile b/src/test/cpp/regression/makefile index ba249518..84c68221 100644 --- a/src/test/cpp/regression/makefile +++ b/src/test/cpp/regression/makefile @@ -1,6 +1,7 @@ DEBUG?=no IBUS?=CACHED +IBUS_TC?=no DBUS?=CACHED TRACE?=no TRACE_ACCESS?=no @@ -42,7 +43,7 @@ ADDCFLAGS += -CFLAGS -DTHREAD_COUNT=${THREAD_COUNT} ifeq ($(DEBUG),yes) ADDCFLAGS += -CFLAGS -O0 -CFLAGS -g else - ADDCFLAGS += -CFLAGS -O3 + ADDCFLAGS += -CFLAGS -O3 -O3 endif @@ -58,6 +59,11 @@ ifneq ($(RUN_HEX),no) ADDCFLAGS += -CFLAGS -DRUN_HEX='\"$(RUN_HEX)\"' endif + +ifeq ($(IBUS_TC),yes) + ADDCFLAGS += -CFLAGS -DIBUS_TC=yes +endif + ifeq ($(COMPRESSED),yes) ADDCFLAGS += -CFLAGS -DCOMPRESSED endif diff --git a/src/test/scala/vexriscv/TestIndividualFeatures.scala b/src/test/scala/vexriscv/TestIndividualFeatures.scala index 10f25c93..7654b4bd 100644 --- a/src/test/scala/vexriscv/TestIndividualFeatures.scala +++ b/src/test/scala/vexriscv/TestIndividualFeatures.scala @@ -284,6 +284,8 @@ class IBusDimension extends VexRiscvDimension("IBus") { } } else { val compressed = r.nextBoolean() + val tighlyCoupled = r.nextBoolean() +// val tighlyCoupled = false val prediction = random(r, List(NONE, STATIC, DYNAMIC, DYNAMIC_TARGET)) val catchAll = universes.contains(VexRiscvUniverse.CATCH_ALL) val relaxedPcCalculation, twoCycleCache, injectorStage = r.nextBoolean() @@ -295,29 +297,33 @@ class IBusDimension extends VexRiscvDimension("IBus") { wayCount = 1 << r.nextInt(3) }while(cacheSize/wayCount < 512) - new VexRiscvPosition("Cached" + (if(twoCycleCache) "2cc" else "") + (if(injectorStage) "Injstage" else "") + (if(twoCycleRam) "2cr" else "") + "S" + cacheSize + "W" + wayCount + (if(relaxedPcCalculation) "Relax" else "") + (if(compressed) "Rvc" else "") + prediction.getClass.getTypeName().replace("$","")) with InstructionAnticipatedPosition{ - override def testParam = "IBUS=CACHED" + (if(compressed) " COMPRESSED=yes" else "") - override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new IBusCachedPlugin( - resetVector = 0x80000000l, - compressedGen = compressed, - prediction = prediction, - relaxedPcCalculation = relaxedPcCalculation, - injectorStage = injectorStage, - config = InstructionCacheConfig( - cacheSize = cacheSize, - bytePerLine = 32, - wayCount = wayCount, - addressWidth = 32, - cpuDataWidth = 32, - memDataWidth = 32, - catchIllegalAccess = catchAll, - catchAccessFault = catchAll, - catchMemoryTranslationMiss = catchAll, - asyncTagMemory = false, - twoCycleRam = twoCycleRam, - twoCycleCache = twoCycleCache + new VexRiscvPosition("Cached" + (if(twoCycleCache) "2cc" else "") + (if(injectorStage) "Injstage" else "") + (if(twoCycleRam) "2cr" else "") + "S" + cacheSize + "W" + wayCount + (if(relaxedPcCalculation) "Relax" else "") + (if(compressed) "Rvc" else "") + prediction.getClass.getTypeName().replace("$","")+ (if(tighlyCoupled)"Tc" else "")) with InstructionAnticipatedPosition{ + override def testParam = "IBUS=CACHED" + (if(compressed) " COMPRESSED=yes" else "") + (if(tighlyCoupled)" IBUS_TC=yes" else "") + override def applyOn(config: VexRiscvConfig): Unit = { + val p = new IBusCachedPlugin( + resetVector = 0x80000000l, + compressedGen = compressed, + prediction = prediction, + relaxedPcCalculation = relaxedPcCalculation, + injectorStage = injectorStage, + config = InstructionCacheConfig( + cacheSize = cacheSize, + bytePerLine = 32, + wayCount = wayCount, + addressWidth = 32, + cpuDataWidth = 32, + memDataWidth = 32, + catchIllegalAccess = catchAll, + catchAccessFault = catchAll, + catchMemoryTranslationMiss = catchAll, + asyncTagMemory = false, + twoCycleRam = twoCycleRam, + twoCycleCache = twoCycleCache + ) ) - ) + if(tighlyCoupled) p.newTightlyCoupledPort(TightlyCoupledPortParameter("iBusTc", a => a(30 downto 28) === 0x0 && a(5))) + config.plugins += p + } override def instructionAnticipatedOk() = !twoCycleCache || ((!twoCycleRam || wayCount == 1) && !compressed) } } @@ -523,8 +529,8 @@ class TestIndividualFeatures extends FunSuite { // val testId = Some(mutable.HashSet[Int](0,28,45,93)) -// val testId = Some(mutable.HashSet[Int](5)) -// val seed = -2089952013329208578l +// val testId = Some(mutable.HashSet[Int](31)) +// val seed = -7716775349351274630l From 285f6bb6ac1aaf5a29b00e154aacb388511dd5f4 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 29 Jan 2019 12:35:12 +0100 Subject: [PATCH 024/951] Update README.md Remove JDK constraints --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ef6df531..85617981 100644 --- a/README.md +++ b/README.md @@ -127,7 +127,7 @@ Note that recently, the capability to remove the Fetch/Memory/WriteBack stage wa On Ubuntu 14 : ```sh -# JAVA JDK 8. Do not try with JDK >= 9 +# JAVA JDK 8 sudo add-apt-repository -y ppa:openjdk-r/ppa sudo apt-get update sudo apt-get install openjdk-8-jdk -y From 56e3321394b85941d8f72755e9f8dd9cca257626 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 30 Jan 2019 01:35:44 +0100 Subject: [PATCH 025/951] cpp regresion now print the time of failure --- src/test/cpp/regression/main.cpp | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 84d1f2bb..5610b2d5 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -1121,7 +1121,7 @@ public: staticMutex.unlock(); } catch (const std::exception& e) { staticMutex.lock(); - cout << "FAIL " << name << " at PC=" << hex << setw(8) << top->VexRiscv->writeBack_PC << dec << endl; //<< " seed : " << seed << + cout << "FAIL " << name << " at PC=" << hex << setw(8) << top->VexRiscv->writeBack_PC << dec << " T=" << i << endl; //<< " seed : " << seed << cycles += instanceCycles; staticMutex.unlock(); failed = true; @@ -2443,13 +2443,20 @@ string freeRtosTests[] = { // "test1","test1","test1","test1","test1","test1","test1","test1", // "test1","test1","test1","test1","test1","test1","test1","test1" - "AltQTest", "AltBlock", "AltPollQ", "blocktim", "countsem", "dead", "EventGroupsDemo", "flop", "integer", "QPeek", - "QueueSet", "recmutex", "semtest", "TaskNotify", "BlockQ", "crhook", "dynamic", - "GenQTest", "PollQ", "QueueOverwrite", "QueueSetPolling", "sp_flop", "test1" +// "AltQTest", "AltBlock", "AltPollQ", "blocktim", "countsem", "dead", "EventGroupsDemo", "flop", "integer", "QPeek", +// "QueueSet", "recmutex", "semtest", "TaskNotify", "BlockQ", "crhook", "dynamic", +// "GenQTest", "PollQ", "QueueOverwrite", "QueueSetPolling", "sp_flop", "test1" //"BlockQ","BlockQ","BlockQ","BlockQ","BlockQ","BlockQ","BlockQ","BlockQ" // "flop" // "flop", "sp_flop" // <- Simple test // "AltBlckQ" ??? + + "TaskNotify","TaskNotify","TaskNotify","TaskNotify","TaskNotify","TaskNotify","TaskNotify","TaskNotify", + "TaskNotify","TaskNotify","TaskNotify","TaskNotify","TaskNotify","TaskNotify","TaskNotify","TaskNotify", + "TaskNotify","TaskNotify","TaskNotify","TaskNotify","TaskNotify","TaskNotify","TaskNotify","TaskNotify", + "TaskNotify","TaskNotify","TaskNotify","TaskNotify","TaskNotify","TaskNotify","TaskNotify","TaskNotify", + "TaskNotify","TaskNotify","TaskNotify","TaskNotify","TaskNotify","TaskNotify","TaskNotify","TaskNotify", + "TaskNotify","TaskNotify","TaskNotify","TaskNotify","TaskNotify","TaskNotify","TaskNotify","TaskNotify" }; @@ -2788,17 +2795,17 @@ int main(int argc, char **argv, char **env) { /*for(int redo = 0;redo < 4;redo++)*/{ for(const string &name : freeRtosTests){ - tasks.push_back([=]() { Workspace(name + "_rv32i_O0").withRiscvRef()->loadHex("../../resources/freertos/" + name + "_rv32i_O0.hex")->bootAt(0x80000000u)->run(4e6*15);}); - tasks.push_back([=]() { Workspace(name + "_rv32i_O3").withRiscvRef()->loadHex("../../resources/freertos/" + name + "_rv32i_O3.hex")->bootAt(0x80000000u)->run(4e6*15);}); +// tasks.push_back([=]() { Workspace(name + "_rv32i_O0").withRiscvRef()->loadHex("../../resources/freertos/" + name + "_rv32i_O0.hex")->bootAt(0x80000000u)->run(4e6*15);}); +// tasks.push_back([=]() { Workspace(name + "_rv32i_O3").withRiscvRef()->loadHex("../../resources/freertos/" + name + "_rv32i_O3.hex")->bootAt(0x80000000u)->run(4e6*15);}); #ifdef COMPRESSED - tasks.push_back([=]() { Workspace(name + "_rv32ic_O0").withRiscvRef()->loadHex("../../resources/freertos/" + name + "_rv32ic_O0.hex")->bootAt(0x80000000u)->run(5e6*15);}); - tasks.push_back([=]() { Workspace(name + "_rv32ic_O3").withRiscvRef()->loadHex("../../resources/freertos/" + name + "_rv32ic_O3.hex")->bootAt(0x80000000u)->run(4e6*15);}); +// tasks.push_back([=]() { Workspace(name + "_rv32ic_O0").withRiscvRef()->loadHex("../../resources/freertos/" + name + "_rv32ic_O0.hex")->bootAt(0x80000000u)->run(5e6*15);}); +// tasks.push_back([=]() { Workspace(name + "_rv32ic_O3").withRiscvRef()->loadHex("../../resources/freertos/" + name + "_rv32ic_O3.hex")->bootAt(0x80000000u)->run(4e6*15);}); #endif #if defined(MUL) && defined(DIV) #ifdef COMPRESSED tasks.push_back([=]() { Workspace(name + "_rv32imac_O3").withRiscvRef()->loadHex("../../resources/freertos/" + name + "_rv32imac_O3.hex")->bootAt(0x80000000u)->run(4e6*15);}); #else - tasks.push_back([=]() { Workspace(name + "_rv32im_O3").withRiscvRef()->loadHex("../../resources/freertos/" + name + "_rv32im_O3.hex")->bootAt(0x80000000u)->run(4e6*15);}); +// tasks.push_back([=]() { Workspace(name + "_rv32im_O3").withRiscvRef()->loadHex("../../resources/freertos/" + name + "_rv32im_O3.hex")->bootAt(0x80000000u)->run(4e6*15);}); #endif #endif } From 11f55359c63c752584900e349b6979fe0ca2e83b Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 30 Jan 2019 01:37:47 +0100 Subject: [PATCH 026/951] IBusCache can now avoid injectorStage in singleStage mode --- src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala index c34c32f2..03285f0f 100644 --- a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala @@ -33,7 +33,8 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l, keepPcPlus4 : Boolean = false, config : InstructionCacheConfig, memoryTranslatorPortConfig : Any = null, - injectorStage : Boolean = false) extends IBusFetcherImpl( + injectorStage : Boolean = false, + withoutInjectorStage : Boolean = false) extends IBusFetcherImpl( resetVector = resetVector, keepPcPlus4 = keepPcPlus4, decodePcGen = compressedGen, @@ -43,9 +44,10 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l, injectorReadyCutGen = false, prediction = prediction, historyRamSizeLog2 = historyRamSizeLog2, - injectorStage = !config.twoCycleCache || injectorStage){ + injectorStage = (!config.twoCycleCache && !withoutInjectorStage) || injectorStage){ import config._ + assert(!(withoutInjectorStage && injectorStage)) var iBus : InstructionCacheMemBus = null var mmuBus : MemoryTranslatorBus = null From e0c8ac01d2d94089a0df5a32bdb0069db92ddd6a Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sun, 3 Feb 2019 15:20:34 +0100 Subject: [PATCH 027/951] Add custom external interrupts --- build.sbt | 34 +++------------ src/main/scala/vexriscv/demo/Briey.scala | 6 ++- src/main/scala/vexriscv/demo/Murax.scala | 2 +- .../scala/vexriscv/plugin/CsrPlugin.scala | 43 ++++++++++++++----- 4 files changed, 43 insertions(+), 42 deletions(-) diff --git a/build.sbt b/build.sbt index 3c2aae66..6b24b153 100644 --- a/build.sbt +++ b/build.sbt @@ -1,25 +1,3 @@ -//name := "VexRiscv" -// -//organization := "com.github.spinalhdl" -// -//version := "1.0.0" -// -//scalaVersion := "2.11.6" -// -//EclipseKeys.withSource := true -// -//libraryDependencies ++= Seq( -// "com.github.spinalhdl" % "spinalhdl-core_2.11" % "1.2.1", -// "com.github.spinalhdl" % "spinalhdl-lib_2.11" % "1.2.1", -// "org.scalatest" % "scalatest_2.11" % "2.2.1", -// "org.yaml" % "snakeyaml" % "1.8" -//) -// -// -// -//addCompilerPlugin("org.scala-lang.plugins" % "scala-continuations-plugin_2.11.6" % "1.0.2") -//scalacOptions += "-P:continuations:enable" -//fork := true lazy val root = (project in file(".")). settings( @@ -29,16 +7,16 @@ lazy val root = (project in file(".")). version := "1.0.0" )), libraryDependencies ++= Seq( - "com.github.spinalhdl" % "spinalhdl-core_2.11" % "1.3.1", - "com.github.spinalhdl" % "spinalhdl-lib_2.11" % "1.3.1", +// "com.github.spinalhdl" % "spinalhdl-core_2.11" % "1.3.1", +// "com.github.spinalhdl" % "spinalhdl-lib_2.11" % "1.3.1", "org.scalatest" % "scalatest_2.11" % "2.2.1", "org.yaml" % "snakeyaml" % "1.8" ), name := "VexRiscv" - )//.dependsOn(spinalHdlSim,spinalHdlCore,spinalHdlLib) -//lazy val spinalHdlSim = ProjectRef(file("../SpinalHDL"), "SpinalHDL-sim") -//lazy val spinalHdlCore = ProjectRef(file("../SpinalHDL"), "SpinalHDL-core") -//lazy val spinalHdlLib = ProjectRef(file("../SpinalHDL"), "SpinalHDL-lib") + ).dependsOn(spinalHdlSim,spinalHdlCore,spinalHdlLib) +lazy val spinalHdlSim = ProjectRef(file("../SpinalHDL"), "sim") +lazy val spinalHdlCore = ProjectRef(file("../SpinalHDL"), "core") +lazy val spinalHdlLib = ProjectRef(file("../SpinalHDL"), "lib") fork := true \ No newline at end of file diff --git a/src/main/scala/vexriscv/demo/Briey.scala b/src/main/scala/vexriscv/demo/Briey.scala index ca76f8b2..31c74602 100644 --- a/src/main/scala/vexriscv/demo/Briey.scala +++ b/src/main/scala/vexriscv/demo/Briey.scala @@ -258,10 +258,12 @@ class Briey(config: BrieyConfig) extends Component{ ) val gpioACtrl = Apb3Gpio( - gpioWidth = 32 + gpioWidth = 32, + withReadSync = true ) val gpioBCtrl = Apb3Gpio( - gpioWidth = 32 + gpioWidth = 32, + withReadSync = true ) val timerCtrl = PinsecTimerCtrl() diff --git a/src/main/scala/vexriscv/demo/Murax.scala b/src/main/scala/vexriscv/demo/Murax.scala index 8a06cbc6..d78beeb1 100644 --- a/src/main/scala/vexriscv/demo/Murax.scala +++ b/src/main/scala/vexriscv/demo/Murax.scala @@ -276,7 +276,7 @@ case class Murax(config : MuraxConfig) extends Component{ //******** APB peripherals ********* val apbMapping = ArrayBuffer[(Apb3, SizeMapping)]() - val gpioACtrl = Apb3Gpio(gpioWidth = gpioWidth) + val gpioACtrl = Apb3Gpio(gpioWidth = gpioWidth, withReadSync = true) io.gpioA <> gpioACtrl.io.gpio apbMapping += gpioACtrl.io.apb -> (0x00000, 4 kB) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index fb383e5f..ab59360a 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -271,6 +271,20 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception val csrMapping = new CsrMapping() + + case class InterruptSource(var cond : Bool, id : Int) + case class InterruptPrivilege(privilege : Int){ + var privilegeCond : Bool = null + val sources = ArrayBuffer[InterruptSource]() + } + + def getInterruptPrivilege(privilege : Int) = customInterrupts.getOrElseUpdate(privilege, InterruptPrivilege(privilege)) + var customInterrupts = mutable.LinkedHashMap[Int, InterruptPrivilege]() + def addInterrupt(cond : Bool, id : Int, privilege : Int): Unit = { + getInterruptPrivilege(privilege).sources += InterruptSource(cond, id) + } + def createInterrupt(id : Int, privilege : Int) : Bool = { val ret = Bool(); addInterrupt(ret, id, privilege); ret} + override def r(csrAddress: Int, bitOffset: Int, that: Data): Unit = csrMapping.r(csrAddress, bitOffset, that) override def w(csrAddress: Int, bitOffset: Int, that: Data): Unit = csrMapping.w(csrAddress, bitOffset, that) override def onWrite(csrAddress: Int)(body: => Unit): Unit = csrMapping.onWrite(csrAddress)(body) @@ -338,6 +352,11 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception allowInterrupts = True allowException = True + + for (privilege <- customInterrupts.values; + source <- privilege.sources){ + source.cond = source.cond.pull() + } } def inhibateInterrupts() : Unit = allowInterrupts := False @@ -500,20 +519,22 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception minstret := minstret + 1 } - case class InterruptSource(cond : Bool, id : Int) - case class InterruptPrivilege(privilege : Int, privilegeCond : Bool, sources : ArrayBuffer[InterruptSource]) - val interruptModel = ArrayBuffer[InterruptPrivilege]() - if(supervisorGen) interruptModel += InterruptPrivilege(1, sstatus.SIE && privilege <= "01", ArrayBuffer( - InterruptSource(sip.STIP && sie.STIE, 5), - InterruptSource(sip.SSIP && sie.SSIE, 1), - InterruptSource(sip.SEIP && sie.SEIE, 9) - )) - interruptModel += InterruptPrivilege(3, mstatus.MIE , ArrayBuffer( + if(supervisorGen) { + getInterruptPrivilege(1).privilegeCond = sstatus.SIE && privilege <= "01" + getInterruptPrivilege(1).sources ++= List( + InterruptSource(sip.STIP && sie.STIE, 5), + InterruptSource(sip.SSIP && sie.SSIE, 1), + InterruptSource(sip.SEIP && sie.SEIE, 9) + ) + } + + getInterruptPrivilege(3).privilegeCond = mstatus.MIE + getInterruptPrivilege(3).sources ++= List( InterruptSource(mip.MTIP && mie.MTIE, 7), InterruptSource(mip.MSIP && mie.MSIE, 3), InterruptSource(mip.MEIP && mie.MEIE, 11) - )) + ) case class DelegatorModel(value : Bits, source : Int, target : Int) // def solveDelegators(delegators : Seq[DelegatorModel], id : Int, lowerBound : Int): UInt = { @@ -621,7 +642,7 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception val interrupt = False val interruptCode = UInt(4 bits).assignDontCare().addTag(Verilator.public) val interruptDelegatorHit = interruptDelegators.map(d => (d -> False)).toMap - for(model <- interruptModel){ + for(model <- customInterrupts.values.toSeq.sortBy(_.privilege)){ when(model.privilegeCond){ when(model.sources.map(_.cond).orR){ interrupt := True From c9f4a09de0d543adfcf438c2cc0a41202dbabdaa Mon Sep 17 00:00:00 2001 From: Tim Ansell Date: Fri, 22 Feb 2019 14:52:09 -0800 Subject: [PATCH 028/951] Fix image in README. --- scripts/Murax/iCE40-hx8k_breakout_board/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/Murax/iCE40-hx8k_breakout_board/README.md b/scripts/Murax/iCE40-hx8k_breakout_board/README.md index 62078a37..bd43f4a3 100644 --- a/scripts/Murax/iCE40-hx8k_breakout_board/README.md +++ b/scripts/Murax/iCE40-hx8k_breakout_board/README.md @@ -2,7 +2,7 @@ This example is for the [Lattice iCE40HX-8K Breakout Board](http://www.latticesemi.com/Products/DevelopmentBoardsAndKits/iCE40HX8KBreakoutBoard.aspx). An image of this board is shown below; -![img/iCE40HX8K-breakout-revA.png] +![`iCE40HX8K breakout revA`](img/iCE40HX8K-breakout-revA.png) This board can be purchased for ~$USD 49 directly from Lattice and is supported by the IceStorm From 5c6cc29304b1520e1622d6ef5f5d901f8af2e5d5 Mon Sep 17 00:00:00 2001 From: Tim Ansell Date: Fri, 22 Feb 2019 14:55:18 -0800 Subject: [PATCH 029/951] Fixing other image. --- scripts/Murax/iCE40-hx8k_breakout_board/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/Murax/iCE40-hx8k_breakout_board/README.md b/scripts/Murax/iCE40-hx8k_breakout_board/README.md index bd43f4a3..1e50a02f 100644 --- a/scripts/Murax/iCE40-hx8k_breakout_board/README.md +++ b/scripts/Murax/iCE40-hx8k_breakout_board/README.md @@ -2,6 +2,7 @@ This example is for the [Lattice iCE40HX-8K Breakout Board](http://www.latticesemi.com/Products/DevelopmentBoardsAndKits/iCE40HX8KBreakoutBoard.aspx). An image of this board is shown below; + ![`iCE40HX8K breakout revA`](img/iCE40HX8K-breakout-revA.png) This board can be purchased for ~$USD 49 directly from Lattice and is supported @@ -20,7 +21,8 @@ mode. This requires removing jumper `J7` and putting the pair of jumpers on This is shown in **Figure 5** of the [iCE40HX-8K Breakout Board User Guide](http://www.latticesemi.com/view_document?document_id=50373). which is also reproduced below; -![img/cram-programming-config.png] + +![CRAM Programming Config](img/cram-programming-config.png) Once your board is ready, you should follow the setup instructions at the [top level](../../../README.md). From 7594cbd9024de96fa4af204b5d4082e775765474 Mon Sep 17 00:00:00 2001 From: Tim Ansell Date: Fri, 22 Feb 2019 14:57:07 -0800 Subject: [PATCH 030/951] Fixing images in README in iCE40-hx8k_breakout_board_xip directory too. --- scripts/Murax/iCE40-hx8k_breakout_board_xip/README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/scripts/Murax/iCE40-hx8k_breakout_board_xip/README.md b/scripts/Murax/iCE40-hx8k_breakout_board_xip/README.md index 62078a37..1e50a02f 100644 --- a/scripts/Murax/iCE40-hx8k_breakout_board_xip/README.md +++ b/scripts/Murax/iCE40-hx8k_breakout_board_xip/README.md @@ -2,7 +2,8 @@ This example is for the [Lattice iCE40HX-8K Breakout Board](http://www.latticesemi.com/Products/DevelopmentBoardsAndKits/iCE40HX8KBreakoutBoard.aspx). An image of this board is shown below; -![img/iCE40HX8K-breakout-revA.png] + +![`iCE40HX8K breakout revA`](img/iCE40HX8K-breakout-revA.png) This board can be purchased for ~$USD 49 directly from Lattice and is supported by the IceStorm @@ -20,7 +21,8 @@ mode. This requires removing jumper `J7` and putting the pair of jumpers on This is shown in **Figure 5** of the [iCE40HX-8K Breakout Board User Guide](http://www.latticesemi.com/view_document?document_id=50373). which is also reproduced below; -![img/cram-programming-config.png] + +![CRAM Programming Config](img/cram-programming-config.png) Once your board is ready, you should follow the setup instructions at the [top level](../../../README.md). From b9922105f0f61a4c72d657ea6bd746a11820eb32 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 26 Feb 2019 17:22:13 +0100 Subject: [PATCH 031/951] Fix readme demo path --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ef6df531..b874eb47 100644 --- a/README.md +++ b/README.md @@ -156,8 +156,8 @@ sudo make install ## CPU generation You can find two example CPU instances in: -- src/main/scala/vexriscv/GenFull.scala -- src/main/scala/vexriscv/GenSmallest.scala +- src/main/scala/vexriscv/demo/GenFull.scala +- src/main/scala/vexriscv/demo/GenSmallest.scala To generate the corresponding RTL as a VexRiscv.v file, run the following commands in the root directory of this repository: From 434793711bab181860d0be8856fcc4cf4520bf2d Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 26 Feb 2019 17:26:42 +0100 Subject: [PATCH 032/951] fix part of #59 --- .../{GenSmallAndPerformant.scala => GenSmallAndProductive.scala} | 0 ...ndPerformantICache.scala => GenSmallAndProductiveICache.scala} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename src/main/scala/vexriscv/demo/{GenSmallAndPerformant.scala => GenSmallAndProductive.scala} (100%) rename src/main/scala/vexriscv/demo/{GenSmallAndPerformantICache.scala => GenSmallAndProductiveICache.scala} (100%) diff --git a/src/main/scala/vexriscv/demo/GenSmallAndPerformant.scala b/src/main/scala/vexriscv/demo/GenSmallAndProductive.scala similarity index 100% rename from src/main/scala/vexriscv/demo/GenSmallAndPerformant.scala rename to src/main/scala/vexriscv/demo/GenSmallAndProductive.scala diff --git a/src/main/scala/vexriscv/demo/GenSmallAndPerformantICache.scala b/src/main/scala/vexriscv/demo/GenSmallAndProductiveICache.scala similarity index 100% rename from src/main/scala/vexriscv/demo/GenSmallAndPerformantICache.scala rename to src/main/scala/vexriscv/demo/GenSmallAndProductiveICache.scala From bad60f39cd02df7aec0616f2a58af10645acb819 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sun, 10 Mar 2019 11:12:32 +0100 Subject: [PATCH 033/951] Fix Decoding benchmark --- .../vexriscv/plugin/DecoderSimplePlugin.scala | 114 ++++++++++-------- 1 file changed, 66 insertions(+), 48 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/DecoderSimplePlugin.scala b/src/main/scala/vexriscv/plugin/DecoderSimplePlugin.scala index 3d604980..e9c4633f 100644 --- a/src/main/scala/vexriscv/plugin/DecoderSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/DecoderSimplePlugin.scala @@ -84,61 +84,79 @@ class DecoderSimplePlugin(catchIllegalInstruction : Boolean = false, forceLegalI val stageables = (encodings.flatMap(_._2.map(_._1)) ++ defaults.map(_._1)).toSet.toList - var offset = 0 - var defaultValue, defaultCare = BigInt(0) - val offsetOf = mutable.HashMap[Stageable[_ <: BaseType],Int]() + val stupidDecoder = false + if(stupidDecoder){ + if (catchIllegalInstruction || forceLegalInstructionComputation) insert(LEGAL_INSTRUCTION) := False + for(stageable <- stageables){ + if(defaults.contains(stageable)){ + insert(stageable).assignFrom(defaults(stageable)) + } else { + insert(stageable).assignDontCare() + } + } + for((key, tasks) <- encodings){ + when(input(INSTRUCTION) === key){ + if (catchIllegalInstruction || forceLegalInstructionComputation) insert(LEGAL_INSTRUCTION) := True + for((stageable, value) <- tasks){ + insert(stageable).assignFrom(value) + } + } + } + } else { + var offset = 0 + var defaultValue, defaultCare = BigInt(0) + val offsetOf = mutable.HashMap[Stageable[_ <: BaseType], Int]() - //Build defaults value and field offset map - stageables.foreach(e => { - defaults.get(e) match { - case Some(value) => { - value.head.source match { + //Build defaults value and field offset map + stageables.foreach(e => { + defaults.get(e) match { + case Some(value) => { + value.head.source match { + case literal: EnumLiteral[_] => literal.fixEncoding(e.dataType.asInstanceOf[SpinalEnumCraft[_]].getEncoding) + case _ => + } + defaultValue += value.head.source.asInstanceOf[Literal].getValue << offset + defaultCare += ((BigInt(1) << e.dataType.getBitsWidth) - 1) << offset + + } + case _ => + } + offsetOf(e) = offset + offset += e.dataType.getBitsWidth + }) + + //Build spec + val spec = encodings.map { case (key, values) => + var decodedValue = defaultValue + var decodedCare = defaultCare + for ((e, literal) <- values) { + literal.head.source match { case literal: EnumLiteral[_] => literal.fixEncoding(e.dataType.asInstanceOf[SpinalEnumCraft[_]].getEncoding) case _ => } - defaultValue += value.head.source .asInstanceOf[Literal].getValue << offset - defaultCare += ((BigInt(1) << e.dataType.getBitsWidth) - 1) << offset - + val offset = offsetOf(e) + decodedValue |= literal.head.source.asInstanceOf[Literal].getValue << offset + decodedCare |= ((BigInt(1) << e.dataType.getBitsWidth) - 1) << offset } - case _ => + (Masked(key.value, key.careAbout), Masked(decodedValue, decodedCare)) } - offsetOf(e) = offset - offset += e.dataType.getBitsWidth - }) - //Build spec - val spec = encodings.map { case (key, values) => - var decodedValue = defaultValue - var decodedCare = defaultCare - for((e, literal) <- values){ - literal.head.source match{ - case literal : EnumLiteral[_] => literal.fixEncoding(e.dataType.asInstanceOf[SpinalEnumCraft[_]].getEncoding) - case _ => - } - val offset = offsetOf(e) - decodedValue |= literal.head.source.asInstanceOf[Literal].getValue << offset - decodedCare |= ((BigInt(1) << e.dataType.getBitsWidth)-1) << offset - } - (Masked(key.value,key.careAbout),Masked(decodedValue,decodedCare)) + + // logic implementation + val decodedBits = Bits(stageables.foldLeft(0)(_ + _.dataType.getBitsWidth) bits) + decodedBits := Symplify(input(INSTRUCTION), spec, decodedBits.getWidth) + if (catchIllegalInstruction || forceLegalInstructionComputation) insert(LEGAL_INSTRUCTION) := Symplify.logicOf(input(INSTRUCTION), SymplifyBit.getPrimeImplicantsByTrueAndDontCare(spec.unzip._1.toSeq, Nil, 32)) + + + //Unpack decodedBits and insert fields in the pipeline + offset = 0 + stageables.foreach(e => { + insert(e).assignFromBits(decodedBits(offset, e.dataType.getBitsWidth bits)) + // insert(e).assignFromBits(RegNext(decodedBits(offset, e.dataType.getBitsWidth bits))) + offset += e.dataType.getBitsWidth + }) } - - - // logic implementation - val decodedBits = Bits(stageables.foldLeft(0)(_ + _.dataType.getBitsWidth) bits) - decodedBits := Symplify(input(INSTRUCTION),spec, decodedBits.getWidth) - if(catchIllegalInstruction || forceLegalInstructionComputation) insert(LEGAL_INSTRUCTION) := Symplify.logicOf(input(INSTRUCTION), SymplifyBit.getPrimeImplicantsByTrueAndDontCare(spec.unzip._1.toSeq, Nil, 32)) - - - //Unpack decodedBits and insert fields in the pipeline - offset = 0 - stageables.foreach(e => { - insert(e).assignFromBits(decodedBits(offset, e.dataType.getBitsWidth bits)) -// insert(e).assignFromBits(RegNext(decodedBits(offset, e.dataType.getBitsWidth bits))) - offset += e.dataType.getBitsWidth - }) - - if(catchIllegalInstruction){ decodeExceptionPort.valid := arbitration.isValid && input(INSTRUCTION_READY) && !input(LEGAL_INSTRUCTION) // ?? HalitIt to alow decoder stage to wait valid data from 2 stages cache cache ?? decodeExceptionPort.code := 2 @@ -149,8 +167,8 @@ class DecoderSimplePlugin(catchIllegalInstruction : Boolean = false, forceLegalI def bench(toplevel : VexRiscv): Unit ={ toplevel.rework{ import toplevel.config._ - toplevel.getAllIo.foreach{io => - if(io.isInput) io.assignDontCare() + toplevel.getAllIo.toList.foreach{io => + if(io.isInput) { io.assignDontCare()} io.setAsDirectionLess() } toplevel.decode.input(INSTRUCTION).removeAssignments() From 2e0b63bc676125586eee9dc82d8c7aae84584bfb Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sun, 10 Mar 2019 11:12:43 +0100 Subject: [PATCH 034/951] SpinalHDL 1.3.2 --- build.sbt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/build.sbt b/build.sbt index 6b24b153..c22fc57f 100644 --- a/build.sbt +++ b/build.sbt @@ -7,16 +7,16 @@ lazy val root = (project in file(".")). version := "1.0.0" )), libraryDependencies ++= Seq( -// "com.github.spinalhdl" % "spinalhdl-core_2.11" % "1.3.1", -// "com.github.spinalhdl" % "spinalhdl-lib_2.11" % "1.3.1", + "com.github.spinalhdl" % "spinalhdl-core_2.11" % "1.3.2", + "com.github.spinalhdl" % "spinalhdl-lib_2.11" % "1.3.2", "org.scalatest" % "scalatest_2.11" % "2.2.1", "org.yaml" % "snakeyaml" % "1.8" ), name := "VexRiscv" - ).dependsOn(spinalHdlSim,spinalHdlCore,spinalHdlLib) -lazy val spinalHdlSim = ProjectRef(file("../SpinalHDL"), "sim") -lazy val spinalHdlCore = ProjectRef(file("../SpinalHDL"), "core") -lazy val spinalHdlLib = ProjectRef(file("../SpinalHDL"), "lib") + )//.dependsOn(spinalHdlSim,spinalHdlCore,spinalHdlLib) +//lazy val spinalHdlSim = ProjectRef(file("../SpinalHDL"), "sim") +//lazy val spinalHdlCore = ProjectRef(file("../SpinalHDL"), "core") +//lazy val spinalHdlLib = ProjectRef(file("../SpinalHDL"), "lib") fork := true \ No newline at end of file From 03663ce91aece476605a3a81ba84124da0cbb785 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 15 Mar 2019 17:35:31 +0100 Subject: [PATCH 035/951] Move unreleased SpinalHDL --- build.sbt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/build.sbt b/build.sbt index c22fc57f..64be7cf7 100644 --- a/build.sbt +++ b/build.sbt @@ -7,16 +7,16 @@ lazy val root = (project in file(".")). version := "1.0.0" )), libraryDependencies ++= Seq( - "com.github.spinalhdl" % "spinalhdl-core_2.11" % "1.3.2", - "com.github.spinalhdl" % "spinalhdl-lib_2.11" % "1.3.2", +// "com.github.spinalhdl" % "spinalhdl-core_2.11" % "1.3.2", +// "com.github.spinalhdl" % "spinalhdl-lib_2.11" % "1.3.2", "org.scalatest" % "scalatest_2.11" % "2.2.1", "org.yaml" % "snakeyaml" % "1.8" ), name := "VexRiscv" - )//.dependsOn(spinalHdlSim,spinalHdlCore,spinalHdlLib) -//lazy val spinalHdlSim = ProjectRef(file("../SpinalHDL"), "sim") -//lazy val spinalHdlCore = ProjectRef(file("../SpinalHDL"), "core") -//lazy val spinalHdlLib = ProjectRef(file("../SpinalHDL"), "lib") + ).dependsOn(spinalHdlSim,spinalHdlCore,spinalHdlLib) +lazy val spinalHdlSim = ProjectRef(file("../SpinalHDL"), "sim") +lazy val spinalHdlCore = ProjectRef(file("../SpinalHDL"), "core") +lazy val spinalHdlLib = ProjectRef(file("../SpinalHDL"), "lib") fork := true \ No newline at end of file From b63395435f12d70419c77251f6ee9d1f35970d30 Mon Sep 17 00:00:00 2001 From: Tom Verbeure Date: Sat, 16 Mar 2019 15:44:18 +0000 Subject: [PATCH 036/951] SimpleMul core. --- .../demo/GenFullNoMmuNoCacheSimpleMul.scala | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 src/main/scala/vexriscv/demo/GenFullNoMmuNoCacheSimpleMul.scala diff --git a/src/main/scala/vexriscv/demo/GenFullNoMmuNoCacheSimpleMul.scala b/src/main/scala/vexriscv/demo/GenFullNoMmuNoCacheSimpleMul.scala new file mode 100644 index 00000000..f1e9874a --- /dev/null +++ b/src/main/scala/vexriscv/demo/GenFullNoMmuNoCacheSimpleMul.scala @@ -0,0 +1,63 @@ +package vexriscv.demo + +import vexriscv.plugin._ +import vexriscv.ip.{DataCacheConfig, InstructionCacheConfig} +import vexriscv.{plugin, VexRiscv, VexRiscvConfig} +import spinal.core._ + +/** + * Created by spinalvm on 15.06.17. + */ +object GenFullNoMmuNoCacheSimpleMul extends App{ + def cpu() = new VexRiscv( + config = VexRiscvConfig( + plugins = List( + new IBusSimplePlugin( + resetVector = 0x80000000l, + cmdForkOnSecondStage = false, + cmdForkPersistence = false, + prediction = STATIC, + catchAccessFault = false, + compressedGen = false + ), + new DBusSimplePlugin( + catchAddressMisaligned = false, + catchAccessFault = false + ), + new DecoderSimplePlugin( + catchIllegalInstruction = true + ), + new RegFilePlugin( + regFileReadyKind = plugin.SYNC, + zeroBoot = false + ), + new IntAluPlugin, + new SrcPlugin( + separatedAddSub = false, + executeInsertion = true + ), + new FullBarrelShifterPlugin, + new HazardSimplePlugin( + bypassExecute = true, + bypassMemory = true, + bypassWriteBack = true, + bypassWriteBackBuffer = true, + pessimisticUseSrc = false, + pessimisticWriteRegFile = false, + pessimisticAddressMatch = false + ), + new MulSimplePlugin, + new DivPlugin, + new CsrPlugin(CsrPluginConfig.small), + new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))), + new BranchPlugin( + earlyBranch = false, + catchAddressMisaligned = true + ), + new YamlPlugin("cpu0.yaml") + ) + ) + ) + + SpinalVerilog(cpu()) +} From ffa489d2114991e666e7c5ae4054d0f13919a1f6 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sun, 17 Mar 2019 21:06:47 +0100 Subject: [PATCH 037/951] hardware refilled MmuPlugin wip --- src/main/scala/vexriscv/Riscv.scala | 1 + src/main/scala/vexriscv/Services.scala | 4 +- .../scala/vexriscv/plugin/MmuPlugin.scala | 221 ++++++++++++++++++ 3 files changed, 224 insertions(+), 2 deletions(-) create mode 100644 src/main/scala/vexriscv/plugin/MmuPlugin.scala diff --git a/src/main/scala/vexriscv/Riscv.scala b/src/main/scala/vexriscv/Riscv.scala index a97f1148..06e666d8 100644 --- a/src/main/scala/vexriscv/Riscv.scala +++ b/src/main/scala/vexriscv/Riscv.scala @@ -105,6 +105,7 @@ object Riscv{ def FENCE = M"-----------------000-----0001111" def FENCE_I = M"-----------------001-----0001111" + def SFENCE_VMA = M"0001001----------000000001110011" object CSR{ def MVENDORID = 0xF11 // MRO Vendor ID. diff --git a/src/main/scala/vexriscv/Services.scala b/src/main/scala/vexriscv/Services.scala index 6f7d641d..5e4e2eb7 100644 --- a/src/main/scala/vexriscv/Services.scala +++ b/src/main/scala/vexriscv/Services.scala @@ -65,8 +65,8 @@ case class MemoryTranslatorRsp() extends Bundle{ val physicalAddress = UInt(32 bits) val isIoAccess = Bool val allowRead, allowWrite, allowExecute, allowUser = Bool - val miss = Bool - val hit = Bool + val exception = Bool + val refilling = Bool } case class MemoryTranslatorBus() extends Bundle with IMasterSlave{ diff --git a/src/main/scala/vexriscv/plugin/MmuPlugin.scala b/src/main/scala/vexriscv/plugin/MmuPlugin.scala new file mode 100644 index 00000000..42a99cc6 --- /dev/null +++ b/src/main/scala/vexriscv/plugin/MmuPlugin.scala @@ -0,0 +1,221 @@ +package vexriscv.plugin + +import vexriscv.{VexRiscv, _} +import spinal.core._ +import spinal.lib._ + +import scala.collection.mutable.ArrayBuffer + +case class DBusAccessCmd() extends Bundle { + val address = UInt(32 bits) + val size = UInt(2 bits) + val write = Bool + val writeData = Bits(32 bits) + val writeMask = Bits(4 bits) +} + +case class DBusAccessRsp() extends Bundle { + val data = Bits(32 bits) + val error = Bool() +} + +case class DBusAccess() extends Bundle { + val cmd = Stream(DBusAccessCmd()) + val rsp = Flow(DBusAccessRsp()) +} + + +object MmuPort{ + val PRIORITY_DATA = 1 + val PRIORITY_INSTRUCTION = 0 +} +case class MmuPort(bus : MemoryTranslatorBus, priority : Int, args : MmuPortConfig, id : Int/*, exceptionBus: Flow[ExceptionCause]*/) + +case class MmuPortConfig(portTlbSize : Int) + +class MmuPlugin(virtualRange : UInt => Bool, + ioRange : UInt => Bool, + allowUserIo : Boolean) extends Plugin[VexRiscv] with MemoryTranslator { + + var dBus : DBusAccess = null + val portsInfo = ArrayBuffer[MmuPort]() + + override def newTranslationPort(priority : Int,args : Any): MemoryTranslatorBus = { +// val exceptionBus = pipeline.service(classOf[ExceptionService]).newExceptionPort(stage) + val port = MmuPort(MemoryTranslatorBus(),priority,args.asInstanceOf[MmuPortConfig], portsInfo.length /*,exceptionBus*/) + portsInfo += port + port.bus + } + + object IS_SFENCE_VMA extends Stageable(Bool) + override def setup(pipeline: VexRiscv): Unit = { + import Riscv._ + import pipeline.config._ + val decoderService = pipeline.service(classOf[DecoderService]) + decoderService.addDefault(IS_SFENCE_VMA, False) + decoderService.add(SFENCE_VMA, List(IS_SFENCE_VMA -> True)) + + + dBus = ??? + } + + override def build(pipeline: VexRiscv): Unit = { + import pipeline._ + import pipeline.config._ + import Riscv._ + val csrService = pipeline.service(classOf[CsrInterface]) + + //Sorted by priority + val sortedPortsInfo = portsInfo.sortWith((a,b) => a.priority > b.priority) + + case class CacheLine() extends Bundle { + val valid, exception = Bool + val virtualAddress = UInt(20 bits) + val physicalAddress = UInt(20 bits) + val allowRead, allowWrite, allowExecute, allowUser = Bool + + def init = { + valid init (False) + this + } + } + + val core = pipeline plug new Area { + val ports = for (port <- sortedPortsInfo yield new Area { + val id = port.id + val cache = Vec(Reg(CacheLine()) init, port.args.portTlbSize) + val cacheHits = cache.map(line => line.valid && line.virtualAddress === port.bus.cmd.virtualAddress(31 downto 12)) + val cacheHit = cacheHits.asBits.orR + val cacheLine = MuxOH(cacheHits, cache) + val isInMmuRange = virtualRange(port.bus.cmd.virtualAddress) && !port.bus.cmd.bypassTranslation + val entryToReplace = Counter(port.args.portTlbSize) + + + when(isInMmuRange) { + port.bus.rsp.physicalAddress := cacheLine.physicalAddress @@ port.bus.cmd.virtualAddress(11 downto 0) + port.bus.rsp.allowRead := cacheLine.allowRead + port.bus.rsp.allowWrite := cacheLine.allowWrite + port.bus.rsp.allowExecute := cacheLine.allowExecute + port.bus.rsp.allowUser := cacheLine.allowUser + port.bus.rsp.exception := cacheHit && cacheLine.exception + port.bus.rsp.refilling := !cacheHit + + } otherwise { + port.bus.rsp.physicalAddress := port.bus.cmd.virtualAddress + port.bus.rsp.allowRead := True + port.bus.rsp.allowWrite := True + port.bus.rsp.allowExecute := True + port.bus.rsp.allowUser := Bool(allowUserIo) + port.bus.rsp.exception := False + port.bus.rsp.refilling := False + } + port.bus.rsp.isIoAccess := ioRange(port.bus.rsp.physicalAddress) + } + + val shared = new Area { + val busy = Reg(Bool) init(False) + + val satp = new Bundle { + val mode = Bool() + val ppn = UInt(20 bits) + } + csrService.rw(CSR.SATP, 31 -> satp.mode, 0 -> satp.ppn) //TODO write only ? + val State = new SpinalEnum{ + val IDLE, L1_CMD, L1_RSP, L0_CMD, L0_RSP = newElement() + } + val state = RegInit(State.IDLE) + val vpn1, vpn0 = Reg(UInt(10 bits)) + val portId = Reg(UInt(log2Up(portsInfo.length) bits)) + case class PTE() extends Bundle { + val V, R, W ,X, U, G, A, D = Bool() + val RSW = Bits(2 bits) + val PPN0 = UInt(10 bits) + val PPN1 = UInt(12 bits) + } + val dBusRsp = new Area{ + val pte = PTE() + pte.assignFromBits(dBus.rsp.data) + val exception = !pte.V || (!pte.R && pte.W) || dBus.rsp.error + val leaf = pte.R || pte.X + } + + val pteBuffer = RegNextWhen(dBusRsp.pte, dBus.rsp.valid) + + dBus.cmd.write := False + dBus.cmd.size := 2 + dBus.cmd.address.assignDontCare() + dBus.cmd.writeData.assignDontCare() + dBus.cmd.writeMask.assignDontCare() + switch(state){ + is(State.IDLE){ + for(port <- portsInfo.sortBy(_.priority)){ + when(port.bus.cmd.isValid && port.bus.rsp.refilling){ + busy := True + vpn1 := port.bus.cmd.virtualAddress(31 downto 22) + vpn0 := port.bus.cmd.virtualAddress(21 downto 12) + portId := port.id + state := State.L1_CMD + } + } + } + is(State.L1_CMD){ + dBus.cmd.valid := True + dBus.cmd.address := satp.ppn @@ vpn1 @@ U"00" + when(dBus.cmd.ready){ + state := State.L1_RSP + } + } + is(State.L1_RSP){ + when(dBus.rsp.valid){ + when(dBusRsp.leaf || dBusRsp.exception){ + state := State.IDLE + } otherwise { + state := State.L0_CMD + } + } + } + is(State.L0_CMD){ + dBus.cmd.valid := True + dBus.cmd.address := pteBuffer.PPN1(9 downto 0) @@ pteBuffer.PPN0 @@ vpn0 @@ U"00" + when(dBus.cmd.ready){ + state := State.L0_RSP + } + } + is(State.L0_RSP){ + when(dBus.rsp.valid) { + state := State.IDLE + } + } + } + + when(dBus.rsp.valid && (dBusRsp.leaf || dBusRsp.exception)){ + for(port <- ports){ + when(portId === port.id) { + port.entryToReplace.increment() + for ((line, lineId) <- port.cache.zipWithIndex) { + when(port.entryToReplace === lineId){ + line.valid := True + line.exception := dBusRsp.exception + line.virtualAddress := vpn1 @@ vpn0 + line.physicalAddress := dBusRsp.pte.PPN1(9 downto 0) @@ dBusRsp.pte.PPN0 + line.allowRead := dBusRsp.pte.R + line.allowWrite := dBusRsp.pte.W + line.allowExecute := dBusRsp.pte.X + line.allowUser := dBusRsp.pte.U + } + } + } + } + } + } + } + + execute plug new Area{ + import execute._ + val tlbWriteBuffer = Reg(UInt(20 bits)) + when(arbitration.isFiring && input(IS_SFENCE_VMA)){ + for(port <- core.ports; line <- port.cache) line.valid := False //Assume that the instruction already fetched into the pipeline are ok + } + } + } +} From c490838202880c6781d72be64450367973fd4227 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 18 Mar 2019 12:17:43 +0100 Subject: [PATCH 038/951] Added MMU support into cacheless DBus IBus plugins (for testing purposes) Probably full of bugs, need testing --- src/main/scala/vexriscv/ip/DataCache.scala | 6 +- .../scala/vexriscv/ip/InstructionCache.scala | 4 +- .../vexriscv/plugin/DBusCachedPlugin.scala | 2 +- .../vexriscv/plugin/DBusSimplePlugin.scala | 129 +++++++++++++++--- src/main/scala/vexriscv/plugin/Fetcher.scala | 6 + .../vexriscv/plugin/IBusCachedPlugin.scala | 7 +- .../vexriscv/plugin/IBusSimplePlugin.scala | 74 +++++++--- .../plugin/MemoryTranslatorPlugin.scala | 9 +- .../scala/vexriscv/plugin/MmuPlugin.scala | 12 +- .../plugin/StaticMemoryTranslatorPlugin.scala | 5 +- 10 files changed, 198 insertions(+), 56 deletions(-) diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index 5e4f9b79..21f1c38b 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -684,11 +684,11 @@ class DataCache(p : DataCacheConfig) extends Component{ when(io.cpu.writeBack.isValid) { if (catchMemoryTranslationMiss) { - io.cpu.writeBack.mmuMiss := mmuRsp.miss + io.cpu.writeBack.mmuMiss := ??? //TODO mmuRsp.miss } switch(request.kind) { is(MANAGMENT) { - when(delayedIsStuck && !mmuRsp.miss) { + when(delayedIsStuck && ???){ //TODO!mmuRsp.miss) { when(delayedWaysHitValid || (request.way && way.tagReadRspTwo.used)) { io.cpu.writeBack.haltIt.clearWhen(!(victim.requestIn.valid && !victim.requestIn.ready)) victim.requestIn.valid := request.clean && way.tagReadRspTwo.dirty @@ -708,7 +708,7 @@ class DataCache(p : DataCacheConfig) extends Component{ val unaligned = if(catchUnaligned) ((request.size === 2 && mmuRsp.physicalAddress(1 downto 0) =/= 0) || (request.size === 1 && mmuRsp.physicalAddress(0 downto 0) =/= 0)) else False io.cpu.writeBack.illegalAccess := illegal io.cpu.writeBack.unalignedAccess := unaligned - when((Bool(!catchMemoryTranslationMiss) || !mmuRsp.miss) && !illegal && !unaligned) { + when((Bool(!catchMemoryTranslationMiss) || ???) && !illegal && !unaligned) { //TODO !mmuRsp.miss when(request.forceUncachedAccess || mmuRsp.isIoAccess) { val memCmdSent = RegInit(False) when(!victim.request.valid) { diff --git a/src/main/scala/vexriscv/ip/InstructionCache.scala b/src/main/scala/vexriscv/ip/InstructionCache.scala index 26d1caa5..e7afa73d 100644 --- a/src/main/scala/vexriscv/ip/InstructionCache.scala +++ b/src/main/scala/vexriscv/ip/InstructionCache.scala @@ -411,7 +411,7 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{ io.cpu.fetch.cacheMiss := !hit.valid io.cpu.fetch.error := hit.error - io.cpu.fetch.mmuMiss := mmuRsp.miss + io.cpu.fetch.mmuMiss := ??? //TODO mmuRsp.miss io.cpu.fetch.illegalAccess := !mmuRsp.allowExecute || (io.cpu.fetch.isUser && !mmuRsp.allowUser) }) } @@ -441,7 +441,7 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{ io.cpu.decode.cacheMiss := !hit.valid io.cpu.decode.error := hit.error - io.cpu.decode.mmuMiss := mmuRsp.miss + io.cpu.decode.mmuMiss := ??? //TODO mmuRsp.miss io.cpu.decode.illegalAccess := !mmuRsp.allowExecute || (io.cpu.decode.isUser && !mmuRsp.allowUser) io.cpu.decode.physicalAddress := mmuRsp.physicalAddress }) diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index 752552a6..8a9d3fd2 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -173,7 +173,7 @@ class DBusCachedPlugin(config : DataCacheConfig, arbitration.haltItself setWhen(cache.io.cpu.memory.haltIt) cache.io.cpu.memory.mmuBus <> mmuBus - arbitration.haltItself setWhen (mmuBus.cmd.isValid && !mmuBus.rsp.hit && !mmuBus.rsp.miss) + arbitration.haltItself setWhen (mmuBus.cmd.isValid && ???) //TODO !mmuBus.rsp.hit && !mmuBus.rsp.miss } writeBack plug new Area{ diff --git a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala index eb4ce468..ed3a1b9c 100644 --- a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala @@ -9,6 +9,8 @@ import spinal.lib.bus.wishbone.{Wishbone, WishboneConfig} import spinal.lib.bus.simple._ import vexriscv.ip.DataCacheMemCmd +import scala.collection.mutable.ArrayBuffer + case class DBusSimpleCmd() extends Bundle{ val wr = Bool @@ -202,7 +204,8 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, catchAccessFault : Boolean = false, earlyInjection : Boolean = false, /*, idempotentRegions : (UInt) => Bool = (x) => False*/ emitCmdInMemoryStage : Boolean = false, - onlyLoadWords : Boolean = false) extends Plugin[VexRiscv]{ + onlyLoadWords : Boolean = false, + memoryTranslatorPortConfig : Any = null) extends Plugin[VexRiscv] with DBusAccessService { var dBus : DBusSimpleBus = null assert(!(emitCmdInMemoryStage && earlyInjection)) @@ -211,9 +214,20 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, object MEMORY_READ_DATA extends Stageable(Bits(32 bits)) object MEMORY_ADDRESS_LOW extends Stageable(UInt(2 bits)) object ALIGNEMENT_FAULT extends Stageable(Bool) + object MMU_RSP extends Stageable(MemoryTranslatorRsp()) var memoryExceptionPort : Flow[ExceptionCause] = null var rspStage : Stage = null + var mmuBus : MemoryTranslatorBus = null + var redoBranch : Flow[UInt] = null + val catchSomething = catchAccessFault || catchAddressMisaligned || memoryTranslatorPortConfig != null + + var dBusAccess : DBusAccess = null + override def newDBusAccess(): DBusAccess = { + assert(dBusAccess == null) + dBusAccess = DBusAccess() + dBusAccess + } override def setup(pipeline: VexRiscv): Unit = { import Riscv._ @@ -250,10 +264,15 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, rspStage = if(stages.last == execute) execute else (if(emitCmdInMemoryStage) writeBack else memory) - if(catchAccessFault || catchAddressMisaligned) { + if(catchSomething) { val exceptionService = pipeline.service(classOf[ExceptionService]) memoryExceptionPort = exceptionService.newExceptionPort(rspStage) } + + if(memoryTranslatorPortConfig != null) { + mmuBus = pipeline.service(classOf[MemoryTranslator]).newTranslationPort(MemoryTranslatorPort.PRIORITY_INSTRUCTION, memoryTranslatorPortConfig) + redoBranch = pipeline.service(classOf[JumpService]).createJumpInterface(pipeline.memory) + } } override def build(pipeline: VexRiscv): Unit = { @@ -262,7 +281,6 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, dBus = master(DBusSimpleBus()).setName("dBus") - //Emit dBus.cmd request val cmdStage = if(emitCmdInMemoryStage) memory else execute cmdStage plug new Area{ @@ -279,7 +297,6 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, dBus.cmd.valid := arbitration.isValid && input(MEMORY_ENABLE) && !arbitration.isStuckByOthers && !arbitration.isFlushed && !input(ALIGNEMENT_FAULT) && !cmdSent dBus.cmd.wr := input(INSTRUCTION)(5) - dBus.cmd.address := input(SRC_ADD).asUInt dBus.cmd.size := input(INSTRUCTION)(13 downto 12).asUInt dBus.cmd.payload.data := dBus.cmd.size.mux ( U(0) -> input(RS2)(7 downto 0) ## input(RS2)(7 downto 0) ## input(RS2)(7 downto 0) ## input(RS2)(7 downto 0), @@ -302,6 +319,25 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, insert(FORMAL_MEM_WMASK) := (dBus.cmd.valid && dBus.cmd.wr) ? formalMask | B"0000" insert(FORMAL_MEM_RMASK) := (dBus.cmd.valid && !dBus.cmd.wr) ? formalMask | B"0000" insert(FORMAL_MEM_WDATA) := dBus.cmd.payload.data + + val mmu = (mmuBus != null) generate new Area { + mmuBus.cmd.isValid := arbitration.isValid && input(MEMORY_ENABLE) + mmuBus.cmd.virtualAddress := input(SRC_ADD).asUInt + mmuBus.cmd.bypassTranslation := False + dBus.cmd.address := mmuBus.rsp.physicalAddress + + //do not emit memory request if MMU miss + when(mmuBus.cmd.isValid && (mmuBus.rsp.exception || mmuBus.rsp.refilling)){ + dBus.cmd.valid := False + arbitration.haltItself := False + } + + insert(MMU_RSP) := mmuBus.rsp + } + + val mmuLess = (mmuBus == null) generate new Area{ + dBus.cmd.address := input(SRC_ADD).asUInt + } } //Collect dBus.rsp read responses @@ -312,26 +348,38 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, insert(MEMORY_READ_DATA) := dBus.rsp.data arbitration.haltItself setWhen(arbitration.isValid && input(MEMORY_ENABLE) && !input(INSTRUCTION)(5) && !dBus.rsp.ready) - if(catchAccessFault || catchAddressMisaligned){ - if(!catchAccessFault){ - memoryExceptionPort.code := (input(INSTRUCTION)(5) ? U(6) | U(4)).resized - memoryExceptionPort.valid := input(ALIGNEMENT_FAULT) - } else if(!catchAddressMisaligned){ - memoryExceptionPort.valid := dBus.rsp.ready && dBus.rsp.error && !input(INSTRUCTION)(5) - memoryExceptionPort.code := 5 - } else { - memoryExceptionPort.valid := dBus.rsp.ready && dBus.rsp.error && !input(INSTRUCTION)(5) - memoryExceptionPort.code := 5 - when(input(ALIGNEMENT_FAULT)){ - memoryExceptionPort.code := (input(INSTRUCTION)(5) ? U(6) | U(4)).resized - memoryExceptionPort.valid := True - } - } - when(!(arbitration.isValid && input(MEMORY_ENABLE) && (if(cmdStage == rspStage) !arbitration.isStuckByOthers else True))){ - memoryExceptionPort.valid := False + if(catchSomething) { + memoryExceptionPort.valid := False + memoryExceptionPort.code.assignDontCare() + memoryExceptionPort.badAddr := input(REGFILE_WRITE_DATA).asUInt + + if(catchAccessFault) when(dBus.rsp.ready && dBus.rsp.error && !input(INSTRUCTION)(5)) { + memoryExceptionPort.valid := True + memoryExceptionPort.code := 5 } - memoryExceptionPort.badAddr := input(REGFILE_WRITE_DATA).asUInt //Drived by IntAluPlugin + if(catchAddressMisaligned) when(input(ALIGNEMENT_FAULT)){ + memoryExceptionPort.code := (input(INSTRUCTION)(5) ? U(6) | U(4)).resized + memoryExceptionPort.valid := True + } + + if(memoryTranslatorPortConfig != null) { + redoBranch.valid := False + redoBranch.payload := input(PC) + + when(input(MMU_RSP).refilling){ + redoBranch.valid := True + memoryExceptionPort.valid := False + } elsewhen(input(MMU_RSP).exception) { + memoryExceptionPort.valid := True + memoryExceptionPort.code := (input(INSTRUCTION)(5) ? U(15) | U(13)).resized + } + } + + when(!(arbitration.isValid && input(MEMORY_ENABLE) && (Bool(cmdStage != rspStage) || !arbitration.isStuckByOthers))){ + memoryExceptionPort.valid := False + redoBranch.valid := False + } } @@ -368,5 +416,42 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, //formal insert(FORMAL_MEM_RDATA) := input(MEMORY_READ_DATA) } + + //Share access to the dBus (used by self refilled MMU) + val dBusSharing = (dBusAccess != null) generate new Area{ + val state = Reg(UInt(2 bits)) init(0) + dBusAccess.rsp.valid := False + dBusAccess.rsp.data := dBus.rsp.data + dBusAccess.rsp.error := dBus.rsp.error + + switch(state){ + is(0){ + when(dBusAccess.cmd.valid){ + decode.arbitration.haltItself := True + when(!stages.dropWhile(_ != execute).map(_.arbitration.isValid).orR){ + state := 1 + } + } + } + is(1){ + decode.arbitration.haltItself := True + dBus.cmd.valid := True + dBus.cmd.address := dBusAccess.cmd.address + dBus.cmd.wr := dBusAccess.cmd.write + dBus.cmd.data := dBusAccess.cmd.data + dBus.cmd.size := dBusAccess.cmd.size + when(dBus.cmd.ready){ + state := (dBusAccess.cmd.write ? U(0) | U(2)) + } + } + is(2){ + decode.arbitration.haltItself := True + when(dBus.rsp.ready){ + dBusAccess.rsp.valid := True + state := 0 + } + } + } + } } } diff --git a/src/main/scala/vexriscv/plugin/Fetcher.scala b/src/main/scala/vexriscv/plugin/Fetcher.scala index 27a22e0c..a6c166a9 100644 --- a/src/main/scala/vexriscv/plugin/Fetcher.scala +++ b/src/main/scala/vexriscv/plugin/Fetcher.scala @@ -605,5 +605,11 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, }) } } + + def stageXToIBusRsp[T <: Data](stage : Any, input : T): (T) ={ + iBusRsp.stages.dropWhile(_ != stage).foldLeft(input)((data,stage) => RegNextWhen(data, stage.output.ready)) + + } + } } \ No newline at end of file diff --git a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala index 03285f0f..027a0151 100644 --- a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala @@ -223,7 +223,7 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l, if (mmuBus != null) { cache.io.cpu.fetch.mmuBus <> mmuBus - (if (twoCycleCache) stages(1).halt else rsp.iBusRspOutputHalt) setWhen (mmuBus.cmd.isValid && !mmuBus.rsp.hit && !mmuBus.rsp.miss) + (if (twoCycleCache) stages(1).halt else rsp.iBusRspOutputHalt) setWhen (mmuBus.cmd.isValid && ???) //TODO !mmuBus.rsp.hit && !mmuBus.rsp.miss } else { cache.io.cpu.fetch.mmuBus.rsp.physicalAddress := cache.io.cpu.fetch.mmuBus.cmd.virtualAddress cache.io.cpu.fetch.mmuBus.rsp.allowExecute := True @@ -231,8 +231,9 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l, 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 - cache.io.cpu.fetch.mmuBus.rsp.hit := False + ??? //TODO +// cache.io.cpu.fetch.mmuBus.rsp.miss := False +// cache.io.cpu.fetch.mmuBus.rsp.hit := False } val flushStage = if(memory != null) memory else execute diff --git a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala index 636b1930..cc0a66d3 100644 --- a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala @@ -166,7 +166,8 @@ class IBusSimplePlugin(resetVector : BigInt, pendingMax : Int = 7, injectorStage : Boolean = true, rspHoldValue : Boolean = false, - singleInstructionPipeline : Boolean = false + singleInstructionPipeline : Boolean = false, + memoryTranslatorPortConfig : Any = null ) extends IBusFetcherImpl( resetVector = resetVector, keepPcPlus4 = keepPcPlus4, @@ -181,15 +182,23 @@ class IBusSimplePlugin(resetVector : BigInt, var iBus : IBusSimpleBus = null var decodeExceptionPort : Flow[ExceptionCause] = null + val catchSomething = memoryTranslatorPortConfig != null || catchAccessFault + var mmuBus : MemoryTranslatorBus = null + var redoBranch : Flow[UInt] = null + if(rspHoldValue) assert(busLatencyMin <= 1) override def setup(pipeline: VexRiscv): Unit = { super.setup(pipeline) iBus = master(IBusSimpleBus(false)).setName("iBus") - if(catchAccessFault) { - val exceptionService = pipeline.service(classOf[ExceptionService]) - decodeExceptionPort = exceptionService.newExceptionPort(pipeline.decode,1) + if(catchSomething) { + decodeExceptionPort = pipeline.service(classOf[ExceptionService]).newExceptionPort(pipeline.decode,1) + } + + if(memoryTranslatorPortConfig != null) { + mmuBus = pipeline.service(classOf[MemoryTranslator]).newTranslationPort(MemoryTranslatorPort.PRIORITY_INSTRUCTION, memoryTranslatorPortConfig) + redoBranch = pipeline.service(classOf[JumpService]).createJumpInterface(pipeline.decode, priority = 1) //Priority 1 will win against branch predictor } } @@ -206,9 +215,12 @@ class IBusSimplePlugin(resetVector : BigInt, val pendingCmdNext = pendingCmd + cmd.fire.asUInt - iBus.rsp.fire.asUInt pendingCmd := pendingCmdNext + def cmdForkStage = if(!cmdForkPersistence || !cmdForkOnSecondStage) iBusRsp.stages(if(cmdForkOnSecondStage) 1 else 0) else iBusRsp.stages(1) + + val cmdFork = if(!cmdForkPersistence || !cmdForkOnSecondStage) new Area { //This implementation keep the cmd on the bus until it's executed or the the pipeline is flushed - def stage = iBusRsp.stages(if(cmdForkOnSecondStage) 1 else 0) + def stage = cmdForkStage stage.halt setWhen(stage.input.valid && (!cmd.valid || !cmd.ready)) if(singleInstructionPipeline) { cmd.valid := stage.input.valid && pendingCmd =/= pendingMax && !stages.map(_.arbitration.isValid).orR @@ -217,16 +229,33 @@ class IBusSimplePlugin(resetVector : BigInt, }else { cmd.valid := stage.input.valid && stage.output.ready && pendingCmd =/= pendingMax } - cmd.pc := stage.input.payload(31 downto 2) @@ "00" } else new Area{ //This implementation keep the cmd on the bus until it's executed, even if the pipeline is flushed - def stage = iBusRsp.stages(1) + def stage = cmdForkStage val pendingFull = pendingCmd === pendingMax val cmdKeep = RegInit(False) setWhen(cmd.valid) clearWhen(cmd.ready) val cmdFired = RegInit(False) setWhen(cmd.fire) clearWhen(stage.input.ready) stage.halt setWhen(cmd.isStall || (pendingFull && !cmdFired)) cmd.valid := (stage.input.valid || cmdKeep) && !pendingFull && !cmdFired - cmd.pc := stage.input.payload(31 downto 2) @@ "00" + } + + val mmu = (mmuBus != null) generate new Area { + mmuBus.cmd.isValid := cmdForkStage.input.valid + mmuBus.cmd.virtualAddress := cmdForkStage.input.payload + mmuBus.cmd.bypassTranslation := False + cmd.pc := mmuBus.rsp.physicalAddress(31 downto 2) @@ "00" + + //do not emit memory request if MMU miss + when(mmuBus.rsp.exception || mmuBus.rsp.refilling){ + cmdForkStage.halt := False + cmd.valid := False + } + + val joinCtx = stageXToIBusRsp(cmdForkStage, mmuBus.rsp) + } + + val mmuLess = (mmuBus == null) generate new Area{ + cmd.pc := cmdForkStage.input.payload(31 downto 2) @@ "00" } val rspJoin = new Area { @@ -261,22 +290,35 @@ class IBusSimplePlugin(resetVector : BigInt, fetchRsp.rsp.error.clearWhen(!rspBufferOutput.valid) //Avoid interference with instruction injection from the debug plugin - var issueDetected = False val join = Stream(FetchRsp()) + val exceptionDetected = False + val redoRequired = False join.valid := stages.last.output.valid && rspBufferOutput.valid join.payload := fetchRsp stages.last.output.ready := stages.last.output.valid ? join.fire | join.ready rspBufferOutput.ready := join.fire - output << join.haltWhen(issueDetected) + output << join.haltWhen(exceptionDetected || redoRequired) - if(catchAccessFault){ + if(memoryTranslatorPortConfig != null){ + redoRequired setWhen( stages.last.input.valid && mmu.joinCtx.refilling) + redoBranch.valid := redoRequired && iBusRsp.readyForError + redoBranch.payload := stages.last.input.payload + } + + if(catchSomething){ decodeExceptionPort.valid := False - decodeExceptionPort.code := 1 - decodeExceptionPort.badAddr := join.pc - when(join.valid && join.rsp.error && !issueDetected){ - issueDetected \= True - decodeExceptionPort.valid := iBusRsp.readyForError + decodeExceptionPort.code.assignDontCare() + decodeExceptionPort.badAddr := join.pc //TODO Should it be the physical address insted ? + + if(catchAccessFault) when(join.valid && join.rsp.error){ + decodeExceptionPort.code := 1 + exceptionDetected := True } + if(memoryTranslatorPortConfig != null) when(stages.last.input.valid && mmu.joinCtx.exception){ + decodeExceptionPort.code := 12 + exceptionDetected := True + } + decodeExceptionPort.valid := exceptionDetected && iBusRsp.readyForError } } } diff --git a/src/main/scala/vexriscv/plugin/MemoryTranslatorPlugin.scala b/src/main/scala/vexriscv/plugin/MemoryTranslatorPlugin.scala index db310223..c5da539a 100644 --- a/src/main/scala/vexriscv/plugin/MemoryTranslatorPlugin.scala +++ b/src/main/scala/vexriscv/plugin/MemoryTranslatorPlugin.scala @@ -113,7 +113,8 @@ class MemoryTranslatorPlugin(tlbSize : Int, port.bus.rsp.allowWrite := cacheLine.allowWrite port.bus.rsp.allowExecute := cacheLine.allowExecute port.bus.rsp.allowUser := cacheLine.allowUser - port.bus.rsp.hit := cacheHit + ??? +// port.bus.rsp.hit := cacheHit // port.stage.arbitration.haltItself setWhen (port.bus.cmd.isValid && !cacheHit && !sharedMiss) } otherwise { port.bus.rsp.physicalAddress := port.bus.cmd.virtualAddress @@ -121,10 +122,12 @@ class MemoryTranslatorPlugin(tlbSize : Int, port.bus.rsp.allowWrite := True port.bus.rsp.allowExecute := True port.bus.rsp.allowUser := True - port.bus.rsp.hit := True + ??? +// port.bus.rsp.hit := True } port.bus.rsp.isIoAccess := ioRange(port.bus.rsp.physicalAddress) - port.bus.rsp.miss := sharedMiss + ??? +// port.bus.rsp.miss := sharedMiss } } diff --git a/src/main/scala/vexriscv/plugin/MmuPlugin.scala b/src/main/scala/vexriscv/plugin/MmuPlugin.scala index 42a99cc6..bbd206d1 100644 --- a/src/main/scala/vexriscv/plugin/MmuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/MmuPlugin.scala @@ -6,11 +6,15 @@ import spinal.lib._ import scala.collection.mutable.ArrayBuffer +trait DBusAccessService{ + def newDBusAccess() : DBusAccess +} + case class DBusAccessCmd() extends Bundle { val address = UInt(32 bits) val size = UInt(2 bits) val write = Bool - val writeData = Bits(32 bits) + val data = Bits(32 bits) val writeMask = Bits(4 bits) } @@ -56,7 +60,7 @@ class MmuPlugin(virtualRange : UInt => Bool, decoderService.add(SFENCE_VMA, List(IS_SFENCE_VMA -> True)) - dBus = ??? + dBus = pipeline.service(classOf[DBusAccessService]).newDBusAccess() } override def build(pipeline: VexRiscv): Unit = { @@ -81,7 +85,7 @@ class MmuPlugin(virtualRange : UInt => Bool, } val core = pipeline plug new Area { - val ports = for (port <- sortedPortsInfo yield new Area { + val ports = for (port <- sortedPortsInfo) yield new Area { val id = port.id val cache = Vec(Reg(CacheLine()) init, port.args.portTlbSize) val cacheHits = cache.map(line => line.valid && line.virtualAddress === port.bus.cmd.virtualAddress(31 downto 12)) @@ -144,7 +148,7 @@ class MmuPlugin(virtualRange : UInt => Bool, dBus.cmd.write := False dBus.cmd.size := 2 dBus.cmd.address.assignDontCare() - dBus.cmd.writeData.assignDontCare() + dBus.cmd.data.assignDontCare() dBus.cmd.writeMask.assignDontCare() switch(state){ is(State.IDLE){ diff --git a/src/main/scala/vexriscv/plugin/StaticMemoryTranslatorPlugin.scala b/src/main/scala/vexriscv/plugin/StaticMemoryTranslatorPlugin.scala index 71d23121..d190ef07 100644 --- a/src/main/scala/vexriscv/plugin/StaticMemoryTranslatorPlugin.scala +++ b/src/main/scala/vexriscv/plugin/StaticMemoryTranslatorPlugin.scala @@ -33,8 +33,9 @@ class StaticMemoryTranslatorPlugin(ioRange : UInt => Bool) extends Plugin[VexRis port.bus.rsp.allowExecute := True port.bus.rsp.allowUser := True port.bus.rsp.isIoAccess := ioRange(port.bus.rsp.physicalAddress) - port.bus.rsp.miss := False - port.bus.rsp.hit := True + ??? +// port.bus.rsp.miss := False +// port.bus.rsp.hit := True } } } From 001ca45c57b8e0719c3d7fe7299efe1cd5ee05c6 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 18 Mar 2019 12:52:22 +0100 Subject: [PATCH 039/951] Add cachless dBus IBus access right checks --- .../vexriscv/plugin/DBusSimplePlugin.scala | 20 +++++++++++-------- .../vexriscv/plugin/IBusSimplePlugin.scala | 9 ++++++--- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala index ed3a1b9c..a5a91aef 100644 --- a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala @@ -214,6 +214,7 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, object MEMORY_READ_DATA extends Stageable(Bits(32 bits)) object MEMORY_ADDRESS_LOW extends Stageable(UInt(2 bits)) object ALIGNEMENT_FAULT extends Stageable(Bool) + object MMU_FAULT extends Stageable(Bool) object MMU_RSP extends Stageable(MemoryTranslatorRsp()) var memoryExceptionPort : Flow[ExceptionCause] = null @@ -285,6 +286,7 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, val cmdStage = if(emitCmdInMemoryStage) memory else execute cmdStage plug new Area{ import cmdStage._ + val privilegeService = pipeline.serviceElse(classOf[PrivilegeService], PrivilegeServiceDefault()) val cmdSent = if(rspStage == execute) RegInit(False) setWhen(dBus.cmd.fire) clearWhen(!execute.arbitration.isStuck) else False @@ -295,7 +297,11 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, False } - dBus.cmd.valid := arbitration.isValid && input(MEMORY_ENABLE) && !arbitration.isStuckByOthers && !arbitration.isFlushed && !input(ALIGNEMENT_FAULT) && !cmdSent + + val skipCmd = False + skipCmd setWhen(input(ALIGNEMENT_FAULT)) + + dBus.cmd.valid := arbitration.isValid && input(MEMORY_ENABLE) && !arbitration.isStuckByOthers && !arbitration.isFlushed && !skipCmd && !cmdSent dBus.cmd.wr := input(INSTRUCTION)(5) dBus.cmd.size := input(INSTRUCTION)(13 downto 12).asUInt dBus.cmd.payload.data := dBus.cmd.size.mux ( @@ -303,7 +309,7 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, U(1) -> input(RS2)(15 downto 0) ## input(RS2)(15 downto 0), default -> input(RS2)(31 downto 0) ) - when(arbitration.isValid && input(MEMORY_ENABLE) && !dBus.cmd.ready && !input(ALIGNEMENT_FAULT) && !cmdSent){ + when(arbitration.isValid && input(MEMORY_ENABLE) && !dBus.cmd.ready && !skipCmd && !cmdSent){ arbitration.haltItself := True } @@ -326,11 +332,9 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, mmuBus.cmd.bypassTranslation := False dBus.cmd.address := mmuBus.rsp.physicalAddress - //do not emit memory request if MMU miss - when(mmuBus.cmd.isValid && (mmuBus.rsp.exception || mmuBus.rsp.refilling)){ - dBus.cmd.valid := False - arbitration.haltItself := False - } + //do not emit memory request if MMU refilling + insert(MMU_FAULT) := input(MMU_RSP).exception || (!input(MMU_RSP).allowWrite && input(INSTRUCTION)(5)) || (!input(MMU_RSP).allowRead && !input(INSTRUCTION)(5)) || (!input(MMU_RSP).allowUser && privilegeService.isUser(memory)) + skipCmd.setWhen(input(MMU_FAULT) || input(MMU_RSP).refilling) insert(MMU_RSP) := mmuBus.rsp } @@ -370,7 +374,7 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, when(input(MMU_RSP).refilling){ redoBranch.valid := True memoryExceptionPort.valid := False - } elsewhen(input(MMU_RSP).exception) { + } elsewhen(input(MMU_FAULT)) { memoryExceptionPort.valid := True memoryExceptionPort.code := (input(INSTRUCTION)(5) ? U(15) | U(13)).resized } diff --git a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala index cc0a66d3..845fca36 100644 --- a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala @@ -314,9 +314,12 @@ class IBusSimplePlugin(resetVector : BigInt, decodeExceptionPort.code := 1 exceptionDetected := True } - if(memoryTranslatorPortConfig != null) when(stages.last.input.valid && mmu.joinCtx.exception){ - decodeExceptionPort.code := 12 - exceptionDetected := True + if(memoryTranslatorPortConfig != null) { + val privilegeService = pipeline.serviceElse(classOf[PrivilegeService], PrivilegeServiceDefault()) + when(stages.last.input.valid && (mmu.joinCtx.exception || !mmu.joinCtx.allowExecute || (!mmu.joinCtx.allowUser && privilegeService.isUser(decode)))){ + decodeExceptionPort.code := 12 + exceptionDetected := True + } } decodeExceptionPort.valid := exceptionDetected && iBusRsp.readyForError } From 915db9d6c96647f9a0cc4c4510053554a27c08a7 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 18 Mar 2019 20:50:19 +0100 Subject: [PATCH 040/951] cleaning --- src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala index a5a91aef..701bbfb1 100644 --- a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala @@ -290,12 +290,10 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, val cmdSent = if(rspStage == execute) RegInit(False) setWhen(dBus.cmd.fire) clearWhen(!execute.arbitration.isStuck) else False - insert(ALIGNEMENT_FAULT) := { - if (catchAddressMisaligned) - (dBus.cmd.size === 2 && dBus.cmd.address(1 downto 0) =/= 0) || (dBus.cmd.size === 1 && dBus.cmd.address(0 downto 0) =/= 0) - else - False - } + if (catchAddressMisaligned) + insert(ALIGNEMENT_FAULT) := (dBus.cmd.size === 2 && dBus.cmd.address(1 downto 0) =/= 0) || (dBus.cmd.size === 1 && dBus.cmd.address(0 downto 0) =/= 0) + else + insert(ALIGNEMENT_FAULT) := False val skipCmd = False @@ -321,6 +319,7 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, U(1) -> B"0011", default -> B"1111" ) |<< dBus.cmd.address(1 downto 0) + insert(FORMAL_MEM_ADDR) := dBus.cmd.address & U"xFFFFFFFC" insert(FORMAL_MEM_WMASK) := (dBus.cmd.valid && dBus.cmd.wr) ? formalMask | B"0000" insert(FORMAL_MEM_RMASK) := (dBus.cmd.valid && !dBus.cmd.wr) ? formalMask | B"0000" From 3fbc2f44581563c9addd8bda1a402aa4c92c2316 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 19 Mar 2019 20:29:28 +0100 Subject: [PATCH 041/951] Fix generation --- src/main/scala/vexriscv/demo/Linux.scala | 396 ++++++++++++++++++ .../vexriscv/plugin/DBusSimplePlugin.scala | 6 +- .../vexriscv/plugin/IBusSimplePlugin.scala | 1 - .../scala/vexriscv/plugin/MmuPlugin.scala | 7 +- src/test/cpp/regression/main.cpp | 10 +- src/test/cpp/regression/makefile | 2 +- 6 files changed, 412 insertions(+), 10 deletions(-) create mode 100644 src/main/scala/vexriscv/demo/Linux.scala diff --git a/src/main/scala/vexriscv/demo/Linux.scala b/src/main/scala/vexriscv/demo/Linux.scala new file mode 100644 index 00000000..0c8979ac --- /dev/null +++ b/src/main/scala/vexriscv/demo/Linux.scala @@ -0,0 +1,396 @@ +/* + * SpinalHDL + * Copyright (c) Dolu, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ + +package vexriscv.demo + +import spinal.core._ +import spinal.lib.eda.bench.{AlteraStdTargets, Bench, Rtl, XilinxStdTargets} +import spinal.lib.eda.icestorm.IcestormStdTargets +import spinal.lib.master +import vexriscv._ +import vexriscv.ip._ +import vexriscv.plugin._ + +object LinuxGen { + def configFull(withMmu : Boolean = true) = { + val config = VexRiscvConfig( + plugins = List( + new IBusSimplePlugin( + resetVector = 0x80000000l, + cmdForkOnSecondStage = false, + cmdForkPersistence = false, + prediction = NONE, + historyRamSizeLog2 = 10, + catchAccessFault = true, + compressedGen = false, + busLatencyMin = 1, + injectorStage = true, + memoryTranslatorPortConfig = withMmu generate MmuPortConfig( + portTlbSize = 4 + ) + ), + // new IBusCachedPlugin( + // resetVector = 0x80000000l, + // compressedGen = false, + // prediction = NONE, + // injectorStage = true, + // config = InstructionCacheConfig( + // cacheSize = 4096, + // bytePerLine = 32, + // wayCount = 1, + // addressWidth = 32, + // cpuDataWidth = 32, + // memDataWidth = 32, + // catchIllegalAccess = true, + // catchAccessFault = true, + // catchMemoryTranslationMiss = true, + // asyncTagMemory = false, + // twoCycleRam = false, + // twoCycleCache = true + // ), + // memoryTranslatorPortConfig = MemoryTranslatorPortConfig( + // portTlbSize = 4 + // ) + // ), + // ).newTightlyCoupledPort(TightlyCoupledPortParameter("iBusTc", a => a(30 downto 28) === 0x0 && a(5))), + new DBusSimplePlugin( + catchAddressMisaligned = true, + catchAccessFault = true, + earlyInjection = false, + memoryTranslatorPortConfig = withMmu generate MmuPortConfig( + portTlbSize = 4 + ) + ), + // new DBusCachedPlugin( + // config = new DataCacheConfig( + // cacheSize = 4096, + // bytePerLine = 32, + // wayCount = 1, + // addressWidth = 32, + // cpuDataWidth = 32, + // memDataWidth = 32, + // catchAccessError = true, + // catchIllegal = true, + // catchUnaligned = true, + // catchMemoryTranslationMiss = true, + // atomicEntriesCount = 2 + // ), + // // memoryTranslatorPortConfig = null + // memoryTranslatorPortConfig = MemoryTranslatorPortConfig( + // portTlbSize = 6 + // ) + // ), + // new StaticMemoryTranslatorPlugin( + // ioRange = _(31 downto 28) === 0xF + // ), + // new MemoryTranslatorPlugin( + // tlbSize = 32, + // virtualRange = _(31 downto 28) === 0xC, + // ioRange = _(31 downto 28) === 0xF + // ), + + new DecoderSimplePlugin( + catchIllegalInstruction = true + ), + new RegFilePlugin( + regFileReadyKind = plugin.ASYNC, + zeroBoot = true + ), + new IntAluPlugin, + new SrcPlugin( + separatedAddSub = false + ), + new FullBarrelShifterPlugin(earlyInjection = true), + // new LightShifterPlugin, + new HazardSimplePlugin( + bypassExecute = true, + bypassMemory = true, + bypassWriteBack = true, + bypassWriteBackBuffer = true, + pessimisticUseSrc = false, + pessimisticWriteRegFile = false, + pessimisticAddressMatch = false + ), + // new HazardSimplePlugin(false, true, false, true), + // new HazardSimplePlugin(false, false, false, false), + new MulPlugin, + new MulDivIterativePlugin( + genMul = false, + genDiv = true, + mulUnrollFactor = 32, + divUnrollFactor = 1 + ), + // new DivPlugin, + new CsrPlugin(CsrPluginConfig.all(0x80000020l)), + // new CsrPlugin(//CsrPluginConfig.all2(0x80000020l).copy(ebreakGen = true)/* + // CsrPluginConfig( + // catchIllegalAccess = false, + // mvendorid = null, + // marchid = null, + // mimpid = null, + // mhartid = null, + // misaExtensionsInit = 0, + // misaAccess = CsrAccess.READ_ONLY, + // mtvecAccess = CsrAccess.WRITE_ONLY, + // mtvecInit = 0x80000020l, + // mepcAccess = CsrAccess.READ_WRITE, + // mscratchGen = true, + // mcauseAccess = CsrAccess.READ_ONLY, + // mbadaddrAccess = CsrAccess.READ_ONLY, + // mcycleAccess = CsrAccess.NONE, + // minstretAccess = CsrAccess.NONE, + // ecallGen = true, + // ebreakGen = true, + // wfiGenAsWait = false, + // wfiGenAsNop = true, + // ucycleAccess = CsrAccess.NONE + // )), + new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))), + new BranchPlugin( + earlyBranch = true, + catchAddressMisaligned = true, + fenceiGenAsAJump = true + ), + new YamlPlugin("cpu0.yaml") + ) + ) + if(withMmu) config.plugins += new MmuPlugin( + virtualRange = _(31 downto 28) === 0xC, + ioRange = _(31 downto 28) === 0xF, + allowUserIo = true + ) + config + } + def main(args: Array[String]) { + + + +// import spinal.core.sim._ +// SimConfig.withConfig(SpinalConfig(mergeAsyncProcess = false, anonymSignalPrefix = "zz_")).allOptimisation.compile(new VexRiscv(configFull)).doSimUntilVoid{ dut => +// dut.clockDomain.forkStimulus(10) +// dut.clockDomain.forkSimSpeedPrinter(4) +// var iBus : InstructionCacheMemBus = null +// +// dut.plugins.foreach{ +// case plugin: IBusCachedPlugin => iBus = plugin.iBus +// case _ => +// } +// dut.clockDomain.onSamplings{ +//// iBus.cmd.ready.randomize() +// iBus.rsp.data #= 0x13 +// } +// } + + SpinalConfig(mergeAsyncProcess = true).generateVerilog { + + + val toplevel = new VexRiscv(configFull()) +// val toplevel = new VexRiscv(configLight) +// val toplevel = new VexRiscv(configTest) + + /*toplevel.rework { + var iBus : AvalonMM = null + for (plugin <- toplevel.config.plugins) plugin match { + case plugin: IBusSimplePlugin => { + plugin.iBus.asDirectionLess() //Unset IO properties of iBus + iBus = master(plugin.iBus.toAvalon()) + .setName("iBusAvalon") + .addTag(ClockDomainTag(ClockDomain.current)) //Specify a clock domain to the iBus (used by QSysify) + } + case plugin: IBusCachedPlugin => { + plugin.iBus.asDirectionLess() //Unset IO properties of iBus + iBus = master(plugin.iBus.toAvalon()) + .setName("iBusAvalon") + .addTag(ClockDomainTag(ClockDomain.current)) //Specify a clock domain to the iBus (used by QSysify) + } + case plugin: DBusSimplePlugin => { + plugin.dBus.asDirectionLess() + master(plugin.dBus.toAvalon()) + .setName("dBusAvalon") + .addTag(ClockDomainTag(ClockDomain.current)) + } + case plugin: DBusCachedPlugin => { + plugin.dBus.asDirectionLess() + master(plugin.dBus.toAvalon()) + .setName("dBusAvalon") + .addTag(ClockDomainTag(ClockDomain.current)) + } + case plugin: DebugPlugin => { + plugin.io.bus.asDirectionLess() + slave(plugin.io.bus.fromAvalon()) + .setName("debugBusAvalon") + .addTag(ClockDomainTag(plugin.debugClockDomain)) + .parent = null //Avoid the io bundle to be interpreted as a QSys conduit + plugin.io.resetOut + .addTag(ResetEmitterTag(plugin.debugClockDomain)) + .parent = null //Avoid the io bundle to be interpreted as a QSys conduit + } + case _ => + } + for (plugin <- toplevel.config.plugins) plugin match { + case plugin: CsrPlugin => { + plugin.externalInterrupt + .addTag(InterruptReceiverTag(iBus, ClockDomain.current)) + plugin.timerInterrupt + .addTag(InterruptReceiverTag(iBus, ClockDomain.current)) + } + case _ => + } + }*/ +// toplevel.writeBack.input(config.PC).addAttribute(Verilator.public) +// toplevel.service(classOf[DecoderSimplePlugin]).bench(toplevel) + // toplevel.children.find(_.isInstanceOf[DataCache]).get.asInstanceOf[DataCache].io.cpu.execute.addAttribute(Verilator.public) + + +// toplevel.rework { +// for (plugin <- toplevel.config.plugins) plugin match { +// case plugin: IBusSimplePlugin => { +// plugin.iBus.setAsDirectionLess().unsetName() //Unset IO properties of iBus +// val iBus = master(IBusSimpleBus()).setName("iBus") +// +// iBus.cmd << plugin.iBus.cmd.halfPipe() +// iBus.rsp.stage >> plugin.iBus.rsp +// } +// case plugin: DBusSimplePlugin => { +// plugin.dBus.setAsDirectionLess().unsetName() +// val dBus = master(DBusSimpleBus()).setName("dBus") +// val pending = RegInit(False) setWhen(plugin.dBus.cmd.fire) clearWhen(plugin.dBus.rsp.ready) +// dBus.cmd << plugin.dBus.cmd.haltWhen(pending).halfPipe() +// plugin.dBus.rsp := RegNext(dBus.rsp) +// plugin.dBus.rsp.ready clearWhen(!pending) +// } +// +// case _ => +// } +// } + + toplevel + } + } +} + +object LinuxSyntesisBench extends App{ + val withoutMmu = new Rtl { + override def getName(): String = "VexRiscv Without Mmu" + override def getRtlPath(): String = "VexRiscvWithoutMmu.v" + SpinalVerilog(new VexRiscv(LinuxGen.configFull(withMmu=false)).setDefinitionName(getRtlPath().split("\\.").head)) + } + + val withMmu = new Rtl { + override def getName(): String = "VexRiscv With Mmu" + override def getRtlPath(): String = "VexRiscvWithMmu.v" + SpinalVerilog(new VexRiscv(LinuxGen.configFull(withMmu=true)).setDefinitionName(getRtlPath().split("\\.").head)) + } + + val rtls = List(withoutMmu, withMmu) + // val rtls = List(smallestNoCsr, smallest, smallAndProductive, smallAndProductiveWithICache) + // val rtls = List(smallAndProductive, smallAndProductiveWithICache, fullNoMmuMaxPerf, fullNoMmu, full) + // val rtls = List(fullNoMmu) + + val targets = XilinxStdTargets( + vivadoArtix7Path = "/eda/Xilinx/Vivado/2017.2/bin" + ) ++ AlteraStdTargets( + quartusCycloneIVPath = "/eda/intelFPGA_lite/17.0/quartus/bin", + quartusCycloneVPath = "/eda/intelFPGA_lite/17.0/quartus/bin" + ) ++ IcestormStdTargets().take(1) + + + Bench(rtls, targets, "/eda/tmp") +} + +object LinuxSim extends App{ + import spinal.core.sim._ + + SimConfig.allOptimisation.compile(new VexRiscv(LinuxGen.configFull())).doSim{dut => +// dut.clockDomain.forkStimulus(10) +// dut.clockDomain.forkSimSpeedPrinter() +// dut.plugins.foreach{ +// case p : IBusSimplePlugin => dut.clockDomain.onRisingEdges{ +// p.iBus.cmd.ready #= ! p.iBus.cmd.ready.toBoolean +//// p.iBus.rsp.valid.randomize() +//// p.iBus.rsp.inst.randomize() +//// p.iBus.rsp.error.randomize() +// } +// case p : DBusSimplePlugin => dut.clockDomain.onRisingEdges{ +// p.dBus.cmd.ready #= ! p.dBus.cmd.ready.toBoolean +//// p.dBus.cmd.ready.randomize() +//// p.dBus.rsp.ready.randomize() +//// p.dBus.rsp.data.randomize() +//// p.dBus.rsp.error.randomize() +// } +// case _ => +// } +// sleep(10*10000000) + + + var cycleCounter = 0l + var lastTime = System.nanoTime() + + + + + var iBus : IBusSimpleBus = null + var dBus : DBusSimpleBus = null + dut.plugins.foreach{ + case p : IBusSimplePlugin => + iBus = p.iBus +// p.iBus.rsp.valid.randomize() +// p.iBus.rsp.inst.randomize() +// p.iBus.rsp.error.randomize() + case p : DBusSimplePlugin => + dBus = p.dBus +// p.dBus.cmd.ready.randomize() +// p.dBus.rsp.ready.randomize() +// p.dBus.rsp.data.randomize() +// p.dBus.rsp.error.randomize() + case _ => + } + + dut.clockDomain.resetSim #= false + dut.clockDomain.clockSim #= false + sleep(1) + dut.clockDomain.resetSim #= true + sleep(1) + + def f(): Unit ={ + cycleCounter += 1 + + if((cycleCounter & 8191) == 0){ + val currentTime = System.nanoTime() + val deltaTime = (currentTime - lastTime)*1e-9 + if(deltaTime > 2.0) { + println(f"[Info] Simulation speed : ${cycleCounter / deltaTime * 1e-3}%4.0f kcycles/s") + lastTime = currentTime + cycleCounter = 0 + } + } + dut.clockDomain.clockSim #= false + iBus.cmd.ready #= ! iBus.cmd.ready.toBoolean + dBus.cmd.ready #= ! dBus.cmd.ready.toBoolean + delayed(1)(f2) + } + def f2(): Unit ={ + dut.clockDomain.clockSim #= true + delayed(1)(f) + } + + delayed(1)(f) + + sleep(100000000) + } +} \ No newline at end of file diff --git a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala index 701bbfb1..9bf9cd39 100644 --- a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala @@ -380,8 +380,8 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, } when(!(arbitration.isValid && input(MEMORY_ENABLE) && (Bool(cmdStage != rspStage) || !arbitration.isStuckByOthers))){ - memoryExceptionPort.valid := False - redoBranch.valid := False + if(catchSomething) memoryExceptionPort.valid := False + if(memoryTranslatorPortConfig != null) redoBranch.valid := False } } @@ -423,6 +423,7 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, //Share access to the dBus (used by self refilled MMU) val dBusSharing = (dBusAccess != null) generate new Area{ val state = Reg(UInt(2 bits)) init(0) + dBusAccess.cmd.ready := False dBusAccess.rsp.valid := False dBusAccess.rsp.data := dBus.rsp.data dBusAccess.rsp.error := dBus.rsp.error @@ -445,6 +446,7 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, dBus.cmd.size := dBusAccess.cmd.size when(dBus.cmd.ready){ state := (dBusAccess.cmd.write ? U(0) | U(2)) + dBusAccess.cmd.ready := True } } is(2){ diff --git a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala index 845fca36..fe4348a7 100644 --- a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala @@ -306,7 +306,6 @@ class IBusSimplePlugin(resetVector : BigInt, } if(catchSomething){ - decodeExceptionPort.valid := False decodeExceptionPort.code.assignDontCare() decodeExceptionPort.badAddr := join.pc //TODO Should it be the physical address insted ? diff --git a/src/main/scala/vexriscv/plugin/MmuPlugin.scala b/src/main/scala/vexriscv/plugin/MmuPlugin.scala index bbd206d1..7b504181 100644 --- a/src/main/scala/vexriscv/plugin/MmuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/MmuPlugin.scala @@ -119,9 +119,9 @@ class MmuPlugin(virtualRange : UInt => Bool, val shared = new Area { val busy = Reg(Bool) init(False) - val satp = new Bundle { - val mode = Bool() - val ppn = UInt(20 bits) + val satp = new Area { + val mode = RegInit(False) + val ppn = Reg(UInt(20 bits)) } csrService.rw(CSR.SATP, 31 -> satp.mode, 0 -> satp.ppn) //TODO write only ? val State = new SpinalEnum{ @@ -145,6 +145,7 @@ class MmuPlugin(virtualRange : UInt => Bool, val pteBuffer = RegNextWhen(dBusRsp.pte, dBus.rsp.valid) + dBus.cmd.valid := False dBus.cmd.write := False dBus.cmd.size := 2 dBus.cmd.address.assignDontCare() diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index a5c1b0d6..f68d7b92 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -759,7 +759,7 @@ public: top = new VVexRiscv; #ifdef TRACE_ACCESS regTraces.open (name + ".regTrace"); - memTraces.open (name + ".memTrace"); + memTraces.open (name + ".memTrace");hh #endif logTraces.open (name + ".logTrace"); fillSimELements(); @@ -990,7 +990,7 @@ public: try { // run simulation for 100 clock periods for (i = 16; i < timeout*2; i+=2) { - while(allowedCycles <= 0.0){ + /*while(allowedCycles <= 0.0){ struct timespec end_time; clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end_time); uint64_t diffInNanos = end_time.tv_sec*1e9 + end_time.tv_nsec - start_time.tv_sec*1e9 - start_time.tv_nsec; @@ -999,7 +999,7 @@ public: allowedCycles += dt*cyclesPerSecond; if(allowedCycles > cyclesPerSecond/100) allowedCycles = cyclesPerSecond/100; } - allowedCycles-=1.0; + allowedCycles-=1.0;*/ #ifndef REF_TIME @@ -1063,17 +1063,21 @@ public: rfWriteValid = true; rfWriteAddress = top->VexRiscv->writeBack_RegFilePlugin_regFileWrite_payload_address; rfWriteData = top->VexRiscv->writeBack_RegFilePlugin_regFileWrite_payload_data; + #ifdef TRACE_ACCESS regTraces << #ifdef TRACE_WITH_TIME currentTime << #endif " PC " << hex << setw(8) << top->VexRiscv->writeBack_PC << " : reg[" << dec << setw(2) << (uint32_t)top->VexRiscv->writeBack_RegFilePlugin_regFileWrite_payload_address << "] = " << hex << setw(8) << top->VexRiscv->writeBack_RegFilePlugin_regFileWrite_payload_data << dec << endl; + #endif } else { + #ifdef TRACE_ACCESS regTraces << #ifdef TRACE_WITH_TIME currentTime << #endif " PC " << hex << setw(8) << top->VexRiscv->writeBack_PC << dec << endl; + #endif } if(riscvRefEnable) if(rfWriteValid != riscvRef.rfWriteValid || (rfWriteValid && (rfWriteAddress!= riscvRef.rfWriteAddress || rfWriteData!= riscvRef.rfWriteData))){ diff --git a/src/test/cpp/regression/makefile b/src/test/cpp/regression/makefile index 84c68221..774ef19d 100644 --- a/src/test/cpp/regression/makefile +++ b/src/test/cpp/regression/makefile @@ -183,7 +183,7 @@ run: compile verilate: ../../../../VexRiscv.v rm -f VexRiscv.v*.bin cp ../../../../VexRiscv.v*.bin . | true - verilator -cc ../../../../VexRiscv.v -O3 -CFLAGS -std=c++11 -LDFLAGS -pthread ${ADDCFLAGS} --gdbbt ${VERILATOR_ARGS} -Wno-UNOPTFLAT -Wno-WIDTH --x-assign 0 --exe main.cpp + verilator -cc ../../../../VexRiscv.v -O3 -CFLAGS -std=c++11 -LDFLAGS -pthread ${ADDCFLAGS} --gdbbt ${VERILATOR_ARGS} -Wno-UNOPTFLAT -Wno-WIDTH --x-assign unique --exe main.cpp compile: verilate make -j${THREAD_COUNT} -C obj_dir/ -f VVexRiscv.mk VVexRiscv From 8f22365959d8c28bb4c92b0427dfc41cffacc83e Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 19 Mar 2019 22:21:30 +0100 Subject: [PATCH 042/951] Disable MMU in machine mode --- src/main/scala/vexriscv/Services.scala | 2 ++ src/main/scala/vexriscv/demo/Linux.scala | 2 +- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 3 ++- src/main/scala/vexriscv/plugin/MmuPlugin.scala | 12 ++++++++---- 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/main/scala/vexriscv/Services.scala b/src/main/scala/vexriscv/Services.scala index 5e4e2eb7..cf3cf0d1 100644 --- a/src/main/scala/vexriscv/Services.scala +++ b/src/main/scala/vexriscv/Services.scala @@ -37,10 +37,12 @@ trait ExceptionService{ trait PrivilegeService{ def isUser(stage : Stage) : Bool + def isMachine(stage : Stage) : Bool } case class PrivilegeServiceDefault() extends PrivilegeService{ override def isUser(stage: Stage): Bool = False + override def isMachine(stage: Stage): Bool = True } trait InterruptionInhibitor{ diff --git a/src/main/scala/vexriscv/demo/Linux.scala b/src/main/scala/vexriscv/demo/Linux.scala index 0c8979ac..81b21597 100644 --- a/src/main/scala/vexriscv/demo/Linux.scala +++ b/src/main/scala/vexriscv/demo/Linux.scala @@ -108,7 +108,7 @@ object LinuxGen { catchIllegalInstruction = true ), new RegFilePlugin( - regFileReadyKind = plugin.ASYNC, + regFileReadyKind = plugin.SYNC, zeroBoot = true ), new IntAluPlugin, diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index ab59360a..45433f59 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -362,7 +362,8 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception def inhibateInterrupts() : Unit = allowInterrupts := False def inhibateException() : Unit = allowException := False - def isUser(stage : Stage) : Bool = privilege === 0 + override def isUser(stage : Stage) : Bool = privilege === 0 + override def isMachine(stage: Stage): Bool = privilege === 3 override def build(pipeline: VexRiscv): Unit = { import pipeline._ diff --git a/src/main/scala/vexriscv/plugin/MmuPlugin.scala b/src/main/scala/vexriscv/plugin/MmuPlugin.scala index 7b504181..25f47d9c 100644 --- a/src/main/scala/vexriscv/plugin/MmuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/MmuPlugin.scala @@ -39,7 +39,8 @@ case class MmuPortConfig(portTlbSize : Int) class MmuPlugin(virtualRange : UInt => Bool, ioRange : UInt => Bool, - allowUserIo : Boolean) extends Plugin[VexRiscv] with MemoryTranslator { + allowUserIo : Boolean, + allowMachineModeMmu : Boolean = false) extends Plugin[VexRiscv] with MemoryTranslator { var dBus : DBusAccess = null val portsInfo = ArrayBuffer[MmuPort]() @@ -91,11 +92,13 @@ class MmuPlugin(virtualRange : UInt => Bool, val cacheHits = cache.map(line => line.valid && line.virtualAddress === port.bus.cmd.virtualAddress(31 downto 12)) val cacheHit = cacheHits.asBits.orR val cacheLine = MuxOH(cacheHits, cache) - val isInMmuRange = virtualRange(port.bus.cmd.virtualAddress) && !port.bus.cmd.bypassTranslation + val privilegeService = pipeline.serviceElse(classOf[PrivilegeService], PrivilegeServiceDefault()) val entryToReplace = Counter(port.args.portTlbSize) + val requireMmuLockup = virtualRange(port.bus.cmd.virtualAddress) && !port.bus.cmd.bypassTranslation + if(!allowMachineModeMmu) requireMmuLockup clearWhen(privilegeService.isMachine(execute)) - when(isInMmuRange) { + when(requireMmuLockup) { port.bus.rsp.physicalAddress := cacheLine.physicalAddress @@ port.bus.cmd.virtualAddress(11 downto 0) port.bus.rsp.allowRead := cacheLine.allowRead port.bus.rsp.allowWrite := cacheLine.allowWrite @@ -103,7 +106,6 @@ class MmuPlugin(virtualRange : UInt => Bool, port.bus.rsp.allowUser := cacheLine.allowUser port.bus.rsp.exception := cacheHit && cacheLine.exception port.bus.rsp.refilling := !cacheHit - } otherwise { port.bus.rsp.physicalAddress := port.bus.cmd.virtualAddress port.bus.rsp.allowRead := True @@ -122,6 +124,8 @@ class MmuPlugin(virtualRange : UInt => Bool, val satp = new Area { val mode = RegInit(False) val ppn = Reg(UInt(20 bits)) + + ports.foreach(_.requireMmuLockup clearWhen(!mode)) } csrService.rw(CSR.SATP, 31 -> satp.mode, 0 -> satp.ppn) //TODO write only ? val State = new SpinalEnum{ From ccc3b63d7c7695d020dcf13eed5d520e20c1d79b Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 20 Mar 2019 01:12:03 +0100 Subject: [PATCH 043/951] Enable golden model check for all regressions Need to implement missing CSR of the golden model --- .gitignore | 1 + .../scala/vexriscv/plugin/CsrPlugin.scala | 69 +++- src/test/cpp/regression/.cproject | 300 ------------------ src/test/cpp/regression/main.cpp | 28 +- 4 files changed, 70 insertions(+), 328 deletions(-) delete mode 100644 src/test/cpp/regression/.cproject diff --git a/.gitignore b/.gitignore index eaab2e7a..c926769c 100644 --- a/.gitignore +++ b/.gitignore @@ -24,6 +24,7 @@ out bin/ .classpath .project +.cproject .settings .cache-main diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 45433f59..cfdb2209 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -78,26 +78,63 @@ object CsrPluginConfig{ def all : CsrPluginConfig = all(0x00000020l) def small : CsrPluginConfig = small(0x00000020l) def smallest : CsrPluginConfig = smallest(0x00000020l) + def linux(mtVecInit : BigInt) = CsrPluginConfig( + catchIllegalAccess = true, + mvendorid = 1, + marchid = 2, + mimpid = 3, + mhartid = 0, + misaExtensionsInit = 0, //TODO + misaAccess = CsrAccess.READ_WRITE, + mtvecAccess = CsrAccess.READ_WRITE, + mtvecInit = mtVecInit, + mepcAccess = CsrAccess.READ_WRITE, + mscratchGen = false, + mcauseAccess = CsrAccess.READ_WRITE, + mbadaddrAccess = CsrAccess.READ_WRITE, + mcycleAccess = CsrAccess.READ_WRITE, + minstretAccess = CsrAccess.READ_WRITE, + ucycleAccess = CsrAccess.READ_ONLY, + wfiGenAsWait = true, + ecallGen = true, + mtvecModeGen = false, + noCsrAlu = false, + wfiGenAsNop = false, + ebreakGen = true, + supervisorGen = true, + sscratchGen = true, + stvecAccess = CsrAccess.READ_WRITE, + sepcAccess = CsrAccess.READ_WRITE, + scauseAccess = CsrAccess.READ_WRITE, + sbadaddrAccess = CsrAccess.READ_WRITE, + scycleAccess = CsrAccess.READ_WRITE, + sinstretAccess = CsrAccess.READ_WRITE, + satpAccess = CsrAccess.READ_WRITE, + medelegAccess = CsrAccess.READ_WRITE, + midelegAccess = CsrAccess.READ_WRITE, + pipelineCsrRead = false, + deterministicInteruptionEntry = false + ) def all(mtvecInit : BigInt) : CsrPluginConfig = CsrPluginConfig( catchIllegalAccess = true, - mvendorid = 11, - marchid = 22, - mimpid = 33, - mhartid = 0, + mvendorid = 11, + marchid = 22, + mimpid = 33, + mhartid = 0, misaExtensionsInit = 66, - misaAccess = CsrAccess.READ_WRITE, - mtvecAccess = CsrAccess.READ_WRITE, - mtvecInit = mtvecInit, - mepcAccess = CsrAccess.READ_WRITE, - mscratchGen = true, - mcauseAccess = CsrAccess.READ_WRITE, - mbadaddrAccess = CsrAccess.READ_WRITE, - mcycleAccess = CsrAccess.READ_WRITE, - minstretAccess = CsrAccess.READ_WRITE, - ecallGen = true, - wfiGenAsWait = true, - ucycleAccess = CsrAccess.READ_ONLY + misaAccess = CsrAccess.READ_WRITE, + mtvecAccess = CsrAccess.READ_WRITE, + mtvecInit = mtvecInit, + mepcAccess = CsrAccess.READ_WRITE, + mscratchGen = true, + mcauseAccess = CsrAccess.READ_WRITE, + mbadaddrAccess = CsrAccess.READ_WRITE, + mcycleAccess = CsrAccess.READ_WRITE, + minstretAccess = CsrAccess.READ_WRITE, + ecallGen = true, + wfiGenAsWait = true, + ucycleAccess = CsrAccess.READ_ONLY ) def all2(mtvecInit : BigInt) : CsrPluginConfig = CsrPluginConfig( diff --git a/src/test/cpp/regression/.cproject b/src/test/cpp/regression/.cproject deleted file mode 100644 index 736b1234..00000000 --- a/src/test/cpp/regression/.cproject +++ /dev/null @@ -1,300 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index f68d7b92..38703a58 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -470,9 +470,9 @@ public: case 0x1:rfWrite(rd32,(int64_t(i32_rs1) * int64_t(i32_rs2)) >> 32);pcWrite(pc + 4);break; case 0x2:rfWrite(rd32,(int64_t(i32_rs1) * uint64_t(uint32_t(i32_rs2)))>> 32);pcWrite(pc + 4);break; case 0x3:rfWrite(rd32,(uint64_t(uint32_t(i32_rs1)) * uint64_t(uint32_t(i32_rs2))) >> 32);pcWrite(pc + 4);break; - case 0x4:rfWrite(rd32,i32_rs2 == 0 ? -1 : int32_t(i32_rs1) / int32_t(i32_rs2));pcWrite(pc + 4);break; + case 0x4:rfWrite(rd32,i32_rs2 == 0 ? -1 : int64_t(i32_rs1) / int64_t(i32_rs2));pcWrite(pc + 4);break; case 0x5:rfWrite(rd32,i32_rs2 == 0 ? -1 : uint32_t(i32_rs1) / uint32_t(i32_rs2));pcWrite(pc + 4);break; - case 0x6:rfWrite(rd32,i32_rs2 == 0 ? i32_rs1 : int32_t(i32_rs1)% int32_t(i32_rs2));pcWrite(pc + 4);break; + case 0x6:rfWrite(rd32,i32_rs2 == 0 ? i32_rs1 : int64_t(i32_rs1)% int64_t(i32_rs2));pcWrite(pc + 4);break; case 0x7:rfWrite(rd32,i32_rs2 == 0 ? i32_rs1 : uint32_t(i32_rs1) % uint32_t(i32_rs2));pcWrite(pc + 4);break; } } else { @@ -2191,7 +2191,7 @@ public: ofstream out32; int out32Counter = 0; Compliance(string name) : Workspace(name) { - //withRiscvRef(); + withRiscvRef(); loadHex("../../resources/hex/" + name + ".elf.hex"); out32.open (name + ".out32"); this->name = name; @@ -2774,20 +2774,24 @@ int main(int argc, char **argv, char **env) { #ifndef COMPRESSED 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(10e4);) + redo(REDO,TestX28("machineCsr",machineCsrRef, sizeof(machineCsrRef)/4).withRiscvRef()->noInstructionReadCheck()->run(10e4);) #else 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, 14,2, 15,5,16,17,1 }; - redo(REDO,TestX28("machineCsrCompressed",machineCsrRef, sizeof(machineCsrRef)/4).noInstructionReadCheck()->run(10e4);) + redo(REDO,TestX28("machineCsrCompressed",machineCsrRef, sizeof(machineCsrRef)/4).withRiscvRef()->noInstructionReadCheck()->run(10e4);) #endif #endif - #ifdef MMU - uint32_t mmuRef[] = {1,2,3, 0x11111111, 0x11111111, 0x11111111, 0x22222222, 0x22222222, 0x22222222, 4, 0x11111111, 0x33333333, 0x33333333, 5, - 13, 0xC4000000,0x33333333, 6,7, - 1,2,3, 0x11111111, 0x11111111, 0x11111111, 0x22222222, 0x22222222, 0x22222222, 4, 0x11111111, 0x33333333, 0x33333333, 5, - 13, 0xC4000000,0x33333333, 6,7}; - redo(REDO,TestX28("mmu",mmuRef, sizeof(mmuRef)/4).noInstructionReadCheck()->run(4e4);) - #endif +// #ifdef MMU +// uint32_t mmuRef[] = {1,2,3, 0x11111111, 0x11111111, 0x11111111, 0x22222222, 0x22222222, 0x22222222, 4, 0x11111111, 0x33333333, 0x33333333, 5, +// 13, 0xC4000000,0x33333333, 6,7, +// 1,2,3, 0x11111111, 0x11111111, 0x11111111, 0x22222222, 0x22222222, 0x22222222, 4, 0x11111111, 0x33333333, 0x33333333, 5, +// 13, 0xC4000000,0x33333333, 6,7}; +// redo(REDO,TestX28("mmu",mmuRef, sizeof(mmuRef)/4).noInstructionReadCheck()->run(4e4);) +// #endif + + #ifdef MMU + redo(REDO,Workspace("mmu").withRiscvRef()->loadHex("../raw/mmu/build/mmu.hex")->bootAt(0x80000000u)->run(50e3);); + #endif #ifdef DEBUG_PLUGIN redo(REDO,DebugPluginTest().run(1e6);); From 3a38fe4130922e9900af3aa7f056e3ba2232fa61 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 20 Mar 2019 01:13:05 +0100 Subject: [PATCH 044/951] Add mmu regresion blank project --- src/test/cpp/raw/common/asm.mk | 73 ++++++++++++++++++++++++++++++ src/test/cpp/raw/mmu/build/mmu.asm | 43 ++++++++++++++++++ src/test/cpp/raw/mmu/build/mmu.hex | 10 ++++ src/test/cpp/raw/mmu/makefile | 3 ++ src/test/cpp/raw/mmu/src/crt.S | 46 +++++++++++++++++++ src/test/cpp/raw/mmu/src/ld | 16 +++++++ 6 files changed, 191 insertions(+) create mode 100644 src/test/cpp/raw/common/asm.mk create mode 100644 src/test/cpp/raw/mmu/build/mmu.asm create mode 100644 src/test/cpp/raw/mmu/build/mmu.hex create mode 100644 src/test/cpp/raw/mmu/makefile create mode 100644 src/test/cpp/raw/mmu/src/crt.S create mode 100644 src/test/cpp/raw/mmu/src/ld diff --git a/src/test/cpp/raw/common/asm.mk b/src/test/cpp/raw/common/asm.mk new file mode 100644 index 00000000..8459b7b8 --- /dev/null +++ b/src/test/cpp/raw/common/asm.mk @@ -0,0 +1,73 @@ +PROJ_NAME=mmu + + +RISCV_PATH?=/opt/riscv/ +CFLAGS += -march=rv32i -mabi=ilp32 +RISCV_NAME = riscv64-unknown-elf +RISCV_OBJCOPY = $(RISCV_PATH)/bin/$(RISCV_NAME)-objcopy +RISCV_OBJDUMP = $(RISCV_PATH)/bin/$(RISCV_NAME)-objdump +RISCV_CLIB=$(RISCV_PATH)$(RISCV_NAME)/lib/ +RISCV_CC=$(RISCV_PATH)/bin/$(RISCV_NAME)-gcc +LDSCRIPT=src/ld + + +SRCS = $(wildcard src/*.c) \ + $(wildcard src/*.cpp) \ + $(wildcard src/*.S) + + +CFLAGS += -static +LDFLAGS += -e_start -T $(LDSCRIPT) -nostartfiles -Wl,-Map,$(OBJDIR)/$(PROJ_NAME).map -Wl,--print-memory-usage +OBJDIR = build +OBJS := $(SRCS) +OBJS := $(OBJS:.c=.o) +OBJS := $(OBJS:.cpp=.o) +OBJS := $(OBJS:.S=.o) +OBJS := $(addprefix $(OBJDIR)/,$(OBJS)) + + + +all: $(OBJDIR)/$(PROJ_NAME).elf $(OBJDIR)/$(PROJ_NAME).hex $(OBJDIR)/$(PROJ_NAME).asm $(OBJDIR)/$(PROJ_NAME).v + @echo "done" + +$(OBJDIR)/%.elf: $(OBJS) | $(OBJDIR) + $(RISCV_CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) $(LIBS) + +%.hex: %.elf + $(RISCV_OBJCOPY) -O ihex $^ $@ + +%.bin: %.elf + $(RISCV_OBJCOPY) -O binary $^ $@ + +%.v: %.elf + $(RISCV_OBJCOPY) -O verilog $^ $@ + +%.asm: %.elf + $(RISCV_OBJDUMP) -S -d $^ > $@ + +$(OBJDIR)/%.o: %.c + mkdir -p $(dir $@) + $(RISCV_CC) -c $(CFLAGS) $(INC) -o $@ $^ + +$(OBJDIR)/%.o: %.cpp + mkdir -p $(dir $@) + $(RISCV_CC) -c $(CFLAGS) $(INC) -o $@ $^ + +$(OBJDIR)/%.o: %.S + mkdir -p $(dir $@) + $(RISCV_CC) -c $(CFLAGS) -o $@ $^ -D__ASSEMBLY__=1 + +$(OBJDIR): + mkdir -p $@ + +clean: + rm -f $(OBJDIR)/$(PROJ_NAME).elf + rm -f $(OBJDIR)/$(PROJ_NAME).hex + rm -f $(OBJDIR)/$(PROJ_NAME).map + rm -f $(OBJDIR)/$(PROJ_NAME).v + rm -f $(OBJDIR)/$(PROJ_NAME).asm + find $(OBJDIR) -type f -name '*.o' -print0 | xargs -0 -r rm + +.SECONDARY: $(OBJS) + + diff --git a/src/test/cpp/raw/mmu/build/mmu.asm b/src/test/cpp/raw/mmu/build/mmu.asm new file mode 100644 index 00000000..243b7860 --- /dev/null +++ b/src/test/cpp/raw/mmu/build/mmu.asm @@ -0,0 +1,43 @@ + +build/mmu.elf: file format elf32-littleriscv + + +Disassembly of section .crt_section: + +80000000 : +80000000: 0280006f j 80000028 <_start> +80000004: 00000013 nop +80000008: 00000013 nop +8000000c: 00000013 nop +80000010: 00000013 nop +80000014: 00000013 nop +80000018: 00000013 nop +8000001c: 00000013 nop + +80000020 : +80000020: 0200006f j 80000040 +80000024: 30200073 mret + +80000028 <_start>: +80000028: 00000097 auipc ra,0x0 +8000002c: 01808093 addi ra,ra,24 # 80000040 +80000030: 30509073 csrw mtvec,ra +80000034: 10509073 csrw stvec,ra +80000038: 00100e13 li t3,1 +8000003c: 0100006f j 8000004c + +80000040 : +80000040: f0100137 lui sp,0xf0100 +80000044: f2410113 addi sp,sp,-220 # f00fff24 +80000048: 01c12023 sw t3,0(sp) + +8000004c : +8000004c: f0100137 lui sp,0xf0100 +80000050: f2010113 addi sp,sp,-224 # f00fff20 +80000054: 00012023 sw zero,0(sp) +80000058: 00000013 nop +8000005c: 00000013 nop +80000060: 00000013 nop +80000064: 00000013 nop +80000068: 00000013 nop +8000006c: 00000013 nop diff --git a/src/test/cpp/raw/mmu/build/mmu.hex b/src/test/cpp/raw/mmu/build/mmu.hex new file mode 100644 index 00000000..096ccfcf --- /dev/null +++ b/src/test/cpp/raw/mmu/build/mmu.hex @@ -0,0 +1,10 @@ +:0200000480007A +:100000006F008002130000001300000013000000C6 +:100010001300000013000000130000001300000094 +:100020006F00000273002030970000009380800171 +:100030007390503073905010130E10006F00000139 +:10004000370110F0130141F22320C101370110F0F4 +:10005000130101F22320010013000000130000002F +:100060001300000013000000130000001300000044 +:04000005800000284F +:00000001FF diff --git a/src/test/cpp/raw/mmu/makefile b/src/test/cpp/raw/mmu/makefile new file mode 100644 index 00000000..961e3bce --- /dev/null +++ b/src/test/cpp/raw/mmu/makefile @@ -0,0 +1,3 @@ +PROJ_NAME=mmu + +include ../common/asm.mk \ No newline at end of file diff --git a/src/test/cpp/raw/mmu/src/crt.S b/src/test/cpp/raw/mmu/src/crt.S new file mode 100644 index 00000000..533939b9 --- /dev/null +++ b/src/test/cpp/raw/mmu/src/crt.S @@ -0,0 +1,46 @@ +.globl _start + + + j _start + nop + nop + nop + nop + nop + nop + nop + +.global trap_entry +trap_entry: + j fail + mret + +_start: + la x1, fail + csrw mtvec, x1 + csrw stvec, x1 + +//Test 1 SC on unreserved area should fail and not write memory + li x28, 1 + + + + j pass + + +fail: //x28 => error code + li x2, 0xF00FFF24 + sw x28, 0(x2) + +pass: + li x2, 0xF00FFF20 + sw x0, 0(x2) + + + + nop + nop + nop + nop + nop + nop diff --git a/src/test/cpp/raw/mmu/src/ld b/src/test/cpp/raw/mmu/src/ld new file mode 100644 index 00000000..cd04151d --- /dev/null +++ b/src/test/cpp/raw/mmu/src/ld @@ -0,0 +1,16 @@ +OUTPUT_ARCH( "riscv" ) + +MEMORY { + onChipRam (W!RX)/*(RX)*/ : ORIGIN = 0x80000000, LENGTH = 8K +} + +SECTIONS +{ + + .crt_section : + { + . = ALIGN(4); + *crt.o(.text) + } > onChipRam + +} From ee402ec5dc78bdc7fcc3565600c10c3285dfed7d Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 20 Mar 2019 01:16:39 +0100 Subject: [PATCH 045/951] clearning --- src/test/cpp/raw/mmu/src/crt.S | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/test/cpp/raw/mmu/src/crt.S b/src/test/cpp/raw/mmu/src/crt.S index 533939b9..f2cb783c 100644 --- a/src/test/cpp/raw/mmu/src/crt.S +++ b/src/test/cpp/raw/mmu/src/crt.S @@ -20,10 +20,11 @@ _start: csrw mtvec, x1 csrw stvec, x1 -//Test 1 SC on unreserved area should fail and not write memory +//Test 1 li x28, 1 - +//Test 2 + li x28, 2 j pass From 3c66f7c58af02ae91186a74d5e519911e15aac7b Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 20 Mar 2019 11:46:27 +0100 Subject: [PATCH 046/951] goldenmodel now pass more machine mode CSR tests --- src/test/cpp/regression/main.cpp | 163 +++++++++++++++++++++++-------- 1 file changed, 121 insertions(+), 42 deletions(-) diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 38703a58..ca08a65c 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -192,7 +192,7 @@ class success : public std::exception { }; class RiscvGolden { public: - int32_t pc; + int32_t pc, lastPc; int32_t regs[32]; union status { @@ -273,7 +273,7 @@ public: status.raw = 0; mip.raw = 0; mie.raw = 0; - mtvec.raw = 0; + mtvec.raw = 0x80000020; mcause.raw = 0; mbadaddr = 0; mepc = 0; @@ -286,7 +286,12 @@ public: } virtual void pcWrite(int32_t target) { - pc = target; + if(isPcAligned(target)){ + lastPc = pc; + pc = target; + } else { + exception(0, 0); + } } uint32_t mbadaddr; uint32_t mepc; @@ -305,6 +310,11 @@ public: if(interrupt) livenessInterrupt = 0; //status.MPP := privilege + if(!interrupt) step(); //As VexRiscv instruction which trap do not reach writeback stage fire + } + + void ilegalInstruction(){ + exception(0, 2); } virtual void fail() { @@ -361,6 +371,15 @@ public: } + bool isPcAligned(uint32_t pc){ +#ifdef COMPRESSED + return (pc & 1) == 0; +#else + return (pc & 3) == 0; +#endif + } + + virtual void step() { livenessStep = 0; @@ -393,15 +412,24 @@ public: uint32_t i; uint32_t u32Buf; if (pc & 2) { - iRead(pc - 2, &i); + if(iRead(pc - 2, &i)){ + exception(0, 1); + return; + } i >>= 16; if (i & 3 == 3) { uint32_t u32Buf; - iRead(pc + 2, &u32Buf); + if(iRead(pc + 2, &u32Buf)){ + exception(0, 1); + return; + } i |= u32Buf << 16; } } else { - iRead(pc, &i); + if(iRead(pc, &i)){ + exception(0, 1); + return; + } } if ((i & 0x3) == 0x3) { //32 bit @@ -411,7 +439,7 @@ public: case 0x6F:rfWrite(rd32, pc + 4);pcWrite(pc + (iBits(21, 10) << 1) + (iBits(20, 1) << 11) + (iBits(12, 8) << 12) + (iSign() << 20));break; //JAL case 0x67:{ uint32_t target = (i32_rs1 + i32_i_imm) & ~1; - rfWrite(rd32, pc + 4); + if(isPcAligned(target)) rfWrite(rd32, pc + 4); pcWrite(target); } break; //JALR case 0x63: @@ -424,24 +452,36 @@ public: case 0x7:if (uint32_t(i32_rs1) >= uint32_t(i32_rs2))pcWrite(pc + i32_sb_imm); else pcWrite(pc + 4);break; } break; - case 0x03: //LOADS + case 0x03:{ //LOADS uint32_t data; - dRead(i32_rs1 + i32_i_imm, 1 << ((i >> 12) & 0x3), &data); - switch ((i >> 12) & 0x7) { - case 0x0:rfWrite(rd32, int8_t(data));pcWrite(pc + 4);break; - case 0x1:rfWrite(rd32, int16_t(data));pcWrite(pc + 4);break; - case 0x2:rfWrite(rd32, int32_t(data));pcWrite(pc + 4);break; - case 0x4:rfWrite(rd32, uint8_t(data));pcWrite(pc + 4);break; - case 0x5:rfWrite(rd32, uint16_t(data));pcWrite(pc + 4);break; + uint32_t address = i32_rs1 + i32_i_imm; + uint32_t size = 1 << ((i >> 12) & 0x3); + if(address & (size-1)){ + exception(0, 4); + } else { + if(dRead(address, size, &data)){ + exception(0, 5); + } else { + switch ((i >> 12) & 0x7) { + case 0x0:rfWrite(rd32, int8_t(data));pcWrite(pc + 4);break; + case 0x1:rfWrite(rd32, int16_t(data));pcWrite(pc + 4);break; + case 0x2:rfWrite(rd32, int32_t(data));pcWrite(pc + 4);break; + case 0x4:rfWrite(rd32, uint8_t(data));pcWrite(pc + 4);break; + case 0x5:rfWrite(rd32, uint16_t(data));pcWrite(pc + 4);break; + } + } } - break; - case 0x23: //STORE - switch ((i >> 12) & 0x7) { - case 0x0:dWrite(i32_rs1 + i32_s_imm, 1, i32_rs2);pcWrite(pc + 4);break; - case 0x1:dWrite(i32_rs1 + i32_s_imm, 2, i32_rs2);pcWrite(pc + 4);break; - case 0x2:dWrite(i32_rs1 + i32_s_imm, 4, i32_rs2);pcWrite(pc + 4);break; + }break; + case 0x23: { //STORE + uint32_t address = i32_rs1 + i32_s_imm; + uint32_t size = 1 << ((i >> 12) & 0x3); + if(address & (size-1)){ + exception(0, 6); + } else { + dWrite(address, size, i32_rs2); + pcWrite(pc + 4); } - break; + }break; case 0x13: //ALUi switch ((i >> 12) & 0x7) { case 0x0:rfWrite(rd32, i32_rs1 + i32_i_imm);pcWrite(pc + 4);break; @@ -500,13 +540,21 @@ public: break; case 0x73:{ if(i32_func3 == 0){ - switch(i){ case 0x30200073:{ //MRET - status.mie = status.mpie; - //privilege := mstatus.MPP - pcWrite(mepc); + status.mie = status.mpie; + //privilege := mstatus.MPP + pcWrite(mepc); }break; + case 0x00000073:{ //ECALL + exception(0, 11); + }break; + case 0x10500073:{ //WFI + pcWrite(pc + 4); + }break; + default: + ilegalInstruction(); + break; } } else { //CSR @@ -533,11 +581,26 @@ public: case 0: rfWrite(i16_addr2, rf_sp + i16_addi4spn_imm); pcWrite(pc + 2); break; case 2: { uint32_t data; - dRead(i16_rf1 + i16_lw_imm, 4, &data); - rfWrite(i16_addr2, data); pcWrite(pc + 2); - break; - } - case 6: dWrite(i16_rf1 + i16_lw_imm, 4, i16_rf2); pcWrite(pc + 2); break; + uint32_t address = i16_rf1 + i16_lw_imm; + if(address & 0x3){ + exception(0, 4); + } else { + if(dRead(i16_rf1 + i16_lw_imm, 4, &data)) { + exception(1, 5); + } else { + rfWrite(i16_addr2, data); pcWrite(pc + 2); + } + } + } break; + case 6: { + uint32_t address = i16_rf1 + i16_lw_imm; + if(address & 0x3){ + exception(0, 6); + } else { + dWrite(address, 4, i16_rf2); + pcWrite(pc + 2); + } + }break; case 8: rfWrite(rd32, regs[rd32] + i16_imm); pcWrite(pc + 2); break; case 9: rfWrite(1, pc + 2);pcWrite(pc + i16_j_imm); break; case 10: rfWrite(rd32, i16_imm);pcWrite(pc + 2); break; @@ -565,9 +628,17 @@ public: case 16: rfWrite(rd32, regs[rd32] << i16_zimm); pcWrite(pc + 2); break; case 18:{ uint32_t data; - dRead(rf_sp + i16_lwsp_imm, 4, &data); - rfWrite(rd32, data); pcWrite(pc + 2); break; - } + uint32_t address = rf_sp + i16_lwsp_imm; + if(address & 0x3){ + exception(0, 4); + } else { + if(dRead(address, 4, &data)){ + exception(1, 5); + } else { + rfWrite(rd32, data); pcWrite(pc + 2); + } + } + }break; case 20: if(i & 0x1000){ if(iBits(2,10) == 0){ @@ -585,7 +656,14 @@ public: } } break; - case 22: dWrite(rf_sp + i16_swsp_imm, 4, regs[iBits(2,5)]); pcWrite(pc + 2); break; + case 22: { + uint32_t address = rf_sp + i16_swsp_imm; + if(address & 3){ + exception(0,6); + } else { + dWrite(address, 4, regs[iBits(2,5)]); pcWrite(pc + 2); + } + }break; } } } @@ -681,9 +759,9 @@ public: virtual bool iRead(int32_t address, uint32_t *data){ - mem.read(address, 4, (uint8_t*)data); bool error; - ws->iBusAccessPatch(address,data,&error); + ws->iBusAccess(address, data, &error); +// ws->iBusAccessPatch(address,data,&error); return error; } @@ -700,6 +778,7 @@ public: } *data = t.data; periphRead.pop(); + return t.error; }else { mem.read(address, size, (uint8_t*)data); } @@ -1032,11 +1111,6 @@ public: } #endif if(top->VexRiscv->writeBack_arbitration_isFiring){ - if(riscvRefEnable && top->VexRiscv->writeBack_PC != riscvRef.pc){ - cout << " pc missmatch " << top->VexRiscv->writeBack_PC << " should be " << riscvRef.pc << endl; - fail(); - } - if(riscvRefEnable) { riscvRef.step(); bool mIntTimer = false; @@ -1053,6 +1127,10 @@ public: riscvRef.liveness(mIntTimer, mIntExt); } + if(riscvRefEnable && top->VexRiscv->writeBack_PC != riscvRef.lastPc){ + cout << hex << " pc missmatch " << top->VexRiscv->writeBack_PC << " should be " << riscvRef.lastPc << dec << endl; + fail(); + } bool rfWriteValid = false; @@ -2687,6 +2765,7 @@ int main(int argc, char **argv, char **env) { printf("BOOT\n"); timespec startedAt = timer_start(); + for(int idx = 0;idx < 1;idx++){ #if defined(DEBUG_PLUGIN_EXTERNAL) || defined(RUN_HEX) From d205f88fb8c85b833fd395d997042d12d68b14d6 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 20 Mar 2019 12:17:43 +0100 Subject: [PATCH 047/951] riscv golden model and RTL pass all current regressions add RVC into the linux config --- src/main/scala/vexriscv/demo/Linux.scala | 2 +- src/test/cpp/regression/main.cpp | 64 +++++++++++++++--------- 2 files changed, 42 insertions(+), 24 deletions(-) diff --git a/src/main/scala/vexriscv/demo/Linux.scala b/src/main/scala/vexriscv/demo/Linux.scala index 81b21597..a935dffd 100644 --- a/src/main/scala/vexriscv/demo/Linux.scala +++ b/src/main/scala/vexriscv/demo/Linux.scala @@ -37,7 +37,7 @@ object LinuxGen { prediction = NONE, historyRamSizeLog2 = 10, catchAccessFault = true, - compressedGen = false, + compressedGen = true, busLatencyMin = 1, injectorStage = true, memoryTranslatorPortConfig = withMmu generate MmuPortConfig( diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index ca08a65c..a3e7e0bc 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -194,6 +194,8 @@ class RiscvGolden { public: int32_t pc, lastPc; int32_t regs[32]; + uint32_t mscratch; + uint32_t misa; union status { uint32_t raw; @@ -277,6 +279,7 @@ public: mcause.raw = 0; mbadaddr = 0; mepc = 0; + misa = 0; //TODO status.mpp = 3; } @@ -290,7 +293,7 @@ public: lastPc = pc; pc = target; } else { - exception(0, 0); + exception(0, 0, target); } } uint32_t mbadaddr; @@ -300,7 +303,16 @@ public: virtual bool dRead(int32_t address, int32_t size, uint32_t *data) = 0; virtual void dWrite(int32_t address, int32_t size, uint32_t data) = 0; - void exception(bool interrupt,int32_t cause) { + void exception(bool interrupt,int32_t cause) { + exception(interrupt, cause, false, 0); + } + void exception(bool interrupt,int32_t cause, uint32_t value) { + exception(interrupt, cause, true, value); + } + void exception(bool interrupt,int32_t cause, bool valueWrite, uint32_t value) { + if(valueWrite){ + mbadaddr = value; + } mcause.interrupt = interrupt; mcause.exceptionCode = cause; status.mie = false; @@ -319,10 +331,7 @@ public: virtual void fail() { } - virtual void decodingError() { - cout << "decoding error" << endl; - fail(); - } + uint32_t* csrPtr(int32_t csr){ switch(csr){ @@ -333,16 +342,24 @@ public: case MCAUSE: return &mcause.raw; break; case MBADADDR: return &mbadaddr; break; case MEPC: return &mepc; break; - default: fail(); return NULL; break; + case MSCRATCH: return &mscratch; break; + case MISA: return &misa; break; + default: ilegalInstruction(); return NULL; break; } } - virtual uint32_t csrRead(int32_t csr){ - return *csrPtr(csr); + virtual bool csrRead(int32_t csr, uint32_t *value){ + auto ptr = csrPtr(csr); + if(ptr){ + *value = *ptr; + } + return ptr == NULL; } - virtual void csrWrite(int32_t csr, uint32_t value){ - *csrPtr(csr) = value; + virtual bool csrWrite(int32_t csr, uint32_t value){ + auto ptr = csrPtr(csr); + if(ptr) *csrPtr(csr) = value; + return ptr == NULL; } @@ -457,10 +474,10 @@ public: uint32_t address = i32_rs1 + i32_i_imm; uint32_t size = 1 << ((i >> 12) & 0x3); if(address & (size-1)){ - exception(0, 4); + exception(0, 4, address); } else { if(dRead(address, size, &data)){ - exception(0, 5); + exception(0, 5, address); } else { switch ((i >> 12) & 0x7) { case 0x0:rfWrite(rd32, int8_t(data));pcWrite(pc + 4);break; @@ -476,7 +493,7 @@ public: uint32_t address = i32_rs1 + i32_s_imm; uint32_t size = 1 << ((i >> 12) & 0x3); if(address & (size-1)){ - exception(0, 6); + exception(0, 6, address); } else { dWrite(address, size, i32_rs2); pcWrite(pc + 4); @@ -567,14 +584,15 @@ public: case 3: clear = input; set = 0; write = ((i >> 15) & 0x1F) != 0; break; } uint32_t csrAddress = i32_csr; - uint32_t old = csrRead(i32_csr); + uint32_t old; + if(csrRead(i32_csr, &old)) { ilegalInstruction();return; } + if(write) if(csrWrite(i32_csr, (old & ~clear) | set)) { ilegalInstruction();return; } rfWrite(rd32, old); - if(write) csrWrite(i32_csr, (old & ~clear) | set); pcWrite(pc + 4); } break; } - default: decodingError(); break; + default: ilegalInstruction(); break; } } else { switch((iBits(0, 2) << 3) + iBits(13, 3)){ @@ -583,10 +601,10 @@ public: uint32_t data; uint32_t address = i16_rf1 + i16_lw_imm; if(address & 0x3){ - exception(0, 4); + exception(0, 4, address); } else { if(dRead(i16_rf1 + i16_lw_imm, 4, &data)) { - exception(1, 5); + exception(1, 5, address); } else { rfWrite(i16_addr2, data); pcWrite(pc + 2); } @@ -595,7 +613,7 @@ public: case 6: { uint32_t address = i16_rf1 + i16_lw_imm; if(address & 0x3){ - exception(0, 6); + exception(0, 6, address); } else { dWrite(address, 4, i16_rf2); pcWrite(pc + 2); @@ -630,10 +648,10 @@ public: uint32_t data; uint32_t address = rf_sp + i16_lwsp_imm; if(address & 0x3){ - exception(0, 4); + exception(0, 4, address); } else { if(dRead(address, 4, &data)){ - exception(1, 5); + exception(1, 5, address); } else { rfWrite(rd32, data); pcWrite(pc + 2); } @@ -659,7 +677,7 @@ public: case 22: { uint32_t address = rf_sp + i16_swsp_imm; if(address & 3){ - exception(0,6); + exception(0,6, address); } else { dWrite(address, 4, regs[iBits(2,5)]); pcWrite(pc + 2); } From 130a69eeaeea64faccf0f43a8963d0953798969f Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 20 Mar 2019 14:14:59 +0100 Subject: [PATCH 048/951] Pass regressions machinemode with CSR config including Supervisor --- src/main/scala/vexriscv/demo/Linux.scala | 2 +- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/demo/Linux.scala b/src/main/scala/vexriscv/demo/Linux.scala index a935dffd..4d11995b 100644 --- a/src/main/scala/vexriscv/demo/Linux.scala +++ b/src/main/scala/vexriscv/demo/Linux.scala @@ -136,7 +136,7 @@ object LinuxGen { divUnrollFactor = 1 ), // new DivPlugin, - new CsrPlugin(CsrPluginConfig.all(0x80000020l)), + new CsrPlugin(CsrPluginConfig.linux(0x80000020l)), // new CsrPlugin(//CsrPluginConfig.all2(0x80000020l).copy(ebreakGen = true)/* // CsrPluginConfig( // catchIllegalAccess = false, diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index cfdb2209..221aeea6 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -89,7 +89,7 @@ object CsrPluginConfig{ mtvecAccess = CsrAccess.READ_WRITE, mtvecInit = mtVecInit, mepcAccess = CsrAccess.READ_WRITE, - mscratchGen = false, + mscratchGen = true, mcauseAccess = CsrAccess.READ_WRITE, mbadaddrAccess = CsrAccess.READ_WRITE, mcycleAccess = CsrAccess.READ_WRITE, From 6c2fe934fd5aea99ff66db6b6c8511ffad6dd129 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 20 Mar 2019 16:27:35 +0100 Subject: [PATCH 049/951] Bring changes and fixies from @kgugala @daveshah1. Thanks guys ! --- .../scala/vexriscv/plugin/CsrPlugin.scala | 51 +++++++++++-------- 1 file changed, 31 insertions(+), 20 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 221aeea6..285360fb 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -51,7 +51,7 @@ case class CsrPluginConfig( ucycleAccess : CsrAccess, wfiGenAsWait : Boolean, ecallGen : Boolean, - mtvecModeGen : Boolean = false, + xtvecModeGen : Boolean = false, noCsrAlu : Boolean = false, wfiGenAsNop : Boolean = false, ebreakGen : Boolean = false, @@ -97,7 +97,7 @@ object CsrPluginConfig{ ucycleAccess = CsrAccess.READ_ONLY, wfiGenAsWait = true, ecallGen = true, - mtvecModeGen = false, + xtvecModeGen = false, noCsrAlu = false, wfiGenAsNop = false, ebreakGen = true, @@ -420,6 +420,11 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception } + case class Xtvec() extends Bundle { + val mode = Bits(2 bits) + val base = UInt(xlen-2 bits) + } + val machineCsr = pipeline plug new Area{ //Define CSR registers // Status => MXR, SUM, TVM, TW, TSE ? @@ -428,11 +433,7 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception val extensions = Reg(Bits(26 bits)) init(misaExtensionsInit) allowUnsetRegToAvoidLatch } - - val mtvec = new Area{ - val mode = Reg(Bits(2 bits)).allowUnsetRegToAvoidLatch - val base = Reg(UInt(xlen-2 bits)).allowUnsetRegToAvoidLatch - } + val mtvec = Reg(Xtvec()).allowUnsetRegToAvoidLatch if(mtvecInit != null) mtvec.mode init(mtvecInit & 0x3) if(mtvecInit != null) mtvec.base init(mtvecInit / 4) @@ -490,7 +491,7 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception //User CSR ucycleAccess(CSR.UCYCLE, mcycle(31 downto 0)) - ucycleAccess(CSR.UCYCLEH, mcycle(31 downto 0)) + ucycleAccess(CSR.UCYCLEH, mcycle(63 downto 32)) } val supervisorCsr = ifGen(supervisorGen) { @@ -508,7 +509,7 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception val sie = new Area { val SEIE, STIE, SSIE = RegInit(False) } - val stvec = Reg(UInt(xlen bits)).allowUnsetRegToAvoidLatch + val stvec = Reg(Xtvec()).allowUnsetRegToAvoidLatch val sscratch = if (sscratchGen) Reg(Bits(xlen bits)) else null val scause = new Area { @@ -526,13 +527,13 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception //Supervisor CSR WRITE_ONLY(CSR.SSTATUS,8 -> sstatus.SPP, 5 -> sstatus.SPIE, 1 -> sstatus.SIE) for(offset <- List(0, 0x200)) { - READ_ONLY(CSR.SSTATUS,8 -> sstatus.SPP, 5 -> sstatus.SPIE, 1 -> sstatus.SIE) + READ_ONLY(CSR.SSTATUS + offset,8 -> sstatus.SPP, 5 -> sstatus.SPIE, 1 -> sstatus.SIE) } READ_ONLY(CSR.SIP, 9 -> sip.SEIP, 5 -> sip.STIP) READ_WRITE(CSR.SIP, 1 -> sip.SSIP) READ_WRITE(CSR.SIE, 9 -> sie.SEIE, 5 -> sie.STIE, 1 -> sie.SSIE) - stvecAccess(CSR.STVEC, stvec) + stvecAccess(CSR.STVEC, 2 -> stvec.base, 0 -> stvec.mode) sepcAccess(CSR.SEPC, sepc) if(sscratchGen) READ_WRITE(CSR.SSCRATCH, sscratch) scauseAccess(CSR.SCAUSE, xlen-1 -> scause.interrupt, 0 -> scause.exceptionCode) @@ -559,7 +560,7 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception if(supervisorGen) { - getInterruptPrivilege(1).privilegeCond = sstatus.SIE && privilege <= "01" + getInterruptPrivilege(1).privilegeCond = (sstatus.SIE && privilege === "01") || privilege === "00" getInterruptPrivilege(1).sources ++= List( InterruptSource(sip.STIP && sie.STIE, 5), InterruptSource(sip.SSIP && sie.SSIE, 1), @@ -567,7 +568,7 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception ) } - getInterruptPrivilege(3).privilegeCond = mstatus.MIE + getInterruptPrivilege(3).privilegeCond = mstatus.MIE || privilege =/= "11" getInterruptPrivilege(3).sources ++= List( InterruptSource(mip.MTIP && mie.MTIE, 7), InterruptSource(mip.MSIP && mie.MSIE, 3), @@ -753,9 +754,16 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception } } + + val xtvec = Xtvec().assignDontCare() + switch(targetPrivilege){ + if(supervisorGen) is(1) { xtvec := supervisorCsr.stvec } + is(3){ xtvec := machineCsr.mtvec } + } + when(hadException || interruptJump){ jumpInterface.valid := True - jumpInterface.payload := (if(!mtvecModeGen) mtvec.base @@ "00" else (mtvec.mode === 0 || hadException) ? (mtvec.base @@ "00") | ((mtvec.base + trapCause) @@ "00") ) + jumpInterface.payload := (if(!xtvecModeGen) xtvec.base @@ "00" else (xtvec.mode === 0 || hadException) ? (xtvec.base @@ "00") | ((xtvec.base + trapCause) @@ "00") ) beforeLastStage.arbitration.flushAll := True privilege := targetPrivilege @@ -789,21 +797,20 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception //Manage MRET / SRET instructions when(arbitration.isValid && input(ENV_CTRL) === EnvCtrlEnum.XRET) { - jumpInterface.payload := mepc jumpInterface.valid := True beforeLastStage.arbitration.flushAll := True switch(input(INSTRUCTION)(29 downto 28)){ is(3){ - mstatus.MIE := mstatus.MPIE mstatus.MPP := U"00" - mstatus.MPIE := True + mstatus.MIE := mstatus.MPIE privilege := mstatus.MPP + jumpInterface.payload := mepc } if(supervisorGen) is(1){ - sstatus.SIE := sstatus.SPIE sstatus.SPP := U"0" - sstatus.SPIE := True + sstatus.SIE := sstatus.SPIE privilege := U"0" @@ sstatus.SPP + jumpInterface.payload := sepc } } } @@ -866,7 +873,11 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception //Manage ECALL instructions if(ecallGen) when(arbitration.isValid && input(ENV_CTRL) === EnvCtrlEnum.ECALL){ selfException.valid := True - selfException.code := 11 + switch(privilege) { + is(0) { selfException.code := 8 } + if(supervisorGen) is(1) { selfException.code := 9 } + default { selfException.code := 11 } + } } From 39b2803914c0677ff2ebdc32ba3bf8f00111f4df Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 20 Mar 2019 20:27:47 +0100 Subject: [PATCH 050/951] Fix some CsrPlugin flags issues --- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 285360fb..ac606757 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -803,12 +803,14 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception is(3){ mstatus.MPP := U"00" mstatus.MIE := mstatus.MPIE + mstatus.MPIE := True privilege := mstatus.MPP jumpInterface.payload := mepc } if(supervisorGen) is(1){ sstatus.SPP := U"0" sstatus.SIE := sstatus.SPIE + sstatus.SPIE := True privilege := U"0" @@ sstatus.SPP jumpInterface.payload := sepc } @@ -864,7 +866,7 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception //Manage MRET / SRET instructions when(arbitration.isValid && input(ENV_CTRL) === EnvCtrlEnum.XRET) { //TODO check MPP value too - when(input(INSTRUCTION)(29 downto 28).asUInt =/= privilege) { + when(input(INSTRUCTION)(29 downto 28).asUInt > privilege) { illegalInstruction := True } } From 6f2e5a0eb73340bab93e393a13796716aaf0c036 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 20 Mar 2019 20:28:04 +0100 Subject: [PATCH 051/951] goldenmodel Implement some of the supervisor CSR --- src/test/cpp/regression/main.cpp | 182 +++++++++++++++++++++---------- 1 file changed, 123 insertions(+), 59 deletions(-) diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index a3e7e0bc..99f7ad4b 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -190,21 +190,49 @@ class success : public std::exception { }; #define MCYCLEH 0xB80 // MRW Upper 32 bits of mcycle, RV32I only. #define MINSTRETH 0xB82 // MRW Upper 32 bits of minstret, RV32I only. + +#define SSTATUS 0x100 +#define SIE 0x104 +#define STVEC 0x105 +#define SCOUNTEREN 0x106 +#define SSCRATCH 0x140 +#define SEPC 0x141 +#define SCAUSE 0x142 +#define STVAL 0x143 +#define SIP 0x144 +#define SATP 0x180 + + + +#define SSTATUS_SIE 0x00000002 +#define SSTATUS_SPIE 0x00000020 +#define SSTATUS_SPP 0x00000100 + class RiscvGolden { public: int32_t pc, lastPc; int32_t regs[32]; + uint32_t mscratch; uint32_t misa; + uint32_t privilege; + + uint32_t medeleg; + uint32_t mideleg; union status { uint32_t raw; struct { - uint32_t _1 : 3; + uint32_t _1a : 1; + uint32_t sie : 1; + uint32_t _1b : 1; uint32_t mie : 1; - uint32_t _2 : 3; + uint32_t _2a : 1; + uint32_t spie : 1; + uint32_t _2b : 1; uint32_t mpie : 1; - uint32_t _3 : 3; + uint32_t spp : 1; + uint32_t _3 : 2; uint32_t mpp : 2; }; }__attribute__((packed)) status; @@ -235,13 +263,16 @@ public: }; }__attribute__((packed)) mie; - union mtvec { + union Xtvec { uint32_t raw; - struct { + struct __attribute__((packed)) { uint32_t _1 : 2; uint32_t base : 30; }; - }__attribute__((packed)) mtvec; + }; + + Xtvec mtvec, stvec; + union mcause { @@ -253,19 +284,16 @@ public: }__attribute__((packed)) mcause; - //Machine CSR -// misaAccess(CSR.MISA, xlen-2 -> misa.base , 0 -> misa.extensions) -// READ_ONLY(CSR.MIP, 11 -> mip.MEIP, 7 -> mip.MTIP) -// READ_WRITE(CSR.MIP, 3 -> mip.MSIP) -// READ_WRITE(CSR.MIE, 11 -> mie.MEIE, 7 -> mie.MTIE, 3 -> mie.MSIE) -// -// mtvecAccess(CSR.MTVEC, mtvec) -// mepcAccess(CSR.MEPC, mepc) -// READ_WRITE(CSR.MSTATUS,11 -> mstatus.MPP, 7 -> mstatus.MPIE, 3 -> mstatus.MIE) -// if(mscratchGen) READ_WRITE(CSR.MSCRATCH, mscratch) -// mcauseAccess(CSR.MCAUSE, xlen-1 -> mcause.interrupt, 0 -> mcause.exceptionCode) -// mbadaddrAccess(CSR.MBADADDR, mbadaddr) - //READ_WRITE(CSR.MSTATUS,11 -> mstatus.MPP, 7 -> mstatus.MPIE, 3 -> mstatus.MIE) + union scause { + uint32_t raw; + struct { + uint32_t exceptionCode : 31; + uint32_t interrupt : 1; + }; + }__attribute__((packed)) scause; + + + RiscvGolden() { pc = 0x80000000; regs[0] = 0; @@ -281,6 +309,9 @@ public: mepc = 0; misa = 0; //TODO status.mpp = 3; + privilege = 3; + medeleg = 0; + mideleg = 0; } virtual void rfWrite(int32_t address, int32_t data) { @@ -296,8 +327,8 @@ public: exception(0, 0, target); } } - uint32_t mbadaddr; - uint32_t mepc; + uint32_t mbadaddr, sbadaddr; + uint32_t mepc, sepc; virtual bool iRead(int32_t address, uint32_t *data) = 0; virtual bool dRead(int32_t address, int32_t size, uint32_t *data) = 0; @@ -310,18 +341,36 @@ public: exception(interrupt, cause, true, value); } void exception(bool interrupt,int32_t cause, bool valueWrite, uint32_t value) { - if(valueWrite){ - mbadaddr = value; - } - mcause.interrupt = interrupt; - mcause.exceptionCode = cause; - status.mie = false; - status.mpie = status.mie; - mepc = pc; - pcWrite(mtvec.base << 2); + uint32_t deleg = interrupt ? mideleg : medeleg; + uint32_t targetPrivilege = 3; + if(deleg & (1 << cause)) targetPrivilege = 1; + Xtvec xtvec = targetPrivilege == 3 ? mtvec : stvec; + + switch(targetPrivilege){ + case 3: + if(valueWrite) mbadaddr = value; + mcause.interrupt = interrupt; + mcause.exceptionCode = cause; + status.mie = false; + status.mpie = status.mie; + status.mpp = privilege; + mepc = pc; + break; + case 1: + if(valueWrite) sbadaddr = value; + scause.interrupt = interrupt; + scause.exceptionCode = cause; + status.sie = false; + status.spie = status.sie; + status.spp = privilege; + sepc = pc; + break; + } + + privilege = targetPrivilege; + pcWrite(xtvec.base << 2); if(interrupt) livenessInterrupt = 0; - //status.MPP := privilege if(!interrupt) step(); //As VexRiscv instruction which trap do not reach writeback stage fire } @@ -333,33 +382,37 @@ public: } - uint32_t* csrPtr(int32_t csr){ - switch(csr){ - case MSTATUS: return &status.raw; break; - case MIP: return &mip.raw; break; - case MIE: return &mie.raw; break; - case MTVEC: return &mtvec.raw; break; - case MCAUSE: return &mcause.raw; break; - case MBADADDR: return &mbadaddr; break; - case MEPC: return &mepc; break; - case MSCRATCH: return &mscratch; break; - case MISA: return &misa; break; - default: ilegalInstruction(); return NULL; break; - } - } virtual bool csrRead(int32_t csr, uint32_t *value){ - auto ptr = csrPtr(csr); - if(ptr){ - *value = *ptr; + switch(csr){ + case MSTATUS: *value = status.raw; break; + case MIP: *value = mip.raw; break; + case MIE: *value = mie.raw; break; + case MTVEC: *value = mtvec.raw; break; + case MCAUSE: *value = mcause.raw; break; + case MBADADDR: *value = mbadaddr; break; + case MEPC: *value = mepc; break; + case MSCRATCH: *value = mscratch; break; + case MISA: *value = misa; break; + default: return true; break; } - return ptr == NULL; + return false; } virtual bool csrWrite(int32_t csr, uint32_t value){ - auto ptr = csrPtr(csr); - if(ptr) *csrPtr(csr) = value; - return ptr == NULL; + switch(csr){ + case MSTATUS: status.raw = value; break; + case MIP: mip.raw = value; break; + case MIE: mie.raw = value; break; + case MTVEC: mtvec.raw = value; break; + case MCAUSE: mcause.raw = value; break; + case MBADADDR: mbadaddr = value; break; + case MEPC: mepc = value; break; + case MSCRATCH: mscratch = value; break; + case MISA: misa = value; break; + default: ilegalInstruction(); return true; break; + } + return false; } @@ -559,19 +612,30 @@ public: if(i32_func3 == 0){ switch(i){ case 0x30200073:{ //MRET - status.mie = status.mpie; - //privilege := mstatus.MPP - pcWrite(mepc); - }break; + if(privilege < 3){ ilegalInstruction(); return;} + status.mpp = 0; + status.mie = status.mpie; + status.mpie = 1; + privilege = status.mpp; + pcWrite(mepc); + }break; + case 0x10200073:{ //SRET + if(privilege < 1){ ilegalInstruction(); return;} + status.spp = 0; + status.sie = status.spie; + status.spie = 1; + privilege = status.spp; + pcWrite(sepc); + }break; case 0x00000073:{ //ECALL exception(0, 11); - }break; + }break; case 0x10500073:{ //WFI pcWrite(pc + 4); - }break; + }break; default: ilegalInstruction(); - break; + break; } } else { //CSR From 7cbe399f1f710a7f3291c1a911257c66ec4f4b48 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 20 Mar 2019 23:25:52 +0100 Subject: [PATCH 052/951] Fix some supervisor CSR access --- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index ac606757..baa6b758 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -525,13 +525,14 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception } //Supervisor CSR - WRITE_ONLY(CSR.SSTATUS,8 -> sstatus.SPP, 5 -> sstatus.SPIE, 1 -> sstatus.SIE) - for(offset <- List(0, 0x200)) { - READ_ONLY(CSR.SSTATUS + offset,8 -> sstatus.SPP, 5 -> sstatus.SPIE, 1 -> sstatus.SIE) + for(offset <- List(CSR.MSTATUS, CSR.SSTATUS)) READ_WRITE(offset,8 -> sstatus.SPP, 5 -> sstatus.SPIE, 1 -> sstatus.SIE) + for(offset <- List(CSR.MIP, CSR.SIP)) { + READ_ONLY(offset, 9 -> sip.SEIP, 5 -> sip.STIP) + READ_WRITE(offset, 1 -> sip.SSIP) } - READ_ONLY(CSR.SIP, 9 -> sip.SEIP, 5 -> sip.STIP) - READ_WRITE(CSR.SIP, 1 -> sip.SSIP) - READ_WRITE(CSR.SIE, 9 -> sie.SEIE, 5 -> sie.STIE, 1 -> sie.SSIE) + + for(offset <- List(CSR.MIE, CSR.SIE)) READ_WRITE(offset, 9 -> sie.SEIE, 5 -> sie.STIE, 1 -> sie.SSIE) + stvecAccess(CSR.STVEC, 2 -> stvec.base, 0 -> stvec.mode) sepcAccess(CSR.SEPC, sepc) From ea56481eadce4c2a014939da7e85bcb09aa50f06 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 20 Mar 2019 23:26:08 +0100 Subject: [PATCH 053/951] Add supervisor CSR in the riscv golden model --- src/test/cpp/regression/main.cpp | 68 +++++++++++++++++++++++--------- 1 file changed, 50 insertions(+), 18 deletions(-) diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 99f7ad4b..94d0f3f5 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -213,7 +213,7 @@ public: int32_t pc, lastPc; int32_t regs[32]; - uint32_t mscratch; + uint32_t mscratch, sscratch; uint32_t misa; uint32_t privilege; @@ -241,27 +241,39 @@ public: union mip { uint32_t raw; struct { - uint32_t _1 : 3; + uint32_t _1a : 1; + uint32_t ssip : 1; + uint32_t _1b : 1; uint32_t msip : 1; - uint32_t _2 : 3; + uint32_t _2a : 1; + uint32_t stip : 1; + uint32_t _2b : 1; uint32_t mtip : 1; - uint32_t _3 : 3; - uint32_t meip : 2; + uint32_t _3a : 1; + uint32_t seip : 1; + uint32_t _3b : 1; + uint32_t meip : 1; }; - }__attribute__((packed)) mip; + }__attribute__((packed)) ip; union mie { uint32_t raw; struct { - uint32_t _1 : 3; + uint32_t _1a : 1; + uint32_t ssie : 1; + uint32_t _1b : 1; uint32_t msie : 1; - uint32_t _2 : 3; + uint32_t _2a : 1; + uint32_t stie : 1; + uint32_t _2b : 1; uint32_t mtie : 1; - uint32_t _3 : 3; - uint32_t meie : 2; + uint32_t _3a : 1; + uint32_t seie : 1; + uint32_t _3b : 1; + uint32_t meie : 1; }; - }__attribute__((packed)) mie; + }__attribute__((packed)) ie; union Xtvec { uint32_t raw; @@ -301,8 +313,8 @@ public: regs[i] = 0; status.raw = 0; - mip.raw = 0; - mie.raw = 0; + ip.raw = 0; + ie.raw = 0; mtvec.raw = 0x80000020; mcause.raw = 0; mbadaddr = 0; @@ -386,30 +398,50 @@ public: virtual bool csrRead(int32_t csr, uint32_t *value){ switch(csr){ case MSTATUS: *value = status.raw; break; - case MIP: *value = mip.raw; break; - case MIE: *value = mie.raw; break; + case MIP: *value = ip.raw; break; + case MIE: *value = ie.raw; break; case MTVEC: *value = mtvec.raw; break; case MCAUSE: *value = mcause.raw; break; case MBADADDR: *value = mbadaddr; break; case MEPC: *value = mepc; break; case MSCRATCH: *value = mscratch; break; case MISA: *value = misa; break; + + case SSTATUS: *value = status.raw & 0x133; break; + case SIP: *value = ip.raw & 0x333; break; + case SIE: *value = ie.raw & 0x333; break; + case STVEC: *value = stvec.raw; break; + case SCAUSE: *value = scause.raw; break; + case STVAL: *value = sbadaddr; break; + case SEPC: *value = sepc; break; + case SSCRATCH: *value = sscratch; break; default: return true; break; } return false; } +#define maskedWrite(dst, src, mask) dst=(dst & ~mask)|(src & mask); virtual bool csrWrite(int32_t csr, uint32_t value){ switch(csr){ case MSTATUS: status.raw = value; break; - case MIP: mip.raw = value; break; - case MIE: mie.raw = value; break; + case MIP: ip.raw = value; break; + case MIE: ie.raw = value; break; case MTVEC: mtvec.raw = value; break; case MCAUSE: mcause.raw = value; break; case MBADADDR: mbadaddr = value; break; case MEPC: mepc = value; break; case MSCRATCH: mscratch = value; break; case MISA: misa = value; break; + + case SSTATUS: maskedWrite(status.raw, value,0x133); break; + case SIP: maskedWrite(ip.raw, value,0x333); break; + case SIE: maskedWrite(ie.raw, value,0x333); break; + case STVEC: stvec.raw = value; break; + case SCAUSE: scause.raw = value; break; + case STVAL: sbadaddr = value; break; + case SEPC: sepc = value; break; + case SSCRATCH: sscratch = value; break; + default: ilegalInstruction(); return true; break; } return false; @@ -420,7 +452,7 @@ public: int livenessInterrupt = 0; virtual void liveness(bool mIntTimer, bool mIntExt){ livenessStep++; - bool interruptRequest = (mie.mtie && mIntTimer); + bool interruptRequest = (ie.mtie && mIntTimer); if(interruptRequest){ if(status.mie){ livenessInterrupt++; From b7ddd02fc67aa3990c2fcc8449f2efe6cc1f5cdd Mon Sep 17 00:00:00 2001 From: Tom Verbeure Date: Thu, 21 Mar 2019 05:17:07 +0000 Subject: [PATCH 054/951] IBusSimplePlugin README. --- README.md | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 11105ecd..5aeddc66 100644 --- a/README.md +++ b/README.md @@ -337,16 +337,16 @@ Here are some timing and area measurements of the Murax SoC: ``` Murax interlocked stages (0.45 DMIPS/Mhz, 8 bits GPIO) -> - Artix 7 -> 299 Mhz 984 LUT 1186 FF + Artix 7 -> 299 Mhz 984 LUT 1186 FF Cyclone V -> 175 Mhz 710 ALMs - Cyclone IV -> 137 Mhz 1,436 LUT 1,193 FF + Cyclone IV -> 137 Mhz 1,436 LUT 1,193 FF iCE40 -> 48 Mhz 2337 LC (icestorm) iCE40Ultra -> 20 Mhz 2337 LC (icestorm) MuraxFast bypassed stages (0.65 DMIPS/Mhz, 8 bits GPIO) -> - Artix 7 -> 294 Mhz 1128 LUT 1219 FF + Artix 7 -> 294 Mhz 1128 LUT 1219 FF Cyclone V -> 165 Mhz 840 ALMs - Cyclone IV -> 141 Mhz 1,680 LUT 1,227 FF + Cyclone IV -> 141 Mhz 1,680 LUT 1,227 FF iCE40 -> 48 Mhz 2702 LC (icestorm) iCE40Ultra -> 22 Mhz 2702 LC (icestorm) ``` @@ -653,18 +653,18 @@ This chapter describes plugins currently implemented. This plugin implement the CPU frontend (instruction fetch) via a very simple and neutral memory interface going outside the CPU. | Parameters | type | description | -| ------ | ----------- | ------ | -| catchAccessFault | Boolean | If an the read response specify an read error and this parameter is true, it will generate an CPU exception trap | -| resetVector | BigInt | Address of the program counter after the reset | -| cmdForkOnSecondStage | Boolean | By default jump have an asynchronous immediate effect on the program counter, which allow to reduce the branch penalties by one cycle but could reduce the FMax as it will combinatorialy drive the instruction bus address signal. To avoid this you can set this parameter to true, which will make the jump affecting the programm counter in a sequancial way, which will cut the combinatorial path but add one additional cycle of penalty when a jump occur. | -| cmdForkPersistence | Boolean | If this parameter is false, then request on the iBus can disappear/change before their completion. Which reduce area but isn't safe/supported by many arbitration/slaves. If you set this parameter to true, then the iBus cmd will stay until they are completed. -| compressedGen | Boolean | Enable RVC support | -| busLatencyMin | Int | Specify the minimal latency between the iBus.cmd and iBus.rsp, which will add the corresponding number of stages into the frontend to keep the IPC to 1.| -| injectorStage | Boolean | Add a stage between the frontend and the decode stage of the CPU to improve FMax. (busLatencyMin + injectorStage) should be at least two. | -| prediction | BranchPrediction | Can be set to NONE/STATIC/DYNAMIC/DYNAMIC_TARGET to specify the branch predictor implementation, see bellow for more descriptions | -| historyRamSizeLog2 | Int | Specify the number of entries in the direct mapped prediction cache of DYNAMIC/DYNAMIC_TARGET implementation. 2 pow historyRamSizeLog2 entries | +| ------ | ----------- | ------ | +| catchAccessFault | Boolean | When true, an instruction read response with read error asserted results in a CPU exception trap. | +| resetVector | BigInt | Address of the program counter after the reset. | +| cmdForkOnSecondStage | Boolean | When false, branches immediately update the program counter. This minimizes branch penalties but might reduce FMax because the instruction bus address signal is a combinatorial path. When true, this combinatorial path is removed and the program counter is updated one cycle after a branch is detected. While FMax may improve, an additional branch penalty will be incurred as well. | +| cmdForkPersistence | Boolean | When false, requests on the iBus can disappear/change before they are acknowledged. This reduces area but isn't safe/supported by many arbitration/slaves. When true, once initiated, iBus requests will stay until they are acknowledged. | +| compressedGen | Boolean | Enable RISC-V compressed instruction (RVC) support. | +| busLatencyMin | Int | Specifies the minimal latency between the iBus.cmd and iBus.rsp. A corresponding number of stages are added to the frontend to keep the IPC to 1.| +| injectorStage | Boolean | When true, a stage between the frontend and the decode stage of the CPU is added to improve FMax. (busLatencyMin + injectorStage) should be at least two. | +| prediction | BranchPrediction | Can be set to NONE/STATIC/DYNAMIC/DYNAMIC_TARGET to specify the branch predictor implementation. See below for more details. | +| historyRamSizeLog2 | Int | Specify the number of entries in the direct mapped prediction cache of DYNAMIC/DYNAMIC_TARGET implementation. 2 pow historyRamSizeLog2 entries. | -Here is the SimpleBus interface definition +Here is the SimpleBus interface definition: ```scala case class IBusSimpleCmd() extends Bundle{ @@ -695,9 +695,9 @@ case class IBusSimpleBus(interfaceKeepData : Boolean) extends Bundle with IMaste Setting cmdForkPersistence and cmdForkOnSecondStage improves iBus cmd timings. -Note that bridges are implemented to convert this interface into AXI4 and Avalon +The iBusSimplePlugin includes bridges to convert from the IBusSimpleBus to AXI4, Avalon, and Wishbone interfaces. -The jump interface implemented by this plugin allow all other plugin to request jumps. The stage argument specify from which stage the jump is asked, which will allow the PcManagerSimplePlugin plugin to manage priorities between jump requests. +This plugin implements a jump interface that allows all other plugins to issue a jump: ```scala trait JumpService{ @@ -705,6 +705,8 @@ trait JumpService{ } ``` +The stage argument specifies the stage from which the jump is asked. This allows the PcManagerSimplePlugin plugin to manage priorities between jump requests from +diffent stages. #### IBusCachedPlugin From 02a6312912ede910d8c2353dc7330a5f622844f6 Mon Sep 17 00:00:00 2001 From: Tom Verbeure Date: Thu, 21 Mar 2019 05:34:15 +0000 Subject: [PATCH 055/951] Update IBusCachedPlugin manual. --- README.md | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 5aeddc66..c109daef 100644 --- a/README.md +++ b/README.md @@ -714,24 +714,25 @@ Simple and light multi-way instruction cache. | Parameters | type | description | | ------ | ----------- | ------ | -| cacheSize | Int | Total storage capacity of the cache | -| bytePerLine | Int | Number of bytes per cache line | -| wayCount | Int | Number of cache ways | -| twoCycleRam | Boolean | Check the tags values in the decode stage instead of the fetch stage to relax timings | -| asyncTagMemory | Boolean | Read the cache tags in a asyncronus manner instead of syncronous one | -| addressWidth | Int | Address width, should be 32 | -| cpuDataWidth | Int | Cpu data width, should be 32 | -| memDataWidth | Int | Memory data width, could potentialy be something else than 32, but only 32 is currently tested | -| catchIllegalAccess | Boolean | Catch when a memory access is done on non valid memory address (MMU) | -| catchAccessFault | Boolean | Catch when the memeory bus is responding with an error | -| catchMemoryTranslationMiss | Boolean | Catch when the MMU miss a TLB | -| resetVector | BigInt | Address of the program counter after the reset | -| relaxedPcCalculation | Boolean | By default jump have an asynchronous immediate effect on the program counter, which allow to reduce the branch penalties by one cycle but could reduce the FMax as it will combinatorialy drive the instruction bus address signal. To avoid this you can set this parameter to true, which will make the jump affecting the programm counter in a sequancial way, which will cut the combinatorial path but add one additional cycle of penalty when a jump occur. | -| compressedGen | Boolean | Enable RVC support | -| prediction | BranchPrediction | Can be set to NONE/STATIC/DYNAMIC/DYNAMIC_TARGET to specify the branch predictor implementation, see bellow for more descriptions | +| resetVector | BigInt | Address of the program counter after the reset. | +| relaxedPcCalculation | Boolean | When false, branches immediately update the program counter. This minimizes branch penalties but might reduce FMax because the instruction bus address signal is a combinatorial path. When true, this combinatorial path is removed and the program counter is updated one cycle after a branch is detected. While FMax may improve, an additional branch penalty will be incurred as well. | +| prediction | BranchPrediction | Can be set to NONE/STATIC/DYNAMIC/DYNAMIC_TARGET to specify the branch predictor implementation. See below for more details. | | historyRamSizeLog2 | Int | Specify the number of entries in the direct mapped prediction cache of DYNAMIC/DYNAMIC_TARGET implementation. 2 pow historyRamSizeLog2 entries | +| compressedGen | Boolean | Enable RISC-V compressed instruction (RVC) support. | -Note: If you enable the twoCycleRam option and if wayCount is bigger than one, then the register file plugin should be configured to read the regFile in a asynchronous manner. +| config.cacheSize | Int | Total storage capacity of the cache in bytes. | +| config.bytePerLine | Int | Number of bytes per cache line | +| config.wayCount | Int | Number of cache ways | +| config.twoCycleRam | Boolean | Check the tags values in the decode stage instead of the fetch stage to relax timings | +| config.asyncTagMemory | Boolean | Read the cache tags in an asynchronous manner instead of syncronous one | +| config.addressWidth | Int | CPU address width. Should be 32 | +| config.cpuDataWidth | Int | CPU data width. Should be 32 | +| config.memDataWidth | Int | Memory data width. Could potentialy be something else than 32, but only 32 is currently tested | +| config.catchIllegalAccess | Boolean | Catch when a memory access is done on non-valid memory address (MMU) | +| config.catchAccessFault | Boolean | Catch when the memeory bus is responding with an error | +| config.catchMemoryTranslationMiss | Boolean | Catch when the MMU miss a TLB | + +Note: If you enable the twoCycleRam option and if wayCount is bigger than one, then the register file plugin should be configured to read the regFile in an asynchronous manner. #### DecoderSimplePlugin From 3f5605f22e3cb69bd0784a6ae246309ad64f8b15 Mon Sep 17 00:00:00 2001 From: Tom Verbeure Date: Thu, 21 Mar 2019 05:36:30 +0000 Subject: [PATCH 056/951] Fix table. --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index c109daef..999ae717 100644 --- a/README.md +++ b/README.md @@ -719,7 +719,6 @@ Simple and light multi-way instruction cache. | prediction | BranchPrediction | Can be set to NONE/STATIC/DYNAMIC/DYNAMIC_TARGET to specify the branch predictor implementation. See below for more details. | | historyRamSizeLog2 | Int | Specify the number of entries in the direct mapped prediction cache of DYNAMIC/DYNAMIC_TARGET implementation. 2 pow historyRamSizeLog2 entries | | compressedGen | Boolean | Enable RISC-V compressed instruction (RVC) support. | - | config.cacheSize | Int | Total storage capacity of the cache in bytes. | | config.bytePerLine | Int | Number of bytes per cache line | | config.wayCount | Int | Number of cache ways | From 59a2817e5ccec281c2955322c076177b111bb5f4 Mon Sep 17 00:00:00 2001 From: Tom Verbeure Date: Thu, 21 Mar 2019 05:53:27 +0000 Subject: [PATCH 057/951] Update DecoderSimplePlugin manual. --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 999ae717..0a901cb0 100644 --- a/README.md +++ b/README.md @@ -737,12 +737,12 @@ Note: If you enable the twoCycleRam option and if wayCount is bigger than one, t This plugin provides instruction decoding capabilities to others plugins. -For instance, for a given instruction, the pipeline hazard plugin needs to know if it uses the register file source 1/2 in order stall the pipeline until the hazard is gone. +For instance, for a given instruction, the pipeline hazard plugin needs to know if it uses the register file source 1/2 in order to stall the pipeline until the hazard is gone. To provide this kind of information, each plugin which implements an instruction documents this kind of information to the DecoderSimplePlugin plugin. | Parameters | type | description | | ------ | ----------- | ------ | -| catchIllegalInstruction | Boolean | If set to true, instruction which have no decoding specification will generate a trap exception | +| catchIllegalInstruction | Boolean | When true, instructions that don't match a decoding specification will generate a trap exception | Here is a usage example : @@ -754,11 +754,11 @@ Here is a usage example : //Decoding specification when the 'key' pattern is recognized in the instruction List( - IS_SIMD_ADD -> True, - REGFILE_WRITE_VALID -> True, //Enable the register file write + IS_SIMD_ADD -> True, //Inform the pipeline that the current instruction is a SIMD_ADD instruction + REGFILE_WRITE_VALID -> True, //Notify the hazard management unit that this instruction writes to the register file BYPASSABLE_EXECUTE_STAGE -> True, //Notify the hazard management unit that the instruction result is already accessible in the EXECUTE stage (Bypass ready) BYPASSABLE_MEMORY_STAGE -> True, //Same as above but for the memory stage - RS1_USE -> True, //Notify the hazard management unit that this instruction use the RS1 value + RS1_USE -> True, //Notify the hazard management unit that this instruction uses the RS1 value RS2_USE -> True //Same than above but for RS2. ) ) From af2acbd46e6c97e1825529abe4165cb7726a1743 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 22 Mar 2019 01:10:17 +0100 Subject: [PATCH 058/951] Got the new MMU design to pass simple tests #60 --- src/main/scala/vexriscv/Pipeline.scala | 7 + src/main/scala/vexriscv/demo/Linux.scala | 2 +- .../scala/vexriscv/plugin/CsrPlugin.scala | 4 +- .../vexriscv/plugin/DBusSimplePlugin.scala | 4 +- src/main/scala/vexriscv/plugin/Fetcher.scala | 3 +- .../vexriscv/plugin/IBusSimplePlugin.scala | 4 +- .../scala/vexriscv/plugin/MmuPlugin.scala | 40 +- src/main/scala/vexriscv/plugin/Plugin.scala | 6 +- src/test/cpp/raw/mmu/.gitignore | 4 + src/test/cpp/raw/mmu/build/mmu.asm | 12375 +++++++++++++++- src/test/cpp/raw/mmu/build/mmu.hex | 3300 ++++- src/test/cpp/raw/mmu/src/crt.S | 168 +- src/test/cpp/raw/mmu/src/ld | 2 +- src/test/cpp/regression/main.cpp | 104 +- src/test/cpp/regression/makefile | 2 +- 15 files changed, 15949 insertions(+), 76 deletions(-) create mode 100644 src/test/cpp/raw/mmu/.gitignore diff --git a/src/main/scala/vexriscv/Pipeline.scala b/src/main/scala/vexriscv/Pipeline.scala index 898094ee..9a518bd6 100644 --- a/src/main/scala/vexriscv/Pipeline.scala +++ b/src/main/scala/vexriscv/Pipeline.scala @@ -44,9 +44,16 @@ trait Pipeline { plugins.foreach(_.pipeline = this.asInstanceOf[T]) plugins.foreach(_.setup(this.asInstanceOf[T])) + plugins.foreach{ p => + p.parentScope = Component.current.dslBody //Put the given plugin as a child of the current component + p.reflectNames() + } + //Build plugins plugins.foreach(_.build(this.asInstanceOf[T])) + + //Interconnect stages class KeyInfo{ var insertStageId = Int.MaxValue diff --git a/src/main/scala/vexriscv/demo/Linux.scala b/src/main/scala/vexriscv/demo/Linux.scala index 4d11995b..05d2af5f 100644 --- a/src/main/scala/vexriscv/demo/Linux.scala +++ b/src/main/scala/vexriscv/demo/Linux.scala @@ -170,7 +170,7 @@ object LinuxGen { ) ) if(withMmu) config.plugins += new MmuPlugin( - virtualRange = _(31 downto 28) === 0xC, + virtualRange = a => True, ioRange = _(31 downto 28) === 0xF, allowUserIo = true ) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index baa6b758..fc906f2a 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -109,7 +109,7 @@ object CsrPluginConfig{ sbadaddrAccess = CsrAccess.READ_WRITE, scycleAccess = CsrAccess.READ_WRITE, sinstretAccess = CsrAccess.READ_WRITE, - satpAccess = CsrAccess.READ_WRITE, + satpAccess = CsrAccess.NONE, //Implemented into the MMU plugin medelegAccess = CsrAccess.READ_WRITE, midelegAccess = CsrAccess.READ_WRITE, pipelineCsrRead = false, @@ -643,7 +643,7 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception }) val sortedByStage = groupedByStage.sortWith((a, b) => pipeline.indexOf(a.stage) < pipeline.indexOf(b.stage)) - sortedByStage.zipWithIndex.foreach(e => e._1.port.setName(e._1.stage.getName() + "_exception_agregat")) +// sortedByStage.zipWithIndex.foreach(e => e._1.port.setName(e._1.stage.getName() + "_exception_agregat")) exceptionValids := exceptionValidsRegs for(portInfo <- sortedByStage; port = portInfo.port ; stage = portInfo.stage; stageId = indexOf(portInfo.stage)) { when(port.valid) { diff --git a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala index 9bf9cd39..225644ae 100644 --- a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala @@ -223,7 +223,7 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, var redoBranch : Flow[UInt] = null val catchSomething = catchAccessFault || catchAddressMisaligned || memoryTranslatorPortConfig != null - var dBusAccess : DBusAccess = null + @dontName var dBusAccess : DBusAccess = null override def newDBusAccess(): DBusAccess = { assert(dBusAccess == null) dBusAccess = DBusAccess() @@ -383,6 +383,8 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, if(catchSomething) memoryExceptionPort.valid := False if(memoryTranslatorPortConfig != null) redoBranch.valid := False } + + arbitration.flushAll setWhen(redoBranch.valid) } diff --git a/src/main/scala/vexriscv/plugin/Fetcher.scala b/src/main/scala/vexriscv/plugin/Fetcher.scala index a6c166a9..625ae518 100644 --- a/src/main/scala/vexriscv/plugin/Fetcher.scala +++ b/src/main/scala/vexriscv/plugin/Fetcher.scala @@ -607,8 +607,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, } def stageXToIBusRsp[T <: Data](stage : Any, input : T): (T) ={ - iBusRsp.stages.dropWhile(_ != stage).foldLeft(input)((data,stage) => RegNextWhen(data, stage.output.ready)) - + iBusRsp.stages.dropWhile(_ != stage).tail.foldLeft(input)((data,stage) => RegNextWhen(data, stage.output.ready)) } } diff --git a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala index fe4348a7..f87a197e 100644 --- a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala @@ -305,6 +305,8 @@ class IBusSimplePlugin(resetVector : BigInt, redoBranch.payload := stages.last.input.payload } + decode.arbitration.flushAll setWhen(redoBranch.valid) + if(catchSomething){ decodeExceptionPort.code.assignDontCare() decodeExceptionPort.badAddr := join.pc //TODO Should it be the physical address insted ? @@ -315,7 +317,7 @@ class IBusSimplePlugin(resetVector : BigInt, } if(memoryTranslatorPortConfig != null) { val privilegeService = pipeline.serviceElse(classOf[PrivilegeService], PrivilegeServiceDefault()) - when(stages.last.input.valid && (mmu.joinCtx.exception || !mmu.joinCtx.allowExecute || (!mmu.joinCtx.allowUser && privilegeService.isUser(decode)))){ + when(stages.last.input.valid && !mmu.joinCtx.refilling && (mmu.joinCtx.exception || !mmu.joinCtx.allowExecute || (!mmu.joinCtx.allowUser && privilegeService.isUser(decode)))){ decodeExceptionPort.code := 12 exceptionDetected := True } diff --git a/src/main/scala/vexriscv/plugin/MmuPlugin.scala b/src/main/scala/vexriscv/plugin/MmuPlugin.scala index 25f47d9c..5248c251 100644 --- a/src/main/scala/vexriscv/plugin/MmuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/MmuPlugin.scala @@ -42,7 +42,7 @@ class MmuPlugin(virtualRange : UInt => Bool, allowUserIo : Boolean, allowMachineModeMmu : Boolean = false) extends Plugin[VexRiscv] with MemoryTranslator { - var dBus : DBusAccess = null + var dBusAccess : DBusAccess = null val portsInfo = ArrayBuffer[MmuPort]() override def newTranslationPort(priority : Int,args : Any): MemoryTranslatorBus = { @@ -61,7 +61,7 @@ class MmuPlugin(virtualRange : UInt => Bool, decoderService.add(SFENCE_VMA, List(IS_SFENCE_VMA -> True)) - dBus = pipeline.service(classOf[DBusAccessService]).newDBusAccess() + dBusAccess = pipeline.service(classOf[DBusAccessService]).newDBusAccess() } override def build(pipeline: VexRiscv): Unit = { @@ -142,19 +142,19 @@ class MmuPlugin(virtualRange : UInt => Bool, } val dBusRsp = new Area{ val pte = PTE() - pte.assignFromBits(dBus.rsp.data) - val exception = !pte.V || (!pte.R && pte.W) || dBus.rsp.error + pte.assignFromBits(dBusAccess.rsp.data) + val exception = !pte.V || (!pte.R && pte.W) || dBusAccess.rsp.error val leaf = pte.R || pte.X } - val pteBuffer = RegNextWhen(dBusRsp.pte, dBus.rsp.valid) + val pteBuffer = RegNextWhen(dBusRsp.pte, dBusAccess.rsp.valid) - dBus.cmd.valid := False - dBus.cmd.write := False - dBus.cmd.size := 2 - dBus.cmd.address.assignDontCare() - dBus.cmd.data.assignDontCare() - dBus.cmd.writeMask.assignDontCare() + dBusAccess.cmd.valid := False + dBusAccess.cmd.write := False + dBusAccess.cmd.size := 2 + dBusAccess.cmd.address.assignDontCare() + dBusAccess.cmd.data.assignDontCare() + dBusAccess.cmd.writeMask.assignDontCare() switch(state){ is(State.IDLE){ for(port <- portsInfo.sortBy(_.priority)){ @@ -168,14 +168,14 @@ class MmuPlugin(virtualRange : UInt => Bool, } } is(State.L1_CMD){ - dBus.cmd.valid := True - dBus.cmd.address := satp.ppn @@ vpn1 @@ U"00" - when(dBus.cmd.ready){ + dBusAccess.cmd.valid := True + dBusAccess.cmd.address := satp.ppn @@ vpn1 @@ U"00" + when(dBusAccess.cmd.ready){ state := State.L1_RSP } } is(State.L1_RSP){ - when(dBus.rsp.valid){ + when(dBusAccess.rsp.valid){ when(dBusRsp.leaf || dBusRsp.exception){ state := State.IDLE } otherwise { @@ -184,20 +184,20 @@ class MmuPlugin(virtualRange : UInt => Bool, } } is(State.L0_CMD){ - dBus.cmd.valid := True - dBus.cmd.address := pteBuffer.PPN1(9 downto 0) @@ pteBuffer.PPN0 @@ vpn0 @@ U"00" - when(dBus.cmd.ready){ + dBusAccess.cmd.valid := True + dBusAccess.cmd.address := pteBuffer.PPN1(9 downto 0) @@ pteBuffer.PPN0 @@ vpn0 @@ U"00" + when(dBusAccess.cmd.ready){ state := State.L0_RSP } } is(State.L0_RSP){ - when(dBus.rsp.valid) { + when(dBusAccess.rsp.valid) { state := State.IDLE } } } - when(dBus.rsp.valid && (dBusRsp.leaf || dBusRsp.exception)){ + when(dBusAccess.rsp.valid && (dBusRsp.leaf || dBusRsp.exception)){ for(port <- ports){ when(portId === port.id) { port.entryToReplace.increment() diff --git a/src/main/scala/vexriscv/plugin/Plugin.scala b/src/main/scala/vexriscv/plugin/Plugin.scala index cd440e07..957a12eb 100644 --- a/src/main/scala/vexriscv/plugin/Plugin.scala +++ b/src/main/scala/vexriscv/plugin/Plugin.scala @@ -1,14 +1,14 @@ package vexriscv.plugin import vexriscv.{Pipeline, Stage} -import spinal.core.Area +import spinal.core.{Area, Nameable} /** * Created by PIC32F_USER on 03/03/2017. */ -trait Plugin[T <: Pipeline] { +trait Plugin[T <: Pipeline] extends Nameable{ var pipeline : T = null.asInstanceOf[T] - def getName() = this.getClass.getSimpleName.replace("$","") + setName(this.getClass.getSimpleName.replace("$","")) def setup(pipeline: T) : Unit = {} def build(pipeline: T) : Unit diff --git a/src/test/cpp/raw/mmu/.gitignore b/src/test/cpp/raw/mmu/.gitignore new file mode 100644 index 00000000..c12cb2c2 --- /dev/null +++ b/src/test/cpp/raw/mmu/.gitignore @@ -0,0 +1,4 @@ +*.map +*.v +*.elf +*.o \ No newline at end of file diff --git a/src/test/cpp/raw/mmu/build/mmu.asm b/src/test/cpp/raw/mmu/build/mmu.asm index 243b7860..79d9f0e8 100644 --- a/src/test/cpp/raw/mmu/build/mmu.asm +++ b/src/test/cpp/raw/mmu/build/mmu.asm @@ -15,29 +15,12370 @@ Disassembly of section .crt_section: 8000001c: 00000013 nop 80000020 : -80000020: 0200006f j 80000040 +80000020: 1440006f j 80000164 80000024: 30200073 mret 80000028 <_start>: 80000028: 00000097 auipc ra,0x0 -8000002c: 01808093 addi ra,ra,24 # 80000040 +8000002c: 13c08093 addi ra,ra,316 # 80000164 80000030: 30509073 csrw mtvec,ra 80000034: 10509073 csrw stvec,ra + +80000038 : 80000038: 00100e13 li t3,1 -8000003c: 0100006f j 8000004c +8000003c: 00007097 auipc ra,0x7 +80000040: fc408093 addi ra,ra,-60 # 80007000 +80000044: 27262137 lui sp,0x27262 +80000048: 52410113 addi sp,sp,1316 # 27262524 +8000004c: 0040a083 lw ra,4(ra) +80000050: 10209a63 bne ra,sp,80000164 -80000040 : -80000040: f0100137 lui sp,0xf0100 -80000044: f2410113 addi sp,sp,-220 # f00fff24 -80000048: 01c12023 sw t3,0(sp) +80000054 : +80000054: 00200e13 li t3,2 +80000058: 00000097 auipc ra,0x0 +8000005c: 02008093 addi ra,ra,32 # 80000078 +80000060: 34109073 csrw mepc,ra +80000064: 000020b7 lui ra,0x2 +80000068: 80008093 addi ra,ra,-2048 # 1800 +8000006c: 30009073 csrw mstatus,ra +80000070: 30200073 mret +80000074: 0f00006f j 80000164 -8000004c : -8000004c: f0100137 lui sp,0xf0100 -80000050: f2010113 addi sp,sp,-224 # f00fff20 -80000054: 00012023 sw zero,0(sp) -80000058: 00000013 nop -8000005c: 00000013 nop -80000060: 00000013 nop -80000064: 00000013 nop -80000068: 00000013 nop -8000006c: 00000013 nop +80000078 : +80000078: 00300e13 li t3,3 +8000007c: 000010b7 lui ra,0x1 +80000080: 80008093 addi ra,ra,-2048 # 800 +80000084: 30009073 csrw mstatus,ra +80000088: 00000097 auipc ra,0x0 +8000008c: 01408093 addi ra,ra,20 # 8000009c +80000090: 34109073 csrw mepc,ra +80000094: 30200073 mret +80000098: 0cc0006f j 80000164 + +8000009c : +8000009c: 00400e13 li t3,4 +800000a0: 00008097 auipc ra,0x8 +800000a4: f6008093 addi ra,ra,-160 # 80008000 +800000a8: 37363137 lui sp,0x37363 +800000ac: 53410113 addi sp,sp,1332 # 37363534 +800000b0: 0040a083 lw ra,4(ra) +800000b4: 0a209863 bne ra,sp,80000164 + +800000b8 : +800000b8: 00500e13 li t3,5 +800000bc: 00001097 auipc ra,0x1 +800000c0: 74408093 addi ra,ra,1860 # 80001800 +800000c4: 00002117 auipc sp,0x2 +800000c8: f3c10113 addi sp,sp,-196 # 80002000 +800000cc: 00215113 srli sp,sp,0x2 +800000d0: 01116113 ori sp,sp,17 +800000d4: 0020a023 sw sp,0(ra) +800000d8: 00002097 auipc ra,0x2 +800000dc: f2808093 addi ra,ra,-216 # 80002000 +800000e0: 80000137 lui sp,0x80000 +800000e4: 00215113 srli sp,sp,0x2 +800000e8: 01f16113 ori sp,sp,31 +800000ec: 0020a023 sw sp,0(ra) +800000f0: 00500e13 li t3,5 +800000f4: 00002097 auipc ra,0x2 +800000f8: 80c08093 addi ra,ra,-2036 # 80001900 +800000fc: 00003117 auipc sp,0x3 +80000100: f0410113 addi sp,sp,-252 # 80003000 +80000104: 00215113 srli sp,sp,0x2 +80000108: 01116113 ori sp,sp,17 +8000010c: 0020a023 sw sp,0(ra) +80000110: 00003097 auipc ra,0x3 +80000114: f1808093 addi ra,ra,-232 # 80003028 +80000118: 00009117 auipc sp,0x9 +8000011c: ee810113 addi sp,sp,-280 # 80009000 +80000120: 00215113 srli sp,sp,0x2 +80000124: 01f16113 ori sp,sp,31 +80000128: 0020a023 sw sp,0(ra) +8000012c: 00001097 auipc ra,0x1 +80000130: ed408093 addi ra,ra,-300 # 80001000 +80000134: 00c0d093 srli ra,ra,0xc +80000138: 80000137 lui sp,0x80000 +8000013c: 0020e0b3 or ra,ra,sp +80000140: 18009073 csrw satp,ra + +80000144 : +80000144: 00600e13 li t3,6 +80000148: 9000a0b7 lui ra,0x9000a +8000014c: 00808093 addi ra,ra,8 # 9000a008 +80000150: 4b4a5137 lui sp,0x4b4a5 +80000154: 94810113 addi sp,sp,-1720 # 4b4a4948 +80000158: 0000a083 lw ra,0(ra) +8000015c: 00209463 bne ra,sp,80000164 +80000160: 0180006f j 80000178 + +80000164 : +80000164: 18005073 csrwi satp,0 +80000168: 0040006f j 8000016c + +8000016c : +8000016c: f0100137 lui sp,0xf0100 +80000170: f2410113 addi sp,sp,-220 # f00fff24 +80000174: 01c12023 sw t3,0(sp) + +80000178 : +80000178: 18005073 csrwi satp,0 +8000017c: 0040006f j 80000180 + +80000180 : +80000180: f0100137 lui sp,0xf0100 +80000184: f2010113 addi sp,sp,-224 # f00fff20 +80000188: 00012023 sw zero,0(sp) +8000018c: 00000013 nop +80000190: 00000013 nop +80000194: 00000013 nop +80000198: 00000013 nop +8000019c: 00000013 nop +800001a0: 00000013 nop +800001a4: 00000013 nop +800001a8: 00000013 nop +800001ac: 00000013 nop +800001b0: 00000013 nop +800001b4: 00000013 nop +800001b8: 00000013 nop +800001bc: 00000013 nop +800001c0: 00000013 nop +800001c4: 00000013 nop +800001c8: 00000013 nop +800001cc: 00000013 nop +800001d0: 00000013 nop +800001d4: 00000013 nop +800001d8: 00000013 nop +800001dc: 00000013 nop +800001e0: 00000013 nop +800001e4: 00000013 nop +800001e8: 00000013 nop +800001ec: 00000013 nop +800001f0: 00000013 nop +800001f4: 00000013 nop +800001f8: 00000013 nop +800001fc: 00000013 nop +80000200: 00000013 nop +80000204: 00000013 nop +80000208: 00000013 nop +8000020c: 00000013 nop +80000210: 00000013 nop +80000214: 00000013 nop +80000218: 00000013 nop +8000021c: 00000013 nop +80000220: 00000013 nop +80000224: 00000013 nop +80000228: 00000013 nop +8000022c: 00000013 nop +80000230: 00000013 nop +80000234: 00000013 nop +80000238: 00000013 nop +8000023c: 00000013 nop +80000240: 00000013 nop +80000244: 00000013 nop +80000248: 00000013 nop +8000024c: 00000013 nop +80000250: 00000013 nop +80000254: 00000013 nop +80000258: 00000013 nop +8000025c: 00000013 nop +80000260: 00000013 nop +80000264: 00000013 nop +80000268: 00000013 nop +8000026c: 00000013 nop +80000270: 00000013 nop +80000274: 00000013 nop +80000278: 00000013 nop +8000027c: 00000013 nop +80000280: 00000013 nop +80000284: 00000013 nop +80000288: 00000013 nop +8000028c: 00000013 nop +80000290: 00000013 nop +80000294: 00000013 nop +80000298: 00000013 nop +8000029c: 00000013 nop +800002a0: 00000013 nop +800002a4: 00000013 nop +800002a8: 00000013 nop +800002ac: 00000013 nop +800002b0: 00000013 nop +800002b4: 00000013 nop +800002b8: 00000013 nop +800002bc: 00000013 nop +800002c0: 00000013 nop +800002c4: 00000013 nop +800002c8: 00000013 nop +800002cc: 00000013 nop +800002d0: 00000013 nop +800002d4: 00000013 nop +800002d8: 00000013 nop +800002dc: 00000013 nop +800002e0: 00000013 nop +800002e4: 00000013 nop +800002e8: 00000013 nop +800002ec: 00000013 nop +800002f0: 00000013 nop +800002f4: 00000013 nop +800002f8: 00000013 nop +800002fc: 00000013 nop +80000300: 00000013 nop +80000304: 00000013 nop +80000308: 00000013 nop +8000030c: 00000013 nop +80000310: 00000013 nop +80000314: 00000013 nop +80000318: 00000013 nop +8000031c: 00000013 nop +80000320: 00000013 nop +80000324: 00000013 nop +80000328: 00000013 nop +8000032c: 00000013 nop +80000330: 00000013 nop +80000334: 00000013 nop +80000338: 00000013 nop +8000033c: 00000013 nop +80000340: 00000013 nop +80000344: 00000013 nop +80000348: 00000013 nop +8000034c: 00000013 nop +80000350: 00000013 nop +80000354: 00000013 nop +80000358: 00000013 nop +8000035c: 00000013 nop +80000360: 00000013 nop +80000364: 00000013 nop +80000368: 00000013 nop +8000036c: 00000013 nop +80000370: 00000013 nop +80000374: 00000013 nop +80000378: 00000013 nop +8000037c: 00000013 nop +80000380: 00000013 nop +80000384: 00000013 nop +80000388: 00000013 nop +8000038c: 00000013 nop +80000390: 00000013 nop +80000394: 00000013 nop +80000398: 00000013 nop +8000039c: 00000013 nop +800003a0: 00000013 nop +800003a4: 00000013 nop +800003a8: 00000013 nop +800003ac: 00000013 nop +800003b0: 00000013 nop +800003b4: 00000013 nop +800003b8: 00000013 nop +800003bc: 00000013 nop +800003c0: 00000013 nop +800003c4: 00000013 nop +800003c8: 00000013 nop +800003cc: 00000013 nop +800003d0: 00000013 nop +800003d4: 00000013 nop +800003d8: 00000013 nop +800003dc: 00000013 nop +800003e0: 00000013 nop +800003e4: 00000013 nop +800003e8: 00000013 nop +800003ec: 00000013 nop +800003f0: 00000013 nop +800003f4: 00000013 nop +800003f8: 00000013 nop +800003fc: 00000013 nop +80000400: 00000013 nop +80000404: 00000013 nop +80000408: 00000013 nop +8000040c: 00000013 nop +80000410: 00000013 nop +80000414: 00000013 nop +80000418: 00000013 nop +8000041c: 00000013 nop +80000420: 00000013 nop +80000424: 00000013 nop +80000428: 00000013 nop +8000042c: 00000013 nop +80000430: 00000013 nop +80000434: 00000013 nop +80000438: 00000013 nop +8000043c: 00000013 nop +80000440: 00000013 nop +80000444: 00000013 nop +80000448: 00000013 nop +8000044c: 00000013 nop +80000450: 00000013 nop +80000454: 00000013 nop +80000458: 00000013 nop +8000045c: 00000013 nop +80000460: 00000013 nop +80000464: 00000013 nop +80000468: 00000013 nop +8000046c: 00000013 nop +80000470: 00000013 nop +80000474: 00000013 nop +80000478: 00000013 nop +8000047c: 00000013 nop +80000480: 00000013 nop +80000484: 00000013 nop +80000488: 00000013 nop +8000048c: 00000013 nop +80000490: 00000013 nop +80000494: 00000013 nop +80000498: 00000013 nop +8000049c: 00000013 nop +800004a0: 00000013 nop +800004a4: 00000013 nop +800004a8: 00000013 nop +800004ac: 00000013 nop +800004b0: 00000013 nop +800004b4: 00000013 nop +800004b8: 00000013 nop +800004bc: 00000013 nop +800004c0: 00000013 nop +800004c4: 00000013 nop +800004c8: 00000013 nop +800004cc: 00000013 nop +800004d0: 00000013 nop +800004d4: 00000013 nop +800004d8: 00000013 nop +800004dc: 00000013 nop +800004e0: 00000013 nop +800004e4: 00000013 nop +800004e8: 00000013 nop +800004ec: 00000013 nop +800004f0: 00000013 nop +800004f4: 00000013 nop +800004f8: 00000013 nop +800004fc: 00000013 nop +80000500: 00000013 nop +80000504: 00000013 nop +80000508: 00000013 nop +8000050c: 00000013 nop +80000510: 00000013 nop +80000514: 00000013 nop +80000518: 00000013 nop +8000051c: 00000013 nop +80000520: 00000013 nop +80000524: 00000013 nop +80000528: 00000013 nop +8000052c: 00000013 nop +80000530: 00000013 nop +80000534: 00000013 nop +80000538: 00000013 nop +8000053c: 00000013 nop +80000540: 00000013 nop +80000544: 00000013 nop +80000548: 00000013 nop +8000054c: 00000013 nop +80000550: 00000013 nop +80000554: 00000013 nop +80000558: 00000013 nop +8000055c: 00000013 nop +80000560: 00000013 nop +80000564: 00000013 nop +80000568: 00000013 nop +8000056c: 00000013 nop +80000570: 00000013 nop +80000574: 00000013 nop +80000578: 00000013 nop +8000057c: 00000013 nop +80000580: 00000013 nop +80000584: 00000013 nop +80000588: 00000013 nop +8000058c: 00000013 nop +80000590: 00000013 nop +80000594: 00000013 nop +80000598: 00000013 nop +8000059c: 00000013 nop +800005a0: 00000013 nop +800005a4: 00000013 nop +800005a8: 00000013 nop +800005ac: 00000013 nop +800005b0: 00000013 nop +800005b4: 00000013 nop +800005b8: 00000013 nop +800005bc: 00000013 nop +800005c0: 00000013 nop +800005c4: 00000013 nop +800005c8: 00000013 nop +800005cc: 00000013 nop +800005d0: 00000013 nop +800005d4: 00000013 nop +800005d8: 00000013 nop +800005dc: 00000013 nop +800005e0: 00000013 nop +800005e4: 00000013 nop +800005e8: 00000013 nop +800005ec: 00000013 nop +800005f0: 00000013 nop +800005f4: 00000013 nop +800005f8: 00000013 nop +800005fc: 00000013 nop +80000600: 00000013 nop +80000604: 00000013 nop +80000608: 00000013 nop +8000060c: 00000013 nop +80000610: 00000013 nop +80000614: 00000013 nop +80000618: 00000013 nop +8000061c: 00000013 nop +80000620: 00000013 nop +80000624: 00000013 nop +80000628: 00000013 nop +8000062c: 00000013 nop +80000630: 00000013 nop +80000634: 00000013 nop +80000638: 00000013 nop +8000063c: 00000013 nop +80000640: 00000013 nop +80000644: 00000013 nop +80000648: 00000013 nop +8000064c: 00000013 nop +80000650: 00000013 nop +80000654: 00000013 nop +80000658: 00000013 nop +8000065c: 00000013 nop +80000660: 00000013 nop +80000664: 00000013 nop +80000668: 00000013 nop +8000066c: 00000013 nop +80000670: 00000013 nop +80000674: 00000013 nop +80000678: 00000013 nop +8000067c: 00000013 nop +80000680: 00000013 nop +80000684: 00000013 nop +80000688: 00000013 nop +8000068c: 00000013 nop +80000690: 00000013 nop +80000694: 00000013 nop +80000698: 00000013 nop +8000069c: 00000013 nop +800006a0: 00000013 nop +800006a4: 00000013 nop +800006a8: 00000013 nop +800006ac: 00000013 nop +800006b0: 00000013 nop +800006b4: 00000013 nop +800006b8: 00000013 nop +800006bc: 00000013 nop +800006c0: 00000013 nop +800006c4: 00000013 nop +800006c8: 00000013 nop +800006cc: 00000013 nop +800006d0: 00000013 nop +800006d4: 00000013 nop +800006d8: 00000013 nop +800006dc: 00000013 nop +800006e0: 00000013 nop +800006e4: 00000013 nop +800006e8: 00000013 nop +800006ec: 00000013 nop +800006f0: 00000013 nop +800006f4: 00000013 nop +800006f8: 00000013 nop +800006fc: 00000013 nop +80000700: 00000013 nop +80000704: 00000013 nop +80000708: 00000013 nop +8000070c: 00000013 nop +80000710: 00000013 nop +80000714: 00000013 nop +80000718: 00000013 nop +8000071c: 00000013 nop +80000720: 00000013 nop +80000724: 00000013 nop +80000728: 00000013 nop +8000072c: 00000013 nop +80000730: 00000013 nop +80000734: 00000013 nop +80000738: 00000013 nop +8000073c: 00000013 nop +80000740: 00000013 nop +80000744: 00000013 nop +80000748: 00000013 nop +8000074c: 00000013 nop +80000750: 00000013 nop +80000754: 00000013 nop +80000758: 00000013 nop +8000075c: 00000013 nop +80000760: 00000013 nop +80000764: 00000013 nop +80000768: 00000013 nop +8000076c: 00000013 nop +80000770: 00000013 nop +80000774: 00000013 nop +80000778: 00000013 nop +8000077c: 00000013 nop +80000780: 00000013 nop +80000784: 00000013 nop +80000788: 00000013 nop +8000078c: 00000013 nop +80000790: 00000013 nop +80000794: 00000013 nop +80000798: 00000013 nop +8000079c: 00000013 nop +800007a0: 00000013 nop +800007a4: 00000013 nop +800007a8: 00000013 nop +800007ac: 00000013 nop +800007b0: 00000013 nop +800007b4: 00000013 nop +800007b8: 00000013 nop +800007bc: 00000013 nop +800007c0: 00000013 nop +800007c4: 00000013 nop +800007c8: 00000013 nop +800007cc: 00000013 nop +800007d0: 00000013 nop +800007d4: 00000013 nop +800007d8: 00000013 nop +800007dc: 00000013 nop +800007e0: 00000013 nop +800007e4: 00000013 nop +800007e8: 00000013 nop +800007ec: 00000013 nop +800007f0: 00000013 nop +800007f4: 00000013 nop +800007f8: 00000013 nop +800007fc: 00000013 nop +80000800: 00000013 nop +80000804: 00000013 nop +80000808: 00000013 nop +8000080c: 00000013 nop +80000810: 00000013 nop +80000814: 00000013 nop +80000818: 00000013 nop +8000081c: 00000013 nop +80000820: 00000013 nop +80000824: 00000013 nop +80000828: 00000013 nop +8000082c: 00000013 nop +80000830: 00000013 nop +80000834: 00000013 nop +80000838: 00000013 nop +8000083c: 00000013 nop +80000840: 00000013 nop +80000844: 00000013 nop +80000848: 00000013 nop +8000084c: 00000013 nop +80000850: 00000013 nop +80000854: 00000013 nop +80000858: 00000013 nop +8000085c: 00000013 nop +80000860: 00000013 nop +80000864: 00000013 nop +80000868: 00000013 nop +8000086c: 00000013 nop +80000870: 00000013 nop +80000874: 00000013 nop +80000878: 00000013 nop +8000087c: 00000013 nop +80000880: 00000013 nop +80000884: 00000013 nop +80000888: 00000013 nop +8000088c: 00000013 nop +80000890: 00000013 nop +80000894: 00000013 nop +80000898: 00000013 nop +8000089c: 00000013 nop +800008a0: 00000013 nop +800008a4: 00000013 nop +800008a8: 00000013 nop +800008ac: 00000013 nop +800008b0: 00000013 nop +800008b4: 00000013 nop +800008b8: 00000013 nop +800008bc: 00000013 nop +800008c0: 00000013 nop +800008c4: 00000013 nop +800008c8: 00000013 nop +800008cc: 00000013 nop +800008d0: 00000013 nop +800008d4: 00000013 nop +800008d8: 00000013 nop +800008dc: 00000013 nop +800008e0: 00000013 nop +800008e4: 00000013 nop +800008e8: 00000013 nop +800008ec: 00000013 nop +800008f0: 00000013 nop +800008f4: 00000013 nop +800008f8: 00000013 nop +800008fc: 00000013 nop +80000900: 00000013 nop +80000904: 00000013 nop +80000908: 00000013 nop +8000090c: 00000013 nop +80000910: 00000013 nop +80000914: 00000013 nop +80000918: 00000013 nop +8000091c: 00000013 nop +80000920: 00000013 nop +80000924: 00000013 nop +80000928: 00000013 nop +8000092c: 00000013 nop +80000930: 00000013 nop +80000934: 00000013 nop +80000938: 00000013 nop +8000093c: 00000013 nop +80000940: 00000013 nop +80000944: 00000013 nop +80000948: 00000013 nop +8000094c: 00000013 nop +80000950: 00000013 nop +80000954: 00000013 nop +80000958: 00000013 nop +8000095c: 00000013 nop +80000960: 00000013 nop +80000964: 00000013 nop +80000968: 00000013 nop +8000096c: 00000013 nop +80000970: 00000013 nop +80000974: 00000013 nop +80000978: 00000013 nop +8000097c: 00000013 nop +80000980: 00000013 nop +80000984: 00000013 nop +80000988: 00000013 nop +8000098c: 00000013 nop +80000990: 00000013 nop +80000994: 00000013 nop +80000998: 00000013 nop +8000099c: 00000013 nop +800009a0: 00000013 nop +800009a4: 00000013 nop +800009a8: 00000013 nop +800009ac: 00000013 nop +800009b0: 00000013 nop +800009b4: 00000013 nop +800009b8: 00000013 nop +800009bc: 00000013 nop +800009c0: 00000013 nop +800009c4: 00000013 nop +800009c8: 00000013 nop +800009cc: 00000013 nop +800009d0: 00000013 nop +800009d4: 00000013 nop +800009d8: 00000013 nop +800009dc: 00000013 nop +800009e0: 00000013 nop +800009e4: 00000013 nop +800009e8: 00000013 nop +800009ec: 00000013 nop +800009f0: 00000013 nop +800009f4: 00000013 nop +800009f8: 00000013 nop +800009fc: 00000013 nop +80000a00: 00000013 nop +80000a04: 00000013 nop +80000a08: 00000013 nop +80000a0c: 00000013 nop +80000a10: 00000013 nop +80000a14: 00000013 nop +80000a18: 00000013 nop +80000a1c: 00000013 nop +80000a20: 00000013 nop +80000a24: 00000013 nop +80000a28: 00000013 nop +80000a2c: 00000013 nop +80000a30: 00000013 nop +80000a34: 00000013 nop +80000a38: 00000013 nop +80000a3c: 00000013 nop +80000a40: 00000013 nop +80000a44: 00000013 nop +80000a48: 00000013 nop +80000a4c: 00000013 nop +80000a50: 00000013 nop +80000a54: 00000013 nop +80000a58: 00000013 nop +80000a5c: 00000013 nop +80000a60: 00000013 nop +80000a64: 00000013 nop +80000a68: 00000013 nop +80000a6c: 00000013 nop +80000a70: 00000013 nop +80000a74: 00000013 nop +80000a78: 00000013 nop +80000a7c: 00000013 nop +80000a80: 00000013 nop +80000a84: 00000013 nop +80000a88: 00000013 nop +80000a8c: 00000013 nop +80000a90: 00000013 nop +80000a94: 00000013 nop +80000a98: 00000013 nop +80000a9c: 00000013 nop +80000aa0: 00000013 nop +80000aa4: 00000013 nop +80000aa8: 00000013 nop +80000aac: 00000013 nop +80000ab0: 00000013 nop +80000ab4: 00000013 nop +80000ab8: 00000013 nop +80000abc: 00000013 nop +80000ac0: 00000013 nop +80000ac4: 00000013 nop +80000ac8: 00000013 nop +80000acc: 00000013 nop +80000ad0: 00000013 nop +80000ad4: 00000013 nop +80000ad8: 00000013 nop +80000adc: 00000013 nop +80000ae0: 00000013 nop +80000ae4: 00000013 nop +80000ae8: 00000013 nop +80000aec: 00000013 nop +80000af0: 00000013 nop +80000af4: 00000013 nop +80000af8: 00000013 nop +80000afc: 00000013 nop +80000b00: 00000013 nop +80000b04: 00000013 nop +80000b08: 00000013 nop +80000b0c: 00000013 nop +80000b10: 00000013 nop +80000b14: 00000013 nop +80000b18: 00000013 nop +80000b1c: 00000013 nop +80000b20: 00000013 nop +80000b24: 00000013 nop +80000b28: 00000013 nop +80000b2c: 00000013 nop +80000b30: 00000013 nop +80000b34: 00000013 nop +80000b38: 00000013 nop +80000b3c: 00000013 nop +80000b40: 00000013 nop +80000b44: 00000013 nop +80000b48: 00000013 nop +80000b4c: 00000013 nop +80000b50: 00000013 nop +80000b54: 00000013 nop +80000b58: 00000013 nop +80000b5c: 00000013 nop +80000b60: 00000013 nop +80000b64: 00000013 nop +80000b68: 00000013 nop +80000b6c: 00000013 nop +80000b70: 00000013 nop +80000b74: 00000013 nop +80000b78: 00000013 nop +80000b7c: 00000013 nop +80000b80: 00000013 nop +80000b84: 00000013 nop +80000b88: 00000013 nop +80000b8c: 00000013 nop +80000b90: 00000013 nop +80000b94: 00000013 nop +80000b98: 00000013 nop +80000b9c: 00000013 nop +80000ba0: 00000013 nop +80000ba4: 00000013 nop +80000ba8: 00000013 nop +80000bac: 00000013 nop +80000bb0: 00000013 nop +80000bb4: 00000013 nop +80000bb8: 00000013 nop +80000bbc: 00000013 nop +80000bc0: 00000013 nop +80000bc4: 00000013 nop +80000bc8: 00000013 nop +80000bcc: 00000013 nop +80000bd0: 00000013 nop +80000bd4: 00000013 nop +80000bd8: 00000013 nop +80000bdc: 00000013 nop +80000be0: 00000013 nop +80000be4: 00000013 nop +80000be8: 00000013 nop +80000bec: 00000013 nop +80000bf0: 00000013 nop +80000bf4: 00000013 nop +80000bf8: 00000013 nop +80000bfc: 00000013 nop +80000c00: 00000013 nop +80000c04: 00000013 nop +80000c08: 00000013 nop +80000c0c: 00000013 nop +80000c10: 00000013 nop +80000c14: 00000013 nop +80000c18: 00000013 nop +80000c1c: 00000013 nop +80000c20: 00000013 nop +80000c24: 00000013 nop +80000c28: 00000013 nop +80000c2c: 00000013 nop +80000c30: 00000013 nop +80000c34: 00000013 nop +80000c38: 00000013 nop +80000c3c: 00000013 nop +80000c40: 00000013 nop +80000c44: 00000013 nop +80000c48: 00000013 nop +80000c4c: 00000013 nop +80000c50: 00000013 nop +80000c54: 00000013 nop +80000c58: 00000013 nop +80000c5c: 00000013 nop +80000c60: 00000013 nop +80000c64: 00000013 nop +80000c68: 00000013 nop +80000c6c: 00000013 nop +80000c70: 00000013 nop +80000c74: 00000013 nop +80000c78: 00000013 nop +80000c7c: 00000013 nop +80000c80: 00000013 nop +80000c84: 00000013 nop +80000c88: 00000013 nop +80000c8c: 00000013 nop +80000c90: 00000013 nop +80000c94: 00000013 nop +80000c98: 00000013 nop +80000c9c: 00000013 nop +80000ca0: 00000013 nop +80000ca4: 00000013 nop +80000ca8: 00000013 nop +80000cac: 00000013 nop +80000cb0: 00000013 nop +80000cb4: 00000013 nop +80000cb8: 00000013 nop +80000cbc: 00000013 nop +80000cc0: 00000013 nop +80000cc4: 00000013 nop +80000cc8: 00000013 nop +80000ccc: 00000013 nop +80000cd0: 00000013 nop +80000cd4: 00000013 nop +80000cd8: 00000013 nop +80000cdc: 00000013 nop +80000ce0: 00000013 nop +80000ce4: 00000013 nop +80000ce8: 00000013 nop +80000cec: 00000013 nop +80000cf0: 00000013 nop +80000cf4: 00000013 nop +80000cf8: 00000013 nop +80000cfc: 00000013 nop +80000d00: 00000013 nop +80000d04: 00000013 nop +80000d08: 00000013 nop +80000d0c: 00000013 nop +80000d10: 00000013 nop +80000d14: 00000013 nop +80000d18: 00000013 nop +80000d1c: 00000013 nop +80000d20: 00000013 nop +80000d24: 00000013 nop +80000d28: 00000013 nop +80000d2c: 00000013 nop +80000d30: 00000013 nop +80000d34: 00000013 nop +80000d38: 00000013 nop +80000d3c: 00000013 nop +80000d40: 00000013 nop +80000d44: 00000013 nop +80000d48: 00000013 nop +80000d4c: 00000013 nop +80000d50: 00000013 nop +80000d54: 00000013 nop +80000d58: 00000013 nop +80000d5c: 00000013 nop +80000d60: 00000013 nop +80000d64: 00000013 nop +80000d68: 00000013 nop +80000d6c: 00000013 nop +80000d70: 00000013 nop +80000d74: 00000013 nop +80000d78: 00000013 nop +80000d7c: 00000013 nop +80000d80: 00000013 nop +80000d84: 00000013 nop +80000d88: 00000013 nop +80000d8c: 00000013 nop +80000d90: 00000013 nop +80000d94: 00000013 nop +80000d98: 00000013 nop +80000d9c: 00000013 nop +80000da0: 00000013 nop +80000da4: 00000013 nop +80000da8: 00000013 nop +80000dac: 00000013 nop +80000db0: 00000013 nop +80000db4: 00000013 nop +80000db8: 00000013 nop +80000dbc: 00000013 nop +80000dc0: 00000013 nop +80000dc4: 00000013 nop +80000dc8: 00000013 nop +80000dcc: 00000013 nop +80000dd0: 00000013 nop +80000dd4: 00000013 nop +80000dd8: 00000013 nop +80000ddc: 00000013 nop +80000de0: 00000013 nop +80000de4: 00000013 nop +80000de8: 00000013 nop +80000dec: 00000013 nop +80000df0: 00000013 nop +80000df4: 00000013 nop +80000df8: 00000013 nop +80000dfc: 00000013 nop +80000e00: 00000013 nop +80000e04: 00000013 nop +80000e08: 00000013 nop +80000e0c: 00000013 nop +80000e10: 00000013 nop +80000e14: 00000013 nop +80000e18: 00000013 nop +80000e1c: 00000013 nop +80000e20: 00000013 nop +80000e24: 00000013 nop +80000e28: 00000013 nop +80000e2c: 00000013 nop +80000e30: 00000013 nop +80000e34: 00000013 nop +80000e38: 00000013 nop +80000e3c: 00000013 nop +80000e40: 00000013 nop +80000e44: 00000013 nop +80000e48: 00000013 nop +80000e4c: 00000013 nop +80000e50: 00000013 nop +80000e54: 00000013 nop +80000e58: 00000013 nop +80000e5c: 00000013 nop +80000e60: 00000013 nop +80000e64: 00000013 nop +80000e68: 00000013 nop +80000e6c: 00000013 nop +80000e70: 00000013 nop +80000e74: 00000013 nop +80000e78: 00000013 nop +80000e7c: 00000013 nop +80000e80: 00000013 nop +80000e84: 00000013 nop +80000e88: 00000013 nop +80000e8c: 00000013 nop +80000e90: 00000013 nop +80000e94: 00000013 nop +80000e98: 00000013 nop +80000e9c: 00000013 nop +80000ea0: 00000013 nop +80000ea4: 00000013 nop +80000ea8: 00000013 nop +80000eac: 00000013 nop +80000eb0: 00000013 nop +80000eb4: 00000013 nop +80000eb8: 00000013 nop +80000ebc: 00000013 nop +80000ec0: 00000013 nop +80000ec4: 00000013 nop +80000ec8: 00000013 nop +80000ecc: 00000013 nop +80000ed0: 00000013 nop +80000ed4: 00000013 nop +80000ed8: 00000013 nop +80000edc: 00000013 nop +80000ee0: 00000013 nop +80000ee4: 00000013 nop +80000ee8: 00000013 nop +80000eec: 00000013 nop +80000ef0: 00000013 nop +80000ef4: 00000013 nop +80000ef8: 00000013 nop +80000efc: 00000013 nop +80000f00: 00000013 nop +80000f04: 00000013 nop +80000f08: 00000013 nop +80000f0c: 00000013 nop +80000f10: 00000013 nop +80000f14: 00000013 nop +80000f18: 00000013 nop +80000f1c: 00000013 nop +80000f20: 00000013 nop +80000f24: 00000013 nop +80000f28: 00000013 nop +80000f2c: 00000013 nop +80000f30: 00000013 nop +80000f34: 00000013 nop +80000f38: 00000013 nop +80000f3c: 00000013 nop +80000f40: 00000013 nop +80000f44: 00000013 nop +80000f48: 00000013 nop +80000f4c: 00000013 nop +80000f50: 00000013 nop +80000f54: 00000013 nop +80000f58: 00000013 nop +80000f5c: 00000013 nop +80000f60: 00000013 nop +80000f64: 00000013 nop +80000f68: 00000013 nop +80000f6c: 00000013 nop +80000f70: 00000013 nop +80000f74: 00000013 nop +80000f78: 00000013 nop +80000f7c: 00000013 nop +80000f80: 00000013 nop +80000f84: 00000013 nop +80000f88: 00000013 nop +80000f8c: 00000013 nop +80000f90: 00000013 nop +80000f94: 00000013 nop +80000f98: 00000013 nop +80000f9c: 00000013 nop +80000fa0: 00000013 nop +80000fa4: 00000013 nop +80000fa8: 00000013 nop +80000fac: 00000013 nop +80000fb0: 00000013 nop +80000fb4: 00000013 nop +80000fb8: 00000013 nop +80000fbc: 00000013 nop +80000fc0: 00000013 nop +80000fc4: 00000013 nop +80000fc8: 00000013 nop +80000fcc: 00000013 nop +80000fd0: 00000013 nop +80000fd4: 00000013 nop +80000fd8: 00000013 nop +80000fdc: 00000013 nop +80000fe0: 00000013 nop +80000fe4: 00000013 nop +80000fe8: 00000013 nop +80000fec: 00000013 nop +80000ff0: 00000013 nop +80000ff4: 00000013 nop +80000ff8: 00000013 nop +80000ffc: 00000013 nop + +80001000 : +80001000: 0000 unimp +80001002: 0000 unimp +80001004: 00000013 nop +80001008: 00000013 nop +8000100c: 00000013 nop +80001010: 00000013 nop +80001014: 00000013 nop +80001018: 00000013 nop +8000101c: 00000013 nop +80001020: 00000013 nop +80001024: 00000013 nop +80001028: 00000013 nop +8000102c: 00000013 nop +80001030: 00000013 nop +80001034: 00000013 nop +80001038: 00000013 nop +8000103c: 00000013 nop +80001040: 00000013 nop +80001044: 00000013 nop +80001048: 00000013 nop +8000104c: 00000013 nop +80001050: 00000013 nop +80001054: 00000013 nop +80001058: 00000013 nop +8000105c: 00000013 nop +80001060: 00000013 nop +80001064: 00000013 nop +80001068: 00000013 nop +8000106c: 00000013 nop +80001070: 00000013 nop +80001074: 00000013 nop +80001078: 00000013 nop +8000107c: 00000013 nop +80001080: 00000013 nop +80001084: 00000013 nop +80001088: 00000013 nop +8000108c: 00000013 nop +80001090: 00000013 nop +80001094: 00000013 nop +80001098: 00000013 nop +8000109c: 00000013 nop +800010a0: 00000013 nop +800010a4: 00000013 nop +800010a8: 00000013 nop +800010ac: 00000013 nop +800010b0: 00000013 nop +800010b4: 00000013 nop +800010b8: 00000013 nop +800010bc: 00000013 nop +800010c0: 00000013 nop +800010c4: 00000013 nop +800010c8: 00000013 nop +800010cc: 00000013 nop +800010d0: 00000013 nop +800010d4: 00000013 nop +800010d8: 00000013 nop +800010dc: 00000013 nop +800010e0: 00000013 nop +800010e4: 00000013 nop +800010e8: 00000013 nop +800010ec: 00000013 nop +800010f0: 00000013 nop +800010f4: 00000013 nop +800010f8: 00000013 nop +800010fc: 00000013 nop +80001100: 00000013 nop +80001104: 00000013 nop +80001108: 00000013 nop +8000110c: 00000013 nop +80001110: 00000013 nop +80001114: 00000013 nop +80001118: 00000013 nop +8000111c: 00000013 nop +80001120: 00000013 nop +80001124: 00000013 nop +80001128: 00000013 nop +8000112c: 00000013 nop +80001130: 00000013 nop +80001134: 00000013 nop +80001138: 00000013 nop +8000113c: 00000013 nop +80001140: 00000013 nop +80001144: 00000013 nop +80001148: 00000013 nop +8000114c: 00000013 nop +80001150: 00000013 nop +80001154: 00000013 nop +80001158: 00000013 nop +8000115c: 00000013 nop +80001160: 00000013 nop +80001164: 00000013 nop +80001168: 00000013 nop +8000116c: 00000013 nop +80001170: 00000013 nop +80001174: 00000013 nop +80001178: 00000013 nop +8000117c: 00000013 nop +80001180: 00000013 nop +80001184: 00000013 nop +80001188: 00000013 nop +8000118c: 00000013 nop +80001190: 00000013 nop +80001194: 00000013 nop +80001198: 00000013 nop +8000119c: 00000013 nop +800011a0: 00000013 nop +800011a4: 00000013 nop +800011a8: 00000013 nop +800011ac: 00000013 nop +800011b0: 00000013 nop +800011b4: 00000013 nop +800011b8: 00000013 nop +800011bc: 00000013 nop +800011c0: 00000013 nop +800011c4: 00000013 nop +800011c8: 00000013 nop +800011cc: 00000013 nop +800011d0: 00000013 nop +800011d4: 00000013 nop +800011d8: 00000013 nop +800011dc: 00000013 nop +800011e0: 00000013 nop +800011e4: 00000013 nop +800011e8: 00000013 nop +800011ec: 00000013 nop +800011f0: 00000013 nop +800011f4: 00000013 nop +800011f8: 00000013 nop +800011fc: 00000013 nop +80001200: 00000013 nop +80001204: 00000013 nop +80001208: 00000013 nop +8000120c: 00000013 nop +80001210: 00000013 nop +80001214: 00000013 nop +80001218: 00000013 nop +8000121c: 00000013 nop +80001220: 00000013 nop +80001224: 00000013 nop +80001228: 00000013 nop +8000122c: 00000013 nop +80001230: 00000013 nop +80001234: 00000013 nop +80001238: 00000013 nop +8000123c: 00000013 nop +80001240: 00000013 nop +80001244: 00000013 nop +80001248: 00000013 nop +8000124c: 00000013 nop +80001250: 00000013 nop +80001254: 00000013 nop +80001258: 00000013 nop +8000125c: 00000013 nop +80001260: 00000013 nop +80001264: 00000013 nop +80001268: 00000013 nop +8000126c: 00000013 nop +80001270: 00000013 nop +80001274: 00000013 nop +80001278: 00000013 nop +8000127c: 00000013 nop +80001280: 00000013 nop +80001284: 00000013 nop +80001288: 00000013 nop +8000128c: 00000013 nop +80001290: 00000013 nop +80001294: 00000013 nop +80001298: 00000013 nop +8000129c: 00000013 nop +800012a0: 00000013 nop +800012a4: 00000013 nop +800012a8: 00000013 nop +800012ac: 00000013 nop +800012b0: 00000013 nop +800012b4: 00000013 nop +800012b8: 00000013 nop +800012bc: 00000013 nop +800012c0: 00000013 nop +800012c4: 00000013 nop +800012c8: 00000013 nop +800012cc: 00000013 nop +800012d0: 00000013 nop +800012d4: 00000013 nop +800012d8: 00000013 nop +800012dc: 00000013 nop +800012e0: 00000013 nop +800012e4: 00000013 nop +800012e8: 00000013 nop +800012ec: 00000013 nop +800012f0: 00000013 nop +800012f4: 00000013 nop +800012f8: 00000013 nop +800012fc: 00000013 nop +80001300: 00000013 nop +80001304: 00000013 nop +80001308: 00000013 nop +8000130c: 00000013 nop +80001310: 00000013 nop +80001314: 00000013 nop +80001318: 00000013 nop +8000131c: 00000013 nop +80001320: 00000013 nop +80001324: 00000013 nop +80001328: 00000013 nop +8000132c: 00000013 nop +80001330: 00000013 nop +80001334: 00000013 nop +80001338: 00000013 nop +8000133c: 00000013 nop +80001340: 00000013 nop +80001344: 00000013 nop +80001348: 00000013 nop +8000134c: 00000013 nop +80001350: 00000013 nop +80001354: 00000013 nop +80001358: 00000013 nop +8000135c: 00000013 nop +80001360: 00000013 nop +80001364: 00000013 nop +80001368: 00000013 nop +8000136c: 00000013 nop +80001370: 00000013 nop +80001374: 00000013 nop +80001378: 00000013 nop +8000137c: 00000013 nop +80001380: 00000013 nop +80001384: 00000013 nop +80001388: 00000013 nop +8000138c: 00000013 nop +80001390: 00000013 nop +80001394: 00000013 nop +80001398: 00000013 nop +8000139c: 00000013 nop +800013a0: 00000013 nop +800013a4: 00000013 nop +800013a8: 00000013 nop +800013ac: 00000013 nop +800013b0: 00000013 nop +800013b4: 00000013 nop +800013b8: 00000013 nop +800013bc: 00000013 nop +800013c0: 00000013 nop +800013c4: 00000013 nop +800013c8: 00000013 nop +800013cc: 00000013 nop +800013d0: 00000013 nop +800013d4: 00000013 nop +800013d8: 00000013 nop +800013dc: 00000013 nop +800013e0: 00000013 nop +800013e4: 00000013 nop +800013e8: 00000013 nop +800013ec: 00000013 nop +800013f0: 00000013 nop +800013f4: 00000013 nop +800013f8: 00000013 nop +800013fc: 00000013 nop +80001400: 00000013 nop +80001404: 00000013 nop +80001408: 00000013 nop +8000140c: 00000013 nop +80001410: 00000013 nop +80001414: 00000013 nop +80001418: 00000013 nop +8000141c: 00000013 nop +80001420: 00000013 nop +80001424: 00000013 nop +80001428: 00000013 nop +8000142c: 00000013 nop +80001430: 00000013 nop +80001434: 00000013 nop +80001438: 00000013 nop +8000143c: 00000013 nop +80001440: 00000013 nop +80001444: 00000013 nop +80001448: 00000013 nop +8000144c: 00000013 nop +80001450: 00000013 nop +80001454: 00000013 nop +80001458: 00000013 nop +8000145c: 00000013 nop +80001460: 00000013 nop +80001464: 00000013 nop +80001468: 00000013 nop +8000146c: 00000013 nop +80001470: 00000013 nop +80001474: 00000013 nop +80001478: 00000013 nop +8000147c: 00000013 nop +80001480: 00000013 nop +80001484: 00000013 nop +80001488: 00000013 nop +8000148c: 00000013 nop +80001490: 00000013 nop +80001494: 00000013 nop +80001498: 00000013 nop +8000149c: 00000013 nop +800014a0: 00000013 nop +800014a4: 00000013 nop +800014a8: 00000013 nop +800014ac: 00000013 nop +800014b0: 00000013 nop +800014b4: 00000013 nop +800014b8: 00000013 nop +800014bc: 00000013 nop +800014c0: 00000013 nop +800014c4: 00000013 nop +800014c8: 00000013 nop +800014cc: 00000013 nop +800014d0: 00000013 nop +800014d4: 00000013 nop +800014d8: 00000013 nop +800014dc: 00000013 nop +800014e0: 00000013 nop +800014e4: 00000013 nop +800014e8: 00000013 nop +800014ec: 00000013 nop +800014f0: 00000013 nop +800014f4: 00000013 nop +800014f8: 00000013 nop +800014fc: 00000013 nop +80001500: 00000013 nop +80001504: 00000013 nop +80001508: 00000013 nop +8000150c: 00000013 nop +80001510: 00000013 nop +80001514: 00000013 nop +80001518: 00000013 nop +8000151c: 00000013 nop +80001520: 00000013 nop +80001524: 00000013 nop +80001528: 00000013 nop +8000152c: 00000013 nop +80001530: 00000013 nop +80001534: 00000013 nop +80001538: 00000013 nop +8000153c: 00000013 nop +80001540: 00000013 nop +80001544: 00000013 nop +80001548: 00000013 nop +8000154c: 00000013 nop +80001550: 00000013 nop +80001554: 00000013 nop +80001558: 00000013 nop +8000155c: 00000013 nop +80001560: 00000013 nop +80001564: 00000013 nop +80001568: 00000013 nop +8000156c: 00000013 nop +80001570: 00000013 nop +80001574: 00000013 nop +80001578: 00000013 nop +8000157c: 00000013 nop +80001580: 00000013 nop +80001584: 00000013 nop +80001588: 00000013 nop +8000158c: 00000013 nop +80001590: 00000013 nop +80001594: 00000013 nop +80001598: 00000013 nop +8000159c: 00000013 nop +800015a0: 00000013 nop +800015a4: 00000013 nop +800015a8: 00000013 nop +800015ac: 00000013 nop +800015b0: 00000013 nop +800015b4: 00000013 nop +800015b8: 00000013 nop +800015bc: 00000013 nop +800015c0: 00000013 nop +800015c4: 00000013 nop +800015c8: 00000013 nop +800015cc: 00000013 nop +800015d0: 00000013 nop +800015d4: 00000013 nop +800015d8: 00000013 nop +800015dc: 00000013 nop +800015e0: 00000013 nop +800015e4: 00000013 nop +800015e8: 00000013 nop +800015ec: 00000013 nop +800015f0: 00000013 nop +800015f4: 00000013 nop +800015f8: 00000013 nop +800015fc: 00000013 nop +80001600: 00000013 nop +80001604: 00000013 nop +80001608: 00000013 nop +8000160c: 00000013 nop +80001610: 00000013 nop +80001614: 00000013 nop +80001618: 00000013 nop +8000161c: 00000013 nop +80001620: 00000013 nop +80001624: 00000013 nop +80001628: 00000013 nop +8000162c: 00000013 nop +80001630: 00000013 nop +80001634: 00000013 nop +80001638: 00000013 nop +8000163c: 00000013 nop +80001640: 00000013 nop +80001644: 00000013 nop +80001648: 00000013 nop +8000164c: 00000013 nop +80001650: 00000013 nop +80001654: 00000013 nop +80001658: 00000013 nop +8000165c: 00000013 nop +80001660: 00000013 nop +80001664: 00000013 nop +80001668: 00000013 nop +8000166c: 00000013 nop +80001670: 00000013 nop +80001674: 00000013 nop +80001678: 00000013 nop +8000167c: 00000013 nop +80001680: 00000013 nop +80001684: 00000013 nop +80001688: 00000013 nop +8000168c: 00000013 nop +80001690: 00000013 nop +80001694: 00000013 nop +80001698: 00000013 nop +8000169c: 00000013 nop +800016a0: 00000013 nop +800016a4: 00000013 nop +800016a8: 00000013 nop +800016ac: 00000013 nop +800016b0: 00000013 nop +800016b4: 00000013 nop +800016b8: 00000013 nop +800016bc: 00000013 nop +800016c0: 00000013 nop +800016c4: 00000013 nop +800016c8: 00000013 nop +800016cc: 00000013 nop +800016d0: 00000013 nop +800016d4: 00000013 nop +800016d8: 00000013 nop +800016dc: 00000013 nop +800016e0: 00000013 nop +800016e4: 00000013 nop +800016e8: 00000013 nop +800016ec: 00000013 nop +800016f0: 00000013 nop +800016f4: 00000013 nop +800016f8: 00000013 nop +800016fc: 00000013 nop +80001700: 00000013 nop +80001704: 00000013 nop +80001708: 00000013 nop +8000170c: 00000013 nop +80001710: 00000013 nop +80001714: 00000013 nop +80001718: 00000013 nop +8000171c: 00000013 nop +80001720: 00000013 nop +80001724: 00000013 nop +80001728: 00000013 nop +8000172c: 00000013 nop +80001730: 00000013 nop +80001734: 00000013 nop +80001738: 00000013 nop +8000173c: 00000013 nop +80001740: 00000013 nop +80001744: 00000013 nop +80001748: 00000013 nop +8000174c: 00000013 nop +80001750: 00000013 nop +80001754: 00000013 nop +80001758: 00000013 nop +8000175c: 00000013 nop +80001760: 00000013 nop +80001764: 00000013 nop +80001768: 00000013 nop +8000176c: 00000013 nop +80001770: 00000013 nop +80001774: 00000013 nop +80001778: 00000013 nop +8000177c: 00000013 nop +80001780: 00000013 nop +80001784: 00000013 nop +80001788: 00000013 nop +8000178c: 00000013 nop +80001790: 00000013 nop +80001794: 00000013 nop +80001798: 00000013 nop +8000179c: 00000013 nop +800017a0: 00000013 nop +800017a4: 00000013 nop +800017a8: 00000013 nop +800017ac: 00000013 nop +800017b0: 00000013 nop +800017b4: 00000013 nop +800017b8: 00000013 nop +800017bc: 00000013 nop +800017c0: 00000013 nop +800017c4: 00000013 nop +800017c8: 00000013 nop +800017cc: 00000013 nop +800017d0: 00000013 nop +800017d4: 00000013 nop +800017d8: 00000013 nop +800017dc: 00000013 nop +800017e0: 00000013 nop +800017e4: 00000013 nop +800017e8: 00000013 nop +800017ec: 00000013 nop +800017f0: 00000013 nop +800017f4: 00000013 nop +800017f8: 00000013 nop +800017fc: 00000013 nop +80001800: 00000013 nop +80001804: 00000013 nop +80001808: 00000013 nop +8000180c: 00000013 nop +80001810: 00000013 nop +80001814: 00000013 nop +80001818: 00000013 nop +8000181c: 00000013 nop +80001820: 00000013 nop +80001824: 00000013 nop +80001828: 00000013 nop +8000182c: 00000013 nop +80001830: 00000013 nop +80001834: 00000013 nop +80001838: 00000013 nop +8000183c: 00000013 nop +80001840: 00000013 nop +80001844: 00000013 nop +80001848: 00000013 nop +8000184c: 00000013 nop +80001850: 00000013 nop +80001854: 00000013 nop +80001858: 00000013 nop +8000185c: 00000013 nop +80001860: 00000013 nop +80001864: 00000013 nop +80001868: 00000013 nop +8000186c: 00000013 nop +80001870: 00000013 nop +80001874: 00000013 nop +80001878: 00000013 nop +8000187c: 00000013 nop +80001880: 00000013 nop +80001884: 00000013 nop +80001888: 00000013 nop +8000188c: 00000013 nop +80001890: 00000013 nop +80001894: 00000013 nop +80001898: 00000013 nop +8000189c: 00000013 nop +800018a0: 00000013 nop +800018a4: 00000013 nop +800018a8: 00000013 nop +800018ac: 00000013 nop +800018b0: 00000013 nop +800018b4: 00000013 nop +800018b8: 00000013 nop +800018bc: 00000013 nop +800018c0: 00000013 nop +800018c4: 00000013 nop +800018c8: 00000013 nop +800018cc: 00000013 nop +800018d0: 00000013 nop +800018d4: 00000013 nop +800018d8: 00000013 nop +800018dc: 00000013 nop +800018e0: 00000013 nop +800018e4: 00000013 nop +800018e8: 00000013 nop +800018ec: 00000013 nop +800018f0: 00000013 nop +800018f4: 00000013 nop +800018f8: 00000013 nop +800018fc: 00000013 nop +80001900: 00000013 nop +80001904: 00000013 nop +80001908: 00000013 nop +8000190c: 00000013 nop +80001910: 00000013 nop +80001914: 00000013 nop +80001918: 00000013 nop +8000191c: 00000013 nop +80001920: 00000013 nop +80001924: 00000013 nop +80001928: 00000013 nop +8000192c: 00000013 nop +80001930: 00000013 nop +80001934: 00000013 nop +80001938: 00000013 nop +8000193c: 00000013 nop +80001940: 00000013 nop +80001944: 00000013 nop +80001948: 00000013 nop +8000194c: 00000013 nop +80001950: 00000013 nop +80001954: 00000013 nop +80001958: 00000013 nop +8000195c: 00000013 nop +80001960: 00000013 nop +80001964: 00000013 nop +80001968: 00000013 nop +8000196c: 00000013 nop +80001970: 00000013 nop +80001974: 00000013 nop +80001978: 00000013 nop +8000197c: 00000013 nop +80001980: 00000013 nop +80001984: 00000013 nop +80001988: 00000013 nop +8000198c: 00000013 nop +80001990: 00000013 nop +80001994: 00000013 nop +80001998: 00000013 nop +8000199c: 00000013 nop +800019a0: 00000013 nop +800019a4: 00000013 nop +800019a8: 00000013 nop +800019ac: 00000013 nop +800019b0: 00000013 nop +800019b4: 00000013 nop +800019b8: 00000013 nop +800019bc: 00000013 nop +800019c0: 00000013 nop +800019c4: 00000013 nop +800019c8: 00000013 nop +800019cc: 00000013 nop +800019d0: 00000013 nop +800019d4: 00000013 nop +800019d8: 00000013 nop +800019dc: 00000013 nop +800019e0: 00000013 nop +800019e4: 00000013 nop +800019e8: 00000013 nop +800019ec: 00000013 nop +800019f0: 00000013 nop +800019f4: 00000013 nop +800019f8: 00000013 nop +800019fc: 00000013 nop +80001a00: 00000013 nop +80001a04: 00000013 nop +80001a08: 00000013 nop +80001a0c: 00000013 nop +80001a10: 00000013 nop +80001a14: 00000013 nop +80001a18: 00000013 nop +80001a1c: 00000013 nop +80001a20: 00000013 nop +80001a24: 00000013 nop +80001a28: 00000013 nop +80001a2c: 00000013 nop +80001a30: 00000013 nop +80001a34: 00000013 nop +80001a38: 00000013 nop +80001a3c: 00000013 nop +80001a40: 00000013 nop +80001a44: 00000013 nop +80001a48: 00000013 nop +80001a4c: 00000013 nop +80001a50: 00000013 nop +80001a54: 00000013 nop +80001a58: 00000013 nop +80001a5c: 00000013 nop +80001a60: 00000013 nop +80001a64: 00000013 nop +80001a68: 00000013 nop +80001a6c: 00000013 nop +80001a70: 00000013 nop +80001a74: 00000013 nop +80001a78: 00000013 nop +80001a7c: 00000013 nop +80001a80: 00000013 nop +80001a84: 00000013 nop +80001a88: 00000013 nop +80001a8c: 00000013 nop +80001a90: 00000013 nop +80001a94: 00000013 nop +80001a98: 00000013 nop +80001a9c: 00000013 nop +80001aa0: 00000013 nop +80001aa4: 00000013 nop +80001aa8: 00000013 nop +80001aac: 00000013 nop +80001ab0: 00000013 nop +80001ab4: 00000013 nop +80001ab8: 00000013 nop +80001abc: 00000013 nop +80001ac0: 00000013 nop +80001ac4: 00000013 nop +80001ac8: 00000013 nop +80001acc: 00000013 nop +80001ad0: 00000013 nop +80001ad4: 00000013 nop +80001ad8: 00000013 nop +80001adc: 00000013 nop +80001ae0: 00000013 nop +80001ae4: 00000013 nop +80001ae8: 00000013 nop +80001aec: 00000013 nop +80001af0: 00000013 nop +80001af4: 00000013 nop +80001af8: 00000013 nop +80001afc: 00000013 nop +80001b00: 00000013 nop +80001b04: 00000013 nop +80001b08: 00000013 nop +80001b0c: 00000013 nop +80001b10: 00000013 nop +80001b14: 00000013 nop +80001b18: 00000013 nop +80001b1c: 00000013 nop +80001b20: 00000013 nop +80001b24: 00000013 nop +80001b28: 00000013 nop +80001b2c: 00000013 nop +80001b30: 00000013 nop +80001b34: 00000013 nop +80001b38: 00000013 nop +80001b3c: 00000013 nop +80001b40: 00000013 nop +80001b44: 00000013 nop +80001b48: 00000013 nop +80001b4c: 00000013 nop +80001b50: 00000013 nop +80001b54: 00000013 nop +80001b58: 00000013 nop +80001b5c: 00000013 nop +80001b60: 00000013 nop +80001b64: 00000013 nop +80001b68: 00000013 nop +80001b6c: 00000013 nop +80001b70: 00000013 nop +80001b74: 00000013 nop +80001b78: 00000013 nop +80001b7c: 00000013 nop +80001b80: 00000013 nop +80001b84: 00000013 nop +80001b88: 00000013 nop +80001b8c: 00000013 nop +80001b90: 00000013 nop +80001b94: 00000013 nop +80001b98: 00000013 nop +80001b9c: 00000013 nop +80001ba0: 00000013 nop +80001ba4: 00000013 nop +80001ba8: 00000013 nop +80001bac: 00000013 nop +80001bb0: 00000013 nop +80001bb4: 00000013 nop +80001bb8: 00000013 nop +80001bbc: 00000013 nop +80001bc0: 00000013 nop +80001bc4: 00000013 nop +80001bc8: 00000013 nop +80001bcc: 00000013 nop +80001bd0: 00000013 nop +80001bd4: 00000013 nop +80001bd8: 00000013 nop +80001bdc: 00000013 nop +80001be0: 00000013 nop +80001be4: 00000013 nop +80001be8: 00000013 nop +80001bec: 00000013 nop +80001bf0: 00000013 nop +80001bf4: 00000013 nop +80001bf8: 00000013 nop +80001bfc: 00000013 nop +80001c00: 00000013 nop +80001c04: 00000013 nop +80001c08: 00000013 nop +80001c0c: 00000013 nop +80001c10: 00000013 nop +80001c14: 00000013 nop +80001c18: 00000013 nop +80001c1c: 00000013 nop +80001c20: 00000013 nop +80001c24: 00000013 nop +80001c28: 00000013 nop +80001c2c: 00000013 nop +80001c30: 00000013 nop +80001c34: 00000013 nop +80001c38: 00000013 nop +80001c3c: 00000013 nop +80001c40: 00000013 nop +80001c44: 00000013 nop +80001c48: 00000013 nop +80001c4c: 00000013 nop +80001c50: 00000013 nop +80001c54: 00000013 nop +80001c58: 00000013 nop +80001c5c: 00000013 nop +80001c60: 00000013 nop +80001c64: 00000013 nop +80001c68: 00000013 nop +80001c6c: 00000013 nop +80001c70: 00000013 nop +80001c74: 00000013 nop +80001c78: 00000013 nop +80001c7c: 00000013 nop +80001c80: 00000013 nop +80001c84: 00000013 nop +80001c88: 00000013 nop +80001c8c: 00000013 nop +80001c90: 00000013 nop +80001c94: 00000013 nop +80001c98: 00000013 nop +80001c9c: 00000013 nop +80001ca0: 00000013 nop +80001ca4: 00000013 nop +80001ca8: 00000013 nop +80001cac: 00000013 nop +80001cb0: 00000013 nop +80001cb4: 00000013 nop +80001cb8: 00000013 nop +80001cbc: 00000013 nop +80001cc0: 00000013 nop +80001cc4: 00000013 nop +80001cc8: 00000013 nop +80001ccc: 00000013 nop +80001cd0: 00000013 nop +80001cd4: 00000013 nop +80001cd8: 00000013 nop +80001cdc: 00000013 nop +80001ce0: 00000013 nop +80001ce4: 00000013 nop +80001ce8: 00000013 nop +80001cec: 00000013 nop +80001cf0: 00000013 nop +80001cf4: 00000013 nop +80001cf8: 00000013 nop +80001cfc: 00000013 nop +80001d00: 00000013 nop +80001d04: 00000013 nop +80001d08: 00000013 nop +80001d0c: 00000013 nop +80001d10: 00000013 nop +80001d14: 00000013 nop +80001d18: 00000013 nop +80001d1c: 00000013 nop +80001d20: 00000013 nop +80001d24: 00000013 nop +80001d28: 00000013 nop +80001d2c: 00000013 nop +80001d30: 00000013 nop +80001d34: 00000013 nop +80001d38: 00000013 nop +80001d3c: 00000013 nop +80001d40: 00000013 nop +80001d44: 00000013 nop +80001d48: 00000013 nop +80001d4c: 00000013 nop +80001d50: 00000013 nop +80001d54: 00000013 nop +80001d58: 00000013 nop +80001d5c: 00000013 nop +80001d60: 00000013 nop +80001d64: 00000013 nop +80001d68: 00000013 nop +80001d6c: 00000013 nop +80001d70: 00000013 nop +80001d74: 00000013 nop +80001d78: 00000013 nop +80001d7c: 00000013 nop +80001d80: 00000013 nop +80001d84: 00000013 nop +80001d88: 00000013 nop +80001d8c: 00000013 nop +80001d90: 00000013 nop +80001d94: 00000013 nop +80001d98: 00000013 nop +80001d9c: 00000013 nop +80001da0: 00000013 nop +80001da4: 00000013 nop +80001da8: 00000013 nop +80001dac: 00000013 nop +80001db0: 00000013 nop +80001db4: 00000013 nop +80001db8: 00000013 nop +80001dbc: 00000013 nop +80001dc0: 00000013 nop +80001dc4: 00000013 nop +80001dc8: 00000013 nop +80001dcc: 00000013 nop +80001dd0: 00000013 nop +80001dd4: 00000013 nop +80001dd8: 00000013 nop +80001ddc: 00000013 nop +80001de0: 00000013 nop +80001de4: 00000013 nop +80001de8: 00000013 nop +80001dec: 00000013 nop +80001df0: 00000013 nop +80001df4: 00000013 nop +80001df8: 00000013 nop +80001dfc: 00000013 nop +80001e00: 00000013 nop +80001e04: 00000013 nop +80001e08: 00000013 nop +80001e0c: 00000013 nop +80001e10: 00000013 nop +80001e14: 00000013 nop +80001e18: 00000013 nop +80001e1c: 00000013 nop +80001e20: 00000013 nop +80001e24: 00000013 nop +80001e28: 00000013 nop +80001e2c: 00000013 nop +80001e30: 00000013 nop +80001e34: 00000013 nop +80001e38: 00000013 nop +80001e3c: 00000013 nop +80001e40: 00000013 nop +80001e44: 00000013 nop +80001e48: 00000013 nop +80001e4c: 00000013 nop +80001e50: 00000013 nop +80001e54: 00000013 nop +80001e58: 00000013 nop +80001e5c: 00000013 nop +80001e60: 00000013 nop +80001e64: 00000013 nop +80001e68: 00000013 nop +80001e6c: 00000013 nop +80001e70: 00000013 nop +80001e74: 00000013 nop +80001e78: 00000013 nop +80001e7c: 00000013 nop +80001e80: 00000013 nop +80001e84: 00000013 nop +80001e88: 00000013 nop +80001e8c: 00000013 nop +80001e90: 00000013 nop +80001e94: 00000013 nop +80001e98: 00000013 nop +80001e9c: 00000013 nop +80001ea0: 00000013 nop +80001ea4: 00000013 nop +80001ea8: 00000013 nop +80001eac: 00000013 nop +80001eb0: 00000013 nop +80001eb4: 00000013 nop +80001eb8: 00000013 nop +80001ebc: 00000013 nop +80001ec0: 00000013 nop +80001ec4: 00000013 nop +80001ec8: 00000013 nop +80001ecc: 00000013 nop +80001ed0: 00000013 nop +80001ed4: 00000013 nop +80001ed8: 00000013 nop +80001edc: 00000013 nop +80001ee0: 00000013 nop +80001ee4: 00000013 nop +80001ee8: 00000013 nop +80001eec: 00000013 nop +80001ef0: 00000013 nop +80001ef4: 00000013 nop +80001ef8: 00000013 nop +80001efc: 00000013 nop +80001f00: 00000013 nop +80001f04: 00000013 nop +80001f08: 00000013 nop +80001f0c: 00000013 nop +80001f10: 00000013 nop +80001f14: 00000013 nop +80001f18: 00000013 nop +80001f1c: 00000013 nop +80001f20: 00000013 nop +80001f24: 00000013 nop +80001f28: 00000013 nop +80001f2c: 00000013 nop +80001f30: 00000013 nop +80001f34: 00000013 nop +80001f38: 00000013 nop +80001f3c: 00000013 nop +80001f40: 00000013 nop +80001f44: 00000013 nop +80001f48: 00000013 nop +80001f4c: 00000013 nop +80001f50: 00000013 nop +80001f54: 00000013 nop +80001f58: 00000013 nop +80001f5c: 00000013 nop +80001f60: 00000013 nop +80001f64: 00000013 nop +80001f68: 00000013 nop +80001f6c: 00000013 nop +80001f70: 00000013 nop +80001f74: 00000013 nop +80001f78: 00000013 nop +80001f7c: 00000013 nop +80001f80: 00000013 nop +80001f84: 00000013 nop +80001f88: 00000013 nop +80001f8c: 00000013 nop +80001f90: 00000013 nop +80001f94: 00000013 nop +80001f98: 00000013 nop +80001f9c: 00000013 nop +80001fa0: 00000013 nop +80001fa4: 00000013 nop +80001fa8: 00000013 nop +80001fac: 00000013 nop +80001fb0: 00000013 nop +80001fb4: 00000013 nop +80001fb8: 00000013 nop +80001fbc: 00000013 nop +80001fc0: 00000013 nop +80001fc4: 00000013 nop +80001fc8: 00000013 nop +80001fcc: 00000013 nop +80001fd0: 00000013 nop +80001fd4: 00000013 nop +80001fd8: 00000013 nop +80001fdc: 00000013 nop +80001fe0: 00000013 nop +80001fe4: 00000013 nop +80001fe8: 00000013 nop +80001fec: 00000013 nop +80001ff0: 00000013 nop +80001ff4: 00000013 nop +80001ff8: 00000013 nop +80001ffc: 00000013 nop + +80002000 : +80002000: 0000 unimp +80002002: 0000 unimp +80002004: 00000013 nop +80002008: 00000013 nop +8000200c: 00000013 nop +80002010: 00000013 nop +80002014: 00000013 nop +80002018: 00000013 nop +8000201c: 00000013 nop +80002020: 00000013 nop +80002024: 00000013 nop +80002028: 00000013 nop +8000202c: 00000013 nop +80002030: 00000013 nop +80002034: 00000013 nop +80002038: 00000013 nop +8000203c: 00000013 nop +80002040: 00000013 nop +80002044: 00000013 nop +80002048: 00000013 nop +8000204c: 00000013 nop +80002050: 00000013 nop +80002054: 00000013 nop +80002058: 00000013 nop +8000205c: 00000013 nop +80002060: 00000013 nop +80002064: 00000013 nop +80002068: 00000013 nop +8000206c: 00000013 nop +80002070: 00000013 nop +80002074: 00000013 nop +80002078: 00000013 nop +8000207c: 00000013 nop +80002080: 00000013 nop +80002084: 00000013 nop +80002088: 00000013 nop +8000208c: 00000013 nop +80002090: 00000013 nop +80002094: 00000013 nop +80002098: 00000013 nop +8000209c: 00000013 nop +800020a0: 00000013 nop +800020a4: 00000013 nop +800020a8: 00000013 nop +800020ac: 00000013 nop +800020b0: 00000013 nop +800020b4: 00000013 nop +800020b8: 00000013 nop +800020bc: 00000013 nop +800020c0: 00000013 nop +800020c4: 00000013 nop +800020c8: 00000013 nop +800020cc: 00000013 nop +800020d0: 00000013 nop +800020d4: 00000013 nop +800020d8: 00000013 nop +800020dc: 00000013 nop +800020e0: 00000013 nop +800020e4: 00000013 nop +800020e8: 00000013 nop +800020ec: 00000013 nop +800020f0: 00000013 nop +800020f4: 00000013 nop +800020f8: 00000013 nop +800020fc: 00000013 nop +80002100: 00000013 nop +80002104: 00000013 nop +80002108: 00000013 nop +8000210c: 00000013 nop +80002110: 00000013 nop +80002114: 00000013 nop +80002118: 00000013 nop +8000211c: 00000013 nop +80002120: 00000013 nop +80002124: 00000013 nop +80002128: 00000013 nop +8000212c: 00000013 nop +80002130: 00000013 nop +80002134: 00000013 nop +80002138: 00000013 nop +8000213c: 00000013 nop +80002140: 00000013 nop +80002144: 00000013 nop +80002148: 00000013 nop +8000214c: 00000013 nop +80002150: 00000013 nop +80002154: 00000013 nop +80002158: 00000013 nop +8000215c: 00000013 nop +80002160: 00000013 nop +80002164: 00000013 nop +80002168: 00000013 nop +8000216c: 00000013 nop +80002170: 00000013 nop +80002174: 00000013 nop +80002178: 00000013 nop +8000217c: 00000013 nop +80002180: 00000013 nop +80002184: 00000013 nop +80002188: 00000013 nop +8000218c: 00000013 nop +80002190: 00000013 nop +80002194: 00000013 nop +80002198: 00000013 nop +8000219c: 00000013 nop +800021a0: 00000013 nop +800021a4: 00000013 nop +800021a8: 00000013 nop +800021ac: 00000013 nop +800021b0: 00000013 nop +800021b4: 00000013 nop +800021b8: 00000013 nop +800021bc: 00000013 nop +800021c0: 00000013 nop +800021c4: 00000013 nop +800021c8: 00000013 nop +800021cc: 00000013 nop +800021d0: 00000013 nop +800021d4: 00000013 nop +800021d8: 00000013 nop +800021dc: 00000013 nop +800021e0: 00000013 nop +800021e4: 00000013 nop +800021e8: 00000013 nop +800021ec: 00000013 nop +800021f0: 00000013 nop +800021f4: 00000013 nop +800021f8: 00000013 nop +800021fc: 00000013 nop +80002200: 00000013 nop +80002204: 00000013 nop +80002208: 00000013 nop +8000220c: 00000013 nop +80002210: 00000013 nop +80002214: 00000013 nop +80002218: 00000013 nop +8000221c: 00000013 nop +80002220: 00000013 nop +80002224: 00000013 nop +80002228: 00000013 nop +8000222c: 00000013 nop +80002230: 00000013 nop +80002234: 00000013 nop +80002238: 00000013 nop +8000223c: 00000013 nop +80002240: 00000013 nop +80002244: 00000013 nop +80002248: 00000013 nop +8000224c: 00000013 nop +80002250: 00000013 nop +80002254: 00000013 nop +80002258: 00000013 nop +8000225c: 00000013 nop +80002260: 00000013 nop +80002264: 00000013 nop +80002268: 00000013 nop +8000226c: 00000013 nop +80002270: 00000013 nop +80002274: 00000013 nop +80002278: 00000013 nop +8000227c: 00000013 nop +80002280: 00000013 nop +80002284: 00000013 nop +80002288: 00000013 nop +8000228c: 00000013 nop +80002290: 00000013 nop +80002294: 00000013 nop +80002298: 00000013 nop +8000229c: 00000013 nop +800022a0: 00000013 nop +800022a4: 00000013 nop +800022a8: 00000013 nop +800022ac: 00000013 nop +800022b0: 00000013 nop +800022b4: 00000013 nop +800022b8: 00000013 nop +800022bc: 00000013 nop +800022c0: 00000013 nop +800022c4: 00000013 nop +800022c8: 00000013 nop +800022cc: 00000013 nop +800022d0: 00000013 nop +800022d4: 00000013 nop +800022d8: 00000013 nop +800022dc: 00000013 nop +800022e0: 00000013 nop +800022e4: 00000013 nop +800022e8: 00000013 nop +800022ec: 00000013 nop +800022f0: 00000013 nop +800022f4: 00000013 nop +800022f8: 00000013 nop +800022fc: 00000013 nop +80002300: 00000013 nop +80002304: 00000013 nop +80002308: 00000013 nop +8000230c: 00000013 nop +80002310: 00000013 nop +80002314: 00000013 nop +80002318: 00000013 nop +8000231c: 00000013 nop +80002320: 00000013 nop +80002324: 00000013 nop +80002328: 00000013 nop +8000232c: 00000013 nop +80002330: 00000013 nop +80002334: 00000013 nop +80002338: 00000013 nop +8000233c: 00000013 nop +80002340: 00000013 nop +80002344: 00000013 nop +80002348: 00000013 nop +8000234c: 00000013 nop +80002350: 00000013 nop +80002354: 00000013 nop +80002358: 00000013 nop +8000235c: 00000013 nop +80002360: 00000013 nop +80002364: 00000013 nop +80002368: 00000013 nop +8000236c: 00000013 nop +80002370: 00000013 nop +80002374: 00000013 nop +80002378: 00000013 nop +8000237c: 00000013 nop +80002380: 00000013 nop +80002384: 00000013 nop +80002388: 00000013 nop +8000238c: 00000013 nop +80002390: 00000013 nop +80002394: 00000013 nop +80002398: 00000013 nop +8000239c: 00000013 nop +800023a0: 00000013 nop +800023a4: 00000013 nop +800023a8: 00000013 nop +800023ac: 00000013 nop +800023b0: 00000013 nop +800023b4: 00000013 nop +800023b8: 00000013 nop +800023bc: 00000013 nop +800023c0: 00000013 nop +800023c4: 00000013 nop +800023c8: 00000013 nop +800023cc: 00000013 nop +800023d0: 00000013 nop +800023d4: 00000013 nop +800023d8: 00000013 nop +800023dc: 00000013 nop +800023e0: 00000013 nop +800023e4: 00000013 nop +800023e8: 00000013 nop +800023ec: 00000013 nop +800023f0: 00000013 nop +800023f4: 00000013 nop +800023f8: 00000013 nop +800023fc: 00000013 nop +80002400: 00000013 nop +80002404: 00000013 nop +80002408: 00000013 nop +8000240c: 00000013 nop +80002410: 00000013 nop +80002414: 00000013 nop +80002418: 00000013 nop +8000241c: 00000013 nop +80002420: 00000013 nop +80002424: 00000013 nop +80002428: 00000013 nop +8000242c: 00000013 nop +80002430: 00000013 nop +80002434: 00000013 nop +80002438: 00000013 nop +8000243c: 00000013 nop +80002440: 00000013 nop +80002444: 00000013 nop +80002448: 00000013 nop +8000244c: 00000013 nop +80002450: 00000013 nop +80002454: 00000013 nop +80002458: 00000013 nop +8000245c: 00000013 nop +80002460: 00000013 nop +80002464: 00000013 nop +80002468: 00000013 nop +8000246c: 00000013 nop +80002470: 00000013 nop +80002474: 00000013 nop +80002478: 00000013 nop +8000247c: 00000013 nop +80002480: 00000013 nop +80002484: 00000013 nop +80002488: 00000013 nop +8000248c: 00000013 nop +80002490: 00000013 nop +80002494: 00000013 nop +80002498: 00000013 nop +8000249c: 00000013 nop +800024a0: 00000013 nop +800024a4: 00000013 nop +800024a8: 00000013 nop +800024ac: 00000013 nop +800024b0: 00000013 nop +800024b4: 00000013 nop +800024b8: 00000013 nop +800024bc: 00000013 nop +800024c0: 00000013 nop +800024c4: 00000013 nop +800024c8: 00000013 nop +800024cc: 00000013 nop +800024d0: 00000013 nop +800024d4: 00000013 nop +800024d8: 00000013 nop +800024dc: 00000013 nop +800024e0: 00000013 nop +800024e4: 00000013 nop +800024e8: 00000013 nop +800024ec: 00000013 nop +800024f0: 00000013 nop +800024f4: 00000013 nop +800024f8: 00000013 nop +800024fc: 00000013 nop +80002500: 00000013 nop +80002504: 00000013 nop +80002508: 00000013 nop +8000250c: 00000013 nop +80002510: 00000013 nop +80002514: 00000013 nop +80002518: 00000013 nop +8000251c: 00000013 nop +80002520: 00000013 nop +80002524: 00000013 nop +80002528: 00000013 nop +8000252c: 00000013 nop +80002530: 00000013 nop +80002534: 00000013 nop +80002538: 00000013 nop +8000253c: 00000013 nop +80002540: 00000013 nop +80002544: 00000013 nop +80002548: 00000013 nop +8000254c: 00000013 nop +80002550: 00000013 nop +80002554: 00000013 nop +80002558: 00000013 nop +8000255c: 00000013 nop +80002560: 00000013 nop +80002564: 00000013 nop +80002568: 00000013 nop +8000256c: 00000013 nop +80002570: 00000013 nop +80002574: 00000013 nop +80002578: 00000013 nop +8000257c: 00000013 nop +80002580: 00000013 nop +80002584: 00000013 nop +80002588: 00000013 nop +8000258c: 00000013 nop +80002590: 00000013 nop +80002594: 00000013 nop +80002598: 00000013 nop +8000259c: 00000013 nop +800025a0: 00000013 nop +800025a4: 00000013 nop +800025a8: 00000013 nop +800025ac: 00000013 nop +800025b0: 00000013 nop +800025b4: 00000013 nop +800025b8: 00000013 nop +800025bc: 00000013 nop +800025c0: 00000013 nop +800025c4: 00000013 nop +800025c8: 00000013 nop +800025cc: 00000013 nop +800025d0: 00000013 nop +800025d4: 00000013 nop +800025d8: 00000013 nop +800025dc: 00000013 nop +800025e0: 00000013 nop +800025e4: 00000013 nop +800025e8: 00000013 nop +800025ec: 00000013 nop +800025f0: 00000013 nop +800025f4: 00000013 nop +800025f8: 00000013 nop +800025fc: 00000013 nop +80002600: 00000013 nop +80002604: 00000013 nop +80002608: 00000013 nop +8000260c: 00000013 nop +80002610: 00000013 nop +80002614: 00000013 nop +80002618: 00000013 nop +8000261c: 00000013 nop +80002620: 00000013 nop +80002624: 00000013 nop +80002628: 00000013 nop +8000262c: 00000013 nop +80002630: 00000013 nop +80002634: 00000013 nop +80002638: 00000013 nop +8000263c: 00000013 nop +80002640: 00000013 nop +80002644: 00000013 nop +80002648: 00000013 nop +8000264c: 00000013 nop +80002650: 00000013 nop +80002654: 00000013 nop +80002658: 00000013 nop +8000265c: 00000013 nop +80002660: 00000013 nop +80002664: 00000013 nop +80002668: 00000013 nop +8000266c: 00000013 nop +80002670: 00000013 nop +80002674: 00000013 nop +80002678: 00000013 nop +8000267c: 00000013 nop +80002680: 00000013 nop +80002684: 00000013 nop +80002688: 00000013 nop +8000268c: 00000013 nop +80002690: 00000013 nop +80002694: 00000013 nop +80002698: 00000013 nop +8000269c: 00000013 nop +800026a0: 00000013 nop +800026a4: 00000013 nop +800026a8: 00000013 nop +800026ac: 00000013 nop +800026b0: 00000013 nop +800026b4: 00000013 nop +800026b8: 00000013 nop +800026bc: 00000013 nop +800026c0: 00000013 nop +800026c4: 00000013 nop +800026c8: 00000013 nop +800026cc: 00000013 nop +800026d0: 00000013 nop +800026d4: 00000013 nop +800026d8: 00000013 nop +800026dc: 00000013 nop +800026e0: 00000013 nop +800026e4: 00000013 nop +800026e8: 00000013 nop +800026ec: 00000013 nop +800026f0: 00000013 nop +800026f4: 00000013 nop +800026f8: 00000013 nop +800026fc: 00000013 nop +80002700: 00000013 nop +80002704: 00000013 nop +80002708: 00000013 nop +8000270c: 00000013 nop +80002710: 00000013 nop +80002714: 00000013 nop +80002718: 00000013 nop +8000271c: 00000013 nop +80002720: 00000013 nop +80002724: 00000013 nop +80002728: 00000013 nop +8000272c: 00000013 nop +80002730: 00000013 nop +80002734: 00000013 nop +80002738: 00000013 nop +8000273c: 00000013 nop +80002740: 00000013 nop +80002744: 00000013 nop +80002748: 00000013 nop +8000274c: 00000013 nop +80002750: 00000013 nop +80002754: 00000013 nop +80002758: 00000013 nop +8000275c: 00000013 nop +80002760: 00000013 nop +80002764: 00000013 nop +80002768: 00000013 nop +8000276c: 00000013 nop +80002770: 00000013 nop +80002774: 00000013 nop +80002778: 00000013 nop +8000277c: 00000013 nop +80002780: 00000013 nop +80002784: 00000013 nop +80002788: 00000013 nop +8000278c: 00000013 nop +80002790: 00000013 nop +80002794: 00000013 nop +80002798: 00000013 nop +8000279c: 00000013 nop +800027a0: 00000013 nop +800027a4: 00000013 nop +800027a8: 00000013 nop +800027ac: 00000013 nop +800027b0: 00000013 nop +800027b4: 00000013 nop +800027b8: 00000013 nop +800027bc: 00000013 nop +800027c0: 00000013 nop +800027c4: 00000013 nop +800027c8: 00000013 nop +800027cc: 00000013 nop +800027d0: 00000013 nop +800027d4: 00000013 nop +800027d8: 00000013 nop +800027dc: 00000013 nop +800027e0: 00000013 nop +800027e4: 00000013 nop +800027e8: 00000013 nop +800027ec: 00000013 nop +800027f0: 00000013 nop +800027f4: 00000013 nop +800027f8: 00000013 nop +800027fc: 00000013 nop +80002800: 00000013 nop +80002804: 00000013 nop +80002808: 00000013 nop +8000280c: 00000013 nop +80002810: 00000013 nop +80002814: 00000013 nop +80002818: 00000013 nop +8000281c: 00000013 nop +80002820: 00000013 nop +80002824: 00000013 nop +80002828: 00000013 nop +8000282c: 00000013 nop +80002830: 00000013 nop +80002834: 00000013 nop +80002838: 00000013 nop +8000283c: 00000013 nop +80002840: 00000013 nop +80002844: 00000013 nop +80002848: 00000013 nop +8000284c: 00000013 nop +80002850: 00000013 nop +80002854: 00000013 nop +80002858: 00000013 nop +8000285c: 00000013 nop +80002860: 00000013 nop +80002864: 00000013 nop +80002868: 00000013 nop +8000286c: 00000013 nop +80002870: 00000013 nop +80002874: 00000013 nop +80002878: 00000013 nop +8000287c: 00000013 nop +80002880: 00000013 nop +80002884: 00000013 nop +80002888: 00000013 nop +8000288c: 00000013 nop +80002890: 00000013 nop +80002894: 00000013 nop +80002898: 00000013 nop +8000289c: 00000013 nop +800028a0: 00000013 nop +800028a4: 00000013 nop +800028a8: 00000013 nop +800028ac: 00000013 nop +800028b0: 00000013 nop +800028b4: 00000013 nop +800028b8: 00000013 nop +800028bc: 00000013 nop +800028c0: 00000013 nop +800028c4: 00000013 nop +800028c8: 00000013 nop +800028cc: 00000013 nop +800028d0: 00000013 nop +800028d4: 00000013 nop +800028d8: 00000013 nop +800028dc: 00000013 nop +800028e0: 00000013 nop +800028e4: 00000013 nop +800028e8: 00000013 nop +800028ec: 00000013 nop +800028f0: 00000013 nop +800028f4: 00000013 nop +800028f8: 00000013 nop +800028fc: 00000013 nop +80002900: 00000013 nop +80002904: 00000013 nop +80002908: 00000013 nop +8000290c: 00000013 nop +80002910: 00000013 nop +80002914: 00000013 nop +80002918: 00000013 nop +8000291c: 00000013 nop +80002920: 00000013 nop +80002924: 00000013 nop +80002928: 00000013 nop +8000292c: 00000013 nop +80002930: 00000013 nop +80002934: 00000013 nop +80002938: 00000013 nop +8000293c: 00000013 nop +80002940: 00000013 nop +80002944: 00000013 nop +80002948: 00000013 nop +8000294c: 00000013 nop +80002950: 00000013 nop +80002954: 00000013 nop +80002958: 00000013 nop +8000295c: 00000013 nop +80002960: 00000013 nop +80002964: 00000013 nop +80002968: 00000013 nop +8000296c: 00000013 nop +80002970: 00000013 nop +80002974: 00000013 nop +80002978: 00000013 nop +8000297c: 00000013 nop +80002980: 00000013 nop +80002984: 00000013 nop +80002988: 00000013 nop +8000298c: 00000013 nop +80002990: 00000013 nop +80002994: 00000013 nop +80002998: 00000013 nop +8000299c: 00000013 nop +800029a0: 00000013 nop +800029a4: 00000013 nop +800029a8: 00000013 nop +800029ac: 00000013 nop +800029b0: 00000013 nop +800029b4: 00000013 nop +800029b8: 00000013 nop +800029bc: 00000013 nop +800029c0: 00000013 nop +800029c4: 00000013 nop +800029c8: 00000013 nop +800029cc: 00000013 nop +800029d0: 00000013 nop +800029d4: 00000013 nop +800029d8: 00000013 nop +800029dc: 00000013 nop +800029e0: 00000013 nop +800029e4: 00000013 nop +800029e8: 00000013 nop +800029ec: 00000013 nop +800029f0: 00000013 nop +800029f4: 00000013 nop +800029f8: 00000013 nop +800029fc: 00000013 nop +80002a00: 00000013 nop +80002a04: 00000013 nop +80002a08: 00000013 nop +80002a0c: 00000013 nop +80002a10: 00000013 nop +80002a14: 00000013 nop +80002a18: 00000013 nop +80002a1c: 00000013 nop +80002a20: 00000013 nop +80002a24: 00000013 nop +80002a28: 00000013 nop +80002a2c: 00000013 nop +80002a30: 00000013 nop +80002a34: 00000013 nop +80002a38: 00000013 nop +80002a3c: 00000013 nop +80002a40: 00000013 nop +80002a44: 00000013 nop +80002a48: 00000013 nop +80002a4c: 00000013 nop +80002a50: 00000013 nop +80002a54: 00000013 nop +80002a58: 00000013 nop +80002a5c: 00000013 nop +80002a60: 00000013 nop +80002a64: 00000013 nop +80002a68: 00000013 nop +80002a6c: 00000013 nop +80002a70: 00000013 nop +80002a74: 00000013 nop +80002a78: 00000013 nop +80002a7c: 00000013 nop +80002a80: 00000013 nop +80002a84: 00000013 nop +80002a88: 00000013 nop +80002a8c: 00000013 nop +80002a90: 00000013 nop +80002a94: 00000013 nop +80002a98: 00000013 nop +80002a9c: 00000013 nop +80002aa0: 00000013 nop +80002aa4: 00000013 nop +80002aa8: 00000013 nop +80002aac: 00000013 nop +80002ab0: 00000013 nop +80002ab4: 00000013 nop +80002ab8: 00000013 nop +80002abc: 00000013 nop +80002ac0: 00000013 nop +80002ac4: 00000013 nop +80002ac8: 00000013 nop +80002acc: 00000013 nop +80002ad0: 00000013 nop +80002ad4: 00000013 nop +80002ad8: 00000013 nop +80002adc: 00000013 nop +80002ae0: 00000013 nop +80002ae4: 00000013 nop +80002ae8: 00000013 nop +80002aec: 00000013 nop +80002af0: 00000013 nop +80002af4: 00000013 nop +80002af8: 00000013 nop +80002afc: 00000013 nop +80002b00: 00000013 nop +80002b04: 00000013 nop +80002b08: 00000013 nop +80002b0c: 00000013 nop +80002b10: 00000013 nop +80002b14: 00000013 nop +80002b18: 00000013 nop +80002b1c: 00000013 nop +80002b20: 00000013 nop +80002b24: 00000013 nop +80002b28: 00000013 nop +80002b2c: 00000013 nop +80002b30: 00000013 nop +80002b34: 00000013 nop +80002b38: 00000013 nop +80002b3c: 00000013 nop +80002b40: 00000013 nop +80002b44: 00000013 nop +80002b48: 00000013 nop +80002b4c: 00000013 nop +80002b50: 00000013 nop +80002b54: 00000013 nop +80002b58: 00000013 nop +80002b5c: 00000013 nop +80002b60: 00000013 nop +80002b64: 00000013 nop +80002b68: 00000013 nop +80002b6c: 00000013 nop +80002b70: 00000013 nop +80002b74: 00000013 nop +80002b78: 00000013 nop +80002b7c: 00000013 nop +80002b80: 00000013 nop +80002b84: 00000013 nop +80002b88: 00000013 nop +80002b8c: 00000013 nop +80002b90: 00000013 nop +80002b94: 00000013 nop +80002b98: 00000013 nop +80002b9c: 00000013 nop +80002ba0: 00000013 nop +80002ba4: 00000013 nop +80002ba8: 00000013 nop +80002bac: 00000013 nop +80002bb0: 00000013 nop +80002bb4: 00000013 nop +80002bb8: 00000013 nop +80002bbc: 00000013 nop +80002bc0: 00000013 nop +80002bc4: 00000013 nop +80002bc8: 00000013 nop +80002bcc: 00000013 nop +80002bd0: 00000013 nop +80002bd4: 00000013 nop +80002bd8: 00000013 nop +80002bdc: 00000013 nop +80002be0: 00000013 nop +80002be4: 00000013 nop +80002be8: 00000013 nop +80002bec: 00000013 nop +80002bf0: 00000013 nop +80002bf4: 00000013 nop +80002bf8: 00000013 nop +80002bfc: 00000013 nop +80002c00: 00000013 nop +80002c04: 00000013 nop +80002c08: 00000013 nop +80002c0c: 00000013 nop +80002c10: 00000013 nop +80002c14: 00000013 nop +80002c18: 00000013 nop +80002c1c: 00000013 nop +80002c20: 00000013 nop +80002c24: 00000013 nop +80002c28: 00000013 nop +80002c2c: 00000013 nop +80002c30: 00000013 nop +80002c34: 00000013 nop +80002c38: 00000013 nop +80002c3c: 00000013 nop +80002c40: 00000013 nop +80002c44: 00000013 nop +80002c48: 00000013 nop +80002c4c: 00000013 nop +80002c50: 00000013 nop +80002c54: 00000013 nop +80002c58: 00000013 nop +80002c5c: 00000013 nop +80002c60: 00000013 nop +80002c64: 00000013 nop +80002c68: 00000013 nop +80002c6c: 00000013 nop +80002c70: 00000013 nop +80002c74: 00000013 nop +80002c78: 00000013 nop +80002c7c: 00000013 nop +80002c80: 00000013 nop +80002c84: 00000013 nop +80002c88: 00000013 nop +80002c8c: 00000013 nop +80002c90: 00000013 nop +80002c94: 00000013 nop +80002c98: 00000013 nop +80002c9c: 00000013 nop +80002ca0: 00000013 nop +80002ca4: 00000013 nop +80002ca8: 00000013 nop +80002cac: 00000013 nop +80002cb0: 00000013 nop +80002cb4: 00000013 nop +80002cb8: 00000013 nop +80002cbc: 00000013 nop +80002cc0: 00000013 nop +80002cc4: 00000013 nop +80002cc8: 00000013 nop +80002ccc: 00000013 nop +80002cd0: 00000013 nop +80002cd4: 00000013 nop +80002cd8: 00000013 nop +80002cdc: 00000013 nop +80002ce0: 00000013 nop +80002ce4: 00000013 nop +80002ce8: 00000013 nop +80002cec: 00000013 nop +80002cf0: 00000013 nop +80002cf4: 00000013 nop +80002cf8: 00000013 nop +80002cfc: 00000013 nop +80002d00: 00000013 nop +80002d04: 00000013 nop +80002d08: 00000013 nop +80002d0c: 00000013 nop +80002d10: 00000013 nop +80002d14: 00000013 nop +80002d18: 00000013 nop +80002d1c: 00000013 nop +80002d20: 00000013 nop +80002d24: 00000013 nop +80002d28: 00000013 nop +80002d2c: 00000013 nop +80002d30: 00000013 nop +80002d34: 00000013 nop +80002d38: 00000013 nop +80002d3c: 00000013 nop +80002d40: 00000013 nop +80002d44: 00000013 nop +80002d48: 00000013 nop +80002d4c: 00000013 nop +80002d50: 00000013 nop +80002d54: 00000013 nop +80002d58: 00000013 nop +80002d5c: 00000013 nop +80002d60: 00000013 nop +80002d64: 00000013 nop +80002d68: 00000013 nop +80002d6c: 00000013 nop +80002d70: 00000013 nop +80002d74: 00000013 nop +80002d78: 00000013 nop +80002d7c: 00000013 nop +80002d80: 00000013 nop +80002d84: 00000013 nop +80002d88: 00000013 nop +80002d8c: 00000013 nop +80002d90: 00000013 nop +80002d94: 00000013 nop +80002d98: 00000013 nop +80002d9c: 00000013 nop +80002da0: 00000013 nop +80002da4: 00000013 nop +80002da8: 00000013 nop +80002dac: 00000013 nop +80002db0: 00000013 nop +80002db4: 00000013 nop +80002db8: 00000013 nop +80002dbc: 00000013 nop +80002dc0: 00000013 nop +80002dc4: 00000013 nop +80002dc8: 00000013 nop +80002dcc: 00000013 nop +80002dd0: 00000013 nop +80002dd4: 00000013 nop +80002dd8: 00000013 nop +80002ddc: 00000013 nop +80002de0: 00000013 nop +80002de4: 00000013 nop +80002de8: 00000013 nop +80002dec: 00000013 nop +80002df0: 00000013 nop +80002df4: 00000013 nop +80002df8: 00000013 nop +80002dfc: 00000013 nop +80002e00: 00000013 nop +80002e04: 00000013 nop +80002e08: 00000013 nop +80002e0c: 00000013 nop +80002e10: 00000013 nop +80002e14: 00000013 nop +80002e18: 00000013 nop +80002e1c: 00000013 nop +80002e20: 00000013 nop +80002e24: 00000013 nop +80002e28: 00000013 nop +80002e2c: 00000013 nop +80002e30: 00000013 nop +80002e34: 00000013 nop +80002e38: 00000013 nop +80002e3c: 00000013 nop +80002e40: 00000013 nop +80002e44: 00000013 nop +80002e48: 00000013 nop +80002e4c: 00000013 nop +80002e50: 00000013 nop +80002e54: 00000013 nop +80002e58: 00000013 nop +80002e5c: 00000013 nop +80002e60: 00000013 nop +80002e64: 00000013 nop +80002e68: 00000013 nop +80002e6c: 00000013 nop +80002e70: 00000013 nop +80002e74: 00000013 nop +80002e78: 00000013 nop +80002e7c: 00000013 nop +80002e80: 00000013 nop +80002e84: 00000013 nop +80002e88: 00000013 nop +80002e8c: 00000013 nop +80002e90: 00000013 nop +80002e94: 00000013 nop +80002e98: 00000013 nop +80002e9c: 00000013 nop +80002ea0: 00000013 nop +80002ea4: 00000013 nop +80002ea8: 00000013 nop +80002eac: 00000013 nop +80002eb0: 00000013 nop +80002eb4: 00000013 nop +80002eb8: 00000013 nop +80002ebc: 00000013 nop +80002ec0: 00000013 nop +80002ec4: 00000013 nop +80002ec8: 00000013 nop +80002ecc: 00000013 nop +80002ed0: 00000013 nop +80002ed4: 00000013 nop +80002ed8: 00000013 nop +80002edc: 00000013 nop +80002ee0: 00000013 nop +80002ee4: 00000013 nop +80002ee8: 00000013 nop +80002eec: 00000013 nop +80002ef0: 00000013 nop +80002ef4: 00000013 nop +80002ef8: 00000013 nop +80002efc: 00000013 nop +80002f00: 00000013 nop +80002f04: 00000013 nop +80002f08: 00000013 nop +80002f0c: 00000013 nop +80002f10: 00000013 nop +80002f14: 00000013 nop +80002f18: 00000013 nop +80002f1c: 00000013 nop +80002f20: 00000013 nop +80002f24: 00000013 nop +80002f28: 00000013 nop +80002f2c: 00000013 nop +80002f30: 00000013 nop +80002f34: 00000013 nop +80002f38: 00000013 nop +80002f3c: 00000013 nop +80002f40: 00000013 nop +80002f44: 00000013 nop +80002f48: 00000013 nop +80002f4c: 00000013 nop +80002f50: 00000013 nop +80002f54: 00000013 nop +80002f58: 00000013 nop +80002f5c: 00000013 nop +80002f60: 00000013 nop +80002f64: 00000013 nop +80002f68: 00000013 nop +80002f6c: 00000013 nop +80002f70: 00000013 nop +80002f74: 00000013 nop +80002f78: 00000013 nop +80002f7c: 00000013 nop +80002f80: 00000013 nop +80002f84: 00000013 nop +80002f88: 00000013 nop +80002f8c: 00000013 nop +80002f90: 00000013 nop +80002f94: 00000013 nop +80002f98: 00000013 nop +80002f9c: 00000013 nop +80002fa0: 00000013 nop +80002fa4: 00000013 nop +80002fa8: 00000013 nop +80002fac: 00000013 nop +80002fb0: 00000013 nop +80002fb4: 00000013 nop +80002fb8: 00000013 nop +80002fbc: 00000013 nop +80002fc0: 00000013 nop +80002fc4: 00000013 nop +80002fc8: 00000013 nop +80002fcc: 00000013 nop +80002fd0: 00000013 nop +80002fd4: 00000013 nop +80002fd8: 00000013 nop +80002fdc: 00000013 nop +80002fe0: 00000013 nop +80002fe4: 00000013 nop +80002fe8: 00000013 nop +80002fec: 00000013 nop +80002ff0: 00000013 nop +80002ff4: 00000013 nop +80002ff8: 00000013 nop +80002ffc: 00000013 nop + +80003000 : +80003000: 0000 unimp +80003002: 0000 unimp +80003004: 00000013 nop +80003008: 00000013 nop +8000300c: 00000013 nop +80003010: 00000013 nop +80003014: 00000013 nop +80003018: 00000013 nop +8000301c: 00000013 nop +80003020: 00000013 nop +80003024: 00000013 nop +80003028: 00000013 nop +8000302c: 00000013 nop +80003030: 00000013 nop +80003034: 00000013 nop +80003038: 00000013 nop +8000303c: 00000013 nop +80003040: 00000013 nop +80003044: 00000013 nop +80003048: 00000013 nop +8000304c: 00000013 nop +80003050: 00000013 nop +80003054: 00000013 nop +80003058: 00000013 nop +8000305c: 00000013 nop +80003060: 00000013 nop +80003064: 00000013 nop +80003068: 00000013 nop +8000306c: 00000013 nop +80003070: 00000013 nop +80003074: 00000013 nop +80003078: 00000013 nop +8000307c: 00000013 nop +80003080: 00000013 nop +80003084: 00000013 nop +80003088: 00000013 nop +8000308c: 00000013 nop +80003090: 00000013 nop +80003094: 00000013 nop +80003098: 00000013 nop +8000309c: 00000013 nop +800030a0: 00000013 nop +800030a4: 00000013 nop +800030a8: 00000013 nop +800030ac: 00000013 nop +800030b0: 00000013 nop +800030b4: 00000013 nop +800030b8: 00000013 nop +800030bc: 00000013 nop +800030c0: 00000013 nop +800030c4: 00000013 nop +800030c8: 00000013 nop +800030cc: 00000013 nop +800030d0: 00000013 nop +800030d4: 00000013 nop +800030d8: 00000013 nop +800030dc: 00000013 nop +800030e0: 00000013 nop +800030e4: 00000013 nop +800030e8: 00000013 nop +800030ec: 00000013 nop +800030f0: 00000013 nop +800030f4: 00000013 nop +800030f8: 00000013 nop +800030fc: 00000013 nop +80003100: 00000013 nop +80003104: 00000013 nop +80003108: 00000013 nop +8000310c: 00000013 nop +80003110: 00000013 nop +80003114: 00000013 nop +80003118: 00000013 nop +8000311c: 00000013 nop +80003120: 00000013 nop +80003124: 00000013 nop +80003128: 00000013 nop +8000312c: 00000013 nop +80003130: 00000013 nop +80003134: 00000013 nop +80003138: 00000013 nop +8000313c: 00000013 nop +80003140: 00000013 nop +80003144: 00000013 nop +80003148: 00000013 nop +8000314c: 00000013 nop +80003150: 00000013 nop +80003154: 00000013 nop +80003158: 00000013 nop +8000315c: 00000013 nop +80003160: 00000013 nop +80003164: 00000013 nop +80003168: 00000013 nop +8000316c: 00000013 nop +80003170: 00000013 nop +80003174: 00000013 nop +80003178: 00000013 nop +8000317c: 00000013 nop +80003180: 00000013 nop +80003184: 00000013 nop +80003188: 00000013 nop +8000318c: 00000013 nop +80003190: 00000013 nop +80003194: 00000013 nop +80003198: 00000013 nop +8000319c: 00000013 nop +800031a0: 00000013 nop +800031a4: 00000013 nop +800031a8: 00000013 nop +800031ac: 00000013 nop +800031b0: 00000013 nop +800031b4: 00000013 nop +800031b8: 00000013 nop +800031bc: 00000013 nop +800031c0: 00000013 nop +800031c4: 00000013 nop +800031c8: 00000013 nop +800031cc: 00000013 nop +800031d0: 00000013 nop +800031d4: 00000013 nop +800031d8: 00000013 nop +800031dc: 00000013 nop +800031e0: 00000013 nop +800031e4: 00000013 nop +800031e8: 00000013 nop +800031ec: 00000013 nop +800031f0: 00000013 nop +800031f4: 00000013 nop +800031f8: 00000013 nop +800031fc: 00000013 nop +80003200: 00000013 nop +80003204: 00000013 nop +80003208: 00000013 nop +8000320c: 00000013 nop +80003210: 00000013 nop +80003214: 00000013 nop +80003218: 00000013 nop +8000321c: 00000013 nop +80003220: 00000013 nop +80003224: 00000013 nop +80003228: 00000013 nop +8000322c: 00000013 nop +80003230: 00000013 nop +80003234: 00000013 nop +80003238: 00000013 nop +8000323c: 00000013 nop +80003240: 00000013 nop +80003244: 00000013 nop +80003248: 00000013 nop +8000324c: 00000013 nop +80003250: 00000013 nop +80003254: 00000013 nop +80003258: 00000013 nop +8000325c: 00000013 nop +80003260: 00000013 nop +80003264: 00000013 nop +80003268: 00000013 nop +8000326c: 00000013 nop +80003270: 00000013 nop +80003274: 00000013 nop +80003278: 00000013 nop +8000327c: 00000013 nop +80003280: 00000013 nop +80003284: 00000013 nop +80003288: 00000013 nop +8000328c: 00000013 nop +80003290: 00000013 nop +80003294: 00000013 nop +80003298: 00000013 nop +8000329c: 00000013 nop +800032a0: 00000013 nop +800032a4: 00000013 nop +800032a8: 00000013 nop +800032ac: 00000013 nop +800032b0: 00000013 nop +800032b4: 00000013 nop +800032b8: 00000013 nop +800032bc: 00000013 nop +800032c0: 00000013 nop +800032c4: 00000013 nop +800032c8: 00000013 nop +800032cc: 00000013 nop +800032d0: 00000013 nop +800032d4: 00000013 nop +800032d8: 00000013 nop +800032dc: 00000013 nop +800032e0: 00000013 nop +800032e4: 00000013 nop +800032e8: 00000013 nop +800032ec: 00000013 nop +800032f0: 00000013 nop +800032f4: 00000013 nop +800032f8: 00000013 nop +800032fc: 00000013 nop +80003300: 00000013 nop +80003304: 00000013 nop +80003308: 00000013 nop +8000330c: 00000013 nop +80003310: 00000013 nop +80003314: 00000013 nop +80003318: 00000013 nop +8000331c: 00000013 nop +80003320: 00000013 nop +80003324: 00000013 nop +80003328: 00000013 nop +8000332c: 00000013 nop +80003330: 00000013 nop +80003334: 00000013 nop +80003338: 00000013 nop +8000333c: 00000013 nop +80003340: 00000013 nop +80003344: 00000013 nop +80003348: 00000013 nop +8000334c: 00000013 nop +80003350: 00000013 nop +80003354: 00000013 nop +80003358: 00000013 nop +8000335c: 00000013 nop +80003360: 00000013 nop +80003364: 00000013 nop +80003368: 00000013 nop +8000336c: 00000013 nop +80003370: 00000013 nop +80003374: 00000013 nop +80003378: 00000013 nop +8000337c: 00000013 nop +80003380: 00000013 nop +80003384: 00000013 nop +80003388: 00000013 nop +8000338c: 00000013 nop +80003390: 00000013 nop +80003394: 00000013 nop +80003398: 00000013 nop +8000339c: 00000013 nop +800033a0: 00000013 nop +800033a4: 00000013 nop +800033a8: 00000013 nop +800033ac: 00000013 nop +800033b0: 00000013 nop +800033b4: 00000013 nop +800033b8: 00000013 nop +800033bc: 00000013 nop +800033c0: 00000013 nop +800033c4: 00000013 nop +800033c8: 00000013 nop +800033cc: 00000013 nop +800033d0: 00000013 nop +800033d4: 00000013 nop +800033d8: 00000013 nop +800033dc: 00000013 nop +800033e0: 00000013 nop +800033e4: 00000013 nop +800033e8: 00000013 nop +800033ec: 00000013 nop +800033f0: 00000013 nop +800033f4: 00000013 nop +800033f8: 00000013 nop +800033fc: 00000013 nop +80003400: 00000013 nop +80003404: 00000013 nop +80003408: 00000013 nop +8000340c: 00000013 nop +80003410: 00000013 nop +80003414: 00000013 nop +80003418: 00000013 nop +8000341c: 00000013 nop +80003420: 00000013 nop +80003424: 00000013 nop +80003428: 00000013 nop +8000342c: 00000013 nop +80003430: 00000013 nop +80003434: 00000013 nop +80003438: 00000013 nop +8000343c: 00000013 nop +80003440: 00000013 nop +80003444: 00000013 nop +80003448: 00000013 nop +8000344c: 00000013 nop +80003450: 00000013 nop +80003454: 00000013 nop +80003458: 00000013 nop +8000345c: 00000013 nop +80003460: 00000013 nop +80003464: 00000013 nop +80003468: 00000013 nop +8000346c: 00000013 nop +80003470: 00000013 nop +80003474: 00000013 nop +80003478: 00000013 nop +8000347c: 00000013 nop +80003480: 00000013 nop +80003484: 00000013 nop +80003488: 00000013 nop +8000348c: 00000013 nop +80003490: 00000013 nop +80003494: 00000013 nop +80003498: 00000013 nop +8000349c: 00000013 nop +800034a0: 00000013 nop +800034a4: 00000013 nop +800034a8: 00000013 nop +800034ac: 00000013 nop +800034b0: 00000013 nop +800034b4: 00000013 nop +800034b8: 00000013 nop +800034bc: 00000013 nop +800034c0: 00000013 nop +800034c4: 00000013 nop +800034c8: 00000013 nop +800034cc: 00000013 nop +800034d0: 00000013 nop +800034d4: 00000013 nop +800034d8: 00000013 nop +800034dc: 00000013 nop +800034e0: 00000013 nop +800034e4: 00000013 nop +800034e8: 00000013 nop +800034ec: 00000013 nop +800034f0: 00000013 nop +800034f4: 00000013 nop +800034f8: 00000013 nop +800034fc: 00000013 nop +80003500: 00000013 nop +80003504: 00000013 nop +80003508: 00000013 nop +8000350c: 00000013 nop +80003510: 00000013 nop +80003514: 00000013 nop +80003518: 00000013 nop +8000351c: 00000013 nop +80003520: 00000013 nop +80003524: 00000013 nop +80003528: 00000013 nop +8000352c: 00000013 nop +80003530: 00000013 nop +80003534: 00000013 nop +80003538: 00000013 nop +8000353c: 00000013 nop +80003540: 00000013 nop +80003544: 00000013 nop +80003548: 00000013 nop +8000354c: 00000013 nop +80003550: 00000013 nop +80003554: 00000013 nop +80003558: 00000013 nop +8000355c: 00000013 nop +80003560: 00000013 nop +80003564: 00000013 nop +80003568: 00000013 nop +8000356c: 00000013 nop +80003570: 00000013 nop +80003574: 00000013 nop +80003578: 00000013 nop +8000357c: 00000013 nop +80003580: 00000013 nop +80003584: 00000013 nop +80003588: 00000013 nop +8000358c: 00000013 nop +80003590: 00000013 nop +80003594: 00000013 nop +80003598: 00000013 nop +8000359c: 00000013 nop +800035a0: 00000013 nop +800035a4: 00000013 nop +800035a8: 00000013 nop +800035ac: 00000013 nop +800035b0: 00000013 nop +800035b4: 00000013 nop +800035b8: 00000013 nop +800035bc: 00000013 nop +800035c0: 00000013 nop +800035c4: 00000013 nop +800035c8: 00000013 nop +800035cc: 00000013 nop +800035d0: 00000013 nop +800035d4: 00000013 nop +800035d8: 00000013 nop +800035dc: 00000013 nop +800035e0: 00000013 nop +800035e4: 00000013 nop +800035e8: 00000013 nop +800035ec: 00000013 nop +800035f0: 00000013 nop +800035f4: 00000013 nop +800035f8: 00000013 nop +800035fc: 00000013 nop +80003600: 00000013 nop +80003604: 00000013 nop +80003608: 00000013 nop +8000360c: 00000013 nop +80003610: 00000013 nop +80003614: 00000013 nop +80003618: 00000013 nop +8000361c: 00000013 nop +80003620: 00000013 nop +80003624: 00000013 nop +80003628: 00000013 nop +8000362c: 00000013 nop +80003630: 00000013 nop +80003634: 00000013 nop +80003638: 00000013 nop +8000363c: 00000013 nop +80003640: 00000013 nop +80003644: 00000013 nop +80003648: 00000013 nop +8000364c: 00000013 nop +80003650: 00000013 nop +80003654: 00000013 nop +80003658: 00000013 nop +8000365c: 00000013 nop +80003660: 00000013 nop +80003664: 00000013 nop +80003668: 00000013 nop +8000366c: 00000013 nop +80003670: 00000013 nop +80003674: 00000013 nop +80003678: 00000013 nop +8000367c: 00000013 nop +80003680: 00000013 nop +80003684: 00000013 nop +80003688: 00000013 nop +8000368c: 00000013 nop +80003690: 00000013 nop +80003694: 00000013 nop +80003698: 00000013 nop +8000369c: 00000013 nop +800036a0: 00000013 nop +800036a4: 00000013 nop +800036a8: 00000013 nop +800036ac: 00000013 nop +800036b0: 00000013 nop +800036b4: 00000013 nop +800036b8: 00000013 nop +800036bc: 00000013 nop +800036c0: 00000013 nop +800036c4: 00000013 nop +800036c8: 00000013 nop +800036cc: 00000013 nop +800036d0: 00000013 nop +800036d4: 00000013 nop +800036d8: 00000013 nop +800036dc: 00000013 nop +800036e0: 00000013 nop +800036e4: 00000013 nop +800036e8: 00000013 nop +800036ec: 00000013 nop +800036f0: 00000013 nop +800036f4: 00000013 nop +800036f8: 00000013 nop +800036fc: 00000013 nop +80003700: 00000013 nop +80003704: 00000013 nop +80003708: 00000013 nop +8000370c: 00000013 nop +80003710: 00000013 nop +80003714: 00000013 nop +80003718: 00000013 nop +8000371c: 00000013 nop +80003720: 00000013 nop +80003724: 00000013 nop +80003728: 00000013 nop +8000372c: 00000013 nop +80003730: 00000013 nop +80003734: 00000013 nop +80003738: 00000013 nop +8000373c: 00000013 nop +80003740: 00000013 nop +80003744: 00000013 nop +80003748: 00000013 nop +8000374c: 00000013 nop +80003750: 00000013 nop +80003754: 00000013 nop +80003758: 00000013 nop +8000375c: 00000013 nop +80003760: 00000013 nop +80003764: 00000013 nop +80003768: 00000013 nop +8000376c: 00000013 nop +80003770: 00000013 nop +80003774: 00000013 nop +80003778: 00000013 nop +8000377c: 00000013 nop +80003780: 00000013 nop +80003784: 00000013 nop +80003788: 00000013 nop +8000378c: 00000013 nop +80003790: 00000013 nop +80003794: 00000013 nop +80003798: 00000013 nop +8000379c: 00000013 nop +800037a0: 00000013 nop +800037a4: 00000013 nop +800037a8: 00000013 nop +800037ac: 00000013 nop +800037b0: 00000013 nop +800037b4: 00000013 nop +800037b8: 00000013 nop +800037bc: 00000013 nop +800037c0: 00000013 nop +800037c4: 00000013 nop +800037c8: 00000013 nop +800037cc: 00000013 nop +800037d0: 00000013 nop +800037d4: 00000013 nop +800037d8: 00000013 nop +800037dc: 00000013 nop +800037e0: 00000013 nop +800037e4: 00000013 nop +800037e8: 00000013 nop +800037ec: 00000013 nop +800037f0: 00000013 nop +800037f4: 00000013 nop +800037f8: 00000013 nop +800037fc: 00000013 nop +80003800: 00000013 nop +80003804: 00000013 nop +80003808: 00000013 nop +8000380c: 00000013 nop +80003810: 00000013 nop +80003814: 00000013 nop +80003818: 00000013 nop +8000381c: 00000013 nop +80003820: 00000013 nop +80003824: 00000013 nop +80003828: 00000013 nop +8000382c: 00000013 nop +80003830: 00000013 nop +80003834: 00000013 nop +80003838: 00000013 nop +8000383c: 00000013 nop +80003840: 00000013 nop +80003844: 00000013 nop +80003848: 00000013 nop +8000384c: 00000013 nop +80003850: 00000013 nop +80003854: 00000013 nop +80003858: 00000013 nop +8000385c: 00000013 nop +80003860: 00000013 nop +80003864: 00000013 nop +80003868: 00000013 nop +8000386c: 00000013 nop +80003870: 00000013 nop +80003874: 00000013 nop +80003878: 00000013 nop +8000387c: 00000013 nop +80003880: 00000013 nop +80003884: 00000013 nop +80003888: 00000013 nop +8000388c: 00000013 nop +80003890: 00000013 nop +80003894: 00000013 nop +80003898: 00000013 nop +8000389c: 00000013 nop +800038a0: 00000013 nop +800038a4: 00000013 nop +800038a8: 00000013 nop +800038ac: 00000013 nop +800038b0: 00000013 nop +800038b4: 00000013 nop +800038b8: 00000013 nop +800038bc: 00000013 nop +800038c0: 00000013 nop +800038c4: 00000013 nop +800038c8: 00000013 nop +800038cc: 00000013 nop +800038d0: 00000013 nop +800038d4: 00000013 nop +800038d8: 00000013 nop +800038dc: 00000013 nop +800038e0: 00000013 nop +800038e4: 00000013 nop +800038e8: 00000013 nop +800038ec: 00000013 nop +800038f0: 00000013 nop +800038f4: 00000013 nop +800038f8: 00000013 nop +800038fc: 00000013 nop +80003900: 00000013 nop +80003904: 00000013 nop +80003908: 00000013 nop +8000390c: 00000013 nop +80003910: 00000013 nop +80003914: 00000013 nop +80003918: 00000013 nop +8000391c: 00000013 nop +80003920: 00000013 nop +80003924: 00000013 nop +80003928: 00000013 nop +8000392c: 00000013 nop +80003930: 00000013 nop +80003934: 00000013 nop +80003938: 00000013 nop +8000393c: 00000013 nop +80003940: 00000013 nop +80003944: 00000013 nop +80003948: 00000013 nop +8000394c: 00000013 nop +80003950: 00000013 nop +80003954: 00000013 nop +80003958: 00000013 nop +8000395c: 00000013 nop +80003960: 00000013 nop +80003964: 00000013 nop +80003968: 00000013 nop +8000396c: 00000013 nop +80003970: 00000013 nop +80003974: 00000013 nop +80003978: 00000013 nop +8000397c: 00000013 nop +80003980: 00000013 nop +80003984: 00000013 nop +80003988: 00000013 nop +8000398c: 00000013 nop +80003990: 00000013 nop +80003994: 00000013 nop +80003998: 00000013 nop +8000399c: 00000013 nop +800039a0: 00000013 nop +800039a4: 00000013 nop +800039a8: 00000013 nop +800039ac: 00000013 nop +800039b0: 00000013 nop +800039b4: 00000013 nop +800039b8: 00000013 nop +800039bc: 00000013 nop +800039c0: 00000013 nop +800039c4: 00000013 nop +800039c8: 00000013 nop +800039cc: 00000013 nop +800039d0: 00000013 nop +800039d4: 00000013 nop +800039d8: 00000013 nop +800039dc: 00000013 nop +800039e0: 00000013 nop +800039e4: 00000013 nop +800039e8: 00000013 nop +800039ec: 00000013 nop +800039f0: 00000013 nop +800039f4: 00000013 nop +800039f8: 00000013 nop +800039fc: 00000013 nop +80003a00: 00000013 nop +80003a04: 00000013 nop +80003a08: 00000013 nop +80003a0c: 00000013 nop +80003a10: 00000013 nop +80003a14: 00000013 nop +80003a18: 00000013 nop +80003a1c: 00000013 nop +80003a20: 00000013 nop +80003a24: 00000013 nop +80003a28: 00000013 nop +80003a2c: 00000013 nop +80003a30: 00000013 nop +80003a34: 00000013 nop +80003a38: 00000013 nop +80003a3c: 00000013 nop +80003a40: 00000013 nop +80003a44: 00000013 nop +80003a48: 00000013 nop +80003a4c: 00000013 nop +80003a50: 00000013 nop +80003a54: 00000013 nop +80003a58: 00000013 nop +80003a5c: 00000013 nop +80003a60: 00000013 nop +80003a64: 00000013 nop +80003a68: 00000013 nop +80003a6c: 00000013 nop +80003a70: 00000013 nop +80003a74: 00000013 nop +80003a78: 00000013 nop +80003a7c: 00000013 nop +80003a80: 00000013 nop +80003a84: 00000013 nop +80003a88: 00000013 nop +80003a8c: 00000013 nop +80003a90: 00000013 nop +80003a94: 00000013 nop +80003a98: 00000013 nop +80003a9c: 00000013 nop +80003aa0: 00000013 nop +80003aa4: 00000013 nop +80003aa8: 00000013 nop +80003aac: 00000013 nop +80003ab0: 00000013 nop +80003ab4: 00000013 nop +80003ab8: 00000013 nop +80003abc: 00000013 nop +80003ac0: 00000013 nop +80003ac4: 00000013 nop +80003ac8: 00000013 nop +80003acc: 00000013 nop +80003ad0: 00000013 nop +80003ad4: 00000013 nop +80003ad8: 00000013 nop +80003adc: 00000013 nop +80003ae0: 00000013 nop +80003ae4: 00000013 nop +80003ae8: 00000013 nop +80003aec: 00000013 nop +80003af0: 00000013 nop +80003af4: 00000013 nop +80003af8: 00000013 nop +80003afc: 00000013 nop +80003b00: 00000013 nop +80003b04: 00000013 nop +80003b08: 00000013 nop +80003b0c: 00000013 nop +80003b10: 00000013 nop +80003b14: 00000013 nop +80003b18: 00000013 nop +80003b1c: 00000013 nop +80003b20: 00000013 nop +80003b24: 00000013 nop +80003b28: 00000013 nop +80003b2c: 00000013 nop +80003b30: 00000013 nop +80003b34: 00000013 nop +80003b38: 00000013 nop +80003b3c: 00000013 nop +80003b40: 00000013 nop +80003b44: 00000013 nop +80003b48: 00000013 nop +80003b4c: 00000013 nop +80003b50: 00000013 nop +80003b54: 00000013 nop +80003b58: 00000013 nop +80003b5c: 00000013 nop +80003b60: 00000013 nop +80003b64: 00000013 nop +80003b68: 00000013 nop +80003b6c: 00000013 nop +80003b70: 00000013 nop +80003b74: 00000013 nop +80003b78: 00000013 nop +80003b7c: 00000013 nop +80003b80: 00000013 nop +80003b84: 00000013 nop +80003b88: 00000013 nop +80003b8c: 00000013 nop +80003b90: 00000013 nop +80003b94: 00000013 nop +80003b98: 00000013 nop +80003b9c: 00000013 nop +80003ba0: 00000013 nop +80003ba4: 00000013 nop +80003ba8: 00000013 nop +80003bac: 00000013 nop +80003bb0: 00000013 nop +80003bb4: 00000013 nop +80003bb8: 00000013 nop +80003bbc: 00000013 nop +80003bc0: 00000013 nop +80003bc4: 00000013 nop +80003bc8: 00000013 nop +80003bcc: 00000013 nop +80003bd0: 00000013 nop +80003bd4: 00000013 nop +80003bd8: 00000013 nop +80003bdc: 00000013 nop +80003be0: 00000013 nop +80003be4: 00000013 nop +80003be8: 00000013 nop +80003bec: 00000013 nop +80003bf0: 00000013 nop +80003bf4: 00000013 nop +80003bf8: 00000013 nop +80003bfc: 00000013 nop +80003c00: 00000013 nop +80003c04: 00000013 nop +80003c08: 00000013 nop +80003c0c: 00000013 nop +80003c10: 00000013 nop +80003c14: 00000013 nop +80003c18: 00000013 nop +80003c1c: 00000013 nop +80003c20: 00000013 nop +80003c24: 00000013 nop +80003c28: 00000013 nop +80003c2c: 00000013 nop +80003c30: 00000013 nop +80003c34: 00000013 nop +80003c38: 00000013 nop +80003c3c: 00000013 nop +80003c40: 00000013 nop +80003c44: 00000013 nop +80003c48: 00000013 nop +80003c4c: 00000013 nop +80003c50: 00000013 nop +80003c54: 00000013 nop +80003c58: 00000013 nop +80003c5c: 00000013 nop +80003c60: 00000013 nop +80003c64: 00000013 nop +80003c68: 00000013 nop +80003c6c: 00000013 nop +80003c70: 00000013 nop +80003c74: 00000013 nop +80003c78: 00000013 nop +80003c7c: 00000013 nop +80003c80: 00000013 nop +80003c84: 00000013 nop +80003c88: 00000013 nop +80003c8c: 00000013 nop +80003c90: 00000013 nop +80003c94: 00000013 nop +80003c98: 00000013 nop +80003c9c: 00000013 nop +80003ca0: 00000013 nop +80003ca4: 00000013 nop +80003ca8: 00000013 nop +80003cac: 00000013 nop +80003cb0: 00000013 nop +80003cb4: 00000013 nop +80003cb8: 00000013 nop +80003cbc: 00000013 nop +80003cc0: 00000013 nop +80003cc4: 00000013 nop +80003cc8: 00000013 nop +80003ccc: 00000013 nop +80003cd0: 00000013 nop +80003cd4: 00000013 nop +80003cd8: 00000013 nop +80003cdc: 00000013 nop +80003ce0: 00000013 nop +80003ce4: 00000013 nop +80003ce8: 00000013 nop +80003cec: 00000013 nop +80003cf0: 00000013 nop +80003cf4: 00000013 nop +80003cf8: 00000013 nop +80003cfc: 00000013 nop +80003d00: 00000013 nop +80003d04: 00000013 nop +80003d08: 00000013 nop +80003d0c: 00000013 nop +80003d10: 00000013 nop +80003d14: 00000013 nop +80003d18: 00000013 nop +80003d1c: 00000013 nop +80003d20: 00000013 nop +80003d24: 00000013 nop +80003d28: 00000013 nop +80003d2c: 00000013 nop +80003d30: 00000013 nop +80003d34: 00000013 nop +80003d38: 00000013 nop +80003d3c: 00000013 nop +80003d40: 00000013 nop +80003d44: 00000013 nop +80003d48: 00000013 nop +80003d4c: 00000013 nop +80003d50: 00000013 nop +80003d54: 00000013 nop +80003d58: 00000013 nop +80003d5c: 00000013 nop +80003d60: 00000013 nop +80003d64: 00000013 nop +80003d68: 00000013 nop +80003d6c: 00000013 nop +80003d70: 00000013 nop +80003d74: 00000013 nop +80003d78: 00000013 nop +80003d7c: 00000013 nop +80003d80: 00000013 nop +80003d84: 00000013 nop +80003d88: 00000013 nop +80003d8c: 00000013 nop +80003d90: 00000013 nop +80003d94: 00000013 nop +80003d98: 00000013 nop +80003d9c: 00000013 nop +80003da0: 00000013 nop +80003da4: 00000013 nop +80003da8: 00000013 nop +80003dac: 00000013 nop +80003db0: 00000013 nop +80003db4: 00000013 nop +80003db8: 00000013 nop +80003dbc: 00000013 nop +80003dc0: 00000013 nop +80003dc4: 00000013 nop +80003dc8: 00000013 nop +80003dcc: 00000013 nop +80003dd0: 00000013 nop +80003dd4: 00000013 nop +80003dd8: 00000013 nop +80003ddc: 00000013 nop +80003de0: 00000013 nop +80003de4: 00000013 nop +80003de8: 00000013 nop +80003dec: 00000013 nop +80003df0: 00000013 nop +80003df4: 00000013 nop +80003df8: 00000013 nop +80003dfc: 00000013 nop +80003e00: 00000013 nop +80003e04: 00000013 nop +80003e08: 00000013 nop +80003e0c: 00000013 nop +80003e10: 00000013 nop +80003e14: 00000013 nop +80003e18: 00000013 nop +80003e1c: 00000013 nop +80003e20: 00000013 nop +80003e24: 00000013 nop +80003e28: 00000013 nop +80003e2c: 00000013 nop +80003e30: 00000013 nop +80003e34: 00000013 nop +80003e38: 00000013 nop +80003e3c: 00000013 nop +80003e40: 00000013 nop +80003e44: 00000013 nop +80003e48: 00000013 nop +80003e4c: 00000013 nop +80003e50: 00000013 nop +80003e54: 00000013 nop +80003e58: 00000013 nop +80003e5c: 00000013 nop +80003e60: 00000013 nop +80003e64: 00000013 nop +80003e68: 00000013 nop +80003e6c: 00000013 nop +80003e70: 00000013 nop +80003e74: 00000013 nop +80003e78: 00000013 nop +80003e7c: 00000013 nop +80003e80: 00000013 nop +80003e84: 00000013 nop +80003e88: 00000013 nop +80003e8c: 00000013 nop +80003e90: 00000013 nop +80003e94: 00000013 nop +80003e98: 00000013 nop +80003e9c: 00000013 nop +80003ea0: 00000013 nop +80003ea4: 00000013 nop +80003ea8: 00000013 nop +80003eac: 00000013 nop +80003eb0: 00000013 nop +80003eb4: 00000013 nop +80003eb8: 00000013 nop +80003ebc: 00000013 nop +80003ec0: 00000013 nop +80003ec4: 00000013 nop +80003ec8: 00000013 nop +80003ecc: 00000013 nop +80003ed0: 00000013 nop +80003ed4: 00000013 nop +80003ed8: 00000013 nop +80003edc: 00000013 nop +80003ee0: 00000013 nop +80003ee4: 00000013 nop +80003ee8: 00000013 nop +80003eec: 00000013 nop +80003ef0: 00000013 nop +80003ef4: 00000013 nop +80003ef8: 00000013 nop +80003efc: 00000013 nop +80003f00: 00000013 nop +80003f04: 00000013 nop +80003f08: 00000013 nop +80003f0c: 00000013 nop +80003f10: 00000013 nop +80003f14: 00000013 nop +80003f18: 00000013 nop +80003f1c: 00000013 nop +80003f20: 00000013 nop +80003f24: 00000013 nop +80003f28: 00000013 nop +80003f2c: 00000013 nop +80003f30: 00000013 nop +80003f34: 00000013 nop +80003f38: 00000013 nop +80003f3c: 00000013 nop +80003f40: 00000013 nop +80003f44: 00000013 nop +80003f48: 00000013 nop +80003f4c: 00000013 nop +80003f50: 00000013 nop +80003f54: 00000013 nop +80003f58: 00000013 nop +80003f5c: 00000013 nop +80003f60: 00000013 nop +80003f64: 00000013 nop +80003f68: 00000013 nop +80003f6c: 00000013 nop +80003f70: 00000013 nop +80003f74: 00000013 nop +80003f78: 00000013 nop +80003f7c: 00000013 nop +80003f80: 00000013 nop +80003f84: 00000013 nop +80003f88: 00000013 nop +80003f8c: 00000013 nop +80003f90: 00000013 nop +80003f94: 00000013 nop +80003f98: 00000013 nop +80003f9c: 00000013 nop +80003fa0: 00000013 nop +80003fa4: 00000013 nop +80003fa8: 00000013 nop +80003fac: 00000013 nop +80003fb0: 00000013 nop +80003fb4: 00000013 nop +80003fb8: 00000013 nop +80003fbc: 00000013 nop +80003fc0: 00000013 nop +80003fc4: 00000013 nop +80003fc8: 00000013 nop +80003fcc: 00000013 nop +80003fd0: 00000013 nop +80003fd4: 00000013 nop +80003fd8: 00000013 nop +80003fdc: 00000013 nop +80003fe0: 00000013 nop +80003fe4: 00000013 nop +80003fe8: 00000013 nop +80003fec: 00000013 nop +80003ff0: 00000013 nop +80003ff4: 00000013 nop +80003ff8: 00000013 nop +80003ffc: 00000013 nop + +80004000 : +80004000: 0000 unimp +80004002: 0000 unimp +80004004: 00000013 nop +80004008: 00000013 nop +8000400c: 00000013 nop +80004010: 00000013 nop +80004014: 00000013 nop +80004018: 00000013 nop +8000401c: 00000013 nop +80004020: 00000013 nop +80004024: 00000013 nop +80004028: 00000013 nop +8000402c: 00000013 nop +80004030: 00000013 nop +80004034: 00000013 nop +80004038: 00000013 nop +8000403c: 00000013 nop +80004040: 00000013 nop +80004044: 00000013 nop +80004048: 00000013 nop +8000404c: 00000013 nop +80004050: 00000013 nop +80004054: 00000013 nop +80004058: 00000013 nop +8000405c: 00000013 nop +80004060: 00000013 nop +80004064: 00000013 nop +80004068: 00000013 nop +8000406c: 00000013 nop +80004070: 00000013 nop +80004074: 00000013 nop +80004078: 00000013 nop +8000407c: 00000013 nop +80004080: 00000013 nop +80004084: 00000013 nop +80004088: 00000013 nop +8000408c: 00000013 nop +80004090: 00000013 nop +80004094: 00000013 nop +80004098: 00000013 nop +8000409c: 00000013 nop +800040a0: 00000013 nop +800040a4: 00000013 nop +800040a8: 00000013 nop +800040ac: 00000013 nop +800040b0: 00000013 nop +800040b4: 00000013 nop +800040b8: 00000013 nop +800040bc: 00000013 nop +800040c0: 00000013 nop +800040c4: 00000013 nop +800040c8: 00000013 nop +800040cc: 00000013 nop +800040d0: 00000013 nop +800040d4: 00000013 nop +800040d8: 00000013 nop +800040dc: 00000013 nop +800040e0: 00000013 nop +800040e4: 00000013 nop +800040e8: 00000013 nop +800040ec: 00000013 nop +800040f0: 00000013 nop +800040f4: 00000013 nop +800040f8: 00000013 nop +800040fc: 00000013 nop +80004100: 00000013 nop +80004104: 00000013 nop +80004108: 00000013 nop +8000410c: 00000013 nop +80004110: 00000013 nop +80004114: 00000013 nop +80004118: 00000013 nop +8000411c: 00000013 nop +80004120: 00000013 nop +80004124: 00000013 nop +80004128: 00000013 nop +8000412c: 00000013 nop +80004130: 00000013 nop +80004134: 00000013 nop +80004138: 00000013 nop +8000413c: 00000013 nop +80004140: 00000013 nop +80004144: 00000013 nop +80004148: 00000013 nop +8000414c: 00000013 nop +80004150: 00000013 nop +80004154: 00000013 nop +80004158: 00000013 nop +8000415c: 00000013 nop +80004160: 00000013 nop +80004164: 00000013 nop +80004168: 00000013 nop +8000416c: 00000013 nop +80004170: 00000013 nop +80004174: 00000013 nop +80004178: 00000013 nop +8000417c: 00000013 nop +80004180: 00000013 nop +80004184: 00000013 nop +80004188: 00000013 nop +8000418c: 00000013 nop +80004190: 00000013 nop +80004194: 00000013 nop +80004198: 00000013 nop +8000419c: 00000013 nop +800041a0: 00000013 nop +800041a4: 00000013 nop +800041a8: 00000013 nop +800041ac: 00000013 nop +800041b0: 00000013 nop +800041b4: 00000013 nop +800041b8: 00000013 nop +800041bc: 00000013 nop +800041c0: 00000013 nop +800041c4: 00000013 nop +800041c8: 00000013 nop +800041cc: 00000013 nop +800041d0: 00000013 nop +800041d4: 00000013 nop +800041d8: 00000013 nop +800041dc: 00000013 nop +800041e0: 00000013 nop +800041e4: 00000013 nop +800041e8: 00000013 nop +800041ec: 00000013 nop +800041f0: 00000013 nop +800041f4: 00000013 nop +800041f8: 00000013 nop +800041fc: 00000013 nop +80004200: 00000013 nop +80004204: 00000013 nop +80004208: 00000013 nop +8000420c: 00000013 nop +80004210: 00000013 nop +80004214: 00000013 nop +80004218: 00000013 nop +8000421c: 00000013 nop +80004220: 00000013 nop +80004224: 00000013 nop +80004228: 00000013 nop +8000422c: 00000013 nop +80004230: 00000013 nop +80004234: 00000013 nop +80004238: 00000013 nop +8000423c: 00000013 nop +80004240: 00000013 nop +80004244: 00000013 nop +80004248: 00000013 nop +8000424c: 00000013 nop +80004250: 00000013 nop +80004254: 00000013 nop +80004258: 00000013 nop +8000425c: 00000013 nop +80004260: 00000013 nop +80004264: 00000013 nop +80004268: 00000013 nop +8000426c: 00000013 nop +80004270: 00000013 nop +80004274: 00000013 nop +80004278: 00000013 nop +8000427c: 00000013 nop +80004280: 00000013 nop +80004284: 00000013 nop +80004288: 00000013 nop +8000428c: 00000013 nop +80004290: 00000013 nop +80004294: 00000013 nop +80004298: 00000013 nop +8000429c: 00000013 nop +800042a0: 00000013 nop +800042a4: 00000013 nop +800042a8: 00000013 nop +800042ac: 00000013 nop +800042b0: 00000013 nop +800042b4: 00000013 nop +800042b8: 00000013 nop +800042bc: 00000013 nop +800042c0: 00000013 nop +800042c4: 00000013 nop +800042c8: 00000013 nop +800042cc: 00000013 nop +800042d0: 00000013 nop +800042d4: 00000013 nop +800042d8: 00000013 nop +800042dc: 00000013 nop +800042e0: 00000013 nop +800042e4: 00000013 nop +800042e8: 00000013 nop +800042ec: 00000013 nop +800042f0: 00000013 nop +800042f4: 00000013 nop +800042f8: 00000013 nop +800042fc: 00000013 nop +80004300: 00000013 nop +80004304: 00000013 nop +80004308: 00000013 nop +8000430c: 00000013 nop +80004310: 00000013 nop +80004314: 00000013 nop +80004318: 00000013 nop +8000431c: 00000013 nop +80004320: 00000013 nop +80004324: 00000013 nop +80004328: 00000013 nop +8000432c: 00000013 nop +80004330: 00000013 nop +80004334: 00000013 nop +80004338: 00000013 nop +8000433c: 00000013 nop +80004340: 00000013 nop +80004344: 00000013 nop +80004348: 00000013 nop +8000434c: 00000013 nop +80004350: 00000013 nop +80004354: 00000013 nop +80004358: 00000013 nop +8000435c: 00000013 nop +80004360: 00000013 nop +80004364: 00000013 nop +80004368: 00000013 nop +8000436c: 00000013 nop +80004370: 00000013 nop +80004374: 00000013 nop +80004378: 00000013 nop +8000437c: 00000013 nop +80004380: 00000013 nop +80004384: 00000013 nop +80004388: 00000013 nop +8000438c: 00000013 nop +80004390: 00000013 nop +80004394: 00000013 nop +80004398: 00000013 nop +8000439c: 00000013 nop +800043a0: 00000013 nop +800043a4: 00000013 nop +800043a8: 00000013 nop +800043ac: 00000013 nop +800043b0: 00000013 nop +800043b4: 00000013 nop +800043b8: 00000013 nop +800043bc: 00000013 nop +800043c0: 00000013 nop +800043c4: 00000013 nop +800043c8: 00000013 nop +800043cc: 00000013 nop +800043d0: 00000013 nop +800043d4: 00000013 nop +800043d8: 00000013 nop +800043dc: 00000013 nop +800043e0: 00000013 nop +800043e4: 00000013 nop +800043e8: 00000013 nop +800043ec: 00000013 nop +800043f0: 00000013 nop +800043f4: 00000013 nop +800043f8: 00000013 nop +800043fc: 00000013 nop +80004400: 00000013 nop +80004404: 00000013 nop +80004408: 00000013 nop +8000440c: 00000013 nop +80004410: 00000013 nop +80004414: 00000013 nop +80004418: 00000013 nop +8000441c: 00000013 nop +80004420: 00000013 nop +80004424: 00000013 nop +80004428: 00000013 nop +8000442c: 00000013 nop +80004430: 00000013 nop +80004434: 00000013 nop +80004438: 00000013 nop +8000443c: 00000013 nop +80004440: 00000013 nop +80004444: 00000013 nop +80004448: 00000013 nop +8000444c: 00000013 nop +80004450: 00000013 nop +80004454: 00000013 nop +80004458: 00000013 nop +8000445c: 00000013 nop +80004460: 00000013 nop +80004464: 00000013 nop +80004468: 00000013 nop +8000446c: 00000013 nop +80004470: 00000013 nop +80004474: 00000013 nop +80004478: 00000013 nop +8000447c: 00000013 nop +80004480: 00000013 nop +80004484: 00000013 nop +80004488: 00000013 nop +8000448c: 00000013 nop +80004490: 00000013 nop +80004494: 00000013 nop +80004498: 00000013 nop +8000449c: 00000013 nop +800044a0: 00000013 nop +800044a4: 00000013 nop +800044a8: 00000013 nop +800044ac: 00000013 nop +800044b0: 00000013 nop +800044b4: 00000013 nop +800044b8: 00000013 nop +800044bc: 00000013 nop +800044c0: 00000013 nop +800044c4: 00000013 nop +800044c8: 00000013 nop +800044cc: 00000013 nop +800044d0: 00000013 nop +800044d4: 00000013 nop +800044d8: 00000013 nop +800044dc: 00000013 nop +800044e0: 00000013 nop +800044e4: 00000013 nop +800044e8: 00000013 nop +800044ec: 00000013 nop +800044f0: 00000013 nop +800044f4: 00000013 nop +800044f8: 00000013 nop +800044fc: 00000013 nop +80004500: 00000013 nop +80004504: 00000013 nop +80004508: 00000013 nop +8000450c: 00000013 nop +80004510: 00000013 nop +80004514: 00000013 nop +80004518: 00000013 nop +8000451c: 00000013 nop +80004520: 00000013 nop +80004524: 00000013 nop +80004528: 00000013 nop +8000452c: 00000013 nop +80004530: 00000013 nop +80004534: 00000013 nop +80004538: 00000013 nop +8000453c: 00000013 nop +80004540: 00000013 nop +80004544: 00000013 nop +80004548: 00000013 nop +8000454c: 00000013 nop +80004550: 00000013 nop +80004554: 00000013 nop +80004558: 00000013 nop +8000455c: 00000013 nop +80004560: 00000013 nop +80004564: 00000013 nop +80004568: 00000013 nop +8000456c: 00000013 nop +80004570: 00000013 nop +80004574: 00000013 nop +80004578: 00000013 nop +8000457c: 00000013 nop +80004580: 00000013 nop +80004584: 00000013 nop +80004588: 00000013 nop +8000458c: 00000013 nop +80004590: 00000013 nop +80004594: 00000013 nop +80004598: 00000013 nop +8000459c: 00000013 nop +800045a0: 00000013 nop +800045a4: 00000013 nop +800045a8: 00000013 nop +800045ac: 00000013 nop +800045b0: 00000013 nop +800045b4: 00000013 nop +800045b8: 00000013 nop +800045bc: 00000013 nop +800045c0: 00000013 nop +800045c4: 00000013 nop +800045c8: 00000013 nop +800045cc: 00000013 nop +800045d0: 00000013 nop +800045d4: 00000013 nop +800045d8: 00000013 nop +800045dc: 00000013 nop +800045e0: 00000013 nop +800045e4: 00000013 nop +800045e8: 00000013 nop +800045ec: 00000013 nop +800045f0: 00000013 nop +800045f4: 00000013 nop +800045f8: 00000013 nop +800045fc: 00000013 nop +80004600: 00000013 nop +80004604: 00000013 nop +80004608: 00000013 nop +8000460c: 00000013 nop +80004610: 00000013 nop +80004614: 00000013 nop +80004618: 00000013 nop +8000461c: 00000013 nop +80004620: 00000013 nop +80004624: 00000013 nop +80004628: 00000013 nop +8000462c: 00000013 nop +80004630: 00000013 nop +80004634: 00000013 nop +80004638: 00000013 nop +8000463c: 00000013 nop +80004640: 00000013 nop +80004644: 00000013 nop +80004648: 00000013 nop +8000464c: 00000013 nop +80004650: 00000013 nop +80004654: 00000013 nop +80004658: 00000013 nop +8000465c: 00000013 nop +80004660: 00000013 nop +80004664: 00000013 nop +80004668: 00000013 nop +8000466c: 00000013 nop +80004670: 00000013 nop +80004674: 00000013 nop +80004678: 00000013 nop +8000467c: 00000013 nop +80004680: 00000013 nop +80004684: 00000013 nop +80004688: 00000013 nop +8000468c: 00000013 nop +80004690: 00000013 nop +80004694: 00000013 nop +80004698: 00000013 nop +8000469c: 00000013 nop +800046a0: 00000013 nop +800046a4: 00000013 nop +800046a8: 00000013 nop +800046ac: 00000013 nop +800046b0: 00000013 nop +800046b4: 00000013 nop +800046b8: 00000013 nop +800046bc: 00000013 nop +800046c0: 00000013 nop +800046c4: 00000013 nop +800046c8: 00000013 nop +800046cc: 00000013 nop +800046d0: 00000013 nop +800046d4: 00000013 nop +800046d8: 00000013 nop +800046dc: 00000013 nop +800046e0: 00000013 nop +800046e4: 00000013 nop +800046e8: 00000013 nop +800046ec: 00000013 nop +800046f0: 00000013 nop +800046f4: 00000013 nop +800046f8: 00000013 nop +800046fc: 00000013 nop +80004700: 00000013 nop +80004704: 00000013 nop +80004708: 00000013 nop +8000470c: 00000013 nop +80004710: 00000013 nop +80004714: 00000013 nop +80004718: 00000013 nop +8000471c: 00000013 nop +80004720: 00000013 nop +80004724: 00000013 nop +80004728: 00000013 nop +8000472c: 00000013 nop +80004730: 00000013 nop +80004734: 00000013 nop +80004738: 00000013 nop +8000473c: 00000013 nop +80004740: 00000013 nop +80004744: 00000013 nop +80004748: 00000013 nop +8000474c: 00000013 nop +80004750: 00000013 nop +80004754: 00000013 nop +80004758: 00000013 nop +8000475c: 00000013 nop +80004760: 00000013 nop +80004764: 00000013 nop +80004768: 00000013 nop +8000476c: 00000013 nop +80004770: 00000013 nop +80004774: 00000013 nop +80004778: 00000013 nop +8000477c: 00000013 nop +80004780: 00000013 nop +80004784: 00000013 nop +80004788: 00000013 nop +8000478c: 00000013 nop +80004790: 00000013 nop +80004794: 00000013 nop +80004798: 00000013 nop +8000479c: 00000013 nop +800047a0: 00000013 nop +800047a4: 00000013 nop +800047a8: 00000013 nop +800047ac: 00000013 nop +800047b0: 00000013 nop +800047b4: 00000013 nop +800047b8: 00000013 nop +800047bc: 00000013 nop +800047c0: 00000013 nop +800047c4: 00000013 nop +800047c8: 00000013 nop +800047cc: 00000013 nop +800047d0: 00000013 nop +800047d4: 00000013 nop +800047d8: 00000013 nop +800047dc: 00000013 nop +800047e0: 00000013 nop +800047e4: 00000013 nop +800047e8: 00000013 nop +800047ec: 00000013 nop +800047f0: 00000013 nop +800047f4: 00000013 nop +800047f8: 00000013 nop +800047fc: 00000013 nop +80004800: 00000013 nop +80004804: 00000013 nop +80004808: 00000013 nop +8000480c: 00000013 nop +80004810: 00000013 nop +80004814: 00000013 nop +80004818: 00000013 nop +8000481c: 00000013 nop +80004820: 00000013 nop +80004824: 00000013 nop +80004828: 00000013 nop +8000482c: 00000013 nop +80004830: 00000013 nop +80004834: 00000013 nop +80004838: 00000013 nop +8000483c: 00000013 nop +80004840: 00000013 nop +80004844: 00000013 nop +80004848: 00000013 nop +8000484c: 00000013 nop +80004850: 00000013 nop +80004854: 00000013 nop +80004858: 00000013 nop +8000485c: 00000013 nop +80004860: 00000013 nop +80004864: 00000013 nop +80004868: 00000013 nop +8000486c: 00000013 nop +80004870: 00000013 nop +80004874: 00000013 nop +80004878: 00000013 nop +8000487c: 00000013 nop +80004880: 00000013 nop +80004884: 00000013 nop +80004888: 00000013 nop +8000488c: 00000013 nop +80004890: 00000013 nop +80004894: 00000013 nop +80004898: 00000013 nop +8000489c: 00000013 nop +800048a0: 00000013 nop +800048a4: 00000013 nop +800048a8: 00000013 nop +800048ac: 00000013 nop +800048b0: 00000013 nop +800048b4: 00000013 nop +800048b8: 00000013 nop +800048bc: 00000013 nop +800048c0: 00000013 nop +800048c4: 00000013 nop +800048c8: 00000013 nop +800048cc: 00000013 nop +800048d0: 00000013 nop +800048d4: 00000013 nop +800048d8: 00000013 nop +800048dc: 00000013 nop +800048e0: 00000013 nop +800048e4: 00000013 nop +800048e8: 00000013 nop +800048ec: 00000013 nop +800048f0: 00000013 nop +800048f4: 00000013 nop +800048f8: 00000013 nop +800048fc: 00000013 nop +80004900: 00000013 nop +80004904: 00000013 nop +80004908: 00000013 nop +8000490c: 00000013 nop +80004910: 00000013 nop +80004914: 00000013 nop +80004918: 00000013 nop +8000491c: 00000013 nop +80004920: 00000013 nop +80004924: 00000013 nop +80004928: 00000013 nop +8000492c: 00000013 nop +80004930: 00000013 nop +80004934: 00000013 nop +80004938: 00000013 nop +8000493c: 00000013 nop +80004940: 00000013 nop +80004944: 00000013 nop +80004948: 00000013 nop +8000494c: 00000013 nop +80004950: 00000013 nop +80004954: 00000013 nop +80004958: 00000013 nop +8000495c: 00000013 nop +80004960: 00000013 nop +80004964: 00000013 nop +80004968: 00000013 nop +8000496c: 00000013 nop +80004970: 00000013 nop +80004974: 00000013 nop +80004978: 00000013 nop +8000497c: 00000013 nop +80004980: 00000013 nop +80004984: 00000013 nop +80004988: 00000013 nop +8000498c: 00000013 nop +80004990: 00000013 nop +80004994: 00000013 nop +80004998: 00000013 nop +8000499c: 00000013 nop +800049a0: 00000013 nop +800049a4: 00000013 nop +800049a8: 00000013 nop +800049ac: 00000013 nop +800049b0: 00000013 nop +800049b4: 00000013 nop +800049b8: 00000013 nop +800049bc: 00000013 nop +800049c0: 00000013 nop +800049c4: 00000013 nop +800049c8: 00000013 nop +800049cc: 00000013 nop +800049d0: 00000013 nop +800049d4: 00000013 nop +800049d8: 00000013 nop +800049dc: 00000013 nop +800049e0: 00000013 nop +800049e4: 00000013 nop +800049e8: 00000013 nop +800049ec: 00000013 nop +800049f0: 00000013 nop +800049f4: 00000013 nop +800049f8: 00000013 nop +800049fc: 00000013 nop +80004a00: 00000013 nop +80004a04: 00000013 nop +80004a08: 00000013 nop +80004a0c: 00000013 nop +80004a10: 00000013 nop +80004a14: 00000013 nop +80004a18: 00000013 nop +80004a1c: 00000013 nop +80004a20: 00000013 nop +80004a24: 00000013 nop +80004a28: 00000013 nop +80004a2c: 00000013 nop +80004a30: 00000013 nop +80004a34: 00000013 nop +80004a38: 00000013 nop +80004a3c: 00000013 nop +80004a40: 00000013 nop +80004a44: 00000013 nop +80004a48: 00000013 nop +80004a4c: 00000013 nop +80004a50: 00000013 nop +80004a54: 00000013 nop +80004a58: 00000013 nop +80004a5c: 00000013 nop +80004a60: 00000013 nop +80004a64: 00000013 nop +80004a68: 00000013 nop +80004a6c: 00000013 nop +80004a70: 00000013 nop +80004a74: 00000013 nop +80004a78: 00000013 nop +80004a7c: 00000013 nop +80004a80: 00000013 nop +80004a84: 00000013 nop +80004a88: 00000013 nop +80004a8c: 00000013 nop +80004a90: 00000013 nop +80004a94: 00000013 nop +80004a98: 00000013 nop +80004a9c: 00000013 nop +80004aa0: 00000013 nop +80004aa4: 00000013 nop +80004aa8: 00000013 nop +80004aac: 00000013 nop +80004ab0: 00000013 nop +80004ab4: 00000013 nop +80004ab8: 00000013 nop +80004abc: 00000013 nop +80004ac0: 00000013 nop +80004ac4: 00000013 nop +80004ac8: 00000013 nop +80004acc: 00000013 nop +80004ad0: 00000013 nop +80004ad4: 00000013 nop +80004ad8: 00000013 nop +80004adc: 00000013 nop +80004ae0: 00000013 nop +80004ae4: 00000013 nop +80004ae8: 00000013 nop +80004aec: 00000013 nop +80004af0: 00000013 nop +80004af4: 00000013 nop +80004af8: 00000013 nop +80004afc: 00000013 nop +80004b00: 00000013 nop +80004b04: 00000013 nop +80004b08: 00000013 nop +80004b0c: 00000013 nop +80004b10: 00000013 nop +80004b14: 00000013 nop +80004b18: 00000013 nop +80004b1c: 00000013 nop +80004b20: 00000013 nop +80004b24: 00000013 nop +80004b28: 00000013 nop +80004b2c: 00000013 nop +80004b30: 00000013 nop +80004b34: 00000013 nop +80004b38: 00000013 nop +80004b3c: 00000013 nop +80004b40: 00000013 nop +80004b44: 00000013 nop +80004b48: 00000013 nop +80004b4c: 00000013 nop +80004b50: 00000013 nop +80004b54: 00000013 nop +80004b58: 00000013 nop +80004b5c: 00000013 nop +80004b60: 00000013 nop +80004b64: 00000013 nop +80004b68: 00000013 nop +80004b6c: 00000013 nop +80004b70: 00000013 nop +80004b74: 00000013 nop +80004b78: 00000013 nop +80004b7c: 00000013 nop +80004b80: 00000013 nop +80004b84: 00000013 nop +80004b88: 00000013 nop +80004b8c: 00000013 nop +80004b90: 00000013 nop +80004b94: 00000013 nop +80004b98: 00000013 nop +80004b9c: 00000013 nop +80004ba0: 00000013 nop +80004ba4: 00000013 nop +80004ba8: 00000013 nop +80004bac: 00000013 nop +80004bb0: 00000013 nop +80004bb4: 00000013 nop +80004bb8: 00000013 nop +80004bbc: 00000013 nop +80004bc0: 00000013 nop +80004bc4: 00000013 nop +80004bc8: 00000013 nop +80004bcc: 00000013 nop +80004bd0: 00000013 nop +80004bd4: 00000013 nop +80004bd8: 00000013 nop +80004bdc: 00000013 nop +80004be0: 00000013 nop +80004be4: 00000013 nop +80004be8: 00000013 nop +80004bec: 00000013 nop +80004bf0: 00000013 nop +80004bf4: 00000013 nop +80004bf8: 00000013 nop +80004bfc: 00000013 nop +80004c00: 00000013 nop +80004c04: 00000013 nop +80004c08: 00000013 nop +80004c0c: 00000013 nop +80004c10: 00000013 nop +80004c14: 00000013 nop +80004c18: 00000013 nop +80004c1c: 00000013 nop +80004c20: 00000013 nop +80004c24: 00000013 nop +80004c28: 00000013 nop +80004c2c: 00000013 nop +80004c30: 00000013 nop +80004c34: 00000013 nop +80004c38: 00000013 nop +80004c3c: 00000013 nop +80004c40: 00000013 nop +80004c44: 00000013 nop +80004c48: 00000013 nop +80004c4c: 00000013 nop +80004c50: 00000013 nop +80004c54: 00000013 nop +80004c58: 00000013 nop +80004c5c: 00000013 nop +80004c60: 00000013 nop +80004c64: 00000013 nop +80004c68: 00000013 nop +80004c6c: 00000013 nop +80004c70: 00000013 nop +80004c74: 00000013 nop +80004c78: 00000013 nop +80004c7c: 00000013 nop +80004c80: 00000013 nop +80004c84: 00000013 nop +80004c88: 00000013 nop +80004c8c: 00000013 nop +80004c90: 00000013 nop +80004c94: 00000013 nop +80004c98: 00000013 nop +80004c9c: 00000013 nop +80004ca0: 00000013 nop +80004ca4: 00000013 nop +80004ca8: 00000013 nop +80004cac: 00000013 nop +80004cb0: 00000013 nop +80004cb4: 00000013 nop +80004cb8: 00000013 nop +80004cbc: 00000013 nop +80004cc0: 00000013 nop +80004cc4: 00000013 nop +80004cc8: 00000013 nop +80004ccc: 00000013 nop +80004cd0: 00000013 nop +80004cd4: 00000013 nop +80004cd8: 00000013 nop +80004cdc: 00000013 nop +80004ce0: 00000013 nop +80004ce4: 00000013 nop +80004ce8: 00000013 nop +80004cec: 00000013 nop +80004cf0: 00000013 nop +80004cf4: 00000013 nop +80004cf8: 00000013 nop +80004cfc: 00000013 nop +80004d00: 00000013 nop +80004d04: 00000013 nop +80004d08: 00000013 nop +80004d0c: 00000013 nop +80004d10: 00000013 nop +80004d14: 00000013 nop +80004d18: 00000013 nop +80004d1c: 00000013 nop +80004d20: 00000013 nop +80004d24: 00000013 nop +80004d28: 00000013 nop +80004d2c: 00000013 nop +80004d30: 00000013 nop +80004d34: 00000013 nop +80004d38: 00000013 nop +80004d3c: 00000013 nop +80004d40: 00000013 nop +80004d44: 00000013 nop +80004d48: 00000013 nop +80004d4c: 00000013 nop +80004d50: 00000013 nop +80004d54: 00000013 nop +80004d58: 00000013 nop +80004d5c: 00000013 nop +80004d60: 00000013 nop +80004d64: 00000013 nop +80004d68: 00000013 nop +80004d6c: 00000013 nop +80004d70: 00000013 nop +80004d74: 00000013 nop +80004d78: 00000013 nop +80004d7c: 00000013 nop +80004d80: 00000013 nop +80004d84: 00000013 nop +80004d88: 00000013 nop +80004d8c: 00000013 nop +80004d90: 00000013 nop +80004d94: 00000013 nop +80004d98: 00000013 nop +80004d9c: 00000013 nop +80004da0: 00000013 nop +80004da4: 00000013 nop +80004da8: 00000013 nop +80004dac: 00000013 nop +80004db0: 00000013 nop +80004db4: 00000013 nop +80004db8: 00000013 nop +80004dbc: 00000013 nop +80004dc0: 00000013 nop +80004dc4: 00000013 nop +80004dc8: 00000013 nop +80004dcc: 00000013 nop +80004dd0: 00000013 nop +80004dd4: 00000013 nop +80004dd8: 00000013 nop +80004ddc: 00000013 nop +80004de0: 00000013 nop +80004de4: 00000013 nop +80004de8: 00000013 nop +80004dec: 00000013 nop +80004df0: 00000013 nop +80004df4: 00000013 nop +80004df8: 00000013 nop +80004dfc: 00000013 nop +80004e00: 00000013 nop +80004e04: 00000013 nop +80004e08: 00000013 nop +80004e0c: 00000013 nop +80004e10: 00000013 nop +80004e14: 00000013 nop +80004e18: 00000013 nop +80004e1c: 00000013 nop +80004e20: 00000013 nop +80004e24: 00000013 nop +80004e28: 00000013 nop +80004e2c: 00000013 nop +80004e30: 00000013 nop +80004e34: 00000013 nop +80004e38: 00000013 nop +80004e3c: 00000013 nop +80004e40: 00000013 nop +80004e44: 00000013 nop +80004e48: 00000013 nop +80004e4c: 00000013 nop +80004e50: 00000013 nop +80004e54: 00000013 nop +80004e58: 00000013 nop +80004e5c: 00000013 nop +80004e60: 00000013 nop +80004e64: 00000013 nop +80004e68: 00000013 nop +80004e6c: 00000013 nop +80004e70: 00000013 nop +80004e74: 00000013 nop +80004e78: 00000013 nop +80004e7c: 00000013 nop +80004e80: 00000013 nop +80004e84: 00000013 nop +80004e88: 00000013 nop +80004e8c: 00000013 nop +80004e90: 00000013 nop +80004e94: 00000013 nop +80004e98: 00000013 nop +80004e9c: 00000013 nop +80004ea0: 00000013 nop +80004ea4: 00000013 nop +80004ea8: 00000013 nop +80004eac: 00000013 nop +80004eb0: 00000013 nop +80004eb4: 00000013 nop +80004eb8: 00000013 nop +80004ebc: 00000013 nop +80004ec0: 00000013 nop +80004ec4: 00000013 nop +80004ec8: 00000013 nop +80004ecc: 00000013 nop +80004ed0: 00000013 nop +80004ed4: 00000013 nop +80004ed8: 00000013 nop +80004edc: 00000013 nop +80004ee0: 00000013 nop +80004ee4: 00000013 nop +80004ee8: 00000013 nop +80004eec: 00000013 nop +80004ef0: 00000013 nop +80004ef4: 00000013 nop +80004ef8: 00000013 nop +80004efc: 00000013 nop +80004f00: 00000013 nop +80004f04: 00000013 nop +80004f08: 00000013 nop +80004f0c: 00000013 nop +80004f10: 00000013 nop +80004f14: 00000013 nop +80004f18: 00000013 nop +80004f1c: 00000013 nop +80004f20: 00000013 nop +80004f24: 00000013 nop +80004f28: 00000013 nop +80004f2c: 00000013 nop +80004f30: 00000013 nop +80004f34: 00000013 nop +80004f38: 00000013 nop +80004f3c: 00000013 nop +80004f40: 00000013 nop +80004f44: 00000013 nop +80004f48: 00000013 nop +80004f4c: 00000013 nop +80004f50: 00000013 nop +80004f54: 00000013 nop +80004f58: 00000013 nop +80004f5c: 00000013 nop +80004f60: 00000013 nop +80004f64: 00000013 nop +80004f68: 00000013 nop +80004f6c: 00000013 nop +80004f70: 00000013 nop +80004f74: 00000013 nop +80004f78: 00000013 nop +80004f7c: 00000013 nop +80004f80: 00000013 nop +80004f84: 00000013 nop +80004f88: 00000013 nop +80004f8c: 00000013 nop +80004f90: 00000013 nop +80004f94: 00000013 nop +80004f98: 00000013 nop +80004f9c: 00000013 nop +80004fa0: 00000013 nop +80004fa4: 00000013 nop +80004fa8: 00000013 nop +80004fac: 00000013 nop +80004fb0: 00000013 nop +80004fb4: 00000013 nop +80004fb8: 00000013 nop +80004fbc: 00000013 nop +80004fc0: 00000013 nop +80004fc4: 00000013 nop +80004fc8: 00000013 nop +80004fcc: 00000013 nop +80004fd0: 00000013 nop +80004fd4: 00000013 nop +80004fd8: 00000013 nop +80004fdc: 00000013 nop +80004fe0: 00000013 nop +80004fe4: 00000013 nop +80004fe8: 00000013 nop +80004fec: 00000013 nop +80004ff0: 00000013 nop +80004ff4: 00000013 nop +80004ff8: 00000013 nop +80004ffc: 00000013 nop + +80005000 : +80005000: 0100 addi s0,sp,128 +80005002: 0302 slli t1,t1,0x0 +80005004: 0504 addi s1,sp,640 +80005006: 0706 slli a4,a4,0x1 +80005008: 0908 addi a0,sp,144 +8000500a: 0b0a slli s6,s6,0x2 +8000500c: 0d0c addi a1,sp,656 +8000500e: 0f0e slli t5,t5,0x3 +80005010: 00000013 nop +80005014: 00000013 nop +80005018: 00000013 nop +8000501c: 00000013 nop +80005020: 00000013 nop +80005024: 00000013 nop +80005028: 00000013 nop +8000502c: 00000013 nop +80005030: 00000013 nop +80005034: 00000013 nop +80005038: 00000013 nop +8000503c: 00000013 nop +80005040: 00000013 nop +80005044: 00000013 nop +80005048: 00000013 nop +8000504c: 00000013 nop +80005050: 00000013 nop +80005054: 00000013 nop +80005058: 00000013 nop +8000505c: 00000013 nop +80005060: 00000013 nop +80005064: 00000013 nop +80005068: 00000013 nop +8000506c: 00000013 nop +80005070: 00000013 nop +80005074: 00000013 nop +80005078: 00000013 nop +8000507c: 00000013 nop +80005080: 00000013 nop +80005084: 00000013 nop +80005088: 00000013 nop +8000508c: 00000013 nop +80005090: 00000013 nop +80005094: 00000013 nop +80005098: 00000013 nop +8000509c: 00000013 nop +800050a0: 00000013 nop +800050a4: 00000013 nop +800050a8: 00000013 nop +800050ac: 00000013 nop +800050b0: 00000013 nop +800050b4: 00000013 nop +800050b8: 00000013 nop +800050bc: 00000013 nop +800050c0: 00000013 nop +800050c4: 00000013 nop +800050c8: 00000013 nop +800050cc: 00000013 nop +800050d0: 00000013 nop +800050d4: 00000013 nop +800050d8: 00000013 nop +800050dc: 00000013 nop +800050e0: 00000013 nop +800050e4: 00000013 nop +800050e8: 00000013 nop +800050ec: 00000013 nop +800050f0: 00000013 nop +800050f4: 00000013 nop +800050f8: 00000013 nop +800050fc: 00000013 nop +80005100: 00000013 nop +80005104: 00000013 nop +80005108: 00000013 nop +8000510c: 00000013 nop +80005110: 00000013 nop +80005114: 00000013 nop +80005118: 00000013 nop +8000511c: 00000013 nop +80005120: 00000013 nop +80005124: 00000013 nop +80005128: 00000013 nop +8000512c: 00000013 nop +80005130: 00000013 nop +80005134: 00000013 nop +80005138: 00000013 nop +8000513c: 00000013 nop +80005140: 00000013 nop +80005144: 00000013 nop +80005148: 00000013 nop +8000514c: 00000013 nop +80005150: 00000013 nop +80005154: 00000013 nop +80005158: 00000013 nop +8000515c: 00000013 nop +80005160: 00000013 nop +80005164: 00000013 nop +80005168: 00000013 nop +8000516c: 00000013 nop +80005170: 00000013 nop +80005174: 00000013 nop +80005178: 00000013 nop +8000517c: 00000013 nop +80005180: 00000013 nop +80005184: 00000013 nop +80005188: 00000013 nop +8000518c: 00000013 nop +80005190: 00000013 nop +80005194: 00000013 nop +80005198: 00000013 nop +8000519c: 00000013 nop +800051a0: 00000013 nop +800051a4: 00000013 nop +800051a8: 00000013 nop +800051ac: 00000013 nop +800051b0: 00000013 nop +800051b4: 00000013 nop +800051b8: 00000013 nop +800051bc: 00000013 nop +800051c0: 00000013 nop +800051c4: 00000013 nop +800051c8: 00000013 nop +800051cc: 00000013 nop +800051d0: 00000013 nop +800051d4: 00000013 nop +800051d8: 00000013 nop +800051dc: 00000013 nop +800051e0: 00000013 nop +800051e4: 00000013 nop +800051e8: 00000013 nop +800051ec: 00000013 nop +800051f0: 00000013 nop +800051f4: 00000013 nop +800051f8: 00000013 nop +800051fc: 00000013 nop +80005200: 00000013 nop +80005204: 00000013 nop +80005208: 00000013 nop +8000520c: 00000013 nop +80005210: 00000013 nop +80005214: 00000013 nop +80005218: 00000013 nop +8000521c: 00000013 nop +80005220: 00000013 nop +80005224: 00000013 nop +80005228: 00000013 nop +8000522c: 00000013 nop +80005230: 00000013 nop +80005234: 00000013 nop +80005238: 00000013 nop +8000523c: 00000013 nop +80005240: 00000013 nop +80005244: 00000013 nop +80005248: 00000013 nop +8000524c: 00000013 nop +80005250: 00000013 nop +80005254: 00000013 nop +80005258: 00000013 nop +8000525c: 00000013 nop +80005260: 00000013 nop +80005264: 00000013 nop +80005268: 00000013 nop +8000526c: 00000013 nop +80005270: 00000013 nop +80005274: 00000013 nop +80005278: 00000013 nop +8000527c: 00000013 nop +80005280: 00000013 nop +80005284: 00000013 nop +80005288: 00000013 nop +8000528c: 00000013 nop +80005290: 00000013 nop +80005294: 00000013 nop +80005298: 00000013 nop +8000529c: 00000013 nop +800052a0: 00000013 nop +800052a4: 00000013 nop +800052a8: 00000013 nop +800052ac: 00000013 nop +800052b0: 00000013 nop +800052b4: 00000013 nop +800052b8: 00000013 nop +800052bc: 00000013 nop +800052c0: 00000013 nop +800052c4: 00000013 nop +800052c8: 00000013 nop +800052cc: 00000013 nop +800052d0: 00000013 nop +800052d4: 00000013 nop +800052d8: 00000013 nop +800052dc: 00000013 nop +800052e0: 00000013 nop +800052e4: 00000013 nop +800052e8: 00000013 nop +800052ec: 00000013 nop +800052f0: 00000013 nop +800052f4: 00000013 nop +800052f8: 00000013 nop +800052fc: 00000013 nop +80005300: 00000013 nop +80005304: 00000013 nop +80005308: 00000013 nop +8000530c: 00000013 nop +80005310: 00000013 nop +80005314: 00000013 nop +80005318: 00000013 nop +8000531c: 00000013 nop +80005320: 00000013 nop +80005324: 00000013 nop +80005328: 00000013 nop +8000532c: 00000013 nop +80005330: 00000013 nop +80005334: 00000013 nop +80005338: 00000013 nop +8000533c: 00000013 nop +80005340: 00000013 nop +80005344: 00000013 nop +80005348: 00000013 nop +8000534c: 00000013 nop +80005350: 00000013 nop +80005354: 00000013 nop +80005358: 00000013 nop +8000535c: 00000013 nop +80005360: 00000013 nop +80005364: 00000013 nop +80005368: 00000013 nop +8000536c: 00000013 nop +80005370: 00000013 nop +80005374: 00000013 nop +80005378: 00000013 nop +8000537c: 00000013 nop +80005380: 00000013 nop +80005384: 00000013 nop +80005388: 00000013 nop +8000538c: 00000013 nop +80005390: 00000013 nop +80005394: 00000013 nop +80005398: 00000013 nop +8000539c: 00000013 nop +800053a0: 00000013 nop +800053a4: 00000013 nop +800053a8: 00000013 nop +800053ac: 00000013 nop +800053b0: 00000013 nop +800053b4: 00000013 nop +800053b8: 00000013 nop +800053bc: 00000013 nop +800053c0: 00000013 nop +800053c4: 00000013 nop +800053c8: 00000013 nop +800053cc: 00000013 nop +800053d0: 00000013 nop +800053d4: 00000013 nop +800053d8: 00000013 nop +800053dc: 00000013 nop +800053e0: 00000013 nop +800053e4: 00000013 nop +800053e8: 00000013 nop +800053ec: 00000013 nop +800053f0: 00000013 nop +800053f4: 00000013 nop +800053f8: 00000013 nop +800053fc: 00000013 nop +80005400: 00000013 nop +80005404: 00000013 nop +80005408: 00000013 nop +8000540c: 00000013 nop +80005410: 00000013 nop +80005414: 00000013 nop +80005418: 00000013 nop +8000541c: 00000013 nop +80005420: 00000013 nop +80005424: 00000013 nop +80005428: 00000013 nop +8000542c: 00000013 nop +80005430: 00000013 nop +80005434: 00000013 nop +80005438: 00000013 nop +8000543c: 00000013 nop +80005440: 00000013 nop +80005444: 00000013 nop +80005448: 00000013 nop +8000544c: 00000013 nop +80005450: 00000013 nop +80005454: 00000013 nop +80005458: 00000013 nop +8000545c: 00000013 nop +80005460: 00000013 nop +80005464: 00000013 nop +80005468: 00000013 nop +8000546c: 00000013 nop +80005470: 00000013 nop +80005474: 00000013 nop +80005478: 00000013 nop +8000547c: 00000013 nop +80005480: 00000013 nop +80005484: 00000013 nop +80005488: 00000013 nop +8000548c: 00000013 nop +80005490: 00000013 nop +80005494: 00000013 nop +80005498: 00000013 nop +8000549c: 00000013 nop +800054a0: 00000013 nop +800054a4: 00000013 nop +800054a8: 00000013 nop +800054ac: 00000013 nop +800054b0: 00000013 nop +800054b4: 00000013 nop +800054b8: 00000013 nop +800054bc: 00000013 nop +800054c0: 00000013 nop +800054c4: 00000013 nop +800054c8: 00000013 nop +800054cc: 00000013 nop +800054d0: 00000013 nop +800054d4: 00000013 nop +800054d8: 00000013 nop +800054dc: 00000013 nop +800054e0: 00000013 nop +800054e4: 00000013 nop +800054e8: 00000013 nop +800054ec: 00000013 nop +800054f0: 00000013 nop +800054f4: 00000013 nop +800054f8: 00000013 nop +800054fc: 00000013 nop +80005500: 00000013 nop +80005504: 00000013 nop +80005508: 00000013 nop +8000550c: 00000013 nop +80005510: 00000013 nop +80005514: 00000013 nop +80005518: 00000013 nop +8000551c: 00000013 nop +80005520: 00000013 nop +80005524: 00000013 nop +80005528: 00000013 nop +8000552c: 00000013 nop +80005530: 00000013 nop +80005534: 00000013 nop +80005538: 00000013 nop +8000553c: 00000013 nop +80005540: 00000013 nop +80005544: 00000013 nop +80005548: 00000013 nop +8000554c: 00000013 nop +80005550: 00000013 nop +80005554: 00000013 nop +80005558: 00000013 nop +8000555c: 00000013 nop +80005560: 00000013 nop +80005564: 00000013 nop +80005568: 00000013 nop +8000556c: 00000013 nop +80005570: 00000013 nop +80005574: 00000013 nop +80005578: 00000013 nop +8000557c: 00000013 nop +80005580: 00000013 nop +80005584: 00000013 nop +80005588: 00000013 nop +8000558c: 00000013 nop +80005590: 00000013 nop +80005594: 00000013 nop +80005598: 00000013 nop +8000559c: 00000013 nop +800055a0: 00000013 nop +800055a4: 00000013 nop +800055a8: 00000013 nop +800055ac: 00000013 nop +800055b0: 00000013 nop +800055b4: 00000013 nop +800055b8: 00000013 nop +800055bc: 00000013 nop +800055c0: 00000013 nop +800055c4: 00000013 nop +800055c8: 00000013 nop +800055cc: 00000013 nop +800055d0: 00000013 nop +800055d4: 00000013 nop +800055d8: 00000013 nop +800055dc: 00000013 nop +800055e0: 00000013 nop +800055e4: 00000013 nop +800055e8: 00000013 nop +800055ec: 00000013 nop +800055f0: 00000013 nop +800055f4: 00000013 nop +800055f8: 00000013 nop +800055fc: 00000013 nop +80005600: 00000013 nop +80005604: 00000013 nop +80005608: 00000013 nop +8000560c: 00000013 nop +80005610: 00000013 nop +80005614: 00000013 nop +80005618: 00000013 nop +8000561c: 00000013 nop +80005620: 00000013 nop +80005624: 00000013 nop +80005628: 00000013 nop +8000562c: 00000013 nop +80005630: 00000013 nop +80005634: 00000013 nop +80005638: 00000013 nop +8000563c: 00000013 nop +80005640: 00000013 nop +80005644: 00000013 nop +80005648: 00000013 nop +8000564c: 00000013 nop +80005650: 00000013 nop +80005654: 00000013 nop +80005658: 00000013 nop +8000565c: 00000013 nop +80005660: 00000013 nop +80005664: 00000013 nop +80005668: 00000013 nop +8000566c: 00000013 nop +80005670: 00000013 nop +80005674: 00000013 nop +80005678: 00000013 nop +8000567c: 00000013 nop +80005680: 00000013 nop +80005684: 00000013 nop +80005688: 00000013 nop +8000568c: 00000013 nop +80005690: 00000013 nop +80005694: 00000013 nop +80005698: 00000013 nop +8000569c: 00000013 nop +800056a0: 00000013 nop +800056a4: 00000013 nop +800056a8: 00000013 nop +800056ac: 00000013 nop +800056b0: 00000013 nop +800056b4: 00000013 nop +800056b8: 00000013 nop +800056bc: 00000013 nop +800056c0: 00000013 nop +800056c4: 00000013 nop +800056c8: 00000013 nop +800056cc: 00000013 nop +800056d0: 00000013 nop +800056d4: 00000013 nop +800056d8: 00000013 nop +800056dc: 00000013 nop +800056e0: 00000013 nop +800056e4: 00000013 nop +800056e8: 00000013 nop +800056ec: 00000013 nop +800056f0: 00000013 nop +800056f4: 00000013 nop +800056f8: 00000013 nop +800056fc: 00000013 nop +80005700: 00000013 nop +80005704: 00000013 nop +80005708: 00000013 nop +8000570c: 00000013 nop +80005710: 00000013 nop +80005714: 00000013 nop +80005718: 00000013 nop +8000571c: 00000013 nop +80005720: 00000013 nop +80005724: 00000013 nop +80005728: 00000013 nop +8000572c: 00000013 nop +80005730: 00000013 nop +80005734: 00000013 nop +80005738: 00000013 nop +8000573c: 00000013 nop +80005740: 00000013 nop +80005744: 00000013 nop +80005748: 00000013 nop +8000574c: 00000013 nop +80005750: 00000013 nop +80005754: 00000013 nop +80005758: 00000013 nop +8000575c: 00000013 nop +80005760: 00000013 nop +80005764: 00000013 nop +80005768: 00000013 nop +8000576c: 00000013 nop +80005770: 00000013 nop +80005774: 00000013 nop +80005778: 00000013 nop +8000577c: 00000013 nop +80005780: 00000013 nop +80005784: 00000013 nop +80005788: 00000013 nop +8000578c: 00000013 nop +80005790: 00000013 nop +80005794: 00000013 nop +80005798: 00000013 nop +8000579c: 00000013 nop +800057a0: 00000013 nop +800057a4: 00000013 nop +800057a8: 00000013 nop +800057ac: 00000013 nop +800057b0: 00000013 nop +800057b4: 00000013 nop +800057b8: 00000013 nop +800057bc: 00000013 nop +800057c0: 00000013 nop +800057c4: 00000013 nop +800057c8: 00000013 nop +800057cc: 00000013 nop +800057d0: 00000013 nop +800057d4: 00000013 nop +800057d8: 00000013 nop +800057dc: 00000013 nop +800057e0: 00000013 nop +800057e4: 00000013 nop +800057e8: 00000013 nop +800057ec: 00000013 nop +800057f0: 00000013 nop +800057f4: 00000013 nop +800057f8: 00000013 nop +800057fc: 00000013 nop +80005800: 00000013 nop +80005804: 00000013 nop +80005808: 00000013 nop +8000580c: 00000013 nop +80005810: 00000013 nop +80005814: 00000013 nop +80005818: 00000013 nop +8000581c: 00000013 nop +80005820: 00000013 nop +80005824: 00000013 nop +80005828: 00000013 nop +8000582c: 00000013 nop +80005830: 00000013 nop +80005834: 00000013 nop +80005838: 00000013 nop +8000583c: 00000013 nop +80005840: 00000013 nop +80005844: 00000013 nop +80005848: 00000013 nop +8000584c: 00000013 nop +80005850: 00000013 nop +80005854: 00000013 nop +80005858: 00000013 nop +8000585c: 00000013 nop +80005860: 00000013 nop +80005864: 00000013 nop +80005868: 00000013 nop +8000586c: 00000013 nop +80005870: 00000013 nop +80005874: 00000013 nop +80005878: 00000013 nop +8000587c: 00000013 nop +80005880: 00000013 nop +80005884: 00000013 nop +80005888: 00000013 nop +8000588c: 00000013 nop +80005890: 00000013 nop +80005894: 00000013 nop +80005898: 00000013 nop +8000589c: 00000013 nop +800058a0: 00000013 nop +800058a4: 00000013 nop +800058a8: 00000013 nop +800058ac: 00000013 nop +800058b0: 00000013 nop +800058b4: 00000013 nop +800058b8: 00000013 nop +800058bc: 00000013 nop +800058c0: 00000013 nop +800058c4: 00000013 nop +800058c8: 00000013 nop +800058cc: 00000013 nop +800058d0: 00000013 nop +800058d4: 00000013 nop +800058d8: 00000013 nop +800058dc: 00000013 nop +800058e0: 00000013 nop +800058e4: 00000013 nop +800058e8: 00000013 nop +800058ec: 00000013 nop +800058f0: 00000013 nop +800058f4: 00000013 nop +800058f8: 00000013 nop +800058fc: 00000013 nop +80005900: 00000013 nop +80005904: 00000013 nop +80005908: 00000013 nop +8000590c: 00000013 nop +80005910: 00000013 nop +80005914: 00000013 nop +80005918: 00000013 nop +8000591c: 00000013 nop +80005920: 00000013 nop +80005924: 00000013 nop +80005928: 00000013 nop +8000592c: 00000013 nop +80005930: 00000013 nop +80005934: 00000013 nop +80005938: 00000013 nop +8000593c: 00000013 nop +80005940: 00000013 nop +80005944: 00000013 nop +80005948: 00000013 nop +8000594c: 00000013 nop +80005950: 00000013 nop +80005954: 00000013 nop +80005958: 00000013 nop +8000595c: 00000013 nop +80005960: 00000013 nop +80005964: 00000013 nop +80005968: 00000013 nop +8000596c: 00000013 nop +80005970: 00000013 nop +80005974: 00000013 nop +80005978: 00000013 nop +8000597c: 00000013 nop +80005980: 00000013 nop +80005984: 00000013 nop +80005988: 00000013 nop +8000598c: 00000013 nop +80005990: 00000013 nop +80005994: 00000013 nop +80005998: 00000013 nop +8000599c: 00000013 nop +800059a0: 00000013 nop +800059a4: 00000013 nop +800059a8: 00000013 nop +800059ac: 00000013 nop +800059b0: 00000013 nop +800059b4: 00000013 nop +800059b8: 00000013 nop +800059bc: 00000013 nop +800059c0: 00000013 nop +800059c4: 00000013 nop +800059c8: 00000013 nop +800059cc: 00000013 nop +800059d0: 00000013 nop +800059d4: 00000013 nop +800059d8: 00000013 nop +800059dc: 00000013 nop +800059e0: 00000013 nop +800059e4: 00000013 nop +800059e8: 00000013 nop +800059ec: 00000013 nop +800059f0: 00000013 nop +800059f4: 00000013 nop +800059f8: 00000013 nop +800059fc: 00000013 nop +80005a00: 00000013 nop +80005a04: 00000013 nop +80005a08: 00000013 nop +80005a0c: 00000013 nop +80005a10: 00000013 nop +80005a14: 00000013 nop +80005a18: 00000013 nop +80005a1c: 00000013 nop +80005a20: 00000013 nop +80005a24: 00000013 nop +80005a28: 00000013 nop +80005a2c: 00000013 nop +80005a30: 00000013 nop +80005a34: 00000013 nop +80005a38: 00000013 nop +80005a3c: 00000013 nop +80005a40: 00000013 nop +80005a44: 00000013 nop +80005a48: 00000013 nop +80005a4c: 00000013 nop +80005a50: 00000013 nop +80005a54: 00000013 nop +80005a58: 00000013 nop +80005a5c: 00000013 nop +80005a60: 00000013 nop +80005a64: 00000013 nop +80005a68: 00000013 nop +80005a6c: 00000013 nop +80005a70: 00000013 nop +80005a74: 00000013 nop +80005a78: 00000013 nop +80005a7c: 00000013 nop +80005a80: 00000013 nop +80005a84: 00000013 nop +80005a88: 00000013 nop +80005a8c: 00000013 nop +80005a90: 00000013 nop +80005a94: 00000013 nop +80005a98: 00000013 nop +80005a9c: 00000013 nop +80005aa0: 00000013 nop +80005aa4: 00000013 nop +80005aa8: 00000013 nop +80005aac: 00000013 nop +80005ab0: 00000013 nop +80005ab4: 00000013 nop +80005ab8: 00000013 nop +80005abc: 00000013 nop +80005ac0: 00000013 nop +80005ac4: 00000013 nop +80005ac8: 00000013 nop +80005acc: 00000013 nop +80005ad0: 00000013 nop +80005ad4: 00000013 nop +80005ad8: 00000013 nop +80005adc: 00000013 nop +80005ae0: 00000013 nop +80005ae4: 00000013 nop +80005ae8: 00000013 nop +80005aec: 00000013 nop +80005af0: 00000013 nop +80005af4: 00000013 nop +80005af8: 00000013 nop +80005afc: 00000013 nop +80005b00: 00000013 nop +80005b04: 00000013 nop +80005b08: 00000013 nop +80005b0c: 00000013 nop +80005b10: 00000013 nop +80005b14: 00000013 nop +80005b18: 00000013 nop +80005b1c: 00000013 nop +80005b20: 00000013 nop +80005b24: 00000013 nop +80005b28: 00000013 nop +80005b2c: 00000013 nop +80005b30: 00000013 nop +80005b34: 00000013 nop +80005b38: 00000013 nop +80005b3c: 00000013 nop +80005b40: 00000013 nop +80005b44: 00000013 nop +80005b48: 00000013 nop +80005b4c: 00000013 nop +80005b50: 00000013 nop +80005b54: 00000013 nop +80005b58: 00000013 nop +80005b5c: 00000013 nop +80005b60: 00000013 nop +80005b64: 00000013 nop +80005b68: 00000013 nop +80005b6c: 00000013 nop +80005b70: 00000013 nop +80005b74: 00000013 nop +80005b78: 00000013 nop +80005b7c: 00000013 nop +80005b80: 00000013 nop +80005b84: 00000013 nop +80005b88: 00000013 nop +80005b8c: 00000013 nop +80005b90: 00000013 nop +80005b94: 00000013 nop +80005b98: 00000013 nop +80005b9c: 00000013 nop +80005ba0: 00000013 nop +80005ba4: 00000013 nop +80005ba8: 00000013 nop +80005bac: 00000013 nop +80005bb0: 00000013 nop +80005bb4: 00000013 nop +80005bb8: 00000013 nop +80005bbc: 00000013 nop +80005bc0: 00000013 nop +80005bc4: 00000013 nop +80005bc8: 00000013 nop +80005bcc: 00000013 nop +80005bd0: 00000013 nop +80005bd4: 00000013 nop +80005bd8: 00000013 nop +80005bdc: 00000013 nop +80005be0: 00000013 nop +80005be4: 00000013 nop +80005be8: 00000013 nop +80005bec: 00000013 nop +80005bf0: 00000013 nop +80005bf4: 00000013 nop +80005bf8: 00000013 nop +80005bfc: 00000013 nop +80005c00: 00000013 nop +80005c04: 00000013 nop +80005c08: 00000013 nop +80005c0c: 00000013 nop +80005c10: 00000013 nop +80005c14: 00000013 nop +80005c18: 00000013 nop +80005c1c: 00000013 nop +80005c20: 00000013 nop +80005c24: 00000013 nop +80005c28: 00000013 nop +80005c2c: 00000013 nop +80005c30: 00000013 nop +80005c34: 00000013 nop +80005c38: 00000013 nop +80005c3c: 00000013 nop +80005c40: 00000013 nop +80005c44: 00000013 nop +80005c48: 00000013 nop +80005c4c: 00000013 nop +80005c50: 00000013 nop +80005c54: 00000013 nop +80005c58: 00000013 nop +80005c5c: 00000013 nop +80005c60: 00000013 nop +80005c64: 00000013 nop +80005c68: 00000013 nop +80005c6c: 00000013 nop +80005c70: 00000013 nop +80005c74: 00000013 nop +80005c78: 00000013 nop +80005c7c: 00000013 nop +80005c80: 00000013 nop +80005c84: 00000013 nop +80005c88: 00000013 nop +80005c8c: 00000013 nop +80005c90: 00000013 nop +80005c94: 00000013 nop +80005c98: 00000013 nop +80005c9c: 00000013 nop +80005ca0: 00000013 nop +80005ca4: 00000013 nop +80005ca8: 00000013 nop +80005cac: 00000013 nop +80005cb0: 00000013 nop +80005cb4: 00000013 nop +80005cb8: 00000013 nop +80005cbc: 00000013 nop +80005cc0: 00000013 nop +80005cc4: 00000013 nop +80005cc8: 00000013 nop +80005ccc: 00000013 nop +80005cd0: 00000013 nop +80005cd4: 00000013 nop +80005cd8: 00000013 nop +80005cdc: 00000013 nop +80005ce0: 00000013 nop +80005ce4: 00000013 nop +80005ce8: 00000013 nop +80005cec: 00000013 nop +80005cf0: 00000013 nop +80005cf4: 00000013 nop +80005cf8: 00000013 nop +80005cfc: 00000013 nop +80005d00: 00000013 nop +80005d04: 00000013 nop +80005d08: 00000013 nop +80005d0c: 00000013 nop +80005d10: 00000013 nop +80005d14: 00000013 nop +80005d18: 00000013 nop +80005d1c: 00000013 nop +80005d20: 00000013 nop +80005d24: 00000013 nop +80005d28: 00000013 nop +80005d2c: 00000013 nop +80005d30: 00000013 nop +80005d34: 00000013 nop +80005d38: 00000013 nop +80005d3c: 00000013 nop +80005d40: 00000013 nop +80005d44: 00000013 nop +80005d48: 00000013 nop +80005d4c: 00000013 nop +80005d50: 00000013 nop +80005d54: 00000013 nop +80005d58: 00000013 nop +80005d5c: 00000013 nop +80005d60: 00000013 nop +80005d64: 00000013 nop +80005d68: 00000013 nop +80005d6c: 00000013 nop +80005d70: 00000013 nop +80005d74: 00000013 nop +80005d78: 00000013 nop +80005d7c: 00000013 nop +80005d80: 00000013 nop +80005d84: 00000013 nop +80005d88: 00000013 nop +80005d8c: 00000013 nop +80005d90: 00000013 nop +80005d94: 00000013 nop +80005d98: 00000013 nop +80005d9c: 00000013 nop +80005da0: 00000013 nop +80005da4: 00000013 nop +80005da8: 00000013 nop +80005dac: 00000013 nop +80005db0: 00000013 nop +80005db4: 00000013 nop +80005db8: 00000013 nop +80005dbc: 00000013 nop +80005dc0: 00000013 nop +80005dc4: 00000013 nop +80005dc8: 00000013 nop +80005dcc: 00000013 nop +80005dd0: 00000013 nop +80005dd4: 00000013 nop +80005dd8: 00000013 nop +80005ddc: 00000013 nop +80005de0: 00000013 nop +80005de4: 00000013 nop +80005de8: 00000013 nop +80005dec: 00000013 nop +80005df0: 00000013 nop +80005df4: 00000013 nop +80005df8: 00000013 nop +80005dfc: 00000013 nop +80005e00: 00000013 nop +80005e04: 00000013 nop +80005e08: 00000013 nop +80005e0c: 00000013 nop +80005e10: 00000013 nop +80005e14: 00000013 nop +80005e18: 00000013 nop +80005e1c: 00000013 nop +80005e20: 00000013 nop +80005e24: 00000013 nop +80005e28: 00000013 nop +80005e2c: 00000013 nop +80005e30: 00000013 nop +80005e34: 00000013 nop +80005e38: 00000013 nop +80005e3c: 00000013 nop +80005e40: 00000013 nop +80005e44: 00000013 nop +80005e48: 00000013 nop +80005e4c: 00000013 nop +80005e50: 00000013 nop +80005e54: 00000013 nop +80005e58: 00000013 nop +80005e5c: 00000013 nop +80005e60: 00000013 nop +80005e64: 00000013 nop +80005e68: 00000013 nop +80005e6c: 00000013 nop +80005e70: 00000013 nop +80005e74: 00000013 nop +80005e78: 00000013 nop +80005e7c: 00000013 nop +80005e80: 00000013 nop +80005e84: 00000013 nop +80005e88: 00000013 nop +80005e8c: 00000013 nop +80005e90: 00000013 nop +80005e94: 00000013 nop +80005e98: 00000013 nop +80005e9c: 00000013 nop +80005ea0: 00000013 nop +80005ea4: 00000013 nop +80005ea8: 00000013 nop +80005eac: 00000013 nop +80005eb0: 00000013 nop +80005eb4: 00000013 nop +80005eb8: 00000013 nop +80005ebc: 00000013 nop +80005ec0: 00000013 nop +80005ec4: 00000013 nop +80005ec8: 00000013 nop +80005ecc: 00000013 nop +80005ed0: 00000013 nop +80005ed4: 00000013 nop +80005ed8: 00000013 nop +80005edc: 00000013 nop +80005ee0: 00000013 nop +80005ee4: 00000013 nop +80005ee8: 00000013 nop +80005eec: 00000013 nop +80005ef0: 00000013 nop +80005ef4: 00000013 nop +80005ef8: 00000013 nop +80005efc: 00000013 nop +80005f00: 00000013 nop +80005f04: 00000013 nop +80005f08: 00000013 nop +80005f0c: 00000013 nop +80005f10: 00000013 nop +80005f14: 00000013 nop +80005f18: 00000013 nop +80005f1c: 00000013 nop +80005f20: 00000013 nop +80005f24: 00000013 nop +80005f28: 00000013 nop +80005f2c: 00000013 nop +80005f30: 00000013 nop +80005f34: 00000013 nop +80005f38: 00000013 nop +80005f3c: 00000013 nop +80005f40: 00000013 nop +80005f44: 00000013 nop +80005f48: 00000013 nop +80005f4c: 00000013 nop +80005f50: 00000013 nop +80005f54: 00000013 nop +80005f58: 00000013 nop +80005f5c: 00000013 nop +80005f60: 00000013 nop +80005f64: 00000013 nop +80005f68: 00000013 nop +80005f6c: 00000013 nop +80005f70: 00000013 nop +80005f74: 00000013 nop +80005f78: 00000013 nop +80005f7c: 00000013 nop +80005f80: 00000013 nop +80005f84: 00000013 nop +80005f88: 00000013 nop +80005f8c: 00000013 nop +80005f90: 00000013 nop +80005f94: 00000013 nop +80005f98: 00000013 nop +80005f9c: 00000013 nop +80005fa0: 00000013 nop +80005fa4: 00000013 nop +80005fa8: 00000013 nop +80005fac: 00000013 nop +80005fb0: 00000013 nop +80005fb4: 00000013 nop +80005fb8: 00000013 nop +80005fbc: 00000013 nop +80005fc0: 00000013 nop +80005fc4: 00000013 nop +80005fc8: 00000013 nop +80005fcc: 00000013 nop +80005fd0: 00000013 nop +80005fd4: 00000013 nop +80005fd8: 00000013 nop +80005fdc: 00000013 nop +80005fe0: 00000013 nop +80005fe4: 00000013 nop +80005fe8: 00000013 nop +80005fec: 00000013 nop +80005ff0: 00000013 nop +80005ff4: 00000013 nop +80005ff8: 00000013 nop +80005ffc: 00000013 nop + +80006000 : +80006000: 1110 addi a2,sp,160 +80006002: 1312 slli t1,t1,0x24 +80006004: 1514 addi a3,sp,672 +80006006: 1716 slli a4,a4,0x25 +80006008: 1918 addi a4,sp,176 +8000600a: 1b1a slli s6,s6,0x26 +8000600c: 1d1c addi a5,sp,688 +8000600e: 1f1e slli t5,t5,0x27 +80006010: 00000013 nop +80006014: 00000013 nop +80006018: 00000013 nop +8000601c: 00000013 nop +80006020: 00000013 nop +80006024: 00000013 nop +80006028: 00000013 nop +8000602c: 00000013 nop +80006030: 00000013 nop +80006034: 00000013 nop +80006038: 00000013 nop +8000603c: 00000013 nop +80006040: 00000013 nop +80006044: 00000013 nop +80006048: 00000013 nop +8000604c: 00000013 nop +80006050: 00000013 nop +80006054: 00000013 nop +80006058: 00000013 nop +8000605c: 00000013 nop +80006060: 00000013 nop +80006064: 00000013 nop +80006068: 00000013 nop +8000606c: 00000013 nop +80006070: 00000013 nop +80006074: 00000013 nop +80006078: 00000013 nop +8000607c: 00000013 nop +80006080: 00000013 nop +80006084: 00000013 nop +80006088: 00000013 nop +8000608c: 00000013 nop +80006090: 00000013 nop +80006094: 00000013 nop +80006098: 00000013 nop +8000609c: 00000013 nop +800060a0: 00000013 nop +800060a4: 00000013 nop +800060a8: 00000013 nop +800060ac: 00000013 nop +800060b0: 00000013 nop +800060b4: 00000013 nop +800060b8: 00000013 nop +800060bc: 00000013 nop +800060c0: 00000013 nop +800060c4: 00000013 nop +800060c8: 00000013 nop +800060cc: 00000013 nop +800060d0: 00000013 nop +800060d4: 00000013 nop +800060d8: 00000013 nop +800060dc: 00000013 nop +800060e0: 00000013 nop +800060e4: 00000013 nop +800060e8: 00000013 nop +800060ec: 00000013 nop +800060f0: 00000013 nop +800060f4: 00000013 nop +800060f8: 00000013 nop +800060fc: 00000013 nop +80006100: 00000013 nop +80006104: 00000013 nop +80006108: 00000013 nop +8000610c: 00000013 nop +80006110: 00000013 nop +80006114: 00000013 nop +80006118: 00000013 nop +8000611c: 00000013 nop +80006120: 00000013 nop +80006124: 00000013 nop +80006128: 00000013 nop +8000612c: 00000013 nop +80006130: 00000013 nop +80006134: 00000013 nop +80006138: 00000013 nop +8000613c: 00000013 nop +80006140: 00000013 nop +80006144: 00000013 nop +80006148: 00000013 nop +8000614c: 00000013 nop +80006150: 00000013 nop +80006154: 00000013 nop +80006158: 00000013 nop +8000615c: 00000013 nop +80006160: 00000013 nop +80006164: 00000013 nop +80006168: 00000013 nop +8000616c: 00000013 nop +80006170: 00000013 nop +80006174: 00000013 nop +80006178: 00000013 nop +8000617c: 00000013 nop +80006180: 00000013 nop +80006184: 00000013 nop +80006188: 00000013 nop +8000618c: 00000013 nop +80006190: 00000013 nop +80006194: 00000013 nop +80006198: 00000013 nop +8000619c: 00000013 nop +800061a0: 00000013 nop +800061a4: 00000013 nop +800061a8: 00000013 nop +800061ac: 00000013 nop +800061b0: 00000013 nop +800061b4: 00000013 nop +800061b8: 00000013 nop +800061bc: 00000013 nop +800061c0: 00000013 nop +800061c4: 00000013 nop +800061c8: 00000013 nop +800061cc: 00000013 nop +800061d0: 00000013 nop +800061d4: 00000013 nop +800061d8: 00000013 nop +800061dc: 00000013 nop +800061e0: 00000013 nop +800061e4: 00000013 nop +800061e8: 00000013 nop +800061ec: 00000013 nop +800061f0: 00000013 nop +800061f4: 00000013 nop +800061f8: 00000013 nop +800061fc: 00000013 nop +80006200: 00000013 nop +80006204: 00000013 nop +80006208: 00000013 nop +8000620c: 00000013 nop +80006210: 00000013 nop +80006214: 00000013 nop +80006218: 00000013 nop +8000621c: 00000013 nop +80006220: 00000013 nop +80006224: 00000013 nop +80006228: 00000013 nop +8000622c: 00000013 nop +80006230: 00000013 nop +80006234: 00000013 nop +80006238: 00000013 nop +8000623c: 00000013 nop +80006240: 00000013 nop +80006244: 00000013 nop +80006248: 00000013 nop +8000624c: 00000013 nop +80006250: 00000013 nop +80006254: 00000013 nop +80006258: 00000013 nop +8000625c: 00000013 nop +80006260: 00000013 nop +80006264: 00000013 nop +80006268: 00000013 nop +8000626c: 00000013 nop +80006270: 00000013 nop +80006274: 00000013 nop +80006278: 00000013 nop +8000627c: 00000013 nop +80006280: 00000013 nop +80006284: 00000013 nop +80006288: 00000013 nop +8000628c: 00000013 nop +80006290: 00000013 nop +80006294: 00000013 nop +80006298: 00000013 nop +8000629c: 00000013 nop +800062a0: 00000013 nop +800062a4: 00000013 nop +800062a8: 00000013 nop +800062ac: 00000013 nop +800062b0: 00000013 nop +800062b4: 00000013 nop +800062b8: 00000013 nop +800062bc: 00000013 nop +800062c0: 00000013 nop +800062c4: 00000013 nop +800062c8: 00000013 nop +800062cc: 00000013 nop +800062d0: 00000013 nop +800062d4: 00000013 nop +800062d8: 00000013 nop +800062dc: 00000013 nop +800062e0: 00000013 nop +800062e4: 00000013 nop +800062e8: 00000013 nop +800062ec: 00000013 nop +800062f0: 00000013 nop +800062f4: 00000013 nop +800062f8: 00000013 nop +800062fc: 00000013 nop +80006300: 00000013 nop +80006304: 00000013 nop +80006308: 00000013 nop +8000630c: 00000013 nop +80006310: 00000013 nop +80006314: 00000013 nop +80006318: 00000013 nop +8000631c: 00000013 nop +80006320: 00000013 nop +80006324: 00000013 nop +80006328: 00000013 nop +8000632c: 00000013 nop +80006330: 00000013 nop +80006334: 00000013 nop +80006338: 00000013 nop +8000633c: 00000013 nop +80006340: 00000013 nop +80006344: 00000013 nop +80006348: 00000013 nop +8000634c: 00000013 nop +80006350: 00000013 nop +80006354: 00000013 nop +80006358: 00000013 nop +8000635c: 00000013 nop +80006360: 00000013 nop +80006364: 00000013 nop +80006368: 00000013 nop +8000636c: 00000013 nop +80006370: 00000013 nop +80006374: 00000013 nop +80006378: 00000013 nop +8000637c: 00000013 nop +80006380: 00000013 nop +80006384: 00000013 nop +80006388: 00000013 nop +8000638c: 00000013 nop +80006390: 00000013 nop +80006394: 00000013 nop +80006398: 00000013 nop +8000639c: 00000013 nop +800063a0: 00000013 nop +800063a4: 00000013 nop +800063a8: 00000013 nop +800063ac: 00000013 nop +800063b0: 00000013 nop +800063b4: 00000013 nop +800063b8: 00000013 nop +800063bc: 00000013 nop +800063c0: 00000013 nop +800063c4: 00000013 nop +800063c8: 00000013 nop +800063cc: 00000013 nop +800063d0: 00000013 nop +800063d4: 00000013 nop +800063d8: 00000013 nop +800063dc: 00000013 nop +800063e0: 00000013 nop +800063e4: 00000013 nop +800063e8: 00000013 nop +800063ec: 00000013 nop +800063f0: 00000013 nop +800063f4: 00000013 nop +800063f8: 00000013 nop +800063fc: 00000013 nop +80006400: 00000013 nop +80006404: 00000013 nop +80006408: 00000013 nop +8000640c: 00000013 nop +80006410: 00000013 nop +80006414: 00000013 nop +80006418: 00000013 nop +8000641c: 00000013 nop +80006420: 00000013 nop +80006424: 00000013 nop +80006428: 00000013 nop +8000642c: 00000013 nop +80006430: 00000013 nop +80006434: 00000013 nop +80006438: 00000013 nop +8000643c: 00000013 nop +80006440: 00000013 nop +80006444: 00000013 nop +80006448: 00000013 nop +8000644c: 00000013 nop +80006450: 00000013 nop +80006454: 00000013 nop +80006458: 00000013 nop +8000645c: 00000013 nop +80006460: 00000013 nop +80006464: 00000013 nop +80006468: 00000013 nop +8000646c: 00000013 nop +80006470: 00000013 nop +80006474: 00000013 nop +80006478: 00000013 nop +8000647c: 00000013 nop +80006480: 00000013 nop +80006484: 00000013 nop +80006488: 00000013 nop +8000648c: 00000013 nop +80006490: 00000013 nop +80006494: 00000013 nop +80006498: 00000013 nop +8000649c: 00000013 nop +800064a0: 00000013 nop +800064a4: 00000013 nop +800064a8: 00000013 nop +800064ac: 00000013 nop +800064b0: 00000013 nop +800064b4: 00000013 nop +800064b8: 00000013 nop +800064bc: 00000013 nop +800064c0: 00000013 nop +800064c4: 00000013 nop +800064c8: 00000013 nop +800064cc: 00000013 nop +800064d0: 00000013 nop +800064d4: 00000013 nop +800064d8: 00000013 nop +800064dc: 00000013 nop +800064e0: 00000013 nop +800064e4: 00000013 nop +800064e8: 00000013 nop +800064ec: 00000013 nop +800064f0: 00000013 nop +800064f4: 00000013 nop +800064f8: 00000013 nop +800064fc: 00000013 nop +80006500: 00000013 nop +80006504: 00000013 nop +80006508: 00000013 nop +8000650c: 00000013 nop +80006510: 00000013 nop +80006514: 00000013 nop +80006518: 00000013 nop +8000651c: 00000013 nop +80006520: 00000013 nop +80006524: 00000013 nop +80006528: 00000013 nop +8000652c: 00000013 nop +80006530: 00000013 nop +80006534: 00000013 nop +80006538: 00000013 nop +8000653c: 00000013 nop +80006540: 00000013 nop +80006544: 00000013 nop +80006548: 00000013 nop +8000654c: 00000013 nop +80006550: 00000013 nop +80006554: 00000013 nop +80006558: 00000013 nop +8000655c: 00000013 nop +80006560: 00000013 nop +80006564: 00000013 nop +80006568: 00000013 nop +8000656c: 00000013 nop +80006570: 00000013 nop +80006574: 00000013 nop +80006578: 00000013 nop +8000657c: 00000013 nop +80006580: 00000013 nop +80006584: 00000013 nop +80006588: 00000013 nop +8000658c: 00000013 nop +80006590: 00000013 nop +80006594: 00000013 nop +80006598: 00000013 nop +8000659c: 00000013 nop +800065a0: 00000013 nop +800065a4: 00000013 nop +800065a8: 00000013 nop +800065ac: 00000013 nop +800065b0: 00000013 nop +800065b4: 00000013 nop +800065b8: 00000013 nop +800065bc: 00000013 nop +800065c0: 00000013 nop +800065c4: 00000013 nop +800065c8: 00000013 nop +800065cc: 00000013 nop +800065d0: 00000013 nop +800065d4: 00000013 nop +800065d8: 00000013 nop +800065dc: 00000013 nop +800065e0: 00000013 nop +800065e4: 00000013 nop +800065e8: 00000013 nop +800065ec: 00000013 nop +800065f0: 00000013 nop +800065f4: 00000013 nop +800065f8: 00000013 nop +800065fc: 00000013 nop +80006600: 00000013 nop +80006604: 00000013 nop +80006608: 00000013 nop +8000660c: 00000013 nop +80006610: 00000013 nop +80006614: 00000013 nop +80006618: 00000013 nop +8000661c: 00000013 nop +80006620: 00000013 nop +80006624: 00000013 nop +80006628: 00000013 nop +8000662c: 00000013 nop +80006630: 00000013 nop +80006634: 00000013 nop +80006638: 00000013 nop +8000663c: 00000013 nop +80006640: 00000013 nop +80006644: 00000013 nop +80006648: 00000013 nop +8000664c: 00000013 nop +80006650: 00000013 nop +80006654: 00000013 nop +80006658: 00000013 nop +8000665c: 00000013 nop +80006660: 00000013 nop +80006664: 00000013 nop +80006668: 00000013 nop +8000666c: 00000013 nop +80006670: 00000013 nop +80006674: 00000013 nop +80006678: 00000013 nop +8000667c: 00000013 nop +80006680: 00000013 nop +80006684: 00000013 nop +80006688: 00000013 nop +8000668c: 00000013 nop +80006690: 00000013 nop +80006694: 00000013 nop +80006698: 00000013 nop +8000669c: 00000013 nop +800066a0: 00000013 nop +800066a4: 00000013 nop +800066a8: 00000013 nop +800066ac: 00000013 nop +800066b0: 00000013 nop +800066b4: 00000013 nop +800066b8: 00000013 nop +800066bc: 00000013 nop +800066c0: 00000013 nop +800066c4: 00000013 nop +800066c8: 00000013 nop +800066cc: 00000013 nop +800066d0: 00000013 nop +800066d4: 00000013 nop +800066d8: 00000013 nop +800066dc: 00000013 nop +800066e0: 00000013 nop +800066e4: 00000013 nop +800066e8: 00000013 nop +800066ec: 00000013 nop +800066f0: 00000013 nop +800066f4: 00000013 nop +800066f8: 00000013 nop +800066fc: 00000013 nop +80006700: 00000013 nop +80006704: 00000013 nop +80006708: 00000013 nop +8000670c: 00000013 nop +80006710: 00000013 nop +80006714: 00000013 nop +80006718: 00000013 nop +8000671c: 00000013 nop +80006720: 00000013 nop +80006724: 00000013 nop +80006728: 00000013 nop +8000672c: 00000013 nop +80006730: 00000013 nop +80006734: 00000013 nop +80006738: 00000013 nop +8000673c: 00000013 nop +80006740: 00000013 nop +80006744: 00000013 nop +80006748: 00000013 nop +8000674c: 00000013 nop +80006750: 00000013 nop +80006754: 00000013 nop +80006758: 00000013 nop +8000675c: 00000013 nop +80006760: 00000013 nop +80006764: 00000013 nop +80006768: 00000013 nop +8000676c: 00000013 nop +80006770: 00000013 nop +80006774: 00000013 nop +80006778: 00000013 nop +8000677c: 00000013 nop +80006780: 00000013 nop +80006784: 00000013 nop +80006788: 00000013 nop +8000678c: 00000013 nop +80006790: 00000013 nop +80006794: 00000013 nop +80006798: 00000013 nop +8000679c: 00000013 nop +800067a0: 00000013 nop +800067a4: 00000013 nop +800067a8: 00000013 nop +800067ac: 00000013 nop +800067b0: 00000013 nop +800067b4: 00000013 nop +800067b8: 00000013 nop +800067bc: 00000013 nop +800067c0: 00000013 nop +800067c4: 00000013 nop +800067c8: 00000013 nop +800067cc: 00000013 nop +800067d0: 00000013 nop +800067d4: 00000013 nop +800067d8: 00000013 nop +800067dc: 00000013 nop +800067e0: 00000013 nop +800067e4: 00000013 nop +800067e8: 00000013 nop +800067ec: 00000013 nop +800067f0: 00000013 nop +800067f4: 00000013 nop +800067f8: 00000013 nop +800067fc: 00000013 nop +80006800: 00000013 nop +80006804: 00000013 nop +80006808: 00000013 nop +8000680c: 00000013 nop +80006810: 00000013 nop +80006814: 00000013 nop +80006818: 00000013 nop +8000681c: 00000013 nop +80006820: 00000013 nop +80006824: 00000013 nop +80006828: 00000013 nop +8000682c: 00000013 nop +80006830: 00000013 nop +80006834: 00000013 nop +80006838: 00000013 nop +8000683c: 00000013 nop +80006840: 00000013 nop +80006844: 00000013 nop +80006848: 00000013 nop +8000684c: 00000013 nop +80006850: 00000013 nop +80006854: 00000013 nop +80006858: 00000013 nop +8000685c: 00000013 nop +80006860: 00000013 nop +80006864: 00000013 nop +80006868: 00000013 nop +8000686c: 00000013 nop +80006870: 00000013 nop +80006874: 00000013 nop +80006878: 00000013 nop +8000687c: 00000013 nop +80006880: 00000013 nop +80006884: 00000013 nop +80006888: 00000013 nop +8000688c: 00000013 nop +80006890: 00000013 nop +80006894: 00000013 nop +80006898: 00000013 nop +8000689c: 00000013 nop +800068a0: 00000013 nop +800068a4: 00000013 nop +800068a8: 00000013 nop +800068ac: 00000013 nop +800068b0: 00000013 nop +800068b4: 00000013 nop +800068b8: 00000013 nop +800068bc: 00000013 nop +800068c0: 00000013 nop +800068c4: 00000013 nop +800068c8: 00000013 nop +800068cc: 00000013 nop +800068d0: 00000013 nop +800068d4: 00000013 nop +800068d8: 00000013 nop +800068dc: 00000013 nop +800068e0: 00000013 nop +800068e4: 00000013 nop +800068e8: 00000013 nop +800068ec: 00000013 nop +800068f0: 00000013 nop +800068f4: 00000013 nop +800068f8: 00000013 nop +800068fc: 00000013 nop +80006900: 00000013 nop +80006904: 00000013 nop +80006908: 00000013 nop +8000690c: 00000013 nop +80006910: 00000013 nop +80006914: 00000013 nop +80006918: 00000013 nop +8000691c: 00000013 nop +80006920: 00000013 nop +80006924: 00000013 nop +80006928: 00000013 nop +8000692c: 00000013 nop +80006930: 00000013 nop +80006934: 00000013 nop +80006938: 00000013 nop +8000693c: 00000013 nop +80006940: 00000013 nop +80006944: 00000013 nop +80006948: 00000013 nop +8000694c: 00000013 nop +80006950: 00000013 nop +80006954: 00000013 nop +80006958: 00000013 nop +8000695c: 00000013 nop +80006960: 00000013 nop +80006964: 00000013 nop +80006968: 00000013 nop +8000696c: 00000013 nop +80006970: 00000013 nop +80006974: 00000013 nop +80006978: 00000013 nop +8000697c: 00000013 nop +80006980: 00000013 nop +80006984: 00000013 nop +80006988: 00000013 nop +8000698c: 00000013 nop +80006990: 00000013 nop +80006994: 00000013 nop +80006998: 00000013 nop +8000699c: 00000013 nop +800069a0: 00000013 nop +800069a4: 00000013 nop +800069a8: 00000013 nop +800069ac: 00000013 nop +800069b0: 00000013 nop +800069b4: 00000013 nop +800069b8: 00000013 nop +800069bc: 00000013 nop +800069c0: 00000013 nop +800069c4: 00000013 nop +800069c8: 00000013 nop +800069cc: 00000013 nop +800069d0: 00000013 nop +800069d4: 00000013 nop +800069d8: 00000013 nop +800069dc: 00000013 nop +800069e0: 00000013 nop +800069e4: 00000013 nop +800069e8: 00000013 nop +800069ec: 00000013 nop +800069f0: 00000013 nop +800069f4: 00000013 nop +800069f8: 00000013 nop +800069fc: 00000013 nop +80006a00: 00000013 nop +80006a04: 00000013 nop +80006a08: 00000013 nop +80006a0c: 00000013 nop +80006a10: 00000013 nop +80006a14: 00000013 nop +80006a18: 00000013 nop +80006a1c: 00000013 nop +80006a20: 00000013 nop +80006a24: 00000013 nop +80006a28: 00000013 nop +80006a2c: 00000013 nop +80006a30: 00000013 nop +80006a34: 00000013 nop +80006a38: 00000013 nop +80006a3c: 00000013 nop +80006a40: 00000013 nop +80006a44: 00000013 nop +80006a48: 00000013 nop +80006a4c: 00000013 nop +80006a50: 00000013 nop +80006a54: 00000013 nop +80006a58: 00000013 nop +80006a5c: 00000013 nop +80006a60: 00000013 nop +80006a64: 00000013 nop +80006a68: 00000013 nop +80006a6c: 00000013 nop +80006a70: 00000013 nop +80006a74: 00000013 nop +80006a78: 00000013 nop +80006a7c: 00000013 nop +80006a80: 00000013 nop +80006a84: 00000013 nop +80006a88: 00000013 nop +80006a8c: 00000013 nop +80006a90: 00000013 nop +80006a94: 00000013 nop +80006a98: 00000013 nop +80006a9c: 00000013 nop +80006aa0: 00000013 nop +80006aa4: 00000013 nop +80006aa8: 00000013 nop +80006aac: 00000013 nop +80006ab0: 00000013 nop +80006ab4: 00000013 nop +80006ab8: 00000013 nop +80006abc: 00000013 nop +80006ac0: 00000013 nop +80006ac4: 00000013 nop +80006ac8: 00000013 nop +80006acc: 00000013 nop +80006ad0: 00000013 nop +80006ad4: 00000013 nop +80006ad8: 00000013 nop +80006adc: 00000013 nop +80006ae0: 00000013 nop +80006ae4: 00000013 nop +80006ae8: 00000013 nop +80006aec: 00000013 nop +80006af0: 00000013 nop +80006af4: 00000013 nop +80006af8: 00000013 nop +80006afc: 00000013 nop +80006b00: 00000013 nop +80006b04: 00000013 nop +80006b08: 00000013 nop +80006b0c: 00000013 nop +80006b10: 00000013 nop +80006b14: 00000013 nop +80006b18: 00000013 nop +80006b1c: 00000013 nop +80006b20: 00000013 nop +80006b24: 00000013 nop +80006b28: 00000013 nop +80006b2c: 00000013 nop +80006b30: 00000013 nop +80006b34: 00000013 nop +80006b38: 00000013 nop +80006b3c: 00000013 nop +80006b40: 00000013 nop +80006b44: 00000013 nop +80006b48: 00000013 nop +80006b4c: 00000013 nop +80006b50: 00000013 nop +80006b54: 00000013 nop +80006b58: 00000013 nop +80006b5c: 00000013 nop +80006b60: 00000013 nop +80006b64: 00000013 nop +80006b68: 00000013 nop +80006b6c: 00000013 nop +80006b70: 00000013 nop +80006b74: 00000013 nop +80006b78: 00000013 nop +80006b7c: 00000013 nop +80006b80: 00000013 nop +80006b84: 00000013 nop +80006b88: 00000013 nop +80006b8c: 00000013 nop +80006b90: 00000013 nop +80006b94: 00000013 nop +80006b98: 00000013 nop +80006b9c: 00000013 nop +80006ba0: 00000013 nop +80006ba4: 00000013 nop +80006ba8: 00000013 nop +80006bac: 00000013 nop +80006bb0: 00000013 nop +80006bb4: 00000013 nop +80006bb8: 00000013 nop +80006bbc: 00000013 nop +80006bc0: 00000013 nop +80006bc4: 00000013 nop +80006bc8: 00000013 nop +80006bcc: 00000013 nop +80006bd0: 00000013 nop +80006bd4: 00000013 nop +80006bd8: 00000013 nop +80006bdc: 00000013 nop +80006be0: 00000013 nop +80006be4: 00000013 nop +80006be8: 00000013 nop +80006bec: 00000013 nop +80006bf0: 00000013 nop +80006bf4: 00000013 nop +80006bf8: 00000013 nop +80006bfc: 00000013 nop +80006c00: 00000013 nop +80006c04: 00000013 nop +80006c08: 00000013 nop +80006c0c: 00000013 nop +80006c10: 00000013 nop +80006c14: 00000013 nop +80006c18: 00000013 nop +80006c1c: 00000013 nop +80006c20: 00000013 nop +80006c24: 00000013 nop +80006c28: 00000013 nop +80006c2c: 00000013 nop +80006c30: 00000013 nop +80006c34: 00000013 nop +80006c38: 00000013 nop +80006c3c: 00000013 nop +80006c40: 00000013 nop +80006c44: 00000013 nop +80006c48: 00000013 nop +80006c4c: 00000013 nop +80006c50: 00000013 nop +80006c54: 00000013 nop +80006c58: 00000013 nop +80006c5c: 00000013 nop +80006c60: 00000013 nop +80006c64: 00000013 nop +80006c68: 00000013 nop +80006c6c: 00000013 nop +80006c70: 00000013 nop +80006c74: 00000013 nop +80006c78: 00000013 nop +80006c7c: 00000013 nop +80006c80: 00000013 nop +80006c84: 00000013 nop +80006c88: 00000013 nop +80006c8c: 00000013 nop +80006c90: 00000013 nop +80006c94: 00000013 nop +80006c98: 00000013 nop +80006c9c: 00000013 nop +80006ca0: 00000013 nop +80006ca4: 00000013 nop +80006ca8: 00000013 nop +80006cac: 00000013 nop +80006cb0: 00000013 nop +80006cb4: 00000013 nop +80006cb8: 00000013 nop +80006cbc: 00000013 nop +80006cc0: 00000013 nop +80006cc4: 00000013 nop +80006cc8: 00000013 nop +80006ccc: 00000013 nop +80006cd0: 00000013 nop +80006cd4: 00000013 nop +80006cd8: 00000013 nop +80006cdc: 00000013 nop +80006ce0: 00000013 nop +80006ce4: 00000013 nop +80006ce8: 00000013 nop +80006cec: 00000013 nop +80006cf0: 00000013 nop +80006cf4: 00000013 nop +80006cf8: 00000013 nop +80006cfc: 00000013 nop +80006d00: 00000013 nop +80006d04: 00000013 nop +80006d08: 00000013 nop +80006d0c: 00000013 nop +80006d10: 00000013 nop +80006d14: 00000013 nop +80006d18: 00000013 nop +80006d1c: 00000013 nop +80006d20: 00000013 nop +80006d24: 00000013 nop +80006d28: 00000013 nop +80006d2c: 00000013 nop +80006d30: 00000013 nop +80006d34: 00000013 nop +80006d38: 00000013 nop +80006d3c: 00000013 nop +80006d40: 00000013 nop +80006d44: 00000013 nop +80006d48: 00000013 nop +80006d4c: 00000013 nop +80006d50: 00000013 nop +80006d54: 00000013 nop +80006d58: 00000013 nop +80006d5c: 00000013 nop +80006d60: 00000013 nop +80006d64: 00000013 nop +80006d68: 00000013 nop +80006d6c: 00000013 nop +80006d70: 00000013 nop +80006d74: 00000013 nop +80006d78: 00000013 nop +80006d7c: 00000013 nop +80006d80: 00000013 nop +80006d84: 00000013 nop +80006d88: 00000013 nop +80006d8c: 00000013 nop +80006d90: 00000013 nop +80006d94: 00000013 nop +80006d98: 00000013 nop +80006d9c: 00000013 nop +80006da0: 00000013 nop +80006da4: 00000013 nop +80006da8: 00000013 nop +80006dac: 00000013 nop +80006db0: 00000013 nop +80006db4: 00000013 nop +80006db8: 00000013 nop +80006dbc: 00000013 nop +80006dc0: 00000013 nop +80006dc4: 00000013 nop +80006dc8: 00000013 nop +80006dcc: 00000013 nop +80006dd0: 00000013 nop +80006dd4: 00000013 nop +80006dd8: 00000013 nop +80006ddc: 00000013 nop +80006de0: 00000013 nop +80006de4: 00000013 nop +80006de8: 00000013 nop +80006dec: 00000013 nop +80006df0: 00000013 nop +80006df4: 00000013 nop +80006df8: 00000013 nop +80006dfc: 00000013 nop +80006e00: 00000013 nop +80006e04: 00000013 nop +80006e08: 00000013 nop +80006e0c: 00000013 nop +80006e10: 00000013 nop +80006e14: 00000013 nop +80006e18: 00000013 nop +80006e1c: 00000013 nop +80006e20: 00000013 nop +80006e24: 00000013 nop +80006e28: 00000013 nop +80006e2c: 00000013 nop +80006e30: 00000013 nop +80006e34: 00000013 nop +80006e38: 00000013 nop +80006e3c: 00000013 nop +80006e40: 00000013 nop +80006e44: 00000013 nop +80006e48: 00000013 nop +80006e4c: 00000013 nop +80006e50: 00000013 nop +80006e54: 00000013 nop +80006e58: 00000013 nop +80006e5c: 00000013 nop +80006e60: 00000013 nop +80006e64: 00000013 nop +80006e68: 00000013 nop +80006e6c: 00000013 nop +80006e70: 00000013 nop +80006e74: 00000013 nop +80006e78: 00000013 nop +80006e7c: 00000013 nop +80006e80: 00000013 nop +80006e84: 00000013 nop +80006e88: 00000013 nop +80006e8c: 00000013 nop +80006e90: 00000013 nop +80006e94: 00000013 nop +80006e98: 00000013 nop +80006e9c: 00000013 nop +80006ea0: 00000013 nop +80006ea4: 00000013 nop +80006ea8: 00000013 nop +80006eac: 00000013 nop +80006eb0: 00000013 nop +80006eb4: 00000013 nop +80006eb8: 00000013 nop +80006ebc: 00000013 nop +80006ec0: 00000013 nop +80006ec4: 00000013 nop +80006ec8: 00000013 nop +80006ecc: 00000013 nop +80006ed0: 00000013 nop +80006ed4: 00000013 nop +80006ed8: 00000013 nop +80006edc: 00000013 nop +80006ee0: 00000013 nop +80006ee4: 00000013 nop +80006ee8: 00000013 nop +80006eec: 00000013 nop +80006ef0: 00000013 nop +80006ef4: 00000013 nop +80006ef8: 00000013 nop +80006efc: 00000013 nop +80006f00: 00000013 nop +80006f04: 00000013 nop +80006f08: 00000013 nop +80006f0c: 00000013 nop +80006f10: 00000013 nop +80006f14: 00000013 nop +80006f18: 00000013 nop +80006f1c: 00000013 nop +80006f20: 00000013 nop +80006f24: 00000013 nop +80006f28: 00000013 nop +80006f2c: 00000013 nop +80006f30: 00000013 nop +80006f34: 00000013 nop +80006f38: 00000013 nop +80006f3c: 00000013 nop +80006f40: 00000013 nop +80006f44: 00000013 nop +80006f48: 00000013 nop +80006f4c: 00000013 nop +80006f50: 00000013 nop +80006f54: 00000013 nop +80006f58: 00000013 nop +80006f5c: 00000013 nop +80006f60: 00000013 nop +80006f64: 00000013 nop +80006f68: 00000013 nop +80006f6c: 00000013 nop +80006f70: 00000013 nop +80006f74: 00000013 nop +80006f78: 00000013 nop +80006f7c: 00000013 nop +80006f80: 00000013 nop +80006f84: 00000013 nop +80006f88: 00000013 nop +80006f8c: 00000013 nop +80006f90: 00000013 nop +80006f94: 00000013 nop +80006f98: 00000013 nop +80006f9c: 00000013 nop +80006fa0: 00000013 nop +80006fa4: 00000013 nop +80006fa8: 00000013 nop +80006fac: 00000013 nop +80006fb0: 00000013 nop +80006fb4: 00000013 nop +80006fb8: 00000013 nop +80006fbc: 00000013 nop +80006fc0: 00000013 nop +80006fc4: 00000013 nop +80006fc8: 00000013 nop +80006fcc: 00000013 nop +80006fd0: 00000013 nop +80006fd4: 00000013 nop +80006fd8: 00000013 nop +80006fdc: 00000013 nop +80006fe0: 00000013 nop +80006fe4: 00000013 nop +80006fe8: 00000013 nop +80006fec: 00000013 nop +80006ff0: 00000013 nop +80006ff4: 00000013 nop +80006ff8: 00000013 nop +80006ffc: 00000013 nop + +80007000 : +80007000: 2120 fld fs0,64(a0) +80007002: 2322 fld ft6,8(sp) +80007004: 2524 fld fs1,72(a0) +80007006: 2726 fld fa4,72(sp) +80007008: 2928 fld fa0,80(a0) +8000700a: 2b2a fld fs6,136(sp) +8000700c: 2d2c fld fa1,88(a0) +8000700e: 2f2e fld ft10,200(sp) +80007010: 00000013 nop +80007014: 00000013 nop +80007018: 00000013 nop +8000701c: 00000013 nop +80007020: 00000013 nop +80007024: 00000013 nop +80007028: 00000013 nop +8000702c: 00000013 nop +80007030: 00000013 nop +80007034: 00000013 nop +80007038: 00000013 nop +8000703c: 00000013 nop +80007040: 00000013 nop +80007044: 00000013 nop +80007048: 00000013 nop +8000704c: 00000013 nop +80007050: 00000013 nop +80007054: 00000013 nop +80007058: 00000013 nop +8000705c: 00000013 nop +80007060: 00000013 nop +80007064: 00000013 nop +80007068: 00000013 nop +8000706c: 00000013 nop +80007070: 00000013 nop +80007074: 00000013 nop +80007078: 00000013 nop +8000707c: 00000013 nop +80007080: 00000013 nop +80007084: 00000013 nop +80007088: 00000013 nop +8000708c: 00000013 nop +80007090: 00000013 nop +80007094: 00000013 nop +80007098: 00000013 nop +8000709c: 00000013 nop +800070a0: 00000013 nop +800070a4: 00000013 nop +800070a8: 00000013 nop +800070ac: 00000013 nop +800070b0: 00000013 nop +800070b4: 00000013 nop +800070b8: 00000013 nop +800070bc: 00000013 nop +800070c0: 00000013 nop +800070c4: 00000013 nop +800070c8: 00000013 nop +800070cc: 00000013 nop +800070d0: 00000013 nop +800070d4: 00000013 nop +800070d8: 00000013 nop +800070dc: 00000013 nop +800070e0: 00000013 nop +800070e4: 00000013 nop +800070e8: 00000013 nop +800070ec: 00000013 nop +800070f0: 00000013 nop +800070f4: 00000013 nop +800070f8: 00000013 nop +800070fc: 00000013 nop +80007100: 00000013 nop +80007104: 00000013 nop +80007108: 00000013 nop +8000710c: 00000013 nop +80007110: 00000013 nop +80007114: 00000013 nop +80007118: 00000013 nop +8000711c: 00000013 nop +80007120: 00000013 nop +80007124: 00000013 nop +80007128: 00000013 nop +8000712c: 00000013 nop +80007130: 00000013 nop +80007134: 00000013 nop +80007138: 00000013 nop +8000713c: 00000013 nop +80007140: 00000013 nop +80007144: 00000013 nop +80007148: 00000013 nop +8000714c: 00000013 nop +80007150: 00000013 nop +80007154: 00000013 nop +80007158: 00000013 nop +8000715c: 00000013 nop +80007160: 00000013 nop +80007164: 00000013 nop +80007168: 00000013 nop +8000716c: 00000013 nop +80007170: 00000013 nop +80007174: 00000013 nop +80007178: 00000013 nop +8000717c: 00000013 nop +80007180: 00000013 nop +80007184: 00000013 nop +80007188: 00000013 nop +8000718c: 00000013 nop +80007190: 00000013 nop +80007194: 00000013 nop +80007198: 00000013 nop +8000719c: 00000013 nop +800071a0: 00000013 nop +800071a4: 00000013 nop +800071a8: 00000013 nop +800071ac: 00000013 nop +800071b0: 00000013 nop +800071b4: 00000013 nop +800071b8: 00000013 nop +800071bc: 00000013 nop +800071c0: 00000013 nop +800071c4: 00000013 nop +800071c8: 00000013 nop +800071cc: 00000013 nop +800071d0: 00000013 nop +800071d4: 00000013 nop +800071d8: 00000013 nop +800071dc: 00000013 nop +800071e0: 00000013 nop +800071e4: 00000013 nop +800071e8: 00000013 nop +800071ec: 00000013 nop +800071f0: 00000013 nop +800071f4: 00000013 nop +800071f8: 00000013 nop +800071fc: 00000013 nop +80007200: 00000013 nop +80007204: 00000013 nop +80007208: 00000013 nop +8000720c: 00000013 nop +80007210: 00000013 nop +80007214: 00000013 nop +80007218: 00000013 nop +8000721c: 00000013 nop +80007220: 00000013 nop +80007224: 00000013 nop +80007228: 00000013 nop +8000722c: 00000013 nop +80007230: 00000013 nop +80007234: 00000013 nop +80007238: 00000013 nop +8000723c: 00000013 nop +80007240: 00000013 nop +80007244: 00000013 nop +80007248: 00000013 nop +8000724c: 00000013 nop +80007250: 00000013 nop +80007254: 00000013 nop +80007258: 00000013 nop +8000725c: 00000013 nop +80007260: 00000013 nop +80007264: 00000013 nop +80007268: 00000013 nop +8000726c: 00000013 nop +80007270: 00000013 nop +80007274: 00000013 nop +80007278: 00000013 nop +8000727c: 00000013 nop +80007280: 00000013 nop +80007284: 00000013 nop +80007288: 00000013 nop +8000728c: 00000013 nop +80007290: 00000013 nop +80007294: 00000013 nop +80007298: 00000013 nop +8000729c: 00000013 nop +800072a0: 00000013 nop +800072a4: 00000013 nop +800072a8: 00000013 nop +800072ac: 00000013 nop +800072b0: 00000013 nop +800072b4: 00000013 nop +800072b8: 00000013 nop +800072bc: 00000013 nop +800072c0: 00000013 nop +800072c4: 00000013 nop +800072c8: 00000013 nop +800072cc: 00000013 nop +800072d0: 00000013 nop +800072d4: 00000013 nop +800072d8: 00000013 nop +800072dc: 00000013 nop +800072e0: 00000013 nop +800072e4: 00000013 nop +800072e8: 00000013 nop +800072ec: 00000013 nop +800072f0: 00000013 nop +800072f4: 00000013 nop +800072f8: 00000013 nop +800072fc: 00000013 nop +80007300: 00000013 nop +80007304: 00000013 nop +80007308: 00000013 nop +8000730c: 00000013 nop +80007310: 00000013 nop +80007314: 00000013 nop +80007318: 00000013 nop +8000731c: 00000013 nop +80007320: 00000013 nop +80007324: 00000013 nop +80007328: 00000013 nop +8000732c: 00000013 nop +80007330: 00000013 nop +80007334: 00000013 nop +80007338: 00000013 nop +8000733c: 00000013 nop +80007340: 00000013 nop +80007344: 00000013 nop +80007348: 00000013 nop +8000734c: 00000013 nop +80007350: 00000013 nop +80007354: 00000013 nop +80007358: 00000013 nop +8000735c: 00000013 nop +80007360: 00000013 nop +80007364: 00000013 nop +80007368: 00000013 nop +8000736c: 00000013 nop +80007370: 00000013 nop +80007374: 00000013 nop +80007378: 00000013 nop +8000737c: 00000013 nop +80007380: 00000013 nop +80007384: 00000013 nop +80007388: 00000013 nop +8000738c: 00000013 nop +80007390: 00000013 nop +80007394: 00000013 nop +80007398: 00000013 nop +8000739c: 00000013 nop +800073a0: 00000013 nop +800073a4: 00000013 nop +800073a8: 00000013 nop +800073ac: 00000013 nop +800073b0: 00000013 nop +800073b4: 00000013 nop +800073b8: 00000013 nop +800073bc: 00000013 nop +800073c0: 00000013 nop +800073c4: 00000013 nop +800073c8: 00000013 nop +800073cc: 00000013 nop +800073d0: 00000013 nop +800073d4: 00000013 nop +800073d8: 00000013 nop +800073dc: 00000013 nop +800073e0: 00000013 nop +800073e4: 00000013 nop +800073e8: 00000013 nop +800073ec: 00000013 nop +800073f0: 00000013 nop +800073f4: 00000013 nop +800073f8: 00000013 nop +800073fc: 00000013 nop +80007400: 00000013 nop +80007404: 00000013 nop +80007408: 00000013 nop +8000740c: 00000013 nop +80007410: 00000013 nop +80007414: 00000013 nop +80007418: 00000013 nop +8000741c: 00000013 nop +80007420: 00000013 nop +80007424: 00000013 nop +80007428: 00000013 nop +8000742c: 00000013 nop +80007430: 00000013 nop +80007434: 00000013 nop +80007438: 00000013 nop +8000743c: 00000013 nop +80007440: 00000013 nop +80007444: 00000013 nop +80007448: 00000013 nop +8000744c: 00000013 nop +80007450: 00000013 nop +80007454: 00000013 nop +80007458: 00000013 nop +8000745c: 00000013 nop +80007460: 00000013 nop +80007464: 00000013 nop +80007468: 00000013 nop +8000746c: 00000013 nop +80007470: 00000013 nop +80007474: 00000013 nop +80007478: 00000013 nop +8000747c: 00000013 nop +80007480: 00000013 nop +80007484: 00000013 nop +80007488: 00000013 nop +8000748c: 00000013 nop +80007490: 00000013 nop +80007494: 00000013 nop +80007498: 00000013 nop +8000749c: 00000013 nop +800074a0: 00000013 nop +800074a4: 00000013 nop +800074a8: 00000013 nop +800074ac: 00000013 nop +800074b0: 00000013 nop +800074b4: 00000013 nop +800074b8: 00000013 nop +800074bc: 00000013 nop +800074c0: 00000013 nop +800074c4: 00000013 nop +800074c8: 00000013 nop +800074cc: 00000013 nop +800074d0: 00000013 nop +800074d4: 00000013 nop +800074d8: 00000013 nop +800074dc: 00000013 nop +800074e0: 00000013 nop +800074e4: 00000013 nop +800074e8: 00000013 nop +800074ec: 00000013 nop +800074f0: 00000013 nop +800074f4: 00000013 nop +800074f8: 00000013 nop +800074fc: 00000013 nop +80007500: 00000013 nop +80007504: 00000013 nop +80007508: 00000013 nop +8000750c: 00000013 nop +80007510: 00000013 nop +80007514: 00000013 nop +80007518: 00000013 nop +8000751c: 00000013 nop +80007520: 00000013 nop +80007524: 00000013 nop +80007528: 00000013 nop +8000752c: 00000013 nop +80007530: 00000013 nop +80007534: 00000013 nop +80007538: 00000013 nop +8000753c: 00000013 nop +80007540: 00000013 nop +80007544: 00000013 nop +80007548: 00000013 nop +8000754c: 00000013 nop +80007550: 00000013 nop +80007554: 00000013 nop +80007558: 00000013 nop +8000755c: 00000013 nop +80007560: 00000013 nop +80007564: 00000013 nop +80007568: 00000013 nop +8000756c: 00000013 nop +80007570: 00000013 nop +80007574: 00000013 nop +80007578: 00000013 nop +8000757c: 00000013 nop +80007580: 00000013 nop +80007584: 00000013 nop +80007588: 00000013 nop +8000758c: 00000013 nop +80007590: 00000013 nop +80007594: 00000013 nop +80007598: 00000013 nop +8000759c: 00000013 nop +800075a0: 00000013 nop +800075a4: 00000013 nop +800075a8: 00000013 nop +800075ac: 00000013 nop +800075b0: 00000013 nop +800075b4: 00000013 nop +800075b8: 00000013 nop +800075bc: 00000013 nop +800075c0: 00000013 nop +800075c4: 00000013 nop +800075c8: 00000013 nop +800075cc: 00000013 nop +800075d0: 00000013 nop +800075d4: 00000013 nop +800075d8: 00000013 nop +800075dc: 00000013 nop +800075e0: 00000013 nop +800075e4: 00000013 nop +800075e8: 00000013 nop +800075ec: 00000013 nop +800075f0: 00000013 nop +800075f4: 00000013 nop +800075f8: 00000013 nop +800075fc: 00000013 nop +80007600: 00000013 nop +80007604: 00000013 nop +80007608: 00000013 nop +8000760c: 00000013 nop +80007610: 00000013 nop +80007614: 00000013 nop +80007618: 00000013 nop +8000761c: 00000013 nop +80007620: 00000013 nop +80007624: 00000013 nop +80007628: 00000013 nop +8000762c: 00000013 nop +80007630: 00000013 nop +80007634: 00000013 nop +80007638: 00000013 nop +8000763c: 00000013 nop +80007640: 00000013 nop +80007644: 00000013 nop +80007648: 00000013 nop +8000764c: 00000013 nop +80007650: 00000013 nop +80007654: 00000013 nop +80007658: 00000013 nop +8000765c: 00000013 nop +80007660: 00000013 nop +80007664: 00000013 nop +80007668: 00000013 nop +8000766c: 00000013 nop +80007670: 00000013 nop +80007674: 00000013 nop +80007678: 00000013 nop +8000767c: 00000013 nop +80007680: 00000013 nop +80007684: 00000013 nop +80007688: 00000013 nop +8000768c: 00000013 nop +80007690: 00000013 nop +80007694: 00000013 nop +80007698: 00000013 nop +8000769c: 00000013 nop +800076a0: 00000013 nop +800076a4: 00000013 nop +800076a8: 00000013 nop +800076ac: 00000013 nop +800076b0: 00000013 nop +800076b4: 00000013 nop +800076b8: 00000013 nop +800076bc: 00000013 nop +800076c0: 00000013 nop +800076c4: 00000013 nop +800076c8: 00000013 nop +800076cc: 00000013 nop +800076d0: 00000013 nop +800076d4: 00000013 nop +800076d8: 00000013 nop +800076dc: 00000013 nop +800076e0: 00000013 nop +800076e4: 00000013 nop +800076e8: 00000013 nop +800076ec: 00000013 nop +800076f0: 00000013 nop +800076f4: 00000013 nop +800076f8: 00000013 nop +800076fc: 00000013 nop +80007700: 00000013 nop +80007704: 00000013 nop +80007708: 00000013 nop +8000770c: 00000013 nop +80007710: 00000013 nop +80007714: 00000013 nop +80007718: 00000013 nop +8000771c: 00000013 nop +80007720: 00000013 nop +80007724: 00000013 nop +80007728: 00000013 nop +8000772c: 00000013 nop +80007730: 00000013 nop +80007734: 00000013 nop +80007738: 00000013 nop +8000773c: 00000013 nop +80007740: 00000013 nop +80007744: 00000013 nop +80007748: 00000013 nop +8000774c: 00000013 nop +80007750: 00000013 nop +80007754: 00000013 nop +80007758: 00000013 nop +8000775c: 00000013 nop +80007760: 00000013 nop +80007764: 00000013 nop +80007768: 00000013 nop +8000776c: 00000013 nop +80007770: 00000013 nop +80007774: 00000013 nop +80007778: 00000013 nop +8000777c: 00000013 nop +80007780: 00000013 nop +80007784: 00000013 nop +80007788: 00000013 nop +8000778c: 00000013 nop +80007790: 00000013 nop +80007794: 00000013 nop +80007798: 00000013 nop +8000779c: 00000013 nop +800077a0: 00000013 nop +800077a4: 00000013 nop +800077a8: 00000013 nop +800077ac: 00000013 nop +800077b0: 00000013 nop +800077b4: 00000013 nop +800077b8: 00000013 nop +800077bc: 00000013 nop +800077c0: 00000013 nop +800077c4: 00000013 nop +800077c8: 00000013 nop +800077cc: 00000013 nop +800077d0: 00000013 nop +800077d4: 00000013 nop +800077d8: 00000013 nop +800077dc: 00000013 nop +800077e0: 00000013 nop +800077e4: 00000013 nop +800077e8: 00000013 nop +800077ec: 00000013 nop +800077f0: 00000013 nop +800077f4: 00000013 nop +800077f8: 00000013 nop +800077fc: 00000013 nop +80007800: 00000013 nop +80007804: 00000013 nop +80007808: 00000013 nop +8000780c: 00000013 nop +80007810: 00000013 nop +80007814: 00000013 nop +80007818: 00000013 nop +8000781c: 00000013 nop +80007820: 00000013 nop +80007824: 00000013 nop +80007828: 00000013 nop +8000782c: 00000013 nop +80007830: 00000013 nop +80007834: 00000013 nop +80007838: 00000013 nop +8000783c: 00000013 nop +80007840: 00000013 nop +80007844: 00000013 nop +80007848: 00000013 nop +8000784c: 00000013 nop +80007850: 00000013 nop +80007854: 00000013 nop +80007858: 00000013 nop +8000785c: 00000013 nop +80007860: 00000013 nop +80007864: 00000013 nop +80007868: 00000013 nop +8000786c: 00000013 nop +80007870: 00000013 nop +80007874: 00000013 nop +80007878: 00000013 nop +8000787c: 00000013 nop +80007880: 00000013 nop +80007884: 00000013 nop +80007888: 00000013 nop +8000788c: 00000013 nop +80007890: 00000013 nop +80007894: 00000013 nop +80007898: 00000013 nop +8000789c: 00000013 nop +800078a0: 00000013 nop +800078a4: 00000013 nop +800078a8: 00000013 nop +800078ac: 00000013 nop +800078b0: 00000013 nop +800078b4: 00000013 nop +800078b8: 00000013 nop +800078bc: 00000013 nop +800078c0: 00000013 nop +800078c4: 00000013 nop +800078c8: 00000013 nop +800078cc: 00000013 nop +800078d0: 00000013 nop +800078d4: 00000013 nop +800078d8: 00000013 nop +800078dc: 00000013 nop +800078e0: 00000013 nop +800078e4: 00000013 nop +800078e8: 00000013 nop +800078ec: 00000013 nop +800078f0: 00000013 nop +800078f4: 00000013 nop +800078f8: 00000013 nop +800078fc: 00000013 nop +80007900: 00000013 nop +80007904: 00000013 nop +80007908: 00000013 nop +8000790c: 00000013 nop +80007910: 00000013 nop +80007914: 00000013 nop +80007918: 00000013 nop +8000791c: 00000013 nop +80007920: 00000013 nop +80007924: 00000013 nop +80007928: 00000013 nop +8000792c: 00000013 nop +80007930: 00000013 nop +80007934: 00000013 nop +80007938: 00000013 nop +8000793c: 00000013 nop +80007940: 00000013 nop +80007944: 00000013 nop +80007948: 00000013 nop +8000794c: 00000013 nop +80007950: 00000013 nop +80007954: 00000013 nop +80007958: 00000013 nop +8000795c: 00000013 nop +80007960: 00000013 nop +80007964: 00000013 nop +80007968: 00000013 nop +8000796c: 00000013 nop +80007970: 00000013 nop +80007974: 00000013 nop +80007978: 00000013 nop +8000797c: 00000013 nop +80007980: 00000013 nop +80007984: 00000013 nop +80007988: 00000013 nop +8000798c: 00000013 nop +80007990: 00000013 nop +80007994: 00000013 nop +80007998: 00000013 nop +8000799c: 00000013 nop +800079a0: 00000013 nop +800079a4: 00000013 nop +800079a8: 00000013 nop +800079ac: 00000013 nop +800079b0: 00000013 nop +800079b4: 00000013 nop +800079b8: 00000013 nop +800079bc: 00000013 nop +800079c0: 00000013 nop +800079c4: 00000013 nop +800079c8: 00000013 nop +800079cc: 00000013 nop +800079d0: 00000013 nop +800079d4: 00000013 nop +800079d8: 00000013 nop +800079dc: 00000013 nop +800079e0: 00000013 nop +800079e4: 00000013 nop +800079e8: 00000013 nop +800079ec: 00000013 nop +800079f0: 00000013 nop +800079f4: 00000013 nop +800079f8: 00000013 nop +800079fc: 00000013 nop +80007a00: 00000013 nop +80007a04: 00000013 nop +80007a08: 00000013 nop +80007a0c: 00000013 nop +80007a10: 00000013 nop +80007a14: 00000013 nop +80007a18: 00000013 nop +80007a1c: 00000013 nop +80007a20: 00000013 nop +80007a24: 00000013 nop +80007a28: 00000013 nop +80007a2c: 00000013 nop +80007a30: 00000013 nop +80007a34: 00000013 nop +80007a38: 00000013 nop +80007a3c: 00000013 nop +80007a40: 00000013 nop +80007a44: 00000013 nop +80007a48: 00000013 nop +80007a4c: 00000013 nop +80007a50: 00000013 nop +80007a54: 00000013 nop +80007a58: 00000013 nop +80007a5c: 00000013 nop +80007a60: 00000013 nop +80007a64: 00000013 nop +80007a68: 00000013 nop +80007a6c: 00000013 nop +80007a70: 00000013 nop +80007a74: 00000013 nop +80007a78: 00000013 nop +80007a7c: 00000013 nop +80007a80: 00000013 nop +80007a84: 00000013 nop +80007a88: 00000013 nop +80007a8c: 00000013 nop +80007a90: 00000013 nop +80007a94: 00000013 nop +80007a98: 00000013 nop +80007a9c: 00000013 nop +80007aa0: 00000013 nop +80007aa4: 00000013 nop +80007aa8: 00000013 nop +80007aac: 00000013 nop +80007ab0: 00000013 nop +80007ab4: 00000013 nop +80007ab8: 00000013 nop +80007abc: 00000013 nop +80007ac0: 00000013 nop +80007ac4: 00000013 nop +80007ac8: 00000013 nop +80007acc: 00000013 nop +80007ad0: 00000013 nop +80007ad4: 00000013 nop +80007ad8: 00000013 nop +80007adc: 00000013 nop +80007ae0: 00000013 nop +80007ae4: 00000013 nop +80007ae8: 00000013 nop +80007aec: 00000013 nop +80007af0: 00000013 nop +80007af4: 00000013 nop +80007af8: 00000013 nop +80007afc: 00000013 nop +80007b00: 00000013 nop +80007b04: 00000013 nop +80007b08: 00000013 nop +80007b0c: 00000013 nop +80007b10: 00000013 nop +80007b14: 00000013 nop +80007b18: 00000013 nop +80007b1c: 00000013 nop +80007b20: 00000013 nop +80007b24: 00000013 nop +80007b28: 00000013 nop +80007b2c: 00000013 nop +80007b30: 00000013 nop +80007b34: 00000013 nop +80007b38: 00000013 nop +80007b3c: 00000013 nop +80007b40: 00000013 nop +80007b44: 00000013 nop +80007b48: 00000013 nop +80007b4c: 00000013 nop +80007b50: 00000013 nop +80007b54: 00000013 nop +80007b58: 00000013 nop +80007b5c: 00000013 nop +80007b60: 00000013 nop +80007b64: 00000013 nop +80007b68: 00000013 nop +80007b6c: 00000013 nop +80007b70: 00000013 nop +80007b74: 00000013 nop +80007b78: 00000013 nop +80007b7c: 00000013 nop +80007b80: 00000013 nop +80007b84: 00000013 nop +80007b88: 00000013 nop +80007b8c: 00000013 nop +80007b90: 00000013 nop +80007b94: 00000013 nop +80007b98: 00000013 nop +80007b9c: 00000013 nop +80007ba0: 00000013 nop +80007ba4: 00000013 nop +80007ba8: 00000013 nop +80007bac: 00000013 nop +80007bb0: 00000013 nop +80007bb4: 00000013 nop +80007bb8: 00000013 nop +80007bbc: 00000013 nop +80007bc0: 00000013 nop +80007bc4: 00000013 nop +80007bc8: 00000013 nop +80007bcc: 00000013 nop +80007bd0: 00000013 nop +80007bd4: 00000013 nop +80007bd8: 00000013 nop +80007bdc: 00000013 nop +80007be0: 00000013 nop +80007be4: 00000013 nop +80007be8: 00000013 nop +80007bec: 00000013 nop +80007bf0: 00000013 nop +80007bf4: 00000013 nop +80007bf8: 00000013 nop +80007bfc: 00000013 nop +80007c00: 00000013 nop +80007c04: 00000013 nop +80007c08: 00000013 nop +80007c0c: 00000013 nop +80007c10: 00000013 nop +80007c14: 00000013 nop +80007c18: 00000013 nop +80007c1c: 00000013 nop +80007c20: 00000013 nop +80007c24: 00000013 nop +80007c28: 00000013 nop +80007c2c: 00000013 nop +80007c30: 00000013 nop +80007c34: 00000013 nop +80007c38: 00000013 nop +80007c3c: 00000013 nop +80007c40: 00000013 nop +80007c44: 00000013 nop +80007c48: 00000013 nop +80007c4c: 00000013 nop +80007c50: 00000013 nop +80007c54: 00000013 nop +80007c58: 00000013 nop +80007c5c: 00000013 nop +80007c60: 00000013 nop +80007c64: 00000013 nop +80007c68: 00000013 nop +80007c6c: 00000013 nop +80007c70: 00000013 nop +80007c74: 00000013 nop +80007c78: 00000013 nop +80007c7c: 00000013 nop +80007c80: 00000013 nop +80007c84: 00000013 nop +80007c88: 00000013 nop +80007c8c: 00000013 nop +80007c90: 00000013 nop +80007c94: 00000013 nop +80007c98: 00000013 nop +80007c9c: 00000013 nop +80007ca0: 00000013 nop +80007ca4: 00000013 nop +80007ca8: 00000013 nop +80007cac: 00000013 nop +80007cb0: 00000013 nop +80007cb4: 00000013 nop +80007cb8: 00000013 nop +80007cbc: 00000013 nop +80007cc0: 00000013 nop +80007cc4: 00000013 nop +80007cc8: 00000013 nop +80007ccc: 00000013 nop +80007cd0: 00000013 nop +80007cd4: 00000013 nop +80007cd8: 00000013 nop +80007cdc: 00000013 nop +80007ce0: 00000013 nop +80007ce4: 00000013 nop +80007ce8: 00000013 nop +80007cec: 00000013 nop +80007cf0: 00000013 nop +80007cf4: 00000013 nop +80007cf8: 00000013 nop +80007cfc: 00000013 nop +80007d00: 00000013 nop +80007d04: 00000013 nop +80007d08: 00000013 nop +80007d0c: 00000013 nop +80007d10: 00000013 nop +80007d14: 00000013 nop +80007d18: 00000013 nop +80007d1c: 00000013 nop +80007d20: 00000013 nop +80007d24: 00000013 nop +80007d28: 00000013 nop +80007d2c: 00000013 nop +80007d30: 00000013 nop +80007d34: 00000013 nop +80007d38: 00000013 nop +80007d3c: 00000013 nop +80007d40: 00000013 nop +80007d44: 00000013 nop +80007d48: 00000013 nop +80007d4c: 00000013 nop +80007d50: 00000013 nop +80007d54: 00000013 nop +80007d58: 00000013 nop +80007d5c: 00000013 nop +80007d60: 00000013 nop +80007d64: 00000013 nop +80007d68: 00000013 nop +80007d6c: 00000013 nop +80007d70: 00000013 nop +80007d74: 00000013 nop +80007d78: 00000013 nop +80007d7c: 00000013 nop +80007d80: 00000013 nop +80007d84: 00000013 nop +80007d88: 00000013 nop +80007d8c: 00000013 nop +80007d90: 00000013 nop +80007d94: 00000013 nop +80007d98: 00000013 nop +80007d9c: 00000013 nop +80007da0: 00000013 nop +80007da4: 00000013 nop +80007da8: 00000013 nop +80007dac: 00000013 nop +80007db0: 00000013 nop +80007db4: 00000013 nop +80007db8: 00000013 nop +80007dbc: 00000013 nop +80007dc0: 00000013 nop +80007dc4: 00000013 nop +80007dc8: 00000013 nop +80007dcc: 00000013 nop +80007dd0: 00000013 nop +80007dd4: 00000013 nop +80007dd8: 00000013 nop +80007ddc: 00000013 nop +80007de0: 00000013 nop +80007de4: 00000013 nop +80007de8: 00000013 nop +80007dec: 00000013 nop +80007df0: 00000013 nop +80007df4: 00000013 nop +80007df8: 00000013 nop +80007dfc: 00000013 nop +80007e00: 00000013 nop +80007e04: 00000013 nop +80007e08: 00000013 nop +80007e0c: 00000013 nop +80007e10: 00000013 nop +80007e14: 00000013 nop +80007e18: 00000013 nop +80007e1c: 00000013 nop +80007e20: 00000013 nop +80007e24: 00000013 nop +80007e28: 00000013 nop +80007e2c: 00000013 nop +80007e30: 00000013 nop +80007e34: 00000013 nop +80007e38: 00000013 nop +80007e3c: 00000013 nop +80007e40: 00000013 nop +80007e44: 00000013 nop +80007e48: 00000013 nop +80007e4c: 00000013 nop +80007e50: 00000013 nop +80007e54: 00000013 nop +80007e58: 00000013 nop +80007e5c: 00000013 nop +80007e60: 00000013 nop +80007e64: 00000013 nop +80007e68: 00000013 nop +80007e6c: 00000013 nop +80007e70: 00000013 nop +80007e74: 00000013 nop +80007e78: 00000013 nop +80007e7c: 00000013 nop +80007e80: 00000013 nop +80007e84: 00000013 nop +80007e88: 00000013 nop +80007e8c: 00000013 nop +80007e90: 00000013 nop +80007e94: 00000013 nop +80007e98: 00000013 nop +80007e9c: 00000013 nop +80007ea0: 00000013 nop +80007ea4: 00000013 nop +80007ea8: 00000013 nop +80007eac: 00000013 nop +80007eb0: 00000013 nop +80007eb4: 00000013 nop +80007eb8: 00000013 nop +80007ebc: 00000013 nop +80007ec0: 00000013 nop +80007ec4: 00000013 nop +80007ec8: 00000013 nop +80007ecc: 00000013 nop +80007ed0: 00000013 nop +80007ed4: 00000013 nop +80007ed8: 00000013 nop +80007edc: 00000013 nop +80007ee0: 00000013 nop +80007ee4: 00000013 nop +80007ee8: 00000013 nop +80007eec: 00000013 nop +80007ef0: 00000013 nop +80007ef4: 00000013 nop +80007ef8: 00000013 nop +80007efc: 00000013 nop +80007f00: 00000013 nop +80007f04: 00000013 nop +80007f08: 00000013 nop +80007f0c: 00000013 nop +80007f10: 00000013 nop +80007f14: 00000013 nop +80007f18: 00000013 nop +80007f1c: 00000013 nop +80007f20: 00000013 nop +80007f24: 00000013 nop +80007f28: 00000013 nop +80007f2c: 00000013 nop +80007f30: 00000013 nop +80007f34: 00000013 nop +80007f38: 00000013 nop +80007f3c: 00000013 nop +80007f40: 00000013 nop +80007f44: 00000013 nop +80007f48: 00000013 nop +80007f4c: 00000013 nop +80007f50: 00000013 nop +80007f54: 00000013 nop +80007f58: 00000013 nop +80007f5c: 00000013 nop +80007f60: 00000013 nop +80007f64: 00000013 nop +80007f68: 00000013 nop +80007f6c: 00000013 nop +80007f70: 00000013 nop +80007f74: 00000013 nop +80007f78: 00000013 nop +80007f7c: 00000013 nop +80007f80: 00000013 nop +80007f84: 00000013 nop +80007f88: 00000013 nop +80007f8c: 00000013 nop +80007f90: 00000013 nop +80007f94: 00000013 nop +80007f98: 00000013 nop +80007f9c: 00000013 nop +80007fa0: 00000013 nop +80007fa4: 00000013 nop +80007fa8: 00000013 nop +80007fac: 00000013 nop +80007fb0: 00000013 nop +80007fb4: 00000013 nop +80007fb8: 00000013 nop +80007fbc: 00000013 nop +80007fc0: 00000013 nop +80007fc4: 00000013 nop +80007fc8: 00000013 nop +80007fcc: 00000013 nop +80007fd0: 00000013 nop +80007fd4: 00000013 nop +80007fd8: 00000013 nop +80007fdc: 00000013 nop +80007fe0: 00000013 nop +80007fe4: 00000013 nop +80007fe8: 00000013 nop +80007fec: 00000013 nop +80007ff0: 00000013 nop +80007ff4: 00000013 nop +80007ff8: 00000013 nop +80007ffc: 00000013 nop + +80008000 : +80008000: 3130 fld fa2,96(a0) +80008002: 3332 fld ft6,296(sp) +80008004: 3534 fld fa3,104(a0) +80008006: 3736 fld fa4,360(sp) +80008008: 3938 fld fa4,112(a0) +8000800a: 3b3a fld fs6,424(sp) +8000800c: 3d3c fld fa5,120(a0) +8000800e: 3f3e fld ft10,488(sp) +80008010: 00000013 nop +80008014: 00000013 nop +80008018: 00000013 nop +8000801c: 00000013 nop +80008020: 00000013 nop +80008024: 00000013 nop +80008028: 00000013 nop +8000802c: 00000013 nop +80008030: 00000013 nop +80008034: 00000013 nop +80008038: 00000013 nop +8000803c: 00000013 nop +80008040: 00000013 nop +80008044: 00000013 nop +80008048: 00000013 nop +8000804c: 00000013 nop +80008050: 00000013 nop +80008054: 00000013 nop +80008058: 00000013 nop +8000805c: 00000013 nop +80008060: 00000013 nop +80008064: 00000013 nop +80008068: 00000013 nop +8000806c: 00000013 nop +80008070: 00000013 nop +80008074: 00000013 nop +80008078: 00000013 nop +8000807c: 00000013 nop +80008080: 00000013 nop +80008084: 00000013 nop +80008088: 00000013 nop +8000808c: 00000013 nop +80008090: 00000013 nop +80008094: 00000013 nop +80008098: 00000013 nop +8000809c: 00000013 nop +800080a0: 00000013 nop +800080a4: 00000013 nop +800080a8: 00000013 nop +800080ac: 00000013 nop +800080b0: 00000013 nop +800080b4: 00000013 nop +800080b8: 00000013 nop +800080bc: 00000013 nop +800080c0: 00000013 nop +800080c4: 00000013 nop +800080c8: 00000013 nop +800080cc: 00000013 nop +800080d0: 00000013 nop +800080d4: 00000013 nop +800080d8: 00000013 nop +800080dc: 00000013 nop +800080e0: 00000013 nop +800080e4: 00000013 nop +800080e8: 00000013 nop +800080ec: 00000013 nop +800080f0: 00000013 nop +800080f4: 00000013 nop +800080f8: 00000013 nop +800080fc: 00000013 nop +80008100: 00000013 nop +80008104: 00000013 nop +80008108: 00000013 nop +8000810c: 00000013 nop +80008110: 00000013 nop +80008114: 00000013 nop +80008118: 00000013 nop +8000811c: 00000013 nop +80008120: 00000013 nop +80008124: 00000013 nop +80008128: 00000013 nop +8000812c: 00000013 nop +80008130: 00000013 nop +80008134: 00000013 nop +80008138: 00000013 nop +8000813c: 00000013 nop +80008140: 00000013 nop +80008144: 00000013 nop +80008148: 00000013 nop +8000814c: 00000013 nop +80008150: 00000013 nop +80008154: 00000013 nop +80008158: 00000013 nop +8000815c: 00000013 nop +80008160: 00000013 nop +80008164: 00000013 nop +80008168: 00000013 nop +8000816c: 00000013 nop +80008170: 00000013 nop +80008174: 00000013 nop +80008178: 00000013 nop +8000817c: 00000013 nop +80008180: 00000013 nop +80008184: 00000013 nop +80008188: 00000013 nop +8000818c: 00000013 nop +80008190: 00000013 nop +80008194: 00000013 nop +80008198: 00000013 nop +8000819c: 00000013 nop +800081a0: 00000013 nop +800081a4: 00000013 nop +800081a8: 00000013 nop +800081ac: 00000013 nop +800081b0: 00000013 nop +800081b4: 00000013 nop +800081b8: 00000013 nop +800081bc: 00000013 nop +800081c0: 00000013 nop +800081c4: 00000013 nop +800081c8: 00000013 nop +800081cc: 00000013 nop +800081d0: 00000013 nop +800081d4: 00000013 nop +800081d8: 00000013 nop +800081dc: 00000013 nop +800081e0: 00000013 nop +800081e4: 00000013 nop +800081e8: 00000013 nop +800081ec: 00000013 nop +800081f0: 00000013 nop +800081f4: 00000013 nop +800081f8: 00000013 nop +800081fc: 00000013 nop +80008200: 00000013 nop +80008204: 00000013 nop +80008208: 00000013 nop +8000820c: 00000013 nop +80008210: 00000013 nop +80008214: 00000013 nop +80008218: 00000013 nop +8000821c: 00000013 nop +80008220: 00000013 nop +80008224: 00000013 nop +80008228: 00000013 nop +8000822c: 00000013 nop +80008230: 00000013 nop +80008234: 00000013 nop +80008238: 00000013 nop +8000823c: 00000013 nop +80008240: 00000013 nop +80008244: 00000013 nop +80008248: 00000013 nop +8000824c: 00000013 nop +80008250: 00000013 nop +80008254: 00000013 nop +80008258: 00000013 nop +8000825c: 00000013 nop +80008260: 00000013 nop +80008264: 00000013 nop +80008268: 00000013 nop +8000826c: 00000013 nop +80008270: 00000013 nop +80008274: 00000013 nop +80008278: 00000013 nop +8000827c: 00000013 nop +80008280: 00000013 nop +80008284: 00000013 nop +80008288: 00000013 nop +8000828c: 00000013 nop +80008290: 00000013 nop +80008294: 00000013 nop +80008298: 00000013 nop +8000829c: 00000013 nop +800082a0: 00000013 nop +800082a4: 00000013 nop +800082a8: 00000013 nop +800082ac: 00000013 nop +800082b0: 00000013 nop +800082b4: 00000013 nop +800082b8: 00000013 nop +800082bc: 00000013 nop +800082c0: 00000013 nop +800082c4: 00000013 nop +800082c8: 00000013 nop +800082cc: 00000013 nop +800082d0: 00000013 nop +800082d4: 00000013 nop +800082d8: 00000013 nop +800082dc: 00000013 nop +800082e0: 00000013 nop +800082e4: 00000013 nop +800082e8: 00000013 nop +800082ec: 00000013 nop +800082f0: 00000013 nop +800082f4: 00000013 nop +800082f8: 00000013 nop +800082fc: 00000013 nop +80008300: 00000013 nop +80008304: 00000013 nop +80008308: 00000013 nop +8000830c: 00000013 nop +80008310: 00000013 nop +80008314: 00000013 nop +80008318: 00000013 nop +8000831c: 00000013 nop +80008320: 00000013 nop +80008324: 00000013 nop +80008328: 00000013 nop +8000832c: 00000013 nop +80008330: 00000013 nop +80008334: 00000013 nop +80008338: 00000013 nop +8000833c: 00000013 nop +80008340: 00000013 nop +80008344: 00000013 nop +80008348: 00000013 nop +8000834c: 00000013 nop +80008350: 00000013 nop +80008354: 00000013 nop +80008358: 00000013 nop +8000835c: 00000013 nop +80008360: 00000013 nop +80008364: 00000013 nop +80008368: 00000013 nop +8000836c: 00000013 nop +80008370: 00000013 nop +80008374: 00000013 nop +80008378: 00000013 nop +8000837c: 00000013 nop +80008380: 00000013 nop +80008384: 00000013 nop +80008388: 00000013 nop +8000838c: 00000013 nop +80008390: 00000013 nop +80008394: 00000013 nop +80008398: 00000013 nop +8000839c: 00000013 nop +800083a0: 00000013 nop +800083a4: 00000013 nop +800083a8: 00000013 nop +800083ac: 00000013 nop +800083b0: 00000013 nop +800083b4: 00000013 nop +800083b8: 00000013 nop +800083bc: 00000013 nop +800083c0: 00000013 nop +800083c4: 00000013 nop +800083c8: 00000013 nop +800083cc: 00000013 nop +800083d0: 00000013 nop +800083d4: 00000013 nop +800083d8: 00000013 nop +800083dc: 00000013 nop +800083e0: 00000013 nop +800083e4: 00000013 nop +800083e8: 00000013 nop +800083ec: 00000013 nop +800083f0: 00000013 nop +800083f4: 00000013 nop +800083f8: 00000013 nop +800083fc: 00000013 nop +80008400: 00000013 nop +80008404: 00000013 nop +80008408: 00000013 nop +8000840c: 00000013 nop +80008410: 00000013 nop +80008414: 00000013 nop +80008418: 00000013 nop +8000841c: 00000013 nop +80008420: 00000013 nop +80008424: 00000013 nop +80008428: 00000013 nop +8000842c: 00000013 nop +80008430: 00000013 nop +80008434: 00000013 nop +80008438: 00000013 nop +8000843c: 00000013 nop +80008440: 00000013 nop +80008444: 00000013 nop +80008448: 00000013 nop +8000844c: 00000013 nop +80008450: 00000013 nop +80008454: 00000013 nop +80008458: 00000013 nop +8000845c: 00000013 nop +80008460: 00000013 nop +80008464: 00000013 nop +80008468: 00000013 nop +8000846c: 00000013 nop +80008470: 00000013 nop +80008474: 00000013 nop +80008478: 00000013 nop +8000847c: 00000013 nop +80008480: 00000013 nop +80008484: 00000013 nop +80008488: 00000013 nop +8000848c: 00000013 nop +80008490: 00000013 nop +80008494: 00000013 nop +80008498: 00000013 nop +8000849c: 00000013 nop +800084a0: 00000013 nop +800084a4: 00000013 nop +800084a8: 00000013 nop +800084ac: 00000013 nop +800084b0: 00000013 nop +800084b4: 00000013 nop +800084b8: 00000013 nop +800084bc: 00000013 nop +800084c0: 00000013 nop +800084c4: 00000013 nop +800084c8: 00000013 nop +800084cc: 00000013 nop +800084d0: 00000013 nop +800084d4: 00000013 nop +800084d8: 00000013 nop +800084dc: 00000013 nop +800084e0: 00000013 nop +800084e4: 00000013 nop +800084e8: 00000013 nop +800084ec: 00000013 nop +800084f0: 00000013 nop +800084f4: 00000013 nop +800084f8: 00000013 nop +800084fc: 00000013 nop +80008500: 00000013 nop +80008504: 00000013 nop +80008508: 00000013 nop +8000850c: 00000013 nop +80008510: 00000013 nop +80008514: 00000013 nop +80008518: 00000013 nop +8000851c: 00000013 nop +80008520: 00000013 nop +80008524: 00000013 nop +80008528: 00000013 nop +8000852c: 00000013 nop +80008530: 00000013 nop +80008534: 00000013 nop +80008538: 00000013 nop +8000853c: 00000013 nop +80008540: 00000013 nop +80008544: 00000013 nop +80008548: 00000013 nop +8000854c: 00000013 nop +80008550: 00000013 nop +80008554: 00000013 nop +80008558: 00000013 nop +8000855c: 00000013 nop +80008560: 00000013 nop +80008564: 00000013 nop +80008568: 00000013 nop +8000856c: 00000013 nop +80008570: 00000013 nop +80008574: 00000013 nop +80008578: 00000013 nop +8000857c: 00000013 nop +80008580: 00000013 nop +80008584: 00000013 nop +80008588: 00000013 nop +8000858c: 00000013 nop +80008590: 00000013 nop +80008594: 00000013 nop +80008598: 00000013 nop +8000859c: 00000013 nop +800085a0: 00000013 nop +800085a4: 00000013 nop +800085a8: 00000013 nop +800085ac: 00000013 nop +800085b0: 00000013 nop +800085b4: 00000013 nop +800085b8: 00000013 nop +800085bc: 00000013 nop +800085c0: 00000013 nop +800085c4: 00000013 nop +800085c8: 00000013 nop +800085cc: 00000013 nop +800085d0: 00000013 nop +800085d4: 00000013 nop +800085d8: 00000013 nop +800085dc: 00000013 nop +800085e0: 00000013 nop +800085e4: 00000013 nop +800085e8: 00000013 nop +800085ec: 00000013 nop +800085f0: 00000013 nop +800085f4: 00000013 nop +800085f8: 00000013 nop +800085fc: 00000013 nop +80008600: 00000013 nop +80008604: 00000013 nop +80008608: 00000013 nop +8000860c: 00000013 nop +80008610: 00000013 nop +80008614: 00000013 nop +80008618: 00000013 nop +8000861c: 00000013 nop +80008620: 00000013 nop +80008624: 00000013 nop +80008628: 00000013 nop +8000862c: 00000013 nop +80008630: 00000013 nop +80008634: 00000013 nop +80008638: 00000013 nop +8000863c: 00000013 nop +80008640: 00000013 nop +80008644: 00000013 nop +80008648: 00000013 nop +8000864c: 00000013 nop +80008650: 00000013 nop +80008654: 00000013 nop +80008658: 00000013 nop +8000865c: 00000013 nop +80008660: 00000013 nop +80008664: 00000013 nop +80008668: 00000013 nop +8000866c: 00000013 nop +80008670: 00000013 nop +80008674: 00000013 nop +80008678: 00000013 nop +8000867c: 00000013 nop +80008680: 00000013 nop +80008684: 00000013 nop +80008688: 00000013 nop +8000868c: 00000013 nop +80008690: 00000013 nop +80008694: 00000013 nop +80008698: 00000013 nop +8000869c: 00000013 nop +800086a0: 00000013 nop +800086a4: 00000013 nop +800086a8: 00000013 nop +800086ac: 00000013 nop +800086b0: 00000013 nop +800086b4: 00000013 nop +800086b8: 00000013 nop +800086bc: 00000013 nop +800086c0: 00000013 nop +800086c4: 00000013 nop +800086c8: 00000013 nop +800086cc: 00000013 nop +800086d0: 00000013 nop +800086d4: 00000013 nop +800086d8: 00000013 nop +800086dc: 00000013 nop +800086e0: 00000013 nop +800086e4: 00000013 nop +800086e8: 00000013 nop +800086ec: 00000013 nop +800086f0: 00000013 nop +800086f4: 00000013 nop +800086f8: 00000013 nop +800086fc: 00000013 nop +80008700: 00000013 nop +80008704: 00000013 nop +80008708: 00000013 nop +8000870c: 00000013 nop +80008710: 00000013 nop +80008714: 00000013 nop +80008718: 00000013 nop +8000871c: 00000013 nop +80008720: 00000013 nop +80008724: 00000013 nop +80008728: 00000013 nop +8000872c: 00000013 nop +80008730: 00000013 nop +80008734: 00000013 nop +80008738: 00000013 nop +8000873c: 00000013 nop +80008740: 00000013 nop +80008744: 00000013 nop +80008748: 00000013 nop +8000874c: 00000013 nop +80008750: 00000013 nop +80008754: 00000013 nop +80008758: 00000013 nop +8000875c: 00000013 nop +80008760: 00000013 nop +80008764: 00000013 nop +80008768: 00000013 nop +8000876c: 00000013 nop +80008770: 00000013 nop +80008774: 00000013 nop +80008778: 00000013 nop +8000877c: 00000013 nop +80008780: 00000013 nop +80008784: 00000013 nop +80008788: 00000013 nop +8000878c: 00000013 nop +80008790: 00000013 nop +80008794: 00000013 nop +80008798: 00000013 nop +8000879c: 00000013 nop +800087a0: 00000013 nop +800087a4: 00000013 nop +800087a8: 00000013 nop +800087ac: 00000013 nop +800087b0: 00000013 nop +800087b4: 00000013 nop +800087b8: 00000013 nop +800087bc: 00000013 nop +800087c0: 00000013 nop +800087c4: 00000013 nop +800087c8: 00000013 nop +800087cc: 00000013 nop +800087d0: 00000013 nop +800087d4: 00000013 nop +800087d8: 00000013 nop +800087dc: 00000013 nop +800087e0: 00000013 nop +800087e4: 00000013 nop +800087e8: 00000013 nop +800087ec: 00000013 nop +800087f0: 00000013 nop +800087f4: 00000013 nop +800087f8: 00000013 nop +800087fc: 00000013 nop +80008800: 00000013 nop +80008804: 00000013 nop +80008808: 00000013 nop +8000880c: 00000013 nop +80008810: 00000013 nop +80008814: 00000013 nop +80008818: 00000013 nop +8000881c: 00000013 nop +80008820: 00000013 nop +80008824: 00000013 nop +80008828: 00000013 nop +8000882c: 00000013 nop +80008830: 00000013 nop +80008834: 00000013 nop +80008838: 00000013 nop +8000883c: 00000013 nop +80008840: 00000013 nop +80008844: 00000013 nop +80008848: 00000013 nop +8000884c: 00000013 nop +80008850: 00000013 nop +80008854: 00000013 nop +80008858: 00000013 nop +8000885c: 00000013 nop +80008860: 00000013 nop +80008864: 00000013 nop +80008868: 00000013 nop +8000886c: 00000013 nop +80008870: 00000013 nop +80008874: 00000013 nop +80008878: 00000013 nop +8000887c: 00000013 nop +80008880: 00000013 nop +80008884: 00000013 nop +80008888: 00000013 nop +8000888c: 00000013 nop +80008890: 00000013 nop +80008894: 00000013 nop +80008898: 00000013 nop +8000889c: 00000013 nop +800088a0: 00000013 nop +800088a4: 00000013 nop +800088a8: 00000013 nop +800088ac: 00000013 nop +800088b0: 00000013 nop +800088b4: 00000013 nop +800088b8: 00000013 nop +800088bc: 00000013 nop +800088c0: 00000013 nop +800088c4: 00000013 nop +800088c8: 00000013 nop +800088cc: 00000013 nop +800088d0: 00000013 nop +800088d4: 00000013 nop +800088d8: 00000013 nop +800088dc: 00000013 nop +800088e0: 00000013 nop +800088e4: 00000013 nop +800088e8: 00000013 nop +800088ec: 00000013 nop +800088f0: 00000013 nop +800088f4: 00000013 nop +800088f8: 00000013 nop +800088fc: 00000013 nop +80008900: 00000013 nop +80008904: 00000013 nop +80008908: 00000013 nop +8000890c: 00000013 nop +80008910: 00000013 nop +80008914: 00000013 nop +80008918: 00000013 nop +8000891c: 00000013 nop +80008920: 00000013 nop +80008924: 00000013 nop +80008928: 00000013 nop +8000892c: 00000013 nop +80008930: 00000013 nop +80008934: 00000013 nop +80008938: 00000013 nop +8000893c: 00000013 nop +80008940: 00000013 nop +80008944: 00000013 nop +80008948: 00000013 nop +8000894c: 00000013 nop +80008950: 00000013 nop +80008954: 00000013 nop +80008958: 00000013 nop +8000895c: 00000013 nop +80008960: 00000013 nop +80008964: 00000013 nop +80008968: 00000013 nop +8000896c: 00000013 nop +80008970: 00000013 nop +80008974: 00000013 nop +80008978: 00000013 nop +8000897c: 00000013 nop +80008980: 00000013 nop +80008984: 00000013 nop +80008988: 00000013 nop +8000898c: 00000013 nop +80008990: 00000013 nop +80008994: 00000013 nop +80008998: 00000013 nop +8000899c: 00000013 nop +800089a0: 00000013 nop +800089a4: 00000013 nop +800089a8: 00000013 nop +800089ac: 00000013 nop +800089b0: 00000013 nop +800089b4: 00000013 nop +800089b8: 00000013 nop +800089bc: 00000013 nop +800089c0: 00000013 nop +800089c4: 00000013 nop +800089c8: 00000013 nop +800089cc: 00000013 nop +800089d0: 00000013 nop +800089d4: 00000013 nop +800089d8: 00000013 nop +800089dc: 00000013 nop +800089e0: 00000013 nop +800089e4: 00000013 nop +800089e8: 00000013 nop +800089ec: 00000013 nop +800089f0: 00000013 nop +800089f4: 00000013 nop +800089f8: 00000013 nop +800089fc: 00000013 nop +80008a00: 00000013 nop +80008a04: 00000013 nop +80008a08: 00000013 nop +80008a0c: 00000013 nop +80008a10: 00000013 nop +80008a14: 00000013 nop +80008a18: 00000013 nop +80008a1c: 00000013 nop +80008a20: 00000013 nop +80008a24: 00000013 nop +80008a28: 00000013 nop +80008a2c: 00000013 nop +80008a30: 00000013 nop +80008a34: 00000013 nop +80008a38: 00000013 nop +80008a3c: 00000013 nop +80008a40: 00000013 nop +80008a44: 00000013 nop +80008a48: 00000013 nop +80008a4c: 00000013 nop +80008a50: 00000013 nop +80008a54: 00000013 nop +80008a58: 00000013 nop +80008a5c: 00000013 nop +80008a60: 00000013 nop +80008a64: 00000013 nop +80008a68: 00000013 nop +80008a6c: 00000013 nop +80008a70: 00000013 nop +80008a74: 00000013 nop +80008a78: 00000013 nop +80008a7c: 00000013 nop +80008a80: 00000013 nop +80008a84: 00000013 nop +80008a88: 00000013 nop +80008a8c: 00000013 nop +80008a90: 00000013 nop +80008a94: 00000013 nop +80008a98: 00000013 nop +80008a9c: 00000013 nop +80008aa0: 00000013 nop +80008aa4: 00000013 nop +80008aa8: 00000013 nop +80008aac: 00000013 nop +80008ab0: 00000013 nop +80008ab4: 00000013 nop +80008ab8: 00000013 nop +80008abc: 00000013 nop +80008ac0: 00000013 nop +80008ac4: 00000013 nop +80008ac8: 00000013 nop +80008acc: 00000013 nop +80008ad0: 00000013 nop +80008ad4: 00000013 nop +80008ad8: 00000013 nop +80008adc: 00000013 nop +80008ae0: 00000013 nop +80008ae4: 00000013 nop +80008ae8: 00000013 nop +80008aec: 00000013 nop +80008af0: 00000013 nop +80008af4: 00000013 nop +80008af8: 00000013 nop +80008afc: 00000013 nop +80008b00: 00000013 nop +80008b04: 00000013 nop +80008b08: 00000013 nop +80008b0c: 00000013 nop +80008b10: 00000013 nop +80008b14: 00000013 nop +80008b18: 00000013 nop +80008b1c: 00000013 nop +80008b20: 00000013 nop +80008b24: 00000013 nop +80008b28: 00000013 nop +80008b2c: 00000013 nop +80008b30: 00000013 nop +80008b34: 00000013 nop +80008b38: 00000013 nop +80008b3c: 00000013 nop +80008b40: 00000013 nop +80008b44: 00000013 nop +80008b48: 00000013 nop +80008b4c: 00000013 nop +80008b50: 00000013 nop +80008b54: 00000013 nop +80008b58: 00000013 nop +80008b5c: 00000013 nop +80008b60: 00000013 nop +80008b64: 00000013 nop +80008b68: 00000013 nop +80008b6c: 00000013 nop +80008b70: 00000013 nop +80008b74: 00000013 nop +80008b78: 00000013 nop +80008b7c: 00000013 nop +80008b80: 00000013 nop +80008b84: 00000013 nop +80008b88: 00000013 nop +80008b8c: 00000013 nop +80008b90: 00000013 nop +80008b94: 00000013 nop +80008b98: 00000013 nop +80008b9c: 00000013 nop +80008ba0: 00000013 nop +80008ba4: 00000013 nop +80008ba8: 00000013 nop +80008bac: 00000013 nop +80008bb0: 00000013 nop +80008bb4: 00000013 nop +80008bb8: 00000013 nop +80008bbc: 00000013 nop +80008bc0: 00000013 nop +80008bc4: 00000013 nop +80008bc8: 00000013 nop +80008bcc: 00000013 nop +80008bd0: 00000013 nop +80008bd4: 00000013 nop +80008bd8: 00000013 nop +80008bdc: 00000013 nop +80008be0: 00000013 nop +80008be4: 00000013 nop +80008be8: 00000013 nop +80008bec: 00000013 nop +80008bf0: 00000013 nop +80008bf4: 00000013 nop +80008bf8: 00000013 nop +80008bfc: 00000013 nop +80008c00: 00000013 nop +80008c04: 00000013 nop +80008c08: 00000013 nop +80008c0c: 00000013 nop +80008c10: 00000013 nop +80008c14: 00000013 nop +80008c18: 00000013 nop +80008c1c: 00000013 nop +80008c20: 00000013 nop +80008c24: 00000013 nop +80008c28: 00000013 nop +80008c2c: 00000013 nop +80008c30: 00000013 nop +80008c34: 00000013 nop +80008c38: 00000013 nop +80008c3c: 00000013 nop +80008c40: 00000013 nop +80008c44: 00000013 nop +80008c48: 00000013 nop +80008c4c: 00000013 nop +80008c50: 00000013 nop +80008c54: 00000013 nop +80008c58: 00000013 nop +80008c5c: 00000013 nop +80008c60: 00000013 nop +80008c64: 00000013 nop +80008c68: 00000013 nop +80008c6c: 00000013 nop +80008c70: 00000013 nop +80008c74: 00000013 nop +80008c78: 00000013 nop +80008c7c: 00000013 nop +80008c80: 00000013 nop +80008c84: 00000013 nop +80008c88: 00000013 nop +80008c8c: 00000013 nop +80008c90: 00000013 nop +80008c94: 00000013 nop +80008c98: 00000013 nop +80008c9c: 00000013 nop +80008ca0: 00000013 nop +80008ca4: 00000013 nop +80008ca8: 00000013 nop +80008cac: 00000013 nop +80008cb0: 00000013 nop +80008cb4: 00000013 nop +80008cb8: 00000013 nop +80008cbc: 00000013 nop +80008cc0: 00000013 nop +80008cc4: 00000013 nop +80008cc8: 00000013 nop +80008ccc: 00000013 nop +80008cd0: 00000013 nop +80008cd4: 00000013 nop +80008cd8: 00000013 nop +80008cdc: 00000013 nop +80008ce0: 00000013 nop +80008ce4: 00000013 nop +80008ce8: 00000013 nop +80008cec: 00000013 nop +80008cf0: 00000013 nop +80008cf4: 00000013 nop +80008cf8: 00000013 nop +80008cfc: 00000013 nop +80008d00: 00000013 nop +80008d04: 00000013 nop +80008d08: 00000013 nop +80008d0c: 00000013 nop +80008d10: 00000013 nop +80008d14: 00000013 nop +80008d18: 00000013 nop +80008d1c: 00000013 nop +80008d20: 00000013 nop +80008d24: 00000013 nop +80008d28: 00000013 nop +80008d2c: 00000013 nop +80008d30: 00000013 nop +80008d34: 00000013 nop +80008d38: 00000013 nop +80008d3c: 00000013 nop +80008d40: 00000013 nop +80008d44: 00000013 nop +80008d48: 00000013 nop +80008d4c: 00000013 nop +80008d50: 00000013 nop +80008d54: 00000013 nop +80008d58: 00000013 nop +80008d5c: 00000013 nop +80008d60: 00000013 nop +80008d64: 00000013 nop +80008d68: 00000013 nop +80008d6c: 00000013 nop +80008d70: 00000013 nop +80008d74: 00000013 nop +80008d78: 00000013 nop +80008d7c: 00000013 nop +80008d80: 00000013 nop +80008d84: 00000013 nop +80008d88: 00000013 nop +80008d8c: 00000013 nop +80008d90: 00000013 nop +80008d94: 00000013 nop +80008d98: 00000013 nop +80008d9c: 00000013 nop +80008da0: 00000013 nop +80008da4: 00000013 nop +80008da8: 00000013 nop +80008dac: 00000013 nop +80008db0: 00000013 nop +80008db4: 00000013 nop +80008db8: 00000013 nop +80008dbc: 00000013 nop +80008dc0: 00000013 nop +80008dc4: 00000013 nop +80008dc8: 00000013 nop +80008dcc: 00000013 nop +80008dd0: 00000013 nop +80008dd4: 00000013 nop +80008dd8: 00000013 nop +80008ddc: 00000013 nop +80008de0: 00000013 nop +80008de4: 00000013 nop +80008de8: 00000013 nop +80008dec: 00000013 nop +80008df0: 00000013 nop +80008df4: 00000013 nop +80008df8: 00000013 nop +80008dfc: 00000013 nop +80008e00: 00000013 nop +80008e04: 00000013 nop +80008e08: 00000013 nop +80008e0c: 00000013 nop +80008e10: 00000013 nop +80008e14: 00000013 nop +80008e18: 00000013 nop +80008e1c: 00000013 nop +80008e20: 00000013 nop +80008e24: 00000013 nop +80008e28: 00000013 nop +80008e2c: 00000013 nop +80008e30: 00000013 nop +80008e34: 00000013 nop +80008e38: 00000013 nop +80008e3c: 00000013 nop +80008e40: 00000013 nop +80008e44: 00000013 nop +80008e48: 00000013 nop +80008e4c: 00000013 nop +80008e50: 00000013 nop +80008e54: 00000013 nop +80008e58: 00000013 nop +80008e5c: 00000013 nop +80008e60: 00000013 nop +80008e64: 00000013 nop +80008e68: 00000013 nop +80008e6c: 00000013 nop +80008e70: 00000013 nop +80008e74: 00000013 nop +80008e78: 00000013 nop +80008e7c: 00000013 nop +80008e80: 00000013 nop +80008e84: 00000013 nop +80008e88: 00000013 nop +80008e8c: 00000013 nop +80008e90: 00000013 nop +80008e94: 00000013 nop +80008e98: 00000013 nop +80008e9c: 00000013 nop +80008ea0: 00000013 nop +80008ea4: 00000013 nop +80008ea8: 00000013 nop +80008eac: 00000013 nop +80008eb0: 00000013 nop +80008eb4: 00000013 nop +80008eb8: 00000013 nop +80008ebc: 00000013 nop +80008ec0: 00000013 nop +80008ec4: 00000013 nop +80008ec8: 00000013 nop +80008ecc: 00000013 nop +80008ed0: 00000013 nop +80008ed4: 00000013 nop +80008ed8: 00000013 nop +80008edc: 00000013 nop +80008ee0: 00000013 nop +80008ee4: 00000013 nop +80008ee8: 00000013 nop +80008eec: 00000013 nop +80008ef0: 00000013 nop +80008ef4: 00000013 nop +80008ef8: 00000013 nop +80008efc: 00000013 nop +80008f00: 00000013 nop +80008f04: 00000013 nop +80008f08: 00000013 nop +80008f0c: 00000013 nop +80008f10: 00000013 nop +80008f14: 00000013 nop +80008f18: 00000013 nop +80008f1c: 00000013 nop +80008f20: 00000013 nop +80008f24: 00000013 nop +80008f28: 00000013 nop +80008f2c: 00000013 nop +80008f30: 00000013 nop +80008f34: 00000013 nop +80008f38: 00000013 nop +80008f3c: 00000013 nop +80008f40: 00000013 nop +80008f44: 00000013 nop +80008f48: 00000013 nop +80008f4c: 00000013 nop +80008f50: 00000013 nop +80008f54: 00000013 nop +80008f58: 00000013 nop +80008f5c: 00000013 nop +80008f60: 00000013 nop +80008f64: 00000013 nop +80008f68: 00000013 nop +80008f6c: 00000013 nop +80008f70: 00000013 nop +80008f74: 00000013 nop +80008f78: 00000013 nop +80008f7c: 00000013 nop +80008f80: 00000013 nop +80008f84: 00000013 nop +80008f88: 00000013 nop +80008f8c: 00000013 nop +80008f90: 00000013 nop +80008f94: 00000013 nop +80008f98: 00000013 nop +80008f9c: 00000013 nop +80008fa0: 00000013 nop +80008fa4: 00000013 nop +80008fa8: 00000013 nop +80008fac: 00000013 nop +80008fb0: 00000013 nop +80008fb4: 00000013 nop +80008fb8: 00000013 nop +80008fbc: 00000013 nop +80008fc0: 00000013 nop +80008fc4: 00000013 nop +80008fc8: 00000013 nop +80008fcc: 00000013 nop +80008fd0: 00000013 nop +80008fd4: 00000013 nop +80008fd8: 00000013 nop +80008fdc: 00000013 nop +80008fe0: 00000013 nop +80008fe4: 00000013 nop +80008fe8: 00000013 nop +80008fec: 00000013 nop +80008ff0: 00000013 nop +80008ff4: 00000013 nop +80008ff8: 00000013 nop +80008ffc: 00000013 nop + +80009000 : +80009000: 4140 lw s0,4(a0) +80009002: 4342 lw t1,16(sp) +80009004: 4544 lw s1,12(a0) +80009006: 4746 lw a4,80(sp) +80009008: 4948 lw a0,20(a0) +8000900a: 4b4a lw s6,144(sp) +8000900c: 4d4c lw a1,28(a0) +8000900e: 4f4e lw t5,208(sp) +80009010: 00000013 nop +80009014: 00000013 nop +80009018: 00000013 nop +8000901c: 00000013 nop +80009020: 00000013 nop +80009024: 00000013 nop +80009028: 00000013 nop +8000902c: 00000013 nop +80009030: 00000013 nop +80009034: 00000013 nop +80009038: 00000013 nop +8000903c: 00000013 nop +80009040: 00000013 nop +80009044: 00000013 nop +80009048: 00000013 nop +8000904c: 00000013 nop +80009050: 00000013 nop +80009054: 00000013 nop +80009058: 00000013 nop +8000905c: 00000013 nop +80009060: 00000013 nop +80009064: 00000013 nop +80009068: 00000013 nop +8000906c: 00000013 nop +80009070: 00000013 nop +80009074: 00000013 nop +80009078: 00000013 nop +8000907c: 00000013 nop +80009080: 00000013 nop +80009084: 00000013 nop +80009088: 00000013 nop +8000908c: 00000013 nop +80009090: 00000013 nop +80009094: 00000013 nop +80009098: 00000013 nop +8000909c: 00000013 nop +800090a0: 00000013 nop +800090a4: 00000013 nop +800090a8: 00000013 nop +800090ac: 00000013 nop +800090b0: 00000013 nop +800090b4: 00000013 nop +800090b8: 00000013 nop +800090bc: 00000013 nop +800090c0: 00000013 nop +800090c4: 00000013 nop +800090c8: 00000013 nop +800090cc: 00000013 nop +800090d0: 00000013 nop +800090d4: 00000013 nop +800090d8: 00000013 nop +800090dc: 00000013 nop +800090e0: 00000013 nop +800090e4: 00000013 nop +800090e8: 00000013 nop +800090ec: 00000013 nop +800090f0: 00000013 nop +800090f4: 00000013 nop +800090f8: 00000013 nop +800090fc: 00000013 nop +80009100: 00000013 nop +80009104: 00000013 nop +80009108: 00000013 nop +8000910c: 00000013 nop +80009110: 00000013 nop +80009114: 00000013 nop +80009118: 00000013 nop +8000911c: 00000013 nop +80009120: 00000013 nop +80009124: 00000013 nop +80009128: 00000013 nop +8000912c: 00000013 nop +80009130: 00000013 nop +80009134: 00000013 nop +80009138: 00000013 nop +8000913c: 00000013 nop +80009140: 00000013 nop +80009144: 00000013 nop +80009148: 00000013 nop +8000914c: 00000013 nop +80009150: 00000013 nop +80009154: 00000013 nop +80009158: 00000013 nop +8000915c: 00000013 nop +80009160: 00000013 nop +80009164: 00000013 nop +80009168: 00000013 nop +8000916c: 00000013 nop +80009170: 00000013 nop +80009174: 00000013 nop +80009178: 00000013 nop +8000917c: 00000013 nop +80009180: 00000013 nop +80009184: 00000013 nop +80009188: 00000013 nop +8000918c: 00000013 nop +80009190: 00000013 nop +80009194: 00000013 nop +80009198: 00000013 nop +8000919c: 00000013 nop +800091a0: 00000013 nop +800091a4: 00000013 nop +800091a8: 00000013 nop +800091ac: 00000013 nop +800091b0: 00000013 nop +800091b4: 00000013 nop +800091b8: 00000013 nop +800091bc: 00000013 nop +800091c0: 00000013 nop +800091c4: 00000013 nop +800091c8: 00000013 nop +800091cc: 00000013 nop +800091d0: 00000013 nop +800091d4: 00000013 nop +800091d8: 00000013 nop +800091dc: 00000013 nop +800091e0: 00000013 nop +800091e4: 00000013 nop +800091e8: 00000013 nop +800091ec: 00000013 nop +800091f0: 00000013 nop +800091f4: 00000013 nop +800091f8: 00000013 nop +800091fc: 00000013 nop +80009200: 00000013 nop +80009204: 00000013 nop +80009208: 00000013 nop +8000920c: 00000013 nop +80009210: 00000013 nop +80009214: 00000013 nop +80009218: 00000013 nop +8000921c: 00000013 nop +80009220: 00000013 nop +80009224: 00000013 nop +80009228: 00000013 nop +8000922c: 00000013 nop +80009230: 00000013 nop +80009234: 00000013 nop +80009238: 00000013 nop +8000923c: 00000013 nop +80009240: 00000013 nop +80009244: 00000013 nop +80009248: 00000013 nop +8000924c: 00000013 nop +80009250: 00000013 nop +80009254: 00000013 nop +80009258: 00000013 nop +8000925c: 00000013 nop +80009260: 00000013 nop +80009264: 00000013 nop +80009268: 00000013 nop +8000926c: 00000013 nop +80009270: 00000013 nop +80009274: 00000013 nop +80009278: 00000013 nop +8000927c: 00000013 nop +80009280: 00000013 nop +80009284: 00000013 nop +80009288: 00000013 nop +8000928c: 00000013 nop +80009290: 00000013 nop +80009294: 00000013 nop +80009298: 00000013 nop +8000929c: 00000013 nop +800092a0: 00000013 nop +800092a4: 00000013 nop +800092a8: 00000013 nop +800092ac: 00000013 nop +800092b0: 00000013 nop +800092b4: 00000013 nop +800092b8: 00000013 nop +800092bc: 00000013 nop +800092c0: 00000013 nop +800092c4: 00000013 nop +800092c8: 00000013 nop +800092cc: 00000013 nop +800092d0: 00000013 nop +800092d4: 00000013 nop +800092d8: 00000013 nop +800092dc: 00000013 nop +800092e0: 00000013 nop +800092e4: 00000013 nop +800092e8: 00000013 nop +800092ec: 00000013 nop +800092f0: 00000013 nop +800092f4: 00000013 nop +800092f8: 00000013 nop +800092fc: 00000013 nop +80009300: 00000013 nop +80009304: 00000013 nop +80009308: 00000013 nop +8000930c: 00000013 nop +80009310: 00000013 nop +80009314: 00000013 nop +80009318: 00000013 nop +8000931c: 00000013 nop +80009320: 00000013 nop +80009324: 00000013 nop +80009328: 00000013 nop +8000932c: 00000013 nop +80009330: 00000013 nop +80009334: 00000013 nop +80009338: 00000013 nop +8000933c: 00000013 nop +80009340: 00000013 nop +80009344: 00000013 nop +80009348: 00000013 nop +8000934c: 00000013 nop +80009350: 00000013 nop +80009354: 00000013 nop +80009358: 00000013 nop +8000935c: 00000013 nop +80009360: 00000013 nop +80009364: 00000013 nop +80009368: 00000013 nop +8000936c: 00000013 nop +80009370: 00000013 nop +80009374: 00000013 nop +80009378: 00000013 nop +8000937c: 00000013 nop +80009380: 00000013 nop +80009384: 00000013 nop +80009388: 00000013 nop +8000938c: 00000013 nop +80009390: 00000013 nop +80009394: 00000013 nop +80009398: 00000013 nop +8000939c: 00000013 nop +800093a0: 00000013 nop +800093a4: 00000013 nop +800093a8: 00000013 nop +800093ac: 00000013 nop +800093b0: 00000013 nop +800093b4: 00000013 nop +800093b8: 00000013 nop +800093bc: 00000013 nop +800093c0: 00000013 nop +800093c4: 00000013 nop +800093c8: 00000013 nop +800093cc: 00000013 nop +800093d0: 00000013 nop +800093d4: 00000013 nop +800093d8: 00000013 nop +800093dc: 00000013 nop +800093e0: 00000013 nop +800093e4: 00000013 nop +800093e8: 00000013 nop +800093ec: 00000013 nop +800093f0: 00000013 nop +800093f4: 00000013 nop +800093f8: 00000013 nop +800093fc: 00000013 nop +80009400: 00000013 nop +80009404: 00000013 nop +80009408: 00000013 nop +8000940c: 00000013 nop +80009410: 00000013 nop +80009414: 00000013 nop +80009418: 00000013 nop +8000941c: 00000013 nop +80009420: 00000013 nop +80009424: 00000013 nop +80009428: 00000013 nop +8000942c: 00000013 nop +80009430: 00000013 nop +80009434: 00000013 nop +80009438: 00000013 nop +8000943c: 00000013 nop +80009440: 00000013 nop +80009444: 00000013 nop +80009448: 00000013 nop +8000944c: 00000013 nop +80009450: 00000013 nop +80009454: 00000013 nop +80009458: 00000013 nop +8000945c: 00000013 nop +80009460: 00000013 nop +80009464: 00000013 nop +80009468: 00000013 nop +8000946c: 00000013 nop +80009470: 00000013 nop +80009474: 00000013 nop +80009478: 00000013 nop +8000947c: 00000013 nop +80009480: 00000013 nop +80009484: 00000013 nop +80009488: 00000013 nop +8000948c: 00000013 nop +80009490: 00000013 nop +80009494: 00000013 nop +80009498: 00000013 nop +8000949c: 00000013 nop +800094a0: 00000013 nop +800094a4: 00000013 nop +800094a8: 00000013 nop +800094ac: 00000013 nop +800094b0: 00000013 nop +800094b4: 00000013 nop +800094b8: 00000013 nop +800094bc: 00000013 nop +800094c0: 00000013 nop +800094c4: 00000013 nop +800094c8: 00000013 nop +800094cc: 00000013 nop +800094d0: 00000013 nop +800094d4: 00000013 nop +800094d8: 00000013 nop +800094dc: 00000013 nop +800094e0: 00000013 nop +800094e4: 00000013 nop +800094e8: 00000013 nop +800094ec: 00000013 nop +800094f0: 00000013 nop +800094f4: 00000013 nop +800094f8: 00000013 nop +800094fc: 00000013 nop +80009500: 00000013 nop +80009504: 00000013 nop +80009508: 00000013 nop +8000950c: 00000013 nop +80009510: 00000013 nop +80009514: 00000013 nop +80009518: 00000013 nop +8000951c: 00000013 nop +80009520: 00000013 nop +80009524: 00000013 nop +80009528: 00000013 nop +8000952c: 00000013 nop +80009530: 00000013 nop +80009534: 00000013 nop +80009538: 00000013 nop +8000953c: 00000013 nop +80009540: 00000013 nop +80009544: 00000013 nop +80009548: 00000013 nop +8000954c: 00000013 nop +80009550: 00000013 nop +80009554: 00000013 nop +80009558: 00000013 nop +8000955c: 00000013 nop +80009560: 00000013 nop +80009564: 00000013 nop +80009568: 00000013 nop +8000956c: 00000013 nop +80009570: 00000013 nop +80009574: 00000013 nop +80009578: 00000013 nop +8000957c: 00000013 nop +80009580: 00000013 nop +80009584: 00000013 nop +80009588: 00000013 nop +8000958c: 00000013 nop +80009590: 00000013 nop +80009594: 00000013 nop +80009598: 00000013 nop +8000959c: 00000013 nop +800095a0: 00000013 nop +800095a4: 00000013 nop +800095a8: 00000013 nop +800095ac: 00000013 nop +800095b0: 00000013 nop +800095b4: 00000013 nop +800095b8: 00000013 nop +800095bc: 00000013 nop +800095c0: 00000013 nop +800095c4: 00000013 nop +800095c8: 00000013 nop +800095cc: 00000013 nop +800095d0: 00000013 nop +800095d4: 00000013 nop +800095d8: 00000013 nop +800095dc: 00000013 nop +800095e0: 00000013 nop +800095e4: 00000013 nop +800095e8: 00000013 nop +800095ec: 00000013 nop +800095f0: 00000013 nop +800095f4: 00000013 nop +800095f8: 00000013 nop +800095fc: 00000013 nop +80009600: 00000013 nop +80009604: 00000013 nop +80009608: 00000013 nop +8000960c: 00000013 nop +80009610: 00000013 nop +80009614: 00000013 nop +80009618: 00000013 nop +8000961c: 00000013 nop +80009620: 00000013 nop +80009624: 00000013 nop +80009628: 00000013 nop +8000962c: 00000013 nop +80009630: 00000013 nop +80009634: 00000013 nop +80009638: 00000013 nop +8000963c: 00000013 nop +80009640: 00000013 nop +80009644: 00000013 nop +80009648: 00000013 nop +8000964c: 00000013 nop +80009650: 00000013 nop +80009654: 00000013 nop +80009658: 00000013 nop +8000965c: 00000013 nop +80009660: 00000013 nop +80009664: 00000013 nop +80009668: 00000013 nop +8000966c: 00000013 nop +80009670: 00000013 nop +80009674: 00000013 nop +80009678: 00000013 nop +8000967c: 00000013 nop +80009680: 00000013 nop +80009684: 00000013 nop +80009688: 00000013 nop +8000968c: 00000013 nop +80009690: 00000013 nop +80009694: 00000013 nop +80009698: 00000013 nop +8000969c: 00000013 nop +800096a0: 00000013 nop +800096a4: 00000013 nop +800096a8: 00000013 nop +800096ac: 00000013 nop +800096b0: 00000013 nop +800096b4: 00000013 nop +800096b8: 00000013 nop +800096bc: 00000013 nop +800096c0: 00000013 nop +800096c4: 00000013 nop +800096c8: 00000013 nop +800096cc: 00000013 nop +800096d0: 00000013 nop +800096d4: 00000013 nop +800096d8: 00000013 nop +800096dc: 00000013 nop +800096e0: 00000013 nop +800096e4: 00000013 nop +800096e8: 00000013 nop +800096ec: 00000013 nop +800096f0: 00000013 nop +800096f4: 00000013 nop +800096f8: 00000013 nop +800096fc: 00000013 nop +80009700: 00000013 nop +80009704: 00000013 nop +80009708: 00000013 nop +8000970c: 00000013 nop +80009710: 00000013 nop +80009714: 00000013 nop +80009718: 00000013 nop +8000971c: 00000013 nop +80009720: 00000013 nop +80009724: 00000013 nop +80009728: 00000013 nop +8000972c: 00000013 nop +80009730: 00000013 nop +80009734: 00000013 nop +80009738: 00000013 nop +8000973c: 00000013 nop +80009740: 00000013 nop +80009744: 00000013 nop +80009748: 00000013 nop +8000974c: 00000013 nop +80009750: 00000013 nop +80009754: 00000013 nop +80009758: 00000013 nop +8000975c: 00000013 nop +80009760: 00000013 nop +80009764: 00000013 nop +80009768: 00000013 nop +8000976c: 00000013 nop +80009770: 00000013 nop +80009774: 00000013 nop +80009778: 00000013 nop +8000977c: 00000013 nop +80009780: 00000013 nop +80009784: 00000013 nop +80009788: 00000013 nop +8000978c: 00000013 nop +80009790: 00000013 nop +80009794: 00000013 nop +80009798: 00000013 nop +8000979c: 00000013 nop +800097a0: 00000013 nop +800097a4: 00000013 nop +800097a8: 00000013 nop +800097ac: 00000013 nop +800097b0: 00000013 nop +800097b4: 00000013 nop +800097b8: 00000013 nop +800097bc: 00000013 nop +800097c0: 00000013 nop +800097c4: 00000013 nop +800097c8: 00000013 nop +800097cc: 00000013 nop +800097d0: 00000013 nop +800097d4: 00000013 nop +800097d8: 00000013 nop +800097dc: 00000013 nop +800097e0: 00000013 nop +800097e4: 00000013 nop +800097e8: 00000013 nop +800097ec: 00000013 nop +800097f0: 00000013 nop +800097f4: 00000013 nop +800097f8: 00000013 nop +800097fc: 00000013 nop +80009800: 00000013 nop +80009804: 00000013 nop +80009808: 00000013 nop +8000980c: 00000013 nop +80009810: 00000013 nop +80009814: 00000013 nop +80009818: 00000013 nop +8000981c: 00000013 nop +80009820: 00000013 nop +80009824: 00000013 nop +80009828: 00000013 nop +8000982c: 00000013 nop +80009830: 00000013 nop +80009834: 00000013 nop +80009838: 00000013 nop +8000983c: 00000013 nop +80009840: 00000013 nop +80009844: 00000013 nop +80009848: 00000013 nop +8000984c: 00000013 nop +80009850: 00000013 nop +80009854: 00000013 nop +80009858: 00000013 nop +8000985c: 00000013 nop +80009860: 00000013 nop +80009864: 00000013 nop +80009868: 00000013 nop +8000986c: 00000013 nop +80009870: 00000013 nop +80009874: 00000013 nop +80009878: 00000013 nop +8000987c: 00000013 nop +80009880: 00000013 nop +80009884: 00000013 nop +80009888: 00000013 nop +8000988c: 00000013 nop +80009890: 00000013 nop +80009894: 00000013 nop +80009898: 00000013 nop +8000989c: 00000013 nop +800098a0: 00000013 nop +800098a4: 00000013 nop +800098a8: 00000013 nop +800098ac: 00000013 nop +800098b0: 00000013 nop +800098b4: 00000013 nop +800098b8: 00000013 nop +800098bc: 00000013 nop +800098c0: 00000013 nop +800098c4: 00000013 nop +800098c8: 00000013 nop +800098cc: 00000013 nop +800098d0: 00000013 nop +800098d4: 00000013 nop +800098d8: 00000013 nop +800098dc: 00000013 nop +800098e0: 00000013 nop +800098e4: 00000013 nop +800098e8: 00000013 nop +800098ec: 00000013 nop +800098f0: 00000013 nop +800098f4: 00000013 nop +800098f8: 00000013 nop +800098fc: 00000013 nop +80009900: 00000013 nop +80009904: 00000013 nop +80009908: 00000013 nop +8000990c: 00000013 nop +80009910: 00000013 nop +80009914: 00000013 nop +80009918: 00000013 nop +8000991c: 00000013 nop +80009920: 00000013 nop +80009924: 00000013 nop +80009928: 00000013 nop +8000992c: 00000013 nop +80009930: 00000013 nop +80009934: 00000013 nop +80009938: 00000013 nop +8000993c: 00000013 nop +80009940: 00000013 nop +80009944: 00000013 nop +80009948: 00000013 nop +8000994c: 00000013 nop +80009950: 00000013 nop +80009954: 00000013 nop +80009958: 00000013 nop +8000995c: 00000013 nop +80009960: 00000013 nop +80009964: 00000013 nop +80009968: 00000013 nop +8000996c: 00000013 nop +80009970: 00000013 nop +80009974: 00000013 nop +80009978: 00000013 nop +8000997c: 00000013 nop +80009980: 00000013 nop +80009984: 00000013 nop +80009988: 00000013 nop +8000998c: 00000013 nop +80009990: 00000013 nop +80009994: 00000013 nop +80009998: 00000013 nop +8000999c: 00000013 nop +800099a0: 00000013 nop +800099a4: 00000013 nop +800099a8: 00000013 nop +800099ac: 00000013 nop +800099b0: 00000013 nop +800099b4: 00000013 nop +800099b8: 00000013 nop +800099bc: 00000013 nop +800099c0: 00000013 nop +800099c4: 00000013 nop +800099c8: 00000013 nop +800099cc: 00000013 nop +800099d0: 00000013 nop +800099d4: 00000013 nop +800099d8: 00000013 nop +800099dc: 00000013 nop +800099e0: 00000013 nop +800099e4: 00000013 nop +800099e8: 00000013 nop +800099ec: 00000013 nop +800099f0: 00000013 nop +800099f4: 00000013 nop +800099f8: 00000013 nop +800099fc: 00000013 nop +80009a00: 00000013 nop +80009a04: 00000013 nop +80009a08: 00000013 nop +80009a0c: 00000013 nop +80009a10: 00000013 nop +80009a14: 00000013 nop +80009a18: 00000013 nop +80009a1c: 00000013 nop +80009a20: 00000013 nop +80009a24: 00000013 nop +80009a28: 00000013 nop +80009a2c: 00000013 nop +80009a30: 00000013 nop +80009a34: 00000013 nop +80009a38: 00000013 nop +80009a3c: 00000013 nop +80009a40: 00000013 nop +80009a44: 00000013 nop +80009a48: 00000013 nop +80009a4c: 00000013 nop +80009a50: 00000013 nop +80009a54: 00000013 nop +80009a58: 00000013 nop +80009a5c: 00000013 nop +80009a60: 00000013 nop +80009a64: 00000013 nop +80009a68: 00000013 nop +80009a6c: 00000013 nop +80009a70: 00000013 nop +80009a74: 00000013 nop +80009a78: 00000013 nop +80009a7c: 00000013 nop +80009a80: 00000013 nop +80009a84: 00000013 nop +80009a88: 00000013 nop +80009a8c: 00000013 nop +80009a90: 00000013 nop +80009a94: 00000013 nop +80009a98: 00000013 nop +80009a9c: 00000013 nop +80009aa0: 00000013 nop +80009aa4: 00000013 nop +80009aa8: 00000013 nop +80009aac: 00000013 nop +80009ab0: 00000013 nop +80009ab4: 00000013 nop +80009ab8: 00000013 nop +80009abc: 00000013 nop +80009ac0: 00000013 nop +80009ac4: 00000013 nop +80009ac8: 00000013 nop +80009acc: 00000013 nop +80009ad0: 00000013 nop +80009ad4: 00000013 nop +80009ad8: 00000013 nop +80009adc: 00000013 nop +80009ae0: 00000013 nop +80009ae4: 00000013 nop +80009ae8: 00000013 nop +80009aec: 00000013 nop +80009af0: 00000013 nop +80009af4: 00000013 nop +80009af8: 00000013 nop +80009afc: 00000013 nop +80009b00: 00000013 nop +80009b04: 00000013 nop +80009b08: 00000013 nop +80009b0c: 00000013 nop +80009b10: 00000013 nop +80009b14: 00000013 nop +80009b18: 00000013 nop +80009b1c: 00000013 nop +80009b20: 00000013 nop +80009b24: 00000013 nop +80009b28: 00000013 nop +80009b2c: 00000013 nop +80009b30: 00000013 nop +80009b34: 00000013 nop +80009b38: 00000013 nop +80009b3c: 00000013 nop +80009b40: 00000013 nop +80009b44: 00000013 nop +80009b48: 00000013 nop +80009b4c: 00000013 nop +80009b50: 00000013 nop +80009b54: 00000013 nop +80009b58: 00000013 nop +80009b5c: 00000013 nop +80009b60: 00000013 nop +80009b64: 00000013 nop +80009b68: 00000013 nop +80009b6c: 00000013 nop +80009b70: 00000013 nop +80009b74: 00000013 nop +80009b78: 00000013 nop +80009b7c: 00000013 nop +80009b80: 00000013 nop +80009b84: 00000013 nop +80009b88: 00000013 nop +80009b8c: 00000013 nop +80009b90: 00000013 nop +80009b94: 00000013 nop +80009b98: 00000013 nop +80009b9c: 00000013 nop +80009ba0: 00000013 nop +80009ba4: 00000013 nop +80009ba8: 00000013 nop +80009bac: 00000013 nop +80009bb0: 00000013 nop +80009bb4: 00000013 nop +80009bb8: 00000013 nop +80009bbc: 00000013 nop +80009bc0: 00000013 nop +80009bc4: 00000013 nop +80009bc8: 00000013 nop +80009bcc: 00000013 nop +80009bd0: 00000013 nop +80009bd4: 00000013 nop +80009bd8: 00000013 nop +80009bdc: 00000013 nop +80009be0: 00000013 nop +80009be4: 00000013 nop +80009be8: 00000013 nop +80009bec: 00000013 nop +80009bf0: 00000013 nop +80009bf4: 00000013 nop +80009bf8: 00000013 nop +80009bfc: 00000013 nop +80009c00: 00000013 nop +80009c04: 00000013 nop +80009c08: 00000013 nop +80009c0c: 00000013 nop +80009c10: 00000013 nop +80009c14: 00000013 nop +80009c18: 00000013 nop +80009c1c: 00000013 nop +80009c20: 00000013 nop +80009c24: 00000013 nop +80009c28: 00000013 nop +80009c2c: 00000013 nop +80009c30: 00000013 nop +80009c34: 00000013 nop +80009c38: 00000013 nop +80009c3c: 00000013 nop +80009c40: 00000013 nop +80009c44: 00000013 nop +80009c48: 00000013 nop +80009c4c: 00000013 nop +80009c50: 00000013 nop +80009c54: 00000013 nop +80009c58: 00000013 nop +80009c5c: 00000013 nop +80009c60: 00000013 nop +80009c64: 00000013 nop +80009c68: 00000013 nop +80009c6c: 00000013 nop +80009c70: 00000013 nop +80009c74: 00000013 nop +80009c78: 00000013 nop +80009c7c: 00000013 nop +80009c80: 00000013 nop +80009c84: 00000013 nop +80009c88: 00000013 nop +80009c8c: 00000013 nop +80009c90: 00000013 nop +80009c94: 00000013 nop +80009c98: 00000013 nop +80009c9c: 00000013 nop +80009ca0: 00000013 nop +80009ca4: 00000013 nop +80009ca8: 00000013 nop +80009cac: 00000013 nop +80009cb0: 00000013 nop +80009cb4: 00000013 nop +80009cb8: 00000013 nop +80009cbc: 00000013 nop +80009cc0: 00000013 nop +80009cc4: 00000013 nop +80009cc8: 00000013 nop +80009ccc: 00000013 nop +80009cd0: 00000013 nop +80009cd4: 00000013 nop +80009cd8: 00000013 nop +80009cdc: 00000013 nop +80009ce0: 00000013 nop +80009ce4: 00000013 nop +80009ce8: 00000013 nop +80009cec: 00000013 nop +80009cf0: 00000013 nop +80009cf4: 00000013 nop +80009cf8: 00000013 nop +80009cfc: 00000013 nop +80009d00: 00000013 nop +80009d04: 00000013 nop +80009d08: 00000013 nop +80009d0c: 00000013 nop +80009d10: 00000013 nop +80009d14: 00000013 nop +80009d18: 00000013 nop +80009d1c: 00000013 nop +80009d20: 00000013 nop +80009d24: 00000013 nop +80009d28: 00000013 nop +80009d2c: 00000013 nop +80009d30: 00000013 nop +80009d34: 00000013 nop +80009d38: 00000013 nop +80009d3c: 00000013 nop +80009d40: 00000013 nop +80009d44: 00000013 nop +80009d48: 00000013 nop +80009d4c: 00000013 nop +80009d50: 00000013 nop +80009d54: 00000013 nop +80009d58: 00000013 nop +80009d5c: 00000013 nop +80009d60: 00000013 nop +80009d64: 00000013 nop +80009d68: 00000013 nop +80009d6c: 00000013 nop +80009d70: 00000013 nop +80009d74: 00000013 nop +80009d78: 00000013 nop +80009d7c: 00000013 nop +80009d80: 00000013 nop +80009d84: 00000013 nop +80009d88: 00000013 nop +80009d8c: 00000013 nop +80009d90: 00000013 nop +80009d94: 00000013 nop +80009d98: 00000013 nop +80009d9c: 00000013 nop +80009da0: 00000013 nop +80009da4: 00000013 nop +80009da8: 00000013 nop +80009dac: 00000013 nop +80009db0: 00000013 nop +80009db4: 00000013 nop +80009db8: 00000013 nop +80009dbc: 00000013 nop +80009dc0: 00000013 nop +80009dc4: 00000013 nop +80009dc8: 00000013 nop +80009dcc: 00000013 nop +80009dd0: 00000013 nop +80009dd4: 00000013 nop +80009dd8: 00000013 nop +80009ddc: 00000013 nop +80009de0: 00000013 nop +80009de4: 00000013 nop +80009de8: 00000013 nop +80009dec: 00000013 nop +80009df0: 00000013 nop +80009df4: 00000013 nop +80009df8: 00000013 nop +80009dfc: 00000013 nop +80009e00: 00000013 nop +80009e04: 00000013 nop +80009e08: 00000013 nop +80009e0c: 00000013 nop +80009e10: 00000013 nop +80009e14: 00000013 nop +80009e18: 00000013 nop +80009e1c: 00000013 nop +80009e20: 00000013 nop +80009e24: 00000013 nop +80009e28: 00000013 nop +80009e2c: 00000013 nop +80009e30: 00000013 nop +80009e34: 00000013 nop +80009e38: 00000013 nop +80009e3c: 00000013 nop +80009e40: 00000013 nop +80009e44: 00000013 nop +80009e48: 00000013 nop +80009e4c: 00000013 nop +80009e50: 00000013 nop +80009e54: 00000013 nop +80009e58: 00000013 nop +80009e5c: 00000013 nop +80009e60: 00000013 nop +80009e64: 00000013 nop +80009e68: 00000013 nop +80009e6c: 00000013 nop +80009e70: 00000013 nop +80009e74: 00000013 nop +80009e78: 00000013 nop +80009e7c: 00000013 nop +80009e80: 00000013 nop +80009e84: 00000013 nop +80009e88: 00000013 nop +80009e8c: 00000013 nop +80009e90: 00000013 nop +80009e94: 00000013 nop +80009e98: 00000013 nop +80009e9c: 00000013 nop +80009ea0: 00000013 nop +80009ea4: 00000013 nop +80009ea8: 00000013 nop +80009eac: 00000013 nop +80009eb0: 00000013 nop +80009eb4: 00000013 nop +80009eb8: 00000013 nop +80009ebc: 00000013 nop +80009ec0: 00000013 nop +80009ec4: 00000013 nop +80009ec8: 00000013 nop +80009ecc: 00000013 nop +80009ed0: 00000013 nop +80009ed4: 00000013 nop +80009ed8: 00000013 nop +80009edc: 00000013 nop +80009ee0: 00000013 nop +80009ee4: 00000013 nop +80009ee8: 00000013 nop +80009eec: 00000013 nop +80009ef0: 00000013 nop +80009ef4: 00000013 nop +80009ef8: 00000013 nop +80009efc: 00000013 nop +80009f00: 00000013 nop +80009f04: 00000013 nop +80009f08: 00000013 nop +80009f0c: 00000013 nop +80009f10: 00000013 nop +80009f14: 00000013 nop +80009f18: 00000013 nop +80009f1c: 00000013 nop +80009f20: 00000013 nop +80009f24: 00000013 nop +80009f28: 00000013 nop +80009f2c: 00000013 nop +80009f30: 00000013 nop +80009f34: 00000013 nop +80009f38: 00000013 nop +80009f3c: 00000013 nop +80009f40: 00000013 nop +80009f44: 00000013 nop +80009f48: 00000013 nop +80009f4c: 00000013 nop +80009f50: 00000013 nop +80009f54: 00000013 nop +80009f58: 00000013 nop +80009f5c: 00000013 nop +80009f60: 00000013 nop +80009f64: 00000013 nop +80009f68: 00000013 nop +80009f6c: 00000013 nop +80009f70: 00000013 nop +80009f74: 00000013 nop +80009f78: 00000013 nop +80009f7c: 00000013 nop +80009f80: 00000013 nop +80009f84: 00000013 nop +80009f88: 00000013 nop +80009f8c: 00000013 nop +80009f90: 00000013 nop +80009f94: 00000013 nop +80009f98: 00000013 nop +80009f9c: 00000013 nop +80009fa0: 00000013 nop +80009fa4: 00000013 nop +80009fa8: 00000013 nop +80009fac: 00000013 nop +80009fb0: 00000013 nop +80009fb4: 00000013 nop +80009fb8: 00000013 nop +80009fbc: 00000013 nop +80009fc0: 00000013 nop +80009fc4: 00000013 nop +80009fc8: 00000013 nop +80009fcc: 00000013 nop +80009fd0: 00000013 nop +80009fd4: 00000013 nop +80009fd8: 00000013 nop +80009fdc: 00000013 nop +80009fe0: 00000013 nop +80009fe4: 00000013 nop +80009fe8: 00000013 nop +80009fec: 00000013 nop +80009ff0: 00000013 nop +80009ff4: 00000013 nop +80009ff8: 00000013 nop +80009ffc: 00000013 nop + +8000a000 : +8000a000: 5150 lw a2,36(a0) +8000a002: 5352 lw t1,52(sp) +8000a004: 5554 lw a3,44(a0) +8000a006: 5756 lw a4,116(sp) +8000a008: 5958 lw a4,52(a0) +8000a00a: 5b5a lw s6,180(sp) +8000a00c: 5d5c lw a5,60(a0) +8000a00e: 5f5e lw t5,244(sp) +8000a010: 00000013 nop +8000a014: 00000013 nop +8000a018: 00000013 nop +8000a01c: 00000013 nop +8000a020: 00000013 nop +8000a024: 00000013 nop +8000a028: 00000013 nop +8000a02c: 00000013 nop +8000a030: 00000013 nop +8000a034: 00000013 nop +8000a038: 00000013 nop +8000a03c: 00000013 nop +8000a040: 00000013 nop +8000a044: 00000013 nop +8000a048: 00000013 nop +8000a04c: 00000013 nop +8000a050: 00000013 nop +8000a054: 00000013 nop +8000a058: 00000013 nop +8000a05c: 00000013 nop +8000a060: 00000013 nop +8000a064: 00000013 nop +8000a068: 00000013 nop +8000a06c: 00000013 nop +8000a070: 00000013 nop +8000a074: 00000013 nop +8000a078: 00000013 nop +8000a07c: 00000013 nop +8000a080: 00000013 nop +8000a084: 00000013 nop +8000a088: 00000013 nop +8000a08c: 00000013 nop +8000a090: 00000013 nop +8000a094: 00000013 nop +8000a098: 00000013 nop +8000a09c: 00000013 nop +8000a0a0: 00000013 nop +8000a0a4: 00000013 nop +8000a0a8: 00000013 nop +8000a0ac: 00000013 nop +8000a0b0: 00000013 nop +8000a0b4: 00000013 nop +8000a0b8: 00000013 nop +8000a0bc: 00000013 nop +8000a0c0: 00000013 nop +8000a0c4: 00000013 nop +8000a0c8: 00000013 nop +8000a0cc: 00000013 nop +8000a0d0: 00000013 nop +8000a0d4: 00000013 nop +8000a0d8: 00000013 nop +8000a0dc: 00000013 nop +8000a0e0: 00000013 nop +8000a0e4: 00000013 nop +8000a0e8: 00000013 nop +8000a0ec: 00000013 nop +8000a0f0: 00000013 nop +8000a0f4: 00000013 nop +8000a0f8: 00000013 nop +8000a0fc: 00000013 nop +8000a100: 00000013 nop +8000a104: 00000013 nop +8000a108: 00000013 nop +8000a10c: 00000013 nop +8000a110: 00000013 nop +8000a114: 00000013 nop +8000a118: 00000013 nop +8000a11c: 00000013 nop +8000a120: 00000013 nop +8000a124: 00000013 nop +8000a128: 00000013 nop +8000a12c: 00000013 nop +8000a130: 00000013 nop +8000a134: 00000013 nop +8000a138: 00000013 nop +8000a13c: 00000013 nop +8000a140: 00000013 nop +8000a144: 00000013 nop +8000a148: 00000013 nop +8000a14c: 00000013 nop +8000a150: 00000013 nop +8000a154: 00000013 nop +8000a158: 00000013 nop +8000a15c: 00000013 nop +8000a160: 00000013 nop +8000a164: 00000013 nop +8000a168: 00000013 nop +8000a16c: 00000013 nop +8000a170: 00000013 nop +8000a174: 00000013 nop +8000a178: 00000013 nop +8000a17c: 00000013 nop +8000a180: 00000013 nop +8000a184: 00000013 nop +8000a188: 00000013 nop +8000a18c: 00000013 nop +8000a190: 00000013 nop +8000a194: 00000013 nop +8000a198: 00000013 nop +8000a19c: 00000013 nop +8000a1a0: 00000013 nop +8000a1a4: 00000013 nop +8000a1a8: 00000013 nop +8000a1ac: 00000013 nop +8000a1b0: 00000013 nop +8000a1b4: 00000013 nop +8000a1b8: 00000013 nop +8000a1bc: 00000013 nop +8000a1c0: 00000013 nop +8000a1c4: 00000013 nop +8000a1c8: 00000013 nop +8000a1cc: 00000013 nop +8000a1d0: 00000013 nop +8000a1d4: 00000013 nop +8000a1d8: 00000013 nop +8000a1dc: 00000013 nop +8000a1e0: 00000013 nop +8000a1e4: 00000013 nop +8000a1e8: 00000013 nop +8000a1ec: 00000013 nop +8000a1f0: 00000013 nop +8000a1f4: 00000013 nop +8000a1f8: 00000013 nop +8000a1fc: 00000013 nop +8000a200: 00000013 nop +8000a204: 00000013 nop +8000a208: 00000013 nop +8000a20c: 00000013 nop +8000a210: 00000013 nop +8000a214: 00000013 nop +8000a218: 00000013 nop +8000a21c: 00000013 nop +8000a220: 00000013 nop +8000a224: 00000013 nop +8000a228: 00000013 nop +8000a22c: 00000013 nop +8000a230: 00000013 nop +8000a234: 00000013 nop +8000a238: 00000013 nop +8000a23c: 00000013 nop +8000a240: 00000013 nop +8000a244: 00000013 nop +8000a248: 00000013 nop +8000a24c: 00000013 nop +8000a250: 00000013 nop +8000a254: 00000013 nop +8000a258: 00000013 nop +8000a25c: 00000013 nop +8000a260: 00000013 nop +8000a264: 00000013 nop +8000a268: 00000013 nop +8000a26c: 00000013 nop +8000a270: 00000013 nop +8000a274: 00000013 nop +8000a278: 00000013 nop +8000a27c: 00000013 nop +8000a280: 00000013 nop +8000a284: 00000013 nop +8000a288: 00000013 nop +8000a28c: 00000013 nop +8000a290: 00000013 nop +8000a294: 00000013 nop +8000a298: 00000013 nop +8000a29c: 00000013 nop +8000a2a0: 00000013 nop +8000a2a4: 00000013 nop +8000a2a8: 00000013 nop +8000a2ac: 00000013 nop +8000a2b0: 00000013 nop +8000a2b4: 00000013 nop +8000a2b8: 00000013 nop +8000a2bc: 00000013 nop +8000a2c0: 00000013 nop +8000a2c4: 00000013 nop +8000a2c8: 00000013 nop +8000a2cc: 00000013 nop +8000a2d0: 00000013 nop +8000a2d4: 00000013 nop +8000a2d8: 00000013 nop +8000a2dc: 00000013 nop +8000a2e0: 00000013 nop +8000a2e4: 00000013 nop +8000a2e8: 00000013 nop +8000a2ec: 00000013 nop +8000a2f0: 00000013 nop +8000a2f4: 00000013 nop +8000a2f8: 00000013 nop +8000a2fc: 00000013 nop +8000a300: 00000013 nop +8000a304: 00000013 nop +8000a308: 00000013 nop +8000a30c: 00000013 nop +8000a310: 00000013 nop +8000a314: 00000013 nop +8000a318: 00000013 nop +8000a31c: 00000013 nop +8000a320: 00000013 nop +8000a324: 00000013 nop +8000a328: 00000013 nop +8000a32c: 00000013 nop +8000a330: 00000013 nop +8000a334: 00000013 nop +8000a338: 00000013 nop +8000a33c: 00000013 nop +8000a340: 00000013 nop +8000a344: 00000013 nop +8000a348: 00000013 nop +8000a34c: 00000013 nop +8000a350: 00000013 nop +8000a354: 00000013 nop +8000a358: 00000013 nop +8000a35c: 00000013 nop +8000a360: 00000013 nop +8000a364: 00000013 nop +8000a368: 00000013 nop +8000a36c: 00000013 nop +8000a370: 00000013 nop +8000a374: 00000013 nop +8000a378: 00000013 nop +8000a37c: 00000013 nop +8000a380: 00000013 nop +8000a384: 00000013 nop +8000a388: 00000013 nop +8000a38c: 00000013 nop +8000a390: 00000013 nop +8000a394: 00000013 nop +8000a398: 00000013 nop +8000a39c: 00000013 nop +8000a3a0: 00000013 nop +8000a3a4: 00000013 nop +8000a3a8: 00000013 nop +8000a3ac: 00000013 nop +8000a3b0: 00000013 nop +8000a3b4: 00000013 nop +8000a3b8: 00000013 nop +8000a3bc: 00000013 nop +8000a3c0: 00000013 nop +8000a3c4: 00000013 nop +8000a3c8: 00000013 nop +8000a3cc: 00000013 nop +8000a3d0: 00000013 nop +8000a3d4: 00000013 nop +8000a3d8: 00000013 nop +8000a3dc: 00000013 nop +8000a3e0: 00000013 nop +8000a3e4: 00000013 nop +8000a3e8: 00000013 nop +8000a3ec: 00000013 nop +8000a3f0: 00000013 nop +8000a3f4: 00000013 nop +8000a3f8: 00000013 nop +8000a3fc: 00000013 nop +8000a400: 00000013 nop +8000a404: 00000013 nop +8000a408: 00000013 nop +8000a40c: 00000013 nop +8000a410: 00000013 nop +8000a414: 00000013 nop +8000a418: 00000013 nop +8000a41c: 00000013 nop +8000a420: 00000013 nop +8000a424: 00000013 nop +8000a428: 00000013 nop +8000a42c: 00000013 nop +8000a430: 00000013 nop +8000a434: 00000013 nop +8000a438: 00000013 nop +8000a43c: 00000013 nop +8000a440: 00000013 nop +8000a444: 00000013 nop +8000a448: 00000013 nop +8000a44c: 00000013 nop +8000a450: 00000013 nop +8000a454: 00000013 nop +8000a458: 00000013 nop +8000a45c: 00000013 nop +8000a460: 00000013 nop +8000a464: 00000013 nop +8000a468: 00000013 nop +8000a46c: 00000013 nop +8000a470: 00000013 nop +8000a474: 00000013 nop +8000a478: 00000013 nop +8000a47c: 00000013 nop +8000a480: 00000013 nop +8000a484: 00000013 nop +8000a488: 00000013 nop +8000a48c: 00000013 nop +8000a490: 00000013 nop +8000a494: 00000013 nop +8000a498: 00000013 nop +8000a49c: 00000013 nop +8000a4a0: 00000013 nop +8000a4a4: 00000013 nop +8000a4a8: 00000013 nop +8000a4ac: 00000013 nop +8000a4b0: 00000013 nop +8000a4b4: 00000013 nop +8000a4b8: 00000013 nop +8000a4bc: 00000013 nop +8000a4c0: 00000013 nop +8000a4c4: 00000013 nop +8000a4c8: 00000013 nop +8000a4cc: 00000013 nop +8000a4d0: 00000013 nop +8000a4d4: 00000013 nop +8000a4d8: 00000013 nop +8000a4dc: 00000013 nop +8000a4e0: 00000013 nop +8000a4e4: 00000013 nop +8000a4e8: 00000013 nop +8000a4ec: 00000013 nop +8000a4f0: 00000013 nop +8000a4f4: 00000013 nop +8000a4f8: 00000013 nop +8000a4fc: 00000013 nop +8000a500: 00000013 nop +8000a504: 00000013 nop +8000a508: 00000013 nop +8000a50c: 00000013 nop +8000a510: 00000013 nop +8000a514: 00000013 nop +8000a518: 00000013 nop +8000a51c: 00000013 nop +8000a520: 00000013 nop +8000a524: 00000013 nop +8000a528: 00000013 nop +8000a52c: 00000013 nop +8000a530: 00000013 nop +8000a534: 00000013 nop +8000a538: 00000013 nop +8000a53c: 00000013 nop +8000a540: 00000013 nop +8000a544: 00000013 nop +8000a548: 00000013 nop +8000a54c: 00000013 nop +8000a550: 00000013 nop +8000a554: 00000013 nop +8000a558: 00000013 nop +8000a55c: 00000013 nop +8000a560: 00000013 nop +8000a564: 00000013 nop +8000a568: 00000013 nop +8000a56c: 00000013 nop +8000a570: 00000013 nop +8000a574: 00000013 nop +8000a578: 00000013 nop +8000a57c: 00000013 nop +8000a580: 00000013 nop +8000a584: 00000013 nop +8000a588: 00000013 nop +8000a58c: 00000013 nop +8000a590: 00000013 nop +8000a594: 00000013 nop +8000a598: 00000013 nop +8000a59c: 00000013 nop +8000a5a0: 00000013 nop +8000a5a4: 00000013 nop +8000a5a8: 00000013 nop +8000a5ac: 00000013 nop +8000a5b0: 00000013 nop +8000a5b4: 00000013 nop +8000a5b8: 00000013 nop +8000a5bc: 00000013 nop +8000a5c0: 00000013 nop +8000a5c4: 00000013 nop +8000a5c8: 00000013 nop +8000a5cc: 00000013 nop +8000a5d0: 00000013 nop +8000a5d4: 00000013 nop +8000a5d8: 00000013 nop +8000a5dc: 00000013 nop +8000a5e0: 00000013 nop +8000a5e4: 00000013 nop +8000a5e8: 00000013 nop +8000a5ec: 00000013 nop +8000a5f0: 00000013 nop +8000a5f4: 00000013 nop +8000a5f8: 00000013 nop +8000a5fc: 00000013 nop +8000a600: 00000013 nop +8000a604: 00000013 nop +8000a608: 00000013 nop +8000a60c: 00000013 nop +8000a610: 00000013 nop +8000a614: 00000013 nop +8000a618: 00000013 nop +8000a61c: 00000013 nop +8000a620: 00000013 nop +8000a624: 00000013 nop +8000a628: 00000013 nop +8000a62c: 00000013 nop +8000a630: 00000013 nop +8000a634: 00000013 nop +8000a638: 00000013 nop +8000a63c: 00000013 nop +8000a640: 00000013 nop +8000a644: 00000013 nop +8000a648: 00000013 nop +8000a64c: 00000013 nop +8000a650: 00000013 nop +8000a654: 00000013 nop +8000a658: 00000013 nop +8000a65c: 00000013 nop +8000a660: 00000013 nop +8000a664: 00000013 nop +8000a668: 00000013 nop +8000a66c: 00000013 nop +8000a670: 00000013 nop +8000a674: 00000013 nop +8000a678: 00000013 nop +8000a67c: 00000013 nop +8000a680: 00000013 nop +8000a684: 00000013 nop +8000a688: 00000013 nop +8000a68c: 00000013 nop +8000a690: 00000013 nop +8000a694: 00000013 nop +8000a698: 00000013 nop +8000a69c: 00000013 nop +8000a6a0: 00000013 nop +8000a6a4: 00000013 nop +8000a6a8: 00000013 nop +8000a6ac: 00000013 nop +8000a6b0: 00000013 nop +8000a6b4: 00000013 nop +8000a6b8: 00000013 nop +8000a6bc: 00000013 nop +8000a6c0: 00000013 nop +8000a6c4: 00000013 nop +8000a6c8: 00000013 nop +8000a6cc: 00000013 nop +8000a6d0: 00000013 nop +8000a6d4: 00000013 nop +8000a6d8: 00000013 nop +8000a6dc: 00000013 nop +8000a6e0: 00000013 nop +8000a6e4: 00000013 nop +8000a6e8: 00000013 nop +8000a6ec: 00000013 nop +8000a6f0: 00000013 nop +8000a6f4: 00000013 nop +8000a6f8: 00000013 nop +8000a6fc: 00000013 nop +8000a700: 00000013 nop +8000a704: 00000013 nop +8000a708: 00000013 nop +8000a70c: 00000013 nop +8000a710: 00000013 nop +8000a714: 00000013 nop +8000a718: 00000013 nop +8000a71c: 00000013 nop +8000a720: 00000013 nop +8000a724: 00000013 nop +8000a728: 00000013 nop +8000a72c: 00000013 nop +8000a730: 00000013 nop +8000a734: 00000013 nop +8000a738: 00000013 nop +8000a73c: 00000013 nop +8000a740: 00000013 nop +8000a744: 00000013 nop +8000a748: 00000013 nop +8000a74c: 00000013 nop +8000a750: 00000013 nop +8000a754: 00000013 nop +8000a758: 00000013 nop +8000a75c: 00000013 nop +8000a760: 00000013 nop +8000a764: 00000013 nop +8000a768: 00000013 nop +8000a76c: 00000013 nop +8000a770: 00000013 nop +8000a774: 00000013 nop +8000a778: 00000013 nop +8000a77c: 00000013 nop +8000a780: 00000013 nop +8000a784: 00000013 nop +8000a788: 00000013 nop +8000a78c: 00000013 nop +8000a790: 00000013 nop +8000a794: 00000013 nop +8000a798: 00000013 nop +8000a79c: 00000013 nop +8000a7a0: 00000013 nop +8000a7a4: 00000013 nop +8000a7a8: 00000013 nop +8000a7ac: 00000013 nop +8000a7b0: 00000013 nop +8000a7b4: 00000013 nop +8000a7b8: 00000013 nop +8000a7bc: 00000013 nop +8000a7c0: 00000013 nop +8000a7c4: 00000013 nop +8000a7c8: 00000013 nop +8000a7cc: 00000013 nop +8000a7d0: 00000013 nop +8000a7d4: 00000013 nop +8000a7d8: 00000013 nop +8000a7dc: 00000013 nop +8000a7e0: 00000013 nop +8000a7e4: 00000013 nop +8000a7e8: 00000013 nop +8000a7ec: 00000013 nop +8000a7f0: 00000013 nop +8000a7f4: 00000013 nop +8000a7f8: 00000013 nop +8000a7fc: 00000013 nop +8000a800: 00000013 nop +8000a804: 00000013 nop +8000a808: 00000013 nop +8000a80c: 00000013 nop +8000a810: 00000013 nop +8000a814: 00000013 nop +8000a818: 00000013 nop +8000a81c: 00000013 nop +8000a820: 00000013 nop +8000a824: 00000013 nop +8000a828: 00000013 nop +8000a82c: 00000013 nop +8000a830: 00000013 nop +8000a834: 00000013 nop +8000a838: 00000013 nop +8000a83c: 00000013 nop +8000a840: 00000013 nop +8000a844: 00000013 nop +8000a848: 00000013 nop +8000a84c: 00000013 nop +8000a850: 00000013 nop +8000a854: 00000013 nop +8000a858: 00000013 nop +8000a85c: 00000013 nop +8000a860: 00000013 nop +8000a864: 00000013 nop +8000a868: 00000013 nop +8000a86c: 00000013 nop +8000a870: 00000013 nop +8000a874: 00000013 nop +8000a878: 00000013 nop +8000a87c: 00000013 nop +8000a880: 00000013 nop +8000a884: 00000013 nop +8000a888: 00000013 nop +8000a88c: 00000013 nop +8000a890: 00000013 nop +8000a894: 00000013 nop +8000a898: 00000013 nop +8000a89c: 00000013 nop +8000a8a0: 00000013 nop +8000a8a4: 00000013 nop +8000a8a8: 00000013 nop +8000a8ac: 00000013 nop +8000a8b0: 00000013 nop +8000a8b4: 00000013 nop +8000a8b8: 00000013 nop +8000a8bc: 00000013 nop +8000a8c0: 00000013 nop +8000a8c4: 00000013 nop +8000a8c8: 00000013 nop +8000a8cc: 00000013 nop +8000a8d0: 00000013 nop +8000a8d4: 00000013 nop +8000a8d8: 00000013 nop +8000a8dc: 00000013 nop +8000a8e0: 00000013 nop +8000a8e4: 00000013 nop +8000a8e8: 00000013 nop +8000a8ec: 00000013 nop +8000a8f0: 00000013 nop +8000a8f4: 00000013 nop +8000a8f8: 00000013 nop +8000a8fc: 00000013 nop +8000a900: 00000013 nop +8000a904: 00000013 nop +8000a908: 00000013 nop +8000a90c: 00000013 nop +8000a910: 00000013 nop +8000a914: 00000013 nop +8000a918: 00000013 nop +8000a91c: 00000013 nop +8000a920: 00000013 nop +8000a924: 00000013 nop +8000a928: 00000013 nop +8000a92c: 00000013 nop +8000a930: 00000013 nop +8000a934: 00000013 nop +8000a938: 00000013 nop +8000a93c: 00000013 nop +8000a940: 00000013 nop +8000a944: 00000013 nop +8000a948: 00000013 nop +8000a94c: 00000013 nop +8000a950: 00000013 nop +8000a954: 00000013 nop +8000a958: 00000013 nop +8000a95c: 00000013 nop +8000a960: 00000013 nop +8000a964: 00000013 nop +8000a968: 00000013 nop +8000a96c: 00000013 nop +8000a970: 00000013 nop +8000a974: 00000013 nop +8000a978: 00000013 nop +8000a97c: 00000013 nop +8000a980: 00000013 nop +8000a984: 00000013 nop +8000a988: 00000013 nop +8000a98c: 00000013 nop +8000a990: 00000013 nop +8000a994: 00000013 nop +8000a998: 00000013 nop +8000a99c: 00000013 nop +8000a9a0: 00000013 nop +8000a9a4: 00000013 nop +8000a9a8: 00000013 nop +8000a9ac: 00000013 nop +8000a9b0: 00000013 nop +8000a9b4: 00000013 nop +8000a9b8: 00000013 nop +8000a9bc: 00000013 nop +8000a9c0: 00000013 nop +8000a9c4: 00000013 nop +8000a9c8: 00000013 nop +8000a9cc: 00000013 nop +8000a9d0: 00000013 nop +8000a9d4: 00000013 nop +8000a9d8: 00000013 nop +8000a9dc: 00000013 nop +8000a9e0: 00000013 nop +8000a9e4: 00000013 nop +8000a9e8: 00000013 nop +8000a9ec: 00000013 nop +8000a9f0: 00000013 nop +8000a9f4: 00000013 nop +8000a9f8: 00000013 nop +8000a9fc: 00000013 nop +8000aa00: 00000013 nop +8000aa04: 00000013 nop +8000aa08: 00000013 nop +8000aa0c: 00000013 nop +8000aa10: 00000013 nop +8000aa14: 00000013 nop +8000aa18: 00000013 nop +8000aa1c: 00000013 nop +8000aa20: 00000013 nop +8000aa24: 00000013 nop +8000aa28: 00000013 nop +8000aa2c: 00000013 nop +8000aa30: 00000013 nop +8000aa34: 00000013 nop +8000aa38: 00000013 nop +8000aa3c: 00000013 nop +8000aa40: 00000013 nop +8000aa44: 00000013 nop +8000aa48: 00000013 nop +8000aa4c: 00000013 nop +8000aa50: 00000013 nop +8000aa54: 00000013 nop +8000aa58: 00000013 nop +8000aa5c: 00000013 nop +8000aa60: 00000013 nop +8000aa64: 00000013 nop +8000aa68: 00000013 nop +8000aa6c: 00000013 nop +8000aa70: 00000013 nop +8000aa74: 00000013 nop +8000aa78: 00000013 nop +8000aa7c: 00000013 nop +8000aa80: 00000013 nop +8000aa84: 00000013 nop +8000aa88: 00000013 nop +8000aa8c: 00000013 nop +8000aa90: 00000013 nop +8000aa94: 00000013 nop +8000aa98: 00000013 nop +8000aa9c: 00000013 nop +8000aaa0: 00000013 nop +8000aaa4: 00000013 nop +8000aaa8: 00000013 nop +8000aaac: 00000013 nop +8000aab0: 00000013 nop +8000aab4: 00000013 nop +8000aab8: 00000013 nop +8000aabc: 00000013 nop +8000aac0: 00000013 nop +8000aac4: 00000013 nop +8000aac8: 00000013 nop +8000aacc: 00000013 nop +8000aad0: 00000013 nop +8000aad4: 00000013 nop +8000aad8: 00000013 nop +8000aadc: 00000013 nop +8000aae0: 00000013 nop +8000aae4: 00000013 nop +8000aae8: 00000013 nop +8000aaec: 00000013 nop +8000aaf0: 00000013 nop +8000aaf4: 00000013 nop +8000aaf8: 00000013 nop +8000aafc: 00000013 nop +8000ab00: 00000013 nop +8000ab04: 00000013 nop +8000ab08: 00000013 nop +8000ab0c: 00000013 nop +8000ab10: 00000013 nop +8000ab14: 00000013 nop +8000ab18: 00000013 nop +8000ab1c: 00000013 nop +8000ab20: 00000013 nop +8000ab24: 00000013 nop +8000ab28: 00000013 nop +8000ab2c: 00000013 nop +8000ab30: 00000013 nop +8000ab34: 00000013 nop +8000ab38: 00000013 nop +8000ab3c: 00000013 nop +8000ab40: 00000013 nop +8000ab44: 00000013 nop +8000ab48: 00000013 nop +8000ab4c: 00000013 nop +8000ab50: 00000013 nop +8000ab54: 00000013 nop +8000ab58: 00000013 nop +8000ab5c: 00000013 nop +8000ab60: 00000013 nop +8000ab64: 00000013 nop +8000ab68: 00000013 nop +8000ab6c: 00000013 nop +8000ab70: 00000013 nop +8000ab74: 00000013 nop +8000ab78: 00000013 nop +8000ab7c: 00000013 nop +8000ab80: 00000013 nop +8000ab84: 00000013 nop +8000ab88: 00000013 nop +8000ab8c: 00000013 nop +8000ab90: 00000013 nop +8000ab94: 00000013 nop +8000ab98: 00000013 nop +8000ab9c: 00000013 nop +8000aba0: 00000013 nop +8000aba4: 00000013 nop +8000aba8: 00000013 nop +8000abac: 00000013 nop +8000abb0: 00000013 nop +8000abb4: 00000013 nop +8000abb8: 00000013 nop +8000abbc: 00000013 nop +8000abc0: 00000013 nop +8000abc4: 00000013 nop +8000abc8: 00000013 nop +8000abcc: 00000013 nop +8000abd0: 00000013 nop +8000abd4: 00000013 nop +8000abd8: 00000013 nop +8000abdc: 00000013 nop +8000abe0: 00000013 nop +8000abe4: 00000013 nop +8000abe8: 00000013 nop +8000abec: 00000013 nop +8000abf0: 00000013 nop +8000abf4: 00000013 nop +8000abf8: 00000013 nop +8000abfc: 00000013 nop +8000ac00: 00000013 nop +8000ac04: 00000013 nop +8000ac08: 00000013 nop +8000ac0c: 00000013 nop +8000ac10: 00000013 nop +8000ac14: 00000013 nop +8000ac18: 00000013 nop +8000ac1c: 00000013 nop +8000ac20: 00000013 nop +8000ac24: 00000013 nop +8000ac28: 00000013 nop +8000ac2c: 00000013 nop +8000ac30: 00000013 nop +8000ac34: 00000013 nop +8000ac38: 00000013 nop +8000ac3c: 00000013 nop +8000ac40: 00000013 nop +8000ac44: 00000013 nop +8000ac48: 00000013 nop +8000ac4c: 00000013 nop +8000ac50: 00000013 nop +8000ac54: 00000013 nop +8000ac58: 00000013 nop +8000ac5c: 00000013 nop +8000ac60: 00000013 nop +8000ac64: 00000013 nop +8000ac68: 00000013 nop +8000ac6c: 00000013 nop +8000ac70: 00000013 nop +8000ac74: 00000013 nop +8000ac78: 00000013 nop +8000ac7c: 00000013 nop +8000ac80: 00000013 nop +8000ac84: 00000013 nop +8000ac88: 00000013 nop +8000ac8c: 00000013 nop +8000ac90: 00000013 nop +8000ac94: 00000013 nop +8000ac98: 00000013 nop +8000ac9c: 00000013 nop +8000aca0: 00000013 nop +8000aca4: 00000013 nop +8000aca8: 00000013 nop +8000acac: 00000013 nop +8000acb0: 00000013 nop +8000acb4: 00000013 nop +8000acb8: 00000013 nop +8000acbc: 00000013 nop +8000acc0: 00000013 nop +8000acc4: 00000013 nop +8000acc8: 00000013 nop +8000accc: 00000013 nop +8000acd0: 00000013 nop +8000acd4: 00000013 nop +8000acd8: 00000013 nop +8000acdc: 00000013 nop +8000ace0: 00000013 nop +8000ace4: 00000013 nop +8000ace8: 00000013 nop +8000acec: 00000013 nop +8000acf0: 00000013 nop +8000acf4: 00000013 nop +8000acf8: 00000013 nop +8000acfc: 00000013 nop +8000ad00: 00000013 nop +8000ad04: 00000013 nop +8000ad08: 00000013 nop +8000ad0c: 00000013 nop +8000ad10: 00000013 nop +8000ad14: 00000013 nop +8000ad18: 00000013 nop +8000ad1c: 00000013 nop +8000ad20: 00000013 nop +8000ad24: 00000013 nop +8000ad28: 00000013 nop +8000ad2c: 00000013 nop +8000ad30: 00000013 nop +8000ad34: 00000013 nop +8000ad38: 00000013 nop +8000ad3c: 00000013 nop +8000ad40: 00000013 nop +8000ad44: 00000013 nop +8000ad48: 00000013 nop +8000ad4c: 00000013 nop +8000ad50: 00000013 nop +8000ad54: 00000013 nop +8000ad58: 00000013 nop +8000ad5c: 00000013 nop +8000ad60: 00000013 nop +8000ad64: 00000013 nop +8000ad68: 00000013 nop +8000ad6c: 00000013 nop +8000ad70: 00000013 nop +8000ad74: 00000013 nop +8000ad78: 00000013 nop +8000ad7c: 00000013 nop +8000ad80: 00000013 nop +8000ad84: 00000013 nop +8000ad88: 00000013 nop +8000ad8c: 00000013 nop +8000ad90: 00000013 nop +8000ad94: 00000013 nop +8000ad98: 00000013 nop +8000ad9c: 00000013 nop +8000ada0: 00000013 nop +8000ada4: 00000013 nop +8000ada8: 00000013 nop +8000adac: 00000013 nop +8000adb0: 00000013 nop +8000adb4: 00000013 nop +8000adb8: 00000013 nop +8000adbc: 00000013 nop +8000adc0: 00000013 nop +8000adc4: 00000013 nop +8000adc8: 00000013 nop +8000adcc: 00000013 nop +8000add0: 00000013 nop +8000add4: 00000013 nop +8000add8: 00000013 nop +8000addc: 00000013 nop +8000ade0: 00000013 nop +8000ade4: 00000013 nop +8000ade8: 00000013 nop +8000adec: 00000013 nop +8000adf0: 00000013 nop +8000adf4: 00000013 nop +8000adf8: 00000013 nop +8000adfc: 00000013 nop +8000ae00: 00000013 nop +8000ae04: 00000013 nop +8000ae08: 00000013 nop +8000ae0c: 00000013 nop +8000ae10: 00000013 nop +8000ae14: 00000013 nop +8000ae18: 00000013 nop +8000ae1c: 00000013 nop +8000ae20: 00000013 nop +8000ae24: 00000013 nop +8000ae28: 00000013 nop +8000ae2c: 00000013 nop +8000ae30: 00000013 nop +8000ae34: 00000013 nop +8000ae38: 00000013 nop +8000ae3c: 00000013 nop +8000ae40: 00000013 nop +8000ae44: 00000013 nop +8000ae48: 00000013 nop +8000ae4c: 00000013 nop +8000ae50: 00000013 nop +8000ae54: 00000013 nop +8000ae58: 00000013 nop +8000ae5c: 00000013 nop +8000ae60: 00000013 nop +8000ae64: 00000013 nop +8000ae68: 00000013 nop +8000ae6c: 00000013 nop +8000ae70: 00000013 nop +8000ae74: 00000013 nop +8000ae78: 00000013 nop +8000ae7c: 00000013 nop +8000ae80: 00000013 nop +8000ae84: 00000013 nop +8000ae88: 00000013 nop +8000ae8c: 00000013 nop +8000ae90: 00000013 nop +8000ae94: 00000013 nop +8000ae98: 00000013 nop +8000ae9c: 00000013 nop +8000aea0: 00000013 nop +8000aea4: 00000013 nop +8000aea8: 00000013 nop +8000aeac: 00000013 nop +8000aeb0: 00000013 nop +8000aeb4: 00000013 nop +8000aeb8: 00000013 nop +8000aebc: 00000013 nop +8000aec0: 00000013 nop +8000aec4: 00000013 nop +8000aec8: 00000013 nop +8000aecc: 00000013 nop +8000aed0: 00000013 nop +8000aed4: 00000013 nop +8000aed8: 00000013 nop +8000aedc: 00000013 nop +8000aee0: 00000013 nop +8000aee4: 00000013 nop +8000aee8: 00000013 nop +8000aeec: 00000013 nop +8000aef0: 00000013 nop +8000aef4: 00000013 nop +8000aef8: 00000013 nop +8000aefc: 00000013 nop +8000af00: 00000013 nop +8000af04: 00000013 nop +8000af08: 00000013 nop +8000af0c: 00000013 nop +8000af10: 00000013 nop +8000af14: 00000013 nop +8000af18: 00000013 nop +8000af1c: 00000013 nop +8000af20: 00000013 nop +8000af24: 00000013 nop +8000af28: 00000013 nop +8000af2c: 00000013 nop +8000af30: 00000013 nop +8000af34: 00000013 nop +8000af38: 00000013 nop +8000af3c: 00000013 nop +8000af40: 00000013 nop +8000af44: 00000013 nop +8000af48: 00000013 nop +8000af4c: 00000013 nop +8000af50: 00000013 nop +8000af54: 00000013 nop +8000af58: 00000013 nop +8000af5c: 00000013 nop +8000af60: 00000013 nop +8000af64: 00000013 nop +8000af68: 00000013 nop +8000af6c: 00000013 nop +8000af70: 00000013 nop +8000af74: 00000013 nop +8000af78: 00000013 nop +8000af7c: 00000013 nop +8000af80: 00000013 nop +8000af84: 00000013 nop +8000af88: 00000013 nop +8000af8c: 00000013 nop +8000af90: 00000013 nop +8000af94: 00000013 nop +8000af98: 00000013 nop +8000af9c: 00000013 nop +8000afa0: 00000013 nop +8000afa4: 00000013 nop +8000afa8: 00000013 nop +8000afac: 00000013 nop +8000afb0: 00000013 nop +8000afb4: 00000013 nop +8000afb8: 00000013 nop +8000afbc: 00000013 nop +8000afc0: 00000013 nop +8000afc4: 00000013 nop +8000afc8: 00000013 nop +8000afcc: 00000013 nop +8000afd0: 00000013 nop +8000afd4: 00000013 nop +8000afd8: 00000013 nop +8000afdc: 00000013 nop +8000afe0: 00000013 nop +8000afe4: 00000013 nop +8000afe8: 00000013 nop +8000afec: 00000013 nop +8000aff0: 00000013 nop +8000aff4: 00000013 nop +8000aff8: 00000013 nop +8000affc: 00000013 nop + +8000b000 : +8000b000: 6160 flw fs0,68(a0) +8000b002: 6362 flw ft6,24(sp) +8000b004: 6564 flw fs1,76(a0) +8000b006: 6766 flw fa4,88(sp) +8000b008: 6968 flw fa0,84(a0) +8000b00a: 6b6a flw fs6,152(sp) +8000b00c: 6d6c flw fa1,92(a0) +8000b00e: 6f6e flw ft10,216(sp) +8000b010: 00000013 nop +8000b014: 00000013 nop +8000b018: 00000013 nop +8000b01c: 00000013 nop +8000b020: 00000013 nop +8000b024: 00000013 nop +8000b028: 00000013 nop +8000b02c: 00000013 nop +8000b030: 00000013 nop +8000b034: 00000013 nop +8000b038: 00000013 nop +8000b03c: 00000013 nop +8000b040: 00000013 nop +8000b044: 00000013 nop +8000b048: 00000013 nop +8000b04c: 00000013 nop +8000b050: 00000013 nop +8000b054: 00000013 nop +8000b058: 00000013 nop +8000b05c: 00000013 nop +8000b060: 00000013 nop +8000b064: 00000013 nop +8000b068: 00000013 nop +8000b06c: 00000013 nop +8000b070: 00000013 nop +8000b074: 00000013 nop +8000b078: 00000013 nop +8000b07c: 00000013 nop +8000b080: 00000013 nop +8000b084: 00000013 nop +8000b088: 00000013 nop +8000b08c: 00000013 nop +8000b090: 00000013 nop +8000b094: 00000013 nop +8000b098: 00000013 nop +8000b09c: 00000013 nop +8000b0a0: 00000013 nop +8000b0a4: 00000013 nop +8000b0a8: 00000013 nop +8000b0ac: 00000013 nop +8000b0b0: 00000013 nop +8000b0b4: 00000013 nop +8000b0b8: 00000013 nop +8000b0bc: 00000013 nop +8000b0c0: 00000013 nop +8000b0c4: 00000013 nop +8000b0c8: 00000013 nop +8000b0cc: 00000013 nop +8000b0d0: 00000013 nop +8000b0d4: 00000013 nop +8000b0d8: 00000013 nop +8000b0dc: 00000013 nop +8000b0e0: 00000013 nop +8000b0e4: 00000013 nop +8000b0e8: 00000013 nop +8000b0ec: 00000013 nop +8000b0f0: 00000013 nop +8000b0f4: 00000013 nop +8000b0f8: 00000013 nop +8000b0fc: 00000013 nop +8000b100: 00000013 nop +8000b104: 00000013 nop +8000b108: 00000013 nop +8000b10c: 00000013 nop +8000b110: 00000013 nop +8000b114: 00000013 nop +8000b118: 00000013 nop +8000b11c: 00000013 nop +8000b120: 00000013 nop +8000b124: 00000013 nop +8000b128: 00000013 nop +8000b12c: 00000013 nop +8000b130: 00000013 nop +8000b134: 00000013 nop +8000b138: 00000013 nop +8000b13c: 00000013 nop +8000b140: 00000013 nop +8000b144: 00000013 nop +8000b148: 00000013 nop +8000b14c: 00000013 nop +8000b150: 00000013 nop +8000b154: 00000013 nop +8000b158: 00000013 nop +8000b15c: 00000013 nop +8000b160: 00000013 nop +8000b164: 00000013 nop +8000b168: 00000013 nop +8000b16c: 00000013 nop +8000b170: 00000013 nop +8000b174: 00000013 nop +8000b178: 00000013 nop +8000b17c: 00000013 nop +8000b180: 00000013 nop +8000b184: 00000013 nop +8000b188: 00000013 nop +8000b18c: 00000013 nop +8000b190: 00000013 nop +8000b194: 00000013 nop +8000b198: 00000013 nop +8000b19c: 00000013 nop +8000b1a0: 00000013 nop +8000b1a4: 00000013 nop +8000b1a8: 00000013 nop +8000b1ac: 00000013 nop +8000b1b0: 00000013 nop +8000b1b4: 00000013 nop +8000b1b8: 00000013 nop +8000b1bc: 00000013 nop +8000b1c0: 00000013 nop +8000b1c4: 00000013 nop +8000b1c8: 00000013 nop +8000b1cc: 00000013 nop +8000b1d0: 00000013 nop +8000b1d4: 00000013 nop +8000b1d8: 00000013 nop +8000b1dc: 00000013 nop +8000b1e0: 00000013 nop +8000b1e4: 00000013 nop +8000b1e8: 00000013 nop +8000b1ec: 00000013 nop +8000b1f0: 00000013 nop +8000b1f4: 00000013 nop +8000b1f8: 00000013 nop +8000b1fc: 00000013 nop +8000b200: 00000013 nop +8000b204: 00000013 nop +8000b208: 00000013 nop +8000b20c: 00000013 nop +8000b210: 00000013 nop +8000b214: 00000013 nop +8000b218: 00000013 nop +8000b21c: 00000013 nop +8000b220: 00000013 nop +8000b224: 00000013 nop +8000b228: 00000013 nop +8000b22c: 00000013 nop +8000b230: 00000013 nop +8000b234: 00000013 nop +8000b238: 00000013 nop +8000b23c: 00000013 nop +8000b240: 00000013 nop +8000b244: 00000013 nop +8000b248: 00000013 nop +8000b24c: 00000013 nop +8000b250: 00000013 nop +8000b254: 00000013 nop +8000b258: 00000013 nop +8000b25c: 00000013 nop +8000b260: 00000013 nop +8000b264: 00000013 nop +8000b268: 00000013 nop +8000b26c: 00000013 nop +8000b270: 00000013 nop +8000b274: 00000013 nop +8000b278: 00000013 nop +8000b27c: 00000013 nop +8000b280: 00000013 nop +8000b284: 00000013 nop +8000b288: 00000013 nop +8000b28c: 00000013 nop +8000b290: 00000013 nop +8000b294: 00000013 nop +8000b298: 00000013 nop +8000b29c: 00000013 nop +8000b2a0: 00000013 nop +8000b2a4: 00000013 nop +8000b2a8: 00000013 nop +8000b2ac: 00000013 nop +8000b2b0: 00000013 nop +8000b2b4: 00000013 nop +8000b2b8: 00000013 nop +8000b2bc: 00000013 nop +8000b2c0: 00000013 nop +8000b2c4: 00000013 nop +8000b2c8: 00000013 nop +8000b2cc: 00000013 nop +8000b2d0: 00000013 nop +8000b2d4: 00000013 nop +8000b2d8: 00000013 nop +8000b2dc: 00000013 nop +8000b2e0: 00000013 nop +8000b2e4: 00000013 nop +8000b2e8: 00000013 nop +8000b2ec: 00000013 nop +8000b2f0: 00000013 nop +8000b2f4: 00000013 nop +8000b2f8: 00000013 nop +8000b2fc: 00000013 nop +8000b300: 00000013 nop +8000b304: 00000013 nop +8000b308: 00000013 nop +8000b30c: 00000013 nop +8000b310: 00000013 nop +8000b314: 00000013 nop +8000b318: 00000013 nop +8000b31c: 00000013 nop +8000b320: 00000013 nop +8000b324: 00000013 nop +8000b328: 00000013 nop +8000b32c: 00000013 nop +8000b330: 00000013 nop +8000b334: 00000013 nop +8000b338: 00000013 nop +8000b33c: 00000013 nop +8000b340: 00000013 nop +8000b344: 00000013 nop +8000b348: 00000013 nop +8000b34c: 00000013 nop +8000b350: 00000013 nop +8000b354: 00000013 nop +8000b358: 00000013 nop +8000b35c: 00000013 nop +8000b360: 00000013 nop +8000b364: 00000013 nop +8000b368: 00000013 nop +8000b36c: 00000013 nop +8000b370: 00000013 nop +8000b374: 00000013 nop +8000b378: 00000013 nop +8000b37c: 00000013 nop +8000b380: 00000013 nop +8000b384: 00000013 nop +8000b388: 00000013 nop +8000b38c: 00000013 nop +8000b390: 00000013 nop +8000b394: 00000013 nop +8000b398: 00000013 nop +8000b39c: 00000013 nop +8000b3a0: 00000013 nop +8000b3a4: 00000013 nop +8000b3a8: 00000013 nop +8000b3ac: 00000013 nop +8000b3b0: 00000013 nop +8000b3b4: 00000013 nop +8000b3b8: 00000013 nop +8000b3bc: 00000013 nop +8000b3c0: 00000013 nop +8000b3c4: 00000013 nop +8000b3c8: 00000013 nop +8000b3cc: 00000013 nop +8000b3d0: 00000013 nop +8000b3d4: 00000013 nop +8000b3d8: 00000013 nop +8000b3dc: 00000013 nop +8000b3e0: 00000013 nop +8000b3e4: 00000013 nop +8000b3e8: 00000013 nop +8000b3ec: 00000013 nop +8000b3f0: 00000013 nop +8000b3f4: 00000013 nop +8000b3f8: 00000013 nop +8000b3fc: 00000013 nop +8000b400: 00000013 nop +8000b404: 00000013 nop +8000b408: 00000013 nop +8000b40c: 00000013 nop +8000b410: 00000013 nop +8000b414: 00000013 nop +8000b418: 00000013 nop +8000b41c: 00000013 nop +8000b420: 00000013 nop +8000b424: 00000013 nop +8000b428: 00000013 nop +8000b42c: 00000013 nop +8000b430: 00000013 nop +8000b434: 00000013 nop +8000b438: 00000013 nop +8000b43c: 00000013 nop +8000b440: 00000013 nop +8000b444: 00000013 nop +8000b448: 00000013 nop +8000b44c: 00000013 nop +8000b450: 00000013 nop +8000b454: 00000013 nop +8000b458: 00000013 nop +8000b45c: 00000013 nop +8000b460: 00000013 nop +8000b464: 00000013 nop +8000b468: 00000013 nop +8000b46c: 00000013 nop +8000b470: 00000013 nop +8000b474: 00000013 nop +8000b478: 00000013 nop +8000b47c: 00000013 nop +8000b480: 00000013 nop +8000b484: 00000013 nop +8000b488: 00000013 nop +8000b48c: 00000013 nop +8000b490: 00000013 nop +8000b494: 00000013 nop +8000b498: 00000013 nop +8000b49c: 00000013 nop +8000b4a0: 00000013 nop +8000b4a4: 00000013 nop +8000b4a8: 00000013 nop +8000b4ac: 00000013 nop +8000b4b0: 00000013 nop +8000b4b4: 00000013 nop +8000b4b8: 00000013 nop +8000b4bc: 00000013 nop +8000b4c0: 00000013 nop +8000b4c4: 00000013 nop +8000b4c8: 00000013 nop +8000b4cc: 00000013 nop +8000b4d0: 00000013 nop +8000b4d4: 00000013 nop +8000b4d8: 00000013 nop +8000b4dc: 00000013 nop +8000b4e0: 00000013 nop +8000b4e4: 00000013 nop +8000b4e8: 00000013 nop +8000b4ec: 00000013 nop +8000b4f0: 00000013 nop +8000b4f4: 00000013 nop +8000b4f8: 00000013 nop +8000b4fc: 00000013 nop +8000b500: 00000013 nop +8000b504: 00000013 nop +8000b508: 00000013 nop +8000b50c: 00000013 nop +8000b510: 00000013 nop +8000b514: 00000013 nop +8000b518: 00000013 nop +8000b51c: 00000013 nop +8000b520: 00000013 nop +8000b524: 00000013 nop +8000b528: 00000013 nop +8000b52c: 00000013 nop +8000b530: 00000013 nop +8000b534: 00000013 nop +8000b538: 00000013 nop +8000b53c: 00000013 nop +8000b540: 00000013 nop +8000b544: 00000013 nop +8000b548: 00000013 nop +8000b54c: 00000013 nop +8000b550: 00000013 nop +8000b554: 00000013 nop +8000b558: 00000013 nop +8000b55c: 00000013 nop +8000b560: 00000013 nop +8000b564: 00000013 nop +8000b568: 00000013 nop +8000b56c: 00000013 nop +8000b570: 00000013 nop +8000b574: 00000013 nop +8000b578: 00000013 nop +8000b57c: 00000013 nop +8000b580: 00000013 nop +8000b584: 00000013 nop +8000b588: 00000013 nop +8000b58c: 00000013 nop +8000b590: 00000013 nop +8000b594: 00000013 nop +8000b598: 00000013 nop +8000b59c: 00000013 nop +8000b5a0: 00000013 nop +8000b5a4: 00000013 nop +8000b5a8: 00000013 nop +8000b5ac: 00000013 nop +8000b5b0: 00000013 nop +8000b5b4: 00000013 nop +8000b5b8: 00000013 nop +8000b5bc: 00000013 nop +8000b5c0: 00000013 nop +8000b5c4: 00000013 nop +8000b5c8: 00000013 nop +8000b5cc: 00000013 nop +8000b5d0: 00000013 nop +8000b5d4: 00000013 nop +8000b5d8: 00000013 nop +8000b5dc: 00000013 nop +8000b5e0: 00000013 nop +8000b5e4: 00000013 nop +8000b5e8: 00000013 nop +8000b5ec: 00000013 nop +8000b5f0: 00000013 nop +8000b5f4: 00000013 nop +8000b5f8: 00000013 nop +8000b5fc: 00000013 nop +8000b600: 00000013 nop +8000b604: 00000013 nop +8000b608: 00000013 nop +8000b60c: 00000013 nop +8000b610: 00000013 nop +8000b614: 00000013 nop +8000b618: 00000013 nop +8000b61c: 00000013 nop +8000b620: 00000013 nop +8000b624: 00000013 nop +8000b628: 00000013 nop +8000b62c: 00000013 nop +8000b630: 00000013 nop +8000b634: 00000013 nop +8000b638: 00000013 nop +8000b63c: 00000013 nop +8000b640: 00000013 nop +8000b644: 00000013 nop +8000b648: 00000013 nop +8000b64c: 00000013 nop +8000b650: 00000013 nop +8000b654: 00000013 nop +8000b658: 00000013 nop +8000b65c: 00000013 nop +8000b660: 00000013 nop +8000b664: 00000013 nop +8000b668: 00000013 nop +8000b66c: 00000013 nop +8000b670: 00000013 nop +8000b674: 00000013 nop +8000b678: 00000013 nop +8000b67c: 00000013 nop +8000b680: 00000013 nop +8000b684: 00000013 nop +8000b688: 00000013 nop +8000b68c: 00000013 nop +8000b690: 00000013 nop +8000b694: 00000013 nop +8000b698: 00000013 nop +8000b69c: 00000013 nop +8000b6a0: 00000013 nop +8000b6a4: 00000013 nop +8000b6a8: 00000013 nop +8000b6ac: 00000013 nop +8000b6b0: 00000013 nop +8000b6b4: 00000013 nop +8000b6b8: 00000013 nop +8000b6bc: 00000013 nop +8000b6c0: 00000013 nop +8000b6c4: 00000013 nop +8000b6c8: 00000013 nop +8000b6cc: 00000013 nop +8000b6d0: 00000013 nop +8000b6d4: 00000013 nop +8000b6d8: 00000013 nop +8000b6dc: 00000013 nop +8000b6e0: 00000013 nop +8000b6e4: 00000013 nop +8000b6e8: 00000013 nop +8000b6ec: 00000013 nop +8000b6f0: 00000013 nop +8000b6f4: 00000013 nop +8000b6f8: 00000013 nop +8000b6fc: 00000013 nop +8000b700: 00000013 nop +8000b704: 00000013 nop +8000b708: 00000013 nop +8000b70c: 00000013 nop +8000b710: 00000013 nop +8000b714: 00000013 nop +8000b718: 00000013 nop +8000b71c: 00000013 nop +8000b720: 00000013 nop +8000b724: 00000013 nop +8000b728: 00000013 nop +8000b72c: 00000013 nop +8000b730: 00000013 nop +8000b734: 00000013 nop +8000b738: 00000013 nop +8000b73c: 00000013 nop +8000b740: 00000013 nop +8000b744: 00000013 nop +8000b748: 00000013 nop +8000b74c: 00000013 nop +8000b750: 00000013 nop +8000b754: 00000013 nop +8000b758: 00000013 nop +8000b75c: 00000013 nop +8000b760: 00000013 nop +8000b764: 00000013 nop +8000b768: 00000013 nop +8000b76c: 00000013 nop +8000b770: 00000013 nop +8000b774: 00000013 nop +8000b778: 00000013 nop +8000b77c: 00000013 nop +8000b780: 00000013 nop +8000b784: 00000013 nop +8000b788: 00000013 nop +8000b78c: 00000013 nop +8000b790: 00000013 nop +8000b794: 00000013 nop +8000b798: 00000013 nop +8000b79c: 00000013 nop +8000b7a0: 00000013 nop +8000b7a4: 00000013 nop +8000b7a8: 00000013 nop +8000b7ac: 00000013 nop +8000b7b0: 00000013 nop +8000b7b4: 00000013 nop +8000b7b8: 00000013 nop +8000b7bc: 00000013 nop +8000b7c0: 00000013 nop +8000b7c4: 00000013 nop +8000b7c8: 00000013 nop +8000b7cc: 00000013 nop +8000b7d0: 00000013 nop +8000b7d4: 00000013 nop +8000b7d8: 00000013 nop +8000b7dc: 00000013 nop +8000b7e0: 00000013 nop +8000b7e4: 00000013 nop +8000b7e8: 00000013 nop +8000b7ec: 00000013 nop +8000b7f0: 00000013 nop +8000b7f4: 00000013 nop +8000b7f8: 00000013 nop +8000b7fc: 00000013 nop +8000b800: 00000013 nop +8000b804: 00000013 nop +8000b808: 00000013 nop +8000b80c: 00000013 nop +8000b810: 00000013 nop +8000b814: 00000013 nop +8000b818: 00000013 nop +8000b81c: 00000013 nop +8000b820: 00000013 nop +8000b824: 00000013 nop +8000b828: 00000013 nop +8000b82c: 00000013 nop +8000b830: 00000013 nop +8000b834: 00000013 nop +8000b838: 00000013 nop +8000b83c: 00000013 nop +8000b840: 00000013 nop +8000b844: 00000013 nop +8000b848: 00000013 nop +8000b84c: 00000013 nop +8000b850: 00000013 nop +8000b854: 00000013 nop +8000b858: 00000013 nop +8000b85c: 00000013 nop +8000b860: 00000013 nop +8000b864: 00000013 nop +8000b868: 00000013 nop +8000b86c: 00000013 nop +8000b870: 00000013 nop +8000b874: 00000013 nop +8000b878: 00000013 nop +8000b87c: 00000013 nop +8000b880: 00000013 nop +8000b884: 00000013 nop +8000b888: 00000013 nop +8000b88c: 00000013 nop +8000b890: 00000013 nop +8000b894: 00000013 nop +8000b898: 00000013 nop +8000b89c: 00000013 nop +8000b8a0: 00000013 nop +8000b8a4: 00000013 nop +8000b8a8: 00000013 nop +8000b8ac: 00000013 nop +8000b8b0: 00000013 nop +8000b8b4: 00000013 nop +8000b8b8: 00000013 nop +8000b8bc: 00000013 nop +8000b8c0: 00000013 nop +8000b8c4: 00000013 nop +8000b8c8: 00000013 nop +8000b8cc: 00000013 nop +8000b8d0: 00000013 nop +8000b8d4: 00000013 nop +8000b8d8: 00000013 nop +8000b8dc: 00000013 nop +8000b8e0: 00000013 nop +8000b8e4: 00000013 nop +8000b8e8: 00000013 nop +8000b8ec: 00000013 nop +8000b8f0: 00000013 nop +8000b8f4: 00000013 nop +8000b8f8: 00000013 nop +8000b8fc: 00000013 nop +8000b900: 00000013 nop +8000b904: 00000013 nop +8000b908: 00000013 nop +8000b90c: 00000013 nop +8000b910: 00000013 nop +8000b914: 00000013 nop +8000b918: 00000013 nop +8000b91c: 00000013 nop +8000b920: 00000013 nop +8000b924: 00000013 nop +8000b928: 00000013 nop +8000b92c: 00000013 nop +8000b930: 00000013 nop +8000b934: 00000013 nop +8000b938: 00000013 nop +8000b93c: 00000013 nop +8000b940: 00000013 nop +8000b944: 00000013 nop +8000b948: 00000013 nop +8000b94c: 00000013 nop +8000b950: 00000013 nop +8000b954: 00000013 nop +8000b958: 00000013 nop +8000b95c: 00000013 nop +8000b960: 00000013 nop +8000b964: 00000013 nop +8000b968: 00000013 nop +8000b96c: 00000013 nop +8000b970: 00000013 nop +8000b974: 00000013 nop +8000b978: 00000013 nop +8000b97c: 00000013 nop +8000b980: 00000013 nop +8000b984: 00000013 nop +8000b988: 00000013 nop +8000b98c: 00000013 nop +8000b990: 00000013 nop +8000b994: 00000013 nop +8000b998: 00000013 nop +8000b99c: 00000013 nop +8000b9a0: 00000013 nop +8000b9a4: 00000013 nop +8000b9a8: 00000013 nop +8000b9ac: 00000013 nop +8000b9b0: 00000013 nop +8000b9b4: 00000013 nop +8000b9b8: 00000013 nop +8000b9bc: 00000013 nop +8000b9c0: 00000013 nop +8000b9c4: 00000013 nop +8000b9c8: 00000013 nop +8000b9cc: 00000013 nop +8000b9d0: 00000013 nop +8000b9d4: 00000013 nop +8000b9d8: 00000013 nop +8000b9dc: 00000013 nop +8000b9e0: 00000013 nop +8000b9e4: 00000013 nop +8000b9e8: 00000013 nop +8000b9ec: 00000013 nop +8000b9f0: 00000013 nop +8000b9f4: 00000013 nop +8000b9f8: 00000013 nop +8000b9fc: 00000013 nop +8000ba00: 00000013 nop +8000ba04: 00000013 nop +8000ba08: 00000013 nop +8000ba0c: 00000013 nop +8000ba10: 00000013 nop +8000ba14: 00000013 nop +8000ba18: 00000013 nop +8000ba1c: 00000013 nop +8000ba20: 00000013 nop +8000ba24: 00000013 nop +8000ba28: 00000013 nop +8000ba2c: 00000013 nop +8000ba30: 00000013 nop +8000ba34: 00000013 nop +8000ba38: 00000013 nop +8000ba3c: 00000013 nop +8000ba40: 00000013 nop +8000ba44: 00000013 nop +8000ba48: 00000013 nop +8000ba4c: 00000013 nop +8000ba50: 00000013 nop +8000ba54: 00000013 nop +8000ba58: 00000013 nop +8000ba5c: 00000013 nop +8000ba60: 00000013 nop +8000ba64: 00000013 nop +8000ba68: 00000013 nop +8000ba6c: 00000013 nop +8000ba70: 00000013 nop +8000ba74: 00000013 nop +8000ba78: 00000013 nop +8000ba7c: 00000013 nop +8000ba80: 00000013 nop +8000ba84: 00000013 nop +8000ba88: 00000013 nop +8000ba8c: 00000013 nop +8000ba90: 00000013 nop +8000ba94: 00000013 nop +8000ba98: 00000013 nop +8000ba9c: 00000013 nop +8000baa0: 00000013 nop +8000baa4: 00000013 nop +8000baa8: 00000013 nop +8000baac: 00000013 nop +8000bab0: 00000013 nop +8000bab4: 00000013 nop +8000bab8: 00000013 nop +8000babc: 00000013 nop +8000bac0: 00000013 nop +8000bac4: 00000013 nop +8000bac8: 00000013 nop +8000bacc: 00000013 nop +8000bad0: 00000013 nop +8000bad4: 00000013 nop +8000bad8: 00000013 nop +8000badc: 00000013 nop +8000bae0: 00000013 nop +8000bae4: 00000013 nop +8000bae8: 00000013 nop +8000baec: 00000013 nop +8000baf0: 00000013 nop +8000baf4: 00000013 nop +8000baf8: 00000013 nop +8000bafc: 00000013 nop +8000bb00: 00000013 nop +8000bb04: 00000013 nop +8000bb08: 00000013 nop +8000bb0c: 00000013 nop +8000bb10: 00000013 nop +8000bb14: 00000013 nop +8000bb18: 00000013 nop +8000bb1c: 00000013 nop +8000bb20: 00000013 nop +8000bb24: 00000013 nop +8000bb28: 00000013 nop +8000bb2c: 00000013 nop +8000bb30: 00000013 nop +8000bb34: 00000013 nop +8000bb38: 00000013 nop +8000bb3c: 00000013 nop +8000bb40: 00000013 nop +8000bb44: 00000013 nop +8000bb48: 00000013 nop +8000bb4c: 00000013 nop +8000bb50: 00000013 nop +8000bb54: 00000013 nop +8000bb58: 00000013 nop +8000bb5c: 00000013 nop +8000bb60: 00000013 nop +8000bb64: 00000013 nop +8000bb68: 00000013 nop +8000bb6c: 00000013 nop +8000bb70: 00000013 nop +8000bb74: 00000013 nop +8000bb78: 00000013 nop +8000bb7c: 00000013 nop +8000bb80: 00000013 nop +8000bb84: 00000013 nop +8000bb88: 00000013 nop +8000bb8c: 00000013 nop +8000bb90: 00000013 nop +8000bb94: 00000013 nop +8000bb98: 00000013 nop +8000bb9c: 00000013 nop +8000bba0: 00000013 nop +8000bba4: 00000013 nop +8000bba8: 00000013 nop +8000bbac: 00000013 nop +8000bbb0: 00000013 nop +8000bbb4: 00000013 nop +8000bbb8: 00000013 nop +8000bbbc: 00000013 nop +8000bbc0: 00000013 nop +8000bbc4: 00000013 nop +8000bbc8: 00000013 nop +8000bbcc: 00000013 nop +8000bbd0: 00000013 nop +8000bbd4: 00000013 nop +8000bbd8: 00000013 nop +8000bbdc: 00000013 nop +8000bbe0: 00000013 nop +8000bbe4: 00000013 nop +8000bbe8: 00000013 nop +8000bbec: 00000013 nop +8000bbf0: 00000013 nop +8000bbf4: 00000013 nop +8000bbf8: 00000013 nop +8000bbfc: 00000013 nop +8000bc00: 00000013 nop +8000bc04: 00000013 nop +8000bc08: 00000013 nop +8000bc0c: 00000013 nop +8000bc10: 00000013 nop +8000bc14: 00000013 nop +8000bc18: 00000013 nop +8000bc1c: 00000013 nop +8000bc20: 00000013 nop +8000bc24: 00000013 nop +8000bc28: 00000013 nop +8000bc2c: 00000013 nop +8000bc30: 00000013 nop +8000bc34: 00000013 nop +8000bc38: 00000013 nop +8000bc3c: 00000013 nop +8000bc40: 00000013 nop +8000bc44: 00000013 nop +8000bc48: 00000013 nop +8000bc4c: 00000013 nop +8000bc50: 00000013 nop +8000bc54: 00000013 nop +8000bc58: 00000013 nop +8000bc5c: 00000013 nop +8000bc60: 00000013 nop +8000bc64: 00000013 nop +8000bc68: 00000013 nop +8000bc6c: 00000013 nop +8000bc70: 00000013 nop +8000bc74: 00000013 nop +8000bc78: 00000013 nop +8000bc7c: 00000013 nop +8000bc80: 00000013 nop +8000bc84: 00000013 nop +8000bc88: 00000013 nop +8000bc8c: 00000013 nop +8000bc90: 00000013 nop +8000bc94: 00000013 nop +8000bc98: 00000013 nop +8000bc9c: 00000013 nop +8000bca0: 00000013 nop +8000bca4: 00000013 nop +8000bca8: 00000013 nop +8000bcac: 00000013 nop +8000bcb0: 00000013 nop +8000bcb4: 00000013 nop +8000bcb8: 00000013 nop +8000bcbc: 00000013 nop +8000bcc0: 00000013 nop +8000bcc4: 00000013 nop +8000bcc8: 00000013 nop +8000bccc: 00000013 nop +8000bcd0: 00000013 nop +8000bcd4: 00000013 nop +8000bcd8: 00000013 nop +8000bcdc: 00000013 nop +8000bce0: 00000013 nop +8000bce4: 00000013 nop +8000bce8: 00000013 nop +8000bcec: 00000013 nop +8000bcf0: 00000013 nop +8000bcf4: 00000013 nop +8000bcf8: 00000013 nop +8000bcfc: 00000013 nop +8000bd00: 00000013 nop +8000bd04: 00000013 nop +8000bd08: 00000013 nop +8000bd0c: 00000013 nop +8000bd10: 00000013 nop +8000bd14: 00000013 nop +8000bd18: 00000013 nop +8000bd1c: 00000013 nop +8000bd20: 00000013 nop +8000bd24: 00000013 nop +8000bd28: 00000013 nop +8000bd2c: 00000013 nop +8000bd30: 00000013 nop +8000bd34: 00000013 nop +8000bd38: 00000013 nop +8000bd3c: 00000013 nop +8000bd40: 00000013 nop +8000bd44: 00000013 nop +8000bd48: 00000013 nop +8000bd4c: 00000013 nop +8000bd50: 00000013 nop +8000bd54: 00000013 nop +8000bd58: 00000013 nop +8000bd5c: 00000013 nop +8000bd60: 00000013 nop +8000bd64: 00000013 nop +8000bd68: 00000013 nop +8000bd6c: 00000013 nop +8000bd70: 00000013 nop +8000bd74: 00000013 nop +8000bd78: 00000013 nop +8000bd7c: 00000013 nop +8000bd80: 00000013 nop +8000bd84: 00000013 nop +8000bd88: 00000013 nop +8000bd8c: 00000013 nop +8000bd90: 00000013 nop +8000bd94: 00000013 nop +8000bd98: 00000013 nop +8000bd9c: 00000013 nop +8000bda0: 00000013 nop +8000bda4: 00000013 nop +8000bda8: 00000013 nop +8000bdac: 00000013 nop +8000bdb0: 00000013 nop +8000bdb4: 00000013 nop +8000bdb8: 00000013 nop +8000bdbc: 00000013 nop +8000bdc0: 00000013 nop +8000bdc4: 00000013 nop +8000bdc8: 00000013 nop +8000bdcc: 00000013 nop +8000bdd0: 00000013 nop +8000bdd4: 00000013 nop +8000bdd8: 00000013 nop +8000bddc: 00000013 nop +8000bde0: 00000013 nop +8000bde4: 00000013 nop +8000bde8: 00000013 nop +8000bdec: 00000013 nop +8000bdf0: 00000013 nop +8000bdf4: 00000013 nop +8000bdf8: 00000013 nop +8000bdfc: 00000013 nop +8000be00: 00000013 nop +8000be04: 00000013 nop +8000be08: 00000013 nop +8000be0c: 00000013 nop +8000be10: 00000013 nop +8000be14: 00000013 nop +8000be18: 00000013 nop +8000be1c: 00000013 nop +8000be20: 00000013 nop +8000be24: 00000013 nop +8000be28: 00000013 nop +8000be2c: 00000013 nop +8000be30: 00000013 nop +8000be34: 00000013 nop +8000be38: 00000013 nop +8000be3c: 00000013 nop +8000be40: 00000013 nop +8000be44: 00000013 nop +8000be48: 00000013 nop +8000be4c: 00000013 nop +8000be50: 00000013 nop +8000be54: 00000013 nop +8000be58: 00000013 nop +8000be5c: 00000013 nop +8000be60: 00000013 nop +8000be64: 00000013 nop +8000be68: 00000013 nop +8000be6c: 00000013 nop +8000be70: 00000013 nop +8000be74: 00000013 nop +8000be78: 00000013 nop +8000be7c: 00000013 nop +8000be80: 00000013 nop +8000be84: 00000013 nop +8000be88: 00000013 nop +8000be8c: 00000013 nop +8000be90: 00000013 nop +8000be94: 00000013 nop +8000be98: 00000013 nop +8000be9c: 00000013 nop +8000bea0: 00000013 nop +8000bea4: 00000013 nop +8000bea8: 00000013 nop +8000beac: 00000013 nop +8000beb0: 00000013 nop +8000beb4: 00000013 nop +8000beb8: 00000013 nop +8000bebc: 00000013 nop +8000bec0: 00000013 nop +8000bec4: 00000013 nop +8000bec8: 00000013 nop +8000becc: 00000013 nop +8000bed0: 00000013 nop +8000bed4: 00000013 nop +8000bed8: 00000013 nop +8000bedc: 00000013 nop +8000bee0: 00000013 nop +8000bee4: 00000013 nop +8000bee8: 00000013 nop +8000beec: 00000013 nop +8000bef0: 00000013 nop +8000bef4: 00000013 nop +8000bef8: 00000013 nop +8000befc: 00000013 nop +8000bf00: 00000013 nop +8000bf04: 00000013 nop +8000bf08: 00000013 nop +8000bf0c: 00000013 nop +8000bf10: 00000013 nop +8000bf14: 00000013 nop +8000bf18: 00000013 nop +8000bf1c: 00000013 nop +8000bf20: 00000013 nop +8000bf24: 00000013 nop +8000bf28: 00000013 nop +8000bf2c: 00000013 nop +8000bf30: 00000013 nop +8000bf34: 00000013 nop +8000bf38: 00000013 nop +8000bf3c: 00000013 nop +8000bf40: 00000013 nop +8000bf44: 00000013 nop +8000bf48: 00000013 nop +8000bf4c: 00000013 nop +8000bf50: 00000013 nop +8000bf54: 00000013 nop +8000bf58: 00000013 nop +8000bf5c: 00000013 nop +8000bf60: 00000013 nop +8000bf64: 00000013 nop +8000bf68: 00000013 nop +8000bf6c: 00000013 nop +8000bf70: 00000013 nop +8000bf74: 00000013 nop +8000bf78: 00000013 nop +8000bf7c: 00000013 nop +8000bf80: 00000013 nop +8000bf84: 00000013 nop +8000bf88: 00000013 nop +8000bf8c: 00000013 nop +8000bf90: 00000013 nop +8000bf94: 00000013 nop +8000bf98: 00000013 nop +8000bf9c: 00000013 nop +8000bfa0: 00000013 nop +8000bfa4: 00000013 nop +8000bfa8: 00000013 nop +8000bfac: 00000013 nop +8000bfb0: 00000013 nop +8000bfb4: 00000013 nop +8000bfb8: 00000013 nop +8000bfbc: 00000013 nop +8000bfc0: 00000013 nop +8000bfc4: 00000013 nop +8000bfc8: 00000013 nop +8000bfcc: 00000013 nop +8000bfd0: 00000013 nop +8000bfd4: 00000013 nop +8000bfd8: 00000013 nop +8000bfdc: 00000013 nop +8000bfe0: 00000013 nop +8000bfe4: 00000013 nop +8000bfe8: 00000013 nop +8000bfec: 00000013 nop +8000bff0: 00000013 nop +8000bff4: 00000013 nop +8000bff8: 00000013 nop +8000bffc: 00000013 nop + +8000c000 : +8000c000: 7170 flw fa2,100(a0) +8000c002: 7372 flw ft6,60(sp) +8000c004: 7574 flw fa3,108(a0) +8000c006: 7776 flw fa4,124(sp) +8000c008: 7978 flw fa4,116(a0) +8000c00a: 7b7a flw fs6,188(sp) +8000c00c: 7d7c flw fa5,124(a0) +8000c00e: 7f7e flw ft10,252(sp) + ... diff --git a/src/test/cpp/raw/mmu/build/mmu.hex b/src/test/cpp/raw/mmu/build/mmu.hex index 096ccfcf..cc70c56c 100644 --- a/src/test/cpp/raw/mmu/build/mmu.hex +++ b/src/test/cpp/raw/mmu/build/mmu.hex @@ -1,10 +1,3300 @@ :0200000480007A :100000006F008002130000001300000013000000C6 :100010001300000013000000130000001300000094 -:100020006F00000273002030970000009380800171 -:100030007390503073905010130E10006F00000139 -:10004000370110F0130141F22320C101370110F0F4 -:10005000130101F22320010013000000130000002F -:100060001300000013000000130000001300000044 +:100020006F00401473002030970000009380C013CD +:100030007390503073905010130E100097700000A2 +:10004000938040FC372126271301415283A04000B2 +:10005000639A2010130E2000970000009380000286 +:1000600073901034B72000009380008073900030AC +:10007000730020306F00000F130E3000B710000027 +:1000800093800080739000309700000093804001BF +:1000900073901034730020306F00C00C130E4000BA +:1000A00097800000938000F63731363713014153B3 +:1000B00083A040006398200A130E500097100000A0 +:1000C00093804074172100001301C1F313512100E4 +:1000D0001361110123A0200097200000938080F27B +:1000E00037010080135121001361F10123A020008A +:1000F000130E5000972000009380C080173100003D +:10010000130141F0135121001361110123A02000BC +:1001100097300000938080F117910000130181EE69 +:10012000135121001361F10123A02000971000005A +:10013000938040ED93D0C00037010080B3E02000F1 +:1001400073900018130E6000B7A000909380800099 +:1001500037514A4B1301819483A00000639420001F +:100160006F008001735000186F004000370110F0DD +:10017000130141F22320C101735000186F004000A9 +:10018000370110F0130101F22320010013000000D9 +:100190001300000013000000130000001300000013 +:1001A0001300000013000000130000001300000003 +:1001B00013000000130000001300000013000000F3 +:1001C00013000000130000001300000013000000E3 +:1001D00013000000130000001300000013000000D3 +:1001E00013000000130000001300000013000000C3 +:1001F00013000000130000001300000013000000B3 +:1002000013000000130000001300000013000000A2 +:100210001300000013000000130000001300000092 +:100220001300000013000000130000001300000082 +:100230001300000013000000130000001300000072 +:100240001300000013000000130000001300000062 +:100250001300000013000000130000001300000052 +:100260001300000013000000130000001300000042 +:100270001300000013000000130000001300000032 +:100280001300000013000000130000001300000022 +:100290001300000013000000130000001300000012 +:1002A0001300000013000000130000001300000002 +:1002B00013000000130000001300000013000000F2 +:1002C00013000000130000001300000013000000E2 +:1002D00013000000130000001300000013000000D2 +:1002E00013000000130000001300000013000000C2 +:1002F00013000000130000001300000013000000B2 +:1003000013000000130000001300000013000000A1 +:100310001300000013000000130000001300000091 +:100320001300000013000000130000001300000081 +:100330001300000013000000130000001300000071 +:100340001300000013000000130000001300000061 +:100350001300000013000000130000001300000051 +:100360001300000013000000130000001300000041 +:100370001300000013000000130000001300000031 +:100380001300000013000000130000001300000021 +:100390001300000013000000130000001300000011 +:1003A0001300000013000000130000001300000001 +:1003B00013000000130000001300000013000000F1 +:1003C00013000000130000001300000013000000E1 +:1003D00013000000130000001300000013000000D1 +:1003E00013000000130000001300000013000000C1 +:1003F00013000000130000001300000013000000B1 +:1004000013000000130000001300000013000000A0 +:100410001300000013000000130000001300000090 +:100420001300000013000000130000001300000080 +:100430001300000013000000130000001300000070 +:100440001300000013000000130000001300000060 +:100450001300000013000000130000001300000050 +:100460001300000013000000130000001300000040 +:100470001300000013000000130000001300000030 +:100480001300000013000000130000001300000020 +:100490001300000013000000130000001300000010 +:1004A0001300000013000000130000001300000000 +:1004B00013000000130000001300000013000000F0 +:1004C00013000000130000001300000013000000E0 +:1004D00013000000130000001300000013000000D0 +:1004E00013000000130000001300000013000000C0 +:1004F00013000000130000001300000013000000B0 +:10050000130000001300000013000000130000009F +:10051000130000001300000013000000130000008F +:10052000130000001300000013000000130000007F +:10053000130000001300000013000000130000006F +:10054000130000001300000013000000130000005F +:10055000130000001300000013000000130000004F +:10056000130000001300000013000000130000003F +:10057000130000001300000013000000130000002F +:10058000130000001300000013000000130000001F +:10059000130000001300000013000000130000000F +:1005A00013000000130000001300000013000000FF +:1005B00013000000130000001300000013000000EF +:1005C00013000000130000001300000013000000DF +:1005D00013000000130000001300000013000000CF +:1005E00013000000130000001300000013000000BF +:1005F00013000000130000001300000013000000AF +:10060000130000001300000013000000130000009E +:10061000130000001300000013000000130000008E +:10062000130000001300000013000000130000007E +:10063000130000001300000013000000130000006E +:10064000130000001300000013000000130000005E +:10065000130000001300000013000000130000004E +:10066000130000001300000013000000130000003E +:10067000130000001300000013000000130000002E +:10068000130000001300000013000000130000001E +:10069000130000001300000013000000130000000E +:1006A00013000000130000001300000013000000FE +:1006B00013000000130000001300000013000000EE +:1006C00013000000130000001300000013000000DE +:1006D00013000000130000001300000013000000CE +:1006E00013000000130000001300000013000000BE +:1006F00013000000130000001300000013000000AE +:10070000130000001300000013000000130000009D +:10071000130000001300000013000000130000008D +:10072000130000001300000013000000130000007D +:10073000130000001300000013000000130000006D +:10074000130000001300000013000000130000005D +:10075000130000001300000013000000130000004D +:10076000130000001300000013000000130000003D +:10077000130000001300000013000000130000002D +:10078000130000001300000013000000130000001D +:10079000130000001300000013000000130000000D +:1007A00013000000130000001300000013000000FD +:1007B00013000000130000001300000013000000ED +:1007C00013000000130000001300000013000000DD +:1007D00013000000130000001300000013000000CD +:1007E00013000000130000001300000013000000BD +:1007F00013000000130000001300000013000000AD +:10080000130000001300000013000000130000009C +:10081000130000001300000013000000130000008C +:10082000130000001300000013000000130000007C +:10083000130000001300000013000000130000006C +:10084000130000001300000013000000130000005C +:10085000130000001300000013000000130000004C +:10086000130000001300000013000000130000003C +:10087000130000001300000013000000130000002C +:10088000130000001300000013000000130000001C +:10089000130000001300000013000000130000000C +:1008A00013000000130000001300000013000000FC +:1008B00013000000130000001300000013000000EC +:1008C00013000000130000001300000013000000DC +:1008D00013000000130000001300000013000000CC +:1008E00013000000130000001300000013000000BC +:1008F00013000000130000001300000013000000AC +:10090000130000001300000013000000130000009B +:10091000130000001300000013000000130000008B +:10092000130000001300000013000000130000007B +:10093000130000001300000013000000130000006B +:10094000130000001300000013000000130000005B +:10095000130000001300000013000000130000004B +:10096000130000001300000013000000130000003B +:10097000130000001300000013000000130000002B +:10098000130000001300000013000000130000001B +:10099000130000001300000013000000130000000B +:1009A00013000000130000001300000013000000FB +:1009B00013000000130000001300000013000000EB +:1009C00013000000130000001300000013000000DB +:1009D00013000000130000001300000013000000CB +:1009E00013000000130000001300000013000000BB +:1009F00013000000130000001300000013000000AB +:100A0000130000001300000013000000130000009A +:100A1000130000001300000013000000130000008A +:100A2000130000001300000013000000130000007A +:100A3000130000001300000013000000130000006A +:100A4000130000001300000013000000130000005A +:100A5000130000001300000013000000130000004A +:100A6000130000001300000013000000130000003A +:100A7000130000001300000013000000130000002A +:100A8000130000001300000013000000130000001A +:100A9000130000001300000013000000130000000A +:100AA00013000000130000001300000013000000FA +:100AB00013000000130000001300000013000000EA +:100AC00013000000130000001300000013000000DA +:100AD00013000000130000001300000013000000CA +:100AE00013000000130000001300000013000000BA +:100AF00013000000130000001300000013000000AA +:100B00001300000013000000130000001300000099 +:100B10001300000013000000130000001300000089 +:100B20001300000013000000130000001300000079 +:100B30001300000013000000130000001300000069 +:100B40001300000013000000130000001300000059 +:100B50001300000013000000130000001300000049 +:100B60001300000013000000130000001300000039 +:100B70001300000013000000130000001300000029 +:100B80001300000013000000130000001300000019 +:100B90001300000013000000130000001300000009 +:100BA00013000000130000001300000013000000F9 +:100BB00013000000130000001300000013000000E9 +:100BC00013000000130000001300000013000000D9 +:100BD00013000000130000001300000013000000C9 +:100BE00013000000130000001300000013000000B9 +:100BF00013000000130000001300000013000000A9 +:100C00001300000013000000130000001300000098 +:100C10001300000013000000130000001300000088 +:100C20001300000013000000130000001300000078 +:100C30001300000013000000130000001300000068 +:100C40001300000013000000130000001300000058 +:100C50001300000013000000130000001300000048 +:100C60001300000013000000130000001300000038 +:100C70001300000013000000130000001300000028 +:100C80001300000013000000130000001300000018 +:100C90001300000013000000130000001300000008 +:100CA00013000000130000001300000013000000F8 +:100CB00013000000130000001300000013000000E8 +:100CC00013000000130000001300000013000000D8 +:100CD00013000000130000001300000013000000C8 +:100CE00013000000130000001300000013000000B8 +:100CF00013000000130000001300000013000000A8 +:100D00001300000013000000130000001300000097 +:100D10001300000013000000130000001300000087 +:100D20001300000013000000130000001300000077 +:100D30001300000013000000130000001300000067 +:100D40001300000013000000130000001300000057 +:100D50001300000013000000130000001300000047 +:100D60001300000013000000130000001300000037 +:100D70001300000013000000130000001300000027 +:100D80001300000013000000130000001300000017 +:100D90001300000013000000130000001300000007 +:100DA00013000000130000001300000013000000F7 +:100DB00013000000130000001300000013000000E7 +:100DC00013000000130000001300000013000000D7 +:100DD00013000000130000001300000013000000C7 +:100DE00013000000130000001300000013000000B7 +:100DF00013000000130000001300000013000000A7 +:100E00001300000013000000130000001300000096 +:100E10001300000013000000130000001300000086 +:100E20001300000013000000130000001300000076 +:100E30001300000013000000130000001300000066 +:100E40001300000013000000130000001300000056 +:100E50001300000013000000130000001300000046 +:100E60001300000013000000130000001300000036 +:100E70001300000013000000130000001300000026 +:100E80001300000013000000130000001300000016 +:100E90001300000013000000130000001300000006 +:100EA00013000000130000001300000013000000F6 +:100EB00013000000130000001300000013000000E6 +:100EC00013000000130000001300000013000000D6 +:100ED00013000000130000001300000013000000C6 +:100EE00013000000130000001300000013000000B6 +:100EF00013000000130000001300000013000000A6 +:100F00001300000013000000130000001300000095 +:100F10001300000013000000130000001300000085 +:100F20001300000013000000130000001300000075 +:100F30001300000013000000130000001300000065 +:100F40001300000013000000130000001300000055 +:100F50001300000013000000130000001300000045 +:100F60001300000013000000130000001300000035 +:100F70001300000013000000130000001300000025 +:100F80001300000013000000130000001300000015 +:100F90001300000013000000130000001300000005 +:100FA00013000000130000001300000013000000F5 +:100FB00013000000130000001300000013000000E5 +:100FC00013000000130000001300000013000000D5 +:100FD00013000000130000001300000013000000C5 +:100FE00013000000130000001300000013000000B5 +:100FF00013000000130000001300000013000000A5 +:1010000000000000130000001300000013000000A7 +:101010001300000013000000130000001300000084 +:101020001300000013000000130000001300000074 +:101030001300000013000000130000001300000064 +:101040001300000013000000130000001300000054 +:101050001300000013000000130000001300000044 +:101060001300000013000000130000001300000034 +:101070001300000013000000130000001300000024 +:101080001300000013000000130000001300000014 +:101090001300000013000000130000001300000004 +:1010A00013000000130000001300000013000000F4 +:1010B00013000000130000001300000013000000E4 +:1010C00013000000130000001300000013000000D4 +:1010D00013000000130000001300000013000000C4 +:1010E00013000000130000001300000013000000B4 +:1010F00013000000130000001300000013000000A4 +:101100001300000013000000130000001300000093 +:101110001300000013000000130000001300000083 +:101120001300000013000000130000001300000073 +:101130001300000013000000130000001300000063 +:101140001300000013000000130000001300000053 +:101150001300000013000000130000001300000043 +:101160001300000013000000130000001300000033 +:101170001300000013000000130000001300000023 +:101180001300000013000000130000001300000013 +:101190001300000013000000130000001300000003 +:1011A00013000000130000001300000013000000F3 +:1011B00013000000130000001300000013000000E3 +:1011C00013000000130000001300000013000000D3 +:1011D00013000000130000001300000013000000C3 +:1011E00013000000130000001300000013000000B3 +:1011F00013000000130000001300000013000000A3 +:101200001300000013000000130000001300000092 +:101210001300000013000000130000001300000082 +:101220001300000013000000130000001300000072 +:101230001300000013000000130000001300000062 +:101240001300000013000000130000001300000052 +:101250001300000013000000130000001300000042 +:101260001300000013000000130000001300000032 +:101270001300000013000000130000001300000022 +:101280001300000013000000130000001300000012 +:101290001300000013000000130000001300000002 +:1012A00013000000130000001300000013000000F2 +:1012B00013000000130000001300000013000000E2 +:1012C00013000000130000001300000013000000D2 +:1012D00013000000130000001300000013000000C2 +:1012E00013000000130000001300000013000000B2 +:1012F00013000000130000001300000013000000A2 +:101300001300000013000000130000001300000091 +:101310001300000013000000130000001300000081 +:101320001300000013000000130000001300000071 +:101330001300000013000000130000001300000061 +:101340001300000013000000130000001300000051 +:101350001300000013000000130000001300000041 +:101360001300000013000000130000001300000031 +:101370001300000013000000130000001300000021 +:101380001300000013000000130000001300000011 +:101390001300000013000000130000001300000001 +:1013A00013000000130000001300000013000000F1 +:1013B00013000000130000001300000013000000E1 +:1013C00013000000130000001300000013000000D1 +:1013D00013000000130000001300000013000000C1 +:1013E00013000000130000001300000013000000B1 +:1013F00013000000130000001300000013000000A1 +:101400001300000013000000130000001300000090 +:101410001300000013000000130000001300000080 +:101420001300000013000000130000001300000070 +:101430001300000013000000130000001300000060 +:101440001300000013000000130000001300000050 +:101450001300000013000000130000001300000040 +:101460001300000013000000130000001300000030 +:101470001300000013000000130000001300000020 +:101480001300000013000000130000001300000010 +:101490001300000013000000130000001300000000 +:1014A00013000000130000001300000013000000F0 +:1014B00013000000130000001300000013000000E0 +:1014C00013000000130000001300000013000000D0 +:1014D00013000000130000001300000013000000C0 +:1014E00013000000130000001300000013000000B0 +:1014F00013000000130000001300000013000000A0 +:10150000130000001300000013000000130000008F +:10151000130000001300000013000000130000007F +:10152000130000001300000013000000130000006F +:10153000130000001300000013000000130000005F +:10154000130000001300000013000000130000004F +:10155000130000001300000013000000130000003F +:10156000130000001300000013000000130000002F +:10157000130000001300000013000000130000001F +:10158000130000001300000013000000130000000F +:1015900013000000130000001300000013000000FF +:1015A00013000000130000001300000013000000EF +:1015B00013000000130000001300000013000000DF +:1015C00013000000130000001300000013000000CF +:1015D00013000000130000001300000013000000BF +:1015E00013000000130000001300000013000000AF +:1015F000130000001300000013000000130000009F +:10160000130000001300000013000000130000008E +:10161000130000001300000013000000130000007E +:10162000130000001300000013000000130000006E +:10163000130000001300000013000000130000005E +:10164000130000001300000013000000130000004E +:10165000130000001300000013000000130000003E +:10166000130000001300000013000000130000002E +:10167000130000001300000013000000130000001E +:10168000130000001300000013000000130000000E +:1016900013000000130000001300000013000000FE +:1016A00013000000130000001300000013000000EE +:1016B00013000000130000001300000013000000DE +:1016C00013000000130000001300000013000000CE +:1016D00013000000130000001300000013000000BE +:1016E00013000000130000001300000013000000AE +:1016F000130000001300000013000000130000009E +:10170000130000001300000013000000130000008D +:10171000130000001300000013000000130000007D +:10172000130000001300000013000000130000006D +:10173000130000001300000013000000130000005D +:10174000130000001300000013000000130000004D +:10175000130000001300000013000000130000003D +:10176000130000001300000013000000130000002D +:10177000130000001300000013000000130000001D +:10178000130000001300000013000000130000000D +:1017900013000000130000001300000013000000FD +:1017A00013000000130000001300000013000000ED +:1017B00013000000130000001300000013000000DD +:1017C00013000000130000001300000013000000CD +:1017D00013000000130000001300000013000000BD +:1017E00013000000130000001300000013000000AD +:1017F000130000001300000013000000130000009D +:10180000130000001300000013000000130000008C +:10181000130000001300000013000000130000007C +:10182000130000001300000013000000130000006C +:10183000130000001300000013000000130000005C +:10184000130000001300000013000000130000004C +:10185000130000001300000013000000130000003C +:10186000130000001300000013000000130000002C +:10187000130000001300000013000000130000001C +:10188000130000001300000013000000130000000C +:1018900013000000130000001300000013000000FC +:1018A00013000000130000001300000013000000EC +:1018B00013000000130000001300000013000000DC +:1018C00013000000130000001300000013000000CC +:1018D00013000000130000001300000013000000BC +:1018E00013000000130000001300000013000000AC +:1018F000130000001300000013000000130000009C +:10190000130000001300000013000000130000008B +:10191000130000001300000013000000130000007B +:10192000130000001300000013000000130000006B +:10193000130000001300000013000000130000005B +:10194000130000001300000013000000130000004B +:10195000130000001300000013000000130000003B +:10196000130000001300000013000000130000002B +:10197000130000001300000013000000130000001B +:10198000130000001300000013000000130000000B +:1019900013000000130000001300000013000000FB +:1019A00013000000130000001300000013000000EB +:1019B00013000000130000001300000013000000DB +:1019C00013000000130000001300000013000000CB +:1019D00013000000130000001300000013000000BB +:1019E00013000000130000001300000013000000AB +:1019F000130000001300000013000000130000009B +:101A0000130000001300000013000000130000008A +:101A1000130000001300000013000000130000007A +:101A2000130000001300000013000000130000006A +:101A3000130000001300000013000000130000005A +:101A4000130000001300000013000000130000004A +:101A5000130000001300000013000000130000003A +:101A6000130000001300000013000000130000002A +:101A7000130000001300000013000000130000001A +:101A8000130000001300000013000000130000000A +:101A900013000000130000001300000013000000FA +:101AA00013000000130000001300000013000000EA +:101AB00013000000130000001300000013000000DA +:101AC00013000000130000001300000013000000CA +:101AD00013000000130000001300000013000000BA +:101AE00013000000130000001300000013000000AA +:101AF000130000001300000013000000130000009A +:101B00001300000013000000130000001300000089 +:101B10001300000013000000130000001300000079 +:101B20001300000013000000130000001300000069 +:101B30001300000013000000130000001300000059 +:101B40001300000013000000130000001300000049 +:101B50001300000013000000130000001300000039 +:101B60001300000013000000130000001300000029 +:101B70001300000013000000130000001300000019 +:101B80001300000013000000130000001300000009 +:101B900013000000130000001300000013000000F9 +:101BA00013000000130000001300000013000000E9 +:101BB00013000000130000001300000013000000D9 +:101BC00013000000130000001300000013000000C9 +:101BD00013000000130000001300000013000000B9 +:101BE00013000000130000001300000013000000A9 +:101BF0001300000013000000130000001300000099 +:101C00001300000013000000130000001300000088 +:101C10001300000013000000130000001300000078 +:101C20001300000013000000130000001300000068 +:101C30001300000013000000130000001300000058 +:101C40001300000013000000130000001300000048 +:101C50001300000013000000130000001300000038 +:101C60001300000013000000130000001300000028 +:101C70001300000013000000130000001300000018 +:101C80001300000013000000130000001300000008 +:101C900013000000130000001300000013000000F8 +:101CA00013000000130000001300000013000000E8 +:101CB00013000000130000001300000013000000D8 +:101CC00013000000130000001300000013000000C8 +:101CD00013000000130000001300000013000000B8 +:101CE00013000000130000001300000013000000A8 +:101CF0001300000013000000130000001300000098 +:101D00001300000013000000130000001300000087 +:101D10001300000013000000130000001300000077 +:101D20001300000013000000130000001300000067 +:101D30001300000013000000130000001300000057 +:101D40001300000013000000130000001300000047 +:101D50001300000013000000130000001300000037 +:101D60001300000013000000130000001300000027 +:101D70001300000013000000130000001300000017 +:101D80001300000013000000130000001300000007 +:101D900013000000130000001300000013000000F7 +:101DA00013000000130000001300000013000000E7 +:101DB00013000000130000001300000013000000D7 +:101DC00013000000130000001300000013000000C7 +:101DD00013000000130000001300000013000000B7 +:101DE00013000000130000001300000013000000A7 +:101DF0001300000013000000130000001300000097 +:101E00001300000013000000130000001300000086 +:101E10001300000013000000130000001300000076 +:101E20001300000013000000130000001300000066 +:101E30001300000013000000130000001300000056 +:101E40001300000013000000130000001300000046 +:101E50001300000013000000130000001300000036 +:101E60001300000013000000130000001300000026 +:101E70001300000013000000130000001300000016 +:101E80001300000013000000130000001300000006 +:101E900013000000130000001300000013000000F6 +:101EA00013000000130000001300000013000000E6 +:101EB00013000000130000001300000013000000D6 +:101EC00013000000130000001300000013000000C6 +:101ED00013000000130000001300000013000000B6 +:101EE00013000000130000001300000013000000A6 +:101EF0001300000013000000130000001300000096 +:101F00001300000013000000130000001300000085 +:101F10001300000013000000130000001300000075 +:101F20001300000013000000130000001300000065 +:101F30001300000013000000130000001300000055 +:101F40001300000013000000130000001300000045 +:101F50001300000013000000130000001300000035 +:101F60001300000013000000130000001300000025 +:101F70001300000013000000130000001300000015 +:101F80001300000013000000130000001300000005 +:101F900013000000130000001300000013000000F5 +:101FA00013000000130000001300000013000000E5 +:101FB00013000000130000001300000013000000D5 +:101FC00013000000130000001300000013000000C5 +:101FD00013000000130000001300000013000000B5 +:101FE00013000000130000001300000013000000A5 +:101FF0001300000013000000130000001300000095 +:102000000000000013000000130000001300000097 +:102010001300000013000000130000001300000074 +:102020001300000013000000130000001300000064 +:102030001300000013000000130000001300000054 +:102040001300000013000000130000001300000044 +:102050001300000013000000130000001300000034 +:102060001300000013000000130000001300000024 +:102070001300000013000000130000001300000014 +:102080001300000013000000130000001300000004 +:1020900013000000130000001300000013000000F4 +:1020A00013000000130000001300000013000000E4 +:1020B00013000000130000001300000013000000D4 +:1020C00013000000130000001300000013000000C4 +:1020D00013000000130000001300000013000000B4 +:1020E00013000000130000001300000013000000A4 +:1020F0001300000013000000130000001300000094 +:102100001300000013000000130000001300000083 +:102110001300000013000000130000001300000073 +:102120001300000013000000130000001300000063 +:102130001300000013000000130000001300000053 +:102140001300000013000000130000001300000043 +:102150001300000013000000130000001300000033 +:102160001300000013000000130000001300000023 +:102170001300000013000000130000001300000013 +:102180001300000013000000130000001300000003 +:1021900013000000130000001300000013000000F3 +:1021A00013000000130000001300000013000000E3 +:1021B00013000000130000001300000013000000D3 +:1021C00013000000130000001300000013000000C3 +:1021D00013000000130000001300000013000000B3 +:1021E00013000000130000001300000013000000A3 +:1021F0001300000013000000130000001300000093 +:102200001300000013000000130000001300000082 +:102210001300000013000000130000001300000072 +:102220001300000013000000130000001300000062 +:102230001300000013000000130000001300000052 +:102240001300000013000000130000001300000042 +:102250001300000013000000130000001300000032 +:102260001300000013000000130000001300000022 +:102270001300000013000000130000001300000012 +:102280001300000013000000130000001300000002 +:1022900013000000130000001300000013000000F2 +:1022A00013000000130000001300000013000000E2 +:1022B00013000000130000001300000013000000D2 +:1022C00013000000130000001300000013000000C2 +:1022D00013000000130000001300000013000000B2 +:1022E00013000000130000001300000013000000A2 +:1022F0001300000013000000130000001300000092 +:102300001300000013000000130000001300000081 +:102310001300000013000000130000001300000071 +:102320001300000013000000130000001300000061 +:102330001300000013000000130000001300000051 +:102340001300000013000000130000001300000041 +:102350001300000013000000130000001300000031 +:102360001300000013000000130000001300000021 +:102370001300000013000000130000001300000011 +:102380001300000013000000130000001300000001 +:1023900013000000130000001300000013000000F1 +:1023A00013000000130000001300000013000000E1 +:1023B00013000000130000001300000013000000D1 +:1023C00013000000130000001300000013000000C1 +:1023D00013000000130000001300000013000000B1 +:1023E00013000000130000001300000013000000A1 +:1023F0001300000013000000130000001300000091 +:102400001300000013000000130000001300000080 +:102410001300000013000000130000001300000070 +:102420001300000013000000130000001300000060 +:102430001300000013000000130000001300000050 +:102440001300000013000000130000001300000040 +:102450001300000013000000130000001300000030 +:102460001300000013000000130000001300000020 +:102470001300000013000000130000001300000010 +:102480001300000013000000130000001300000000 +:1024900013000000130000001300000013000000F0 +:1024A00013000000130000001300000013000000E0 +:1024B00013000000130000001300000013000000D0 +:1024C00013000000130000001300000013000000C0 +:1024D00013000000130000001300000013000000B0 +:1024E00013000000130000001300000013000000A0 +:1024F0001300000013000000130000001300000090 +:10250000130000001300000013000000130000007F +:10251000130000001300000013000000130000006F +:10252000130000001300000013000000130000005F +:10253000130000001300000013000000130000004F +:10254000130000001300000013000000130000003F +:10255000130000001300000013000000130000002F +:10256000130000001300000013000000130000001F +:10257000130000001300000013000000130000000F +:1025800013000000130000001300000013000000FF +:1025900013000000130000001300000013000000EF +:1025A00013000000130000001300000013000000DF +:1025B00013000000130000001300000013000000CF +:1025C00013000000130000001300000013000000BF +:1025D00013000000130000001300000013000000AF +:1025E000130000001300000013000000130000009F +:1025F000130000001300000013000000130000008F +:10260000130000001300000013000000130000007E +:10261000130000001300000013000000130000006E +:10262000130000001300000013000000130000005E +:10263000130000001300000013000000130000004E +:10264000130000001300000013000000130000003E +:10265000130000001300000013000000130000002E +:10266000130000001300000013000000130000001E +:10267000130000001300000013000000130000000E +:1026800013000000130000001300000013000000FE +:1026900013000000130000001300000013000000EE +:1026A00013000000130000001300000013000000DE +:1026B00013000000130000001300000013000000CE +:1026C00013000000130000001300000013000000BE +:1026D00013000000130000001300000013000000AE +:1026E000130000001300000013000000130000009E +:1026F000130000001300000013000000130000008E +:10270000130000001300000013000000130000007D +:10271000130000001300000013000000130000006D +:10272000130000001300000013000000130000005D +:10273000130000001300000013000000130000004D +:10274000130000001300000013000000130000003D +:10275000130000001300000013000000130000002D +:10276000130000001300000013000000130000001D +:10277000130000001300000013000000130000000D +:1027800013000000130000001300000013000000FD +:1027900013000000130000001300000013000000ED +:1027A00013000000130000001300000013000000DD +:1027B00013000000130000001300000013000000CD +:1027C00013000000130000001300000013000000BD +:1027D00013000000130000001300000013000000AD +:1027E000130000001300000013000000130000009D +:1027F000130000001300000013000000130000008D +:10280000130000001300000013000000130000007C +:10281000130000001300000013000000130000006C +:10282000130000001300000013000000130000005C +:10283000130000001300000013000000130000004C +:10284000130000001300000013000000130000003C +:10285000130000001300000013000000130000002C +:10286000130000001300000013000000130000001C +:10287000130000001300000013000000130000000C +:1028800013000000130000001300000013000000FC +:1028900013000000130000001300000013000000EC +:1028A00013000000130000001300000013000000DC +:1028B00013000000130000001300000013000000CC +:1028C00013000000130000001300000013000000BC +:1028D00013000000130000001300000013000000AC +:1028E000130000001300000013000000130000009C +:1028F000130000001300000013000000130000008C +:10290000130000001300000013000000130000007B +:10291000130000001300000013000000130000006B +:10292000130000001300000013000000130000005B +:10293000130000001300000013000000130000004B +:10294000130000001300000013000000130000003B +:10295000130000001300000013000000130000002B +:10296000130000001300000013000000130000001B +:10297000130000001300000013000000130000000B +:1029800013000000130000001300000013000000FB +:1029900013000000130000001300000013000000EB +:1029A00013000000130000001300000013000000DB +:1029B00013000000130000001300000013000000CB +:1029C00013000000130000001300000013000000BB +:1029D00013000000130000001300000013000000AB +:1029E000130000001300000013000000130000009B +:1029F000130000001300000013000000130000008B +:102A0000130000001300000013000000130000007A +:102A1000130000001300000013000000130000006A +:102A2000130000001300000013000000130000005A +:102A3000130000001300000013000000130000004A +:102A4000130000001300000013000000130000003A +:102A5000130000001300000013000000130000002A +:102A6000130000001300000013000000130000001A +:102A7000130000001300000013000000130000000A +:102A800013000000130000001300000013000000FA +:102A900013000000130000001300000013000000EA +:102AA00013000000130000001300000013000000DA +:102AB00013000000130000001300000013000000CA +:102AC00013000000130000001300000013000000BA +:102AD00013000000130000001300000013000000AA +:102AE000130000001300000013000000130000009A +:102AF000130000001300000013000000130000008A +:102B00001300000013000000130000001300000079 +:102B10001300000013000000130000001300000069 +:102B20001300000013000000130000001300000059 +:102B30001300000013000000130000001300000049 +:102B40001300000013000000130000001300000039 +:102B50001300000013000000130000001300000029 +:102B60001300000013000000130000001300000019 +:102B70001300000013000000130000001300000009 +:102B800013000000130000001300000013000000F9 +:102B900013000000130000001300000013000000E9 +:102BA00013000000130000001300000013000000D9 +:102BB00013000000130000001300000013000000C9 +:102BC00013000000130000001300000013000000B9 +:102BD00013000000130000001300000013000000A9 +:102BE0001300000013000000130000001300000099 +:102BF0001300000013000000130000001300000089 +:102C00001300000013000000130000001300000078 +:102C10001300000013000000130000001300000068 +:102C20001300000013000000130000001300000058 +:102C30001300000013000000130000001300000048 +:102C40001300000013000000130000001300000038 +:102C50001300000013000000130000001300000028 +:102C60001300000013000000130000001300000018 +:102C70001300000013000000130000001300000008 +:102C800013000000130000001300000013000000F8 +:102C900013000000130000001300000013000000E8 +:102CA00013000000130000001300000013000000D8 +:102CB00013000000130000001300000013000000C8 +:102CC00013000000130000001300000013000000B8 +:102CD00013000000130000001300000013000000A8 +:102CE0001300000013000000130000001300000098 +:102CF0001300000013000000130000001300000088 +:102D00001300000013000000130000001300000077 +:102D10001300000013000000130000001300000067 +:102D20001300000013000000130000001300000057 +:102D30001300000013000000130000001300000047 +:102D40001300000013000000130000001300000037 +:102D50001300000013000000130000001300000027 +:102D60001300000013000000130000001300000017 +:102D70001300000013000000130000001300000007 +:102D800013000000130000001300000013000000F7 +:102D900013000000130000001300000013000000E7 +:102DA00013000000130000001300000013000000D7 +:102DB00013000000130000001300000013000000C7 +:102DC00013000000130000001300000013000000B7 +:102DD00013000000130000001300000013000000A7 +:102DE0001300000013000000130000001300000097 +:102DF0001300000013000000130000001300000087 +:102E00001300000013000000130000001300000076 +:102E10001300000013000000130000001300000066 +:102E20001300000013000000130000001300000056 +:102E30001300000013000000130000001300000046 +:102E40001300000013000000130000001300000036 +:102E50001300000013000000130000001300000026 +:102E60001300000013000000130000001300000016 +:102E70001300000013000000130000001300000006 +:102E800013000000130000001300000013000000F6 +:102E900013000000130000001300000013000000E6 +:102EA00013000000130000001300000013000000D6 +:102EB00013000000130000001300000013000000C6 +:102EC00013000000130000001300000013000000B6 +:102ED00013000000130000001300000013000000A6 +:102EE0001300000013000000130000001300000096 +:102EF0001300000013000000130000001300000086 +:102F00001300000013000000130000001300000075 +:102F10001300000013000000130000001300000065 +:102F20001300000013000000130000001300000055 +:102F30001300000013000000130000001300000045 +:102F40001300000013000000130000001300000035 +:102F50001300000013000000130000001300000025 +:102F60001300000013000000130000001300000015 +:102F70001300000013000000130000001300000005 +:102F800013000000130000001300000013000000F5 +:102F900013000000130000001300000013000000E5 +:102FA00013000000130000001300000013000000D5 +:102FB00013000000130000001300000013000000C5 +:102FC00013000000130000001300000013000000B5 +:102FD00013000000130000001300000013000000A5 +:102FE0001300000013000000130000001300000095 +:102FF0001300000013000000130000001300000085 +:103000000000000013000000130000001300000087 +:103010001300000013000000130000001300000064 +:103020001300000013000000130000001300000054 +:103030001300000013000000130000001300000044 +:103040001300000013000000130000001300000034 +:103050001300000013000000130000001300000024 +:103060001300000013000000130000001300000014 +:103070001300000013000000130000001300000004 +:1030800013000000130000001300000013000000F4 +:1030900013000000130000001300000013000000E4 +:1030A00013000000130000001300000013000000D4 +:1030B00013000000130000001300000013000000C4 +:1030C00013000000130000001300000013000000B4 +:1030D00013000000130000001300000013000000A4 +:1030E0001300000013000000130000001300000094 +:1030F0001300000013000000130000001300000084 +:103100001300000013000000130000001300000073 +:103110001300000013000000130000001300000063 +:103120001300000013000000130000001300000053 +:103130001300000013000000130000001300000043 +:103140001300000013000000130000001300000033 +:103150001300000013000000130000001300000023 +:103160001300000013000000130000001300000013 +:103170001300000013000000130000001300000003 +:1031800013000000130000001300000013000000F3 +:1031900013000000130000001300000013000000E3 +:1031A00013000000130000001300000013000000D3 +:1031B00013000000130000001300000013000000C3 +:1031C00013000000130000001300000013000000B3 +:1031D00013000000130000001300000013000000A3 +:1031E0001300000013000000130000001300000093 +:1031F0001300000013000000130000001300000083 +:103200001300000013000000130000001300000072 +:103210001300000013000000130000001300000062 +:103220001300000013000000130000001300000052 +:103230001300000013000000130000001300000042 +:103240001300000013000000130000001300000032 +:103250001300000013000000130000001300000022 +:103260001300000013000000130000001300000012 +:103270001300000013000000130000001300000002 +:1032800013000000130000001300000013000000F2 +:1032900013000000130000001300000013000000E2 +:1032A00013000000130000001300000013000000D2 +:1032B00013000000130000001300000013000000C2 +:1032C00013000000130000001300000013000000B2 +:1032D00013000000130000001300000013000000A2 +:1032E0001300000013000000130000001300000092 +:1032F0001300000013000000130000001300000082 +:103300001300000013000000130000001300000071 +:103310001300000013000000130000001300000061 +:103320001300000013000000130000001300000051 +:103330001300000013000000130000001300000041 +:103340001300000013000000130000001300000031 +:103350001300000013000000130000001300000021 +:103360001300000013000000130000001300000011 +:103370001300000013000000130000001300000001 +:1033800013000000130000001300000013000000F1 +:1033900013000000130000001300000013000000E1 +:1033A00013000000130000001300000013000000D1 +:1033B00013000000130000001300000013000000C1 +:1033C00013000000130000001300000013000000B1 +:1033D00013000000130000001300000013000000A1 +:1033E0001300000013000000130000001300000091 +:1033F0001300000013000000130000001300000081 +:103400001300000013000000130000001300000070 +:103410001300000013000000130000001300000060 +:103420001300000013000000130000001300000050 +:103430001300000013000000130000001300000040 +:103440001300000013000000130000001300000030 +:103450001300000013000000130000001300000020 +:103460001300000013000000130000001300000010 +:103470001300000013000000130000001300000000 +:1034800013000000130000001300000013000000F0 +:1034900013000000130000001300000013000000E0 +:1034A00013000000130000001300000013000000D0 +:1034B00013000000130000001300000013000000C0 +:1034C00013000000130000001300000013000000B0 +:1034D00013000000130000001300000013000000A0 +:1034E0001300000013000000130000001300000090 +:1034F0001300000013000000130000001300000080 +:10350000130000001300000013000000130000006F +:10351000130000001300000013000000130000005F +:10352000130000001300000013000000130000004F +:10353000130000001300000013000000130000003F +:10354000130000001300000013000000130000002F +:10355000130000001300000013000000130000001F +:10356000130000001300000013000000130000000F +:1035700013000000130000001300000013000000FF +:1035800013000000130000001300000013000000EF +:1035900013000000130000001300000013000000DF +:1035A00013000000130000001300000013000000CF +:1035B00013000000130000001300000013000000BF +:1035C00013000000130000001300000013000000AF +:1035D000130000001300000013000000130000009F +:1035E000130000001300000013000000130000008F +:1035F000130000001300000013000000130000007F +:10360000130000001300000013000000130000006E +:10361000130000001300000013000000130000005E +:10362000130000001300000013000000130000004E +:10363000130000001300000013000000130000003E +:10364000130000001300000013000000130000002E +:10365000130000001300000013000000130000001E +:10366000130000001300000013000000130000000E +:1036700013000000130000001300000013000000FE +:1036800013000000130000001300000013000000EE +:1036900013000000130000001300000013000000DE +:1036A00013000000130000001300000013000000CE +:1036B00013000000130000001300000013000000BE +:1036C00013000000130000001300000013000000AE +:1036D000130000001300000013000000130000009E +:1036E000130000001300000013000000130000008E +:1036F000130000001300000013000000130000007E +:10370000130000001300000013000000130000006D +:10371000130000001300000013000000130000005D +:10372000130000001300000013000000130000004D +:10373000130000001300000013000000130000003D +:10374000130000001300000013000000130000002D +:10375000130000001300000013000000130000001D +:10376000130000001300000013000000130000000D +:1037700013000000130000001300000013000000FD +:1037800013000000130000001300000013000000ED +:1037900013000000130000001300000013000000DD +:1037A00013000000130000001300000013000000CD +:1037B00013000000130000001300000013000000BD +:1037C00013000000130000001300000013000000AD +:1037D000130000001300000013000000130000009D +:1037E000130000001300000013000000130000008D +:1037F000130000001300000013000000130000007D +:10380000130000001300000013000000130000006C +:10381000130000001300000013000000130000005C +:10382000130000001300000013000000130000004C +:10383000130000001300000013000000130000003C +:10384000130000001300000013000000130000002C +:10385000130000001300000013000000130000001C +:10386000130000001300000013000000130000000C +:1038700013000000130000001300000013000000FC +:1038800013000000130000001300000013000000EC +:1038900013000000130000001300000013000000DC +:1038A00013000000130000001300000013000000CC +:1038B00013000000130000001300000013000000BC +:1038C00013000000130000001300000013000000AC +:1038D000130000001300000013000000130000009C +:1038E000130000001300000013000000130000008C +:1038F000130000001300000013000000130000007C +:10390000130000001300000013000000130000006B +:10391000130000001300000013000000130000005B +:10392000130000001300000013000000130000004B +:10393000130000001300000013000000130000003B +:10394000130000001300000013000000130000002B +:10395000130000001300000013000000130000001B +:10396000130000001300000013000000130000000B +:1039700013000000130000001300000013000000FB +:1039800013000000130000001300000013000000EB +:1039900013000000130000001300000013000000DB +:1039A00013000000130000001300000013000000CB +:1039B00013000000130000001300000013000000BB +:1039C00013000000130000001300000013000000AB +:1039D000130000001300000013000000130000009B +:1039E000130000001300000013000000130000008B +:1039F000130000001300000013000000130000007B +:103A0000130000001300000013000000130000006A +:103A1000130000001300000013000000130000005A +:103A2000130000001300000013000000130000004A +:103A3000130000001300000013000000130000003A +:103A4000130000001300000013000000130000002A +:103A5000130000001300000013000000130000001A +:103A6000130000001300000013000000130000000A +:103A700013000000130000001300000013000000FA +:103A800013000000130000001300000013000000EA +:103A900013000000130000001300000013000000DA +:103AA00013000000130000001300000013000000CA +:103AB00013000000130000001300000013000000BA +:103AC00013000000130000001300000013000000AA +:103AD000130000001300000013000000130000009A +:103AE000130000001300000013000000130000008A +:103AF000130000001300000013000000130000007A +:103B00001300000013000000130000001300000069 +:103B10001300000013000000130000001300000059 +:103B20001300000013000000130000001300000049 +:103B30001300000013000000130000001300000039 +:103B40001300000013000000130000001300000029 +:103B50001300000013000000130000001300000019 +:103B60001300000013000000130000001300000009 +:103B700013000000130000001300000013000000F9 +:103B800013000000130000001300000013000000E9 +:103B900013000000130000001300000013000000D9 +:103BA00013000000130000001300000013000000C9 +:103BB00013000000130000001300000013000000B9 +:103BC00013000000130000001300000013000000A9 +:103BD0001300000013000000130000001300000099 +:103BE0001300000013000000130000001300000089 +:103BF0001300000013000000130000001300000079 +:103C00001300000013000000130000001300000068 +:103C10001300000013000000130000001300000058 +:103C20001300000013000000130000001300000048 +:103C30001300000013000000130000001300000038 +:103C40001300000013000000130000001300000028 +:103C50001300000013000000130000001300000018 +:103C60001300000013000000130000001300000008 +:103C700013000000130000001300000013000000F8 +:103C800013000000130000001300000013000000E8 +:103C900013000000130000001300000013000000D8 +:103CA00013000000130000001300000013000000C8 +:103CB00013000000130000001300000013000000B8 +:103CC00013000000130000001300000013000000A8 +:103CD0001300000013000000130000001300000098 +:103CE0001300000013000000130000001300000088 +:103CF0001300000013000000130000001300000078 +:103D00001300000013000000130000001300000067 +:103D10001300000013000000130000001300000057 +:103D20001300000013000000130000001300000047 +:103D30001300000013000000130000001300000037 +:103D40001300000013000000130000001300000027 +:103D50001300000013000000130000001300000017 +:103D60001300000013000000130000001300000007 +:103D700013000000130000001300000013000000F7 +:103D800013000000130000001300000013000000E7 +:103D900013000000130000001300000013000000D7 +:103DA00013000000130000001300000013000000C7 +:103DB00013000000130000001300000013000000B7 +:103DC00013000000130000001300000013000000A7 +:103DD0001300000013000000130000001300000097 +:103DE0001300000013000000130000001300000087 +:103DF0001300000013000000130000001300000077 +:103E00001300000013000000130000001300000066 +:103E10001300000013000000130000001300000056 +:103E20001300000013000000130000001300000046 +:103E30001300000013000000130000001300000036 +:103E40001300000013000000130000001300000026 +:103E50001300000013000000130000001300000016 +:103E60001300000013000000130000001300000006 +:103E700013000000130000001300000013000000F6 +:103E800013000000130000001300000013000000E6 +:103E900013000000130000001300000013000000D6 +:103EA00013000000130000001300000013000000C6 +:103EB00013000000130000001300000013000000B6 +:103EC00013000000130000001300000013000000A6 +:103ED0001300000013000000130000001300000096 +:103EE0001300000013000000130000001300000086 +:103EF0001300000013000000130000001300000076 +:103F00001300000013000000130000001300000065 +:103F10001300000013000000130000001300000055 +:103F20001300000013000000130000001300000045 +:103F30001300000013000000130000001300000035 +:103F40001300000013000000130000001300000025 +:103F50001300000013000000130000001300000015 +:103F60001300000013000000130000001300000005 +:103F700013000000130000001300000013000000F5 +:103F800013000000130000001300000013000000E5 +:103F900013000000130000001300000013000000D5 +:103FA00013000000130000001300000013000000C5 +:103FB00013000000130000001300000013000000B5 +:103FC00013000000130000001300000013000000A5 +:103FD0001300000013000000130000001300000095 +:103FE0001300000013000000130000001300000085 +:103FF0001300000013000000130000001300000075 +:104000000000000013000000130000001300000077 +:104010001300000013000000130000001300000054 +:104020001300000013000000130000001300000044 +:104030001300000013000000130000001300000034 +:104040001300000013000000130000001300000024 +:104050001300000013000000130000001300000014 +:104060001300000013000000130000001300000004 +:1040700013000000130000001300000013000000F4 +:1040800013000000130000001300000013000000E4 +:1040900013000000130000001300000013000000D4 +:1040A00013000000130000001300000013000000C4 +:1040B00013000000130000001300000013000000B4 +:1040C00013000000130000001300000013000000A4 +:1040D0001300000013000000130000001300000094 +:1040E0001300000013000000130000001300000084 +:1040F0001300000013000000130000001300000074 +:104100001300000013000000130000001300000063 +:104110001300000013000000130000001300000053 +:104120001300000013000000130000001300000043 +:104130001300000013000000130000001300000033 +:104140001300000013000000130000001300000023 +:104150001300000013000000130000001300000013 +:104160001300000013000000130000001300000003 +:1041700013000000130000001300000013000000F3 +:1041800013000000130000001300000013000000E3 +:1041900013000000130000001300000013000000D3 +:1041A00013000000130000001300000013000000C3 +:1041B00013000000130000001300000013000000B3 +:1041C00013000000130000001300000013000000A3 +:1041D0001300000013000000130000001300000093 +:1041E0001300000013000000130000001300000083 +:1041F0001300000013000000130000001300000073 +:104200001300000013000000130000001300000062 +:104210001300000013000000130000001300000052 +:104220001300000013000000130000001300000042 +:104230001300000013000000130000001300000032 +:104240001300000013000000130000001300000022 +:104250001300000013000000130000001300000012 +:104260001300000013000000130000001300000002 +:1042700013000000130000001300000013000000F2 +:1042800013000000130000001300000013000000E2 +:1042900013000000130000001300000013000000D2 +:1042A00013000000130000001300000013000000C2 +:1042B00013000000130000001300000013000000B2 +:1042C00013000000130000001300000013000000A2 +:1042D0001300000013000000130000001300000092 +:1042E0001300000013000000130000001300000082 +:1042F0001300000013000000130000001300000072 +:104300001300000013000000130000001300000061 +:104310001300000013000000130000001300000051 +:104320001300000013000000130000001300000041 +:104330001300000013000000130000001300000031 +:104340001300000013000000130000001300000021 +:104350001300000013000000130000001300000011 +:104360001300000013000000130000001300000001 +:1043700013000000130000001300000013000000F1 +:1043800013000000130000001300000013000000E1 +:1043900013000000130000001300000013000000D1 +:1043A00013000000130000001300000013000000C1 +:1043B00013000000130000001300000013000000B1 +:1043C00013000000130000001300000013000000A1 +:1043D0001300000013000000130000001300000091 +:1043E0001300000013000000130000001300000081 +:1043F0001300000013000000130000001300000071 +:104400001300000013000000130000001300000060 +:104410001300000013000000130000001300000050 +:104420001300000013000000130000001300000040 +:104430001300000013000000130000001300000030 +:104440001300000013000000130000001300000020 +:104450001300000013000000130000001300000010 +:104460001300000013000000130000001300000000 +:1044700013000000130000001300000013000000F0 +:1044800013000000130000001300000013000000E0 +:1044900013000000130000001300000013000000D0 +:1044A00013000000130000001300000013000000C0 +:1044B00013000000130000001300000013000000B0 +:1044C00013000000130000001300000013000000A0 +:1044D0001300000013000000130000001300000090 +:1044E0001300000013000000130000001300000080 +:1044F0001300000013000000130000001300000070 +:10450000130000001300000013000000130000005F +:10451000130000001300000013000000130000004F +:10452000130000001300000013000000130000003F +:10453000130000001300000013000000130000002F +:10454000130000001300000013000000130000001F +:10455000130000001300000013000000130000000F +:1045600013000000130000001300000013000000FF +:1045700013000000130000001300000013000000EF +:1045800013000000130000001300000013000000DF +:1045900013000000130000001300000013000000CF +:1045A00013000000130000001300000013000000BF +:1045B00013000000130000001300000013000000AF +:1045C000130000001300000013000000130000009F +:1045D000130000001300000013000000130000008F +:1045E000130000001300000013000000130000007F +:1045F000130000001300000013000000130000006F +:10460000130000001300000013000000130000005E +:10461000130000001300000013000000130000004E +:10462000130000001300000013000000130000003E +:10463000130000001300000013000000130000002E +:10464000130000001300000013000000130000001E +:10465000130000001300000013000000130000000E +:1046600013000000130000001300000013000000FE +:1046700013000000130000001300000013000000EE +:1046800013000000130000001300000013000000DE +:1046900013000000130000001300000013000000CE +:1046A00013000000130000001300000013000000BE +:1046B00013000000130000001300000013000000AE +:1046C000130000001300000013000000130000009E +:1046D000130000001300000013000000130000008E +:1046E000130000001300000013000000130000007E +:1046F000130000001300000013000000130000006E +:10470000130000001300000013000000130000005D +:10471000130000001300000013000000130000004D +:10472000130000001300000013000000130000003D +:10473000130000001300000013000000130000002D +:10474000130000001300000013000000130000001D +:10475000130000001300000013000000130000000D +:1047600013000000130000001300000013000000FD +:1047700013000000130000001300000013000000ED +:1047800013000000130000001300000013000000DD +:1047900013000000130000001300000013000000CD +:1047A00013000000130000001300000013000000BD +:1047B00013000000130000001300000013000000AD +:1047C000130000001300000013000000130000009D +:1047D000130000001300000013000000130000008D +:1047E000130000001300000013000000130000007D +:1047F000130000001300000013000000130000006D +:10480000130000001300000013000000130000005C +:10481000130000001300000013000000130000004C +:10482000130000001300000013000000130000003C +:10483000130000001300000013000000130000002C +:10484000130000001300000013000000130000001C +:10485000130000001300000013000000130000000C +:1048600013000000130000001300000013000000FC +:1048700013000000130000001300000013000000EC +:1048800013000000130000001300000013000000DC +:1048900013000000130000001300000013000000CC +:1048A00013000000130000001300000013000000BC +:1048B00013000000130000001300000013000000AC +:1048C000130000001300000013000000130000009C +:1048D000130000001300000013000000130000008C +:1048E000130000001300000013000000130000007C +:1048F000130000001300000013000000130000006C +:10490000130000001300000013000000130000005B +:10491000130000001300000013000000130000004B +:10492000130000001300000013000000130000003B +:10493000130000001300000013000000130000002B +:10494000130000001300000013000000130000001B +:10495000130000001300000013000000130000000B +:1049600013000000130000001300000013000000FB +:1049700013000000130000001300000013000000EB +:1049800013000000130000001300000013000000DB +:1049900013000000130000001300000013000000CB +:1049A00013000000130000001300000013000000BB +:1049B00013000000130000001300000013000000AB +:1049C000130000001300000013000000130000009B +:1049D000130000001300000013000000130000008B +:1049E000130000001300000013000000130000007B +:1049F000130000001300000013000000130000006B +:104A0000130000001300000013000000130000005A +:104A1000130000001300000013000000130000004A +:104A2000130000001300000013000000130000003A +:104A3000130000001300000013000000130000002A +:104A4000130000001300000013000000130000001A +:104A5000130000001300000013000000130000000A +:104A600013000000130000001300000013000000FA +:104A700013000000130000001300000013000000EA +:104A800013000000130000001300000013000000DA +:104A900013000000130000001300000013000000CA +:104AA00013000000130000001300000013000000BA +:104AB00013000000130000001300000013000000AA +:104AC000130000001300000013000000130000009A +:104AD000130000001300000013000000130000008A +:104AE000130000001300000013000000130000007A +:104AF000130000001300000013000000130000006A +:104B00001300000013000000130000001300000059 +:104B10001300000013000000130000001300000049 +:104B20001300000013000000130000001300000039 +:104B30001300000013000000130000001300000029 +:104B40001300000013000000130000001300000019 +:104B50001300000013000000130000001300000009 +:104B600013000000130000001300000013000000F9 +:104B700013000000130000001300000013000000E9 +:104B800013000000130000001300000013000000D9 +:104B900013000000130000001300000013000000C9 +:104BA00013000000130000001300000013000000B9 +:104BB00013000000130000001300000013000000A9 +:104BC0001300000013000000130000001300000099 +:104BD0001300000013000000130000001300000089 +:104BE0001300000013000000130000001300000079 +:104BF0001300000013000000130000001300000069 +:104C00001300000013000000130000001300000058 +:104C10001300000013000000130000001300000048 +:104C20001300000013000000130000001300000038 +:104C30001300000013000000130000001300000028 +:104C40001300000013000000130000001300000018 +:104C50001300000013000000130000001300000008 +:104C600013000000130000001300000013000000F8 +:104C700013000000130000001300000013000000E8 +:104C800013000000130000001300000013000000D8 +:104C900013000000130000001300000013000000C8 +:104CA00013000000130000001300000013000000B8 +:104CB00013000000130000001300000013000000A8 +:104CC0001300000013000000130000001300000098 +:104CD0001300000013000000130000001300000088 +:104CE0001300000013000000130000001300000078 +:104CF0001300000013000000130000001300000068 +:104D00001300000013000000130000001300000057 +:104D10001300000013000000130000001300000047 +:104D20001300000013000000130000001300000037 +:104D30001300000013000000130000001300000027 +:104D40001300000013000000130000001300000017 +:104D50001300000013000000130000001300000007 +:104D600013000000130000001300000013000000F7 +:104D700013000000130000001300000013000000E7 +:104D800013000000130000001300000013000000D7 +:104D900013000000130000001300000013000000C7 +:104DA00013000000130000001300000013000000B7 +:104DB00013000000130000001300000013000000A7 +:104DC0001300000013000000130000001300000097 +:104DD0001300000013000000130000001300000087 +:104DE0001300000013000000130000001300000077 +:104DF0001300000013000000130000001300000067 +:104E00001300000013000000130000001300000056 +:104E10001300000013000000130000001300000046 +:104E20001300000013000000130000001300000036 +:104E30001300000013000000130000001300000026 +:104E40001300000013000000130000001300000016 +:104E50001300000013000000130000001300000006 +:104E600013000000130000001300000013000000F6 +:104E700013000000130000001300000013000000E6 +:104E800013000000130000001300000013000000D6 +:104E900013000000130000001300000013000000C6 +:104EA00013000000130000001300000013000000B6 +:104EB00013000000130000001300000013000000A6 +:104EC0001300000013000000130000001300000096 +:104ED0001300000013000000130000001300000086 +:104EE0001300000013000000130000001300000076 +:104EF0001300000013000000130000001300000066 +:104F00001300000013000000130000001300000055 +:104F10001300000013000000130000001300000045 +:104F20001300000013000000130000001300000035 +:104F30001300000013000000130000001300000025 +:104F40001300000013000000130000001300000015 +:104F50001300000013000000130000001300000005 +:104F600013000000130000001300000013000000F5 +:104F700013000000130000001300000013000000E5 +:104F800013000000130000001300000013000000D5 +:104F900013000000130000001300000013000000C5 +:104FA00013000000130000001300000013000000B5 +:104FB00013000000130000001300000013000000A5 +:104FC0001300000013000000130000001300000095 +:104FD0001300000013000000130000001300000085 +:104FE0001300000013000000130000001300000075 +:104FF0001300000013000000130000001300000065 +:10500000000102030405060708090A0B0C0D0E0F28 +:105010001300000013000000130000001300000044 +:105020001300000013000000130000001300000034 +:105030001300000013000000130000001300000024 +:105040001300000013000000130000001300000014 +:105050001300000013000000130000001300000004 +:1050600013000000130000001300000013000000F4 +:1050700013000000130000001300000013000000E4 +:1050800013000000130000001300000013000000D4 +:1050900013000000130000001300000013000000C4 +:1050A00013000000130000001300000013000000B4 +:1050B00013000000130000001300000013000000A4 +:1050C0001300000013000000130000001300000094 +:1050D0001300000013000000130000001300000084 +:1050E0001300000013000000130000001300000074 +:1050F0001300000013000000130000001300000064 +:105100001300000013000000130000001300000053 +:105110001300000013000000130000001300000043 +:105120001300000013000000130000001300000033 +:105130001300000013000000130000001300000023 +:105140001300000013000000130000001300000013 +:105150001300000013000000130000001300000003 +:1051600013000000130000001300000013000000F3 +:1051700013000000130000001300000013000000E3 +:1051800013000000130000001300000013000000D3 +:1051900013000000130000001300000013000000C3 +:1051A00013000000130000001300000013000000B3 +:1051B00013000000130000001300000013000000A3 +:1051C0001300000013000000130000001300000093 +:1051D0001300000013000000130000001300000083 +:1051E0001300000013000000130000001300000073 +:1051F0001300000013000000130000001300000063 +:105200001300000013000000130000001300000052 +:105210001300000013000000130000001300000042 +:105220001300000013000000130000001300000032 +:105230001300000013000000130000001300000022 +:105240001300000013000000130000001300000012 +:105250001300000013000000130000001300000002 +:1052600013000000130000001300000013000000F2 +:1052700013000000130000001300000013000000E2 +:1052800013000000130000001300000013000000D2 +:1052900013000000130000001300000013000000C2 +:1052A00013000000130000001300000013000000B2 +:1052B00013000000130000001300000013000000A2 +:1052C0001300000013000000130000001300000092 +:1052D0001300000013000000130000001300000082 +:1052E0001300000013000000130000001300000072 +:1052F0001300000013000000130000001300000062 +:105300001300000013000000130000001300000051 +:105310001300000013000000130000001300000041 +:105320001300000013000000130000001300000031 +:105330001300000013000000130000001300000021 +:105340001300000013000000130000001300000011 +:105350001300000013000000130000001300000001 +:1053600013000000130000001300000013000000F1 +:1053700013000000130000001300000013000000E1 +:1053800013000000130000001300000013000000D1 +:1053900013000000130000001300000013000000C1 +:1053A00013000000130000001300000013000000B1 +:1053B00013000000130000001300000013000000A1 +:1053C0001300000013000000130000001300000091 +:1053D0001300000013000000130000001300000081 +:1053E0001300000013000000130000001300000071 +:1053F0001300000013000000130000001300000061 +:105400001300000013000000130000001300000050 +:105410001300000013000000130000001300000040 +:105420001300000013000000130000001300000030 +:105430001300000013000000130000001300000020 +:105440001300000013000000130000001300000010 +:105450001300000013000000130000001300000000 +:1054600013000000130000001300000013000000F0 +:1054700013000000130000001300000013000000E0 +:1054800013000000130000001300000013000000D0 +:1054900013000000130000001300000013000000C0 +:1054A00013000000130000001300000013000000B0 +:1054B00013000000130000001300000013000000A0 +:1054C0001300000013000000130000001300000090 +:1054D0001300000013000000130000001300000080 +:1054E0001300000013000000130000001300000070 +:1054F0001300000013000000130000001300000060 +:10550000130000001300000013000000130000004F +:10551000130000001300000013000000130000003F +:10552000130000001300000013000000130000002F +:10553000130000001300000013000000130000001F +:10554000130000001300000013000000130000000F +:1055500013000000130000001300000013000000FF +:1055600013000000130000001300000013000000EF +:1055700013000000130000001300000013000000DF +:1055800013000000130000001300000013000000CF +:1055900013000000130000001300000013000000BF +:1055A00013000000130000001300000013000000AF +:1055B000130000001300000013000000130000009F +:1055C000130000001300000013000000130000008F +:1055D000130000001300000013000000130000007F +:1055E000130000001300000013000000130000006F +:1055F000130000001300000013000000130000005F +:10560000130000001300000013000000130000004E +:10561000130000001300000013000000130000003E +:10562000130000001300000013000000130000002E +:10563000130000001300000013000000130000001E +:10564000130000001300000013000000130000000E +:1056500013000000130000001300000013000000FE +:1056600013000000130000001300000013000000EE +:1056700013000000130000001300000013000000DE +:1056800013000000130000001300000013000000CE +:1056900013000000130000001300000013000000BE +:1056A00013000000130000001300000013000000AE +:1056B000130000001300000013000000130000009E +:1056C000130000001300000013000000130000008E +:1056D000130000001300000013000000130000007E +:1056E000130000001300000013000000130000006E +:1056F000130000001300000013000000130000005E +:10570000130000001300000013000000130000004D +:10571000130000001300000013000000130000003D +:10572000130000001300000013000000130000002D +:10573000130000001300000013000000130000001D +:10574000130000001300000013000000130000000D +:1057500013000000130000001300000013000000FD +:1057600013000000130000001300000013000000ED +:1057700013000000130000001300000013000000DD +:1057800013000000130000001300000013000000CD +:1057900013000000130000001300000013000000BD +:1057A00013000000130000001300000013000000AD +:1057B000130000001300000013000000130000009D +:1057C000130000001300000013000000130000008D +:1057D000130000001300000013000000130000007D +:1057E000130000001300000013000000130000006D +:1057F000130000001300000013000000130000005D +:10580000130000001300000013000000130000004C +:10581000130000001300000013000000130000003C +:10582000130000001300000013000000130000002C +:10583000130000001300000013000000130000001C +:10584000130000001300000013000000130000000C +:1058500013000000130000001300000013000000FC +:1058600013000000130000001300000013000000EC +:1058700013000000130000001300000013000000DC +:1058800013000000130000001300000013000000CC +:1058900013000000130000001300000013000000BC +:1058A00013000000130000001300000013000000AC +:1058B000130000001300000013000000130000009C +:1058C000130000001300000013000000130000008C +:1058D000130000001300000013000000130000007C +:1058E000130000001300000013000000130000006C +:1058F000130000001300000013000000130000005C +:10590000130000001300000013000000130000004B +:10591000130000001300000013000000130000003B +:10592000130000001300000013000000130000002B +:10593000130000001300000013000000130000001B +:10594000130000001300000013000000130000000B +:1059500013000000130000001300000013000000FB +:1059600013000000130000001300000013000000EB +:1059700013000000130000001300000013000000DB +:1059800013000000130000001300000013000000CB +:1059900013000000130000001300000013000000BB +:1059A00013000000130000001300000013000000AB +:1059B000130000001300000013000000130000009B +:1059C000130000001300000013000000130000008B +:1059D000130000001300000013000000130000007B +:1059E000130000001300000013000000130000006B +:1059F000130000001300000013000000130000005B +:105A0000130000001300000013000000130000004A +:105A1000130000001300000013000000130000003A +:105A2000130000001300000013000000130000002A +:105A3000130000001300000013000000130000001A +:105A4000130000001300000013000000130000000A +:105A500013000000130000001300000013000000FA +:105A600013000000130000001300000013000000EA +:105A700013000000130000001300000013000000DA +:105A800013000000130000001300000013000000CA +:105A900013000000130000001300000013000000BA +:105AA00013000000130000001300000013000000AA +:105AB000130000001300000013000000130000009A +:105AC000130000001300000013000000130000008A +:105AD000130000001300000013000000130000007A +:105AE000130000001300000013000000130000006A +:105AF000130000001300000013000000130000005A +:105B00001300000013000000130000001300000049 +:105B10001300000013000000130000001300000039 +:105B20001300000013000000130000001300000029 +:105B30001300000013000000130000001300000019 +:105B40001300000013000000130000001300000009 +:105B500013000000130000001300000013000000F9 +:105B600013000000130000001300000013000000E9 +:105B700013000000130000001300000013000000D9 +:105B800013000000130000001300000013000000C9 +:105B900013000000130000001300000013000000B9 +:105BA00013000000130000001300000013000000A9 +:105BB0001300000013000000130000001300000099 +:105BC0001300000013000000130000001300000089 +:105BD0001300000013000000130000001300000079 +:105BE0001300000013000000130000001300000069 +:105BF0001300000013000000130000001300000059 +:105C00001300000013000000130000001300000048 +:105C10001300000013000000130000001300000038 +:105C20001300000013000000130000001300000028 +:105C30001300000013000000130000001300000018 +:105C40001300000013000000130000001300000008 +:105C500013000000130000001300000013000000F8 +:105C600013000000130000001300000013000000E8 +:105C700013000000130000001300000013000000D8 +:105C800013000000130000001300000013000000C8 +:105C900013000000130000001300000013000000B8 +:105CA00013000000130000001300000013000000A8 +:105CB0001300000013000000130000001300000098 +:105CC0001300000013000000130000001300000088 +:105CD0001300000013000000130000001300000078 +:105CE0001300000013000000130000001300000068 +:105CF0001300000013000000130000001300000058 +:105D00001300000013000000130000001300000047 +:105D10001300000013000000130000001300000037 +:105D20001300000013000000130000001300000027 +:105D30001300000013000000130000001300000017 +:105D40001300000013000000130000001300000007 +:105D500013000000130000001300000013000000F7 +:105D600013000000130000001300000013000000E7 +:105D700013000000130000001300000013000000D7 +:105D800013000000130000001300000013000000C7 +:105D900013000000130000001300000013000000B7 +:105DA00013000000130000001300000013000000A7 +:105DB0001300000013000000130000001300000097 +:105DC0001300000013000000130000001300000087 +:105DD0001300000013000000130000001300000077 +:105DE0001300000013000000130000001300000067 +:105DF0001300000013000000130000001300000057 +:105E00001300000013000000130000001300000046 +:105E10001300000013000000130000001300000036 +:105E20001300000013000000130000001300000026 +:105E30001300000013000000130000001300000016 +:105E40001300000013000000130000001300000006 +:105E500013000000130000001300000013000000F6 +:105E600013000000130000001300000013000000E6 +:105E700013000000130000001300000013000000D6 +:105E800013000000130000001300000013000000C6 +:105E900013000000130000001300000013000000B6 +:105EA00013000000130000001300000013000000A6 +:105EB0001300000013000000130000001300000096 +:105EC0001300000013000000130000001300000086 +:105ED0001300000013000000130000001300000076 +:105EE0001300000013000000130000001300000066 +:105EF0001300000013000000130000001300000056 +:105F00001300000013000000130000001300000045 +:105F10001300000013000000130000001300000035 +:105F20001300000013000000130000001300000025 +:105F30001300000013000000130000001300000015 +:105F40001300000013000000130000001300000005 +:105F500013000000130000001300000013000000F5 +:105F600013000000130000001300000013000000E5 +:105F700013000000130000001300000013000000D5 +:105F800013000000130000001300000013000000C5 +:105F900013000000130000001300000013000000B5 +:105FA00013000000130000001300000013000000A5 +:105FB0001300000013000000130000001300000095 +:105FC0001300000013000000130000001300000085 +:105FD0001300000013000000130000001300000075 +:105FE0001300000013000000130000001300000065 +:105FF0001300000013000000130000001300000055 +:10600000101112131415161718191A1B1C1D1E1F18 +:106010001300000013000000130000001300000034 +:106020001300000013000000130000001300000024 +:106030001300000013000000130000001300000014 +:106040001300000013000000130000001300000004 +:1060500013000000130000001300000013000000F4 +:1060600013000000130000001300000013000000E4 +:1060700013000000130000001300000013000000D4 +:1060800013000000130000001300000013000000C4 +:1060900013000000130000001300000013000000B4 +:1060A00013000000130000001300000013000000A4 +:1060B0001300000013000000130000001300000094 +:1060C0001300000013000000130000001300000084 +:1060D0001300000013000000130000001300000074 +:1060E0001300000013000000130000001300000064 +:1060F0001300000013000000130000001300000054 +:106100001300000013000000130000001300000043 +:106110001300000013000000130000001300000033 +:106120001300000013000000130000001300000023 +:106130001300000013000000130000001300000013 +:106140001300000013000000130000001300000003 +:1061500013000000130000001300000013000000F3 +:1061600013000000130000001300000013000000E3 +:1061700013000000130000001300000013000000D3 +:1061800013000000130000001300000013000000C3 +:1061900013000000130000001300000013000000B3 +:1061A00013000000130000001300000013000000A3 +:1061B0001300000013000000130000001300000093 +:1061C0001300000013000000130000001300000083 +:1061D0001300000013000000130000001300000073 +:1061E0001300000013000000130000001300000063 +:1061F0001300000013000000130000001300000053 +:106200001300000013000000130000001300000042 +:106210001300000013000000130000001300000032 +:106220001300000013000000130000001300000022 +:106230001300000013000000130000001300000012 +:106240001300000013000000130000001300000002 +:1062500013000000130000001300000013000000F2 +:1062600013000000130000001300000013000000E2 +:1062700013000000130000001300000013000000D2 +:1062800013000000130000001300000013000000C2 +:1062900013000000130000001300000013000000B2 +:1062A00013000000130000001300000013000000A2 +:1062B0001300000013000000130000001300000092 +:1062C0001300000013000000130000001300000082 +:1062D0001300000013000000130000001300000072 +:1062E0001300000013000000130000001300000062 +:1062F0001300000013000000130000001300000052 +:106300001300000013000000130000001300000041 +:106310001300000013000000130000001300000031 +:106320001300000013000000130000001300000021 +:106330001300000013000000130000001300000011 +:106340001300000013000000130000001300000001 +:1063500013000000130000001300000013000000F1 +:1063600013000000130000001300000013000000E1 +:1063700013000000130000001300000013000000D1 +:1063800013000000130000001300000013000000C1 +:1063900013000000130000001300000013000000B1 +:1063A00013000000130000001300000013000000A1 +:1063B0001300000013000000130000001300000091 +:1063C0001300000013000000130000001300000081 +:1063D0001300000013000000130000001300000071 +:1063E0001300000013000000130000001300000061 +:1063F0001300000013000000130000001300000051 +:106400001300000013000000130000001300000040 +:106410001300000013000000130000001300000030 +:106420001300000013000000130000001300000020 +:106430001300000013000000130000001300000010 +:106440001300000013000000130000001300000000 +:1064500013000000130000001300000013000000F0 +:1064600013000000130000001300000013000000E0 +:1064700013000000130000001300000013000000D0 +:1064800013000000130000001300000013000000C0 +:1064900013000000130000001300000013000000B0 +:1064A00013000000130000001300000013000000A0 +:1064B0001300000013000000130000001300000090 +:1064C0001300000013000000130000001300000080 +:1064D0001300000013000000130000001300000070 +:1064E0001300000013000000130000001300000060 +:1064F0001300000013000000130000001300000050 +:10650000130000001300000013000000130000003F +:10651000130000001300000013000000130000002F +:10652000130000001300000013000000130000001F +:10653000130000001300000013000000130000000F +:1065400013000000130000001300000013000000FF +:1065500013000000130000001300000013000000EF +:1065600013000000130000001300000013000000DF +:1065700013000000130000001300000013000000CF +:1065800013000000130000001300000013000000BF +:1065900013000000130000001300000013000000AF +:1065A000130000001300000013000000130000009F +:1065B000130000001300000013000000130000008F +:1065C000130000001300000013000000130000007F +:1065D000130000001300000013000000130000006F +:1065E000130000001300000013000000130000005F +:1065F000130000001300000013000000130000004F +:10660000130000001300000013000000130000003E +:10661000130000001300000013000000130000002E +:10662000130000001300000013000000130000001E +:10663000130000001300000013000000130000000E +:1066400013000000130000001300000013000000FE +:1066500013000000130000001300000013000000EE +:1066600013000000130000001300000013000000DE +:1066700013000000130000001300000013000000CE +:1066800013000000130000001300000013000000BE +:1066900013000000130000001300000013000000AE +:1066A000130000001300000013000000130000009E +:1066B000130000001300000013000000130000008E +:1066C000130000001300000013000000130000007E +:1066D000130000001300000013000000130000006E +:1066E000130000001300000013000000130000005E +:1066F000130000001300000013000000130000004E +:10670000130000001300000013000000130000003D +:10671000130000001300000013000000130000002D +:10672000130000001300000013000000130000001D +:10673000130000001300000013000000130000000D +:1067400013000000130000001300000013000000FD +:1067500013000000130000001300000013000000ED +:1067600013000000130000001300000013000000DD +:1067700013000000130000001300000013000000CD +:1067800013000000130000001300000013000000BD +:1067900013000000130000001300000013000000AD +:1067A000130000001300000013000000130000009D +:1067B000130000001300000013000000130000008D +:1067C000130000001300000013000000130000007D +:1067D000130000001300000013000000130000006D +:1067E000130000001300000013000000130000005D +:1067F000130000001300000013000000130000004D +:10680000130000001300000013000000130000003C +:10681000130000001300000013000000130000002C +:10682000130000001300000013000000130000001C +:10683000130000001300000013000000130000000C +:1068400013000000130000001300000013000000FC +:1068500013000000130000001300000013000000EC +:1068600013000000130000001300000013000000DC +:1068700013000000130000001300000013000000CC +:1068800013000000130000001300000013000000BC +:1068900013000000130000001300000013000000AC +:1068A000130000001300000013000000130000009C +:1068B000130000001300000013000000130000008C +:1068C000130000001300000013000000130000007C +:1068D000130000001300000013000000130000006C +:1068E000130000001300000013000000130000005C +:1068F000130000001300000013000000130000004C +:10690000130000001300000013000000130000003B +:10691000130000001300000013000000130000002B +:10692000130000001300000013000000130000001B +:10693000130000001300000013000000130000000B +:1069400013000000130000001300000013000000FB +:1069500013000000130000001300000013000000EB +:1069600013000000130000001300000013000000DB +:1069700013000000130000001300000013000000CB +:1069800013000000130000001300000013000000BB +:1069900013000000130000001300000013000000AB +:1069A000130000001300000013000000130000009B +:1069B000130000001300000013000000130000008B +:1069C000130000001300000013000000130000007B +:1069D000130000001300000013000000130000006B +:1069E000130000001300000013000000130000005B +:1069F000130000001300000013000000130000004B +:106A0000130000001300000013000000130000003A +:106A1000130000001300000013000000130000002A +:106A2000130000001300000013000000130000001A +:106A3000130000001300000013000000130000000A +:106A400013000000130000001300000013000000FA +:106A500013000000130000001300000013000000EA +:106A600013000000130000001300000013000000DA +:106A700013000000130000001300000013000000CA +:106A800013000000130000001300000013000000BA +:106A900013000000130000001300000013000000AA +:106AA000130000001300000013000000130000009A +:106AB000130000001300000013000000130000008A +:106AC000130000001300000013000000130000007A +:106AD000130000001300000013000000130000006A +:106AE000130000001300000013000000130000005A +:106AF000130000001300000013000000130000004A +:106B00001300000013000000130000001300000039 +:106B10001300000013000000130000001300000029 +:106B20001300000013000000130000001300000019 +:106B30001300000013000000130000001300000009 +:106B400013000000130000001300000013000000F9 +:106B500013000000130000001300000013000000E9 +:106B600013000000130000001300000013000000D9 +:106B700013000000130000001300000013000000C9 +:106B800013000000130000001300000013000000B9 +:106B900013000000130000001300000013000000A9 +:106BA0001300000013000000130000001300000099 +:106BB0001300000013000000130000001300000089 +:106BC0001300000013000000130000001300000079 +:106BD0001300000013000000130000001300000069 +:106BE0001300000013000000130000001300000059 +:106BF0001300000013000000130000001300000049 +:106C00001300000013000000130000001300000038 +:106C10001300000013000000130000001300000028 +:106C20001300000013000000130000001300000018 +:106C30001300000013000000130000001300000008 +:106C400013000000130000001300000013000000F8 +:106C500013000000130000001300000013000000E8 +:106C600013000000130000001300000013000000D8 +:106C700013000000130000001300000013000000C8 +:106C800013000000130000001300000013000000B8 +:106C900013000000130000001300000013000000A8 +:106CA0001300000013000000130000001300000098 +:106CB0001300000013000000130000001300000088 +:106CC0001300000013000000130000001300000078 +:106CD0001300000013000000130000001300000068 +:106CE0001300000013000000130000001300000058 +:106CF0001300000013000000130000001300000048 +:106D00001300000013000000130000001300000037 +:106D10001300000013000000130000001300000027 +:106D20001300000013000000130000001300000017 +:106D30001300000013000000130000001300000007 +:106D400013000000130000001300000013000000F7 +:106D500013000000130000001300000013000000E7 +:106D600013000000130000001300000013000000D7 +:106D700013000000130000001300000013000000C7 +:106D800013000000130000001300000013000000B7 +:106D900013000000130000001300000013000000A7 +:106DA0001300000013000000130000001300000097 +:106DB0001300000013000000130000001300000087 +:106DC0001300000013000000130000001300000077 +:106DD0001300000013000000130000001300000067 +:106DE0001300000013000000130000001300000057 +:106DF0001300000013000000130000001300000047 +:106E00001300000013000000130000001300000036 +:106E10001300000013000000130000001300000026 +:106E20001300000013000000130000001300000016 +:106E30001300000013000000130000001300000006 +:106E400013000000130000001300000013000000F6 +:106E500013000000130000001300000013000000E6 +:106E600013000000130000001300000013000000D6 +:106E700013000000130000001300000013000000C6 +:106E800013000000130000001300000013000000B6 +:106E900013000000130000001300000013000000A6 +:106EA0001300000013000000130000001300000096 +:106EB0001300000013000000130000001300000086 +:106EC0001300000013000000130000001300000076 +:106ED0001300000013000000130000001300000066 +:106EE0001300000013000000130000001300000056 +:106EF0001300000013000000130000001300000046 +:106F00001300000013000000130000001300000035 +:106F10001300000013000000130000001300000025 +:106F20001300000013000000130000001300000015 +:106F30001300000013000000130000001300000005 +:106F400013000000130000001300000013000000F5 +:106F500013000000130000001300000013000000E5 +:106F600013000000130000001300000013000000D5 +:106F700013000000130000001300000013000000C5 +:106F800013000000130000001300000013000000B5 +:106F900013000000130000001300000013000000A5 +:106FA0001300000013000000130000001300000095 +:106FB0001300000013000000130000001300000085 +:106FC0001300000013000000130000001300000075 +:106FD0001300000013000000130000001300000065 +:106FE0001300000013000000130000001300000055 +:106FF0001300000013000000130000001300000045 +:10700000202122232425262728292A2B2C2D2E2F08 +:107010001300000013000000130000001300000024 +:107020001300000013000000130000001300000014 +:107030001300000013000000130000001300000004 +:1070400013000000130000001300000013000000F4 +:1070500013000000130000001300000013000000E4 +:1070600013000000130000001300000013000000D4 +:1070700013000000130000001300000013000000C4 +:1070800013000000130000001300000013000000B4 +:1070900013000000130000001300000013000000A4 +:1070A0001300000013000000130000001300000094 +:1070B0001300000013000000130000001300000084 +:1070C0001300000013000000130000001300000074 +:1070D0001300000013000000130000001300000064 +:1070E0001300000013000000130000001300000054 +:1070F0001300000013000000130000001300000044 +:107100001300000013000000130000001300000033 +:107110001300000013000000130000001300000023 +:107120001300000013000000130000001300000013 +:107130001300000013000000130000001300000003 +:1071400013000000130000001300000013000000F3 +:1071500013000000130000001300000013000000E3 +:1071600013000000130000001300000013000000D3 +:1071700013000000130000001300000013000000C3 +:1071800013000000130000001300000013000000B3 +:1071900013000000130000001300000013000000A3 +:1071A0001300000013000000130000001300000093 +:1071B0001300000013000000130000001300000083 +:1071C0001300000013000000130000001300000073 +:1071D0001300000013000000130000001300000063 +:1071E0001300000013000000130000001300000053 +:1071F0001300000013000000130000001300000043 +:107200001300000013000000130000001300000032 +:107210001300000013000000130000001300000022 +:107220001300000013000000130000001300000012 +:107230001300000013000000130000001300000002 +:1072400013000000130000001300000013000000F2 +:1072500013000000130000001300000013000000E2 +:1072600013000000130000001300000013000000D2 +:1072700013000000130000001300000013000000C2 +:1072800013000000130000001300000013000000B2 +:1072900013000000130000001300000013000000A2 +:1072A0001300000013000000130000001300000092 +:1072B0001300000013000000130000001300000082 +:1072C0001300000013000000130000001300000072 +:1072D0001300000013000000130000001300000062 +:1072E0001300000013000000130000001300000052 +:1072F0001300000013000000130000001300000042 +:107300001300000013000000130000001300000031 +:107310001300000013000000130000001300000021 +:107320001300000013000000130000001300000011 +:107330001300000013000000130000001300000001 +:1073400013000000130000001300000013000000F1 +:1073500013000000130000001300000013000000E1 +:1073600013000000130000001300000013000000D1 +:1073700013000000130000001300000013000000C1 +:1073800013000000130000001300000013000000B1 +:1073900013000000130000001300000013000000A1 +:1073A0001300000013000000130000001300000091 +:1073B0001300000013000000130000001300000081 +:1073C0001300000013000000130000001300000071 +:1073D0001300000013000000130000001300000061 +:1073E0001300000013000000130000001300000051 +:1073F0001300000013000000130000001300000041 +:107400001300000013000000130000001300000030 +:107410001300000013000000130000001300000020 +:107420001300000013000000130000001300000010 +:107430001300000013000000130000001300000000 +:1074400013000000130000001300000013000000F0 +:1074500013000000130000001300000013000000E0 +:1074600013000000130000001300000013000000D0 +:1074700013000000130000001300000013000000C0 +:1074800013000000130000001300000013000000B0 +:1074900013000000130000001300000013000000A0 +:1074A0001300000013000000130000001300000090 +:1074B0001300000013000000130000001300000080 +:1074C0001300000013000000130000001300000070 +:1074D0001300000013000000130000001300000060 +:1074E0001300000013000000130000001300000050 +:1074F0001300000013000000130000001300000040 +:10750000130000001300000013000000130000002F +:10751000130000001300000013000000130000001F +:10752000130000001300000013000000130000000F +:1075300013000000130000001300000013000000FF +:1075400013000000130000001300000013000000EF +:1075500013000000130000001300000013000000DF +:1075600013000000130000001300000013000000CF +:1075700013000000130000001300000013000000BF +:1075800013000000130000001300000013000000AF +:10759000130000001300000013000000130000009F +:1075A000130000001300000013000000130000008F +:1075B000130000001300000013000000130000007F +:1075C000130000001300000013000000130000006F +:1075D000130000001300000013000000130000005F +:1075E000130000001300000013000000130000004F +:1075F000130000001300000013000000130000003F +:10760000130000001300000013000000130000002E +:10761000130000001300000013000000130000001E +:10762000130000001300000013000000130000000E +:1076300013000000130000001300000013000000FE +:1076400013000000130000001300000013000000EE +:1076500013000000130000001300000013000000DE +:1076600013000000130000001300000013000000CE +:1076700013000000130000001300000013000000BE +:1076800013000000130000001300000013000000AE +:10769000130000001300000013000000130000009E +:1076A000130000001300000013000000130000008E +:1076B000130000001300000013000000130000007E +:1076C000130000001300000013000000130000006E +:1076D000130000001300000013000000130000005E +:1076E000130000001300000013000000130000004E +:1076F000130000001300000013000000130000003E +:10770000130000001300000013000000130000002D +:10771000130000001300000013000000130000001D +:10772000130000001300000013000000130000000D +:1077300013000000130000001300000013000000FD +:1077400013000000130000001300000013000000ED +:1077500013000000130000001300000013000000DD +:1077600013000000130000001300000013000000CD +:1077700013000000130000001300000013000000BD +:1077800013000000130000001300000013000000AD +:10779000130000001300000013000000130000009D +:1077A000130000001300000013000000130000008D +:1077B000130000001300000013000000130000007D +:1077C000130000001300000013000000130000006D +:1077D000130000001300000013000000130000005D +:1077E000130000001300000013000000130000004D +:1077F000130000001300000013000000130000003D +:10780000130000001300000013000000130000002C +:10781000130000001300000013000000130000001C +:10782000130000001300000013000000130000000C +:1078300013000000130000001300000013000000FC +:1078400013000000130000001300000013000000EC +:1078500013000000130000001300000013000000DC +:1078600013000000130000001300000013000000CC +:1078700013000000130000001300000013000000BC +:1078800013000000130000001300000013000000AC +:10789000130000001300000013000000130000009C +:1078A000130000001300000013000000130000008C +:1078B000130000001300000013000000130000007C +:1078C000130000001300000013000000130000006C +:1078D000130000001300000013000000130000005C +:1078E000130000001300000013000000130000004C +:1078F000130000001300000013000000130000003C +:10790000130000001300000013000000130000002B +:10791000130000001300000013000000130000001B +:10792000130000001300000013000000130000000B +:1079300013000000130000001300000013000000FB +:1079400013000000130000001300000013000000EB +:1079500013000000130000001300000013000000DB +:1079600013000000130000001300000013000000CB +:1079700013000000130000001300000013000000BB +:1079800013000000130000001300000013000000AB +:10799000130000001300000013000000130000009B +:1079A000130000001300000013000000130000008B +:1079B000130000001300000013000000130000007B +:1079C000130000001300000013000000130000006B +:1079D000130000001300000013000000130000005B +:1079E000130000001300000013000000130000004B +:1079F000130000001300000013000000130000003B +:107A0000130000001300000013000000130000002A +:107A1000130000001300000013000000130000001A +:107A2000130000001300000013000000130000000A +:107A300013000000130000001300000013000000FA +:107A400013000000130000001300000013000000EA +:107A500013000000130000001300000013000000DA +:107A600013000000130000001300000013000000CA +:107A700013000000130000001300000013000000BA +:107A800013000000130000001300000013000000AA +:107A9000130000001300000013000000130000009A +:107AA000130000001300000013000000130000008A +:107AB000130000001300000013000000130000007A +:107AC000130000001300000013000000130000006A +:107AD000130000001300000013000000130000005A +:107AE000130000001300000013000000130000004A +:107AF000130000001300000013000000130000003A +:107B00001300000013000000130000001300000029 +:107B10001300000013000000130000001300000019 +:107B20001300000013000000130000001300000009 +:107B300013000000130000001300000013000000F9 +:107B400013000000130000001300000013000000E9 +:107B500013000000130000001300000013000000D9 +:107B600013000000130000001300000013000000C9 +:107B700013000000130000001300000013000000B9 +:107B800013000000130000001300000013000000A9 +:107B90001300000013000000130000001300000099 +:107BA0001300000013000000130000001300000089 +:107BB0001300000013000000130000001300000079 +:107BC0001300000013000000130000001300000069 +:107BD0001300000013000000130000001300000059 +:107BE0001300000013000000130000001300000049 +:107BF0001300000013000000130000001300000039 +:107C00001300000013000000130000001300000028 +:107C10001300000013000000130000001300000018 +:107C20001300000013000000130000001300000008 +:107C300013000000130000001300000013000000F8 +:107C400013000000130000001300000013000000E8 +:107C500013000000130000001300000013000000D8 +:107C600013000000130000001300000013000000C8 +:107C700013000000130000001300000013000000B8 +:107C800013000000130000001300000013000000A8 +:107C90001300000013000000130000001300000098 +:107CA0001300000013000000130000001300000088 +:107CB0001300000013000000130000001300000078 +:107CC0001300000013000000130000001300000068 +:107CD0001300000013000000130000001300000058 +:107CE0001300000013000000130000001300000048 +:107CF0001300000013000000130000001300000038 +:107D00001300000013000000130000001300000027 +:107D10001300000013000000130000001300000017 +:107D20001300000013000000130000001300000007 +:107D300013000000130000001300000013000000F7 +:107D400013000000130000001300000013000000E7 +:107D500013000000130000001300000013000000D7 +:107D600013000000130000001300000013000000C7 +:107D700013000000130000001300000013000000B7 +:107D800013000000130000001300000013000000A7 +:107D90001300000013000000130000001300000097 +:107DA0001300000013000000130000001300000087 +:107DB0001300000013000000130000001300000077 +:107DC0001300000013000000130000001300000067 +:107DD0001300000013000000130000001300000057 +:107DE0001300000013000000130000001300000047 +:107DF0001300000013000000130000001300000037 +:107E00001300000013000000130000001300000026 +:107E10001300000013000000130000001300000016 +:107E20001300000013000000130000001300000006 +:107E300013000000130000001300000013000000F6 +:107E400013000000130000001300000013000000E6 +:107E500013000000130000001300000013000000D6 +:107E600013000000130000001300000013000000C6 +:107E700013000000130000001300000013000000B6 +:107E800013000000130000001300000013000000A6 +:107E90001300000013000000130000001300000096 +:107EA0001300000013000000130000001300000086 +:107EB0001300000013000000130000001300000076 +:107EC0001300000013000000130000001300000066 +:107ED0001300000013000000130000001300000056 +:107EE0001300000013000000130000001300000046 +:107EF0001300000013000000130000001300000036 +:107F00001300000013000000130000001300000025 +:107F10001300000013000000130000001300000015 +:107F20001300000013000000130000001300000005 +:107F300013000000130000001300000013000000F5 +:107F400013000000130000001300000013000000E5 +:107F500013000000130000001300000013000000D5 +:107F600013000000130000001300000013000000C5 +:107F700013000000130000001300000013000000B5 +:107F800013000000130000001300000013000000A5 +:107F90001300000013000000130000001300000095 +:107FA0001300000013000000130000001300000085 +:107FB0001300000013000000130000001300000075 +:107FC0001300000013000000130000001300000065 +:107FD0001300000013000000130000001300000055 +:107FE0001300000013000000130000001300000045 +:107FF0001300000013000000130000001300000035 +:10800000303132333435363738393A3B3C3D3E3FF8 +:108010001300000013000000130000001300000014 +:108020001300000013000000130000001300000004 +:1080300013000000130000001300000013000000F4 +:1080400013000000130000001300000013000000E4 +:1080500013000000130000001300000013000000D4 +:1080600013000000130000001300000013000000C4 +:1080700013000000130000001300000013000000B4 +:1080800013000000130000001300000013000000A4 +:108090001300000013000000130000001300000094 +:1080A0001300000013000000130000001300000084 +:1080B0001300000013000000130000001300000074 +:1080C0001300000013000000130000001300000064 +:1080D0001300000013000000130000001300000054 +:1080E0001300000013000000130000001300000044 +:1080F0001300000013000000130000001300000034 +:108100001300000013000000130000001300000023 +:108110001300000013000000130000001300000013 +:108120001300000013000000130000001300000003 +:1081300013000000130000001300000013000000F3 +:1081400013000000130000001300000013000000E3 +:1081500013000000130000001300000013000000D3 +:1081600013000000130000001300000013000000C3 +:1081700013000000130000001300000013000000B3 +:1081800013000000130000001300000013000000A3 +:108190001300000013000000130000001300000093 +:1081A0001300000013000000130000001300000083 +:1081B0001300000013000000130000001300000073 +:1081C0001300000013000000130000001300000063 +:1081D0001300000013000000130000001300000053 +:1081E0001300000013000000130000001300000043 +:1081F0001300000013000000130000001300000033 +:108200001300000013000000130000001300000022 +:108210001300000013000000130000001300000012 +:108220001300000013000000130000001300000002 +:1082300013000000130000001300000013000000F2 +:1082400013000000130000001300000013000000E2 +:1082500013000000130000001300000013000000D2 +:1082600013000000130000001300000013000000C2 +:1082700013000000130000001300000013000000B2 +:1082800013000000130000001300000013000000A2 +:108290001300000013000000130000001300000092 +:1082A0001300000013000000130000001300000082 +:1082B0001300000013000000130000001300000072 +:1082C0001300000013000000130000001300000062 +:1082D0001300000013000000130000001300000052 +:1082E0001300000013000000130000001300000042 +:1082F0001300000013000000130000001300000032 +:108300001300000013000000130000001300000021 +:108310001300000013000000130000001300000011 +:108320001300000013000000130000001300000001 +:1083300013000000130000001300000013000000F1 +:1083400013000000130000001300000013000000E1 +:1083500013000000130000001300000013000000D1 +:1083600013000000130000001300000013000000C1 +:1083700013000000130000001300000013000000B1 +:1083800013000000130000001300000013000000A1 +:108390001300000013000000130000001300000091 +:1083A0001300000013000000130000001300000081 +:1083B0001300000013000000130000001300000071 +:1083C0001300000013000000130000001300000061 +:1083D0001300000013000000130000001300000051 +:1083E0001300000013000000130000001300000041 +:1083F0001300000013000000130000001300000031 +:108400001300000013000000130000001300000020 +:108410001300000013000000130000001300000010 +:108420001300000013000000130000001300000000 +:1084300013000000130000001300000013000000F0 +:1084400013000000130000001300000013000000E0 +:1084500013000000130000001300000013000000D0 +:1084600013000000130000001300000013000000C0 +:1084700013000000130000001300000013000000B0 +:1084800013000000130000001300000013000000A0 +:108490001300000013000000130000001300000090 +:1084A0001300000013000000130000001300000080 +:1084B0001300000013000000130000001300000070 +:1084C0001300000013000000130000001300000060 +:1084D0001300000013000000130000001300000050 +:1084E0001300000013000000130000001300000040 +:1084F0001300000013000000130000001300000030 +:10850000130000001300000013000000130000001F +:10851000130000001300000013000000130000000F +:1085200013000000130000001300000013000000FF +:1085300013000000130000001300000013000000EF +:1085400013000000130000001300000013000000DF +:1085500013000000130000001300000013000000CF +:1085600013000000130000001300000013000000BF +:1085700013000000130000001300000013000000AF +:10858000130000001300000013000000130000009F +:10859000130000001300000013000000130000008F +:1085A000130000001300000013000000130000007F +:1085B000130000001300000013000000130000006F +:1085C000130000001300000013000000130000005F +:1085D000130000001300000013000000130000004F +:1085E000130000001300000013000000130000003F +:1085F000130000001300000013000000130000002F +:10860000130000001300000013000000130000001E +:10861000130000001300000013000000130000000E +:1086200013000000130000001300000013000000FE +:1086300013000000130000001300000013000000EE +:1086400013000000130000001300000013000000DE +:1086500013000000130000001300000013000000CE +:1086600013000000130000001300000013000000BE +:1086700013000000130000001300000013000000AE +:10868000130000001300000013000000130000009E +:10869000130000001300000013000000130000008E +:1086A000130000001300000013000000130000007E +:1086B000130000001300000013000000130000006E +:1086C000130000001300000013000000130000005E +:1086D000130000001300000013000000130000004E +:1086E000130000001300000013000000130000003E +:1086F000130000001300000013000000130000002E +:10870000130000001300000013000000130000001D +:10871000130000001300000013000000130000000D +:1087200013000000130000001300000013000000FD +:1087300013000000130000001300000013000000ED +:1087400013000000130000001300000013000000DD +:1087500013000000130000001300000013000000CD +:1087600013000000130000001300000013000000BD +:1087700013000000130000001300000013000000AD +:10878000130000001300000013000000130000009D +:10879000130000001300000013000000130000008D +:1087A000130000001300000013000000130000007D +:1087B000130000001300000013000000130000006D +:1087C000130000001300000013000000130000005D +:1087D000130000001300000013000000130000004D +:1087E000130000001300000013000000130000003D +:1087F000130000001300000013000000130000002D +:10880000130000001300000013000000130000001C +:10881000130000001300000013000000130000000C +:1088200013000000130000001300000013000000FC +:1088300013000000130000001300000013000000EC +:1088400013000000130000001300000013000000DC +:1088500013000000130000001300000013000000CC +:1088600013000000130000001300000013000000BC +:1088700013000000130000001300000013000000AC +:10888000130000001300000013000000130000009C +:10889000130000001300000013000000130000008C +:1088A000130000001300000013000000130000007C +:1088B000130000001300000013000000130000006C +:1088C000130000001300000013000000130000005C +:1088D000130000001300000013000000130000004C +:1088E000130000001300000013000000130000003C +:1088F000130000001300000013000000130000002C +:10890000130000001300000013000000130000001B +:10891000130000001300000013000000130000000B +:1089200013000000130000001300000013000000FB +:1089300013000000130000001300000013000000EB +:1089400013000000130000001300000013000000DB +:1089500013000000130000001300000013000000CB +:1089600013000000130000001300000013000000BB +:1089700013000000130000001300000013000000AB +:10898000130000001300000013000000130000009B +:10899000130000001300000013000000130000008B +:1089A000130000001300000013000000130000007B +:1089B000130000001300000013000000130000006B +:1089C000130000001300000013000000130000005B +:1089D000130000001300000013000000130000004B +:1089E000130000001300000013000000130000003B +:1089F000130000001300000013000000130000002B +:108A0000130000001300000013000000130000001A +:108A1000130000001300000013000000130000000A +:108A200013000000130000001300000013000000FA +:108A300013000000130000001300000013000000EA +:108A400013000000130000001300000013000000DA +:108A500013000000130000001300000013000000CA +:108A600013000000130000001300000013000000BA +:108A700013000000130000001300000013000000AA +:108A8000130000001300000013000000130000009A +:108A9000130000001300000013000000130000008A +:108AA000130000001300000013000000130000007A +:108AB000130000001300000013000000130000006A +:108AC000130000001300000013000000130000005A +:108AD000130000001300000013000000130000004A +:108AE000130000001300000013000000130000003A +:108AF000130000001300000013000000130000002A +:108B00001300000013000000130000001300000019 +:108B10001300000013000000130000001300000009 +:108B200013000000130000001300000013000000F9 +:108B300013000000130000001300000013000000E9 +:108B400013000000130000001300000013000000D9 +:108B500013000000130000001300000013000000C9 +:108B600013000000130000001300000013000000B9 +:108B700013000000130000001300000013000000A9 +:108B80001300000013000000130000001300000099 +:108B90001300000013000000130000001300000089 +:108BA0001300000013000000130000001300000079 +:108BB0001300000013000000130000001300000069 +:108BC0001300000013000000130000001300000059 +:108BD0001300000013000000130000001300000049 +:108BE0001300000013000000130000001300000039 +:108BF0001300000013000000130000001300000029 +:108C00001300000013000000130000001300000018 +:108C10001300000013000000130000001300000008 +:108C200013000000130000001300000013000000F8 +:108C300013000000130000001300000013000000E8 +:108C400013000000130000001300000013000000D8 +:108C500013000000130000001300000013000000C8 +:108C600013000000130000001300000013000000B8 +:108C700013000000130000001300000013000000A8 +:108C80001300000013000000130000001300000098 +:108C90001300000013000000130000001300000088 +:108CA0001300000013000000130000001300000078 +:108CB0001300000013000000130000001300000068 +:108CC0001300000013000000130000001300000058 +:108CD0001300000013000000130000001300000048 +:108CE0001300000013000000130000001300000038 +:108CF0001300000013000000130000001300000028 +:108D00001300000013000000130000001300000017 +:108D10001300000013000000130000001300000007 +:108D200013000000130000001300000013000000F7 +:108D300013000000130000001300000013000000E7 +:108D400013000000130000001300000013000000D7 +:108D500013000000130000001300000013000000C7 +:108D600013000000130000001300000013000000B7 +:108D700013000000130000001300000013000000A7 +:108D80001300000013000000130000001300000097 +:108D90001300000013000000130000001300000087 +:108DA0001300000013000000130000001300000077 +:108DB0001300000013000000130000001300000067 +:108DC0001300000013000000130000001300000057 +:108DD0001300000013000000130000001300000047 +:108DE0001300000013000000130000001300000037 +:108DF0001300000013000000130000001300000027 +:108E00001300000013000000130000001300000016 +:108E10001300000013000000130000001300000006 +:108E200013000000130000001300000013000000F6 +:108E300013000000130000001300000013000000E6 +:108E400013000000130000001300000013000000D6 +:108E500013000000130000001300000013000000C6 +:108E600013000000130000001300000013000000B6 +:108E700013000000130000001300000013000000A6 +:108E80001300000013000000130000001300000096 +:108E90001300000013000000130000001300000086 +:108EA0001300000013000000130000001300000076 +:108EB0001300000013000000130000001300000066 +:108EC0001300000013000000130000001300000056 +:108ED0001300000013000000130000001300000046 +:108EE0001300000013000000130000001300000036 +:108EF0001300000013000000130000001300000026 +:108F00001300000013000000130000001300000015 +:108F10001300000013000000130000001300000005 +:108F200013000000130000001300000013000000F5 +:108F300013000000130000001300000013000000E5 +:108F400013000000130000001300000013000000D5 +:108F500013000000130000001300000013000000C5 +:108F600013000000130000001300000013000000B5 +:108F700013000000130000001300000013000000A5 +:108F80001300000013000000130000001300000095 +:108F90001300000013000000130000001300000085 +:108FA0001300000013000000130000001300000075 +:108FB0001300000013000000130000001300000065 +:108FC0001300000013000000130000001300000055 +:108FD0001300000013000000130000001300000045 +:108FE0001300000013000000130000001300000035 +:108FF0001300000013000000130000001300000025 +:10900000404142434445464748494A4B4C4D4E4FE8 +:109010001300000013000000130000001300000004 +:1090200013000000130000001300000013000000F4 +:1090300013000000130000001300000013000000E4 +:1090400013000000130000001300000013000000D4 +:1090500013000000130000001300000013000000C4 +:1090600013000000130000001300000013000000B4 +:1090700013000000130000001300000013000000A4 +:109080001300000013000000130000001300000094 +:109090001300000013000000130000001300000084 +:1090A0001300000013000000130000001300000074 +:1090B0001300000013000000130000001300000064 +:1090C0001300000013000000130000001300000054 +:1090D0001300000013000000130000001300000044 +:1090E0001300000013000000130000001300000034 +:1090F0001300000013000000130000001300000024 +:109100001300000013000000130000001300000013 +:109110001300000013000000130000001300000003 +:1091200013000000130000001300000013000000F3 +:1091300013000000130000001300000013000000E3 +:1091400013000000130000001300000013000000D3 +:1091500013000000130000001300000013000000C3 +:1091600013000000130000001300000013000000B3 +:1091700013000000130000001300000013000000A3 +:109180001300000013000000130000001300000093 +:109190001300000013000000130000001300000083 +:1091A0001300000013000000130000001300000073 +:1091B0001300000013000000130000001300000063 +:1091C0001300000013000000130000001300000053 +:1091D0001300000013000000130000001300000043 +:1091E0001300000013000000130000001300000033 +:1091F0001300000013000000130000001300000023 +:109200001300000013000000130000001300000012 +:109210001300000013000000130000001300000002 +:1092200013000000130000001300000013000000F2 +:1092300013000000130000001300000013000000E2 +:1092400013000000130000001300000013000000D2 +:1092500013000000130000001300000013000000C2 +:1092600013000000130000001300000013000000B2 +:1092700013000000130000001300000013000000A2 +:109280001300000013000000130000001300000092 +:109290001300000013000000130000001300000082 +:1092A0001300000013000000130000001300000072 +:1092B0001300000013000000130000001300000062 +:1092C0001300000013000000130000001300000052 +:1092D0001300000013000000130000001300000042 +:1092E0001300000013000000130000001300000032 +:1092F0001300000013000000130000001300000022 +:109300001300000013000000130000001300000011 +:109310001300000013000000130000001300000001 +:1093200013000000130000001300000013000000F1 +:1093300013000000130000001300000013000000E1 +:1093400013000000130000001300000013000000D1 +:1093500013000000130000001300000013000000C1 +:1093600013000000130000001300000013000000B1 +:1093700013000000130000001300000013000000A1 +:109380001300000013000000130000001300000091 +:109390001300000013000000130000001300000081 +:1093A0001300000013000000130000001300000071 +:1093B0001300000013000000130000001300000061 +:1093C0001300000013000000130000001300000051 +:1093D0001300000013000000130000001300000041 +:1093E0001300000013000000130000001300000031 +:1093F0001300000013000000130000001300000021 +:109400001300000013000000130000001300000010 +:109410001300000013000000130000001300000000 +:1094200013000000130000001300000013000000F0 +:1094300013000000130000001300000013000000E0 +:1094400013000000130000001300000013000000D0 +:1094500013000000130000001300000013000000C0 +:1094600013000000130000001300000013000000B0 +:1094700013000000130000001300000013000000A0 +:109480001300000013000000130000001300000090 +:109490001300000013000000130000001300000080 +:1094A0001300000013000000130000001300000070 +:1094B0001300000013000000130000001300000060 +:1094C0001300000013000000130000001300000050 +:1094D0001300000013000000130000001300000040 +:1094E0001300000013000000130000001300000030 +:1094F0001300000013000000130000001300000020 +:10950000130000001300000013000000130000000F +:1095100013000000130000001300000013000000FF +:1095200013000000130000001300000013000000EF +:1095300013000000130000001300000013000000DF +:1095400013000000130000001300000013000000CF +:1095500013000000130000001300000013000000BF +:1095600013000000130000001300000013000000AF +:10957000130000001300000013000000130000009F +:10958000130000001300000013000000130000008F +:10959000130000001300000013000000130000007F +:1095A000130000001300000013000000130000006F +:1095B000130000001300000013000000130000005F +:1095C000130000001300000013000000130000004F +:1095D000130000001300000013000000130000003F +:1095E000130000001300000013000000130000002F +:1095F000130000001300000013000000130000001F +:10960000130000001300000013000000130000000E +:1096100013000000130000001300000013000000FE +:1096200013000000130000001300000013000000EE +:1096300013000000130000001300000013000000DE +:1096400013000000130000001300000013000000CE +:1096500013000000130000001300000013000000BE +:1096600013000000130000001300000013000000AE +:10967000130000001300000013000000130000009E +:10968000130000001300000013000000130000008E +:10969000130000001300000013000000130000007E +:1096A000130000001300000013000000130000006E +:1096B000130000001300000013000000130000005E +:1096C000130000001300000013000000130000004E +:1096D000130000001300000013000000130000003E +:1096E000130000001300000013000000130000002E +:1096F000130000001300000013000000130000001E +:10970000130000001300000013000000130000000D +:1097100013000000130000001300000013000000FD +:1097200013000000130000001300000013000000ED +:1097300013000000130000001300000013000000DD +:1097400013000000130000001300000013000000CD +:1097500013000000130000001300000013000000BD +:1097600013000000130000001300000013000000AD +:10977000130000001300000013000000130000009D +:10978000130000001300000013000000130000008D +:10979000130000001300000013000000130000007D +:1097A000130000001300000013000000130000006D +:1097B000130000001300000013000000130000005D +:1097C000130000001300000013000000130000004D +:1097D000130000001300000013000000130000003D +:1097E000130000001300000013000000130000002D +:1097F000130000001300000013000000130000001D +:10980000130000001300000013000000130000000C +:1098100013000000130000001300000013000000FC +:1098200013000000130000001300000013000000EC +:1098300013000000130000001300000013000000DC +:1098400013000000130000001300000013000000CC +:1098500013000000130000001300000013000000BC +:1098600013000000130000001300000013000000AC +:10987000130000001300000013000000130000009C +:10988000130000001300000013000000130000008C +:10989000130000001300000013000000130000007C +:1098A000130000001300000013000000130000006C +:1098B000130000001300000013000000130000005C +:1098C000130000001300000013000000130000004C +:1098D000130000001300000013000000130000003C +:1098E000130000001300000013000000130000002C +:1098F000130000001300000013000000130000001C +:10990000130000001300000013000000130000000B +:1099100013000000130000001300000013000000FB +:1099200013000000130000001300000013000000EB +:1099300013000000130000001300000013000000DB +:1099400013000000130000001300000013000000CB +:1099500013000000130000001300000013000000BB +:1099600013000000130000001300000013000000AB +:10997000130000001300000013000000130000009B +:10998000130000001300000013000000130000008B +:10999000130000001300000013000000130000007B +:1099A000130000001300000013000000130000006B +:1099B000130000001300000013000000130000005B +:1099C000130000001300000013000000130000004B +:1099D000130000001300000013000000130000003B +:1099E000130000001300000013000000130000002B +:1099F000130000001300000013000000130000001B +:109A0000130000001300000013000000130000000A +:109A100013000000130000001300000013000000FA +:109A200013000000130000001300000013000000EA +:109A300013000000130000001300000013000000DA +:109A400013000000130000001300000013000000CA +:109A500013000000130000001300000013000000BA +:109A600013000000130000001300000013000000AA +:109A7000130000001300000013000000130000009A +:109A8000130000001300000013000000130000008A +:109A9000130000001300000013000000130000007A +:109AA000130000001300000013000000130000006A +:109AB000130000001300000013000000130000005A +:109AC000130000001300000013000000130000004A +:109AD000130000001300000013000000130000003A +:109AE000130000001300000013000000130000002A +:109AF000130000001300000013000000130000001A +:109B00001300000013000000130000001300000009 +:109B100013000000130000001300000013000000F9 +:109B200013000000130000001300000013000000E9 +:109B300013000000130000001300000013000000D9 +:109B400013000000130000001300000013000000C9 +:109B500013000000130000001300000013000000B9 +:109B600013000000130000001300000013000000A9 +:109B70001300000013000000130000001300000099 +:109B80001300000013000000130000001300000089 +:109B90001300000013000000130000001300000079 +:109BA0001300000013000000130000001300000069 +:109BB0001300000013000000130000001300000059 +:109BC0001300000013000000130000001300000049 +:109BD0001300000013000000130000001300000039 +:109BE0001300000013000000130000001300000029 +:109BF0001300000013000000130000001300000019 +:109C00001300000013000000130000001300000008 +:109C100013000000130000001300000013000000F8 +:109C200013000000130000001300000013000000E8 +:109C300013000000130000001300000013000000D8 +:109C400013000000130000001300000013000000C8 +:109C500013000000130000001300000013000000B8 +:109C600013000000130000001300000013000000A8 +:109C70001300000013000000130000001300000098 +:109C80001300000013000000130000001300000088 +:109C90001300000013000000130000001300000078 +:109CA0001300000013000000130000001300000068 +:109CB0001300000013000000130000001300000058 +:109CC0001300000013000000130000001300000048 +:109CD0001300000013000000130000001300000038 +:109CE0001300000013000000130000001300000028 +:109CF0001300000013000000130000001300000018 +:109D00001300000013000000130000001300000007 +:109D100013000000130000001300000013000000F7 +:109D200013000000130000001300000013000000E7 +:109D300013000000130000001300000013000000D7 +:109D400013000000130000001300000013000000C7 +:109D500013000000130000001300000013000000B7 +:109D600013000000130000001300000013000000A7 +:109D70001300000013000000130000001300000097 +:109D80001300000013000000130000001300000087 +:109D90001300000013000000130000001300000077 +:109DA0001300000013000000130000001300000067 +:109DB0001300000013000000130000001300000057 +:109DC0001300000013000000130000001300000047 +:109DD0001300000013000000130000001300000037 +:109DE0001300000013000000130000001300000027 +:109DF0001300000013000000130000001300000017 +:109E00001300000013000000130000001300000006 +:109E100013000000130000001300000013000000F6 +:109E200013000000130000001300000013000000E6 +:109E300013000000130000001300000013000000D6 +:109E400013000000130000001300000013000000C6 +:109E500013000000130000001300000013000000B6 +:109E600013000000130000001300000013000000A6 +:109E70001300000013000000130000001300000096 +:109E80001300000013000000130000001300000086 +:109E90001300000013000000130000001300000076 +:109EA0001300000013000000130000001300000066 +:109EB0001300000013000000130000001300000056 +:109EC0001300000013000000130000001300000046 +:109ED0001300000013000000130000001300000036 +:109EE0001300000013000000130000001300000026 +:109EF0001300000013000000130000001300000016 +:109F00001300000013000000130000001300000005 +:109F100013000000130000001300000013000000F5 +:109F200013000000130000001300000013000000E5 +:109F300013000000130000001300000013000000D5 +:109F400013000000130000001300000013000000C5 +:109F500013000000130000001300000013000000B5 +:109F600013000000130000001300000013000000A5 +:109F70001300000013000000130000001300000095 +:109F80001300000013000000130000001300000085 +:109F90001300000013000000130000001300000075 +:109FA0001300000013000000130000001300000065 +:109FB0001300000013000000130000001300000055 +:109FC0001300000013000000130000001300000045 +:109FD0001300000013000000130000001300000035 +:109FE0001300000013000000130000001300000025 +:109FF0001300000013000000130000001300000015 +:10A00000505152535455565758595A5B5C5D5E5FD8 +:10A0100013000000130000001300000013000000F4 +:10A0200013000000130000001300000013000000E4 +:10A0300013000000130000001300000013000000D4 +:10A0400013000000130000001300000013000000C4 +:10A0500013000000130000001300000013000000B4 +:10A0600013000000130000001300000013000000A4 +:10A070001300000013000000130000001300000094 +:10A080001300000013000000130000001300000084 +:10A090001300000013000000130000001300000074 +:10A0A0001300000013000000130000001300000064 +:10A0B0001300000013000000130000001300000054 +:10A0C0001300000013000000130000001300000044 +:10A0D0001300000013000000130000001300000034 +:10A0E0001300000013000000130000001300000024 +:10A0F0001300000013000000130000001300000014 +:10A100001300000013000000130000001300000003 +:10A1100013000000130000001300000013000000F3 +:10A1200013000000130000001300000013000000E3 +:10A1300013000000130000001300000013000000D3 +:10A1400013000000130000001300000013000000C3 +:10A1500013000000130000001300000013000000B3 +:10A1600013000000130000001300000013000000A3 +:10A170001300000013000000130000001300000093 +:10A180001300000013000000130000001300000083 +:10A190001300000013000000130000001300000073 +:10A1A0001300000013000000130000001300000063 +:10A1B0001300000013000000130000001300000053 +:10A1C0001300000013000000130000001300000043 +:10A1D0001300000013000000130000001300000033 +:10A1E0001300000013000000130000001300000023 +:10A1F0001300000013000000130000001300000013 +:10A200001300000013000000130000001300000002 +:10A2100013000000130000001300000013000000F2 +:10A2200013000000130000001300000013000000E2 +:10A2300013000000130000001300000013000000D2 +:10A2400013000000130000001300000013000000C2 +:10A2500013000000130000001300000013000000B2 +:10A2600013000000130000001300000013000000A2 +:10A270001300000013000000130000001300000092 +:10A280001300000013000000130000001300000082 +:10A290001300000013000000130000001300000072 +:10A2A0001300000013000000130000001300000062 +:10A2B0001300000013000000130000001300000052 +:10A2C0001300000013000000130000001300000042 +:10A2D0001300000013000000130000001300000032 +:10A2E0001300000013000000130000001300000022 +:10A2F0001300000013000000130000001300000012 +:10A300001300000013000000130000001300000001 +:10A3100013000000130000001300000013000000F1 +:10A3200013000000130000001300000013000000E1 +:10A3300013000000130000001300000013000000D1 +:10A3400013000000130000001300000013000000C1 +:10A3500013000000130000001300000013000000B1 +:10A3600013000000130000001300000013000000A1 +:10A370001300000013000000130000001300000091 +:10A380001300000013000000130000001300000081 +:10A390001300000013000000130000001300000071 +:10A3A0001300000013000000130000001300000061 +:10A3B0001300000013000000130000001300000051 +:10A3C0001300000013000000130000001300000041 +:10A3D0001300000013000000130000001300000031 +:10A3E0001300000013000000130000001300000021 +:10A3F0001300000013000000130000001300000011 +:10A400001300000013000000130000001300000000 +:10A4100013000000130000001300000013000000F0 +:10A4200013000000130000001300000013000000E0 +:10A4300013000000130000001300000013000000D0 +:10A4400013000000130000001300000013000000C0 +:10A4500013000000130000001300000013000000B0 +:10A4600013000000130000001300000013000000A0 +:10A470001300000013000000130000001300000090 +:10A480001300000013000000130000001300000080 +:10A490001300000013000000130000001300000070 +:10A4A0001300000013000000130000001300000060 +:10A4B0001300000013000000130000001300000050 +:10A4C0001300000013000000130000001300000040 +:10A4D0001300000013000000130000001300000030 +:10A4E0001300000013000000130000001300000020 +:10A4F0001300000013000000130000001300000010 +:10A5000013000000130000001300000013000000FF +:10A5100013000000130000001300000013000000EF +:10A5200013000000130000001300000013000000DF +:10A5300013000000130000001300000013000000CF +:10A5400013000000130000001300000013000000BF +:10A5500013000000130000001300000013000000AF +:10A56000130000001300000013000000130000009F +:10A57000130000001300000013000000130000008F +:10A58000130000001300000013000000130000007F +:10A59000130000001300000013000000130000006F +:10A5A000130000001300000013000000130000005F +:10A5B000130000001300000013000000130000004F +:10A5C000130000001300000013000000130000003F +:10A5D000130000001300000013000000130000002F +:10A5E000130000001300000013000000130000001F +:10A5F000130000001300000013000000130000000F +:10A6000013000000130000001300000013000000FE +:10A6100013000000130000001300000013000000EE +:10A6200013000000130000001300000013000000DE +:10A6300013000000130000001300000013000000CE +:10A6400013000000130000001300000013000000BE +:10A6500013000000130000001300000013000000AE +:10A66000130000001300000013000000130000009E +:10A67000130000001300000013000000130000008E +:10A68000130000001300000013000000130000007E +:10A69000130000001300000013000000130000006E +:10A6A000130000001300000013000000130000005E +:10A6B000130000001300000013000000130000004E +:10A6C000130000001300000013000000130000003E +:10A6D000130000001300000013000000130000002E +:10A6E000130000001300000013000000130000001E +:10A6F000130000001300000013000000130000000E +:10A7000013000000130000001300000013000000FD +:10A7100013000000130000001300000013000000ED +:10A7200013000000130000001300000013000000DD +:10A7300013000000130000001300000013000000CD +:10A7400013000000130000001300000013000000BD +:10A7500013000000130000001300000013000000AD +:10A76000130000001300000013000000130000009D +:10A77000130000001300000013000000130000008D +:10A78000130000001300000013000000130000007D +:10A79000130000001300000013000000130000006D +:10A7A000130000001300000013000000130000005D +:10A7B000130000001300000013000000130000004D +:10A7C000130000001300000013000000130000003D +:10A7D000130000001300000013000000130000002D +:10A7E000130000001300000013000000130000001D +:10A7F000130000001300000013000000130000000D +:10A8000013000000130000001300000013000000FC +:10A8100013000000130000001300000013000000EC +:10A8200013000000130000001300000013000000DC +:10A8300013000000130000001300000013000000CC +:10A8400013000000130000001300000013000000BC +:10A8500013000000130000001300000013000000AC +:10A86000130000001300000013000000130000009C +:10A87000130000001300000013000000130000008C +:10A88000130000001300000013000000130000007C +:10A89000130000001300000013000000130000006C +:10A8A000130000001300000013000000130000005C +:10A8B000130000001300000013000000130000004C +:10A8C000130000001300000013000000130000003C +:10A8D000130000001300000013000000130000002C +:10A8E000130000001300000013000000130000001C +:10A8F000130000001300000013000000130000000C +:10A9000013000000130000001300000013000000FB +:10A9100013000000130000001300000013000000EB +:10A9200013000000130000001300000013000000DB +:10A9300013000000130000001300000013000000CB +:10A9400013000000130000001300000013000000BB +:10A9500013000000130000001300000013000000AB +:10A96000130000001300000013000000130000009B +:10A97000130000001300000013000000130000008B +:10A98000130000001300000013000000130000007B +:10A99000130000001300000013000000130000006B +:10A9A000130000001300000013000000130000005B +:10A9B000130000001300000013000000130000004B +:10A9C000130000001300000013000000130000003B +:10A9D000130000001300000013000000130000002B +:10A9E000130000001300000013000000130000001B +:10A9F000130000001300000013000000130000000B +:10AA000013000000130000001300000013000000FA +:10AA100013000000130000001300000013000000EA +:10AA200013000000130000001300000013000000DA +:10AA300013000000130000001300000013000000CA +:10AA400013000000130000001300000013000000BA +:10AA500013000000130000001300000013000000AA +:10AA6000130000001300000013000000130000009A +:10AA7000130000001300000013000000130000008A +:10AA8000130000001300000013000000130000007A +:10AA9000130000001300000013000000130000006A +:10AAA000130000001300000013000000130000005A +:10AAB000130000001300000013000000130000004A +:10AAC000130000001300000013000000130000003A +:10AAD000130000001300000013000000130000002A +:10AAE000130000001300000013000000130000001A +:10AAF000130000001300000013000000130000000A +:10AB000013000000130000001300000013000000F9 +:10AB100013000000130000001300000013000000E9 +:10AB200013000000130000001300000013000000D9 +:10AB300013000000130000001300000013000000C9 +:10AB400013000000130000001300000013000000B9 +:10AB500013000000130000001300000013000000A9 +:10AB60001300000013000000130000001300000099 +:10AB70001300000013000000130000001300000089 +:10AB80001300000013000000130000001300000079 +:10AB90001300000013000000130000001300000069 +:10ABA0001300000013000000130000001300000059 +:10ABB0001300000013000000130000001300000049 +:10ABC0001300000013000000130000001300000039 +:10ABD0001300000013000000130000001300000029 +:10ABE0001300000013000000130000001300000019 +:10ABF0001300000013000000130000001300000009 +:10AC000013000000130000001300000013000000F8 +:10AC100013000000130000001300000013000000E8 +:10AC200013000000130000001300000013000000D8 +:10AC300013000000130000001300000013000000C8 +:10AC400013000000130000001300000013000000B8 +:10AC500013000000130000001300000013000000A8 +:10AC60001300000013000000130000001300000098 +:10AC70001300000013000000130000001300000088 +:10AC80001300000013000000130000001300000078 +:10AC90001300000013000000130000001300000068 +:10ACA0001300000013000000130000001300000058 +:10ACB0001300000013000000130000001300000048 +:10ACC0001300000013000000130000001300000038 +:10ACD0001300000013000000130000001300000028 +:10ACE0001300000013000000130000001300000018 +:10ACF0001300000013000000130000001300000008 +:10AD000013000000130000001300000013000000F7 +:10AD100013000000130000001300000013000000E7 +:10AD200013000000130000001300000013000000D7 +:10AD300013000000130000001300000013000000C7 +:10AD400013000000130000001300000013000000B7 +:10AD500013000000130000001300000013000000A7 +:10AD60001300000013000000130000001300000097 +:10AD70001300000013000000130000001300000087 +:10AD80001300000013000000130000001300000077 +:10AD90001300000013000000130000001300000067 +:10ADA0001300000013000000130000001300000057 +:10ADB0001300000013000000130000001300000047 +:10ADC0001300000013000000130000001300000037 +:10ADD0001300000013000000130000001300000027 +:10ADE0001300000013000000130000001300000017 +:10ADF0001300000013000000130000001300000007 +:10AE000013000000130000001300000013000000F6 +:10AE100013000000130000001300000013000000E6 +:10AE200013000000130000001300000013000000D6 +:10AE300013000000130000001300000013000000C6 +:10AE400013000000130000001300000013000000B6 +:10AE500013000000130000001300000013000000A6 +:10AE60001300000013000000130000001300000096 +:10AE70001300000013000000130000001300000086 +:10AE80001300000013000000130000001300000076 +:10AE90001300000013000000130000001300000066 +:10AEA0001300000013000000130000001300000056 +:10AEB0001300000013000000130000001300000046 +:10AEC0001300000013000000130000001300000036 +:10AED0001300000013000000130000001300000026 +:10AEE0001300000013000000130000001300000016 +:10AEF0001300000013000000130000001300000006 +:10AF000013000000130000001300000013000000F5 +:10AF100013000000130000001300000013000000E5 +:10AF200013000000130000001300000013000000D5 +:10AF300013000000130000001300000013000000C5 +:10AF400013000000130000001300000013000000B5 +:10AF500013000000130000001300000013000000A5 +:10AF60001300000013000000130000001300000095 +:10AF70001300000013000000130000001300000085 +:10AF80001300000013000000130000001300000075 +:10AF90001300000013000000130000001300000065 +:10AFA0001300000013000000130000001300000055 +:10AFB0001300000013000000130000001300000045 +:10AFC0001300000013000000130000001300000035 +:10AFD0001300000013000000130000001300000025 +:10AFE0001300000013000000130000001300000015 +:10AFF0001300000013000000130000001300000005 +:10B00000606162636465666768696A6B6C6D6E6FC8 +:10B0100013000000130000001300000013000000E4 +:10B0200013000000130000001300000013000000D4 +:10B0300013000000130000001300000013000000C4 +:10B0400013000000130000001300000013000000B4 +:10B0500013000000130000001300000013000000A4 +:10B060001300000013000000130000001300000094 +:10B070001300000013000000130000001300000084 +:10B080001300000013000000130000001300000074 +:10B090001300000013000000130000001300000064 +:10B0A0001300000013000000130000001300000054 +:10B0B0001300000013000000130000001300000044 +:10B0C0001300000013000000130000001300000034 +:10B0D0001300000013000000130000001300000024 +:10B0E0001300000013000000130000001300000014 +:10B0F0001300000013000000130000001300000004 +:10B1000013000000130000001300000013000000F3 +:10B1100013000000130000001300000013000000E3 +:10B1200013000000130000001300000013000000D3 +:10B1300013000000130000001300000013000000C3 +:10B1400013000000130000001300000013000000B3 +:10B1500013000000130000001300000013000000A3 +:10B160001300000013000000130000001300000093 +:10B170001300000013000000130000001300000083 +:10B180001300000013000000130000001300000073 +:10B190001300000013000000130000001300000063 +:10B1A0001300000013000000130000001300000053 +:10B1B0001300000013000000130000001300000043 +:10B1C0001300000013000000130000001300000033 +:10B1D0001300000013000000130000001300000023 +:10B1E0001300000013000000130000001300000013 +:10B1F0001300000013000000130000001300000003 +:10B2000013000000130000001300000013000000F2 +:10B2100013000000130000001300000013000000E2 +:10B2200013000000130000001300000013000000D2 +:10B2300013000000130000001300000013000000C2 +:10B2400013000000130000001300000013000000B2 +:10B2500013000000130000001300000013000000A2 +:10B260001300000013000000130000001300000092 +:10B270001300000013000000130000001300000082 +:10B280001300000013000000130000001300000072 +:10B290001300000013000000130000001300000062 +:10B2A0001300000013000000130000001300000052 +:10B2B0001300000013000000130000001300000042 +:10B2C0001300000013000000130000001300000032 +:10B2D0001300000013000000130000001300000022 +:10B2E0001300000013000000130000001300000012 +:10B2F0001300000013000000130000001300000002 +:10B3000013000000130000001300000013000000F1 +:10B3100013000000130000001300000013000000E1 +:10B3200013000000130000001300000013000000D1 +:10B3300013000000130000001300000013000000C1 +:10B3400013000000130000001300000013000000B1 +:10B3500013000000130000001300000013000000A1 +:10B360001300000013000000130000001300000091 +:10B370001300000013000000130000001300000081 +:10B380001300000013000000130000001300000071 +:10B390001300000013000000130000001300000061 +:10B3A0001300000013000000130000001300000051 +:10B3B0001300000013000000130000001300000041 +:10B3C0001300000013000000130000001300000031 +:10B3D0001300000013000000130000001300000021 +:10B3E0001300000013000000130000001300000011 +:10B3F0001300000013000000130000001300000001 +:10B4000013000000130000001300000013000000F0 +:10B4100013000000130000001300000013000000E0 +:10B4200013000000130000001300000013000000D0 +:10B4300013000000130000001300000013000000C0 +:10B4400013000000130000001300000013000000B0 +:10B4500013000000130000001300000013000000A0 +:10B460001300000013000000130000001300000090 +:10B470001300000013000000130000001300000080 +:10B480001300000013000000130000001300000070 +:10B490001300000013000000130000001300000060 +:10B4A0001300000013000000130000001300000050 +:10B4B0001300000013000000130000001300000040 +:10B4C0001300000013000000130000001300000030 +:10B4D0001300000013000000130000001300000020 +:10B4E0001300000013000000130000001300000010 +:10B4F0001300000013000000130000001300000000 +:10B5000013000000130000001300000013000000EF +:10B5100013000000130000001300000013000000DF +:10B5200013000000130000001300000013000000CF +:10B5300013000000130000001300000013000000BF +:10B5400013000000130000001300000013000000AF +:10B55000130000001300000013000000130000009F +:10B56000130000001300000013000000130000008F +:10B57000130000001300000013000000130000007F +:10B58000130000001300000013000000130000006F +:10B59000130000001300000013000000130000005F +:10B5A000130000001300000013000000130000004F +:10B5B000130000001300000013000000130000003F +:10B5C000130000001300000013000000130000002F +:10B5D000130000001300000013000000130000001F +:10B5E000130000001300000013000000130000000F +:10B5F00013000000130000001300000013000000FF +:10B6000013000000130000001300000013000000EE +:10B6100013000000130000001300000013000000DE +:10B6200013000000130000001300000013000000CE +:10B6300013000000130000001300000013000000BE +:10B6400013000000130000001300000013000000AE +:10B65000130000001300000013000000130000009E +:10B66000130000001300000013000000130000008E +:10B67000130000001300000013000000130000007E +:10B68000130000001300000013000000130000006E +:10B69000130000001300000013000000130000005E +:10B6A000130000001300000013000000130000004E +:10B6B000130000001300000013000000130000003E +:10B6C000130000001300000013000000130000002E +:10B6D000130000001300000013000000130000001E +:10B6E000130000001300000013000000130000000E +:10B6F00013000000130000001300000013000000FE +:10B7000013000000130000001300000013000000ED +:10B7100013000000130000001300000013000000DD +:10B7200013000000130000001300000013000000CD +:10B7300013000000130000001300000013000000BD +:10B7400013000000130000001300000013000000AD +:10B75000130000001300000013000000130000009D +:10B76000130000001300000013000000130000008D +:10B77000130000001300000013000000130000007D +:10B78000130000001300000013000000130000006D +:10B79000130000001300000013000000130000005D +:10B7A000130000001300000013000000130000004D +:10B7B000130000001300000013000000130000003D +:10B7C000130000001300000013000000130000002D +:10B7D000130000001300000013000000130000001D +:10B7E000130000001300000013000000130000000D +:10B7F00013000000130000001300000013000000FD +:10B8000013000000130000001300000013000000EC +:10B8100013000000130000001300000013000000DC +:10B8200013000000130000001300000013000000CC +:10B8300013000000130000001300000013000000BC +:10B8400013000000130000001300000013000000AC +:10B85000130000001300000013000000130000009C +:10B86000130000001300000013000000130000008C +:10B87000130000001300000013000000130000007C +:10B88000130000001300000013000000130000006C +:10B89000130000001300000013000000130000005C +:10B8A000130000001300000013000000130000004C +:10B8B000130000001300000013000000130000003C +:10B8C000130000001300000013000000130000002C +:10B8D000130000001300000013000000130000001C +:10B8E000130000001300000013000000130000000C +:10B8F00013000000130000001300000013000000FC +:10B9000013000000130000001300000013000000EB +:10B9100013000000130000001300000013000000DB +:10B9200013000000130000001300000013000000CB +:10B9300013000000130000001300000013000000BB +:10B9400013000000130000001300000013000000AB +:10B95000130000001300000013000000130000009B +:10B96000130000001300000013000000130000008B +:10B97000130000001300000013000000130000007B +:10B98000130000001300000013000000130000006B +:10B99000130000001300000013000000130000005B +:10B9A000130000001300000013000000130000004B +:10B9B000130000001300000013000000130000003B +:10B9C000130000001300000013000000130000002B +:10B9D000130000001300000013000000130000001B +:10B9E000130000001300000013000000130000000B +:10B9F00013000000130000001300000013000000FB +:10BA000013000000130000001300000013000000EA +:10BA100013000000130000001300000013000000DA +:10BA200013000000130000001300000013000000CA +:10BA300013000000130000001300000013000000BA +:10BA400013000000130000001300000013000000AA +:10BA5000130000001300000013000000130000009A +:10BA6000130000001300000013000000130000008A +:10BA7000130000001300000013000000130000007A +:10BA8000130000001300000013000000130000006A +:10BA9000130000001300000013000000130000005A +:10BAA000130000001300000013000000130000004A +:10BAB000130000001300000013000000130000003A +:10BAC000130000001300000013000000130000002A +:10BAD000130000001300000013000000130000001A +:10BAE000130000001300000013000000130000000A +:10BAF00013000000130000001300000013000000FA +:10BB000013000000130000001300000013000000E9 +:10BB100013000000130000001300000013000000D9 +:10BB200013000000130000001300000013000000C9 +:10BB300013000000130000001300000013000000B9 +:10BB400013000000130000001300000013000000A9 +:10BB50001300000013000000130000001300000099 +:10BB60001300000013000000130000001300000089 +:10BB70001300000013000000130000001300000079 +:10BB80001300000013000000130000001300000069 +:10BB90001300000013000000130000001300000059 +:10BBA0001300000013000000130000001300000049 +:10BBB0001300000013000000130000001300000039 +:10BBC0001300000013000000130000001300000029 +:10BBD0001300000013000000130000001300000019 +:10BBE0001300000013000000130000001300000009 +:10BBF00013000000130000001300000013000000F9 +:10BC000013000000130000001300000013000000E8 +:10BC100013000000130000001300000013000000D8 +:10BC200013000000130000001300000013000000C8 +:10BC300013000000130000001300000013000000B8 +:10BC400013000000130000001300000013000000A8 +:10BC50001300000013000000130000001300000098 +:10BC60001300000013000000130000001300000088 +:10BC70001300000013000000130000001300000078 +:10BC80001300000013000000130000001300000068 +:10BC90001300000013000000130000001300000058 +:10BCA0001300000013000000130000001300000048 +:10BCB0001300000013000000130000001300000038 +:10BCC0001300000013000000130000001300000028 +:10BCD0001300000013000000130000001300000018 +:10BCE0001300000013000000130000001300000008 +:10BCF00013000000130000001300000013000000F8 +:10BD000013000000130000001300000013000000E7 +:10BD100013000000130000001300000013000000D7 +:10BD200013000000130000001300000013000000C7 +:10BD300013000000130000001300000013000000B7 +:10BD400013000000130000001300000013000000A7 +:10BD50001300000013000000130000001300000097 +:10BD60001300000013000000130000001300000087 +:10BD70001300000013000000130000001300000077 +:10BD80001300000013000000130000001300000067 +:10BD90001300000013000000130000001300000057 +:10BDA0001300000013000000130000001300000047 +:10BDB0001300000013000000130000001300000037 +:10BDC0001300000013000000130000001300000027 +:10BDD0001300000013000000130000001300000017 +:10BDE0001300000013000000130000001300000007 +:10BDF00013000000130000001300000013000000F7 +:10BE000013000000130000001300000013000000E6 +:10BE100013000000130000001300000013000000D6 +:10BE200013000000130000001300000013000000C6 +:10BE300013000000130000001300000013000000B6 +:10BE400013000000130000001300000013000000A6 +:10BE50001300000013000000130000001300000096 +:10BE60001300000013000000130000001300000086 +:10BE70001300000013000000130000001300000076 +:10BE80001300000013000000130000001300000066 +:10BE90001300000013000000130000001300000056 +:10BEA0001300000013000000130000001300000046 +:10BEB0001300000013000000130000001300000036 +:10BEC0001300000013000000130000001300000026 +:10BED0001300000013000000130000001300000016 +:10BEE0001300000013000000130000001300000006 +:10BEF00013000000130000001300000013000000F6 +:10BF000013000000130000001300000013000000E5 +:10BF100013000000130000001300000013000000D5 +:10BF200013000000130000001300000013000000C5 +:10BF300013000000130000001300000013000000B5 +:10BF400013000000130000001300000013000000A5 +:10BF50001300000013000000130000001300000095 +:10BF60001300000013000000130000001300000085 +:10BF70001300000013000000130000001300000075 +:10BF80001300000013000000130000001300000065 +:10BF90001300000013000000130000001300000055 +:10BFA0001300000013000000130000001300000045 +:10BFB0001300000013000000130000001300000035 +:10BFC0001300000013000000130000001300000025 +:10BFD0001300000013000000130000001300000015 +:10BFE0001300000013000000130000001300000005 +:10BFF00013000000130000001300000013000000F5 +:10C00000707172737475767778797A7B7C7D7E7FB8 +:10C010000000000000000000000000000000000020 +:10C020000000000000000000000000000000000010 +:10C030000000000000000000000000000000000000 +:10C0400000000000000000000000000000000000F0 +:10C0500000000000000000000000000000000000E0 +:10C0600000000000000000000000000000000000D0 +:10C0700000000000000000000000000000000000C0 +:10C0800000000000000000000000000000000000B0 +:10C0900000000000000000000000000000000000A0 +:10C0A0000000000000000000000000000000000090 +:10C0B0000000000000000000000000000000000080 +:10C0C0000000000000000000000000000000000070 +:10C0D0000000000000000000000000000000000060 +:10C0E0000000000000000000000000000000000050 +:10C0F0000000000000000000000000000000000040 +:10C10000000000000000000000000000000000002F +:10C11000000000000000000000000000000000001F +:10C12000000000000000000000000000000000000F +:10C1300000000000000000000000000000000000FF +:10C1400000000000000000000000000000000000EF +:10C1500000000000000000000000000000000000DF +:10C1600000000000000000000000000000000000CF +:10C1700000000000000000000000000000000000BF +:10C1800000000000000000000000000000000000AF +:10C19000000000000000000000000000000000009F +:10C1A000000000000000000000000000000000008F +:10C1B000000000000000000000000000000000007F +:10C1C000000000000000000000000000000000006F +:10C1D000000000000000000000000000000000005F +:10C1E000000000000000000000000000000000004F +:10C1F000000000000000000000000000000000003F +:10C20000000000000000000000000000000000002E +:10C21000000000000000000000000000000000001E +:10C22000000000000000000000000000000000000E +:10C2300000000000000000000000000000000000FE +:10C2400000000000000000000000000000000000EE +:10C2500000000000000000000000000000000000DE +:10C2600000000000000000000000000000000000CE +:10C2700000000000000000000000000000000000BE +:10C2800000000000000000000000000000000000AE +:10C29000000000000000000000000000000000009E +:10C2A000000000000000000000000000000000008E +:10C2B000000000000000000000000000000000007E +:10C2C000000000000000000000000000000000006E +:10C2D000000000000000000000000000000000005E +:10C2E000000000000000000000000000000000004E +:10C2F000000000000000000000000000000000003E +:10C30000000000000000000000000000000000002D +:10C31000000000000000000000000000000000001D +:10C32000000000000000000000000000000000000D +:10C3300000000000000000000000000000000000FD +:10C3400000000000000000000000000000000000ED +:10C3500000000000000000000000000000000000DD +:10C3600000000000000000000000000000000000CD +:10C3700000000000000000000000000000000000BD +:10C3800000000000000000000000000000000000AD +:10C39000000000000000000000000000000000009D +:10C3A000000000000000000000000000000000008D +:10C3B000000000000000000000000000000000007D +:10C3C000000000000000000000000000000000006D +:10C3D000000000000000000000000000000000005D +:10C3E000000000000000000000000000000000004D +:10C3F000000000000000000000000000000000003D +:10C40000000000000000000000000000000000002C +:10C41000000000000000000000000000000000001C +:10C42000000000000000000000000000000000000C +:10C4300000000000000000000000000000000000FC +:10C4400000000000000000000000000000000000EC +:10C4500000000000000000000000000000000000DC +:10C4600000000000000000000000000000000000CC +:10C4700000000000000000000000000000000000BC +:10C4800000000000000000000000000000000000AC +:10C49000000000000000000000000000000000009C +:10C4A000000000000000000000000000000000008C +:10C4B000000000000000000000000000000000007C +:10C4C000000000000000000000000000000000006C +:10C4D000000000000000000000000000000000005C +:10C4E000000000000000000000000000000000004C +:10C4F000000000000000000000000000000000003C +:10C50000000000000000000000000000000000002B +:10C51000000000000000000000000000000000001B +:10C52000000000000000000000000000000000000B +:10C5300000000000000000000000000000000000FB +:10C5400000000000000000000000000000000000EB +:10C5500000000000000000000000000000000000DB +:10C5600000000000000000000000000000000000CB +:10C5700000000000000000000000000000000000BB +:10C5800000000000000000000000000000000000AB +:10C59000000000000000000000000000000000009B +:10C5A000000000000000000000000000000000008B +:10C5B000000000000000000000000000000000007B +:10C5C000000000000000000000000000000000006B +:10C5D000000000000000000000000000000000005B +:10C5E000000000000000000000000000000000004B +:10C5F000000000000000000000000000000000003B +:10C60000000000000000000000000000000000002A +:10C61000000000000000000000000000000000001A +:10C62000000000000000000000000000000000000A +:10C6300000000000000000000000000000000000FA +:10C6400000000000000000000000000000000000EA +:10C6500000000000000000000000000000000000DA +:10C6600000000000000000000000000000000000CA +:10C6700000000000000000000000000000000000BA +:10C6800000000000000000000000000000000000AA +:10C69000000000000000000000000000000000009A +:10C6A000000000000000000000000000000000008A +:10C6B000000000000000000000000000000000007A +:10C6C000000000000000000000000000000000006A +:10C6D000000000000000000000000000000000005A +:10C6E000000000000000000000000000000000004A +:10C6F000000000000000000000000000000000003A +:10C700000000000000000000000000000000000029 +:10C710000000000000000000000000000000000019 +:10C720000000000000000000000000000000000009 +:10C7300000000000000000000000000000000000F9 +:10C7400000000000000000000000000000000000E9 +:10C7500000000000000000000000000000000000D9 +:10C7600000000000000000000000000000000000C9 +:10C7700000000000000000000000000000000000B9 +:10C7800000000000000000000000000000000000A9 +:10C790000000000000000000000000000000000099 +:10C7A0000000000000000000000000000000000089 +:10C7B0000000000000000000000000000000000079 +:10C7C0000000000000000000000000000000000069 +:10C7D0000000000000000000000000000000000059 +:10C7E0000000000000000000000000000000000049 +:10C7F0000000000000000000000000000000000039 +:10C800000000000000000000000000000000000028 +:10C810000000000000000000000000000000000018 +:10C820000000000000000000000000000000000008 +:10C8300000000000000000000000000000000000F8 +:10C8400000000000000000000000000000000000E8 +:10C8500000000000000000000000000000000000D8 +:10C8600000000000000000000000000000000000C8 +:10C8700000000000000000000000000000000000B8 +:10C8800000000000000000000000000000000000A8 +:10C890000000000000000000000000000000000098 +:10C8A0000000000000000000000000000000000088 +:10C8B0000000000000000000000000000000000078 +:10C8C0000000000000000000000000000000000068 +:10C8D0000000000000000000000000000000000058 +:10C8E0000000000000000000000000000000000048 +:10C8F0000000000000000000000000000000000038 +:10C900000000000000000000000000000000000027 +:10C910000000000000000000000000000000000017 +:10C920000000000000000000000000000000000007 +:10C9300000000000000000000000000000000000F7 +:10C9400000000000000000000000000000000000E7 +:10C9500000000000000000000000000000000000D7 +:10C9600000000000000000000000000000000000C7 +:10C9700000000000000000000000000000000000B7 +:10C9800000000000000000000000000000000000A7 +:10C990000000000000000000000000000000000097 +:10C9A0000000000000000000000000000000000087 +:10C9B0000000000000000000000000000000000077 +:10C9C0000000000000000000000000000000000067 +:10C9D0000000000000000000000000000000000057 +:10C9E0000000000000000000000000000000000047 +:10C9F0000000000000000000000000000000000037 +:10CA00000000000000000000000000000000000026 +:10CA10000000000000000000000000000000000016 +:10CA20000000000000000000000000000000000006 +:10CA300000000000000000000000000000000000F6 +:10CA400000000000000000000000000000000000E6 +:10CA500000000000000000000000000000000000D6 +:10CA600000000000000000000000000000000000C6 +:10CA700000000000000000000000000000000000B6 +:10CA800000000000000000000000000000000000A6 +:10CA90000000000000000000000000000000000096 +:10CAA0000000000000000000000000000000000086 +:10CAB0000000000000000000000000000000000076 +:10CAC0000000000000000000000000000000000066 +:10CAD0000000000000000000000000000000000056 +:10CAE0000000000000000000000000000000000046 +:10CAF0000000000000000000000000000000000036 +:10CB00000000000000000000000000000000000025 +:10CB10000000000000000000000000000000000015 +:10CB20000000000000000000000000000000000005 +:10CB300000000000000000000000000000000000F5 +:10CB400000000000000000000000000000000000E5 +:10CB500000000000000000000000000000000000D5 +:10CB600000000000000000000000000000000000C5 +:10CB700000000000000000000000000000000000B5 +:10CB800000000000000000000000000000000000A5 +:10CB90000000000000000000000000000000000095 +:10CBA0000000000000000000000000000000000085 +:10CBB0000000000000000000000000000000000075 +:10CBC0000000000000000000000000000000000065 +:10CBD0000000000000000000000000000000000055 +:10CBE0000000000000000000000000000000000045 +:10CBF0000000000000000000000000000000000035 +:10CC00000000000000000000000000000000000024 +:10CC10000000000000000000000000000000000014 +:10CC20000000000000000000000000000000000004 +:10CC300000000000000000000000000000000000F4 +:10CC400000000000000000000000000000000000E4 +:10CC500000000000000000000000000000000000D4 +:10CC600000000000000000000000000000000000C4 +:10CC700000000000000000000000000000000000B4 +:10CC800000000000000000000000000000000000A4 +:10CC90000000000000000000000000000000000094 +:10CCA0000000000000000000000000000000000084 +:10CCB0000000000000000000000000000000000074 +:10CCC0000000000000000000000000000000000064 +:10CCD0000000000000000000000000000000000054 +:10CCE0000000000000000000000000000000000044 +:10CCF0000000000000000000000000000000000034 +:10CD00000000000000000000000000000000000023 +:10CD10000000000000000000000000000000000013 +:10CD20000000000000000000000000000000000003 +:10CD300000000000000000000000000000000000F3 +:10CD400000000000000000000000000000000000E3 +:10CD500000000000000000000000000000000000D3 +:10CD600000000000000000000000000000000000C3 +:10CD700000000000000000000000000000000000B3 +:10CD800000000000000000000000000000000000A3 +:10CD90000000000000000000000000000000000093 +:10CDA0000000000000000000000000000000000083 +:10CDB0000000000000000000000000000000000073 +:10CDC0000000000000000000000000000000000063 +:10CDD0000000000000000000000000000000000053 +:10CDE0000000000000000000000000000000000043 +:10CDF0000000000000000000000000000000000033 +:0CCE000000000000000000000000000026 :04000005800000284F :00000001FF diff --git a/src/test/cpp/raw/mmu/src/crt.S b/src/test/cpp/raw/mmu/src/crt.S index f2cb783c..195c8a40 100644 --- a/src/test/cpp/raw/mmu/src/crt.S +++ b/src/test/cpp/raw/mmu/src/crt.S @@ -20,20 +20,108 @@ _start: csrw mtvec, x1 csrw stvec, x1 -//Test 1 +test1: //test ram li x28, 1 + la x1, ROM_2 + li x2, 0x27262524 + lw x1, 4(x1) + bne x1, x2, fail -//Test 2 +test2: //dummy mret li x28, 2 + la x1, test3 + csrw mepc, x1 + li x1, 0x1800 + csrw mstatus, x1 + mret + j fail + + +test3: // jump to supervisor + li x28, 3 + li x1, 0x0800 + csrw mstatus, x1 + la x1, test4 + csrw mepc, x1 + mret + j fail + + + +test4: //test ram mmu off + li x28, 4 + la x1, ROM_3 + li x2, 0x37363534 + lw x1, 4(x1) + bne x1, x2, fail + +test5: //setup MMU + + li x28, 5 + la x1, MMU_TABLE_0 + 0x800 + la x2, MMU_TABLE_1 + srli x2, x2, 2 + ori x2, x2, 0x11 + sw x2, 0(x1) + + la x1, MMU_TABLE_1 + 0x000*4 + li x2, 0x80000000 + srli x2, x2, 2 + ori x2, x2, 0x1F + sw x2, 0(x1) + + + li x28, 5 + la x1, MMU_TABLE_0 + 0x900 + la x2, MMU_TABLE_2 + srli x2, x2, 2 + ori x2, x2, 0x11 + sw x2, 0(x1) + + la x1, MMU_TABLE_2 + 0x00A*4 + la x2, ROM_4 + srli x2, x2, 2 + ori x2, x2, 0x1F + sw x2, 0(x1) + + la x1, MMU_TABLE_0 + srli x1, x1, 12 + li x2, 0x80000000 + or x1, x1, x2 + csrw satp, x1 + + +test6: //read through MMU ! + li x28, 6 + li x1, 0x9000A008 + li x2, 0x4B4A4948 + lw x1, 0(x1) + bne x1, x2, fail + + + + + + + + + + + j pass - fail: //x28 => error code + csrwi satp, 0 + j failFence +failFence: li x2, 0xF00FFF24 sw x28, 0(x2) pass: + csrwi satp, 0 + j passFence +passFence: li x2, 0xF00FFF20 sw x0, 0(x2) @@ -45,3 +133,77 @@ pass: nop nop nop + +.align 12 +MMU_TABLE_0: +.word 0 + +.align 12 +MMU_TABLE_1: +.word 0 + +.align 12 +MMU_TABLE_2: +.word 0 + +.align 12 +MMU_TABLE_3: +.word 0 + +.align 12 +ROM_0: +.word 0x03020100 +.word 0x07060504 +.word 0x0B0A0908 +.word 0x0F0E0D0C + +.align 12 +ROM_1: +.word 0x13121110 +.word 0x17161514 +.word 0x1B1A1918 +.word 0x1F1E1D1C + +.align 12 +ROM_2: +.word 0x23222120 +.word 0x27262524 +.word 0x2B2A2928 +.word 0x2F2E2D2C + +.align 12 +ROM_3: +.word 0x33323130 +.word 0x37363534 +.word 0x3B3A3938 +.word 0x3F3E3D3C + +.align 12 +ROM_4: +.word 0x43424140 +.word 0x47464544 +.word 0x4B4A4948 +.word 0x4F4E4D4C + +.align 12 +ROM_5: +.word 0x53525150 +.word 0x57565554 +.word 0x5B5A5958 +.word 0x5F5E5D5C + +.align 12 +ROM_6: +.word 0x63626160 +.word 0x67666564 +.word 0x6B6A6968 +.word 0x6F6E6D6C + +.align 12 +ROM_7: +.word 0x73727170 +.word 0x77767574 +.word 0x7B7A7978 +.word 0x7F7E7D7C + + diff --git a/src/test/cpp/raw/mmu/src/ld b/src/test/cpp/raw/mmu/src/ld index cd04151d..e60e987d 100644 --- a/src/test/cpp/raw/mmu/src/ld +++ b/src/test/cpp/raw/mmu/src/ld @@ -1,7 +1,7 @@ OUTPUT_ARCH( "riscv" ) MEMORY { - onChipRam (W!RX)/*(RX)*/ : ORIGIN = 0x80000000, LENGTH = 8K + onChipRam (W!RX)/*(RX)*/ : ORIGIN = 0x80000000, LENGTH = 1M } SECTIONS diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 94d0f3f5..07b44294 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -289,20 +289,42 @@ public: union mcause { uint32_t raw; - struct { + struct __attribute__((packed)) { uint32_t exceptionCode : 31; uint32_t interrupt : 1; }; - }__attribute__((packed)) mcause; + } mcause; union scause { uint32_t raw; - struct { + struct __attribute__((packed)){ uint32_t exceptionCode : 31; uint32_t interrupt : 1; }; - }__attribute__((packed)) scause; + } scause; + + union satp { + uint32_t raw; + struct __attribute__((packed)){ + uint32_t ppn : 22; + uint32_t _x : 9; + uint32_t mode : 1; + }; + }satp; + + union Tlb { + uint32_t raw; + struct __attribute__((packed)){ + uint32_t v : 1; + uint32_t r : 1; + uint32_t w : 1; + uint32_t x : 1; + uint32_t u : 1; + uint32_t _dummy : 5; + uint32_t ppn : 22; + }; + }; @@ -324,6 +346,7 @@ public: privilege = 3; medeleg = 0; mideleg = 0; + satp.mode = 0; } virtual void rfWrite(int32_t address, int32_t data) { @@ -346,6 +369,29 @@ public: virtual bool dRead(int32_t address, int32_t size, uint32_t *data) = 0; virtual void dWrite(int32_t address, int32_t size, uint32_t data) = 0; + enum AccessKind {READ,WRITE,EXECUTE}; + bool v2p(uint32_t v, uint32_t *p, AccessKind kind){ + if(privilege == 3 || satp.mode == 0){ + *p = v; + } else { + Tlb tlb; + dRead((satp.ppn << 12) | ((v >> 22) << 2), 4, &tlb.raw); + if(!tlb.v) return true; + if(!tlb.x && !tlb.r && !tlb.w){ + dRead((tlb.ppn << 12) | (((v >> 12) & 0x3FF) << 2), 4, &tlb.raw); + if(!tlb.v) return true; + } + if(!tlb.u && privilege == 0) return true; + switch(kind){ + case READ: if(!tlb.r) return true; break; + case WRITE: if(!tlb.w) return true; break; + case EXECUTE: if(!tlb.x) return true; break; + } + *p = (tlb.ppn << 12) | (v & 0xFFF); + } + return false; + } + void exception(bool interrupt,int32_t cause) { exception(interrupt, cause, false, 0); } @@ -396,6 +442,7 @@ public: virtual bool csrRead(int32_t csr, uint32_t *value){ + if(((csr >> 8) & 0x3) > privilege) return true; switch(csr){ case MSTATUS: *value = status.raw; break; case MIP: *value = ip.raw; break; @@ -415,6 +462,7 @@ public: case STVAL: *value = sbadaddr; break; case SEPC: *value = sepc; break; case SSCRATCH: *value = sscratch; break; + case SATP: *value = satp.raw; break; default: return true; break; } return false; @@ -422,6 +470,7 @@ public: #define maskedWrite(dst, src, mask) dst=(dst & ~mask)|(src & mask); virtual bool csrWrite(int32_t csr, uint32_t value){ + if(((csr >> 8) & 0x3) > privilege) return true; switch(csr){ case MSTATUS: status.raw = value; break; case MIP: ip.raw = value; break; @@ -441,6 +490,7 @@ public: case STVAL: sbadaddr = value; break; case SEPC: sepc = value; break; case SSCRATCH: sscratch = value; break; + case SATP: satp.raw = value; break; default: ilegalInstruction(); return true; break; } @@ -513,22 +563,26 @@ public: #define i16_swsp_imm ((iBits(9, 4) << 2) + (iBits(7, 2) << 6)) uint32_t i; uint32_t u32Buf; + uint32_t pAddr; if (pc & 2) { - if(iRead(pc - 2, &i)){ + if(v2p(pc - 2, &pAddr, EXECUTE)){ exception(0, 12); return; } + if(iRead(pAddr, &i)){ exception(0, 1); return; } i >>= 16; if (i & 3 == 3) { uint32_t u32Buf; - if(iRead(pc + 2, &u32Buf)){ + if(v2p(pc + 2, &pAddr, EXECUTE)){ exception(0, 12); return; } + if(iRead(pAddr, &u32Buf)){ exception(0, 1); return; } i |= u32Buf << 16; } } else { - if(iRead(pc, &i)){ + if(v2p(pc, &pAddr, EXECUTE)){ exception(0, 12); return; } + if(iRead(pAddr, &i)){ exception(0, 1); return; } @@ -561,7 +615,8 @@ public: if(address & (size-1)){ exception(0, 4, address); } else { - if(dRead(address, size, &data)){ + if(v2p(address, &pAddr, READ)){ exception(0, 13); return; } + if(dRead(pAddr, size, &data)){ exception(0, 5, address); } else { switch ((i >> 12) & 0x7) { @@ -580,7 +635,8 @@ public: if(address & (size-1)){ exception(0, 6, address); } else { - dWrite(address, size, i32_rs2); + if(v2p(address, &pAddr, WRITE)){ exception(0, 15); return; } + dWrite(pAddr, size, i32_rs2); pcWrite(pc + 4); } }break; @@ -645,18 +701,18 @@ public: switch(i){ case 0x30200073:{ //MRET if(privilege < 3){ ilegalInstruction(); return;} - status.mpp = 0; + privilege = status.mpp; status.mie = status.mpie; status.mpie = 1; - privilege = status.mpp; + status.mpp = 0; pcWrite(mepc); }break; case 0x10200073:{ //SRET if(privilege < 1){ ilegalInstruction(); return;} - status.spp = 0; + privilege = status.spp; status.sie = status.spie; status.spie = 1; - privilege = status.spp; + status.spp = 0; pcWrite(sepc); }break; case 0x00000073:{ //ECALL @@ -699,7 +755,8 @@ public: if(address & 0x3){ exception(0, 4, address); } else { - if(dRead(i16_rf1 + i16_lw_imm, 4, &data)) { + if(v2p(address, &pAddr, READ)){ exception(0, 13); return; } + if(dRead(address, 4, &data)) { exception(1, 5, address); } else { rfWrite(i16_addr2, data); pcWrite(pc + 2); @@ -711,7 +768,8 @@ public: if(address & 0x3){ exception(0, 6, address); } else { - dWrite(address, 4, i16_rf2); + if(v2p(address, &pAddr, WRITE)){ exception(0, 15); return; } + dWrite(pAddr, 4, i16_rf2); pcWrite(pc + 2); } }break; @@ -746,7 +804,8 @@ public: if(address & 0x3){ exception(0, 4, address); } else { - if(dRead(address, 4, &data)){ + if(v2p(address, &pAddr, READ)){ exception(0, 13); return; } + if(dRead(pAddr, 4, &data)){ exception(1, 5, address); } else { rfWrite(rd32, data); pcWrite(pc + 2); @@ -775,7 +834,8 @@ public: if(address & 3){ exception(0,6, address); } else { - dWrite(address, 4, regs[iBits(2,5)]); pcWrite(pc + 2); + if(v2p(address, &pAddr, WRITE)){ exception(0, 15); return; } + dWrite(pAddr, 4, regs[iBits(2,5)]); pcWrite(pc + 2); } }break; } @@ -884,7 +944,8 @@ public: cout << "dRead size=" << size << endl; fail(); } - if(address & (size-1) != 0) cout << "Ref did a unaligned read" << endl; + if(address & (size-1) != 0) + cout << "Ref did a unaligned read" << endl; if((address & 0xF0000000) == 0xF0000000){ MemRead t = periphRead.front(); if(t.address != address || t.size != size){ @@ -899,7 +960,8 @@ public: return false; } virtual void dWrite(int32_t address, int32_t size, uint32_t data){ - if(address & (size-1) != 0) cout << "Ref did a unaligned write" << endl; + if(address & (size-1) != 0) + cout << "Ref did a unaligned write" << endl; if((address & 0xF0000000) == 0xF0000000){ MemWrite w; w.address = address; @@ -2879,6 +2941,10 @@ int main(int argc, char **argv, char **env) { printf("BOOT\n"); timespec startedAt = timer_start(); + #ifdef MMU + redo(REDO,Workspace("mmu").withRiscvRef()->loadHex("../raw/mmu/build/mmu.hex")->bootAt(0x80000000u)->run(50e3);); + #endif + return 0; for(int idx = 0;idx < 1;idx++){ diff --git a/src/test/cpp/regression/makefile b/src/test/cpp/regression/makefile index 774ef19d..937a6204 100644 --- a/src/test/cpp/regression/makefile +++ b/src/test/cpp/regression/makefile @@ -1,4 +1,4 @@ -DEBUG?=no +DEBUG?=yes IBUS?=CACHED IBUS_TC?=no From 2b458fc642b7116ef3c6e761a34fca27e4a95ff9 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 22 Mar 2019 12:23:47 +0100 Subject: [PATCH 059/951] Added MMU superpage support, pass MMU tests --- .../scala/vexriscv/plugin/MmuPlugin.scala | 28 +-- src/test/cpp/raw/common/asm.mk | 2 +- src/test/cpp/raw/mmu/build/mmu.asm | 178 +++++++++--------- src/test/cpp/raw/mmu/build/mmu.hex | 59 +++--- src/test/cpp/raw/mmu/src/crt.S | 69 ++++++- src/test/cpp/raw/mmu/src/ld | 2 +- src/test/cpp/regression/main.cpp | 10 +- 7 files changed, 211 insertions(+), 137 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/MmuPlugin.scala b/src/main/scala/vexriscv/plugin/MmuPlugin.scala index 5248c251..6e98de5a 100644 --- a/src/main/scala/vexriscv/plugin/MmuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/MmuPlugin.scala @@ -74,9 +74,9 @@ class MmuPlugin(virtualRange : UInt => Bool, val sortedPortsInfo = portsInfo.sortWith((a,b) => a.priority > b.priority) case class CacheLine() extends Bundle { - val valid, exception = Bool - val virtualAddress = UInt(20 bits) - val physicalAddress = UInt(20 bits) + val valid, exception, superPage = Bool + val virtualAddress = Vec(UInt(10 bits), UInt(10 bits)) + val physicalAddress = Vec(UInt(10 bits), UInt(10 bits)) val allowRead, allowWrite, allowExecute, allowUser = Bool def init = { @@ -89,7 +89,7 @@ class MmuPlugin(virtualRange : UInt => Bool, val ports = for (port <- sortedPortsInfo) yield new Area { val id = port.id val cache = Vec(Reg(CacheLine()) init, port.args.portTlbSize) - val cacheHits = cache.map(line => line.valid && line.virtualAddress === port.bus.cmd.virtualAddress(31 downto 12)) + val cacheHits = cache.map(line => line.valid && line.virtualAddress(1) === port.bus.cmd.virtualAddress(31 downto 22) && (line.superPage || line.virtualAddress(0) === port.bus.cmd.virtualAddress(21 downto 12))) val cacheHit = cacheHits.asBits.orR val cacheLine = MuxOH(cacheHits, cache) val privilegeService = pipeline.serviceElse(classOf[PrivilegeService], PrivilegeServiceDefault()) @@ -99,7 +99,7 @@ class MmuPlugin(virtualRange : UInt => Bool, if(!allowMachineModeMmu) requireMmuLockup clearWhen(privilegeService.isMachine(execute)) when(requireMmuLockup) { - port.bus.rsp.physicalAddress := cacheLine.physicalAddress @@ port.bus.cmd.virtualAddress(11 downto 0) + port.bus.rsp.physicalAddress := cacheLine.physicalAddress(1) @@ (cacheLine.superPage ? port.bus.cmd.virtualAddress(21 downto 12) | cacheLine.physicalAddress(0)) @@ port.bus.cmd.virtualAddress(11 downto 0) port.bus.rsp.allowRead := cacheLine.allowRead port.bus.rsp.allowWrite := cacheLine.allowWrite port.bus.rsp.allowExecute := cacheLine.allowExecute @@ -132,7 +132,7 @@ class MmuPlugin(virtualRange : UInt => Bool, val IDLE, L1_CMD, L1_RSP, L0_CMD, L0_RSP = newElement() } val state = RegInit(State.IDLE) - val vpn1, vpn0 = Reg(UInt(10 bits)) + val vpn = Reg(Vec(UInt(10 bits), UInt(10 bits))) val portId = Reg(UInt(log2Up(portsInfo.length) bits)) case class PTE() extends Bundle { val V, R, W ,X, U, G, A, D = Bool() @@ -160,8 +160,8 @@ class MmuPlugin(virtualRange : UInt => Bool, for(port <- portsInfo.sortBy(_.priority)){ when(port.bus.cmd.isValid && port.bus.rsp.refilling){ busy := True - vpn1 := port.bus.cmd.virtualAddress(31 downto 22) - vpn0 := port.bus.cmd.virtualAddress(21 downto 12) + vpn(1) := port.bus.cmd.virtualAddress(31 downto 22) + vpn(0) := port.bus.cmd.virtualAddress(21 downto 12) portId := port.id state := State.L1_CMD } @@ -169,7 +169,7 @@ class MmuPlugin(virtualRange : UInt => Bool, } is(State.L1_CMD){ dBusAccess.cmd.valid := True - dBusAccess.cmd.address := satp.ppn @@ vpn1 @@ U"00" + dBusAccess.cmd.address := satp.ppn @@ vpn(1) @@ U"00" when(dBusAccess.cmd.ready){ state := State.L1_RSP } @@ -185,7 +185,7 @@ class MmuPlugin(virtualRange : UInt => Bool, } is(State.L0_CMD){ dBusAccess.cmd.valid := True - dBusAccess.cmd.address := pteBuffer.PPN1(9 downto 0) @@ pteBuffer.PPN0 @@ vpn0 @@ U"00" + dBusAccess.cmd.address := pteBuffer.PPN1(9 downto 0) @@ pteBuffer.PPN0 @@ vpn(0) @@ U"00" when(dBusAccess.cmd.ready){ state := State.L0_RSP } @@ -203,14 +203,16 @@ class MmuPlugin(virtualRange : UInt => Bool, port.entryToReplace.increment() for ((line, lineId) <- port.cache.zipWithIndex) { when(port.entryToReplace === lineId){ + val superPage = state === State.L1_RSP line.valid := True - line.exception := dBusRsp.exception - line.virtualAddress := vpn1 @@ vpn0 - line.physicalAddress := dBusRsp.pte.PPN1(9 downto 0) @@ dBusRsp.pte.PPN0 + line.exception := dBusRsp.exception || (superPage && dBusRsp.pte.PPN0 =/= 0) + line.virtualAddress := vpn + line.physicalAddress := Vec(dBusRsp.pte.PPN0, dBusRsp.pte.PPN1(9 downto 0)) line.allowRead := dBusRsp.pte.R line.allowWrite := dBusRsp.pte.W line.allowExecute := dBusRsp.pte.X line.allowUser := dBusRsp.pte.U + line.superPage := state === State.L1_RSP } } } diff --git a/src/test/cpp/raw/common/asm.mk b/src/test/cpp/raw/common/asm.mk index 8459b7b8..a4f94f6a 100644 --- a/src/test/cpp/raw/common/asm.mk +++ b/src/test/cpp/raw/common/asm.mk @@ -27,7 +27,7 @@ OBJS := $(addprefix $(OBJDIR)/,$(OBJS)) -all: $(OBJDIR)/$(PROJ_NAME).elf $(OBJDIR)/$(PROJ_NAME).hex $(OBJDIR)/$(PROJ_NAME).asm $(OBJDIR)/$(PROJ_NAME).v +all: $(OBJDIR)/$(PROJ_NAME).elf $(OBJDIR)/$(PROJ_NAME).hex $(OBJDIR)/$(PROJ_NAME).asm @echo "done" $(OBJDIR)/%.elf: $(OBJS) | $(OBJDIR) diff --git a/src/test/cpp/raw/mmu/build/mmu.asm b/src/test/cpp/raw/mmu/build/mmu.asm index 79d9f0e8..198f6f3d 100644 --- a/src/test/cpp/raw/mmu/build/mmu.asm +++ b/src/test/cpp/raw/mmu/build/mmu.asm @@ -4,7 +4,7 @@ build/mmu.elf: file format elf32-littleriscv Disassembly of section .crt_section: -80000000 : +80000000 : 80000000: 0280006f j 80000028 <_start> 80000004: 00000013 nop 80000008: 00000013 nop @@ -15,12 +15,12 @@ Disassembly of section .crt_section: 8000001c: 00000013 nop 80000020 : -80000020: 1440006f j 80000164 +80000020: 1f80006f j 80000218 80000024: 30200073 mret 80000028 <_start>: 80000028: 00000097 auipc ra,0x0 -8000002c: 13c08093 addi ra,ra,316 # 80000164 +8000002c: 1f008093 addi ra,ra,496 # 80000218 80000030: 30509073 csrw mtvec,ra 80000034: 10509073 csrw stvec,ra @@ -29,9 +29,9 @@ Disassembly of section .crt_section: 8000003c: 00007097 auipc ra,0x7 80000040: fc408093 addi ra,ra,-60 # 80007000 80000044: 27262137 lui sp,0x27262 -80000048: 52410113 addi sp,sp,1316 # 27262524 +80000048: 52410113 addi sp,sp,1316 # 27262524 8000004c: 0040a083 lw ra,4(ra) -80000050: 10209a63 bne ra,sp,80000164 +80000050: 1c209463 bne ra,sp,80000218 80000054 : 80000054: 00200e13 li t3,2 @@ -39,30 +39,30 @@ Disassembly of section .crt_section: 8000005c: 02008093 addi ra,ra,32 # 80000078 80000060: 34109073 csrw mepc,ra 80000064: 000020b7 lui ra,0x2 -80000068: 80008093 addi ra,ra,-2048 # 1800 +80000068: 80008093 addi ra,ra,-2048 # 1800 8000006c: 30009073 csrw mstatus,ra 80000070: 30200073 mret -80000074: 0f00006f j 80000164 +80000074: 1a40006f j 80000218 80000078 : 80000078: 00300e13 li t3,3 8000007c: 000010b7 lui ra,0x1 -80000080: 80008093 addi ra,ra,-2048 # 800 +80000080: 80008093 addi ra,ra,-2048 # 800 80000084: 30009073 csrw mstatus,ra 80000088: 00000097 auipc ra,0x0 8000008c: 01408093 addi ra,ra,20 # 8000009c 80000090: 34109073 csrw mepc,ra 80000094: 30200073 mret -80000098: 0cc0006f j 80000164 +80000098: 1800006f j 80000218 8000009c : 8000009c: 00400e13 li t3,4 800000a0: 00008097 auipc ra,0x8 800000a4: f6008093 addi ra,ra,-160 # 80008000 800000a8: 37363137 lui sp,0x37363 -800000ac: 53410113 addi sp,sp,1332 # 37363534 +800000ac: 53410113 addi sp,sp,1332 # 37363534 800000b0: 0040a083 lw ra,4(ra) -800000b4: 0a209863 bne ra,sp,80000164 +800000b4: 16209263 bne ra,sp,80000218 800000b8 : 800000b8: 00500e13 li t3,5 @@ -94,85 +94,93 @@ Disassembly of section .crt_section: 80000120: 00215113 srli sp,sp,0x2 80000124: 01f16113 ori sp,sp,31 80000128: 0020a023 sw sp,0(ra) -8000012c: 00001097 auipc ra,0x1 -80000130: ed408093 addi ra,ra,-300 # 80001000 -80000134: 00c0d093 srli ra,ra,0xc -80000138: 80000137 lui sp,0x80000 -8000013c: 0020e0b3 or ra,ra,sp -80000140: 18009073 csrw satp,ra +8000012c: 00500e13 li t3,5 +80000130: 00002097 auipc ra,0x2 +80000134: 8d008093 addi ra,ra,-1840 # 80001a00 +80000138: 00000117 auipc sp,0x0 +8000013c: ec810113 addi sp,sp,-312 # 80000000 +80000140: 00215113 srli sp,sp,0x2 +80000144: 01f16113 ori sp,sp,31 +80000148: 0020a023 sw sp,0(ra) +8000014c: 00001097 auipc ra,0x1 +80000150: eb408093 addi ra,ra,-332 # 80001000 +80000154: 00c0d093 srli ra,ra,0xc +80000158: 80000137 lui sp,0x80000 +8000015c: 0020e0b3 or ra,ra,sp +80000160: 18009073 csrw satp,ra -80000144 : -80000144: 00600e13 li t3,6 -80000148: 9000a0b7 lui ra,0x9000a -8000014c: 00808093 addi ra,ra,8 # 9000a008 -80000150: 4b4a5137 lui sp,0x4b4a5 -80000154: 94810113 addi sp,sp,-1720 # 4b4a4948 -80000158: 0000a083 lw ra,0(ra) -8000015c: 00209463 bne ra,sp,80000164 -80000160: 0180006f j 80000178 +80000164 : +80000164: 00600e13 li t3,6 +80000168: 9000a0b7 lui ra,0x9000a +8000016c: 00808093 addi ra,ra,8 # 9000a008 +80000170: 4b4a5137 lui sp,0x4b4a5 +80000174: 94810113 addi sp,sp,-1720 # 4b4a4948 +80000178: 0000a083 lw ra,0(ra) +8000017c: 08209e63 bne ra,sp,80000218 -80000164 : -80000164: 18005073 csrwi satp,0 -80000168: 0040006f j 8000016c +80000180 : +80000180: 00700e13 li t3,7 +80000184: 9000a0b7 lui ra,0x9000a +80000188: 36008093 addi ra,ra,864 # 9000a360 +8000018c: aaee0137 lui sp,0xaaee0 +80000190: 00110113 addi sp,sp,1 # aaee0001 +80000194: 0020a023 sw sp,0(ra) +80000198: 0000a083 lw ra,0(ra) +8000019c: 06209e63 bne ra,sp,80000218 -8000016c : -8000016c: f0100137 lui sp,0xf0100 -80000170: f2410113 addi sp,sp,-220 # f00fff24 -80000174: 01c12023 sw t3,0(sp) +800001a0 : +800001a0: 00800e13 li t3,8 +800001a4: 2000c097 auipc ra,0x2000c +800001a8: e6008093 addi ra,ra,-416 # a000c004 +800001ac: 77767137 lui sp,0x77767 +800001b0: 57410113 addi sp,sp,1396 # 77767574 +800001b4: 0000a083 lw ra,0(ra) +800001b8: 06209063 bne ra,sp,80000218 -80000178 : -80000178: 18005073 csrwi satp,0 -8000017c: 0040006f j 80000180 +800001bc : +800001bc: 00900e13 li t3,9 +800001c0: a000a0b7 lui ra,0xa000a +800001c4: 36008093 addi ra,ra,864 # a000a360 +800001c8: aaee0137 lui sp,0xaaee0 +800001cc: 00210113 addi sp,sp,2 # aaee0002 +800001d0: 0020a023 sw sp,0(ra) +800001d4: 0000a083 lw ra,0(ra) +800001d8: 04209063 bne ra,sp,80000218 -80000180 : -80000180: f0100137 lui sp,0xf0100 -80000184: f2010113 addi sp,sp,-224 # f00fff20 -80000188: 00012023 sw zero,0(sp) -8000018c: 00000013 nop -80000190: 00000013 nop -80000194: 00000013 nop -80000198: 00000013 nop -8000019c: 00000013 nop -800001a0: 00000013 nop -800001a4: 00000013 nop -800001a8: 00000013 nop -800001ac: 00000013 nop -800001b0: 00000013 nop -800001b4: 00000013 nop -800001b8: 00000013 nop -800001bc: 00000013 nop -800001c0: 00000013 nop -800001c4: 00000013 nop -800001c8: 00000013 nop -800001cc: 00000013 nop -800001d0: 00000013 nop -800001d4: 00000013 nop -800001d8: 00000013 nop -800001dc: 00000013 nop -800001e0: 00000013 nop -800001e4: 00000013 nop -800001e8: 00000013 nop -800001ec: 00000013 nop -800001f0: 00000013 nop -800001f4: 00000013 nop -800001f8: 00000013 nop -800001fc: 00000013 nop -80000200: 00000013 nop -80000204: 00000013 nop -80000208: 00000013 nop -8000020c: 00000013 nop -80000210: 00000013 nop -80000214: 00000013 nop -80000218: 00000013 nop -8000021c: 00000013 nop -80000220: 00000013 nop -80000224: 00000013 nop -80000228: 00000013 nop -8000022c: 00000013 nop -80000230: 00000013 nop -80000234: 00000013 nop -80000238: 00000013 nop -8000023c: 00000013 nop +800001dc : +800001dc: 00a00e13 li t3,10 +800001e0: 18005073 csrwi satp,0 +800001e4: 00009097 auipc ra,0x9 +800001e8: 17c08093 addi ra,ra,380 # 80009360 +800001ec: aaee0137 lui sp,0xaaee0 +800001f0: 00110113 addi sp,sp,1 # aaee0001 +800001f4: 0000a083 lw ra,0(ra) +800001f8: 02209063 bne ra,sp,80000218 +800001fc: 0000a097 auipc ra,0xa +80000200: 16408093 addi ra,ra,356 # 8000a360 +80000204: aaee0137 lui sp,0xaaee0 +80000208: 00210113 addi sp,sp,2 # aaee0002 +8000020c: 0000a083 lw ra,0(ra) +80000210: 00209463 bne ra,sp,80000218 +80000214: 0180006f j 8000022c + +80000218 : +80000218: 18005073 csrwi satp,0 +8000021c: 0040006f j 80000220 + +80000220 : +80000220: f0100137 lui sp,0xf0100 +80000224: f2410113 addi sp,sp,-220 # f00fff24 +80000228: 01c12023 sw t3,0(sp) + +8000022c : +8000022c: 18005073 csrwi satp,0 +80000230: 0040006f j 80000234 + +80000234 : +80000234: f0100137 lui sp,0xf0100 +80000238: f2010113 addi sp,sp,-224 # f00fff20 +8000023c: 00012023 sw zero,0(sp) 80000240: 00000013 nop 80000244: 00000013 nop 80000248: 00000013 nop diff --git a/src/test/cpp/raw/mmu/build/mmu.hex b/src/test/cpp/raw/mmu/build/mmu.hex index cc70c56c..257d6c67 100644 --- a/src/test/cpp/raw/mmu/build/mmu.hex +++ b/src/test/cpp/raw/mmu/build/mmu.hex @@ -1,40 +1,40 @@ :0200000480007A :100000006F008002130000001300000013000000C6 :100010001300000013000000130000001300000094 -:100020006F00401473002030970000009380C013CD +:100020006F00801F73002030970000009380001F36 :100030007390503073905010130E100097700000A2 :10004000938040FC372126271301415283A04000B2 -:10005000639A2010130E2000970000009380000286 +:100050006394201C130E2000970000009380000280 :1000600073901034B72000009380008073900030AC -:10007000730020306F00000F130E3000B710000027 +:10007000730020306F00401A130E3000B7100000DC :1000800093800080739000309700000093804001BF -:1000900073901034730020306F00C00C130E4000BA +:1000900073901034730020306F000018130E40006E :1000A00097800000938000F63731363713014153B3 -:1000B00083A040006398200A130E500097100000A0 +:1000B00083A0400063922016130E5000971000009A :1000C00093804074172100001301C1F313512100E4 :1000D0001361110123A0200097200000938080F27B :1000E00037010080135121001361F10123A020008A :1000F000130E5000972000009380C080173100003D :10010000130141F0135121001361110123A02000BC :1001100097300000938080F117910000130181EE69 -:10012000135121001361F10123A02000971000005A -:10013000938040ED93D0C00037010080B3E02000F1 -:1001400073900018130E6000B7A000909380800099 -:1001500037514A4B1301819483A00000639420001F -:100160006F008001735000186F004000370110F0DD -:10017000130141F22320C101735000186F004000A9 -:10018000370110F0130101F22320010013000000D9 -:100190001300000013000000130000001300000013 -:1001A0001300000013000000130000001300000003 -:1001B00013000000130000001300000013000000F3 -:1001C00013000000130000001300000013000000E3 -:1001D00013000000130000001300000013000000D3 -:1001E00013000000130000001300000013000000C3 -:1001F00013000000130000001300000013000000B3 -:1002000013000000130000001300000013000000A2 -:100210001300000013000000130000001300000092 -:100220001300000013000000130000001300000082 -:100230001300000013000000130000001300000072 +:10012000135121001361F10123A02000130E500090 +:10013000972000009380008D17010000130181ECCF +:10014000135121001361F10123A02000971000003A +:10015000938040EB93D0C00037010080B3E02000D3 +:1001600073900018130E6000B7A000909380800079 +:1001700037514A4B1301819483A00000639E2008ED +:10018000130E7000B7A00090938000363701EEAADE +:100190001301110023A0200083A00000639E20060D +:1001A000130E800097C00020938000E637717677A9 +:1001B0001301415783A0000063902006130E9000A6 +:1001C000B7A000A0938000363701EEAA13012100EA +:1001D00023A0200083A0000063902004130EA00041 +:1001E00073500018979000009380C0173701EEAA53 +:1001F0001301110083A000006390200297A000006B +:10020000938040163701EEAA1301210083A000005D +:10021000639420006F008001735000186F0040004D +:10022000370110F0130141F22320C101735000186F +:100230006F004000370110F0130101F2232001008C :100240001300000013000000130000001300000062 :100250001300000013000000130000001300000052 :100260001300000013000000130000001300000042 @@ -3284,17 +3284,6 @@ :10CD20000000000000000000000000000000000003 :10CD300000000000000000000000000000000000F3 :10CD400000000000000000000000000000000000E3 -:10CD500000000000000000000000000000000000D3 -:10CD600000000000000000000000000000000000C3 -:10CD700000000000000000000000000000000000B3 -:10CD800000000000000000000000000000000000A3 -:10CD90000000000000000000000000000000000093 -:10CDA0000000000000000000000000000000000083 -:10CDB0000000000000000000000000000000000073 -:10CDC0000000000000000000000000000000000063 -:10CDD0000000000000000000000000000000000053 -:10CDE0000000000000000000000000000000000043 -:10CDF0000000000000000000000000000000000033 -:0CCE000000000000000000000000000026 +:08CD50000000000000000000DB :04000005800000284F :00000001FF diff --git a/src/test/cpp/raw/mmu/src/crt.S b/src/test/cpp/raw/mmu/src/crt.S index 195c8a40..a25ec57d 100644 --- a/src/test/cpp/raw/mmu/src/crt.S +++ b/src/test/cpp/raw/mmu/src/crt.S @@ -1,5 +1,6 @@ .globl _start +ROM_SUPER_0: j _start nop @@ -84,6 +85,14 @@ test5: //setup MMU ori x2, x2, 0x1F sw x2, 0(x1) + li x28, 5 + la x1, MMU_TABLE_0 + 0xA00 + la x2, ROM_SUPER_0 + srli x2, x2, 2 + ori x2, x2, 0x1F + sw x2, 0(x1) + + la x1, MMU_TABLE_0 srli x1, x1, 12 li x2, 0x80000000 @@ -91,7 +100,7 @@ test5: //setup MMU csrw satp, x1 -test6: //read through MMU ! +test6: //read through MMU li x28, 6 li x1, 0x9000A008 li x2, 0x4B4A4948 @@ -100,6 +109,49 @@ test6: //read through MMU ! +test7: //write-read through MMU + li x28, 7 + li x1, 0x9000A360 + li x2, 0xAAEE0001 + sw x2, 0(x1) + lw x1, 0(x1) + bne x1, x2, fail + + +test8: //read through MMU super page + li x28, 8 + la x1, ROM_7 + 0x20000004 + li x2, 0x77767574 + lw x1, 0(x1) + bne x1, x2, fail + + + +test9: //write-read through MMU super page + li x28, 9 + li x1, 0xA000A360 + li x2, 0xAAEE0002 + sw x2, 0(x1) + lw x1, 0(x1) + bne x1, x2, fail + + + +test10: //check previously written value without the MMU + li x28, 10 + csrwi satp, 0 + + la x1, ROM_4 + 0x360 + li x2, 0xAAEE0001 + lw x1, 0(x1) + bne x1, x2, fail + + + la x1, ROM_SUPER_0 + 0xA360 + li x2, 0xAAEE0002 + lw x1, 0(x1) + bne x1, x2, fail + @@ -206,4 +258,19 @@ ROM_7: .word 0x7B7A7978 .word 0x7F7E7D7C +/* +.align 22 +ROM_SUPER_0: +.word 0x83828180 +.word 0x87868584 +.word 0x8B8A8988 +.word 0x8F8E8D8C + +.align 12 +ROM_SUPER_1: +.word 0x93929190 +.word 0x97969594 +.word 0x9B9A9998 +.word 0x9F9E9D9C*/ + diff --git a/src/test/cpp/raw/mmu/src/ld b/src/test/cpp/raw/mmu/src/ld index e60e987d..93d8de8e 100644 --- a/src/test/cpp/raw/mmu/src/ld +++ b/src/test/cpp/raw/mmu/src/ld @@ -1,7 +1,7 @@ OUTPUT_ARCH( "riscv" ) MEMORY { - onChipRam (W!RX)/*(RX)*/ : ORIGIN = 0x80000000, LENGTH = 1M + onChipRam (W!RX)/*(RX)*/ : ORIGIN = 0x80000000, LENGTH = 128K } SECTIONS diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 07b44294..bf17f42c 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -324,6 +324,11 @@ public: uint32_t _dummy : 5; uint32_t ppn : 22; }; + struct __attribute__((packed)){ + uint32_t _dummyX : 10; + uint32_t ppn0 : 10; + uint32_t ppn1 : 12; + }; }; @@ -377,17 +382,20 @@ public: Tlb tlb; dRead((satp.ppn << 12) | ((v >> 22) << 2), 4, &tlb.raw); if(!tlb.v) return true; + bool superPage = true; if(!tlb.x && !tlb.r && !tlb.w){ dRead((tlb.ppn << 12) | (((v >> 12) & 0x3FF) << 2), 4, &tlb.raw); if(!tlb.v) return true; + superPage = false; } if(!tlb.u && privilege == 0) return true; + if(superPage && tlb.ppn0 != 0) return true; switch(kind){ case READ: if(!tlb.r) return true; break; case WRITE: if(!tlb.w) return true; break; case EXECUTE: if(!tlb.x) return true; break; } - *p = (tlb.ppn << 12) | (v & 0xFFF); + *p = (tlb.ppn1 << 22) | (superPage ? v & 0x3FF000 : tlb.ppn0 << 12) | (v & 0xFFF); } return false; } From e4cdc2397af2a8373ee74ba5136f3382ef0e2670 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 22 Mar 2019 14:52:49 +0100 Subject: [PATCH 060/951] MMU pass all test, need to and SUM and MXR and it's all ok --- src/main/scala/vexriscv/Pipeline.scala | 2 +- src/main/scala/vexriscv/Stage.scala | 3 + .../scala/vexriscv/plugin/CsrPlugin.scala | 18 +- .../vexriscv/plugin/DBusSimplePlugin.scala | 3 +- .../vexriscv/plugin/IBusSimplePlugin.scala | 4 +- src/test/cpp/raw/mmu/build/mmu.asm | 576 +++++++++--------- src/test/cpp/raw/mmu/build/mmu.hex | 162 ++--- src/test/cpp/raw/mmu/src/crt.S | 147 ++++- src/test/cpp/regression/main.cpp | 8 +- 9 files changed, 517 insertions(+), 406 deletions(-) diff --git a/src/main/scala/vexriscv/Pipeline.scala b/src/main/scala/vexriscv/Pipeline.scala index 9a518bd6..91c5c1f0 100644 --- a/src/main/scala/vexriscv/Pipeline.scala +++ b/src/main/scala/vexriscv/Pipeline.scala @@ -119,7 +119,7 @@ trait Pipeline { inputDefault := stage.inserts(key) } else { val stageBefore = stages(stageIndex - 1) - inputDefault := RegNextWhen(stageBefore.output(key), !stage.arbitration.isStuck).setName(s"${stageBefore.getName()}_to_${stage.getName()}_${key.getName()}") + inputDefault := RegNextWhen(stageBefore.output(key), stage.dontSample.getOrElse(key, Nil).foldLeft(!stage.arbitration.isStuck)(_ && !_)).setName(s"${stageBefore.getName()}_to_${stage.getName()}_${key.getName()}") } } } diff --git a/src/main/scala/vexriscv/Stage.scala b/src/main/scala/vexriscv/Stage.scala index d54127c1..504b0d36 100644 --- a/src/main/scala/vexriscv/Stage.scala +++ b/src/main/scala/vexriscv/Stage.scala @@ -4,6 +4,7 @@ import spinal.core._ import spinal.lib._ import scala.collection.mutable +import scala.collection.mutable.ArrayBuffer class Stageable[T <: Data](_dataType : => T) extends HardType[T](_dataType) with Nameable{ @@ -68,6 +69,8 @@ class Stage() extends Area{ val inputsDefault = mutable.HashMap[Stageable[Data],Data]() val outputsDefault = mutable.HashMap[Stageable[Data],Data]() + val dontSample = mutable.HashMap[Stageable[_], ArrayBuffer[Bool]]() + def inputInit[T <: BaseType](stageable : Stageable[T],initValue : T) = Component.current.addPrePopTask(() => inputsDefault(stageable.asInstanceOf[Stageable[Data]]).asInstanceOf[T].getDrivingReg.init(initValue)) } \ No newline at end of file diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index fc906f2a..118c3bf9 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -672,6 +672,9 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception when(exceptionValidsRegs.orR){ fetcher.haltIt() } + + //Avoid the PC register of the last stage to change durring an exception handleing (Used to fill Xepc) + stages.last.dontSample.getOrElseUpdate(PC, ArrayBuffer[Bool]()) += exceptionValids.last } else null @@ -744,18 +747,6 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception trapCause := exceptionPortCtrl.exceptionContext.code } - when(exception || interruptJump){ - switch(privilege){ - if(supervisorGen) is(1) { - sepc := mepcCaptureStage.input(PC) - } - is(3){ - mepc := mepcCaptureStage.input(PC) - } - } - } - - val xtvec = Xtvec().assignDontCare() switch(targetPrivilege){ if(supervisorGen) is(1) { xtvec := supervisorCsr.stvec } @@ -768,6 +759,7 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception beforeLastStage.arbitration.flushAll := True privilege := targetPrivilege + switch(targetPrivilege){ if(supervisorGen) is(1) { sstatus.SIE := False @@ -775,6 +767,7 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception sstatus.SPP := privilege(0 downto 0) scause.interrupt := !hadException scause.exceptionCode := trapCause + sepc := mepcCaptureStage.input(PC) if (exceptionPortCtrl != null) { stval := exceptionPortCtrl.exceptionContext.badAddr } @@ -786,6 +779,7 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception mstatus.MPP := privilege mcause.interrupt := !hadException mcause.exceptionCode := trapCause + mepc := mepcCaptureStage.input(PC) if(exceptionPortCtrl != null) { mtval := exceptionPortCtrl.exceptionContext.badAddr } diff --git a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala index 225644ae..d3d145d7 100644 --- a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala @@ -377,6 +377,8 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, memoryExceptionPort.valid := True memoryExceptionPort.code := (input(INSTRUCTION)(5) ? U(15) | U(13)).resized } + + arbitration.flushAll setWhen(redoBranch.valid) } when(!(arbitration.isValid && input(MEMORY_ENABLE) && (Bool(cmdStage != rspStage) || !arbitration.isStuckByOthers))){ @@ -384,7 +386,6 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, if(memoryTranslatorPortConfig != null) redoBranch.valid := False } - arbitration.flushAll setWhen(redoBranch.valid) } diff --git a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala index f87a197e..ab226c8e 100644 --- a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala @@ -303,9 +303,9 @@ class IBusSimplePlugin(resetVector : BigInt, redoRequired setWhen( stages.last.input.valid && mmu.joinCtx.refilling) redoBranch.valid := redoRequired && iBusRsp.readyForError redoBranch.payload := stages.last.input.payload + decode.arbitration.flushAll setWhen(redoBranch.valid) } - decode.arbitration.flushAll setWhen(redoBranch.valid) if(catchSomething){ decodeExceptionPort.code.assignDontCare() @@ -322,7 +322,7 @@ class IBusSimplePlugin(resetVector : BigInt, exceptionDetected := True } } - decodeExceptionPort.valid := exceptionDetected && iBusRsp.readyForError + decodeExceptionPort.valid := exceptionDetected && iBusRsp.readyForError && !fetcherHalt } } } diff --git a/src/test/cpp/raw/mmu/build/mmu.asm b/src/test/cpp/raw/mmu/build/mmu.asm index 198f6f3d..fc8a3308 100644 --- a/src/test/cpp/raw/mmu/build/mmu.asm +++ b/src/test/cpp/raw/mmu/build/mmu.asm @@ -4,295 +4,317 @@ build/mmu.elf: file format elf32-littleriscv Disassembly of section .crt_section: -80000000 : -80000000: 0280006f j 80000028 <_start> -80000004: 00000013 nop -80000008: 00000013 nop -8000000c: 00000013 nop -80000010: 00000013 nop -80000014: 00000013 nop -80000018: 00000013 nop -8000001c: 00000013 nop +80000000 <_start>: +80000000: 00000e93 li t4,0 +80000004: 00000097 auipc ra,0x0 +80000008: 3e808093 addi ra,ra,1000 # 800003ec +8000000c: 30509073 csrw mtvec,ra -80000020 : -80000020: 1f80006f j 80000218 -80000024: 30200073 mret +80000010 : +80000010: 00100e13 li t3,1 +80000014: 00007097 auipc ra,0x7 +80000018: fec08093 addi ra,ra,-20 # 80007000 +8000001c: 27262137 lui sp,0x27262 +80000020: 52410113 addi sp,sp,1316 # 27262524 <_start-0x58d9dadc> +80000024: 0040a083 lw ra,4(ra) +80000028: 38209e63 bne ra,sp,800003c4 -80000028 <_start>: -80000028: 00000097 auipc ra,0x0 -8000002c: 1f008093 addi ra,ra,496 # 80000218 -80000030: 30509073 csrw mtvec,ra -80000034: 10509073 csrw stvec,ra +8000002c : +8000002c: 00200e13 li t3,2 +80000030: 00000097 auipc ra,0x0 +80000034: 02008093 addi ra,ra,32 # 80000050 +80000038: 34109073 csrw mepc,ra +8000003c: 000020b7 lui ra,0x2 +80000040: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800> +80000044: 30009073 csrw mstatus,ra +80000048: 30200073 mret +8000004c: 3780006f j 800003c4 -80000038 : -80000038: 00100e13 li t3,1 -8000003c: 00007097 auipc ra,0x7 -80000040: fc408093 addi ra,ra,-60 # 80007000 -80000044: 27262137 lui sp,0x27262 -80000048: 52410113 addi sp,sp,1316 # 27262524 -8000004c: 0040a083 lw ra,4(ra) -80000050: 1c209463 bne ra,sp,80000218 +80000050 : +80000050: 00300e13 li t3,3 +80000054: 000010b7 lui ra,0x1 +80000058: 80008093 addi ra,ra,-2048 # 800 <_start-0x7ffff800> +8000005c: 30009073 csrw mstatus,ra +80000060: 00000097 auipc ra,0x0 +80000064: 01408093 addi ra,ra,20 # 80000074 +80000068: 34109073 csrw mepc,ra +8000006c: 30200073 mret +80000070: 3540006f j 800003c4 -80000054 : -80000054: 00200e13 li t3,2 -80000058: 00000097 auipc ra,0x0 -8000005c: 02008093 addi ra,ra,32 # 80000078 -80000060: 34109073 csrw mepc,ra -80000064: 000020b7 lui ra,0x2 -80000068: 80008093 addi ra,ra,-2048 # 1800 -8000006c: 30009073 csrw mstatus,ra -80000070: 30200073 mret -80000074: 1a40006f j 80000218 +80000074 : +80000074: 00400e13 li t3,4 +80000078: 00008097 auipc ra,0x8 +8000007c: f8808093 addi ra,ra,-120 # 80008000 +80000080: 37363137 lui sp,0x37363 +80000084: 53410113 addi sp,sp,1332 # 37363534 <_start-0x48c9cacc> +80000088: 0040a083 lw ra,4(ra) +8000008c: 32209c63 bne ra,sp,800003c4 -80000078 : -80000078: 00300e13 li t3,3 -8000007c: 000010b7 lui ra,0x1 -80000080: 80008093 addi ra,ra,-2048 # 800 -80000084: 30009073 csrw mstatus,ra -80000088: 00000097 auipc ra,0x0 -8000008c: 01408093 addi ra,ra,20 # 8000009c -80000090: 34109073 csrw mepc,ra -80000094: 30200073 mret -80000098: 1800006f j 80000218 +80000090 : +80000090: 00500e13 li t3,5 +80000094: 00001097 auipc ra,0x1 +80000098: 76c08093 addi ra,ra,1900 # 80001800 +8000009c: 00002117 auipc sp,0x2 +800000a0: f6410113 addi sp,sp,-156 # 80002000 +800000a4: 00215113 srli sp,sp,0x2 +800000a8: 01116113 ori sp,sp,17 +800000ac: 0020a023 sw sp,0(ra) +800000b0: 00002097 auipc ra,0x2 +800000b4: f5008093 addi ra,ra,-176 # 80002000 +800000b8: 80000137 lui sp,0x80000 +800000bc: 00215113 srli sp,sp,0x2 +800000c0: 01f16113 ori sp,sp,31 +800000c4: 0020a023 sw sp,0(ra) +800000c8: 00500e13 li t3,5 +800000cc: 00002097 auipc ra,0x2 +800000d0: 83408093 addi ra,ra,-1996 # 80001900 +800000d4: 00003117 auipc sp,0x3 +800000d8: f2c10113 addi sp,sp,-212 # 80003000 +800000dc: 00215113 srli sp,sp,0x2 +800000e0: 01116113 ori sp,sp,17 +800000e4: 0020a023 sw sp,0(ra) +800000e8: 00003097 auipc ra,0x3 +800000ec: f4008093 addi ra,ra,-192 # 80003028 +800000f0: 00009117 auipc sp,0x9 +800000f4: f1010113 addi sp,sp,-240 # 80009000 +800000f8: 00215113 srli sp,sp,0x2 +800000fc: 01f16113 ori sp,sp,31 +80000100: 0020a023 sw sp,0(ra) +80000104: 00003097 auipc ra,0x3 +80000108: f3c08093 addi ra,ra,-196 # 80003040 +8000010c: 0000a117 auipc sp,0xa +80000110: ef410113 addi sp,sp,-268 # 8000a000 +80000114: 00215113 srli sp,sp,0x2 +80000118: 01316113 ori sp,sp,19 +8000011c: 0020a023 sw sp,0(ra) +80000120: 00003097 auipc ra,0x3 +80000124: f2408093 addi ra,ra,-220 # 80003044 +80000128: 0000a117 auipc sp,0xa +8000012c: ed810113 addi sp,sp,-296 # 8000a000 +80000130: 00215113 srli sp,sp,0x2 +80000134: 01716113 ori sp,sp,23 +80000138: 0020a023 sw sp,0(ra) +8000013c: 00003097 auipc ra,0x3 +80000140: f0c08093 addi ra,ra,-244 # 80003048 +80000144: 0000a117 auipc sp,0xa +80000148: ebc10113 addi sp,sp,-324 # 8000a000 +8000014c: 00215113 srli sp,sp,0x2 +80000150: 01916113 ori sp,sp,25 +80000154: 0020a023 sw sp,0(ra) +80000158: 00003097 auipc ra,0x3 +8000015c: ef408093 addi ra,ra,-268 # 8000304c +80000160: 0000a117 auipc sp,0xa +80000164: ea010113 addi sp,sp,-352 # 8000a000 +80000168: 00215113 srli sp,sp,0x2 +8000016c: 01b16113 ori sp,sp,27 +80000170: 0020a023 sw sp,0(ra) +80000174: 00500e13 li t3,5 +80000178: 00002097 auipc ra,0x2 +8000017c: 88808093 addi ra,ra,-1912 # 80001a00 +80000180: 00000117 auipc sp,0x0 +80000184: e8010113 addi sp,sp,-384 # 80000000 <_start> +80000188: 00215113 srli sp,sp,0x2 +8000018c: 01f16113 ori sp,sp,31 +80000190: 0020a023 sw sp,0(ra) +80000194: 00500e13 li t3,5 +80000198: 00002097 auipc ra,0x2 +8000019c: 96808093 addi ra,ra,-1688 # 80001b00 +800001a0: 0000a023 sw zero,0(ra) +800001a4: 00001097 auipc ra,0x1 +800001a8: e5c08093 addi ra,ra,-420 # 80001000 +800001ac: 00c0d093 srli ra,ra,0xc +800001b0: 80000137 lui sp,0x80000 +800001b4: 0020e0b3 or ra,ra,sp +800001b8: 18009073 csrw satp,ra -8000009c : -8000009c: 00400e13 li t3,4 -800000a0: 00008097 auipc ra,0x8 -800000a4: f6008093 addi ra,ra,-160 # 80008000 -800000a8: 37363137 lui sp,0x37363 -800000ac: 53410113 addi sp,sp,1332 # 37363534 -800000b0: 0040a083 lw ra,4(ra) -800000b4: 16209263 bne ra,sp,80000218 +800001bc : +800001bc: 00600e13 li t3,6 +800001c0: 9000a0b7 lui ra,0x9000a +800001c4: 00808093 addi ra,ra,8 # 9000a008 +800001c8: 4b4a5137 lui sp,0x4b4a5 +800001cc: 94810113 addi sp,sp,-1720 # 4b4a4948 <_start-0x34b5b6b8> +800001d0: 0000a083 lw ra,0(ra) +800001d4: 1e209863 bne ra,sp,800003c4 -800000b8 : -800000b8: 00500e13 li t3,5 -800000bc: 00001097 auipc ra,0x1 -800000c0: 74408093 addi ra,ra,1860 # 80001800 -800000c4: 00002117 auipc sp,0x2 -800000c8: f3c10113 addi sp,sp,-196 # 80002000 -800000cc: 00215113 srli sp,sp,0x2 -800000d0: 01116113 ori sp,sp,17 -800000d4: 0020a023 sw sp,0(ra) -800000d8: 00002097 auipc ra,0x2 -800000dc: f2808093 addi ra,ra,-216 # 80002000 -800000e0: 80000137 lui sp,0x80000 -800000e4: 00215113 srli sp,sp,0x2 -800000e8: 01f16113 ori sp,sp,31 -800000ec: 0020a023 sw sp,0(ra) -800000f0: 00500e13 li t3,5 -800000f4: 00002097 auipc ra,0x2 -800000f8: 80c08093 addi ra,ra,-2036 # 80001900 -800000fc: 00003117 auipc sp,0x3 -80000100: f0410113 addi sp,sp,-252 # 80003000 -80000104: 00215113 srli sp,sp,0x2 -80000108: 01116113 ori sp,sp,17 -8000010c: 0020a023 sw sp,0(ra) -80000110: 00003097 auipc ra,0x3 -80000114: f1808093 addi ra,ra,-232 # 80003028 -80000118: 00009117 auipc sp,0x9 -8000011c: ee810113 addi sp,sp,-280 # 80009000 -80000120: 00215113 srli sp,sp,0x2 -80000124: 01f16113 ori sp,sp,31 -80000128: 0020a023 sw sp,0(ra) -8000012c: 00500e13 li t3,5 -80000130: 00002097 auipc ra,0x2 -80000134: 8d008093 addi ra,ra,-1840 # 80001a00 -80000138: 00000117 auipc sp,0x0 -8000013c: ec810113 addi sp,sp,-312 # 80000000 -80000140: 00215113 srli sp,sp,0x2 -80000144: 01f16113 ori sp,sp,31 -80000148: 0020a023 sw sp,0(ra) -8000014c: 00001097 auipc ra,0x1 -80000150: eb408093 addi ra,ra,-332 # 80001000 -80000154: 00c0d093 srli ra,ra,0xc -80000158: 80000137 lui sp,0x80000 -8000015c: 0020e0b3 or ra,ra,sp -80000160: 18009073 csrw satp,ra +800001d8 : +800001d8: 00700e13 li t3,7 +800001dc: 9000a0b7 lui ra,0x9000a +800001e0: 36008093 addi ra,ra,864 # 9000a360 +800001e4: aaee0137 lui sp,0xaaee0 +800001e8: 00110113 addi sp,sp,1 # aaee0001 +800001ec: 0020a023 sw sp,0(ra) +800001f0: 0000a083 lw ra,0(ra) +800001f4: 1c209863 bne ra,sp,800003c4 -80000164 : -80000164: 00600e13 li t3,6 -80000168: 9000a0b7 lui ra,0x9000a -8000016c: 00808093 addi ra,ra,8 # 9000a008 -80000170: 4b4a5137 lui sp,0x4b4a5 -80000174: 94810113 addi sp,sp,-1720 # 4b4a4948 -80000178: 0000a083 lw ra,0(ra) -8000017c: 08209e63 bne ra,sp,80000218 - -80000180 : -80000180: 00700e13 li t3,7 -80000184: 9000a0b7 lui ra,0x9000a -80000188: 36008093 addi ra,ra,864 # 9000a360 -8000018c: aaee0137 lui sp,0xaaee0 -80000190: 00110113 addi sp,sp,1 # aaee0001 -80000194: 0020a023 sw sp,0(ra) -80000198: 0000a083 lw ra,0(ra) -8000019c: 06209e63 bne ra,sp,80000218 - -800001a0 : -800001a0: 00800e13 li t3,8 -800001a4: 2000c097 auipc ra,0x2000c -800001a8: e6008093 addi ra,ra,-416 # a000c004 -800001ac: 77767137 lui sp,0x77767 -800001b0: 57410113 addi sp,sp,1396 # 77767574 -800001b4: 0000a083 lw ra,0(ra) -800001b8: 06209063 bne ra,sp,80000218 - -800001bc : -800001bc: 00900e13 li t3,9 -800001c0: a000a0b7 lui ra,0xa000a -800001c4: 36008093 addi ra,ra,864 # a000a360 -800001c8: aaee0137 lui sp,0xaaee0 -800001cc: 00210113 addi sp,sp,2 # aaee0002 -800001d0: 0020a023 sw sp,0(ra) -800001d4: 0000a083 lw ra,0(ra) -800001d8: 04209063 bne ra,sp,80000218 - -800001dc : -800001dc: 00a00e13 li t3,10 -800001e0: 18005073 csrwi satp,0 -800001e4: 00009097 auipc ra,0x9 -800001e8: 17c08093 addi ra,ra,380 # 80009360 -800001ec: aaee0137 lui sp,0xaaee0 -800001f0: 00110113 addi sp,sp,1 # aaee0001 -800001f4: 0000a083 lw ra,0(ra) -800001f8: 02209063 bne ra,sp,80000218 -800001fc: 0000a097 auipc ra,0xa -80000200: 16408093 addi ra,ra,356 # 8000a360 -80000204: aaee0137 lui sp,0xaaee0 -80000208: 00210113 addi sp,sp,2 # aaee0002 +800001f8 : +800001f8: 00800e13 li t3,8 +800001fc: 2000c097 auipc ra,0x2000c +80000200: e0808093 addi ra,ra,-504 # a000c004 +80000204: 77767137 lui sp,0x77767 +80000208: 57410113 addi sp,sp,1396 # 77767574 <_start-0x8898a8c> 8000020c: 0000a083 lw ra,0(ra) -80000210: 00209463 bne ra,sp,80000218 -80000214: 0180006f j 8000022c +80000210: 1a209a63 bne ra,sp,800003c4 -80000218 : -80000218: 18005073 csrwi satp,0 -8000021c: 0040006f j 80000220 +80000214 : +80000214: 00900e13 li t3,9 +80000218: a000a0b7 lui ra,0xa000a +8000021c: 36008093 addi ra,ra,864 # a000a360 +80000220: aaee0137 lui sp,0xaaee0 +80000224: 00210113 addi sp,sp,2 # aaee0002 +80000228: 0020a023 sw sp,0(ra) +8000022c: 0000a083 lw ra,0(ra) +80000230: 18209a63 bne ra,sp,800003c4 -80000220 : -80000220: f0100137 lui sp,0xf0100 -80000224: f2410113 addi sp,sp,-220 # f00fff24 -80000228: 01c12023 sw t3,0(sp) +80000234 : +80000234: 00a00e13 li t3,10 +80000238: 18005073 csrwi satp,0 +8000023c: 00009097 auipc ra,0x9 +80000240: 12408093 addi ra,ra,292 # 80009360 +80000244: aaee0137 lui sp,0xaaee0 +80000248: 00110113 addi sp,sp,1 # aaee0001 +8000024c: 0000a083 lw ra,0(ra) +80000250: 16209a63 bne ra,sp,800003c4 -8000022c : -8000022c: 18005073 csrwi satp,0 -80000230: 0040006f j 80000234 +80000254 : +80000254: 00b00e13 li t3,11 +80000258: 0000a097 auipc ra,0xa +8000025c: 10808093 addi ra,ra,264 # 8000a360 +80000260: aaee0137 lui sp,0xaaee0 +80000264: 00210113 addi sp,sp,2 # aaee0002 +80000268: 0000a083 lw ra,0(ra) +8000026c: 14209c63 bne ra,sp,800003c4 +80000270: 00001097 auipc ra,0x1 +80000274: d9008093 addi ra,ra,-624 # 80001000 +80000278: 00c0d093 srli ra,ra,0xc +8000027c: 80000137 lui sp,0x80000 +80000280: 0020e0b3 or ra,ra,sp +80000284: 18009073 csrw satp,ra -80000234 : -80000234: f0100137 lui sp,0xf0100 -80000238: f2010113 addi sp,sp,-224 # f00fff20 -8000023c: 00012023 sw zero,0(sp) -80000240: 00000013 nop -80000244: 00000013 nop -80000248: 00000013 nop -8000024c: 00000013 nop -80000250: 00000013 nop -80000254: 00000013 nop -80000258: 00000013 nop -8000025c: 00000013 nop -80000260: 00000013 nop -80000264: 00000013 nop -80000268: 00000013 nop -8000026c: 00000013 nop -80000270: 00000013 nop -80000274: 00000013 nop -80000278: 00000013 nop -8000027c: 00000013 nop -80000280: 00000013 nop -80000284: 00000013 nop -80000288: 00000013 nop -8000028c: 00000013 nop -80000290: 00000013 nop -80000294: 00000013 nop -80000298: 00000013 nop -8000029c: 00000013 nop -800002a0: 00000013 nop -800002a4: 00000013 nop -800002a8: 00000013 nop -800002ac: 00000013 nop -800002b0: 00000013 nop -800002b4: 00000013 nop -800002b8: 00000013 nop -800002bc: 00000013 nop -800002c0: 00000013 nop -800002c4: 00000013 nop -800002c8: 00000013 nop -800002cc: 00000013 nop -800002d0: 00000013 nop -800002d4: 00000013 nop -800002d8: 00000013 nop -800002dc: 00000013 nop -800002e0: 00000013 nop -800002e4: 00000013 nop -800002e8: 00000013 nop -800002ec: 00000013 nop -800002f0: 00000013 nop -800002f4: 00000013 nop -800002f8: 00000013 nop -800002fc: 00000013 nop -80000300: 00000013 nop -80000304: 00000013 nop -80000308: 00000013 nop -8000030c: 00000013 nop -80000310: 00000013 nop -80000314: 00000013 nop -80000318: 00000013 nop -8000031c: 00000013 nop -80000320: 00000013 nop -80000324: 00000013 nop -80000328: 00000013 nop -8000032c: 00000013 nop -80000330: 00000013 nop -80000334: 00000013 nop -80000338: 00000013 nop -8000033c: 00000013 nop -80000340: 00000013 nop -80000344: 00000013 nop -80000348: 00000013 nop -8000034c: 00000013 nop -80000350: 00000013 nop -80000354: 00000013 nop -80000358: 00000013 nop -8000035c: 00000013 nop -80000360: 00000013 nop -80000364: 00000013 nop -80000368: 00000013 nop -8000036c: 00000013 nop -80000370: 00000013 nop -80000374: 00000013 nop -80000378: 00000013 nop -8000037c: 00000013 nop -80000380: 00000013 nop -80000384: 00000013 nop -80000388: 00000013 nop -8000038c: 00000013 nop -80000390: 00000013 nop -80000394: 00000013 nop -80000398: 00000013 nop -8000039c: 00000013 nop -800003a0: 00000013 nop -800003a4: 00000013 nop -800003a8: 00000013 nop -800003ac: 00000013 nop -800003b0: 00000013 nop -800003b4: 00000013 nop -800003b8: 00000013 nop -800003bc: 00000013 nop -800003c0: 00000013 nop -800003c4: 00000013 nop -800003c8: 00000013 nop -800003cc: 00000013 nop -800003d0: 00000013 nop -800003d4: 00000013 nop -800003d8: 00000013 nop -800003dc: 00000013 nop -800003e0: 00000013 nop -800003e4: 00000013 nop -800003e8: 00000013 nop -800003ec: 00000013 nop -800003f0: 00000013 nop -800003f4: 00000013 nop -800003f8: 00000013 nop -800003fc: 00000013 nop +80000288 : +80000288: 00c00e13 li t3,12 +8000028c: 00100e93 li t4,1 +80000290: 00000f17 auipc t5,0x0 +80000294: 010f0f13 addi t5,t5,16 # 800002a0 +80000298: 00000073 ecall +8000029c: 1280006f j 800003c4 + +800002a0 : +800002a0: 00d00e13 li t3,13 +800002a4: 00000f17 auipc t5,0x0 +800002a8: 014f0f13 addi t5,t5,20 # 800002b8 +800002ac: b00000b7 lui ra,0xb0000 +800002b0: 0080a083 lw ra,8(ra) # b0000008 +800002b4: 1100006f j 800003c4 + +800002b8 : +800002b8: 00e00e13 li t3,14 +800002bc: 00000f17 auipc t5,0x0 +800002c0: 014f0f13 addi t5,t5,20 # 800002d0 +800002c4: b00000b7 lui ra,0xb0000 +800002c8: 0010a423 sw ra,8(ra) # b0000008 +800002cc: 0f80006f j 800003c4 + +800002d0 : +800002d0: 00f00e13 li t3,15 +800002d4: 00000f17 auipc t5,0x0 +800002d8: 014f0f13 addi t5,t5,20 # 800002e8 +800002dc: b00000b7 lui ra,0xb0000 +800002e0: 00008067 ret +800002e4: 0e00006f j 800003c4 + +800002e8 : +800002e8: 01000e13 li t3,16 +800002ec: 00000e93 li t4,0 +800002f0: 900100b7 lui ra,0x90010 +800002f4: 00808093 addi ra,ra,8 # 90010008 +800002f8: 5b5a6137 lui sp,0x5b5a6 +800002fc: 95810113 addi sp,sp,-1704 # 5b5a5958 <_start-0x24a5a6a8> +80000300: 0000a083 lw ra,0(ra) +80000304: 0c209063 bne ra,sp,800003c4 +80000308: 900110b7 lui ra,0x90011 +8000030c: 00808093 addi ra,ra,8 # 90011008 +80000310: 5b5a6137 lui sp,0x5b5a6 +80000314: 95810113 addi sp,sp,-1704 # 5b5a5958 <_start-0x24a5a6a8> +80000318: 0000a083 lw ra,0(ra) +8000031c: 0a209463 bne ra,sp,800003c4 +80000320: 900130b7 lui ra,0x90013 +80000324: 00808093 addi ra,ra,8 # 90013008 +80000328: 5b5a6137 lui sp,0x5b5a6 +8000032c: 95810113 addi sp,sp,-1704 # 5b5a5958 <_start-0x24a5a6a8> +80000330: 0000a083 lw ra,0(ra) +80000334: 08209863 bne ra,sp,800003c4 + +80000338 : +80000338: 01100e13 li t3,17 +8000033c: 900110b7 lui ra,0x90011 +80000340: 36008093 addi ra,ra,864 # 90011360 +80000344: aaee0137 lui sp,0xaaee0 +80000348: 00310113 addi sp,sp,3 # aaee0003 +8000034c: 0020a023 sw sp,0(ra) +80000350: 0000a083 lw ra,0(ra) +80000354: 06209863 bne ra,sp,800003c4 + +80000358 : +80000358: 01200e13 li t3,18 +8000035c: 00000097 auipc ra,0x0 +80000360: 01808093 addi ra,ra,24 # 80000374 +80000364: 90012137 lui sp,0x90012 +80000368: 01010113 addi sp,sp,16 # 90012010 +8000036c: 00010067 jr sp +80000370: 0540006f j 800003c4 + +80000374 : +80000374: 00100e93 li t4,1 +80000378: 00000f17 auipc t5,0x0 +8000037c: 018f0f13 addi t5,t5,24 # 80000390 +80000380: 900120b7 lui ra,0x90012 +80000384: 01008093 addi ra,ra,16 # 90012010 +80000388: 0000a083 lw ra,0(ra) +8000038c: 0380006f j 800003c4 + +80000390 : +80000390: 00000f17 auipc t5,0x0 +80000394: 018f0f13 addi t5,t5,24 # 800003a8 +80000398: 900130b7 lui ra,0x90013 +8000039c: 01008093 addi ra,ra,16 # 90013010 +800003a0: 0010a023 sw ra,0(ra) +800003a4: 0200006f j 800003c4 + +800003a8 : +800003a8: 00000f17 auipc t5,0x0 +800003ac: 018f0f13 addi t5,t5,24 # 800003c0 +800003b0: 900110b7 lui ra,0x90011 +800003b4: 01008093 addi ra,ra,16 # 90011010 +800003b8: 00008067 ret +800003bc: 0080006f j 800003c4 + +800003c0 : +800003c0: 0180006f j 800003d8 + +800003c4 : +800003c4: 18005073 csrwi satp,0 +800003c8: 0040006f j 800003cc + +800003cc : +800003cc: f0100137 lui sp,0xf0100 +800003d0: f2410113 addi sp,sp,-220 # f00fff24 +800003d4: 01c12023 sw t3,0(sp) + +800003d8 : +800003d8: 18005073 csrwi satp,0 +800003dc: 0040006f j 800003e0 + +800003e0 : +800003e0: f0100137 lui sp,0xf0100 +800003e4: f2010113 addi sp,sp,-224 # f00fff20 +800003e8: 00012023 sw zero,0(sp) + +800003ec : +800003ec: fc0e8ce3 beqz t4,800003c4 +800003f0: 342020f3 csrr ra,mcause +800003f4: 341020f3 csrr ra,mepc +800003f8: 341f1073 csrw mepc,t5 +800003fc: 30200073 mret 80000400: 00000013 nop 80000404: 00000013 nop 80000408: 00000013 nop @@ -10329,7 +10351,7 @@ Disassembly of section .crt_section: 8000a00a: 5b5a lw s6,180(sp) 8000a00c: 5d5c lw a5,60(a0) 8000a00e: 5f5e lw t5,244(sp) -8000a010: 00000013 nop +8000a010: 00008067 ret 8000a014: 00000013 nop 8000a018: 00000013 nop 8000a01c: 00000013 nop diff --git a/src/test/cpp/raw/mmu/build/mmu.hex b/src/test/cpp/raw/mmu/build/mmu.hex index 257d6c67..affa9ad7 100644 --- a/src/test/cpp/raw/mmu/build/mmu.hex +++ b/src/test/cpp/raw/mmu/build/mmu.hex @@ -1,68 +1,68 @@ :0200000480007A -:100000006F008002130000001300000013000000C6 -:100010001300000013000000130000001300000094 -:100020006F00801F73002030970000009380001F36 -:100030007390503073905010130E100097700000A2 -:10004000938040FC372126271301415283A04000B2 -:100050006394201C130E2000970000009380000280 -:1000600073901034B72000009380008073900030AC -:10007000730020306F00401A130E3000B7100000DC -:1000800093800080739000309700000093804001BF -:1000900073901034730020306F000018130E40006E -:1000A00097800000938000F63731363713014153B3 -:1000B00083A0400063922016130E5000971000009A -:1000C00093804074172100001301C1F313512100E4 -:1000D0001361110123A0200097200000938080F27B -:1000E00037010080135121001361F10123A020008A -:1000F000130E5000972000009380C080173100003D -:10010000130141F0135121001361110123A02000BC -:1001100097300000938080F117910000130181EE69 -:10012000135121001361F10123A02000130E500090 -:10013000972000009380008D17010000130181ECCF -:10014000135121001361F10123A02000971000003A -:10015000938040EB93D0C00037010080B3E02000D3 -:1001600073900018130E6000B7A000909380800079 -:1001700037514A4B1301819483A00000639E2008ED -:10018000130E7000B7A00090938000363701EEAADE -:100190001301110023A0200083A00000639E20060D -:1001A000130E800097C00020938000E637717677A9 -:1001B0001301415783A0000063902006130E9000A6 -:1001C000B7A000A0938000363701EEAA13012100EA -:1001D00023A0200083A0000063902004130EA00041 -:1001E00073500018979000009380C0173701EEAA53 -:1001F0001301110083A000006390200297A000006B -:10020000938040163701EEAA1301210083A000005D -:10021000639420006F008001735000186F0040004D -:10022000370110F0130141F22320C101735000186F -:100230006F004000370110F0130101F2232001008C -:100240001300000013000000130000001300000062 -:100250001300000013000000130000001300000052 -:100260001300000013000000130000001300000042 -:100270001300000013000000130000001300000032 -:100280001300000013000000130000001300000022 -:100290001300000013000000130000001300000012 -:1002A0001300000013000000130000001300000002 -:1002B00013000000130000001300000013000000F2 -:1002C00013000000130000001300000013000000E2 -:1002D00013000000130000001300000013000000D2 -:1002E00013000000130000001300000013000000C2 -:1002F00013000000130000001300000013000000B2 -:1003000013000000130000001300000013000000A1 -:100310001300000013000000130000001300000091 -:100320001300000013000000130000001300000081 -:100330001300000013000000130000001300000071 -:100340001300000013000000130000001300000061 -:100350001300000013000000130000001300000051 -:100360001300000013000000130000001300000041 -:100370001300000013000000130000001300000031 -:100380001300000013000000130000001300000021 -:100390001300000013000000130000001300000011 -:1003A0001300000013000000130000001300000001 -:1003B00013000000130000001300000013000000F1 -:1003C00013000000130000001300000013000000E1 -:1003D00013000000130000001300000013000000D1 -:1003E00013000000130000001300000013000000C1 -:1003F00013000000130000001300000013000000B1 +:10000000930E0000970000009380803E7390503064 +:10001000130E1000977000009380C0FE3721262732 +:100020001301415283A04000639E2038130E20002C +:10003000970000009380000273901034B7200000F6 +:100040009380008073900030730020306F00803701 +:10005000130E3000B71000009380008073900030C2 +:10006000970000009380400173901034730020309B +:100070006F004035130E400097800000938080F899 +:10008000373136371301415383A04000639C20323F +:10009000130E5000971000009380C07617210000C7 +:1000A000130141F6135121001361110123A0200017 +:1000B00097200000938000F5370100801351210044 +:1000C0001361F10123A02000130E500097200000BF +:1000D00093804083173100001301C1F213512100B6 +:1000E0001361110123A0200097300000938000F4D9 +:1000F00017910000130101F1135121001361F10167 +:1001000023A02000973000009380C0F317A10000C7 +:10011000130141EF135121001361310123A020008D +:1001200097300000938040F217A10000130181ED89 +:10013000135121001361710123A0200097300000AA +:100140009380C0F017A100001301C1EB13512100EF +:100150001361910123A0200097300000938040EFAD +:1001600017A10000130101EA135121001361B1012D +:1001700023A02000130E5000972000009380808859 +:1001800017010000130101E8135121001361F1016F +:1001900023A02000130E500097200000938080962B +:1001A00023A00000971000009380C0E593D0C0000A +:1001B00037010080B3E0200073900018130E600038 +:1001C000B7A000909380800037514A4B130181946F +:1001D00083A000006398201E130E7000B7A000904B +:1001E000938000363701EEAA1301110023A02000EE +:1001F00083A000006398201C130E800097C000208D +:10020000938080E0377176771301415783A0000017 +:10021000639A201A130E9000B7A000A093800036B6 +:100220003701EEAA1301210023A0200083A00000C3 +:10023000639A2018130EA0007350001897900000C6 +:10024000938040123701EEAA1301110083A0000031 +:10025000639A2016130EB00097A0000093808010C0 +:100260003701EEAA1301210083A00000639C201433 +:1002700097100000938000D993D0C0003701008010 +:10028000B3E0200073900018130EC000930E10000E +:10029000170F0000130F0F01730000006F00801292 +:1002A000130ED000170F0000130F4F01B70000B05E +:1002B00083A080006F000011130EE000170F0000F4 +:1002C000130F4F01B70000B023A410006F00800F80 +:1002D000130EF000170F0000130F4F01B70000B00E +:1002E000678000006F00000E130E0001930E0000E7 +:1002F000B70001909380800037615A5B13018195AC +:1003000083A000006390200CB710019093808000C0 +:1003100037615A5B1301819583A000006394200A22 +:10032000B73001909380800037615A5B130181954B +:1003300083A0000063982008130E1001B7100190ED +:10034000938000363701EEAA1301310023A020006C +:1003500083A0000063982006130E20019700000080 +:100360009380800137210190130101016700010092 +:100370006F004005930E1000170F0000130F8F0140 +:10038000B72001909380000183A000006F008003DC +:10039000170F0000130F8F01B730019093800001F9 +:1003A00023A010006F000002170F0000130F8F0131 +:1003B000B710019093800001678000006F008000FB +:1003C0006F008001735000186F004000370110F07B +:1003D000130141F22320C101735000186F00400047 +:1003E000370110F0130101F223200100E38C0EFC11 +:1003F000F3202034F320103473101F3473002030A6 :1004000013000000130000001300000013000000A0 :100410001300000013000000130000001300000090 :100420001300000013000000130000001300000080 @@ -2560,7 +2560,7 @@ :109FE0001300000013000000130000001300000025 :109FF0001300000013000000130000001300000015 :10A00000505152535455565758595A5B5C5D5E5FD8 -:10A0100013000000130000001300000013000000F4 +:10A010006780000013000000130000001300000020 :10A0200013000000130000001300000013000000E4 :10A0300013000000130000001300000013000000D4 :10A0400013000000130000001300000013000000C4 @@ -3256,34 +3256,6 @@ :10CB600000000000000000000000000000000000C5 :10CB700000000000000000000000000000000000B5 :10CB800000000000000000000000000000000000A5 -:10CB90000000000000000000000000000000000095 -:10CBA0000000000000000000000000000000000085 -:10CBB0000000000000000000000000000000000075 -:10CBC0000000000000000000000000000000000065 -:10CBD0000000000000000000000000000000000055 -:10CBE0000000000000000000000000000000000045 -:10CBF0000000000000000000000000000000000035 -:10CC00000000000000000000000000000000000024 -:10CC10000000000000000000000000000000000014 -:10CC20000000000000000000000000000000000004 -:10CC300000000000000000000000000000000000F4 -:10CC400000000000000000000000000000000000E4 -:10CC500000000000000000000000000000000000D4 -:10CC600000000000000000000000000000000000C4 -:10CC700000000000000000000000000000000000B4 -:10CC800000000000000000000000000000000000A4 -:10CC90000000000000000000000000000000000094 -:10CCA0000000000000000000000000000000000084 -:10CCB0000000000000000000000000000000000074 -:10CCC0000000000000000000000000000000000064 -:10CCD0000000000000000000000000000000000054 -:10CCE0000000000000000000000000000000000044 -:10CCF0000000000000000000000000000000000034 -:10CD00000000000000000000000000000000000023 -:10CD10000000000000000000000000000000000013 -:10CD20000000000000000000000000000000000003 -:10CD300000000000000000000000000000000000F3 -:10CD400000000000000000000000000000000000E3 -:08CD50000000000000000000DB -:04000005800000284F +:04CB900000000000A1 +:040000058000000077 :00000001FF diff --git a/src/test/cpp/raw/mmu/src/crt.S b/src/test/cpp/raw/mmu/src/crt.S index a25ec57d..238aefcf 100644 --- a/src/test/cpp/raw/mmu/src/crt.S +++ b/src/test/cpp/raw/mmu/src/crt.S @@ -2,24 +2,10 @@ ROM_SUPER_0: - j _start - nop - nop - nop - nop - nop - nop - nop - -.global trap_entry -trap_entry: - j fail - mret - _start: - la x1, fail + li x29, 0 //Do not allow trap + la x1, trap csrw mtvec, x1 - csrw stvec, x1 test1: //test ram li x28, 1 @@ -85,6 +71,30 @@ test5: //setup MMU ori x2, x2, 0x1F sw x2, 0(x1) + la x1, MMU_TABLE_2 + 0x010*4 // Read Only + la x2, ROM_5 + srli x2, x2, 2 + ori x2, x2, 0x11 + (0x1 << 1) + sw x2, 0(x1) + + la x1, MMU_TABLE_2 + 0x011*4 // Read Write + la x2, ROM_5 + srli x2, x2, 2 + ori x2, x2, 0x11 + (0x3 << 1) + sw x2, 0(x1) + + la x1, MMU_TABLE_2 + 0x012*4 // Execute only + la x2, ROM_5 + srli x2, x2, 2 + ori x2, x2, 0x11 + (0x4 << 1) + sw x2, 0(x1) + + la x1, MMU_TABLE_2 + 0x013*4 //Read Execute + la x2, ROM_5 + srli x2, x2, 2 + ori x2, x2, 0x11 + (0x5 << 1) + sw x2, 0(x1) + li x28, 5 la x1, MMU_TABLE_0 + 0xA00 la x2, ROM_SUPER_0 @@ -92,6 +102,10 @@ test5: //setup MMU ori x2, x2, 0x1F sw x2, 0(x1) + li x28, 5 + la x1, MMU_TABLE_0 + 0xB00 + sw x0, 0(x1) + la x1, MMU_TABLE_0 srli x1, x1, 12 @@ -147,18 +161,111 @@ test10: //check previously written value without the MMU bne x1, x2, fail +test11: + li x28, 11 la x1, ROM_SUPER_0 + 0xA360 li x2, 0xAAEE0002 lw x1, 0(x1) bne x1, x2, fail + la x1, MMU_TABLE_0 + srli x1, x1, 12 + li x2, 0x80000000 + or x1, x1, x2 + csrw satp, x1 +test12: //Dummy trap + li x28, 12 + li x29, 1 //Allow trap + la x30, test13 // trap return address + ecall + j fail +test13: //Trap load page fault + li x28, 13 + la x30, test14 + li x1, 0xB0000000 + lw x1, 8(x1) + j fail +test14: //Trap store page fault + li x28, 14 + la x30, test15 + li x1, 0xB0000000 + sw x1, 8(x1) + j fail + + +test15: //Trap instruction fetch + li x28, 15 + la x30, test15_end + li x1, 0xB0000000 + jr x1 + j fail + +test15_end: + + +test16: //Test limited read access + li x28, 16 + li x29, 0 //disable trap + + li x1, 0x90010008 + li x2, 0x5B5A5958 + lw x1, 0(x1) + bne x1, x2, fail + + + li x1, 0x90011008 + li x2, 0x5B5A5958 + lw x1, 0(x1) + bne x1, x2, fail + + li x1, 0x90013008 + li x2, 0x5B5A5958 + lw x1, 0(x1) + bne x1, x2, fail + +test17: //Test limited write access + li x28, 17 + + li x1, 0x90011360 + li x2, 0xAAEE0003 + sw x2, 0(x1) + lw x1, 0(x1) + bne x1, x2, fail + +test18: //Test limited execute access + li x28, 18 + + la x1, test18_end + li x2, 0x90012010 + jr x2 + j fail +test18_end: + + +test19: //exception by access limitations + li x29, 1 //Allow trap + la x30, test19_readTrap + li x1, 0x90012010 + lw x1, 0(x1) + j fail +test19_readTrap: + la x30, test19_writeTrap + li x1, 0x90013010 + sw x1, 0(x1) + j fail +test19_writeTrap: + la x30, test19_executeTrap + li x1, 0x90011010 + jr x1 + j fail +test19_executeTrap: j pass @@ -178,6 +285,13 @@ passFence: sw x0, 0(x2) +trap: + beq x29, x0, fail + csrr x1, mcause + csrr x1, mepc + csrw mepc, x30 + mret + nop nop @@ -243,6 +357,7 @@ ROM_5: .word 0x57565554 .word 0x5B5A5958 .word 0x5F5E5D5C + jr x1 .align 12 ROM_6: diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index bf17f42c..39e1e397 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -724,7 +724,7 @@ public: pcWrite(sepc); }break; case 0x00000073:{ //ECALL - exception(0, 11); + exception(0, 8+privilege); }break; case 0x10500073:{ //WFI pcWrite(pc + 4); @@ -1343,7 +1343,11 @@ public: } if(riscvRefEnable) if(rfWriteValid != riscvRef.rfWriteValid || (rfWriteValid && (rfWriteAddress!= riscvRef.rfWriteAddress || rfWriteData!= riscvRef.rfWriteData))){ - cout << "regFile write missmatch at " << endl; + cout << "regFile write missmatch "; + if(rfWriteValid) cout << "REF: RF[" << riscvRef.rfWriteAddress << "] = 0x" << hex << riscvRef.rfWriteData << dec << " "; + if(rfWriteValid) cout << "RTL: RF[" << rfWriteAddress << "] = 0x" << hex << rfWriteData << dec << " "; + + cout << endl; fail(); } } From f7b793b7bfcee485e8d81ff900e87388729b10d9 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 22 Mar 2019 15:49:36 +0100 Subject: [PATCH 061/951] Add SSTATUS.SUM/MXR feature, need testing --- src/main/scala/vexriscv/Services.scala | 10 +- .../scala/vexriscv/plugin/CsrPlugin.scala | 5 +- .../vexriscv/plugin/DBusCachedPlugin.scala | 2 +- .../vexriscv/plugin/DBusSimplePlugin.scala | 2 +- .../vexriscv/plugin/IBusCachedPlugin.scala | 4 +- .../vexriscv/plugin/IBusSimplePlugin.scala | 2 +- .../scala/vexriscv/plugin/MmuPlugin.scala | 31 +- src/test/cpp/raw/mmu/build/mmu.asm | 360 +++++++++--------- src/test/cpp/raw/mmu/build/mmu.hex | 91 +++-- src/test/cpp/raw/mmu/src/crt.S | 2 + src/test/cpp/regression/main.cpp | 12 +- 11 files changed, 268 insertions(+), 253 deletions(-) diff --git a/src/main/scala/vexriscv/Services.scala b/src/main/scala/vexriscv/Services.scala index cf3cf0d1..fb2a29a0 100644 --- a/src/main/scala/vexriscv/Services.scala +++ b/src/main/scala/vexriscv/Services.scala @@ -36,13 +36,15 @@ trait ExceptionService{ } trait PrivilegeService{ - def isUser(stage : Stage) : Bool - def isMachine(stage : Stage) : Bool + def isUser() : Bool + def isSupervisor() : Bool + def isMachine() : Bool } case class PrivilegeServiceDefault() extends PrivilegeService{ - override def isUser(stage: Stage): Bool = False - override def isMachine(stage: Stage): Bool = True + override def isUser(): Bool = False + override def isSupervisor(): Bool = False + override def isMachine(): Bool = True } trait InterruptionInhibitor{ diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 118c3bf9..9834cbab 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -399,8 +399,9 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception def inhibateInterrupts() : Unit = allowInterrupts := False def inhibateException() : Unit = allowException := False - override def isUser(stage : Stage) : Bool = privilege === 0 - override def isMachine(stage: Stage): Bool = privilege === 3 + override def isUser() : Bool = privilege === 0 + override def isSupervisor(): Bool = privilege === 1 + override def isMachine(): Bool = privilege === 3 override def build(pipeline: VexRiscv): Unit = { import pipeline._ diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index 8a9d3fd2..b5eca04b 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -180,7 +180,7 @@ class DBusCachedPlugin(config : DataCacheConfig, import writeBack._ 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) + cache.io.cpu.writeBack.isUser := (if(privilegeService != null) privilegeService.isUser() else False) if(genAtomic) cache.io.cpu.writeBack.clearAtomicEntries := service(classOf[IContextSwitching]).isContextSwitching if(catchSomething) { diff --git a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala index d3d145d7..3e847898 100644 --- a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala @@ -332,7 +332,7 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, dBus.cmd.address := mmuBus.rsp.physicalAddress //do not emit memory request if MMU refilling - insert(MMU_FAULT) := input(MMU_RSP).exception || (!input(MMU_RSP).allowWrite && input(INSTRUCTION)(5)) || (!input(MMU_RSP).allowRead && !input(INSTRUCTION)(5)) || (!input(MMU_RSP).allowUser && privilegeService.isUser(memory)) + insert(MMU_FAULT) := input(MMU_RSP).exception || (!input(MMU_RSP).allowWrite && input(INSTRUCTION)(5)) || (!input(MMU_RSP).allowRead && !input(INSTRUCTION)(5)) || (!input(MMU_RSP).allowUser && privilegeService.isUser()) skipCmd.setWhen(input(MMU_FAULT) || input(MMU_RSP).refilling) insert(MMU_RSP) := mmuBus.rsp diff --git a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala index 027a0151..3b8d4614 100644 --- a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala @@ -164,7 +164,7 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l, cache.io.cpu.fetch.pc := stages(1).input.payload if (!twoCycleCache) { - cache.io.cpu.fetch.isUser := privilegeService.isUser(decode) + cache.io.cpu.fetch.isUser := privilegeService.isUser() } } @@ -173,7 +173,7 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l, cache.io.cpu.decode.isValid := stages(2).input.valid && !tightlyCoupledHit cache.io.cpu.decode.isStuck := !stages(2).input.ready cache.io.cpu.decode.pc := stages(2).input.payload - cache.io.cpu.decode.isUser := privilegeService.isUser(decode) + cache.io.cpu.decode.isUser := privilegeService.isUser() if ((!twoCycleRam || wayCount == 1) && !compressedGen && !injectorStage) { decode.insert(INSTRUCTION_ANTICIPATED) := Mux(decode.arbitration.isStuck, decode.input(INSTRUCTION), cache.io.cpu.fetch.data) diff --git a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala index ab226c8e..7f47e805 100644 --- a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala @@ -317,7 +317,7 @@ class IBusSimplePlugin(resetVector : BigInt, } if(memoryTranslatorPortConfig != null) { val privilegeService = pipeline.serviceElse(classOf[PrivilegeService], PrivilegeServiceDefault()) - when(stages.last.input.valid && !mmu.joinCtx.refilling && (mmu.joinCtx.exception || !mmu.joinCtx.allowExecute || (!mmu.joinCtx.allowUser && privilegeService.isUser(decode)))){ + when(stages.last.input.valid && !mmu.joinCtx.refilling && (mmu.joinCtx.exception || !mmu.joinCtx.allowExecute || (!mmu.joinCtx.allowUser && privilegeService.isUser()))){ decodeExceptionPort.code := 12 exceptionDetected := True } diff --git a/src/main/scala/vexriscv/plugin/MmuPlugin.scala b/src/main/scala/vexriscv/plugin/MmuPlugin.scala index 6e98de5a..ae515148 100644 --- a/src/main/scala/vexriscv/plugin/MmuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/MmuPlugin.scala @@ -85,6 +85,19 @@ class MmuPlugin(virtualRange : UInt => Bool, } } + val csr = pipeline plug new Area{ + val status = new Area{ + val sum, mxr = RegInit(False) + } + val satp = new Area { + val mode = RegInit(False) + val ppn = Reg(UInt(20 bits)) + } + + for(offset <- List(CSR.MSTATUS, CSR.SSTATUS)) csrService.rw(offset, 19 -> status.mxr, 18 -> status.sum) + csrService.rw(CSR.SATP, 31 -> satp.mode, 0 -> satp.ppn) //TODO write only ? + } + val core = pipeline plug new Area { val ports = for (port <- sortedPortsInfo) yield new Area { val id = port.id @@ -94,17 +107,16 @@ class MmuPlugin(virtualRange : UInt => Bool, val cacheLine = MuxOH(cacheHits, cache) val privilegeService = pipeline.serviceElse(classOf[PrivilegeService], PrivilegeServiceDefault()) val entryToReplace = Counter(port.args.portTlbSize) - - val requireMmuLockup = virtualRange(port.bus.cmd.virtualAddress) && !port.bus.cmd.bypassTranslation - if(!allowMachineModeMmu) requireMmuLockup clearWhen(privilegeService.isMachine(execute)) + val requireMmuLockup = virtualRange(port.bus.cmd.virtualAddress) && !port.bus.cmd.bypassTranslation && csr.satp.mode + if(!allowMachineModeMmu) requireMmuLockup clearWhen(privilegeService.isMachine()) when(requireMmuLockup) { port.bus.rsp.physicalAddress := cacheLine.physicalAddress(1) @@ (cacheLine.superPage ? port.bus.cmd.virtualAddress(21 downto 12) | cacheLine.physicalAddress(0)) @@ port.bus.cmd.virtualAddress(11 downto 0) - port.bus.rsp.allowRead := cacheLine.allowRead + port.bus.rsp.allowRead := cacheLine.allowRead || csr.status.mxr && cacheLine.allowExecute port.bus.rsp.allowWrite := cacheLine.allowWrite port.bus.rsp.allowExecute := cacheLine.allowExecute port.bus.rsp.allowUser := cacheLine.allowUser - port.bus.rsp.exception := cacheHit && cacheLine.exception + port.bus.rsp.exception := cacheHit && (cacheLine.exception || cacheLine.allowUser && privilegeService.isSupervisor() && !csr.status.sum) port.bus.rsp.refilling := !cacheHit } otherwise { port.bus.rsp.physicalAddress := port.bus.cmd.virtualAddress @@ -121,13 +133,6 @@ class MmuPlugin(virtualRange : UInt => Bool, val shared = new Area { val busy = Reg(Bool) init(False) - val satp = new Area { - val mode = RegInit(False) - val ppn = Reg(UInt(20 bits)) - - ports.foreach(_.requireMmuLockup clearWhen(!mode)) - } - csrService.rw(CSR.SATP, 31 -> satp.mode, 0 -> satp.ppn) //TODO write only ? val State = new SpinalEnum{ val IDLE, L1_CMD, L1_RSP, L0_CMD, L0_RSP = newElement() } @@ -169,7 +174,7 @@ class MmuPlugin(virtualRange : UInt => Bool, } is(State.L1_CMD){ dBusAccess.cmd.valid := True - dBusAccess.cmd.address := satp.ppn @@ vpn(1) @@ U"00" + dBusAccess.cmd.address := csr.satp.ppn @@ vpn(1) @@ U"00" when(dBusAccess.cmd.ready){ state := State.L1_RSP } diff --git a/src/test/cpp/raw/mmu/build/mmu.asm b/src/test/cpp/raw/mmu/build/mmu.asm index fc8a3308..fe325833 100644 --- a/src/test/cpp/raw/mmu/build/mmu.asm +++ b/src/test/cpp/raw/mmu/build/mmu.asm @@ -7,7 +7,7 @@ Disassembly of section .crt_section: 80000000 <_start>: 80000000: 00000e93 li t4,0 80000004: 00000097 auipc ra,0x0 -80000008: 3e808093 addi ra,ra,1000 # 800003ec +80000008: 3f008093 addi ra,ra,1008 # 800003f4 8000000c: 30509073 csrw mtvec,ra 80000010 : @@ -17,7 +17,7 @@ Disassembly of section .crt_section: 8000001c: 27262137 lui sp,0x27262 80000020: 52410113 addi sp,sp,1316 # 27262524 <_start-0x58d9dadc> 80000024: 0040a083 lw ra,4(ra) -80000028: 38209e63 bne ra,sp,800003c4 +80000028: 3a209263 bne ra,sp,800003cc 8000002c : 8000002c: 00200e13 li t3,2 @@ -28,7 +28,7 @@ Disassembly of section .crt_section: 80000040: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800> 80000044: 30009073 csrw mstatus,ra 80000048: 30200073 mret -8000004c: 3780006f j 800003c4 +8000004c: 3800006f j 800003cc 80000050 : 80000050: 00300e13 li t3,3 @@ -39,7 +39,7 @@ Disassembly of section .crt_section: 80000064: 01408093 addi ra,ra,20 # 80000074 80000068: 34109073 csrw mepc,ra 8000006c: 30200073 mret -80000070: 3540006f j 800003c4 +80000070: 35c0006f j 800003cc 80000074 : 80000074: 00400e13 li t3,4 @@ -48,7 +48,7 @@ Disassembly of section .crt_section: 80000080: 37363137 lui sp,0x37363 80000084: 53410113 addi sp,sp,1332 # 37363534 <_start-0x48c9cacc> 80000088: 0040a083 lw ra,4(ra) -8000008c: 32209c63 bne ra,sp,800003c4 +8000008c: 34209063 bne ra,sp,800003cc 80000090 : 80000090: 00500e13 li t3,5 @@ -120,203 +120,203 @@ Disassembly of section .crt_section: 80000198: 00002097 auipc ra,0x2 8000019c: 96808093 addi ra,ra,-1688 # 80001b00 800001a0: 0000a023 sw zero,0(ra) -800001a4: 00001097 auipc ra,0x1 -800001a8: e5c08093 addi ra,ra,-420 # 80001000 -800001ac: 00c0d093 srli ra,ra,0xc -800001b0: 80000137 lui sp,0x80000 -800001b4: 0020e0b3 or ra,ra,sp -800001b8: 18009073 csrw satp,ra +800001a4: 000400b7 lui ra,0x40 +800001a8: 1000a073 csrs sstatus,ra +800001ac: 00001097 auipc ra,0x1 +800001b0: e5408093 addi ra,ra,-428 # 80001000 +800001b4: 00c0d093 srli ra,ra,0xc +800001b8: 80000137 lui sp,0x80000 +800001bc: 0020e0b3 or ra,ra,sp +800001c0: 18009073 csrw satp,ra -800001bc : -800001bc: 00600e13 li t3,6 -800001c0: 9000a0b7 lui ra,0x9000a -800001c4: 00808093 addi ra,ra,8 # 9000a008 -800001c8: 4b4a5137 lui sp,0x4b4a5 -800001cc: 94810113 addi sp,sp,-1720 # 4b4a4948 <_start-0x34b5b6b8> -800001d0: 0000a083 lw ra,0(ra) -800001d4: 1e209863 bne ra,sp,800003c4 +800001c4 : +800001c4: 00600e13 li t3,6 +800001c8: 9000a0b7 lui ra,0x9000a +800001cc: 00808093 addi ra,ra,8 # 9000a008 +800001d0: 4b4a5137 lui sp,0x4b4a5 +800001d4: 94810113 addi sp,sp,-1720 # 4b4a4948 <_start-0x34b5b6b8> +800001d8: 0000a083 lw ra,0(ra) +800001dc: 1e209863 bne ra,sp,800003cc -800001d8 : -800001d8: 00700e13 li t3,7 -800001dc: 9000a0b7 lui ra,0x9000a -800001e0: 36008093 addi ra,ra,864 # 9000a360 -800001e4: aaee0137 lui sp,0xaaee0 -800001e8: 00110113 addi sp,sp,1 # aaee0001 -800001ec: 0020a023 sw sp,0(ra) -800001f0: 0000a083 lw ra,0(ra) -800001f4: 1c209863 bne ra,sp,800003c4 +800001e0 : +800001e0: 00700e13 li t3,7 +800001e4: 9000a0b7 lui ra,0x9000a +800001e8: 36008093 addi ra,ra,864 # 9000a360 +800001ec: aaee0137 lui sp,0xaaee0 +800001f0: 00110113 addi sp,sp,1 # aaee0001 +800001f4: 0020a023 sw sp,0(ra) +800001f8: 0000a083 lw ra,0(ra) +800001fc: 1c209863 bne ra,sp,800003cc -800001f8 : -800001f8: 00800e13 li t3,8 -800001fc: 2000c097 auipc ra,0x2000c -80000200: e0808093 addi ra,ra,-504 # a000c004 -80000204: 77767137 lui sp,0x77767 -80000208: 57410113 addi sp,sp,1396 # 77767574 <_start-0x8898a8c> -8000020c: 0000a083 lw ra,0(ra) -80000210: 1a209a63 bne ra,sp,800003c4 +80000200 : +80000200: 00800e13 li t3,8 +80000204: 2000c097 auipc ra,0x2000c +80000208: e0008093 addi ra,ra,-512 # a000c004 +8000020c: 77767137 lui sp,0x77767 +80000210: 57410113 addi sp,sp,1396 # 77767574 <_start-0x8898a8c> +80000214: 0000a083 lw ra,0(ra) +80000218: 1a209a63 bne ra,sp,800003cc -80000214 : -80000214: 00900e13 li t3,9 -80000218: a000a0b7 lui ra,0xa000a -8000021c: 36008093 addi ra,ra,864 # a000a360 -80000220: aaee0137 lui sp,0xaaee0 -80000224: 00210113 addi sp,sp,2 # aaee0002 -80000228: 0020a023 sw sp,0(ra) -8000022c: 0000a083 lw ra,0(ra) -80000230: 18209a63 bne ra,sp,800003c4 +8000021c : +8000021c: 00900e13 li t3,9 +80000220: a000a0b7 lui ra,0xa000a +80000224: 36008093 addi ra,ra,864 # a000a360 +80000228: aaee0137 lui sp,0xaaee0 +8000022c: 00210113 addi sp,sp,2 # aaee0002 +80000230: 0020a023 sw sp,0(ra) +80000234: 0000a083 lw ra,0(ra) +80000238: 18209a63 bne ra,sp,800003cc -80000234 : -80000234: 00a00e13 li t3,10 -80000238: 18005073 csrwi satp,0 -8000023c: 00009097 auipc ra,0x9 -80000240: 12408093 addi ra,ra,292 # 80009360 -80000244: aaee0137 lui sp,0xaaee0 -80000248: 00110113 addi sp,sp,1 # aaee0001 -8000024c: 0000a083 lw ra,0(ra) -80000250: 16209a63 bne ra,sp,800003c4 +8000023c : +8000023c: 00a00e13 li t3,10 +80000240: 18005073 csrwi satp,0 +80000244: 00009097 auipc ra,0x9 +80000248: 11c08093 addi ra,ra,284 # 80009360 +8000024c: aaee0137 lui sp,0xaaee0 +80000250: 00110113 addi sp,sp,1 # aaee0001 +80000254: 0000a083 lw ra,0(ra) +80000258: 16209a63 bne ra,sp,800003cc -80000254 : -80000254: 00b00e13 li t3,11 -80000258: 0000a097 auipc ra,0xa -8000025c: 10808093 addi ra,ra,264 # 8000a360 -80000260: aaee0137 lui sp,0xaaee0 -80000264: 00210113 addi sp,sp,2 # aaee0002 -80000268: 0000a083 lw ra,0(ra) -8000026c: 14209c63 bne ra,sp,800003c4 -80000270: 00001097 auipc ra,0x1 -80000274: d9008093 addi ra,ra,-624 # 80001000 -80000278: 00c0d093 srli ra,ra,0xc -8000027c: 80000137 lui sp,0x80000 -80000280: 0020e0b3 or ra,ra,sp -80000284: 18009073 csrw satp,ra +8000025c : +8000025c: 00b00e13 li t3,11 +80000260: 0000a097 auipc ra,0xa +80000264: 10008093 addi ra,ra,256 # 8000a360 +80000268: aaee0137 lui sp,0xaaee0 +8000026c: 00210113 addi sp,sp,2 # aaee0002 +80000270: 0000a083 lw ra,0(ra) +80000274: 14209c63 bne ra,sp,800003cc +80000278: 00001097 auipc ra,0x1 +8000027c: d8808093 addi ra,ra,-632 # 80001000 +80000280: 00c0d093 srli ra,ra,0xc +80000284: 80000137 lui sp,0x80000 +80000288: 0020e0b3 or ra,ra,sp +8000028c: 18009073 csrw satp,ra -80000288 : -80000288: 00c00e13 li t3,12 -8000028c: 00100e93 li t4,1 -80000290: 00000f17 auipc t5,0x0 -80000294: 010f0f13 addi t5,t5,16 # 800002a0 -80000298: 00000073 ecall -8000029c: 1280006f j 800003c4 +80000290 : +80000290: 00c00e13 li t3,12 +80000294: 00100e93 li t4,1 +80000298: 00000f17 auipc t5,0x0 +8000029c: 010f0f13 addi t5,t5,16 # 800002a8 +800002a0: 00000073 ecall +800002a4: 1280006f j 800003cc -800002a0 : -800002a0: 00d00e13 li t3,13 -800002a4: 00000f17 auipc t5,0x0 -800002a8: 014f0f13 addi t5,t5,20 # 800002b8 -800002ac: b00000b7 lui ra,0xb0000 -800002b0: 0080a083 lw ra,8(ra) # b0000008 -800002b4: 1100006f j 800003c4 +800002a8 : +800002a8: 00d00e13 li t3,13 +800002ac: 00000f17 auipc t5,0x0 +800002b0: 014f0f13 addi t5,t5,20 # 800002c0 +800002b4: b00000b7 lui ra,0xb0000 +800002b8: 0080a083 lw ra,8(ra) # b0000008 +800002bc: 1100006f j 800003cc -800002b8 : -800002b8: 00e00e13 li t3,14 -800002bc: 00000f17 auipc t5,0x0 -800002c0: 014f0f13 addi t5,t5,20 # 800002d0 -800002c4: b00000b7 lui ra,0xb0000 -800002c8: 0010a423 sw ra,8(ra) # b0000008 -800002cc: 0f80006f j 800003c4 +800002c0 : +800002c0: 00e00e13 li t3,14 +800002c4: 00000f17 auipc t5,0x0 +800002c8: 014f0f13 addi t5,t5,20 # 800002d8 +800002cc: b00000b7 lui ra,0xb0000 +800002d0: 0010a423 sw ra,8(ra) # b0000008 +800002d4: 0f80006f j 800003cc -800002d0 : -800002d0: 00f00e13 li t3,15 -800002d4: 00000f17 auipc t5,0x0 -800002d8: 014f0f13 addi t5,t5,20 # 800002e8 -800002dc: b00000b7 lui ra,0xb0000 -800002e0: 00008067 ret -800002e4: 0e00006f j 800003c4 +800002d8 : +800002d8: 00f00e13 li t3,15 +800002dc: 00000f17 auipc t5,0x0 +800002e0: 014f0f13 addi t5,t5,20 # 800002f0 +800002e4: b00000b7 lui ra,0xb0000 +800002e8: 00008067 ret +800002ec: 0e00006f j 800003cc -800002e8 : -800002e8: 01000e13 li t3,16 -800002ec: 00000e93 li t4,0 -800002f0: 900100b7 lui ra,0x90010 -800002f4: 00808093 addi ra,ra,8 # 90010008 -800002f8: 5b5a6137 lui sp,0x5b5a6 -800002fc: 95810113 addi sp,sp,-1704 # 5b5a5958 <_start-0x24a5a6a8> -80000300: 0000a083 lw ra,0(ra) -80000304: 0c209063 bne ra,sp,800003c4 -80000308: 900110b7 lui ra,0x90011 -8000030c: 00808093 addi ra,ra,8 # 90011008 -80000310: 5b5a6137 lui sp,0x5b5a6 -80000314: 95810113 addi sp,sp,-1704 # 5b5a5958 <_start-0x24a5a6a8> -80000318: 0000a083 lw ra,0(ra) -8000031c: 0a209463 bne ra,sp,800003c4 -80000320: 900130b7 lui ra,0x90013 -80000324: 00808093 addi ra,ra,8 # 90013008 -80000328: 5b5a6137 lui sp,0x5b5a6 -8000032c: 95810113 addi sp,sp,-1704 # 5b5a5958 <_start-0x24a5a6a8> -80000330: 0000a083 lw ra,0(ra) -80000334: 08209863 bne ra,sp,800003c4 +800002f0 : +800002f0: 01000e13 li t3,16 +800002f4: 00000e93 li t4,0 +800002f8: 900100b7 lui ra,0x90010 +800002fc: 00808093 addi ra,ra,8 # 90010008 +80000300: 5b5a6137 lui sp,0x5b5a6 +80000304: 95810113 addi sp,sp,-1704 # 5b5a5958 <_start-0x24a5a6a8> +80000308: 0000a083 lw ra,0(ra) +8000030c: 0c209063 bne ra,sp,800003cc +80000310: 900110b7 lui ra,0x90011 +80000314: 00808093 addi ra,ra,8 # 90011008 +80000318: 5b5a6137 lui sp,0x5b5a6 +8000031c: 95810113 addi sp,sp,-1704 # 5b5a5958 <_start-0x24a5a6a8> +80000320: 0000a083 lw ra,0(ra) +80000324: 0a209463 bne ra,sp,800003cc +80000328: 900130b7 lui ra,0x90013 +8000032c: 00808093 addi ra,ra,8 # 90013008 +80000330: 5b5a6137 lui sp,0x5b5a6 +80000334: 95810113 addi sp,sp,-1704 # 5b5a5958 <_start-0x24a5a6a8> +80000338: 0000a083 lw ra,0(ra) +8000033c: 08209863 bne ra,sp,800003cc -80000338 : -80000338: 01100e13 li t3,17 -8000033c: 900110b7 lui ra,0x90011 -80000340: 36008093 addi ra,ra,864 # 90011360 -80000344: aaee0137 lui sp,0xaaee0 -80000348: 00310113 addi sp,sp,3 # aaee0003 -8000034c: 0020a023 sw sp,0(ra) -80000350: 0000a083 lw ra,0(ra) -80000354: 06209863 bne ra,sp,800003c4 +80000340 : +80000340: 01100e13 li t3,17 +80000344: 900110b7 lui ra,0x90011 +80000348: 36008093 addi ra,ra,864 # 90011360 +8000034c: aaee0137 lui sp,0xaaee0 +80000350: 00310113 addi sp,sp,3 # aaee0003 +80000354: 0020a023 sw sp,0(ra) +80000358: 0000a083 lw ra,0(ra) +8000035c: 06209863 bne ra,sp,800003cc -80000358 : -80000358: 01200e13 li t3,18 -8000035c: 00000097 auipc ra,0x0 -80000360: 01808093 addi ra,ra,24 # 80000374 -80000364: 90012137 lui sp,0x90012 -80000368: 01010113 addi sp,sp,16 # 90012010 -8000036c: 00010067 jr sp -80000370: 0540006f j 800003c4 +80000360 : +80000360: 01200e13 li t3,18 +80000364: 00000097 auipc ra,0x0 +80000368: 01808093 addi ra,ra,24 # 8000037c +8000036c: 90012137 lui sp,0x90012 +80000370: 01010113 addi sp,sp,16 # 90012010 +80000374: 00010067 jr sp +80000378: 0540006f j 800003cc -80000374 : -80000374: 00100e93 li t4,1 -80000378: 00000f17 auipc t5,0x0 -8000037c: 018f0f13 addi t5,t5,24 # 80000390 -80000380: 900120b7 lui ra,0x90012 -80000384: 01008093 addi ra,ra,16 # 90012010 -80000388: 0000a083 lw ra,0(ra) -8000038c: 0380006f j 800003c4 +8000037c : +8000037c: 00100e93 li t4,1 +80000380: 00000f17 auipc t5,0x0 +80000384: 018f0f13 addi t5,t5,24 # 80000398 +80000388: 900120b7 lui ra,0x90012 +8000038c: 01008093 addi ra,ra,16 # 90012010 +80000390: 0000a083 lw ra,0(ra) +80000394: 0380006f j 800003cc -80000390 : -80000390: 00000f17 auipc t5,0x0 -80000394: 018f0f13 addi t5,t5,24 # 800003a8 -80000398: 900130b7 lui ra,0x90013 -8000039c: 01008093 addi ra,ra,16 # 90013010 -800003a0: 0010a023 sw ra,0(ra) -800003a4: 0200006f j 800003c4 +80000398 : +80000398: 00000f17 auipc t5,0x0 +8000039c: 018f0f13 addi t5,t5,24 # 800003b0 +800003a0: 900130b7 lui ra,0x90013 +800003a4: 01008093 addi ra,ra,16 # 90013010 +800003a8: 0010a023 sw ra,0(ra) +800003ac: 0200006f j 800003cc -800003a8 : -800003a8: 00000f17 auipc t5,0x0 -800003ac: 018f0f13 addi t5,t5,24 # 800003c0 -800003b0: 900110b7 lui ra,0x90011 -800003b4: 01008093 addi ra,ra,16 # 90011010 -800003b8: 00008067 ret -800003bc: 0080006f j 800003c4 +800003b0 : +800003b0: 00000f17 auipc t5,0x0 +800003b4: 018f0f13 addi t5,t5,24 # 800003c8 +800003b8: 900110b7 lui ra,0x90011 +800003bc: 01008093 addi ra,ra,16 # 90011010 +800003c0: 00008067 ret +800003c4: 0080006f j 800003cc -800003c0 : -800003c0: 0180006f j 800003d8 +800003c8 : +800003c8: 0180006f j 800003e0 -800003c4 : -800003c4: 18005073 csrwi satp,0 -800003c8: 0040006f j 800003cc +800003cc : +800003cc: 18005073 csrwi satp,0 +800003d0: 0040006f j 800003d4 -800003cc : -800003cc: f0100137 lui sp,0xf0100 -800003d0: f2410113 addi sp,sp,-220 # f00fff24 -800003d4: 01c12023 sw t3,0(sp) +800003d4 : +800003d4: f0100137 lui sp,0xf0100 +800003d8: f2410113 addi sp,sp,-220 # f00fff24 +800003dc: 01c12023 sw t3,0(sp) -800003d8 : -800003d8: 18005073 csrwi satp,0 -800003dc: 0040006f j 800003e0 +800003e0 : +800003e0: 18005073 csrwi satp,0 +800003e4: 0040006f j 800003e8 -800003e0 : -800003e0: f0100137 lui sp,0xf0100 -800003e4: f2010113 addi sp,sp,-224 # f00fff20 -800003e8: 00012023 sw zero,0(sp) +800003e8 : +800003e8: f0100137 lui sp,0xf0100 +800003ec: f2010113 addi sp,sp,-224 # f00fff20 +800003f0: 00012023 sw zero,0(sp) -800003ec : -800003ec: fc0e8ce3 beqz t4,800003c4 -800003f0: 342020f3 csrr ra,mcause -800003f4: 341020f3 csrr ra,mepc -800003f8: 341f1073 csrw mepc,t5 -800003fc: 30200073 mret -80000400: 00000013 nop -80000404: 00000013 nop +800003f4 : +800003f4: fc0e8ce3 beqz t4,800003cc +800003f8: 342020f3 csrr ra,mcause +800003fc: 341020f3 csrr ra,mepc +80000400: 341f1073 csrw mepc,t5 +80000404: 30200073 mret 80000408: 00000013 nop 8000040c: 00000013 nop 80000410: 00000013 nop diff --git a/src/test/cpp/raw/mmu/build/mmu.hex b/src/test/cpp/raw/mmu/build/mmu.hex index affa9ad7..a473dd93 100644 --- a/src/test/cpp/raw/mmu/build/mmu.hex +++ b/src/test/cpp/raw/mmu/build/mmu.hex @@ -1,13 +1,13 @@ :0200000480007A -:10000000930E0000970000009380803E7390503064 +:10000000930E0000970000009380003F73905030E3 :10001000130E1000977000009380C0FE3721262732 -:100020001301415283A04000639E2038130E20002C +:100020001301415283A040006392203A130E200036 :10003000970000009380000273901034B7200000F6 -:100040009380008073900030730020306F00803701 +:100040009380008073900030730020306F00003880 :10005000130E3000B71000009380008073900030C2 :10006000970000009380400173901034730020309B -:100070006F004035130E400097800000938080F899 -:10008000373136371301415383A04000639C20323F +:100070006F00C035130E400097800000938080F819 +:10008000373136371301415383A040006390203449 :10009000130E5000971000009380C07617210000C7 :1000A000130141F6135121001361110123A0200017 :1000B00097200000938000F5370100801351210044 @@ -25,45 +25,45 @@ :1001700023A02000130E5000972000009380808859 :1001800017010000130101E8135121001361F1016F :1001900023A02000130E500097200000938080962B -:1001A00023A00000971000009380C0E593D0C0000A -:1001B00037010080B3E0200073900018130E600038 -:1001C000B7A000909380800037514A4B130181946F -:1001D00083A000006398201E130E7000B7A000904B -:1001E000938000363701EEAA1301110023A02000EE -:1001F00083A000006398201C130E800097C000208D -:10020000938080E0377176771301415783A0000017 -:10021000639A201A130E9000B7A000A093800036B6 -:100220003701EEAA1301210023A0200083A00000C3 -:10023000639A2018130EA0007350001897900000C6 -:10024000938040123701EEAA1301110083A0000031 -:10025000639A2016130EB00097A0000093808010C0 -:100260003701EEAA1301210083A00000639C201433 -:1002700097100000938000D993D0C0003701008010 -:10028000B3E0200073900018130EC000930E10000E -:10029000170F0000130F0F01730000006F00801292 -:1002A000130ED000170F0000130F4F01B70000B05E -:1002B00083A080006F000011130EE000170F0000F4 -:1002C000130F4F01B70000B023A410006F00800F80 -:1002D000130EF000170F0000130F4F01B70000B00E -:1002E000678000006F00000E130E0001930E0000E7 -:1002F000B70001909380800037615A5B13018195AC -:1003000083A000006390200CB710019093808000C0 -:1003100037615A5B1301819583A000006394200A22 -:10032000B73001909380800037615A5B130181954B -:1003300083A0000063982008130E1001B7100190ED -:10034000938000363701EEAA1301310023A020006C -:1003500083A0000063982006130E20019700000080 -:100360009380800137210190130101016700010092 -:100370006F004005930E1000170F0000130F8F0140 -:10038000B72001909380000183A000006F008003DC -:10039000170F0000130F8F01B730019093800001F9 -:1003A00023A010006F000002170F0000130F8F0131 -:1003B000B710019093800001678000006F008000FB -:1003C0006F008001735000186F004000370110F07B -:1003D000130141F22320C101735000186F00400047 -:1003E000370110F0130101F223200100E38C0EFC11 -:1003F000F3202034F320103473101F3473002030A6 -:1004000013000000130000001300000013000000A0 +:1001A00023A00000B700040073A000109710000007 +:1001B000938040E593D0C00037010080B3E0200079 +:1001C00073900018130E6000B7A000909380800019 +:1001D00037514A4B1301819483A000006398201E7D +:1001E000130E7000B7A00090938000363701EEAA7E +:1001F0001301110023A0200083A000006398201C9D +:10020000130E800097C00020938000E0377176774E +:100210001301415783A00000639A201A130E900027 +:10022000B7A000A0938000363701EEAA1301210089 +:1002300023A0200083A00000639A2018130EA000C2 +:1002400073500018979000009380C0113701EEAAF8 +:100250001301110083A00000639A2016130EB00052 +:1002600097A00000938000103701EEAA130121002F +:1002700083A00000639C201497100000938080D816 +:1002800093D0C00037010080B3E0200073900018C5 +:10029000130EC000930E1000170F0000130F0F0174 +:1002A000730000006F008012130ED000170F0000C3 +:1002B000130F4F01B70000B083A080006F00001142 +:1002C000130EE000170F0000130F4F01B70000B02E +:1002D00023A410006F00800F130EF000170F000012 +:1002E000130F4F01B70000B0678000006F00000ED1 +:1002F000130E0001930E0000B70001909380800060 +:1003000037615A5B1301819583A000006390200C34 +:10031000B71001909380800037615A5B130181957B +:1003200083A000006394200AB7300190938080007E +:1003300037615A5B1301819583A000006398200800 +:10034000130E1001B7100190938000363701EEAA0A +:100350001301310023A0200083A000006398200631 +:10036000130E200197000000938080013721019037 +:1003700013010101670001006F004005930E10009A +:10038000170F0000130F8F01B72001909380000119 +:1003900083A000006F008003170F0000130F8F0170 +:1003A000B73001909380000123A010006F0000027D +:1003B000170F0000130F8F01B710019093800001F9 +:1003C000678000006F0080006F008001735000188C +:1003D0006F004000370110F0130141F22320C101EA +:1003E000735000186F004000370110F0130101F244 +:1003F00023200100E38C0EFCF3202034F320103482 +:1004000073101F347300203013000000130000002D :100410001300000013000000130000001300000090 :100420001300000013000000130000001300000080 :100430001300000013000000130000001300000070 @@ -3255,7 +3255,6 @@ :10CB500000000000000000000000000000000000D5 :10CB600000000000000000000000000000000000C5 :10CB700000000000000000000000000000000000B5 -:10CB800000000000000000000000000000000000A5 -:04CB900000000000A1 +:0CCB8000000000000000000000000000A9 :040000058000000077 :00000001FF diff --git a/src/test/cpp/raw/mmu/src/crt.S b/src/test/cpp/raw/mmu/src/crt.S index 238aefcf..5c48514e 100644 --- a/src/test/cpp/raw/mmu/src/crt.S +++ b/src/test/cpp/raw/mmu/src/crt.S @@ -106,6 +106,8 @@ test5: //setup MMU la x1, MMU_TABLE_0 + 0xB00 sw x0, 0(x1) + li x1, 1 << 18 //SUM + csrs sstatus, x1 la x1, MMU_TABLE_0 srli x1, x1, 12 diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 39e1e397..47bc3614 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -234,6 +234,9 @@ public: uint32_t spp : 1; uint32_t _3 : 2; uint32_t mpp : 2; + uint32_t _4 : 5; + uint32_t sum : 1; + uint32_t mxr : 1; }; }__attribute__((packed)) status; @@ -352,6 +355,8 @@ public: medeleg = 0; mideleg = 0; satp.mode = 0; + status.mxr = 0; + status.sum = 0; } virtual void rfWrite(int32_t address, int32_t data) { @@ -389,9 +394,10 @@ public: superPage = false; } if(!tlb.u && privilege == 0) return true; + if( tlb.u && privilege == 1 && !status.sum) return true; if(superPage && tlb.ppn0 != 0) return true; switch(kind){ - case READ: if(!tlb.r) return true; break; + case READ: if(!tlb.r && !(status.mxr && tlb.x)) return true; break; case WRITE: if(!tlb.w) return true; break; case EXECUTE: if(!tlb.x) return true; break; } @@ -462,7 +468,7 @@ public: case MSCRATCH: *value = mscratch; break; case MISA: *value = misa; break; - case SSTATUS: *value = status.raw & 0x133; break; + case SSTATUS: *value = status.raw & 0xC0133; break; case SIP: *value = ip.raw & 0x333; break; case SIE: *value = ie.raw & 0x333; break; case STVEC: *value = stvec.raw; break; @@ -490,7 +496,7 @@ public: case MSCRATCH: mscratch = value; break; case MISA: misa = value; break; - case SSTATUS: maskedWrite(status.raw, value,0x133); break; + case SSTATUS: maskedWrite(status.raw, value,0xC0133); break; case SIP: maskedWrite(ip.raw, value,0x333); break; case SIE: maskedWrite(ie.raw, value,0x333); break; case STVEC: stvec.raw = value; break; From 597336b4912c40a470042712406af8d20b34cb08 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 22 Mar 2019 17:11:55 +0100 Subject: [PATCH 062/951] MMU sum/mxr tested and ok, all seem finen --- src/test/cpp/raw/mmu/build/mmu.asm | 608 +++++++++++++++-------------- src/test/cpp/raw/mmu/build/mmu.hex | 176 ++++----- src/test/cpp/raw/mmu/src/crt.S | 213 ++++++++-- src/test/cpp/regression/main.cpp | 6 +- 4 files changed, 564 insertions(+), 439 deletions(-) diff --git a/src/test/cpp/raw/mmu/build/mmu.asm b/src/test/cpp/raw/mmu/build/mmu.asm index fe325833..5d39ccc4 100644 --- a/src/test/cpp/raw/mmu/build/mmu.asm +++ b/src/test/cpp/raw/mmu/build/mmu.asm @@ -7,7 +7,7 @@ Disassembly of section .crt_section: 80000000 <_start>: 80000000: 00000e93 li t4,0 80000004: 00000097 auipc ra,0x0 -80000008: 3f008093 addi ra,ra,1008 # 800003f4 +80000008: 59008093 addi ra,ra,1424 # 80000594 8000000c: 30509073 csrw mtvec,ra 80000010 : @@ -17,7 +17,7 @@ Disassembly of section .crt_section: 8000001c: 27262137 lui sp,0x27262 80000020: 52410113 addi sp,sp,1316 # 27262524 <_start-0x58d9dadc> 80000024: 0040a083 lw ra,4(ra) -80000028: 3a209263 bne ra,sp,800003cc +80000028: 54209263 bne ra,sp,8000056c 8000002c : 8000002c: 00200e13 li t3,2 @@ -28,7 +28,7 @@ Disassembly of section .crt_section: 80000040: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800> 80000044: 30009073 csrw mstatus,ra 80000048: 30200073 mret -8000004c: 3800006f j 800003cc +8000004c: 5200006f j 8000056c 80000050 : 80000050: 00300e13 li t3,3 @@ -39,7 +39,7 @@ Disassembly of section .crt_section: 80000064: 01408093 addi ra,ra,20 # 80000074 80000068: 34109073 csrw mepc,ra 8000006c: 30200073 mret -80000070: 35c0006f j 800003cc +80000070: 4fc0006f j 8000056c 80000074 : 80000074: 00400e13 li t3,4 @@ -48,7 +48,7 @@ Disassembly of section .crt_section: 80000080: 37363137 lui sp,0x37363 80000084: 53410113 addi sp,sp,1332 # 37363534 <_start-0x48c9cacc> 80000088: 0040a083 lw ra,4(ra) -8000008c: 34209063 bne ra,sp,800003cc +8000008c: 4e209063 bne ra,sp,8000056c 80000090 : 80000090: 00500e13 li t3,5 @@ -63,7 +63,7 @@ Disassembly of section .crt_section: 800000b4: f5008093 addi ra,ra,-176 # 80002000 800000b8: 80000137 lui sp,0x80000 800000bc: 00215113 srli sp,sp,0x2 -800000c0: 01f16113 ori sp,sp,31 +800000c0: 00f16113 ori sp,sp,15 800000c4: 0020a023 sw sp,0(ra) 800000c8: 00500e13 li t3,5 800000cc: 00002097 auipc ra,0x2 @@ -108,321 +108,337 @@ Disassembly of section .crt_section: 80000168: 00215113 srli sp,sp,0x2 8000016c: 01b16113 ori sp,sp,27 80000170: 0020a023 sw sp,0(ra) -80000174: 00500e13 li t3,5 -80000178: 00002097 auipc ra,0x2 -8000017c: 88808093 addi ra,ra,-1912 # 80001a00 -80000180: 00000117 auipc sp,0x0 -80000184: e8010113 addi sp,sp,-384 # 80000000 <_start> -80000188: 00215113 srli sp,sp,0x2 -8000018c: 01f16113 ori sp,sp,31 -80000190: 0020a023 sw sp,0(ra) -80000194: 00500e13 li t3,5 -80000198: 00002097 auipc ra,0x2 -8000019c: 96808093 addi ra,ra,-1688 # 80001b00 -800001a0: 0000a023 sw zero,0(ra) -800001a4: 000400b7 lui ra,0x40 -800001a8: 1000a073 csrs sstatus,ra -800001ac: 00001097 auipc ra,0x1 -800001b0: e5408093 addi ra,ra,-428 # 80001000 -800001b4: 00c0d093 srli ra,ra,0xc -800001b8: 80000137 lui sp,0x80000 -800001bc: 0020e0b3 or ra,ra,sp -800001c0: 18009073 csrw satp,ra +80000174: 00003097 auipc ra,0x3 +80000178: edc08093 addi ra,ra,-292 # 80003050 +8000017c: 0000a117 auipc sp,0xa +80000180: e8410113 addi sp,sp,-380 # 8000a000 +80000184: 00215113 srli sp,sp,0x2 +80000188: 00f16113 ori sp,sp,15 +8000018c: 0020a023 sw sp,0(ra) +80000190: 00500e13 li t3,5 +80000194: 00002097 auipc ra,0x2 +80000198: 86c08093 addi ra,ra,-1940 # 80001a00 +8000019c: 00000117 auipc sp,0x0 +800001a0: e6410113 addi sp,sp,-412 # 80000000 <_start> +800001a4: 00215113 srli sp,sp,0x2 +800001a8: 01f16113 ori sp,sp,31 +800001ac: 0020a023 sw sp,0(ra) +800001b0: 00500e13 li t3,5 +800001b4: 00002097 auipc ra,0x2 +800001b8: 94c08093 addi ra,ra,-1716 # 80001b00 +800001bc: 0000a023 sw zero,0(ra) +800001c0: 000400b7 lui ra,0x40 +800001c4: 1000a073 csrs sstatus,ra +800001c8: 00001097 auipc ra,0x1 +800001cc: e3808093 addi ra,ra,-456 # 80001000 +800001d0: 00c0d093 srli ra,ra,0xc +800001d4: 80000137 lui sp,0x80000 +800001d8: 0020e0b3 or ra,ra,sp +800001dc: 18009073 csrw satp,ra -800001c4 : -800001c4: 00600e13 li t3,6 -800001c8: 9000a0b7 lui ra,0x9000a -800001cc: 00808093 addi ra,ra,8 # 9000a008 -800001d0: 4b4a5137 lui sp,0x4b4a5 -800001d4: 94810113 addi sp,sp,-1720 # 4b4a4948 <_start-0x34b5b6b8> -800001d8: 0000a083 lw ra,0(ra) -800001dc: 1e209863 bne ra,sp,800003cc - -800001e0 : -800001e0: 00700e13 li t3,7 +800001e0 : +800001e0: 00600e13 li t3,6 800001e4: 9000a0b7 lui ra,0x9000a -800001e8: 36008093 addi ra,ra,864 # 9000a360 -800001ec: aaee0137 lui sp,0xaaee0 -800001f0: 00110113 addi sp,sp,1 # aaee0001 -800001f4: 0020a023 sw sp,0(ra) -800001f8: 0000a083 lw ra,0(ra) -800001fc: 1c209863 bne ra,sp,800003cc +800001e8: 00808093 addi ra,ra,8 # 9000a008 +800001ec: 4b4a5137 lui sp,0x4b4a5 +800001f0: 94810113 addi sp,sp,-1720 # 4b4a4948 <_start-0x34b5b6b8> +800001f4: 0000a083 lw ra,0(ra) +800001f8: 36209a63 bne ra,sp,8000056c -80000200 : -80000200: 00800e13 li t3,8 -80000204: 2000c097 auipc ra,0x2000c -80000208: e0008093 addi ra,ra,-512 # a000c004 -8000020c: 77767137 lui sp,0x77767 -80000210: 57410113 addi sp,sp,1396 # 77767574 <_start-0x8898a8c> +800001fc : +800001fc: 00700e13 li t3,7 +80000200: 9000a0b7 lui ra,0x9000a +80000204: 36008093 addi ra,ra,864 # 9000a360 +80000208: aaee0137 lui sp,0xaaee0 +8000020c: 00110113 addi sp,sp,1 # aaee0001 +80000210: 0020a023 sw sp,0(ra) 80000214: 0000a083 lw ra,0(ra) -80000218: 1a209a63 bne ra,sp,800003cc +80000218: 34209a63 bne ra,sp,8000056c -8000021c : -8000021c: 00900e13 li t3,9 -80000220: a000a0b7 lui ra,0xa000a -80000224: 36008093 addi ra,ra,864 # a000a360 -80000228: aaee0137 lui sp,0xaaee0 -8000022c: 00210113 addi sp,sp,2 # aaee0002 -80000230: 0020a023 sw sp,0(ra) -80000234: 0000a083 lw ra,0(ra) -80000238: 18209a63 bne ra,sp,800003cc +8000021c : +8000021c: 00800e13 li t3,8 +80000220: 2000c097 auipc ra,0x2000c +80000224: de408093 addi ra,ra,-540 # a000c004 +80000228: 77767137 lui sp,0x77767 +8000022c: 57410113 addi sp,sp,1396 # 77767574 <_start-0x8898a8c> +80000230: 0000a083 lw ra,0(ra) +80000234: 32209c63 bne ra,sp,8000056c -8000023c : -8000023c: 00a00e13 li t3,10 -80000240: 18005073 csrwi satp,0 -80000244: 00009097 auipc ra,0x9 -80000248: 11c08093 addi ra,ra,284 # 80009360 -8000024c: aaee0137 lui sp,0xaaee0 -80000250: 00110113 addi sp,sp,1 # aaee0001 -80000254: 0000a083 lw ra,0(ra) -80000258: 16209a63 bne ra,sp,800003cc +80000238 : +80000238: 00900e13 li t3,9 +8000023c: a000a0b7 lui ra,0xa000a +80000240: 36008093 addi ra,ra,864 # a000a360 +80000244: aaee0137 lui sp,0xaaee0 +80000248: 00210113 addi sp,sp,2 # aaee0002 +8000024c: 0020a023 sw sp,0(ra) +80000250: 0000a083 lw ra,0(ra) +80000254: 30209c63 bne ra,sp,8000056c -8000025c : -8000025c: 00b00e13 li t3,11 -80000260: 0000a097 auipc ra,0xa -80000264: 10008093 addi ra,ra,256 # 8000a360 +80000258 : +80000258: 00a00e13 li t3,10 +8000025c: 18005073 csrwi satp,0 +80000260: 00009097 auipc ra,0x9 +80000264: 10008093 addi ra,ra,256 # 80009360 80000268: aaee0137 lui sp,0xaaee0 -8000026c: 00210113 addi sp,sp,2 # aaee0002 +8000026c: 00110113 addi sp,sp,1 # aaee0001 80000270: 0000a083 lw ra,0(ra) -80000274: 14209c63 bne ra,sp,800003cc -80000278: 00001097 auipc ra,0x1 -8000027c: d8808093 addi ra,ra,-632 # 80001000 -80000280: 00c0d093 srli ra,ra,0xc -80000284: 80000137 lui sp,0x80000 -80000288: 0020e0b3 or ra,ra,sp -8000028c: 18009073 csrw satp,ra +80000274: 2e209c63 bne ra,sp,8000056c -80000290 : -80000290: 00c00e13 li t3,12 -80000294: 00100e93 li t4,1 -80000298: 00000f17 auipc t5,0x0 -8000029c: 010f0f13 addi t5,t5,16 # 800002a8 -800002a0: 00000073 ecall -800002a4: 1280006f j 800003cc +80000278 : +80000278: 00b00e13 li t3,11 +8000027c: 0000a097 auipc ra,0xa +80000280: 0e408093 addi ra,ra,228 # 8000a360 +80000284: aaee0137 lui sp,0xaaee0 +80000288: 00210113 addi sp,sp,2 # aaee0002 +8000028c: 0000a083 lw ra,0(ra) +80000290: 2c209e63 bne ra,sp,8000056c +80000294: 00001097 auipc ra,0x1 +80000298: d6c08093 addi ra,ra,-660 # 80001000 +8000029c: 00c0d093 srli ra,ra,0xc +800002a0: 80000137 lui sp,0x80000 +800002a4: 0020e0b3 or ra,ra,sp +800002a8: 18009073 csrw satp,ra -800002a8 : -800002a8: 00d00e13 li t3,13 -800002ac: 00000f17 auipc t5,0x0 -800002b0: 014f0f13 addi t5,t5,20 # 800002c0 -800002b4: b00000b7 lui ra,0xb0000 -800002b8: 0080a083 lw ra,8(ra) # b0000008 -800002bc: 1100006f j 800003cc +800002ac : +800002ac: 00c00e13 li t3,12 +800002b0: 00100e93 li t4,1 +800002b4: 00000f17 auipc t5,0x0 +800002b8: 010f0f13 addi t5,t5,16 # 800002c4 +800002bc: 00000073 ecall +800002c0: 2ac0006f j 8000056c -800002c0 : -800002c0: 00e00e13 li t3,14 -800002c4: 00000f17 auipc t5,0x0 -800002c8: 014f0f13 addi t5,t5,20 # 800002d8 -800002cc: b00000b7 lui ra,0xb0000 -800002d0: 0010a423 sw ra,8(ra) # b0000008 -800002d4: 0f80006f j 800003cc +800002c4 : +800002c4: 00d00e13 li t3,13 +800002c8: 00000f17 auipc t5,0x0 +800002cc: 014f0f13 addi t5,t5,20 # 800002dc +800002d0: b00000b7 lui ra,0xb0000 +800002d4: 0080a083 lw ra,8(ra) # b0000008 +800002d8: 2940006f j 8000056c -800002d8 : -800002d8: 00f00e13 li t3,15 -800002dc: 00000f17 auipc t5,0x0 -800002e0: 014f0f13 addi t5,t5,20 # 800002f0 -800002e4: b00000b7 lui ra,0xb0000 -800002e8: 00008067 ret -800002ec: 0e00006f j 800003cc +800002dc : +800002dc: 00e00e13 li t3,14 +800002e0: 00000f17 auipc t5,0x0 +800002e4: 014f0f13 addi t5,t5,20 # 800002f4 +800002e8: b00000b7 lui ra,0xb0000 +800002ec: 0010a423 sw ra,8(ra) # b0000008 +800002f0: 27c0006f j 8000056c -800002f0 : -800002f0: 01000e13 li t3,16 -800002f4: 00000e93 li t4,0 -800002f8: 900100b7 lui ra,0x90010 -800002fc: 00808093 addi ra,ra,8 # 90010008 -80000300: 5b5a6137 lui sp,0x5b5a6 -80000304: 95810113 addi sp,sp,-1704 # 5b5a5958 <_start-0x24a5a6a8> -80000308: 0000a083 lw ra,0(ra) -8000030c: 0c209063 bne ra,sp,800003cc -80000310: 900110b7 lui ra,0x90011 -80000314: 00808093 addi ra,ra,8 # 90011008 -80000318: 5b5a6137 lui sp,0x5b5a6 -8000031c: 95810113 addi sp,sp,-1704 # 5b5a5958 <_start-0x24a5a6a8> -80000320: 0000a083 lw ra,0(ra) -80000324: 0a209463 bne ra,sp,800003cc -80000328: 900130b7 lui ra,0x90013 -8000032c: 00808093 addi ra,ra,8 # 90013008 -80000330: 5b5a6137 lui sp,0x5b5a6 -80000334: 95810113 addi sp,sp,-1704 # 5b5a5958 <_start-0x24a5a6a8> -80000338: 0000a083 lw ra,0(ra) -8000033c: 08209863 bne ra,sp,800003cc +800002f4 : +800002f4: 00f00e13 li t3,15 +800002f8: 00000f17 auipc t5,0x0 +800002fc: 014f0f13 addi t5,t5,20 # 8000030c +80000300: b00000b7 lui ra,0xb0000 +80000304: 00008067 ret +80000308: 2640006f j 8000056c -80000340 : -80000340: 01100e13 li t3,17 -80000344: 900110b7 lui ra,0x90011 -80000348: 36008093 addi ra,ra,864 # 90011360 -8000034c: aaee0137 lui sp,0xaaee0 -80000350: 00310113 addi sp,sp,3 # aaee0003 -80000354: 0020a023 sw sp,0(ra) -80000358: 0000a083 lw ra,0(ra) -8000035c: 06209863 bne ra,sp,800003cc +8000030c : +8000030c: 01000e13 li t3,16 +80000310: 00000e93 li t4,0 +80000314: 900100b7 lui ra,0x90010 +80000318: 00808093 addi ra,ra,8 # 90010008 +8000031c: 5b5a6137 lui sp,0x5b5a6 +80000320: 95810113 addi sp,sp,-1704 # 5b5a5958 <_start-0x24a5a6a8> +80000324: 0000a083 lw ra,0(ra) +80000328: 24209263 bne ra,sp,8000056c +8000032c: 900110b7 lui ra,0x90011 +80000330: 00808093 addi ra,ra,8 # 90011008 +80000334: 5b5a6137 lui sp,0x5b5a6 +80000338: 95810113 addi sp,sp,-1704 # 5b5a5958 <_start-0x24a5a6a8> +8000033c: 0000a083 lw ra,0(ra) +80000340: 22209663 bne ra,sp,8000056c +80000344: 900130b7 lui ra,0x90013 +80000348: 00808093 addi ra,ra,8 # 90013008 +8000034c: 5b5a6137 lui sp,0x5b5a6 +80000350: 95810113 addi sp,sp,-1704 # 5b5a5958 <_start-0x24a5a6a8> +80000354: 0000a083 lw ra,0(ra) +80000358: 20209a63 bne ra,sp,8000056c -80000360 : -80000360: 01200e13 li t3,18 -80000364: 00000097 auipc ra,0x0 -80000368: 01808093 addi ra,ra,24 # 8000037c -8000036c: 90012137 lui sp,0x90012 -80000370: 01010113 addi sp,sp,16 # 90012010 -80000374: 00010067 jr sp -80000378: 0540006f j 800003cc +8000035c : +8000035c: 01100e13 li t3,17 +80000360: 900110b7 lui ra,0x90011 +80000364: 36008093 addi ra,ra,864 # 90011360 +80000368: aaee0137 lui sp,0xaaee0 +8000036c: 00310113 addi sp,sp,3 # aaee0003 +80000370: 0020a023 sw sp,0(ra) +80000374: 0000a083 lw ra,0(ra) +80000378: 1e209a63 bne ra,sp,8000056c -8000037c : -8000037c: 00100e93 li t4,1 -80000380: 00000f17 auipc t5,0x0 -80000384: 018f0f13 addi t5,t5,24 # 80000398 -80000388: 900120b7 lui ra,0x90012 -8000038c: 01008093 addi ra,ra,16 # 90012010 -80000390: 0000a083 lw ra,0(ra) -80000394: 0380006f j 800003cc +8000037c : +8000037c: 01200e13 li t3,18 +80000380: 00000097 auipc ra,0x0 +80000384: 01808093 addi ra,ra,24 # 80000398 +80000388: 90012137 lui sp,0x90012 +8000038c: 01010113 addi sp,sp,16 # 90012010 +80000390: 00010067 jr sp +80000394: 1d80006f j 8000056c -80000398 : -80000398: 00000f17 auipc t5,0x0 -8000039c: 018f0f13 addi t5,t5,24 # 800003b0 -800003a0: 900130b7 lui ra,0x90013 -800003a4: 01008093 addi ra,ra,16 # 90013010 -800003a8: 0010a023 sw ra,0(ra) -800003ac: 0200006f j 800003cc +80000398 : +80000398: 01300e13 li t3,19 +8000039c: 00100e93 li t4,1 +800003a0: 00000f17 auipc t5,0x0 +800003a4: 018f0f13 addi t5,t5,24 # 800003b8 +800003a8: 900120b7 lui ra,0x90012 +800003ac: 01008093 addi ra,ra,16 # 90012010 +800003b0: 0000a083 lw ra,0(ra) +800003b4: 1b80006f j 8000056c -800003b0 : -800003b0: 00000f17 auipc t5,0x0 -800003b4: 018f0f13 addi t5,t5,24 # 800003c8 -800003b8: 900110b7 lui ra,0x90011 -800003bc: 01008093 addi ra,ra,16 # 90011010 -800003c0: 00008067 ret -800003c4: 0080006f j 800003cc +800003b8 : +800003b8: 00000f17 auipc t5,0x0 +800003bc: 018f0f13 addi t5,t5,24 # 800003d0 +800003c0: 900130b7 lui ra,0x90013 +800003c4: 01008093 addi ra,ra,16 # 90013010 +800003c8: 0010a023 sw ra,0(ra) +800003cc: 1a00006f j 8000056c -800003c8 : -800003c8: 0180006f j 800003e0 +800003d0 : +800003d0: 00000f17 auipc t5,0x0 +800003d4: 018f0f13 addi t5,t5,24 # 800003e8 +800003d8: 900110b7 lui ra,0x90011 +800003dc: 01008093 addi ra,ra,16 # 90011010 +800003e0: 00008067 ret +800003e4: 1880006f j 8000056c -800003cc : -800003cc: 18005073 csrwi satp,0 -800003d0: 0040006f j 800003d4 +800003e8 : +800003e8: 01500e13 li t3,21 +800003ec: 00000e93 li t4,0 +800003f0: 000800b7 lui ra,0x80 +800003f4: 1000a073 csrs sstatus,ra +800003f8: 900120b7 lui ra,0x90012 +800003fc: 00808093 addi ra,ra,8 # 90012008 +80000400: 5b5a6137 lui sp,0x5b5a6 +80000404: 95810113 addi sp,sp,-1704 # 5b5a5958 <_start-0x24a5a6a8> +80000408: 0000a083 lw ra,0(ra) +8000040c: 16209063 bne ra,sp,8000056c +80000410: 000800b7 lui ra,0x80 +80000414: 1000b073 csrc sstatus,ra -800003d4 : -800003d4: f0100137 lui sp,0xf0100 -800003d8: f2410113 addi sp,sp,-220 # f00fff24 -800003dc: 01c12023 sw t3,0(sp) +80000418 : +80000418: 00000e93 li t4,0 +8000041c: 01400e13 li t3,20 +80000420: 900140b7 lui ra,0x90014 +80000424: 38008093 addi ra,ra,896 # 90014380 +80000428: aaee0137 lui sp,0xaaee0 +8000042c: 00510113 addi sp,sp,5 # aaee0005 +80000430: 0020a023 sw sp,0(ra) +80000434: 0000a083 lw ra,0(ra) +80000438: 12209a63 bne ra,sp,8000056c +8000043c: 000400b7 lui ra,0x40 +80000440: 1000b073 csrc sstatus,ra +80000444: 00100e93 li t4,1 +80000448: 00000f17 auipc t5,0x0 +8000044c: 018f0f13 addi t5,t5,24 # 80000460 +80000450: 900110b7 lui ra,0x90011 +80000454: 64808093 addi ra,ra,1608 # 90011648 +80000458: 0010a023 sw ra,0(ra) +8000045c: 1100006f j 8000056c -800003e0 : -800003e0: 18005073 csrwi satp,0 -800003e4: 0040006f j 800003e8 +80000460 : +80000460: 03200e13 li t3,50 +80000464: 00000e93 li t4,0 +80000468: 000400b7 lui ra,0x40 +8000046c: 1000a073 csrs sstatus,ra +80000470: 18002573 csrr a0,satp +80000474: 18001073 csrw satp,zero +80000478: 00002097 auipc ra,0x2 +8000047c: b8808093 addi ra,ra,-1144 # 80002000 +80000480: 80000137 lui sp,0x80000 +80000484: 00215113 srli sp,sp,0x2 +80000488: 01f16113 ori sp,sp,31 +8000048c: 0020a023 sw sp,0(ra) +80000490: 18051073 csrw satp,a0 +80000494: 10000093 li ra,256 +80000498: 1000b073 csrc sstatus,ra +8000049c: 00000097 auipc ra,0x0 +800004a0: 01808093 addi ra,ra,24 # 800004b4 +800004a4: 14109073 csrw sepc,ra +800004a8: 12000073 sfence.vma +800004ac: 10200073 sret +800004b0: 0bc0006f j 8000056c -800003e8 : -800003e8: f0100137 lui sp,0xf0100 -800003ec: f2010113 addi sp,sp,-224 # f00fff20 -800003f0: 00012023 sw zero,0(sp) +800004b4 : +800004b4: 03300e13 li t3,51 +800004b8: 900110b7 lui ra,0x90011 +800004bc: 00808093 addi ra,ra,8 # 90011008 +800004c0: 5b5a6137 lui sp,0x5b5a6 +800004c4: 95810113 addi sp,sp,-1704 # 5b5a5958 <_start-0x24a5a6a8> +800004c8: 0000a083 lw ra,0(ra) +800004cc: 0a209063 bne ra,sp,8000056c +800004d0: a000a0b7 lui ra,0xa000a +800004d4: 32408093 addi ra,ra,804 # a000a324 +800004d8: aaee0137 lui sp,0xaaee0 +800004dc: 00810113 addi sp,sp,8 # aaee0008 +800004e0: 0020a023 sw sp,0(ra) +800004e4: 0000a083 lw ra,0(ra) +800004e8: 08209263 bne ra,sp,8000056c -800003f4 : -800003f4: fc0e8ce3 beqz t4,800003cc -800003f8: 342020f3 csrr ra,mcause -800003fc: 341020f3 csrr ra,mepc -80000400: 341f1073 csrw mepc,t5 -80000404: 30200073 mret -80000408: 00000013 nop -8000040c: 00000013 nop -80000410: 00000013 nop -80000414: 00000013 nop -80000418: 00000013 nop -8000041c: 00000013 nop -80000420: 00000013 nop -80000424: 00000013 nop -80000428: 00000013 nop -8000042c: 00000013 nop -80000430: 00000013 nop -80000434: 00000013 nop -80000438: 00000013 nop -8000043c: 00000013 nop -80000440: 00000013 nop -80000444: 00000013 nop -80000448: 00000013 nop -8000044c: 00000013 nop -80000450: 00000013 nop -80000454: 00000013 nop -80000458: 00000013 nop -8000045c: 00000013 nop -80000460: 00000013 nop -80000464: 00000013 nop -80000468: 00000013 nop -8000046c: 00000013 nop -80000470: 00000013 nop -80000474: 00000013 nop -80000478: 00000013 nop -8000047c: 00000013 nop -80000480: 00000013 nop -80000484: 00000013 nop -80000488: 00000013 nop -8000048c: 00000013 nop -80000490: 00000013 nop -80000494: 00000013 nop -80000498: 00000013 nop -8000049c: 00000013 nop -800004a0: 00000013 nop -800004a4: 00000013 nop -800004a8: 00000013 nop -800004ac: 00000013 nop -800004b0: 00000013 nop -800004b4: 00000013 nop -800004b8: 00000013 nop -800004bc: 00000013 nop -800004c0: 00000013 nop -800004c4: 00000013 nop -800004c8: 00000013 nop -800004cc: 00000013 nop -800004d0: 00000013 nop -800004d4: 00000013 nop -800004d8: 00000013 nop -800004dc: 00000013 nop -800004e0: 00000013 nop -800004e4: 00000013 nop -800004e8: 00000013 nop -800004ec: 00000013 nop -800004f0: 00000013 nop -800004f4: 00000013 nop -800004f8: 00000013 nop -800004fc: 00000013 nop -80000500: 00000013 nop -80000504: 00000013 nop -80000508: 00000013 nop -8000050c: 00000013 nop -80000510: 00000013 nop -80000514: 00000013 nop -80000518: 00000013 nop -8000051c: 00000013 nop -80000520: 00000013 nop -80000524: 00000013 nop -80000528: 00000013 nop -8000052c: 00000013 nop -80000530: 00000013 nop -80000534: 00000013 nop -80000538: 00000013 nop -8000053c: 00000013 nop -80000540: 00000013 nop -80000544: 00000013 nop -80000548: 00000013 nop -8000054c: 00000013 nop -80000550: 00000013 nop -80000554: 00000013 nop -80000558: 00000013 nop -8000055c: 00000013 nop -80000560: 00000013 nop -80000564: 00000013 nop -80000568: 00000013 nop -8000056c: 00000013 nop -80000570: 00000013 nop -80000574: 00000013 nop -80000578: 00000013 nop -8000057c: 00000013 nop -80000580: 00000013 nop -80000584: 00000013 nop -80000588: 00000013 nop -8000058c: 00000013 nop -80000590: 00000013 nop -80000594: 00000013 nop -80000598: 00000013 nop -8000059c: 00000013 nop -800005a0: 00000013 nop -800005a4: 00000013 nop -800005a8: 00000013 nop -800005ac: 00000013 nop +800004ec : +800004ec: 03400e13 li t3,52 +800004f0: 00000097 auipc ra,0x0 +800004f4: 01808093 addi ra,ra,24 # 80000508 +800004f8: 90012137 lui sp,0x90012 +800004fc: 01010113 addi sp,sp,16 # 90012010 +80000500: 00010067 jr sp +80000504: 0680006f j 8000056c + +80000508 : +80000508: 03500e13 li t3,53 +8000050c: 00100e93 li t4,1 +80000510: 00000f17 auipc t5,0x0 +80000514: 018f0f13 addi t5,t5,24 # 80000528 +80000518: 900140b7 lui ra,0x90014 +8000051c: 39008093 addi ra,ra,912 # 90014390 +80000520: 00008067 ret +80000524: 0480006f j 8000056c + +80000528 : +80000528: 03600e13 li t3,54 +8000052c: 00100e93 li t4,1 +80000530: 00000f17 auipc t5,0x0 +80000534: 018f0f13 addi t5,t5,24 # 80000548 +80000538: 900140b7 lui ra,0x90014 +8000053c: 39408093 addi ra,ra,916 # 90014394 +80000540: 0000a083 lw ra,0(ra) +80000544: 0280006f j 8000056c + +80000548 : +80000548: 03700e13 li t3,55 +8000054c: 00100e93 li t4,1 +80000550: 00000f17 auipc t5,0x0 +80000554: 018f0f13 addi t5,t5,24 # 80000568 +80000558: 900140b7 lui ra,0x90014 +8000055c: 39808093 addi ra,ra,920 # 90014398 +80000560: 0010a023 sw ra,0(ra) +80000564: 0080006f j 8000056c + +80000568 : +80000568: 0180006f j 80000580 + +8000056c : +8000056c: 00000e93 li t4,0 +80000570: 00000073 ecall + +80000574 : +80000574: f0100137 lui sp,0xf0100 +80000578: f2410113 addi sp,sp,-220 # f00fff24 +8000057c: 01c12023 sw t3,0(sp) + +80000580 : +80000580: 00200e93 li t4,2 +80000584: 00000073 ecall + +80000588 : +80000588: f0100137 lui sp,0xf0100 +8000058c: f2010113 addi sp,sp,-224 # f00fff20 +80000590: 00012023 sw zero,0(sp) + +80000594 : +80000594: fe0e80e3 beqz t4,80000574 +80000598: 342020f3 csrr ra,mcause +8000059c: 341020f3 csrr ra,mepc +800005a0: 00200093 li ra,2 +800005a4: fe1e82e3 beq t4,ra,80000588 +800005a8: 341f1073 csrw mepc,t5 +800005ac: 30200073 mret 800005b0: 00000013 nop 800005b4: 00000013 nop 800005b8: 00000013 nop diff --git a/src/test/cpp/raw/mmu/build/mmu.hex b/src/test/cpp/raw/mmu/build/mmu.hex index a473dd93..bcf2f1da 100644 --- a/src/test/cpp/raw/mmu/build/mmu.hex +++ b/src/test/cpp/raw/mmu/build/mmu.hex @@ -1,17 +1,17 @@ :0200000480007A -:10000000930E0000970000009380003F73905030E3 +:10000000930E0000970000009380005973905030C9 :10001000130E1000977000009380C0FE3721262732 -:100020001301415283A040006392203A130E200036 +:100020001301415283A0400063922054130E20001C :10003000970000009380000273901034B7200000F6 -:100040009380008073900030730020306F00003880 +:100040009380008073900030730020306F00005266 :10005000130E3000B71000009380008073900030C2 :10006000970000009380400173901034730020309B -:100070006F00C035130E400097800000938080F819 -:10008000373136371301415383A040006390203449 +:100070006F00C04F130E400097800000938080F8FF +:10008000373136371301415383A040006390204E2F :10009000130E5000971000009380C07617210000C7 :1000A000130141F6135121001361110123A0200017 :1000B00097200000938000F5370100801351210044 -:1000C0001361F10123A02000130E500097200000BF +:1000C0001361F10023A02000130E500097200000C0 :1000D00093804083173100001301C1F213512100B6 :1000E0001361110123A0200097300000938000F4D9 :1000F00017910000130101F1135121001361F10167 @@ -22,74 +22,74 @@ :100140009380C0F017A100001301C1EB13512100EF :100150001361910123A0200097300000938040EFAD :1001600017A10000130101EA135121001361B1012D -:1001700023A02000130E5000972000009380808859 -:1001800017010000130101E8135121001361F1016F -:1001900023A02000130E500097200000938080962B -:1001A00023A00000B700040073A000109710000007 -:1001B000938040E593D0C00037010080B3E0200079 -:1001C00073900018130E6000B7A000909380800019 -:1001D00037514A4B1301819483A000006398201E7D -:1001E000130E7000B7A00090938000363701EEAA7E -:1001F0001301110023A0200083A000006398201C9D -:10020000130E800097C00020938000E0377176774E -:100210001301415783A00000639A201A130E900027 -:10022000B7A000A0938000363701EEAA1301210089 -:1002300023A0200083A00000639A2018130EA000C2 -:1002400073500018979000009380C0113701EEAAF8 -:100250001301110083A00000639A2016130EB00052 -:1002600097A00000938000103701EEAA130121002F -:1002700083A00000639C201497100000938080D816 -:1002800093D0C00037010080B3E0200073900018C5 -:10029000130EC000930E1000170F0000130F0F0174 -:1002A000730000006F008012130ED000170F0000C3 -:1002B000130F4F01B70000B083A080006F00001142 -:1002C000130EE000170F0000130F4F01B70000B02E -:1002D00023A410006F00800F130EF000170F000012 -:1002E000130F4F01B70000B0678000006F00000ED1 -:1002F000130E0001930E0000B70001909380800060 -:1003000037615A5B1301819583A000006390200C34 -:10031000B71001909380800037615A5B130181957B -:1003200083A000006394200AB7300190938080007E -:1003300037615A5B1301819583A000006398200800 -:10034000130E1001B7100190938000363701EEAA0A -:100350001301310023A0200083A000006398200631 -:10036000130E200197000000938080013721019037 -:1003700013010101670001006F004005930E10009A -:10038000170F0000130F8F01B72001909380000119 -:1003900083A000006F008003170F0000130F8F0170 -:1003A000B73001909380000123A010006F0000027D -:1003B000170F0000130F8F01B710019093800001F9 -:1003C000678000006F0080006F008001735000188C -:1003D0006F004000370110F0130141F22320C101EA -:1003E000735000186F004000370110F0130101F244 -:1003F00023200100E38C0EFCF3202034F320103482 -:1004000073101F347300203013000000130000002D -:100410001300000013000000130000001300000090 -:100420001300000013000000130000001300000080 -:100430001300000013000000130000001300000070 -:100440001300000013000000130000001300000060 -:100450001300000013000000130000001300000050 -:100460001300000013000000130000001300000040 -:100470001300000013000000130000001300000030 -:100480001300000013000000130000001300000020 -:100490001300000013000000130000001300000010 -:1004A0001300000013000000130000001300000000 -:1004B00013000000130000001300000013000000F0 -:1004C00013000000130000001300000013000000E0 -:1004D00013000000130000001300000013000000D0 -:1004E00013000000130000001300000013000000C0 -:1004F00013000000130000001300000013000000B0 -:10050000130000001300000013000000130000009F -:10051000130000001300000013000000130000008F -:10052000130000001300000013000000130000007F -:10053000130000001300000013000000130000006F -:10054000130000001300000013000000130000005F -:10055000130000001300000013000000130000004F -:10056000130000001300000013000000130000003F -:10057000130000001300000013000000130000002F -:10058000130000001300000013000000130000001F -:10059000130000001300000013000000130000000F -:1005A00013000000130000001300000013000000FF +:1001700023A02000973000009380C0ED17A100005D +:10018000130141E8135121001361F10023A0200065 +:10019000130E5000972000009380C08617010000C6 +:1001A000130141E6135121001361F10123A0200046 +:1001B000130E5000972000009380C09423A00000ED +:1001C000B700040073A0001097100000938080E334 +:1001D00093D0C00037010080B3E020007390001876 +:1001E000130E6000B7A000909380800037514A4BF7 +:1001F0001301819483A00000639A2036130E7000CF +:10020000B7A00090938000363701EEAA13011100C9 +:1002100023A0200083A00000639A2034130E8000E6 +:1002200097C00020938040DE3771767713014157E5 +:1002300083A00000639C2032130E9000B7A000A0A2 +:10024000938000363701EEAA1301210023A020007D +:1002500083A00000639C2030130EA0007350001890 +:1002600097900000938000103701EEAA130111004F +:1002700083A00000639C202E130EB00097A0000006 +:100280009380400E3701EEAA1301210083A00000E5 +:10029000639E202C971000009380C0D693D0C0009E +:1002A00037010080B3E0200073900018130EC000E7 +:1002B000930E1000170F0000130F0F0173000000C2 +:1002C0006F00C02A130ED000170F0000130F4F014C +:1002D000B70000B083A080006F004029130EE0003B +:1002E000170F0000130F4F01B70000B023A4100038 +:1002F0006F00C027130EF000170F0000130F4F01FF +:10030000B70000B0678000006F004026130E0001A8 +:10031000930E0000B70001909380800037615A5B14 +:100320001301819583A0000063922024B7100190EF +:100330009380800037615A5B1301819583A0000090 +:1003400063962022B73001909380800037615A5B1A +:100350001301819583A00000639A2020130E1001E1 +:10036000B7100190938000363701EEAA13013100D7 +:1003700023A0200083A00000639A201E130E2001FA +:100380009700000093808001372101901301010143 +:10039000670001006F00801D130E3001930E1000E6 +:1003A000170F0000130F8F01B720019093800001F9 +:1003B00083A000006F00801B170F0000130F8F0138 +:1003C000B73001909380000123A010006F00001A45 +:1003D000170F0000130F8F01B710019093800001D9 +:1003E000678000006F008018130E5001930E00000C +:1003F000B700080073A00010B72001909380800020 +:1004000037615A5B1301819583A000006390201629 +:10041000B700080073B00010930E0000130E4001E7 +:10042000B7400190938000383701EEAA13015100C4 +:1004300023A0200083A00000639A2012B7000400CC +:1004400073B00010930E1000170F0000130F8F01F0 +:10045000B71001909380806423A010006F000011FA +:10046000130E2003930E0000B700040073A00010C9 +:10047000732500187310001897200000938080B82F +:1004800037010080135121001361F10123A02000E6 +:10049000731005189300001073B00010970000004F +:1004A0009380800173901014730000127300201069 +:1004B0006F00C00B130E3003B710019093808000C3 +:1004C00037615A5B1301819583A000006390200A75 +:1004D000B7A000A0938040323701EEAA130181003B +:1004E00023A0200083A0000063922008130E400385 +:1004F00097000000938080013721019013010101D2 +:10050000670001006F008006130E5003930E100069 +:10051000170F0000130F8F01B7400190938000392F +:10052000678000006F008004130E6003930E1000BC +:10053000170F0000130F8F01B740019093804039CF +:1005400083A000006F008002130E7003930E100052 +:10055000170F0000130F8F01B7400190938080396F +:1005600023A010006F0080006F008001930E000038 +:1005700073000000370110F0130141F22320C10184 +:10058000930E200073000000370110F0130101F2F8 +:1005900023200100E3800EFEF3202034F3201034EA +:1005A00093002000E3821EFE73101F34730020307E :1005B00013000000130000001300000013000000EF :1005C00013000000130000001300000013000000DF :1005D00013000000130000001300000013000000CF @@ -3229,32 +3229,6 @@ :10C9B0000000000000000000000000000000000077 :10C9C0000000000000000000000000000000000067 :10C9D0000000000000000000000000000000000057 -:10C9E0000000000000000000000000000000000047 -:10C9F0000000000000000000000000000000000037 -:10CA00000000000000000000000000000000000026 -:10CA10000000000000000000000000000000000016 -:10CA20000000000000000000000000000000000006 -:10CA300000000000000000000000000000000000F6 -:10CA400000000000000000000000000000000000E6 -:10CA500000000000000000000000000000000000D6 -:10CA600000000000000000000000000000000000C6 -:10CA700000000000000000000000000000000000B6 -:10CA800000000000000000000000000000000000A6 -:10CA90000000000000000000000000000000000096 -:10CAA0000000000000000000000000000000000086 -:10CAB0000000000000000000000000000000000076 -:10CAC0000000000000000000000000000000000066 -:10CAD0000000000000000000000000000000000056 -:10CAE0000000000000000000000000000000000046 -:10CAF0000000000000000000000000000000000036 -:10CB00000000000000000000000000000000000025 -:10CB10000000000000000000000000000000000015 -:10CB20000000000000000000000000000000000005 -:10CB300000000000000000000000000000000000F5 -:10CB400000000000000000000000000000000000E5 -:10CB500000000000000000000000000000000000D5 -:10CB600000000000000000000000000000000000C5 -:10CB700000000000000000000000000000000000B5 -:0CCB8000000000000000000000000000A9 +:04C9E0000000000053 :040000058000000077 :00000001FF diff --git a/src/test/cpp/raw/mmu/src/crt.S b/src/test/cpp/raw/mmu/src/crt.S index 5c48514e..afee5dd7 100644 --- a/src/test/cpp/raw/mmu/src/crt.S +++ b/src/test/cpp/raw/mmu/src/crt.S @@ -1,21 +1,26 @@ .globl _start +#define TEST_ID x28 +#define TRAP_OK x29 +#define TRAP_RET x30 + + ROM_SUPER_0: _start: - li x29, 0 //Do not allow trap + li TRAP_OK, 0 //Do not allow trap la x1, trap csrw mtvec, x1 test1: //test ram - li x28, 1 + li TEST_ID, 1 la x1, ROM_2 li x2, 0x27262524 lw x1, 4(x1) bne x1, x2, fail test2: //dummy mret - li x28, 2 + li TEST_ID, 2 la x1, test3 csrw mepc, x1 li x1, 0x1800 @@ -25,7 +30,7 @@ test2: //dummy mret test3: // jump to supervisor - li x28, 3 + li TEST_ID, 3 li x1, 0x0800 csrw mstatus, x1 la x1, test4 @@ -36,7 +41,7 @@ test3: // jump to supervisor test4: //test ram mmu off - li x28, 4 + li TEST_ID, 4 la x1, ROM_3 li x2, 0x37363534 lw x1, 4(x1) @@ -44,7 +49,7 @@ test4: //test ram mmu off test5: //setup MMU - li x28, 5 + li TEST_ID, 5 la x1, MMU_TABLE_0 + 0x800 la x2, MMU_TABLE_1 srli x2, x2, 2 @@ -54,11 +59,11 @@ test5: //setup MMU la x1, MMU_TABLE_1 + 0x000*4 li x2, 0x80000000 srli x2, x2, 2 - ori x2, x2, 0x1F + ori x2, x2, 0x0F sw x2, 0(x1) - li x28, 5 + li TEST_ID, 5 la x1, MMU_TABLE_0 + 0x900 la x2, MMU_TABLE_2 srli x2, x2, 2 @@ -95,14 +100,20 @@ test5: //setup MMU ori x2, x2, 0x11 + (0x5 << 1) sw x2, 0(x1) - li x28, 5 + la x1, MMU_TABLE_2 + 0x014*4 //no user + la x2, ROM_5 + srli x2, x2, 2 + ori x2, x2, 0x01 + (0x7 << 1) + sw x2, 0(x1) + + li TEST_ID, 5 la x1, MMU_TABLE_0 + 0xA00 la x2, ROM_SUPER_0 srli x2, x2, 2 ori x2, x2, 0x1F sw x2, 0(x1) - li x28, 5 + li TEST_ID, 5 la x1, MMU_TABLE_0 + 0xB00 sw x0, 0(x1) @@ -117,7 +128,7 @@ test5: //setup MMU test6: //read through MMU - li x28, 6 + li TEST_ID, 6 li x1, 0x9000A008 li x2, 0x4B4A4948 lw x1, 0(x1) @@ -126,7 +137,7 @@ test6: //read through MMU test7: //write-read through MMU - li x28, 7 + li TEST_ID, 7 li x1, 0x9000A360 li x2, 0xAAEE0001 sw x2, 0(x1) @@ -135,7 +146,7 @@ test7: //write-read through MMU test8: //read through MMU super page - li x28, 8 + li TEST_ID, 8 la x1, ROM_7 + 0x20000004 li x2, 0x77767574 lw x1, 0(x1) @@ -144,7 +155,7 @@ test8: //read through MMU super page test9: //write-read through MMU super page - li x28, 9 + li TEST_ID, 9 li x1, 0xA000A360 li x2, 0xAAEE0002 sw x2, 0(x1) @@ -154,7 +165,7 @@ test9: //write-read through MMU super page test10: //check previously written value without the MMU - li x28, 10 + li TEST_ID, 10 csrwi satp, 0 la x1, ROM_4 + 0x360 @@ -164,7 +175,7 @@ test10: //check previously written value without the MMU test11: - li x28, 11 + li TEST_ID, 11 la x1, ROM_SUPER_0 + 0xA360 li x2, 0xAAEE0002 lw x1, 0(x1) @@ -179,32 +190,32 @@ test11: test12: //Dummy trap - li x28, 12 - li x29, 1 //Allow trap - la x30, test13 // trap return address + li TEST_ID, 12 + li TRAP_OK, 1 //Allow trap + la TRAP_RET, test13 // trap return address ecall j fail test13: //Trap load page fault - li x28, 13 - la x30, test14 + li TEST_ID, 13 + la TRAP_RET, test14 li x1, 0xB0000000 lw x1, 8(x1) j fail test14: //Trap store page fault - li x28, 14 - la x30, test15 + li TEST_ID, 14 + la TRAP_RET, test15 li x1, 0xB0000000 sw x1, 8(x1) j fail test15: //Trap instruction fetch - li x28, 15 - la x30, test15_end + li TEST_ID, 15 + la TRAP_RET, test15_end li x1, 0xB0000000 jr x1 j fail @@ -213,8 +224,8 @@ test15_end: test16: //Test limited read access - li x28, 16 - li x29, 0 //disable trap + li TEST_ID, 16 + li TRAP_OK, 0 //disable trap li x1, 0x90010008 li x2, 0x5B5A5958 @@ -233,7 +244,7 @@ test16: //Test limited read access bne x1, x2, fail test17: //Test limited write access - li x28, 17 + li TEST_ID, 17 li x1, 0x90011360 li x2, 0xAAEE0003 @@ -242,7 +253,7 @@ test17: //Test limited write access bne x1, x2, fail test18: //Test limited execute access - li x28, 18 + li TEST_ID, 18 la x1, test18_end li x2, 0x90012010 @@ -252,46 +263,166 @@ test18_end: test19: //exception by access limitations - li x29, 1 //Allow trap - la x30, test19_readTrap + li TEST_ID, 19 + li TRAP_OK, 1 //Allow trap + la TRAP_RET, test19_readTrap li x1, 0x90012010 lw x1, 0(x1) j fail test19_readTrap: - la x30, test19_writeTrap + la TRAP_RET, test19_writeTrap li x1, 0x90013010 sw x1, 0(x1) j fail test19_writeTrap: - la x30, test19_executeTrap + la TRAP_RET, test19_executeTrap li x1, 0x90011010 jr x1 j fail test19_executeTrap: +test20: //mxr set, read executable + li TEST_ID, 21 + li TRAP_OK, 0 + li x1, 1 << 19 + csrs sstatus, x1 + li x1, 0x90012008 + li x2, 0x5B5A5958 + lw x1, 0(x1) + bne x1, x2, fail + li x1, 1 << 19 + csrc sstatus, x1 + + +test21: //supervisor accessing not user + li TRAP_OK, 0 + li TEST_ID, 20 + li x1, 0x90014380 + li x2, 0xAAEE0005 + sw x2, 0(x1) + lw x1, 0(x1) + bne x1, x2, fail + + + + li x1, 1 << 18 //clear SUM + csrc sstatus, x1 + li TRAP_OK, 1 + la TRAP_RET, test21_pass + li x1, 0x90011648 + sw x1, 0(x1) + j fail + +test21_pass: + + + + + +test50: //User mode setup + li TEST_ID, 50 + li TRAP_OK, 0 + + //set SUM + li x1, 1 << 18 + csrs sstatus, x1 + + //remap code tlb into userspace + csrr x10, satp + csrw satp, x0 + la x1, MMU_TABLE_1 + 0x000*4 + li x2, 0x80000000 + srli x2, x2, 2 + ori x2, x2, 0x1F + sw x2, 0(x1) + csrw satp, x10 + + li x1, 1 << 8 + csrc sstatus, x1 //clear SPP + + la x1, test51 + csrw sepc, x1 + sfence.vma + sret + j fail + +test51: //user read/write + li TEST_ID, 51 + li x1, 0x90011008 + li x2, 0x5B5A5958 + lw x1, 0(x1) + bne x1, x2, fail + + li x1, 0xA000A324 + li x2, 0xAAEE0008 + sw x2, 0(x1) + lw x1, 0(x1) + bne x1, x2, fail + +test52: //user fetch + li TEST_ID, 52 + la x1, test53 + li x2, 0x90012010 + jr x2 + j fail + +test53: // user fetch page fault + li TEST_ID, 53 + li TRAP_OK, 1 + la TRAP_RET, test54 + li x1, 0x90014390 + jr x1 + j fail + +test54: //user load page fault + li TEST_ID, 54 + li TRAP_OK, 1 + la TRAP_RET, test55 + li x1, 0x90014394 + lw x1, 0(x1) + j fail + +test55: //user store page fault + li TEST_ID, 55 + li TRAP_OK, 1 + la TRAP_RET, test56 + li x1, 0x90014398 + sw x1, 0(x1) + j fail + +test56: + + + + + + + j pass -fail: //x28 => error code - csrwi satp, 0 - j failFence +fail: //TEST_ID => error code + li TRAP_OK, 0 + ecall failFence: li x2, 0xF00FFF24 - sw x28, 0(x2) + sw TEST_ID, 0(x2) pass: - csrwi satp, 0 - j passFence + li TRAP_OK, 2 + ecall passFence: li x2, 0xF00FFF20 sw x0, 0(x2) trap: - beq x29, x0, fail + beq TRAP_OK, x0, failFence csrr x1, mcause csrr x1, mepc - csrw mepc, x30 + li x1, 2 + beq TRAP_OK, x1, passFence + csrw mepc, TRAP_RET mret diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 47bc3614..fceb5a97 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -736,7 +736,11 @@ public: pcWrite(pc + 4); }break; default: - ilegalInstruction(); + if((i & 0xFE007FFF) == 0x12000073){ //SFENCE.VMA + pcWrite(pc + 4); + }else { + ilegalInstruction(); + } break; } } else { From 9139b4d2698fafbb13c01aa3558d8903966f4fb6 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 22 Mar 2019 18:03:35 +0100 Subject: [PATCH 063/951] Restore all tests --- src/test/cpp/regression/main.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index fceb5a97..36f75e00 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -2963,10 +2963,10 @@ int main(int argc, char **argv, char **env) { printf("BOOT\n"); timespec startedAt = timer_start(); - #ifdef MMU - redo(REDO,Workspace("mmu").withRiscvRef()->loadHex("../raw/mmu/build/mmu.hex")->bootAt(0x80000000u)->run(50e3);); - #endif - return 0; +// #ifdef MMU +// redo(REDO,Workspace("mmu").withRiscvRef()->loadHex("../raw/mmu/build/mmu.hex")->bootAt(0x80000000u)->run(50e3);); +// #endif +// return 0; for(int idx = 0;idx < 1;idx++){ From 3652ede1302d42538b0ae19227ff4875510562c2 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sat, 23 Mar 2019 11:41:10 +0100 Subject: [PATCH 064/951] Add mdeleg tests --- .../scala/vexriscv/plugin/CsrPlugin.scala | 2 + src/test/cpp/raw/common/asm.mk | 2 - src/test/cpp/raw/deleg/.gitignore | 4 + src/test/cpp/raw/deleg/build/deleg.asm | 399 +++++ src/test/cpp/raw/deleg/build/deleg.hex | 90 + src/test/cpp/raw/deleg/makefile | 3 + src/test/cpp/raw/deleg/src/crt.S | 273 +++ src/test/cpp/raw/deleg/src/encoding.h | 1471 +++++++++++++++++ src/test/cpp/raw/deleg/src/ld | 16 + src/test/cpp/raw/mmu/build/mmu.asm | 10 +- src/test/cpp/raw/mmu/build/mmu.hex | 5 +- src/test/cpp/raw/mmu/src/crt.S | 1 + src/test/cpp/regression/encoding.h | 1471 +++++++++++++++++ src/test/cpp/regression/main.cpp | 182 +- src/test/cpp/regression/makefile | 5 +- 15 files changed, 3863 insertions(+), 71 deletions(-) create mode 100644 src/test/cpp/raw/deleg/.gitignore create mode 100644 src/test/cpp/raw/deleg/build/deleg.asm create mode 100644 src/test/cpp/raw/deleg/build/deleg.hex create mode 100644 src/test/cpp/raw/deleg/makefile create mode 100644 src/test/cpp/raw/deleg/src/crt.S create mode 100644 src/test/cpp/raw/deleg/src/encoding.h create mode 100644 src/test/cpp/raw/deleg/src/ld create mode 100644 src/test/cpp/regression/encoding.h diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 9834cbab..bcd70d61 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -833,7 +833,9 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception execute plug new Area{ import execute._ //Manage WFI instructions + val inWfi = False.addTag(Verilator.public) if(wfiGenAsWait) when(arbitration.isValid && input(ENV_CTRL) === EnvCtrlEnum.WFI){ + inWfi := True when(!interrupt){ arbitration.haltItself := True } diff --git a/src/test/cpp/raw/common/asm.mk b/src/test/cpp/raw/common/asm.mk index a4f94f6a..88db8ab1 100644 --- a/src/test/cpp/raw/common/asm.mk +++ b/src/test/cpp/raw/common/asm.mk @@ -1,5 +1,3 @@ -PROJ_NAME=mmu - RISCV_PATH?=/opt/riscv/ CFLAGS += -march=rv32i -mabi=ilp32 diff --git a/src/test/cpp/raw/deleg/.gitignore b/src/test/cpp/raw/deleg/.gitignore new file mode 100644 index 00000000..c12cb2c2 --- /dev/null +++ b/src/test/cpp/raw/deleg/.gitignore @@ -0,0 +1,4 @@ +*.map +*.v +*.elf +*.o \ No newline at end of file diff --git a/src/test/cpp/raw/deleg/build/deleg.asm b/src/test/cpp/raw/deleg/build/deleg.asm new file mode 100644 index 00000000..d6bf46a0 --- /dev/null +++ b/src/test/cpp/raw/deleg/build/deleg.asm @@ -0,0 +1,399 @@ + +build/deleg.elf: file format elf32-littleriscv + + +Disassembly of section .crt_section: + +80000000 <_start>: +80000000: 00100e93 li t4,1 +80000004: 00000097 auipc ra,0x0 +80000008: 50408093 addi ra,ra,1284 # 80000508 +8000000c: 30509073 csrw mtvec,ra +80000010: 00000097 auipc ra,0x0 +80000014: 52c08093 addi ra,ra,1324 # 8000053c +80000018: 10509073 csrw stvec,ra +8000001c: f00110b7 lui ra,0xf0011 +80000020: 00000113 li sp,0 +80000024: 0020a023 sw sp,0(ra) # f0011000 + +80000028 : +80000028: 00100e13 li t3,1 +8000002c: 00000f17 auipc t5,0x0 +80000030: 00cf0f13 addi t5,t5,12 # 80000038 +80000034: 00000073 ecall + +80000038 : +80000038: 00200e13 li t3,2 +8000003c: 000020b7 lui ra,0x2 +80000040: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800> +80000044: 00000113 li sp,0 +80000048: 3000b073 csrc mstatus,ra +8000004c: 30012073 csrs mstatus,sp +80000050: 00000097 auipc ra,0x0 +80000054: 01408093 addi ra,ra,20 # 80000064 +80000058: 34109073 csrw mepc,ra +8000005c: 30200073 mret +80000060: 4900006f j 800004f0 +80000064: 00000f17 auipc t5,0x0 +80000068: 024f0f13 addi t5,t5,36 # 80000088 +8000006c: 00000073 ecall +80000070: 4800006f j 800004f0 + +80000074 : +80000074: 00300e13 li t3,3 +80000078: 00000f17 auipc t5,0x0 +8000007c: 010f0f13 addi t5,t5,16 # 80000088 +80000080: 00102083 lw ra,1(zero) # 1 <_start-0x7fffffff> +80000084: 46c0006f j 800004f0 + +80000088 : +80000088: 00400e13 li t3,4 +8000008c: 000020b7 lui ra,0x2 +80000090: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800> +80000094: 00001137 lui sp,0x1 +80000098: 80010113 addi sp,sp,-2048 # 800 <_start-0x7ffff800> +8000009c: 3000b073 csrc mstatus,ra +800000a0: 30012073 csrs mstatus,sp +800000a4: 00000097 auipc ra,0x0 +800000a8: 01408093 addi ra,ra,20 # 800000b8 +800000ac: 34109073 csrw mepc,ra +800000b0: 30200073 mret +800000b4: 43c0006f j 800004f0 +800000b8: 00000f17 auipc t5,0x0 +800000bc: 010f0f13 addi t5,t5,16 # 800000c8 +800000c0: 00102083 lw ra,1(zero) # 1 <_start-0x7fffffff> +800000c4: 42c0006f j 800004f0 + +800000c8 : +800000c8: 00500e13 li t3,5 +800000cc: 000020b7 lui ra,0x2 +800000d0: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800> +800000d4: 00000113 li sp,0 +800000d8: 3000b073 csrc mstatus,ra +800000dc: 30012073 csrs mstatus,sp +800000e0: 00000097 auipc ra,0x0 +800000e4: 01408093 addi ra,ra,20 # 800000f4 +800000e8: 34109073 csrw mepc,ra +800000ec: 30200073 mret +800000f0: 4000006f j 800004f0 +800000f4: 00000f17 auipc t5,0x0 +800000f8: 010f0f13 addi t5,t5,16 # 80000104 +800000fc: 00102083 lw ra,1(zero) # 1 <_start-0x7fffffff> +80000100: 3f00006f j 800004f0 + +80000104 : +80000104: 00600e13 li t3,6 +80000108: 01000093 li ra,16 +8000010c: 30209073 csrw medeleg,ra + +80000110 : +80000110: 00700e13 li t3,7 +80000114: 00000f17 auipc t5,0x0 +80000118: 010f0f13 addi t5,t5,16 # 80000124 +8000011c: 00102083 lw ra,1(zero) # 1 <_start-0x7fffffff> +80000120: 3d00006f j 800004f0 + +80000124 : +80000124: 00800e13 li t3,8 +80000128: 00000f17 auipc t5,0x0 +8000012c: 03cf0f13 addi t5,t5,60 # 80000164 +80000130: 000020b7 lui ra,0x2 +80000134: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800> +80000138: 00001137 lui sp,0x1 +8000013c: 80010113 addi sp,sp,-2048 # 800 <_start-0x7ffff800> +80000140: 3000b073 csrc mstatus,ra +80000144: 30012073 csrs mstatus,sp +80000148: 00000097 auipc ra,0x0 +8000014c: 01408093 addi ra,ra,20 # 8000015c +80000150: 34109073 csrw mepc,ra +80000154: 30200073 mret +80000158: 3980006f j 800004f0 +8000015c: 00102083 lw ra,1(zero) # 1 <_start-0x7fffffff> +80000160: 3900006f j 800004f0 + +80000164 : +80000164: 00900e13 li t3,9 +80000168: 00000f17 auipc t5,0x0 +8000016c: 038f0f13 addi t5,t5,56 # 800001a0 +80000170: 000020b7 lui ra,0x2 +80000174: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800> +80000178: 00000113 li sp,0 +8000017c: 3000b073 csrc mstatus,ra +80000180: 30012073 csrs mstatus,sp +80000184: 00000097 auipc ra,0x0 +80000188: 01408093 addi ra,ra,20 # 80000198 +8000018c: 34109073 csrw mepc,ra +80000190: 30200073 mret +80000194: 35c0006f j 800004f0 +80000198: 00102083 lw ra,1(zero) # 1 <_start-0x7fffffff> +8000019c: 3540006f j 800004f0 + +800001a0 : +800001a0: 00a00e13 li t3,10 +800001a4: 00000f17 auipc t5,0x0 +800001a8: 03cf0f13 addi t5,t5,60 # 800001e0 +800001ac: f00110b7 lui ra,0xf0011 +800001b0: 00000113 li sp,0 +800001b4: 0020a023 sw sp,0(ra) # f0011000 +800001b8: 00800093 li ra,8 +800001bc: 30009073 csrw mstatus,ra +800001c0: 000010b7 lui ra,0x1 +800001c4: 80008093 addi ra,ra,-2048 # 800 <_start-0x7ffff800> +800001c8: 30409073 csrw mie,ra +800001cc: f00110b7 lui ra,0xf0011 +800001d0: 00100113 li sp,1 +800001d4: 0020a023 sw sp,0(ra) # f0011000 +800001d8: 10500073 wfi +800001dc: 3140006f j 800004f0 + +800001e0 : +800001e0: 00b00e13 li t3,11 +800001e4: 00000f17 auipc t5,0x0 +800001e8: 068f0f13 addi t5,t5,104 # 8000024c +800001ec: f00110b7 lui ra,0xf0011 +800001f0: 00000113 li sp,0 +800001f4: 0020a023 sw sp,0(ra) # f0011000 +800001f8: 00800093 li ra,8 +800001fc: 30009073 csrw mstatus,ra +80000200: 000010b7 lui ra,0x1 +80000204: 80008093 addi ra,ra,-2048 # 800 <_start-0x7ffff800> +80000208: 30409073 csrw mie,ra +8000020c: 000020b7 lui ra,0x2 +80000210: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800> +80000214: 00001137 lui sp,0x1 +80000218: 80010113 addi sp,sp,-2048 # 800 <_start-0x7ffff800> +8000021c: 3000b073 csrc mstatus,ra +80000220: 30012073 csrs mstatus,sp +80000224: 00000097 auipc ra,0x0 +80000228: 01408093 addi ra,ra,20 # 80000238 +8000022c: 34109073 csrw mepc,ra +80000230: 30200073 mret +80000234: 2bc0006f j 800004f0 +80000238: f00110b7 lui ra,0xf0011 +8000023c: 00100113 li sp,1 +80000240: 0020a023 sw sp,0(ra) # f0011000 +80000244: 10500073 wfi +80000248: 2a80006f j 800004f0 + +8000024c : +8000024c: 00c00e13 li t3,12 +80000250: 00000f17 auipc t5,0x0 +80000254: 064f0f13 addi t5,t5,100 # 800002b4 +80000258: f00110b7 lui ra,0xf0011 +8000025c: 00000113 li sp,0 +80000260: 0020a023 sw sp,0(ra) # f0011000 +80000264: 00800093 li ra,8 +80000268: 30009073 csrw mstatus,ra +8000026c: 000010b7 lui ra,0x1 +80000270: 80008093 addi ra,ra,-2048 # 800 <_start-0x7ffff800> +80000274: 30409073 csrw mie,ra +80000278: 000020b7 lui ra,0x2 +8000027c: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800> +80000280: 00000113 li sp,0 +80000284: 3000b073 csrc mstatus,ra +80000288: 30012073 csrs mstatus,sp +8000028c: 00000097 auipc ra,0x0 +80000290: 01408093 addi ra,ra,20 # 800002a0 +80000294: 34109073 csrw mepc,ra +80000298: 30200073 mret +8000029c: 2540006f j 800004f0 +800002a0: f00110b7 lui ra,0xf0011 +800002a4: 00100113 li sp,1 +800002a8: 0020a023 sw sp,0(ra) # f0011000 +800002ac: 10500073 wfi +800002b0: 2400006f j 800004f0 + +800002b4 : +800002b4: 00200093 li ra,2 +800002b8: 10009073 csrw sstatus,ra +800002bc: 00e00e13 li t3,14 +800002c0: 00000f17 auipc t5,0x0 +800002c4: 040f0f13 addi t5,t5,64 # 80000300 +800002c8: f00120b7 lui ra,0xf0012 +800002cc: 00000113 li sp,0 +800002d0: 0020a023 sw sp,0(ra) # f0012000 +800002d4: 00200093 li ra,2 +800002d8: 30009073 csrw mstatus,ra +800002dc: 20000093 li ra,512 +800002e0: 30409073 csrw mie,ra +800002e4: 00000e93 li t4,0 +800002e8: f00120b7 lui ra,0xf0012 +800002ec: 00100113 li sp,1 +800002f0: 0020a023 sw sp,0(ra) # f0012000 +800002f4: 06400093 li ra,100 +800002f8: fff08093 addi ra,ra,-1 +800002fc: fe104ee3 bgtz ra,800002f8 + +80000300 : +80000300: 00f00e13 li t3,15 +80000304: 00000f17 auipc t5,0x0 +80000308: 068f0f13 addi t5,t5,104 # 8000036c +8000030c: f00120b7 lui ra,0xf0012 +80000310: 00000113 li sp,0 +80000314: 0020a023 sw sp,0(ra) # f0012000 +80000318: 00200093 li ra,2 +8000031c: 30009073 csrw mstatus,ra +80000320: 20000093 li ra,512 +80000324: 30409073 csrw mie,ra +80000328: 000020b7 lui ra,0x2 +8000032c: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800> +80000330: 00001137 lui sp,0x1 +80000334: 80010113 addi sp,sp,-2048 # 800 <_start-0x7ffff800> +80000338: 3000b073 csrc mstatus,ra +8000033c: 30012073 csrs mstatus,sp +80000340: 00000097 auipc ra,0x0 +80000344: 01408093 addi ra,ra,20 # 80000354 +80000348: 34109073 csrw mepc,ra +8000034c: 30200073 mret +80000350: 1a00006f j 800004f0 +80000354: 00100e93 li t4,1 +80000358: f00120b7 lui ra,0xf0012 +8000035c: 00100113 li sp,1 +80000360: 0020a023 sw sp,0(ra) # f0012000 +80000364: 10500073 wfi +80000368: 1880006f j 800004f0 + +8000036c : +8000036c: 01000e13 li t3,16 +80000370: 00000f17 auipc t5,0x0 +80000374: 060f0f13 addi t5,t5,96 # 800003d0 +80000378: f00120b7 lui ra,0xf0012 +8000037c: 00000113 li sp,0 +80000380: 0020a023 sw sp,0(ra) # f0012000 +80000384: 00200093 li ra,2 +80000388: 30009073 csrw mstatus,ra +8000038c: 20000093 li ra,512 +80000390: 30409073 csrw mie,ra +80000394: 000020b7 lui ra,0x2 +80000398: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800> +8000039c: 00000113 li sp,0 +800003a0: 3000b073 csrc mstatus,ra +800003a4: 30012073 csrs mstatus,sp +800003a8: 00000097 auipc ra,0x0 +800003ac: 01408093 addi ra,ra,20 # 800003bc +800003b0: 34109073 csrw mepc,ra +800003b4: 30200073 mret +800003b8: 1380006f j 800004f0 +800003bc: f00120b7 lui ra,0xf0012 +800003c0: 00100113 li sp,1 +800003c4: 0020a023 sw sp,0(ra) # f0012000 +800003c8: 10500073 wfi +800003cc: 1240006f j 800004f0 + +800003d0 : +800003d0: 01100e13 li t3,17 +800003d4: 20000093 li ra,512 +800003d8: 30309073 csrw mideleg,ra +800003dc: 00000f17 auipc t5,0x0 +800003e0: 040f0f13 addi t5,t5,64 # 8000041c +800003e4: f00120b7 lui ra,0xf0012 +800003e8: 00000113 li sp,0 +800003ec: 0020a023 sw sp,0(ra) # f0012000 +800003f0: 00200093 li ra,2 +800003f4: 30009073 csrw mstatus,ra +800003f8: 20000093 li ra,512 +800003fc: 30409073 csrw mie,ra +80000400: 00000e93 li t4,0 +80000404: f00120b7 lui ra,0xf0012 +80000408: 00100113 li sp,1 +8000040c: 0020a023 sw sp,0(ra) # f0012000 +80000410: 06400093 li ra,100 +80000414: fff08093 addi ra,ra,-1 +80000418: fe104ee3 bgtz ra,80000414 + +8000041c : +8000041c: 01200e13 li t3,18 +80000420: 00000f17 auipc t5,0x0 +80000424: 068f0f13 addi t5,t5,104 # 80000488 +80000428: f00120b7 lui ra,0xf0012 +8000042c: 00000113 li sp,0 +80000430: 0020a023 sw sp,0(ra) # f0012000 +80000434: 00200093 li ra,2 +80000438: 30009073 csrw mstatus,ra +8000043c: 20000093 li ra,512 +80000440: 30409073 csrw mie,ra +80000444: 000020b7 lui ra,0x2 +80000448: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800> +8000044c: 00001137 lui sp,0x1 +80000450: 80010113 addi sp,sp,-2048 # 800 <_start-0x7ffff800> +80000454: 3000b073 csrc mstatus,ra +80000458: 30012073 csrs mstatus,sp +8000045c: 00000097 auipc ra,0x0 +80000460: 01408093 addi ra,ra,20 # 80000470 +80000464: 34109073 csrw mepc,ra +80000468: 30200073 mret +8000046c: 0840006f j 800004f0 +80000470: 00100e93 li t4,1 +80000474: f00120b7 lui ra,0xf0012 +80000478: 00100113 li sp,1 +8000047c: 0020a023 sw sp,0(ra) # f0012000 +80000480: 10500073 wfi +80000484: 06c0006f j 800004f0 + +80000488 : +80000488: 01300e13 li t3,19 +8000048c: 00000f17 auipc t5,0x0 +80000490: 060f0f13 addi t5,t5,96 # 800004ec +80000494: f00120b7 lui ra,0xf0012 +80000498: 00000113 li sp,0 +8000049c: 0020a023 sw sp,0(ra) # f0012000 +800004a0: 00200093 li ra,2 +800004a4: 30009073 csrw mstatus,ra +800004a8: 20000093 li ra,512 +800004ac: 30409073 csrw mie,ra +800004b0: 000020b7 lui ra,0x2 +800004b4: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800> +800004b8: 00000113 li sp,0 +800004bc: 3000b073 csrc mstatus,ra +800004c0: 30012073 csrs mstatus,sp +800004c4: 00000097 auipc ra,0x0 +800004c8: 01408093 addi ra,ra,20 # 800004d8 +800004cc: 34109073 csrw mepc,ra +800004d0: 30200073 mret +800004d4: 01c0006f j 800004f0 +800004d8: f00120b7 lui ra,0xf0012 +800004dc: 00100113 li sp,1 +800004e0: 0020a023 sw sp,0(ra) # f0012000 +800004e4: 10500073 wfi +800004e8: 0080006f j 800004f0 + +800004ec : +800004ec: 0100006f j 800004fc + +800004f0 : +800004f0: f0100137 lui sp,0xf0100 +800004f4: f2410113 addi sp,sp,-220 # f00fff24 +800004f8: 01c12023 sw t3,0(sp) + +800004fc : +800004fc: f0100137 lui sp,0xf0100 +80000500: f2010113 addi sp,sp,-224 # f00fff20 +80000504: 00012023 sw zero,0(sp) + +80000508 : +80000508: fe0e84e3 beqz t4,800004f0 +8000050c: 342020f3 csrr ra,mcause +80000510: 341020f3 csrr ra,mepc +80000514: 300020f3 csrr ra,mstatus +80000518: 08000093 li ra,128 +8000051c: 3000b073 csrc mstatus,ra +80000520: 00200093 li ra,2 +80000524: fc1e8ce3 beq t4,ra,800004fc +80000528: 000020b7 lui ra,0x2 +8000052c: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800> +80000530: 3000a073 csrs mstatus,ra +80000534: 341f1073 csrw mepc,t5 +80000538: 30200073 mret + +8000053c : +8000053c: fa0e8ae3 beqz t4,800004f0 +80000540: 142020f3 csrr ra,scause +80000544: 141020f3 csrr ra,sepc +80000548: 100020f3 csrr ra,sstatus +8000054c: 00000073 ecall +80000550: 00000013 nop +80000554: 00000013 nop +80000558: 00000013 nop +8000055c: 00000013 nop +80000560: 00000013 nop +80000564: 00000013 nop diff --git a/src/test/cpp/raw/deleg/build/deleg.hex b/src/test/cpp/raw/deleg/build/deleg.hex new file mode 100644 index 00000000..10d04288 --- /dev/null +++ b/src/test/cpp/raw/deleg/build/deleg.hex @@ -0,0 +1,90 @@ +:0200000480007A +:10000000930E100097000000938040507390503082 +:10001000970000009380C05273905010B71001F009 +:100020001301000023A02000130E1000170F000082 +:10003000130FCF0073000000130E2000B720000044 +:10004000938000801301000073B0003073200130F2 +:1000500097000000938040017390103473002030AB +:100060006F000049170F0000130F4F0273000000CC +:100070006F000048130E3000170F0000130F0F0120 +:10008000832010006F00C046130E4000B720000010 +:1000900093800080371100001301018073B000309D +:1000A000732001309700000093804001739010345A +:1000B000730020306F00C043170F0000130F0F01B3 +:1000C000832010006F00C042130E5000B7200000C4 +:1000D000938000801301000073B000307320013062 +:1000E000970000009380400173901034730020301B +:1000F0006F000040170F0000130F0F018320100046 +:100100006F00003F130E60009300000173902030D9 +:10011000130E7000170F0000130F0F018320100043 +:100120006F00003D130E8000170F0000130FCF0368 +:10013000B720000093800080371100001301018078 +:1001400073B00030732001309700000093804001AD +:1001500073901034730020306F00803983201000BA +:100160006F000039130E9000170F0000130F8F035C +:10017000B7200000938000801301000073B00030AE +:100180007320013097000000938040017390103479 +:10019000730020306F00C035832010006F004035A1 +:1001A000130EA000170F0000130FCF03B71001F0BC +:1001B0001301000023A02000930080007390003002 +:1001C000B71000009380008073904030B71001F0AA +:1001D0001301100023A02000730050106F00403165 +:1001E000130EB000170F0000130F8F06B71001F0A9 +:1001F0001301000023A020009300800073900030C2 +:10020000B71000009380008073904030B72000004A +:1002100093800080371100001301018073B000301B +:1002200073200130970000009380400173901034D8 +:10023000730020306F00C02BB71001F013011000C5 +:1002400023A02000730050106F00802A130EC000FE +:10025000170F0000130F4F06B71001F01301000035 +:1002600023A020009300800073900030B71000009E +:100270009380008073904030B7200000938000800E +:100280001301000073B000307320013097000000AC +:100290009380400173901034730020306F0040252C +:1002A000B71001F01301100023A0200073005010BC +:1002B0006F0000249300200073900010130EE000E4 +:1002C000170F0000130F0F04B72001F013010000F7 +:1002D00023A02000930020007390003093000020A2 +:1002E00073904030930E0000B72001F0130110000E +:1002F00023A02000930040069380F0FFE34E10FE01 +:10030000130EF000170F0000130F8F06B72001F037 +:100310001301000023A02000930020007390003000 +:100320009300002073904030B7200000938000803D +:10033000371100001301018073B0003073200130C9 +:1003400097000000938040017390103473002030B8 +:100350006F00001A930E1000B72001F01301100077 +:1003600023A02000730050106F008018130E0001AE +:10037000170F0000130F0F06B72001F01301000044 +:1003800023A02000930020007390003093000020F1 +:1003900073904030B720000093800080130100006C +:1003A00073B000307320013097000000938040014B +:1003B00073901034730020306F008013B72001F069 +:1003C0001301100023A02000730050106F00401292 +:1003D000130E10019300002073903030170F0000AF +:1003E000130F0F04B72001F01301000023A0200019 +:1003F00093002000739000309300002073904030F1 +:10040000930E0000B72001F01301100023A020007C +:10041000930040069380F0FFE34E10FE130E200180 +:10042000170F0000130F8F06B72001F01301000013 +:1004300023A0200093002000739000309300002040 +:1004400073904030B7200000938000803711000087 +:100450001301018073B00030732001309700000059 +:100460009380400173901034730020306F00400877 +:10047000930E1000B72001F01301100023A02000FC +:10048000730050106F00C006130E3001170F0000EC +:10049000130F0F06B72001F01301000023A0200066 +:1004A0009300200073900030930000207390403040 +:1004B000B7200000938000801301000073B000306B +:1004C0007320013097000000938040017390103436 +:1004D000730020306F00C001B72001F0130110003D +:1004E00023A02000730050106F0080006F000001F7 +:1004F000370110F0130141F22320C101370110F040 +:10050000130101F223200100E3840EFEF3202034C6 +:10051000F3201034F32000309300000873B0003053 +:1005200093002000E38C1EFCB72000009380008025 +:1005300073A0003073101F3473002030E38A0EFA6A +:10054000F3202014F3201014F32000107300000097 +:10055000130000001300000013000000130000004F +:0805600013000000130000006D +:040000058000000077 +:00000001FF diff --git a/src/test/cpp/raw/deleg/makefile b/src/test/cpp/raw/deleg/makefile new file mode 100644 index 00000000..8f98b68f --- /dev/null +++ b/src/test/cpp/raw/deleg/makefile @@ -0,0 +1,3 @@ +PROJ_NAME=deleg + +include ../common/asm.mk \ No newline at end of file diff --git a/src/test/cpp/raw/deleg/src/crt.S b/src/test/cpp/raw/deleg/src/crt.S new file mode 100644 index 00000000..ad6a323a --- /dev/null +++ b/src/test/cpp/raw/deleg/src/crt.S @@ -0,0 +1,273 @@ +.globl _start + +#define TEST_ID x28 +#define TRAP_OK x29 +#define TRAP_RET x30 + +#include "encoding.h" + +#define externalInterrupt(value) \ + li x1, 0xF0011000; \ + li x2, value; \ + sw x2, 0(x1); \ + +#define externalInterruptS(value) \ + li x1, 0xF0012000; \ + li x2, value; \ + sw x2, 0(x1); \ + + + +#define delay() \ + li x1, 100; \ +1: \ + addi x1, x1, -1; \ + bgt x1, x0, 1b; \ + + +#define setPriv(value) \ + li x1, 3 << 11; \ + li x2, value << 11; \ + csrc mstatus, x1; \ + csrs mstatus, x2; \ + auipc x1, 0; \ + addi x1, x1, 20; \ + csrw mepc, x1; \ + mret; \ + j fail; \ + + +ROM_SUPER_0: + +_start: + li TRAP_OK, 1 + la x1, mtrap + csrw mtvec, x1 + la x1, strap + csrw stvec, x1 + externalInterrupt(0); + +test1: + li TEST_ID, 1 + la TRAP_RET, test2 + ecall + +test2: //simple ecall from user to machine + li TEST_ID, 2 + setPriv(0) + la TRAP_RET, test4 + ecall + j fail + +test3: //M mialigned load exception without deleg + li TEST_ID, 3 + la TRAP_RET, test4 + lw x1, 1(x0) + j fail +test4: //S mialigned load exception without deleg + li TEST_ID, 4 + setPriv(1) + la TRAP_RET, test5 + lw x1, 1(x0) + j fail +test5: //U mialigned load exception without deleg + li TEST_ID, 5 + setPriv(0) + la TRAP_RET, test6 + lw x1, 1(x0) + j fail + +test6: // set medeleg + li TEST_ID, 6 + li x1, 1 << CAUSE_MISALIGNED_LOAD + csrw medeleg, x1 + +test7: //machine mode exception + li TEST_ID, 7 + la TRAP_RET, test8 + lw x1, 1(x0) + j fail + +test8: //supervisor mode exception + li TEST_ID, 8 + la TRAP_RET, test9 + setPriv(1) + lw x1, 1(x0) + j fail + +test9: //user mode exception + li TEST_ID, 9 + la TRAP_RET, test10 + setPriv(0) + lw x1, 1(x0) + j fail + +test10: //M external interrupt + li TEST_ID, 10 + la TRAP_RET, test11 + externalInterrupt(0) + li x1, MSTATUS_MIE + csrw mstatus, x1 + li x1, 1 << 11 + csrw mie, x1 + externalInterrupt(1) + wfi + j fail + +test11: //S external interrupt + li TEST_ID, 11 + la TRAP_RET, test12 + externalInterrupt(0) + li x1, MSTATUS_MIE + csrw mstatus, x1 + li x1, 1 << 11 + csrw mie, x1 + setPriv(1) + externalInterrupt(1) + wfi + j fail + +test12: //U external interrupt + li TEST_ID, 12 + la TRAP_RET, test14 + externalInterrupt(0) + li x1, MSTATUS_MIE + csrw mstatus, x1 + li x1, 1 << 11 + csrw mie, x1 + setPriv(0) + externalInterrupt(1) + wfi + j fail + + + +test14: //M external interrupt S + li x1, MSTATUS_SIE + csrw sstatus, x1 + + li TEST_ID, 14 + la TRAP_RET, test15 + externalInterruptS(0) + li x1, MSTATUS_SIE + csrw mstatus, x1 + li x1, 1 << 9 + csrw mie, x1 + li TRAP_OK, 0 + externalInterruptS(1) + delay() + +test15: //S external interrupt S + li TEST_ID, 15 + la TRAP_RET, test16 + externalInterruptS(0) + li x1, SSTATUS_SIE + csrw mstatus, x1 + li x1, 1 << 9 + csrw mie, x1 + setPriv(1) + li TRAP_OK, 1 + externalInterruptS(1) + wfi + j fail + +test16: //U external interrupt S + li TEST_ID, 16 + la TRAP_RET, test17 + externalInterruptS(0) + li x1, SSTATUS_SIE + csrw mstatus, x1 + li x1, 1 << 9 + csrw mie, x1 + setPriv(0) + externalInterruptS(1) + wfi + j fail + + +test17:// set mideleg + li TEST_ID, 17 + li x1, 1 << 9 + csrw mideleg, x1 + + + la TRAP_RET, test18 + externalInterruptS(0) + li x1, MSTATUS_SIE + csrw mstatus, x1 + li x1, 1 << 9 + csrw mie, x1 + li TRAP_OK, 0 + externalInterruptS(1) + delay() + +test18: //S external interrupt S with deleg + li TEST_ID, 18 + la TRAP_RET, test19 + externalInterruptS(0) + li x1, SSTATUS_SIE + csrw mstatus, x1 + li x1, 1 << 9 + csrw mie, x1 + setPriv(1) + li TRAP_OK, 1 + externalInterruptS(1) + wfi + j fail + +test19: //U external interrupt S with deleg + li TEST_ID, 19 + la TRAP_RET, test20 + externalInterruptS(0) + li x1, SSTATUS_SIE + csrw mstatus, x1 + li x1, 1 << 9 + csrw mie, x1 + setPriv(0) + externalInterruptS(1) + wfi + j fail + + +test20: + j pass + +fail: + li x2, 0xF00FFF24 + sw TEST_ID, 0(x2) + +pass: + li x2, 0xF00FFF20 + sw x0, 0(x2) + + +mtrap: + beq TRAP_OK, x0, fail + csrr x1, mcause + csrr x1, mepc + csrr x1, mstatus + li x1, MSTATUS_MPIE + csrc mstatus, x1 + li x1, 2 + beq TRAP_OK, x1, pass + li x1, 3 << 11 + csrs mstatus, x1 + csrw mepc, TRAP_RET + mret + + +strap: + beq TRAP_OK, x0, fail + csrr x1, scause + csrr x1, sepc + csrr x1, sstatus + ecall + + + + nop + nop + nop + nop + nop + nop diff --git a/src/test/cpp/raw/deleg/src/encoding.h b/src/test/cpp/raw/deleg/src/encoding.h new file mode 100644 index 00000000..c109ce18 --- /dev/null +++ b/src/test/cpp/raw/deleg/src/encoding.h @@ -0,0 +1,1471 @@ +// See LICENSE for license details. + +#ifndef RISCV_CSR_ENCODING_H +#define RISCV_CSR_ENCODING_H + +#define MSTATUS_UIE 0x00000001 +#define MSTATUS_SIE 0x00000002 +#define MSTATUS_HIE 0x00000004 +#define MSTATUS_MIE 0x00000008 +#define MSTATUS_UPIE 0x00000010 +#define MSTATUS_SPIE 0x00000020 +#define MSTATUS_HPIE 0x00000040 +#define MSTATUS_MPIE 0x00000080 +#define MSTATUS_SPP 0x00000100 +#define MSTATUS_HPP 0x00000600 +#define MSTATUS_MPP 0x00001800 +#define MSTATUS_FS 0x00006000 +#define MSTATUS_XS 0x00018000 +#define MSTATUS_MPRV 0x00020000 +#define MSTATUS_SUM 0x00040000 +#define MSTATUS_MXR 0x00080000 +#define MSTATUS_TVM 0x00100000 +#define MSTATUS_TW 0x00200000 +#define MSTATUS_TSR 0x00400000 +#define MSTATUS32_SD 0x80000000 +#define MSTATUS_UXL 0x0000000300000000 +#define MSTATUS_SXL 0x0000000C00000000 +#define MSTATUS64_SD 0x8000000000000000 + +#define SSTATUS_UIE 0x00000001 +#define SSTATUS_SIE 0x00000002 +#define SSTATUS_UPIE 0x00000010 +#define SSTATUS_SPIE 0x00000020 +#define SSTATUS_SPP 0x00000100 +#define SSTATUS_FS 0x00006000 +#define SSTATUS_XS 0x00018000 +#define SSTATUS_SUM 0x00040000 +#define SSTATUS_MXR 0x00080000 +#define SSTATUS32_SD 0x80000000 +#define SSTATUS_UXL 0x0000000300000000 +#define SSTATUS64_SD 0x8000000000000000 + +#define DCSR_XDEBUGVER (3U<<30) +#define DCSR_NDRESET (1<<29) +#define DCSR_FULLRESET (1<<28) +#define DCSR_EBREAKM (1<<15) +#define DCSR_EBREAKH (1<<14) +#define DCSR_EBREAKS (1<<13) +#define DCSR_EBREAKU (1<<12) +#define DCSR_STOPCYCLE (1<<10) +#define DCSR_STOPTIME (1<<9) +#define DCSR_CAUSE (7<<6) +#define DCSR_DEBUGINT (1<<5) +#define DCSR_HALT (1<<3) +#define DCSR_STEP (1<<2) +#define DCSR_PRV (3<<0) + +#define DCSR_CAUSE_NONE 0 +#define DCSR_CAUSE_SWBP 1 +#define DCSR_CAUSE_HWBP 2 +#define DCSR_CAUSE_DEBUGINT 3 +#define DCSR_CAUSE_STEP 4 +#define DCSR_CAUSE_HALT 5 + +#define MCONTROL_TYPE(xlen) (0xfULL<<((xlen)-4)) +#define MCONTROL_DMODE(xlen) (1ULL<<((xlen)-5)) +#define MCONTROL_MASKMAX(xlen) (0x3fULL<<((xlen)-11)) + +#define MCONTROL_SELECT (1<<19) +#define MCONTROL_TIMING (1<<18) +#define MCONTROL_ACTION (0x3f<<12) +#define MCONTROL_CHAIN (1<<11) +#define MCONTROL_MATCH (0xf<<7) +#define MCONTROL_M (1<<6) +#define MCONTROL_H (1<<5) +#define MCONTROL_S (1<<4) +#define MCONTROL_U (1<<3) +#define MCONTROL_EXECUTE (1<<2) +#define MCONTROL_STORE (1<<1) +#define MCONTROL_LOAD (1<<0) + +#define MCONTROL_TYPE_NONE 0 +#define MCONTROL_TYPE_MATCH 2 + +#define MCONTROL_ACTION_DEBUG_EXCEPTION 0 +#define MCONTROL_ACTION_DEBUG_MODE 1 +#define MCONTROL_ACTION_TRACE_START 2 +#define MCONTROL_ACTION_TRACE_STOP 3 +#define MCONTROL_ACTION_TRACE_EMIT 4 + +#define MCONTROL_MATCH_EQUAL 0 +#define MCONTROL_MATCH_NAPOT 1 +#define MCONTROL_MATCH_GE 2 +#define MCONTROL_MATCH_LT 3 +#define MCONTROL_MATCH_MASK_LOW 4 +#define MCONTROL_MATCH_MASK_HIGH 5 + +#define MIP_SSIP (1 << IRQ_S_SOFT) +#define MIP_HSIP (1 << IRQ_H_SOFT) +#define MIP_MSIP (1 << IRQ_M_SOFT) +#define MIP_STIP (1 << IRQ_S_TIMER) +#define MIP_HTIP (1 << IRQ_H_TIMER) +#define MIP_MTIP (1 << IRQ_M_TIMER) +#define MIP_SEIP (1 << IRQ_S_EXT) +#define MIP_HEIP (1 << IRQ_H_EXT) +#define MIP_MEIP (1 << IRQ_M_EXT) + +#define SIP_SSIP MIP_SSIP +#define SIP_STIP MIP_STIP + +#define PRV_U 0 +#define PRV_S 1 +#define PRV_H 2 +#define PRV_M 3 + +#define SATP32_MODE 0x80000000 +#define SATP32_ASID 0x7FC00000 +#define SATP32_PPN 0x003FFFFF +#define SATP64_MODE 0xF000000000000000 +#define SATP64_ASID 0x0FFFF00000000000 +#define SATP64_PPN 0x00000FFFFFFFFFFF + +#define SATP_MODE_OFF 0 +#define SATP_MODE_SV32 1 +#define SATP_MODE_SV39 8 +#define SATP_MODE_SV48 9 +#define SATP_MODE_SV57 10 +#define SATP_MODE_SV64 11 + +#define PMP_R 0x01 +#define PMP_W 0x02 +#define PMP_X 0x04 +#define PMP_A 0x18 +#define PMP_L 0x80 +#define PMP_SHIFT 2 + +#define PMP_TOR 0x08 +#define PMP_NA4 0x10 +#define PMP_NAPOT 0x18 + +#define IRQ_S_SOFT 1 +#define IRQ_H_SOFT 2 +#define IRQ_M_SOFT 3 +#define IRQ_S_TIMER 5 +#define IRQ_H_TIMER 6 +#define IRQ_M_TIMER 7 +#define IRQ_S_EXT 9 +#define IRQ_H_EXT 10 +#define IRQ_M_EXT 11 +#define IRQ_COP 12 +#define IRQ_HOST 13 + +#define DEFAULT_RSTVEC 0x00001000 +#define CLINT_BASE 0x02000000 +#define CLINT_SIZE 0x000c0000 +#define EXT_IO_BASE 0x40000000 +#define DRAM_BASE 0x80000000 + +// page table entry (PTE) fields +#define PTE_V 0x001 // Valid +#define PTE_R 0x002 // Read +#define PTE_W 0x004 // Write +#define PTE_X 0x008 // Execute +#define PTE_U 0x010 // User +#define PTE_G 0x020 // Global +#define PTE_A 0x040 // Accessed +#define PTE_D 0x080 // Dirty +#define PTE_SOFT 0x300 // Reserved for Software + +#define PTE_PPN_SHIFT 10 + +#define PTE_TABLE(PTE) (((PTE) & (PTE_V | PTE_R | PTE_W | PTE_X)) == PTE_V) + +#ifdef __riscv + +#if __riscv_xlen == 64 +# define MSTATUS_SD MSTATUS64_SD +# define SSTATUS_SD SSTATUS64_SD +# define RISCV_PGLEVEL_BITS 9 +# define SATP_MODE SATP64_MODE +#else +# define MSTATUS_SD MSTATUS32_SD +# define SSTATUS_SD SSTATUS32_SD +# define RISCV_PGLEVEL_BITS 10 +# define SATP_MODE SATP32_MODE +#endif +#define RISCV_PGSHIFT 12 +#define RISCV_PGSIZE (1 << RISCV_PGSHIFT) + +#ifndef __ASSEMBLER__ + +#ifdef __GNUC__ + +#define read_csr(reg) ({ unsigned long __tmp; \ + asm volatile ("csrr %0, " #reg : "=r"(__tmp)); \ + __tmp; }) + +#define write_csr(reg, val) ({ \ + asm volatile ("csrw " #reg ", %0" :: "rK"(val)); }) + +#define swap_csr(reg, val) ({ unsigned long __tmp; \ + asm volatile ("csrrw %0, " #reg ", %1" : "=r"(__tmp) : "rK"(val)); \ + __tmp; }) + +#define set_csr(reg, bit) ({ unsigned long __tmp; \ + asm volatile ("csrrs %0, " #reg ", %1" : "=r"(__tmp) : "rK"(bit)); \ + __tmp; }) + +#define clear_csr(reg, bit) ({ unsigned long __tmp; \ + asm volatile ("csrrc %0, " #reg ", %1" : "=r"(__tmp) : "rK"(bit)); \ + __tmp; }) + +#define rdtime() read_csr(time) +#define rdcycle() read_csr(cycle) +#define rdinstret() read_csr(instret) + +#endif + +#endif + +#endif + +#endif +/* Automatically generated by parse-opcodes. */ +#ifndef RISCV_ENCODING_H +#define RISCV_ENCODING_H +#define MATCH_BEQ 0x63 +#define MASK_BEQ 0x707f +#define MATCH_BNE 0x1063 +#define MASK_BNE 0x707f +#define MATCH_BLT 0x4063 +#define MASK_BLT 0x707f +#define MATCH_BGE 0x5063 +#define MASK_BGE 0x707f +#define MATCH_BLTU 0x6063 +#define MASK_BLTU 0x707f +#define MATCH_BGEU 0x7063 +#define MASK_BGEU 0x707f +#define MATCH_JALR 0x67 +#define MASK_JALR 0x707f +#define MATCH_JAL 0x6f +#define MASK_JAL 0x7f +#define MATCH_LUI 0x37 +#define MASK_LUI 0x7f +#define MATCH_AUIPC 0x17 +#define MASK_AUIPC 0x7f +#define MATCH_ADDI 0x13 +#define MASK_ADDI 0x707f +#define MATCH_SLLI 0x1013 +#define MASK_SLLI 0xfc00707f +#define MATCH_SLTI 0x2013 +#define MASK_SLTI 0x707f +#define MATCH_SLTIU 0x3013 +#define MASK_SLTIU 0x707f +#define MATCH_XORI 0x4013 +#define MASK_XORI 0x707f +#define MATCH_SRLI 0x5013 +#define MASK_SRLI 0xfc00707f +#define MATCH_SRAI 0x40005013 +#define MASK_SRAI 0xfc00707f +#define MATCH_ORI 0x6013 +#define MASK_ORI 0x707f +#define MATCH_ANDI 0x7013 +#define MASK_ANDI 0x707f +#define MATCH_ADD 0x33 +#define MASK_ADD 0xfe00707f +#define MATCH_SUB 0x40000033 +#define MASK_SUB 0xfe00707f +#define MATCH_SLL 0x1033 +#define MASK_SLL 0xfe00707f +#define MATCH_SLT 0x2033 +#define MASK_SLT 0xfe00707f +#define MATCH_SLTU 0x3033 +#define MASK_SLTU 0xfe00707f +#define MATCH_XOR 0x4033 +#define MASK_XOR 0xfe00707f +#define MATCH_SRL 0x5033 +#define MASK_SRL 0xfe00707f +#define MATCH_SRA 0x40005033 +#define MASK_SRA 0xfe00707f +#define MATCH_OR 0x6033 +#define MASK_OR 0xfe00707f +#define MATCH_AND 0x7033 +#define MASK_AND 0xfe00707f +#define MATCH_ADDIW 0x1b +#define MASK_ADDIW 0x707f +#define MATCH_SLLIW 0x101b +#define MASK_SLLIW 0xfe00707f +#define MATCH_SRLIW 0x501b +#define MASK_SRLIW 0xfe00707f +#define MATCH_SRAIW 0x4000501b +#define MASK_SRAIW 0xfe00707f +#define MATCH_ADDW 0x3b +#define MASK_ADDW 0xfe00707f +#define MATCH_SUBW 0x4000003b +#define MASK_SUBW 0xfe00707f +#define MATCH_SLLW 0x103b +#define MASK_SLLW 0xfe00707f +#define MATCH_SRLW 0x503b +#define MASK_SRLW 0xfe00707f +#define MATCH_SRAW 0x4000503b +#define MASK_SRAW 0xfe00707f +#define MATCH_LB 0x3 +#define MASK_LB 0x707f +#define MATCH_LH 0x1003 +#define MASK_LH 0x707f +#define MATCH_LW 0x2003 +#define MASK_LW 0x707f +#define MATCH_LD 0x3003 +#define MASK_LD 0x707f +#define MATCH_LBU 0x4003 +#define MASK_LBU 0x707f +#define MATCH_LHU 0x5003 +#define MASK_LHU 0x707f +#define MATCH_LWU 0x6003 +#define MASK_LWU 0x707f +#define MATCH_SB 0x23 +#define MASK_SB 0x707f +#define MATCH_SH 0x1023 +#define MASK_SH 0x707f +#define MATCH_SW 0x2023 +#define MASK_SW 0x707f +#define MATCH_SD 0x3023 +#define MASK_SD 0x707f +#define MATCH_FENCE 0xf +#define MASK_FENCE 0x707f +#define MATCH_FENCE_I 0x100f +#define MASK_FENCE_I 0x707f +#define MATCH_MUL 0x2000033 +#define MASK_MUL 0xfe00707f +#define MATCH_MULH 0x2001033 +#define MASK_MULH 0xfe00707f +#define MATCH_MULHSU 0x2002033 +#define MASK_MULHSU 0xfe00707f +#define MATCH_MULHU 0x2003033 +#define MASK_MULHU 0xfe00707f +#define MATCH_DIV 0x2004033 +#define MASK_DIV 0xfe00707f +#define MATCH_DIVU 0x2005033 +#define MASK_DIVU 0xfe00707f +#define MATCH_REM 0x2006033 +#define MASK_REM 0xfe00707f +#define MATCH_REMU 0x2007033 +#define MASK_REMU 0xfe00707f +#define MATCH_MULW 0x200003b +#define MASK_MULW 0xfe00707f +#define MATCH_DIVW 0x200403b +#define MASK_DIVW 0xfe00707f +#define MATCH_DIVUW 0x200503b +#define MASK_DIVUW 0xfe00707f +#define MATCH_REMW 0x200603b +#define MASK_REMW 0xfe00707f +#define MATCH_REMUW 0x200703b +#define MASK_REMUW 0xfe00707f +#define MATCH_AMOADD_W 0x202f +#define MASK_AMOADD_W 0xf800707f +#define MATCH_AMOXOR_W 0x2000202f +#define MASK_AMOXOR_W 0xf800707f +#define MATCH_AMOOR_W 0x4000202f +#define MASK_AMOOR_W 0xf800707f +#define MATCH_AMOAND_W 0x6000202f +#define MASK_AMOAND_W 0xf800707f +#define MATCH_AMOMIN_W 0x8000202f +#define MASK_AMOMIN_W 0xf800707f +#define MATCH_AMOMAX_W 0xa000202f +#define MASK_AMOMAX_W 0xf800707f +#define MATCH_AMOMINU_W 0xc000202f +#define MASK_AMOMINU_W 0xf800707f +#define MATCH_AMOMAXU_W 0xe000202f +#define MASK_AMOMAXU_W 0xf800707f +#define MATCH_AMOSWAP_W 0x800202f +#define MASK_AMOSWAP_W 0xf800707f +#define MATCH_LR_W 0x1000202f +#define MASK_LR_W 0xf9f0707f +#define MATCH_SC_W 0x1800202f +#define MASK_SC_W 0xf800707f +#define MATCH_AMOADD_D 0x302f +#define MASK_AMOADD_D 0xf800707f +#define MATCH_AMOXOR_D 0x2000302f +#define MASK_AMOXOR_D 0xf800707f +#define MATCH_AMOOR_D 0x4000302f +#define MASK_AMOOR_D 0xf800707f +#define MATCH_AMOAND_D 0x6000302f +#define MASK_AMOAND_D 0xf800707f +#define MATCH_AMOMIN_D 0x8000302f +#define MASK_AMOMIN_D 0xf800707f +#define MATCH_AMOMAX_D 0xa000302f +#define MASK_AMOMAX_D 0xf800707f +#define MATCH_AMOMINU_D 0xc000302f +#define MASK_AMOMINU_D 0xf800707f +#define MATCH_AMOMAXU_D 0xe000302f +#define MASK_AMOMAXU_D 0xf800707f +#define MATCH_AMOSWAP_D 0x800302f +#define MASK_AMOSWAP_D 0xf800707f +#define MATCH_LR_D 0x1000302f +#define MASK_LR_D 0xf9f0707f +#define MATCH_SC_D 0x1800302f +#define MASK_SC_D 0xf800707f +#define MATCH_ECALL 0x73 +#define MASK_ECALL 0xffffffff +#define MATCH_EBREAK 0x100073 +#define MASK_EBREAK 0xffffffff +#define MATCH_URET 0x200073 +#define MASK_URET 0xffffffff +#define MATCH_SRET 0x10200073 +#define MASK_SRET 0xffffffff +#define MATCH_MRET 0x30200073 +#define MASK_MRET 0xffffffff +#define MATCH_DRET 0x7b200073 +#define MASK_DRET 0xffffffff +#define MATCH_SFENCE_VMA 0x12000073 +#define MASK_SFENCE_VMA 0xfe007fff +#define MATCH_WFI 0x10500073 +#define MASK_WFI 0xffffffff +#define MATCH_CSRRW 0x1073 +#define MASK_CSRRW 0x707f +#define MATCH_CSRRS 0x2073 +#define MASK_CSRRS 0x707f +#define MATCH_CSRRC 0x3073 +#define MASK_CSRRC 0x707f +#define MATCH_CSRRWI 0x5073 +#define MASK_CSRRWI 0x707f +#define MATCH_CSRRSI 0x6073 +#define MASK_CSRRSI 0x707f +#define MATCH_CSRRCI 0x7073 +#define MASK_CSRRCI 0x707f +#define MATCH_FADD_S 0x53 +#define MASK_FADD_S 0xfe00007f +#define MATCH_FSUB_S 0x8000053 +#define MASK_FSUB_S 0xfe00007f +#define MATCH_FMUL_S 0x10000053 +#define MASK_FMUL_S 0xfe00007f +#define MATCH_FDIV_S 0x18000053 +#define MASK_FDIV_S 0xfe00007f +#define MATCH_FSGNJ_S 0x20000053 +#define MASK_FSGNJ_S 0xfe00707f +#define MATCH_FSGNJN_S 0x20001053 +#define MASK_FSGNJN_S 0xfe00707f +#define MATCH_FSGNJX_S 0x20002053 +#define MASK_FSGNJX_S 0xfe00707f +#define MATCH_FMIN_S 0x28000053 +#define MASK_FMIN_S 0xfe00707f +#define MATCH_FMAX_S 0x28001053 +#define MASK_FMAX_S 0xfe00707f +#define MATCH_FSQRT_S 0x58000053 +#define MASK_FSQRT_S 0xfff0007f +#define MATCH_FADD_D 0x2000053 +#define MASK_FADD_D 0xfe00007f +#define MATCH_FSUB_D 0xa000053 +#define MASK_FSUB_D 0xfe00007f +#define MATCH_FMUL_D 0x12000053 +#define MASK_FMUL_D 0xfe00007f +#define MATCH_FDIV_D 0x1a000053 +#define MASK_FDIV_D 0xfe00007f +#define MATCH_FSGNJ_D 0x22000053 +#define MASK_FSGNJ_D 0xfe00707f +#define MATCH_FSGNJN_D 0x22001053 +#define MASK_FSGNJN_D 0xfe00707f +#define MATCH_FSGNJX_D 0x22002053 +#define MASK_FSGNJX_D 0xfe00707f +#define MATCH_FMIN_D 0x2a000053 +#define MASK_FMIN_D 0xfe00707f +#define MATCH_FMAX_D 0x2a001053 +#define MASK_FMAX_D 0xfe00707f +#define MATCH_FCVT_S_D 0x40100053 +#define MASK_FCVT_S_D 0xfff0007f +#define MATCH_FCVT_D_S 0x42000053 +#define MASK_FCVT_D_S 0xfff0007f +#define MATCH_FSQRT_D 0x5a000053 +#define MASK_FSQRT_D 0xfff0007f +#define MATCH_FADD_Q 0x6000053 +#define MASK_FADD_Q 0xfe00007f +#define MATCH_FSUB_Q 0xe000053 +#define MASK_FSUB_Q 0xfe00007f +#define MATCH_FMUL_Q 0x16000053 +#define MASK_FMUL_Q 0xfe00007f +#define MATCH_FDIV_Q 0x1e000053 +#define MASK_FDIV_Q 0xfe00007f +#define MATCH_FSGNJ_Q 0x26000053 +#define MASK_FSGNJ_Q 0xfe00707f +#define MATCH_FSGNJN_Q 0x26001053 +#define MASK_FSGNJN_Q 0xfe00707f +#define MATCH_FSGNJX_Q 0x26002053 +#define MASK_FSGNJX_Q 0xfe00707f +#define MATCH_FMIN_Q 0x2e000053 +#define MASK_FMIN_Q 0xfe00707f +#define MATCH_FMAX_Q 0x2e001053 +#define MASK_FMAX_Q 0xfe00707f +#define MATCH_FCVT_S_Q 0x40300053 +#define MASK_FCVT_S_Q 0xfff0007f +#define MATCH_FCVT_Q_S 0x46000053 +#define MASK_FCVT_Q_S 0xfff0007f +#define MATCH_FCVT_D_Q 0x42300053 +#define MASK_FCVT_D_Q 0xfff0007f +#define MATCH_FCVT_Q_D 0x46100053 +#define MASK_FCVT_Q_D 0xfff0007f +#define MATCH_FSQRT_Q 0x5e000053 +#define MASK_FSQRT_Q 0xfff0007f +#define MATCH_FLE_S 0xa0000053 +#define MASK_FLE_S 0xfe00707f +#define MATCH_FLT_S 0xa0001053 +#define MASK_FLT_S 0xfe00707f +#define MATCH_FEQ_S 0xa0002053 +#define MASK_FEQ_S 0xfe00707f +#define MATCH_FLE_D 0xa2000053 +#define MASK_FLE_D 0xfe00707f +#define MATCH_FLT_D 0xa2001053 +#define MASK_FLT_D 0xfe00707f +#define MATCH_FEQ_D 0xa2002053 +#define MASK_FEQ_D 0xfe00707f +#define MATCH_FLE_Q 0xa6000053 +#define MASK_FLE_Q 0xfe00707f +#define MATCH_FLT_Q 0xa6001053 +#define MASK_FLT_Q 0xfe00707f +#define MATCH_FEQ_Q 0xa6002053 +#define MASK_FEQ_Q 0xfe00707f +#define MATCH_FCVT_W_S 0xc0000053 +#define MASK_FCVT_W_S 0xfff0007f +#define MATCH_FCVT_WU_S 0xc0100053 +#define MASK_FCVT_WU_S 0xfff0007f +#define MATCH_FCVT_L_S 0xc0200053 +#define MASK_FCVT_L_S 0xfff0007f +#define MATCH_FCVT_LU_S 0xc0300053 +#define MASK_FCVT_LU_S 0xfff0007f +#define MATCH_FMV_X_W 0xe0000053 +#define MASK_FMV_X_W 0xfff0707f +#define MATCH_FCLASS_S 0xe0001053 +#define MASK_FCLASS_S 0xfff0707f +#define MATCH_FCVT_W_D 0xc2000053 +#define MASK_FCVT_W_D 0xfff0007f +#define MATCH_FCVT_WU_D 0xc2100053 +#define MASK_FCVT_WU_D 0xfff0007f +#define MATCH_FCVT_L_D 0xc2200053 +#define MASK_FCVT_L_D 0xfff0007f +#define MATCH_FCVT_LU_D 0xc2300053 +#define MASK_FCVT_LU_D 0xfff0007f +#define MATCH_FMV_X_D 0xe2000053 +#define MASK_FMV_X_D 0xfff0707f +#define MATCH_FCLASS_D 0xe2001053 +#define MASK_FCLASS_D 0xfff0707f +#define MATCH_FCVT_W_Q 0xc6000053 +#define MASK_FCVT_W_Q 0xfff0007f +#define MATCH_FCVT_WU_Q 0xc6100053 +#define MASK_FCVT_WU_Q 0xfff0007f +#define MATCH_FCVT_L_Q 0xc6200053 +#define MASK_FCVT_L_Q 0xfff0007f +#define MATCH_FCVT_LU_Q 0xc6300053 +#define MASK_FCVT_LU_Q 0xfff0007f +#define MATCH_FMV_X_Q 0xe6000053 +#define MASK_FMV_X_Q 0xfff0707f +#define MATCH_FCLASS_Q 0xe6001053 +#define MASK_FCLASS_Q 0xfff0707f +#define MATCH_FCVT_S_W 0xd0000053 +#define MASK_FCVT_S_W 0xfff0007f +#define MATCH_FCVT_S_WU 0xd0100053 +#define MASK_FCVT_S_WU 0xfff0007f +#define MATCH_FCVT_S_L 0xd0200053 +#define MASK_FCVT_S_L 0xfff0007f +#define MATCH_FCVT_S_LU 0xd0300053 +#define MASK_FCVT_S_LU 0xfff0007f +#define MATCH_FMV_W_X 0xf0000053 +#define MASK_FMV_W_X 0xfff0707f +#define MATCH_FCVT_D_W 0xd2000053 +#define MASK_FCVT_D_W 0xfff0007f +#define MATCH_FCVT_D_WU 0xd2100053 +#define MASK_FCVT_D_WU 0xfff0007f +#define MATCH_FCVT_D_L 0xd2200053 +#define MASK_FCVT_D_L 0xfff0007f +#define MATCH_FCVT_D_LU 0xd2300053 +#define MASK_FCVT_D_LU 0xfff0007f +#define MATCH_FMV_D_X 0xf2000053 +#define MASK_FMV_D_X 0xfff0707f +#define MATCH_FCVT_Q_W 0xd6000053 +#define MASK_FCVT_Q_W 0xfff0007f +#define MATCH_FCVT_Q_WU 0xd6100053 +#define MASK_FCVT_Q_WU 0xfff0007f +#define MATCH_FCVT_Q_L 0xd6200053 +#define MASK_FCVT_Q_L 0xfff0007f +#define MATCH_FCVT_Q_LU 0xd6300053 +#define MASK_FCVT_Q_LU 0xfff0007f +#define MATCH_FMV_Q_X 0xf6000053 +#define MASK_FMV_Q_X 0xfff0707f +#define MATCH_FLW 0x2007 +#define MASK_FLW 0x707f +#define MATCH_FLD 0x3007 +#define MASK_FLD 0x707f +#define MATCH_FLQ 0x4007 +#define MASK_FLQ 0x707f +#define MATCH_FSW 0x2027 +#define MASK_FSW 0x707f +#define MATCH_FSD 0x3027 +#define MASK_FSD 0x707f +#define MATCH_FSQ 0x4027 +#define MASK_FSQ 0x707f +#define MATCH_FMADD_S 0x43 +#define MASK_FMADD_S 0x600007f +#define MATCH_FMSUB_S 0x47 +#define MASK_FMSUB_S 0x600007f +#define MATCH_FNMSUB_S 0x4b +#define MASK_FNMSUB_S 0x600007f +#define MATCH_FNMADD_S 0x4f +#define MASK_FNMADD_S 0x600007f +#define MATCH_FMADD_D 0x2000043 +#define MASK_FMADD_D 0x600007f +#define MATCH_FMSUB_D 0x2000047 +#define MASK_FMSUB_D 0x600007f +#define MATCH_FNMSUB_D 0x200004b +#define MASK_FNMSUB_D 0x600007f +#define MATCH_FNMADD_D 0x200004f +#define MASK_FNMADD_D 0x600007f +#define MATCH_FMADD_Q 0x6000043 +#define MASK_FMADD_Q 0x600007f +#define MATCH_FMSUB_Q 0x6000047 +#define MASK_FMSUB_Q 0x600007f +#define MATCH_FNMSUB_Q 0x600004b +#define MASK_FNMSUB_Q 0x600007f +#define MATCH_FNMADD_Q 0x600004f +#define MASK_FNMADD_Q 0x600007f +#define MATCH_C_NOP 0x1 +#define MASK_C_NOP 0xffff +#define MATCH_C_ADDI16SP 0x6101 +#define MASK_C_ADDI16SP 0xef83 +#define MATCH_C_JR 0x8002 +#define MASK_C_JR 0xf07f +#define MATCH_C_JALR 0x9002 +#define MASK_C_JALR 0xf07f +#define MATCH_C_EBREAK 0x9002 +#define MASK_C_EBREAK 0xffff +#define MATCH_C_LD 0x6000 +#define MASK_C_LD 0xe003 +#define MATCH_C_SD 0xe000 +#define MASK_C_SD 0xe003 +#define MATCH_C_ADDIW 0x2001 +#define MASK_C_ADDIW 0xe003 +#define MATCH_C_LDSP 0x6002 +#define MASK_C_LDSP 0xe003 +#define MATCH_C_SDSP 0xe002 +#define MASK_C_SDSP 0xe003 +#define MATCH_C_ADDI4SPN 0x0 +#define MASK_C_ADDI4SPN 0xe003 +#define MATCH_C_FLD 0x2000 +#define MASK_C_FLD 0xe003 +#define MATCH_C_LW 0x4000 +#define MASK_C_LW 0xe003 +#define MATCH_C_FLW 0x6000 +#define MASK_C_FLW 0xe003 +#define MATCH_C_FSD 0xa000 +#define MASK_C_FSD 0xe003 +#define MATCH_C_SW 0xc000 +#define MASK_C_SW 0xe003 +#define MATCH_C_FSW 0xe000 +#define MASK_C_FSW 0xe003 +#define MATCH_C_ADDI 0x1 +#define MASK_C_ADDI 0xe003 +#define MATCH_C_JAL 0x2001 +#define MASK_C_JAL 0xe003 +#define MATCH_C_LI 0x4001 +#define MASK_C_LI 0xe003 +#define MATCH_C_LUI 0x6001 +#define MASK_C_LUI 0xe003 +#define MATCH_C_SRLI 0x8001 +#define MASK_C_SRLI 0xec03 +#define MATCH_C_SRAI 0x8401 +#define MASK_C_SRAI 0xec03 +#define MATCH_C_ANDI 0x8801 +#define MASK_C_ANDI 0xec03 +#define MATCH_C_SUB 0x8c01 +#define MASK_C_SUB 0xfc63 +#define MATCH_C_XOR 0x8c21 +#define MASK_C_XOR 0xfc63 +#define MATCH_C_OR 0x8c41 +#define MASK_C_OR 0xfc63 +#define MATCH_C_AND 0x8c61 +#define MASK_C_AND 0xfc63 +#define MATCH_C_SUBW 0x9c01 +#define MASK_C_SUBW 0xfc63 +#define MATCH_C_ADDW 0x9c21 +#define MASK_C_ADDW 0xfc63 +#define MATCH_C_J 0xa001 +#define MASK_C_J 0xe003 +#define MATCH_C_BEQZ 0xc001 +#define MASK_C_BEQZ 0xe003 +#define MATCH_C_BNEZ 0xe001 +#define MASK_C_BNEZ 0xe003 +#define MATCH_C_SLLI 0x2 +#define MASK_C_SLLI 0xe003 +#define MATCH_C_FLDSP 0x2002 +#define MASK_C_FLDSP 0xe003 +#define MATCH_C_LWSP 0x4002 +#define MASK_C_LWSP 0xe003 +#define MATCH_C_FLWSP 0x6002 +#define MASK_C_FLWSP 0xe003 +#define MATCH_C_MV 0x8002 +#define MASK_C_MV 0xf003 +#define MATCH_C_ADD 0x9002 +#define MASK_C_ADD 0xf003 +#define MATCH_C_FSDSP 0xa002 +#define MASK_C_FSDSP 0xe003 +#define MATCH_C_SWSP 0xc002 +#define MASK_C_SWSP 0xe003 +#define MATCH_C_FSWSP 0xe002 +#define MASK_C_FSWSP 0xe003 +#define MATCH_CUSTOM0 0xb +#define MASK_CUSTOM0 0x707f +#define MATCH_CUSTOM0_RS1 0x200b +#define MASK_CUSTOM0_RS1 0x707f +#define MATCH_CUSTOM0_RS1_RS2 0x300b +#define MASK_CUSTOM0_RS1_RS2 0x707f +#define MATCH_CUSTOM0_RD 0x400b +#define MASK_CUSTOM0_RD 0x707f +#define MATCH_CUSTOM0_RD_RS1 0x600b +#define MASK_CUSTOM0_RD_RS1 0x707f +#define MATCH_CUSTOM0_RD_RS1_RS2 0x700b +#define MASK_CUSTOM0_RD_RS1_RS2 0x707f +#define MATCH_CUSTOM1 0x2b +#define MASK_CUSTOM1 0x707f +#define MATCH_CUSTOM1_RS1 0x202b +#define MASK_CUSTOM1_RS1 0x707f +#define MATCH_CUSTOM1_RS1_RS2 0x302b +#define MASK_CUSTOM1_RS1_RS2 0x707f +#define MATCH_CUSTOM1_RD 0x402b +#define MASK_CUSTOM1_RD 0x707f +#define MATCH_CUSTOM1_RD_RS1 0x602b +#define MASK_CUSTOM1_RD_RS1 0x707f +#define MATCH_CUSTOM1_RD_RS1_RS2 0x702b +#define MASK_CUSTOM1_RD_RS1_RS2 0x707f +#define MATCH_CUSTOM2 0x5b +#define MASK_CUSTOM2 0x707f +#define MATCH_CUSTOM2_RS1 0x205b +#define MASK_CUSTOM2_RS1 0x707f +#define MATCH_CUSTOM2_RS1_RS2 0x305b +#define MASK_CUSTOM2_RS1_RS2 0x707f +#define MATCH_CUSTOM2_RD 0x405b +#define MASK_CUSTOM2_RD 0x707f +#define MATCH_CUSTOM2_RD_RS1 0x605b +#define MASK_CUSTOM2_RD_RS1 0x707f +#define MATCH_CUSTOM2_RD_RS1_RS2 0x705b +#define MASK_CUSTOM2_RD_RS1_RS2 0x707f +#define MATCH_CUSTOM3 0x7b +#define MASK_CUSTOM3 0x707f +#define MATCH_CUSTOM3_RS1 0x207b +#define MASK_CUSTOM3_RS1 0x707f +#define MATCH_CUSTOM3_RS1_RS2 0x307b +#define MASK_CUSTOM3_RS1_RS2 0x707f +#define MATCH_CUSTOM3_RD 0x407b +#define MASK_CUSTOM3_RD 0x707f +#define MATCH_CUSTOM3_RD_RS1 0x607b +#define MASK_CUSTOM3_RD_RS1 0x707f +#define MATCH_CUSTOM3_RD_RS1_RS2 0x707b +#define MASK_CUSTOM3_RD_RS1_RS2 0x707f +#define CSR_FFLAGS 0x1 +#define CSR_FRM 0x2 +#define CSR_FCSR 0x3 +#define CSR_CYCLE 0xc00 +#define CSR_TIME 0xc01 +#define CSR_INSTRET 0xc02 +#define CSR_HPMCOUNTER3 0xc03 +#define CSR_HPMCOUNTER4 0xc04 +#define CSR_HPMCOUNTER5 0xc05 +#define CSR_HPMCOUNTER6 0xc06 +#define CSR_HPMCOUNTER7 0xc07 +#define CSR_HPMCOUNTER8 0xc08 +#define CSR_HPMCOUNTER9 0xc09 +#define CSR_HPMCOUNTER10 0xc0a +#define CSR_HPMCOUNTER11 0xc0b +#define CSR_HPMCOUNTER12 0xc0c +#define CSR_HPMCOUNTER13 0xc0d +#define CSR_HPMCOUNTER14 0xc0e +#define CSR_HPMCOUNTER15 0xc0f +#define CSR_HPMCOUNTER16 0xc10 +#define CSR_HPMCOUNTER17 0xc11 +#define CSR_HPMCOUNTER18 0xc12 +#define CSR_HPMCOUNTER19 0xc13 +#define CSR_HPMCOUNTER20 0xc14 +#define CSR_HPMCOUNTER21 0xc15 +#define CSR_HPMCOUNTER22 0xc16 +#define CSR_HPMCOUNTER23 0xc17 +#define CSR_HPMCOUNTER24 0xc18 +#define CSR_HPMCOUNTER25 0xc19 +#define CSR_HPMCOUNTER26 0xc1a +#define CSR_HPMCOUNTER27 0xc1b +#define CSR_HPMCOUNTER28 0xc1c +#define CSR_HPMCOUNTER29 0xc1d +#define CSR_HPMCOUNTER30 0xc1e +#define CSR_HPMCOUNTER31 0xc1f +#define CSR_SSTATUS 0x100 +#define CSR_SIE 0x104 +#define CSR_STVEC 0x105 +#define CSR_SCOUNTEREN 0x106 +#define CSR_SSCRATCH 0x140 +#define CSR_SEPC 0x141 +#define CSR_SCAUSE 0x142 +#define CSR_STVAL 0x143 +#define CSR_SIP 0x144 +#define CSR_SATP 0x180 +#define CSR_MSTATUS 0x300 +#define CSR_MISA 0x301 +#define CSR_MEDELEG 0x302 +#define CSR_MIDELEG 0x303 +#define CSR_MIE 0x304 +#define CSR_MTVEC 0x305 +#define CSR_MCOUNTEREN 0x306 +#define CSR_MSCRATCH 0x340 +#define CSR_MEPC 0x341 +#define CSR_MCAUSE 0x342 +#define CSR_MTVAL 0x343 +#define CSR_MIP 0x344 +#define CSR_PMPCFG0 0x3a0 +#define CSR_PMPCFG1 0x3a1 +#define CSR_PMPCFG2 0x3a2 +#define CSR_PMPCFG3 0x3a3 +#define CSR_PMPADDR0 0x3b0 +#define CSR_PMPADDR1 0x3b1 +#define CSR_PMPADDR2 0x3b2 +#define CSR_PMPADDR3 0x3b3 +#define CSR_PMPADDR4 0x3b4 +#define CSR_PMPADDR5 0x3b5 +#define CSR_PMPADDR6 0x3b6 +#define CSR_PMPADDR7 0x3b7 +#define CSR_PMPADDR8 0x3b8 +#define CSR_PMPADDR9 0x3b9 +#define CSR_PMPADDR10 0x3ba +#define CSR_PMPADDR11 0x3bb +#define CSR_PMPADDR12 0x3bc +#define CSR_PMPADDR13 0x3bd +#define CSR_PMPADDR14 0x3be +#define CSR_PMPADDR15 0x3bf +#define CSR_TSELECT 0x7a0 +#define CSR_TDATA1 0x7a1 +#define CSR_TDATA2 0x7a2 +#define CSR_TDATA3 0x7a3 +#define CSR_DCSR 0x7b0 +#define CSR_DPC 0x7b1 +#define CSR_DSCRATCH 0x7b2 +#define CSR_MCYCLE 0xb00 +#define CSR_MINSTRET 0xb02 +#define CSR_MHPMCOUNTER3 0xb03 +#define CSR_MHPMCOUNTER4 0xb04 +#define CSR_MHPMCOUNTER5 0xb05 +#define CSR_MHPMCOUNTER6 0xb06 +#define CSR_MHPMCOUNTER7 0xb07 +#define CSR_MHPMCOUNTER8 0xb08 +#define CSR_MHPMCOUNTER9 0xb09 +#define CSR_MHPMCOUNTER10 0xb0a +#define CSR_MHPMCOUNTER11 0xb0b +#define CSR_MHPMCOUNTER12 0xb0c +#define CSR_MHPMCOUNTER13 0xb0d +#define CSR_MHPMCOUNTER14 0xb0e +#define CSR_MHPMCOUNTER15 0xb0f +#define CSR_MHPMCOUNTER16 0xb10 +#define CSR_MHPMCOUNTER17 0xb11 +#define CSR_MHPMCOUNTER18 0xb12 +#define CSR_MHPMCOUNTER19 0xb13 +#define CSR_MHPMCOUNTER20 0xb14 +#define CSR_MHPMCOUNTER21 0xb15 +#define CSR_MHPMCOUNTER22 0xb16 +#define CSR_MHPMCOUNTER23 0xb17 +#define CSR_MHPMCOUNTER24 0xb18 +#define CSR_MHPMCOUNTER25 0xb19 +#define CSR_MHPMCOUNTER26 0xb1a +#define CSR_MHPMCOUNTER27 0xb1b +#define CSR_MHPMCOUNTER28 0xb1c +#define CSR_MHPMCOUNTER29 0xb1d +#define CSR_MHPMCOUNTER30 0xb1e +#define CSR_MHPMCOUNTER31 0xb1f +#define CSR_MHPMEVENT3 0x323 +#define CSR_MHPMEVENT4 0x324 +#define CSR_MHPMEVENT5 0x325 +#define CSR_MHPMEVENT6 0x326 +#define CSR_MHPMEVENT7 0x327 +#define CSR_MHPMEVENT8 0x328 +#define CSR_MHPMEVENT9 0x329 +#define CSR_MHPMEVENT10 0x32a +#define CSR_MHPMEVENT11 0x32b +#define CSR_MHPMEVENT12 0x32c +#define CSR_MHPMEVENT13 0x32d +#define CSR_MHPMEVENT14 0x32e +#define CSR_MHPMEVENT15 0x32f +#define CSR_MHPMEVENT16 0x330 +#define CSR_MHPMEVENT17 0x331 +#define CSR_MHPMEVENT18 0x332 +#define CSR_MHPMEVENT19 0x333 +#define CSR_MHPMEVENT20 0x334 +#define CSR_MHPMEVENT21 0x335 +#define CSR_MHPMEVENT22 0x336 +#define CSR_MHPMEVENT23 0x337 +#define CSR_MHPMEVENT24 0x338 +#define CSR_MHPMEVENT25 0x339 +#define CSR_MHPMEVENT26 0x33a +#define CSR_MHPMEVENT27 0x33b +#define CSR_MHPMEVENT28 0x33c +#define CSR_MHPMEVENT29 0x33d +#define CSR_MHPMEVENT30 0x33e +#define CSR_MHPMEVENT31 0x33f +#define CSR_MVENDORID 0xf11 +#define CSR_MARCHID 0xf12 +#define CSR_MIMPID 0xf13 +#define CSR_MHARTID 0xf14 +#define CSR_CYCLEH 0xc80 +#define CSR_TIMEH 0xc81 +#define CSR_INSTRETH 0xc82 +#define CSR_HPMCOUNTER3H 0xc83 +#define CSR_HPMCOUNTER4H 0xc84 +#define CSR_HPMCOUNTER5H 0xc85 +#define CSR_HPMCOUNTER6H 0xc86 +#define CSR_HPMCOUNTER7H 0xc87 +#define CSR_HPMCOUNTER8H 0xc88 +#define CSR_HPMCOUNTER9H 0xc89 +#define CSR_HPMCOUNTER10H 0xc8a +#define CSR_HPMCOUNTER11H 0xc8b +#define CSR_HPMCOUNTER12H 0xc8c +#define CSR_HPMCOUNTER13H 0xc8d +#define CSR_HPMCOUNTER14H 0xc8e +#define CSR_HPMCOUNTER15H 0xc8f +#define CSR_HPMCOUNTER16H 0xc90 +#define CSR_HPMCOUNTER17H 0xc91 +#define CSR_HPMCOUNTER18H 0xc92 +#define CSR_HPMCOUNTER19H 0xc93 +#define CSR_HPMCOUNTER20H 0xc94 +#define CSR_HPMCOUNTER21H 0xc95 +#define CSR_HPMCOUNTER22H 0xc96 +#define CSR_HPMCOUNTER23H 0xc97 +#define CSR_HPMCOUNTER24H 0xc98 +#define CSR_HPMCOUNTER25H 0xc99 +#define CSR_HPMCOUNTER26H 0xc9a +#define CSR_HPMCOUNTER27H 0xc9b +#define CSR_HPMCOUNTER28H 0xc9c +#define CSR_HPMCOUNTER29H 0xc9d +#define CSR_HPMCOUNTER30H 0xc9e +#define CSR_HPMCOUNTER31H 0xc9f +#define CSR_MCYCLEH 0xb80 +#define CSR_MINSTRETH 0xb82 +#define CSR_MHPMCOUNTER3H 0xb83 +#define CSR_MHPMCOUNTER4H 0xb84 +#define CSR_MHPMCOUNTER5H 0xb85 +#define CSR_MHPMCOUNTER6H 0xb86 +#define CSR_MHPMCOUNTER7H 0xb87 +#define CSR_MHPMCOUNTER8H 0xb88 +#define CSR_MHPMCOUNTER9H 0xb89 +#define CSR_MHPMCOUNTER10H 0xb8a +#define CSR_MHPMCOUNTER11H 0xb8b +#define CSR_MHPMCOUNTER12H 0xb8c +#define CSR_MHPMCOUNTER13H 0xb8d +#define CSR_MHPMCOUNTER14H 0xb8e +#define CSR_MHPMCOUNTER15H 0xb8f +#define CSR_MHPMCOUNTER16H 0xb90 +#define CSR_MHPMCOUNTER17H 0xb91 +#define CSR_MHPMCOUNTER18H 0xb92 +#define CSR_MHPMCOUNTER19H 0xb93 +#define CSR_MHPMCOUNTER20H 0xb94 +#define CSR_MHPMCOUNTER21H 0xb95 +#define CSR_MHPMCOUNTER22H 0xb96 +#define CSR_MHPMCOUNTER23H 0xb97 +#define CSR_MHPMCOUNTER24H 0xb98 +#define CSR_MHPMCOUNTER25H 0xb99 +#define CSR_MHPMCOUNTER26H 0xb9a +#define CSR_MHPMCOUNTER27H 0xb9b +#define CSR_MHPMCOUNTER28H 0xb9c +#define CSR_MHPMCOUNTER29H 0xb9d +#define CSR_MHPMCOUNTER30H 0xb9e +#define CSR_MHPMCOUNTER31H 0xb9f +#define CAUSE_MISALIGNED_FETCH 0x0 +#define CAUSE_FETCH_ACCESS 0x1 +#define CAUSE_ILLEGAL_INSTRUCTION 0x2 +#define CAUSE_BREAKPOINT 0x3 +#define CAUSE_MISALIGNED_LOAD 0x4 +#define CAUSE_LOAD_ACCESS 0x5 +#define CAUSE_MISALIGNED_STORE 0x6 +#define CAUSE_STORE_ACCESS 0x7 +#define CAUSE_USER_ECALL 0x8 +#define CAUSE_SUPERVISOR_ECALL 0x9 +#define CAUSE_HYPERVISOR_ECALL 0xa +#define CAUSE_MACHINE_ECALL 0xb +#define CAUSE_FETCH_PAGE_FAULT 0xc +#define CAUSE_LOAD_PAGE_FAULT 0xd +#define CAUSE_STORE_PAGE_FAULT 0xf +#endif +#ifdef DECLARE_INSN +DECLARE_INSN(beq, MATCH_BEQ, MASK_BEQ) +DECLARE_INSN(bne, MATCH_BNE, MASK_BNE) +DECLARE_INSN(blt, MATCH_BLT, MASK_BLT) +DECLARE_INSN(bge, MATCH_BGE, MASK_BGE) +DECLARE_INSN(bltu, MATCH_BLTU, MASK_BLTU) +DECLARE_INSN(bgeu, MATCH_BGEU, MASK_BGEU) +DECLARE_INSN(jalr, MATCH_JALR, MASK_JALR) +DECLARE_INSN(jal, MATCH_JAL, MASK_JAL) +DECLARE_INSN(lui, MATCH_LUI, MASK_LUI) +DECLARE_INSN(auipc, MATCH_AUIPC, MASK_AUIPC) +DECLARE_INSN(addi, MATCH_ADDI, MASK_ADDI) +DECLARE_INSN(slli, MATCH_SLLI, MASK_SLLI) +DECLARE_INSN(slti, MATCH_SLTI, MASK_SLTI) +DECLARE_INSN(sltiu, MATCH_SLTIU, MASK_SLTIU) +DECLARE_INSN(xori, MATCH_XORI, MASK_XORI) +DECLARE_INSN(srli, MATCH_SRLI, MASK_SRLI) +DECLARE_INSN(srai, MATCH_SRAI, MASK_SRAI) +DECLARE_INSN(ori, MATCH_ORI, MASK_ORI) +DECLARE_INSN(andi, MATCH_ANDI, MASK_ANDI) +DECLARE_INSN(add, MATCH_ADD, MASK_ADD) +DECLARE_INSN(sub, MATCH_SUB, MASK_SUB) +DECLARE_INSN(sll, MATCH_SLL, MASK_SLL) +DECLARE_INSN(slt, MATCH_SLT, MASK_SLT) +DECLARE_INSN(sltu, MATCH_SLTU, MASK_SLTU) +DECLARE_INSN(xor, MATCH_XOR, MASK_XOR) +DECLARE_INSN(srl, MATCH_SRL, MASK_SRL) +DECLARE_INSN(sra, MATCH_SRA, MASK_SRA) +DECLARE_INSN(or, MATCH_OR, MASK_OR) +DECLARE_INSN(and, MATCH_AND, MASK_AND) +DECLARE_INSN(addiw, MATCH_ADDIW, MASK_ADDIW) +DECLARE_INSN(slliw, MATCH_SLLIW, MASK_SLLIW) +DECLARE_INSN(srliw, MATCH_SRLIW, MASK_SRLIW) +DECLARE_INSN(sraiw, MATCH_SRAIW, MASK_SRAIW) +DECLARE_INSN(addw, MATCH_ADDW, MASK_ADDW) +DECLARE_INSN(subw, MATCH_SUBW, MASK_SUBW) +DECLARE_INSN(sllw, MATCH_SLLW, MASK_SLLW) +DECLARE_INSN(srlw, MATCH_SRLW, MASK_SRLW) +DECLARE_INSN(sraw, MATCH_SRAW, MASK_SRAW) +DECLARE_INSN(lb, MATCH_LB, MASK_LB) +DECLARE_INSN(lh, MATCH_LH, MASK_LH) +DECLARE_INSN(lw, MATCH_LW, MASK_LW) +DECLARE_INSN(ld, MATCH_LD, MASK_LD) +DECLARE_INSN(lbu, MATCH_LBU, MASK_LBU) +DECLARE_INSN(lhu, MATCH_LHU, MASK_LHU) +DECLARE_INSN(lwu, MATCH_LWU, MASK_LWU) +DECLARE_INSN(sb, MATCH_SB, MASK_SB) +DECLARE_INSN(sh, MATCH_SH, MASK_SH) +DECLARE_INSN(sw, MATCH_SW, MASK_SW) +DECLARE_INSN(sd, MATCH_SD, MASK_SD) +DECLARE_INSN(fence, MATCH_FENCE, MASK_FENCE) +DECLARE_INSN(fence_i, MATCH_FENCE_I, MASK_FENCE_I) +DECLARE_INSN(mul, MATCH_MUL, MASK_MUL) +DECLARE_INSN(mulh, MATCH_MULH, MASK_MULH) +DECLARE_INSN(mulhsu, MATCH_MULHSU, MASK_MULHSU) +DECLARE_INSN(mulhu, MATCH_MULHU, MASK_MULHU) +DECLARE_INSN(div, MATCH_DIV, MASK_DIV) +DECLARE_INSN(divu, MATCH_DIVU, MASK_DIVU) +DECLARE_INSN(rem, MATCH_REM, MASK_REM) +DECLARE_INSN(remu, MATCH_REMU, MASK_REMU) +DECLARE_INSN(mulw, MATCH_MULW, MASK_MULW) +DECLARE_INSN(divw, MATCH_DIVW, MASK_DIVW) +DECLARE_INSN(divuw, MATCH_DIVUW, MASK_DIVUW) +DECLARE_INSN(remw, MATCH_REMW, MASK_REMW) +DECLARE_INSN(remuw, MATCH_REMUW, MASK_REMUW) +DECLARE_INSN(amoadd_w, MATCH_AMOADD_W, MASK_AMOADD_W) +DECLARE_INSN(amoxor_w, MATCH_AMOXOR_W, MASK_AMOXOR_W) +DECLARE_INSN(amoor_w, MATCH_AMOOR_W, MASK_AMOOR_W) +DECLARE_INSN(amoand_w, MATCH_AMOAND_W, MASK_AMOAND_W) +DECLARE_INSN(amomin_w, MATCH_AMOMIN_W, MASK_AMOMIN_W) +DECLARE_INSN(amomax_w, MATCH_AMOMAX_W, MASK_AMOMAX_W) +DECLARE_INSN(amominu_w, MATCH_AMOMINU_W, MASK_AMOMINU_W) +DECLARE_INSN(amomaxu_w, MATCH_AMOMAXU_W, MASK_AMOMAXU_W) +DECLARE_INSN(amoswap_w, MATCH_AMOSWAP_W, MASK_AMOSWAP_W) +DECLARE_INSN(lr_w, MATCH_LR_W, MASK_LR_W) +DECLARE_INSN(sc_w, MATCH_SC_W, MASK_SC_W) +DECLARE_INSN(amoadd_d, MATCH_AMOADD_D, MASK_AMOADD_D) +DECLARE_INSN(amoxor_d, MATCH_AMOXOR_D, MASK_AMOXOR_D) +DECLARE_INSN(amoor_d, MATCH_AMOOR_D, MASK_AMOOR_D) +DECLARE_INSN(amoand_d, MATCH_AMOAND_D, MASK_AMOAND_D) +DECLARE_INSN(amomin_d, MATCH_AMOMIN_D, MASK_AMOMIN_D) +DECLARE_INSN(amomax_d, MATCH_AMOMAX_D, MASK_AMOMAX_D) +DECLARE_INSN(amominu_d, MATCH_AMOMINU_D, MASK_AMOMINU_D) +DECLARE_INSN(amomaxu_d, MATCH_AMOMAXU_D, MASK_AMOMAXU_D) +DECLARE_INSN(amoswap_d, MATCH_AMOSWAP_D, MASK_AMOSWAP_D) +DECLARE_INSN(lr_d, MATCH_LR_D, MASK_LR_D) +DECLARE_INSN(sc_d, MATCH_SC_D, MASK_SC_D) +DECLARE_INSN(ecall, MATCH_ECALL, MASK_ECALL) +DECLARE_INSN(ebreak, MATCH_EBREAK, MASK_EBREAK) +DECLARE_INSN(uret, MATCH_URET, MASK_URET) +DECLARE_INSN(sret, MATCH_SRET, MASK_SRET) +DECLARE_INSN(mret, MATCH_MRET, MASK_MRET) +DECLARE_INSN(dret, MATCH_DRET, MASK_DRET) +DECLARE_INSN(sfence_vma, MATCH_SFENCE_VMA, MASK_SFENCE_VMA) +DECLARE_INSN(wfi, MATCH_WFI, MASK_WFI) +DECLARE_INSN(csrrw, MATCH_CSRRW, MASK_CSRRW) +DECLARE_INSN(csrrs, MATCH_CSRRS, MASK_CSRRS) +DECLARE_INSN(csrrc, MATCH_CSRRC, MASK_CSRRC) +DECLARE_INSN(csrrwi, MATCH_CSRRWI, MASK_CSRRWI) +DECLARE_INSN(csrrsi, MATCH_CSRRSI, MASK_CSRRSI) +DECLARE_INSN(csrrci, MATCH_CSRRCI, MASK_CSRRCI) +DECLARE_INSN(fadd_s, MATCH_FADD_S, MASK_FADD_S) +DECLARE_INSN(fsub_s, MATCH_FSUB_S, MASK_FSUB_S) +DECLARE_INSN(fmul_s, MATCH_FMUL_S, MASK_FMUL_S) +DECLARE_INSN(fdiv_s, MATCH_FDIV_S, MASK_FDIV_S) +DECLARE_INSN(fsgnj_s, MATCH_FSGNJ_S, MASK_FSGNJ_S) +DECLARE_INSN(fsgnjn_s, MATCH_FSGNJN_S, MASK_FSGNJN_S) +DECLARE_INSN(fsgnjx_s, MATCH_FSGNJX_S, MASK_FSGNJX_S) +DECLARE_INSN(fmin_s, MATCH_FMIN_S, MASK_FMIN_S) +DECLARE_INSN(fmax_s, MATCH_FMAX_S, MASK_FMAX_S) +DECLARE_INSN(fsqrt_s, MATCH_FSQRT_S, MASK_FSQRT_S) +DECLARE_INSN(fadd_d, MATCH_FADD_D, MASK_FADD_D) +DECLARE_INSN(fsub_d, MATCH_FSUB_D, MASK_FSUB_D) +DECLARE_INSN(fmul_d, MATCH_FMUL_D, MASK_FMUL_D) +DECLARE_INSN(fdiv_d, MATCH_FDIV_D, MASK_FDIV_D) +DECLARE_INSN(fsgnj_d, MATCH_FSGNJ_D, MASK_FSGNJ_D) +DECLARE_INSN(fsgnjn_d, MATCH_FSGNJN_D, MASK_FSGNJN_D) +DECLARE_INSN(fsgnjx_d, MATCH_FSGNJX_D, MASK_FSGNJX_D) +DECLARE_INSN(fmin_d, MATCH_FMIN_D, MASK_FMIN_D) +DECLARE_INSN(fmax_d, MATCH_FMAX_D, MASK_FMAX_D) +DECLARE_INSN(fcvt_s_d, MATCH_FCVT_S_D, MASK_FCVT_S_D) +DECLARE_INSN(fcvt_d_s, MATCH_FCVT_D_S, MASK_FCVT_D_S) +DECLARE_INSN(fsqrt_d, MATCH_FSQRT_D, MASK_FSQRT_D) +DECLARE_INSN(fadd_q, MATCH_FADD_Q, MASK_FADD_Q) +DECLARE_INSN(fsub_q, MATCH_FSUB_Q, MASK_FSUB_Q) +DECLARE_INSN(fmul_q, MATCH_FMUL_Q, MASK_FMUL_Q) +DECLARE_INSN(fdiv_q, MATCH_FDIV_Q, MASK_FDIV_Q) +DECLARE_INSN(fsgnj_q, MATCH_FSGNJ_Q, MASK_FSGNJ_Q) +DECLARE_INSN(fsgnjn_q, MATCH_FSGNJN_Q, MASK_FSGNJN_Q) +DECLARE_INSN(fsgnjx_q, MATCH_FSGNJX_Q, MASK_FSGNJX_Q) +DECLARE_INSN(fmin_q, MATCH_FMIN_Q, MASK_FMIN_Q) +DECLARE_INSN(fmax_q, MATCH_FMAX_Q, MASK_FMAX_Q) +DECLARE_INSN(fcvt_s_q, MATCH_FCVT_S_Q, MASK_FCVT_S_Q) +DECLARE_INSN(fcvt_q_s, MATCH_FCVT_Q_S, MASK_FCVT_Q_S) +DECLARE_INSN(fcvt_d_q, MATCH_FCVT_D_Q, MASK_FCVT_D_Q) +DECLARE_INSN(fcvt_q_d, MATCH_FCVT_Q_D, MASK_FCVT_Q_D) +DECLARE_INSN(fsqrt_q, MATCH_FSQRT_Q, MASK_FSQRT_Q) +DECLARE_INSN(fle_s, MATCH_FLE_S, MASK_FLE_S) +DECLARE_INSN(flt_s, MATCH_FLT_S, MASK_FLT_S) +DECLARE_INSN(feq_s, MATCH_FEQ_S, MASK_FEQ_S) +DECLARE_INSN(fle_d, MATCH_FLE_D, MASK_FLE_D) +DECLARE_INSN(flt_d, MATCH_FLT_D, MASK_FLT_D) +DECLARE_INSN(feq_d, MATCH_FEQ_D, MASK_FEQ_D) +DECLARE_INSN(fle_q, MATCH_FLE_Q, MASK_FLE_Q) +DECLARE_INSN(flt_q, MATCH_FLT_Q, MASK_FLT_Q) +DECLARE_INSN(feq_q, MATCH_FEQ_Q, MASK_FEQ_Q) +DECLARE_INSN(fcvt_w_s, MATCH_FCVT_W_S, MASK_FCVT_W_S) +DECLARE_INSN(fcvt_wu_s, MATCH_FCVT_WU_S, MASK_FCVT_WU_S) +DECLARE_INSN(fcvt_l_s, MATCH_FCVT_L_S, MASK_FCVT_L_S) +DECLARE_INSN(fcvt_lu_s, MATCH_FCVT_LU_S, MASK_FCVT_LU_S) +DECLARE_INSN(fmv_x_w, MATCH_FMV_X_W, MASK_FMV_X_W) +DECLARE_INSN(fclass_s, MATCH_FCLASS_S, MASK_FCLASS_S) +DECLARE_INSN(fcvt_w_d, MATCH_FCVT_W_D, MASK_FCVT_W_D) +DECLARE_INSN(fcvt_wu_d, MATCH_FCVT_WU_D, MASK_FCVT_WU_D) +DECLARE_INSN(fcvt_l_d, MATCH_FCVT_L_D, MASK_FCVT_L_D) +DECLARE_INSN(fcvt_lu_d, MATCH_FCVT_LU_D, MASK_FCVT_LU_D) +DECLARE_INSN(fmv_x_d, MATCH_FMV_X_D, MASK_FMV_X_D) +DECLARE_INSN(fclass_d, MATCH_FCLASS_D, MASK_FCLASS_D) +DECLARE_INSN(fcvt_w_q, MATCH_FCVT_W_Q, MASK_FCVT_W_Q) +DECLARE_INSN(fcvt_wu_q, MATCH_FCVT_WU_Q, MASK_FCVT_WU_Q) +DECLARE_INSN(fcvt_l_q, MATCH_FCVT_L_Q, MASK_FCVT_L_Q) +DECLARE_INSN(fcvt_lu_q, MATCH_FCVT_LU_Q, MASK_FCVT_LU_Q) +DECLARE_INSN(fmv_x_q, MATCH_FMV_X_Q, MASK_FMV_X_Q) +DECLARE_INSN(fclass_q, MATCH_FCLASS_Q, MASK_FCLASS_Q) +DECLARE_INSN(fcvt_s_w, MATCH_FCVT_S_W, MASK_FCVT_S_W) +DECLARE_INSN(fcvt_s_wu, MATCH_FCVT_S_WU, MASK_FCVT_S_WU) +DECLARE_INSN(fcvt_s_l, MATCH_FCVT_S_L, MASK_FCVT_S_L) +DECLARE_INSN(fcvt_s_lu, MATCH_FCVT_S_LU, MASK_FCVT_S_LU) +DECLARE_INSN(fmv_w_x, MATCH_FMV_W_X, MASK_FMV_W_X) +DECLARE_INSN(fcvt_d_w, MATCH_FCVT_D_W, MASK_FCVT_D_W) +DECLARE_INSN(fcvt_d_wu, MATCH_FCVT_D_WU, MASK_FCVT_D_WU) +DECLARE_INSN(fcvt_d_l, MATCH_FCVT_D_L, MASK_FCVT_D_L) +DECLARE_INSN(fcvt_d_lu, MATCH_FCVT_D_LU, MASK_FCVT_D_LU) +DECLARE_INSN(fmv_d_x, MATCH_FMV_D_X, MASK_FMV_D_X) +DECLARE_INSN(fcvt_q_w, MATCH_FCVT_Q_W, MASK_FCVT_Q_W) +DECLARE_INSN(fcvt_q_wu, MATCH_FCVT_Q_WU, MASK_FCVT_Q_WU) +DECLARE_INSN(fcvt_q_l, MATCH_FCVT_Q_L, MASK_FCVT_Q_L) +DECLARE_INSN(fcvt_q_lu, MATCH_FCVT_Q_LU, MASK_FCVT_Q_LU) +DECLARE_INSN(fmv_q_x, MATCH_FMV_Q_X, MASK_FMV_Q_X) +DECLARE_INSN(flw, MATCH_FLW, MASK_FLW) +DECLARE_INSN(fld, MATCH_FLD, MASK_FLD) +DECLARE_INSN(flq, MATCH_FLQ, MASK_FLQ) +DECLARE_INSN(fsw, MATCH_FSW, MASK_FSW) +DECLARE_INSN(fsd, MATCH_FSD, MASK_FSD) +DECLARE_INSN(fsq, MATCH_FSQ, MASK_FSQ) +DECLARE_INSN(fmadd_s, MATCH_FMADD_S, MASK_FMADD_S) +DECLARE_INSN(fmsub_s, MATCH_FMSUB_S, MASK_FMSUB_S) +DECLARE_INSN(fnmsub_s, MATCH_FNMSUB_S, MASK_FNMSUB_S) +DECLARE_INSN(fnmadd_s, MATCH_FNMADD_S, MASK_FNMADD_S) +DECLARE_INSN(fmadd_d, MATCH_FMADD_D, MASK_FMADD_D) +DECLARE_INSN(fmsub_d, MATCH_FMSUB_D, MASK_FMSUB_D) +DECLARE_INSN(fnmsub_d, MATCH_FNMSUB_D, MASK_FNMSUB_D) +DECLARE_INSN(fnmadd_d, MATCH_FNMADD_D, MASK_FNMADD_D) +DECLARE_INSN(fmadd_q, MATCH_FMADD_Q, MASK_FMADD_Q) +DECLARE_INSN(fmsub_q, MATCH_FMSUB_Q, MASK_FMSUB_Q) +DECLARE_INSN(fnmsub_q, MATCH_FNMSUB_Q, MASK_FNMSUB_Q) +DECLARE_INSN(fnmadd_q, MATCH_FNMADD_Q, MASK_FNMADD_Q) +DECLARE_INSN(c_nop, MATCH_C_NOP, MASK_C_NOP) +DECLARE_INSN(c_addi16sp, MATCH_C_ADDI16SP, MASK_C_ADDI16SP) +DECLARE_INSN(c_jr, MATCH_C_JR, MASK_C_JR) +DECLARE_INSN(c_jalr, MATCH_C_JALR, MASK_C_JALR) +DECLARE_INSN(c_ebreak, MATCH_C_EBREAK, MASK_C_EBREAK) +DECLARE_INSN(c_ld, MATCH_C_LD, MASK_C_LD) +DECLARE_INSN(c_sd, MATCH_C_SD, MASK_C_SD) +DECLARE_INSN(c_addiw, MATCH_C_ADDIW, MASK_C_ADDIW) +DECLARE_INSN(c_ldsp, MATCH_C_LDSP, MASK_C_LDSP) +DECLARE_INSN(c_sdsp, MATCH_C_SDSP, MASK_C_SDSP) +DECLARE_INSN(c_addi4spn, MATCH_C_ADDI4SPN, MASK_C_ADDI4SPN) +DECLARE_INSN(c_fld, MATCH_C_FLD, MASK_C_FLD) +DECLARE_INSN(c_lw, MATCH_C_LW, MASK_C_LW) +DECLARE_INSN(c_flw, MATCH_C_FLW, MASK_C_FLW) +DECLARE_INSN(c_fsd, MATCH_C_FSD, MASK_C_FSD) +DECLARE_INSN(c_sw, MATCH_C_SW, MASK_C_SW) +DECLARE_INSN(c_fsw, MATCH_C_FSW, MASK_C_FSW) +DECLARE_INSN(c_addi, MATCH_C_ADDI, MASK_C_ADDI) +DECLARE_INSN(c_jal, MATCH_C_JAL, MASK_C_JAL) +DECLARE_INSN(c_li, MATCH_C_LI, MASK_C_LI) +DECLARE_INSN(c_lui, MATCH_C_LUI, MASK_C_LUI) +DECLARE_INSN(c_srli, MATCH_C_SRLI, MASK_C_SRLI) +DECLARE_INSN(c_srai, MATCH_C_SRAI, MASK_C_SRAI) +DECLARE_INSN(c_andi, MATCH_C_ANDI, MASK_C_ANDI) +DECLARE_INSN(c_sub, MATCH_C_SUB, MASK_C_SUB) +DECLARE_INSN(c_xor, MATCH_C_XOR, MASK_C_XOR) +DECLARE_INSN(c_or, MATCH_C_OR, MASK_C_OR) +DECLARE_INSN(c_and, MATCH_C_AND, MASK_C_AND) +DECLARE_INSN(c_subw, MATCH_C_SUBW, MASK_C_SUBW) +DECLARE_INSN(c_addw, MATCH_C_ADDW, MASK_C_ADDW) +DECLARE_INSN(c_j, MATCH_C_J, MASK_C_J) +DECLARE_INSN(c_beqz, MATCH_C_BEQZ, MASK_C_BEQZ) +DECLARE_INSN(c_bnez, MATCH_C_BNEZ, MASK_C_BNEZ) +DECLARE_INSN(c_slli, MATCH_C_SLLI, MASK_C_SLLI) +DECLARE_INSN(c_fldsp, MATCH_C_FLDSP, MASK_C_FLDSP) +DECLARE_INSN(c_lwsp, MATCH_C_LWSP, MASK_C_LWSP) +DECLARE_INSN(c_flwsp, MATCH_C_FLWSP, MASK_C_FLWSP) +DECLARE_INSN(c_mv, MATCH_C_MV, MASK_C_MV) +DECLARE_INSN(c_add, MATCH_C_ADD, MASK_C_ADD) +DECLARE_INSN(c_fsdsp, MATCH_C_FSDSP, MASK_C_FSDSP) +DECLARE_INSN(c_swsp, MATCH_C_SWSP, MASK_C_SWSP) +DECLARE_INSN(c_fswsp, MATCH_C_FSWSP, MASK_C_FSWSP) +DECLARE_INSN(custom0, MATCH_CUSTOM0, MASK_CUSTOM0) +DECLARE_INSN(custom0_rs1, MATCH_CUSTOM0_RS1, MASK_CUSTOM0_RS1) +DECLARE_INSN(custom0_rs1_rs2, MATCH_CUSTOM0_RS1_RS2, MASK_CUSTOM0_RS1_RS2) +DECLARE_INSN(custom0_rd, MATCH_CUSTOM0_RD, MASK_CUSTOM0_RD) +DECLARE_INSN(custom0_rd_rs1, MATCH_CUSTOM0_RD_RS1, MASK_CUSTOM0_RD_RS1) +DECLARE_INSN(custom0_rd_rs1_rs2, MATCH_CUSTOM0_RD_RS1_RS2, MASK_CUSTOM0_RD_RS1_RS2) +DECLARE_INSN(custom1, MATCH_CUSTOM1, MASK_CUSTOM1) +DECLARE_INSN(custom1_rs1, MATCH_CUSTOM1_RS1, MASK_CUSTOM1_RS1) +DECLARE_INSN(custom1_rs1_rs2, MATCH_CUSTOM1_RS1_RS2, MASK_CUSTOM1_RS1_RS2) +DECLARE_INSN(custom1_rd, MATCH_CUSTOM1_RD, MASK_CUSTOM1_RD) +DECLARE_INSN(custom1_rd_rs1, MATCH_CUSTOM1_RD_RS1, MASK_CUSTOM1_RD_RS1) +DECLARE_INSN(custom1_rd_rs1_rs2, MATCH_CUSTOM1_RD_RS1_RS2, MASK_CUSTOM1_RD_RS1_RS2) +DECLARE_INSN(custom2, MATCH_CUSTOM2, MASK_CUSTOM2) +DECLARE_INSN(custom2_rs1, MATCH_CUSTOM2_RS1, MASK_CUSTOM2_RS1) +DECLARE_INSN(custom2_rs1_rs2, MATCH_CUSTOM2_RS1_RS2, MASK_CUSTOM2_RS1_RS2) +DECLARE_INSN(custom2_rd, MATCH_CUSTOM2_RD, MASK_CUSTOM2_RD) +DECLARE_INSN(custom2_rd_rs1, MATCH_CUSTOM2_RD_RS1, MASK_CUSTOM2_RD_RS1) +DECLARE_INSN(custom2_rd_rs1_rs2, MATCH_CUSTOM2_RD_RS1_RS2, MASK_CUSTOM2_RD_RS1_RS2) +DECLARE_INSN(custom3, MATCH_CUSTOM3, MASK_CUSTOM3) +DECLARE_INSN(custom3_rs1, MATCH_CUSTOM3_RS1, MASK_CUSTOM3_RS1) +DECLARE_INSN(custom3_rs1_rs2, MATCH_CUSTOM3_RS1_RS2, MASK_CUSTOM3_RS1_RS2) +DECLARE_INSN(custom3_rd, MATCH_CUSTOM3_RD, MASK_CUSTOM3_RD) +DECLARE_INSN(custom3_rd_rs1, MATCH_CUSTOM3_RD_RS1, MASK_CUSTOM3_RD_RS1) +DECLARE_INSN(custom3_rd_rs1_rs2, MATCH_CUSTOM3_RD_RS1_RS2, MASK_CUSTOM3_RD_RS1_RS2) +#endif +#ifdef DECLARE_CSR +DECLARE_CSR(fflags, CSR_FFLAGS) +DECLARE_CSR(frm, CSR_FRM) +DECLARE_CSR(fcsr, CSR_FCSR) +DECLARE_CSR(cycle, CSR_CYCLE) +DECLARE_CSR(time, CSR_TIME) +DECLARE_CSR(instret, CSR_INSTRET) +DECLARE_CSR(hpmcounter3, CSR_HPMCOUNTER3) +DECLARE_CSR(hpmcounter4, CSR_HPMCOUNTER4) +DECLARE_CSR(hpmcounter5, CSR_HPMCOUNTER5) +DECLARE_CSR(hpmcounter6, CSR_HPMCOUNTER6) +DECLARE_CSR(hpmcounter7, CSR_HPMCOUNTER7) +DECLARE_CSR(hpmcounter8, CSR_HPMCOUNTER8) +DECLARE_CSR(hpmcounter9, CSR_HPMCOUNTER9) +DECLARE_CSR(hpmcounter10, CSR_HPMCOUNTER10) +DECLARE_CSR(hpmcounter11, CSR_HPMCOUNTER11) +DECLARE_CSR(hpmcounter12, CSR_HPMCOUNTER12) +DECLARE_CSR(hpmcounter13, CSR_HPMCOUNTER13) +DECLARE_CSR(hpmcounter14, CSR_HPMCOUNTER14) +DECLARE_CSR(hpmcounter15, CSR_HPMCOUNTER15) +DECLARE_CSR(hpmcounter16, CSR_HPMCOUNTER16) +DECLARE_CSR(hpmcounter17, CSR_HPMCOUNTER17) +DECLARE_CSR(hpmcounter18, CSR_HPMCOUNTER18) +DECLARE_CSR(hpmcounter19, CSR_HPMCOUNTER19) +DECLARE_CSR(hpmcounter20, CSR_HPMCOUNTER20) +DECLARE_CSR(hpmcounter21, CSR_HPMCOUNTER21) +DECLARE_CSR(hpmcounter22, CSR_HPMCOUNTER22) +DECLARE_CSR(hpmcounter23, CSR_HPMCOUNTER23) +DECLARE_CSR(hpmcounter24, CSR_HPMCOUNTER24) +DECLARE_CSR(hpmcounter25, CSR_HPMCOUNTER25) +DECLARE_CSR(hpmcounter26, CSR_HPMCOUNTER26) +DECLARE_CSR(hpmcounter27, CSR_HPMCOUNTER27) +DECLARE_CSR(hpmcounter28, CSR_HPMCOUNTER28) +DECLARE_CSR(hpmcounter29, CSR_HPMCOUNTER29) +DECLARE_CSR(hpmcounter30, CSR_HPMCOUNTER30) +DECLARE_CSR(hpmcounter31, CSR_HPMCOUNTER31) +DECLARE_CSR(sstatus, CSR_SSTATUS) +DECLARE_CSR(sie, CSR_SIE) +DECLARE_CSR(stvec, CSR_STVEC) +DECLARE_CSR(scounteren, CSR_SCOUNTEREN) +DECLARE_CSR(sscratch, CSR_SSCRATCH) +DECLARE_CSR(sepc, CSR_SEPC) +DECLARE_CSR(scause, CSR_SCAUSE) +DECLARE_CSR(stval, CSR_STVAL) +DECLARE_CSR(sip, CSR_SIP) +DECLARE_CSR(satp, CSR_SATP) +DECLARE_CSR(mstatus, CSR_MSTATUS) +DECLARE_CSR(misa, CSR_MISA) +DECLARE_CSR(medeleg, CSR_MEDELEG) +DECLARE_CSR(mideleg, CSR_MIDELEG) +DECLARE_CSR(mie, CSR_MIE) +DECLARE_CSR(mtvec, CSR_MTVEC) +DECLARE_CSR(mcounteren, CSR_MCOUNTEREN) +DECLARE_CSR(mscratch, CSR_MSCRATCH) +DECLARE_CSR(mepc, CSR_MEPC) +DECLARE_CSR(mcause, CSR_MCAUSE) +DECLARE_CSR(mtval, CSR_MTVAL) +DECLARE_CSR(mip, CSR_MIP) +DECLARE_CSR(pmpcfg0, CSR_PMPCFG0) +DECLARE_CSR(pmpcfg1, CSR_PMPCFG1) +DECLARE_CSR(pmpcfg2, CSR_PMPCFG2) +DECLARE_CSR(pmpcfg3, CSR_PMPCFG3) +DECLARE_CSR(pmpaddr0, CSR_PMPADDR0) +DECLARE_CSR(pmpaddr1, CSR_PMPADDR1) +DECLARE_CSR(pmpaddr2, CSR_PMPADDR2) +DECLARE_CSR(pmpaddr3, CSR_PMPADDR3) +DECLARE_CSR(pmpaddr4, CSR_PMPADDR4) +DECLARE_CSR(pmpaddr5, CSR_PMPADDR5) +DECLARE_CSR(pmpaddr6, CSR_PMPADDR6) +DECLARE_CSR(pmpaddr7, CSR_PMPADDR7) +DECLARE_CSR(pmpaddr8, CSR_PMPADDR8) +DECLARE_CSR(pmpaddr9, CSR_PMPADDR9) +DECLARE_CSR(pmpaddr10, CSR_PMPADDR10) +DECLARE_CSR(pmpaddr11, CSR_PMPADDR11) +DECLARE_CSR(pmpaddr12, CSR_PMPADDR12) +DECLARE_CSR(pmpaddr13, CSR_PMPADDR13) +DECLARE_CSR(pmpaddr14, CSR_PMPADDR14) +DECLARE_CSR(pmpaddr15, CSR_PMPADDR15) +DECLARE_CSR(tselect, CSR_TSELECT) +DECLARE_CSR(tdata1, CSR_TDATA1) +DECLARE_CSR(tdata2, CSR_TDATA2) +DECLARE_CSR(tdata3, CSR_TDATA3) +DECLARE_CSR(dcsr, CSR_DCSR) +DECLARE_CSR(dpc, CSR_DPC) +DECLARE_CSR(dscratch, CSR_DSCRATCH) +DECLARE_CSR(mcycle, CSR_MCYCLE) +DECLARE_CSR(minstret, CSR_MINSTRET) +DECLARE_CSR(mhpmcounter3, CSR_MHPMCOUNTER3) +DECLARE_CSR(mhpmcounter4, CSR_MHPMCOUNTER4) +DECLARE_CSR(mhpmcounter5, CSR_MHPMCOUNTER5) +DECLARE_CSR(mhpmcounter6, CSR_MHPMCOUNTER6) +DECLARE_CSR(mhpmcounter7, CSR_MHPMCOUNTER7) +DECLARE_CSR(mhpmcounter8, CSR_MHPMCOUNTER8) +DECLARE_CSR(mhpmcounter9, CSR_MHPMCOUNTER9) +DECLARE_CSR(mhpmcounter10, CSR_MHPMCOUNTER10) +DECLARE_CSR(mhpmcounter11, CSR_MHPMCOUNTER11) +DECLARE_CSR(mhpmcounter12, CSR_MHPMCOUNTER12) +DECLARE_CSR(mhpmcounter13, CSR_MHPMCOUNTER13) +DECLARE_CSR(mhpmcounter14, CSR_MHPMCOUNTER14) +DECLARE_CSR(mhpmcounter15, CSR_MHPMCOUNTER15) +DECLARE_CSR(mhpmcounter16, CSR_MHPMCOUNTER16) +DECLARE_CSR(mhpmcounter17, CSR_MHPMCOUNTER17) +DECLARE_CSR(mhpmcounter18, CSR_MHPMCOUNTER18) +DECLARE_CSR(mhpmcounter19, CSR_MHPMCOUNTER19) +DECLARE_CSR(mhpmcounter20, CSR_MHPMCOUNTER20) +DECLARE_CSR(mhpmcounter21, CSR_MHPMCOUNTER21) +DECLARE_CSR(mhpmcounter22, CSR_MHPMCOUNTER22) +DECLARE_CSR(mhpmcounter23, CSR_MHPMCOUNTER23) +DECLARE_CSR(mhpmcounter24, CSR_MHPMCOUNTER24) +DECLARE_CSR(mhpmcounter25, CSR_MHPMCOUNTER25) +DECLARE_CSR(mhpmcounter26, CSR_MHPMCOUNTER26) +DECLARE_CSR(mhpmcounter27, CSR_MHPMCOUNTER27) +DECLARE_CSR(mhpmcounter28, CSR_MHPMCOUNTER28) +DECLARE_CSR(mhpmcounter29, CSR_MHPMCOUNTER29) +DECLARE_CSR(mhpmcounter30, CSR_MHPMCOUNTER30) +DECLARE_CSR(mhpmcounter31, CSR_MHPMCOUNTER31) +DECLARE_CSR(mhpmevent3, CSR_MHPMEVENT3) +DECLARE_CSR(mhpmevent4, CSR_MHPMEVENT4) +DECLARE_CSR(mhpmevent5, CSR_MHPMEVENT5) +DECLARE_CSR(mhpmevent6, CSR_MHPMEVENT6) +DECLARE_CSR(mhpmevent7, CSR_MHPMEVENT7) +DECLARE_CSR(mhpmevent8, CSR_MHPMEVENT8) +DECLARE_CSR(mhpmevent9, CSR_MHPMEVENT9) +DECLARE_CSR(mhpmevent10, CSR_MHPMEVENT10) +DECLARE_CSR(mhpmevent11, CSR_MHPMEVENT11) +DECLARE_CSR(mhpmevent12, CSR_MHPMEVENT12) +DECLARE_CSR(mhpmevent13, CSR_MHPMEVENT13) +DECLARE_CSR(mhpmevent14, CSR_MHPMEVENT14) +DECLARE_CSR(mhpmevent15, CSR_MHPMEVENT15) +DECLARE_CSR(mhpmevent16, CSR_MHPMEVENT16) +DECLARE_CSR(mhpmevent17, CSR_MHPMEVENT17) +DECLARE_CSR(mhpmevent18, CSR_MHPMEVENT18) +DECLARE_CSR(mhpmevent19, CSR_MHPMEVENT19) +DECLARE_CSR(mhpmevent20, CSR_MHPMEVENT20) +DECLARE_CSR(mhpmevent21, CSR_MHPMEVENT21) +DECLARE_CSR(mhpmevent22, CSR_MHPMEVENT22) +DECLARE_CSR(mhpmevent23, CSR_MHPMEVENT23) +DECLARE_CSR(mhpmevent24, CSR_MHPMEVENT24) +DECLARE_CSR(mhpmevent25, CSR_MHPMEVENT25) +DECLARE_CSR(mhpmevent26, CSR_MHPMEVENT26) +DECLARE_CSR(mhpmevent27, CSR_MHPMEVENT27) +DECLARE_CSR(mhpmevent28, CSR_MHPMEVENT28) +DECLARE_CSR(mhpmevent29, CSR_MHPMEVENT29) +DECLARE_CSR(mhpmevent30, CSR_MHPMEVENT30) +DECLARE_CSR(mhpmevent31, CSR_MHPMEVENT31) +DECLARE_CSR(mvendorid, CSR_MVENDORID) +DECLARE_CSR(marchid, CSR_MARCHID) +DECLARE_CSR(mimpid, CSR_MIMPID) +DECLARE_CSR(mhartid, CSR_MHARTID) +DECLARE_CSR(cycleh, CSR_CYCLEH) +DECLARE_CSR(timeh, CSR_TIMEH) +DECLARE_CSR(instreth, CSR_INSTRETH) +DECLARE_CSR(hpmcounter3h, CSR_HPMCOUNTER3H) +DECLARE_CSR(hpmcounter4h, CSR_HPMCOUNTER4H) +DECLARE_CSR(hpmcounter5h, CSR_HPMCOUNTER5H) +DECLARE_CSR(hpmcounter6h, CSR_HPMCOUNTER6H) +DECLARE_CSR(hpmcounter7h, CSR_HPMCOUNTER7H) +DECLARE_CSR(hpmcounter8h, CSR_HPMCOUNTER8H) +DECLARE_CSR(hpmcounter9h, CSR_HPMCOUNTER9H) +DECLARE_CSR(hpmcounter10h, CSR_HPMCOUNTER10H) +DECLARE_CSR(hpmcounter11h, CSR_HPMCOUNTER11H) +DECLARE_CSR(hpmcounter12h, CSR_HPMCOUNTER12H) +DECLARE_CSR(hpmcounter13h, CSR_HPMCOUNTER13H) +DECLARE_CSR(hpmcounter14h, CSR_HPMCOUNTER14H) +DECLARE_CSR(hpmcounter15h, CSR_HPMCOUNTER15H) +DECLARE_CSR(hpmcounter16h, CSR_HPMCOUNTER16H) +DECLARE_CSR(hpmcounter17h, CSR_HPMCOUNTER17H) +DECLARE_CSR(hpmcounter18h, CSR_HPMCOUNTER18H) +DECLARE_CSR(hpmcounter19h, CSR_HPMCOUNTER19H) +DECLARE_CSR(hpmcounter20h, CSR_HPMCOUNTER20H) +DECLARE_CSR(hpmcounter21h, CSR_HPMCOUNTER21H) +DECLARE_CSR(hpmcounter22h, CSR_HPMCOUNTER22H) +DECLARE_CSR(hpmcounter23h, CSR_HPMCOUNTER23H) +DECLARE_CSR(hpmcounter24h, CSR_HPMCOUNTER24H) +DECLARE_CSR(hpmcounter25h, CSR_HPMCOUNTER25H) +DECLARE_CSR(hpmcounter26h, CSR_HPMCOUNTER26H) +DECLARE_CSR(hpmcounter27h, CSR_HPMCOUNTER27H) +DECLARE_CSR(hpmcounter28h, CSR_HPMCOUNTER28H) +DECLARE_CSR(hpmcounter29h, CSR_HPMCOUNTER29H) +DECLARE_CSR(hpmcounter30h, CSR_HPMCOUNTER30H) +DECLARE_CSR(hpmcounter31h, CSR_HPMCOUNTER31H) +DECLARE_CSR(mcycleh, CSR_MCYCLEH) +DECLARE_CSR(minstreth, CSR_MINSTRETH) +DECLARE_CSR(mhpmcounter3h, CSR_MHPMCOUNTER3H) +DECLARE_CSR(mhpmcounter4h, CSR_MHPMCOUNTER4H) +DECLARE_CSR(mhpmcounter5h, CSR_MHPMCOUNTER5H) +DECLARE_CSR(mhpmcounter6h, CSR_MHPMCOUNTER6H) +DECLARE_CSR(mhpmcounter7h, CSR_MHPMCOUNTER7H) +DECLARE_CSR(mhpmcounter8h, CSR_MHPMCOUNTER8H) +DECLARE_CSR(mhpmcounter9h, CSR_MHPMCOUNTER9H) +DECLARE_CSR(mhpmcounter10h, CSR_MHPMCOUNTER10H) +DECLARE_CSR(mhpmcounter11h, CSR_MHPMCOUNTER11H) +DECLARE_CSR(mhpmcounter12h, CSR_MHPMCOUNTER12H) +DECLARE_CSR(mhpmcounter13h, CSR_MHPMCOUNTER13H) +DECLARE_CSR(mhpmcounter14h, CSR_MHPMCOUNTER14H) +DECLARE_CSR(mhpmcounter15h, CSR_MHPMCOUNTER15H) +DECLARE_CSR(mhpmcounter16h, CSR_MHPMCOUNTER16H) +DECLARE_CSR(mhpmcounter17h, CSR_MHPMCOUNTER17H) +DECLARE_CSR(mhpmcounter18h, CSR_MHPMCOUNTER18H) +DECLARE_CSR(mhpmcounter19h, CSR_MHPMCOUNTER19H) +DECLARE_CSR(mhpmcounter20h, CSR_MHPMCOUNTER20H) +DECLARE_CSR(mhpmcounter21h, CSR_MHPMCOUNTER21H) +DECLARE_CSR(mhpmcounter22h, CSR_MHPMCOUNTER22H) +DECLARE_CSR(mhpmcounter23h, CSR_MHPMCOUNTER23H) +DECLARE_CSR(mhpmcounter24h, CSR_MHPMCOUNTER24H) +DECLARE_CSR(mhpmcounter25h, CSR_MHPMCOUNTER25H) +DECLARE_CSR(mhpmcounter26h, CSR_MHPMCOUNTER26H) +DECLARE_CSR(mhpmcounter27h, CSR_MHPMCOUNTER27H) +DECLARE_CSR(mhpmcounter28h, CSR_MHPMCOUNTER28H) +DECLARE_CSR(mhpmcounter29h, CSR_MHPMCOUNTER29H) +DECLARE_CSR(mhpmcounter30h, CSR_MHPMCOUNTER30H) +DECLARE_CSR(mhpmcounter31h, CSR_MHPMCOUNTER31H) +#endif +#ifdef DECLARE_CAUSE +DECLARE_CAUSE("misaligned fetch", CAUSE_MISALIGNED_FETCH) +DECLARE_CAUSE("fetch access", CAUSE_FETCH_ACCESS) +DECLARE_CAUSE("illegal instruction", CAUSE_ILLEGAL_INSTRUCTION) +DECLARE_CAUSE("breakpoint", CAUSE_BREAKPOINT) +DECLARE_CAUSE("misaligned load", CAUSE_MISALIGNED_LOAD) +DECLARE_CAUSE("load access", CAUSE_LOAD_ACCESS) +DECLARE_CAUSE("misaligned store", CAUSE_MISALIGNED_STORE) +DECLARE_CAUSE("store access", CAUSE_STORE_ACCESS) +DECLARE_CAUSE("user_ecall", CAUSE_USER_ECALL) +DECLARE_CAUSE("supervisor_ecall", CAUSE_SUPERVISOR_ECALL) +DECLARE_CAUSE("hypervisor_ecall", CAUSE_HYPERVISOR_ECALL) +DECLARE_CAUSE("machine_ecall", CAUSE_MACHINE_ECALL) +DECLARE_CAUSE("fetch page fault", CAUSE_FETCH_PAGE_FAULT) +DECLARE_CAUSE("load page fault", CAUSE_LOAD_PAGE_FAULT) +DECLARE_CAUSE("store page fault", CAUSE_STORE_PAGE_FAULT) +#endif diff --git a/src/test/cpp/raw/deleg/src/ld b/src/test/cpp/raw/deleg/src/ld new file mode 100644 index 00000000..93d8de8e --- /dev/null +++ b/src/test/cpp/raw/deleg/src/ld @@ -0,0 +1,16 @@ +OUTPUT_ARCH( "riscv" ) + +MEMORY { + onChipRam (W!RX)/*(RX)*/ : ORIGIN = 0x80000000, LENGTH = 128K +} + +SECTIONS +{ + + .crt_section : + { + . = ALIGN(4); + *crt.o(.text) + } > onChipRam + +} diff --git a/src/test/cpp/raw/mmu/build/mmu.asm b/src/test/cpp/raw/mmu/build/mmu.asm index 5d39ccc4..1cb5df41 100644 --- a/src/test/cpp/raw/mmu/build/mmu.asm +++ b/src/test/cpp/raw/mmu/build/mmu.asm @@ -435,11 +435,11 @@ Disassembly of section .crt_section: 80000594: fe0e80e3 beqz t4,80000574 80000598: 342020f3 csrr ra,mcause 8000059c: 341020f3 csrr ra,mepc -800005a0: 00200093 li ra,2 -800005a4: fe1e82e3 beq t4,ra,80000588 -800005a8: 341f1073 csrw mepc,t5 -800005ac: 30200073 mret -800005b0: 00000013 nop +800005a0: 300020f3 csrr ra,mstatus +800005a4: 00200093 li ra,2 +800005a8: fe1e80e3 beq t4,ra,80000588 +800005ac: 341f1073 csrw mepc,t5 +800005b0: 30200073 mret 800005b4: 00000013 nop 800005b8: 00000013 nop 800005bc: 00000013 nop diff --git a/src/test/cpp/raw/mmu/build/mmu.hex b/src/test/cpp/raw/mmu/build/mmu.hex index bcf2f1da..8ee88714 100644 --- a/src/test/cpp/raw/mmu/build/mmu.hex +++ b/src/test/cpp/raw/mmu/build/mmu.hex @@ -89,8 +89,8 @@ :1005700073000000370110F0130141F22320C10184 :10058000930E200073000000370110F0130101F2F8 :1005900023200100E3800EFEF3202034F3201034EA -:1005A00093002000E3821EFE73101F34730020307E -:1005B00013000000130000001300000013000000EF +:1005A000F320003093002000E3801EFE73101F3400 +:1005B000730020301300000013000000130000003F :1005C00013000000130000001300000013000000DF :1005D00013000000130000001300000013000000CF :1005E00013000000130000001300000013000000BF @@ -3229,6 +3229,5 @@ :10C9B0000000000000000000000000000000000077 :10C9C0000000000000000000000000000000000067 :10C9D0000000000000000000000000000000000057 -:04C9E0000000000053 :040000058000000077 :00000001FF diff --git a/src/test/cpp/raw/mmu/src/crt.S b/src/test/cpp/raw/mmu/src/crt.S index afee5dd7..4e11e52d 100644 --- a/src/test/cpp/raw/mmu/src/crt.S +++ b/src/test/cpp/raw/mmu/src/crt.S @@ -420,6 +420,7 @@ trap: beq TRAP_OK, x0, failFence csrr x1, mcause csrr x1, mepc + csrr x1, mstatus li x1, 2 beq TRAP_OK, x1, passFence csrw mepc, TRAP_RET diff --git a/src/test/cpp/regression/encoding.h b/src/test/cpp/regression/encoding.h new file mode 100644 index 00000000..c109ce18 --- /dev/null +++ b/src/test/cpp/regression/encoding.h @@ -0,0 +1,1471 @@ +// See LICENSE for license details. + +#ifndef RISCV_CSR_ENCODING_H +#define RISCV_CSR_ENCODING_H + +#define MSTATUS_UIE 0x00000001 +#define MSTATUS_SIE 0x00000002 +#define MSTATUS_HIE 0x00000004 +#define MSTATUS_MIE 0x00000008 +#define MSTATUS_UPIE 0x00000010 +#define MSTATUS_SPIE 0x00000020 +#define MSTATUS_HPIE 0x00000040 +#define MSTATUS_MPIE 0x00000080 +#define MSTATUS_SPP 0x00000100 +#define MSTATUS_HPP 0x00000600 +#define MSTATUS_MPP 0x00001800 +#define MSTATUS_FS 0x00006000 +#define MSTATUS_XS 0x00018000 +#define MSTATUS_MPRV 0x00020000 +#define MSTATUS_SUM 0x00040000 +#define MSTATUS_MXR 0x00080000 +#define MSTATUS_TVM 0x00100000 +#define MSTATUS_TW 0x00200000 +#define MSTATUS_TSR 0x00400000 +#define MSTATUS32_SD 0x80000000 +#define MSTATUS_UXL 0x0000000300000000 +#define MSTATUS_SXL 0x0000000C00000000 +#define MSTATUS64_SD 0x8000000000000000 + +#define SSTATUS_UIE 0x00000001 +#define SSTATUS_SIE 0x00000002 +#define SSTATUS_UPIE 0x00000010 +#define SSTATUS_SPIE 0x00000020 +#define SSTATUS_SPP 0x00000100 +#define SSTATUS_FS 0x00006000 +#define SSTATUS_XS 0x00018000 +#define SSTATUS_SUM 0x00040000 +#define SSTATUS_MXR 0x00080000 +#define SSTATUS32_SD 0x80000000 +#define SSTATUS_UXL 0x0000000300000000 +#define SSTATUS64_SD 0x8000000000000000 + +#define DCSR_XDEBUGVER (3U<<30) +#define DCSR_NDRESET (1<<29) +#define DCSR_FULLRESET (1<<28) +#define DCSR_EBREAKM (1<<15) +#define DCSR_EBREAKH (1<<14) +#define DCSR_EBREAKS (1<<13) +#define DCSR_EBREAKU (1<<12) +#define DCSR_STOPCYCLE (1<<10) +#define DCSR_STOPTIME (1<<9) +#define DCSR_CAUSE (7<<6) +#define DCSR_DEBUGINT (1<<5) +#define DCSR_HALT (1<<3) +#define DCSR_STEP (1<<2) +#define DCSR_PRV (3<<0) + +#define DCSR_CAUSE_NONE 0 +#define DCSR_CAUSE_SWBP 1 +#define DCSR_CAUSE_HWBP 2 +#define DCSR_CAUSE_DEBUGINT 3 +#define DCSR_CAUSE_STEP 4 +#define DCSR_CAUSE_HALT 5 + +#define MCONTROL_TYPE(xlen) (0xfULL<<((xlen)-4)) +#define MCONTROL_DMODE(xlen) (1ULL<<((xlen)-5)) +#define MCONTROL_MASKMAX(xlen) (0x3fULL<<((xlen)-11)) + +#define MCONTROL_SELECT (1<<19) +#define MCONTROL_TIMING (1<<18) +#define MCONTROL_ACTION (0x3f<<12) +#define MCONTROL_CHAIN (1<<11) +#define MCONTROL_MATCH (0xf<<7) +#define MCONTROL_M (1<<6) +#define MCONTROL_H (1<<5) +#define MCONTROL_S (1<<4) +#define MCONTROL_U (1<<3) +#define MCONTROL_EXECUTE (1<<2) +#define MCONTROL_STORE (1<<1) +#define MCONTROL_LOAD (1<<0) + +#define MCONTROL_TYPE_NONE 0 +#define MCONTROL_TYPE_MATCH 2 + +#define MCONTROL_ACTION_DEBUG_EXCEPTION 0 +#define MCONTROL_ACTION_DEBUG_MODE 1 +#define MCONTROL_ACTION_TRACE_START 2 +#define MCONTROL_ACTION_TRACE_STOP 3 +#define MCONTROL_ACTION_TRACE_EMIT 4 + +#define MCONTROL_MATCH_EQUAL 0 +#define MCONTROL_MATCH_NAPOT 1 +#define MCONTROL_MATCH_GE 2 +#define MCONTROL_MATCH_LT 3 +#define MCONTROL_MATCH_MASK_LOW 4 +#define MCONTROL_MATCH_MASK_HIGH 5 + +#define MIP_SSIP (1 << IRQ_S_SOFT) +#define MIP_HSIP (1 << IRQ_H_SOFT) +#define MIP_MSIP (1 << IRQ_M_SOFT) +#define MIP_STIP (1 << IRQ_S_TIMER) +#define MIP_HTIP (1 << IRQ_H_TIMER) +#define MIP_MTIP (1 << IRQ_M_TIMER) +#define MIP_SEIP (1 << IRQ_S_EXT) +#define MIP_HEIP (1 << IRQ_H_EXT) +#define MIP_MEIP (1 << IRQ_M_EXT) + +#define SIP_SSIP MIP_SSIP +#define SIP_STIP MIP_STIP + +#define PRV_U 0 +#define PRV_S 1 +#define PRV_H 2 +#define PRV_M 3 + +#define SATP32_MODE 0x80000000 +#define SATP32_ASID 0x7FC00000 +#define SATP32_PPN 0x003FFFFF +#define SATP64_MODE 0xF000000000000000 +#define SATP64_ASID 0x0FFFF00000000000 +#define SATP64_PPN 0x00000FFFFFFFFFFF + +#define SATP_MODE_OFF 0 +#define SATP_MODE_SV32 1 +#define SATP_MODE_SV39 8 +#define SATP_MODE_SV48 9 +#define SATP_MODE_SV57 10 +#define SATP_MODE_SV64 11 + +#define PMP_R 0x01 +#define PMP_W 0x02 +#define PMP_X 0x04 +#define PMP_A 0x18 +#define PMP_L 0x80 +#define PMP_SHIFT 2 + +#define PMP_TOR 0x08 +#define PMP_NA4 0x10 +#define PMP_NAPOT 0x18 + +#define IRQ_S_SOFT 1 +#define IRQ_H_SOFT 2 +#define IRQ_M_SOFT 3 +#define IRQ_S_TIMER 5 +#define IRQ_H_TIMER 6 +#define IRQ_M_TIMER 7 +#define IRQ_S_EXT 9 +#define IRQ_H_EXT 10 +#define IRQ_M_EXT 11 +#define IRQ_COP 12 +#define IRQ_HOST 13 + +#define DEFAULT_RSTVEC 0x00001000 +#define CLINT_BASE 0x02000000 +#define CLINT_SIZE 0x000c0000 +#define EXT_IO_BASE 0x40000000 +#define DRAM_BASE 0x80000000 + +// page table entry (PTE) fields +#define PTE_V 0x001 // Valid +#define PTE_R 0x002 // Read +#define PTE_W 0x004 // Write +#define PTE_X 0x008 // Execute +#define PTE_U 0x010 // User +#define PTE_G 0x020 // Global +#define PTE_A 0x040 // Accessed +#define PTE_D 0x080 // Dirty +#define PTE_SOFT 0x300 // Reserved for Software + +#define PTE_PPN_SHIFT 10 + +#define PTE_TABLE(PTE) (((PTE) & (PTE_V | PTE_R | PTE_W | PTE_X)) == PTE_V) + +#ifdef __riscv + +#if __riscv_xlen == 64 +# define MSTATUS_SD MSTATUS64_SD +# define SSTATUS_SD SSTATUS64_SD +# define RISCV_PGLEVEL_BITS 9 +# define SATP_MODE SATP64_MODE +#else +# define MSTATUS_SD MSTATUS32_SD +# define SSTATUS_SD SSTATUS32_SD +# define RISCV_PGLEVEL_BITS 10 +# define SATP_MODE SATP32_MODE +#endif +#define RISCV_PGSHIFT 12 +#define RISCV_PGSIZE (1 << RISCV_PGSHIFT) + +#ifndef __ASSEMBLER__ + +#ifdef __GNUC__ + +#define read_csr(reg) ({ unsigned long __tmp; \ + asm volatile ("csrr %0, " #reg : "=r"(__tmp)); \ + __tmp; }) + +#define write_csr(reg, val) ({ \ + asm volatile ("csrw " #reg ", %0" :: "rK"(val)); }) + +#define swap_csr(reg, val) ({ unsigned long __tmp; \ + asm volatile ("csrrw %0, " #reg ", %1" : "=r"(__tmp) : "rK"(val)); \ + __tmp; }) + +#define set_csr(reg, bit) ({ unsigned long __tmp; \ + asm volatile ("csrrs %0, " #reg ", %1" : "=r"(__tmp) : "rK"(bit)); \ + __tmp; }) + +#define clear_csr(reg, bit) ({ unsigned long __tmp; \ + asm volatile ("csrrc %0, " #reg ", %1" : "=r"(__tmp) : "rK"(bit)); \ + __tmp; }) + +#define rdtime() read_csr(time) +#define rdcycle() read_csr(cycle) +#define rdinstret() read_csr(instret) + +#endif + +#endif + +#endif + +#endif +/* Automatically generated by parse-opcodes. */ +#ifndef RISCV_ENCODING_H +#define RISCV_ENCODING_H +#define MATCH_BEQ 0x63 +#define MASK_BEQ 0x707f +#define MATCH_BNE 0x1063 +#define MASK_BNE 0x707f +#define MATCH_BLT 0x4063 +#define MASK_BLT 0x707f +#define MATCH_BGE 0x5063 +#define MASK_BGE 0x707f +#define MATCH_BLTU 0x6063 +#define MASK_BLTU 0x707f +#define MATCH_BGEU 0x7063 +#define MASK_BGEU 0x707f +#define MATCH_JALR 0x67 +#define MASK_JALR 0x707f +#define MATCH_JAL 0x6f +#define MASK_JAL 0x7f +#define MATCH_LUI 0x37 +#define MASK_LUI 0x7f +#define MATCH_AUIPC 0x17 +#define MASK_AUIPC 0x7f +#define MATCH_ADDI 0x13 +#define MASK_ADDI 0x707f +#define MATCH_SLLI 0x1013 +#define MASK_SLLI 0xfc00707f +#define MATCH_SLTI 0x2013 +#define MASK_SLTI 0x707f +#define MATCH_SLTIU 0x3013 +#define MASK_SLTIU 0x707f +#define MATCH_XORI 0x4013 +#define MASK_XORI 0x707f +#define MATCH_SRLI 0x5013 +#define MASK_SRLI 0xfc00707f +#define MATCH_SRAI 0x40005013 +#define MASK_SRAI 0xfc00707f +#define MATCH_ORI 0x6013 +#define MASK_ORI 0x707f +#define MATCH_ANDI 0x7013 +#define MASK_ANDI 0x707f +#define MATCH_ADD 0x33 +#define MASK_ADD 0xfe00707f +#define MATCH_SUB 0x40000033 +#define MASK_SUB 0xfe00707f +#define MATCH_SLL 0x1033 +#define MASK_SLL 0xfe00707f +#define MATCH_SLT 0x2033 +#define MASK_SLT 0xfe00707f +#define MATCH_SLTU 0x3033 +#define MASK_SLTU 0xfe00707f +#define MATCH_XOR 0x4033 +#define MASK_XOR 0xfe00707f +#define MATCH_SRL 0x5033 +#define MASK_SRL 0xfe00707f +#define MATCH_SRA 0x40005033 +#define MASK_SRA 0xfe00707f +#define MATCH_OR 0x6033 +#define MASK_OR 0xfe00707f +#define MATCH_AND 0x7033 +#define MASK_AND 0xfe00707f +#define MATCH_ADDIW 0x1b +#define MASK_ADDIW 0x707f +#define MATCH_SLLIW 0x101b +#define MASK_SLLIW 0xfe00707f +#define MATCH_SRLIW 0x501b +#define MASK_SRLIW 0xfe00707f +#define MATCH_SRAIW 0x4000501b +#define MASK_SRAIW 0xfe00707f +#define MATCH_ADDW 0x3b +#define MASK_ADDW 0xfe00707f +#define MATCH_SUBW 0x4000003b +#define MASK_SUBW 0xfe00707f +#define MATCH_SLLW 0x103b +#define MASK_SLLW 0xfe00707f +#define MATCH_SRLW 0x503b +#define MASK_SRLW 0xfe00707f +#define MATCH_SRAW 0x4000503b +#define MASK_SRAW 0xfe00707f +#define MATCH_LB 0x3 +#define MASK_LB 0x707f +#define MATCH_LH 0x1003 +#define MASK_LH 0x707f +#define MATCH_LW 0x2003 +#define MASK_LW 0x707f +#define MATCH_LD 0x3003 +#define MASK_LD 0x707f +#define MATCH_LBU 0x4003 +#define MASK_LBU 0x707f +#define MATCH_LHU 0x5003 +#define MASK_LHU 0x707f +#define MATCH_LWU 0x6003 +#define MASK_LWU 0x707f +#define MATCH_SB 0x23 +#define MASK_SB 0x707f +#define MATCH_SH 0x1023 +#define MASK_SH 0x707f +#define MATCH_SW 0x2023 +#define MASK_SW 0x707f +#define MATCH_SD 0x3023 +#define MASK_SD 0x707f +#define MATCH_FENCE 0xf +#define MASK_FENCE 0x707f +#define MATCH_FENCE_I 0x100f +#define MASK_FENCE_I 0x707f +#define MATCH_MUL 0x2000033 +#define MASK_MUL 0xfe00707f +#define MATCH_MULH 0x2001033 +#define MASK_MULH 0xfe00707f +#define MATCH_MULHSU 0x2002033 +#define MASK_MULHSU 0xfe00707f +#define MATCH_MULHU 0x2003033 +#define MASK_MULHU 0xfe00707f +#define MATCH_DIV 0x2004033 +#define MASK_DIV 0xfe00707f +#define MATCH_DIVU 0x2005033 +#define MASK_DIVU 0xfe00707f +#define MATCH_REM 0x2006033 +#define MASK_REM 0xfe00707f +#define MATCH_REMU 0x2007033 +#define MASK_REMU 0xfe00707f +#define MATCH_MULW 0x200003b +#define MASK_MULW 0xfe00707f +#define MATCH_DIVW 0x200403b +#define MASK_DIVW 0xfe00707f +#define MATCH_DIVUW 0x200503b +#define MASK_DIVUW 0xfe00707f +#define MATCH_REMW 0x200603b +#define MASK_REMW 0xfe00707f +#define MATCH_REMUW 0x200703b +#define MASK_REMUW 0xfe00707f +#define MATCH_AMOADD_W 0x202f +#define MASK_AMOADD_W 0xf800707f +#define MATCH_AMOXOR_W 0x2000202f +#define MASK_AMOXOR_W 0xf800707f +#define MATCH_AMOOR_W 0x4000202f +#define MASK_AMOOR_W 0xf800707f +#define MATCH_AMOAND_W 0x6000202f +#define MASK_AMOAND_W 0xf800707f +#define MATCH_AMOMIN_W 0x8000202f +#define MASK_AMOMIN_W 0xf800707f +#define MATCH_AMOMAX_W 0xa000202f +#define MASK_AMOMAX_W 0xf800707f +#define MATCH_AMOMINU_W 0xc000202f +#define MASK_AMOMINU_W 0xf800707f +#define MATCH_AMOMAXU_W 0xe000202f +#define MASK_AMOMAXU_W 0xf800707f +#define MATCH_AMOSWAP_W 0x800202f +#define MASK_AMOSWAP_W 0xf800707f +#define MATCH_LR_W 0x1000202f +#define MASK_LR_W 0xf9f0707f +#define MATCH_SC_W 0x1800202f +#define MASK_SC_W 0xf800707f +#define MATCH_AMOADD_D 0x302f +#define MASK_AMOADD_D 0xf800707f +#define MATCH_AMOXOR_D 0x2000302f +#define MASK_AMOXOR_D 0xf800707f +#define MATCH_AMOOR_D 0x4000302f +#define MASK_AMOOR_D 0xf800707f +#define MATCH_AMOAND_D 0x6000302f +#define MASK_AMOAND_D 0xf800707f +#define MATCH_AMOMIN_D 0x8000302f +#define MASK_AMOMIN_D 0xf800707f +#define MATCH_AMOMAX_D 0xa000302f +#define MASK_AMOMAX_D 0xf800707f +#define MATCH_AMOMINU_D 0xc000302f +#define MASK_AMOMINU_D 0xf800707f +#define MATCH_AMOMAXU_D 0xe000302f +#define MASK_AMOMAXU_D 0xf800707f +#define MATCH_AMOSWAP_D 0x800302f +#define MASK_AMOSWAP_D 0xf800707f +#define MATCH_LR_D 0x1000302f +#define MASK_LR_D 0xf9f0707f +#define MATCH_SC_D 0x1800302f +#define MASK_SC_D 0xf800707f +#define MATCH_ECALL 0x73 +#define MASK_ECALL 0xffffffff +#define MATCH_EBREAK 0x100073 +#define MASK_EBREAK 0xffffffff +#define MATCH_URET 0x200073 +#define MASK_URET 0xffffffff +#define MATCH_SRET 0x10200073 +#define MASK_SRET 0xffffffff +#define MATCH_MRET 0x30200073 +#define MASK_MRET 0xffffffff +#define MATCH_DRET 0x7b200073 +#define MASK_DRET 0xffffffff +#define MATCH_SFENCE_VMA 0x12000073 +#define MASK_SFENCE_VMA 0xfe007fff +#define MATCH_WFI 0x10500073 +#define MASK_WFI 0xffffffff +#define MATCH_CSRRW 0x1073 +#define MASK_CSRRW 0x707f +#define MATCH_CSRRS 0x2073 +#define MASK_CSRRS 0x707f +#define MATCH_CSRRC 0x3073 +#define MASK_CSRRC 0x707f +#define MATCH_CSRRWI 0x5073 +#define MASK_CSRRWI 0x707f +#define MATCH_CSRRSI 0x6073 +#define MASK_CSRRSI 0x707f +#define MATCH_CSRRCI 0x7073 +#define MASK_CSRRCI 0x707f +#define MATCH_FADD_S 0x53 +#define MASK_FADD_S 0xfe00007f +#define MATCH_FSUB_S 0x8000053 +#define MASK_FSUB_S 0xfe00007f +#define MATCH_FMUL_S 0x10000053 +#define MASK_FMUL_S 0xfe00007f +#define MATCH_FDIV_S 0x18000053 +#define MASK_FDIV_S 0xfe00007f +#define MATCH_FSGNJ_S 0x20000053 +#define MASK_FSGNJ_S 0xfe00707f +#define MATCH_FSGNJN_S 0x20001053 +#define MASK_FSGNJN_S 0xfe00707f +#define MATCH_FSGNJX_S 0x20002053 +#define MASK_FSGNJX_S 0xfe00707f +#define MATCH_FMIN_S 0x28000053 +#define MASK_FMIN_S 0xfe00707f +#define MATCH_FMAX_S 0x28001053 +#define MASK_FMAX_S 0xfe00707f +#define MATCH_FSQRT_S 0x58000053 +#define MASK_FSQRT_S 0xfff0007f +#define MATCH_FADD_D 0x2000053 +#define MASK_FADD_D 0xfe00007f +#define MATCH_FSUB_D 0xa000053 +#define MASK_FSUB_D 0xfe00007f +#define MATCH_FMUL_D 0x12000053 +#define MASK_FMUL_D 0xfe00007f +#define MATCH_FDIV_D 0x1a000053 +#define MASK_FDIV_D 0xfe00007f +#define MATCH_FSGNJ_D 0x22000053 +#define MASK_FSGNJ_D 0xfe00707f +#define MATCH_FSGNJN_D 0x22001053 +#define MASK_FSGNJN_D 0xfe00707f +#define MATCH_FSGNJX_D 0x22002053 +#define MASK_FSGNJX_D 0xfe00707f +#define MATCH_FMIN_D 0x2a000053 +#define MASK_FMIN_D 0xfe00707f +#define MATCH_FMAX_D 0x2a001053 +#define MASK_FMAX_D 0xfe00707f +#define MATCH_FCVT_S_D 0x40100053 +#define MASK_FCVT_S_D 0xfff0007f +#define MATCH_FCVT_D_S 0x42000053 +#define MASK_FCVT_D_S 0xfff0007f +#define MATCH_FSQRT_D 0x5a000053 +#define MASK_FSQRT_D 0xfff0007f +#define MATCH_FADD_Q 0x6000053 +#define MASK_FADD_Q 0xfe00007f +#define MATCH_FSUB_Q 0xe000053 +#define MASK_FSUB_Q 0xfe00007f +#define MATCH_FMUL_Q 0x16000053 +#define MASK_FMUL_Q 0xfe00007f +#define MATCH_FDIV_Q 0x1e000053 +#define MASK_FDIV_Q 0xfe00007f +#define MATCH_FSGNJ_Q 0x26000053 +#define MASK_FSGNJ_Q 0xfe00707f +#define MATCH_FSGNJN_Q 0x26001053 +#define MASK_FSGNJN_Q 0xfe00707f +#define MATCH_FSGNJX_Q 0x26002053 +#define MASK_FSGNJX_Q 0xfe00707f +#define MATCH_FMIN_Q 0x2e000053 +#define MASK_FMIN_Q 0xfe00707f +#define MATCH_FMAX_Q 0x2e001053 +#define MASK_FMAX_Q 0xfe00707f +#define MATCH_FCVT_S_Q 0x40300053 +#define MASK_FCVT_S_Q 0xfff0007f +#define MATCH_FCVT_Q_S 0x46000053 +#define MASK_FCVT_Q_S 0xfff0007f +#define MATCH_FCVT_D_Q 0x42300053 +#define MASK_FCVT_D_Q 0xfff0007f +#define MATCH_FCVT_Q_D 0x46100053 +#define MASK_FCVT_Q_D 0xfff0007f +#define MATCH_FSQRT_Q 0x5e000053 +#define MASK_FSQRT_Q 0xfff0007f +#define MATCH_FLE_S 0xa0000053 +#define MASK_FLE_S 0xfe00707f +#define MATCH_FLT_S 0xa0001053 +#define MASK_FLT_S 0xfe00707f +#define MATCH_FEQ_S 0xa0002053 +#define MASK_FEQ_S 0xfe00707f +#define MATCH_FLE_D 0xa2000053 +#define MASK_FLE_D 0xfe00707f +#define MATCH_FLT_D 0xa2001053 +#define MASK_FLT_D 0xfe00707f +#define MATCH_FEQ_D 0xa2002053 +#define MASK_FEQ_D 0xfe00707f +#define MATCH_FLE_Q 0xa6000053 +#define MASK_FLE_Q 0xfe00707f +#define MATCH_FLT_Q 0xa6001053 +#define MASK_FLT_Q 0xfe00707f +#define MATCH_FEQ_Q 0xa6002053 +#define MASK_FEQ_Q 0xfe00707f +#define MATCH_FCVT_W_S 0xc0000053 +#define MASK_FCVT_W_S 0xfff0007f +#define MATCH_FCVT_WU_S 0xc0100053 +#define MASK_FCVT_WU_S 0xfff0007f +#define MATCH_FCVT_L_S 0xc0200053 +#define MASK_FCVT_L_S 0xfff0007f +#define MATCH_FCVT_LU_S 0xc0300053 +#define MASK_FCVT_LU_S 0xfff0007f +#define MATCH_FMV_X_W 0xe0000053 +#define MASK_FMV_X_W 0xfff0707f +#define MATCH_FCLASS_S 0xe0001053 +#define MASK_FCLASS_S 0xfff0707f +#define MATCH_FCVT_W_D 0xc2000053 +#define MASK_FCVT_W_D 0xfff0007f +#define MATCH_FCVT_WU_D 0xc2100053 +#define MASK_FCVT_WU_D 0xfff0007f +#define MATCH_FCVT_L_D 0xc2200053 +#define MASK_FCVT_L_D 0xfff0007f +#define MATCH_FCVT_LU_D 0xc2300053 +#define MASK_FCVT_LU_D 0xfff0007f +#define MATCH_FMV_X_D 0xe2000053 +#define MASK_FMV_X_D 0xfff0707f +#define MATCH_FCLASS_D 0xe2001053 +#define MASK_FCLASS_D 0xfff0707f +#define MATCH_FCVT_W_Q 0xc6000053 +#define MASK_FCVT_W_Q 0xfff0007f +#define MATCH_FCVT_WU_Q 0xc6100053 +#define MASK_FCVT_WU_Q 0xfff0007f +#define MATCH_FCVT_L_Q 0xc6200053 +#define MASK_FCVT_L_Q 0xfff0007f +#define MATCH_FCVT_LU_Q 0xc6300053 +#define MASK_FCVT_LU_Q 0xfff0007f +#define MATCH_FMV_X_Q 0xe6000053 +#define MASK_FMV_X_Q 0xfff0707f +#define MATCH_FCLASS_Q 0xe6001053 +#define MASK_FCLASS_Q 0xfff0707f +#define MATCH_FCVT_S_W 0xd0000053 +#define MASK_FCVT_S_W 0xfff0007f +#define MATCH_FCVT_S_WU 0xd0100053 +#define MASK_FCVT_S_WU 0xfff0007f +#define MATCH_FCVT_S_L 0xd0200053 +#define MASK_FCVT_S_L 0xfff0007f +#define MATCH_FCVT_S_LU 0xd0300053 +#define MASK_FCVT_S_LU 0xfff0007f +#define MATCH_FMV_W_X 0xf0000053 +#define MASK_FMV_W_X 0xfff0707f +#define MATCH_FCVT_D_W 0xd2000053 +#define MASK_FCVT_D_W 0xfff0007f +#define MATCH_FCVT_D_WU 0xd2100053 +#define MASK_FCVT_D_WU 0xfff0007f +#define MATCH_FCVT_D_L 0xd2200053 +#define MASK_FCVT_D_L 0xfff0007f +#define MATCH_FCVT_D_LU 0xd2300053 +#define MASK_FCVT_D_LU 0xfff0007f +#define MATCH_FMV_D_X 0xf2000053 +#define MASK_FMV_D_X 0xfff0707f +#define MATCH_FCVT_Q_W 0xd6000053 +#define MASK_FCVT_Q_W 0xfff0007f +#define MATCH_FCVT_Q_WU 0xd6100053 +#define MASK_FCVT_Q_WU 0xfff0007f +#define MATCH_FCVT_Q_L 0xd6200053 +#define MASK_FCVT_Q_L 0xfff0007f +#define MATCH_FCVT_Q_LU 0xd6300053 +#define MASK_FCVT_Q_LU 0xfff0007f +#define MATCH_FMV_Q_X 0xf6000053 +#define MASK_FMV_Q_X 0xfff0707f +#define MATCH_FLW 0x2007 +#define MASK_FLW 0x707f +#define MATCH_FLD 0x3007 +#define MASK_FLD 0x707f +#define MATCH_FLQ 0x4007 +#define MASK_FLQ 0x707f +#define MATCH_FSW 0x2027 +#define MASK_FSW 0x707f +#define MATCH_FSD 0x3027 +#define MASK_FSD 0x707f +#define MATCH_FSQ 0x4027 +#define MASK_FSQ 0x707f +#define MATCH_FMADD_S 0x43 +#define MASK_FMADD_S 0x600007f +#define MATCH_FMSUB_S 0x47 +#define MASK_FMSUB_S 0x600007f +#define MATCH_FNMSUB_S 0x4b +#define MASK_FNMSUB_S 0x600007f +#define MATCH_FNMADD_S 0x4f +#define MASK_FNMADD_S 0x600007f +#define MATCH_FMADD_D 0x2000043 +#define MASK_FMADD_D 0x600007f +#define MATCH_FMSUB_D 0x2000047 +#define MASK_FMSUB_D 0x600007f +#define MATCH_FNMSUB_D 0x200004b +#define MASK_FNMSUB_D 0x600007f +#define MATCH_FNMADD_D 0x200004f +#define MASK_FNMADD_D 0x600007f +#define MATCH_FMADD_Q 0x6000043 +#define MASK_FMADD_Q 0x600007f +#define MATCH_FMSUB_Q 0x6000047 +#define MASK_FMSUB_Q 0x600007f +#define MATCH_FNMSUB_Q 0x600004b +#define MASK_FNMSUB_Q 0x600007f +#define MATCH_FNMADD_Q 0x600004f +#define MASK_FNMADD_Q 0x600007f +#define MATCH_C_NOP 0x1 +#define MASK_C_NOP 0xffff +#define MATCH_C_ADDI16SP 0x6101 +#define MASK_C_ADDI16SP 0xef83 +#define MATCH_C_JR 0x8002 +#define MASK_C_JR 0xf07f +#define MATCH_C_JALR 0x9002 +#define MASK_C_JALR 0xf07f +#define MATCH_C_EBREAK 0x9002 +#define MASK_C_EBREAK 0xffff +#define MATCH_C_LD 0x6000 +#define MASK_C_LD 0xe003 +#define MATCH_C_SD 0xe000 +#define MASK_C_SD 0xe003 +#define MATCH_C_ADDIW 0x2001 +#define MASK_C_ADDIW 0xe003 +#define MATCH_C_LDSP 0x6002 +#define MASK_C_LDSP 0xe003 +#define MATCH_C_SDSP 0xe002 +#define MASK_C_SDSP 0xe003 +#define MATCH_C_ADDI4SPN 0x0 +#define MASK_C_ADDI4SPN 0xe003 +#define MATCH_C_FLD 0x2000 +#define MASK_C_FLD 0xe003 +#define MATCH_C_LW 0x4000 +#define MASK_C_LW 0xe003 +#define MATCH_C_FLW 0x6000 +#define MASK_C_FLW 0xe003 +#define MATCH_C_FSD 0xa000 +#define MASK_C_FSD 0xe003 +#define MATCH_C_SW 0xc000 +#define MASK_C_SW 0xe003 +#define MATCH_C_FSW 0xe000 +#define MASK_C_FSW 0xe003 +#define MATCH_C_ADDI 0x1 +#define MASK_C_ADDI 0xe003 +#define MATCH_C_JAL 0x2001 +#define MASK_C_JAL 0xe003 +#define MATCH_C_LI 0x4001 +#define MASK_C_LI 0xe003 +#define MATCH_C_LUI 0x6001 +#define MASK_C_LUI 0xe003 +#define MATCH_C_SRLI 0x8001 +#define MASK_C_SRLI 0xec03 +#define MATCH_C_SRAI 0x8401 +#define MASK_C_SRAI 0xec03 +#define MATCH_C_ANDI 0x8801 +#define MASK_C_ANDI 0xec03 +#define MATCH_C_SUB 0x8c01 +#define MASK_C_SUB 0xfc63 +#define MATCH_C_XOR 0x8c21 +#define MASK_C_XOR 0xfc63 +#define MATCH_C_OR 0x8c41 +#define MASK_C_OR 0xfc63 +#define MATCH_C_AND 0x8c61 +#define MASK_C_AND 0xfc63 +#define MATCH_C_SUBW 0x9c01 +#define MASK_C_SUBW 0xfc63 +#define MATCH_C_ADDW 0x9c21 +#define MASK_C_ADDW 0xfc63 +#define MATCH_C_J 0xa001 +#define MASK_C_J 0xe003 +#define MATCH_C_BEQZ 0xc001 +#define MASK_C_BEQZ 0xe003 +#define MATCH_C_BNEZ 0xe001 +#define MASK_C_BNEZ 0xe003 +#define MATCH_C_SLLI 0x2 +#define MASK_C_SLLI 0xe003 +#define MATCH_C_FLDSP 0x2002 +#define MASK_C_FLDSP 0xe003 +#define MATCH_C_LWSP 0x4002 +#define MASK_C_LWSP 0xe003 +#define MATCH_C_FLWSP 0x6002 +#define MASK_C_FLWSP 0xe003 +#define MATCH_C_MV 0x8002 +#define MASK_C_MV 0xf003 +#define MATCH_C_ADD 0x9002 +#define MASK_C_ADD 0xf003 +#define MATCH_C_FSDSP 0xa002 +#define MASK_C_FSDSP 0xe003 +#define MATCH_C_SWSP 0xc002 +#define MASK_C_SWSP 0xe003 +#define MATCH_C_FSWSP 0xe002 +#define MASK_C_FSWSP 0xe003 +#define MATCH_CUSTOM0 0xb +#define MASK_CUSTOM0 0x707f +#define MATCH_CUSTOM0_RS1 0x200b +#define MASK_CUSTOM0_RS1 0x707f +#define MATCH_CUSTOM0_RS1_RS2 0x300b +#define MASK_CUSTOM0_RS1_RS2 0x707f +#define MATCH_CUSTOM0_RD 0x400b +#define MASK_CUSTOM0_RD 0x707f +#define MATCH_CUSTOM0_RD_RS1 0x600b +#define MASK_CUSTOM0_RD_RS1 0x707f +#define MATCH_CUSTOM0_RD_RS1_RS2 0x700b +#define MASK_CUSTOM0_RD_RS1_RS2 0x707f +#define MATCH_CUSTOM1 0x2b +#define MASK_CUSTOM1 0x707f +#define MATCH_CUSTOM1_RS1 0x202b +#define MASK_CUSTOM1_RS1 0x707f +#define MATCH_CUSTOM1_RS1_RS2 0x302b +#define MASK_CUSTOM1_RS1_RS2 0x707f +#define MATCH_CUSTOM1_RD 0x402b +#define MASK_CUSTOM1_RD 0x707f +#define MATCH_CUSTOM1_RD_RS1 0x602b +#define MASK_CUSTOM1_RD_RS1 0x707f +#define MATCH_CUSTOM1_RD_RS1_RS2 0x702b +#define MASK_CUSTOM1_RD_RS1_RS2 0x707f +#define MATCH_CUSTOM2 0x5b +#define MASK_CUSTOM2 0x707f +#define MATCH_CUSTOM2_RS1 0x205b +#define MASK_CUSTOM2_RS1 0x707f +#define MATCH_CUSTOM2_RS1_RS2 0x305b +#define MASK_CUSTOM2_RS1_RS2 0x707f +#define MATCH_CUSTOM2_RD 0x405b +#define MASK_CUSTOM2_RD 0x707f +#define MATCH_CUSTOM2_RD_RS1 0x605b +#define MASK_CUSTOM2_RD_RS1 0x707f +#define MATCH_CUSTOM2_RD_RS1_RS2 0x705b +#define MASK_CUSTOM2_RD_RS1_RS2 0x707f +#define MATCH_CUSTOM3 0x7b +#define MASK_CUSTOM3 0x707f +#define MATCH_CUSTOM3_RS1 0x207b +#define MASK_CUSTOM3_RS1 0x707f +#define MATCH_CUSTOM3_RS1_RS2 0x307b +#define MASK_CUSTOM3_RS1_RS2 0x707f +#define MATCH_CUSTOM3_RD 0x407b +#define MASK_CUSTOM3_RD 0x707f +#define MATCH_CUSTOM3_RD_RS1 0x607b +#define MASK_CUSTOM3_RD_RS1 0x707f +#define MATCH_CUSTOM3_RD_RS1_RS2 0x707b +#define MASK_CUSTOM3_RD_RS1_RS2 0x707f +#define CSR_FFLAGS 0x1 +#define CSR_FRM 0x2 +#define CSR_FCSR 0x3 +#define CSR_CYCLE 0xc00 +#define CSR_TIME 0xc01 +#define CSR_INSTRET 0xc02 +#define CSR_HPMCOUNTER3 0xc03 +#define CSR_HPMCOUNTER4 0xc04 +#define CSR_HPMCOUNTER5 0xc05 +#define CSR_HPMCOUNTER6 0xc06 +#define CSR_HPMCOUNTER7 0xc07 +#define CSR_HPMCOUNTER8 0xc08 +#define CSR_HPMCOUNTER9 0xc09 +#define CSR_HPMCOUNTER10 0xc0a +#define CSR_HPMCOUNTER11 0xc0b +#define CSR_HPMCOUNTER12 0xc0c +#define CSR_HPMCOUNTER13 0xc0d +#define CSR_HPMCOUNTER14 0xc0e +#define CSR_HPMCOUNTER15 0xc0f +#define CSR_HPMCOUNTER16 0xc10 +#define CSR_HPMCOUNTER17 0xc11 +#define CSR_HPMCOUNTER18 0xc12 +#define CSR_HPMCOUNTER19 0xc13 +#define CSR_HPMCOUNTER20 0xc14 +#define CSR_HPMCOUNTER21 0xc15 +#define CSR_HPMCOUNTER22 0xc16 +#define CSR_HPMCOUNTER23 0xc17 +#define CSR_HPMCOUNTER24 0xc18 +#define CSR_HPMCOUNTER25 0xc19 +#define CSR_HPMCOUNTER26 0xc1a +#define CSR_HPMCOUNTER27 0xc1b +#define CSR_HPMCOUNTER28 0xc1c +#define CSR_HPMCOUNTER29 0xc1d +#define CSR_HPMCOUNTER30 0xc1e +#define CSR_HPMCOUNTER31 0xc1f +#define CSR_SSTATUS 0x100 +#define CSR_SIE 0x104 +#define CSR_STVEC 0x105 +#define CSR_SCOUNTEREN 0x106 +#define CSR_SSCRATCH 0x140 +#define CSR_SEPC 0x141 +#define CSR_SCAUSE 0x142 +#define CSR_STVAL 0x143 +#define CSR_SIP 0x144 +#define CSR_SATP 0x180 +#define CSR_MSTATUS 0x300 +#define CSR_MISA 0x301 +#define CSR_MEDELEG 0x302 +#define CSR_MIDELEG 0x303 +#define CSR_MIE 0x304 +#define CSR_MTVEC 0x305 +#define CSR_MCOUNTEREN 0x306 +#define CSR_MSCRATCH 0x340 +#define CSR_MEPC 0x341 +#define CSR_MCAUSE 0x342 +#define CSR_MTVAL 0x343 +#define CSR_MIP 0x344 +#define CSR_PMPCFG0 0x3a0 +#define CSR_PMPCFG1 0x3a1 +#define CSR_PMPCFG2 0x3a2 +#define CSR_PMPCFG3 0x3a3 +#define CSR_PMPADDR0 0x3b0 +#define CSR_PMPADDR1 0x3b1 +#define CSR_PMPADDR2 0x3b2 +#define CSR_PMPADDR3 0x3b3 +#define CSR_PMPADDR4 0x3b4 +#define CSR_PMPADDR5 0x3b5 +#define CSR_PMPADDR6 0x3b6 +#define CSR_PMPADDR7 0x3b7 +#define CSR_PMPADDR8 0x3b8 +#define CSR_PMPADDR9 0x3b9 +#define CSR_PMPADDR10 0x3ba +#define CSR_PMPADDR11 0x3bb +#define CSR_PMPADDR12 0x3bc +#define CSR_PMPADDR13 0x3bd +#define CSR_PMPADDR14 0x3be +#define CSR_PMPADDR15 0x3bf +#define CSR_TSELECT 0x7a0 +#define CSR_TDATA1 0x7a1 +#define CSR_TDATA2 0x7a2 +#define CSR_TDATA3 0x7a3 +#define CSR_DCSR 0x7b0 +#define CSR_DPC 0x7b1 +#define CSR_DSCRATCH 0x7b2 +#define CSR_MCYCLE 0xb00 +#define CSR_MINSTRET 0xb02 +#define CSR_MHPMCOUNTER3 0xb03 +#define CSR_MHPMCOUNTER4 0xb04 +#define CSR_MHPMCOUNTER5 0xb05 +#define CSR_MHPMCOUNTER6 0xb06 +#define CSR_MHPMCOUNTER7 0xb07 +#define CSR_MHPMCOUNTER8 0xb08 +#define CSR_MHPMCOUNTER9 0xb09 +#define CSR_MHPMCOUNTER10 0xb0a +#define CSR_MHPMCOUNTER11 0xb0b +#define CSR_MHPMCOUNTER12 0xb0c +#define CSR_MHPMCOUNTER13 0xb0d +#define CSR_MHPMCOUNTER14 0xb0e +#define CSR_MHPMCOUNTER15 0xb0f +#define CSR_MHPMCOUNTER16 0xb10 +#define CSR_MHPMCOUNTER17 0xb11 +#define CSR_MHPMCOUNTER18 0xb12 +#define CSR_MHPMCOUNTER19 0xb13 +#define CSR_MHPMCOUNTER20 0xb14 +#define CSR_MHPMCOUNTER21 0xb15 +#define CSR_MHPMCOUNTER22 0xb16 +#define CSR_MHPMCOUNTER23 0xb17 +#define CSR_MHPMCOUNTER24 0xb18 +#define CSR_MHPMCOUNTER25 0xb19 +#define CSR_MHPMCOUNTER26 0xb1a +#define CSR_MHPMCOUNTER27 0xb1b +#define CSR_MHPMCOUNTER28 0xb1c +#define CSR_MHPMCOUNTER29 0xb1d +#define CSR_MHPMCOUNTER30 0xb1e +#define CSR_MHPMCOUNTER31 0xb1f +#define CSR_MHPMEVENT3 0x323 +#define CSR_MHPMEVENT4 0x324 +#define CSR_MHPMEVENT5 0x325 +#define CSR_MHPMEVENT6 0x326 +#define CSR_MHPMEVENT7 0x327 +#define CSR_MHPMEVENT8 0x328 +#define CSR_MHPMEVENT9 0x329 +#define CSR_MHPMEVENT10 0x32a +#define CSR_MHPMEVENT11 0x32b +#define CSR_MHPMEVENT12 0x32c +#define CSR_MHPMEVENT13 0x32d +#define CSR_MHPMEVENT14 0x32e +#define CSR_MHPMEVENT15 0x32f +#define CSR_MHPMEVENT16 0x330 +#define CSR_MHPMEVENT17 0x331 +#define CSR_MHPMEVENT18 0x332 +#define CSR_MHPMEVENT19 0x333 +#define CSR_MHPMEVENT20 0x334 +#define CSR_MHPMEVENT21 0x335 +#define CSR_MHPMEVENT22 0x336 +#define CSR_MHPMEVENT23 0x337 +#define CSR_MHPMEVENT24 0x338 +#define CSR_MHPMEVENT25 0x339 +#define CSR_MHPMEVENT26 0x33a +#define CSR_MHPMEVENT27 0x33b +#define CSR_MHPMEVENT28 0x33c +#define CSR_MHPMEVENT29 0x33d +#define CSR_MHPMEVENT30 0x33e +#define CSR_MHPMEVENT31 0x33f +#define CSR_MVENDORID 0xf11 +#define CSR_MARCHID 0xf12 +#define CSR_MIMPID 0xf13 +#define CSR_MHARTID 0xf14 +#define CSR_CYCLEH 0xc80 +#define CSR_TIMEH 0xc81 +#define CSR_INSTRETH 0xc82 +#define CSR_HPMCOUNTER3H 0xc83 +#define CSR_HPMCOUNTER4H 0xc84 +#define CSR_HPMCOUNTER5H 0xc85 +#define CSR_HPMCOUNTER6H 0xc86 +#define CSR_HPMCOUNTER7H 0xc87 +#define CSR_HPMCOUNTER8H 0xc88 +#define CSR_HPMCOUNTER9H 0xc89 +#define CSR_HPMCOUNTER10H 0xc8a +#define CSR_HPMCOUNTER11H 0xc8b +#define CSR_HPMCOUNTER12H 0xc8c +#define CSR_HPMCOUNTER13H 0xc8d +#define CSR_HPMCOUNTER14H 0xc8e +#define CSR_HPMCOUNTER15H 0xc8f +#define CSR_HPMCOUNTER16H 0xc90 +#define CSR_HPMCOUNTER17H 0xc91 +#define CSR_HPMCOUNTER18H 0xc92 +#define CSR_HPMCOUNTER19H 0xc93 +#define CSR_HPMCOUNTER20H 0xc94 +#define CSR_HPMCOUNTER21H 0xc95 +#define CSR_HPMCOUNTER22H 0xc96 +#define CSR_HPMCOUNTER23H 0xc97 +#define CSR_HPMCOUNTER24H 0xc98 +#define CSR_HPMCOUNTER25H 0xc99 +#define CSR_HPMCOUNTER26H 0xc9a +#define CSR_HPMCOUNTER27H 0xc9b +#define CSR_HPMCOUNTER28H 0xc9c +#define CSR_HPMCOUNTER29H 0xc9d +#define CSR_HPMCOUNTER30H 0xc9e +#define CSR_HPMCOUNTER31H 0xc9f +#define CSR_MCYCLEH 0xb80 +#define CSR_MINSTRETH 0xb82 +#define CSR_MHPMCOUNTER3H 0xb83 +#define CSR_MHPMCOUNTER4H 0xb84 +#define CSR_MHPMCOUNTER5H 0xb85 +#define CSR_MHPMCOUNTER6H 0xb86 +#define CSR_MHPMCOUNTER7H 0xb87 +#define CSR_MHPMCOUNTER8H 0xb88 +#define CSR_MHPMCOUNTER9H 0xb89 +#define CSR_MHPMCOUNTER10H 0xb8a +#define CSR_MHPMCOUNTER11H 0xb8b +#define CSR_MHPMCOUNTER12H 0xb8c +#define CSR_MHPMCOUNTER13H 0xb8d +#define CSR_MHPMCOUNTER14H 0xb8e +#define CSR_MHPMCOUNTER15H 0xb8f +#define CSR_MHPMCOUNTER16H 0xb90 +#define CSR_MHPMCOUNTER17H 0xb91 +#define CSR_MHPMCOUNTER18H 0xb92 +#define CSR_MHPMCOUNTER19H 0xb93 +#define CSR_MHPMCOUNTER20H 0xb94 +#define CSR_MHPMCOUNTER21H 0xb95 +#define CSR_MHPMCOUNTER22H 0xb96 +#define CSR_MHPMCOUNTER23H 0xb97 +#define CSR_MHPMCOUNTER24H 0xb98 +#define CSR_MHPMCOUNTER25H 0xb99 +#define CSR_MHPMCOUNTER26H 0xb9a +#define CSR_MHPMCOUNTER27H 0xb9b +#define CSR_MHPMCOUNTER28H 0xb9c +#define CSR_MHPMCOUNTER29H 0xb9d +#define CSR_MHPMCOUNTER30H 0xb9e +#define CSR_MHPMCOUNTER31H 0xb9f +#define CAUSE_MISALIGNED_FETCH 0x0 +#define CAUSE_FETCH_ACCESS 0x1 +#define CAUSE_ILLEGAL_INSTRUCTION 0x2 +#define CAUSE_BREAKPOINT 0x3 +#define CAUSE_MISALIGNED_LOAD 0x4 +#define CAUSE_LOAD_ACCESS 0x5 +#define CAUSE_MISALIGNED_STORE 0x6 +#define CAUSE_STORE_ACCESS 0x7 +#define CAUSE_USER_ECALL 0x8 +#define CAUSE_SUPERVISOR_ECALL 0x9 +#define CAUSE_HYPERVISOR_ECALL 0xa +#define CAUSE_MACHINE_ECALL 0xb +#define CAUSE_FETCH_PAGE_FAULT 0xc +#define CAUSE_LOAD_PAGE_FAULT 0xd +#define CAUSE_STORE_PAGE_FAULT 0xf +#endif +#ifdef DECLARE_INSN +DECLARE_INSN(beq, MATCH_BEQ, MASK_BEQ) +DECLARE_INSN(bne, MATCH_BNE, MASK_BNE) +DECLARE_INSN(blt, MATCH_BLT, MASK_BLT) +DECLARE_INSN(bge, MATCH_BGE, MASK_BGE) +DECLARE_INSN(bltu, MATCH_BLTU, MASK_BLTU) +DECLARE_INSN(bgeu, MATCH_BGEU, MASK_BGEU) +DECLARE_INSN(jalr, MATCH_JALR, MASK_JALR) +DECLARE_INSN(jal, MATCH_JAL, MASK_JAL) +DECLARE_INSN(lui, MATCH_LUI, MASK_LUI) +DECLARE_INSN(auipc, MATCH_AUIPC, MASK_AUIPC) +DECLARE_INSN(addi, MATCH_ADDI, MASK_ADDI) +DECLARE_INSN(slli, MATCH_SLLI, MASK_SLLI) +DECLARE_INSN(slti, MATCH_SLTI, MASK_SLTI) +DECLARE_INSN(sltiu, MATCH_SLTIU, MASK_SLTIU) +DECLARE_INSN(xori, MATCH_XORI, MASK_XORI) +DECLARE_INSN(srli, MATCH_SRLI, MASK_SRLI) +DECLARE_INSN(srai, MATCH_SRAI, MASK_SRAI) +DECLARE_INSN(ori, MATCH_ORI, MASK_ORI) +DECLARE_INSN(andi, MATCH_ANDI, MASK_ANDI) +DECLARE_INSN(add, MATCH_ADD, MASK_ADD) +DECLARE_INSN(sub, MATCH_SUB, MASK_SUB) +DECLARE_INSN(sll, MATCH_SLL, MASK_SLL) +DECLARE_INSN(slt, MATCH_SLT, MASK_SLT) +DECLARE_INSN(sltu, MATCH_SLTU, MASK_SLTU) +DECLARE_INSN(xor, MATCH_XOR, MASK_XOR) +DECLARE_INSN(srl, MATCH_SRL, MASK_SRL) +DECLARE_INSN(sra, MATCH_SRA, MASK_SRA) +DECLARE_INSN(or, MATCH_OR, MASK_OR) +DECLARE_INSN(and, MATCH_AND, MASK_AND) +DECLARE_INSN(addiw, MATCH_ADDIW, MASK_ADDIW) +DECLARE_INSN(slliw, MATCH_SLLIW, MASK_SLLIW) +DECLARE_INSN(srliw, MATCH_SRLIW, MASK_SRLIW) +DECLARE_INSN(sraiw, MATCH_SRAIW, MASK_SRAIW) +DECLARE_INSN(addw, MATCH_ADDW, MASK_ADDW) +DECLARE_INSN(subw, MATCH_SUBW, MASK_SUBW) +DECLARE_INSN(sllw, MATCH_SLLW, MASK_SLLW) +DECLARE_INSN(srlw, MATCH_SRLW, MASK_SRLW) +DECLARE_INSN(sraw, MATCH_SRAW, MASK_SRAW) +DECLARE_INSN(lb, MATCH_LB, MASK_LB) +DECLARE_INSN(lh, MATCH_LH, MASK_LH) +DECLARE_INSN(lw, MATCH_LW, MASK_LW) +DECLARE_INSN(ld, MATCH_LD, MASK_LD) +DECLARE_INSN(lbu, MATCH_LBU, MASK_LBU) +DECLARE_INSN(lhu, MATCH_LHU, MASK_LHU) +DECLARE_INSN(lwu, MATCH_LWU, MASK_LWU) +DECLARE_INSN(sb, MATCH_SB, MASK_SB) +DECLARE_INSN(sh, MATCH_SH, MASK_SH) +DECLARE_INSN(sw, MATCH_SW, MASK_SW) +DECLARE_INSN(sd, MATCH_SD, MASK_SD) +DECLARE_INSN(fence, MATCH_FENCE, MASK_FENCE) +DECLARE_INSN(fence_i, MATCH_FENCE_I, MASK_FENCE_I) +DECLARE_INSN(mul, MATCH_MUL, MASK_MUL) +DECLARE_INSN(mulh, MATCH_MULH, MASK_MULH) +DECLARE_INSN(mulhsu, MATCH_MULHSU, MASK_MULHSU) +DECLARE_INSN(mulhu, MATCH_MULHU, MASK_MULHU) +DECLARE_INSN(div, MATCH_DIV, MASK_DIV) +DECLARE_INSN(divu, MATCH_DIVU, MASK_DIVU) +DECLARE_INSN(rem, MATCH_REM, MASK_REM) +DECLARE_INSN(remu, MATCH_REMU, MASK_REMU) +DECLARE_INSN(mulw, MATCH_MULW, MASK_MULW) +DECLARE_INSN(divw, MATCH_DIVW, MASK_DIVW) +DECLARE_INSN(divuw, MATCH_DIVUW, MASK_DIVUW) +DECLARE_INSN(remw, MATCH_REMW, MASK_REMW) +DECLARE_INSN(remuw, MATCH_REMUW, MASK_REMUW) +DECLARE_INSN(amoadd_w, MATCH_AMOADD_W, MASK_AMOADD_W) +DECLARE_INSN(amoxor_w, MATCH_AMOXOR_W, MASK_AMOXOR_W) +DECLARE_INSN(amoor_w, MATCH_AMOOR_W, MASK_AMOOR_W) +DECLARE_INSN(amoand_w, MATCH_AMOAND_W, MASK_AMOAND_W) +DECLARE_INSN(amomin_w, MATCH_AMOMIN_W, MASK_AMOMIN_W) +DECLARE_INSN(amomax_w, MATCH_AMOMAX_W, MASK_AMOMAX_W) +DECLARE_INSN(amominu_w, MATCH_AMOMINU_W, MASK_AMOMINU_W) +DECLARE_INSN(amomaxu_w, MATCH_AMOMAXU_W, MASK_AMOMAXU_W) +DECLARE_INSN(amoswap_w, MATCH_AMOSWAP_W, MASK_AMOSWAP_W) +DECLARE_INSN(lr_w, MATCH_LR_W, MASK_LR_W) +DECLARE_INSN(sc_w, MATCH_SC_W, MASK_SC_W) +DECLARE_INSN(amoadd_d, MATCH_AMOADD_D, MASK_AMOADD_D) +DECLARE_INSN(amoxor_d, MATCH_AMOXOR_D, MASK_AMOXOR_D) +DECLARE_INSN(amoor_d, MATCH_AMOOR_D, MASK_AMOOR_D) +DECLARE_INSN(amoand_d, MATCH_AMOAND_D, MASK_AMOAND_D) +DECLARE_INSN(amomin_d, MATCH_AMOMIN_D, MASK_AMOMIN_D) +DECLARE_INSN(amomax_d, MATCH_AMOMAX_D, MASK_AMOMAX_D) +DECLARE_INSN(amominu_d, MATCH_AMOMINU_D, MASK_AMOMINU_D) +DECLARE_INSN(amomaxu_d, MATCH_AMOMAXU_D, MASK_AMOMAXU_D) +DECLARE_INSN(amoswap_d, MATCH_AMOSWAP_D, MASK_AMOSWAP_D) +DECLARE_INSN(lr_d, MATCH_LR_D, MASK_LR_D) +DECLARE_INSN(sc_d, MATCH_SC_D, MASK_SC_D) +DECLARE_INSN(ecall, MATCH_ECALL, MASK_ECALL) +DECLARE_INSN(ebreak, MATCH_EBREAK, MASK_EBREAK) +DECLARE_INSN(uret, MATCH_URET, MASK_URET) +DECLARE_INSN(sret, MATCH_SRET, MASK_SRET) +DECLARE_INSN(mret, MATCH_MRET, MASK_MRET) +DECLARE_INSN(dret, MATCH_DRET, MASK_DRET) +DECLARE_INSN(sfence_vma, MATCH_SFENCE_VMA, MASK_SFENCE_VMA) +DECLARE_INSN(wfi, MATCH_WFI, MASK_WFI) +DECLARE_INSN(csrrw, MATCH_CSRRW, MASK_CSRRW) +DECLARE_INSN(csrrs, MATCH_CSRRS, MASK_CSRRS) +DECLARE_INSN(csrrc, MATCH_CSRRC, MASK_CSRRC) +DECLARE_INSN(csrrwi, MATCH_CSRRWI, MASK_CSRRWI) +DECLARE_INSN(csrrsi, MATCH_CSRRSI, MASK_CSRRSI) +DECLARE_INSN(csrrci, MATCH_CSRRCI, MASK_CSRRCI) +DECLARE_INSN(fadd_s, MATCH_FADD_S, MASK_FADD_S) +DECLARE_INSN(fsub_s, MATCH_FSUB_S, MASK_FSUB_S) +DECLARE_INSN(fmul_s, MATCH_FMUL_S, MASK_FMUL_S) +DECLARE_INSN(fdiv_s, MATCH_FDIV_S, MASK_FDIV_S) +DECLARE_INSN(fsgnj_s, MATCH_FSGNJ_S, MASK_FSGNJ_S) +DECLARE_INSN(fsgnjn_s, MATCH_FSGNJN_S, MASK_FSGNJN_S) +DECLARE_INSN(fsgnjx_s, MATCH_FSGNJX_S, MASK_FSGNJX_S) +DECLARE_INSN(fmin_s, MATCH_FMIN_S, MASK_FMIN_S) +DECLARE_INSN(fmax_s, MATCH_FMAX_S, MASK_FMAX_S) +DECLARE_INSN(fsqrt_s, MATCH_FSQRT_S, MASK_FSQRT_S) +DECLARE_INSN(fadd_d, MATCH_FADD_D, MASK_FADD_D) +DECLARE_INSN(fsub_d, MATCH_FSUB_D, MASK_FSUB_D) +DECLARE_INSN(fmul_d, MATCH_FMUL_D, MASK_FMUL_D) +DECLARE_INSN(fdiv_d, MATCH_FDIV_D, MASK_FDIV_D) +DECLARE_INSN(fsgnj_d, MATCH_FSGNJ_D, MASK_FSGNJ_D) +DECLARE_INSN(fsgnjn_d, MATCH_FSGNJN_D, MASK_FSGNJN_D) +DECLARE_INSN(fsgnjx_d, MATCH_FSGNJX_D, MASK_FSGNJX_D) +DECLARE_INSN(fmin_d, MATCH_FMIN_D, MASK_FMIN_D) +DECLARE_INSN(fmax_d, MATCH_FMAX_D, MASK_FMAX_D) +DECLARE_INSN(fcvt_s_d, MATCH_FCVT_S_D, MASK_FCVT_S_D) +DECLARE_INSN(fcvt_d_s, MATCH_FCVT_D_S, MASK_FCVT_D_S) +DECLARE_INSN(fsqrt_d, MATCH_FSQRT_D, MASK_FSQRT_D) +DECLARE_INSN(fadd_q, MATCH_FADD_Q, MASK_FADD_Q) +DECLARE_INSN(fsub_q, MATCH_FSUB_Q, MASK_FSUB_Q) +DECLARE_INSN(fmul_q, MATCH_FMUL_Q, MASK_FMUL_Q) +DECLARE_INSN(fdiv_q, MATCH_FDIV_Q, MASK_FDIV_Q) +DECLARE_INSN(fsgnj_q, MATCH_FSGNJ_Q, MASK_FSGNJ_Q) +DECLARE_INSN(fsgnjn_q, MATCH_FSGNJN_Q, MASK_FSGNJN_Q) +DECLARE_INSN(fsgnjx_q, MATCH_FSGNJX_Q, MASK_FSGNJX_Q) +DECLARE_INSN(fmin_q, MATCH_FMIN_Q, MASK_FMIN_Q) +DECLARE_INSN(fmax_q, MATCH_FMAX_Q, MASK_FMAX_Q) +DECLARE_INSN(fcvt_s_q, MATCH_FCVT_S_Q, MASK_FCVT_S_Q) +DECLARE_INSN(fcvt_q_s, MATCH_FCVT_Q_S, MASK_FCVT_Q_S) +DECLARE_INSN(fcvt_d_q, MATCH_FCVT_D_Q, MASK_FCVT_D_Q) +DECLARE_INSN(fcvt_q_d, MATCH_FCVT_Q_D, MASK_FCVT_Q_D) +DECLARE_INSN(fsqrt_q, MATCH_FSQRT_Q, MASK_FSQRT_Q) +DECLARE_INSN(fle_s, MATCH_FLE_S, MASK_FLE_S) +DECLARE_INSN(flt_s, MATCH_FLT_S, MASK_FLT_S) +DECLARE_INSN(feq_s, MATCH_FEQ_S, MASK_FEQ_S) +DECLARE_INSN(fle_d, MATCH_FLE_D, MASK_FLE_D) +DECLARE_INSN(flt_d, MATCH_FLT_D, MASK_FLT_D) +DECLARE_INSN(feq_d, MATCH_FEQ_D, MASK_FEQ_D) +DECLARE_INSN(fle_q, MATCH_FLE_Q, MASK_FLE_Q) +DECLARE_INSN(flt_q, MATCH_FLT_Q, MASK_FLT_Q) +DECLARE_INSN(feq_q, MATCH_FEQ_Q, MASK_FEQ_Q) +DECLARE_INSN(fcvt_w_s, MATCH_FCVT_W_S, MASK_FCVT_W_S) +DECLARE_INSN(fcvt_wu_s, MATCH_FCVT_WU_S, MASK_FCVT_WU_S) +DECLARE_INSN(fcvt_l_s, MATCH_FCVT_L_S, MASK_FCVT_L_S) +DECLARE_INSN(fcvt_lu_s, MATCH_FCVT_LU_S, MASK_FCVT_LU_S) +DECLARE_INSN(fmv_x_w, MATCH_FMV_X_W, MASK_FMV_X_W) +DECLARE_INSN(fclass_s, MATCH_FCLASS_S, MASK_FCLASS_S) +DECLARE_INSN(fcvt_w_d, MATCH_FCVT_W_D, MASK_FCVT_W_D) +DECLARE_INSN(fcvt_wu_d, MATCH_FCVT_WU_D, MASK_FCVT_WU_D) +DECLARE_INSN(fcvt_l_d, MATCH_FCVT_L_D, MASK_FCVT_L_D) +DECLARE_INSN(fcvt_lu_d, MATCH_FCVT_LU_D, MASK_FCVT_LU_D) +DECLARE_INSN(fmv_x_d, MATCH_FMV_X_D, MASK_FMV_X_D) +DECLARE_INSN(fclass_d, MATCH_FCLASS_D, MASK_FCLASS_D) +DECLARE_INSN(fcvt_w_q, MATCH_FCVT_W_Q, MASK_FCVT_W_Q) +DECLARE_INSN(fcvt_wu_q, MATCH_FCVT_WU_Q, MASK_FCVT_WU_Q) +DECLARE_INSN(fcvt_l_q, MATCH_FCVT_L_Q, MASK_FCVT_L_Q) +DECLARE_INSN(fcvt_lu_q, MATCH_FCVT_LU_Q, MASK_FCVT_LU_Q) +DECLARE_INSN(fmv_x_q, MATCH_FMV_X_Q, MASK_FMV_X_Q) +DECLARE_INSN(fclass_q, MATCH_FCLASS_Q, MASK_FCLASS_Q) +DECLARE_INSN(fcvt_s_w, MATCH_FCVT_S_W, MASK_FCVT_S_W) +DECLARE_INSN(fcvt_s_wu, MATCH_FCVT_S_WU, MASK_FCVT_S_WU) +DECLARE_INSN(fcvt_s_l, MATCH_FCVT_S_L, MASK_FCVT_S_L) +DECLARE_INSN(fcvt_s_lu, MATCH_FCVT_S_LU, MASK_FCVT_S_LU) +DECLARE_INSN(fmv_w_x, MATCH_FMV_W_X, MASK_FMV_W_X) +DECLARE_INSN(fcvt_d_w, MATCH_FCVT_D_W, MASK_FCVT_D_W) +DECLARE_INSN(fcvt_d_wu, MATCH_FCVT_D_WU, MASK_FCVT_D_WU) +DECLARE_INSN(fcvt_d_l, MATCH_FCVT_D_L, MASK_FCVT_D_L) +DECLARE_INSN(fcvt_d_lu, MATCH_FCVT_D_LU, MASK_FCVT_D_LU) +DECLARE_INSN(fmv_d_x, MATCH_FMV_D_X, MASK_FMV_D_X) +DECLARE_INSN(fcvt_q_w, MATCH_FCVT_Q_W, MASK_FCVT_Q_W) +DECLARE_INSN(fcvt_q_wu, MATCH_FCVT_Q_WU, MASK_FCVT_Q_WU) +DECLARE_INSN(fcvt_q_l, MATCH_FCVT_Q_L, MASK_FCVT_Q_L) +DECLARE_INSN(fcvt_q_lu, MATCH_FCVT_Q_LU, MASK_FCVT_Q_LU) +DECLARE_INSN(fmv_q_x, MATCH_FMV_Q_X, MASK_FMV_Q_X) +DECLARE_INSN(flw, MATCH_FLW, MASK_FLW) +DECLARE_INSN(fld, MATCH_FLD, MASK_FLD) +DECLARE_INSN(flq, MATCH_FLQ, MASK_FLQ) +DECLARE_INSN(fsw, MATCH_FSW, MASK_FSW) +DECLARE_INSN(fsd, MATCH_FSD, MASK_FSD) +DECLARE_INSN(fsq, MATCH_FSQ, MASK_FSQ) +DECLARE_INSN(fmadd_s, MATCH_FMADD_S, MASK_FMADD_S) +DECLARE_INSN(fmsub_s, MATCH_FMSUB_S, MASK_FMSUB_S) +DECLARE_INSN(fnmsub_s, MATCH_FNMSUB_S, MASK_FNMSUB_S) +DECLARE_INSN(fnmadd_s, MATCH_FNMADD_S, MASK_FNMADD_S) +DECLARE_INSN(fmadd_d, MATCH_FMADD_D, MASK_FMADD_D) +DECLARE_INSN(fmsub_d, MATCH_FMSUB_D, MASK_FMSUB_D) +DECLARE_INSN(fnmsub_d, MATCH_FNMSUB_D, MASK_FNMSUB_D) +DECLARE_INSN(fnmadd_d, MATCH_FNMADD_D, MASK_FNMADD_D) +DECLARE_INSN(fmadd_q, MATCH_FMADD_Q, MASK_FMADD_Q) +DECLARE_INSN(fmsub_q, MATCH_FMSUB_Q, MASK_FMSUB_Q) +DECLARE_INSN(fnmsub_q, MATCH_FNMSUB_Q, MASK_FNMSUB_Q) +DECLARE_INSN(fnmadd_q, MATCH_FNMADD_Q, MASK_FNMADD_Q) +DECLARE_INSN(c_nop, MATCH_C_NOP, MASK_C_NOP) +DECLARE_INSN(c_addi16sp, MATCH_C_ADDI16SP, MASK_C_ADDI16SP) +DECLARE_INSN(c_jr, MATCH_C_JR, MASK_C_JR) +DECLARE_INSN(c_jalr, MATCH_C_JALR, MASK_C_JALR) +DECLARE_INSN(c_ebreak, MATCH_C_EBREAK, MASK_C_EBREAK) +DECLARE_INSN(c_ld, MATCH_C_LD, MASK_C_LD) +DECLARE_INSN(c_sd, MATCH_C_SD, MASK_C_SD) +DECLARE_INSN(c_addiw, MATCH_C_ADDIW, MASK_C_ADDIW) +DECLARE_INSN(c_ldsp, MATCH_C_LDSP, MASK_C_LDSP) +DECLARE_INSN(c_sdsp, MATCH_C_SDSP, MASK_C_SDSP) +DECLARE_INSN(c_addi4spn, MATCH_C_ADDI4SPN, MASK_C_ADDI4SPN) +DECLARE_INSN(c_fld, MATCH_C_FLD, MASK_C_FLD) +DECLARE_INSN(c_lw, MATCH_C_LW, MASK_C_LW) +DECLARE_INSN(c_flw, MATCH_C_FLW, MASK_C_FLW) +DECLARE_INSN(c_fsd, MATCH_C_FSD, MASK_C_FSD) +DECLARE_INSN(c_sw, MATCH_C_SW, MASK_C_SW) +DECLARE_INSN(c_fsw, MATCH_C_FSW, MASK_C_FSW) +DECLARE_INSN(c_addi, MATCH_C_ADDI, MASK_C_ADDI) +DECLARE_INSN(c_jal, MATCH_C_JAL, MASK_C_JAL) +DECLARE_INSN(c_li, MATCH_C_LI, MASK_C_LI) +DECLARE_INSN(c_lui, MATCH_C_LUI, MASK_C_LUI) +DECLARE_INSN(c_srli, MATCH_C_SRLI, MASK_C_SRLI) +DECLARE_INSN(c_srai, MATCH_C_SRAI, MASK_C_SRAI) +DECLARE_INSN(c_andi, MATCH_C_ANDI, MASK_C_ANDI) +DECLARE_INSN(c_sub, MATCH_C_SUB, MASK_C_SUB) +DECLARE_INSN(c_xor, MATCH_C_XOR, MASK_C_XOR) +DECLARE_INSN(c_or, MATCH_C_OR, MASK_C_OR) +DECLARE_INSN(c_and, MATCH_C_AND, MASK_C_AND) +DECLARE_INSN(c_subw, MATCH_C_SUBW, MASK_C_SUBW) +DECLARE_INSN(c_addw, MATCH_C_ADDW, MASK_C_ADDW) +DECLARE_INSN(c_j, MATCH_C_J, MASK_C_J) +DECLARE_INSN(c_beqz, MATCH_C_BEQZ, MASK_C_BEQZ) +DECLARE_INSN(c_bnez, MATCH_C_BNEZ, MASK_C_BNEZ) +DECLARE_INSN(c_slli, MATCH_C_SLLI, MASK_C_SLLI) +DECLARE_INSN(c_fldsp, MATCH_C_FLDSP, MASK_C_FLDSP) +DECLARE_INSN(c_lwsp, MATCH_C_LWSP, MASK_C_LWSP) +DECLARE_INSN(c_flwsp, MATCH_C_FLWSP, MASK_C_FLWSP) +DECLARE_INSN(c_mv, MATCH_C_MV, MASK_C_MV) +DECLARE_INSN(c_add, MATCH_C_ADD, MASK_C_ADD) +DECLARE_INSN(c_fsdsp, MATCH_C_FSDSP, MASK_C_FSDSP) +DECLARE_INSN(c_swsp, MATCH_C_SWSP, MASK_C_SWSP) +DECLARE_INSN(c_fswsp, MATCH_C_FSWSP, MASK_C_FSWSP) +DECLARE_INSN(custom0, MATCH_CUSTOM0, MASK_CUSTOM0) +DECLARE_INSN(custom0_rs1, MATCH_CUSTOM0_RS1, MASK_CUSTOM0_RS1) +DECLARE_INSN(custom0_rs1_rs2, MATCH_CUSTOM0_RS1_RS2, MASK_CUSTOM0_RS1_RS2) +DECLARE_INSN(custom0_rd, MATCH_CUSTOM0_RD, MASK_CUSTOM0_RD) +DECLARE_INSN(custom0_rd_rs1, MATCH_CUSTOM0_RD_RS1, MASK_CUSTOM0_RD_RS1) +DECLARE_INSN(custom0_rd_rs1_rs2, MATCH_CUSTOM0_RD_RS1_RS2, MASK_CUSTOM0_RD_RS1_RS2) +DECLARE_INSN(custom1, MATCH_CUSTOM1, MASK_CUSTOM1) +DECLARE_INSN(custom1_rs1, MATCH_CUSTOM1_RS1, MASK_CUSTOM1_RS1) +DECLARE_INSN(custom1_rs1_rs2, MATCH_CUSTOM1_RS1_RS2, MASK_CUSTOM1_RS1_RS2) +DECLARE_INSN(custom1_rd, MATCH_CUSTOM1_RD, MASK_CUSTOM1_RD) +DECLARE_INSN(custom1_rd_rs1, MATCH_CUSTOM1_RD_RS1, MASK_CUSTOM1_RD_RS1) +DECLARE_INSN(custom1_rd_rs1_rs2, MATCH_CUSTOM1_RD_RS1_RS2, MASK_CUSTOM1_RD_RS1_RS2) +DECLARE_INSN(custom2, MATCH_CUSTOM2, MASK_CUSTOM2) +DECLARE_INSN(custom2_rs1, MATCH_CUSTOM2_RS1, MASK_CUSTOM2_RS1) +DECLARE_INSN(custom2_rs1_rs2, MATCH_CUSTOM2_RS1_RS2, MASK_CUSTOM2_RS1_RS2) +DECLARE_INSN(custom2_rd, MATCH_CUSTOM2_RD, MASK_CUSTOM2_RD) +DECLARE_INSN(custom2_rd_rs1, MATCH_CUSTOM2_RD_RS1, MASK_CUSTOM2_RD_RS1) +DECLARE_INSN(custom2_rd_rs1_rs2, MATCH_CUSTOM2_RD_RS1_RS2, MASK_CUSTOM2_RD_RS1_RS2) +DECLARE_INSN(custom3, MATCH_CUSTOM3, MASK_CUSTOM3) +DECLARE_INSN(custom3_rs1, MATCH_CUSTOM3_RS1, MASK_CUSTOM3_RS1) +DECLARE_INSN(custom3_rs1_rs2, MATCH_CUSTOM3_RS1_RS2, MASK_CUSTOM3_RS1_RS2) +DECLARE_INSN(custom3_rd, MATCH_CUSTOM3_RD, MASK_CUSTOM3_RD) +DECLARE_INSN(custom3_rd_rs1, MATCH_CUSTOM3_RD_RS1, MASK_CUSTOM3_RD_RS1) +DECLARE_INSN(custom3_rd_rs1_rs2, MATCH_CUSTOM3_RD_RS1_RS2, MASK_CUSTOM3_RD_RS1_RS2) +#endif +#ifdef DECLARE_CSR +DECLARE_CSR(fflags, CSR_FFLAGS) +DECLARE_CSR(frm, CSR_FRM) +DECLARE_CSR(fcsr, CSR_FCSR) +DECLARE_CSR(cycle, CSR_CYCLE) +DECLARE_CSR(time, CSR_TIME) +DECLARE_CSR(instret, CSR_INSTRET) +DECLARE_CSR(hpmcounter3, CSR_HPMCOUNTER3) +DECLARE_CSR(hpmcounter4, CSR_HPMCOUNTER4) +DECLARE_CSR(hpmcounter5, CSR_HPMCOUNTER5) +DECLARE_CSR(hpmcounter6, CSR_HPMCOUNTER6) +DECLARE_CSR(hpmcounter7, CSR_HPMCOUNTER7) +DECLARE_CSR(hpmcounter8, CSR_HPMCOUNTER8) +DECLARE_CSR(hpmcounter9, CSR_HPMCOUNTER9) +DECLARE_CSR(hpmcounter10, CSR_HPMCOUNTER10) +DECLARE_CSR(hpmcounter11, CSR_HPMCOUNTER11) +DECLARE_CSR(hpmcounter12, CSR_HPMCOUNTER12) +DECLARE_CSR(hpmcounter13, CSR_HPMCOUNTER13) +DECLARE_CSR(hpmcounter14, CSR_HPMCOUNTER14) +DECLARE_CSR(hpmcounter15, CSR_HPMCOUNTER15) +DECLARE_CSR(hpmcounter16, CSR_HPMCOUNTER16) +DECLARE_CSR(hpmcounter17, CSR_HPMCOUNTER17) +DECLARE_CSR(hpmcounter18, CSR_HPMCOUNTER18) +DECLARE_CSR(hpmcounter19, CSR_HPMCOUNTER19) +DECLARE_CSR(hpmcounter20, CSR_HPMCOUNTER20) +DECLARE_CSR(hpmcounter21, CSR_HPMCOUNTER21) +DECLARE_CSR(hpmcounter22, CSR_HPMCOUNTER22) +DECLARE_CSR(hpmcounter23, CSR_HPMCOUNTER23) +DECLARE_CSR(hpmcounter24, CSR_HPMCOUNTER24) +DECLARE_CSR(hpmcounter25, CSR_HPMCOUNTER25) +DECLARE_CSR(hpmcounter26, CSR_HPMCOUNTER26) +DECLARE_CSR(hpmcounter27, CSR_HPMCOUNTER27) +DECLARE_CSR(hpmcounter28, CSR_HPMCOUNTER28) +DECLARE_CSR(hpmcounter29, CSR_HPMCOUNTER29) +DECLARE_CSR(hpmcounter30, CSR_HPMCOUNTER30) +DECLARE_CSR(hpmcounter31, CSR_HPMCOUNTER31) +DECLARE_CSR(sstatus, CSR_SSTATUS) +DECLARE_CSR(sie, CSR_SIE) +DECLARE_CSR(stvec, CSR_STVEC) +DECLARE_CSR(scounteren, CSR_SCOUNTEREN) +DECLARE_CSR(sscratch, CSR_SSCRATCH) +DECLARE_CSR(sepc, CSR_SEPC) +DECLARE_CSR(scause, CSR_SCAUSE) +DECLARE_CSR(stval, CSR_STVAL) +DECLARE_CSR(sip, CSR_SIP) +DECLARE_CSR(satp, CSR_SATP) +DECLARE_CSR(mstatus, CSR_MSTATUS) +DECLARE_CSR(misa, CSR_MISA) +DECLARE_CSR(medeleg, CSR_MEDELEG) +DECLARE_CSR(mideleg, CSR_MIDELEG) +DECLARE_CSR(mie, CSR_MIE) +DECLARE_CSR(mtvec, CSR_MTVEC) +DECLARE_CSR(mcounteren, CSR_MCOUNTEREN) +DECLARE_CSR(mscratch, CSR_MSCRATCH) +DECLARE_CSR(mepc, CSR_MEPC) +DECLARE_CSR(mcause, CSR_MCAUSE) +DECLARE_CSR(mtval, CSR_MTVAL) +DECLARE_CSR(mip, CSR_MIP) +DECLARE_CSR(pmpcfg0, CSR_PMPCFG0) +DECLARE_CSR(pmpcfg1, CSR_PMPCFG1) +DECLARE_CSR(pmpcfg2, CSR_PMPCFG2) +DECLARE_CSR(pmpcfg3, CSR_PMPCFG3) +DECLARE_CSR(pmpaddr0, CSR_PMPADDR0) +DECLARE_CSR(pmpaddr1, CSR_PMPADDR1) +DECLARE_CSR(pmpaddr2, CSR_PMPADDR2) +DECLARE_CSR(pmpaddr3, CSR_PMPADDR3) +DECLARE_CSR(pmpaddr4, CSR_PMPADDR4) +DECLARE_CSR(pmpaddr5, CSR_PMPADDR5) +DECLARE_CSR(pmpaddr6, CSR_PMPADDR6) +DECLARE_CSR(pmpaddr7, CSR_PMPADDR7) +DECLARE_CSR(pmpaddr8, CSR_PMPADDR8) +DECLARE_CSR(pmpaddr9, CSR_PMPADDR9) +DECLARE_CSR(pmpaddr10, CSR_PMPADDR10) +DECLARE_CSR(pmpaddr11, CSR_PMPADDR11) +DECLARE_CSR(pmpaddr12, CSR_PMPADDR12) +DECLARE_CSR(pmpaddr13, CSR_PMPADDR13) +DECLARE_CSR(pmpaddr14, CSR_PMPADDR14) +DECLARE_CSR(pmpaddr15, CSR_PMPADDR15) +DECLARE_CSR(tselect, CSR_TSELECT) +DECLARE_CSR(tdata1, CSR_TDATA1) +DECLARE_CSR(tdata2, CSR_TDATA2) +DECLARE_CSR(tdata3, CSR_TDATA3) +DECLARE_CSR(dcsr, CSR_DCSR) +DECLARE_CSR(dpc, CSR_DPC) +DECLARE_CSR(dscratch, CSR_DSCRATCH) +DECLARE_CSR(mcycle, CSR_MCYCLE) +DECLARE_CSR(minstret, CSR_MINSTRET) +DECLARE_CSR(mhpmcounter3, CSR_MHPMCOUNTER3) +DECLARE_CSR(mhpmcounter4, CSR_MHPMCOUNTER4) +DECLARE_CSR(mhpmcounter5, CSR_MHPMCOUNTER5) +DECLARE_CSR(mhpmcounter6, CSR_MHPMCOUNTER6) +DECLARE_CSR(mhpmcounter7, CSR_MHPMCOUNTER7) +DECLARE_CSR(mhpmcounter8, CSR_MHPMCOUNTER8) +DECLARE_CSR(mhpmcounter9, CSR_MHPMCOUNTER9) +DECLARE_CSR(mhpmcounter10, CSR_MHPMCOUNTER10) +DECLARE_CSR(mhpmcounter11, CSR_MHPMCOUNTER11) +DECLARE_CSR(mhpmcounter12, CSR_MHPMCOUNTER12) +DECLARE_CSR(mhpmcounter13, CSR_MHPMCOUNTER13) +DECLARE_CSR(mhpmcounter14, CSR_MHPMCOUNTER14) +DECLARE_CSR(mhpmcounter15, CSR_MHPMCOUNTER15) +DECLARE_CSR(mhpmcounter16, CSR_MHPMCOUNTER16) +DECLARE_CSR(mhpmcounter17, CSR_MHPMCOUNTER17) +DECLARE_CSR(mhpmcounter18, CSR_MHPMCOUNTER18) +DECLARE_CSR(mhpmcounter19, CSR_MHPMCOUNTER19) +DECLARE_CSR(mhpmcounter20, CSR_MHPMCOUNTER20) +DECLARE_CSR(mhpmcounter21, CSR_MHPMCOUNTER21) +DECLARE_CSR(mhpmcounter22, CSR_MHPMCOUNTER22) +DECLARE_CSR(mhpmcounter23, CSR_MHPMCOUNTER23) +DECLARE_CSR(mhpmcounter24, CSR_MHPMCOUNTER24) +DECLARE_CSR(mhpmcounter25, CSR_MHPMCOUNTER25) +DECLARE_CSR(mhpmcounter26, CSR_MHPMCOUNTER26) +DECLARE_CSR(mhpmcounter27, CSR_MHPMCOUNTER27) +DECLARE_CSR(mhpmcounter28, CSR_MHPMCOUNTER28) +DECLARE_CSR(mhpmcounter29, CSR_MHPMCOUNTER29) +DECLARE_CSR(mhpmcounter30, CSR_MHPMCOUNTER30) +DECLARE_CSR(mhpmcounter31, CSR_MHPMCOUNTER31) +DECLARE_CSR(mhpmevent3, CSR_MHPMEVENT3) +DECLARE_CSR(mhpmevent4, CSR_MHPMEVENT4) +DECLARE_CSR(mhpmevent5, CSR_MHPMEVENT5) +DECLARE_CSR(mhpmevent6, CSR_MHPMEVENT6) +DECLARE_CSR(mhpmevent7, CSR_MHPMEVENT7) +DECLARE_CSR(mhpmevent8, CSR_MHPMEVENT8) +DECLARE_CSR(mhpmevent9, CSR_MHPMEVENT9) +DECLARE_CSR(mhpmevent10, CSR_MHPMEVENT10) +DECLARE_CSR(mhpmevent11, CSR_MHPMEVENT11) +DECLARE_CSR(mhpmevent12, CSR_MHPMEVENT12) +DECLARE_CSR(mhpmevent13, CSR_MHPMEVENT13) +DECLARE_CSR(mhpmevent14, CSR_MHPMEVENT14) +DECLARE_CSR(mhpmevent15, CSR_MHPMEVENT15) +DECLARE_CSR(mhpmevent16, CSR_MHPMEVENT16) +DECLARE_CSR(mhpmevent17, CSR_MHPMEVENT17) +DECLARE_CSR(mhpmevent18, CSR_MHPMEVENT18) +DECLARE_CSR(mhpmevent19, CSR_MHPMEVENT19) +DECLARE_CSR(mhpmevent20, CSR_MHPMEVENT20) +DECLARE_CSR(mhpmevent21, CSR_MHPMEVENT21) +DECLARE_CSR(mhpmevent22, CSR_MHPMEVENT22) +DECLARE_CSR(mhpmevent23, CSR_MHPMEVENT23) +DECLARE_CSR(mhpmevent24, CSR_MHPMEVENT24) +DECLARE_CSR(mhpmevent25, CSR_MHPMEVENT25) +DECLARE_CSR(mhpmevent26, CSR_MHPMEVENT26) +DECLARE_CSR(mhpmevent27, CSR_MHPMEVENT27) +DECLARE_CSR(mhpmevent28, CSR_MHPMEVENT28) +DECLARE_CSR(mhpmevent29, CSR_MHPMEVENT29) +DECLARE_CSR(mhpmevent30, CSR_MHPMEVENT30) +DECLARE_CSR(mhpmevent31, CSR_MHPMEVENT31) +DECLARE_CSR(mvendorid, CSR_MVENDORID) +DECLARE_CSR(marchid, CSR_MARCHID) +DECLARE_CSR(mimpid, CSR_MIMPID) +DECLARE_CSR(mhartid, CSR_MHARTID) +DECLARE_CSR(cycleh, CSR_CYCLEH) +DECLARE_CSR(timeh, CSR_TIMEH) +DECLARE_CSR(instreth, CSR_INSTRETH) +DECLARE_CSR(hpmcounter3h, CSR_HPMCOUNTER3H) +DECLARE_CSR(hpmcounter4h, CSR_HPMCOUNTER4H) +DECLARE_CSR(hpmcounter5h, CSR_HPMCOUNTER5H) +DECLARE_CSR(hpmcounter6h, CSR_HPMCOUNTER6H) +DECLARE_CSR(hpmcounter7h, CSR_HPMCOUNTER7H) +DECLARE_CSR(hpmcounter8h, CSR_HPMCOUNTER8H) +DECLARE_CSR(hpmcounter9h, CSR_HPMCOUNTER9H) +DECLARE_CSR(hpmcounter10h, CSR_HPMCOUNTER10H) +DECLARE_CSR(hpmcounter11h, CSR_HPMCOUNTER11H) +DECLARE_CSR(hpmcounter12h, CSR_HPMCOUNTER12H) +DECLARE_CSR(hpmcounter13h, CSR_HPMCOUNTER13H) +DECLARE_CSR(hpmcounter14h, CSR_HPMCOUNTER14H) +DECLARE_CSR(hpmcounter15h, CSR_HPMCOUNTER15H) +DECLARE_CSR(hpmcounter16h, CSR_HPMCOUNTER16H) +DECLARE_CSR(hpmcounter17h, CSR_HPMCOUNTER17H) +DECLARE_CSR(hpmcounter18h, CSR_HPMCOUNTER18H) +DECLARE_CSR(hpmcounter19h, CSR_HPMCOUNTER19H) +DECLARE_CSR(hpmcounter20h, CSR_HPMCOUNTER20H) +DECLARE_CSR(hpmcounter21h, CSR_HPMCOUNTER21H) +DECLARE_CSR(hpmcounter22h, CSR_HPMCOUNTER22H) +DECLARE_CSR(hpmcounter23h, CSR_HPMCOUNTER23H) +DECLARE_CSR(hpmcounter24h, CSR_HPMCOUNTER24H) +DECLARE_CSR(hpmcounter25h, CSR_HPMCOUNTER25H) +DECLARE_CSR(hpmcounter26h, CSR_HPMCOUNTER26H) +DECLARE_CSR(hpmcounter27h, CSR_HPMCOUNTER27H) +DECLARE_CSR(hpmcounter28h, CSR_HPMCOUNTER28H) +DECLARE_CSR(hpmcounter29h, CSR_HPMCOUNTER29H) +DECLARE_CSR(hpmcounter30h, CSR_HPMCOUNTER30H) +DECLARE_CSR(hpmcounter31h, CSR_HPMCOUNTER31H) +DECLARE_CSR(mcycleh, CSR_MCYCLEH) +DECLARE_CSR(minstreth, CSR_MINSTRETH) +DECLARE_CSR(mhpmcounter3h, CSR_MHPMCOUNTER3H) +DECLARE_CSR(mhpmcounter4h, CSR_MHPMCOUNTER4H) +DECLARE_CSR(mhpmcounter5h, CSR_MHPMCOUNTER5H) +DECLARE_CSR(mhpmcounter6h, CSR_MHPMCOUNTER6H) +DECLARE_CSR(mhpmcounter7h, CSR_MHPMCOUNTER7H) +DECLARE_CSR(mhpmcounter8h, CSR_MHPMCOUNTER8H) +DECLARE_CSR(mhpmcounter9h, CSR_MHPMCOUNTER9H) +DECLARE_CSR(mhpmcounter10h, CSR_MHPMCOUNTER10H) +DECLARE_CSR(mhpmcounter11h, CSR_MHPMCOUNTER11H) +DECLARE_CSR(mhpmcounter12h, CSR_MHPMCOUNTER12H) +DECLARE_CSR(mhpmcounter13h, CSR_MHPMCOUNTER13H) +DECLARE_CSR(mhpmcounter14h, CSR_MHPMCOUNTER14H) +DECLARE_CSR(mhpmcounter15h, CSR_MHPMCOUNTER15H) +DECLARE_CSR(mhpmcounter16h, CSR_MHPMCOUNTER16H) +DECLARE_CSR(mhpmcounter17h, CSR_MHPMCOUNTER17H) +DECLARE_CSR(mhpmcounter18h, CSR_MHPMCOUNTER18H) +DECLARE_CSR(mhpmcounter19h, CSR_MHPMCOUNTER19H) +DECLARE_CSR(mhpmcounter20h, CSR_MHPMCOUNTER20H) +DECLARE_CSR(mhpmcounter21h, CSR_MHPMCOUNTER21H) +DECLARE_CSR(mhpmcounter22h, CSR_MHPMCOUNTER22H) +DECLARE_CSR(mhpmcounter23h, CSR_MHPMCOUNTER23H) +DECLARE_CSR(mhpmcounter24h, CSR_MHPMCOUNTER24H) +DECLARE_CSR(mhpmcounter25h, CSR_MHPMCOUNTER25H) +DECLARE_CSR(mhpmcounter26h, CSR_MHPMCOUNTER26H) +DECLARE_CSR(mhpmcounter27h, CSR_MHPMCOUNTER27H) +DECLARE_CSR(mhpmcounter28h, CSR_MHPMCOUNTER28H) +DECLARE_CSR(mhpmcounter29h, CSR_MHPMCOUNTER29H) +DECLARE_CSR(mhpmcounter30h, CSR_MHPMCOUNTER30H) +DECLARE_CSR(mhpmcounter31h, CSR_MHPMCOUNTER31H) +#endif +#ifdef DECLARE_CAUSE +DECLARE_CAUSE("misaligned fetch", CAUSE_MISALIGNED_FETCH) +DECLARE_CAUSE("fetch access", CAUSE_FETCH_ACCESS) +DECLARE_CAUSE("illegal instruction", CAUSE_ILLEGAL_INSTRUCTION) +DECLARE_CAUSE("breakpoint", CAUSE_BREAKPOINT) +DECLARE_CAUSE("misaligned load", CAUSE_MISALIGNED_LOAD) +DECLARE_CAUSE("load access", CAUSE_LOAD_ACCESS) +DECLARE_CAUSE("misaligned store", CAUSE_MISALIGNED_STORE) +DECLARE_CAUSE("store access", CAUSE_STORE_ACCESS) +DECLARE_CAUSE("user_ecall", CAUSE_USER_ECALL) +DECLARE_CAUSE("supervisor_ecall", CAUSE_SUPERVISOR_ECALL) +DECLARE_CAUSE("hypervisor_ecall", CAUSE_HYPERVISOR_ECALL) +DECLARE_CAUSE("machine_ecall", CAUSE_MACHINE_ECALL) +DECLARE_CAUSE("fetch page fault", CAUSE_FETCH_PAGE_FAULT) +DECLARE_CAUSE("load page fault", CAUSE_LOAD_PAGE_FAULT) +DECLARE_CAUSE("store page fault", CAUSE_STORE_PAGE_FAULT) +#endif diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 36f75e00..b6a33076 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -18,6 +18,7 @@ #include #include #include +#include "encoding.h" using namespace std; @@ -220,6 +221,8 @@ public: uint32_t medeleg; uint32_t mideleg; + uint32_t interrupts; + union status { uint32_t raw; struct { @@ -350,13 +353,14 @@ public: mbadaddr = 0; mepc = 0; misa = 0; //TODO + status.raw = 0; status.mpp = 3; + status.spp = 1; privilege = 3; medeleg = 0; mideleg = 0; satp.mode = 0; - status.mxr = 0; - status.sum = 0; + interrupts = 0; } virtual void rfWrite(int32_t address, int32_t data) { @@ -369,7 +373,7 @@ public: lastPc = pc; pc = target; } else { - exception(0, 0, target); + trap(0, 0, target); } } uint32_t mbadaddr, sbadaddr; @@ -406,16 +410,32 @@ public: return false; } - void exception(bool interrupt,int32_t cause) { - exception(interrupt, cause, false, 0); + void trap(bool interrupt,int32_t cause) { + trap(interrupt, cause, false, 0); } - void exception(bool interrupt,int32_t cause, uint32_t value) { - exception(interrupt, cause, true, value); + void trap(bool interrupt,int32_t cause, uint32_t value) { + trap(interrupt, cause, true, value); } - void exception(bool interrupt,int32_t cause, bool valueWrite, uint32_t value) { + void trap(bool interrupt,int32_t cause, bool valueWrite, uint32_t value) { + //Check leguality of the interrupt + if(interrupt) { + bool hit = false; + for(int i = 0;i < 5;i++){ + if(pendingInterrupts[i] == 1 << cause){ + hit = true; + break; + } + } + if(!hit){ + cout << "DUT had trigger an interrupts which wasn't by the REF" << endl; + fail(); + } + } + uint32_t deleg = interrupt ? mideleg : medeleg; uint32_t targetPrivilege = 3; if(deleg & (1 << cause)) targetPrivilege = 1; + targetPrivilege = max(targetPrivilege, privilege); Xtvec xtvec = targetPrivilege == 3 ? mtvec : stvec; switch(targetPrivilege){ @@ -423,8 +443,8 @@ public: if(valueWrite) mbadaddr = value; mcause.interrupt = interrupt; mcause.exceptionCode = cause; - status.mie = false; status.mpie = status.mie; + status.mie = false; status.mpp = privilege; mepc = pc; break; @@ -432,8 +452,8 @@ public: if(valueWrite) sbadaddr = value; scause.interrupt = interrupt; scause.exceptionCode = cause; - status.sie = false; status.spie = status.sie; + status.sie = false; status.spp = privilege; sepc = pc; break; @@ -447,7 +467,7 @@ public: } void ilegalInstruction(){ - exception(0, 2); + trap(0, 2); } virtual void fail() { @@ -467,6 +487,8 @@ public: case MEPC: *value = mepc; break; case MSCRATCH: *value = mscratch; break; case MISA: *value = misa; break; + case MEDELEG: *value = medeleg; break; + case MIDELEG: *value = mideleg; break; case SSTATUS: *value = status.raw & 0xC0133; break; case SIP: *value = ip.raw & 0x333; break; @@ -495,6 +517,8 @@ public: case MEPC: mepc = value; break; case MSCRATCH: mscratch = value; break; case MISA: misa = value; break; + case MEDELEG: medeleg = value; break; + case MIDELEG: mideleg = value; break; case SSTATUS: maskedWrite(status.raw, value,0xC0133); break; case SIP: maskedWrite(ip.raw, value,0x333); break; @@ -514,16 +538,14 @@ public: int livenessStep = 0; int livenessInterrupt = 0; - virtual void liveness(bool mIntTimer, bool mIntExt){ - livenessStep++; - bool interruptRequest = (ie.mtie && mIntTimer); - if(interruptRequest){ - if(status.mie){ - livenessInterrupt++; - } - } else { - livenessInterrupt = 0; - } + uint32_t pendingInterruptsPtr = 0; + uint32_t pendingInterrupts[5] = {0,0,0,0,0}; + virtual void liveness(bool inWfi){ + uint32_t pendingInterrupt = getPendingInterrupt(); + pendingInterrupts[pendingInterruptsPtr++] = getPendingInterrupt(); + if(pendingInterruptsPtr >= 5) pendingInterruptsPtr = 0; + if(pendingInterrupt) livenessInterrupt++; else livenessInterrupt = 0; + if(!inWfi) livenessStep++; else livenessStep = 0; if(livenessStep > 1000){ cout << "Liveness step failure" << endl; @@ -534,9 +556,34 @@ public: cout << "Liveness interrupt failure" << endl; fail(); } - } + + uint32_t getPendingInterrupt(){ + uint32_t mEnabled = status.mie && privilege == 3 || privilege < 3; + uint32_t sEnabled = status.sie && privilege == 1 || privilege < 1; + + uint32_t masked = interrupts & ~mideleg & -mEnabled & ie.raw; + if (masked == 0) + masked = interrupts & mideleg & -sEnabled & ie.raw & 0x333; + + if (masked) { + if (masked & (MIP_MEIP | MIP_SEIP)) + masked &= (MIP_MEIP | MIP_SEIP); + // software interrupts have next-highest priority + else if (masked & (MIP_MSIP | MIP_SSIP)) + masked &= (MIP_MSIP | MIP_SSIP); + // timer interrupts have next-highest priority + else if (masked & (MIP_MTIP | MIP_STIP)) + masked &= (MIP_MTIP | MIP_STIP); + else + fail(); + } + + return masked; + } + + bool isPcAligned(uint32_t pc){ #ifdef COMPRESSED return (pc & 1) == 0; @@ -579,25 +626,25 @@ public: uint32_t u32Buf; uint32_t pAddr; if (pc & 2) { - if(v2p(pc - 2, &pAddr, EXECUTE)){ exception(0, 12); return; } + if(v2p(pc - 2, &pAddr, EXECUTE)){ trap(0, 12); return; } if(iRead(pAddr, &i)){ - exception(0, 1); + trap(0, 1); return; } i >>= 16; if (i & 3 == 3) { uint32_t u32Buf; - if(v2p(pc + 2, &pAddr, EXECUTE)){ exception(0, 12); return; } + if(v2p(pc + 2, &pAddr, EXECUTE)){ trap(0, 12); return; } if(iRead(pAddr, &u32Buf)){ - exception(0, 1); + trap(0, 1); return; } i |= u32Buf << 16; } } else { - if(v2p(pc, &pAddr, EXECUTE)){ exception(0, 12); return; } + if(v2p(pc, &pAddr, EXECUTE)){ trap(0, 12); return; } if(iRead(pAddr, &i)){ - exception(0, 1); + trap(0, 1); return; } } @@ -627,11 +674,11 @@ public: uint32_t address = i32_rs1 + i32_i_imm; uint32_t size = 1 << ((i >> 12) & 0x3); if(address & (size-1)){ - exception(0, 4, address); + trap(0, 4, address); } else { - if(v2p(address, &pAddr, READ)){ exception(0, 13); return; } + if(v2p(address, &pAddr, READ)){ trap(0, 13); return; } if(dRead(pAddr, size, &data)){ - exception(0, 5, address); + trap(0, 5, address); } else { switch ((i >> 12) & 0x7) { case 0x0:rfWrite(rd32, int8_t(data));pcWrite(pc + 4);break; @@ -647,9 +694,9 @@ public: uint32_t address = i32_rs1 + i32_s_imm; uint32_t size = 1 << ((i >> 12) & 0x3); if(address & (size-1)){ - exception(0, 6, address); + trap(0, 6, address); } else { - if(v2p(address, &pAddr, WRITE)){ exception(0, 15); return; } + if(v2p(address, &pAddr, WRITE)){ trap(0, 15); return; } dWrite(pAddr, size, i32_rs2); pcWrite(pc + 4); } @@ -730,7 +777,7 @@ public: pcWrite(sepc); }break; case 0x00000073:{ //ECALL - exception(0, 8+privilege); + trap(0, 8+privilege); }break; case 0x10500073:{ //WFI pcWrite(pc + 4); @@ -771,11 +818,11 @@ public: uint32_t data; uint32_t address = i16_rf1 + i16_lw_imm; if(address & 0x3){ - exception(0, 4, address); + trap(0, 4, address); } else { - if(v2p(address, &pAddr, READ)){ exception(0, 13); return; } + if(v2p(address, &pAddr, READ)){ trap(0, 13); return; } if(dRead(address, 4, &data)) { - exception(1, 5, address); + trap(1, 5, address); } else { rfWrite(i16_addr2, data); pcWrite(pc + 2); } @@ -784,9 +831,9 @@ public: case 6: { uint32_t address = i16_rf1 + i16_lw_imm; if(address & 0x3){ - exception(0, 6, address); + trap(0, 6, address); } else { - if(v2p(address, &pAddr, WRITE)){ exception(0, 15); return; } + if(v2p(address, &pAddr, WRITE)){ trap(0, 15); return; } dWrite(pAddr, 4, i16_rf2); pcWrite(pc + 2); } @@ -820,11 +867,11 @@ public: uint32_t data; uint32_t address = rf_sp + i16_lwsp_imm; if(address & 0x3){ - exception(0, 4, address); + trap(0, 4, address); } else { - if(v2p(address, &pAddr, READ)){ exception(0, 13); return; } + if(v2p(address, &pAddr, READ)){ trap(0, 13); return; } if(dRead(pAddr, 4, &data)){ - exception(1, 5, address); + trap(1, 5, address); } else { rfWrite(rd32, data); pcWrite(pc + 2); } @@ -850,9 +897,9 @@ public: case 22: { uint32_t address = rf_sp + i16_swsp_imm; if(address & 3){ - exception(0,6, address); + trap(0,6, address); } else { - if(v2p(address, &pAddr, WRITE)){ exception(0, 15); return; } + if(v2p(address, &pAddr, WRITE)){ trap(0, 15); return; } dWrite(pAddr, 4, regs[iBits(2,5)]); pcWrite(pc + 2); } }break; @@ -1112,6 +1159,13 @@ public: logTraces << (char)mem[0xF0010000u]; break; } +#ifdef EXTERNAL_INTERRUPT + case 0xF0011000u: top->externalInterrupt = *data & 1; break; +#endif + +#ifdef SUPERVISOR + case 0xF0012000u: top->externalInterruptS = *data & 1; break; +#endif case 0xF00FFF00u: { cout << mem[0xF00FFF00u]; logTraces << (char)mem[0xF00FFF00u]; @@ -1222,6 +1276,9 @@ public: top->timerInterrupt = 0; top->externalInterrupt = 1; #endif + #ifdef SUPERVISOR + top->externalInterruptS = 0; + #endif #ifdef DEBUG_PLUGIN_EXTERNAL top->timerInterrupt = 0; top->externalInterrupt = 0; @@ -1300,8 +1357,21 @@ public: top->eval(); #ifdef CSR + riscvRef.interrupts = 0; +#ifdef TIMER_INTERRUPT + riscvRef.interrupts |= top->timerInterrupt << 7; +#endif +#ifdef EXTERNAL_INTERRUPT + riscvRef.interrupts |= top->externalInterrupt << 11; +#endif +#ifdef SUPERVISOR + riscvRef.interrupts |= top->timerInterruptS << 5; + riscvRef.interrupts |= top->externalInterruptS << 9; +#endif + + riscvRef.liveness(top->VexRiscv->execute_CsrPlugin_inWfi); if(top->VexRiscv->CsrPlugin_interruptJump){ - if(riscvRefEnable) riscvRef.exception(true, top->VexRiscv->CsrPlugin_interruptCode); + if(riscvRefEnable) riscvRef.trap(true, top->VexRiscv->CsrPlugin_interruptCode); } #endif if(top->VexRiscv->writeBack_arbitration_isFiring){ @@ -1309,16 +1379,6 @@ public: riscvRef.step(); bool mIntTimer = false; bool mIntExt = false; - -#ifdef TIMER_INTERRUPT - mIntTimer = top->timerInterrupt; -#endif -#ifdef EXTERNAL_INTERRUPT - mIntExt = top->externalInterrupt; -#endif - - - riscvRef.liveness(mIntTimer, mIntExt); } if(riscvRefEnable && top->VexRiscv->writeBack_PC != riscvRef.lastPc){ @@ -1353,11 +1413,9 @@ public: } if(riscvRefEnable) if(rfWriteValid != riscvRef.rfWriteValid || (rfWriteValid && (rfWriteAddress!= riscvRef.rfWriteAddress || rfWriteData!= riscvRef.rfWriteData))){ - cout << "regFile write missmatch "; - if(rfWriteValid) cout << "REF: RF[" << riscvRef.rfWriteAddress << "] = 0x" << hex << riscvRef.rfWriteData << dec << " "; - if(rfWriteValid) cout << "RTL: RF[" << rfWriteAddress << "] = 0x" << hex << rfWriteData << dec << " "; - - cout << endl; + cout << "regFile write missmatch :" << endl; + if(rfWriteValid) cout << " REF: RF[" << riscvRef.rfWriteAddress << "] = 0x" << hex << riscvRef.rfWriteData << dec << endl; + if(rfWriteValid) cout << " RTL: RF[" << rfWriteAddress << "] = 0x" << hex << rfWriteData << dec << endl; fail(); } } @@ -2966,6 +3024,7 @@ int main(int argc, char **argv, char **env) { // #ifdef MMU // redo(REDO,Workspace("mmu").withRiscvRef()->loadHex("../raw/mmu/build/mmu.hex")->bootAt(0x80000000u)->run(50e3);); // #endif +// redo(REDO,Workspace("deleg").withRiscvRef()->loadHex("../raw/deleg/build/deleg.hex")->bootAt(0x80000000u)->run(50e3);); // return 0; for(int idx = 0;idx < 1;idx++){ @@ -3073,6 +3132,9 @@ int main(int argc, char **argv, char **env) { #ifdef MMU redo(REDO,Workspace("mmu").withRiscvRef()->loadHex("../raw/mmu/build/mmu.hex")->bootAt(0x80000000u)->run(50e3);); #endif + #ifdef SUPERVISOR + redo(REDO,Workspace("deleg").withRiscvRef()->loadHex("../raw/deleg/build/deleg.hex")->bootAt(0x80000000u)->run(50e3);); + #endif #ifdef DEBUG_PLUGIN redo(REDO,DebugPluginTest().run(1e6);); diff --git a/src/test/cpp/regression/makefile b/src/test/cpp/regression/makefile index 937a6204..1037feb9 100644 --- a/src/test/cpp/regression/makefile +++ b/src/test/cpp/regression/makefile @@ -30,6 +30,7 @@ REF_TIME=no THREAD_COUNT?=4 MTIME_INSTR_FACTOR?=no COMPRESSED?=no +SUPERVISOR?=no STOP_ON_ERROR?=no @@ -67,7 +68,9 @@ endif ifeq ($(COMPRESSED),yes) ADDCFLAGS += -CFLAGS -DCOMPRESSED endif - +ifeq ($(SUPERVISOR),yes) + ADDCFLAGS += -CFLAGS -DSUPERVISOR +endif ifeq ($(FENCEI),yes) ADDCFLAGS += -CFLAGS -DFENCEI endif From 505bff6f454b3da01f611985a1412d6a064806a2 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sat, 23 Mar 2019 12:56:04 +0100 Subject: [PATCH 065/951] CSR Plugin now implement interruptions as specified in the spec --- .../scala/vexriscv/plugin/CsrPlugin.scala | 24 +-- src/test/cpp/raw/common/asm.mk | 14 +- src/test/cpp/raw/machineCsr/.gitignore | 4 + .../cpp/raw/machineCsr/build/machineCsr.asm | 138 +++++++++++++++++ .../cpp/raw/machineCsr/build/machineCsr.hex | 33 ++++ .../machineCsr/build/machineCsrCompressed.asm | 139 +++++++++++++++++ .../machineCsr/build/machineCsrCompressed.hex | 27 ++++ src/test/cpp/raw/machineCsr/makefile | 10 ++ src/test/cpp/raw/machineCsr/src/crt.S | 143 ++++++++++++++++++ src/test/cpp/raw/machineCsr/src/ld | 16 ++ src/test/cpp/regression/main.cpp | 14 +- 11 files changed, 546 insertions(+), 16 deletions(-) create mode 100644 src/test/cpp/raw/machineCsr/.gitignore create mode 100644 src/test/cpp/raw/machineCsr/build/machineCsr.asm create mode 100644 src/test/cpp/raw/machineCsr/build/machineCsr.hex create mode 100644 src/test/cpp/raw/machineCsr/build/machineCsrCompressed.asm create mode 100644 src/test/cpp/raw/machineCsr/build/machineCsrCompressed.hex create mode 100644 src/test/cpp/raw/machineCsr/makefile create mode 100644 src/test/cpp/raw/machineCsr/src/crt.S create mode 100644 src/test/cpp/raw/machineCsr/src/ld diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index bcd70d61..434db5d2 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -282,8 +282,8 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception } var jumpInterface : Flow[UInt] = null - var timerInterrupt, externalInterrupt : Bool = null - var timerInterruptS, externalInterruptS : Bool = null + var timerInterrupt, externalInterrupt, softwareInterrupt : Bool = null + var externalInterruptS : Bool = null var privilege : UInt = null var selfException : Flow[ExceptionCause] = null var contextSwitching : Bool = null @@ -376,8 +376,9 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception timerInterrupt = in Bool() setName("timerInterrupt") externalInterrupt = in Bool() setName("externalInterrupt") + softwareInterrupt = in Bool() setName("softwareInterrupt") if(supervisorGen){ - timerInterruptS = in Bool() setName("timerInterruptS") +// timerInterruptS = in Bool() setName("timerInterruptS") externalInterruptS = in Bool() setName("externalInterruptS") } contextSwitching = Bool().setName("contextSwitching") @@ -444,9 +445,9 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception val MPP = RegInit(U"11") } val mip = new Area{ - val MEIP = RegNext(externalInterrupt) init(False) - val MTIP = RegNext(timerInterrupt) init(False) - val MSIP = RegInit(False) + val MEIP = RegNext(externalInterrupt) + val MTIP = RegNext(timerInterrupt) + val MSIP = RegNext(softwareInterrupt) } val mie = new Area{ val MEIE, MTIE, MSIE = RegInit(False) @@ -503,8 +504,10 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception } val sip = new Area { - val SEIP = RegNext(externalInterruptS) init (False) - val STIP = RegNext(timerInterruptS) init (False) + val SEIP_SOFT = RegInit(False) + val SEIP_INPUT = RegNext(externalInterruptS) + val SEIP_OR = SEIP_SOFT || SEIP_INPUT + val STIP = RegInit(False) val SSIP = RegInit(False) } val sie = new Area { @@ -528,8 +531,7 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception //Supervisor CSR for(offset <- List(CSR.MSTATUS, CSR.SSTATUS)) READ_WRITE(offset,8 -> sstatus.SPP, 5 -> sstatus.SPIE, 1 -> sstatus.SIE) for(offset <- List(CSR.MIP, CSR.SIP)) { - READ_ONLY(offset, 9 -> sip.SEIP, 5 -> sip.STIP) - READ_WRITE(offset, 1 -> sip.SSIP) + READ_WRITE(offset, 9 -> sip.SEIP_SOFT, 5 -> sip.STIP, 1 -> sip.SSIP) } for(offset <- List(CSR.MIE, CSR.SIE)) READ_WRITE(offset, 9 -> sie.SEIE, 5 -> sie.STIE, 1 -> sie.SSIE) @@ -566,7 +568,7 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception getInterruptPrivilege(1).sources ++= List( InterruptSource(sip.STIP && sie.STIE, 5), InterruptSource(sip.SSIP && sie.SSIE, 1), - InterruptSource(sip.SEIP && sie.SEIE, 9) + InterruptSource(sip.SEIP_OR && sie.SEIE, 9) ) } diff --git a/src/test/cpp/raw/common/asm.mk b/src/test/cpp/raw/common/asm.mk index 88db8ab1..f16774de 100644 --- a/src/test/cpp/raw/common/asm.mk +++ b/src/test/cpp/raw/common/asm.mk @@ -1,6 +1,5 @@ RISCV_PATH?=/opt/riscv/ -CFLAGS += -march=rv32i -mabi=ilp32 RISCV_NAME = riscv64-unknown-elf RISCV_OBJCOPY = $(RISCV_PATH)/bin/$(RISCV_NAME)-objcopy RISCV_OBJDUMP = $(RISCV_PATH)/bin/$(RISCV_NAME)-objdump @@ -8,6 +7,19 @@ RISCV_CLIB=$(RISCV_PATH)$(RISCV_NAME)/lib/ RISCV_CC=$(RISCV_PATH)/bin/$(RISCV_NAME)-gcc LDSCRIPT=src/ld +MABI=ilp32 +MARCH := rv32i +ifeq ($(MULDIV),yes) + MARCH := $(MARCH)m +endif +ifeq ($(COMPRESSED),yes) + MARCH := $(MARCH)ac +endif + +CFLAGS += -march=$(MARCH) -mabi=$(MABI) +LDFLAGS += -march=$(MARCH) -mabi=$(MABI) + + SRCS = $(wildcard src/*.c) \ $(wildcard src/*.cpp) \ diff --git a/src/test/cpp/raw/machineCsr/.gitignore b/src/test/cpp/raw/machineCsr/.gitignore new file mode 100644 index 00000000..c12cb2c2 --- /dev/null +++ b/src/test/cpp/raw/machineCsr/.gitignore @@ -0,0 +1,4 @@ +*.map +*.v +*.elf +*.o \ No newline at end of file diff --git a/src/test/cpp/raw/machineCsr/build/machineCsr.asm b/src/test/cpp/raw/machineCsr/build/machineCsr.asm new file mode 100644 index 00000000..c480c266 --- /dev/null +++ b/src/test/cpp/raw/machineCsr/build/machineCsr.asm @@ -0,0 +1,138 @@ + +build/machineCsr.elf: file format elf32-littleriscv + + +Disassembly of section .crt_section: + +80000000 : +80000000: 0940006f j 80000094 <_start> +80000004: 00000013 nop +80000008: 00000013 nop +8000000c: 00000013 nop +80000010: 00000013 nop +80000014: 00000013 nop +80000018: 00000013 nop +8000001c: 00000013 nop + +80000020 : +80000020: 34202e73 csrr t3,mcause +80000024: 000e1e63 bnez t3,80000040 +80000028: ffc00f13 li t5,-4 +8000002c: 34102ef3 csrr t4,mepc +80000030: 01eefeb3 and t4,t4,t5 +80000034: 004e8e93 addi t4,t4,4 +80000038: 341e9073 csrw mepc,t4 +8000003c: 01c0006f j 80000058 + +80000040 : +80000040: 80000eb7 lui t4,0x80000 +80000044: 01de7f33 and t5,t3,t4 +80000048: 000f1863 bnez t5,80000058 +8000004c: 34102ef3 csrr t4,mepc +80000050: 004e8e93 addi t4,t4,4 # 80000004 <_start+0xffffff70> +80000054: 341e9073 csrw mepc,t4 + +80000058 : +80000058: 80000eb7 lui t4,0x80000 +8000005c: 003e8e93 addi t4,t4,3 # 80000003 <_start+0xffffff6f> +80000060: 01ce9863 bne t4,t3,80000070 +80000064: f0013c37 lui s8,0xf0013 +80000068: 00000c93 li s9,0 +8000006c: 019c2023 sw s9,0(s8) # f0013000 <_start+0x70012f6c> + +80000070 : +80000070: 80000eb7 lui t4,0x80000 +80000074: 007e8e93 addi t4,t4,7 # 80000007 <_start+0xffffff73> +80000078: 01ce9463 bne t4,t3,80000080 +8000007c: 30405073 csrwi mie,0 + +80000080 : +80000080: 80000eb7 lui t4,0x80000 +80000084: 00be8e93 addi t4,t4,11 # 8000000b <_start+0xffffff77> +80000088: 01ce9463 bne t4,t3,80000090 +8000008c: 30405073 csrwi mie,0 + +80000090 : +80000090: 30200073 mret + +80000094 <_start>: +80000094: 00100e13 li t3,1 +80000098: 00000073 ecall +8000009c: 00200e13 li t3,2 +800000a0: 00800293 li t0,8 +800000a4: 3002a073 csrs mstatus,t0 +800000a8: 00800293 li t0,8 +800000ac: 30429073 csrw mie,t0 +800000b0: f0013c37 lui s8,0xf0013 +800000b4: 00100c93 li s9,1 +800000b8: 019c2023 sw s9,0(s8) # f0013000 <_start+0x70012f6c> +800000bc: 00000013 nop +800000c0: 00000013 nop +800000c4: 00000013 nop +800000c8: 00000013 nop +800000cc: 00000013 nop +800000d0: 00000013 nop +800000d4: 00000013 nop +800000d8: 00000013 nop +800000dc: 00000013 nop +800000e0: 00000013 nop +800000e4: 00000013 nop +800000e8: 00000013 nop +800000ec: 00300e13 li t3,3 +800000f0: 08000293 li t0,128 +800000f4: 30429073 csrw mie,t0 +800000f8: 00000013 nop +800000fc: 00000013 nop +80000100: 00000013 nop +80000104: 00000013 nop +80000108: 00000013 nop +8000010c: 00000013 nop +80000110: 00000013 nop +80000114: 00400e13 li t3,4 +80000118: 000012b7 lui t0,0x1 +8000011c: 80028293 addi t0,t0,-2048 # 800 +80000120: 30429073 csrw mie,t0 +80000124: 00000013 nop +80000128: 00000013 nop +8000012c: 00000013 nop +80000130: 00000013 nop +80000134: 00000013 nop +80000138: 00000013 nop +8000013c: 00000013 nop +80000140: 00500e13 li t3,5 +80000144: f01001b7 lui gp,0xf0100 +80000148: f4018193 addi gp,gp,-192 # f00fff40 <_start+0x700ffeac> +8000014c: 0001a203 lw tp,0(gp) +80000150: 0041a283 lw t0,4(gp) +80000154: 3ff20213 addi tp,tp,1023 # 3ff +80000158: 0041a423 sw tp,8(gp) +8000015c: 0051a623 sw t0,12(gp) +80000160: 00600e13 li t3,6 +80000164: 08000213 li tp,128 +80000168: 30421073 csrw mie,tp +8000016c: 00700e13 li t3,7 +80000170: 10500073 wfi +80000174: 00800e13 li t3,8 +80000178: 00100193 li gp,1 +8000017c: 0041a023 sw tp,0(gp) +80000180: 00900e13 li t3,9 +80000184: 00419023 sh tp,0(gp) +80000188: 00a00e13 li t3,10 +8000018c: 0001a203 lw tp,0(gp) +80000190: 00b00e13 li t3,11 +80000194: 00019203 lh tp,0(gp) +80000198: 00c00e13 li t3,12 +8000019c: 00d00e13 li t3,13 +800001a0: 00002083 lw ra,0(zero) # 0 +800001a4: 00002083 lw ra,0(zero) # 0 +800001a8: 00e00e13 li t3,14 +800001ac: 20200073 hret +800001b0: 00f00e13 li t3,15 +800001b4: f01000b7 lui ra,0xf0100 +800001b8: f6008093 addi ra,ra,-160 # f00fff60 <_start+0x700ffecc> +800001bc: 0000a103 lw sp,0(ra) +800001c0: 01000e13 li t3,16 +800001c4: 0020a023 sw sp,0(ra) +800001c8: 01100e13 li t3,17 +800001cc: 00008067 ret + ... diff --git a/src/test/cpp/raw/machineCsr/build/machineCsr.hex b/src/test/cpp/raw/machineCsr/build/machineCsr.hex new file mode 100644 index 00000000..9a59bd18 --- /dev/null +++ b/src/test/cpp/raw/machineCsr/build/machineCsr.hex @@ -0,0 +1,33 @@ +:0200000480007A +:100000006F004009130000001300000013000000FF +:100010001300000013000000130000001300000094 +:10002000732E2034631E0E00130FC0FFF32E103406 +:10003000B3FEEE01938E4E0073901E346F00C0012C +:10004000B70E0080337FDE0163180F00F32E1034EB +:10005000938E4E0073901E34B70E0080938E3E0038 +:100060006398CE01373C01F0930C000023209C01E3 +:10007000B70E0080938E7E006394CE0173504030A3 +:10008000B70E0080938EBE006394CE017350403053 +:1000900073002030130E100073000000130E2000B8 +:1000A0009302800073A0023093028000739042306C +:1000B000373C01F0930C100023209C01130000003A +:1000C00013000000130000001300000013000000E4 +:1000D00013000000130000001300000013000000D4 +:1000E000130000001300000013000000130E300086 +:1000F00093020008739042301300000013000000C8 +:1001000013000000130000001300000013000000A3 +:1001100013000000130E4000B7120000938202800B +:100120007390423013000000130000001300000021 +:100130001300000013000000130000001300000073 +:10014000130E5000B70110F0938101F403A20100D7 +:1001500083A241001302F23F23A4410023A65100D1 +:10016000130E60001302000873104230130E70006B +:1001700073005010130E80009301100023A0410063 +:10018000130E900023904100130EA00003A2010063 +:10019000130EB00003920100130EC000130ED00026 +:1001A0008320000083200000130EE0007300202055 +:1001B000130EF000B70010F0938000F603A10000CA +:1001C000130E000123A02000130E10016780000011 +:1001D000000000000000000000000000000000001F +:0400000580000094E3 +:00000001FF diff --git a/src/test/cpp/raw/machineCsr/build/machineCsrCompressed.asm b/src/test/cpp/raw/machineCsr/build/machineCsrCompressed.asm new file mode 100644 index 00000000..df9e96ff --- /dev/null +++ b/src/test/cpp/raw/machineCsr/build/machineCsrCompressed.asm @@ -0,0 +1,139 @@ + +build/machineCsrCompressed.elf: file format elf32-littleriscv + + +Disassembly of section .crt_section: + +80000000 : +80000000: a071 j 8000008c <_start> +80000002: 0001 nop +80000004: 00000013 nop +80000008: 00000013 nop +8000000c: 00000013 nop +80000010: 00000013 nop +80000014: 00000013 nop +80000018: 00000013 nop +8000001c: 00000013 nop + +80000020 : +80000020: 34202e73 csrr t3,mcause +80000024: 000e1c63 bnez t3,8000003c +80000028: ffc00f13 li t5,-4 +8000002c: 34102ef3 csrr t4,mepc +80000030: 01eefeb3 and t4,t4,t5 +80000034: 0e91 addi t4,t4,4 +80000036: 341e9073 csrw mepc,t4 +8000003a: a821 j 80000052 + +8000003c : +8000003c: 80000eb7 lui t4,0x80000 +80000040: 01de7f33 and t5,t3,t4 +80000044: 000f1763 bnez t5,80000052 +80000048: 34102ef3 csrr t4,mepc +8000004c: 0e91 addi t4,t4,4 +8000004e: 341e9073 csrw mepc,t4 + +80000052 : +80000052: 80000eb7 lui t4,0x80000 +80000056: 003e8e93 addi t4,t4,3 # 80000003 <_start+0xffffff77> +8000005a: 01ce9763 bne t4,t3,80000068 +8000005e: f0013c37 lui s8,0xf0013 +80000062: 4c81 li s9,0 +80000064: 019c2023 sw s9,0(s8) # f0013000 <_start+0x70012f74> + +80000068 : +80000068: 80000eb7 lui t4,0x80000 +8000006c: 007e8e93 addi t4,t4,7 # 80000007 <_start+0xffffff7b> +80000070: 01ce9463 bne t4,t3,80000078 +80000074: 30405073 csrwi mie,0 + +80000078 : +80000078: 80000eb7 lui t4,0x80000 +8000007c: 00be8e93 addi t4,t4,11 # 8000000b <_start+0xffffff7f> +80000080: 01ce9463 bne t4,t3,80000088 +80000084: 30405073 csrwi mie,0 + +80000088 : +80000088: 30200073 mret + +8000008c <_start>: +8000008c: 4e05 li t3,1 +8000008e: 00000073 ecall +80000092: 4e09 li t3,2 +80000094: 42a1 li t0,8 +80000096: 3002a073 csrs mstatus,t0 +8000009a: 42a1 li t0,8 +8000009c: 30429073 csrw mie,t0 +800000a0: f0013c37 lui s8,0xf0013 +800000a4: 4c85 li s9,1 +800000a6: 019c2023 sw s9,0(s8) # f0013000 <_start+0x70012f74> +800000aa: 0001 nop +800000ac: 0001 nop +800000ae: 0001 nop +800000b0: 0001 nop +800000b2: 0001 nop +800000b4: 0001 nop +800000b6: 0001 nop +800000b8: 0001 nop +800000ba: 0001 nop +800000bc: 0001 nop +800000be: 0001 nop +800000c0: 0001 nop +800000c2: 4e0d li t3,3 +800000c4: 08000293 li t0,128 +800000c8: 30429073 csrw mie,t0 +800000cc: 0001 nop +800000ce: 0001 nop +800000d0: 0001 nop +800000d2: 0001 nop +800000d4: 0001 nop +800000d6: 0001 nop +800000d8: 0001 nop +800000da: 4e11 li t3,4 +800000dc: 000012b7 lui t0,0x1 +800000e0: 80028293 addi t0,t0,-2048 # 800 +800000e4: 30429073 csrw mie,t0 +800000e8: 0001 nop +800000ea: 0001 nop +800000ec: 0001 nop +800000ee: 0001 nop +800000f0: 0001 nop +800000f2: 0001 nop +800000f4: 0001 nop +800000f6: 4e15 li t3,5 +800000f8: f01001b7 lui gp,0xf0100 +800000fc: f4018193 addi gp,gp,-192 # f00fff40 <_start+0x700ffeb4> +80000100: 0001a203 lw tp,0(gp) +80000104: 0041a283 lw t0,4(gp) +80000108: 3ff20213 addi tp,tp,1023 # 3ff +8000010c: 0041a423 sw tp,8(gp) +80000110: 0051a623 sw t0,12(gp) +80000114: 4e19 li t3,6 +80000116: 08000213 li tp,128 +8000011a: 30421073 csrw mie,tp +8000011e: 4e1d li t3,7 +80000120: 10500073 wfi +80000124: 4e21 li t3,8 +80000126: 4185 li gp,1 +80000128: 0041a023 sw tp,0(gp) +8000012c: 4e25 li t3,9 +8000012e: 00419023 sh tp,0(gp) +80000132: 4e29 li t3,10 +80000134: 0001a203 lw tp,0(gp) +80000138: 4e2d li t3,11 +8000013a: 00019203 lh tp,0(gp) +8000013e: 4e31 li t3,12 +80000140: 4e35 li t3,13 +80000142: 00002083 lw ra,0(zero) # 0 +80000146: 00002083 lw ra,0(zero) # 0 +8000014a: 4e39 li t3,14 +8000014c: 20200073 hret +80000150: 4e3d li t3,15 +80000152: f01000b7 lui ra,0xf0100 +80000156: f6008093 addi ra,ra,-160 # f00fff60 <_start+0x700ffed4> +8000015a: 0000a103 lw sp,0(ra) +8000015e: 4e41 li t3,16 +80000160: 0020a023 sw sp,0(ra) +80000164: 4e45 li t3,17 +80000166: 8082 ret + ... diff --git a/src/test/cpp/raw/machineCsr/build/machineCsrCompressed.hex b/src/test/cpp/raw/machineCsr/build/machineCsrCompressed.hex new file mode 100644 index 00000000..15466729 --- /dev/null +++ b/src/test/cpp/raw/machineCsr/build/machineCsrCompressed.hex @@ -0,0 +1,27 @@ +:0200000480007A +:1000000071A00100130000001300000013000000A5 +:100010001300000013000000130000001300000094 +:10002000732E2034631C0E00130FC0FFF32E103408 +:10003000B3FEEE01910E73901E3421A8B70E00801E +:10004000337FDE0163170F00F32E1034910E73908F +:100050001E34B70E0080938E3E006397CE01373C6E +:1000600001F0814C23209C01B70E0080938E7E000E +:100070006394CE0173504030B70E0080938EBE0063 +:100080006394CE017350403073002030054E7300EE +:100090000000094EA14273A00230A1427390423089 +:1000A000373C01F0854C23209C0101000100010038 +:1000B0000100010001000100010001000100010038 +:1000C00001000D4E930200087390423001000100C0 +:1000D00001000100010001000100114EB7120000F3 +:1000E0009382028073904230010001000100010000 +:1000F000010001000100154EB70110F0938101F4D9 +:1001000003A2010083A241001302F23F23A4410095 +:1001100023A65100194E13020008731042301D4EE1 +:1001200073005010214E854123A04100254E23909D +:100130004100294E03A201002D4E03920100314ED1 +:10014000354E8320000083200000394E73002020AC +:100150003D4EB70010F0938000F603A10000414E21 +:1001600023A02000454E8280000000000000000017 +:10017000000000000000000000000000000000007F +:040000058000008CEB +:00000001FF diff --git a/src/test/cpp/raw/machineCsr/makefile b/src/test/cpp/raw/machineCsr/makefile new file mode 100644 index 00000000..f43d48d7 --- /dev/null +++ b/src/test/cpp/raw/machineCsr/makefile @@ -0,0 +1,10 @@ +ifeq ($(COMPRESSED),yes) + PROJ_NAME=machineCsrCompressed +else + PROJ_NAME=machineCsr +endif + + + + +include ../common/asm.mk \ No newline at end of file diff --git a/src/test/cpp/raw/machineCsr/src/crt.S b/src/test/cpp/raw/machineCsr/src/crt.S new file mode 100644 index 00000000..9d1ee5fd --- /dev/null +++ b/src/test/cpp/raw/machineCsr/src/crt.S @@ -0,0 +1,143 @@ + j _start + +#define writeSoftwareInterrupt(value) \ + li x24, 0xF0013000; \ + li x25, value; \ + sw x25, 0(x24); \ + +.align 5 +.global trap_entry +trap_entry: + csrr x28, mcause + + bnez x28, notICmdAlignementException + li x30, 0xFFFFFFFC + csrr x29, mepc + and x29,x29,x30 + addi x29, x29, 4 + csrw mepc, x29 + j mepcFixed + +notICmdAlignementException: + li x29, 0x80000000 + and x30, x28, x29 + bnez x30, mepcFixed + csrr x29, mepc + addi x29, x29, 4 + csrw mepc, x29 +mepcFixed: + + + li x29, 0x80000003u + bne x29, x28, noSoftwareInterrupt + writeSoftwareInterrupt(0) + +noSoftwareInterrupt: + + li x29, 0x80000007u + bne x29, x28, noTimerInterrupt + csrw mie, 0 +noTimerInterrupt: + + li x29, 0x8000000bu + bne x29, x28, noExernalInterrupt + csrw mie, 0 +noExernalInterrupt: + + mret + + + .text + .globl _start +_start: + li x28, 1 + ecall + + li x28, 2 + li t0, 0x008 + csrs mstatus,t0 + li t0, 0x008 + csrw mie,t0 + writeSoftwareInterrupt(1) + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + + + li x28, 3 + li t0, 0x080 + csrw mie,t0 + nop + nop + nop + nop + nop + nop + nop + + li x28, 4 + li t0, 0x800 + csrw mie,t0 + nop + nop + nop + nop + nop + nop + nop + + li x28, 5 + li x3, 0xF00FFF40 + lw x4, 0(x3) + lw x5, 4(x3) + addi x4, x4, 1023 + sw x4, 8(x3) + sw x5, 12(x3) + li x28, 6 + li x4, 0x080 + csrw mie,x4 + li x28, 7 + wfi + + + li x28, 8 + li x3, 1 + sw x4,0(x3) + li x28, 9 + sh x4,0(x3) + li x28, 10 + lw x4,0(x3) + li x28, 11 + lh x4,0(x3) + li x28, 12 + + + + li x28, 13 + lw x1,0(x0) +#ifdef COMPRESSED +unalignedPcA: + j unalignedPcA+2 +#endif + lw x1,0(x0) + + li x28, 14 + hret + li x28, 15 + + + li x1, 0xF00FFF60 + lw x2, 0(x1) + li x28, 16 + sw x2, 0(x1) + li x28, 17 + jr x1 diff --git a/src/test/cpp/raw/machineCsr/src/ld b/src/test/cpp/raw/machineCsr/src/ld new file mode 100644 index 00000000..93d8de8e --- /dev/null +++ b/src/test/cpp/raw/machineCsr/src/ld @@ -0,0 +1,16 @@ +OUTPUT_ARCH( "riscv" ) + +MEMORY { + onChipRam (W!RX)/*(RX)*/ : ORIGIN = 0x80000000, LENGTH = 128K +} + +SECTIONS +{ + + .crt_section : + { + . = ALIGN(4); + *crt.o(.text) + } > onChipRam + +} diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index b6a33076..6732c0c6 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -1162,9 +1162,11 @@ public: #ifdef EXTERNAL_INTERRUPT case 0xF0011000u: top->externalInterrupt = *data & 1; break; #endif - #ifdef SUPERVISOR case 0xF0012000u: top->externalInterruptS = *data & 1; break; +#endif +#ifdef CSR + case 0xF0013000u: top->softwareInterrupt = *data & 1; break; #endif case 0xF00FFF00u: { cout << mem[0xF00FFF00u]; @@ -1275,6 +1277,7 @@ public: #ifdef CSR top->timerInterrupt = 0; top->externalInterrupt = 1; + top->softwareInterrupt = 0; #endif #ifdef SUPERVISOR top->externalInterruptS = 0; @@ -1364,8 +1367,11 @@ public: #ifdef EXTERNAL_INTERRUPT riscvRef.interrupts |= top->externalInterrupt << 11; #endif +#ifdef CSR + riscvRef.interrupts |= top->softwareInterrupt << 3; +#endif #ifdef SUPERVISOR - riscvRef.interrupts |= top->timerInterruptS << 5; +// riscvRef.interrupts |= top->timerInterruptS << 5; riscvRef.interrupts |= top->externalInterruptS << 9; #endif @@ -3114,11 +3120,11 @@ int main(int argc, char **argv, char **env) { #ifndef COMPRESSED 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).withRiscvRef()->noInstructionReadCheck()->run(10e4);) + redo(REDO,TestX28("../../cpp/raw/machineCsr/build/machineCsr",machineCsrRef, sizeof(machineCsrRef)/4).withRiscvRef()->noInstructionReadCheck()->run(10e4);) #else 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, 14,2, 15,5,16,17,1 }; - redo(REDO,TestX28("machineCsrCompressed",machineCsrRef, sizeof(machineCsrRef)/4).withRiscvRef()->noInstructionReadCheck()->run(10e4);) + redo(REDO,TestX28("../../cpp/raw/machineCsr/build/machineCsrCompressed",machineCsrRef, sizeof(machineCsrRef)/4).withRiscvRef()->noInstructionReadCheck()->run(10e4);) #endif #endif // #ifdef MMU From 7159237104edc6b5e1f2602c72d4e5969adf82b2 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sat, 23 Mar 2019 18:11:26 +0100 Subject: [PATCH 066/951] Fix csrrs/csrrc for xip registers --- .../scala/vexriscv/plugin/CsrPlugin.scala | 25 +- src/test/cpp/raw/deleg/build/deleg.asm | 264 ++++++++++++------ src/test/cpp/raw/deleg/build/deleg.hex | 92 +++--- src/test/cpp/raw/deleg/src/crt.S | 84 +++++- src/test/cpp/regression/main.cpp | 78 ++++-- 5 files changed, 395 insertions(+), 148 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 434db5d2..a1d34da7 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -214,6 +214,7 @@ object CsrPluginConfig{ } case class CsrWrite(that : Data, bitOffset : Int) case class CsrRead(that : Data , bitOffset : Int) +case class CsrReadToWriteOverride(that : Data, bitOffset : Int) //Used for special cases, as MIP where there shadow stuff case class CsrOnWrite(doThat :() => Unit) case class CsrOnRead(doThat : () => Unit) case class CsrMapping() extends CsrInterface{ @@ -221,6 +222,7 @@ case class CsrMapping() extends CsrInterface{ def addMappingAt(address : Int,that : Any) = mapping.getOrElseUpdate(address,new ArrayBuffer[Any]) += that override def r(csrAddress : Int, bitOffset : Int, that : Data): Unit = addMappingAt(csrAddress, CsrRead(that,bitOffset)) override def w(csrAddress : Int, bitOffset : Int, that : Data): Unit = addMappingAt(csrAddress, CsrWrite(that,bitOffset)) + override def r2w(csrAddress : Int, bitOffset : Int, that : Data): Unit = addMappingAt(csrAddress, CsrReadToWriteOverride(that,bitOffset)) override def onWrite(csrAddress: Int)(body: => Unit): Unit = addMappingAt(csrAddress, CsrOnWrite(() => body)) override def onRead(csrAddress: Int)(body: => Unit): Unit = addMappingAt(csrAddress, CsrOnRead(() => {body})) } @@ -236,6 +238,8 @@ trait CsrInterface{ w(csrAddress,bitOffset,that) } + def r2w(csrAddress : Int, bitOffset : Int,that : Data): Unit + def rw(csrAddress : Int, thats : (Int, Data)*) : Unit = for(that <- thats) rw(csrAddress,that._1, that._2) def w(csrAddress : Int, thats : (Int, Data)*) : Unit = for(that <- thats) w(csrAddress,that._1, that._2) def r(csrAddress : Int, thats : (Int, Data)*) : Unit = for(that <- thats) r(csrAddress,that._1, that._2) @@ -324,6 +328,7 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception override def r(csrAddress: Int, bitOffset: Int, that: Data): Unit = csrMapping.r(csrAddress, bitOffset, that) override def w(csrAddress: Int, bitOffset: Int, that: Data): Unit = csrMapping.w(csrAddress, bitOffset, that) + override def r2w(csrAddress: Int, bitOffset: Int, that: Data): Unit = csrMapping.r2w(csrAddress, bitOffset, that) override def onWrite(csrAddress: Int)(body: => Unit): Unit = csrMapping.onWrite(csrAddress)(body) override def onRead(csrAddress: Int)(body: => Unit): Unit = csrMapping.onRead(csrAddress)(body) @@ -531,7 +536,10 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception //Supervisor CSR for(offset <- List(CSR.MSTATUS, CSR.SSTATUS)) READ_WRITE(offset,8 -> sstatus.SPP, 5 -> sstatus.SPIE, 1 -> sstatus.SIE) for(offset <- List(CSR.MIP, CSR.SIP)) { - READ_WRITE(offset, 9 -> sip.SEIP_SOFT, 5 -> sip.STIP, 1 -> sip.SSIP) + READ_WRITE(offset, 5 -> sip.STIP, 1 -> sip.SSIP) + READ_ONLY(offset, 9 -> sip.SEIP_OR) + WRITE_ONLY(offset, 9 -> sip.SEIP_SOFT) + r2w(offset, 9, sip.SEIP_SOFT) } for(offset <- List(CSR.MIE, CSR.SIE)) READ_WRITE(offset, 9 -> sie.SEIE, 5 -> sie.STIE, 1 -> sie.SSIE) @@ -907,9 +915,11 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception // False -> writeSrc, // True -> Mux(input(INSTRUCTION)(12), ~writeSrc, writeSrc) // ) + + val readToWriteData = CombInit(readData) val writeData = if(noCsrAlu) writeSrc else input(INSTRUCTION)(13).mux( False -> writeSrc, - True -> Mux(input(INSTRUCTION)(12), readData & ~writeSrc, readData | writeSrc) + True -> Mux(input(INSTRUCTION)(12), readToWriteData & ~writeSrc, readToWriteData | writeSrc) ) @@ -974,6 +984,17 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception } } + switch(csrAddress) { + for ((address, jobs) <- csrMapping.mapping if jobs.exists(_.isInstanceOf[CsrReadToWriteOverride])) { + is(address) { + for (element <- jobs) element match { + case element: CsrReadToWriteOverride if element.that.getBitsWidth != 0 => readToWriteData(element.bitOffset, element.that.getBitsWidth bits) := element.that.asBits + case _ => + } + } + } + } + illegalAccess setWhen(privilege < csrAddress(9 downto 8).asUInt) illegalAccess clearWhen(!arbitration.isValid || !input(IS_CSR)) }) diff --git a/src/test/cpp/raw/deleg/build/deleg.asm b/src/test/cpp/raw/deleg/build/deleg.asm index d6bf46a0..b1e420da 100644 --- a/src/test/cpp/raw/deleg/build/deleg.asm +++ b/src/test/cpp/raw/deleg/build/deleg.asm @@ -7,14 +7,14 @@ Disassembly of section .crt_section: 80000000 <_start>: 80000000: 00100e93 li t4,1 80000004: 00000097 auipc ra,0x0 -80000008: 50408093 addi ra,ra,1284 # 80000508 +80000008: 68408093 addi ra,ra,1668 # 80000688 8000000c: 30509073 csrw mtvec,ra 80000010: 00000097 auipc ra,0x0 -80000014: 52c08093 addi ra,ra,1324 # 8000053c +80000014: 6ac08093 addi ra,ra,1708 # 800006bc 80000018: 10509073 csrw stvec,ra 8000001c: f00110b7 lui ra,0xf0011 80000020: 00000113 li sp,0 -80000024: 0020a023 sw sp,0(ra) # f0011000 +80000024: 0020a023 sw sp,0(ra) # f0011000 80000028 : 80000028: 00100e13 li t3,1 @@ -33,18 +33,18 @@ Disassembly of section .crt_section: 80000054: 01408093 addi ra,ra,20 # 80000064 80000058: 34109073 csrw mepc,ra 8000005c: 30200073 mret -80000060: 4900006f j 800004f0 +80000060: 6100006f j 80000670 80000064: 00000f17 auipc t5,0x0 80000068: 024f0f13 addi t5,t5,36 # 80000088 8000006c: 00000073 ecall -80000070: 4800006f j 800004f0 +80000070: 6000006f j 80000670 80000074 : 80000074: 00300e13 li t3,3 80000078: 00000f17 auipc t5,0x0 8000007c: 010f0f13 addi t5,t5,16 # 80000088 80000080: 00102083 lw ra,1(zero) # 1 <_start-0x7fffffff> -80000084: 46c0006f j 800004f0 +80000084: 5ec0006f j 80000670 80000088 : 80000088: 00400e13 li t3,4 @@ -58,11 +58,11 @@ Disassembly of section .crt_section: 800000a8: 01408093 addi ra,ra,20 # 800000b8 800000ac: 34109073 csrw mepc,ra 800000b0: 30200073 mret -800000b4: 43c0006f j 800004f0 +800000b4: 5bc0006f j 80000670 800000b8: 00000f17 auipc t5,0x0 800000bc: 010f0f13 addi t5,t5,16 # 800000c8 800000c0: 00102083 lw ra,1(zero) # 1 <_start-0x7fffffff> -800000c4: 42c0006f j 800004f0 +800000c4: 5ac0006f j 80000670 800000c8 : 800000c8: 00500e13 li t3,5 @@ -75,11 +75,11 @@ Disassembly of section .crt_section: 800000e4: 01408093 addi ra,ra,20 # 800000f4 800000e8: 34109073 csrw mepc,ra 800000ec: 30200073 mret -800000f0: 4000006f j 800004f0 +800000f0: 5800006f j 80000670 800000f4: 00000f17 auipc t5,0x0 800000f8: 010f0f13 addi t5,t5,16 # 80000104 800000fc: 00102083 lw ra,1(zero) # 1 <_start-0x7fffffff> -80000100: 3f00006f j 800004f0 +80000100: 5700006f j 80000670 80000104 : 80000104: 00600e13 li t3,6 @@ -91,7 +91,7 @@ Disassembly of section .crt_section: 80000114: 00000f17 auipc t5,0x0 80000118: 010f0f13 addi t5,t5,16 # 80000124 8000011c: 00102083 lw ra,1(zero) # 1 <_start-0x7fffffff> -80000120: 3d00006f j 800004f0 +80000120: 5500006f j 80000670 80000124 : 80000124: 00800e13 li t3,8 @@ -107,9 +107,9 @@ Disassembly of section .crt_section: 8000014c: 01408093 addi ra,ra,20 # 8000015c 80000150: 34109073 csrw mepc,ra 80000154: 30200073 mret -80000158: 3980006f j 800004f0 +80000158: 5180006f j 80000670 8000015c: 00102083 lw ra,1(zero) # 1 <_start-0x7fffffff> -80000160: 3900006f j 800004f0 +80000160: 5100006f j 80000670 80000164 : 80000164: 00900e13 li t3,9 @@ -124,9 +124,9 @@ Disassembly of section .crt_section: 80000188: 01408093 addi ra,ra,20 # 80000198 8000018c: 34109073 csrw mepc,ra 80000190: 30200073 mret -80000194: 35c0006f j 800004f0 +80000194: 4dc0006f j 80000670 80000198: 00102083 lw ra,1(zero) # 1 <_start-0x7fffffff> -8000019c: 3540006f j 800004f0 +8000019c: 4d40006f j 80000670 800001a0 : 800001a0: 00a00e13 li t3,10 @@ -134,7 +134,7 @@ Disassembly of section .crt_section: 800001a8: 03cf0f13 addi t5,t5,60 # 800001e0 800001ac: f00110b7 lui ra,0xf0011 800001b0: 00000113 li sp,0 -800001b4: 0020a023 sw sp,0(ra) # f0011000 +800001b4: 0020a023 sw sp,0(ra) # f0011000 800001b8: 00800093 li ra,8 800001bc: 30009073 csrw mstatus,ra 800001c0: 000010b7 lui ra,0x1 @@ -142,9 +142,9 @@ Disassembly of section .crt_section: 800001c8: 30409073 csrw mie,ra 800001cc: f00110b7 lui ra,0xf0011 800001d0: 00100113 li sp,1 -800001d4: 0020a023 sw sp,0(ra) # f0011000 +800001d4: 0020a023 sw sp,0(ra) # f0011000 800001d8: 10500073 wfi -800001dc: 3140006f j 800004f0 +800001dc: 4940006f j 80000670 800001e0 : 800001e0: 00b00e13 li t3,11 @@ -152,7 +152,7 @@ Disassembly of section .crt_section: 800001e8: 068f0f13 addi t5,t5,104 # 8000024c 800001ec: f00110b7 lui ra,0xf0011 800001f0: 00000113 li sp,0 -800001f4: 0020a023 sw sp,0(ra) # f0011000 +800001f4: 0020a023 sw sp,0(ra) # f0011000 800001f8: 00800093 li ra,8 800001fc: 30009073 csrw mstatus,ra 80000200: 000010b7 lui ra,0x1 @@ -168,12 +168,12 @@ Disassembly of section .crt_section: 80000228: 01408093 addi ra,ra,20 # 80000238 8000022c: 34109073 csrw mepc,ra 80000230: 30200073 mret -80000234: 2bc0006f j 800004f0 +80000234: 43c0006f j 80000670 80000238: f00110b7 lui ra,0xf0011 8000023c: 00100113 li sp,1 -80000240: 0020a023 sw sp,0(ra) # f0011000 +80000240: 0020a023 sw sp,0(ra) # f0011000 80000244: 10500073 wfi -80000248: 2a80006f j 800004f0 +80000248: 4280006f j 80000670 8000024c : 8000024c: 00c00e13 li t3,12 @@ -181,7 +181,7 @@ Disassembly of section .crt_section: 80000254: 064f0f13 addi t5,t5,100 # 800002b4 80000258: f00110b7 lui ra,0xf0011 8000025c: 00000113 li sp,0 -80000260: 0020a023 sw sp,0(ra) # f0011000 +80000260: 0020a023 sw sp,0(ra) # f0011000 80000264: 00800093 li ra,8 80000268: 30009073 csrw mstatus,ra 8000026c: 000010b7 lui ra,0x1 @@ -196,12 +196,12 @@ Disassembly of section .crt_section: 80000290: 01408093 addi ra,ra,20 # 800002a0 80000294: 34109073 csrw mepc,ra 80000298: 30200073 mret -8000029c: 2540006f j 800004f0 +8000029c: 3d40006f j 80000670 800002a0: f00110b7 lui ra,0xf0011 800002a4: 00100113 li sp,1 -800002a8: 0020a023 sw sp,0(ra) # f0011000 +800002a8: 0020a023 sw sp,0(ra) # f0011000 800002ac: 10500073 wfi -800002b0: 2400006f j 800004f0 +800002b0: 3c00006f j 80000670 800002b4 : 800002b4: 00200093 li ra,2 @@ -211,7 +211,7 @@ Disassembly of section .crt_section: 800002c4: 040f0f13 addi t5,t5,64 # 80000300 800002c8: f00120b7 lui ra,0xf0012 800002cc: 00000113 li sp,0 -800002d0: 0020a023 sw sp,0(ra) # f0012000 +800002d0: 0020a023 sw sp,0(ra) # f0012000 800002d4: 00200093 li ra,2 800002d8: 30009073 csrw mstatus,ra 800002dc: 20000093 li ra,512 @@ -219,7 +219,7 @@ Disassembly of section .crt_section: 800002e4: 00000e93 li t4,0 800002e8: f00120b7 lui ra,0xf0012 800002ec: 00100113 li sp,1 -800002f0: 0020a023 sw sp,0(ra) # f0012000 +800002f0: 0020a023 sw sp,0(ra) # f0012000 800002f4: 06400093 li ra,100 800002f8: fff08093 addi ra,ra,-1 800002fc: fe104ee3 bgtz ra,800002f8 @@ -230,7 +230,7 @@ Disassembly of section .crt_section: 80000308: 068f0f13 addi t5,t5,104 # 8000036c 8000030c: f00120b7 lui ra,0xf0012 80000310: 00000113 li sp,0 -80000314: 0020a023 sw sp,0(ra) # f0012000 +80000314: 0020a023 sw sp,0(ra) # f0012000 80000318: 00200093 li ra,2 8000031c: 30009073 csrw mstatus,ra 80000320: 20000093 li ra,512 @@ -245,13 +245,13 @@ Disassembly of section .crt_section: 80000344: 01408093 addi ra,ra,20 # 80000354 80000348: 34109073 csrw mepc,ra 8000034c: 30200073 mret -80000350: 1a00006f j 800004f0 +80000350: 3200006f j 80000670 80000354: 00100e93 li t4,1 80000358: f00120b7 lui ra,0xf0012 8000035c: 00100113 li sp,1 -80000360: 0020a023 sw sp,0(ra) # f0012000 +80000360: 0020a023 sw sp,0(ra) # f0012000 80000364: 10500073 wfi -80000368: 1880006f j 800004f0 +80000368: 3080006f j 80000670 8000036c : 8000036c: 01000e13 li t3,16 @@ -259,7 +259,7 @@ Disassembly of section .crt_section: 80000374: 060f0f13 addi t5,t5,96 # 800003d0 80000378: f00120b7 lui ra,0xf0012 8000037c: 00000113 li sp,0 -80000380: 0020a023 sw sp,0(ra) # f0012000 +80000380: 0020a023 sw sp,0(ra) # f0012000 80000384: 00200093 li ra,2 80000388: 30009073 csrw mstatus,ra 8000038c: 20000093 li ra,512 @@ -273,12 +273,12 @@ Disassembly of section .crt_section: 800003ac: 01408093 addi ra,ra,20 # 800003bc 800003b0: 34109073 csrw mepc,ra 800003b4: 30200073 mret -800003b8: 1380006f j 800004f0 +800003b8: 2b80006f j 80000670 800003bc: f00120b7 lui ra,0xf0012 800003c0: 00100113 li sp,1 -800003c4: 0020a023 sw sp,0(ra) # f0012000 +800003c4: 0020a023 sw sp,0(ra) # f0012000 800003c8: 10500073 wfi -800003cc: 1240006f j 800004f0 +800003cc: 2a40006f j 80000670 800003d0 : 800003d0: 01100e13 li t3,17 @@ -288,7 +288,7 @@ Disassembly of section .crt_section: 800003e0: 040f0f13 addi t5,t5,64 # 8000041c 800003e4: f00120b7 lui ra,0xf0012 800003e8: 00000113 li sp,0 -800003ec: 0020a023 sw sp,0(ra) # f0012000 +800003ec: 0020a023 sw sp,0(ra) # f0012000 800003f0: 00200093 li ra,2 800003f4: 30009073 csrw mstatus,ra 800003f8: 20000093 li ra,512 @@ -296,7 +296,7 @@ Disassembly of section .crt_section: 80000400: 00000e93 li t4,0 80000404: f00120b7 lui ra,0xf0012 80000408: 00100113 li sp,1 -8000040c: 0020a023 sw sp,0(ra) # f0012000 +8000040c: 0020a023 sw sp,0(ra) # f0012000 80000410: 06400093 li ra,100 80000414: fff08093 addi ra,ra,-1 80000418: fe104ee3 bgtz ra,80000414 @@ -307,7 +307,7 @@ Disassembly of section .crt_section: 80000424: 068f0f13 addi t5,t5,104 # 80000488 80000428: f00120b7 lui ra,0xf0012 8000042c: 00000113 li sp,0 -80000430: 0020a023 sw sp,0(ra) # f0012000 +80000430: 0020a023 sw sp,0(ra) # f0012000 80000434: 00200093 li ra,2 80000438: 30009073 csrw mstatus,ra 8000043c: 20000093 li ra,512 @@ -322,13 +322,13 @@ Disassembly of section .crt_section: 80000460: 01408093 addi ra,ra,20 # 80000470 80000464: 34109073 csrw mepc,ra 80000468: 30200073 mret -8000046c: 0840006f j 800004f0 +8000046c: 2040006f j 80000670 80000470: 00100e93 li t4,1 80000474: f00120b7 lui ra,0xf0012 80000478: 00100113 li sp,1 -8000047c: 0020a023 sw sp,0(ra) # f0012000 +8000047c: 0020a023 sw sp,0(ra) # f0012000 80000480: 10500073 wfi -80000484: 06c0006f j 800004f0 +80000484: 1ec0006f j 80000670 80000488 : 80000488: 01300e13 li t3,19 @@ -336,7 +336,7 @@ Disassembly of section .crt_section: 80000490: 060f0f13 addi t5,t5,96 # 800004ec 80000494: f00120b7 lui ra,0xf0012 80000498: 00000113 li sp,0 -8000049c: 0020a023 sw sp,0(ra) # f0012000 +8000049c: 0020a023 sw sp,0(ra) # f0012000 800004a0: 00200093 li ra,2 800004a4: 30009073 csrw mstatus,ra 800004a8: 20000093 li ra,512 @@ -350,50 +350,152 @@ Disassembly of section .crt_section: 800004c8: 01408093 addi ra,ra,20 # 800004d8 800004cc: 34109073 csrw mepc,ra 800004d0: 30200073 mret -800004d4: 01c0006f j 800004f0 +800004d4: 19c0006f j 80000670 800004d8: f00120b7 lui ra,0xf0012 800004dc: 00100113 li sp,1 -800004e0: 0020a023 sw sp,0(ra) # f0012000 +800004e0: 0020a023 sw sp,0(ra) # f0012000 800004e4: 10500073 wfi -800004e8: 0080006f j 800004f0 +800004e8: 1880006f j 80000670 800004ec : -800004ec: 0100006f j 800004fc +800004ec: f00120b7 lui ra,0xf0012 +800004f0: 00000113 li sp,0 +800004f4: 0020a023 sw sp,0(ra) # f0012000 +800004f8: 01400e13 li t3,20 +800004fc: 00000f17 auipc t5,0x0 +80000500: 030f0f13 addi t5,t5,48 # 8000052c +80000504: 00200093 li ra,2 +80000508: 30009073 csrw mstatus,ra +8000050c: 20000093 li ra,512 +80000510: 30409073 csrw mie,ra +80000514: 00000e93 li t4,0 +80000518: 20000093 li ra,512 +8000051c: 1440a073 csrs sip,ra +80000520: 06400093 li ra,100 +80000524: fff08093 addi ra,ra,-1 +80000528: fe104ee3 bgtz ra,80000524 -800004f0 : -800004f0: f0100137 lui sp,0xf0100 -800004f4: f2410113 addi sp,sp,-220 # f00fff24 -800004f8: 01c12023 sw t3,0(sp) +8000052c : +8000052c: 01500e13 li t3,21 +80000530: 00000f17 auipc t5,0x0 +80000534: 060f0f13 addi t5,t5,96 # 80000590 +80000538: 20000093 li ra,512 +8000053c: 1440b073 csrc sip,ra +80000540: 00200093 li ra,2 +80000544: 30009073 csrw mstatus,ra +80000548: 20000093 li ra,512 +8000054c: 30409073 csrw mie,ra +80000550: 000020b7 lui ra,0x2 +80000554: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800> +80000558: 00001137 lui sp,0x1 +8000055c: 80010113 addi sp,sp,-2048 # 800 <_start-0x7ffff800> +80000560: 3000b073 csrc mstatus,ra +80000564: 30012073 csrs mstatus,sp +80000568: 00000097 auipc ra,0x0 +8000056c: 01408093 addi ra,ra,20 # 8000057c +80000570: 34109073 csrw mepc,ra +80000574: 30200073 mret +80000578: 0f80006f j 80000670 +8000057c: 00100e93 li t4,1 +80000580: 20000093 li ra,512 +80000584: 1440a073 csrs sip,ra +80000588: 10500073 wfi +8000058c: 0e40006f j 80000670 -800004fc : -800004fc: f0100137 lui sp,0xf0100 -80000500: f2010113 addi sp,sp,-224 # f00fff20 -80000504: 00012023 sw zero,0(sp) +80000590 : +80000590: 01600e13 li t3,22 +80000594: 00000f17 auipc t5,0x0 +80000598: 058f0f13 addi t5,t5,88 # 800005ec +8000059c: 20000093 li ra,512 +800005a0: 1440b073 csrc sip,ra +800005a4: 00200093 li ra,2 +800005a8: 30009073 csrw mstatus,ra +800005ac: 20000093 li ra,512 +800005b0: 30409073 csrw mie,ra +800005b4: 20000093 li ra,512 +800005b8: 1440a073 csrs sip,ra +800005bc: 000020b7 lui ra,0x2 +800005c0: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800> +800005c4: 00000113 li sp,0 +800005c8: 3000b073 csrc mstatus,ra +800005cc: 30012073 csrs mstatus,sp +800005d0: 00000097 auipc ra,0x0 +800005d4: 01408093 addi ra,ra,20 # 800005e4 +800005d8: 34109073 csrw mepc,ra +800005dc: 30200073 mret +800005e0: 0900006f j 80000670 +800005e4: 10500073 wfi +800005e8: 0880006f j 80000670 -80000508 : -80000508: fe0e84e3 beqz t4,800004f0 -8000050c: 342020f3 csrr ra,mcause -80000510: 341020f3 csrr ra,mepc -80000514: 300020f3 csrr ra,mstatus -80000518: 08000093 li ra,128 -8000051c: 3000b073 csrc mstatus,ra -80000520: 00200093 li ra,2 -80000524: fc1e8ce3 beq t4,ra,800004fc -80000528: 000020b7 lui ra,0x2 -8000052c: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800> -80000530: 3000a073 csrs mstatus,ra -80000534: 341f1073 csrw mepc,t5 -80000538: 30200073 mret +800005ec : +800005ec: 01700e13 li t3,23 +800005f0: 00000e93 li t4,0 +800005f4: f00120b7 lui ra,0xf0012 +800005f8: 00000113 li sp,0 +800005fc: 0020a023 sw sp,0(ra) # f0012000 +80000600: 20000093 li ra,512 +80000604: 1440b073 csrc sip,ra +80000608: 344021f3 csrr gp,mip +8000060c: f00120b7 lui ra,0xf0012 +80000610: 00100113 li sp,1 +80000614: 0020a023 sw sp,0(ra) # f0012000 +80000618: 20000093 li ra,512 +8000061c: 1440b073 csrc sip,ra +80000620: 344021f3 csrr gp,mip +80000624: f00120b7 lui ra,0xf0012 +80000628: 00000113 li sp,0 +8000062c: 0020a023 sw sp,0(ra) # f0012000 +80000630: 20000093 li ra,512 +80000634: 1440b073 csrc sip,ra +80000638: 344021f3 csrr gp,mip +8000063c: f00120b7 lui ra,0xf0012 +80000640: 00000113 li sp,0 +80000644: 0020a023 sw sp,0(ra) # f0012000 +80000648: 20000093 li ra,512 +8000064c: 1440a073 csrs sip,ra +80000650: 344021f3 csrr gp,mip +80000654: f00120b7 lui ra,0xf0012 +80000658: 00100113 li sp,1 +8000065c: 0020a023 sw sp,0(ra) # f0012000 +80000660: 20000093 li ra,512 +80000664: 1440a073 csrs sip,ra +80000668: 344021f3 csrr gp,mip +8000066c: 0100006f j 8000067c -8000053c : -8000053c: fa0e8ae3 beqz t4,800004f0 -80000540: 142020f3 csrr ra,scause -80000544: 141020f3 csrr ra,sepc -80000548: 100020f3 csrr ra,sstatus -8000054c: 00000073 ecall -80000550: 00000013 nop -80000554: 00000013 nop -80000558: 00000013 nop -8000055c: 00000013 nop -80000560: 00000013 nop -80000564: 00000013 nop +80000670 : +80000670: f0100137 lui sp,0xf0100 +80000674: f2410113 addi sp,sp,-220 # f00fff24 +80000678: 01c12023 sw t3,0(sp) + +8000067c : +8000067c: f0100137 lui sp,0xf0100 +80000680: f2010113 addi sp,sp,-224 # f00fff20 +80000684: 00012023 sw zero,0(sp) + +80000688 : +80000688: fe0e84e3 beqz t4,80000670 +8000068c: 342020f3 csrr ra,mcause +80000690: 341020f3 csrr ra,mepc +80000694: 300020f3 csrr ra,mstatus +80000698: 08000093 li ra,128 +8000069c: 3000b073 csrc mstatus,ra +800006a0: 00200093 li ra,2 +800006a4: fc1e8ce3 beq t4,ra,8000067c +800006a8: 000020b7 lui ra,0x2 +800006ac: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800> +800006b0: 3000a073 csrs mstatus,ra +800006b4: 341f1073 csrw mepc,t5 +800006b8: 30200073 mret + +800006bc : +800006bc: fa0e8ae3 beqz t4,80000670 +800006c0: 142020f3 csrr ra,scause +800006c4: 141020f3 csrr ra,sepc +800006c8: 100020f3 csrr ra,sstatus +800006cc: 00000073 ecall +800006d0: 00000013 nop +800006d4: 00000013 nop +800006d8: 00000013 nop +800006dc: 00000013 nop +800006e0: 00000013 nop +800006e4: 00000013 nop diff --git a/src/test/cpp/raw/deleg/build/deleg.hex b/src/test/cpp/raw/deleg/build/deleg.hex index 10d04288..3ff7ecc4 100644 --- a/src/test/cpp/raw/deleg/build/deleg.hex +++ b/src/test/cpp/raw/deleg/build/deleg.hex @@ -1,48 +1,48 @@ :0200000480007A -:10000000930E100097000000938040507390503082 -:10001000970000009380C05273905010B71001F009 +:10000000930E10009700000093804068739050306A +:10001000970000009380C06A73905010B71001F0F1 :100020001301000023A02000130E1000170F000082 :10003000130FCF0073000000130E2000B720000044 :10004000938000801301000073B0003073200130F2 :1000500097000000938040017390103473002030AB -:100060006F000049170F0000130F4F0273000000CC -:100070006F000048130E3000170F0000130F0F0120 -:10008000832010006F00C046130E4000B720000010 +:100060006F000061170F0000130F4F0273000000B4 +:100070006F000060130E3000170F0000130F0F0108 +:10008000832010006F00C05E130E4000B7200000F8 :1000900093800080371100001301018073B000309D :1000A000732001309700000093804001739010345A -:1000B000730020306F00C043170F0000130F0F01B3 -:1000C000832010006F00C042130E5000B7200000C4 +:1000B000730020306F00C05B170F0000130F0F019B +:1000C000832010006F00C05A130E5000B7200000AC :1000D000938000801301000073B000307320013062 :1000E000970000009380400173901034730020301B -:1000F0006F000040170F0000130F0F018320100046 -:100100006F00003F130E60009300000173902030D9 +:1000F0006F000058170F0000130F0F01832010002E +:100100006F000057130E60009300000173902030C1 :10011000130E7000170F0000130F0F018320100043 -:100120006F00003D130E8000170F0000130FCF0368 +:100120006F000055130E8000170F0000130FCF0350 :10013000B720000093800080371100001301018078 :1001400073B00030732001309700000093804001AD -:1001500073901034730020306F00803983201000BA -:100160006F000039130E9000170F0000130F8F035C +:1001500073901034730020306F00805183201000A2 +:100160006F000051130E9000170F0000130F8F0344 :10017000B7200000938000801301000073B00030AE :100180007320013097000000938040017390103479 -:10019000730020306F00C035832010006F004035A1 +:10019000730020306F00C04D832010006F00404D71 :1001A000130EA000170F0000130FCF03B71001F0BC :1001B0001301000023A02000930080007390003002 :1001C000B71000009380008073904030B71001F0AA -:1001D0001301100023A02000730050106F00403165 +:1001D0001301100023A02000730050106F0040494D :1001E000130EB000170F0000130F8F06B71001F0A9 :1001F0001301000023A020009300800073900030C2 :10020000B71000009380008073904030B72000004A :1002100093800080371100001301018073B000301B :1002200073200130970000009380400173901034D8 -:10023000730020306F00C02BB71001F013011000C5 -:1002400023A02000730050106F00802A130EC000FE +:10023000730020306F00C043B71001F013011000AD +:1002400023A02000730050106F008042130EC000E6 :10025000170F0000130F4F06B71001F01301000035 :1002600023A020009300800073900030B71000009E :100270009380008073904030B7200000938000800E :100280001301000073B000307320013097000000AC -:100290009380400173901034730020306F0040252C +:100290009380400173901034730020306F00403D14 :1002A000B71001F01301100023A0200073005010BC -:1002B0006F0000249300200073900010130EE000E4 +:1002B0006F00003C9300200073900010130EE000CC :1002C000170F0000130F0F04B72001F013010000F7 :1002D00023A02000930020007390003093000020A2 :1002E00073904030930E0000B72001F0130110000E @@ -52,14 +52,14 @@ :100320009300002073904030B7200000938000803D :10033000371100001301018073B0003073200130C9 :1003400097000000938040017390103473002030B8 -:100350006F00001A930E1000B72001F01301100077 -:1003600023A02000730050106F008018130E0001AE +:100350006F000032930E1000B72001F0130110005F +:1003600023A02000730050106F008030130E000196 :10037000170F0000130F0F06B72001F01301000044 :1003800023A02000930020007390003093000020F1 :1003900073904030B720000093800080130100006C :1003A00073B000307320013097000000938040014B -:1003B00073901034730020306F008013B72001F069 -:1003C0001301100023A02000730050106F00401292 +:1003B00073901034730020306F00802BB72001F051 +:1003C0001301100023A02000730050106F00402A7A :1003D000130E10019300002073903030170F0000AF :1003E000130F0F04B72001F01301000023A0200019 :1003F00093002000739000309300002073904030F1 @@ -69,22 +69,46 @@ :1004300023A0200093002000739000309300002040 :1004400073904030B7200000938000803711000087 :100450001301018073B00030732001309700000059 -:100460009380400173901034730020306F00400877 +:100460009380400173901034730020306F0040205F :10047000930E1000B72001F01301100023A02000FC -:10048000730050106F00C006130E3001170F0000EC +:10048000730050106F00C01E130E3001170F0000D4 :10049000130F0F06B72001F01301000023A0200066 :1004A0009300200073900030930000207390403040 :1004B000B7200000938000801301000073B000306B :1004C0007320013097000000938040017390103436 -:1004D000730020306F00C001B72001F0130110003D -:1004E00023A02000730050106F0080006F000001F7 -:1004F000370110F0130141F22320C101370110F040 -:10050000130101F223200100E3840EFEF3202034C6 -:10051000F3201034F32000309300000873B0003053 -:1005200093002000E38C1EFCB72000009380008025 -:1005300073A0003073101F3473002030E38A0EFA6A -:10054000F3202014F3201014F32000107300000097 -:10055000130000001300000013000000130000004F -:0805600013000000130000006D +:1004D000730020306F00C019B72001F01301100025 +:1004E00023A02000730050106F008018B72001F087 +:1004F0001301000023A02000130E4001170F00007D +:10050000130F0F039300200073900030930000201E +:1005100073904030930E00009300002073A04014AD +:10052000930040069380F0FFE34E10FE130E50013F +:10053000170F0000130F0F069300002073B0401434 +:10054000930020007390003093000020739040309F +:10055000B720000093800080371100001301018054 +:1005600073B0003073200130970000009380400189 +:1005700073901034730020306F00800F930E1000C2 +:100580009300002073A04014730050106F00400EC1 +:10059000130E6001170F0000130F8F05930000204A +:1005A00073B040149300200073900030930000203B +:1005B000739040309300002073A04014B7200000D7 +:1005C000938000801301000073B00030732001306D +:1005D0009700000093804001739010347300203026 +:1005E0006F000009730050106F008008130E700137 +:1005F000930E0000B72001F01301000023A020009B +:100600009300002073B04014F3214034B72001F070 +:100610001301100023A020009300002073B04014A9 +:10062000F3214034B72001F01301000023A0200083 +:100630009300002073B04014F3214034B72001F040 +:100640001301000023A020009300002073A0401499 +:10065000F3214034B72001F01301100023A0200043 +:100660009300002073A04014F32140346F00000178 +:10067000370110F0130141F22320C101370110F0BE +:10068000130101F223200100E3840EFEF320203445 +:10069000F3201034F32000309300000873B00030D2 +:1006A00093002000E38C1EFCB720000093800080A4 +:1006B00073A0003073101F3473002030E38A0EFAE9 +:1006C000F3202014F3201014F32000107300000016 +:1006D00013000000130000001300000013000000CE +:0806E0001300000013000000EC :040000058000000077 :00000001FF diff --git a/src/test/cpp/raw/deleg/src/crt.S b/src/test/cpp/raw/deleg/src/crt.S index ad6a323a..38ff7e2c 100644 --- a/src/test/cpp/raw/deleg/src/crt.S +++ b/src/test/cpp/raw/deleg/src/crt.S @@ -229,7 +229,89 @@ test19: //U external interrupt S with deleg j fail -test20: + + + +test20:// M external interrupt S by software with deleg + externalInterruptS(0) + li TEST_ID, 20 + la TRAP_RET, test21 + li x1, MSTATUS_SIE + csrw mstatus, x1 + li x1, 1 << 9 + csrw mie, x1 + li TRAP_OK, 0 + li x1, 1 << 9 + csrs sip, x1 + delay() + +test21: //S external interrupt S by software with deleg + li TEST_ID, 21 + la TRAP_RET, test22 + li x1, 1 << 9 + csrc sip, x1 + li x1, SSTATUS_SIE + csrw mstatus, x1 + li x1, 1 << 9 + csrw mie, x1 + setPriv(1) + li TRAP_OK, 1 + li x1, 1 << 9 + csrs sip, x1 + wfi + j fail + +test22: //U external interrupt S by software with deleg + li TEST_ID, 22 + la TRAP_RET, test23 + li x1, 1 << 9 + csrc sip, x1 + li x1, SSTATUS_SIE + csrw mstatus, x1 + li x1, 1 << 9 + csrw mie, x1 + li x1, 1 << 9 + csrs sip, x1 + setPriv(0) + wfi + j fail + + + +test23: //Test software and hardware setting inettrupt + li TEST_ID, 23 + li TRAP_OK, 0 + externalInterruptS(0) + li x1, 1 << 9 + csrc sip, x1 + csrr x3, mip + + + externalInterruptS(1) + li x1, 1 << 9 + csrc sip, x1 + csrr x3, mip + + + externalInterruptS(0) + li x1, 1 << 9 + csrc sip, x1 + csrr x3, mip + + + externalInterruptS(0) + li x1, 1 << 9 + csrs sip, x1 + csrr x3, mip + + + externalInterruptS(1) + li x1, 1 << 9 + csrs sip, x1 + csrr x3, mip + + + j pass fail: diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 6732c0c6..4f4b63d3 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -221,7 +221,6 @@ public: uint32_t medeleg; uint32_t mideleg; - uint32_t interrupts; union status { uint32_t raw; @@ -244,7 +243,10 @@ public: }__attribute__((packed)) status; - union mip { + + uint32_t ipInput; + uint32_t ipSoft; + union IpOr { uint32_t raw; struct { uint32_t _1a : 1; @@ -260,8 +262,13 @@ public: uint32_t _3b : 1; uint32_t meip : 1; }; - }__attribute__((packed)) ip; + }__attribute__((packed)); + IpOr getIp(){ + IpOr ret; + ret.raw = ipSoft | ipInput; + return ret; + } union mie { uint32_t raw; @@ -346,7 +353,6 @@ public: regs[i] = 0; status.raw = 0; - ip.raw = 0; ie.raw = 0; mtvec.raw = 0x80000020; mcause.raw = 0; @@ -360,7 +366,8 @@ public: medeleg = 0; mideleg = 0; satp.mode = 0; - interrupts = 0; + ipSoft = 0; + ipInput = 0; } virtual void rfWrite(int32_t address, int32_t data) { @@ -479,7 +486,7 @@ public: if(((csr >> 8) & 0x3) > privilege) return true; switch(csr){ case MSTATUS: *value = status.raw; break; - case MIP: *value = ip.raw; break; + case MIP: *value = getIp().raw; break; case MIE: *value = ie.raw; break; case MTVEC: *value = mtvec.raw; break; case MCAUSE: *value = mcause.raw; break; @@ -491,7 +498,7 @@ public: case MIDELEG: *value = mideleg; break; case SSTATUS: *value = status.raw & 0xC0133; break; - case SIP: *value = ip.raw & 0x333; break; + case SIP: *value = getIp().raw & 0x333; break; case SIE: *value = ie.raw & 0x333; break; case STVEC: *value = stvec.raw; break; case SCAUSE: *value = scause.raw; break; @@ -504,12 +511,21 @@ public: return false; } + virtual uint32_t csrReadToWriteOverride(int32_t csr, uint32_t value){ + if(((csr >> 8) & 0x3) > privilege) return true; + switch(csr){ + case MIP: return ipSoft; break; + case SIP: return ipSoft & 0x333; break; + }; + return value; + } + #define maskedWrite(dst, src, mask) dst=(dst & ~mask)|(src & mask); virtual bool csrWrite(int32_t csr, uint32_t value){ if(((csr >> 8) & 0x3) > privilege) return true; switch(csr){ case MSTATUS: status.raw = value; break; - case MIP: ip.raw = value; break; + case MIP: ipSoft = value; break; case MIE: ie.raw = value; break; case MTVEC: mtvec.raw = value; break; case MCAUSE: mcause.raw = value; break; @@ -521,7 +537,7 @@ public: case MIDELEG: mideleg = value; break; case SSTATUS: maskedWrite(status.raw, value,0xC0133); break; - case SIP: maskedWrite(ip.raw, value,0x333); break; + case SIP: maskedWrite(ipSoft, value,0x333); break; case SIE: maskedWrite(ie.raw, value,0x333); break; case STVEC: stvec.raw = value; break; case SCAUSE: scause.raw = value; break; @@ -563,9 +579,9 @@ public: uint32_t mEnabled = status.mie && privilege == 3 || privilege < 3; uint32_t sEnabled = status.sie && privilege == 1 || privilege < 1; - uint32_t masked = interrupts & ~mideleg & -mEnabled & ie.raw; + uint32_t masked = getIp().raw & ~mideleg & -mEnabled & ie.raw; if (masked == 0) - masked = interrupts & mideleg & -sEnabled & ie.raw & 0x333; + masked = getIp().raw & mideleg & -sEnabled & ie.raw & 0x333; if (masked) { if (masked & (MIP_MEIP | MIP_SEIP)) @@ -803,7 +819,7 @@ public: uint32_t csrAddress = i32_csr; uint32_t old; if(csrRead(i32_csr, &old)) { ilegalInstruction();return; } - if(write) if(csrWrite(i32_csr, (old & ~clear) | set)) { ilegalInstruction();return; } + if(write) if(csrWrite(i32_csr, (csrReadToWriteOverride(i32_csr, old) & ~clear) | set)) { ilegalInstruction();return; } rfWrite(rd32, old); pcWrite(pc + 4); } @@ -1360,25 +1376,27 @@ public: top->eval(); #ifdef CSR - riscvRef.interrupts = 0; -#ifdef TIMER_INTERRUPT - riscvRef.interrupts |= top->timerInterrupt << 7; -#endif -#ifdef EXTERNAL_INTERRUPT - riscvRef.interrupts |= top->externalInterrupt << 11; -#endif -#ifdef CSR - riscvRef.interrupts |= top->softwareInterrupt << 3; -#endif -#ifdef SUPERVISOR -// riscvRef.interrupts |= top->timerInterruptS << 5; - riscvRef.interrupts |= top->externalInterruptS << 9; -#endif + if(riscvRefEnable) { + riscvRef.ipInput = 0; + #ifdef TIMER_INTERRUPT + riscvRef.ipInput |= top->timerInterrupt << 7; + #endif + #ifdef EXTERNAL_INTERRUPT + riscvRef.ipInput |= top->externalInterrupt << 11; + #endif + #ifdef CSR + riscvRef.ipInput |= top->softwareInterrupt << 3; + #endif + #ifdef SUPERVISOR + // riscvRef.ipInput |= top->timerInterruptS << 5; + riscvRef.ipInput |= top->externalInterruptS << 9; + #endif - riscvRef.liveness(top->VexRiscv->execute_CsrPlugin_inWfi); - if(top->VexRiscv->CsrPlugin_interruptJump){ - if(riscvRefEnable) riscvRef.trap(true, top->VexRiscv->CsrPlugin_interruptCode); - } + riscvRef.liveness(top->VexRiscv->execute_CsrPlugin_inWfi); + if(top->VexRiscv->CsrPlugin_interruptJump){ + if(riscvRefEnable) riscvRef.trap(true, top->VexRiscv->CsrPlugin_interruptCode); + } + } #endif if(top->VexRiscv->writeBack_arbitration_isFiring){ if(riscvRefEnable) { From 0656a49332f87f06fdd2d27f5a22ba49c83b6989 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sat, 23 Mar 2019 20:12:36 +0100 Subject: [PATCH 067/951] Make xtval more compliant --- .../scala/vexriscv/plugin/CsrPlugin.scala | 2 +- .../vexriscv/plugin/DecoderSimplePlugin.scala | 2 +- src/test/cpp/raw/deleg/build/deleg.asm | 92 ++++++++++--------- src/test/cpp/raw/deleg/build/deleg.hex | 14 +-- src/test/cpp/raw/deleg/src/crt.S | 2 + src/test/cpp/raw/mmu/build/mmu.asm | 10 +- src/test/cpp/raw/mmu/build/mmu.hex | 6 +- src/test/cpp/raw/mmu/src/crt.S | 1 + src/test/cpp/regression/main.cpp | 20 ++-- 9 files changed, 77 insertions(+), 72 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index a1d34da7..c3e254f5 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -864,7 +864,7 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception if(selfException != null) { selfException.valid := False selfException.code.assignDontCare() - selfException.badAddr.assignDontCare() + selfException.badAddr := 0 if(catchIllegalAccess) when(illegalAccess || illegalInstruction){ selfException.valid := True selfException.code := 2 diff --git a/src/main/scala/vexriscv/plugin/DecoderSimplePlugin.scala b/src/main/scala/vexriscv/plugin/DecoderSimplePlugin.scala index e9c4633f..c7135579 100644 --- a/src/main/scala/vexriscv/plugin/DecoderSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/DecoderSimplePlugin.scala @@ -160,7 +160,7 @@ class DecoderSimplePlugin(catchIllegalInstruction : Boolean = false, forceLegalI if(catchIllegalInstruction){ decodeExceptionPort.valid := arbitration.isValid && input(INSTRUCTION_READY) && !input(LEGAL_INSTRUCTION) // ?? HalitIt to alow decoder stage to wait valid data from 2 stages cache cache ?? decodeExceptionPort.code := 2 - decodeExceptionPort.badAddr.assignDontCare() + decodeExceptionPort.badAddr := input(INSTRUCTION).asUInt } } diff --git a/src/test/cpp/raw/deleg/build/deleg.asm b/src/test/cpp/raw/deleg/build/deleg.asm index b1e420da..4084d8cf 100644 --- a/src/test/cpp/raw/deleg/build/deleg.asm +++ b/src/test/cpp/raw/deleg/build/deleg.asm @@ -10,11 +10,11 @@ Disassembly of section .crt_section: 80000008: 68408093 addi ra,ra,1668 # 80000688 8000000c: 30509073 csrw mtvec,ra 80000010: 00000097 auipc ra,0x0 -80000014: 6ac08093 addi ra,ra,1708 # 800006bc +80000014: 6b008093 addi ra,ra,1712 # 800006c0 80000018: 10509073 csrw stvec,ra 8000001c: f00110b7 lui ra,0xf0011 80000020: 00000113 li sp,0 -80000024: 0020a023 sw sp,0(ra) # f0011000 +80000024: 0020a023 sw sp,0(ra) # f0011000 80000028 : 80000028: 00100e13 li t3,1 @@ -134,7 +134,7 @@ Disassembly of section .crt_section: 800001a8: 03cf0f13 addi t5,t5,60 # 800001e0 800001ac: f00110b7 lui ra,0xf0011 800001b0: 00000113 li sp,0 -800001b4: 0020a023 sw sp,0(ra) # f0011000 +800001b4: 0020a023 sw sp,0(ra) # f0011000 800001b8: 00800093 li ra,8 800001bc: 30009073 csrw mstatus,ra 800001c0: 000010b7 lui ra,0x1 @@ -142,7 +142,7 @@ Disassembly of section .crt_section: 800001c8: 30409073 csrw mie,ra 800001cc: f00110b7 lui ra,0xf0011 800001d0: 00100113 li sp,1 -800001d4: 0020a023 sw sp,0(ra) # f0011000 +800001d4: 0020a023 sw sp,0(ra) # f0011000 800001d8: 10500073 wfi 800001dc: 4940006f j 80000670 @@ -152,7 +152,7 @@ Disassembly of section .crt_section: 800001e8: 068f0f13 addi t5,t5,104 # 8000024c 800001ec: f00110b7 lui ra,0xf0011 800001f0: 00000113 li sp,0 -800001f4: 0020a023 sw sp,0(ra) # f0011000 +800001f4: 0020a023 sw sp,0(ra) # f0011000 800001f8: 00800093 li ra,8 800001fc: 30009073 csrw mstatus,ra 80000200: 000010b7 lui ra,0x1 @@ -171,7 +171,7 @@ Disassembly of section .crt_section: 80000234: 43c0006f j 80000670 80000238: f00110b7 lui ra,0xf0011 8000023c: 00100113 li sp,1 -80000240: 0020a023 sw sp,0(ra) # f0011000 +80000240: 0020a023 sw sp,0(ra) # f0011000 80000244: 10500073 wfi 80000248: 4280006f j 80000670 @@ -181,7 +181,7 @@ Disassembly of section .crt_section: 80000254: 064f0f13 addi t5,t5,100 # 800002b4 80000258: f00110b7 lui ra,0xf0011 8000025c: 00000113 li sp,0 -80000260: 0020a023 sw sp,0(ra) # f0011000 +80000260: 0020a023 sw sp,0(ra) # f0011000 80000264: 00800093 li ra,8 80000268: 30009073 csrw mstatus,ra 8000026c: 000010b7 lui ra,0x1 @@ -199,7 +199,7 @@ Disassembly of section .crt_section: 8000029c: 3d40006f j 80000670 800002a0: f00110b7 lui ra,0xf0011 800002a4: 00100113 li sp,1 -800002a8: 0020a023 sw sp,0(ra) # f0011000 +800002a8: 0020a023 sw sp,0(ra) # f0011000 800002ac: 10500073 wfi 800002b0: 3c00006f j 80000670 @@ -211,7 +211,7 @@ Disassembly of section .crt_section: 800002c4: 040f0f13 addi t5,t5,64 # 80000300 800002c8: f00120b7 lui ra,0xf0012 800002cc: 00000113 li sp,0 -800002d0: 0020a023 sw sp,0(ra) # f0012000 +800002d0: 0020a023 sw sp,0(ra) # f0012000 800002d4: 00200093 li ra,2 800002d8: 30009073 csrw mstatus,ra 800002dc: 20000093 li ra,512 @@ -219,7 +219,7 @@ Disassembly of section .crt_section: 800002e4: 00000e93 li t4,0 800002e8: f00120b7 lui ra,0xf0012 800002ec: 00100113 li sp,1 -800002f0: 0020a023 sw sp,0(ra) # f0012000 +800002f0: 0020a023 sw sp,0(ra) # f0012000 800002f4: 06400093 li ra,100 800002f8: fff08093 addi ra,ra,-1 800002fc: fe104ee3 bgtz ra,800002f8 @@ -230,7 +230,7 @@ Disassembly of section .crt_section: 80000308: 068f0f13 addi t5,t5,104 # 8000036c 8000030c: f00120b7 lui ra,0xf0012 80000310: 00000113 li sp,0 -80000314: 0020a023 sw sp,0(ra) # f0012000 +80000314: 0020a023 sw sp,0(ra) # f0012000 80000318: 00200093 li ra,2 8000031c: 30009073 csrw mstatus,ra 80000320: 20000093 li ra,512 @@ -249,7 +249,7 @@ Disassembly of section .crt_section: 80000354: 00100e93 li t4,1 80000358: f00120b7 lui ra,0xf0012 8000035c: 00100113 li sp,1 -80000360: 0020a023 sw sp,0(ra) # f0012000 +80000360: 0020a023 sw sp,0(ra) # f0012000 80000364: 10500073 wfi 80000368: 3080006f j 80000670 @@ -259,7 +259,7 @@ Disassembly of section .crt_section: 80000374: 060f0f13 addi t5,t5,96 # 800003d0 80000378: f00120b7 lui ra,0xf0012 8000037c: 00000113 li sp,0 -80000380: 0020a023 sw sp,0(ra) # f0012000 +80000380: 0020a023 sw sp,0(ra) # f0012000 80000384: 00200093 li ra,2 80000388: 30009073 csrw mstatus,ra 8000038c: 20000093 li ra,512 @@ -276,7 +276,7 @@ Disassembly of section .crt_section: 800003b8: 2b80006f j 80000670 800003bc: f00120b7 lui ra,0xf0012 800003c0: 00100113 li sp,1 -800003c4: 0020a023 sw sp,0(ra) # f0012000 +800003c4: 0020a023 sw sp,0(ra) # f0012000 800003c8: 10500073 wfi 800003cc: 2a40006f j 80000670 @@ -288,7 +288,7 @@ Disassembly of section .crt_section: 800003e0: 040f0f13 addi t5,t5,64 # 8000041c 800003e4: f00120b7 lui ra,0xf0012 800003e8: 00000113 li sp,0 -800003ec: 0020a023 sw sp,0(ra) # f0012000 +800003ec: 0020a023 sw sp,0(ra) # f0012000 800003f0: 00200093 li ra,2 800003f4: 30009073 csrw mstatus,ra 800003f8: 20000093 li ra,512 @@ -296,7 +296,7 @@ Disassembly of section .crt_section: 80000400: 00000e93 li t4,0 80000404: f00120b7 lui ra,0xf0012 80000408: 00100113 li sp,1 -8000040c: 0020a023 sw sp,0(ra) # f0012000 +8000040c: 0020a023 sw sp,0(ra) # f0012000 80000410: 06400093 li ra,100 80000414: fff08093 addi ra,ra,-1 80000418: fe104ee3 bgtz ra,80000414 @@ -307,7 +307,7 @@ Disassembly of section .crt_section: 80000424: 068f0f13 addi t5,t5,104 # 80000488 80000428: f00120b7 lui ra,0xf0012 8000042c: 00000113 li sp,0 -80000430: 0020a023 sw sp,0(ra) # f0012000 +80000430: 0020a023 sw sp,0(ra) # f0012000 80000434: 00200093 li ra,2 80000438: 30009073 csrw mstatus,ra 8000043c: 20000093 li ra,512 @@ -326,7 +326,7 @@ Disassembly of section .crt_section: 80000470: 00100e93 li t4,1 80000474: f00120b7 lui ra,0xf0012 80000478: 00100113 li sp,1 -8000047c: 0020a023 sw sp,0(ra) # f0012000 +8000047c: 0020a023 sw sp,0(ra) # f0012000 80000480: 10500073 wfi 80000484: 1ec0006f j 80000670 @@ -336,7 +336,7 @@ Disassembly of section .crt_section: 80000490: 060f0f13 addi t5,t5,96 # 800004ec 80000494: f00120b7 lui ra,0xf0012 80000498: 00000113 li sp,0 -8000049c: 0020a023 sw sp,0(ra) # f0012000 +8000049c: 0020a023 sw sp,0(ra) # f0012000 800004a0: 00200093 li ra,2 800004a4: 30009073 csrw mstatus,ra 800004a8: 20000093 li ra,512 @@ -353,14 +353,14 @@ Disassembly of section .crt_section: 800004d4: 19c0006f j 80000670 800004d8: f00120b7 lui ra,0xf0012 800004dc: 00100113 li sp,1 -800004e0: 0020a023 sw sp,0(ra) # f0012000 +800004e0: 0020a023 sw sp,0(ra) # f0012000 800004e4: 10500073 wfi 800004e8: 1880006f j 80000670 800004ec : 800004ec: f00120b7 lui ra,0xf0012 800004f0: 00000113 li sp,0 -800004f4: 0020a023 sw sp,0(ra) # f0012000 +800004f4: 0020a023 sw sp,0(ra) # f0012000 800004f8: 01400e13 li t3,20 800004fc: 00000f17 auipc t5,0x0 80000500: 030f0f13 addi t5,t5,48 # 8000052c @@ -432,31 +432,31 @@ Disassembly of section .crt_section: 800005f0: 00000e93 li t4,0 800005f4: f00120b7 lui ra,0xf0012 800005f8: 00000113 li sp,0 -800005fc: 0020a023 sw sp,0(ra) # f0012000 +800005fc: 0020a023 sw sp,0(ra) # f0012000 80000600: 20000093 li ra,512 80000604: 1440b073 csrc sip,ra 80000608: 344021f3 csrr gp,mip 8000060c: f00120b7 lui ra,0xf0012 80000610: 00100113 li sp,1 -80000614: 0020a023 sw sp,0(ra) # f0012000 +80000614: 0020a023 sw sp,0(ra) # f0012000 80000618: 20000093 li ra,512 8000061c: 1440b073 csrc sip,ra 80000620: 344021f3 csrr gp,mip 80000624: f00120b7 lui ra,0xf0012 80000628: 00000113 li sp,0 -8000062c: 0020a023 sw sp,0(ra) # f0012000 +8000062c: 0020a023 sw sp,0(ra) # f0012000 80000630: 20000093 li ra,512 80000634: 1440b073 csrc sip,ra 80000638: 344021f3 csrr gp,mip 8000063c: f00120b7 lui ra,0xf0012 80000640: 00000113 li sp,0 -80000644: 0020a023 sw sp,0(ra) # f0012000 +80000644: 0020a023 sw sp,0(ra) # f0012000 80000648: 20000093 li ra,512 8000064c: 1440a073 csrs sip,ra 80000650: 344021f3 csrr gp,mip 80000654: f00120b7 lui ra,0xf0012 80000658: 00100113 li sp,1 -8000065c: 0020a023 sw sp,0(ra) # f0012000 +8000065c: 0020a023 sw sp,0(ra) # f0012000 80000660: 20000093 li ra,512 80000664: 1440a073 csrs sip,ra 80000668: 344021f3 csrr gp,mip @@ -464,12 +464,12 @@ Disassembly of section .crt_section: 80000670 : 80000670: f0100137 lui sp,0xf0100 -80000674: f2410113 addi sp,sp,-220 # f00fff24 +80000674: f2410113 addi sp,sp,-220 # f00fff24 80000678: 01c12023 sw t3,0(sp) 8000067c : 8000067c: f0100137 lui sp,0xf0100 -80000680: f2010113 addi sp,sp,-224 # f00fff20 +80000680: f2010113 addi sp,sp,-224 # f00fff20 80000684: 00012023 sw zero,0(sp) 80000688 : @@ -477,25 +477,27 @@ Disassembly of section .crt_section: 8000068c: 342020f3 csrr ra,mcause 80000690: 341020f3 csrr ra,mepc 80000694: 300020f3 csrr ra,mstatus -80000698: 08000093 li ra,128 -8000069c: 3000b073 csrc mstatus,ra -800006a0: 00200093 li ra,2 -800006a4: fc1e8ce3 beq t4,ra,8000067c -800006a8: 000020b7 lui ra,0x2 -800006ac: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800> -800006b0: 3000a073 csrs mstatus,ra -800006b4: 341f1073 csrw mepc,t5 -800006b8: 30200073 mret +80000698: 343020f3 csrr ra,mbadaddr +8000069c: 08000093 li ra,128 +800006a0: 3000b073 csrc mstatus,ra +800006a4: 00200093 li ra,2 +800006a8: fc1e8ae3 beq t4,ra,8000067c +800006ac: 000020b7 lui ra,0x2 +800006b0: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800> +800006b4: 3000a073 csrs mstatus,ra +800006b8: 341f1073 csrw mepc,t5 +800006bc: 30200073 mret -800006bc : -800006bc: fa0e8ae3 beqz t4,80000670 -800006c0: 142020f3 csrr ra,scause -800006c4: 141020f3 csrr ra,sepc -800006c8: 100020f3 csrr ra,sstatus -800006cc: 00000073 ecall -800006d0: 00000013 nop -800006d4: 00000013 nop +800006c0 : +800006c0: fa0e88e3 beqz t4,80000670 +800006c4: 142020f3 csrr ra,scause +800006c8: 141020f3 csrr ra,sepc +800006cc: 100020f3 csrr ra,sstatus +800006d0: 143020f3 csrr ra,sbadaddr +800006d4: 00000073 ecall 800006d8: 00000013 nop 800006dc: 00000013 nop 800006e0: 00000013 nop 800006e4: 00000013 nop +800006e8: 00000013 nop +800006ec: 00000013 nop diff --git a/src/test/cpp/raw/deleg/build/deleg.hex b/src/test/cpp/raw/deleg/build/deleg.hex index 3ff7ecc4..eff4ff20 100644 --- a/src/test/cpp/raw/deleg/build/deleg.hex +++ b/src/test/cpp/raw/deleg/build/deleg.hex @@ -1,6 +1,6 @@ :0200000480007A :10000000930E10009700000093804068739050306A -:10001000970000009380C06A73905010B71001F0F1 +:10001000970000009380006B73905010B71001F0B0 :100020001301000023A02000130E1000170F000082 :10003000130FCF0073000000130E2000B720000044 :10004000938000801301000073B0003073200130F2 @@ -104,11 +104,11 @@ :100660009300002073A04014F32140346F00000178 :10067000370110F0130141F22320C101370110F0BE :10068000130101F223200100E3840EFEF320203445 -:10069000F3201034F32000309300000873B00030D2 -:1006A00093002000E38C1EFCB720000093800080A4 -:1006B00073A0003073101F3473002030E38A0EFAE9 -:1006C000F3202014F3201014F32000107300000016 -:1006D00013000000130000001300000013000000CE -:0806E0001300000013000000EC +:10069000F3201034F3200030F320303493000008AE +:1006A00073B0003093002000E38A1EFCB7200000E6 +:1006B0009380008073A0003073101F3473002030CB +:1006C000E3880EFAF3202014F3201014F320001016 +:1006D000F32030147300000013000000130000002A +:1006E00013000000130000001300000013000000BE :040000058000000077 :00000001FF diff --git a/src/test/cpp/raw/deleg/src/crt.S b/src/test/cpp/raw/deleg/src/crt.S index 38ff7e2c..f91981ff 100644 --- a/src/test/cpp/raw/deleg/src/crt.S +++ b/src/test/cpp/raw/deleg/src/crt.S @@ -328,6 +328,7 @@ mtrap: csrr x1, mcause csrr x1, mepc csrr x1, mstatus + csrr x1, mbadaddr li x1, MSTATUS_MPIE csrc mstatus, x1 li x1, 2 @@ -343,6 +344,7 @@ strap: csrr x1, scause csrr x1, sepc csrr x1, sstatus + csrr x1, sbadaddr ecall diff --git a/src/test/cpp/raw/mmu/build/mmu.asm b/src/test/cpp/raw/mmu/build/mmu.asm index 1cb5df41..9bbf17fd 100644 --- a/src/test/cpp/raw/mmu/build/mmu.asm +++ b/src/test/cpp/raw/mmu/build/mmu.asm @@ -436,11 +436,11 @@ Disassembly of section .crt_section: 80000598: 342020f3 csrr ra,mcause 8000059c: 341020f3 csrr ra,mepc 800005a0: 300020f3 csrr ra,mstatus -800005a4: 00200093 li ra,2 -800005a8: fe1e80e3 beq t4,ra,80000588 -800005ac: 341f1073 csrw mepc,t5 -800005b0: 30200073 mret -800005b4: 00000013 nop +800005a4: 343020f3 csrr ra,mbadaddr +800005a8: 00200093 li ra,2 +800005ac: fc1e8ee3 beq t4,ra,80000588 +800005b0: 341f1073 csrw mepc,t5 +800005b4: 30200073 mret 800005b8: 00000013 nop 800005bc: 00000013 nop 800005c0: 00000013 nop diff --git a/src/test/cpp/raw/mmu/build/mmu.hex b/src/test/cpp/raw/mmu/build/mmu.hex index 8ee88714..67603477 100644 --- a/src/test/cpp/raw/mmu/build/mmu.hex +++ b/src/test/cpp/raw/mmu/build/mmu.hex @@ -89,8 +89,8 @@ :1005700073000000370110F0130141F22320C10184 :10058000930E200073000000370110F0130101F2F8 :1005900023200100E3800EFEF3202034F3201034EA -:1005A000F320003093002000E3801EFE73101F3400 -:1005B000730020301300000013000000130000003F +:1005A000F3200030F320303493002000E38E1EFC53 +:1005B00073101F347300203013000000130000007C :1005C00013000000130000001300000013000000DF :1005D00013000000130000001300000013000000CF :1005E00013000000130000001300000013000000BF @@ -3228,6 +3228,6 @@ :10C9A0000000000000000000000000000000000087 :10C9B0000000000000000000000000000000000077 :10C9C0000000000000000000000000000000000067 -:10C9D0000000000000000000000000000000000057 +:0CC9D0000000000000000000000000005B :040000058000000077 :00000001FF diff --git a/src/test/cpp/raw/mmu/src/crt.S b/src/test/cpp/raw/mmu/src/crt.S index 4e11e52d..2f85bbe4 100644 --- a/src/test/cpp/raw/mmu/src/crt.S +++ b/src/test/cpp/raw/mmu/src/crt.S @@ -421,6 +421,7 @@ trap: csrr x1, mcause csrr x1, mepc csrr x1, mstatus + csrr x1, mbadaddr li x1, 2 beq TRAP_OK, x1, passFence csrw mepc, TRAP_RET diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 4f4b63d3..981ef6fc 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -418,7 +418,7 @@ public: } void trap(bool interrupt,int32_t cause) { - trap(interrupt, cause, false, 0); + trap(interrupt, cause, true, 0); } void trap(bool interrupt,int32_t cause, uint32_t value) { trap(interrupt, cause, true, value); @@ -642,7 +642,7 @@ public: uint32_t u32Buf; uint32_t pAddr; if (pc & 2) { - if(v2p(pc - 2, &pAddr, EXECUTE)){ trap(0, 12); return; } + if(v2p(pc - 2, &pAddr, EXECUTE)){ trap(0, 12, pc - 2); return; } if(iRead(pAddr, &i)){ trap(0, 1); return; @@ -650,7 +650,7 @@ public: i >>= 16; if (i & 3 == 3) { uint32_t u32Buf; - if(v2p(pc + 2, &pAddr, EXECUTE)){ trap(0, 12); return; } + if(v2p(pc + 2, &pAddr, EXECUTE)){ trap(0, 12, pc + 2); return; } if(iRead(pAddr, &u32Buf)){ trap(0, 1); return; @@ -658,7 +658,7 @@ public: i |= u32Buf << 16; } } else { - if(v2p(pc, &pAddr, EXECUTE)){ trap(0, 12); return; } + if(v2p(pc, &pAddr, EXECUTE)){ trap(0, 12, pc); return; } if(iRead(pAddr, &i)){ trap(0, 1); return; @@ -692,7 +692,7 @@ public: if(address & (size-1)){ trap(0, 4, address); } else { - if(v2p(address, &pAddr, READ)){ trap(0, 13); return; } + if(v2p(address, &pAddr, READ)){ trap(0, 13, address); return; } if(dRead(pAddr, size, &data)){ trap(0, 5, address); } else { @@ -712,7 +712,7 @@ public: if(address & (size-1)){ trap(0, 6, address); } else { - if(v2p(address, &pAddr, WRITE)){ trap(0, 15); return; } + if(v2p(address, &pAddr, WRITE)){ trap(0, 15, address); return; } dWrite(pAddr, size, i32_rs2); pcWrite(pc + 4); } @@ -836,7 +836,7 @@ public: if(address & 0x3){ trap(0, 4, address); } else { - if(v2p(address, &pAddr, READ)){ trap(0, 13); return; } + if(v2p(address, &pAddr, READ)){ trap(0, 13, address); return; } if(dRead(address, 4, &data)) { trap(1, 5, address); } else { @@ -849,7 +849,7 @@ public: if(address & 0x3){ trap(0, 6, address); } else { - if(v2p(address, &pAddr, WRITE)){ trap(0, 15); return; } + if(v2p(address, &pAddr, WRITE)){ trap(0, 15, address); return; } dWrite(pAddr, 4, i16_rf2); pcWrite(pc + 2); } @@ -885,7 +885,7 @@ public: if(address & 0x3){ trap(0, 4, address); } else { - if(v2p(address, &pAddr, READ)){ trap(0, 13); return; } + if(v2p(address, &pAddr, READ)){ trap(0, 13, address); return; } if(dRead(pAddr, 4, &data)){ trap(1, 5, address); } else { @@ -915,7 +915,7 @@ public: if(address & 3){ trap(0,6, address); } else { - if(v2p(address, &pAddr, WRITE)){ trap(0, 15); return; } + if(v2p(address, &pAddr, WRITE)){ trap(0, 15, address); return; } dWrite(pAddr, 4, regs[iBits(2,5)]); pcWrite(pc + 2); } }break; From 95c3e436dceea548702a882f0a3c44d05af482a5 Mon Sep 17 00:00:00 2001 From: Tom Verbeure Date: Sat, 23 Mar 2019 22:32:48 +0000 Subject: [PATCH 068/951] Make toPipelinedMemoryBus() just like the other busses --- src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala index 636b1930..5d6ad0b1 100644 --- a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala @@ -59,6 +59,11 @@ object IBusSimpleBus{ useBTE = true, useCTI = true ) + + def getPipelinedMemoryBusConfig() = PipelinedMemoryBusConfig( + addressWidth = 32, + dataWidth = 32 + ) } @@ -136,7 +141,8 @@ case class IBusSimpleBus(interfaceKeepData : Boolean = false) extends Bundle wit } def toPipelinedMemoryBus(): PipelinedMemoryBus = { - val bus = PipelinedMemoryBus(32,32) + val pipelinedMemoryBusConfig = IBusSimpleBus.getPipelinedMemoryBusConfig() + val bus = PipelinedMemoryBus(pipelinedMemoryBusConfig) bus.cmd.arbitrationFrom(cmd) bus.cmd.address := cmd.pc.resized bus.cmd.write := False @@ -281,4 +287,4 @@ class IBusSimplePlugin(resetVector : BigInt, } } } -} \ No newline at end of file +} From 1afad4f240fbe8899f46f1d5fc867370ae32974f Mon Sep 17 00:00:00 2001 From: Tom Verbeure Date: Sat, 23 Mar 2019 22:34:22 +0000 Subject: [PATCH 069/951] Ignore vim backup files. --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index eaab2e7a..2737be08 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ *.class *.log *.bak +.*.swp # sbt specific .cache/ @@ -46,4 +47,4 @@ obj_dir simWorkspace/ tmp/ /archive.tar.gz -*.out32 \ No newline at end of file +*.out32 From ea62fd0e16764b3921404081f6b8afbdbc308172 Mon Sep 17 00:00:00 2001 From: Tom Verbeure Date: Sat, 23 Mar 2019 23:36:13 +0000 Subject: [PATCH 070/951] Same thing for DBusSimpleBus. --- src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala index eb4ce468..44b9ee17 100644 --- a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala @@ -63,6 +63,12 @@ object DBusSimpleBus{ useBTE = true, useCTI = true ) + + def getPipelinedMemoryBusConfig() = PipelinedMemoryBusConfig( + addressWidth = 32, + dataWidth = 32 + ) + } case class DBusSimpleBus() extends Bundle with IMasterSlave{ @@ -178,7 +184,8 @@ case class DBusSimpleBus() extends Bundle with IMasterSlave{ } def toPipelinedMemoryBus() : PipelinedMemoryBus = { - val bus = PipelinedMemoryBus(32,32) + val pipelinedMemoryBusConfig = DBusSimpleBus.getPipelinedMemoryBusConfig() + val bus = PipelinedMemoryBus(pipelinedMemoryBusConfig) bus.cmd.valid := cmd.valid bus.cmd.write := cmd.wr bus.cmd.address := cmd.address.resized From 6c0608f0dd69834145d614db744d0603b215a295 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sun, 24 Mar 2019 10:52:56 +0100 Subject: [PATCH 071/951] #60 Add LitexSoC workspace / linux loading. Need to emulate peripherals and adapte the kernel now. Probably also need some machine mode emulation Software time ! --- src/main/scala/vexriscv/demo/Linux.scala | 38 ++- src/test/cpp/regression/main.cpp | 367 +++++++++++++++-------- src/test/cpp/regression/makefile | 7 + 3 files changed, 278 insertions(+), 134 deletions(-) diff --git a/src/main/scala/vexriscv/demo/Linux.scala b/src/main/scala/vexriscv/demo/Linux.scala index 05d2af5f..8eea1ad8 100644 --- a/src/main/scala/vexriscv/demo/Linux.scala +++ b/src/main/scala/vexriscv/demo/Linux.scala @@ -26,8 +26,25 @@ import vexriscv._ import vexriscv.ip._ import vexriscv.plugin._ +/* +Setup things => +git clone https://github.com/SpinalHDL/SpinalHDL.git -b dev +git clone https://github.com/SpinalHDL/VexRiscv.git -b linux +cd VexRiscv + +Run regressions => +sbt "runMain vexriscv.demo.LinuxGen -r" +cd src/test/cpp/regression +make run DBUS=SIMPLE IBUS=SIMPLE DHRYSTONE=yes SUPERVISOR=yes CSR=yes COMPRESSED=yes REDO=10 TRACE=no + +Run linux => +sbt "runMain vexriscv.demo.LinuxGen" +cd src/test/cpp/regression +make run DBUS=SIMPLE IBUS=SIMPLE SUPERVISOR=yes CSR=yes COMPRESSED=yes LITEX=yes VMLINUX=/home/spinalvm/hdl/linuxDave/vmlinux.bin RAMDISK=/home/spinalvm/hdl/linuxDave/initramdisk_dave TRACE=no +*/ + object LinuxGen { - def configFull(withMmu : Boolean = true) = { + def configFull(litex : Boolean, withMmu : Boolean) = { val config = VexRiscvConfig( plugins = List( new IBusSimplePlugin( @@ -171,15 +188,15 @@ object LinuxGen { ) if(withMmu) config.plugins += new MmuPlugin( virtualRange = a => True, - ioRange = _(31 downto 28) === 0xF, + ioRange = (x => if(litex) x(31 downto 28) === 0xB || x(31 downto 28) === 0xE else x(31 downto 28) === 0xF), allowUserIo = true ) config } + + + def main(args: Array[String]) { - - - // import spinal.core.sim._ // SimConfig.withConfig(SpinalConfig(mergeAsyncProcess = false, anonymSignalPrefix = "zz_")).allOptimisation.compile(new VexRiscv(configFull)).doSimUntilVoid{ dut => // dut.clockDomain.forkStimulus(10) @@ -199,7 +216,10 @@ object LinuxGen { SpinalConfig(mergeAsyncProcess = true).generateVerilog { - val toplevel = new VexRiscv(configFull()) + val toplevel = new VexRiscv(configFull( + litex = !args.contains("-r"), + withMmu = true + )) // val toplevel = new VexRiscv(configLight) // val toplevel = new VexRiscv(configTest) @@ -288,13 +308,13 @@ object LinuxSyntesisBench extends App{ val withoutMmu = new Rtl { override def getName(): String = "VexRiscv Without Mmu" override def getRtlPath(): String = "VexRiscvWithoutMmu.v" - SpinalVerilog(new VexRiscv(LinuxGen.configFull(withMmu=false)).setDefinitionName(getRtlPath().split("\\.").head)) + SpinalVerilog(new VexRiscv(LinuxGen.configFull(litex = false, withMmu = false)).setDefinitionName(getRtlPath().split("\\.").head)) } val withMmu = new Rtl { override def getName(): String = "VexRiscv With Mmu" override def getRtlPath(): String = "VexRiscvWithMmu.v" - SpinalVerilog(new VexRiscv(LinuxGen.configFull(withMmu=true)).setDefinitionName(getRtlPath().split("\\.").head)) + SpinalVerilog(new VexRiscv(LinuxGen.configFull(litex = false, withMmu = true)).setDefinitionName(getRtlPath().split("\\.").head)) } val rtls = List(withoutMmu, withMmu) @@ -316,7 +336,7 @@ object LinuxSyntesisBench extends App{ object LinuxSim extends App{ import spinal.core.sim._ - SimConfig.allOptimisation.compile(new VexRiscv(LinuxGen.configFull())).doSim{dut => + SimConfig.allOptimisation.compile(new VexRiscv(LinuxGen.configFull(litex = false, withMmu = true))).doSim{dut => // dut.clockDomain.forkStimulus(10) // dut.clockDomain.forkSimSpeedPrinter() // dut.plugins.foreach{ diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 981ef6fc..86ba2d09 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -151,6 +151,26 @@ void loadHexImpl(string path,Memory* mem) { delete [] content; } +void loadBinImpl(string path,Memory* mem, uint32_t offset) { + FILE *fp = fopen(&path[0], "r"); + if(fp == 0){ + cout << path << " not found" << endl; + } + + fseek(fp, 0, SEEK_END); + uint32_t size = ftell(fp); + fseek(fp, 0, SEEK_SET); + char* content = new char[size]; + fread(content, 1, size, fp); + fclose(fp); + + for(int byteId = 0; byteId < size;byteId++){ + *(mem->get(offset + byteId)) = content[byteId]; + } + + delete [] content; +} + #define TEXTIFY(A) #A @@ -965,8 +985,8 @@ public: uint32_t seed; bool withInstructionReadCheck = true; - void setIStall(bool enable) { iStall = enable; } - void setDStall(bool enable) { dStall = enable; } + Workspace* setIStall(bool enable) { iStall = enable; return this; } + Workspace* setDStall(bool enable) { dStall = enable; return this; } ofstream regTraces; ofstream memTraces; @@ -1027,7 +1047,7 @@ public: } if(address & (size-1) != 0) cout << "Ref did a unaligned read" << endl; - if((address & 0xF0000000) == 0xF0000000){ + if(ws->isPerifRegion(address)){ MemRead t = periphRead.front(); if(t.address != address || t.size != size){ fail(); @@ -1043,7 +1063,7 @@ public: virtual void dWrite(int32_t address, int32_t size, uint32_t data){ if(address & (size-1) != 0) cout << "Ref did a unaligned write" << endl; - if((address & 0xF0000000) == 0xF0000000){ + if(ws->isPerifRegion(address)){ MemWrite w; w.address = address; w.size = size; @@ -1119,6 +1139,12 @@ public: return this; } + Workspace* loadBin(string path, uint32_t offset){ + loadBinImpl(path,&mem, offset); + loadBinImpl(path,&riscvRef.mem, offset); + return this; + } + Workspace* setCyclesPerSecond(double value){ cyclesPerSecond = value; return this; @@ -1135,108 +1161,25 @@ public: return this; } - void iBusAccess(uint32_t addr, uint32_t *data, bool *error) { + virtual bool isPerifRegion(uint32_t addr) { return false; } + + virtual void iBusAccess(uint32_t addr, uint32_t *data, bool *error) { if(addr % 4 != 0) { - //cout << "Warning, unaligned IBusAccess : " << addr << endl; - // fail(); + cout << "Warning, unaligned IBusAccess : " << addr << endl; + fail(); } *data = ( (mem[addr + 0] << 0) | (mem[addr + 1] << 8) | (mem[addr + 2] << 16) | (mem[addr + 3] << 24)); - *error = addr == 0xF00FFF60u; - iBusAccessPatch(addr,data,error); + *error = false; } - virtual void iBusAccessPatch(uint32_t addr, uint32_t *data, bool *error){} + virtual void dBusAccess(uint32_t addr,bool wr, uint32_t size,uint32_t mask, uint32_t *data, bool *error) { assertEq(addr % (1 << size), 0); - *error = addr == 0xF00FFF60u; - if(wr){ - memTraces << - #ifdef TRACE_WITH_TIME - (currentTime - #ifdef REF - -2 - #endif - ) << - #endif - " : WRITE mem" << (1 << size) << "[" << addr << "] = " << *data << endl; - for(uint32_t b = 0;b < (1 << size);b++){ - uint32_t offset = (addr+b)&0x3; - if((mask >> offset) & 1 == 1) - *mem.get(addr + b) = *data >> (offset*8); - } - - switch(addr){ - case 0xF0010000u: { - cout << mem[0xF0010000u]; - logTraces << (char)mem[0xF0010000u]; - break; - } -#ifdef EXTERNAL_INTERRUPT - case 0xF0011000u: top->externalInterrupt = *data & 1; break; -#endif -#ifdef SUPERVISOR - case 0xF0012000u: top->externalInterruptS = *data & 1; break; -#endif -#ifdef CSR - case 0xF0013000u: top->softwareInterrupt = *data & 1; break; -#endif - case 0xF00FFF00u: { - cout << mem[0xF00FFF00u]; - logTraces << (char)mem[0xF00FFF00u]; - break; - } - #ifndef DEBUG_PLUGIN_EXTERNAL - case 0xF00FFF20u: - if(*data == 0) - pass(); - else - fail(); - break; - case 0xF00FFF24u: - cout << "TEST ERROR CODE " << *data << endl; - fail(); - break; - #endif - case 0xF00FFF48u: mTimeCmp = (mTimeCmp & 0xFFFFFFFF00000000) | *data;break; - case 0xF00FFF4Cu: mTimeCmp = (mTimeCmp & 0x00000000FFFFFFFF) | (((uint64_t)*data) << 32); /*cout << "mTimeCmp <= " << mTimeCmp << endl; */break; - } - }else{ - *data = VL_RANDOM_I(32); - for(uint32_t b = 0;b < (1 << size);b++){ - uint32_t offset = (addr+b)&0x3; - *data &= ~(0xFF << (offset*8)); - *data |= mem[addr + b] << (offset*8); - } - switch(addr){ - case 0xF00FFF10u: - *data = mTime; - #ifdef REF_TIME - mTime += 100000; - #endif - break; - case 0xF00FFF40u: *data = mTime; break; - case 0xF00FFF44u: *data = mTime >> 32; break; - case 0xF00FFF48u: *data = mTimeCmp; break; - case 0xF00FFF4Cu: *data = mTimeCmp >> 32; break; - case 0xF0010004u: *data = ~0; break; - } - memTraces << - #ifdef TRACE_WITH_TIME - (currentTime - #ifdef REF - -2 - #endif - ) << - #endif - " : READ mem" << (1 << size) << "[" << addr << "] = " << *data << endl; - - } - - if((addr & 0xF0000000) == 0xF0000000){ + if(isPerifRegion(addr)){ if(wr){ CpuRef::MemWrite w; w.address = addr; @@ -1251,8 +1194,61 @@ public: r.error = *error; riscvRef.periphRead.push(r); } + } else { + if(wr){ + memTraces << + #ifdef TRACE_WITH_TIME + (currentTime + #ifdef REF + -2 + #endif + ) << + #endif + " : WRITE mem" << (1 << size) << "[" << addr << "] = " << *data << endl; + for(uint32_t b = 0;b < (1 << size);b++){ + uint32_t offset = (addr+b)&0x3; + if((mask >> offset) & 1 == 1) + *mem.get(addr + b) = *data >> (offset*8); + } + + }else{ + *data = VL_RANDOM_I(32); + for(uint32_t b = 0;b < (1 << size);b++){ + uint32_t offset = (addr+b)&0x3; + *data &= ~(0xFF << (offset*8)); + *data |= mem[addr + b] << (offset*8); + } + memTraces << + #ifdef TRACE_WITH_TIME + (currentTime + #ifdef REF + -2 + #endif + ) << + #endif + " : READ mem" << (1 << size) << "[" << addr << "] = " << *data << endl; + + } } } + +// void periphAccess(uint32_t addr,bool wr, uint32_t size,uint32_t mask, uint32_t *data, bool *error){ +// if(wr){ +// CpuRef::MemWrite w; +// w.address = addr; +// w.size = 1 << size; +// w.data = *data; +// riscvRef.periphWrites.push(w); +// } else { +// CpuRef::MemRead r; +// r.address = addr; +// r.size = 1 << size; +// r.data = *data; +// r.error = *error; +// riscvRef.periphRead.push(r); +// } +// } + virtual void postReset() {} virtual void checks(){} virtual void pass(){ throw success();} @@ -1266,6 +1262,7 @@ public: } Workspace* run(uint64_t timeout = 5000){ // cout << "Start " << name << endl; + if(timeout == 0) timeout = 0x7FFFFFFFFFFFFFFF; currentTime = 4; // init trace dump @@ -1507,6 +1504,91 @@ public: }; +class WorkspaceRegression : public Workspace { +public: + + WorkspaceRegression(string name) : Workspace(name){ + + } + + virtual bool isPerifRegion(uint32_t addr) { return (addr & 0xF0000000) == 0xF0000000;} + + + virtual void iBusAccess(uint32_t addr, uint32_t *data, bool *error){ + Workspace::iBusAccess(addr,data,error); + *error = addr == 0xF00FFF60u; + } + + virtual void dBusAccess(uint32_t addr,bool wr, uint32_t size,uint32_t mask, uint32_t *data, bool *error) { + if(wr){ + switch(addr){ + case 0xF0010000u: { + cout << (char)*data; + logTraces << (char)*data; + break; + } +#ifdef EXTERNAL_INTERRUPT + case 0xF0011000u: top->externalInterrupt = *data & 1; break; +#endif +#ifdef SUPERVISOR + case 0xF0012000u: top->externalInterruptS = *data & 1; break; +#endif +#ifdef CSR + case 0xF0013000u: top->softwareInterrupt = *data & 1; break; +#endif + case 0xF00FFF00u: { + cout << (char)*data; + logTraces << (char)*data; + break; + } + #ifndef DEBUG_PLUGIN_EXTERNAL + case 0xF00FFF20u: + if(*data == 0) + pass(); + else + fail(); + break; + case 0xF00FFF24u: + cout << "TEST ERROR CODE " << *data << endl; + fail(); + break; + #endif + case 0xF00FFF48u: mTimeCmp = (mTimeCmp & 0xFFFFFFFF00000000) | *data;break; + case 0xF00FFF4Cu: mTimeCmp = (mTimeCmp & 0x00000000FFFFFFFF) | (((uint64_t)*data) << 32); /*cout << "mTimeCmp <= " << mTimeCmp << endl; */break; + } + }else{ + switch(addr){ + case 0xF00FFF10u: + *data = mTime; + #ifdef REF_TIME + mTime += 100000; + #endif + break; + case 0xF00FFF40u: *data = mTime; break; + case 0xF00FFF44u: *data = mTime >> 32; break; + case 0xF00FFF48u: *data = mTimeCmp; break; + case 0xF00FFF4Cu: *data = mTimeCmp >> 32; break; + case 0xF0010004u: *data = ~0; break; + } + memTraces << + #ifdef TRACE_WITH_TIME + (currentTime + #ifdef REF + -2 + #endif + ) << + #endif + " : READ mem" << (1 << size) << "[" << addr << "] = " << *data << endl; + } + + *error = addr == 0xF00FFF60u; + Workspace::dBusAccess(addr,wr,size,mask,data,error); + } + + + +}; + #ifdef IBUS_SIMPLE class IBusSimple : public SimElement{ @@ -2407,13 +2489,13 @@ uint32_t regFileWriteRefArray[][2] = { testA2ReagFileWriteRef }; -class TestA : public Workspace{ +class TestA : public WorkspaceRegression{ public: uint32_t regFileWriteRefIndex = 0; - TestA() : Workspace("testA") { + TestA() : WorkspaceRegression("testA") { loadHex("../../resources/hex/testA.hex"); } @@ -2431,13 +2513,13 @@ public: } }; -class TestX28 : public Workspace{ +class TestX28 : public WorkspaceRegression{ public: uint32_t refIndex = 0; uint32_t *ref; uint32_t refSize; - TestX28(string name, uint32_t *ref, uint32_t refSize) : Workspace(name) { + TestX28(string name, uint32_t *ref, uint32_t refSize) : WorkspaceRegression(name) { this->ref = ref; this->refSize = refSize; loadHex("../../resources/hex/" + name + ".hex"); @@ -2457,9 +2539,9 @@ public: }; -class RiscvTest : public Workspace{ +class RiscvTest : public WorkspaceRegression{ public: - RiscvTest(string name) : Workspace(name) { + RiscvTest(string name) : WorkspaceRegression(name) { loadHex("../../resources/hex/" + name + ".hex"); bootAt(0x800000bcu); } @@ -2494,16 +2576,17 @@ public: } } - virtual void iBusAccessPatch(uint32_t addr, uint32_t *data, bool *error){ + virtual void iBusAccess(uint32_t addr, uint32_t *data, bool *error){ + WorkspaceRegression::iBusAccess(addr,data,error); if(*data == 0x0ff0000f) *data = 0x00000013; if(*data == 0x00000073) *data = 0x00000013; } }; #endif -class Dhrystone : public Workspace{ +class Dhrystone : public WorkspaceRegression{ public: string hexName; - Dhrystone(string name,string hexName,bool iStall, bool dStall) : Workspace(name) { + Dhrystone(string name,string hexName,bool iStall, bool dStall) : WorkspaceRegression(name) { setIStall(iStall); setDStall(dStall); withRiscvRef(); @@ -2543,12 +2626,12 @@ public: } }; -class Compliance : public Workspace{ +class Compliance : public WorkspaceRegression{ public: string name; ofstream out32; int out32Counter = 0; - Compliance(string name) : Workspace(name) { + Compliance(string name) : WorkspaceRegression(name) { withRiscvRef(); loadHex("../../resources/hex/" + name + ".elf.hex"); out32.open (name + ".out32"); @@ -2558,12 +2641,11 @@ public: virtual void dBusAccess(uint32_t addr,bool wr, uint32_t size,uint32_t mask, uint32_t *data, bool *error) { - Workspace::dBusAccess(addr,wr,size,mask,data,error); if(wr && addr == 0xF00FFF2C){ out32 << hex << setw(8) << std::setfill('0') << *data << dec; if(++out32Counter % 4 == 0) out32 << "\n"; - *error = 0; } + WorkspaceRegression::dBusAccess(addr,wr,size,mask,data,error); } virtual void checks(){ @@ -2621,7 +2703,7 @@ public: #define RISCV_SPINAL_FLAGS_RESET_CLEAR 1<<24 #define RISCV_SPINAL_FLAGS_HALT_CLEAR 1<<25 -class DebugPluginTest : public Workspace{ +class DebugPluginTest : public WorkspaceRegression{ public: pthread_t clientThreadId; char buffer[1024]; @@ -2761,7 +2843,7 @@ public: } - DebugPluginTest() : Workspace("DebugPluginTest") { + DebugPluginTest() : WorkspaceRegression("DebugPluginTest") { loadHex("../../resources/hex/debugPlugin.hex"); pthread_create(&clientThreadId, NULL, &clientThreadWrapper, this); noInstructionReadCheck(); @@ -2779,6 +2861,28 @@ public: #endif + +#ifdef LITEX +class LitexSoC : public Workspace{ +public: + + LitexSoC(string name) : Workspace(name) { + + } + + virtual bool isPerifRegion(uint32_t addr) { return (addr & 0xF0000000) == 0xB0000000 || (addr & 0xF0000000) == 0xE0000000;} + + + virtual void dBusAccess(uint32_t addr,bool wr, uint32_t size,uint32_t mask, uint32_t *data, bool *error) { + switch(addr){ + //TODO Emulate peripherals here + } + + Workspace::dBusAccess(addr,wr,size,mask,data,error); + } +}; +#endif + string riscvTestMain[] = { //"rv32ui-p-simple", "rv32ui-p-lui", @@ -3045,17 +3149,30 @@ int main(int argc, char **argv, char **env) { printf("BOOT\n"); timespec startedAt = timer_start(); + +#ifdef LITEX + LitexSoC("linux") + .withRiscvRef() + ->loadBin(VMLINUX, 0xc0000000) + ->loadBin(RAMDISK, 0xc2000000) + ->setIStall(false) //TODO It currently improve speed but should be removed later + ->setDStall(false) + ->bootAt(0xc0000000) + ->run(0); + return 1; +#endif + // #ifdef MMU -// redo(REDO,Workspace("mmu").withRiscvRef()->loadHex("../raw/mmu/build/mmu.hex")->bootAt(0x80000000u)->run(50e3);); +// redo(REDO,WorkspaceRegression("mmu").withRiscvRef()->loadHex("../raw/mmu/build/mmu.hex")->bootAt(0x80000000u)->run(50e3);); // #endif -// redo(REDO,Workspace("deleg").withRiscvRef()->loadHex("../raw/deleg/build/deleg.hex")->bootAt(0x80000000u)->run(50e3);); +// redo(REDO,WorkspaceRegression("deleg").withRiscvRef()->loadHex("../raw/deleg/build/deleg.hex")->bootAt(0x80000000u)->run(50e3);); // return 0; for(int idx = 0;idx < 1;idx++){ #if defined(DEBUG_PLUGIN_EXTERNAL) || defined(RUN_HEX) { - Workspace w("run"); + WorkspaceRegression w("run"); #ifdef RUN_HEX //w.loadHex("/home/spinalvm/hdl/zephyr/zephyrSpinalHdl/samples/synchronization/build/zephyr/zephyr.hex"); w.loadHex(RUN_HEX); @@ -3154,10 +3271,10 @@ int main(int argc, char **argv, char **env) { // #endif #ifdef MMU - redo(REDO,Workspace("mmu").withRiscvRef()->loadHex("../raw/mmu/build/mmu.hex")->bootAt(0x80000000u)->run(50e3);); + redo(REDO,WorkspaceRegression("mmu").withRiscvRef()->loadHex("../raw/mmu/build/mmu.hex")->bootAt(0x80000000u)->run(50e3);); #endif #ifdef SUPERVISOR - redo(REDO,Workspace("deleg").withRiscvRef()->loadHex("../raw/deleg/build/deleg.hex")->bootAt(0x80000000u)->run(50e3);); + redo(REDO,WorkspaceRegression("deleg").withRiscvRef()->loadHex("../raw/deleg/build/deleg.hex")->bootAt(0x80000000u)->run(50e3);); #endif #ifdef DEBUG_PLUGIN @@ -3166,16 +3283,16 @@ int main(int argc, char **argv, char **env) { #endif #ifdef CUSTOM_SIMD_ADD - redo(REDO,Workspace("custom_simd_add").loadHex("../custom/simd_add/build/custom_simd_add.hex")->bootAt(0x00000000u)->run(50e3);); + redo(REDO,WorkspaceRegression("custom_simd_add").loadHex("../custom/simd_add/build/custom_simd_add.hex")->bootAt(0x00000000u)->run(50e3);); #endif #ifdef CUSTOM_CSR - redo(REDO,Workspace("custom_csr").loadHex("../custom/custom_csr/build/custom_csr.hex")->bootAt(0x00000000u)->run(50e3);); + redo(REDO,WorkspaceRegression("custom_csr").loadHex("../custom/custom_csr/build/custom_csr.hex")->bootAt(0x00000000u)->run(50e3);); #endif #ifdef ATOMIC - redo(REDO,Workspace("atomic").loadHex("../custom/atomic/build/atomic.hex")->bootAt(0x00000000u)->run(10e3);); + redo(REDO,WorkspaceRegression("atomic").loadHex("../custom/atomic/build/atomic.hex")->bootAt(0x00000000u)->run(10e3);); #endif #ifdef DHRYSTONE @@ -3206,22 +3323,22 @@ int main(int argc, char **argv, char **env) { #ifdef SEED srand48(SEED); #endif - //redo(1,Workspace("freeRTOS_demo").loadHex("../../resources/hex/freeRTOS_demo.hex")->bootAt(0x80000000u)->run(100e6);) + //redo(1,WorkspaceRegression("freeRTOS_demo").loadHex("../../resources/hex/freeRTOS_demo.hex")->bootAt(0x80000000u)->run(100e6);) vector > tasks; /*for(int redo = 0;redo < 4;redo++)*/{ for(const string &name : freeRtosTests){ - tasks.push_back([=]() { Workspace(name + "_rv32i_O0").withRiscvRef()->loadHex("../../resources/freertos/" + name + "_rv32i_O0.hex")->bootAt(0x80000000u)->run(4e6*15);}); - tasks.push_back([=]() { Workspace(name + "_rv32i_O3").withRiscvRef()->loadHex("../../resources/freertos/" + name + "_rv32i_O3.hex")->bootAt(0x80000000u)->run(4e6*15);}); + tasks.push_back([=]() { WorkspaceRegression(name + "_rv32i_O0").withRiscvRef()->loadHex("../../resources/freertos/" + name + "_rv32i_O0.hex")->bootAt(0x80000000u)->run(4e6*15);}); + tasks.push_back([=]() { WorkspaceRegression(name + "_rv32i_O3").withRiscvRef()->loadHex("../../resources/freertos/" + name + "_rv32i_O3.hex")->bootAt(0x80000000u)->run(4e6*15);}); #ifdef COMPRESSED - tasks.push_back([=]() { Workspace(name + "_rv32ic_O0").withRiscvRef()->loadHex("../../resources/freertos/" + name + "_rv32ic_O0.hex")->bootAt(0x80000000u)->run(5e6*15);}); - tasks.push_back([=]() { Workspace(name + "_rv32ic_O3").withRiscvRef()->loadHex("../../resources/freertos/" + name + "_rv32ic_O3.hex")->bootAt(0x80000000u)->run(4e6*15);}); + tasks.push_back([=]() { WorkspaceRegression(name + "_rv32ic_O0").withRiscvRef()->loadHex("../../resources/freertos/" + name + "_rv32ic_O0.hex")->bootAt(0x80000000u)->run(5e6*15);}); + tasks.push_back([=]() { WorkspaceRegression(name + "_rv32ic_O3").withRiscvRef()->loadHex("../../resources/freertos/" + name + "_rv32ic_O3.hex")->bootAt(0x80000000u)->run(4e6*15);}); #endif #if defined(MUL) && defined(DIV) #ifdef COMPRESSED - tasks.push_back([=]() { Workspace(name + "_rv32imac_O3").withRiscvRef()->loadHex("../../resources/freertos/" + name + "_rv32imac_O3.hex")->bootAt(0x80000000u)->run(4e6*15);}); + tasks.push_back([=]() { WorkspaceRegression(name + "_rv32imac_O3").withRiscvRef()->loadHex("../../resources/freertos/" + name + "_rv32imac_O3.hex")->bootAt(0x80000000u)->run(4e6*15);}); #else - tasks.push_back([=]() { Workspace(name + "_rv32im_O3").withRiscvRef()->loadHex("../../resources/freertos/" + name + "_rv32im_O3.hex")->bootAt(0x80000000u)->run(4e6*15);}); + tasks.push_back([=]() { WorkspaceRegression(name + "_rv32im_O3").withRiscvRef()->loadHex("../../resources/freertos/" + name + "_rv32im_O3.hex")->bootAt(0x80000000u)->run(4e6*15);}); #endif #endif } diff --git a/src/test/cpp/regression/makefile b/src/test/cpp/regression/makefile index 1037feb9..f44cd598 100644 --- a/src/test/cpp/regression/makefile +++ b/src/test/cpp/regression/makefile @@ -48,6 +48,13 @@ else endif + +ifeq ($(LITEX),yes) + ADDCFLAGS += -CFLAGS -DLITEX + ADDCFLAGS += -CFLAGS -DVMLINUX='\"$(VMLINUX)\"' + ADDCFLAGS += -CFLAGS -DRAMDISK='\"$(RAMDISK)\"' +endif + ifneq ($(shell grep timerInterrupt ../../../../VexRiscv.v -w),) ADDCFLAGS += -CFLAGS -DTIMER_INTERRUPT endif From e28702eb40556983c62c5f63a25ef8b7cee71bcb Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sun, 24 Mar 2019 12:17:39 +0100 Subject: [PATCH 072/951] Add PlicCost test --- .../vexriscv/experimental/PlicCost.scala | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 src/test/scala/vexriscv/experimental/PlicCost.scala diff --git a/src/test/scala/vexriscv/experimental/PlicCost.scala b/src/test/scala/vexriscv/experimental/PlicCost.scala new file mode 100644 index 00000000..6f044e64 --- /dev/null +++ b/src/test/scala/vexriscv/experimental/PlicCost.scala @@ -0,0 +1,76 @@ +package vexriscv.experimental + +import spinal.core._ +import spinal.lib._ +import spinal.lib.bus.amba3.apb._ +import spinal.lib.eda.bench.{Bench, Rtl, XilinxStdTargets} +import spinal.lib.eda.icestorm.IcestormStdTargets +import spinal.lib.misc.plic._ +import vexriscv.VexRiscv +import vexriscv.demo.LinuxGen + +import scala.collection.mutable.ArrayBuffer + +class PlicBench(inputCount : Int) extends Component{ + val io = new Bundle { + val apb = slave(Apb3(addressWidth = 16, dataWidth = 32)) + val interrupts = in Bits(inputCount bits) + val cpuInterrupt = out Bool() + } + + + val priorityWidth = 1 + val gateways = ArrayBuffer[PlicGateway]() + + for(i <- 0 until inputCount) { + gateways += PlicGatewayActiveHigh( + source = io.interrupts(i), + id = 1 + i, + priorityWidth = priorityWidth + ) + } + + + val targets = Seq( + PlicTarget( + gateways = gateways, + priorityWidth = priorityWidth + ) + ) + io.cpuInterrupt := targets(0).iep + + val plicMapping = PlicMapping.light.copy( + // gatewayPriorityReadGen = true, + // gatewayPendingReadGen = true, + // targetThresholdReadGen = true + ) + + gateways.foreach(_.priority := 1) + targets.foreach(_.threshold := 0) + // targets.foreach(_.ie.foreach(_ := True)) + + val bus = Apb3SlaveFactory(io.apb) + val mapping = PlicMapper(bus, plicMapping)( + gateways = gateways, + targets = targets + ) +} + + +object PlicCost extends App{ + def rtlGen(inputCount : Int) = new Rtl { + override def getName(): String = s"PlicBench$inputCount" + override def getRtlPath(): String = s"PlicBench$inputCount.v" + SpinalVerilog(new PlicBench(inputCount).setDefinitionName(getRtlPath().split("\\.").head)) + } + + val rtls = List(8, 12, 16, 32).map(rtlGen) + // val rtls = List(smallestNoCsr, smallest, smallAndProductive, smallAndProductiveWithICache) + // val rtls = List(smallAndProductive, smallAndProductiveWithICache, fullNoMmuMaxPerf, fullNoMmu, full) + // val rtls = List(fullNoMmu) + + val targets = IcestormStdTargets().take(1) + + + Bench(rtls, targets, "/eda/tmp") +} From 9d55283b3ba2ff14dc8f6438acc0cb806ab16a75 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 25 Mar 2019 02:00:19 +0100 Subject: [PATCH 073/951] Machine mode emulator --- src/main/c/common/ram.ld | 151 ++++++ src/main/c/common/riscv64-unknown-elf.mk | 16 + src/main/c/common/standalone.mk | 74 +++ src/main/c/emulator/.gitignore | 4 + src/main/c/emulator/build/emulator.asm | 509 ++++++++++++++++++ src/main/c/emulator/build/emulator.hex | 80 +++ src/main/c/emulator/makefile | 17 + src/main/c/emulator/src/config.h | 10 + src/main/c/emulator/src/main.c | 109 ++++ src/main/c/emulator/src/riscv.h | 107 ++++ src/main/c/emulator/src/start.S | 51 ++ src/main/c/emulator/src/trap.S | 71 +++ src/main/scala/vexriscv/demo/Linux.scala | 21 +- .../scala/vexriscv/plugin/CsrPlugin.scala | 8 +- src/test/cpp/regression/main.cpp | 29 +- src/test/cpp/regression/makefile | 8 + 16 files changed, 1255 insertions(+), 10 deletions(-) create mode 100755 src/main/c/common/ram.ld create mode 100644 src/main/c/common/riscv64-unknown-elf.mk create mode 100644 src/main/c/common/standalone.mk create mode 100644 src/main/c/emulator/.gitignore create mode 100644 src/main/c/emulator/build/emulator.asm create mode 100644 src/main/c/emulator/build/emulator.hex create mode 100755 src/main/c/emulator/makefile create mode 100644 src/main/c/emulator/src/config.h create mode 100755 src/main/c/emulator/src/main.c create mode 100644 src/main/c/emulator/src/riscv.h create mode 100755 src/main/c/emulator/src/start.S create mode 100644 src/main/c/emulator/src/trap.S diff --git a/src/main/c/common/ram.ld b/src/main/c/common/ram.ld new file mode 100755 index 00000000..19dc3d95 --- /dev/null +++ b/src/main/c/common/ram.ld @@ -0,0 +1,151 @@ +OUTPUT_ARCH( "riscv" ) + +ENTRY( _start ) + +MEMORY +{ + ram : ORIGIN = 0x80000000, LENGTH = 64k +} + + +SECTIONS +{ + __stack_size = DEFINED(__stack_size) ? __stack_size : 2K; + + .init : + { + KEEP (*(SORT_NONE(.init))) + }> ram + + .text : + { + *(.text.unlikely .text.unlikely.*) + *(.text.startup .text.startup.*) + *(.text .text.*) + *(.gnu.linkonce.t.*) + *(.note.gnu.build-id) + } > ram + + .fini : + { + KEEP (*(SORT_NONE(.fini))) + } > ram + + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + + . = ALIGN(4); + + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } > ram + + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) + KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors)) + PROVIDE_HIDDEN (__init_array_end = .); + } > ram + + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*))) + KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors)) + PROVIDE_HIDDEN (__fini_array_end = .); + } > ram + + .ctors : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*crtbegin?.o(.ctors)) + /* We don't want to include the .ctor section from + the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } > ram + + .dtors : + { + KEEP (*crtbegin.o(.dtors)) + KEEP (*crtbegin?.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } > ram + + .lalign : + { + . = ALIGN(4); + PROVIDE( _data_lma = . ); + } > ram + + .dalign : + { + . = ALIGN(4); + PROVIDE( _data = . ); + } > ram + + .data : + { + *(.rdata) + *(.rodata .rodata.*) + *(.gnu.linkonce.r.*) + *(.data .data.*) + *(.gnu.linkonce.d.*) + . = ALIGN(8); + PROVIDE( __global_pointer$ = . + 0x800 ); + *(.sdata .sdata.*) + *(.gnu.linkonce.s.*) + . = ALIGN(8); + *(.srodata.cst16) + *(.srodata.cst8) + *(.srodata.cst4) + *(.srodata.cst2) + *(.srodata .srodata.*) + } >ram + + . = ALIGN(4); + PROVIDE( _edata = . ); + PROVIDE( edata = . ); + + PROVIDE( _fbss = . ); + PROVIDE( __bss_start = . ); + .bss : + { + *(.sbss*) + *(.gnu.linkonce.sb.*) + *(.bss .bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(4); + } >ram + + . = ALIGN(8); + PROVIDE( _end = . ); + PROVIDE( end = . ); + + .stack : + { + PROVIDE( _heap_end = . ); + . = __stack_size; + PROVIDE( _sp = . ); + } > ram +} diff --git a/src/main/c/common/riscv64-unknown-elf.mk b/src/main/c/common/riscv64-unknown-elf.mk new file mode 100644 index 00000000..e17a9d18 --- /dev/null +++ b/src/main/c/common/riscv64-unknown-elf.mk @@ -0,0 +1,16 @@ +RISCV_BIN ?= riscv64-unknown-elf- +RISCV_CC=${RISCV_BIN}gcc +RISCV_OBJCOPY=${RISCV_BIN}objcopy +RISCV_OBJDUMP=${RISCV_BIN}objdump + +MARCH := rv32i +ifeq ($(MULDIV),yes) + MARCH := $(MARCH)M +endif +ifeq ($(COMPRESSED),yes) + MARCH := $(MARCH)AC +endif + +CFLAGS += -march=$(MARCH) -mabi=ilp32 -DUSE_GP +LDFLAGS += -march=$(MARCH) -mabi=ilp32 + diff --git a/src/main/c/common/standalone.mk b/src/main/c/common/standalone.mk new file mode 100644 index 00000000..88328a2a --- /dev/null +++ b/src/main/c/common/standalone.mk @@ -0,0 +1,74 @@ + + +LDFLAGS += -lc + +CFLAGS += -I${STANDALONE}/include + + + + +ifeq ($(DEBUG),yes) + CFLAGS += -g3 -Og +endif + +ifeq ($(DEBUG),no) + CFLAGS += -O3 +endif + + +LDFLAGS += -nostdlib -lgcc -nostartfiles -ffreestanding -Wl,-Bstatic,-T,$(LDSCRIPT),-Map,$(OBJDIR)/$(PROJ_NAME).map,--print-memory-usage + + + +OBJDIR ?= build +OBJS := $(SRCS) +OBJS := $(OBJS:.c=.o) +OBJS := $(OBJS:.cpp=.o) +OBJS := $(OBJS:.S=.o) +OBJS := $(OBJS:..=miaou) +OBJS := $(addprefix $(OBJDIR)/,$(OBJS)) + + + +all: $(OBJDIR)/$(PROJ_NAME).elf $(OBJDIR)/$(PROJ_NAME).hex $(OBJDIR)/$(PROJ_NAME).asm $(OBJDIR)/$(PROJ_NAME).bin + +$(OBJDIR)/%.elf: $(OBJS) | $(OBJDIR) + $(RISCV_CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) $(LIBS) + +%.hex: %.elf + $(RISCV_OBJCOPY) -O ihex $^ $@ + +%.bin: %.elf + $(RISCV_OBJCOPY) -O binary $^ $@ + +%.v: %.elf + $(RISCV_OBJCOPY) -O verilog $^ $@ + +%.asm: %.elf + $(RISCV_OBJDUMP) -S -d $^ > $@ + +$(OBJDIR)/%.o: %.c + mkdir -p $(dir $@) + $(RISCV_CC) -c $(CFLAGS) $(INC) -o $@ $^ + +$(OBJDIR)/%.o: %.cpp + mkdir -p $(dir $@) + $(RISCV_CC) -c $(CFLAGS) $(INC) -o $@ $^ + +$(OBJDIR)/%.o: %.S + mkdir -p $(dir $@) + $(RISCV_CC) -c $(CFLAGS) -o $@ $^ -D__ASSEMBLY__=1 + +$(OBJDIR): + mkdir -p $@ + +clean: + rm -f $(OBJDIR)/$(PROJ_NAME).elf + rm -f $(OBJDIR)/$(PROJ_NAME).hex + rm -f $(OBJDIR)/$(PROJ_NAME).map + rm -f $(OBJDIR)/$(PROJ_NAME).v + rm -f $(OBJDIR)/$(PROJ_NAME).bin + rm -f $(OBJDIR)/$(PROJ_NAME).asm + find $(OBJDIR) -type f -name '*.o' -print0 | xargs -0 -r rm + +.SECONDARY: $(OBJS) \ No newline at end of file diff --git a/src/main/c/emulator/.gitignore b/src/main/c/emulator/.gitignore new file mode 100644 index 00000000..c12cb2c2 --- /dev/null +++ b/src/main/c/emulator/.gitignore @@ -0,0 +1,4 @@ +*.map +*.v +*.elf +*.o \ No newline at end of file diff --git a/src/main/c/emulator/build/emulator.asm b/src/main/c/emulator/build/emulator.asm new file mode 100644 index 00000000..58931887 --- /dev/null +++ b/src/main/c/emulator/build/emulator.asm @@ -0,0 +1,509 @@ + +build/emulator.elf: file format elf32-littleriscv + + +Disassembly of section .init: + +80000000 <_start>: +.option push +.option norelax + la gp, __global_pointer$ +.option pop +#endif*/ + la sp, _sp +80000000: 00001117 auipc sp,0x1 +80000004: cb010113 addi sp,sp,-848 # 80000cb0 <_sp> + + + /* Load data section */ + la a0, _data_lma +80000008: 00000517 auipc a0,0x0 +8000000c: 43450513 addi a0,a0,1076 # 8000043c <__init_array_end> + la a1, _data +80000010: 00000597 auipc a1,0x0 +80000014: 42c58593 addi a1,a1,1068 # 8000043c <__init_array_end> + la a2, _edata +80000018: 00000617 auipc a2,0x0 +8000001c: 49860613 addi a2,a2,1176 # 800004b0 <__bss_start> + bgeu a1, a2, 2f +80000020: 00c5fc63 bleu a2,a1,80000038 <_start+0x38> +1: + lw t0, (a0) +80000024: 00052283 lw t0,0(a0) + sw t0, (a1) +80000028: 0055a023 sw t0,0(a1) + addi a0, a0, 4 +8000002c: 00450513 addi a0,a0,4 + addi a1, a1, 4 +80000030: 00458593 addi a1,a1,4 + bltu a1, a2, 1b +80000034: fec5e8e3 bltu a1,a2,80000024 <_start+0x24> +2: + + /* Clear bss section */ + la a0, __bss_start +80000038: 00000517 auipc a0,0x0 +8000003c: 47850513 addi a0,a0,1144 # 800004b0 <__bss_start> + la a1, _end +80000040: 00000597 auipc a1,0x0 +80000044: 47058593 addi a1,a1,1136 # 800004b0 <__bss_start> + bgeu a0, a1, 2f +80000048: 00b57863 bleu a1,a0,80000058 <_start+0x58> +1: + sw zero, (a0) +8000004c: 00052023 sw zero,0(a0) + addi a0, a0, 4 +80000050: 00450513 addi a0,a0,4 + bltu a0, a1, 1b +80000054: feb56ce3 bltu a0,a1,8000004c <_start+0x4c> +2: + + call __libc_init_array +80000058: 34c000ef jal ra,800003a4 <__libc_init_array> + call init +8000005c: 128000ef jal ra,80000184 + la ra, done +80000060: 00000097 auipc ra,0x0 +80000064: 01408093 addi ra,ra,20 # 80000074 + li a0, DTB +80000068: 81000537 lui a0,0x81000 + li a1, 0 +8000006c: 00000593 li a1,0 + mret +80000070: 30200073 mret + +80000074 : +done: + j done +80000074: 0000006f j 80000074 + +80000078 <_init>: + + + .globl _init +_init: + ret +80000078: 00008067 ret + +8000007c : + .section .init + .globl trapEntry + .type trapEntry,@function + +trapEntry: + csrrw sp, mscratch, sp +8000007c: 34011173 csrrw sp,mscratch,sp + sw x0, 0*4(sp) +80000080: 00012023 sw zero,0(sp) + sw x1, 1*4(sp) +80000084: 00112223 sw ra,4(sp) + sw x3, 3*4(sp) +80000088: 00312623 sw gp,12(sp) + sw x4, 4*4(sp) +8000008c: 00412823 sw tp,16(sp) + sw x5, 5*4(sp) +80000090: 00512a23 sw t0,20(sp) + sw x6, 6*4(sp) +80000094: 00612c23 sw t1,24(sp) + sw x7, 7*4(sp) +80000098: 00712e23 sw t2,28(sp) + sw x8, 8*4(sp) +8000009c: 02812023 sw s0,32(sp) + sw x9, 9*4(sp) +800000a0: 02912223 sw s1,36(sp) + sw x10, 10*4(sp) +800000a4: 02a12423 sw a0,40(sp) + sw x11, 11*4(sp) +800000a8: 02b12623 sw a1,44(sp) + sw x12, 12*4(sp) +800000ac: 02c12823 sw a2,48(sp) + sw x13, 13*4(sp) +800000b0: 02d12a23 sw a3,52(sp) + sw x14, 14*4(sp) +800000b4: 02e12c23 sw a4,56(sp) + sw x15, 15*4(sp) +800000b8: 02f12e23 sw a5,60(sp) + sw x16, 16*4(sp) +800000bc: 05012023 sw a6,64(sp) + sw x17, 17*4(sp) +800000c0: 05112223 sw a7,68(sp) + sw x18, 18*4(sp) +800000c4: 05212423 sw s2,72(sp) + sw x19, 19*4(sp) +800000c8: 05312623 sw s3,76(sp) + sw x20, 20*4(sp) +800000cc: 05412823 sw s4,80(sp) + sw x21, 21*4(sp) +800000d0: 05512a23 sw s5,84(sp) + sw x22, 22*4(sp) +800000d4: 05612c23 sw s6,88(sp) + sw x23, 23*4(sp) +800000d8: 05712e23 sw s7,92(sp) + sw x24, 24*4(sp) +800000dc: 07812023 sw s8,96(sp) + sw x25, 25*4(sp) +800000e0: 07912223 sw s9,100(sp) + sw x26, 26*4(sp) +800000e4: 07a12423 sw s10,104(sp) + sw x27, 27*4(sp) +800000e8: 07b12623 sw s11,108(sp) + sw x28, 28*4(sp) +800000ec: 07c12823 sw t3,112(sp) + sw x29, 29*4(sp) +800000f0: 07d12a23 sw t4,116(sp) + sw x30, 30*4(sp) +800000f4: 07e12c23 sw t5,120(sp) + sw x31, 31*4(sp) +800000f8: 07f12e23 sw t6,124(sp) + call trap +800000fc: 134000ef jal ra,80000230 + lw x0, 0*4(sp) +80000100: 00012003 lw zero,0(sp) + lw x1, 1*4(sp) +80000104: 00412083 lw ra,4(sp) + lw x3, 3*4(sp) +80000108: 00c12183 lw gp,12(sp) + lw x4, 4*4(sp) +8000010c: 01012203 lw tp,16(sp) + lw x5, 5*4(sp) +80000110: 01412283 lw t0,20(sp) + lw x6, 6*4(sp) +80000114: 01812303 lw t1,24(sp) + lw x7, 7*4(sp) +80000118: 01c12383 lw t2,28(sp) + lw x8, 8*4(sp) +8000011c: 02012403 lw s0,32(sp) + lw x9, 9*4(sp) +80000120: 02412483 lw s1,36(sp) + lw x10, 10*4(sp) +80000124: 02812503 lw a0,40(sp) + lw x11, 11*4(sp) +80000128: 02c12583 lw a1,44(sp) + lw x12, 12*4(sp) +8000012c: 03012603 lw a2,48(sp) + lw x13, 13*4(sp) +80000130: 03412683 lw a3,52(sp) + lw x14, 14*4(sp) +80000134: 03812703 lw a4,56(sp) + lw x15, 15*4(sp) +80000138: 03c12783 lw a5,60(sp) + lw x16, 16*4(sp) +8000013c: 04012803 lw a6,64(sp) + lw x17, 17*4(sp) +80000140: 04412883 lw a7,68(sp) + lw x18, 18*4(sp) +80000144: 04812903 lw s2,72(sp) + lw x19, 19*4(sp) +80000148: 04c12983 lw s3,76(sp) + lw x20, 20*4(sp) +8000014c: 05012a03 lw s4,80(sp) + lw x21, 21*4(sp) +80000150: 05412a83 lw s5,84(sp) + lw x22, 22*4(sp) +80000154: 05812b03 lw s6,88(sp) + lw x23, 23*4(sp) +80000158: 05c12b83 lw s7,92(sp) + lw x24, 24*4(sp) +8000015c: 06012c03 lw s8,96(sp) + lw x25, 25*4(sp) +80000160: 06412c83 lw s9,100(sp) + lw x26, 26*4(sp) +80000164: 06812d03 lw s10,104(sp) + lw x27, 27*4(sp) +80000168: 06c12d83 lw s11,108(sp) + lw x28, 28*4(sp) +8000016c: 07012e03 lw t3,112(sp) + lw x29, 29*4(sp) +80000170: 07412e83 lw t4,116(sp) + lw x30, 30*4(sp) +80000174: 07812f03 lw t5,120(sp) + lw x31, 31*4(sp) +80000178: 07c12f83 lw t6,124(sp) + csrrw sp, mscratch, sp +8000017c: 34011173 csrrw sp,mscratch,sp + mret +80000180: 30200073 mret + +Disassembly of section .text: + +80000184 : + +extern const unsigned int _sp; +extern void trapEntry(); + +void init() { + csr_write(mtvec, trapEntry); +80000184: 800007b7 lui a5,0x80000 +80000188: 07c78793 addi a5,a5,124 # 8000007c <_sp+0xfffff3cc> +8000018c: 30579073 csrw mtvec,a5 + + unsigned int sp = (unsigned int) (&_sp); +80000190: 800017b7 lui a5,0x80001 +80000194: cb078793 addi a5,a5,-848 # 80000cb0 <_sp+0x0> + csr_write(mscratch, sp -32*4); +80000198: f8078793 addi a5,a5,-128 +8000019c: 34079073 csrw mscratch,a5 + csr_write(mstatus, 0x0800); +800001a0: 000017b7 lui a5,0x1 +800001a4: 80078793 addi a5,a5,-2048 # 800 <__stack_size> +800001a8: 30079073 csrw mstatus,a5 + csr_write(mepc, OS_CALL); +800001ac: c00007b7 lui a5,0xc0000 +800001b0: 34179073 csrw mepc,a5 + csr_write(medeleg, MDELEG_INSTRUCTION_PAGE_FAULT | MDELEG_LOAD_PAGE_FAULT | MDELEG_STORE_PAGE_FAULT); +800001b4: 0000b7b7 lui a5,0xb +800001b8: 30279073 csrw medeleg,a5 +} +800001bc: 00008067 ret + +800001c0 : + +int readRegister(int id){ + unsigned int sp = (unsigned int) (&_sp); + return ((int*) sp)[id-32]; +800001c0: 00251513 slli a0,a0,0x2 +800001c4: 800017b7 lui a5,0x80001 +800001c8: cb078793 addi a5,a5,-848 # 80000cb0 <_sp+0x0> +800001cc: 00f50533 add a0,a0,a5 +} +800001d0: f8052503 lw a0,-128(a0) # 80ffff80 <_sp+0xfff2d0> +800001d4: 00008067 ret + +800001d8 : +void writeRegister(int id, int value){ + unsigned int sp = (unsigned int) (&_sp); + ((int*) sp)[id-32] = value; +800001d8: 00251513 slli a0,a0,0x2 +800001dc: 800017b7 lui a5,0x80001 +800001e0: cb078793 addi a5,a5,-848 # 80000cb0 <_sp+0x0> +800001e4: 00f50533 add a0,a0,a5 +800001e8: f8b52023 sw a1,-128(a0) +} +800001ec: 00008067 ret + +800001f0 : + + +void stopSim(){ + *((volatile int*) SIM_STOP) = 0; +800001f0: fe002e23 sw zero,-4(zero) # fffffffc <_sp+0x7ffff34c> +} +800001f4: 00008067 ret + +800001f8 : + +void putC(char c){ + *((volatile int*) PUTC) = c; +800001f8: fea02c23 sw a0,-8(zero) # fffffff8 <_sp+0x7ffff348> +} +800001fc: 00008067 ret + +80000200 : + + +void redirectTrap(){ +80000200: ff010113 addi sp,sp,-16 +80000204: 00112623 sw ra,12(sp) + stopSim(); +80000208: fe9ff0ef jal ra,800001f0 + csr_write(sbadaddr, csr_read(mbadaddr)); +8000020c: 343027f3 csrr a5,mbadaddr +80000210: 14379073 csrw sbadaddr,a5 + csr_write(sepc, csr_read(mepc)); +80000214: 341027f3 csrr a5,mepc +80000218: 14179073 csrw sepc,a5 + csr_write(scause, csr_read(mcause)); +8000021c: 342027f3 csrr a5,mcause +80000220: 14279073 csrw scause,a5 +} +80000224: 00c12083 lw ra,12(sp) +80000228: 01010113 addi sp,sp,16 +8000022c: 00008067 ret + +80000230 : +#define min(a,b) \ + ({ __typeof__ (a) _a = (a); \ + __typeof__ (b) _b = (b); \ + _a < _b ? _a : _b; }) + +void trap(){ +80000230: fe010113 addi sp,sp,-32 +80000234: 00112e23 sw ra,28(sp) +80000238: 00812c23 sw s0,24(sp) +8000023c: 00912a23 sw s1,20(sp) +80000240: 01212823 sw s2,16(sp) +80000244: 01312623 sw s3,12(sp) + int cause = csr_read(mcause); +80000248: 342027f3 csrr a5,mcause + if(cause < 0){ +8000024c: 0207ca63 bltz a5,80000280 + redirectTrap(); + } else { + switch(cause){ +80000250: 00200713 li a4,2 +80000254: 02e78a63 beq a5,a4,80000288 +80000258: 00900713 li a4,9 +8000025c: 10e78863 beq a5,a4,8000036c + csr_write(mepc, csr_read(mepc) + 4); + }break; + default: stopSim(); break; + } + }break; + default: redirectTrap(); break; +80000260: fa1ff0ef jal ra,80000200 + } + } + +} +80000264: 01c12083 lw ra,28(sp) +80000268: 01812403 lw s0,24(sp) +8000026c: 01412483 lw s1,20(sp) +80000270: 01012903 lw s2,16(sp) +80000274: 00c12983 lw s3,12(sp) +80000278: 02010113 addi sp,sp,32 +8000027c: 00008067 ret + redirectTrap(); +80000280: f81ff0ef jal ra,80000200 +80000284: fe1ff06f j 80000264 + int instruction = csr_read(mbadaddr); +80000288: 34302473 csrr s0,mbadaddr + int opcode = instruction & 0x7F; +8000028c: 07f47693 andi a3,s0,127 + int funct3 = (instruction >> 12) & 0x7; +80000290: 40c45793 srai a5,s0,0xc +80000294: 0077f793 andi a5,a5,7 + switch(opcode){ +80000298: 02f00713 li a4,47 +8000029c: fce694e3 bne a3,a4,80000264 + switch(funct3){ +800002a0: 00200713 li a4,2 +800002a4: 0ce79063 bne a5,a4,80000364 + int sel = instruction >> 27; +800002a8: 41b45493 srai s1,s0,0x1b + int*addr = (int*)readRegister((instruction >> 15) & 0x1F); +800002ac: 40f45513 srai a0,s0,0xf +800002b0: 01f57513 andi a0,a0,31 +800002b4: f0dff0ef jal ra,800001c0 +800002b8: 00050993 mv s3,a0 + int src = readRegister((instruction >> 20) & 0x1F); +800002bc: 41445513 srai a0,s0,0x14 +800002c0: 01f57513 andi a0,a0,31 +800002c4: efdff0ef jal ra,800001c0 +800002c8: 00050913 mv s2,a0 + int rd = (instruction >> 7) & 0x1F; +800002cc: 40745413 srai s0,s0,0x7 +800002d0: 01f47513 andi a0,s0,31 + int readValue = *addr; +800002d4: 0009a583 lw a1,0(s3) + switch(sel){ +800002d8: 01c00793 li a5,28 +800002dc: 0897e063 bltu a5,s1,8000035c +800002e0: 00249493 slli s1,s1,0x2 +800002e4: 800007b7 lui a5,0x80000 +800002e8: 43c78793 addi a5,a5,1084 # 8000043c <_sp+0xfffff78c> +800002ec: 00f484b3 add s1,s1,a5 +800002f0: 0004a783 lw a5,0(s1) +800002f4: 00078067 jr a5 + case 0x0: writeValue = src + readValue; break; +800002f8: 00b90933 add s2,s2,a1 + writeRegister(rd, readValue); +800002fc: eddff0ef jal ra,800001d8 + *addr = writeValue; +80000300: 0129a023 sw s2,0(s3) + csr_write(mepc, csr_read(mepc) + 4); +80000304: 341027f3 csrr a5,mepc +80000308: 00478793 addi a5,a5,4 +8000030c: 34179073 csrw mepc,a5 + }break; +80000310: f55ff06f j 80000264 + case 0x4: writeValue = src ^ readValue; break; +80000314: 00b94933 xor s2,s2,a1 +80000318: fe5ff06f j 800002fc + case 0xC: writeValue = src & readValue; break; +8000031c: 00b97933 and s2,s2,a1 +80000320: fddff06f j 800002fc + case 0x8: writeValue = src | readValue; break; +80000324: 00b96933 or s2,s2,a1 +80000328: fd5ff06f j 800002fc + case 0x10: writeValue = min(src, readValue); break; +8000032c: fd25d8e3 ble s2,a1,800002fc +80000330: 00058913 mv s2,a1 +80000334: fc9ff06f j 800002fc + case 0x14: writeValue = max(src, readValue); break; +80000338: fcb952e3 ble a1,s2,800002fc +8000033c: 00058913 mv s2,a1 +80000340: fbdff06f j 800002fc + case 0x18: writeValue = min((unsigned int)src, (unsigned int)readValue); break; +80000344: fb25fce3 bleu s2,a1,800002fc +80000348: 00058913 mv s2,a1 +8000034c: fb1ff06f j 800002fc + case 0x1C: writeValue = max((unsigned int)src, (unsigned int)readValue); break; +80000350: fab976e3 bleu a1,s2,800002fc +80000354: 00058913 mv s2,a1 +80000358: fa5ff06f j 800002fc + default: redirectTrap(); return; break; +8000035c: ea5ff0ef jal ra,80000200 +80000360: f05ff06f j 80000264 + default: redirectTrap(); break; +80000364: e9dff0ef jal ra,80000200 +80000368: efdff06f j 80000264 + int which = readRegister(17); +8000036c: 01100513 li a0,17 +80000370: e51ff0ef jal ra,800001c0 + switch(which){ +80000374: 00100793 li a5,1 +80000378: 02f51263 bne a0,a5,8000039c + putC(readRegister(10)); +8000037c: 00a00513 li a0,10 +80000380: e41ff0ef jal ra,800001c0 +80000384: 0ff57513 andi a0,a0,255 +80000388: e71ff0ef jal ra,800001f8 + csr_write(mepc, csr_read(mepc) + 4); +8000038c: 341027f3 csrr a5,mepc +80000390: 00478793 addi a5,a5,4 +80000394: 34179073 csrw mepc,a5 + }break; +80000398: ecdff06f j 80000264 + default: stopSim(); break; +8000039c: e55ff0ef jal ra,800001f0 +800003a0: ec5ff06f j 80000264 + +800003a4 <__libc_init_array>: +800003a4: ff010113 addi sp,sp,-16 +800003a8: 00812423 sw s0,8(sp) +800003ac: 00912223 sw s1,4(sp) +800003b0: 00000417 auipc s0,0x0 +800003b4: 08c40413 addi s0,s0,140 # 8000043c <__init_array_end> +800003b8: 00000497 auipc s1,0x0 +800003bc: 08448493 addi s1,s1,132 # 8000043c <__init_array_end> +800003c0: 408484b3 sub s1,s1,s0 +800003c4: 01212023 sw s2,0(sp) +800003c8: 00112623 sw ra,12(sp) +800003cc: 4024d493 srai s1,s1,0x2 +800003d0: 00000913 li s2,0 +800003d4: 04991063 bne s2,s1,80000414 <__libc_init_array+0x70> +800003d8: 00000417 auipc s0,0x0 +800003dc: 06440413 addi s0,s0,100 # 8000043c <__init_array_end> +800003e0: 00000497 auipc s1,0x0 +800003e4: 05c48493 addi s1,s1,92 # 8000043c <__init_array_end> +800003e8: 408484b3 sub s1,s1,s0 +800003ec: c8dff0ef jal ra,80000078 <_init> +800003f0: 4024d493 srai s1,s1,0x2 +800003f4: 00000913 li s2,0 +800003f8: 02991863 bne s2,s1,80000428 <__libc_init_array+0x84> +800003fc: 00c12083 lw ra,12(sp) +80000400: 00812403 lw s0,8(sp) +80000404: 00412483 lw s1,4(sp) +80000408: 00012903 lw s2,0(sp) +8000040c: 01010113 addi sp,sp,16 +80000410: 00008067 ret +80000414: 00042783 lw a5,0(s0) +80000418: 00190913 addi s2,s2,1 +8000041c: 00440413 addi s0,s0,4 +80000420: 000780e7 jalr a5 +80000424: fb1ff06f j 800003d4 <__libc_init_array+0x30> +80000428: 00042783 lw a5,0(s0) +8000042c: 00190913 addi s2,s2,1 +80000430: 00440413 addi s0,s0,4 +80000434: 000780e7 jalr a5 +80000438: fc1ff06f j 800003f8 <__libc_init_array+0x54> diff --git a/src/main/c/emulator/build/emulator.hex b/src/main/c/emulator/build/emulator.hex new file mode 100644 index 00000000..f70c1b48 --- /dev/null +++ b/src/main/c/emulator/build/emulator.hex @@ -0,0 +1,80 @@ +:0200000480007A +:1000000017110000130101CB17050000130545432C +:10001000970500009385C542170600001306864920 +:1000200063FCC5008322050023A05500130545008D +:1000300093854500E3E8C5FE1705000013058547D5 +:1000400097050000938505476378B50023200500D8 +:1000500013054500E36CB5FEEF00C034EF008012DD +:100060009700000093804001370500819305000050 +:10007000730020306F0000006780000073110134AE +:1000800023200100232211002326310023284100D0 +:10009000232A5100232C6100232E7100232081028A +:1000A000232291022324A1022326B1022328C10284 +:1000B000232AD102232CE102232EF1022320010561 +:1000C0002322110523242105232631052328410558 +:1000D000232A5105232C6105232E71052320810736 +:1000E000232291072324A1072326B1072328C10730 +:1000F000232AD107232CE107232EF107EF00401319 +:1001000003200100832041008321C100032201015B +:1001100083224101032381018323C10103240102BE +:1001200083244102032581028325C10203260103A2 +:1001300083264103032781038327C1030328010486 +:1001400083284104032981048329C104032A01056A +:10015000832A4105032B8105832BC105032C01064E +:10016000832C4106032D8106832DC106032E010732 +:10017000832E4107032F8107832FC1077311013499 +:0401800073002030B8 +:10018400B70700809387C70773905730B71700806D +:10019400938707CB938707F873900734B71700004A +:1001A4009387078073900730B70700C073901734A4 +:1001B400B7B700007390273067800000131525003F +:1001C400B7170080938707CB3305F500032505F89F +:1001D4006780000013152500B7170080938707CBAD +:1001E4003305F5002320B5F867800000232E00FEB8 +:1001F40067800000232CA0FE67800000130101FF2C +:1002040023261100EFF09FFEF32730347390371448 +:10021400F327103473901714F327203473902714A2 +:100224008320C1001301010167800000130101FE56 +:10023400232E1100232C8100232A9100232821013D +:1002440023263101F327203463CA07021307200051 +:10025400638AE702130790006388E710EFF01FFA40 +:100264008320C10103248101832441010329010165 +:100274008329C1001301010267800000EFF01FF819 +:100284006FF01FFE732430349376F4079357C44001 +:1002940093F777001307F002E394E6FC13072000BA +:1002A4006390E70C9354B4411355F4401375F5016E +:1002B400EFF0DFF093090500135544411375F50180 +:1002C400EFF0DFEF13090500135474401375F401C4 +:1002D40083A509009307C00163E097089394240061 +:1002E400B70700809387C743B384F40083A704004F +:1002F400678007003309B900EFF0DFED23A029017F +:10030400F327103493874700739017346FF05FF529 +:100314003349B9006FF05FFE3379B9006FF0DFFD48 +:100324003369B9006FF05FFDE3D825FD138905003B +:100334006FF09FFCE352B9FC138905006FF0DFFBFB +:10034400E3FC25FB138905006FF01FFBE376B9FA84 +:10035400138905006FF05FFAEFF05FEA6FF05FF06A +:10036400EFF0DFE96FF0DFEF13051001EFF01FE5A9 +:10037400930710006312F5021305A000EFF01FE4C9 +:100384001375F50FEFF01FE7F32710349387470039 +:10039400739017346FF0DFECEFF05FE56FF05FEC14 +:1003A400130101FF2324810023229100170400007C +:1003B4001304C4089704000093844408B38484405D +:1003C400232021012326110093D424401309000083 +:1003D40063109904170400001304440697040000F2 +:1003E4009384C405B3848440EFF0DFC893D42440DD +:1003F40013090000631899028320C10003248100BB +:1004040083244100032901001301010167800000D6 +:10041400832704001309190013044400E78007002C +:100424006FF01FFB83270400130919001304440011 +:08043400E78007006FF01FFCD8 +:10043C00F8020080FC0200805C0300805C030080FA +:10044C00140300805C0300805C0300805C0300806C +:10045C00240300805C0300805C0300805C0300804C +:10046C001C0300805C0300805C0300805C03008044 +:10047C002C0300805C0300805C0300805C03008024 +:10048C00380300805C0300805C0300805C03008008 +:10049C00440300805C0300805C0300805C030080EC +:0404AC005003008079 +:040000058000000077 +:00000001FF diff --git a/src/main/c/emulator/makefile b/src/main/c/emulator/makefile new file mode 100755 index 00000000..348a1134 --- /dev/null +++ b/src/main/c/emulator/makefile @@ -0,0 +1,17 @@ +PROJ_NAME=emulator +DEBUG=yes +MULDIV=no +COMPRESSED=no +STANDALONE = .. + + +SRCS = $(wildcard src/*.c) \ + $(wildcard src/*.cpp) \ + $(wildcard src/*.S) + + +LDSCRIPT = ${STANDALONE}/common/ram.ld + +include ${STANDALONE}/common/riscv64-unknown-elf.mk +include ${STANDALONE}/common/standalone.mk + diff --git a/src/main/c/emulator/src/config.h b/src/main/c/emulator/src/config.h new file mode 100644 index 00000000..e39fa657 --- /dev/null +++ b/src/main/c/emulator/src/config.h @@ -0,0 +1,10 @@ +#ifndef CONFIG_H +#define CONFIG_H + +#define OS_CALL 0xC0000000 +#define DTB 0x81000000 +#define SIM_STOP 0xFFFFFFFC +#define PUTC 0xFFFFFFF8 + + +#endif diff --git a/src/main/c/emulator/src/main.c b/src/main/c/emulator/src/main.c new file mode 100755 index 00000000..36090c72 --- /dev/null +++ b/src/main/c/emulator/src/main.c @@ -0,0 +1,109 @@ +#include +#include "riscv.h" +#include "config.h" + +extern const unsigned int _sp; +extern void trapEntry(); + +void init() { + csr_write(mtvec, trapEntry); + + unsigned int sp = (unsigned int) (&_sp); + csr_write(mscratch, sp -32*4); + csr_write(mstatus, 0x0800); + csr_write(mepc, OS_CALL); + csr_write(medeleg, MDELEG_INSTRUCTION_PAGE_FAULT | MDELEG_LOAD_PAGE_FAULT | MDELEG_STORE_PAGE_FAULT); +} + +int readRegister(int id){ + unsigned int sp = (unsigned int) (&_sp); + return ((int*) sp)[id-32]; +} +void writeRegister(int id, int value){ + unsigned int sp = (unsigned int) (&_sp); + ((int*) sp)[id-32] = value; +} + + +void stopSim(){ + *((volatile int*) SIM_STOP) = 0; +} + +void putC(char c){ + *((volatile int*) PUTC) = c; +} + + +void redirectTrap(){ + stopSim(); + csr_write(sbadaddr, csr_read(mbadaddr)); + csr_write(sepc, csr_read(mepc)); + csr_write(scause, csr_read(mcause)); +} + +#define max(a,b) \ + ({ __typeof__ (a) _a = (a); \ + __typeof__ (b) _b = (b); \ + _a > _b ? _a : _b; }) + + +#define min(a,b) \ + ({ __typeof__ (a) _a = (a); \ + __typeof__ (b) _b = (b); \ + _a < _b ? _a : _b; }) + +void trap(){ + int cause = csr_read(mcause); + if(cause < 0){ + redirectTrap(); + } else { + switch(cause){ + case CAUSE_ILLEGAL_INSTRUCTION:{ + int instruction = csr_read(mbadaddr); + int opcode = instruction & 0x7F; + int funct3 = (instruction >> 12) & 0x7; + switch(opcode){ + case 0x2F: //Atomic + switch(funct3){ + case 0x2:{ + int sel = instruction >> 27; + int*addr = (int*)readRegister((instruction >> 15) & 0x1F); + int src = readRegister((instruction >> 20) & 0x1F); + int rd = (instruction >> 7) & 0x1F; + int readValue = *addr; + int writeValue; + switch(sel){ + case 0x0: writeValue = src + readValue; break; + case 0x1: writeValue = src; break; + case 0x4: writeValue = src ^ readValue; break; + case 0xC: writeValue = src & readValue; break; + case 0x8: writeValue = src | readValue; break; + case 0x10: writeValue = min(src, readValue); break; + case 0x14: writeValue = max(src, readValue); break; + case 0x18: writeValue = min((unsigned int)src, (unsigned int)readValue); break; + case 0x1C: writeValue = max((unsigned int)src, (unsigned int)readValue); break; + default: redirectTrap(); return; break; + } + writeRegister(rd, readValue); + *addr = writeValue; + csr_write(mepc, csr_read(mepc) + 4); + }break; + default: redirectTrap(); break; + } + } + }break; + case CAUSE_SCALL:{ + int which = readRegister(17); + switch(which){ + case 1:{ + putC(readRegister(10)); + csr_write(mepc, csr_read(mepc) + 4); + }break; + default: stopSim(); break; + } + }break; + default: redirectTrap(); break; + } + } + +} diff --git a/src/main/c/emulator/src/riscv.h b/src/main/c/emulator/src/riscv.h new file mode 100644 index 00000000..dcb125e5 --- /dev/null +++ b/src/main/c/emulator/src/riscv.h @@ -0,0 +1,107 @@ +#ifndef RISCV_H +#define RISCV_H + +#define CAUSE_ILLEGAL_INSTRUCTION 2 +#define CAUSE_SCALL 9 + +#define MDELEG_INSTRUCTION_PAGE_FAULT (1 << 12) +#define MDELEG_LOAD_PAGE_FAULT (1 << 13) +#define MDELEG_STORE_PAGE_FAULT (1 << 15) + +#define MSTATUS_UIE 0x00000001 +#define MSTATUS_SIE 0x00000002 +#define MSTATUS_HIE 0x00000004 +#define MSTATUS_MIE 0x00000008 +#define MSTATUS_UPIE 0x00000010 +#define MSTATUS_SPIE 0x00000020 +#define MSTATUS_HPIE 0x00000040 +#define MSTATUS_MPIE 0x00000080 +#define MSTATUS_SPP 0x00000100 +#define MSTATUS_HPP 0x00000600 +#define MSTATUS_MPP 0x00001800 +#define MSTATUS_FS 0x00006000 +#define MSTATUS_XS 0x00018000 +#define MSTATUS_MPRV 0x00020000 +#define MSTATUS_SUM 0x00040000 +#define MSTATUS_MXR 0x00080000 +#define MSTATUS_TVM 0x00100000 +#define MSTATUS_TW 0x00200000 +#define MSTATUS_TSR 0x00400000 +#define MSTATUS32_SD 0x80000000 +#define MSTATUS_UXL 0x0000000300000000 +#define MSTATUS_SXL 0x0000000C00000000 +#define MSTATUS64_SD 0x8000000000000000 + +#define SSTATUS_UIE 0x00000001 +#define SSTATUS_SIE 0x00000002 +#define SSTATUS_UPIE 0x00000010 +#define SSTATUS_SPIE 0x00000020 +#define SSTATUS_SPP 0x00000100 +#define SSTATUS_FS 0x00006000 +#define SSTATUS_XS 0x00018000 +#define SSTATUS_SUM 0x00040000 +#define SSTATUS_MXR 0x00080000 +#define SSTATUS32_SD 0x80000000 +#define SSTATUS_UXL 0x0000000300000000 +#define SSTATUS64_SD 0x8000000000000000 + + + +#define csr_swap(csr, val) \ +({ \ + unsigned long __v = (unsigned long)(val); \ + __asm__ __volatile__ ("csrrw %0, " #csr ", %1" \ + : "=r" (__v) : "rK" (__v)); \ + __v; \ +}) + +#define csr_read(csr) \ +({ \ + register unsigned long __v; \ + __asm__ __volatile__ ("csrr %0, " #csr \ + : "=r" (__v)); \ + __v; \ +}) + +#define csr_write(csr, val) \ +({ \ + unsigned long __v = (unsigned long)(val); \ + __asm__ __volatile__ ("csrw " #csr ", %0" \ + : : "rK" (__v)); \ +}) + +#define csr_read_set(csr, val) \ +({ \ + unsigned long __v = (unsigned long)(val); \ + __asm__ __volatile__ ("csrrs %0, " #csr ", %1" \ + : "=r" (__v) : "rK" (__v)); \ + __v; \ +}) + +#define csr_set(csr, val) \ +({ \ + unsigned long __v = (unsigned long)(val); \ + __asm__ __volatile__ ("csrs " #csr ", %0" \ + : : "rK" (__v)); \ +}) + +#define csr_read_clear(csr, val) \ +({ \ + unsigned long __v = (unsigned long)(val); \ + __asm__ __volatile__ ("csrrc %0, " #csr ", %1" \ + : "=r" (__v) : "rK" (__v)); \ + __v; \ +}) + +#define csr_clear(csr, val) \ +({ \ + unsigned long __v = (unsigned long)(val); \ + __asm__ __volatile__ ("csrc " #csr ", %0" \ + : : "rK" (__v)); \ +}) + + + +#endif + + diff --git a/src/main/c/emulator/src/start.S b/src/main/c/emulator/src/start.S new file mode 100755 index 00000000..ef020e3c --- /dev/null +++ b/src/main/c/emulator/src/start.S @@ -0,0 +1,51 @@ + .section .init + .globl _start + .type _start,@function + +#include "config.h" +_start: +/*#ifdef USE_GP +.option push +.option norelax + la gp, __global_pointer$ +.option pop +#endif*/ + la sp, _sp + + + /* Load data section */ + la a0, _data_lma + la a1, _data + la a2, _edata + bgeu a1, a2, 2f +1: + lw t0, (a0) + sw t0, (a1) + addi a0, a0, 4 + addi a1, a1, 4 + bltu a1, a2, 1b +2: + + /* Clear bss section */ + la a0, __bss_start + la a1, _end + bgeu a0, a1, 2f +1: + sw zero, (a0) + addi a0, a0, 4 + bltu a0, a1, 1b +2: + + call __libc_init_array + call init + la ra, done + li a0, DTB + li a1, 0 + mret +done: + j done + + + .globl _init +_init: + ret diff --git a/src/main/c/emulator/src/trap.S b/src/main/c/emulator/src/trap.S new file mode 100644 index 00000000..4746c228 --- /dev/null +++ b/src/main/c/emulator/src/trap.S @@ -0,0 +1,71 @@ + .section .init + .globl trapEntry + .type trapEntry,@function + +trapEntry: + csrrw sp, mscratch, sp + sw x0, 0*4(sp) + sw x1, 1*4(sp) + sw x3, 3*4(sp) + sw x4, 4*4(sp) + sw x5, 5*4(sp) + sw x6, 6*4(sp) + sw x7, 7*4(sp) + sw x8, 8*4(sp) + sw x9, 9*4(sp) + sw x10, 10*4(sp) + sw x11, 11*4(sp) + sw x12, 12*4(sp) + sw x13, 13*4(sp) + sw x14, 14*4(sp) + sw x15, 15*4(sp) + sw x16, 16*4(sp) + sw x17, 17*4(sp) + sw x18, 18*4(sp) + sw x19, 19*4(sp) + sw x20, 20*4(sp) + sw x21, 21*4(sp) + sw x22, 22*4(sp) + sw x23, 23*4(sp) + sw x24, 24*4(sp) + sw x25, 25*4(sp) + sw x26, 26*4(sp) + sw x27, 27*4(sp) + sw x28, 28*4(sp) + sw x29, 29*4(sp) + sw x30, 30*4(sp) + sw x31, 31*4(sp) + call trap + lw x0, 0*4(sp) + lw x1, 1*4(sp) + lw x3, 3*4(sp) + lw x4, 4*4(sp) + lw x5, 5*4(sp) + lw x6, 6*4(sp) + lw x7, 7*4(sp) + lw x8, 8*4(sp) + lw x9, 9*4(sp) + lw x10, 10*4(sp) + lw x11, 11*4(sp) + lw x12, 12*4(sp) + lw x13, 13*4(sp) + lw x14, 14*4(sp) + lw x15, 15*4(sp) + lw x16, 16*4(sp) + lw x17, 17*4(sp) + lw x18, 18*4(sp) + lw x19, 19*4(sp) + lw x20, 20*4(sp) + lw x21, 21*4(sp) + lw x22, 22*4(sp) + lw x23, 23*4(sp) + lw x24, 24*4(sp) + lw x25, 25*4(sp) + lw x26, 26*4(sp) + lw x27, 27*4(sp) + lw x28, 28*4(sp) + lw x29, 29*4(sp) + lw x30, 30*4(sp) + lw x31, 31*4(sp) + csrrw sp, mscratch, sp + mret diff --git a/src/main/scala/vexriscv/demo/Linux.scala b/src/main/scala/vexriscv/demo/Linux.scala index 8eea1ad8..f2a84e89 100644 --- a/src/main/scala/vexriscv/demo/Linux.scala +++ b/src/main/scala/vexriscv/demo/Linux.scala @@ -40,7 +40,20 @@ make run DBUS=SIMPLE IBUS=SIMPLE DHRYSTONE=yes SUPERVISOR=yes CSR=yes COMPRESSED Run linux => sbt "runMain vexriscv.demo.LinuxGen" cd src/test/cpp/regression -make run DBUS=SIMPLE IBUS=SIMPLE SUPERVISOR=yes CSR=yes COMPRESSED=yes LITEX=yes VMLINUX=/home/spinalvm/hdl/linuxDave/vmlinux.bin RAMDISK=/home/spinalvm/hdl/linuxDave/initramdisk_dave TRACE=no +make run DBUS=SIMPLE IBUS=SIMPLE SUPERVISOR=yes CSR=yes COMPRESSED=yes LITEX=yes EMULATOR=/home/spinalvm/hdl/VexRiscv/src/main/c/emulator/build/emulator.bin VMLINUX=/home/spinalvm/hdl/linuxDave/vmlinux.bin DTB=/home/spinalvm/hdl/linuxDave/vmlinux/rv32.dtb RAMDISK=/home/spinalvm/hdl/linuxDave/initramdisk_dave TRACE=no + + + +Other commands (Memo): +cp litex_default_configuration .config +ARCH=riscv CROSS_COMPILE=riscv64-unknown-elf- make -j`nproc` +riscv64-unknown-elf-objcopy -O binary vmlinux vmlinux.bin +riscv64-unknown-elf-objdump -S -d vmlinux > vmlinux.asm + +split -b 1M vmlinux.asm +dtc -O dtb -o rv32.dtb rv32.dts +make run DBUS=SIMPLE IBUS=SIMPLE SUPERVISOR=yes CSR=yes COMPRESSED=yes LITEX=yes EMULATOR=/home/spinalvm/hdl/VexRiscv/src/main/c/emulator/build/emulator.bin VMLINUX=/home/spinalvm/hdl/riscv-linux/vmlinux.bin DTB=/home/spinalvm/hdl/riscv-linux/rv32.dtb RAMDISK=/home/spinalvm/hdl/linuxDave/initramdisk_dave TRACE=yes FLOW_INFO=yes TRACE_START=0000000 + */ object LinuxGen { @@ -188,7 +201,7 @@ object LinuxGen { ) if(withMmu) config.plugins += new MmuPlugin( virtualRange = a => True, - ioRange = (x => if(litex) x(31 downto 28) === 0xB || x(31 downto 28) === 0xE else x(31 downto 28) === 0xF), + ioRange = (x => if(litex) x(31 downto 28) === 0xB || x(31 downto 28) === 0xE || x(31 downto 28) === 0xF else x(31 downto 28) === 0xF), allowUserIo = true ) config @@ -324,10 +337,10 @@ object LinuxSyntesisBench extends App{ val targets = XilinxStdTargets( vivadoArtix7Path = "/eda/Xilinx/Vivado/2017.2/bin" - ) ++ AlteraStdTargets( + )/* ++ AlteraStdTargets( quartusCycloneIVPath = "/eda/intelFPGA_lite/17.0/quartus/bin", quartusCycloneVPath = "/eda/intelFPGA_lite/17.0/quartus/bin" - ) ++ IcestormStdTargets().take(1) + ) ++ IcestormStdTargets().take(1)*/ Bench(rtls, targets, "/eda/tmp") diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index c3e254f5..35866b41 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -798,11 +798,17 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception } } + //Avoid having the fetch confused by the incomming privilege switch + when(hadException){ + fetcher.haltIt() + } + lastStage plug new Area{ import lastStage._ //Manage MRET / SRET instructions when(arbitration.isValid && input(ENV_CTRL) === EnvCtrlEnum.XRET) { + fetcher.haltIt() jumpInterface.valid := True beforeLastStage.arbitration.flushAll := True switch(input(INSTRUCTION)(29 downto 28)){ @@ -852,7 +858,7 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception } } - decode.arbitration.haltByOther setWhen(stagesFromExecute.dropRight(1).map(s => s.arbitration.isValid && s.input(ENV_CTRL) === EnvCtrlEnum.XRET).asBits.orR) + decode.arbitration.haltByOther setWhen(stagesFromExecute.map(s => s.arbitration.isValid && s.input(ENV_CTRL) === EnvCtrlEnum.XRET).asBits.orR) execute plug new Area { import execute._ diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 86ba2d09..f5832ce0 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -444,6 +444,12 @@ public: trap(interrupt, cause, true, value); } void trap(bool interrupt,int32_t cause, bool valueWrite, uint32_t value) { +#ifdef FLOW_INFO + cout << "TRAP " << (interrupt ? "interrupt" : "exception") << " cause=" << cause << " PC=0x" << hex << pc << " val=0x" << hex << value << dec << endl; + if(cause == 9){ + cout << hex << " a7=0x" << regs[17] << " a0=0x" << regs[10] << " a1=0x" << regs[11] << " a2=0x" << regs[12] << dec << endl; + } +#endif //Check leguality of the interrupt if(interrupt) { bool hit = false; @@ -493,8 +499,9 @@ public: if(!interrupt) step(); //As VexRiscv instruction which trap do not reach writeback stage fire } + uint32_t currentInstruction; void ilegalInstruction(){ - trap(0, 2); + trap(0, 2, currentInstruction); } virtual void fail() { @@ -684,6 +691,7 @@ public: return; } } + currentInstruction = i; if ((i & 0x3) == 0x3) { //32 bit switch (i & 0x7F) { @@ -1362,7 +1370,9 @@ public: currentTime = i; - + #ifdef FLOW_INFO + if(i % 100000 == 0) cout << "PROGRESS TRACE_START=" << i << endl; + #endif // dump variables into VCD file and toggle clock @@ -2876,6 +2886,13 @@ public: virtual void dBusAccess(uint32_t addr,bool wr, uint32_t size,uint32_t mask, uint32_t *data, bool *error) { switch(addr){ //TODO Emulate peripherals here + case 0xFFFFFFFC: fail(); break; //Simulation end + case 0xFFFFFFF8: + if(wr){ + cout << (char)*data; + logTraces << (char)*data; + } + break; } Workspace::dBusAccess(addr,wr,size,mask,data,error); @@ -3153,11 +3170,13 @@ int main(int argc, char **argv, char **env) { #ifdef LITEX LitexSoC("linux") .withRiscvRef() - ->loadBin(VMLINUX, 0xc0000000) - ->loadBin(RAMDISK, 0xc2000000) + ->loadBin(EMULATOR, 0x80000000) + ->loadBin(DTB, 0x81000000) + ->loadBin(VMLINUX, 0xc0000000) + ->loadBin(RAMDISK, 0xc2000000) ->setIStall(false) //TODO It currently improve speed but should be removed later ->setDStall(false) - ->bootAt(0xc0000000) + ->bootAt(0x80000000) ->run(0); return 1; #endif diff --git a/src/test/cpp/regression/makefile b/src/test/cpp/regression/makefile index f44cd598..86d5d52e 100644 --- a/src/test/cpp/regression/makefile +++ b/src/test/cpp/regression/makefile @@ -52,9 +52,17 @@ endif ifeq ($(LITEX),yes) ADDCFLAGS += -CFLAGS -DLITEX ADDCFLAGS += -CFLAGS -DVMLINUX='\"$(VMLINUX)\"' + ADDCFLAGS += -CFLAGS -DDTB='\"$(DTB)\"' ADDCFLAGS += -CFLAGS -DRAMDISK='\"$(RAMDISK)\"' + ADDCFLAGS += -CFLAGS -DEMULATOR='\"$(EMULATOR)\"' endif +ifeq ($(FLOW_INFO),yes) + ADDCFLAGS += -CFLAGS -DFLOW_INFO +endif + + + ifneq ($(shell grep timerInterrupt ../../../../VexRiscv.v -w),) ADDCFLAGS += -CFLAGS -DTIMER_INTERRUPT endif From c34f5413a3eaa560fdccb9be31576e3895d6c83e Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 25 Mar 2019 10:30:13 +0100 Subject: [PATCH 074/951] Add MMU MPRIV for easier machinemode emulation #60 --- src/main/scala/vexriscv/Pipeline.scala | 8 ++++---- src/main/scala/vexriscv/VexRiscv.scala | 3 ++- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 2 ++ src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala | 2 +- src/main/scala/vexriscv/plugin/MmuPlugin.scala | 9 ++++++--- 5 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/main/scala/vexriscv/Pipeline.scala b/src/main/scala/vexriscv/Pipeline.scala index 91c5c1f0..6cbf1c7b 100644 --- a/src/main/scala/vexriscv/Pipeline.scala +++ b/src/main/scala/vexriscv/Pipeline.scala @@ -7,14 +7,14 @@ import spinal.lib._ import scala.collection.mutable import scala.collection.mutable.ArrayBuffer -trait PipelineConfig[T] +trait PipelineThing[T] trait Pipeline { type T <: Pipeline val plugins = ArrayBuffer[Plugin[T]]() var stages = ArrayBuffer[Stage]() var unremovableStages = mutable.Set[Stage]() - val configs = mutable.HashMap[PipelineConfig[_], Any]() + val configs = mutable.HashMap[PipelineThing[_], Any]() // val services = ArrayBuffer[Any]() def indexOf(stage : Stage) = stages.indexOf(stage) @@ -37,8 +37,8 @@ trait Pipeline { filtered.head.asInstanceOf[T] } - def update[T](that : PipelineConfig[T], value : T) : Unit = configs(that) = value - def apply[T](that : PipelineConfig[T]) : T = configs(that).asInstanceOf[T] + def update[T](that : PipelineThing[T], value : T) : Unit = configs(that) = value + def apply[T](that : PipelineThing[T]) : T = configs(that).asInstanceOf[T] def build(): Unit ={ plugins.foreach(_.pipeline = this.asInstanceOf[T]) diff --git a/src/main/scala/vexriscv/VexRiscv.scala b/src/main/scala/vexriscv/VexRiscv.scala index 9665a31c..aead2400 100644 --- a/src/main/scala/vexriscv/VexRiscv.scala +++ b/src/main/scala/vexriscv/VexRiscv.scala @@ -42,6 +42,7 @@ case class VexRiscvConfig(){ object REGFILE_WRITE_VALID extends Stageable(Bool) object REGFILE_WRITE_DATA extends Stageable(Bits(32 bits)) + object MPP extends PipelineThing[UInt] object SRC1 extends Stageable(Bits(32 bits)) object SRC2 extends Stageable(Bits(32 bits)) @@ -79,7 +80,7 @@ case class VexRiscvConfig(){ -object RVC_GEN extends PipelineConfig[Boolean] +object RVC_GEN extends PipelineThing[Boolean] class VexRiscv(val config : VexRiscvConfig) extends Component with Pipeline{ type T = VexRiscv import config._ diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 35866b41..eeb7eb1a 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -499,6 +499,8 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception //User CSR ucycleAccess(CSR.UCYCLE, mcycle(31 downto 0)) ucycleAccess(CSR.UCYCLEH, mcycle(63 downto 32)) + + pipeline.update(MPP, mstatus.MPP) } val supervisorCsr = ifGen(supervisorGen) { diff --git a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala index 3e847898..3dc7ad34 100644 --- a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala @@ -271,7 +271,7 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, } if(memoryTranslatorPortConfig != null) { - mmuBus = pipeline.service(classOf[MemoryTranslator]).newTranslationPort(MemoryTranslatorPort.PRIORITY_INSTRUCTION, memoryTranslatorPortConfig) + mmuBus = pipeline.service(classOf[MemoryTranslator]).newTranslationPort(MemoryTranslatorPort.PRIORITY_DATA, memoryTranslatorPortConfig) redoBranch = pipeline.service(classOf[JumpService]).createJumpInterface(pipeline.memory) } } diff --git a/src/main/scala/vexriscv/plugin/MmuPlugin.scala b/src/main/scala/vexriscv/plugin/MmuPlugin.scala index ae515148..682ab744 100644 --- a/src/main/scala/vexriscv/plugin/MmuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/MmuPlugin.scala @@ -87,14 +87,14 @@ class MmuPlugin(virtualRange : UInt => Bool, val csr = pipeline plug new Area{ val status = new Area{ - val sum, mxr = RegInit(False) + val sum, mxr, mprv = RegInit(False) } val satp = new Area { val mode = RegInit(False) val ppn = Reg(UInt(20 bits)) } - for(offset <- List(CSR.MSTATUS, CSR.SSTATUS)) csrService.rw(offset, 19 -> status.mxr, 18 -> status.sum) + for(offset <- List(CSR.MSTATUS, CSR.SSTATUS)) csrService.rw(offset, 19 -> status.mxr, 18 -> status.sum, 17 -> status.mprv) csrService.rw(CSR.SATP, 31 -> satp.mode, 0 -> satp.ppn) //TODO write only ? } @@ -108,7 +108,10 @@ class MmuPlugin(virtualRange : UInt => Bool, val privilegeService = pipeline.serviceElse(classOf[PrivilegeService], PrivilegeServiceDefault()) val entryToReplace = Counter(port.args.portTlbSize) val requireMmuLockup = virtualRange(port.bus.cmd.virtualAddress) && !port.bus.cmd.bypassTranslation && csr.satp.mode - if(!allowMachineModeMmu) requireMmuLockup clearWhen(privilegeService.isMachine()) + if(!allowMachineModeMmu) { + requireMmuLockup clearWhen(!csr.status.mprv && privilegeService.isMachine()) + if(port.priority == MmuPort.PRIORITY_DATA) requireMmuLockup clearWhen(csr.status.mprv && pipeline(config.MPP) === 3) + } when(requireMmuLockup) { port.bus.rsp.physicalAddress := cacheLine.physicalAddress(1) @@ (cacheLine.superPage ? port.bus.cmd.virtualAddress(21 downto 12) | cacheLine.physicalAddress(0)) @@ port.bus.cmd.virtualAddress(11 downto 0) From 1ec11dc03df9530ce1d442137e88edaf4a6460e2 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 25 Mar 2019 11:47:56 +0100 Subject: [PATCH 075/951] Fix mprv --- src/main/scala/vexriscv/plugin/MmuPlugin.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/plugin/MmuPlugin.scala b/src/main/scala/vexriscv/plugin/MmuPlugin.scala index 682ab744..cc98e104 100644 --- a/src/main/scala/vexriscv/plugin/MmuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/MmuPlugin.scala @@ -110,7 +110,7 @@ class MmuPlugin(virtualRange : UInt => Bool, val requireMmuLockup = virtualRange(port.bus.cmd.virtualAddress) && !port.bus.cmd.bypassTranslation && csr.satp.mode if(!allowMachineModeMmu) { requireMmuLockup clearWhen(!csr.status.mprv && privilegeService.isMachine()) - if(port.priority == MmuPort.PRIORITY_DATA) requireMmuLockup clearWhen(csr.status.mprv && pipeline(config.MPP) === 3) + if(port.priority != MmuPort.PRIORITY_DATA) requireMmuLockup clearWhen(csr.status.mprv && pipeline(config.MPP) === 3) } when(requireMmuLockup) { From 1c3fd5c38bc06475f6a4d86ded6d2216b60d7f12 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 25 Mar 2019 12:03:32 +0100 Subject: [PATCH 076/951] Fix mprv and add it into the softare model --- src/main/c/emulator/build/emulator.asm | 484 +++++++++++------- src/main/c/emulator/build/emulator.hex | 120 +++-- src/main/c/emulator/src/main.c | 88 +++- src/main/c/emulator/src/trap.S | 2 + .../scala/vexriscv/plugin/MmuPlugin.scala | 8 +- src/test/cpp/regression/main.cpp | 10 +- .../vexriscv/experimental/PlicCost.scala | 6 +- 7 files changed, 472 insertions(+), 246 deletions(-) diff --git a/src/main/c/emulator/build/emulator.asm b/src/main/c/emulator/build/emulator.asm index 58931887..dffc8975 100644 --- a/src/main/c/emulator/build/emulator.asm +++ b/src/main/c/emulator/build/emulator.asm @@ -12,19 +12,19 @@ Disassembly of section .init: #endif*/ la sp, _sp 80000000: 00001117 auipc sp,0x1 -80000004: cb010113 addi sp,sp,-848 # 80000cb0 <_sp> +80000004: dd810113 addi sp,sp,-552 # 80000dd8 <_sp> /* Load data section */ la a0, _data_lma 80000008: 00000517 auipc a0,0x0 -8000000c: 43450513 addi a0,a0,1076 # 8000043c <__init_array_end> +8000000c: 55c50513 addi a0,a0,1372 # 80000564 <__init_array_end> la a1, _data 80000010: 00000597 auipc a1,0x0 -80000014: 42c58593 addi a1,a1,1068 # 8000043c <__init_array_end> +80000014: 55458593 addi a1,a1,1364 # 80000564 <__init_array_end> la a2, _edata 80000018: 00000617 auipc a2,0x0 -8000001c: 49860613 addi a2,a2,1176 # 800004b0 <__bss_start> +8000001c: 5c060613 addi a2,a2,1472 # 800005d8 <__bss_start> bgeu a1, a2, 2f 80000020: 00c5fc63 bleu a2,a1,80000038 <_start+0x38> 1: @@ -43,10 +43,10 @@ Disassembly of section .init: /* Clear bss section */ la a0, __bss_start 80000038: 00000517 auipc a0,0x0 -8000003c: 47850513 addi a0,a0,1144 # 800004b0 <__bss_start> +8000003c: 5a050513 addi a0,a0,1440 # 800005d8 <__bss_start> la a1, _end 80000040: 00000597 auipc a1,0x0 -80000044: 47058593 addi a1,a1,1136 # 800004b0 <__bss_start> +80000044: 59858593 addi a1,a1,1432 # 800005d8 <__bss_start> bgeu a0, a1, 2f 80000048: 00b57863 bleu a1,a0,80000058 <_start+0x58> 1: @@ -59,7 +59,7 @@ Disassembly of section .init: 2: call __libc_init_array -80000058: 34c000ef jal ra,800003a4 <__libc_init_array> +80000058: 474000ef jal ra,800004cc <__libc_init_array> call init 8000005c: 128000ef jal ra,80000184 la ra, done @@ -156,7 +156,7 @@ trapEntry: sw x31, 31*4(sp) 800000f8: 07f12e23 sw t6,124(sp) call trap -800000fc: 134000ef jal ra,80000230 +800000fc: 1e8000ef jal ra,800002e4 lw x0, 0*4(sp) 80000100: 00012003 lw zero,0(sp) lw x1, 1*4(sp) @@ -227,20 +227,18 @@ trapEntry: Disassembly of section .text: 80000184 : - -extern const unsigned int _sp; extern void trapEntry(); +extern void emulationTrap(); void init() { + unsigned int sp = (unsigned int) (&_sp); csr_write(mtvec, trapEntry); 80000184: 800007b7 lui a5,0x80000 -80000188: 07c78793 addi a5,a5,124 # 8000007c <_sp+0xfffff3cc> +80000188: 07c78793 addi a5,a5,124 # 8000007c <_sp+0xfffff2a4> 8000018c: 30579073 csrw mtvec,a5 - - unsigned int sp = (unsigned int) (&_sp); -80000190: 800017b7 lui a5,0x80001 -80000194: cb078793 addi a5,a5,-848 # 80000cb0 <_sp+0x0> csr_write(mscratch, sp -32*4); +80000190: 800017b7 lui a5,0x80001 +80000194: dd878793 addi a5,a5,-552 # 80000dd8 <_sp+0x0> 80000198: f8078793 addi a5,a5,-128 8000019c: 34079073 csrw mscratch,a5 csr_write(mstatus, 0x0800); @@ -263,10 +261,10 @@ int readRegister(int id){ return ((int*) sp)[id-32]; 800001c0: 00251513 slli a0,a0,0x2 800001c4: 800017b7 lui a5,0x80001 -800001c8: cb078793 addi a5,a5,-848 # 80000cb0 <_sp+0x0> +800001c8: dd878793 addi a5,a5,-552 # 80000dd8 <_sp+0x0> 800001cc: 00f50533 add a0,a0,a5 } -800001d0: f8052503 lw a0,-128(a0) # 80ffff80 <_sp+0xfff2d0> +800001d0: f8052503 lw a0,-128(a0) # 80ffff80 <_sp+0xfff1a8> 800001d4: 00008067 ret 800001d8 : @@ -275,7 +273,7 @@ void writeRegister(int id, int value){ ((int*) sp)[id-32] = value; 800001d8: 00251513 slli a0,a0,0x2 800001dc: 800017b7 lui a5,0x80001 -800001e0: cb078793 addi a5,a5,-848 # 80000cb0 <_sp+0x0> +800001e0: dd878793 addi a5,a5,-552 # 80000dd8 <_sp+0x0> 800001e4: 00f50533 add a0,a0,a5 800001e8: f8b52023 sw a1,-128(a0) } @@ -286,7 +284,7 @@ void writeRegister(int id, int value){ void stopSim(){ *((volatile int*) SIM_STOP) = 0; -800001f0: fe002e23 sw zero,-4(zero) # fffffffc <_sp+0x7ffff34c> +800001f0: fe002e23 sw zero,-4(zero) # fffffffc <_sp+0x7ffff224> } 800001f4: 00008067 ret @@ -294,7 +292,7 @@ void stopSim(){ void putC(char c){ *((volatile int*) PUTC) = c; -800001f8: fea02c23 sw a0,-8(zero) # fffffff8 <_sp+0x7ffff348> +800001f8: fea02c23 sw a0,-8(zero) # fffffff8 <_sp+0x7ffff220> } 800001fc: 00008067 ret @@ -315,195 +313,319 @@ void redirectTrap(){ csr_write(scause, csr_read(mcause)); 8000021c: 342027f3 csrr a5,mcause 80000220: 14279073 csrw scause,a5 + csr_write(mepc, csr_read(stvec)); +80000224: 105027f3 csrr a5,stvec +80000228: 34179073 csrw mepc,a5 } -80000224: 00c12083 lw ra,12(sp) -80000228: 01010113 addi sp,sp,16 -8000022c: 00008067 ret +8000022c: 00c12083 lw ra,12(sp) +80000230: 01010113 addi sp,sp,16 +80000234: 00008067 ret + +80000238 : + +void emulationTrapToSupervisorTrap(uint32_t sepc, uint32_t mstatus){ + csr_write(sbadaddr, csr_read(mbadaddr)); +80000238: 343027f3 csrr a5,mbadaddr +8000023c: 14379073 csrw sbadaddr,a5 + csr_write(scause, csr_read(mcause)); +80000240: 342027f3 csrr a5,mcause +80000244: 14279073 csrw scause,a5 + csr_write(sepc, sepc); +80000248: 14151073 csrw sepc,a0 + csr_write(mepc, csr_read(stvec)); +8000024c: 105027f3 csrr a5,stvec +80000250: 34179073 csrw mepc,a5 + csr_clear(sstatus, MSTATUS_SPP); +80000254: 10000793 li a5,256 +80000258: 1007b073 csrc sstatus,a5 + csr_set(sstatus, (mstatus >> 3) & MSTATUS_SPP); +8000025c: 0035d593 srli a1,a1,0x3 +80000260: 1005f593 andi a1,a1,256 +80000264: 1005a073 csrs sstatus,a1 + csr_clear(mstatus, MSTATUS_MPP); +80000268: 000027b7 lui a5,0x2 +8000026c: 80078793 addi a5,a5,-2048 # 1800 <__stack_size+0x1000> +80000270: 3007b073 csrc mstatus,a5 + csr_set(mstatus, 0x8000); +80000274: 000087b7 lui a5,0x8 +80000278: 3007a073 csrs mstatus,a5 +} +8000027c: 00008067 ret + +80000280 : + +//Will modify MEPC +int readWord(int address, int *data){ + int result, tmp; + int failed; + __asm__ __volatile__ ( +80000280: 00020737 lui a4,0x20 +80000284: 30072073 csrs mstatus,a4 +80000288: 00000717 auipc a4,0x0 +8000028c: 01870713 addi a4,a4,24 # 800002a0 +80000290: 34171073 csrw mepc,a4 +80000294: 00100693 li a3,1 +80000298: 00052783 lw a5,0(a0) +8000029c: 00000693 li a3,0 +800002a0: 00020737 lui a4,0x20 +800002a4: 30073073 csrc mstatus,a4 +800002a8: 00068513 mv a0,a3 + : [result]"=&r" (result), [failed]"=&r" (failed), [tmp]"=&r" (tmp) + : [address]"r" (address) + : "memory" + ); + + *data = result; +800002ac: 00f5a023 sw a5,0(a1) + return failed; +} +800002b0: 00008067 ret + +800002b4 : + +//Will modify MEPC +int writeWord(uint32_t address, uint32_t data){ + int result, tmp; + int failed; + __asm__ __volatile__ ( +800002b4: 00020737 lui a4,0x20 +800002b8: 30072073 csrs mstatus,a4 +800002bc: 00000717 auipc a4,0x0 +800002c0: 01870713 addi a4,a4,24 # 800002d4 +800002c4: 34171073 csrw mepc,a4 +800002c8: 00100793 li a5,1 +800002cc: 00b52023 sw a1,0(a0) +800002d0: 00000793 li a5,0 +800002d4: 00020737 lui a4,0x20 +800002d8: 30073073 csrc mstatus,a4 +800002dc: 00078513 mv a0,a5 + : [address]"r" (address), [data]"r" (data) + : "memory" + ); + + return failed; +} +800002e0: 00008067 ret + +800002e4 : + + + -80000230 : -#define min(a,b) \ - ({ __typeof__ (a) _a = (a); \ - __typeof__ (b) _b = (b); \ - _a < _b ? _a : _b; }) void trap(){ -80000230: fe010113 addi sp,sp,-32 -80000234: 00112e23 sw ra,28(sp) -80000238: 00812c23 sw s0,24(sp) -8000023c: 00912a23 sw s1,20(sp) -80000240: 01212823 sw s2,16(sp) -80000244: 01312623 sw s3,12(sp) +800002e4: fd010113 addi sp,sp,-48 +800002e8: 02112623 sw ra,44(sp) +800002ec: 02812423 sw s0,40(sp) +800002f0: 02912223 sw s1,36(sp) +800002f4: 03212023 sw s2,32(sp) +800002f8: 01312e23 sw s3,28(sp) +800002fc: 01412c23 sw s4,24(sp) +80000300: 01512a23 sw s5,20(sp) int cause = csr_read(mcause); -80000248: 342027f3 csrr a5,mcause +80000304: 342027f3 csrr a5,mcause if(cause < 0){ -8000024c: 0207ca63 bltz a5,80000280 +80000308: 0207ce63 bltz a5,80000344 redirectTrap(); } else { switch(cause){ -80000250: 00200713 li a4,2 -80000254: 02e78a63 beq a5,a4,80000288 -80000258: 00900713 li a4,9 -8000025c: 10e78863 beq a5,a4,8000036c +8000030c: 00200713 li a4,2 +80000310: 02e78e63 beq a5,a4,8000034c +80000314: 00900713 li a4,9 +80000318: 16e78e63 beq a5,a4,80000494 csr_write(mepc, csr_read(mepc) + 4); }break; default: stopSim(); break; } }break; default: redirectTrap(); break; -80000260: fa1ff0ef jal ra,80000200 +8000031c: ee5ff0ef jal ra,80000200 } } } -80000264: 01c12083 lw ra,28(sp) -80000268: 01812403 lw s0,24(sp) -8000026c: 01412483 lw s1,20(sp) -80000270: 01012903 lw s2,16(sp) -80000274: 00c12983 lw s3,12(sp) -80000278: 02010113 addi sp,sp,32 -8000027c: 00008067 ret +80000320: 02c12083 lw ra,44(sp) +80000324: 02812403 lw s0,40(sp) +80000328: 02412483 lw s1,36(sp) +8000032c: 02012903 lw s2,32(sp) +80000330: 01c12983 lw s3,28(sp) +80000334: 01812a03 lw s4,24(sp) +80000338: 01412a83 lw s5,20(sp) +8000033c: 03010113 addi sp,sp,48 +80000340: 00008067 ret redirectTrap(); -80000280: f81ff0ef jal ra,80000200 -80000284: fe1ff06f j 80000264 +80000344: ebdff0ef jal ra,80000200 +80000348: fd9ff06f j 80000320 + int mepc = csr_read(mepc); +8000034c: 341024f3 csrr s1,mepc + int mstatus = csr_read(mstatus); +80000350: 300029f3 csrr s3,mstatus int instruction = csr_read(mbadaddr); -80000288: 34302473 csrr s0,mbadaddr +80000354: 34302473 csrr s0,mbadaddr int opcode = instruction & 0x7F; -8000028c: 07f47693 andi a3,s0,127 +80000358: 07f47693 andi a3,s0,127 int funct3 = (instruction >> 12) & 0x7; -80000290: 40c45793 srai a5,s0,0xc -80000294: 0077f793 andi a5,a5,7 +8000035c: 40c45793 srai a5,s0,0xc +80000360: 0077f793 andi a5,a5,7 switch(opcode){ -80000298: 02f00713 li a4,47 -8000029c: fce694e3 bne a3,a4,80000264 +80000364: 02f00713 li a4,47 +80000368: fae69ce3 bne a3,a4,80000320 switch(funct3){ -800002a0: 00200713 li a4,2 -800002a4: 0ce79063 bne a5,a4,80000364 +8000036c: 00200713 li a4,2 +80000370: 10e79e63 bne a5,a4,8000048c int sel = instruction >> 27; -800002a8: 41b45493 srai s1,s0,0x1b - int*addr = (int*)readRegister((instruction >> 15) & 0x1F); -800002ac: 40f45513 srai a0,s0,0xf -800002b0: 01f57513 andi a0,a0,31 -800002b4: f0dff0ef jal ra,800001c0 -800002b8: 00050993 mv s3,a0 - int src = readRegister((instruction >> 20) & 0x1F); -800002bc: 41445513 srai a0,s0,0x14 -800002c0: 01f57513 andi a0,a0,31 -800002c4: efdff0ef jal ra,800001c0 -800002c8: 00050913 mv s2,a0 - int rd = (instruction >> 7) & 0x1F; -800002cc: 40745413 srai s0,s0,0x7 -800002d0: 01f47513 andi a0,s0,31 - int readValue = *addr; -800002d4: 0009a583 lw a1,0(s3) - switch(sel){ -800002d8: 01c00793 li a5,28 -800002dc: 0897e063 bltu a5,s1,8000035c -800002e0: 00249493 slli s1,s1,0x2 -800002e4: 800007b7 lui a5,0x80000 -800002e8: 43c78793 addi a5,a5,1084 # 8000043c <_sp+0xfffff78c> -800002ec: 00f484b3 add s1,s1,a5 -800002f0: 0004a783 lw a5,0(s1) -800002f4: 00078067 jr a5 - case 0x0: writeValue = src + readValue; break; -800002f8: 00b90933 add s2,s2,a1 - writeRegister(rd, readValue); -800002fc: eddff0ef jal ra,800001d8 - *addr = writeValue; -80000300: 0129a023 sw s2,0(s3) - csr_write(mepc, csr_read(mepc) + 4); -80000304: 341027f3 csrr a5,mepc -80000308: 00478793 addi a5,a5,4 -8000030c: 34179073 csrw mepc,a5 - }break; -80000310: f55ff06f j 80000264 - case 0x4: writeValue = src ^ readValue; break; -80000314: 00b94933 xor s2,s2,a1 -80000318: fe5ff06f j 800002fc - case 0xC: writeValue = src & readValue; break; -8000031c: 00b97933 and s2,s2,a1 -80000320: fddff06f j 800002fc - case 0x8: writeValue = src | readValue; break; -80000324: 00b96933 or s2,s2,a1 -80000328: fd5ff06f j 800002fc - case 0x10: writeValue = min(src, readValue); break; -8000032c: fd25d8e3 ble s2,a1,800002fc -80000330: 00058913 mv s2,a1 -80000334: fc9ff06f j 800002fc - case 0x14: writeValue = max(src, readValue); break; -80000338: fcb952e3 ble a1,s2,800002fc -8000033c: 00058913 mv s2,a1 -80000340: fbdff06f j 800002fc - case 0x18: writeValue = min((unsigned int)src, (unsigned int)readValue); break; -80000344: fb25fce3 bleu s2,a1,800002fc -80000348: 00058913 mv s2,a1 -8000034c: fb1ff06f j 800002fc - case 0x1C: writeValue = max((unsigned int)src, (unsigned int)readValue); break; -80000350: fab976e3 bleu a1,s2,800002fc -80000354: 00058913 mv s2,a1 -80000358: fa5ff06f j 800002fc - default: redirectTrap(); return; break; -8000035c: ea5ff0ef jal ra,80000200 -80000360: f05ff06f j 80000264 - default: redirectTrap(); break; -80000364: e9dff0ef jal ra,80000200 -80000368: efdff06f j 80000264 - int which = readRegister(17); -8000036c: 01100513 li a0,17 -80000370: e51ff0ef jal ra,800001c0 - switch(which){ -80000374: 00100793 li a5,1 -80000378: 02f51263 bne a0,a5,8000039c - putC(readRegister(10)); -8000037c: 00a00513 li a0,10 +80000374: 41b45913 srai s2,s0,0x1b + int addr = readRegister((instruction >> 15) & 0x1F); +80000378: 40f45513 srai a0,s0,0xf +8000037c: 01f57513 andi a0,a0,31 80000380: e41ff0ef jal ra,800001c0 -80000384: 0ff57513 andi a0,a0,255 -80000388: e71ff0ef jal ra,800001f8 +80000384: 00050a93 mv s5,a0 + int src = readRegister((instruction >> 20) & 0x1F); +80000388: 41445513 srai a0,s0,0x14 +8000038c: 01f57513 andi a0,a0,31 +80000390: e31ff0ef jal ra,800001c0 +80000394: 00050a13 mv s4,a0 + int rd = (instruction >> 7) & 0x1F; +80000398: 40745413 srai s0,s0,0x7 +8000039c: 01f47413 andi s0,s0,31 + if(readWord(addr, &readValue)){ +800003a0: 00c10593 addi a1,sp,12 +800003a4: 000a8513 mv a0,s5 +800003a8: ed9ff0ef jal ra,80000280 +800003ac: 02051263 bnez a0,800003d0 + switch(sel){ +800003b0: 01c00793 li a5,28 +800003b4: 0d27e063 bltu a5,s2,80000474 +800003b8: 00291913 slli s2,s2,0x2 +800003bc: 800007b7 lui a5,0x80000 +800003c0: 56478793 addi a5,a5,1380 # 80000564 <_sp+0xfffff78c> +800003c4: 00f90933 add s2,s2,a5 +800003c8: 00092783 lw a5,0(s2) +800003cc: 00078067 jr a5 + emulationTrapToSupervisorTrap(mepc, mstatus); +800003d0: 00098593 mv a1,s3 +800003d4: 00048513 mv a0,s1 +800003d8: e61ff0ef jal ra,80000238 + return; +800003dc: f45ff06f j 80000320 + case 0x0: writeValue = src + readValue; break; +800003e0: 00c12783 lw a5,12(sp) +800003e4: 00fa0a33 add s4,s4,a5 + writeRegister(rd, readValue); +800003e8: 00c12583 lw a1,12(sp) +800003ec: 00040513 mv a0,s0 +800003f0: de9ff0ef jal ra,800001d8 + if(writeWord(addr, writeValue)){ +800003f4: 000a0593 mv a1,s4 +800003f8: 000a8513 mv a0,s5 +800003fc: eb9ff0ef jal ra,800002b4 +80000400: 06051e63 bnez a0,8000047c + csr_write(mepc, mepc + 4); +80000404: 00448493 addi s1,s1,4 +80000408: 34149073 csrw mepc,s1 + }break; +8000040c: f15ff06f j 80000320 + case 0x4: writeValue = src ^ readValue; break; +80000410: 00c12783 lw a5,12(sp) +80000414: 00fa4a33 xor s4,s4,a5 +80000418: fd1ff06f j 800003e8 + case 0xC: writeValue = src & readValue; break; +8000041c: 00c12783 lw a5,12(sp) +80000420: 00fa7a33 and s4,s4,a5 +80000424: fc5ff06f j 800003e8 + case 0x8: writeValue = src | readValue; break; +80000428: 00c12783 lw a5,12(sp) +8000042c: 00fa6a33 or s4,s4,a5 +80000430: fb9ff06f j 800003e8 + case 0x10: writeValue = min(src, readValue); break; +80000434: 00c12783 lw a5,12(sp) +80000438: fb47d8e3 ble s4,a5,800003e8 +8000043c: 00078a13 mv s4,a5 +80000440: fa9ff06f j 800003e8 + case 0x14: writeValue = max(src, readValue); break; +80000444: 00c12783 lw a5,12(sp) +80000448: fafa50e3 ble a5,s4,800003e8 +8000044c: 00078a13 mv s4,a5 +80000450: f99ff06f j 800003e8 + case 0x18: writeValue = min((unsigned int)src, (unsigned int)readValue); break; +80000454: 00c12783 lw a5,12(sp) +80000458: f947f8e3 bleu s4,a5,800003e8 +8000045c: 00078a13 mv s4,a5 +80000460: f89ff06f j 800003e8 + case 0x1C: writeValue = max((unsigned int)src, (unsigned int)readValue); break; +80000464: 00c12783 lw a5,12(sp) +80000468: f8fa70e3 bleu a5,s4,800003e8 +8000046c: 00078a13 mv s4,a5 +80000470: f79ff06f j 800003e8 + default: redirectTrap(); return; break; +80000474: d8dff0ef jal ra,80000200 +80000478: ea9ff06f j 80000320 + emulationTrapToSupervisorTrap(mepc, mstatus); +8000047c: 00098593 mv a1,s3 +80000480: 00048513 mv a0,s1 +80000484: db5ff0ef jal ra,80000238 + return; +80000488: e99ff06f j 80000320 + default: redirectTrap(); break; +8000048c: d75ff0ef jal ra,80000200 +80000490: e91ff06f j 80000320 + int which = readRegister(17); +80000494: 01100513 li a0,17 +80000498: d29ff0ef jal ra,800001c0 + switch(which){ +8000049c: 00100793 li a5,1 +800004a0: 02f51263 bne a0,a5,800004c4 + putC(readRegister(10)); +800004a4: 00a00513 li a0,10 +800004a8: d19ff0ef jal ra,800001c0 +800004ac: 0ff57513 andi a0,a0,255 +800004b0: d49ff0ef jal ra,800001f8 csr_write(mepc, csr_read(mepc) + 4); -8000038c: 341027f3 csrr a5,mepc -80000390: 00478793 addi a5,a5,4 -80000394: 34179073 csrw mepc,a5 +800004b4: 341027f3 csrr a5,mepc +800004b8: 00478793 addi a5,a5,4 +800004bc: 34179073 csrw mepc,a5 }break; -80000398: ecdff06f j 80000264 +800004c0: e61ff06f j 80000320 default: stopSim(); break; -8000039c: e55ff0ef jal ra,800001f0 -800003a0: ec5ff06f j 80000264 +800004c4: d2dff0ef jal ra,800001f0 +800004c8: e59ff06f j 80000320 -800003a4 <__libc_init_array>: -800003a4: ff010113 addi sp,sp,-16 -800003a8: 00812423 sw s0,8(sp) -800003ac: 00912223 sw s1,4(sp) -800003b0: 00000417 auipc s0,0x0 -800003b4: 08c40413 addi s0,s0,140 # 8000043c <__init_array_end> -800003b8: 00000497 auipc s1,0x0 -800003bc: 08448493 addi s1,s1,132 # 8000043c <__init_array_end> -800003c0: 408484b3 sub s1,s1,s0 -800003c4: 01212023 sw s2,0(sp) -800003c8: 00112623 sw ra,12(sp) -800003cc: 4024d493 srai s1,s1,0x2 -800003d0: 00000913 li s2,0 -800003d4: 04991063 bne s2,s1,80000414 <__libc_init_array+0x70> -800003d8: 00000417 auipc s0,0x0 -800003dc: 06440413 addi s0,s0,100 # 8000043c <__init_array_end> -800003e0: 00000497 auipc s1,0x0 -800003e4: 05c48493 addi s1,s1,92 # 8000043c <__init_array_end> -800003e8: 408484b3 sub s1,s1,s0 -800003ec: c8dff0ef jal ra,80000078 <_init> -800003f0: 4024d493 srai s1,s1,0x2 -800003f4: 00000913 li s2,0 -800003f8: 02991863 bne s2,s1,80000428 <__libc_init_array+0x84> -800003fc: 00c12083 lw ra,12(sp) -80000400: 00812403 lw s0,8(sp) -80000404: 00412483 lw s1,4(sp) -80000408: 00012903 lw s2,0(sp) -8000040c: 01010113 addi sp,sp,16 -80000410: 00008067 ret -80000414: 00042783 lw a5,0(s0) -80000418: 00190913 addi s2,s2,1 -8000041c: 00440413 addi s0,s0,4 -80000420: 000780e7 jalr a5 -80000424: fb1ff06f j 800003d4 <__libc_init_array+0x30> -80000428: 00042783 lw a5,0(s0) -8000042c: 00190913 addi s2,s2,1 -80000430: 00440413 addi s0,s0,4 -80000434: 000780e7 jalr a5 -80000438: fc1ff06f j 800003f8 <__libc_init_array+0x54> +800004cc <__libc_init_array>: +800004cc: ff010113 addi sp,sp,-16 +800004d0: 00812423 sw s0,8(sp) +800004d4: 00912223 sw s1,4(sp) +800004d8: 00000417 auipc s0,0x0 +800004dc: 08c40413 addi s0,s0,140 # 80000564 <__init_array_end> +800004e0: 00000497 auipc s1,0x0 +800004e4: 08448493 addi s1,s1,132 # 80000564 <__init_array_end> +800004e8: 408484b3 sub s1,s1,s0 +800004ec: 01212023 sw s2,0(sp) +800004f0: 00112623 sw ra,12(sp) +800004f4: 4024d493 srai s1,s1,0x2 +800004f8: 00000913 li s2,0 +800004fc: 04991063 bne s2,s1,8000053c <__libc_init_array+0x70> +80000500: 00000417 auipc s0,0x0 +80000504: 06440413 addi s0,s0,100 # 80000564 <__init_array_end> +80000508: 00000497 auipc s1,0x0 +8000050c: 05c48493 addi s1,s1,92 # 80000564 <__init_array_end> +80000510: 408484b3 sub s1,s1,s0 +80000514: b65ff0ef jal ra,80000078 <_init> +80000518: 4024d493 srai s1,s1,0x2 +8000051c: 00000913 li s2,0 +80000520: 02991863 bne s2,s1,80000550 <__libc_init_array+0x84> +80000524: 00c12083 lw ra,12(sp) +80000528: 00812403 lw s0,8(sp) +8000052c: 00412483 lw s1,4(sp) +80000530: 00012903 lw s2,0(sp) +80000534: 01010113 addi sp,sp,16 +80000538: 00008067 ret +8000053c: 00042783 lw a5,0(s0) +80000540: 00190913 addi s2,s2,1 +80000544: 00440413 addi s0,s0,4 +80000548: 000780e7 jalr a5 +8000054c: fb1ff06f j 800004fc <__libc_init_array+0x30> +80000550: 00042783 lw a5,0(s0) +80000554: 00190913 addi s2,s2,1 +80000558: 00440413 addi s0,s0,4 +8000055c: 000780e7 jalr a5 +80000560: fc1ff06f j 80000520 <__libc_init_array+0x54> diff --git a/src/main/c/emulator/build/emulator.hex b/src/main/c/emulator/build/emulator.hex index f70c1b48..7aba5679 100644 --- a/src/main/c/emulator/build/emulator.hex +++ b/src/main/c/emulator/build/emulator.hex @@ -1,10 +1,10 @@ :0200000480007A -:1000000017110000130101CB17050000130545432C -:10001000970500009385C542170600001306864920 +:1000000017110000130181DD170500001305C55508 +:100010009705000093854555170600001306065CFA :1000200063FCC5008322050023A05500130545008D -:1000300093854500E3E8C5FE1705000013058547D5 -:1000400097050000938505476378B50023200500D8 -:1000500013054500E36CB5FEEF00C034EF008012DD +:1000300093854500E3E8C5FE170500001305055A42 +:1000400097050000938585596378B5002320050046 +:1000500013054500E36CB5FEEF004047EF0080124A :100060009700000093804001370500819305000050 :10007000730020306F0000006780000073110134AE :1000800023200100232211002326310023284100D0 @@ -14,7 +14,7 @@ :1000C0002322110523242105232631052328410558 :1000D000232A5105232C6105232E71052320810736 :1000E000232291072324A1072326B1072328C10730 -:1000F000232AD107232CE107232EF107EF00401319 +:1000F000232AD107232CE107232EF107EF00801ECE :1001000003200100832041008321C100032201015B :1001100083224101032381018323C10103240102BE :1001200083244102032581028325C10203260103A2 @@ -25,56 +25,74 @@ :10017000832E4107032F8107832FC1077311013499 :0401800073002030B8 :10018400B70700809387C70773905730B71700806D -:10019400938707CB938707F873900734B71700004A +:10019400938787DD938707F873900734B7170000B8 :1001A4009387078073900730B70700C073901734A4 :1001B400B7B700007390273067800000131525003F -:1001C400B7170080938707CB3305F500032505F89F -:1001D4006780000013152500B7170080938707CBAD +:1001C400B7170080938787DD3305F500032505F80D +:1001D4006780000013152500B7170080938787DD1B :1001E4003305F5002320B5F867800000232E00FEB8 :1001F40067800000232CA0FE67800000130101FF2C :1002040023261100EFF09FFEF32730347390371448 :10021400F327103473901714F327203473902714A2 -:100224008320C1001301010167800000130101FE56 -:10023400232E1100232C8100232A9100232821013D -:1002440023263101F327203463CA07021307200051 -:10025400638AE702130790006388E710EFF01FFA40 -:100264008320C10103248101832441010329010165 -:100274008329C1001301010267800000EFF01FF819 -:100284006FF01FFE732430349376F4079357C44001 -:1002940093F777001307F002E394E6FC13072000BA -:1002A4006390E70C9354B4411355F4401375F5016E -:1002B400EFF0DFF093090500135544411375F50180 -:1002C400EFF0DFEF13090500135474401375F401C4 -:1002D40083A509009307C00163E097089394240061 -:1002E400B70700809387C743B384F40083A704004F -:1002F400678007003309B900EFF0DFED23A029017F -:10030400F327103493874700739017346FF05FF529 -:100314003349B9006FF05FFE3379B9006FF0DFFD48 -:100324003369B9006FF05FFDE3D825FD138905003B -:100334006FF09FFCE352B9FC138905006FF0DFFBFB -:10034400E3FC25FB138905006FF01FFBE376B9FA84 -:10035400138905006FF05FFAEFF05FEA6FF05FF06A -:10036400EFF0DFE96FF0DFEF13051001EFF01FE5A9 -:10037400930710006312F5021305A000EFF01FE4C9 -:100384001375F50FEFF01FE7F32710349387470039 -:10039400739017346FF0DFECEFF05FE56FF05FEC14 -:1003A400130101FF2324810023229100170400007C -:1003B4001304C4089704000093844408B38484405D -:1003C400232021012326110093D424401309000083 -:1003D40063109904170400001304440697040000F2 -:1003E4009384C405B3848440EFF0DFC893D42440DD -:1003F40013090000631899028320C10003248100BB -:1004040083244100032901001301010167800000D6 -:10041400832704001309190013044400E78007002C -:100424006FF01FFB83270400130919001304440011 -:08043400E78007006FF01FFCD8 -:10043C00F8020080FC0200805C0300805C030080FA -:10044C00140300805C0300805C0300805C0300806C -:10045C00240300805C0300805C0300805C0300804C -:10046C001C0300805C0300805C0300805C03008044 -:10047C002C0300805C0300805C0300805C03008024 -:10048C00380300805C0300805C0300805C03008008 -:10049C00440300805C0300805C0300805C030080EC -:0404AC005003008079 +:10022400F3275010739017348320C1001301010188 +:1002340067800000F327303473903714F327203499 +:100244007390271473101514F327501073901734F8 +:100254009307001073B0071093D5350093F505107C +:1002640073A00510B72700009387078073B0073089 +:10027400B787000073A007306780000037070200CB +:100284007320073017070000130787017310173412 +:100294009306100083270500930600003707020029 +:1002A400733007301385060023A0F5006780000033 +:1002B4003707020073200730170700001307870170 +:1002C40073101734930710002320B5009307000020 +:1002D400370702007330073013850700678000007A +:1002E400130101FD232611022324810223229102FA +:1002F40023202103232E3101232C4101232A5101E0 +:10030400F327203463CE070213072000638EE7022D +:1003140013079000638EE716EFF05FEE8320C102AF +:100324000324810283244102032901028329C10198 +:10033400032A8101832A410113010103678000001C +:10034400EFF0DFEB6FF09FFDF3241034F32900305E +:10035400732430349376F4079357C44093F77700AB +:100364001307F002E39CE6FA13072000639EE710EC +:100374001359B4411355F4401375F501EFF01FE41C +:10038400930A0500135544411375F501EFF01FE37B +:10039400130A0500135474401374F4019305C10047 +:1003A40013850A00EFF09FED631205029307C00165 +:1003B40063E0270D13192900B70700809387475678 +:1003C4003309F90083270900678007009385090032 +:1003D40013850400EFF01FE66FF05FF48327C1007C +:1003E400330AFA008325C10013050400EFF09FDEF1 +:1003F40093050A0013850A00EFF09FEB631E0506C0 +:1004040093844400739014346FF05FF18327C10028 +:10041400334AFA006FF01FFD8327C100337AFA00D4 +:100424006FF05FFC8327C100336AFA006FF09FFB13 +:100434008327C100E3D847FB138A07006FF09FFAB4 +:100444008327C100E350FAFA138A07006FF09FF97B +:100454008327C100E3F847F9138A07006FF09FF878 +:100464008327C100E370FAF8138A07006FF09FF73F +:10047400EFF0DFD86FF09FEA93850900138504003D +:10048400EFF05FDB6FF09FE9EFF05FD76FF01FE9EC +:1004940013051001EFF09FD2930710006312F502C9 +:1004A4001305A000EFF09FD11375F50FEFF09FD463 +:1004B400F327103493874700739017346FF01FE6C7 +:1004C400EFF0DFD26FF09FE5130101FF23248100D9 +:1004D40023229100170400001304C40897040000A9 +:1004E40093844408B38484402320210123261100EB +:1004F40093D42440130900006310990417040000E6 +:1005040013044406970400009384C405B384844010 +:10051400EFF05FB693D424401309000063189902E6 +:100524008320C100032481008324410003290100A6 +:1005340013010101678000008327040013091900D7 +:1005440013044400E78007006FF01FFB83270400B7 +:100554001309190013044400E78007006FF01FFC1F +:10056400E0030080E80300807404008074040080C9 +:1005740010040080740400807404008074040080FB +:1005840028040080740400807404008074040080D3 +:100594001C040080740400807404008074040080CF +:1005A40034040080740400807404008074040080A7 +:1005B4004404008074040080740400807404008087 +:1005C4005404008074040080740400807404008067 +:0405D400640400803B :040000058000000077 :00000001FF diff --git a/src/main/c/emulator/src/main.c b/src/main/c/emulator/src/main.c index 36090c72..aa058f71 100755 --- a/src/main/c/emulator/src/main.c +++ b/src/main/c/emulator/src/main.c @@ -4,11 +4,11 @@ extern const unsigned int _sp; extern void trapEntry(); +extern void emulationTrap(); void init() { - csr_write(mtvec, trapEntry); - unsigned int sp = (unsigned int) (&_sp); + csr_write(mtvec, trapEntry); csr_write(mscratch, sp -32*4); csr_write(mstatus, 0x0800); csr_write(mepc, OS_CALL); @@ -39,6 +39,18 @@ void redirectTrap(){ csr_write(sbadaddr, csr_read(mbadaddr)); csr_write(sepc, csr_read(mepc)); csr_write(scause, csr_read(mcause)); + csr_write(mepc, csr_read(stvec)); +} + +void emulationTrapToSupervisorTrap(uint32_t sepc, uint32_t mstatus){ + csr_write(sbadaddr, csr_read(mbadaddr)); + csr_write(scause, csr_read(mcause)); + csr_write(sepc, sepc); + csr_write(mepc, csr_read(stvec)); + csr_clear(sstatus, MSTATUS_SPP); + csr_set(sstatus, (mstatus >> 3) & MSTATUS_SPP); + csr_clear(mstatus, MSTATUS_MPP); + csr_set(mstatus, 0x8000); } #define max(a,b) \ @@ -52,6 +64,61 @@ void redirectTrap(){ __typeof__ (b) _b = (b); \ _a < _b ? _a : _b; }) + + +//Will modify MEPC +int readWord(int address, int *data){ + int result, tmp; + int failed; + __asm__ __volatile__ ( + " li %[tmp], 0x00020000\n" + " csrs mstatus, %[tmp]\n" + " la %[tmp], 1f\n" + " csrw mepc, %[tmp]\n" + " li %[failed], 1\n" + " lw %[result], 0(%[address])\n" + " li %[failed], 0\n" + "1:\n" + " li %[tmp], 0x00020000\n" + " csrc mstatus, %[tmp]\n" + : [result]"=&r" (result), [failed]"=&r" (failed), [tmp]"=&r" (tmp) + : [address]"r" (address) + : "memory" + ); + + *data = result; + return failed; +} + +//Will modify MEPC +int writeWord(uint32_t address, uint32_t data){ + int result, tmp; + int failed; + __asm__ __volatile__ ( + " li %[tmp], 0x00020000\n" + " csrs mstatus, %[tmp]\n" + " la %[tmp], 1f\n" + " csrw mepc, %[tmp]\n" + " li %[failed], 1\n" + " sw %[data], 0(%[address])\n" + " li %[failed], 0\n" + "1:\n" + " li %[tmp], 0x00020000\n" + " csrc mstatus, %[tmp]\n" + : [failed]"=&r" (failed), [tmp]"=&r" (tmp) + : [address]"r" (address), [data]"r" (data) + : "memory" + ); + + return failed; +} + + + + + + + void trap(){ int cause = csr_read(mcause); if(cause < 0){ @@ -59,6 +126,8 @@ void trap(){ } else { switch(cause){ case CAUSE_ILLEGAL_INSTRUCTION:{ + int mepc = csr_read(mepc); + int mstatus = csr_read(mstatus); int instruction = csr_read(mbadaddr); int opcode = instruction & 0x7F; int funct3 = (instruction >> 12) & 0x7; @@ -67,10 +136,14 @@ void trap(){ switch(funct3){ case 0x2:{ int sel = instruction >> 27; - int*addr = (int*)readRegister((instruction >> 15) & 0x1F); + int addr = readRegister((instruction >> 15) & 0x1F); int src = readRegister((instruction >> 20) & 0x1F); int rd = (instruction >> 7) & 0x1F; - int readValue = *addr; + int readValue; + if(readWord(addr, &readValue)){ + emulationTrapToSupervisorTrap(mepc, mstatus); + return; + } int writeValue; switch(sel){ case 0x0: writeValue = src + readValue; break; @@ -85,8 +158,11 @@ void trap(){ default: redirectTrap(); return; break; } writeRegister(rd, readValue); - *addr = writeValue; - csr_write(mepc, csr_read(mepc) + 4); + if(writeWord(addr, writeValue)){ + emulationTrapToSupervisorTrap(mepc, mstatus); + return; + } + csr_write(mepc, mepc + 4); }break; default: redirectTrap(); break; } diff --git a/src/main/c/emulator/src/trap.S b/src/main/c/emulator/src/trap.S index 4746c228..4384d349 100644 --- a/src/main/c/emulator/src/trap.S +++ b/src/main/c/emulator/src/trap.S @@ -69,3 +69,5 @@ trapEntry: lw x31, 31*4(sp) csrrw sp, mscratch, sp mret + + diff --git a/src/main/scala/vexriscv/plugin/MmuPlugin.scala b/src/main/scala/vexriscv/plugin/MmuPlugin.scala index cc98e104..56a4f262 100644 --- a/src/main/scala/vexriscv/plugin/MmuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/MmuPlugin.scala @@ -110,7 +110,13 @@ class MmuPlugin(virtualRange : UInt => Bool, val requireMmuLockup = virtualRange(port.bus.cmd.virtualAddress) && !port.bus.cmd.bypassTranslation && csr.satp.mode if(!allowMachineModeMmu) { requireMmuLockup clearWhen(!csr.status.mprv && privilegeService.isMachine()) - if(port.priority != MmuPort.PRIORITY_DATA) requireMmuLockup clearWhen(csr.status.mprv && pipeline(config.MPP) === 3) + when(privilegeService.isMachine()) { + if (port.priority == MmuPort.PRIORITY_DATA) { + requireMmuLockup clearWhen (!csr.status.mprv) + } else { + requireMmuLockup := False + } + } } when(requireMmuLockup) { diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index f5832ce0..3b4953b2 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -256,7 +256,8 @@ public: uint32_t spp : 1; uint32_t _3 : 2; uint32_t mpp : 2; - uint32_t _4 : 5; + uint32_t _4 : 4; + uint32_t mprv : 1; uint32_t sum : 1; uint32_t mxr : 1; }; @@ -412,7 +413,8 @@ public: enum AccessKind {READ,WRITE,EXECUTE}; bool v2p(uint32_t v, uint32_t *p, AccessKind kind){ - if(privilege == 3 || satp.mode == 0){ + uint32_t effectivePrivilege = status.mprv && kind != EXECUTE ? status.mpp : privilege; + if(effectivePrivilege == 3 || satp.mode == 0){ *p = v; } else { Tlb tlb; @@ -424,8 +426,8 @@ public: if(!tlb.v) return true; superPage = false; } - if(!tlb.u && privilege == 0) return true; - if( tlb.u && privilege == 1 && !status.sum) return true; + if(!tlb.u && effectivePrivilege == 0) return true; + if( tlb.u && effectivePrivilege == 1 && !status.sum) return true; if(superPage && tlb.ppn0 != 0) return true; switch(kind){ case READ: if(!tlb.r && !(status.mxr && tlb.x)) return true; break; diff --git a/src/test/scala/vexriscv/experimental/PlicCost.scala b/src/test/scala/vexriscv/experimental/PlicCost.scala index 6f044e64..79d5c663 100644 --- a/src/test/scala/vexriscv/experimental/PlicCost.scala +++ b/src/test/scala/vexriscv/experimental/PlicCost.scala @@ -40,9 +40,9 @@ class PlicBench(inputCount : Int) extends Component{ io.cpuInterrupt := targets(0).iep val plicMapping = PlicMapping.light.copy( - // gatewayPriorityReadGen = true, - // gatewayPendingReadGen = true, - // targetThresholdReadGen = true +// gatewayPriorityReadGen = true, +// gatewayPendingReadGen = true, +// targetThresholdReadGen = true ) gateways.foreach(_.priority := 1) From 94fc2c3ecf51dabbf4aea6430d4cbefafc57f837 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 26 Mar 2019 01:25:18 +0100 Subject: [PATCH 077/951] Fix some models missmatch Add more SBI Add hardware LR/SC support in dbus cacheless --- src/main/c/emulator/build/emulator.asm | 693 +++++++++++------- src/main/c/emulator/build/emulator.hex | 162 ++-- src/main/c/emulator/src/config.h | 3 - src/main/c/emulator/src/hal.c | 25 + src/main/c/emulator/src/hal.h | 23 + src/main/c/emulator/src/main.c | 131 ++-- src/main/c/emulator/src/riscv.h | 18 +- src/main/c/emulator/src/start.S | 4 +- src/main/c/emulator/src/utils.S | 47 ++ src/main/scala/vexriscv/demo/Linux.scala | 12 +- .../scala/vexriscv/plugin/CsrPlugin.scala | 6 +- .../vexriscv/plugin/DBusSimplePlugin.scala | 89 ++- src/test/cpp/regression/main.cpp | 104 ++- src/test/cpp/regression/makefile | 2 +- 14 files changed, 886 insertions(+), 433 deletions(-) create mode 100644 src/main/c/emulator/src/hal.c create mode 100644 src/main/c/emulator/src/hal.h create mode 100644 src/main/c/emulator/src/utils.S diff --git a/src/main/c/emulator/build/emulator.asm b/src/main/c/emulator/build/emulator.asm index dffc8975..e1e89d06 100644 --- a/src/main/c/emulator/build/emulator.asm +++ b/src/main/c/emulator/build/emulator.asm @@ -12,19 +12,19 @@ Disassembly of section .init: #endif*/ la sp, _sp 80000000: 00001117 auipc sp,0x1 -80000004: dd810113 addi sp,sp,-552 # 80000dd8 <_sp> +80000004: f3810113 addi sp,sp,-200 # 80000f38 <_sp> /* Load data section */ la a0, _data_lma 80000008: 00000517 auipc a0,0x0 -8000000c: 55c50513 addi a0,a0,1372 # 80000564 <__init_array_end> +8000000c: 6b850513 addi a0,a0,1720 # 800006c0 <__init_array_end> la a1, _data 80000010: 00000597 auipc a1,0x0 -80000014: 55458593 addi a1,a1,1364 # 80000564 <__init_array_end> +80000014: 6b058593 addi a1,a1,1712 # 800006c0 <__init_array_end> la a2, _edata 80000018: 00000617 auipc a2,0x0 -8000001c: 5c060613 addi a2,a2,1472 # 800005d8 <__bss_start> +8000001c: 72060613 addi a2,a2,1824 # 80000738 <__bss_start> bgeu a1, a2, 2f 80000020: 00c5fc63 bleu a2,a1,80000038 <_start+0x38> 1: @@ -43,10 +43,10 @@ Disassembly of section .init: /* Clear bss section */ la a0, __bss_start 80000038: 00000517 auipc a0,0x0 -8000003c: 5a050513 addi a0,a0,1440 # 800005d8 <__bss_start> +8000003c: 70050513 addi a0,a0,1792 # 80000738 <__bss_start> la a1, _end 80000040: 00000597 auipc a1,0x0 -80000044: 59858593 addi a1,a1,1432 # 800005d8 <__bss_start> +80000044: 6f858593 addi a1,a1,1784 # 80000738 <__bss_start> bgeu a0, a1, 2f 80000048: 00b57863 bleu a1,a0,80000058 <_start+0x58> 1: @@ -59,16 +59,16 @@ Disassembly of section .init: 2: call __libc_init_array -80000058: 474000ef jal ra,800004cc <__libc_init_array> +80000058: 5d0000ef jal ra,80000628 <__libc_init_array> call init 8000005c: 128000ef jal ra,80000184 la ra, done 80000060: 00000097 auipc ra,0x0 80000064: 01408093 addi ra,ra,20 # 80000074 - li a0, DTB -80000068: 81000537 lui a0,0x81000 - li a1, 0 -8000006c: 00000593 li a1,0 + li a0, 0 +80000068: 00000513 li a0,0 + li a1, DTB +8000006c: 810005b7 lui a1,0x81000 mret 80000070: 30200073 mret @@ -156,7 +156,7 @@ trapEntry: sw x31, 31*4(sp) 800000f8: 07f12e23 sw t6,124(sp) call trap -800000fc: 1e8000ef jal ra,800002e4 +800000fc: 1ec000ef jal ra,800002e8 lw x0, 0*4(sp) 80000100: 00012003 lw zero,0(sp) lw x1, 1*4(sp) @@ -231,79 +231,70 @@ extern void trapEntry(); extern void emulationTrap(); void init() { - unsigned int sp = (unsigned int) (&_sp); + uint32_t sp = (uint32_t) (&_sp); csr_write(mtvec, trapEntry); 80000184: 800007b7 lui a5,0x80000 -80000188: 07c78793 addi a5,a5,124 # 8000007c <_sp+0xfffff2a4> +80000188: 07c78793 addi a5,a5,124 # 8000007c <_sp+0xfffff144> 8000018c: 30579073 csrw mtvec,a5 csr_write(mscratch, sp -32*4); 80000190: 800017b7 lui a5,0x80001 -80000194: dd878793 addi a5,a5,-552 # 80000dd8 <_sp+0x0> +80000194: f3878793 addi a5,a5,-200 # 80000f38 <_sp+0x0> 80000198: f8078793 addi a5,a5,-128 8000019c: 34079073 csrw mscratch,a5 - csr_write(mstatus, 0x0800); + csr_write(mstatus, 0x0800 | MSTATUS_MPIE); 800001a0: 000017b7 lui a5,0x1 -800001a4: 80078793 addi a5,a5,-2048 # 800 <__stack_size> +800001a4: 88078793 addi a5,a5,-1920 # 880 <__stack_size+0x80> 800001a8: 30079073 csrw mstatus,a5 + csr_write(mie, 0); +800001ac: 30405073 csrwi mie,0 csr_write(mepc, OS_CALL); -800001ac: c00007b7 lui a5,0xc0000 -800001b0: 34179073 csrw mepc,a5 - csr_write(medeleg, MDELEG_INSTRUCTION_PAGE_FAULT | MDELEG_LOAD_PAGE_FAULT | MDELEG_STORE_PAGE_FAULT); -800001b4: 0000b7b7 lui a5,0xb -800001b8: 30279073 csrw medeleg,a5 +800001b0: c00007b7 lui a5,0xc0000 +800001b4: 34179073 csrw mepc,a5 + csr_write(medeleg, MEDELEG_INSTRUCTION_PAGE_FAULT | MEDELEG_LOAD_PAGE_FAULT | MEDELEG_STORE_PAGE_FAULT); +800001b8: 0000b7b7 lui a5,0xb +800001bc: 30279073 csrw medeleg,a5 + csr_write(mideleg, MIDELEG_SUPERVISOR_TIMER); +800001c0: 02000793 li a5,32 +800001c4: 30379073 csrw mideleg,a5 + csr_write(sbadaddr, 0); //Used to avoid simulation missmatch +800001c8: 14305073 csrwi sbadaddr,0 } -800001bc: 00008067 ret +800001cc: 00008067 ret -800001c0 : +800001d0 : -int readRegister(int id){ +int readRegister(uint32_t id){ unsigned int sp = (unsigned int) (&_sp); return ((int*) sp)[id-32]; -800001c0: 00251513 slli a0,a0,0x2 -800001c4: 800017b7 lui a5,0x80001 -800001c8: dd878793 addi a5,a5,-552 # 80000dd8 <_sp+0x0> -800001cc: 00f50533 add a0,a0,a5 +800001d0: 00251513 slli a0,a0,0x2 +800001d4: 800017b7 lui a5,0x80001 +800001d8: f3878793 addi a5,a5,-200 # 80000f38 <_sp+0x0> +800001dc: 00f50533 add a0,a0,a5 } -800001d0: f8052503 lw a0,-128(a0) # 80ffff80 <_sp+0xfff1a8> -800001d4: 00008067 ret +800001e0: f8052503 lw a0,-128(a0) +800001e4: 00008067 ret -800001d8 : -void writeRegister(int id, int value){ - unsigned int sp = (unsigned int) (&_sp); - ((int*) sp)[id-32] = value; -800001d8: 00251513 slli a0,a0,0x2 -800001dc: 800017b7 lui a5,0x80001 -800001e0: dd878793 addi a5,a5,-552 # 80000dd8 <_sp+0x0> -800001e4: 00f50533 add a0,a0,a5 -800001e8: f8b52023 sw a1,-128(a0) -} -800001ec: 00008067 ret - -800001f0 : - - -void stopSim(){ - *((volatile int*) SIM_STOP) = 0; -800001f0: fe002e23 sw zero,-4(zero) # fffffffc <_sp+0x7ffff224> -} -800001f4: 00008067 ret - -800001f8 : - -void putC(char c){ - *((volatile int*) PUTC) = c; -800001f8: fea02c23 sw a0,-8(zero) # fffffff8 <_sp+0x7ffff220> +800001e8 : +void writeRegister(uint32_t id, int value){ + uint32_t sp = (uint32_t) (&_sp); + ((uint32_t*) sp)[id-32] = value; +800001e8: 00251513 slli a0,a0,0x2 +800001ec: 800017b7 lui a5,0x80001 +800001f0: f3878793 addi a5,a5,-200 # 80000f38 <_sp+0x0> +800001f4: 00f50533 add a0,a0,a5 +800001f8: f8b52023 sw a1,-128(a0) } 800001fc: 00008067 ret 80000200 : + void redirectTrap(){ 80000200: ff010113 addi sp,sp,-16 80000204: 00112623 sw ra,12(sp) stopSim(); -80000208: fe9ff0ef jal ra,800001f0 +80000208: 3e8000ef jal ra,800005f0 csr_write(sbadaddr, csr_read(mbadaddr)); 8000020c: 343027f3 csrr a5,mbadaddr 80000210: 14379073 csrw sbadaddr,a5 @@ -346,286 +337,436 @@ void emulationTrapToSupervisorTrap(uint32_t sepc, uint32_t mstatus){ 80000268: 000027b7 lui a5,0x2 8000026c: 80078793 addi a5,a5,-2048 # 1800 <__stack_size+0x1000> 80000270: 3007b073 csrc mstatus,a5 - csr_set(mstatus, 0x8000); + csr_set(mstatus, 0x8000 | MSTATUS_MPIE); 80000274: 000087b7 lui a5,0x8 -80000278: 3007a073 csrs mstatus,a5 +80000278: 08078793 addi a5,a5,128 # 8080 <__stack_size+0x7880> +8000027c: 3007a073 csrs mstatus,a5 } -8000027c: 00008067 ret +80000280: 00008067 ret -80000280 : +80000284 : //Will modify MEPC -int readWord(int address, int *data){ - int result, tmp; - int failed; +int32_t readWord(uint32_t address, int32_t *data){ + int32_t result, tmp; + int32_t failed; __asm__ __volatile__ ( -80000280: 00020737 lui a4,0x20 -80000284: 30072073 csrs mstatus,a4 -80000288: 00000717 auipc a4,0x0 -8000028c: 01870713 addi a4,a4,24 # 800002a0 -80000290: 34171073 csrw mepc,a4 -80000294: 00100693 li a3,1 -80000298: 00052783 lw a5,0(a0) -8000029c: 00000693 li a3,0 -800002a0: 00020737 lui a4,0x20 -800002a4: 30073073 csrc mstatus,a4 -800002a8: 00068513 mv a0,a3 +80000284: 00020737 lui a4,0x20 +80000288: 30072073 csrs mstatus,a4 +8000028c: 00000717 auipc a4,0x0 +80000290: 01870713 addi a4,a4,24 # 800002a4 +80000294: 34171073 csrw mepc,a4 +80000298: 00100693 li a3,1 +8000029c: 00052783 lw a5,0(a0) +800002a0: 00000693 li a3,0 +800002a4: 00020737 lui a4,0x20 +800002a8: 30073073 csrc mstatus,a4 +800002ac: 00068513 mv a0,a3 : [result]"=&r" (result), [failed]"=&r" (failed), [tmp]"=&r" (tmp) : [address]"r" (address) : "memory" ); *data = result; -800002ac: 00f5a023 sw a5,0(a1) +800002b0: 00f5a023 sw a5,0(a1) # 81000000 <_sp+0xfff0c8> return failed; } -800002b0: 00008067 ret +800002b4: 00008067 ret -800002b4 : +800002b8 : //Will modify MEPC -int writeWord(uint32_t address, uint32_t data){ - int result, tmp; - int failed; +int32_t writeWord(uint32_t address, int32_t data){ + int32_t result, tmp; + int32_t failed; __asm__ __volatile__ ( -800002b4: 00020737 lui a4,0x20 -800002b8: 30072073 csrs mstatus,a4 -800002bc: 00000717 auipc a4,0x0 -800002c0: 01870713 addi a4,a4,24 # 800002d4 -800002c4: 34171073 csrw mepc,a4 -800002c8: 00100793 li a5,1 -800002cc: 00b52023 sw a1,0(a0) -800002d0: 00000793 li a5,0 -800002d4: 00020737 lui a4,0x20 -800002d8: 30073073 csrc mstatus,a4 -800002dc: 00078513 mv a0,a5 +800002b8: 00020737 lui a4,0x20 +800002bc: 30072073 csrs mstatus,a4 +800002c0: 00000717 auipc a4,0x0 +800002c4: 01870713 addi a4,a4,24 # 800002d8 +800002c8: 34171073 csrw mepc,a4 +800002cc: 00100793 li a5,1 +800002d0: 00b52023 sw a1,0(a0) +800002d4: 00000793 li a5,0 +800002d8: 00020737 lui a4,0x20 +800002dc: 30073073 csrc mstatus,a4 +800002e0: 00078513 mv a0,a5 : [address]"r" (address), [data]"r" (data) : "memory" ); return failed; } -800002e0: 00008067 ret - -800002e4 : +800002e4: 00008067 ret +800002e8 : void trap(){ -800002e4: fd010113 addi sp,sp,-48 -800002e8: 02112623 sw ra,44(sp) -800002ec: 02812423 sw s0,40(sp) -800002f0: 02912223 sw s1,36(sp) -800002f4: 03212023 sw s2,32(sp) -800002f8: 01312e23 sw s3,28(sp) -800002fc: 01412c23 sw s4,24(sp) -80000300: 01512a23 sw s5,20(sp) - int cause = csr_read(mcause); -80000304: 342027f3 csrr a5,mcause - if(cause < 0){ -80000308: 0207ce63 bltz a5,80000344 - redirectTrap(); - } else { +800002e8: fd010113 addi sp,sp,-48 +800002ec: 02112623 sw ra,44(sp) +800002f0: 02812423 sw s0,40(sp) +800002f4: 02912223 sw s1,36(sp) +800002f8: 03212023 sw s2,32(sp) +800002fc: 01312e23 sw s3,28(sp) +80000300: 01412c23 sw s4,24(sp) +80000304: 01512a23 sw s5,20(sp) + int32_t cause = csr_read(mcause); +80000308: 342027f3 csrr a5,mcause + if(cause < 0){ //interrupt +8000030c: 0007ce63 bltz a5,80000328 + csr_clear(mie, MIE_MTIE); + }break; + default: redirectTrap(); break; + } + } else { //exception switch(cause){ -8000030c: 00200713 li a4,2 -80000310: 02e78e63 beq a5,a4,8000034c -80000314: 00900713 li a4,9 -80000318: 16e78e63 beq a5,a4,80000494 +80000310: 00200713 li a4,2 +80000314: 04e78e63 beq a5,a4,80000370 +80000318: 00900713 li a4,9 +8000031c: 24e78e63 beq a5,a4,80000578 csr_write(mepc, csr_read(mepc) + 4); }break; default: stopSim(); break; } }break; default: redirectTrap(); break; -8000031c: ee5ff0ef jal ra,80000200 +80000320: ee1ff0ef jal ra,80000200 +80000324: 0200006f j 80000344 + switch(cause & 0xFF){ +80000328: 0ff7f793 andi a5,a5,255 +8000032c: 00700713 li a4,7 +80000330: 02e79c63 bne a5,a4,80000368 + csr_set(sip, MIP_STIP); +80000334: 02000793 li a5,32 +80000338: 1447a073 csrs sip,a5 + csr_clear(mie, MIE_MTIE); +8000033c: 08000793 li a5,128 +80000340: 3047b073 csrc mie,a5 } } } -80000320: 02c12083 lw ra,44(sp) -80000324: 02812403 lw s0,40(sp) -80000328: 02412483 lw s1,36(sp) -8000032c: 02012903 lw s2,32(sp) -80000330: 01c12983 lw s3,28(sp) -80000334: 01812a03 lw s4,24(sp) -80000338: 01412a83 lw s5,20(sp) -8000033c: 03010113 addi sp,sp,48 -80000340: 00008067 ret - redirectTrap(); -80000344: ebdff0ef jal ra,80000200 -80000348: fd9ff06f j 80000320 - int mepc = csr_read(mepc); -8000034c: 341024f3 csrr s1,mepc - int mstatus = csr_read(mstatus); -80000350: 300029f3 csrr s3,mstatus - int instruction = csr_read(mbadaddr); -80000354: 34302473 csrr s0,mbadaddr - int opcode = instruction & 0x7F; -80000358: 07f47693 andi a3,s0,127 - int funct3 = (instruction >> 12) & 0x7; -8000035c: 40c45793 srai a5,s0,0xc -80000360: 0077f793 andi a5,a5,7 +80000344: 02c12083 lw ra,44(sp) +80000348: 02812403 lw s0,40(sp) +8000034c: 02412483 lw s1,36(sp) +80000350: 02012903 lw s2,32(sp) +80000354: 01c12983 lw s3,28(sp) +80000358: 01812a03 lw s4,24(sp) +8000035c: 01412a83 lw s5,20(sp) +80000360: 03010113 addi sp,sp,48 +80000364: 00008067 ret + default: redirectTrap(); break; +80000368: e99ff0ef jal ra,80000200 +8000036c: fd9ff06f j 80000344 + uint32_t mepc = csr_read(mepc); +80000370: 341024f3 csrr s1,mepc + uint32_t mstatus = csr_read(mstatus); +80000374: 30002a73 csrr s4,mstatus + uint32_t instruction = csr_read(mbadaddr); +80000378: 34302473 csrr s0,mbadaddr + uint32_t opcode = instruction & 0x7F; +8000037c: 07f47713 andi a4,s0,127 + uint32_t funct3 = (instruction >> 12) & 0x7; +80000380: 00c45793 srli a5,s0,0xc +80000384: 0077f613 andi a2,a5,7 switch(opcode){ -80000364: 02f00713 li a4,47 -80000368: fae69ce3 bne a3,a4,80000320 +80000388: 02f00693 li a3,47 +8000038c: 00d70a63 beq a4,a3,800003a0 +80000390: 07300693 li a3,115 +80000394: 12d70a63 beq a4,a3,800004c8 + default: redirectTrap(); break; +80000398: e69ff0ef jal ra,80000200 +8000039c: fa9ff06f j 80000344 switch(funct3){ -8000036c: 00200713 li a4,2 -80000370: 10e79e63 bne a5,a4,8000048c - int sel = instruction >> 27; -80000374: 41b45913 srai s2,s0,0x1b - int addr = readRegister((instruction >> 15) & 0x1F); -80000378: 40f45513 srai a0,s0,0xf -8000037c: 01f57513 andi a0,a0,31 -80000380: e41ff0ef jal ra,800001c0 -80000384: 00050a93 mv s5,a0 - int src = readRegister((instruction >> 20) & 0x1F); -80000388: 41445513 srai a0,s0,0x14 -8000038c: 01f57513 andi a0,a0,31 -80000390: e31ff0ef jal ra,800001c0 -80000394: 00050a13 mv s4,a0 - int rd = (instruction >> 7) & 0x1F; -80000398: 40745413 srai s0,s0,0x7 -8000039c: 01f47413 andi s0,s0,31 +800003a0: 00200793 li a5,2 +800003a4: 10f61e63 bne a2,a5,800004c0 + uint32_t sel = instruction >> 27; +800003a8: 01b45913 srli s2,s0,0x1b + uint32_t addr = readRegister((instruction >> 15) & 0x1F); +800003ac: 00f45513 srli a0,s0,0xf +800003b0: 01f57513 andi a0,a0,31 +800003b4: e1dff0ef jal ra,800001d0 +800003b8: 00050a93 mv s5,a0 + int32_t src = readRegister((instruction >> 20) & 0x1F); +800003bc: 01445513 srli a0,s0,0x14 +800003c0: 01f57513 andi a0,a0,31 +800003c4: e0dff0ef jal ra,800001d0 +800003c8: 00050993 mv s3,a0 + uint32_t rd = (instruction >> 7) & 0x1F; +800003cc: 00745413 srli s0,s0,0x7 +800003d0: 01f47413 andi s0,s0,31 if(readWord(addr, &readValue)){ -800003a0: 00c10593 addi a1,sp,12 -800003a4: 000a8513 mv a0,s5 -800003a8: ed9ff0ef jal ra,80000280 -800003ac: 02051263 bnez a0,800003d0 +800003d4: 00c10593 addi a1,sp,12 +800003d8: 000a8513 mv a0,s5 +800003dc: ea9ff0ef jal ra,80000284 +800003e0: 02051263 bnez a0,80000404 switch(sel){ -800003b0: 01c00793 li a5,28 -800003b4: 0d27e063 bltu a5,s2,80000474 -800003b8: 00291913 slli s2,s2,0x2 -800003bc: 800007b7 lui a5,0x80000 -800003c0: 56478793 addi a5,a5,1380 # 80000564 <_sp+0xfffff78c> -800003c4: 00f90933 add s2,s2,a5 -800003c8: 00092783 lw a5,0(s2) -800003cc: 00078067 jr a5 +800003e4: 01c00793 li a5,28 +800003e8: 0d27e063 bltu a5,s2,800004a8 +800003ec: 00291913 slli s2,s2,0x2 +800003f0: 800007b7 lui a5,0x80000 +800003f4: 6c078793 addi a5,a5,1728 # 800006c0 <_sp+0xfffff788> +800003f8: 00f90933 add s2,s2,a5 +800003fc: 00092783 lw a5,0(s2) +80000400: 00078067 jr a5 emulationTrapToSupervisorTrap(mepc, mstatus); -800003d0: 00098593 mv a1,s3 -800003d4: 00048513 mv a0,s1 -800003d8: e61ff0ef jal ra,80000238 +80000404: 000a0593 mv a1,s4 +80000408: 00048513 mv a0,s1 +8000040c: e2dff0ef jal ra,80000238 return; -800003dc: f45ff06f j 80000320 +80000410: f35ff06f j 80000344 case 0x0: writeValue = src + readValue; break; -800003e0: 00c12783 lw a5,12(sp) -800003e4: 00fa0a33 add s4,s4,a5 +80000414: 00c12783 lw a5,12(sp) +80000418: 00f989b3 add s3,s3,a5 writeRegister(rd, readValue); -800003e8: 00c12583 lw a1,12(sp) -800003ec: 00040513 mv a0,s0 -800003f0: de9ff0ef jal ra,800001d8 +8000041c: 00c12583 lw a1,12(sp) +80000420: 00040513 mv a0,s0 +80000424: dc5ff0ef jal ra,800001e8 if(writeWord(addr, writeValue)){ -800003f4: 000a0593 mv a1,s4 -800003f8: 000a8513 mv a0,s5 -800003fc: eb9ff0ef jal ra,800002b4 -80000400: 06051e63 bnez a0,8000047c +80000428: 00098593 mv a1,s3 +8000042c: 000a8513 mv a0,s5 +80000430: e89ff0ef jal ra,800002b8 +80000434: 06051e63 bnez a0,800004b0 csr_write(mepc, mepc + 4); -80000404: 00448493 addi s1,s1,4 -80000408: 34149073 csrw mepc,s1 +80000438: 00448493 addi s1,s1,4 +8000043c: 34149073 csrw mepc,s1 }break; -8000040c: f15ff06f j 80000320 +80000440: f05ff06f j 80000344 case 0x4: writeValue = src ^ readValue; break; -80000410: 00c12783 lw a5,12(sp) -80000414: 00fa4a33 xor s4,s4,a5 -80000418: fd1ff06f j 800003e8 - case 0xC: writeValue = src & readValue; break; -8000041c: 00c12783 lw a5,12(sp) -80000420: 00fa7a33 and s4,s4,a5 -80000424: fc5ff06f j 800003e8 - case 0x8: writeValue = src | readValue; break; -80000428: 00c12783 lw a5,12(sp) -8000042c: 00fa6a33 or s4,s4,a5 -80000430: fb9ff06f j 800003e8 - case 0x10: writeValue = min(src, readValue); break; -80000434: 00c12783 lw a5,12(sp) -80000438: fb47d8e3 ble s4,a5,800003e8 -8000043c: 00078a13 mv s4,a5 -80000440: fa9ff06f j 800003e8 - case 0x14: writeValue = max(src, readValue); break; 80000444: 00c12783 lw a5,12(sp) -80000448: fafa50e3 ble a5,s4,800003e8 -8000044c: 00078a13 mv s4,a5 -80000450: f99ff06f j 800003e8 +80000448: 00f9c9b3 xor s3,s3,a5 +8000044c: fd1ff06f j 8000041c + case 0xC: writeValue = src & readValue; break; +80000450: 00c12783 lw a5,12(sp) +80000454: 00f9f9b3 and s3,s3,a5 +80000458: fc5ff06f j 8000041c + case 0x8: writeValue = src | readValue; break; +8000045c: 00c12783 lw a5,12(sp) +80000460: 00f9e9b3 or s3,s3,a5 +80000464: fb9ff06f j 8000041c + case 0x10: writeValue = min(src, readValue); break; +80000468: 00c12783 lw a5,12(sp) +8000046c: fb37d8e3 ble s3,a5,8000041c +80000470: 00078993 mv s3,a5 +80000474: fa9ff06f j 8000041c + case 0x14: writeValue = max(src, readValue); break; +80000478: 00c12783 lw a5,12(sp) +8000047c: faf9d0e3 ble a5,s3,8000041c +80000480: 00078993 mv s3,a5 +80000484: f99ff06f j 8000041c case 0x18: writeValue = min((unsigned int)src, (unsigned int)readValue); break; -80000454: 00c12783 lw a5,12(sp) -80000458: f947f8e3 bleu s4,a5,800003e8 -8000045c: 00078a13 mv s4,a5 -80000460: f89ff06f j 800003e8 +80000488: 00c12783 lw a5,12(sp) +8000048c: f937f8e3 bleu s3,a5,8000041c +80000490: 00078993 mv s3,a5 +80000494: f89ff06f j 8000041c case 0x1C: writeValue = max((unsigned int)src, (unsigned int)readValue); break; -80000464: 00c12783 lw a5,12(sp) -80000468: f8fa70e3 bleu a5,s4,800003e8 -8000046c: 00078a13 mv s4,a5 -80000470: f79ff06f j 800003e8 +80000498: 00c12783 lw a5,12(sp) +8000049c: f8f9f0e3 bleu a5,s3,8000041c +800004a0: 00078993 mv s3,a5 +800004a4: f79ff06f j 8000041c default: redirectTrap(); return; break; -80000474: d8dff0ef jal ra,80000200 -80000478: ea9ff06f j 80000320 +800004a8: d59ff0ef jal ra,80000200 +800004ac: e99ff06f j 80000344 emulationTrapToSupervisorTrap(mepc, mstatus); -8000047c: 00098593 mv a1,s3 -80000480: 00048513 mv a0,s1 -80000484: db5ff0ef jal ra,80000238 +800004b0: 000a0593 mv a1,s4 +800004b4: 00048513 mv a0,s1 +800004b8: d81ff0ef jal ra,80000238 return; -80000488: e99ff06f j 80000320 +800004bc: e89ff06f j 80000344 default: redirectTrap(); break; -8000048c: d75ff0ef jal ra,80000200 -80000490: e91ff06f j 80000320 - int which = readRegister(17); -80000494: 01100513 li a0,17 -80000498: d29ff0ef jal ra,800001c0 +800004c0: d41ff0ef jal ra,80000200 +800004c4: e81ff06f j 80000344 + switch (funct3 & 0x3) { +800004c8: 0037f793 andi a5,a5,3 +800004cc: 00100713 li a4,1 +800004d0: 06e78263 beq a5,a4,80000534 +800004d4: 02078c63 beqz a5,8000050c +800004d8: 00200713 li a4,2 +800004dc: 02e78c63 beq a5,a4,80000514 +800004e0: 00300713 li a4,3 +800004e4: 04e78063 beq a5,a4,80000524 + uint32_t csrAddress = instruction >> 20; +800004e8: 01445713 srli a4,s0,0x14 + switch(csrAddress){ +800004ec: 000017b7 lui a5,0x1 +800004f0: c0178793 addi a5,a5,-1023 # c01 <__stack_size+0x401> +800004f4: 04f70463 beq a4,a5,8000053c +800004f8: 000017b7 lui a5,0x1 +800004fc: c8178793 addi a5,a5,-895 # c81 <__stack_size+0x481> +80000500: 06f70263 beq a4,a5,80000564 + default: redirectTrap(); break; +80000504: cfdff0ef jal ra,80000200 +80000508: 03c0006f j 80000544 + case 0: redirectTrap(); break; +8000050c: cf5ff0ef jal ra,80000200 +80000510: fd9ff06f j 800004e8 + case 2: clear = 0; set = input; write = ((instruction >> 15) & 0x1F) != 0; break; +80000514: 00f45993 srli s3,s0,0xf +80000518: 01f9f993 andi s3,s3,31 +8000051c: 013039b3 snez s3,s3 +80000520: fc9ff06f j 800004e8 + case 3: clear = input; set = 0; write = ((instruction >> 15) & 0x1F) != 0; break; +80000524: 00f45993 srli s3,s0,0xf +80000528: 01f9f993 andi s3,s3,31 +8000052c: 013039b3 snez s3,s3 +80000530: fb9ff06f j 800004e8 + case 1: clear = ~0; set = input; write = 1; break; +80000534: 00100993 li s3,1 +80000538: fb1ff06f j 800004e8 + case RDTIME : old = rdtime(); break; +8000053c: 0c4000ef jal ra,80000600 +80000540: 00050913 mv s2,a0 + if(write) { +80000544: 02099663 bnez s3,80000570 + writeRegister((instruction >> 7) & 0x1F, old); +80000548: 00745513 srli a0,s0,0x7 +8000054c: 00090593 mv a1,s2 +80000550: 01f57513 andi a0,a0,31 +80000554: c95ff0ef jal ra,800001e8 + csr_write(mepc, mepc + 4); +80000558: 00448493 addi s1,s1,4 +8000055c: 34149073 csrw mepc,s1 + }break; +80000560: de5ff06f j 80000344 + case RDTIMEH : old = rdtimeh(); break; +80000564: 0a4000ef jal ra,80000608 +80000568: 00050913 mv s2,a0 +8000056c: fd9ff06f j 80000544 + default: redirectTrap(); break; +80000570: c91ff0ef jal ra,80000200 +80000574: fd5ff06f j 80000548 + uint32_t which = readRegister(17); +80000578: 01100513 li a0,17 +8000057c: c55ff0ef jal ra,800001d0 +80000580: 00050413 mv s0,a0 + uint32_t a0 = readRegister(10); +80000584: 00a00513 li a0,10 +80000588: c49ff0ef jal ra,800001d0 +8000058c: 00050493 mv s1,a0 + uint32_t a1 = readRegister(11); +80000590: 00b00513 li a0,11 +80000594: c3dff0ef jal ra,800001d0 switch(which){ -8000049c: 00100793 li a5,1 -800004a0: 02f51263 bne a0,a5,800004c4 - putC(readRegister(10)); -800004a4: 00a00513 li a0,10 -800004a8: d19ff0ef jal ra,800001c0 -800004ac: 0ff57513 andi a0,a0,255 -800004b0: d49ff0ef jal ra,800001f8 +80000598: 02040263 beqz s0,800005bc +8000059c: 00100793 li a5,1 +800005a0: 04f41463 bne s0,a5,800005e8 + putC(a0); +800005a4: 0ff4f513 andi a0,s1,255 +800005a8: 050000ef jal ra,800005f8 csr_write(mepc, csr_read(mepc) + 4); -800004b4: 341027f3 csrr a5,mepc -800004b8: 00478793 addi a5,a5,4 -800004bc: 34179073 csrw mepc,a5 +800005ac: 341027f3 csrr a5,mepc +800005b0: 00478793 addi a5,a5,4 +800005b4: 34179073 csrw mepc,a5 }break; -800004c0: e61ff06f j 80000320 +800005b8: d8dff06f j 80000344 + setMachineTimerCmp(a0, a1); +800005bc: 00050593 mv a1,a0 +800005c0: 00048513 mv a0,s1 +800005c4: 04c000ef jal ra,80000610 + csr_set(mie, MIE_MTIE); +800005c8: 08000793 li a5,128 +800005cc: 3047a073 csrs mie,a5 + csr_clear(sip, MIP_STIP); +800005d0: 02000793 li a5,32 +800005d4: 1447b073 csrc sip,a5 + csr_write(mepc, csr_read(mepc) + 4); +800005d8: 341027f3 csrr a5,mepc +800005dc: 00478793 addi a5,a5,4 +800005e0: 34179073 csrw mepc,a5 + }break; +800005e4: d61ff06f j 80000344 default: stopSim(); break; -800004c4: d2dff0ef jal ra,800001f0 -800004c8: e59ff06f j 80000320 +800005e8: 008000ef jal ra,800005f0 +800005ec: d59ff06f j 80000344 -800004cc <__libc_init_array>: -800004cc: ff010113 addi sp,sp,-16 -800004d0: 00812423 sw s0,8(sp) -800004d4: 00912223 sw s1,4(sp) -800004d8: 00000417 auipc s0,0x0 -800004dc: 08c40413 addi s0,s0,140 # 80000564 <__init_array_end> -800004e0: 00000497 auipc s1,0x0 -800004e4: 08448493 addi s1,s1,132 # 80000564 <__init_array_end> -800004e8: 408484b3 sub s1,s1,s0 -800004ec: 01212023 sw s2,0(sp) -800004f0: 00112623 sw ra,12(sp) -800004f4: 4024d493 srai s1,s1,0x2 -800004f8: 00000913 li s2,0 -800004fc: 04991063 bne s2,s1,8000053c <__libc_init_array+0x70> -80000500: 00000417 auipc s0,0x0 -80000504: 06440413 addi s0,s0,100 # 80000564 <__init_array_end> -80000508: 00000497 auipc s1,0x0 -8000050c: 05c48493 addi s1,s1,92 # 80000564 <__init_array_end> -80000510: 408484b3 sub s1,s1,s0 -80000514: b65ff0ef jal ra,80000078 <_init> -80000518: 4024d493 srai s1,s1,0x2 -8000051c: 00000913 li s2,0 -80000520: 02991863 bne s2,s1,80000550 <__libc_init_array+0x84> -80000524: 00c12083 lw ra,12(sp) -80000528: 00812403 lw s0,8(sp) -8000052c: 00412483 lw s1,4(sp) -80000530: 00012903 lw s2,0(sp) -80000534: 01010113 addi sp,sp,16 -80000538: 00008067 ret -8000053c: 00042783 lw a5,0(s0) -80000540: 00190913 addi s2,s2,1 -80000544: 00440413 addi s0,s0,4 -80000548: 000780e7 jalr a5 -8000054c: fb1ff06f j 800004fc <__libc_init_array+0x30> -80000550: 00042783 lw a5,0(s0) -80000554: 00190913 addi s2,s2,1 -80000558: 00440413 addi s0,s0,4 -8000055c: 000780e7 jalr a5 -80000560: fc1ff06f j 80000520 <__libc_init_array+0x54> +800005f0 : +#include "hal.h" + +void stopSim(){ + *((volatile uint32_t*) 0xFFFFFFFC) = 0; +800005f0: fe002e23 sw zero,-4(zero) # fffffffc <_sp+0x7ffff0c4> +} +800005f4: 00008067 ret + +800005f8 : + +void putC(char c){ + *((volatile uint32_t*) 0xFFFFFFF8) = c; +800005f8: fea02c23 sw a0,-8(zero) # fffffff8 <_sp+0x7ffff0c0> +} +800005fc: 00008067 ret + +80000600 : + +uint32_t rdtime(){ + return *((volatile uint32_t*) 0xFFFFFFE0); +80000600: fe002503 lw a0,-32(zero) # ffffffe0 <_sp+0x7ffff0a8> +} +80000604: 00008067 ret + +80000608 : + +uint32_t rdtimeh(){ + return *((volatile uint32_t*) 0xFFFFFFE4); +80000608: fe402503 lw a0,-28(zero) # ffffffe4 <_sp+0x7ffff0ac> +} +8000060c: 00008067 ret + +80000610 : + + +void setMachineTimerCmp(uint32_t low, uint32_t high){ + volatile uint32_t* base = (volatile uint32_t*) 0xFFFFFFE8; + base[1] = 0xffffffff; +80000610: fec00793 li a5,-20 +80000614: fff00713 li a4,-1 +80000618: 00e7a023 sw a4,0(a5) + base[0] = low; +8000061c: fea02423 sw a0,-24(zero) # ffffffe8 <_sp+0x7ffff0b0> + base[1] = high; +80000620: 00b7a023 sw a1,0(a5) +} +80000624: 00008067 ret + +80000628 <__libc_init_array>: +80000628: ff010113 addi sp,sp,-16 +8000062c: 00812423 sw s0,8(sp) +80000630: 00912223 sw s1,4(sp) +80000634: 00000417 auipc s0,0x0 +80000638: 08c40413 addi s0,s0,140 # 800006c0 <__init_array_end> +8000063c: 00000497 auipc s1,0x0 +80000640: 08448493 addi s1,s1,132 # 800006c0 <__init_array_end> +80000644: 408484b3 sub s1,s1,s0 +80000648: 01212023 sw s2,0(sp) +8000064c: 00112623 sw ra,12(sp) +80000650: 4024d493 srai s1,s1,0x2 +80000654: 00000913 li s2,0 +80000658: 04991063 bne s2,s1,80000698 <__libc_init_array+0x70> +8000065c: 00000417 auipc s0,0x0 +80000660: 06440413 addi s0,s0,100 # 800006c0 <__init_array_end> +80000664: 00000497 auipc s1,0x0 +80000668: 05c48493 addi s1,s1,92 # 800006c0 <__init_array_end> +8000066c: 408484b3 sub s1,s1,s0 +80000670: a09ff0ef jal ra,80000078 <_init> +80000674: 4024d493 srai s1,s1,0x2 +80000678: 00000913 li s2,0 +8000067c: 02991863 bne s2,s1,800006ac <__libc_init_array+0x84> +80000680: 00c12083 lw ra,12(sp) +80000684: 00812403 lw s0,8(sp) +80000688: 00412483 lw s1,4(sp) +8000068c: 00012903 lw s2,0(sp) +80000690: 01010113 addi sp,sp,16 +80000694: 00008067 ret +80000698: 00042783 lw a5,0(s0) +8000069c: 00190913 addi s2,s2,1 +800006a0: 00440413 addi s0,s0,4 +800006a4: 000780e7 jalr a5 +800006a8: fb1ff06f j 80000658 <__libc_init_array+0x30> +800006ac: 00042783 lw a5,0(s0) +800006b0: 00190913 addi s2,s2,1 +800006b4: 00440413 addi s0,s0,4 +800006b8: 000780e7 jalr a5 +800006bc: fc1ff06f j 8000067c <__libc_init_array+0x54> diff --git a/src/main/c/emulator/build/emulator.hex b/src/main/c/emulator/build/emulator.hex index 7aba5679..4b5dcb75 100644 --- a/src/main/c/emulator/build/emulator.hex +++ b/src/main/c/emulator/build/emulator.hex @@ -1,11 +1,11 @@ :0200000480007A -:1000000017110000130181DD170500001305C55508 -:100010009705000093854555170600001306065CFA +:1000000017110000130181F3170500001305856B1C +:10001000970500009385056B17060000130606720E :1000200063FCC5008322050023A05500130545008D -:1000300093854500E3E8C5FE170500001305055A42 -:1000400097050000938585596378B5002320050046 -:1000500013054500E36CB5FEEF004047EF0080124A -:100060009700000093804001370500819305000050 +:1000300093854500E3E8C5FE17050000130505702C +:10004000970500009385856F6378B5002320050030 +:1000500013054500E36CB5FEEF00005DEF00801274 +:10006000970000009380400113050000B705008150 :10007000730020306F0000006780000073110134AE :1000800023200100232211002326310023284100D0 :10009000232A5100232C6100232E7100232081028A @@ -14,7 +14,7 @@ :1000C0002322110523242105232631052328410558 :1000D000232A5105232C6105232E71052320810736 :1000E000232291072324A1072326B1072328C10730 -:1000F000232AD107232CE107232EF107EF00801ECE +:1000F000232AD107232CE107232EF107EF00C01E8E :1001000003200100832041008321C100032201015B :1001100083224101032381018323C10103240102BE :1001200083244102032581028325C10203260103A2 @@ -25,74 +25,96 @@ :10017000832E4107032F8107832FC1077311013499 :0401800073002030B8 :10018400B70700809387C70773905730B71700806D -:10019400938787DD938707F873900734B7170000B8 -:1001A4009387078073900730B70700C073901734A4 -:1001B400B7B700007390273067800000131525003F -:1001C400B7170080938787DD3305F500032505F80D -:1001D4006780000013152500B7170080938787DD1B -:1001E4003305F5002320B5F867800000232E00FEB8 -:1001F40067800000232CA0FE67800000130101FF2C -:1002040023261100EFF09FFEF32730347390371448 +:10019400938787F3938707F873900734B7170000A2 +:1001A400938707887390073073504030B70700C0B7 +:1001B40073901734B7B70000739027309307000289 +:1001C4007390373073503014678000001315250086 +:1001D400B7170080938787F33305F500032505F8E7 +:1001E4006780000013152500B7170080938787F3F5 +:1001F4003305F5002320B5F867800000130101FFE3 +:1002040023261100EF00803EF32730347390371417 :10021400F327103473901714F327203473902714A2 :10022400F3275010739017348320C1001301010188 :1002340067800000F327303473903714F327203499 :100244007390271473101514F327501073901734F8 :100254009307001073B0071093D5350093F505107C :1002640073A00510B72700009387078073B0073089 -:10027400B787000073A007306780000037070200CB -:100284007320073017070000130787017310173412 -:100294009306100083270500930600003707020029 -:1002A400733007301385060023A0F5006780000033 -:1002B4003707020073200730170700001307870170 -:1002C40073101734930710002320B5009307000020 -:1002D400370702007330073013850700678000007A -:1002E400130101FD232611022324810223229102FA -:1002F40023202103232E3101232C4101232A5101E0 -:10030400F327203463CE070213072000638EE7022D -:1003140013079000638EE716EFF05FEE8320C102AF -:100324000324810283244102032901028329C10198 -:10033400032A8101832A410113010103678000001C -:10034400EFF0DFEB6FF09FFDF3241034F32900305E -:10035400732430349376F4079357C44093F77700AB -:100364001307F002E39CE6FA13072000639EE710EC -:100374001359B4411355F4401375F501EFF01FE41C -:10038400930A0500135544411375F501EFF01FE37B -:10039400130A0500135474401374F4019305C10047 -:1003A40013850A00EFF09FED631205029307C00165 -:1003B40063E0270D13192900B70700809387475678 -:1003C4003309F90083270900678007009385090032 -:1003D40013850400EFF01FE66FF05FF48327C1007C -:1003E400330AFA008325C10013050400EFF09FDEF1 -:1003F40093050A0013850A00EFF09FEB631E0506C0 -:1004040093844400739014346FF05FF18327C10028 -:10041400334AFA006FF01FFD8327C100337AFA00D4 -:100424006FF05FFC8327C100336AFA006FF09FFB13 -:100434008327C100E3D847FB138A07006FF09FFAB4 -:100444008327C100E350FAFA138A07006FF09FF97B -:100454008327C100E3F847F9138A07006FF09FF878 -:100464008327C100E370FAF8138A07006FF09FF73F -:10047400EFF0DFD86FF09FEA93850900138504003D -:10048400EFF05FDB6FF09FE9EFF05FD76FF01FE9EC -:1004940013051001EFF09FD2930710006312F502C9 -:1004A4001305A000EFF09FD11375F50FEFF09FD463 -:1004B400F327103493874700739017346FF01FE6C7 -:1004C400EFF0DFD26FF09FE5130101FF23248100D9 -:1004D40023229100170400001304C40897040000A9 -:1004E40093844408B38484402320210123261100EB -:1004F40093D42440130900006310990417040000E6 -:1005040013044406970400009384C405B384844010 -:10051400EFF05FB693D424401309000063189902E6 -:100524008320C100032481008324410003290100A6 -:1005340013010101678000008327040013091900D7 -:1005440013044400E78007006FF01FFB83270400B7 -:100554001309190013044400E78007006FF01FFC1F -:10056400E0030080E80300807404008074040080C9 -:1005740010040080740400807404008074040080FB -:1005840028040080740400807404008074040080D3 -:100594001C040080740400807404008074040080CF -:1005A40034040080740400807404008074040080A7 -:1005B4004404008074040080740400807404008087 -:1005C4005404008074040080740400807404008067 -:0405D400640400803B +:10027400B78700009387070873A0073067800000E2 +:1002840037070200732007301707000013078701A0 +:10029400731017349306100083270500930600009B +:1002A40037070200733007301385060023A0F500DA +:1002B400678000003707020073200730170700002B +:1002C4001307870173101734930710002320B50018 +:1002D40093070000370702007330073013850700C7 +:1002E40067800000130101FD2326110223248102EB +:1002F4002322910223202103232E3101232C4101A7 +:10030400232A5101F327203463CE0700130720006A +:10031400638EE70413079000638EE724EFF01FEE6B +:100324006F00000293F7F70F13077000639CE70256 +:100334009307000273A047149307000873B0473073 +:100344008320C10203248102832441020329010280 +:100354008329C101032A8101832A41011301010375 +:1003640067800000EFF09FE96FF09FFDF3241034E5 +:10037400732A0030732430341377F4079357C4007E +:1003840013F677009306F002630AD700930630074A +:10039400630AD712EFF09FE66FF09FFA93072000ED +:1003A400631EF6101359B4011355F4001375F501C7 +:1003B400EFF0DFE1930A0500135544011375F501CD +:1003C400EFF0DFE093090500135474001374F40193 +:1003D4009305C10013850A00EFF09FEA631205023A +:1003E4009307C00163E0270D13192900B7070080A4 +:1003F4009387076C3309F900832709006780070096 +:1004040093050A0013850400EFF0DFE26FF05FF359 +:100414008327C100B389F9008325C10013050400B3 +:10042400EFF05FDC9385090013850A00EFF09FE885 +:10043400631E050693844400739014346FF05FF0D8 +:100444008327C100B3C9F9006FF01FFD8327C100E2 +:10045400B3F9F9006FF05FFC8327C100B3E9F90039 +:100464006FF09FFB8327C100E3D837FB9389070014 +:100474006FF09FFA8327C100E3D0F9FA938907004C +:100484006FF09FF98327C100E3F837F993890700D8 +:100494006FF09FF88327C100E3F0F9F89389070010 +:1004A4006FF09FF7EFF09FD56FF09FE993050A0077 +:1004B40013850400EFF01FD86FF09FE8EFF01FD40E +:1004C4006FF01FE893F73700130710006382E70605 +:1004D400638C070213072000638CE70213073000C4 +:1004E4006380E70413574401B7170000938717C0CC +:1004F4006304F704B7170000938717C86302F7066D +:10050400EFF0DFCF6F00C003EFF05FCF6FF09FFD20 +:100514009359F40093F9F901B33930016FF09FFC5A +:100524009359F40093F9F901B33930016FF09FFB4B +:10053400930910006FF01FFBEF00400C1309050036 +:100544006396090213557400930509001375F501A8 +:10055400EFF05FC993844400739014346FF05FDE4E +:10056400EF00400A130905006FF09FFDEFF01FC96B +:100574006FF05FFD13051001EFF05FC51304050074 +:100584001305A000EFF09FC4930405001305B00009 +:10059400EFF0DFC363020402930710006314F40452 +:1005A40013F5F40FEF000005F32710349387470089 +:1005B400739017346FF0DFD893050500138504009A +:1005C400EF00C0049307000873A0473093070002AC +:1005D40073B04714F327103493874700739017348C +:1005E4006FF01FD6EF0080006FF09FD5232E00FE22 +:1005F40067800000232CA0FE67800000032500FE16 +:1006040067800000032540FE678000009307C0FE5A +:100614001307F0FF23A0E7002324A0FE23A0B700C4 +:1006240067800000130101FF23248100232291002D +:10063400170400001304C4089704000093844408BA +:10064400B3848440232021012326110093D4244021 +:1006540013090000631099041704000013044406EE +:10066400970400009384C405B3848440EFF09FA0F2 +:1006740093D4244013090000631899028320C10015 +:100684000324810083244100032901001301010193 +:100694006780000083270400130919001304440031 +:1006A400E78007006FF01FFB83270400130919007C +:0C06B40013044400E78007006FF01FFCF7 +:1006C000140400801C040080A8040080A80400809A +:1006D00044040080A8040080A8040080A8040080CE +:1006E0005C040080A8040080A8040080A8040080A6 +:1006F00050040080A8040080A8040080A8040080A2 +:1007000068040080A8040080A8040080A804008079 +:1007100078040080A8040080A8040080A804008059 +:1007200088040080A8040080A8040080A804008039 +:080730009804008000000000A5 :040000058000000077 :00000001FF diff --git a/src/main/c/emulator/src/config.h b/src/main/c/emulator/src/config.h index e39fa657..3c1f1aa3 100644 --- a/src/main/c/emulator/src/config.h +++ b/src/main/c/emulator/src/config.h @@ -3,8 +3,5 @@ #define OS_CALL 0xC0000000 #define DTB 0x81000000 -#define SIM_STOP 0xFFFFFFFC -#define PUTC 0xFFFFFFF8 - #endif diff --git a/src/main/c/emulator/src/hal.c b/src/main/c/emulator/src/hal.c new file mode 100644 index 00000000..cdb052df --- /dev/null +++ b/src/main/c/emulator/src/hal.c @@ -0,0 +1,25 @@ +#include "hal.h" + +void stopSim(){ + *((volatile uint32_t*) 0xFFFFFFFC) = 0; +} + +void putC(char c){ + *((volatile uint32_t*) 0xFFFFFFF8) = c; +} + +uint32_t rdtime(){ + return *((volatile uint32_t*) 0xFFFFFFE0); +} + +uint32_t rdtimeh(){ + return *((volatile uint32_t*) 0xFFFFFFE4); +} + + +void setMachineTimerCmp(uint32_t low, uint32_t high){ + volatile uint32_t* base = (volatile uint32_t*) 0xFFFFFFE8; + base[1] = 0xffffffff; + base[0] = low; + base[1] = high; +} diff --git a/src/main/c/emulator/src/hal.h b/src/main/c/emulator/src/hal.h new file mode 100644 index 00000000..c5cb70ae --- /dev/null +++ b/src/main/c/emulator/src/hal.h @@ -0,0 +1,23 @@ + +#ifndef HAL_H +#define HAL_H + +#include + +#define SBI_SET_TIMER 0 +#define SBI_CONSOLE_PUTCHAR 1 +#define SBI_CONSOLE_GETCHAR 2 +#define SBI_CLEAR_IPI 3 +#define SBI_SEND_IPI 4 +#define SBI_REMOTE_FENCE_I 5 +#define SBI_REMOTE_SFENCE_VMA 6 +#define SBI_REMOTE_SFENCE_VMA_ASID 7 +#define SBI_SHUTDOWN 8 + +void stopSim(); +void putC(char c); +uint32_t rdtime(); +uint32_t rdtimeh(); +void setMachineTimerCmp(uint32_t low, uint32_t high); + +#endif diff --git a/src/main/c/emulator/src/main.c b/src/main/c/emulator/src/main.c index aa058f71..a2171b83 100755 --- a/src/main/c/emulator/src/main.c +++ b/src/main/c/emulator/src/main.c @@ -1,38 +1,34 @@ #include #include "riscv.h" #include "config.h" +#include "hal.h" -extern const unsigned int _sp; +extern const uint32_t _sp; extern void trapEntry(); extern void emulationTrap(); void init() { - unsigned int sp = (unsigned int) (&_sp); + uint32_t sp = (uint32_t) (&_sp); csr_write(mtvec, trapEntry); csr_write(mscratch, sp -32*4); - csr_write(mstatus, 0x0800); + csr_write(mstatus, 0x0800 | MSTATUS_MPIE); + csr_write(mie, 0); csr_write(mepc, OS_CALL); - csr_write(medeleg, MDELEG_INSTRUCTION_PAGE_FAULT | MDELEG_LOAD_PAGE_FAULT | MDELEG_STORE_PAGE_FAULT); + csr_write(medeleg, MEDELEG_INSTRUCTION_PAGE_FAULT | MEDELEG_LOAD_PAGE_FAULT | MEDELEG_STORE_PAGE_FAULT); + csr_write(mideleg, MIDELEG_SUPERVISOR_TIMER); + csr_write(sbadaddr, 0); //Used to avoid simulation missmatch } -int readRegister(int id){ +int readRegister(uint32_t id){ unsigned int sp = (unsigned int) (&_sp); return ((int*) sp)[id-32]; } -void writeRegister(int id, int value){ - unsigned int sp = (unsigned int) (&_sp); - ((int*) sp)[id-32] = value; +void writeRegister(uint32_t id, int value){ + uint32_t sp = (uint32_t) (&_sp); + ((uint32_t*) sp)[id-32] = value; } -void stopSim(){ - *((volatile int*) SIM_STOP) = 0; -} - -void putC(char c){ - *((volatile int*) PUTC) = c; -} - void redirectTrap(){ stopSim(); @@ -50,7 +46,7 @@ void emulationTrapToSupervisorTrap(uint32_t sepc, uint32_t mstatus){ csr_clear(sstatus, MSTATUS_SPP); csr_set(sstatus, (mstatus >> 3) & MSTATUS_SPP); csr_clear(mstatus, MSTATUS_MPP); - csr_set(mstatus, 0x8000); + csr_set(mstatus, 0x8000 | MSTATUS_MPIE); } #define max(a,b) \ @@ -67,9 +63,9 @@ void emulationTrapToSupervisorTrap(uint32_t sepc, uint32_t mstatus){ //Will modify MEPC -int readWord(int address, int *data){ - int result, tmp; - int failed; +int32_t readWord(uint32_t address, int32_t *data){ + int32_t result, tmp; + int32_t failed; __asm__ __volatile__ ( " li %[tmp], 0x00020000\n" " csrs mstatus, %[tmp]\n" @@ -91,9 +87,9 @@ int readWord(int address, int *data){ } //Will modify MEPC -int writeWord(uint32_t address, uint32_t data){ - int result, tmp; - int failed; +int32_t writeWord(uint32_t address, int32_t data){ + int32_t result, tmp; + int32_t failed; __asm__ __volatile__ ( " li %[tmp], 0x00020000\n" " csrs mstatus, %[tmp]\n" @@ -116,30 +112,33 @@ int writeWord(uint32_t address, uint32_t data){ - - - void trap(){ - int cause = csr_read(mcause); - if(cause < 0){ - redirectTrap(); - } else { + int32_t cause = csr_read(mcause); + if(cause < 0){ //interrupt + switch(cause & 0xFF){ + case CAUSE_MACHINE_TIMER:{ + csr_set(sip, MIP_STIP); + csr_clear(mie, MIE_MTIE); + }break; + default: redirectTrap(); break; + } + } else { //exception switch(cause){ case CAUSE_ILLEGAL_INSTRUCTION:{ - int mepc = csr_read(mepc); - int mstatus = csr_read(mstatus); - int instruction = csr_read(mbadaddr); - int opcode = instruction & 0x7F; - int funct3 = (instruction >> 12) & 0x7; + uint32_t mepc = csr_read(mepc); + uint32_t mstatus = csr_read(mstatus); + uint32_t instruction = csr_read(mbadaddr); + uint32_t opcode = instruction & 0x7F; + uint32_t funct3 = (instruction >> 12) & 0x7; switch(opcode){ case 0x2F: //Atomic switch(funct3){ case 0x2:{ - int sel = instruction >> 27; - int addr = readRegister((instruction >> 15) & 0x1F); - int src = readRegister((instruction >> 20) & 0x1F); - int rd = (instruction >> 7) & 0x1F; - int readValue; + uint32_t sel = instruction >> 27; + uint32_t addr = readRegister((instruction >> 15) & 0x1F); + int32_t src = readRegister((instruction >> 20) & 0x1F); + uint32_t rd = (instruction >> 7) & 0x1F; + int32_t readValue; if(readWord(addr, &readValue)){ emulationTrapToSupervisorTrap(mepc, mstatus); return; @@ -148,6 +147,11 @@ void trap(){ switch(sel){ case 0x0: writeValue = src + readValue; break; case 0x1: writeValue = src; break; +//LR SC done in hardware (cheap), and require to keep track of context switches +// case 0x2:{ //LR +// }break; +// case 0x3:{ //SC +// }break; case 0x4: writeValue = src ^ readValue; break; case 0xC: writeValue = src & readValue; break; case 0x8: writeValue = src | readValue; break; @@ -165,14 +169,53 @@ void trap(){ csr_write(mepc, mepc + 4); }break; default: redirectTrap(); break; - } + } break; + case 0x73:{ + //CSR + uint32_t input = (instruction & 0x4000) ? ((instruction >> 15) & 0x1F) : readRegister((instruction >> 15) & 0x1F);; + uint32_t clear, set; + uint32_t write; + switch (funct3 & 0x3) { + case 0: redirectTrap(); break; + case 1: clear = ~0; set = input; write = 1; break; + case 2: clear = 0; set = input; write = ((instruction >> 15) & 0x1F) != 0; break; + case 3: clear = input; set = 0; write = ((instruction >> 15) & 0x1F) != 0; break; + } + uint32_t csrAddress = instruction >> 20; + uint32_t old; + switch(csrAddress){ + case RDTIME : old = rdtime(); break; + case RDTIMEH : old = rdtimeh(); break; + default: redirectTrap(); break; + } + if(write) { + uint32_t newValue = (old & ~clear) | set; + switch(csrAddress){ + default: redirectTrap(); break; + } + } + + writeRegister((instruction >> 7) & 0x1F, old); + csr_write(mepc, mepc + 4); + + }break; + default: redirectTrap(); break; } }break; case CAUSE_SCALL:{ - int which = readRegister(17); + uint32_t which = readRegister(17); + uint32_t a0 = readRegister(10); + uint32_t a1 = readRegister(11); + uint32_t a2 = readRegister(12); switch(which){ - case 1:{ - putC(readRegister(10)); + case SBI_CONSOLE_PUTCHAR:{ + putC(a0); + csr_write(mepc, csr_read(mepc) + 4); + }break; + case SBI_SET_TIMER:{ + setMachineTimerCmp(a0, a1); + csr_set(mie, MIE_MTIE); + csr_clear(sip, MIP_STIP); csr_write(mepc, csr_read(mepc) + 4); }break; default: stopSim(); break; diff --git a/src/main/c/emulator/src/riscv.h b/src/main/c/emulator/src/riscv.h index dcb125e5..06d2333c 100644 --- a/src/main/c/emulator/src/riscv.h +++ b/src/main/c/emulator/src/riscv.h @@ -2,11 +2,16 @@ #define RISCV_H #define CAUSE_ILLEGAL_INSTRUCTION 2 +#define CAUSE_MACHINE_TIMER 7 #define CAUSE_SCALL 9 -#define MDELEG_INSTRUCTION_PAGE_FAULT (1 << 12) -#define MDELEG_LOAD_PAGE_FAULT (1 << 13) -#define MDELEG_STORE_PAGE_FAULT (1 << 15) +#define MEDELEG_INSTRUCTION_PAGE_FAULT (1 << 12) +#define MEDELEG_LOAD_PAGE_FAULT (1 << 13) +#define MEDELEG_STORE_PAGE_FAULT (1 << 15) +#define MIDELEG_SUPERVISOR_TIMER (1 << 5) + +#define MIE_MTIE (1 << 7) +#define MIP_STIP (1 << 5) #define MSTATUS_UIE 0x00000001 #define MSTATUS_SIE 0x00000002 @@ -46,6 +51,13 @@ #define SSTATUS64_SD 0x8000000000000000 +#define RDCYCLE 0xC00 //Read-only cycle Cycle counter for RDCYCLE instruction. +#define RDTIME 0xC01 //Read-only time Timer for RDTIME instruction. +#define RDINSTRET 0xC02 //Read-only instret Instructions-retired counter for RDINSTRET instruction. +#define RDCYCLEH 0xC80 //Read-only cycleh Upper 32 bits of cycle, RV32I only. +#define RDTIMEH 0xC81 //Read-only timeh Upper 32 bits of time, RV32I only. +#define RDINSTRETH 0xC82 //Read-only instreth Upper 32 bits of instret, RV32I only. + #define csr_swap(csr, val) \ ({ \ diff --git a/src/main/c/emulator/src/start.S b/src/main/c/emulator/src/start.S index ef020e3c..af7fafe0 100755 --- a/src/main/c/emulator/src/start.S +++ b/src/main/c/emulator/src/start.S @@ -39,8 +39,8 @@ _start: call __libc_init_array call init la ra, done - li a0, DTB - li a1, 0 + li a0, 0 + li a1, DTB mret done: j done diff --git a/src/main/c/emulator/src/utils.S b/src/main/c/emulator/src/utils.S new file mode 100644 index 00000000..90c7b647 --- /dev/null +++ b/src/main/c/emulator/src/utils.S @@ -0,0 +1,47 @@ +#include "riscv.h" +/* + + .section .init + .globl readMemory + .type readMemory,@function +readWord: + csrr a4, mepc + li a2, MSTATUS_MPRV + csrs mstatus, a2 + li a3, emulationTrap + csrw mepc, a3 + lw a0, 0(a0) + li a3, trapEntry + csrw mepc, a3 + csrc mstatus, a2 + +writeWord: + csrr a4, mepc + li a2, MSTATUS_MPRV + csrs mstatus, a2 + li a3, emulationTrap + csrw mepc, a3 + sw a1, 0(a0) + li a3, trapEntry + csrw mepc, a3 + csrc mstatus, a2 +*/ +//Redirect trap to supervisor +/* + .section .init + .globl emulationTrap + .type emulationTrap,@function +emulationTrap: + li a0, MSTATUS_MPRV + csrc mstatus, a0 + + la sp, _sp + csrw sepc, a4 + csrr a0, mcause + csrw scause, a0 + csrr a0, mbadaddr + csrw sbadaddr, a0 + + call init + mret +*/ diff --git a/src/main/scala/vexriscv/demo/Linux.scala b/src/main/scala/vexriscv/demo/Linux.scala index f2a84e89..9a35bb9b 100644 --- a/src/main/scala/vexriscv/demo/Linux.scala +++ b/src/main/scala/vexriscv/demo/Linux.scala @@ -46,9 +46,8 @@ make run DBUS=SIMPLE IBUS=SIMPLE SUPERVISOR=yes CSR=yes COMPRESSED=yes LITEX=yes Other commands (Memo): cp litex_default_configuration .config -ARCH=riscv CROSS_COMPILE=riscv64-unknown-elf- make -j`nproc` -riscv64-unknown-elf-objcopy -O binary vmlinux vmlinux.bin -riscv64-unknown-elf-objdump -S -d vmlinux > vmlinux.asm +ARCH=riscv CROSS_COMPILE=riscv64-unknown-elf- make -j`nproc`; riscv64-unknown-elf-objcopy -O binary vmlinux vmlinux.bin +riscv64-unknown-elf-objdump -S -d vmlinux > vmlinux.asm; split -b 1M vmlinux.asm split -b 1M vmlinux.asm dtc -O dtb -o rv32.dtb rv32.dts @@ -56,10 +55,13 @@ make run DBUS=SIMPLE IBUS=SIMPLE SUPERVISOR=yes CSR=yes COMPRESSED=yes LITEX=yes */ + +//TODO have to check, look like supervisor can't get interrupt if the machine mod didn't delegated it, have to check exactly object LinuxGen { def configFull(litex : Boolean, withMmu : Boolean) = { val config = VexRiscvConfig( plugins = List( + new DummyFencePlugin(), //TODO should be removed for design with caches new IBusSimplePlugin( resetVector = 0x80000000l, cmdForkOnSecondStage = false, @@ -102,6 +104,7 @@ object LinuxGen { catchAddressMisaligned = true, catchAccessFault = true, earlyInjection = false, + atomicEntriesCount = 1, memoryTranslatorPortConfig = withMmu generate MmuPortConfig( portTlbSize = 4 ) @@ -200,7 +203,8 @@ object LinuxGen { ) ) if(withMmu) config.plugins += new MmuPlugin( - virtualRange = a => True, +// virtualRange = a => True, + virtualRange = x => x(31 downto 24) =/= 0x81, //TODO It fix the DTB kernel access (workaround) ioRange = (x => if(litex) x(31 downto 28) === 0xB || x(31 downto 28) === 0xE || x(31 downto 28) === 0xF else x(31 downto 28) === 0xF), allowUserIo = true ) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index eeb7eb1a..b6e77877 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -781,7 +781,7 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception scause.interrupt := !hadException scause.exceptionCode := trapCause sepc := mepcCaptureStage.input(PC) - if (exceptionPortCtrl != null) { + if (exceptionPortCtrl != null) when(hadException){ stval := exceptionPortCtrl.exceptionContext.badAddr } } @@ -793,7 +793,7 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception mcause.interrupt := !hadException mcause.exceptionCode := trapCause mepc := mepcCaptureStage.input(PC) - if(exceptionPortCtrl != null) { + if(exceptionPortCtrl != null) when(hadException){ mtval := exceptionPortCtrl.exceptionContext.badAddr } } @@ -872,7 +872,7 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception if(selfException != null) { selfException.valid := False selfException.code.assignDontCare() - selfException.badAddr := 0 + selfException.badAddr := input(INSTRUCTION).asUInt if(catchIllegalAccess) when(illegalAccess || illegalInstruction){ selfException.valid := True selfException.code := 2 diff --git a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala index 3dc7ad34..3dde6dc8 100644 --- a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala @@ -205,17 +205,21 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, earlyInjection : Boolean = false, /*, idempotentRegions : (UInt) => Bool = (x) => False*/ emitCmdInMemoryStage : Boolean = false, onlyLoadWords : Boolean = false, + atomicEntriesCount : Int = 0, memoryTranslatorPortConfig : Any = null) extends Plugin[VexRiscv] with DBusAccessService { var dBus : DBusSimpleBus = null assert(!(emitCmdInMemoryStage && earlyInjection)) - + def genAtomic = atomicEntriesCount != 0 object MEMORY_ENABLE extends Stageable(Bool) object MEMORY_READ_DATA extends Stageable(Bits(32 bits)) object MEMORY_ADDRESS_LOW extends Stageable(UInt(2 bits)) object ALIGNEMENT_FAULT extends Stageable(Bool) object MMU_FAULT extends Stageable(Bool) object MMU_RSP extends Stageable(MemoryTranslatorRsp()) + object MEMORY_ATOMIC extends Stageable(Bool) + object ATOMIC_HIT extends Stageable(Bool) + object MEMORY_STORE extends Stageable(Bool) var memoryExceptionPort : Flow[ExceptionCause] = null var rspStage : Stage = null @@ -248,12 +252,14 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, SRC2_CTRL -> Src2CtrlEnum.IMI, REGFILE_WRITE_VALID -> True, BYPASSABLE_EXECUTE_STAGE -> False, - BYPASSABLE_MEMORY_STAGE -> Bool(earlyInjection) + BYPASSABLE_MEMORY_STAGE -> Bool(earlyInjection), + MEMORY_STORE -> False ) ++ (if(catchAccessFault || catchAddressMisaligned) List(HAS_SIDE_EFFECT -> True) else Nil) val storeActions = stdActions ++ List( SRC2_CTRL -> Src2CtrlEnum.IMS, - RS2_USE -> True + RS2_USE -> True, + MEMORY_STORE -> True ) decoderService.addDefault(MEMORY_ENABLE, False) @@ -263,6 +269,29 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, ) + 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( + SRC2_CTRL -> Src2CtrlEnum.RS, + MEMORY_ATOMIC -> True + ) + ) + //TODO probably the cached implemention of SC is bugy (address calculation) + decoderService.add( + key = SC, + values = storeActions.filter(_._1 != SRC2_CTRL) ++ Seq( + REGFILE_WRITE_VALID -> True, + BYPASSABLE_EXECUTE_STAGE -> False, + BYPASSABLE_MEMORY_STAGE -> False, + MEMORY_ATOMIC -> True + ) + ) + } + rspStage = if(stages.last == execute) execute else (if(emitCmdInMemoryStage) writeBack else memory) if(catchSomething) { @@ -300,7 +329,7 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, skipCmd setWhen(input(ALIGNEMENT_FAULT)) dBus.cmd.valid := arbitration.isValid && input(MEMORY_ENABLE) && !arbitration.isStuckByOthers && !arbitration.isFlushed && !skipCmd && !cmdSent - dBus.cmd.wr := input(INSTRUCTION)(5) + dBus.cmd.wr := input(MEMORY_STORE) dBus.cmd.size := input(INSTRUCTION)(13 downto 12).asUInt dBus.cmd.payload.data := dBus.cmd.size.mux ( U(0) -> input(RS2)(7 downto 0) ## input(RS2)(7 downto 0) ## input(RS2)(7 downto 0) ## input(RS2)(7 downto 0), @@ -332,7 +361,7 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, dBus.cmd.address := mmuBus.rsp.physicalAddress //do not emit memory request if MMU refilling - insert(MMU_FAULT) := input(MMU_RSP).exception || (!input(MMU_RSP).allowWrite && input(INSTRUCTION)(5)) || (!input(MMU_RSP).allowRead && !input(INSTRUCTION)(5)) || (!input(MMU_RSP).allowUser && privilegeService.isUser()) + insert(MMU_FAULT) := input(MMU_RSP).exception || (!input(MMU_RSP).allowWrite && input(MEMORY_STORE)) || (!input(MMU_RSP).allowRead && !input(MEMORY_STORE)) || (!input(MMU_RSP).allowUser && privilegeService.isUser()) skipCmd.setWhen(input(MMU_FAULT) || input(MMU_RSP).refilling) insert(MMU_RSP) := mmuBus.rsp @@ -341,6 +370,40 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, val mmuLess = (mmuBus == null) generate new Area{ dBus.cmd.address := input(SRC_ADD).asUInt } + + + val atomic = genAtomic generate new Area{ + val address = input(SRC1).asUInt //TODO could avoid 32 muxes if SRC_ADD can be disabled + case class AtomicEntry() extends Bundle{ + val valid = Bool() + val address = UInt(32 bits) + + def init: this.type ={ + valid init(False) + this + } + } + val entries = Vec(Reg(AtomicEntry()).init, atomicEntriesCount) + val entriesAllocCounter = Counter(atomicEntriesCount) + insert(ATOMIC_HIT) := entries.map(e => e.valid && e.address === address).orR + when(arbitration.isValid && input(MEMORY_ENABLE) && input(MEMORY_ATOMIC) && !input(MEMORY_STORE)){ + entries(entriesAllocCounter).valid := True + entries(entriesAllocCounter).address := address + when(!arbitration.isStuck){ + entriesAllocCounter.increment() + } + } + when(service(classOf[IContextSwitching]).isContextSwitching){ + entries.foreach(_.valid := False) + } + + when(input(MEMORY_STORE) && input(MEMORY_ATOMIC) && !input(ATOMIC_HIT)){ + skipCmd := True + } + when(input(MEMORY_ATOMIC)){ + mmuBus.cmd.virtualAddress := address + } + } } //Collect dBus.rsp read responses @@ -349,20 +412,21 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, insert(MEMORY_READ_DATA) := dBus.rsp.data - arbitration.haltItself setWhen(arbitration.isValid && input(MEMORY_ENABLE) && !input(INSTRUCTION)(5) && !dBus.rsp.ready) + + arbitration.haltItself setWhen(arbitration.isValid && input(MEMORY_ENABLE) && !input(MEMORY_STORE) && !dBus.rsp.ready) if(catchSomething) { memoryExceptionPort.valid := False memoryExceptionPort.code.assignDontCare() memoryExceptionPort.badAddr := input(REGFILE_WRITE_DATA).asUInt - if(catchAccessFault) when(dBus.rsp.ready && dBus.rsp.error && !input(INSTRUCTION)(5)) { + if(catchAccessFault) when(dBus.rsp.ready && dBus.rsp.error && !input(MEMORY_STORE)) { memoryExceptionPort.valid := True memoryExceptionPort.code := 5 } if(catchAddressMisaligned) when(input(ALIGNEMENT_FAULT)){ - memoryExceptionPort.code := (input(INSTRUCTION)(5) ? U(6) | U(4)).resized + memoryExceptionPort.code := (input(MEMORY_STORE) ? U(6) | U(4)).resized memoryExceptionPort.valid := True } @@ -375,7 +439,7 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, memoryExceptionPort.valid := False } elsewhen(input(MMU_FAULT)) { memoryExceptionPort.valid := True - memoryExceptionPort.code := (input(INSTRUCTION)(5) ? U(15) | U(13)).resized + memoryExceptionPort.code := (input(MEMORY_STORE) ? U(15) | U(13)).resized } arbitration.flushAll setWhen(redoBranch.valid) @@ -414,10 +478,15 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, when(arbitration.isValid && input(MEMORY_ENABLE)) { output(REGFILE_WRITE_DATA) := (if(!onlyLoadWords) rspFormated else input(MEMORY_READ_DATA)) + if(genAtomic){ + when(input(MEMORY_ATOMIC) && input(MEMORY_STORE)){ + output(REGFILE_WRITE_DATA) := (!input(ATOMIC_HIT)).asBits.resized + } + } } if(!earlyInjection && !emitCmdInMemoryStage && config.withWriteBackStage) - assert(!(arbitration.isValid && input(MEMORY_ENABLE) && !input(INSTRUCTION)(5) && arbitration.isStuck),"DBusSimplePlugin doesn't allow writeback stage stall when read happend") + assert(!(arbitration.isValid && input(MEMORY_ENABLE) && !input(MEMORY_STORE) && arbitration.isStuck),"DBusSimplePlugin doesn't allow writeback stage stall when read happend") //formal insert(FORMAL_MEM_RDATA) := input(MEMORY_READ_DATA) diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 3b4953b2..75d5fdad 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -365,7 +365,14 @@ public: }; }; +#define RESERVED_ENTRY_COUNT 1 + struct ReservedEntry{ + bool valid; + uint32_t address; + }; + ReservedEntry reservedEntries[RESERVED_ENTRY_COUNT]; + int reservedEntriesPtr = 0; RiscvGolden() { pc = 0x80000000; @@ -373,6 +380,9 @@ public: for (int i = 0; i < 32; i++) regs[i] = 0; + for(int i = 0;i < RESERVED_ENTRY_COUNT;i++) reservedEntries[i].valid = false; + + status.raw = 0; ie.raw = 0; mtvec.raw = 0x80000020; @@ -412,9 +422,10 @@ public: virtual void dWrite(int32_t address, int32_t size, uint32_t data) = 0; enum AccessKind {READ,WRITE,EXECUTE}; + virtual bool isMmuRegion(uint32_t v) = 0; bool v2p(uint32_t v, uint32_t *p, AccessKind kind){ uint32_t effectivePrivilege = status.mprv && kind != EXECUTE ? status.mpp : privilege; - if(effectivePrivilege == 3 || satp.mode == 0){ + if(effectivePrivilege == 3 || satp.mode == 0 || !isMmuRegion(v)){ *p = v; } else { Tlb tlb; @@ -440,7 +451,7 @@ public: } void trap(bool interrupt,int32_t cause) { - trap(interrupt, cause, true, 0); + trap(interrupt, cause, false, 0); } void trap(bool interrupt,int32_t cause, uint32_t value) { trap(interrupt, cause, true, value); @@ -452,6 +463,7 @@ public: cout << hex << " a7=0x" << regs[17] << " a0=0x" << regs[10] << " a1=0x" << regs[11] << " a2=0x" << regs[12] << dec << endl; } #endif + for(int i = 0;i < RESERVED_ENTRY_COUNT;i++) reservedEntries[i].valid = false; //Check leguality of the interrupt if(interrupt) { bool hit = false; @@ -673,7 +685,7 @@ public: if (pc & 2) { if(v2p(pc - 2, &pAddr, EXECUTE)){ trap(0, 12, pc - 2); return; } if(iRead(pAddr, &i)){ - trap(0, 1); + trap(0, 1, 0); return; } i >>= 16; @@ -681,7 +693,7 @@ public: uint32_t u32Buf; if(v2p(pc + 2, &pAddr, EXECUTE)){ trap(0, 12, pc + 2); return; } if(iRead(pAddr, &u32Buf)){ - trap(0, 1); + trap(0, 1, 0); return; } i |= u32Buf << 16; @@ -689,7 +701,7 @@ public: } else { if(v2p(pc, &pAddr, EXECUTE)){ trap(0, 12, pc); return; } if(iRead(pAddr, &i)){ - trap(0, 1); + trap(0, 1, 0); return; } } @@ -855,6 +867,56 @@ public: } break; } + case 0x2F: // Atomic stuff + switch(i32_func3){ + case 0x2: + switch(iBits(27,5)){ + case 0x2:{ //LR + uint32_t data; + uint32_t address = i32_rs1; + if(address & 3){ + trap(0, 4, address); + } else { + if(v2p(address, &pAddr, READ)){ trap(0, 13, address); return; } + if(dRead(pAddr, 4, &data)){ + trap(0, 5, address); + } else { + reservedEntries[reservedEntriesPtr].valid = true; + reservedEntries[reservedEntriesPtr].address = address; + reservedEntriesPtr = (reservedEntriesPtr + 1) % RESERVED_ENTRY_COUNT; + rfWrite(rd32, data); + pcWrite(pc + 4); + } + } + } break; + case 0x3:{ //SC + uint32_t address = i32_rs1; + if(address & 3){ + trap(0, 6, address); + } else { + if(v2p(address, &pAddr, WRITE)){ trap(0, 15, address); return; } + bool hit = false; + for(int i = 0;i < RESERVED_ENTRY_COUNT;i++) hit |= reservedEntries[i].valid && reservedEntries[i].address == address; + rfWrite(rd32, !hit); + if(hit){ + dWrite(pAddr, 4, i32_rs2); + } + pcWrite(pc + 4); + } + } break; + default: ilegalInstruction(); break; + } + break; + default: ilegalInstruction(); break; + } + break; + case 0x0f: + if(i == 0x100F || (i & 0xF00FFFFF) == 0x000F){ // FENCE FENCE.I + pcWrite(pc + 4); + } else{ + ilegalInstruction(); + } + break; default: ilegalInstruction(); break; } } else { @@ -868,7 +930,7 @@ public: } else { if(v2p(address, &pAddr, READ)){ trap(0, 13, address); return; } if(dRead(address, 4, &data)) { - trap(1, 5, address); + trap(0, 5, address); } else { rfWrite(i16_addr2, data); pcWrite(pc + 2); } @@ -917,7 +979,7 @@ public: } else { if(v2p(address, &pAddr, READ)){ trap(0, 13, address); return; } if(dRead(pAddr, 4, &data)){ - trap(1, 5, address); + trap(0, 5, address); } else { rfWrite(rd32, data); pcWrite(pc + 2); } @@ -1032,6 +1094,9 @@ public: virtual void fail() { ws->fail(); } + + virtual bool isMmuRegion(uint32_t v) {return ws->isMmuRegion(v);} + bool rfWriteValid; int32_t rfWriteAddress; int32_t rfWriteData; @@ -1172,7 +1237,7 @@ public: } virtual bool isPerifRegion(uint32_t addr) { return false; } - + virtual bool isMmuRegion(uint32_t addr) { return true;} virtual void iBusAccess(uint32_t addr, uint32_t *data, bool *error) { if(addr % 4 != 0) { cout << "Warning, unaligned IBusAccess : " << addr << endl; @@ -1186,7 +1251,7 @@ public: } - + virtual bool isDBusCheckedRegion(uint32_t address){ return isPerifRegion(address);} virtual void dBusAccess(uint32_t addr,bool wr, uint32_t size,uint32_t mask, uint32_t *data, bool *error) { assertEq(addr % (1 << size), 0); if(isPerifRegion(addr)){ @@ -1448,7 +1513,7 @@ public: (rfWriteValid && (rfWriteAddress!= riscvRef.rfWriteAddress || rfWriteData!= riscvRef.rfWriteData))){ cout << "regFile write missmatch :" << endl; if(rfWriteValid) cout << " REF: RF[" << riscvRef.rfWriteAddress << "] = 0x" << hex << riscvRef.rfWriteData << dec << endl; - if(rfWriteValid) cout << " RTL: RF[" << rfWriteAddress << "] = 0x" << hex << rfWriteData << dec << endl; + if(rfWriteValid) cout << " DUT: RF[" << rfWriteAddress << "] = 0x" << hex << rfWriteData << dec << endl; fail(); } } @@ -1566,7 +1631,7 @@ public: break; #endif case 0xF00FFF48u: mTimeCmp = (mTimeCmp & 0xFFFFFFFF00000000) | *data;break; - case 0xF00FFF4Cu: mTimeCmp = (mTimeCmp & 0x00000000FFFFFFFF) | (((uint64_t)*data) << 32); /*cout << "mTimeCmp <= " << mTimeCmp << endl; */break; + case 0xF00FFF4Cu: mTimeCmp = (mTimeCmp & 0x00000000FFFFFFFF) | (((uint64_t)*data) << 32); break; } }else{ switch(addr){ @@ -2882,19 +2947,25 @@ public: } - virtual bool isPerifRegion(uint32_t addr) { return (addr & 0xF0000000) == 0xB0000000 || (addr & 0xF0000000) == 0xE0000000;} - + virtual bool isPerifRegion(uint32_t addr) { return (addr & 0xF0000000) == 0xB0000000 || (addr & 0xE0000000) == 0xE0000000;} + virtual bool isMmuRegion(uint32_t addr) { return (addr & 0xFF000000) != 0x81000000;} virtual void dBusAccess(uint32_t addr,bool wr, uint32_t size,uint32_t mask, uint32_t *data, bool *error) { - switch(addr){ + if(isPerifRegion(addr)) switch(addr){ //TODO Emulate peripherals here - case 0xFFFFFFFC: fail(); break; //Simulation end + case 0xFFFFFFE0: if(wr) fail(); else *data = mTime; break; + case 0xFFFFFFE4: if(wr) fail(); else *data = mTime >> 32; break; + case 0xFFFFFFE8: if(wr) mTimeCmp = (mTimeCmp & 0xFFFFFFFF00000000) | *data; else *data = mTimeCmp; break; + case 0xFFFFFFEC: if(wr) mTimeCmp = (mTimeCmp & 0x00000000FFFFFFFF) | (((uint64_t)*data) << 32); else *data = mTimeCmp >> 32; break; case 0xFFFFFFF8: if(wr){ cout << (char)*data; logTraces << (char)*data; - } + logTraces.flush(); + } else fail(); break; + case 0xFFFFFFFC: fail(); break; //Simulation end + default: cout << "Unmapped peripheral access : addr=0x" << hex << addr << " wr=" << wr << " mask=0x" << mask << " data=0x" << data << dec << endl; fail(); break; } Workspace::dBusAccess(addr,wr,size,mask,data,error); @@ -3180,7 +3251,6 @@ int main(int argc, char **argv, char **env) { ->setDStall(false) ->bootAt(0x80000000) ->run(0); - return 1; #endif // #ifdef MMU diff --git a/src/test/cpp/regression/makefile b/src/test/cpp/regression/makefile index 86d5d52e..f5c8d95e 100644 --- a/src/test/cpp/regression/makefile +++ b/src/test/cpp/regression/makefile @@ -1,4 +1,4 @@ -DEBUG?=yes +DEBUG?=no IBUS?=CACHED IBUS_TC?=no From 7a9f7c4fb9f9602c2ea370785d9bea0488bb7e3b Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 26 Mar 2019 16:30:53 +0100 Subject: [PATCH 078/951] Untested cacheless buses to AHB bridges --- .../vexriscv/plugin/DBusSimplePlugin.scala | 28 +++++++++++ .../vexriscv/plugin/IBusSimplePlugin.scala | 26 ++++++++++ src/test/cpp/regression/main.cpp | 49 +++++++++++++++++++ 3 files changed, 103 insertions(+) diff --git a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala index eb4ce468..9ef11217 100644 --- a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala @@ -3,6 +3,7 @@ package vexriscv.plugin import vexriscv._ import spinal.core._ import spinal.lib._ +import spinal.lib.bus.amba3.ahblite.{AhbLite3Config, AhbLite3Master} import spinal.lib.bus.amba4.axi._ import spinal.lib.bus.avalon.{AvalonMM, AvalonMMConfig} import spinal.lib.bus.wishbone.{Wishbone, WishboneConfig} @@ -63,6 +64,11 @@ object DBusSimpleBus{ useBTE = true, useCTI = true ) + + def getAhbLite3Config() = AhbLite3Config( + addressWidth = 32, + dataWidth = 32 + ) } case class DBusSimpleBus() extends Bundle with IMasterSlave{ @@ -195,6 +201,28 @@ case class DBusSimpleBus() extends Bundle with IMasterSlave{ bus } + + + + def toAhbLite3Master(): AhbLite3Master = { + val bus = AhbLite3Master(DBusSimpleBus.getAhbLite3Config()) + bus.HADDR := this.cmd.address + bus.HWRITE := this.cmd.wr + bus.HSIZE := B(this.cmd.size, 3 bits) + bus.HBURST := 0 + bus.HPROT := "1111" + bus.HTRANS := B"0" ## this.cmd.valid + bus.HMASTLOCK := False + bus.HWDATA := RegNextWhen(this.cmd.data, bus.HREADY) + this.cmd.ready := bus.HREADY + + val pending = RegInit(False) clearWhen(bus.HREADY) setWhen(this.cmd.fire && !this.cmd.wr) + this.rsp.ready := bus.HREADY + this.rsp.data := bus.HRDATA + this.rsp.error := bus.HRESP + bus + } + } diff --git a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala index 636b1930..a3f6a5b5 100644 --- a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala @@ -3,6 +3,7 @@ package vexriscv.plugin import vexriscv._ import spinal.core._ import spinal.lib._ +import spinal.lib.bus.amba3.ahblite.{AhbLite3, AhbLite3Config, AhbLite3Master} import spinal.lib.bus.amba4.axi._ import spinal.lib.bus.avalon.{AvalonMM, AvalonMMConfig} import spinal.lib.bus.wishbone.{Wishbone, WishboneConfig} @@ -59,6 +60,11 @@ object IBusSimpleBus{ useBTE = true, useCTI = true ) + + def getAhbLite3Config() = AhbLite3Config( + addressWidth = 32, + dataWidth = 32 + ) } @@ -147,6 +153,26 @@ case class IBusSimpleBus(interfaceKeepData : Boolean = false) extends Bundle wit rsp.error := False bus } + + //cmdForkPersistence need to bet set + def toAhbLite3Master(): AhbLite3Master = { + val bus = AhbLite3Master(IBusSimpleBus.getAhbLite3Config()) + bus.HADDR := this.cmd.pc + bus.HWRITE := False + bus.HSIZE := 2 + bus.HBURST := 0 + bus.HPROT := "1110" + bus.HTRANS := B"0" ## this.cmd.valid + bus.HMASTLOCK := False + bus.HWDATA.assignDontCare() + this.cmd.ready := bus.HREADY + + val pending = RegInit(False) clearWhen(bus.HREADY) setWhen(this.cmd.fire) + this.rsp.valid := pending && bus.HREADY + this.rsp.inst := bus.HRDATA + this.rsp.error := bus.HRESP + bus + } } diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index a5c1b0d6..1c741618 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -1279,6 +1279,50 @@ public: #endif + +#ifdef IBUS_SIMPLE_AHBLITE3 +class IBusSimpleAhbLite3 : public SimElement{ +public: + Workspace *ws; + VVexRiscv* top; + + uint32_t iBusAhbLite3_HRDATA; + bool iBusAhbLite3_HRESP, iBusAhbLite3_HREADY; + + IBusSimpleAhbLite3(Workspace* ws){ + this->ws = ws; + this->top = ws->top; + } + + virtual void onReset(){ + top->iBusAhbLite3_HREADY = 1; + top->iBusAhbLite3_HRESP = 0; + } + + virtual void preCycle(){ + if (top->iBusAhbLite3_HTRANS == 2 && top->iBusAhbLite3_HREADY && !top->iBusAhbLite3_HWRITE) { + ws->iBusAccess(top->iBusAhbLite3_HADDR,&iBusAhbLite3_HRDATA,&iBusAhbLite3_HRESP); + } + } + + virtual void postCycle(){ + if(top->iBusAhbLite3_HREADY && (!ws->iStall || VL_RANDOM_I(7) < 100)){ + IBusSimpleAvalonRsp rsp = rsps.front(); rsps.pop(); + top->iBusAhbLite3_HRDATA = iBusAhbLite3_HRDATA; + top->iBusAhbLite3_HREADY = iBusAhbLite3_HREADY; + top->iBusAhbLite3_HRESP = iBusAhbLite3_HRESP; + } else { + top->iBusAhbLite3_HRESP = 0; + top->iBusAhbLite3_HRDATA = VL_RANDOM_I(32); + top->iBusAhbLite3_HRESP = VL_RANDOM_I(1); + } + if(ws->iStall) + top->iBusAhbLite3_HREADY = VL_RANDOM_I(7) < 100; + } +}; +#endif + + #ifdef IBUS_CACHED class IBusCached : public SimElement{ public: @@ -1994,6 +2038,11 @@ void Workspace::fillSimELements(){ #ifdef IBUS_SIMPLE_AVALON simElements.push_back(new IBusSimpleAvalon(this)); #endif + #ifdef IBUS_SIMPLE_AHBLITE3 + simElements.push_back(new IBusSimpleAhbLite3(this)); + #endif + + #ifdef IBUS_CACHED simElements.push_back(new IBusCached(this)); #endif From b69c474fa266fe4c48de2cf30acad69430b47c0d Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 27 Mar 2019 00:26:51 +0100 Subject: [PATCH 079/951] #60 user space reached /sbin/init: error while loading shared libraries: libm.so.6: cannot stat shared object: Error 38 --- .gitignore | 1 + src/main/c/emulator/build/emulator.asm | 910 +++++++++-------------- src/main/c/emulator/build/emulator.hex | 179 ++--- src/main/c/emulator/makefile | 2 +- src/main/c/emulator/src/main.c | 6 +- src/main/c/emulator/src/riscv.h | 1 + src/main/scala/vexriscv/demo/Linux.scala | 4 +- src/test/cpp/regression/main.cpp | 70 +- 8 files changed, 485 insertions(+), 688 deletions(-) diff --git a/.gitignore b/.gitignore index c926769c..c054ba5d 100644 --- a/.gitignore +++ b/.gitignore @@ -40,6 +40,7 @@ obj_dir *.yaml *.memTrace *.regTrace +*.debugTrace *.tcl *.o *.bin diff --git a/src/main/c/emulator/build/emulator.asm b/src/main/c/emulator/build/emulator.asm index e1e89d06..aba0bdf4 100644 --- a/src/main/c/emulator/build/emulator.asm +++ b/src/main/c/emulator/build/emulator.asm @@ -5,352 +5,187 @@ build/emulator.elf: file format elf32-littleriscv Disassembly of section .init: 80000000 <_start>: -.option push -.option norelax - la gp, __global_pointer$ -.option pop -#endif*/ - la sp, _sp 80000000: 00001117 auipc sp,0x1 -80000004: f3810113 addi sp,sp,-200 # 80000f38 <_sp> - - - /* Load data section */ - la a0, _data_lma +80000004: 00010113 mv sp,sp 80000008: 00000517 auipc a0,0x0 -8000000c: 6b850513 addi a0,a0,1720 # 800006c0 <__init_array_end> - la a1, _data +8000000c: 78450513 addi a0,a0,1924 # 8000078c <__init_array_end> 80000010: 00000597 auipc a1,0x0 -80000014: 6b058593 addi a1,a1,1712 # 800006c0 <__init_array_end> - la a2, _edata +80000014: 77c58593 addi a1,a1,1916 # 8000078c <__init_array_end> 80000018: 00000617 auipc a2,0x0 -8000001c: 72060613 addi a2,a2,1824 # 80000738 <__bss_start> - bgeu a1, a2, 2f +8000001c: 7e860613 addi a2,a2,2024 # 80000800 <__bss_start> 80000020: 00c5fc63 bleu a2,a1,80000038 <_start+0x38> -1: - lw t0, (a0) 80000024: 00052283 lw t0,0(a0) - sw t0, (a1) 80000028: 0055a023 sw t0,0(a1) - addi a0, a0, 4 8000002c: 00450513 addi a0,a0,4 - addi a1, a1, 4 80000030: 00458593 addi a1,a1,4 - bltu a1, a2, 1b 80000034: fec5e8e3 bltu a1,a2,80000024 <_start+0x24> -2: - - /* Clear bss section */ - la a0, __bss_start 80000038: 00000517 auipc a0,0x0 -8000003c: 70050513 addi a0,a0,1792 # 80000738 <__bss_start> - la a1, _end +8000003c: 7c850513 addi a0,a0,1992 # 80000800 <__bss_start> 80000040: 00000597 auipc a1,0x0 -80000044: 6f858593 addi a1,a1,1784 # 80000738 <__bss_start> - bgeu a0, a1, 2f +80000044: 7c058593 addi a1,a1,1984 # 80000800 <__bss_start> 80000048: 00b57863 bleu a1,a0,80000058 <_start+0x58> -1: - sw zero, (a0) 8000004c: 00052023 sw zero,0(a0) - addi a0, a0, 4 80000050: 00450513 addi a0,a0,4 - bltu a0, a1, 1b 80000054: feb56ce3 bltu a0,a1,8000004c <_start+0x4c> -2: - - call __libc_init_array -80000058: 5d0000ef jal ra,80000628 <__libc_init_array> - call init +80000058: 69c000ef jal ra,800006f4 <__libc_init_array> 8000005c: 128000ef jal ra,80000184 - la ra, done 80000060: 00000097 auipc ra,0x0 80000064: 01408093 addi ra,ra,20 # 80000074 - li a0, 0 80000068: 00000513 li a0,0 - li a1, DTB 8000006c: 810005b7 lui a1,0x81000 - mret 80000070: 30200073 mret 80000074 : -done: - j done 80000074: 0000006f j 80000074 80000078 <_init>: - - - .globl _init -_init: - ret 80000078: 00008067 ret 8000007c : - .section .init - .globl trapEntry - .type trapEntry,@function - -trapEntry: - csrrw sp, mscratch, sp 8000007c: 34011173 csrrw sp,mscratch,sp - sw x0, 0*4(sp) -80000080: 00012023 sw zero,0(sp) - sw x1, 1*4(sp) +80000080: 00012023 sw zero,0(sp) # 80001000 <_sp> 80000084: 00112223 sw ra,4(sp) - sw x3, 3*4(sp) 80000088: 00312623 sw gp,12(sp) - sw x4, 4*4(sp) 8000008c: 00412823 sw tp,16(sp) - sw x5, 5*4(sp) 80000090: 00512a23 sw t0,20(sp) - sw x6, 6*4(sp) 80000094: 00612c23 sw t1,24(sp) - sw x7, 7*4(sp) 80000098: 00712e23 sw t2,28(sp) - sw x8, 8*4(sp) 8000009c: 02812023 sw s0,32(sp) - sw x9, 9*4(sp) 800000a0: 02912223 sw s1,36(sp) - sw x10, 10*4(sp) 800000a4: 02a12423 sw a0,40(sp) - sw x11, 11*4(sp) 800000a8: 02b12623 sw a1,44(sp) - sw x12, 12*4(sp) 800000ac: 02c12823 sw a2,48(sp) - sw x13, 13*4(sp) 800000b0: 02d12a23 sw a3,52(sp) - sw x14, 14*4(sp) 800000b4: 02e12c23 sw a4,56(sp) - sw x15, 15*4(sp) 800000b8: 02f12e23 sw a5,60(sp) - sw x16, 16*4(sp) 800000bc: 05012023 sw a6,64(sp) - sw x17, 17*4(sp) 800000c0: 05112223 sw a7,68(sp) - sw x18, 18*4(sp) 800000c4: 05212423 sw s2,72(sp) - sw x19, 19*4(sp) 800000c8: 05312623 sw s3,76(sp) - sw x20, 20*4(sp) 800000cc: 05412823 sw s4,80(sp) - sw x21, 21*4(sp) 800000d0: 05512a23 sw s5,84(sp) - sw x22, 22*4(sp) 800000d4: 05612c23 sw s6,88(sp) - sw x23, 23*4(sp) 800000d8: 05712e23 sw s7,92(sp) - sw x24, 24*4(sp) 800000dc: 07812023 sw s8,96(sp) - sw x25, 25*4(sp) 800000e0: 07912223 sw s9,100(sp) - sw x26, 26*4(sp) 800000e4: 07a12423 sw s10,104(sp) - sw x27, 27*4(sp) 800000e8: 07b12623 sw s11,108(sp) - sw x28, 28*4(sp) 800000ec: 07c12823 sw t3,112(sp) - sw x29, 29*4(sp) 800000f0: 07d12a23 sw t4,116(sp) - sw x30, 30*4(sp) 800000f4: 07e12c23 sw t5,120(sp) - sw x31, 31*4(sp) 800000f8: 07f12e23 sw t6,124(sp) - call trap 800000fc: 1ec000ef jal ra,800002e8 - lw x0, 0*4(sp) 80000100: 00012003 lw zero,0(sp) - lw x1, 1*4(sp) 80000104: 00412083 lw ra,4(sp) - lw x3, 3*4(sp) 80000108: 00c12183 lw gp,12(sp) - lw x4, 4*4(sp) 8000010c: 01012203 lw tp,16(sp) - lw x5, 5*4(sp) 80000110: 01412283 lw t0,20(sp) - lw x6, 6*4(sp) 80000114: 01812303 lw t1,24(sp) - lw x7, 7*4(sp) 80000118: 01c12383 lw t2,28(sp) - lw x8, 8*4(sp) 8000011c: 02012403 lw s0,32(sp) - lw x9, 9*4(sp) 80000120: 02412483 lw s1,36(sp) - lw x10, 10*4(sp) 80000124: 02812503 lw a0,40(sp) - lw x11, 11*4(sp) 80000128: 02c12583 lw a1,44(sp) - lw x12, 12*4(sp) 8000012c: 03012603 lw a2,48(sp) - lw x13, 13*4(sp) 80000130: 03412683 lw a3,52(sp) - lw x14, 14*4(sp) 80000134: 03812703 lw a4,56(sp) - lw x15, 15*4(sp) 80000138: 03c12783 lw a5,60(sp) - lw x16, 16*4(sp) 8000013c: 04012803 lw a6,64(sp) - lw x17, 17*4(sp) 80000140: 04412883 lw a7,68(sp) - lw x18, 18*4(sp) 80000144: 04812903 lw s2,72(sp) - lw x19, 19*4(sp) 80000148: 04c12983 lw s3,76(sp) - lw x20, 20*4(sp) 8000014c: 05012a03 lw s4,80(sp) - lw x21, 21*4(sp) 80000150: 05412a83 lw s5,84(sp) - lw x22, 22*4(sp) 80000154: 05812b03 lw s6,88(sp) - lw x23, 23*4(sp) 80000158: 05c12b83 lw s7,92(sp) - lw x24, 24*4(sp) 8000015c: 06012c03 lw s8,96(sp) - lw x25, 25*4(sp) 80000160: 06412c83 lw s9,100(sp) - lw x26, 26*4(sp) 80000164: 06812d03 lw s10,104(sp) - lw x27, 27*4(sp) 80000168: 06c12d83 lw s11,108(sp) - lw x28, 28*4(sp) 8000016c: 07012e03 lw t3,112(sp) - lw x29, 29*4(sp) 80000170: 07412e83 lw t4,116(sp) - lw x30, 30*4(sp) 80000174: 07812f03 lw t5,120(sp) - lw x31, 31*4(sp) 80000178: 07c12f83 lw t6,124(sp) - csrrw sp, mscratch, sp 8000017c: 34011173 csrrw sp,mscratch,sp - mret 80000180: 30200073 mret Disassembly of section .text: 80000184 : -extern void trapEntry(); -extern void emulationTrap(); - -void init() { - uint32_t sp = (uint32_t) (&_sp); - csr_write(mtvec, trapEntry); 80000184: 800007b7 lui a5,0x80000 -80000188: 07c78793 addi a5,a5,124 # 8000007c <_sp+0xfffff144> +80000188: 07c78793 addi a5,a5,124 # 8000007c <_sp+0xfffff07c> 8000018c: 30579073 csrw mtvec,a5 - csr_write(mscratch, sp -32*4); 80000190: 800017b7 lui a5,0x80001 -80000194: f3878793 addi a5,a5,-200 # 80000f38 <_sp+0x0> -80000198: f8078793 addi a5,a5,-128 -8000019c: 34079073 csrw mscratch,a5 - csr_write(mstatus, 0x0800 | MSTATUS_MPIE); -800001a0: 000017b7 lui a5,0x1 -800001a4: 88078793 addi a5,a5,-1920 # 880 <__stack_size+0x80> -800001a8: 30079073 csrw mstatus,a5 - csr_write(mie, 0); -800001ac: 30405073 csrwi mie,0 - csr_write(mepc, OS_CALL); -800001b0: c00007b7 lui a5,0xc0000 -800001b4: 34179073 csrw mepc,a5 - csr_write(medeleg, MEDELEG_INSTRUCTION_PAGE_FAULT | MEDELEG_LOAD_PAGE_FAULT | MEDELEG_STORE_PAGE_FAULT); -800001b8: 0000b7b7 lui a5,0xb +80000194: f8078793 addi a5,a5,-128 # 80000f80 <_sp+0xffffff80> +80000198: 34079073 csrw mscratch,a5 +8000019c: 000017b7 lui a5,0x1 +800001a0: 88078793 addi a5,a5,-1920 # 880 <__stack_size+0x80> +800001a4: 30079073 csrw mstatus,a5 +800001a8: 30405073 csrwi mie,0 +800001ac: c00007b7 lui a5,0xc0000 +800001b0: 34179073 csrw mepc,a5 +800001b4: 0000b7b7 lui a5,0xb +800001b8: 10078793 addi a5,a5,256 # b100 <__stack_size+0xa900> 800001bc: 30279073 csrw medeleg,a5 - csr_write(mideleg, MIDELEG_SUPERVISOR_TIMER); 800001c0: 02000793 li a5,32 800001c4: 30379073 csrw mideleg,a5 - csr_write(sbadaddr, 0); //Used to avoid simulation missmatch 800001c8: 14305073 csrwi sbadaddr,0 -} 800001cc: 00008067 ret 800001d0 : - -int readRegister(uint32_t id){ - unsigned int sp = (unsigned int) (&_sp); - return ((int*) sp)[id-32]; -800001d0: 00251513 slli a0,a0,0x2 -800001d4: 800017b7 lui a5,0x80001 -800001d8: f3878793 addi a5,a5,-200 # 80000f38 <_sp+0x0> +800001d0: 800017b7 lui a5,0x80001 +800001d4: f8078793 addi a5,a5,-128 # 80000f80 <_sp+0xffffff80> +800001d8: 00251513 slli a0,a0,0x2 800001dc: 00f50533 add a0,a0,a5 -} -800001e0: f8052503 lw a0,-128(a0) +800001e0: 00052503 lw a0,0(a0) 800001e4: 00008067 ret 800001e8 : -void writeRegister(uint32_t id, int value){ - uint32_t sp = (uint32_t) (&_sp); - ((uint32_t*) sp)[id-32] = value; -800001e8: 00251513 slli a0,a0,0x2 -800001ec: 800017b7 lui a5,0x80001 -800001f0: f3878793 addi a5,a5,-200 # 80000f38 <_sp+0x0> +800001e8: 800017b7 lui a5,0x80001 +800001ec: 00251513 slli a0,a0,0x2 +800001f0: f8078793 addi a5,a5,-128 # 80000f80 <_sp+0xffffff80> 800001f4: 00f50533 add a0,a0,a5 -800001f8: f8b52023 sw a1,-128(a0) -} +800001f8: 00b52023 sw a1,0(a0) 800001fc: 00008067 ret 80000200 : - - - -void redirectTrap(){ 80000200: ff010113 addi sp,sp,-16 80000204: 00112623 sw ra,12(sp) - stopSim(); -80000208: 3e8000ef jal ra,800005f0 - csr_write(sbadaddr, csr_read(mbadaddr)); +80000208: 4b4000ef jal ra,800006bc 8000020c: 343027f3 csrr a5,mbadaddr 80000210: 14379073 csrw sbadaddr,a5 - csr_write(sepc, csr_read(mepc)); 80000214: 341027f3 csrr a5,mepc 80000218: 14179073 csrw sepc,a5 - csr_write(scause, csr_read(mcause)); 8000021c: 342027f3 csrr a5,mcause 80000220: 14279073 csrw scause,a5 - csr_write(mepc, csr_read(stvec)); 80000224: 105027f3 csrr a5,stvec 80000228: 34179073 csrw mepc,a5 -} 8000022c: 00c12083 lw ra,12(sp) 80000230: 01010113 addi sp,sp,16 80000234: 00008067 ret 80000238 : - -void emulationTrapToSupervisorTrap(uint32_t sepc, uint32_t mstatus){ - csr_write(sbadaddr, csr_read(mbadaddr)); 80000238: 343027f3 csrr a5,mbadaddr 8000023c: 14379073 csrw sbadaddr,a5 - csr_write(scause, csr_read(mcause)); 80000240: 342027f3 csrr a5,mcause 80000244: 14279073 csrw scause,a5 - csr_write(sepc, sepc); 80000248: 14151073 csrw sepc,a0 - csr_write(mepc, csr_read(stvec)); 8000024c: 105027f3 csrr a5,stvec 80000250: 34179073 csrw mepc,a5 - csr_clear(sstatus, MSTATUS_SPP); 80000254: 10000793 li a5,256 80000258: 1007b073 csrc sstatus,a5 - csr_set(sstatus, (mstatus >> 3) & MSTATUS_SPP); 8000025c: 0035d593 srli a1,a1,0x3 80000260: 1005f593 andi a1,a1,256 80000264: 1005a073 csrs sstatus,a1 - csr_clear(mstatus, MSTATUS_MPP); 80000268: 000027b7 lui a5,0x2 8000026c: 80078793 addi a5,a5,-2048 # 1800 <__stack_size+0x1000> 80000270: 3007b073 csrc mstatus,a5 - csr_set(mstatus, 0x8000 | MSTATUS_MPIE); 80000274: 000087b7 lui a5,0x8 80000278: 08078793 addi a5,a5,128 # 8080 <__stack_size+0x7880> 8000027c: 3007a073 csrs mstatus,a5 -} 80000280: 00008067 ret 80000284 : - -//Will modify MEPC -int32_t readWord(uint32_t address, int32_t *data){ - int32_t result, tmp; - int32_t failed; - __asm__ __volatile__ ( 80000284: 00020737 lui a4,0x20 80000288: 30072073 csrs mstatus,a4 8000028c: 00000717 auipc a4,0x0 @@ -362,24 +197,10 @@ int32_t readWord(uint32_t address, int32_t *data){ 800002a4: 00020737 lui a4,0x20 800002a8: 30073073 csrc mstatus,a4 800002ac: 00068513 mv a0,a3 - : [result]"=&r" (result), [failed]"=&r" (failed), [tmp]"=&r" (tmp) - : [address]"r" (address) - : "memory" - ); - - *data = result; -800002b0: 00f5a023 sw a5,0(a1) # 81000000 <_sp+0xfff0c8> - return failed; -} +800002b0: 00f5a023 sw a5,0(a1) # 81000000 <_sp+0xfff000> 800002b4: 00008067 ret 800002b8 : - -//Will modify MEPC -int32_t writeWord(uint32_t address, int32_t data){ - int32_t result, tmp; - int32_t failed; - __asm__ __volatile__ ( 800002b8: 00020737 lui a4,0x20 800002bc: 30072073 csrs mstatus,a4 800002c0: 00000717 auipc a4,0x0 @@ -391,382 +212,315 @@ int32_t writeWord(uint32_t address, int32_t data){ 800002d8: 00020737 lui a4,0x20 800002dc: 30073073 csrc mstatus,a4 800002e0: 00078513 mv a0,a5 - : [address]"r" (address), [data]"r" (data) - : "memory" - ); - - return failed; -} 800002e4: 00008067 ret 800002e8 : +800002e8: fe010113 addi sp,sp,-32 +800002ec: 00112e23 sw ra,28(sp) +800002f0: 00812c23 sw s0,24(sp) +800002f4: 00912a23 sw s1,20(sp) +800002f8: 01212823 sw s2,16(sp) +800002fc: 01312623 sw s3,12(sp) +80000300: 342027f3 csrr a5,mcause +80000304: 1407ce63 bltz a5,80000460 +80000308: 00200713 li a4,2 +8000030c: 04e78463 beq a5,a4,80000354 +80000310: 00900693 li a3,9 +80000314: 10d79663 bne a5,a3,80000420 +80000318: 800017b7 lui a5,0x80001 +8000031c: 00078793 mv a5,a5 +80000320: fc47a683 lw a3,-60(a5) # 80000fc4 <_sp+0xffffffc4> +80000324: 00100613 li a2,1 +80000328: fa87a503 lw a0,-88(a5) +8000032c: 1ec68663 beq a3,a2,80000518 +80000330: 22e68463 beq a3,a4,80000558 +80000334: 1e068e63 beqz a3,80000530 +80000338: 01812403 lw s0,24(sp) +8000033c: 01c12083 lw ra,28(sp) +80000340: 01412483 lw s1,20(sp) +80000344: 01012903 lw s2,16(sp) +80000348: 00c12983 lw s3,12(sp) +8000034c: 02010113 addi sp,sp,32 +80000350: 36c0006f j 800006bc +80000354: 341024f3 csrr s1,mepc +80000358: 300025f3 csrr a1,mstatus +8000035c: 34302473 csrr s0,mbadaddr +80000360: 02f00613 li a2,47 +80000364: 07f47693 andi a3,s0,127 +80000368: 00c45713 srli a4,s0,0xc +8000036c: 12c68663 beq a3,a2,80000498 +80000370: 07300613 li a2,115 +80000374: 0ac69663 bne a3,a2,80000420 +80000378: 00377713 andi a4,a4,3 +8000037c: 24f70063 beq a4,a5,800005bc +80000380: 00300793 li a5,3 +80000384: 22f70c63 beq a4,a5,800005bc +80000388: 00100993 li s3,1 +8000038c: 03370463 beq a4,s3,800003b4 +80000390: 32c000ef jal ra,800006bc +80000394: 343027f3 csrr a5,mbadaddr +80000398: 14379073 csrw sbadaddr,a5 +8000039c: 341027f3 csrr a5,mepc +800003a0: 14179073 csrw sepc,a5 +800003a4: 342027f3 csrr a5,mcause +800003a8: 14279073 csrw scause,a5 +800003ac: 105027f3 csrr a5,stvec +800003b0: 34179073 csrw mepc,a5 +800003b4: 000017b7 lui a5,0x1 +800003b8: 01445713 srli a4,s0,0x14 +800003bc: c0178693 addi a3,a5,-1023 # c01 <__stack_size+0x401> +800003c0: 2ed70863 beq a4,a3,800006b0 +800003c4: c8178793 addi a5,a5,-895 +800003c8: 2cf71063 bne a4,a5,80000688 +800003cc: 308000ef jal ra,800006d4 +800003d0: 00050913 mv s2,a0 +800003d4: 02098463 beqz s3,800003fc +800003d8: 2e4000ef jal ra,800006bc +800003dc: 343027f3 csrr a5,mbadaddr +800003e0: 14379073 csrw sbadaddr,a5 +800003e4: 341027f3 csrr a5,mepc +800003e8: 14179073 csrw sepc,a5 +800003ec: 342027f3 csrr a5,mcause +800003f0: 14279073 csrw scause,a5 +800003f4: 105027f3 csrr a5,stvec +800003f8: 34179073 csrw mepc,a5 +800003fc: 00545413 srli s0,s0,0x5 +80000400: 800017b7 lui a5,0x80001 +80000404: 07c47413 andi s0,s0,124 +80000408: f8078793 addi a5,a5,-128 # 80000f80 <_sp+0xffffff80> +8000040c: 00f40433 add s0,s0,a5 +80000410: 01242023 sw s2,0(s0) +80000414: 00448493 addi s1,s1,4 +80000418: 34149073 csrw mepc,s1 +8000041c: 0280006f j 80000444 +80000420: 29c000ef jal ra,800006bc +80000424: 343027f3 csrr a5,mbadaddr +80000428: 14379073 csrw sbadaddr,a5 +8000042c: 341027f3 csrr a5,mepc +80000430: 14179073 csrw sepc,a5 +80000434: 342027f3 csrr a5,mcause +80000438: 14279073 csrw scause,a5 +8000043c: 105027f3 csrr a5,stvec +80000440: 34179073 csrw mepc,a5 +80000444: 01c12083 lw ra,28(sp) +80000448: 01812403 lw s0,24(sp) +8000044c: 01412483 lw s1,20(sp) +80000450: 01012903 lw s2,16(sp) +80000454: 00c12983 lw s3,12(sp) +80000458: 02010113 addi sp,sp,32 +8000045c: 00008067 ret +80000460: 0ff7f793 andi a5,a5,255 +80000464: 00700713 li a4,7 +80000468: fae79ce3 bne a5,a4,80000420 +8000046c: 02000793 li a5,32 +80000470: 1447a073 csrs sip,a5 +80000474: 08000793 li a5,128 +80000478: 3047b073 csrc mie,a5 +8000047c: 01c12083 lw ra,28(sp) +80000480: 01812403 lw s0,24(sp) +80000484: 01412483 lw s1,20(sp) +80000488: 01012903 lw s2,16(sp) +8000048c: 00c12983 lw s3,12(sp) +80000490: 02010113 addi sp,sp,32 +80000494: 00008067 ret +80000498: 00777713 andi a4,a4,7 +8000049c: f8f712e3 bne a4,a5,80000420 +800004a0: 00d45713 srli a4,s0,0xd +800004a4: 01245793 srli a5,s0,0x12 +800004a8: 800016b7 lui a3,0x80001 +800004ac: f8068693 addi a3,a3,-128 # 80000f80 <_sp+0xffffff80> +800004b0: 07c77713 andi a4,a4,124 +800004b4: 07c7f793 andi a5,a5,124 +800004b8: 00d70733 add a4,a4,a3 +800004bc: 00d787b3 add a5,a5,a3 +800004c0: 00072703 lw a4,0(a4) # 20000 <__stack_size+0x1f800> +800004c4: 0007a603 lw a2,0(a5) +800004c8: 00020537 lui a0,0x20 +800004cc: 30052073 csrs mstatus,a0 +800004d0: 00000517 auipc a0,0x0 +800004d4: 01850513 addi a0,a0,24 # 800004e8 +800004d8: 34151073 csrw mepc,a0 +800004dc: 00100793 li a5,1 +800004e0: 00072803 lw a6,0(a4) +800004e4: 00000793 li a5,0 +800004e8: 00020537 lui a0,0x20 +800004ec: 30053073 csrc mstatus,a0 +800004f0: 08079063 bnez a5,80000570 +800004f4: 01b45793 srli a5,s0,0x1b +800004f8: 01c00513 li a0,28 +800004fc: f2f562e3 bltu a0,a5,80000420 +80000500: 80000537 lui a0,0x80000 +80000504: 00279793 slli a5,a5,0x2 +80000508: 78c50513 addi a0,a0,1932 # 8000078c <_sp+0xfffff78c> +8000050c: 00a787b3 add a5,a5,a0 +80000510: 0007a783 lw a5,0(a5) +80000514: 00078067 jr a5 +80000518: 0ff57513 andi a0,a0,255 +8000051c: 1a8000ef jal ra,800006c4 +80000520: 341027f3 csrr a5,mepc +80000524: 00478793 addi a5,a5,4 +80000528: 34179073 csrw mepc,a5 +8000052c: f19ff06f j 80000444 +80000530: fac7a583 lw a1,-84(a5) +80000534: 1a8000ef jal ra,800006dc +80000538: 08000793 li a5,128 +8000053c: 3047a073 csrs mie,a5 +80000540: 02000793 li a5,32 +80000544: 1447b073 csrc sip,a5 +80000548: 341027f3 csrr a5,mepc +8000054c: 00478793 addi a5,a5,4 +80000550: 34179073 csrw mepc,a5 +80000554: ef1ff06f j 80000444 +80000558: fff00713 li a4,-1 +8000055c: fae7a423 sw a4,-88(a5) +80000560: 341027f3 csrr a5,mepc +80000564: 00478793 addi a5,a5,4 +80000568: 34179073 csrw mepc,a5 +8000056c: ed9ff06f j 80000444 +80000570: 343027f3 csrr a5,mbadaddr +80000574: 14379073 csrw sbadaddr,a5 +80000578: 342027f3 csrr a5,mcause +8000057c: 14279073 csrw scause,a5 +80000580: 14149073 csrw sepc,s1 +80000584: 105027f3 csrr a5,stvec +80000588: 34179073 csrw mepc,a5 +8000058c: 10000793 li a5,256 +80000590: 1007b073 csrc sstatus,a5 +80000594: 0035d593 srli a1,a1,0x3 +80000598: 1005f593 andi a1,a1,256 +8000059c: 1005a073 csrs sstatus,a1 +800005a0: 000027b7 lui a5,0x2 +800005a4: 80078793 addi a5,a5,-2048 # 1800 <__stack_size+0x1000> +800005a8: 3007b073 csrc mstatus,a5 +800005ac: 000087b7 lui a5,0x8 +800005b0: 08078793 addi a5,a5,128 # 8080 <__stack_size+0x7880> +800005b4: 3007a073 csrs mstatus,a5 +800005b8: e8dff06f j 80000444 +800005bc: 00f45993 srli s3,s0,0xf +800005c0: 01f9f993 andi s3,s3,31 +800005c4: 013039b3 snez s3,s3 +800005c8: dedff06f j 800003b4 +800005cc: 01060633 add a2,a2,a6 +800005d0: 00545413 srli s0,s0,0x5 +800005d4: 07c47413 andi s0,s0,124 +800005d8: 00d406b3 add a3,s0,a3 +800005dc: 0106a023 sw a6,0(a3) +800005e0: 000206b7 lui a3,0x20 +800005e4: 3006a073 csrs mstatus,a3 +800005e8: 00000697 auipc a3,0x0 +800005ec: 01868693 addi a3,a3,24 # 80000600 +800005f0: 34169073 csrw mepc,a3 +800005f4: 00100793 li a5,1 +800005f8: 00c72023 sw a2,0(a4) +800005fc: 00000793 li a5,0 +80000600: 000206b7 lui a3,0x20 +80000604: 3006b073 csrc mstatus,a3 +80000608: e00786e3 beqz a5,80000414 +8000060c: 343027f3 csrr a5,mbadaddr +80000610: 14379073 csrw sbadaddr,a5 +80000614: 342027f3 csrr a5,mcause +80000618: 14279073 csrw scause,a5 +8000061c: 14149073 csrw sepc,s1 +80000620: 105027f3 csrr a5,stvec +80000624: 34179073 csrw mepc,a5 +80000628: 10000793 li a5,256 +8000062c: 1007b073 csrc sstatus,a5 +80000630: 0035d793 srli a5,a1,0x3 +80000634: 1007f793 andi a5,a5,256 +80000638: 1007a073 csrs sstatus,a5 +8000063c: f65ff06f j 800005a0 +80000640: f90678e3 bleu a6,a2,800005d0 +80000644: 00080613 mv a2,a6 +80000648: f89ff06f j 800005d0 +8000064c: 01066633 or a2,a2,a6 +80000650: f81ff06f j 800005d0 +80000654: 01064633 xor a2,a2,a6 +80000658: f79ff06f j 800005d0 +8000065c: f6c87ae3 bleu a2,a6,800005d0 +80000660: 00080613 mv a2,a6 +80000664: f6dff06f j 800005d0 +80000668: f70654e3 ble a6,a2,800005d0 +8000066c: 00080613 mv a2,a6 +80000670: f61ff06f j 800005d0 +80000674: f4c85ee3 ble a2,a6,800005d0 +80000678: 00080613 mv a2,a6 +8000067c: f55ff06f j 800005d0 +80000680: 01067633 and a2,a2,a6 +80000684: f4dff06f j 800005d0 +80000688: 034000ef jal ra,800006bc +8000068c: 343027f3 csrr a5,mbadaddr +80000690: 14379073 csrw sbadaddr,a5 +80000694: 341027f3 csrr a5,mepc +80000698: 14179073 csrw sepc,a5 +8000069c: 342027f3 csrr a5,mcause +800006a0: 14279073 csrw scause,a5 +800006a4: 105027f3 csrr a5,stvec +800006a8: 34179073 csrw mepc,a5 +800006ac: d29ff06f j 800003d4 +800006b0: 01c000ef jal ra,800006cc +800006b4: 00050913 mv s2,a0 +800006b8: d1dff06f j 800003d4 +800006bc : +800006bc: fe002e23 sw zero,-4(zero) # fffffffc <_sp+0x7fffeffc> +800006c0: 00008067 ret +800006c4 : +800006c4: fea02c23 sw a0,-8(zero) # fffffff8 <_sp+0x7fffeff8> +800006c8: 00008067 ret +800006cc : +800006cc: fe002503 lw a0,-32(zero) # ffffffe0 <_sp+0x7fffefe0> +800006d0: 00008067 ret -void trap(){ -800002e8: fd010113 addi sp,sp,-48 -800002ec: 02112623 sw ra,44(sp) -800002f0: 02812423 sw s0,40(sp) -800002f4: 02912223 sw s1,36(sp) -800002f8: 03212023 sw s2,32(sp) -800002fc: 01312e23 sw s3,28(sp) -80000300: 01412c23 sw s4,24(sp) -80000304: 01512a23 sw s5,20(sp) - int32_t cause = csr_read(mcause); -80000308: 342027f3 csrr a5,mcause - if(cause < 0){ //interrupt -8000030c: 0007ce63 bltz a5,80000328 - csr_clear(mie, MIE_MTIE); - }break; - default: redirectTrap(); break; - } - } else { //exception - switch(cause){ -80000310: 00200713 li a4,2 -80000314: 04e78e63 beq a5,a4,80000370 -80000318: 00900713 li a4,9 -8000031c: 24e78e63 beq a5,a4,80000578 - csr_write(mepc, csr_read(mepc) + 4); - }break; - default: stopSim(); break; - } - }break; - default: redirectTrap(); break; -80000320: ee1ff0ef jal ra,80000200 -80000324: 0200006f j 80000344 - switch(cause & 0xFF){ -80000328: 0ff7f793 andi a5,a5,255 -8000032c: 00700713 li a4,7 -80000330: 02e79c63 bne a5,a4,80000368 - csr_set(sip, MIP_STIP); -80000334: 02000793 li a5,32 -80000338: 1447a073 csrs sip,a5 - csr_clear(mie, MIE_MTIE); -8000033c: 08000793 li a5,128 -80000340: 3047b073 csrc mie,a5 - } - } +800006d4 : +800006d4: fe402503 lw a0,-28(zero) # ffffffe4 <_sp+0x7fffefe4> +800006d8: 00008067 ret -} -80000344: 02c12083 lw ra,44(sp) -80000348: 02812403 lw s0,40(sp) -8000034c: 02412483 lw s1,36(sp) -80000350: 02012903 lw s2,32(sp) -80000354: 01c12983 lw s3,28(sp) -80000358: 01812a03 lw s4,24(sp) -8000035c: 01412a83 lw s5,20(sp) -80000360: 03010113 addi sp,sp,48 -80000364: 00008067 ret - default: redirectTrap(); break; -80000368: e99ff0ef jal ra,80000200 -8000036c: fd9ff06f j 80000344 - uint32_t mepc = csr_read(mepc); -80000370: 341024f3 csrr s1,mepc - uint32_t mstatus = csr_read(mstatus); -80000374: 30002a73 csrr s4,mstatus - uint32_t instruction = csr_read(mbadaddr); -80000378: 34302473 csrr s0,mbadaddr - uint32_t opcode = instruction & 0x7F; -8000037c: 07f47713 andi a4,s0,127 - uint32_t funct3 = (instruction >> 12) & 0x7; -80000380: 00c45793 srli a5,s0,0xc -80000384: 0077f613 andi a2,a5,7 - switch(opcode){ -80000388: 02f00693 li a3,47 -8000038c: 00d70a63 beq a4,a3,800003a0 -80000390: 07300693 li a3,115 -80000394: 12d70a63 beq a4,a3,800004c8 - default: redirectTrap(); break; -80000398: e69ff0ef jal ra,80000200 -8000039c: fa9ff06f j 80000344 - switch(funct3){ -800003a0: 00200793 li a5,2 -800003a4: 10f61e63 bne a2,a5,800004c0 - uint32_t sel = instruction >> 27; -800003a8: 01b45913 srli s2,s0,0x1b - uint32_t addr = readRegister((instruction >> 15) & 0x1F); -800003ac: 00f45513 srli a0,s0,0xf -800003b0: 01f57513 andi a0,a0,31 -800003b4: e1dff0ef jal ra,800001d0 -800003b8: 00050a93 mv s5,a0 - int32_t src = readRegister((instruction >> 20) & 0x1F); -800003bc: 01445513 srli a0,s0,0x14 -800003c0: 01f57513 andi a0,a0,31 -800003c4: e0dff0ef jal ra,800001d0 -800003c8: 00050993 mv s3,a0 - uint32_t rd = (instruction >> 7) & 0x1F; -800003cc: 00745413 srli s0,s0,0x7 -800003d0: 01f47413 andi s0,s0,31 - if(readWord(addr, &readValue)){ -800003d4: 00c10593 addi a1,sp,12 -800003d8: 000a8513 mv a0,s5 -800003dc: ea9ff0ef jal ra,80000284 -800003e0: 02051263 bnez a0,80000404 - switch(sel){ -800003e4: 01c00793 li a5,28 -800003e8: 0d27e063 bltu a5,s2,800004a8 -800003ec: 00291913 slli s2,s2,0x2 -800003f0: 800007b7 lui a5,0x80000 -800003f4: 6c078793 addi a5,a5,1728 # 800006c0 <_sp+0xfffff788> -800003f8: 00f90933 add s2,s2,a5 -800003fc: 00092783 lw a5,0(s2) -80000400: 00078067 jr a5 - emulationTrapToSupervisorTrap(mepc, mstatus); -80000404: 000a0593 mv a1,s4 -80000408: 00048513 mv a0,s1 -8000040c: e2dff0ef jal ra,80000238 - return; -80000410: f35ff06f j 80000344 - case 0x0: writeValue = src + readValue; break; -80000414: 00c12783 lw a5,12(sp) -80000418: 00f989b3 add s3,s3,a5 - writeRegister(rd, readValue); -8000041c: 00c12583 lw a1,12(sp) -80000420: 00040513 mv a0,s0 -80000424: dc5ff0ef jal ra,800001e8 - if(writeWord(addr, writeValue)){ -80000428: 00098593 mv a1,s3 -8000042c: 000a8513 mv a0,s5 -80000430: e89ff0ef jal ra,800002b8 -80000434: 06051e63 bnez a0,800004b0 - csr_write(mepc, mepc + 4); -80000438: 00448493 addi s1,s1,4 -8000043c: 34149073 csrw mepc,s1 - }break; -80000440: f05ff06f j 80000344 - case 0x4: writeValue = src ^ readValue; break; -80000444: 00c12783 lw a5,12(sp) -80000448: 00f9c9b3 xor s3,s3,a5 -8000044c: fd1ff06f j 8000041c - case 0xC: writeValue = src & readValue; break; -80000450: 00c12783 lw a5,12(sp) -80000454: 00f9f9b3 and s3,s3,a5 -80000458: fc5ff06f j 8000041c - case 0x8: writeValue = src | readValue; break; -8000045c: 00c12783 lw a5,12(sp) -80000460: 00f9e9b3 or s3,s3,a5 -80000464: fb9ff06f j 8000041c - case 0x10: writeValue = min(src, readValue); break; -80000468: 00c12783 lw a5,12(sp) -8000046c: fb37d8e3 ble s3,a5,8000041c -80000470: 00078993 mv s3,a5 -80000474: fa9ff06f j 8000041c - case 0x14: writeValue = max(src, readValue); break; -80000478: 00c12783 lw a5,12(sp) -8000047c: faf9d0e3 ble a5,s3,8000041c -80000480: 00078993 mv s3,a5 -80000484: f99ff06f j 8000041c - case 0x18: writeValue = min((unsigned int)src, (unsigned int)readValue); break; -80000488: 00c12783 lw a5,12(sp) -8000048c: f937f8e3 bleu s3,a5,8000041c -80000490: 00078993 mv s3,a5 -80000494: f89ff06f j 8000041c - case 0x1C: writeValue = max((unsigned int)src, (unsigned int)readValue); break; -80000498: 00c12783 lw a5,12(sp) -8000049c: f8f9f0e3 bleu a5,s3,8000041c -800004a0: 00078993 mv s3,a5 -800004a4: f79ff06f j 8000041c - default: redirectTrap(); return; break; -800004a8: d59ff0ef jal ra,80000200 -800004ac: e99ff06f j 80000344 - emulationTrapToSupervisorTrap(mepc, mstatus); -800004b0: 000a0593 mv a1,s4 -800004b4: 00048513 mv a0,s1 -800004b8: d81ff0ef jal ra,80000238 - return; -800004bc: e89ff06f j 80000344 - default: redirectTrap(); break; -800004c0: d41ff0ef jal ra,80000200 -800004c4: e81ff06f j 80000344 - switch (funct3 & 0x3) { -800004c8: 0037f793 andi a5,a5,3 -800004cc: 00100713 li a4,1 -800004d0: 06e78263 beq a5,a4,80000534 -800004d4: 02078c63 beqz a5,8000050c -800004d8: 00200713 li a4,2 -800004dc: 02e78c63 beq a5,a4,80000514 -800004e0: 00300713 li a4,3 -800004e4: 04e78063 beq a5,a4,80000524 - uint32_t csrAddress = instruction >> 20; -800004e8: 01445713 srli a4,s0,0x14 - switch(csrAddress){ -800004ec: 000017b7 lui a5,0x1 -800004f0: c0178793 addi a5,a5,-1023 # c01 <__stack_size+0x401> -800004f4: 04f70463 beq a4,a5,8000053c -800004f8: 000017b7 lui a5,0x1 -800004fc: c8178793 addi a5,a5,-895 # c81 <__stack_size+0x481> -80000500: 06f70263 beq a4,a5,80000564 - default: redirectTrap(); break; -80000504: cfdff0ef jal ra,80000200 -80000508: 03c0006f j 80000544 - case 0: redirectTrap(); break; -8000050c: cf5ff0ef jal ra,80000200 -80000510: fd9ff06f j 800004e8 - case 2: clear = 0; set = input; write = ((instruction >> 15) & 0x1F) != 0; break; -80000514: 00f45993 srli s3,s0,0xf -80000518: 01f9f993 andi s3,s3,31 -8000051c: 013039b3 snez s3,s3 -80000520: fc9ff06f j 800004e8 - case 3: clear = input; set = 0; write = ((instruction >> 15) & 0x1F) != 0; break; -80000524: 00f45993 srli s3,s0,0xf -80000528: 01f9f993 andi s3,s3,31 -8000052c: 013039b3 snez s3,s3 -80000530: fb9ff06f j 800004e8 - case 1: clear = ~0; set = input; write = 1; break; -80000534: 00100993 li s3,1 -80000538: fb1ff06f j 800004e8 - case RDTIME : old = rdtime(); break; -8000053c: 0c4000ef jal ra,80000600 -80000540: 00050913 mv s2,a0 - if(write) { -80000544: 02099663 bnez s3,80000570 - writeRegister((instruction >> 7) & 0x1F, old); -80000548: 00745513 srli a0,s0,0x7 -8000054c: 00090593 mv a1,s2 -80000550: 01f57513 andi a0,a0,31 -80000554: c95ff0ef jal ra,800001e8 - csr_write(mepc, mepc + 4); -80000558: 00448493 addi s1,s1,4 -8000055c: 34149073 csrw mepc,s1 - }break; -80000560: de5ff06f j 80000344 - case RDTIMEH : old = rdtimeh(); break; -80000564: 0a4000ef jal ra,80000608 -80000568: 00050913 mv s2,a0 -8000056c: fd9ff06f j 80000544 - default: redirectTrap(); break; -80000570: c91ff0ef jal ra,80000200 -80000574: fd5ff06f j 80000548 - uint32_t which = readRegister(17); -80000578: 01100513 li a0,17 -8000057c: c55ff0ef jal ra,800001d0 -80000580: 00050413 mv s0,a0 - uint32_t a0 = readRegister(10); -80000584: 00a00513 li a0,10 -80000588: c49ff0ef jal ra,800001d0 -8000058c: 00050493 mv s1,a0 - uint32_t a1 = readRegister(11); -80000590: 00b00513 li a0,11 -80000594: c3dff0ef jal ra,800001d0 - switch(which){ -80000598: 02040263 beqz s0,800005bc -8000059c: 00100793 li a5,1 -800005a0: 04f41463 bne s0,a5,800005e8 - putC(a0); -800005a4: 0ff4f513 andi a0,s1,255 -800005a8: 050000ef jal ra,800005f8 - csr_write(mepc, csr_read(mepc) + 4); -800005ac: 341027f3 csrr a5,mepc -800005b0: 00478793 addi a5,a5,4 -800005b4: 34179073 csrw mepc,a5 - }break; -800005b8: d8dff06f j 80000344 - setMachineTimerCmp(a0, a1); -800005bc: 00050593 mv a1,a0 -800005c0: 00048513 mv a0,s1 -800005c4: 04c000ef jal ra,80000610 - csr_set(mie, MIE_MTIE); -800005c8: 08000793 li a5,128 -800005cc: 3047a073 csrs mie,a5 - csr_clear(sip, MIP_STIP); -800005d0: 02000793 li a5,32 -800005d4: 1447b073 csrc sip,a5 - csr_write(mepc, csr_read(mepc) + 4); -800005d8: 341027f3 csrr a5,mepc -800005dc: 00478793 addi a5,a5,4 -800005e0: 34179073 csrw mepc,a5 - }break; -800005e4: d61ff06f j 80000344 - default: stopSim(); break; -800005e8: 008000ef jal ra,800005f0 -800005ec: d59ff06f j 80000344 +800006dc : +800006dc: fec00793 li a5,-20 +800006e0: fff00713 li a4,-1 +800006e4: 00e7a023 sw a4,0(a5) +800006e8: fea02423 sw a0,-24(zero) # ffffffe8 <_sp+0x7fffefe8> +800006ec: 00b7a023 sw a1,0(a5) +800006f0: 00008067 ret -800005f0 : -#include "hal.h" - -void stopSim(){ - *((volatile uint32_t*) 0xFFFFFFFC) = 0; -800005f0: fe002e23 sw zero,-4(zero) # fffffffc <_sp+0x7ffff0c4> -} -800005f4: 00008067 ret - -800005f8 : - -void putC(char c){ - *((volatile uint32_t*) 0xFFFFFFF8) = c; -800005f8: fea02c23 sw a0,-8(zero) # fffffff8 <_sp+0x7ffff0c0> -} -800005fc: 00008067 ret - -80000600 : - -uint32_t rdtime(){ - return *((volatile uint32_t*) 0xFFFFFFE0); -80000600: fe002503 lw a0,-32(zero) # ffffffe0 <_sp+0x7ffff0a8> -} -80000604: 00008067 ret - -80000608 : - -uint32_t rdtimeh(){ - return *((volatile uint32_t*) 0xFFFFFFE4); -80000608: fe402503 lw a0,-28(zero) # ffffffe4 <_sp+0x7ffff0ac> -} -8000060c: 00008067 ret - -80000610 : - - -void setMachineTimerCmp(uint32_t low, uint32_t high){ - volatile uint32_t* base = (volatile uint32_t*) 0xFFFFFFE8; - base[1] = 0xffffffff; -80000610: fec00793 li a5,-20 -80000614: fff00713 li a4,-1 -80000618: 00e7a023 sw a4,0(a5) - base[0] = low; -8000061c: fea02423 sw a0,-24(zero) # ffffffe8 <_sp+0x7ffff0b0> - base[1] = high; -80000620: 00b7a023 sw a1,0(a5) -} -80000624: 00008067 ret - -80000628 <__libc_init_array>: -80000628: ff010113 addi sp,sp,-16 -8000062c: 00812423 sw s0,8(sp) -80000630: 00912223 sw s1,4(sp) -80000634: 00000417 auipc s0,0x0 -80000638: 08c40413 addi s0,s0,140 # 800006c0 <__init_array_end> -8000063c: 00000497 auipc s1,0x0 -80000640: 08448493 addi s1,s1,132 # 800006c0 <__init_array_end> -80000644: 408484b3 sub s1,s1,s0 -80000648: 01212023 sw s2,0(sp) -8000064c: 00112623 sw ra,12(sp) -80000650: 4024d493 srai s1,s1,0x2 -80000654: 00000913 li s2,0 -80000658: 04991063 bne s2,s1,80000698 <__libc_init_array+0x70> -8000065c: 00000417 auipc s0,0x0 -80000660: 06440413 addi s0,s0,100 # 800006c0 <__init_array_end> -80000664: 00000497 auipc s1,0x0 -80000668: 05c48493 addi s1,s1,92 # 800006c0 <__init_array_end> -8000066c: 408484b3 sub s1,s1,s0 -80000670: a09ff0ef jal ra,80000078 <_init> -80000674: 4024d493 srai s1,s1,0x2 -80000678: 00000913 li s2,0 -8000067c: 02991863 bne s2,s1,800006ac <__libc_init_array+0x84> -80000680: 00c12083 lw ra,12(sp) -80000684: 00812403 lw s0,8(sp) -80000688: 00412483 lw s1,4(sp) -8000068c: 00012903 lw s2,0(sp) -80000690: 01010113 addi sp,sp,16 -80000694: 00008067 ret -80000698: 00042783 lw a5,0(s0) -8000069c: 00190913 addi s2,s2,1 -800006a0: 00440413 addi s0,s0,4 -800006a4: 000780e7 jalr a5 -800006a8: fb1ff06f j 80000658 <__libc_init_array+0x30> -800006ac: 00042783 lw a5,0(s0) -800006b0: 00190913 addi s2,s2,1 -800006b4: 00440413 addi s0,s0,4 -800006b8: 000780e7 jalr a5 -800006bc: fc1ff06f j 8000067c <__libc_init_array+0x54> +800006f4 <__libc_init_array>: +800006f4: ff010113 addi sp,sp,-16 +800006f8: 00812423 sw s0,8(sp) +800006fc: 00912223 sw s1,4(sp) +80000700: 00000417 auipc s0,0x0 +80000704: 08c40413 addi s0,s0,140 # 8000078c <__init_array_end> +80000708: 00000497 auipc s1,0x0 +8000070c: 08448493 addi s1,s1,132 # 8000078c <__init_array_end> +80000710: 408484b3 sub s1,s1,s0 +80000714: 01212023 sw s2,0(sp) +80000718: 00112623 sw ra,12(sp) +8000071c: 4024d493 srai s1,s1,0x2 +80000720: 00000913 li s2,0 +80000724: 04991063 bne s2,s1,80000764 <__libc_init_array+0x70> +80000728: 00000417 auipc s0,0x0 +8000072c: 06440413 addi s0,s0,100 # 8000078c <__init_array_end> +80000730: 00000497 auipc s1,0x0 +80000734: 05c48493 addi s1,s1,92 # 8000078c <__init_array_end> +80000738: 408484b3 sub s1,s1,s0 +8000073c: 93dff0ef jal ra,80000078 <_init> +80000740: 4024d493 srai s1,s1,0x2 +80000744: 00000913 li s2,0 +80000748: 02991863 bne s2,s1,80000778 <__libc_init_array+0x84> +8000074c: 00c12083 lw ra,12(sp) +80000750: 00812403 lw s0,8(sp) +80000754: 00412483 lw s1,4(sp) +80000758: 00012903 lw s2,0(sp) +8000075c: 01010113 addi sp,sp,16 +80000760: 00008067 ret +80000764: 00042783 lw a5,0(s0) +80000768: 00190913 addi s2,s2,1 +8000076c: 00440413 addi s0,s0,4 +80000770: 000780e7 jalr a5 +80000774: fb1ff06f j 80000724 <__libc_init_array+0x30> +80000778: 00042783 lw a5,0(s0) +8000077c: 00190913 addi s2,s2,1 +80000780: 00440413 addi s0,s0,4 +80000784: 000780e7 jalr a5 +80000788: fc1ff06f j 80000748 <__libc_init_array+0x54> diff --git a/src/main/c/emulator/build/emulator.hex b/src/main/c/emulator/build/emulator.hex index 4b5dcb75..65444a19 100644 --- a/src/main/c/emulator/build/emulator.hex +++ b/src/main/c/emulator/build/emulator.hex @@ -1,10 +1,10 @@ :0200000480007A -:1000000017110000130181F3170500001305856B1C -:10001000970500009385056B17060000130606720E +:1000000017110000130101001705000013054578C2 +:10001000970500009385C577170600001306867EB6 :1000200063FCC5008322050023A05500130545008D -:1000300093854500E3E8C5FE17050000130505702C -:10004000970500009385856F6378B5002320050030 -:1000500013054500E36CB5FEEF00005DEF00801274 +:1000300093854500E3E8C5FE170500001305857CA0 +:10004000970500009385057C6378B50023200500A3 +:1000500013054500E36CB5FEEF00C069EF008012A8 :10006000970000009380400113050000B705008150 :10007000730020306F0000006780000073110134AE :1000800023200100232211002326310023284100D0 @@ -25,14 +25,14 @@ :10017000832E4107032F8107832FC1077311013499 :0401800073002030B8 :10018400B70700809387C70773905730B71700806D -:10019400938787F3938707F873900734B7170000A2 -:1001A400938707887390073073504030B70700C0B7 -:1001B40073901734B7B70000739027309307000289 -:1001C4007390373073503014678000001315250086 -:1001D400B7170080938787F33305F500032505F8E7 -:1001E4006780000013152500B7170080938787F3F5 -:1001F4003305F5002320B5F867800000130101FFE3 -:1002040023261100EF00803EF32730347390371417 +:10019400938707F873900734B7170000938707888D +:1001A4007390073073504030B70700C07390173412 +:1001B400B7B70000938707107390273093070002A6 +:1001C400739037307350301467800000B717008085 +:1001D400938707F8131525003305F500032505005B +:1001E40067800000B717008013152500938707F870 +:1001F4003305F5002320B50067800000130101FFDB +:1002040023261100EF00404BF3273034739037144A :10021400F327103473901714F327203473902714A2 :10022400F3275010739017348320C1001301010188 :1002340067800000F327303473903714F327203499 @@ -46,75 +46,88 @@ :1002B400678000003707020073200730170700002B :1002C4001307870173101734930710002320B50018 :1002D40093070000370702007330073013850700C7 -:1002E40067800000130101FD2326110223248102EB -:1002F4002322910223202103232E3101232C4101A7 -:10030400232A5101F327203463CE0700130720006A -:10031400638EE70413079000638EE724EFF01FEE6B -:100324006F00000293F7F70F13077000639CE70256 -:100334009307000273A047149307000873B0473073 -:100344008320C10203248102832441020329010280 -:100354008329C101032A8101832A41011301010375 -:1003640067800000EFF09FE96FF09FFDF3241034E5 -:10037400732A0030732430341377F4079357C4007E -:1003840013F677009306F002630AD700930630074A -:10039400630AD712EFF09FE66FF09FFA93072000ED -:1003A400631EF6101359B4011355F4001375F501C7 -:1003B400EFF0DFE1930A0500135544011375F501CD -:1003C400EFF0DFE093090500135474001374F40193 -:1003D4009305C10013850A00EFF09FEA631205023A -:1003E4009307C00163E0270D13192900B7070080A4 -:1003F4009387076C3309F900832709006780070096 -:1004040093050A0013850400EFF0DFE26FF05FF359 -:100414008327C100B389F9008325C10013050400B3 -:10042400EFF05FDC9385090013850A00EFF09FE885 -:10043400631E050693844400739014346FF05FF0D8 -:100444008327C100B3C9F9006FF01FFD8327C100E2 -:10045400B3F9F9006FF05FFC8327C100B3E9F90039 -:100464006FF09FFB8327C100E3D837FB9389070014 -:100474006FF09FFA8327C100E3D0F9FA938907004C -:100484006FF09FF98327C100E3F837F993890700D8 -:100494006FF09FF88327C100E3F0F9F89389070010 -:1004A4006FF09FF7EFF09FD56FF09FE993050A0077 -:1004B40013850400EFF01FD86FF09FE8EFF01FD40E -:1004C4006FF01FE893F73700130710006382E70605 -:1004D400638C070213072000638CE70213073000C4 -:1004E4006380E70413574401B7170000938717C0CC -:1004F4006304F704B7170000938717C86302F7066D -:10050400EFF0DFCF6F00C003EFF05FCF6FF09FFD20 -:100514009359F40093F9F901B33930016FF09FFC5A -:100524009359F40093F9F901B33930016FF09FFB4B -:10053400930910006FF01FFBEF00400C1309050036 -:100544006396090213557400930509001375F501A8 -:10055400EFF05FC993844400739014346FF05FDE4E -:10056400EF00400A130905006FF09FFDEFF01FC96B -:100574006FF05FFD13051001EFF05FC51304050074 -:100584001305A000EFF09FC4930405001305B00009 -:10059400EFF0DFC363020402930710006314F40452 -:1005A40013F5F40FEF000005F32710349387470089 -:1005B400739017346FF0DFD893050500138504009A -:1005C400EF00C0049307000873A0473093070002AC -:1005D40073B04714F327103493874700739017348C -:1005E4006FF01FD6EF0080006FF09FD5232E00FE22 -:1005F40067800000232CA0FE67800000032500FE16 -:1006040067800000032540FE678000009307C0FE5A -:100614001307F0FF23A0E7002324A0FE23A0B700C4 -:1006240067800000130101FF23248100232291002D -:10063400170400001304C4089704000093844408BA -:10064400B3848440232021012326110093D4244021 -:1006540013090000631099041704000013044406EE -:10066400970400009384C405B3848440EFF09FA0F2 -:1006740093D4244013090000631899028320C10015 -:100684000324810083244100032901001301010193 -:100694006780000083270400130919001304440031 -:1006A400E78007006FF01FFB83270400130919007C -:0C06B40013044400E78007006FF01FFCF7 -:1006C000140400801C040080A8040080A80400809A -:1006D00044040080A8040080A8040080A8040080CE -:1006E0005C040080A8040080A8040080A8040080A6 -:1006F00050040080A8040080A8040080A8040080A2 -:1007000068040080A8040080A8040080A804008079 -:1007100078040080A8040080A8040080A804008059 -:1007200088040080A8040080A8040080A804008039 -:080730009804008000000000A5 +:1002E40067800000130101FE232E1100232C8100DE +:1002F400232A91002328210123263101F3272034C6 +:1003040063CE0714130720006384E7049306900068 +:100314006396D710B71700809387070083A647FC1E +:100324001306100003A587FA6386C61E6384E622BB +:10033400638E061E032481018320C10183244101AD +:10034400032901018329C100130101026F00C03692 +:10035400F3241034F3250030732430341306F002F0 +:100364009376F4071357C4006386C6121306300746 +:100374006396C60A137737006300F72493073000A7 +:10038400630CF7229309100063043703EF00C032B3 +:10039400F327303473903714F32710347390171401 +:1003A400F327203473902714F327501073901734D5 +:1003B400B717000013574401938617C06308D72E5C +:1003C400938717C86310F72CEF00803013090500DA +:1003D40063840902EF00402EF327303473903714FE +:1003E400F327103473901714F327203473902714D1 +:1003F400F32750107390173413545400B717008028 +:100404001374C407938707F83304F40023202401EA +:1004140093844400739014346F008002EF00C02969 +:10042400F327303473903714F32710347390171470 +:10043400F327203473902714F32750107390173444 +:100444008320C10103248101832441010329010183 +:100454008329C100130101026780000093F7F70F9D +:1004640013077000E39CE7FA9307000273A0471494 +:100474009307000873B047308320C101032481012E +:1004840083244101032901018329C10013010102CD +:100494006780000013777700E312F7F81357D4004E +:1004A40093572401B7160080938606F81377C7077D +:1004B40093F7C7073307D700B387D700032707008D +:1004C40003A6070037050200732005301705000056 +:1004D40013058501731015349307100003280700D2 +:1004E4009307000037050200733005306390070856 +:1004F4009357B4011305C001E362F5F23705008098 +:10050400939727001305C578B387A70083A707002F +:10051400678007001375F50FEF00801AF327103476 +:1005240093874700739017346FF09FF183A5C7FA40 +:10053400EF00801A9307000873A047309307000266 +:1005440073B04714F327103493874700739017341C +:100554006FF01FEF1307F0FF23A4E7FAF32710341B +:1005640093874700739017346FF09FEDF32730346F +:1005740073903714F3272034739027147390141452 +:10058400F3275010739017349307001073B00710BB +:1005940093D5350093F5051073A00510B727000017 +:1005A4009387078073B00730B787000093870708E5 +:1005B40073A007306FF0DFE89359F40093F9F90161 +:1005C400B33930016FF0DFDE3306060113545400F3 +:1005D4001374C407B306D40023A00601B7060200AF +:1005E40073A0063097060000938686017390163434 +:1005F400930710002320C70093070000B7060200EA +:1006040073B00630E38607E0F32730347390371471 +:10061400F32720347390271473901414F327501085 +:10062400739017349307001073B0071093D73500F5 +:1006340093F7071073A007106FF05FF6E37806F9DD +:10064400130608006FF09FF8336606016FF01FF879 +:10065400334606016FF09FF7E37AC8F613060800E5 +:100664006FF0DFF6E35406F7130608006FF01FF689 +:10067400E35EC8F4130608006FF05FF533760601F5 +:100684006FF0DFF4EF004003F32730347390371436 +:10069400F327103473901714F3272034739027141E +:1006A400F3275010739017346FF09FD2EF00C001FE +:1006B400130905006FF0DFD1232E00FE67800000D0 +:1006C400232CA0FE67800000032500FE6780000045 +:1006D400032540FE678000009307C0FE1307F0FF68 +:1006E40023A0E7002324A0FE23A0B7006780000016 +:1006F400130101FF23248100232291001704000029 +:100704001304C4089704000093844408B384844009 +:10071400232021012326110093D42440130900002F +:10072400631099041704000013044406970400009E +:100734009384C405B3848440EFF0DF9393D42440BE +:1007440013090000631899028320C1000324810067 +:100754008324410003290100130101016780000083 +:10076400832704001309190013044400E7800700D9 +:100774006FF01FFB832704001309190013044400BE +:08078400E78007006FF01FFC85 +:10078C00CC050080D005008020040080200400806F +:10079C005406008020040080200400802004008087 +:1007AC004C0600802004008020040080200400807F +:1007BC00800600802004008020040080200400803B +:1007CC007406008020040080200400802004008037 +:1007DC006806008020040080200400802004008033 +:1007EC005C0600802004008020040080200400802F +:0407FC004006008033 :040000058000000077 :00000001FF diff --git a/src/main/c/emulator/makefile b/src/main/c/emulator/makefile index 348a1134..e861785c 100755 --- a/src/main/c/emulator/makefile +++ b/src/main/c/emulator/makefile @@ -1,5 +1,5 @@ PROJ_NAME=emulator -DEBUG=yes +DEBUG=no MULDIV=no COMPRESSED=no STANDALONE = .. diff --git a/src/main/c/emulator/src/main.c b/src/main/c/emulator/src/main.c index a2171b83..498929b7 100755 --- a/src/main/c/emulator/src/main.c +++ b/src/main/c/emulator/src/main.c @@ -14,7 +14,7 @@ void init() { csr_write(mstatus, 0x0800 | MSTATUS_MPIE); csr_write(mie, 0); csr_write(mepc, OS_CALL); - csr_write(medeleg, MEDELEG_INSTRUCTION_PAGE_FAULT | MEDELEG_LOAD_PAGE_FAULT | MEDELEG_STORE_PAGE_FAULT); + csr_write(medeleg, MEDELEG_INSTRUCTION_PAGE_FAULT | MEDELEG_LOAD_PAGE_FAULT | MEDELEG_STORE_PAGE_FAULT | MEDELEG_USER_ENVIRONNEMENT_CALL); csr_write(mideleg, MIDELEG_SUPERVISOR_TIMER); csr_write(sbadaddr, 0); //Used to avoid simulation missmatch } @@ -212,6 +212,10 @@ void trap(){ putC(a0); csr_write(mepc, csr_read(mepc) + 4); }break; + case SBI_CONSOLE_GETCHAR:{ + writeRegister(10, -1); //no char + csr_write(mepc, csr_read(mepc) + 4); + }break; case SBI_SET_TIMER:{ setMachineTimerCmp(a0, a1); csr_set(mie, MIE_MTIE); diff --git a/src/main/c/emulator/src/riscv.h b/src/main/c/emulator/src/riscv.h index 06d2333c..ea6ddd56 100644 --- a/src/main/c/emulator/src/riscv.h +++ b/src/main/c/emulator/src/riscv.h @@ -8,6 +8,7 @@ #define MEDELEG_INSTRUCTION_PAGE_FAULT (1 << 12) #define MEDELEG_LOAD_PAGE_FAULT (1 << 13) #define MEDELEG_STORE_PAGE_FAULT (1 << 15) +#define MEDELEG_USER_ENVIRONNEMENT_CALL (1 << 8) #define MIDELEG_SUPERVISOR_TIMER (1 << 5) #define MIE_MTIE (1 << 7) diff --git a/src/main/scala/vexriscv/demo/Linux.scala b/src/main/scala/vexriscv/demo/Linux.scala index 9a35bb9b..323940cb 100644 --- a/src/main/scala/vexriscv/demo/Linux.scala +++ b/src/main/scala/vexriscv/demo/Linux.scala @@ -40,7 +40,7 @@ make run DBUS=SIMPLE IBUS=SIMPLE DHRYSTONE=yes SUPERVISOR=yes CSR=yes COMPRESSED Run linux => sbt "runMain vexriscv.demo.LinuxGen" cd src/test/cpp/regression -make run DBUS=SIMPLE IBUS=SIMPLE SUPERVISOR=yes CSR=yes COMPRESSED=yes LITEX=yes EMULATOR=/home/spinalvm/hdl/VexRiscv/src/main/c/emulator/build/emulator.bin VMLINUX=/home/spinalvm/hdl/linuxDave/vmlinux.bin DTB=/home/spinalvm/hdl/linuxDave/vmlinux/rv32.dtb RAMDISK=/home/spinalvm/hdl/linuxDave/initramdisk_dave TRACE=no +make run DBUS=SIMPLE IBUS=SIMPLE SUPERVISOR=yes CSR=yes COMPRESSED=yes REDO=0 DHRYSTONE=no LITEX=yes EMULATOR=/home/spinalvm/hdl/VexRiscv/src/main/c/emulator/build/emulator.bin VMLINUX=/home/spinalvm/hdl/riscv-linux/vmlinux.bin DTB=/home/spinalvm/hdl/riscv-linux/rv32.dtb RAMDISK=/home/spinalvm/hdl/linuxDave/initramdisk_dave TRACE=yes0 FLOW_INFO=yes TRACE_START=9570000099 @@ -51,7 +51,7 @@ riscv64-unknown-elf-objdump -S -d vmlinux > vmlinux.asm; split -b 1M vmlinux.asm split -b 1M vmlinux.asm dtc -O dtb -o rv32.dtb rv32.dts -make run DBUS=SIMPLE IBUS=SIMPLE SUPERVISOR=yes CSR=yes COMPRESSED=yes LITEX=yes EMULATOR=/home/spinalvm/hdl/VexRiscv/src/main/c/emulator/build/emulator.bin VMLINUX=/home/spinalvm/hdl/riscv-linux/vmlinux.bin DTB=/home/spinalvm/hdl/riscv-linux/rv32.dtb RAMDISK=/home/spinalvm/hdl/linuxDave/initramdisk_dave TRACE=yes FLOW_INFO=yes TRACE_START=0000000 +make run DBUS=SIMPLE IBUS=SIMPLE SUPERVISOR=yes CSR=yes COMPRESSED=yes REDO=0 DHRYSTONE=no LITEX=yes EMULATOR=/home/spinalvm/hdl/VexRiscv/src/main/c/emulator/build/emulator.bin VMLINUX=/home/spinalvm/hdl/riscv-linux/vmlinux.bin DTB=/home/spinalvm/hdl/riscv-linux/rv32.dtb RAMDISK=/home/spinalvm/hdl/linuxDave/initramdisk_dave TRACE=yes0 FLOW_INFO=yes TRACE_START=9570000099 */ diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 75d5fdad..91af6ee5 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -835,7 +835,7 @@ public: pcWrite(sepc); }break; case 0x00000073:{ //ECALL - trap(0, 8+privilege); + trap(0, 8+privilege, 0x00000073); //To follow the VexRiscv area saving implementation }break; case 0x10500073:{ //WFI pcWrite(pc + 4); @@ -897,10 +897,10 @@ public: if(v2p(address, &pAddr, WRITE)){ trap(0, 15, address); return; } bool hit = false; for(int i = 0;i < RESERVED_ENTRY_COUNT;i++) hit |= reservedEntries[i].valid && reservedEntries[i].address == address; - rfWrite(rd32, !hit); if(hit){ dWrite(pAddr, 4, i32_rs2); } + rfWrite(rd32, !hit); pcWrite(pc + 4); } } break; @@ -1063,6 +1063,7 @@ public: ofstream regTraces; ofstream memTraces; ofstream logTraces; + ofstream debugLog; struct timespec start_time; @@ -1125,6 +1126,9 @@ public: if(ws->isPerifRegion(address)){ MemRead t = periphRead.front(); if(t.address != address || t.size != size){ + cout << "DRead missmatch" << hex << endl; + cout << " REF : address=" << address << " size=" << size << endl; + cout << " DUT : address=" << t.address << " size=" << t.size << endl; fail(); } *data = t.data; @@ -1138,14 +1142,24 @@ public: virtual void dWrite(int32_t address, int32_t size, uint32_t data){ if(address & (size-1) != 0) cout << "Ref did a unaligned write" << endl; - if(ws->isPerifRegion(address)){ + + if(!ws->isPerifRegion(address)){ + mem.write(address, size, (uint8_t*)&data); + } + if(ws->isDBusCheckedRegion(address)){ MemWrite w; w.address = address; w.size = size; - w.data = data; + switch(size){ + case 1: w.data = data & 0xFF; break; + case 2: w.data = data & 0xFFFF; break; + case 4: w.data = data; break; + } periphWritesGolden.push(w); - }else { - mem.write(address, size, (uint8_t*)&data); + if(periphWritesGolden.size() > 10){ + cout << "??? periphWritesGolden" << endl; + fail(); + } } } @@ -1193,6 +1207,7 @@ public: memTraces.open (name + ".memTrace");hh #endif logTraces.open (name + ".logTrace"); + debugLog.open (name + ".debugTrace"); fillSimELements(); clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start_time); } @@ -1254,22 +1269,7 @@ public: virtual bool isDBusCheckedRegion(uint32_t address){ return isPerifRegion(address);} virtual void dBusAccess(uint32_t addr,bool wr, uint32_t size,uint32_t mask, uint32_t *data, bool *error) { assertEq(addr % (1 << size), 0); - if(isPerifRegion(addr)){ - if(wr){ - CpuRef::MemWrite w; - w.address = addr; - w.size = 1 << size; - w.data = *data; - riscvRef.periphWrites.push(w); - } else { - CpuRef::MemRead r; - r.address = addr; - r.size = 1 << size; - r.data = *data; - r.error = *error; - riscvRef.periphRead.push(r); - } - } else { + if(!isPerifRegion(addr)) { if(wr){ memTraces << #ifdef TRACE_WITH_TIME @@ -1305,6 +1305,30 @@ public: } } + + + if(wr){ + if(isDBusCheckedRegion(addr)){ + CpuRef::MemWrite w; + w.address = addr; + w.size = 1 << size; + switch(size){ + case 0: w.data = *data & 0xFF; break; + case 1: w.data = *data & 0xFFFF; break; + case 2: w.data = *data ; break; + } + riscvRef.periphWrites.push(w); + } + } else { + if(isPerifRegion(addr)){ + CpuRef::MemRead r; + r.address = addr; + r.size = 1 << size; + r.data = *data; + r.error = *error; + riscvRef.periphRead.push(r); + } + } } // void periphAccess(uint32_t addr,bool wr, uint32_t size,uint32_t mask, uint32_t *data, bool *error){ @@ -2946,7 +2970,7 @@ public: LitexSoC(string name) : Workspace(name) { } - + virtual bool isDBusCheckedRegion(uint32_t address){ return true;} virtual bool isPerifRegion(uint32_t addr) { return (addr & 0xF0000000) == 0xB0000000 || (addr & 0xE0000000) == 0xE0000000;} virtual bool isMmuRegion(uint32_t addr) { return (addr & 0xFF000000) != 0x81000000;} From f113946e6675d9c9534d70200c302cbb09334ee1 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 27 Mar 2019 10:53:41 +0100 Subject: [PATCH 080/951] Added a neutral LINUX_SOC for sim purposes --- src/main/scala/vexriscv/demo/Linux.scala | 16 +++++++ src/test/cpp/regression/main.cpp | 61 ++++++++++++++++++++++-- src/test/cpp/regression/makefile | 8 ++++ 3 files changed, 80 insertions(+), 5 deletions(-) diff --git a/src/main/scala/vexriscv/demo/Linux.scala b/src/main/scala/vexriscv/demo/Linux.scala index 323940cb..f18088d9 100644 --- a/src/main/scala/vexriscv/demo/Linux.scala +++ b/src/main/scala/vexriscv/demo/Linux.scala @@ -40,15 +40,31 @@ make run DBUS=SIMPLE IBUS=SIMPLE DHRYSTONE=yes SUPERVISOR=yes CSR=yes COMPRESSED Run linux => sbt "runMain vexriscv.demo.LinuxGen" cd src/test/cpp/regression +make run DBUS=SIMPLE IBUS=SIMPLE SUPERVISOR=yes CSR=yes COMPRESSED=yes REDO=0 DHRYSTONE=no LINUX_SOC=yes EMULATOR=../../../main/c/emulator/build/emulator.bin VMLINUX=???/vmlinux.bin DTB=???/rv32.dtb RAMDISK=???/initramdisk TRACE=no FLOW_INFO=yes TRACE_START=9570000099 + + + + + + make run DBUS=SIMPLE IBUS=SIMPLE SUPERVISOR=yes CSR=yes COMPRESSED=yes REDO=0 DHRYSTONE=no LITEX=yes EMULATOR=/home/spinalvm/hdl/VexRiscv/src/main/c/emulator/build/emulator.bin VMLINUX=/home/spinalvm/hdl/riscv-linux/vmlinux.bin DTB=/home/spinalvm/hdl/riscv-linux/rv32.dtb RAMDISK=/home/spinalvm/hdl/linuxDave/initramdisk_dave TRACE=yes0 FLOW_INFO=yes TRACE_START=9570000099 +make run DBUS=SIMPLE IBUS=SIMPLE SUPERVISOR=yes CSR=yes COMPRESSED=yes REDO=0 DHRYSTONE=no LINUX_SOC=yes EMULATOR=/home/spinalvm/hdl/VexRiscv/src/main/c/emulator/build/emulator.bin VMLINUX=/home/spinalvm/hdl/linux/linux-1c163f4c7b3f621efff9b28a47abb36f7378d783/vmlinux.bin DTB=/home/spinalvm/hdl/linux/linux-1c163f4c7b3f621efff9b28a47abb36f7378d783/rv32.dtb RAMDISK=/home/spinalvm/hdl/linuxDave/initramdisk_dave TRACE=yes0 FLOW_INFO=yes TRACE_START=9570000099 + + + + Other commands (Memo): cp litex_default_configuration .config ARCH=riscv CROSS_COMPILE=riscv64-unknown-elf- make -j`nproc`; riscv64-unknown-elf-objcopy -O binary vmlinux vmlinux.bin riscv64-unknown-elf-objdump -S -d vmlinux > vmlinux.asm; split -b 1M vmlinux.asm + + +ARCH=riscv CROSS_COMPILE=riscv32-unknown-linux-gnu- make -j`nproc`; riscv32-unknown-linux-gnu-objcopy -O binary vmlinux vmlinux.bin + split -b 1M vmlinux.asm dtc -O dtb -o rv32.dtb rv32.dts make run DBUS=SIMPLE IBUS=SIMPLE SUPERVISOR=yes CSR=yes COMPRESSED=yes REDO=0 DHRYSTONE=no LITEX=yes EMULATOR=/home/spinalvm/hdl/VexRiscv/src/main/c/emulator/build/emulator.bin VMLINUX=/home/spinalvm/hdl/riscv-linux/vmlinux.bin DTB=/home/spinalvm/hdl/riscv-linux/rv32.dtb RAMDISK=/home/spinalvm/hdl/linuxDave/initramdisk_dave TRACE=yes0 FLOW_INFO=yes TRACE_START=9570000099 diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 91af6ee5..ab90652f 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -2963,11 +2963,46 @@ public: #endif -#ifdef LITEX -class LitexSoC : public Workspace{ +//#ifdef LITEX +//class LitexSoC : public Workspace{ +//public: +// +// LitexSoC(string name) : Workspace(name) { +// +// } +// virtual bool isDBusCheckedRegion(uint32_t address){ return true;} +// virtual bool isPerifRegion(uint32_t addr) { return (addr & 0xF0000000) == 0xB0000000 || (addr & 0xE0000000) == 0xE0000000;} +// virtual bool isMmuRegion(uint32_t addr) { return (addr & 0xFF000000) != 0x81000000;} +// +// virtual void dBusAccess(uint32_t addr,bool wr, uint32_t size,uint32_t mask, uint32_t *data, bool *error) { +// if(isPerifRegion(addr)) switch(addr){ +// //TODO Emulate peripherals here +// case 0xFFFFFFE0: if(wr) fail(); else *data = mTime; break; +// case 0xFFFFFFE4: if(wr) fail(); else *data = mTime >> 32; break; +// case 0xFFFFFFE8: if(wr) mTimeCmp = (mTimeCmp & 0xFFFFFFFF00000000) | *data; else *data = mTimeCmp; break; +// case 0xFFFFFFEC: if(wr) mTimeCmp = (mTimeCmp & 0x00000000FFFFFFFF) | (((uint64_t)*data) << 32); else *data = mTimeCmp >> 32; break; +// case 0xFFFFFFF8: +// if(wr){ +// cout << (char)*data; +// logTraces << (char)*data; +// logTraces.flush(); +// } else fail(); +// break; +// case 0xFFFFFFFC: fail(); break; //Simulation end +// default: cout << "Unmapped peripheral access : addr=0x" << hex << addr << " wr=" << wr << " mask=0x" << mask << " data=0x" << data << dec << endl; fail(); break; +// } +// +// Workspace::dBusAccess(addr,wr,size,mask,data,error); +// } +//}; +//#endif + + +#ifdef LINUX_SOC +class LinuxSoc : public Workspace{ public: - LitexSoC(string name) : Workspace(name) { + LinuxSoc(string name) : Workspace(name) { } virtual bool isDBusCheckedRegion(uint32_t address){ return true;} @@ -3264,8 +3299,24 @@ int main(int argc, char **argv, char **env) { timespec startedAt = timer_start(); -#ifdef LITEX - LitexSoC("linux") + + +//#ifdef LITEX +// LitexSoC("linux") +// .withRiscvRef() +// ->loadBin(EMULATOR, 0x80000000) +// ->loadBin(DTB, 0x81000000) +// ->loadBin(VMLINUX, 0xc0000000) +// ->loadBin(RAMDISK, 0xc2000000) +// ->setIStall(false) //TODO It currently improve speed but should be removed later +// ->setDStall(false) +// ->bootAt(0x80000000) +// ->run(0); +//#endif + + +#ifdef LINUX_SOC + LinuxSoc("linux") .withRiscvRef() ->loadBin(EMULATOR, 0x80000000) ->loadBin(DTB, 0x81000000) diff --git a/src/test/cpp/regression/makefile b/src/test/cpp/regression/makefile index f5c8d95e..62981797 100644 --- a/src/test/cpp/regression/makefile +++ b/src/test/cpp/regression/makefile @@ -57,6 +57,14 @@ ifeq ($(LITEX),yes) ADDCFLAGS += -CFLAGS -DEMULATOR='\"$(EMULATOR)\"' endif +ifeq ($(LINUX_SOC),yes) + ADDCFLAGS += -CFLAGS -DLINUX_SOC + ADDCFLAGS += -CFLAGS -DVMLINUX='\"$(VMLINUX)\"' + ADDCFLAGS += -CFLAGS -DDTB='\"$(DTB)\"' + ADDCFLAGS += -CFLAGS -DRAMDISK='\"$(RAMDISK)\"' + ADDCFLAGS += -CFLAGS -DEMULATOR='\"$(EMULATOR)\"' +endif + ifeq ($(FLOW_INFO),yes) ADDCFLAGS += -CFLAGS -DFLOW_INFO endif From 43c3922a3d9e26bdf6db41ca132504efd48a6a3d Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 27 Mar 2019 10:55:20 +0100 Subject: [PATCH 081/951] Add prerequired stuff --- src/main/scala/vexriscv/demo/Linux.scala | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/scala/vexriscv/demo/Linux.scala b/src/main/scala/vexriscv/demo/Linux.scala index f18088d9..f9cb68c5 100644 --- a/src/main/scala/vexriscv/demo/Linux.scala +++ b/src/main/scala/vexriscv/demo/Linux.scala @@ -27,6 +27,11 @@ import vexriscv.ip._ import vexriscv.plugin._ /* +prerequired stuff => +- JAVA JDK >= 8 +- SBT +- Verilator + Setup things => git clone https://github.com/SpinalHDL/SpinalHDL.git -b dev git clone https://github.com/SpinalHDL/VexRiscv.git -b linux From 0bed511a6c222ea579baf6c0a5d6fe3eba0c7ed9 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 27 Mar 2019 18:58:02 +0100 Subject: [PATCH 082/951] Fix cacheless LR/SC xtval, did some SRC/ADD_SUB/ALU redesign --- src/main/scala/vexriscv/VexRiscv.scala | 3 ++- src/main/scala/vexriscv/demo/Linux.scala | 5 ++++- .../vexriscv/plugin/DBusSimplePlugin.scala | 8 +++---- .../scala/vexriscv/plugin/IntAluPlugin.scala | 7 +++--- .../scala/vexriscv/plugin/ShiftPlugins.scala | 18 ++++++++++----- .../scala/vexriscv/plugin/SrcPlugin.scala | 22 ++++++++++++++++--- 6 files changed, 43 insertions(+), 20 deletions(-) diff --git a/src/main/scala/vexriscv/VexRiscv.scala b/src/main/scala/vexriscv/VexRiscv.scala index aead2400..c0da1d4a 100644 --- a/src/main/scala/vexriscv/VexRiscv.scala +++ b/src/main/scala/vexriscv/VexRiscv.scala @@ -52,6 +52,7 @@ case class VexRiscvConfig(){ object SRC_LESS extends Stageable(Bool) object SRC_USE_SUB_LESS extends Stageable(Bool) object SRC_LESS_UNSIGNED extends Stageable(Bool) + object SRC_ADD_ZERO extends Stageable(Bool) object HAS_SIDE_EFFECT extends Stageable(Bool) @@ -72,7 +73,7 @@ case class VexRiscvConfig(){ } object Src2CtrlEnum extends SpinalEnum(binarySequential){ - val RS, IMI, IMS, PC = newElement() + val RS, IMI, IMS, PC = newElement() //TODO remplacing ZERO could avoid 32 muxes if SRC_ADD can be disabled } object SRC1_CTRL extends Stageable(Src1CtrlEnum()) object SRC2_CTRL extends Stageable(Src2CtrlEnum()) diff --git a/src/main/scala/vexriscv/demo/Linux.scala b/src/main/scala/vexriscv/demo/Linux.scala index f9cb68c5..c274554e 100644 --- a/src/main/scala/vexriscv/demo/Linux.scala +++ b/src/main/scala/vexriscv/demo/Linux.scala @@ -52,7 +52,8 @@ make run DBUS=SIMPLE IBUS=SIMPLE SUPERVISOR=yes CSR=yes COMPRESSED=yes REDO=0 DH -make run DBUS=SIMPLE IBUS=SIMPLE SUPERVISOR=yes CSR=yes COMPRESSED=yes REDO=0 DHRYSTONE=no LITEX=yes EMULATOR=/home/spinalvm/hdl/VexRiscv/src/main/c/emulator/build/emulator.bin VMLINUX=/home/spinalvm/hdl/riscv-linux/vmlinux.bin DTB=/home/spinalvm/hdl/riscv-linux/rv32.dtb RAMDISK=/home/spinalvm/hdl/linuxDave/initramdisk_dave TRACE=yes0 FLOW_INFO=yes TRACE_START=9570000099 +make run DBUS=SIMPLE IBUS=SIMPLE SUPERVISOR=yes CSR=yes COMPRESSED=yes REDO=0 DHRYSTONE=no LINUX_SOC=yes EMULATOR=/home/spinalvm/hdl/VexRiscv/src/main/c/emulator/build/emulator.bin VMLINUX=/home/spinalvm/hdl/riscv-linux/vmlinux.bin DTB=/home/spinalvm/hdl/riscv-linux/rv32.dtb RAMDISK=/home/spinalvm/hdl/linuxDave/initramdisk_dave TRACE=yes0 FLOW_INFO=yes TRACE_START=9570000099 +make run DBUS=SIMPLE IBUS=SIMPLE SUPERVISOR=yes CSR=yes COMPRESSED=yes REDO=0 DHRYSTONE=no LINUX_SOC=yes EMULATOR=/home/spinalvm/hdl/VexRiscv/src/main/c/emulator/build/emulator.bin VMLINUX=/home/spinalvm/hdl/riscv-linux/vmlinux.bin DTB=/home/spinalvm/hdl/riscv-linux/rv32.dtb RAMDISK=/home/spinalvm/hdl/linux/fs/rootfs.ext2 TRACE=yes0 FLOW_INFO=yes TRACE_START=9570000099 make run DBUS=SIMPLE IBUS=SIMPLE SUPERVISOR=yes CSR=yes COMPRESSED=yes REDO=0 DHRYSTONE=no LINUX_SOC=yes EMULATOR=/home/spinalvm/hdl/VexRiscv/src/main/c/emulator/build/emulator.bin VMLINUX=/home/spinalvm/hdl/linux/linux-1c163f4c7b3f621efff9b28a47abb36f7378d783/vmlinux.bin DTB=/home/spinalvm/hdl/linux/linux-1c163f4c7b3f621efff9b28a47abb36f7378d783/rv32.dtb RAMDISK=/home/spinalvm/hdl/linuxDave/initramdisk_dave TRACE=yes0 FLOW_INFO=yes TRACE_START=9570000099 @@ -64,7 +65,9 @@ make run DBUS=SIMPLE IBUS=SIMPLE SUPERVISOR=yes CSR=yes COMPRESSED=yes REDO=0 DH Other commands (Memo): cp litex_default_configuration .config ARCH=riscv CROSS_COMPILE=riscv64-unknown-elf- make -j`nproc`; riscv64-unknown-elf-objcopy -O binary vmlinux vmlinux.bin +ARCH=riscv CROSS_COMPILE=riscv32-unknown-linux-gnu- make -j`nproc`; riscv32-unknown-linux-gnu-objcopy -O binary vmlinux vmlinux.bin riscv64-unknown-elf-objdump -S -d vmlinux > vmlinux.asm; split -b 1M vmlinux.asm +riscv32-unknown-linux-gnu-objdump -S -d vmlinux > vmlinux.asm; split -b 1M vmlinux.asm diff --git a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala index 3dde6dc8..e775767c 100644 --- a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala @@ -276,7 +276,7 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, decoderService.add( key = LR, values = loadActions.filter(_._1 != SRC2_CTRL) ++ Seq( - SRC2_CTRL -> Src2CtrlEnum.RS, + SRC_ADD_ZERO -> True, MEMORY_ATOMIC -> True ) ) @@ -284,6 +284,7 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, decoderService.add( key = SC, values = storeActions.filter(_._1 != SRC2_CTRL) ++ Seq( + SRC_ADD_ZERO -> True, REGFILE_WRITE_VALID -> True, BYPASSABLE_EXECUTE_STAGE -> False, BYPASSABLE_MEMORY_STAGE -> False, @@ -373,7 +374,7 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, val atomic = genAtomic generate new Area{ - val address = input(SRC1).asUInt //TODO could avoid 32 muxes if SRC_ADD can be disabled + val address = input(SRC_ADD).asUInt case class AtomicEntry() extends Bundle{ val valid = Bool() val address = UInt(32 bits) @@ -400,9 +401,6 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, when(input(MEMORY_STORE) && input(MEMORY_ATOMIC) && !input(ATOMIC_HIT)){ skipCmd := True } - when(input(MEMORY_ATOMIC)){ - mmuBus.cmd.virtualAddress := address - } } } diff --git a/src/main/scala/vexriscv/plugin/IntAluPlugin.scala b/src/main/scala/vexriscv/plugin/IntAluPlugin.scala index 1b7467e6..0520c2ff 100644 --- a/src/main/scala/vexriscv/plugin/IntAluPlugin.scala +++ b/src/main/scala/vexriscv/plugin/IntAluPlugin.scala @@ -4,7 +4,7 @@ import vexriscv._ import spinal.core._ object IntAluPlugin{ object AluBitwiseCtrlEnum extends SpinalEnum(binarySequential){ - val XOR, OR, AND, SRC1 = newElement() + val XOR, OR, AND = newElement() } object AluCtrlEnum extends SpinalEnum(binarySequential){ val ADD_SUB, SLT_SLTU, BITWISE = newElement() @@ -70,7 +70,7 @@ class IntAluPlugin extends Plugin[VexRiscv]{ )) decoderService.add(List( - LUI -> (otherAction ++ List(ALU_CTRL -> AluCtrlEnum.BITWISE, ALU_BITWISE_CTRL -> AluBitwiseCtrlEnum.SRC1, SRC1_CTRL -> Src1CtrlEnum.IMU)), + LUI -> (otherAction ++ List(ALU_CTRL -> AluCtrlEnum.ADD_SUB, SRC1_CTRL -> Src1CtrlEnum.IMU, SRC_USE_SUB_LESS -> False, SRC_ADD_ZERO -> True)), AUIPC -> (otherAction ++ List(ALU_CTRL -> AluCtrlEnum.ADD_SUB, SRC_USE_SUB_LESS -> False, SRC1_CTRL -> Src1CtrlEnum.IMU, SRC2_CTRL -> Src2CtrlEnum.PC)) )) } @@ -86,8 +86,7 @@ class IntAluPlugin extends Plugin[VexRiscv]{ val bitwise = input(ALU_BITWISE_CTRL).mux( AluBitwiseCtrlEnum.AND -> (input(SRC1) & input(SRC2)), AluBitwiseCtrlEnum.OR -> (input(SRC1) | input(SRC2)), - AluBitwiseCtrlEnum.XOR -> (input(SRC1) ^ input(SRC2)), - AluBitwiseCtrlEnum.SRC1 -> input(SRC1) + AluBitwiseCtrlEnum.XOR -> (input(SRC1) ^ input(SRC2)) ) // mux results diff --git a/src/main/scala/vexriscv/plugin/ShiftPlugins.scala b/src/main/scala/vexriscv/plugin/ShiftPlugins.scala index 086528df..6fa26d78 100644 --- a/src/main/scala/vexriscv/plugin/ShiftPlugins.scala +++ b/src/main/scala/vexriscv/plugin/ShiftPlugins.scala @@ -105,24 +105,30 @@ class LightShifterPlugin extends Plugin[VexRiscv]{ val immediateActions = List[(Stageable[_ <: BaseType],Any)]( SRC1_CTRL -> Src1CtrlEnum.RS, SRC2_CTRL -> Src2CtrlEnum.IMI, - ALU_CTRL -> AluCtrlEnum.BITWISE, - ALU_BITWISE_CTRL -> AluBitwiseCtrlEnum.SRC1, REGFILE_WRITE_VALID -> True, BYPASSABLE_EXECUTE_STAGE -> True, BYPASSABLE_MEMORY_STAGE -> True, - RS1_USE -> True + RS1_USE -> True, + + //Get SRC1 through the MMU to the RF write path + ALU_CTRL -> AluCtrlEnum.ADD_SUB, + SRC_USE_SUB_LESS -> False, + SRC_ADD_ZERO -> True ) val nonImmediateActions = List[(Stageable[_ <: BaseType],Any)]( SRC1_CTRL -> Src1CtrlEnum.RS, SRC2_CTRL -> Src2CtrlEnum.RS, - ALU_CTRL -> AluCtrlEnum.BITWISE, - ALU_BITWISE_CTRL -> AluBitwiseCtrlEnum.SRC1, REGFILE_WRITE_VALID -> True, BYPASSABLE_EXECUTE_STAGE -> True, BYPASSABLE_MEMORY_STAGE -> True, RS1_USE -> True, - RS2_USE -> True + RS2_USE -> True, + + //Get SRC1 through the MMU to the RF write path + ALU_CTRL -> AluCtrlEnum.ADD_SUB, + SRC_USE_SUB_LESS -> False, + SRC_ADD_ZERO -> True ) val decoderService = pipeline.service(classOf[DecoderService]) diff --git a/src/main/scala/vexriscv/plugin/SrcPlugin.scala b/src/main/scala/vexriscv/plugin/SrcPlugin.scala index 395c0a73..79bc763b 100644 --- a/src/main/scala/vexriscv/plugin/SrcPlugin.scala +++ b/src/main/scala/vexriscv/plugin/SrcPlugin.scala @@ -1,13 +1,26 @@ package vexriscv.plugin -import vexriscv.{RVC_GEN, Riscv, VexRiscv} +import vexriscv._ import spinal.core._ class SrcPlugin(separatedAddSub : Boolean = false, executeInsertion : Boolean = false, decodeAddSub : Boolean = false) extends Plugin[VexRiscv]{ + object SRC2_FORCE_ZERO extends Stageable(Bool) + + + override def setup(pipeline: VexRiscv): Unit = { + import pipeline.config._ + + val decoderService = pipeline.service(classOf[DecoderService]) + decoderService.addDefault(SRC_ADD_ZERO, False) //TODO avoid this default to simplify decoding ? + } + override def build(pipeline: VexRiscv): Unit = { import pipeline._ import pipeline.config._ + + decode.insert(SRC2_FORCE_ZERO) := decode.input(SRC_ADD_ZERO) && !decode.input(SRC_USE_SUB_LESS) + val insertionStage = if(executeInsertion) execute else decode insertionStage plug new Area{ import insertionStage._ @@ -33,8 +46,9 @@ class SrcPlugin(separatedAddSub : Boolean = false, executeInsertion : Boolean = import addSubStage._ // ADD, SUB - val add = (input(SRC1).asUInt + input(SRC2).asUInt).asBits.addAttribute("keep") - val sub = (input(SRC1).asUInt - input(SRC2).asUInt).asBits.addAttribute("keep") + val add = (U(input(SRC1)) + U(input(SRC2))).asBits.addAttribute("keep") + val sub = (U(input(SRC1)) - U(input(SRC2))).asBits.addAttribute("keep") + when(input(SRC_ADD_ZERO)){ add := input(SRC1) } // SLT, SLTU val less = Mux(input(SRC1).msb === input(SRC2).msb, sub.msb, @@ -51,6 +65,8 @@ class SrcPlugin(separatedAddSub : Boolean = false, executeInsertion : Boolean = // ADD, SUB val addSub = (input(SRC1).asSInt + Mux(input(SRC_USE_SUB_LESS), ~input(SRC2), input(SRC2)).asSInt + Mux(input(SRC_USE_SUB_LESS), S(1), S(0))).asBits + when(input(SRC2_FORCE_ZERO)){ addSub := input(SRC1) } + // SLT, SLTU val less = Mux(input(SRC1).msb === input(SRC2).msb, addSub.msb, From ac061111634ec9478950b75b3dc03417f30cd5b3 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 27 Mar 2019 22:58:30 +0100 Subject: [PATCH 083/951] Fix MMU MPRV, Fix emulator nested exception --- src/main/c/emulator/build/emulator.asm | 955 +++++++++--------- src/main/c/emulator/build/emulator.hex | 256 ++--- src/main/c/emulator/src/main.c | 12 +- src/main/c/emulator/src/trap.S | 2 - .../scala/vexriscv/plugin/MmuPlugin.scala | 2 +- src/test/cpp/regression/main.cpp | 5 +- 6 files changed, 624 insertions(+), 608 deletions(-) diff --git a/src/main/c/emulator/build/emulator.asm b/src/main/c/emulator/build/emulator.asm index aba0bdf4..e2dcdda9 100644 --- a/src/main/c/emulator/build/emulator.asm +++ b/src/main/c/emulator/build/emulator.asm @@ -6,13 +6,13 @@ Disassembly of section .init: 80000000 <_start>: 80000000: 00001117 auipc sp,0x1 -80000004: 00010113 mv sp,sp +80000004: 03010113 addi sp,sp,48 # 80001030 <_sp> 80000008: 00000517 auipc a0,0x0 -8000000c: 78450513 addi a0,a0,1924 # 8000078c <__init_array_end> +8000000c: 7b050513 addi a0,a0,1968 # 800007b8 <__init_array_end> 80000010: 00000597 auipc a1,0x0 -80000014: 77c58593 addi a1,a1,1916 # 8000078c <__init_array_end> -80000018: 00000617 auipc a2,0x0 -8000001c: 7e860613 addi a2,a2,2024 # 80000800 <__bss_start> +80000014: 7a858593 addi a1,a1,1960 # 800007b8 <__init_array_end> +80000018: 00001617 auipc a2,0x1 +8000001c: 81860613 addi a2,a2,-2024 # 80000830 <__bss_start> 80000020: 00c5fc63 bleu a2,a1,80000038 <_start+0x38> 80000024: 00052283 lw t0,0(a0) 80000028: 0055a023 sw t0,0(a1) @@ -20,15 +20,15 @@ Disassembly of section .init: 80000030: 00458593 addi a1,a1,4 80000034: fec5e8e3 bltu a1,a2,80000024 <_start+0x24> 80000038: 00000517 auipc a0,0x0 -8000003c: 7c850513 addi a0,a0,1992 # 80000800 <__bss_start> +8000003c: 7f850513 addi a0,a0,2040 # 80000830 <__bss_start> 80000040: 00000597 auipc a1,0x0 -80000044: 7c058593 addi a1,a1,1984 # 80000800 <__bss_start> +80000044: 7f058593 addi a1,a1,2032 # 80000830 <__bss_start> 80000048: 00b57863 bleu a1,a0,80000058 <_start+0x58> 8000004c: 00052023 sw zero,0(a0) 80000050: 00450513 addi a0,a0,4 80000054: feb56ce3 bltu a0,a1,8000004c <_start+0x4c> -80000058: 69c000ef jal ra,800006f4 <__libc_init_array> -8000005c: 128000ef jal ra,80000184 +80000058: 6c8000ef jal ra,80000720 <__libc_init_array> +8000005c: 120000ef jal ra,8000017c 80000060: 00000097 auipc ra,0x0 80000064: 01408093 addi ra,ra,20 # 80000074 80000068: 00000513 li a0,0 @@ -43,484 +43,495 @@ Disassembly of section .init: 8000007c : 8000007c: 34011173 csrrw sp,mscratch,sp -80000080: 00012023 sw zero,0(sp) # 80001000 <_sp> -80000084: 00112223 sw ra,4(sp) -80000088: 00312623 sw gp,12(sp) -8000008c: 00412823 sw tp,16(sp) -80000090: 00512a23 sw t0,20(sp) -80000094: 00612c23 sw t1,24(sp) -80000098: 00712e23 sw t2,28(sp) -8000009c: 02812023 sw s0,32(sp) -800000a0: 02912223 sw s1,36(sp) -800000a4: 02a12423 sw a0,40(sp) -800000a8: 02b12623 sw a1,44(sp) -800000ac: 02c12823 sw a2,48(sp) -800000b0: 02d12a23 sw a3,52(sp) -800000b4: 02e12c23 sw a4,56(sp) -800000b8: 02f12e23 sw a5,60(sp) -800000bc: 05012023 sw a6,64(sp) -800000c0: 05112223 sw a7,68(sp) -800000c4: 05212423 sw s2,72(sp) -800000c8: 05312623 sw s3,76(sp) -800000cc: 05412823 sw s4,80(sp) -800000d0: 05512a23 sw s5,84(sp) -800000d4: 05612c23 sw s6,88(sp) -800000d8: 05712e23 sw s7,92(sp) -800000dc: 07812023 sw s8,96(sp) -800000e0: 07912223 sw s9,100(sp) -800000e4: 07a12423 sw s10,104(sp) -800000e8: 07b12623 sw s11,108(sp) -800000ec: 07c12823 sw t3,112(sp) -800000f0: 07d12a23 sw t4,116(sp) -800000f4: 07e12c23 sw t5,120(sp) -800000f8: 07f12e23 sw t6,124(sp) -800000fc: 1ec000ef jal ra,800002e8 -80000100: 00012003 lw zero,0(sp) -80000104: 00412083 lw ra,4(sp) -80000108: 00c12183 lw gp,12(sp) -8000010c: 01012203 lw tp,16(sp) -80000110: 01412283 lw t0,20(sp) -80000114: 01812303 lw t1,24(sp) -80000118: 01c12383 lw t2,28(sp) -8000011c: 02012403 lw s0,32(sp) -80000120: 02412483 lw s1,36(sp) -80000124: 02812503 lw a0,40(sp) -80000128: 02c12583 lw a1,44(sp) -8000012c: 03012603 lw a2,48(sp) -80000130: 03412683 lw a3,52(sp) -80000134: 03812703 lw a4,56(sp) -80000138: 03c12783 lw a5,60(sp) -8000013c: 04012803 lw a6,64(sp) -80000140: 04412883 lw a7,68(sp) -80000144: 04812903 lw s2,72(sp) -80000148: 04c12983 lw s3,76(sp) -8000014c: 05012a03 lw s4,80(sp) -80000150: 05412a83 lw s5,84(sp) -80000154: 05812b03 lw s6,88(sp) -80000158: 05c12b83 lw s7,92(sp) -8000015c: 06012c03 lw s8,96(sp) -80000160: 06412c83 lw s9,100(sp) -80000164: 06812d03 lw s10,104(sp) -80000168: 06c12d83 lw s11,108(sp) -8000016c: 07012e03 lw t3,112(sp) -80000170: 07412e83 lw t4,116(sp) -80000174: 07812f03 lw t5,120(sp) -80000178: 07c12f83 lw t6,124(sp) -8000017c: 34011173 csrrw sp,mscratch,sp -80000180: 30200073 mret +80000080: 00112223 sw ra,4(sp) +80000084: 00312623 sw gp,12(sp) +80000088: 00412823 sw tp,16(sp) +8000008c: 00512a23 sw t0,20(sp) +80000090: 00612c23 sw t1,24(sp) +80000094: 00712e23 sw t2,28(sp) +80000098: 02812023 sw s0,32(sp) +8000009c: 02912223 sw s1,36(sp) +800000a0: 02a12423 sw a0,40(sp) +800000a4: 02b12623 sw a1,44(sp) +800000a8: 02c12823 sw a2,48(sp) +800000ac: 02d12a23 sw a3,52(sp) +800000b0: 02e12c23 sw a4,56(sp) +800000b4: 02f12e23 sw a5,60(sp) +800000b8: 05012023 sw a6,64(sp) +800000bc: 05112223 sw a7,68(sp) +800000c0: 05212423 sw s2,72(sp) +800000c4: 05312623 sw s3,76(sp) +800000c8: 05412823 sw s4,80(sp) +800000cc: 05512a23 sw s5,84(sp) +800000d0: 05612c23 sw s6,88(sp) +800000d4: 05712e23 sw s7,92(sp) +800000d8: 07812023 sw s8,96(sp) +800000dc: 07912223 sw s9,100(sp) +800000e0: 07a12423 sw s10,104(sp) +800000e4: 07b12623 sw s11,108(sp) +800000e8: 07c12823 sw t3,112(sp) +800000ec: 07d12a23 sw t4,116(sp) +800000f0: 07e12c23 sw t5,120(sp) +800000f4: 07f12e23 sw t6,124(sp) +800000f8: 1f4000ef jal ra,800002ec +800000fc: 00412083 lw ra,4(sp) +80000100: 00c12183 lw gp,12(sp) +80000104: 01012203 lw tp,16(sp) +80000108: 01412283 lw t0,20(sp) +8000010c: 01812303 lw t1,24(sp) +80000110: 01c12383 lw t2,28(sp) +80000114: 02012403 lw s0,32(sp) +80000118: 02412483 lw s1,36(sp) +8000011c: 02812503 lw a0,40(sp) +80000120: 02c12583 lw a1,44(sp) +80000124: 03012603 lw a2,48(sp) +80000128: 03412683 lw a3,52(sp) +8000012c: 03812703 lw a4,56(sp) +80000130: 03c12783 lw a5,60(sp) +80000134: 04012803 lw a6,64(sp) +80000138: 04412883 lw a7,68(sp) +8000013c: 04812903 lw s2,72(sp) +80000140: 04c12983 lw s3,76(sp) +80000144: 05012a03 lw s4,80(sp) +80000148: 05412a83 lw s5,84(sp) +8000014c: 05812b03 lw s6,88(sp) +80000150: 05c12b83 lw s7,92(sp) +80000154: 06012c03 lw s8,96(sp) +80000158: 06412c83 lw s9,100(sp) +8000015c: 06812d03 lw s10,104(sp) +80000160: 06c12d83 lw s11,108(sp) +80000164: 07012e03 lw t3,112(sp) +80000168: 07412e83 lw t4,116(sp) +8000016c: 07812f03 lw t5,120(sp) +80000170: 07c12f83 lw t6,124(sp) +80000174: 34011173 csrrw sp,mscratch,sp +80000178: 30200073 mret Disassembly of section .text: -80000184 : -80000184: 800007b7 lui a5,0x80000 -80000188: 07c78793 addi a5,a5,124 # 8000007c <_sp+0xfffff07c> -8000018c: 30579073 csrw mtvec,a5 -80000190: 800017b7 lui a5,0x80001 -80000194: f8078793 addi a5,a5,-128 # 80000f80 <_sp+0xffffff80> -80000198: 34079073 csrw mscratch,a5 -8000019c: 000017b7 lui a5,0x1 -800001a0: 88078793 addi a5,a5,-1920 # 880 <__stack_size+0x80> -800001a4: 30079073 csrw mstatus,a5 -800001a8: 30405073 csrwi mie,0 -800001ac: c00007b7 lui a5,0xc0000 -800001b0: 34179073 csrw mepc,a5 -800001b4: 0000b7b7 lui a5,0xb -800001b8: 10078793 addi a5,a5,256 # b100 <__stack_size+0xa900> -800001bc: 30279073 csrw medeleg,a5 -800001c0: 02000793 li a5,32 -800001c4: 30379073 csrw mideleg,a5 -800001c8: 14305073 csrwi sbadaddr,0 -800001cc: 00008067 ret +8000017c : +8000017c: 800007b7 lui a5,0x80000 +80000180: 07c78793 addi a5,a5,124 # 8000007c <_sp+0xfffff04c> +80000184: 30579073 csrw mtvec,a5 +80000188: 800017b7 lui a5,0x80001 +8000018c: fb078793 addi a5,a5,-80 # 80000fb0 <_sp+0xffffff80> +80000190: 34079073 csrw mscratch,a5 +80000194: 000017b7 lui a5,0x1 +80000198: 88078793 addi a5,a5,-1920 # 880 <__stack_size+0x80> +8000019c: 30079073 csrw mstatus,a5 +800001a0: 30405073 csrwi mie,0 +800001a4: c00007b7 lui a5,0xc0000 +800001a8: 34179073 csrw mepc,a5 +800001ac: 0000b7b7 lui a5,0xb +800001b0: 10078793 addi a5,a5,256 # b100 <__stack_size+0xa900> +800001b4: 30279073 csrw medeleg,a5 +800001b8: 02000793 li a5,32 +800001bc: 30379073 csrw mideleg,a5 +800001c0: 14305073 csrwi sbadaddr,0 +800001c4: 00008067 ret -800001d0 : -800001d0: 800017b7 lui a5,0x80001 -800001d4: f8078793 addi a5,a5,-128 # 80000f80 <_sp+0xffffff80> -800001d8: 00251513 slli a0,a0,0x2 -800001dc: 00f50533 add a0,a0,a5 -800001e0: 00052503 lw a0,0(a0) -800001e4: 00008067 ret +800001c8 : +800001c8: 800017b7 lui a5,0x80001 +800001cc: fb078793 addi a5,a5,-80 # 80000fb0 <_sp+0xffffff80> +800001d0: 00251513 slli a0,a0,0x2 +800001d4: 00f50533 add a0,a0,a5 +800001d8: 00052503 lw a0,0(a0) +800001dc: 00008067 ret -800001e8 : -800001e8: 800017b7 lui a5,0x80001 -800001ec: 00251513 slli a0,a0,0x2 -800001f0: f8078793 addi a5,a5,-128 # 80000f80 <_sp+0xffffff80> -800001f4: 00f50533 add a0,a0,a5 -800001f8: 00b52023 sw a1,0(a0) -800001fc: 00008067 ret +800001e0 : +800001e0: 800017b7 lui a5,0x80001 +800001e4: 00251513 slli a0,a0,0x2 +800001e8: fb078793 addi a5,a5,-80 # 80000fb0 <_sp+0xffffff80> +800001ec: 00f50533 add a0,a0,a5 +800001f0: 00b52023 sw a1,0(a0) +800001f4: 00008067 ret -80000200 : -80000200: ff010113 addi sp,sp,-16 -80000204: 00112623 sw ra,12(sp) -80000208: 4b4000ef jal ra,800006bc -8000020c: 343027f3 csrr a5,mbadaddr -80000210: 14379073 csrw sbadaddr,a5 -80000214: 341027f3 csrr a5,mepc -80000218: 14179073 csrw sepc,a5 -8000021c: 342027f3 csrr a5,mcause -80000220: 14279073 csrw scause,a5 -80000224: 105027f3 csrr a5,stvec -80000228: 34179073 csrw mepc,a5 -8000022c: 00c12083 lw ra,12(sp) -80000230: 01010113 addi sp,sp,16 -80000234: 00008067 ret +800001f8 : +800001f8: ff010113 addi sp,sp,-16 +800001fc: 00112623 sw ra,12(sp) +80000200: 4e8000ef jal ra,800006e8 +80000204: 343027f3 csrr a5,mbadaddr +80000208: 14379073 csrw sbadaddr,a5 +8000020c: 341027f3 csrr a5,mepc +80000210: 14179073 csrw sepc,a5 +80000214: 342027f3 csrr a5,mcause +80000218: 14279073 csrw scause,a5 +8000021c: 105027f3 csrr a5,stvec +80000220: 34179073 csrw mepc,a5 +80000224: 00c12083 lw ra,12(sp) +80000228: 01010113 addi sp,sp,16 +8000022c: 00008067 ret -80000238 : -80000238: 343027f3 csrr a5,mbadaddr -8000023c: 14379073 csrw sbadaddr,a5 -80000240: 342027f3 csrr a5,mcause -80000244: 14279073 csrw scause,a5 -80000248: 14151073 csrw sepc,a0 -8000024c: 105027f3 csrr a5,stvec -80000250: 34179073 csrw mepc,a5 -80000254: 10000793 li a5,256 -80000258: 1007b073 csrc sstatus,a5 -8000025c: 0035d593 srli a1,a1,0x3 -80000260: 1005f593 andi a1,a1,256 -80000264: 1005a073 csrs sstatus,a1 -80000268: 000027b7 lui a5,0x2 -8000026c: 80078793 addi a5,a5,-2048 # 1800 <__stack_size+0x1000> -80000270: 3007b073 csrc mstatus,a5 -80000274: 000087b7 lui a5,0x8 -80000278: 08078793 addi a5,a5,128 # 8080 <__stack_size+0x7880> -8000027c: 3007a073 csrs mstatus,a5 -80000280: 00008067 ret +80000230 : +80000230: 800007b7 lui a5,0x80000 +80000234: 07c78793 addi a5,a5,124 # 8000007c <_sp+0xfffff04c> +80000238: 30579073 csrw mtvec,a5 +8000023c: 343027f3 csrr a5,mbadaddr +80000240: 14379073 csrw sbadaddr,a5 +80000244: 342027f3 csrr a5,mcause +80000248: 14279073 csrw scause,a5 +8000024c: 14151073 csrw sepc,a0 +80000250: 105027f3 csrr a5,stvec +80000254: 34179073 csrw mepc,a5 +80000258: 10000793 li a5,256 +8000025c: 1007b073 csrc sstatus,a5 +80000260: 0035d593 srli a1,a1,0x3 +80000264: 1005f593 andi a1,a1,256 +80000268: 1005a073 csrs sstatus,a1 +8000026c: 000027b7 lui a5,0x2 +80000270: 80078793 addi a5,a5,-2048 # 1800 <__stack_size+0x1000> +80000274: 3007b073 csrc mstatus,a5 +80000278: 000087b7 lui a5,0x8 +8000027c: 08078793 addi a5,a5,128 # 8080 <__stack_size+0x7880> +80000280: 3007a073 csrs mstatus,a5 +80000284: 00008067 ret -80000284 : -80000284: 00020737 lui a4,0x20 -80000288: 30072073 csrs mstatus,a4 -8000028c: 00000717 auipc a4,0x0 -80000290: 01870713 addi a4,a4,24 # 800002a4 -80000294: 34171073 csrw mepc,a4 -80000298: 00100693 li a3,1 -8000029c: 00052783 lw a5,0(a0) -800002a0: 00000693 li a3,0 -800002a4: 00020737 lui a4,0x20 -800002a8: 30073073 csrc mstatus,a4 -800002ac: 00068513 mv a0,a3 -800002b0: 00f5a023 sw a5,0(a1) # 81000000 <_sp+0xfff000> -800002b4: 00008067 ret +80000288 : +80000288: 00020737 lui a4,0x20 +8000028c: 30072073 csrs mstatus,a4 +80000290: 00000717 auipc a4,0x0 +80000294: 01870713 addi a4,a4,24 # 800002a8 +80000298: 30571073 csrw mtvec,a4 +8000029c: 00100693 li a3,1 +800002a0: 00052783 lw a5,0(a0) +800002a4: 00000693 li a3,0 +800002a8: 00020737 lui a4,0x20 +800002ac: 30073073 csrc mstatus,a4 +800002b0: 00068513 mv a0,a3 +800002b4: 00f5a023 sw a5,0(a1) # 81000000 <_sp+0xffefd0> +800002b8: 00008067 ret -800002b8 : -800002b8: 00020737 lui a4,0x20 -800002bc: 30072073 csrs mstatus,a4 -800002c0: 00000717 auipc a4,0x0 -800002c4: 01870713 addi a4,a4,24 # 800002d8 -800002c8: 34171073 csrw mepc,a4 -800002cc: 00100793 li a5,1 -800002d0: 00b52023 sw a1,0(a0) -800002d4: 00000793 li a5,0 -800002d8: 00020737 lui a4,0x20 -800002dc: 30073073 csrc mstatus,a4 -800002e0: 00078513 mv a0,a5 -800002e4: 00008067 ret +800002bc : +800002bc: 00020737 lui a4,0x20 +800002c0: 30072073 csrs mstatus,a4 +800002c4: 00000717 auipc a4,0x0 +800002c8: 01870713 addi a4,a4,24 # 800002dc +800002cc: 30571073 csrw mtvec,a4 +800002d0: 00100793 li a5,1 +800002d4: 00b52023 sw a1,0(a0) +800002d8: 00000793 li a5,0 +800002dc: 00020737 lui a4,0x20 +800002e0: 30073073 csrc mstatus,a4 +800002e4: 00078513 mv a0,a5 +800002e8: 00008067 ret -800002e8 : -800002e8: fe010113 addi sp,sp,-32 -800002ec: 00112e23 sw ra,28(sp) -800002f0: 00812c23 sw s0,24(sp) -800002f4: 00912a23 sw s1,20(sp) -800002f8: 01212823 sw s2,16(sp) -800002fc: 01312623 sw s3,12(sp) -80000300: 342027f3 csrr a5,mcause -80000304: 1407ce63 bltz a5,80000460 -80000308: 00200713 li a4,2 -8000030c: 04e78463 beq a5,a4,80000354 -80000310: 00900693 li a3,9 -80000314: 10d79663 bne a5,a3,80000420 -80000318: 800017b7 lui a5,0x80001 -8000031c: 00078793 mv a5,a5 -80000320: fc47a683 lw a3,-60(a5) # 80000fc4 <_sp+0xffffffc4> -80000324: 00100613 li a2,1 -80000328: fa87a503 lw a0,-88(a5) -8000032c: 1ec68663 beq a3,a2,80000518 -80000330: 22e68463 beq a3,a4,80000558 -80000334: 1e068e63 beqz a3,80000530 -80000338: 01812403 lw s0,24(sp) -8000033c: 01c12083 lw ra,28(sp) -80000340: 01412483 lw s1,20(sp) -80000344: 01012903 lw s2,16(sp) -80000348: 00c12983 lw s3,12(sp) -8000034c: 02010113 addi sp,sp,32 -80000350: 36c0006f j 800006bc -80000354: 341024f3 csrr s1,mepc -80000358: 300025f3 csrr a1,mstatus -8000035c: 34302473 csrr s0,mbadaddr -80000360: 02f00613 li a2,47 -80000364: 07f47693 andi a3,s0,127 -80000368: 00c45713 srli a4,s0,0xc -8000036c: 12c68663 beq a3,a2,80000498 -80000370: 07300613 li a2,115 -80000374: 0ac69663 bne a3,a2,80000420 -80000378: 00377713 andi a4,a4,3 -8000037c: 24f70063 beq a4,a5,800005bc -80000380: 00300793 li a5,3 -80000384: 22f70c63 beq a4,a5,800005bc -80000388: 00100993 li s3,1 -8000038c: 03370463 beq a4,s3,800003b4 -80000390: 32c000ef jal ra,800006bc -80000394: 343027f3 csrr a5,mbadaddr -80000398: 14379073 csrw sbadaddr,a5 -8000039c: 341027f3 csrr a5,mepc -800003a0: 14179073 csrw sepc,a5 -800003a4: 342027f3 csrr a5,mcause -800003a8: 14279073 csrw scause,a5 -800003ac: 105027f3 csrr a5,stvec -800003b0: 34179073 csrw mepc,a5 -800003b4: 000017b7 lui a5,0x1 -800003b8: 01445713 srli a4,s0,0x14 -800003bc: c0178693 addi a3,a5,-1023 # c01 <__stack_size+0x401> -800003c0: 2ed70863 beq a4,a3,800006b0 -800003c4: c8178793 addi a5,a5,-895 -800003c8: 2cf71063 bne a4,a5,80000688 -800003cc: 308000ef jal ra,800006d4 -800003d0: 00050913 mv s2,a0 -800003d4: 02098463 beqz s3,800003fc -800003d8: 2e4000ef jal ra,800006bc -800003dc: 343027f3 csrr a5,mbadaddr -800003e0: 14379073 csrw sbadaddr,a5 -800003e4: 341027f3 csrr a5,mepc -800003e8: 14179073 csrw sepc,a5 -800003ec: 342027f3 csrr a5,mcause -800003f0: 14279073 csrw scause,a5 -800003f4: 105027f3 csrr a5,stvec -800003f8: 34179073 csrw mepc,a5 -800003fc: 00545413 srli s0,s0,0x5 -80000400: 800017b7 lui a5,0x80001 -80000404: 07c47413 andi s0,s0,124 -80000408: f8078793 addi a5,a5,-128 # 80000f80 <_sp+0xffffff80> -8000040c: 00f40433 add s0,s0,a5 -80000410: 01242023 sw s2,0(s0) -80000414: 00448493 addi s1,s1,4 -80000418: 34149073 csrw mepc,s1 -8000041c: 0280006f j 80000444 -80000420: 29c000ef jal ra,800006bc -80000424: 343027f3 csrr a5,mbadaddr -80000428: 14379073 csrw sbadaddr,a5 -8000042c: 341027f3 csrr a5,mepc -80000430: 14179073 csrw sepc,a5 -80000434: 342027f3 csrr a5,mcause -80000438: 14279073 csrw scause,a5 -8000043c: 105027f3 csrr a5,stvec -80000440: 34179073 csrw mepc,a5 -80000444: 01c12083 lw ra,28(sp) -80000448: 01812403 lw s0,24(sp) -8000044c: 01412483 lw s1,20(sp) -80000450: 01012903 lw s2,16(sp) -80000454: 00c12983 lw s3,12(sp) -80000458: 02010113 addi sp,sp,32 -8000045c: 00008067 ret -80000460: 0ff7f793 andi a5,a5,255 -80000464: 00700713 li a4,7 -80000468: fae79ce3 bne a5,a4,80000420 -8000046c: 02000793 li a5,32 -80000470: 1447a073 csrs sip,a5 -80000474: 08000793 li a5,128 -80000478: 3047b073 csrc mie,a5 -8000047c: 01c12083 lw ra,28(sp) -80000480: 01812403 lw s0,24(sp) -80000484: 01412483 lw s1,20(sp) -80000488: 01012903 lw s2,16(sp) -8000048c: 00c12983 lw s3,12(sp) -80000490: 02010113 addi sp,sp,32 -80000494: 00008067 ret -80000498: 00777713 andi a4,a4,7 -8000049c: f8f712e3 bne a4,a5,80000420 -800004a0: 00d45713 srli a4,s0,0xd -800004a4: 01245793 srli a5,s0,0x12 -800004a8: 800016b7 lui a3,0x80001 -800004ac: f8068693 addi a3,a3,-128 # 80000f80 <_sp+0xffffff80> -800004b0: 07c77713 andi a4,a4,124 -800004b4: 07c7f793 andi a5,a5,124 -800004b8: 00d70733 add a4,a4,a3 -800004bc: 00d787b3 add a5,a5,a3 -800004c0: 00072703 lw a4,0(a4) # 20000 <__stack_size+0x1f800> -800004c4: 0007a603 lw a2,0(a5) -800004c8: 00020537 lui a0,0x20 -800004cc: 30052073 csrs mstatus,a0 -800004d0: 00000517 auipc a0,0x0 -800004d4: 01850513 addi a0,a0,24 # 800004e8 -800004d8: 34151073 csrw mepc,a0 -800004dc: 00100793 li a5,1 -800004e0: 00072803 lw a6,0(a4) -800004e4: 00000793 li a5,0 -800004e8: 00020537 lui a0,0x20 -800004ec: 30053073 csrc mstatus,a0 -800004f0: 08079063 bnez a5,80000570 -800004f4: 01b45793 srli a5,s0,0x1b -800004f8: 01c00513 li a0,28 -800004fc: f2f562e3 bltu a0,a5,80000420 -80000500: 80000537 lui a0,0x80000 -80000504: 00279793 slli a5,a5,0x2 -80000508: 78c50513 addi a0,a0,1932 # 8000078c <_sp+0xfffff78c> -8000050c: 00a787b3 add a5,a5,a0 -80000510: 0007a783 lw a5,0(a5) -80000514: 00078067 jr a5 -80000518: 0ff57513 andi a0,a0,255 -8000051c: 1a8000ef jal ra,800006c4 -80000520: 341027f3 csrr a5,mepc -80000524: 00478793 addi a5,a5,4 -80000528: 34179073 csrw mepc,a5 -8000052c: f19ff06f j 80000444 -80000530: fac7a583 lw a1,-84(a5) -80000534: 1a8000ef jal ra,800006dc -80000538: 08000793 li a5,128 -8000053c: 3047a073 csrs mie,a5 -80000540: 02000793 li a5,32 -80000544: 1447b073 csrc sip,a5 -80000548: 341027f3 csrr a5,mepc -8000054c: 00478793 addi a5,a5,4 -80000550: 34179073 csrw mepc,a5 -80000554: ef1ff06f j 80000444 -80000558: fff00713 li a4,-1 -8000055c: fae7a423 sw a4,-88(a5) -80000560: 341027f3 csrr a5,mepc -80000564: 00478793 addi a5,a5,4 -80000568: 34179073 csrw mepc,a5 -8000056c: ed9ff06f j 80000444 -80000570: 343027f3 csrr a5,mbadaddr -80000574: 14379073 csrw sbadaddr,a5 -80000578: 342027f3 csrr a5,mcause -8000057c: 14279073 csrw scause,a5 -80000580: 14149073 csrw sepc,s1 -80000584: 105027f3 csrr a5,stvec -80000588: 34179073 csrw mepc,a5 -8000058c: 10000793 li a5,256 -80000590: 1007b073 csrc sstatus,a5 -80000594: 0035d593 srli a1,a1,0x3 -80000598: 1005f593 andi a1,a1,256 -8000059c: 1005a073 csrs sstatus,a1 -800005a0: 000027b7 lui a5,0x2 -800005a4: 80078793 addi a5,a5,-2048 # 1800 <__stack_size+0x1000> -800005a8: 3007b073 csrc mstatus,a5 -800005ac: 000087b7 lui a5,0x8 -800005b0: 08078793 addi a5,a5,128 # 8080 <__stack_size+0x7880> -800005b4: 3007a073 csrs mstatus,a5 -800005b8: e8dff06f j 80000444 -800005bc: 00f45993 srli s3,s0,0xf -800005c0: 01f9f993 andi s3,s3,31 -800005c4: 013039b3 snez s3,s3 -800005c8: dedff06f j 800003b4 -800005cc: 01060633 add a2,a2,a6 -800005d0: 00545413 srli s0,s0,0x5 -800005d4: 07c47413 andi s0,s0,124 -800005d8: 00d406b3 add a3,s0,a3 -800005dc: 0106a023 sw a6,0(a3) -800005e0: 000206b7 lui a3,0x20 -800005e4: 3006a073 csrs mstatus,a3 -800005e8: 00000697 auipc a3,0x0 -800005ec: 01868693 addi a3,a3,24 # 80000600 -800005f0: 34169073 csrw mepc,a3 -800005f4: 00100793 li a5,1 -800005f8: 00c72023 sw a2,0(a4) -800005fc: 00000793 li a5,0 -80000600: 000206b7 lui a3,0x20 -80000604: 3006b073 csrc mstatus,a3 -80000608: e00786e3 beqz a5,80000414 -8000060c: 343027f3 csrr a5,mbadaddr -80000610: 14379073 csrw sbadaddr,a5 -80000614: 342027f3 csrr a5,mcause -80000618: 14279073 csrw scause,a5 -8000061c: 14149073 csrw sepc,s1 -80000620: 105027f3 csrr a5,stvec -80000624: 34179073 csrw mepc,a5 -80000628: 10000793 li a5,256 -8000062c: 1007b073 csrc sstatus,a5 -80000630: 0035d793 srli a5,a1,0x3 -80000634: 1007f793 andi a5,a5,256 -80000638: 1007a073 csrs sstatus,a5 -8000063c: f65ff06f j 800005a0 -80000640: f90678e3 bleu a6,a2,800005d0 -80000644: 00080613 mv a2,a6 -80000648: f89ff06f j 800005d0 -8000064c: 01066633 or a2,a2,a6 -80000650: f81ff06f j 800005d0 -80000654: 01064633 xor a2,a2,a6 -80000658: f79ff06f j 800005d0 -8000065c: f6c87ae3 bleu a2,a6,800005d0 +800002ec : +800002ec: fe010113 addi sp,sp,-32 +800002f0: 00112e23 sw ra,28(sp) +800002f4: 00812c23 sw s0,24(sp) +800002f8: 00912a23 sw s1,20(sp) +800002fc: 01212823 sw s2,16(sp) +80000300: 01312623 sw s3,12(sp) +80000304: 342027f3 csrr a5,mcause +80000308: 1407ce63 bltz a5,80000464 +8000030c: 00200713 li a4,2 +80000310: 04e78463 beq a5,a4,80000358 +80000314: 00900693 li a3,9 +80000318: 10d79663 bne a5,a3,80000424 +8000031c: 800017b7 lui a5,0x80001 +80000320: 03078793 addi a5,a5,48 # 80001030 <_sp+0x0> +80000324: fc47a683 lw a3,-60(a5) +80000328: 00100613 li a2,1 +8000032c: fa87a503 lw a0,-88(a5) +80000330: 1ec68663 beq a3,a2,8000051c +80000334: 22e68463 beq a3,a4,8000055c +80000338: 1e068e63 beqz a3,80000534 +8000033c: 01812403 lw s0,24(sp) +80000340: 01c12083 lw ra,28(sp) +80000344: 01412483 lw s1,20(sp) +80000348: 01012903 lw s2,16(sp) +8000034c: 00c12983 lw s3,12(sp) +80000350: 02010113 addi sp,sp,32 +80000354: 3940006f j 800006e8 +80000358: 341024f3 csrr s1,mepc +8000035c: 300025f3 csrr a1,mstatus +80000360: 34302473 csrr s0,mbadaddr +80000364: 02f00613 li a2,47 +80000368: 07f47693 andi a3,s0,127 +8000036c: 00c45713 srli a4,s0,0xc +80000370: 12c68663 beq a3,a2,8000049c +80000374: 07300613 li a2,115 +80000378: 0ac69663 bne a3,a2,80000424 +8000037c: 00377713 andi a4,a4,3 +80000380: 24f70663 beq a4,a5,800005cc +80000384: 00300793 li a5,3 +80000388: 24f70263 beq a4,a5,800005cc +8000038c: 00100993 li s3,1 +80000390: 03370463 beq a4,s3,800003b8 +80000394: 354000ef jal ra,800006e8 +80000398: 343027f3 csrr a5,mbadaddr +8000039c: 14379073 csrw sbadaddr,a5 +800003a0: 341027f3 csrr a5,mepc +800003a4: 14179073 csrw sepc,a5 +800003a8: 342027f3 csrr a5,mcause +800003ac: 14279073 csrw scause,a5 +800003b0: 105027f3 csrr a5,stvec +800003b4: 34179073 csrw mepc,a5 +800003b8: 000017b7 lui a5,0x1 +800003bc: 01445713 srli a4,s0,0x14 +800003c0: c0178693 addi a3,a5,-1023 # c01 <__stack_size+0x401> +800003c4: 30d70463 beq a4,a3,800006cc +800003c8: c8178793 addi a5,a5,-895 +800003cc: 2cf71c63 bne a4,a5,800006a4 +800003d0: 330000ef jal ra,80000700 +800003d4: 00050913 mv s2,a0 +800003d8: 02098463 beqz s3,80000400 +800003dc: 30c000ef jal ra,800006e8 +800003e0: 343027f3 csrr a5,mbadaddr +800003e4: 14379073 csrw sbadaddr,a5 +800003e8: 341027f3 csrr a5,mepc +800003ec: 14179073 csrw sepc,a5 +800003f0: 342027f3 csrr a5,mcause +800003f4: 14279073 csrw scause,a5 +800003f8: 105027f3 csrr a5,stvec +800003fc: 34179073 csrw mepc,a5 +80000400: 00545413 srli s0,s0,0x5 +80000404: 800017b7 lui a5,0x80001 +80000408: fb078793 addi a5,a5,-80 # 80000fb0 <_sp+0xffffff80> +8000040c: 07c47413 andi s0,s0,124 +80000410: 00f40433 add s0,s0,a5 +80000414: 01242023 sw s2,0(s0) +80000418: 00448493 addi s1,s1,4 +8000041c: 34149073 csrw mepc,s1 +80000420: 0280006f j 80000448 +80000424: 2c4000ef jal ra,800006e8 +80000428: 343027f3 csrr a5,mbadaddr +8000042c: 14379073 csrw sbadaddr,a5 +80000430: 341027f3 csrr a5,mepc +80000434: 14179073 csrw sepc,a5 +80000438: 342027f3 csrr a5,mcause +8000043c: 14279073 csrw scause,a5 +80000440: 105027f3 csrr a5,stvec +80000444: 34179073 csrw mepc,a5 +80000448: 01c12083 lw ra,28(sp) +8000044c: 01812403 lw s0,24(sp) +80000450: 01412483 lw s1,20(sp) +80000454: 01012903 lw s2,16(sp) +80000458: 00c12983 lw s3,12(sp) +8000045c: 02010113 addi sp,sp,32 +80000460: 00008067 ret +80000464: 0ff7f793 andi a5,a5,255 +80000468: 00700713 li a4,7 +8000046c: fae79ce3 bne a5,a4,80000424 +80000470: 02000793 li a5,32 +80000474: 1447a073 csrs sip,a5 +80000478: 08000793 li a5,128 +8000047c: 3047b073 csrc mie,a5 +80000480: 01c12083 lw ra,28(sp) +80000484: 01812403 lw s0,24(sp) +80000488: 01412483 lw s1,20(sp) +8000048c: 01012903 lw s2,16(sp) +80000490: 00c12983 lw s3,12(sp) +80000494: 02010113 addi sp,sp,32 +80000498: 00008067 ret +8000049c: 00777713 andi a4,a4,7 +800004a0: f8f712e3 bne a4,a5,80000424 +800004a4: 00d45713 srli a4,s0,0xd +800004a8: 01245793 srli a5,s0,0x12 +800004ac: 800016b7 lui a3,0x80001 +800004b0: fb068693 addi a3,a3,-80 # 80000fb0 <_sp+0xffffff80> +800004b4: 07c77713 andi a4,a4,124 +800004b8: 07c7f793 andi a5,a5,124 +800004bc: 00d70733 add a4,a4,a3 +800004c0: 00d787b3 add a5,a5,a3 +800004c4: 00072703 lw a4,0(a4) # 20000 <__stack_size+0x1f800> +800004c8: 0007a603 lw a2,0(a5) +800004cc: 00020537 lui a0,0x20 +800004d0: 30052073 csrs mstatus,a0 +800004d4: 00000517 auipc a0,0x0 +800004d8: 01850513 addi a0,a0,24 # 800004ec +800004dc: 30551073 csrw mtvec,a0 +800004e0: 00100793 li a5,1 +800004e4: 00072803 lw a6,0(a4) +800004e8: 00000793 li a5,0 +800004ec: 00020537 lui a0,0x20 +800004f0: 30053073 csrc mstatus,a0 +800004f4: 08079063 bnez a5,80000574 +800004f8: 01b45793 srli a5,s0,0x1b +800004fc: 01c00513 li a0,28 +80000500: f2f562e3 bltu a0,a5,80000424 +80000504: 80000537 lui a0,0x80000 +80000508: 00279793 slli a5,a5,0x2 +8000050c: 7b850513 addi a0,a0,1976 # 800007b8 <_sp+0xfffff788> +80000510: 00a787b3 add a5,a5,a0 +80000514: 0007a783 lw a5,0(a5) +80000518: 00078067 jr a5 +8000051c: 0ff57513 andi a0,a0,255 +80000520: 1d0000ef jal ra,800006f0 +80000524: 341027f3 csrr a5,mepc +80000528: 00478793 addi a5,a5,4 +8000052c: 34179073 csrw mepc,a5 +80000530: f19ff06f j 80000448 +80000534: fac7a583 lw a1,-84(a5) +80000538: 1d0000ef jal ra,80000708 +8000053c: 08000793 li a5,128 +80000540: 3047a073 csrs mie,a5 +80000544: 02000793 li a5,32 +80000548: 1447b073 csrc sip,a5 +8000054c: 341027f3 csrr a5,mepc +80000550: 00478793 addi a5,a5,4 +80000554: 34179073 csrw mepc,a5 +80000558: ef1ff06f j 80000448 +8000055c: fff00713 li a4,-1 +80000560: fae7a423 sw a4,-88(a5) +80000564: 341027f3 csrr a5,mepc +80000568: 00478793 addi a5,a5,4 +8000056c: 34179073 csrw mepc,a5 +80000570: ed9ff06f j 80000448 +80000574: 800007b7 lui a5,0x80000 +80000578: 07c78793 addi a5,a5,124 # 8000007c <_sp+0xfffff04c> +8000057c: 30579073 csrw mtvec,a5 +80000580: 343027f3 csrr a5,mbadaddr +80000584: 14379073 csrw sbadaddr,a5 +80000588: 342027f3 csrr a5,mcause +8000058c: 14279073 csrw scause,a5 +80000590: 14149073 csrw sepc,s1 +80000594: 105027f3 csrr a5,stvec +80000598: 34179073 csrw mepc,a5 +8000059c: 10000793 li a5,256 +800005a0: 1007b073 csrc sstatus,a5 +800005a4: 0035d593 srli a1,a1,0x3 +800005a8: 1005f593 andi a1,a1,256 +800005ac: 1005a073 csrs sstatus,a1 +800005b0: 000027b7 lui a5,0x2 +800005b4: 80078793 addi a5,a5,-2048 # 1800 <__stack_size+0x1000> +800005b8: 3007b073 csrc mstatus,a5 +800005bc: 000087b7 lui a5,0x8 +800005c0: 08078793 addi a5,a5,128 # 8080 <__stack_size+0x7880> +800005c4: 3007a073 csrs mstatus,a5 +800005c8: e81ff06f j 80000448 +800005cc: 00f45993 srli s3,s0,0xf +800005d0: 01f9f993 andi s3,s3,31 +800005d4: 013039b3 snez s3,s3 +800005d8: de1ff06f j 800003b8 +800005dc: 01060633 add a2,a2,a6 +800005e0: 00545413 srli s0,s0,0x5 +800005e4: 07c47413 andi s0,s0,124 +800005e8: 00d406b3 add a3,s0,a3 +800005ec: 0106a023 sw a6,0(a3) +800005f0: 000207b7 lui a5,0x20 +800005f4: 3007a073 csrs mstatus,a5 +800005f8: 00000797 auipc a5,0x0 +800005fc: 01878793 addi a5,a5,24 # 80000610 +80000600: 30579073 csrw mtvec,a5 +80000604: 00100693 li a3,1 +80000608: 00c72023 sw a2,0(a4) +8000060c: 00000693 li a3,0 +80000610: 000207b7 lui a5,0x20 +80000614: 3007b073 csrc mstatus,a5 +80000618: 800007b7 lui a5,0x80000 +8000061c: 07c78793 addi a5,a5,124 # 8000007c <_sp+0xfffff04c> +80000620: 0a068c63 beqz a3,800006d8 +80000624: 30579073 csrw mtvec,a5 +80000628: 343027f3 csrr a5,mbadaddr +8000062c: 14379073 csrw sbadaddr,a5 +80000630: 342027f3 csrr a5,mcause +80000634: 14279073 csrw scause,a5 +80000638: 14149073 csrw sepc,s1 +8000063c: 105027f3 csrr a5,stvec +80000640: 34179073 csrw mepc,a5 +80000644: 10000793 li a5,256 +80000648: 1007b073 csrc sstatus,a5 +8000064c: 0035d793 srli a5,a1,0x3 +80000650: 1007f793 andi a5,a5,256 +80000654: 1007a073 csrs sstatus,a5 +80000658: f59ff06f j 800005b0 +8000065c: f90672e3 bleu a6,a2,800005e0 80000660: 00080613 mv a2,a6 -80000664: f6dff06f j 800005d0 -80000668: f70654e3 ble a6,a2,800005d0 +80000664: f7dff06f j 800005e0 +80000668: f6c87ce3 bleu a2,a6,800005e0 8000066c: 00080613 mv a2,a6 -80000670: f61ff06f j 800005d0 -80000674: f4c85ee3 ble a2,a6,800005d0 -80000678: 00080613 mv a2,a6 -8000067c: f55ff06f j 800005d0 -80000680: 01067633 and a2,a2,a6 -80000684: f4dff06f j 800005d0 -80000688: 034000ef jal ra,800006bc -8000068c: 343027f3 csrr a5,mbadaddr -80000690: 14379073 csrw sbadaddr,a5 -80000694: 341027f3 csrr a5,mepc -80000698: 14179073 csrw sepc,a5 -8000069c: 342027f3 csrr a5,mcause -800006a0: 14279073 csrw scause,a5 -800006a4: 105027f3 csrr a5,stvec -800006a8: 34179073 csrw mepc,a5 -800006ac: d29ff06f j 800003d4 -800006b0: 01c000ef jal ra,800006cc -800006b4: 00050913 mv s2,a0 -800006b8: d1dff06f j 800003d4 +80000670: f71ff06f j 800005e0 +80000674: 01066633 or a2,a2,a6 +80000678: f69ff06f j 800005e0 +8000067c: 01064633 xor a2,a2,a6 +80000680: f61ff06f j 800005e0 +80000684: f4c85ee3 ble a2,a6,800005e0 +80000688: 00080613 mv a2,a6 +8000068c: f55ff06f j 800005e0 +80000690: 01067633 and a2,a2,a6 +80000694: f4dff06f j 800005e0 +80000698: f50654e3 ble a6,a2,800005e0 +8000069c: 00080613 mv a2,a6 +800006a0: f41ff06f j 800005e0 +800006a4: 044000ef jal ra,800006e8 +800006a8: 343027f3 csrr a5,mbadaddr +800006ac: 14379073 csrw sbadaddr,a5 +800006b0: 341027f3 csrr a5,mepc +800006b4: 14179073 csrw sepc,a5 +800006b8: 342027f3 csrr a5,mcause +800006bc: 14279073 csrw scause,a5 +800006c0: 105027f3 csrr a5,stvec +800006c4: 34179073 csrw mepc,a5 +800006c8: d11ff06f j 800003d8 +800006cc: 02c000ef jal ra,800006f8 +800006d0: 00050913 mv s2,a0 +800006d4: d05ff06f j 800003d8 +800006d8: 00448493 addi s1,s1,4 +800006dc: 34149073 csrw mepc,s1 +800006e0: 30579073 csrw mtvec,a5 +800006e4: d65ff06f j 80000448 -800006bc : -800006bc: fe002e23 sw zero,-4(zero) # fffffffc <_sp+0x7fffeffc> -800006c0: 00008067 ret +800006e8 : +800006e8: fe002e23 sw zero,-4(zero) # fffffffc <_sp+0x7fffefcc> +800006ec: 00008067 ret -800006c4 : -800006c4: fea02c23 sw a0,-8(zero) # fffffff8 <_sp+0x7fffeff8> -800006c8: 00008067 ret +800006f0 : +800006f0: fea02c23 sw a0,-8(zero) # fffffff8 <_sp+0x7fffefc8> +800006f4: 00008067 ret -800006cc : -800006cc: fe002503 lw a0,-32(zero) # ffffffe0 <_sp+0x7fffefe0> -800006d0: 00008067 ret +800006f8 : +800006f8: fe002503 lw a0,-32(zero) # ffffffe0 <_sp+0x7fffefb0> +800006fc: 00008067 ret -800006d4 : -800006d4: fe402503 lw a0,-28(zero) # ffffffe4 <_sp+0x7fffefe4> -800006d8: 00008067 ret +80000700 : +80000700: fe402503 lw a0,-28(zero) # ffffffe4 <_sp+0x7fffefb4> +80000704: 00008067 ret -800006dc : -800006dc: fec00793 li a5,-20 -800006e0: fff00713 li a4,-1 -800006e4: 00e7a023 sw a4,0(a5) -800006e8: fea02423 sw a0,-24(zero) # ffffffe8 <_sp+0x7fffefe8> -800006ec: 00b7a023 sw a1,0(a5) -800006f0: 00008067 ret +80000708 : +80000708: fec00793 li a5,-20 +8000070c: fff00713 li a4,-1 +80000710: 00e7a023 sw a4,0(a5) +80000714: fea02423 sw a0,-24(zero) # ffffffe8 <_sp+0x7fffefb8> +80000718: 00b7a023 sw a1,0(a5) +8000071c: 00008067 ret -800006f4 <__libc_init_array>: -800006f4: ff010113 addi sp,sp,-16 -800006f8: 00812423 sw s0,8(sp) -800006fc: 00912223 sw s1,4(sp) -80000700: 00000417 auipc s0,0x0 -80000704: 08c40413 addi s0,s0,140 # 8000078c <__init_array_end> -80000708: 00000497 auipc s1,0x0 -8000070c: 08448493 addi s1,s1,132 # 8000078c <__init_array_end> -80000710: 408484b3 sub s1,s1,s0 -80000714: 01212023 sw s2,0(sp) -80000718: 00112623 sw ra,12(sp) -8000071c: 4024d493 srai s1,s1,0x2 -80000720: 00000913 li s2,0 -80000724: 04991063 bne s2,s1,80000764 <__libc_init_array+0x70> -80000728: 00000417 auipc s0,0x0 -8000072c: 06440413 addi s0,s0,100 # 8000078c <__init_array_end> -80000730: 00000497 auipc s1,0x0 -80000734: 05c48493 addi s1,s1,92 # 8000078c <__init_array_end> -80000738: 408484b3 sub s1,s1,s0 -8000073c: 93dff0ef jal ra,80000078 <_init> -80000740: 4024d493 srai s1,s1,0x2 -80000744: 00000913 li s2,0 -80000748: 02991863 bne s2,s1,80000778 <__libc_init_array+0x84> -8000074c: 00c12083 lw ra,12(sp) -80000750: 00812403 lw s0,8(sp) -80000754: 00412483 lw s1,4(sp) -80000758: 00012903 lw s2,0(sp) -8000075c: 01010113 addi sp,sp,16 -80000760: 00008067 ret -80000764: 00042783 lw a5,0(s0) -80000768: 00190913 addi s2,s2,1 -8000076c: 00440413 addi s0,s0,4 -80000770: 000780e7 jalr a5 -80000774: fb1ff06f j 80000724 <__libc_init_array+0x30> -80000778: 00042783 lw a5,0(s0) -8000077c: 00190913 addi s2,s2,1 -80000780: 00440413 addi s0,s0,4 -80000784: 000780e7 jalr a5 -80000788: fc1ff06f j 80000748 <__libc_init_array+0x54> +80000720 <__libc_init_array>: +80000720: ff010113 addi sp,sp,-16 +80000724: 00812423 sw s0,8(sp) +80000728: 00912223 sw s1,4(sp) +8000072c: 00000417 auipc s0,0x0 +80000730: 08c40413 addi s0,s0,140 # 800007b8 <__init_array_end> +80000734: 00000497 auipc s1,0x0 +80000738: 08448493 addi s1,s1,132 # 800007b8 <__init_array_end> +8000073c: 408484b3 sub s1,s1,s0 +80000740: 01212023 sw s2,0(sp) +80000744: 00112623 sw ra,12(sp) +80000748: 4024d493 srai s1,s1,0x2 +8000074c: 00000913 li s2,0 +80000750: 04991063 bne s2,s1,80000790 <__libc_init_array+0x70> +80000754: 00000417 auipc s0,0x0 +80000758: 06440413 addi s0,s0,100 # 800007b8 <__init_array_end> +8000075c: 00000497 auipc s1,0x0 +80000760: 05c48493 addi s1,s1,92 # 800007b8 <__init_array_end> +80000764: 408484b3 sub s1,s1,s0 +80000768: 911ff0ef jal ra,80000078 <_init> +8000076c: 4024d493 srai s1,s1,0x2 +80000770: 00000913 li s2,0 +80000774: 02991863 bne s2,s1,800007a4 <__libc_init_array+0x84> +80000778: 00c12083 lw ra,12(sp) +8000077c: 00812403 lw s0,8(sp) +80000780: 00412483 lw s1,4(sp) +80000784: 00012903 lw s2,0(sp) +80000788: 01010113 addi sp,sp,16 +8000078c: 00008067 ret +80000790: 00042783 lw a5,0(s0) +80000794: 00190913 addi s2,s2,1 +80000798: 00440413 addi s0,s0,4 +8000079c: 000780e7 jalr a5 +800007a0: fb1ff06f j 80000750 <__libc_init_array+0x30> +800007a4: 00042783 lw a5,0(s0) +800007a8: 00190913 addi s2,s2,1 +800007ac: 00440413 addi s0,s0,4 +800007b0: 000780e7 jalr a5 +800007b4: fc1ff06f j 80000774 <__libc_init_array+0x54> diff --git a/src/main/c/emulator/build/emulator.hex b/src/main/c/emulator/build/emulator.hex index 65444a19..99d25eae 100644 --- a/src/main/c/emulator/build/emulator.hex +++ b/src/main/c/emulator/build/emulator.hex @@ -1,133 +1,135 @@ :0200000480007A -:1000000017110000130101001705000013054578C2 -:10001000970500009385C577170600001306867EB6 +:100000001711000013010103170500001305057BFC +:10001000970500009385857A1716000013068681E0 :1000200063FCC5008322050023A05500130545008D -:1000300093854500E3E8C5FE170500001305857CA0 -:10004000970500009385057C6378B50023200500A3 -:1000500013054500E36CB5FEEF00C069EF008012A8 +:1000300093854500E3E8C5FE170500001305857F9D +:10004000970500009385057F6378B50023200500A0 +:1000500013054500E36CB5FEEF00806CEF00001265 :10006000970000009380400113050000B705008150 :10007000730020306F0000006780000073110134AE -:1000800023200100232211002326310023284100D0 -:10009000232A5100232C6100232E7100232081028A -:1000A000232291022324A1022326B1022328C10284 -:1000B000232AD102232CE102232EF1022320010561 -:1000C0002322110523242105232631052328410558 -:1000D000232A5105232C6105232E71052320810736 -:1000E000232291072324A1072326B1072328C10730 -:1000F000232AD107232CE107232EF107EF00C01E8E -:1001000003200100832041008321C100032201015B -:1001100083224101032381018323C10103240102BE -:1001200083244102032581028325C10203260103A2 -:1001300083264103032781038327C1030328010486 -:1001400083284104032981048329C104032A01056A -:10015000832A4105032B8105832BC105032C01064E -:10016000832C4106032D8106832DC106032E010732 -:10017000832E4107032F8107832FC1077311013499 -:0401800073002030B8 -:10018400B70700809387C70773905730B71700806D -:10019400938707F873900734B7170000938707888D -:1001A4007390073073504030B70700C07390173412 -:1001B400B7B70000938707107390273093070002A6 -:1001C400739037307350301467800000B717008085 -:1001D400938707F8131525003305F500032505005B -:1001E40067800000B717008013152500938707F870 -:1001F4003305F5002320B50067800000130101FFDB -:1002040023261100EF00404BF3273034739037144A -:10021400F327103473901714F327203473902714A2 -:10022400F3275010739017348320C1001301010188 -:1002340067800000F327303473903714F327203499 -:100244007390271473101514F327501073901734F8 -:100254009307001073B0071093D5350093F505107C -:1002640073A00510B72700009387078073B0073089 -:10027400B78700009387070873A0073067800000E2 -:1002840037070200732007301707000013078701A0 -:10029400731017349306100083270500930600009B -:1002A40037070200733007301385060023A0F500DA -:1002B400678000003707020073200730170700002B -:1002C4001307870173101734930710002320B50018 -:1002D40093070000370702007330073013850700C7 -:1002E40067800000130101FE232E1100232C8100DE -:1002F400232A91002328210123263101F3272034C6 -:1003040063CE0714130720006384E7049306900068 -:100314006396D710B71700809387070083A647FC1E -:100324001306100003A587FA6386C61E6384E622BB -:10033400638E061E032481018320C10183244101AD -:10034400032901018329C100130101026F00C03692 -:10035400F3241034F3250030732430341306F002F0 -:100364009376F4071357C4006386C6121306300746 -:100374006396C60A137737006300F72493073000A7 -:10038400630CF7229309100063043703EF00C032B3 -:10039400F327303473903714F32710347390171401 -:1003A400F327203473902714F327501073901734D5 -:1003B400B717000013574401938617C06308D72E5C -:1003C400938717C86310F72CEF00803013090500DA -:1003D40063840902EF00402EF327303473903714FE -:1003E400F327103473901714F327203473902714D1 -:1003F400F32750107390173413545400B717008028 -:100404001374C407938707F83304F40023202401EA -:1004140093844400739014346F008002EF00C02969 -:10042400F327303473903714F32710347390171470 -:10043400F327203473902714F32750107390173444 -:100444008320C10103248101832441010329010183 -:100454008329C100130101026780000093F7F70F9D -:1004640013077000E39CE7FA9307000273A0471494 -:100474009307000873B047308320C101032481012E -:1004840083244101032901018329C10013010102CD -:100494006780000013777700E312F7F81357D4004E -:1004A40093572401B7160080938606F81377C7077D -:1004B40093F7C7073307D700B387D700032707008D -:1004C40003A6070037050200732005301705000056 -:1004D40013058501731015349307100003280700D2 -:1004E4009307000037050200733005306390070856 -:1004F4009357B4011305C001E362F5F23705008098 -:10050400939727001305C578B387A70083A707002F -:10051400678007001375F50FEF00801AF327103476 -:1005240093874700739017346FF09FF183A5C7FA40 -:10053400EF00801A9307000873A047309307000266 -:1005440073B04714F327103493874700739017341C -:100554006FF01FEF1307F0FF23A4E7FAF32710341B -:1005640093874700739017346FF09FEDF32730346F -:1005740073903714F3272034739027147390141452 -:10058400F3275010739017349307001073B00710BB -:1005940093D5350093F5051073A00510B727000017 -:1005A4009387078073B00730B787000093870708E5 -:1005B40073A007306FF0DFE89359F40093F9F90161 -:1005C400B33930016FF0DFDE3306060113545400F3 -:1005D4001374C407B306D40023A00601B7060200AF -:1005E40073A0063097060000938686017390163434 -:1005F400930710002320C70093070000B7060200EA -:1006040073B00630E38607E0F32730347390371471 -:10061400F32720347390271473901414F327501085 -:10062400739017349307001073B0071093D73500F5 -:1006340093F7071073A007106FF05FF6E37806F9DD -:10064400130608006FF09FF8336606016FF01FF879 -:10065400334606016FF09FF7E37AC8F613060800E5 -:100664006FF0DFF6E35406F7130608006FF01FF689 -:10067400E35EC8F4130608006FF05FF533760601F5 -:100684006FF0DFF4EF004003F32730347390371436 -:10069400F327103473901714F3272034739027141E -:1006A400F3275010739017346FF09FD2EF00C001FE -:1006B400130905006FF0DFD1232E00FE67800000D0 -:1006C400232CA0FE67800000032500FE6780000045 -:1006D400032540FE678000009307C0FE1307F0FF68 -:1006E40023A0E7002324A0FE23A0B7006780000016 -:1006F400130101FF23248100232291001704000029 -:100704001304C4089704000093844408B384844009 -:10071400232021012326110093D42440130900002F -:10072400631099041704000013044406970400009E -:100734009384C405B3848440EFF0DF9393D42440BE -:1007440013090000631899028320C1000324810067 -:100754008324410003290100130101016780000083 -:10076400832704001309190013044400E7800700D9 -:100774006FF01FFB832704001309190013044400BE -:08078400E78007006FF01FFC85 -:10078C00CC050080D005008020040080200400806F -:10079C005406008020040080200400802004008087 -:1007AC004C0600802004008020040080200400807F -:1007BC00800600802004008020040080200400803B -:1007CC007406008020040080200400802004008037 -:1007DC006806008020040080200400802004008033 -:1007EC005C0600802004008020040080200400802F -:0407FC004006008033 +:10008000232211002326310023284100232A510076 +:10009000232C6100232E7100232081022322910250 +:1000A0002324A1022326B1022328C102232AD1023C +:1000B000232CE102232EF102232001052322110526 +:1000C000232421052326310523284105232A510510 +:1000D000232C6105232E71052320810723229107FC +:1000E0002324A1072326B1072328C107232AD107E8 +:1000F000232CE107232EF107EF00401F832041004E +:100100008321C100032201018322410103238101D4 +:100110008323C101032401028324410203258102B8 +:100120008325C1020326010383264103032781039C +:100130008327C10303280104832841040329810480 +:100140008329C104032A0105832A4105032B810564 +:10015000832BC105032C0106832C4106032D810648 +:10016000832DC106032E0107832E4107032F81072C +:0C017000832FC10773110134730020308D +:10017C00B70700809387C70773905730B717008075 +:10018C00938707FB73900734B71700009387078892 +:10019C007390073073504030B70700C0739017341A +:1001AC00B7B70000938707107390273093070002AE +:1001BC00739037307350301467800000B71700808D +:1001CC00938707FB131525003305F5000325050060 +:1001DC0067800000B717008013152500938707FB75 +:1001EC003305F5002320B50067800000130101FFE3 +:1001FC0023261100EF00804EF32730347390371410 +:10020C00F327103473901714F327203473902714AA +:10021C00F3275010739017348320C1001301010190 +:10022C0067800000B70700809387C707739057302B +:10023C00F327303473903714F3272034739027143A +:10024C0073101514F3275010739017349307001084 +:10025C0073B0071093D5350093F5051073A00510F6 +:10026C00B72700009387078073B00730B78700006B +:10027C009387070873A007306780000037070200D8 +:10028C0073200730170700001307870173105730CE +:10029C009306100083270500930600003707020021 +:1002AC00733007301385060023A0F500678000002B +:1002BC003707020073200730170700001307870168 +:1002CC0073105730930710002320B50093070000DC +:1002DC003707020073300730138507006780000072 +:1002EC00130101FE232E1100232C8100232A9100DF +:1002FC002328210123263101F327203463CE071450 +:10030C00130720006384E704930690006396D710CC +:10031C00B71700809387070383A647FC13061000CA +:10032C0003A587FA6386C61E6384E622638E061EC7 +:10033C00032481018320C10183244101032901018C +:10034C008329C100130101026F004039F3241034DA +:10035C00F3250030732430341306F0029376F4073F +:10036C001357C4006386C612130630076396C60A79 +:10037C00137737006306F724930730006302F724E2 +:10038C009309100063043703EF004035F327303432 +:10039C0073903714F327103473901714F327203409 +:1003AC0073902714F327501073901734B71700006D +:1003BC0013574401938617C06304D730938717C82B +:1003CC00631CF72CEF00003313090500638409024A +:1003DC00EF00C030F327303473903714F327103408 +:1003EC0073901714F327203473902714F3275010AD +:1003FC007390173413545400B7170080938707FB7E +:10040C001374C4073304F4002320240193844400A0 +:10041C00739014346F008002EF00402CF3273034BB +:10042C0073903714F327103473901714F327203478 +:10043C0073902714F3275010739017348320C10145 +:10044C000324810183244101032901018329C10073 +:10045C00130101026780000093F7F70F1307700078 +:10046C00E39CE7FA9307000273A047149307000874 +:10047C0073B047308320C1010324810183244101DF +:10048C00032901018329C1001301010267800000C7 +:10049C0013777700E312F7F81357D400935724011E +:1004AC00B7160080938606FB1377C70793F7C70729 +:1004BC003307D700B387D7000327070003A607002D +:1004CC003705020073200530170500001305850160 +:1004DC007310553093071000032807009307000092 +:1004EC003705020073300530639007089357B40149 +:1004FC001305C001E362F5F23705008093972700DE +:10050C001305857BB387A70083A7070067800700C7 +:10051C001375F50FEF00001DF32710349387470078 +:10052C00739017346FF09FF183A5C7FAEF00001D8D +:10053C009307000873A047309307000273B0471469 +:10054C00F327103493874700739017346FF01FEF25 +:10055C001307F0FF23A4E7FAF3271034938747001F +:10056C00739017346FF09FEDB70700809387C70720 +:10057C0073905730F327303473903714F3272034AB +:10058C007390271473901414F3275010739017342E +:10059C009307001073B0071093D5350093F5051031 +:1005AC0073A00510B72700009387078073B007303E +:1005BC00B78700009387070873A007306FF01FE818 +:1005CC009359F40093F9F901B33930016FF01FDE40 +:1005DC0033060601135454001374C407B306D40035 +:1005EC0023A00601B707020073A00730970700008D +:1005FC009387870173905730930610002320C70010 +:10060C0093060000B707020073B00730B7070080ED +:10061C009387C707638C060A73905730F3273034DF +:10062C0073903714F3272034739027147390141499 +:10063C00F3275010739017349307001073B0071002 +:10064C0093D7350093F7071073A007106FF09FF541 +:10065C00E37206F9130608006FF0DFF7E37CC8F6C7 +:10066C00130608006FF01FF7336606016FF09FF654 +:10067C00334606016FF01FF6E35EC8F4130608005C +:10068C006FF05FF5337606016FF0DFF4E35406F597 +:10069C00130608006FF01FF4EF004004F32730340A +:1006AC0073903714F327103473901714F3272034F6 +:1006BC0073902714F3275010739017346FF01FD1D9 +:1006CC00EF00C002130905006FF05FD09384440063 +:1006DC0073901434739057306FF05FD6232E00FE56 +:1006EC0067800000232CA0FE67800000032500FE1D +:1006FC0067800000032540FE678000009307C0FE62 +:10070C001307F0FF23A0E7002324A0FE23A0B700CB +:10071C0067800000130101FF232481002322910034 +:10072C00170400001304C4089704000093844408C1 +:10073C00B3848440232021012326110093D4244028 +:10074C0013090000631099041704000013044406F5 +:10075C00970400009384C405B3848440EFF01F9188 +:10076C0093D4244013090000631899028320C1001C +:10077C00032481008324410003290100130101019A +:10078C006780000083270400130919001304440038 +:10079C00E78007006FF01FFB832704001309190083 +:0C07AC0013044400E78007006FF01FFCFE +:1007B800DC050080E005008024040080240400801B +:1007C8007C06008024040080240400802404008027 +:1007D800740600802404008024040080240400801F +:1007E80090060080240400802404008024040080F3 +:1007F80084060080240400802404008024040080EF +:1008080098060080240400802404008024040080CA +:1008180068060080240400802404008024040080EA +:080828005C06008000000000E6 :040000058000000077 :00000001FF diff --git a/src/main/c/emulator/src/main.c b/src/main/c/emulator/src/main.c index 498929b7..1147c4b8 100755 --- a/src/main/c/emulator/src/main.c +++ b/src/main/c/emulator/src/main.c @@ -39,10 +39,11 @@ void redirectTrap(){ } void emulationTrapToSupervisorTrap(uint32_t sepc, uint32_t mstatus){ + csr_write(mtvec, trapEntry); csr_write(sbadaddr, csr_read(mbadaddr)); csr_write(scause, csr_read(mcause)); csr_write(sepc, sepc); - csr_write(mepc, csr_read(stvec)); + csr_write(mepc, csr_read(stvec)); csr_clear(sstatus, MSTATUS_SPP); csr_set(sstatus, (mstatus >> 3) & MSTATUS_SPP); csr_clear(mstatus, MSTATUS_MPP); @@ -62,7 +63,7 @@ void emulationTrapToSupervisorTrap(uint32_t sepc, uint32_t mstatus){ -//Will modify MEPC +//Will modify MTVEC int32_t readWord(uint32_t address, int32_t *data){ int32_t result, tmp; int32_t failed; @@ -70,7 +71,7 @@ int32_t readWord(uint32_t address, int32_t *data){ " li %[tmp], 0x00020000\n" " csrs mstatus, %[tmp]\n" " la %[tmp], 1f\n" - " csrw mepc, %[tmp]\n" + " csrw mtvec, %[tmp]\n" " li %[failed], 1\n" " lw %[result], 0(%[address])\n" " li %[failed], 0\n" @@ -86,7 +87,7 @@ int32_t readWord(uint32_t address, int32_t *data){ return failed; } -//Will modify MEPC +//Will modify MTVEC int32_t writeWord(uint32_t address, int32_t data){ int32_t result, tmp; int32_t failed; @@ -94,7 +95,7 @@ int32_t writeWord(uint32_t address, int32_t data){ " li %[tmp], 0x00020000\n" " csrs mstatus, %[tmp]\n" " la %[tmp], 1f\n" - " csrw mepc, %[tmp]\n" + " csrw mtvec, %[tmp]\n" " li %[failed], 1\n" " sw %[data], 0(%[address])\n" " li %[failed], 0\n" @@ -167,6 +168,7 @@ void trap(){ return; } csr_write(mepc, mepc + 4); + csr_write(mtvec, trapEntry); //Restore mtvec }break; default: redirectTrap(); break; } break; diff --git a/src/main/c/emulator/src/trap.S b/src/main/c/emulator/src/trap.S index 4384d349..53af1a89 100644 --- a/src/main/c/emulator/src/trap.S +++ b/src/main/c/emulator/src/trap.S @@ -4,7 +4,6 @@ trapEntry: csrrw sp, mscratch, sp - sw x0, 0*4(sp) sw x1, 1*4(sp) sw x3, 3*4(sp) sw x4, 4*4(sp) @@ -36,7 +35,6 @@ trapEntry: sw x30, 30*4(sp) sw x31, 31*4(sp) call trap - lw x0, 0*4(sp) lw x1, 1*4(sp) lw x3, 3*4(sp) lw x4, 4*4(sp) diff --git a/src/main/scala/vexriscv/plugin/MmuPlugin.scala b/src/main/scala/vexriscv/plugin/MmuPlugin.scala index 56a4f262..f4aad4f7 100644 --- a/src/main/scala/vexriscv/plugin/MmuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/MmuPlugin.scala @@ -112,7 +112,7 @@ class MmuPlugin(virtualRange : UInt => Bool, requireMmuLockup clearWhen(!csr.status.mprv && privilegeService.isMachine()) when(privilegeService.isMachine()) { if (port.priority == MmuPort.PRIORITY_DATA) { - requireMmuLockup clearWhen (!csr.status.mprv) + requireMmuLockup clearWhen (!csr.status.mprv || pipeline(MPP) === 3) } else { requireMmuLockup := False } diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index ab90652f..d25ff396 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -1177,7 +1177,9 @@ public: MemWrite t = periphWrites.front(); MemWrite t2 = periphWritesGolden.front(); if(t.address != t2.address || t.size != t2.size || t.data != t2.data){ - cout << "periphWrite missmatch" << endl; + cout << hex << "periphWrite missmatch" << endl; + cout << " DUT address=" << t.address << " size=" << t.size << " data=" << t.data << endl; + cout << " REF address=" << t2.address << " size=" << t2.size << " data=" << t2.data << endl; fail(); } periphWrites.pop(); @@ -3326,6 +3328,7 @@ int main(int argc, char **argv, char **env) { ->setDStall(false) ->bootAt(0x80000000) ->run(0); +// ->run(1173000000l ); #endif // #ifdef MMU From 9ac49984784ab784f109fd5564f56d2063753e40 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 28 Mar 2019 00:38:38 +0100 Subject: [PATCH 084/951] Fix emulator nested exception redirection privilege --- src/main/c/emulator/build/emulator.asm | 8 ++++---- src/main/c/emulator/build/emulator.hex | 6 +++--- src/main/c/emulator/src/main.c | 2 +- src/test/cpp/regression/main.cpp | 3 ++- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/main/c/emulator/build/emulator.asm b/src/main/c/emulator/build/emulator.asm index e2dcdda9..cb720c30 100644 --- a/src/main/c/emulator/build/emulator.asm +++ b/src/main/c/emulator/build/emulator.asm @@ -181,8 +181,8 @@ Disassembly of section .text: 8000026c: 000027b7 lui a5,0x2 80000270: 80078793 addi a5,a5,-2048 # 1800 <__stack_size+0x1000> 80000274: 3007b073 csrc mstatus,a5 -80000278: 000087b7 lui a5,0x8 -8000027c: 08078793 addi a5,a5,128 # 8080 <__stack_size+0x7880> +80000278: 000017b7 lui a5,0x1 +8000027c: 88078793 addi a5,a5,-1920 # 880 <__stack_size+0x80> 80000280: 3007a073 csrs mstatus,a5 80000284: 00008067 ret @@ -396,8 +396,8 @@ Disassembly of section .text: 800005b0: 000027b7 lui a5,0x2 800005b4: 80078793 addi a5,a5,-2048 # 1800 <__stack_size+0x1000> 800005b8: 3007b073 csrc mstatus,a5 -800005bc: 000087b7 lui a5,0x8 -800005c0: 08078793 addi a5,a5,128 # 8080 <__stack_size+0x7880> +800005bc: 000017b7 lui a5,0x1 +800005c0: 88078793 addi a5,a5,-1920 # 880 <__stack_size+0x80> 800005c4: 3007a073 csrs mstatus,a5 800005c8: e81ff06f j 80000448 800005cc: 00f45993 srli s3,s0,0xf diff --git a/src/main/c/emulator/build/emulator.hex b/src/main/c/emulator/build/emulator.hex index 99d25eae..1892272e 100644 --- a/src/main/c/emulator/build/emulator.hex +++ b/src/main/c/emulator/build/emulator.hex @@ -38,8 +38,8 @@ :10023C00F327303473903714F3272034739027143A :10024C0073101514F3275010739017349307001084 :10025C0073B0071093D5350093F5051073A00510F6 -:10026C00B72700009387078073B00730B78700006B -:10027C009387070873A007306780000037070200D8 +:10026C00B72700009387078073B00730B7170000DB +:10027C009387078873A00730678000003707020058 :10028C0073200730170700001307870173105730CE :10029C009306100083270500930600003707020021 :1002AC00733007301385060023A0F500678000002B @@ -91,7 +91,7 @@ :10058C007390271473901414F3275010739017342E :10059C009307001073B0071093D5350093F5051031 :1005AC0073A00510B72700009387078073B007303E -:1005BC00B78700009387070873A007306FF01FE818 +:1005BC00B71700009387078873A007306FF01FE808 :1005CC009359F40093F9F901B33930016FF01FDE40 :1005DC0033060601135454001374C407B306D40035 :1005EC0023A00601B707020073A00730970700008D diff --git a/src/main/c/emulator/src/main.c b/src/main/c/emulator/src/main.c index 1147c4b8..1181786d 100755 --- a/src/main/c/emulator/src/main.c +++ b/src/main/c/emulator/src/main.c @@ -47,7 +47,7 @@ void emulationTrapToSupervisorTrap(uint32_t sepc, uint32_t mstatus){ csr_clear(sstatus, MSTATUS_SPP); csr_set(sstatus, (mstatus >> 3) & MSTATUS_SPP); csr_clear(mstatus, MSTATUS_MPP); - csr_set(mstatus, 0x8000 | MSTATUS_MPIE); + csr_set(mstatus, 0x0800 | MSTATUS_MPIE); } #define max(a,b) \ diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index d25ff396..53553337 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -561,7 +561,8 @@ public: return value; } -#define maskedWrite(dst, src, mask) dst=(dst & ~mask)|(src & mask); + #define maskedWrite(dst, src, mask) dst=(dst & ~mask)|(src & mask); + virtual bool csrWrite(int32_t csr, uint32_t value){ if(((csr >> 8) & 0x3) > privilege) return true; switch(csr){ From b0522cb4918c4fe3b91dc7d9325f79e060fd59ea Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 28 Mar 2019 08:32:12 +0100 Subject: [PATCH 085/951] Add AhbLite3 simulation config --- .../demo/VexRiscvAhbLite3ForSim.scala | 177 ++++++++++++++++++ 1 file changed, 177 insertions(+) create mode 100644 src/main/scala/vexriscv/demo/VexRiscvAhbLite3ForSim.scala diff --git a/src/main/scala/vexriscv/demo/VexRiscvAhbLite3ForSim.scala b/src/main/scala/vexriscv/demo/VexRiscvAhbLite3ForSim.scala new file mode 100644 index 00000000..2a2613f9 --- /dev/null +++ b/src/main/scala/vexriscv/demo/VexRiscvAhbLite3ForSim.scala @@ -0,0 +1,177 @@ +package vexriscv.demo + +import spinal.core._ +import spinal.lib._ +import spinal.lib.bus.avalon.AvalonMM +import spinal.lib.eda.altera.{InterruptReceiverTag, QSysify, ResetEmitterTag} +import vexriscv.ip.{DataCacheConfig, InstructionCacheConfig} +import vexriscv.plugin._ +import vexriscv.{VexRiscv, VexRiscvConfig, plugin} + +/** + * Created by spinalvm on 14.07.17. + */ +//class VexRiscvAvalon(debugClockDomain : ClockDomain) extends Component{ +// +//} + +//make clean run DBUS=CACHED_AVALON IBUS=CACHED_AVALON MMU=no CSR=no DEBUG_PLUGIN=AVALON + +object VexRiscvAhbLite3ForSim{ + def main(args: Array[String]) { + val report = SpinalVerilog{ + + //CPU configuration + val cpuConfig = VexRiscvConfig( + plugins = List( + new IBusSimplePlugin( + resetVector = 0x80000000l, + cmdForkOnSecondStage = false, + cmdForkPersistence = true, + prediction = STATIC, + catchAccessFault = false, + compressedGen = false + ), + new DBusSimplePlugin( + catchAddressMisaligned = false, + catchAccessFault = false + ), +// new IBusCachedPlugin( +// config = InstructionCacheConfig( +// cacheSize = 4096, +// bytePerLine =32, +// wayCount = 1, +// addressWidth = 32, +// cpuDataWidth = 32, +// memDataWidth = 32, +// catchIllegalAccess = true, +// catchAccessFault = true, +// catchMemoryTranslationMiss = true, +// asyncTagMemory = false, +// twoCycleRam = true +// ) +// // askMemoryTranslation = true, +// // memoryTranslatorPortConfig = MemoryTranslatorPortConfig( +// // portTlbSize = 4 +// // ) +// ), +// new DBusCachedPlugin( +// config = new DataCacheConfig( +// cacheSize = 4096, +// bytePerLine = 32, +// wayCount = 1, +// addressWidth = 32, +// cpuDataWidth = 32, +// memDataWidth = 32, +// catchAccessError = true, +// catchIllegal = true, +// catchUnaligned = true, +// catchMemoryTranslationMiss = true +// ), +// memoryTranslatorPortConfig = null +// // memoryTranslatorPortConfig = MemoryTranslatorPortConfig( +// // portTlbSize = 6 +// // ) +// ), + new StaticMemoryTranslatorPlugin( + ioRange = _(31 downto 28) === 0xF + ), + new DecoderSimplePlugin( + catchIllegalInstruction = true + ), + new RegFilePlugin( + regFileReadyKind = plugin.SYNC, + zeroBoot = false + ), + new IntAluPlugin, + new SrcPlugin( + separatedAddSub = false, + executeInsertion = true + ), + new FullBarrelShifterPlugin, + new MulPlugin, + new DivPlugin, + new HazardSimplePlugin( + bypassExecute = true, + bypassMemory = true, + bypassWriteBack = true, + bypassWriteBackBuffer = true, + pessimisticUseSrc = false, + pessimisticWriteRegFile = false, + pessimisticAddressMatch = false + ), + new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))), + new BranchPlugin( + earlyBranch = false, + catchAddressMisaligned = true + ), + new CsrPlugin( + config = CsrPluginConfig( + catchIllegalAccess = false, + mvendorid = null, + marchid = null, + mimpid = null, + mhartid = null, + misaExtensionsInit = 66, + misaAccess = CsrAccess.NONE, + mtvecAccess = CsrAccess.NONE, + mtvecInit = 0x00000020l, + mepcAccess = CsrAccess.READ_WRITE, + mscratchGen = false, + mcauseAccess = CsrAccess.READ_ONLY, + mbadaddrAccess = CsrAccess.READ_ONLY, + mcycleAccess = CsrAccess.NONE, + minstretAccess = CsrAccess.NONE, + ecallGen = false, + wfiGenAsWait = false, + ucycleAccess = CsrAccess.NONE + ) + ), + new YamlPlugin("cpu0.yaml") + ) + ) + + //CPU instanciation + val cpu = new VexRiscv(cpuConfig) + + //CPU modifications to be an AhbLite3 one + cpu.rework { + for (plugin <- cpuConfig.plugins) plugin match { + case plugin: IBusSimplePlugin => { + plugin.iBus.setAsDirectionLess() //Unset IO properties of iBus + master(plugin.iBus.toAhbLite3Master()).setName("iBusAhbLite3") + } +// case plugin: DBusSimplePlugin => { +// plugin.dBus.setAsDirectionLess() +// master(plugin.dBus.toAhbLite3Master()).setName("dBusAhbLite3") +// } +// case plugin: IBusCachedPlugin => { +// plugin.iBus.setAsDirectionLess() //Unset IO properties of iBus +// iBus = master(plugin.iBus.toAvalon()) +// .setName("iBusAvalon") +// .addTag(ClockDomainTag(ClockDomain.current)) //Specify a clock domain to the iBus (used by QSysify) +// } +// case plugin: DBusCachedPlugin => { +// plugin.dBus.setAsDirectionLess() +// master(plugin.dBus.toAvalon()) +// .setName("dBusAvalon") +// .addTag(ClockDomainTag(ClockDomain.current)) +// } +// case plugin: DebugPlugin => plugin.debugClockDomain { +// plugin.io.bus.setAsDirectionLess() +// slave(plugin.io.bus.fromAvalon()) +// .setName("debugBusAvalon") +// .addTag(ClockDomainTag(plugin.debugClockDomain)) +// .parent = null //Avoid the io bundle to be interpreted as a QSys conduit +// plugin.io.resetOut +// .addTag(ResetEmitterTag(plugin.debugClockDomain)) +// .parent = null //Avoid the io bundle to be interpreted as a QSys conduit +// } + case _ => + } + } + cpu + } + } +} + From 53c05c31c7a7f185b9f4af642dcecaa2cfa9e167 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 28 Mar 2019 10:12:42 +0100 Subject: [PATCH 086/951] IBusSimplePlugin AHB bridge fix, pass tests --- .../vexriscv/plugin/DBusSimplePlugin.scala | 2 +- .../vexriscv/plugin/IBusSimplePlugin.scala | 2 +- src/test/cpp/regression/main.cpp | 18 ++++++++++-------- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala index 9ef11217..fcafd3a4 100644 --- a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala @@ -211,7 +211,7 @@ case class DBusSimpleBus() extends Bundle with IMasterSlave{ bus.HSIZE := B(this.cmd.size, 3 bits) bus.HBURST := 0 bus.HPROT := "1111" - bus.HTRANS := B"0" ## this.cmd.valid + bus.HTRANS := this.cmd.valid ## B"0" bus.HMASTLOCK := False bus.HWDATA := RegNextWhen(this.cmd.data, bus.HREADY) this.cmd.ready := bus.HREADY diff --git a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala index a3f6a5b5..8f233372 100644 --- a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala @@ -162,7 +162,7 @@ case class IBusSimpleBus(interfaceKeepData : Boolean = false) extends Bundle wit bus.HSIZE := 2 bus.HBURST := 0 bus.HPROT := "1110" - bus.HTRANS := B"0" ## this.cmd.valid + bus.HTRANS := this.cmd.valid ## B"0" bus.HMASTLOCK := False bus.HWDATA.assignDontCare() this.cmd.ready := bus.HREADY diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 1c741618..8ac4ffe4 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -972,7 +972,7 @@ public: if(bootPc != -1) top->VexRiscv->core->prefetch_pc = bootPc; #else if(bootPc != -1) { - #if defined(IBUS_SIMPLE) || defined(IBUS_SIMPLE_WISHBONE) + #if defined(IBUS_SIMPLE) || defined(IBUS_SIMPLE_WISHBONE) || defined(IBUS_SIMPLE_AHBLITE3) top->VexRiscv->IBusSimplePlugin_fetchPc_pcReg = bootPc; #ifdef COMPRESSED top->VexRiscv->IBusSimplePlugin_decodePc_pcReg = bootPc; @@ -1287,7 +1287,8 @@ public: VVexRiscv* top; uint32_t iBusAhbLite3_HRDATA; - bool iBusAhbLite3_HRESP, iBusAhbLite3_HREADY; + bool iBusAhbLite3_HRESP; + bool pending; IBusSimpleAhbLite3(Workspace* ws){ this->ws = ws; @@ -1295,6 +1296,7 @@ public: } virtual void onReset(){ + pending = false; top->iBusAhbLite3_HREADY = 1; top->iBusAhbLite3_HRESP = 0; } @@ -1302,22 +1304,22 @@ public: virtual void preCycle(){ if (top->iBusAhbLite3_HTRANS == 2 && top->iBusAhbLite3_HREADY && !top->iBusAhbLite3_HWRITE) { ws->iBusAccess(top->iBusAhbLite3_HADDR,&iBusAhbLite3_HRDATA,&iBusAhbLite3_HRESP); + pending = true; } } virtual void postCycle(){ - if(top->iBusAhbLite3_HREADY && (!ws->iStall || VL_RANDOM_I(7) < 100)){ - IBusSimpleAvalonRsp rsp = rsps.front(); rsps.pop(); + if(ws->iStall) + top->iBusAhbLite3_HREADY = (!ws->iStall || VL_RANDOM_I(7) < 100); + + if(pending && top->iBusAhbLite3_HREADY){ top->iBusAhbLite3_HRDATA = iBusAhbLite3_HRDATA; - top->iBusAhbLite3_HREADY = iBusAhbLite3_HREADY; top->iBusAhbLite3_HRESP = iBusAhbLite3_HRESP; + pending = false; } else { - top->iBusAhbLite3_HRESP = 0; top->iBusAhbLite3_HRDATA = VL_RANDOM_I(32); top->iBusAhbLite3_HRESP = VL_RANDOM_I(1); } - if(ws->iStall) - top->iBusAhbLite3_HREADY = VL_RANDOM_I(7) < 100; } }; #endif From ad27007c3cb53ede7db2f37928312a412d652871 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 28 Mar 2019 11:41:49 +0100 Subject: [PATCH 087/951] DBusSimplePlugin AHB bridge add hazard checking, pass tests --- .../demo/VexRiscvAhbLite3ForSim.scala | 8 +-- .../vexriscv/plugin/DBusSimplePlugin.scala | 12 +++- src/test/cpp/regression/main.cpp | 57 +++++++++++++++++++ 3 files changed, 72 insertions(+), 5 deletions(-) diff --git a/src/main/scala/vexriscv/demo/VexRiscvAhbLite3ForSim.scala b/src/main/scala/vexriscv/demo/VexRiscvAhbLite3ForSim.scala index 2a2613f9..d11994b3 100644 --- a/src/main/scala/vexriscv/demo/VexRiscvAhbLite3ForSim.scala +++ b/src/main/scala/vexriscv/demo/VexRiscvAhbLite3ForSim.scala @@ -141,10 +141,10 @@ object VexRiscvAhbLite3ForSim{ plugin.iBus.setAsDirectionLess() //Unset IO properties of iBus master(plugin.iBus.toAhbLite3Master()).setName("iBusAhbLite3") } -// case plugin: DBusSimplePlugin => { -// plugin.dBus.setAsDirectionLess() -// master(plugin.dBus.toAhbLite3Master()).setName("dBusAhbLite3") -// } + case plugin: DBusSimplePlugin => { + plugin.dBus.setAsDirectionLess() + master(plugin.dBus.toAhbLite3Master(avoidWriteToReadHazard = true)).setName("dBusAhbLite3") + } // case plugin: IBusCachedPlugin => { // plugin.iBus.setAsDirectionLess() //Unset IO properties of iBus // iBus = master(plugin.iBus.toAvalon()) diff --git a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala index fcafd3a4..266c7625 100644 --- a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala @@ -204,7 +204,7 @@ case class DBusSimpleBus() extends Bundle with IMasterSlave{ - def toAhbLite3Master(): AhbLite3Master = { + def toAhbLite3Master(avoidWriteToReadHazard : Boolean): AhbLite3Master = { val bus = AhbLite3Master(DBusSimpleBus.getAhbLite3Config()) bus.HADDR := this.cmd.address bus.HWRITE := this.cmd.wr @@ -220,6 +220,16 @@ case class DBusSimpleBus() extends Bundle with IMasterSlave{ this.rsp.ready := bus.HREADY this.rsp.data := bus.HRDATA this.rsp.error := bus.HRESP + + if(avoidWriteToReadHazard) { + val writeDataPhase = RegNextWhen(bus.HTRANS === 2 && bus.HWRITE, bus.HREADY) init (False) + val potentialHazard = this.cmd.valid && !this.cmd.wr && writeDataPhase + when(potentialHazard) { + bus.HTRANS := 0 + this.cmd.ready := False + } + } + bus } diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 8ac4ffe4..f81183d9 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -1572,6 +1572,60 @@ public: }; #endif + + +#ifdef DBUS_SIMPLE_AHBLITE3 +class DBusSimpleAhbLite3 : public SimElement{ +public: + Workspace *ws; + VVexRiscv* top; + + uint32_t dBusAhbLite3_HADDR, dBusAhbLite3_HSIZE, dBusAhbLite3_HTRANS, dBusAhbLite3_HWRITE; + + DBusSimpleAhbLite3(Workspace* ws){ + this->ws = ws; + this->top = ws->top; + } + + virtual void onReset(){ + top->dBusAhbLite3_HREADY = 1; + top->dBusAhbLite3_HRESP = 0; + dBusAhbLite3_HTRANS = 0; + } + + virtual void preCycle(){ + if(top->dBusAhbLite3_HREADY && dBusAhbLite3_HTRANS == 2 && dBusAhbLite3_HWRITE){ + uint32_t data = top->dBusAhbLite3_HWDATA; + bool error; + ws->dBusAccess(dBusAhbLite3_HADDR, 1, dBusAhbLite3_HSIZE, ((1 << (1 << dBusAhbLite3_HSIZE))-1) << (dBusAhbLite3_HADDR & 0x3),&data,&error); + } + + if(top->dBusAhbLite3_HREADY){ + dBusAhbLite3_HADDR = top->dBusAhbLite3_HADDR ; + dBusAhbLite3_HSIZE = top->dBusAhbLite3_HSIZE ; + dBusAhbLite3_HTRANS = top->dBusAhbLite3_HTRANS ; + dBusAhbLite3_HWRITE = top->dBusAhbLite3_HWRITE ; + } + } + + virtual void postCycle(){ + if(ws->iStall) + top->dBusAhbLite3_HREADY = (!ws->iStall || VL_RANDOM_I(7) < 100); + + top->dBusAhbLite3_HRDATA = VL_RANDOM_I(32); + top->dBusAhbLite3_HRESP = VL_RANDOM_I(1); + + if(top->dBusAhbLite3_HREADY && dBusAhbLite3_HTRANS == 2 && !dBusAhbLite3_HWRITE){ + + bool error; + ws->dBusAccess(dBusAhbLite3_HADDR, 0, dBusAhbLite3_HSIZE, ((1 << (1 << dBusAhbLite3_HSIZE))-1) << (dBusAhbLite3_HADDR & 0x3),&top->dBusAhbLite3_HRDATA,&error); + top->dBusAhbLite3_HRESP = error; + } + } +}; +#endif + + #if defined(DBUS_CACHED_WISHBONE) || defined(DBUS_SIMPLE_WISHBONE) #include @@ -2065,6 +2119,9 @@ void Workspace::fillSimELements(){ #ifdef DBUS_SIMPLE_AVALON simElements.push_back(new DBusSimpleAvalon(this)); #endif + #ifdef DBUS_SIMPLE_AHBLITE3 + simElements.push_back(new DBusSimpleAhbLite3(this)); + #endif #ifdef DBUS_CACHED simElements.push_back(new DBusCached(this)); #endif From 0c4872961166aabb59b240bc4462b16e2bae64ad Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 29 Mar 2019 08:43:15 +0100 Subject: [PATCH 088/951] Sync impact less changes (asfar i know) --- src/main/c/emulator/build/emulator.asm | 2 +- src/main/c/emulator/build/emulator.hex | 2 +- src/main/c/emulator/src/main.c | 2 +- src/main/c/emulator/src/riscv.h | 2 ++ src/main/scala/vexriscv/demo/Linux.scala | 22 +++++++++++++++++++++- 5 files changed, 26 insertions(+), 4 deletions(-) diff --git a/src/main/c/emulator/build/emulator.asm b/src/main/c/emulator/build/emulator.asm index cb720c30..b8718130 100644 --- a/src/main/c/emulator/build/emulator.asm +++ b/src/main/c/emulator/build/emulator.asm @@ -125,7 +125,7 @@ Disassembly of section .text: 800001ac: 0000b7b7 lui a5,0xb 800001b0: 10078793 addi a5,a5,256 # b100 <__stack_size+0xa900> 800001b4: 30279073 csrw medeleg,a5 -800001b8: 02000793 li a5,32 +800001b8: 22200793 li a5,546 800001bc: 30379073 csrw mideleg,a5 800001c0: 14305073 csrwi sbadaddr,0 800001c4: 00008067 ret diff --git a/src/main/c/emulator/build/emulator.hex b/src/main/c/emulator/build/emulator.hex index 1892272e..d0e288e0 100644 --- a/src/main/c/emulator/build/emulator.hex +++ b/src/main/c/emulator/build/emulator.hex @@ -26,7 +26,7 @@ :10017C00B70700809387C70773905730B717008075 :10018C00938707FB73900734B71700009387078892 :10019C007390073073504030B70700C0739017341A -:1001AC00B7B70000938707107390273093070002AE +:1001AC00B7B700009387071073902730930720226E :1001BC00739037307350301467800000B71700808D :1001CC00938707FB131525003305F5000325050060 :1001DC0067800000B717008013152500938707FB75 diff --git a/src/main/c/emulator/src/main.c b/src/main/c/emulator/src/main.c index 1181786d..bcaf82f0 100755 --- a/src/main/c/emulator/src/main.c +++ b/src/main/c/emulator/src/main.c @@ -15,7 +15,7 @@ void init() { csr_write(mie, 0); csr_write(mepc, OS_CALL); csr_write(medeleg, MEDELEG_INSTRUCTION_PAGE_FAULT | MEDELEG_LOAD_PAGE_FAULT | MEDELEG_STORE_PAGE_FAULT | MEDELEG_USER_ENVIRONNEMENT_CALL); - csr_write(mideleg, MIDELEG_SUPERVISOR_TIMER); + csr_write(mideleg, MIDELEG_SUPERVISOR_TIMER | MIDELEG_SUPERVISOR_EXTERNAL | MIDELEG_SUPERVISOR_SOFTWARE); csr_write(sbadaddr, 0); //Used to avoid simulation missmatch } diff --git a/src/main/c/emulator/src/riscv.h b/src/main/c/emulator/src/riscv.h index ea6ddd56..facb90d8 100644 --- a/src/main/c/emulator/src/riscv.h +++ b/src/main/c/emulator/src/riscv.h @@ -9,7 +9,9 @@ #define MEDELEG_LOAD_PAGE_FAULT (1 << 13) #define MEDELEG_STORE_PAGE_FAULT (1 << 15) #define MEDELEG_USER_ENVIRONNEMENT_CALL (1 << 8) +#define MIDELEG_SUPERVISOR_SOFTWARE (1 << 1) #define MIDELEG_SUPERVISOR_TIMER (1 << 5) +#define MIDELEG_SUPERVISOR_EXTERNAL (1 << 9) #define MIE_MTIE (1 << 7) #define MIP_STIP (1 << 5) diff --git a/src/main/scala/vexriscv/demo/Linux.scala b/src/main/scala/vexriscv/demo/Linux.scala index c274554e..e96260d5 100644 --- a/src/main/scala/vexriscv/demo/Linux.scala +++ b/src/main/scala/vexriscv/demo/Linux.scala @@ -58,6 +58,10 @@ make run DBUS=SIMPLE IBUS=SIMPLE SUPERVISOR=yes CSR=yes COMPRESSED=yes REDO=0 DH make run DBUS=SIMPLE IBUS=SIMPLE SUPERVISOR=yes CSR=yes COMPRESSED=yes REDO=0 DHRYSTONE=no LINUX_SOC=yes EMULATOR=/home/spinalvm/hdl/VexRiscv/src/main/c/emulator/build/emulator.bin VMLINUX=/home/spinalvm/hdl/linux/linux-1c163f4c7b3f621efff9b28a47abb36f7378d783/vmlinux.bin DTB=/home/spinalvm/hdl/linux/linux-1c163f4c7b3f621efff9b28a47abb36f7378d783/rv32.dtb RAMDISK=/home/spinalvm/hdl/linuxDave/initramdisk_dave TRACE=yes0 FLOW_INFO=yes TRACE_START=9570000099 +make run DBUS=SIMPLE IBUS=SIMPLE SUPERVISOR=yes CSR=yes COMPRESSED=yes REDO=0 DHRYSTONE=no LINUX_SOC=yes EMULATOR=/home/spinalvm/hdl/VexRiscv/src/main/c/emulator/build/emulator.bin VMLINUX=/home/spinalvm/hdl/linux/linux-1c163f4c7b3f621efff9b28a47abb36f7378d783/vmlinux.bin DTB=/home/spinalvm/hdl/linux/linux-1c163f4c7b3f621efff9b28a47abb36f7378d783/rv32.dtb RAMDISK=/home/spinalvm/hdl/linux/fs/rootfs.ext2 TRACE=yes0 FLOW_INFO=yes TRACE_START=9570000099 + + +make run DBUS=SIMPLE IBUS=SIMPLE SUPERVISOR=yes CSR=yes COMPRESSED=yes REDO=0 DHRYSTONE=no LINUX_SOC=yes EMULATOR=/home/spinalvm/hdl/VexRiscv/src/main/c/emulator/build/emulator.bin VMLINUX=/home/spinalvm/hdl/linux/linux-1c163f4c7b3f621efff9b28a47abb36f7378d783/vmlinux.bin DTB=/home/spinalvm/hdl/linux/linux-1c163f4c7b3f621efff9b28a47abb36f7378d783/rv32.dtb RAMDISK=/home/spinalvm/hdl/linux/debug/rootfs.cpio.lzma TRACE=yes0 FLOW_INFO=yes TRACE_START=9570000099 @@ -69,14 +73,30 @@ ARCH=riscv CROSS_COMPILE=riscv32-unknown-linux-gnu- make -j`nproc`; riscv32-unkn riscv64-unknown-elf-objdump -S -d vmlinux > vmlinux.asm; split -b 1M vmlinux.asm riscv32-unknown-linux-gnu-objdump -S -d vmlinux > vmlinux.asm; split -b 1M vmlinux.asm - +Linux => +ARCH=riscv CROSS_COMPILE=riscv32-unknown-linux-gnu- make menuconfig ARCH=riscv CROSS_COMPILE=riscv32-unknown-linux-gnu- make -j`nproc`; riscv32-unknown-linux-gnu-objcopy -O binary vmlinux vmlinux.bin + + split -b 1M vmlinux.asm dtc -O dtb -o rv32.dtb rv32.dts make run DBUS=SIMPLE IBUS=SIMPLE SUPERVISOR=yes CSR=yes COMPRESSED=yes REDO=0 DHRYSTONE=no LITEX=yes EMULATOR=/home/spinalvm/hdl/VexRiscv/src/main/c/emulator/build/emulator.bin VMLINUX=/home/spinalvm/hdl/riscv-linux/vmlinux.bin DTB=/home/spinalvm/hdl/riscv-linux/rv32.dtb RAMDISK=/home/spinalvm/hdl/linuxDave/initramdisk_dave TRACE=yes0 FLOW_INFO=yes TRACE_START=9570000099 + +https://github.com/riscv/riscv-qemu/wiki#build-and-install + + +buildroot => +make spinalhdl_vexriscv_sim_defconfig +make -j + +make run DBUS=SIMPLE IBUS=SIMPLE SUPERVISOR=yes CSR=yes COMPRESSED=yes REDO=0 DHRYSTONE=no LINUX_SOC=yes EMULATOR=/home/spinalvm/hdl/VexRiscv/src/main/c/emulator/build/emulator.bin VMLINUX=/home/spinalvm/hdl/linux/buildroot/output/images/Image DTB=/home/spinalvm/hdl/linux/linux-1c163f4c7b3f621efff9b28a47abb36f7378d783/rv32.dtb RAMDISK=/home/spinalvm/hdl/linux/buildroot/output/images/rootfs.tar TRACE=yes0 FLOW_INFO=yes TRACE_START=9570000099 + + + + */ From 391cff69d33d4415fd4d6398ce6833f186b57caf Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 29 Mar 2019 09:02:44 +0100 Subject: [PATCH 089/951] #60 should fix the first instruction fetch privilege after interrupt --- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index b6e77877..7116e76a 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -767,6 +767,9 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception } when(hadException || interruptJump){ + //Avoid having the fetch confused by the incomming privilege switch + fetcher.haltIt() + jumpInterface.valid := True jumpInterface.payload := (if(!xtvecModeGen) xtvec.base @@ "00" else (xtvec.mode === 0 || hadException) ? (xtvec.base @@ "00") | ((xtvec.base + trapCause) @@ "00") ) beforeLastStage.arbitration.flushAll := True @@ -800,11 +803,6 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception } } - //Avoid having the fetch confused by the incomming privilege switch - when(hadException){ - fetcher.haltIt() - } - lastStage plug new Area{ import lastStage._ From 9fff4193467642705d5783a313fa7a94cf63b1ce Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 29 Mar 2019 09:18:44 +0100 Subject: [PATCH 090/951] Better fix --- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 7116e76a..b904f6b3 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -734,7 +734,7 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception //Used to make the pipeline empty softly (for interrupts) val pipelineLiberator = new Area{ - when(interrupt && decode.arbitration.isValid){ + when(interrupt){ decode.arbitration.haltByOther := True } @@ -767,9 +767,6 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception } when(hadException || interruptJump){ - //Avoid having the fetch confused by the incomming privilege switch - fetcher.haltIt() - jumpInterface.valid := True jumpInterface.payload := (if(!xtvecModeGen) xtvec.base @@ "00" else (xtvec.mode === 0 || hadException) ? (xtvec.base @@ "00") | ((xtvec.base + trapCause) @@ "00") ) beforeLastStage.arbitration.flushAll := True @@ -803,6 +800,11 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception } } + //Avoid having the fetch confused by the incomming privilege switch + when(hadException){ + fetcher.haltIt() + } + lastStage plug new Area{ import lastStage._ From 29980016f38277523e7dd1505d5dd1ccebad0eb2 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Sat, 30 Mar 2019 10:10:25 +0100 Subject: [PATCH 091/951] #60 Fix instruction fetch exception PC by forcing LSB to be zero --- src/main/c/emulator/.gitignore | 4 +- src/main/c/emulator/build/emulator.asm | 623 +++++++++--------- src/main/c/emulator/build/emulator.bin | Bin 0 -> 2056 bytes .../vexriscv/plugin/IBusSimplePlugin.scala | 2 +- 4 files changed, 311 insertions(+), 318 deletions(-) create mode 100755 src/main/c/emulator/build/emulator.bin diff --git a/src/main/c/emulator/.gitignore b/src/main/c/emulator/.gitignore index c12cb2c2..a7caa3b4 100644 --- a/src/main/c/emulator/.gitignore +++ b/src/main/c/emulator/.gitignore @@ -1,4 +1,6 @@ *.map *.v *.elf -*.o \ No newline at end of file +*.o +*.hex +!*.bin \ No newline at end of file diff --git a/src/main/c/emulator/build/emulator.asm b/src/main/c/emulator/build/emulator.asm index b8718130..3a5b2a03 100644 --- a/src/main/c/emulator/build/emulator.asm +++ b/src/main/c/emulator/build/emulator.asm @@ -6,28 +6,28 @@ Disassembly of section .init: 80000000 <_start>: 80000000: 00001117 auipc sp,0x1 -80000004: 03010113 addi sp,sp,48 # 80001030 <_sp> +80000004: 00810113 addi sp,sp,8 # 80001008 <_sp> 80000008: 00000517 auipc a0,0x0 -8000000c: 7b050513 addi a0,a0,1968 # 800007b8 <__init_array_end> +8000000c: 78c50513 addi a0,a0,1932 # 80000794 <__init_array_end> 80000010: 00000597 auipc a1,0x0 -80000014: 7a858593 addi a1,a1,1960 # 800007b8 <__init_array_end> -80000018: 00001617 auipc a2,0x1 -8000001c: 81860613 addi a2,a2,-2024 # 80000830 <__bss_start> -80000020: 00c5fc63 bleu a2,a1,80000038 <_start+0x38> +80000014: 78458593 addi a1,a1,1924 # 80000794 <__init_array_end> +80000018: 00000617 auipc a2,0x0 +8000001c: 7f060613 addi a2,a2,2032 # 80000808 <__bss_start> +80000020: 00c5fc63 bgeu a1,a2,80000038 <_start+0x38> 80000024: 00052283 lw t0,0(a0) 80000028: 0055a023 sw t0,0(a1) 8000002c: 00450513 addi a0,a0,4 80000030: 00458593 addi a1,a1,4 80000034: fec5e8e3 bltu a1,a2,80000024 <_start+0x24> 80000038: 00000517 auipc a0,0x0 -8000003c: 7f850513 addi a0,a0,2040 # 80000830 <__bss_start> +8000003c: 7d050513 addi a0,a0,2000 # 80000808 <__bss_start> 80000040: 00000597 auipc a1,0x0 -80000044: 7f058593 addi a1,a1,2032 # 80000830 <__bss_start> -80000048: 00b57863 bleu a1,a0,80000058 <_start+0x58> +80000044: 7c858593 addi a1,a1,1992 # 80000808 <__bss_start> +80000048: 00b57863 bgeu a0,a1,80000058 <_start+0x58> 8000004c: 00052023 sw zero,0(a0) 80000050: 00450513 addi a0,a0,4 80000054: feb56ce3 bltu a0,a1,8000004c <_start+0x4c> -80000058: 6c8000ef jal ra,80000720 <__libc_init_array> +80000058: 694000ef jal ra,800006ec <__libc_init_array> 8000005c: 120000ef jal ra,8000017c 80000060: 00000097 auipc ra,0x0 80000064: 01408093 addi ra,ra,20 # 80000074 @@ -111,10 +111,10 @@ Disassembly of section .text: 8000017c : 8000017c: 800007b7 lui a5,0x80000 -80000180: 07c78793 addi a5,a5,124 # 8000007c <_sp+0xfffff04c> +80000180: 07c78793 addi a5,a5,124 # 8000007c <_sp+0xfffff074> 80000184: 30579073 csrw mtvec,a5 80000188: 800017b7 lui a5,0x80001 -8000018c: fb078793 addi a5,a5,-80 # 80000fb0 <_sp+0xffffff80> +8000018c: f8878793 addi a5,a5,-120 # 80000f88 <_sp+0xffffff80> 80000190: 34079073 csrw mscratch,a5 80000194: 000017b7 lui a5,0x1 80000198: 88078793 addi a5,a5,-1920 # 880 <__stack_size+0x80> @@ -127,12 +127,12 @@ Disassembly of section .text: 800001b4: 30279073 csrw medeleg,a5 800001b8: 22200793 li a5,546 800001bc: 30379073 csrw mideleg,a5 -800001c0: 14305073 csrwi sbadaddr,0 +800001c0: 14305073 csrwi stval,0 800001c4: 00008067 ret 800001c8 : 800001c8: 800017b7 lui a5,0x80001 -800001cc: fb078793 addi a5,a5,-80 # 80000fb0 <_sp+0xffffff80> +800001cc: f8878793 addi a5,a5,-120 # 80000f88 <_sp+0xffffff80> 800001d0: 00251513 slli a0,a0,0x2 800001d4: 00f50533 add a0,a0,a5 800001d8: 00052503 lw a0,0(a0) @@ -141,7 +141,7 @@ Disassembly of section .text: 800001e0 : 800001e0: 800017b7 lui a5,0x80001 800001e4: 00251513 slli a0,a0,0x2 -800001e8: fb078793 addi a5,a5,-80 # 80000fb0 <_sp+0xffffff80> +800001e8: f8878793 addi a5,a5,-120 # 80000f88 <_sp+0xffffff80> 800001ec: 00f50533 add a0,a0,a5 800001f0: 00b52023 sw a1,0(a0) 800001f4: 00008067 ret @@ -149,9 +149,9 @@ Disassembly of section .text: 800001f8 : 800001f8: ff010113 addi sp,sp,-16 800001fc: 00112623 sw ra,12(sp) -80000200: 4e8000ef jal ra,800006e8 -80000204: 343027f3 csrr a5,mbadaddr -80000208: 14379073 csrw sbadaddr,a5 +80000200: 4b4000ef jal ra,800006b4 +80000204: 343027f3 csrr a5,mtval +80000208: 14379073 csrw stval,a5 8000020c: 341027f3 csrr a5,mepc 80000210: 14179073 csrw sepc,a5 80000214: 342027f3 csrr a5,mcause @@ -164,10 +164,10 @@ Disassembly of section .text: 80000230 : 80000230: 800007b7 lui a5,0x80000 -80000234: 07c78793 addi a5,a5,124 # 8000007c <_sp+0xfffff04c> +80000234: 07c78793 addi a5,a5,124 # 8000007c <_sp+0xfffff074> 80000238: 30579073 csrw mtvec,a5 -8000023c: 343027f3 csrr a5,mbadaddr -80000240: 14379073 csrw sbadaddr,a5 +8000023c: 343027f3 csrr a5,mtval +80000240: 14379073 csrw stval,a5 80000244: 342027f3 csrr a5,mcause 80000248: 14279073 csrw scause,a5 8000024c: 14151073 csrw sepc,a0 @@ -198,7 +198,7 @@ Disassembly of section .text: 800002a8: 00020737 lui a4,0x20 800002ac: 30073073 csrc mstatus,a4 800002b0: 00068513 mv a0,a3 -800002b4: 00f5a023 sw a5,0(a1) # 81000000 <_sp+0xffefd0> +800002b4: 00f5a023 sw a5,0(a1) # 81000000 <_sp+0xffeff8> 800002b8: 00008067 ret 800002bc : @@ -223,315 +223,306 @@ Disassembly of section .text: 800002fc: 01212823 sw s2,16(sp) 80000300: 01312623 sw s3,12(sp) 80000304: 342027f3 csrr a5,mcause -80000308: 1407ce63 bltz a5,80000464 +80000308: 0807cc63 bltz a5,800003a0 8000030c: 00200713 li a4,2 -80000310: 04e78463 beq a5,a4,80000358 +80000310: 0ce78463 beq a5,a4,800003d8 80000314: 00900693 li a3,9 -80000318: 10d79663 bne a5,a3,80000424 +80000318: 04d79463 bne a5,a3,80000360 8000031c: 800017b7 lui a5,0x80001 -80000320: 03078793 addi a5,a5,48 # 80001030 <_sp+0x0> +80000320: 00878793 addi a5,a5,8 # 80001008 <_sp+0x0> 80000324: fc47a683 lw a3,-60(a5) 80000328: 00100613 li a2,1 8000032c: fa87a503 lw a0,-88(a5) -80000330: 1ec68663 beq a3,a2,8000051c -80000334: 22e68463 beq a3,a4,8000055c -80000338: 1e068e63 beqz a3,80000534 +80000330: 2ec68663 beq a3,a2,8000061c +80000334: 2ae68463 beq a3,a4,800005dc +80000338: 2a068e63 beqz a3,800005f4 8000033c: 01812403 lw s0,24(sp) 80000340: 01c12083 lw ra,28(sp) 80000344: 01412483 lw s1,20(sp) 80000348: 01012903 lw s2,16(sp) 8000034c: 00c12983 lw s3,12(sp) 80000350: 02010113 addi sp,sp,32 -80000354: 3940006f j 800006e8 -80000358: 341024f3 csrr s1,mepc -8000035c: 300025f3 csrr a1,mstatus -80000360: 34302473 csrr s0,mbadaddr -80000364: 02f00613 li a2,47 -80000368: 07f47693 andi a3,s0,127 -8000036c: 00c45713 srli a4,s0,0xc -80000370: 12c68663 beq a3,a2,8000049c -80000374: 07300613 li a2,115 -80000378: 0ac69663 bne a3,a2,80000424 -8000037c: 00377713 andi a4,a4,3 -80000380: 24f70663 beq a4,a5,800005cc -80000384: 00300793 li a5,3 -80000388: 24f70263 beq a4,a5,800005cc -8000038c: 00100993 li s3,1 -80000390: 03370463 beq a4,s3,800003b8 -80000394: 354000ef jal ra,800006e8 -80000398: 343027f3 csrr a5,mbadaddr -8000039c: 14379073 csrw sbadaddr,a5 -800003a0: 341027f3 csrr a5,mepc -800003a4: 14179073 csrw sepc,a5 -800003a8: 342027f3 csrr a5,mcause -800003ac: 14279073 csrw scause,a5 -800003b0: 105027f3 csrr a5,stvec -800003b4: 34179073 csrw mepc,a5 -800003b8: 000017b7 lui a5,0x1 -800003bc: 01445713 srli a4,s0,0x14 -800003c0: c0178693 addi a3,a5,-1023 # c01 <__stack_size+0x401> -800003c4: 30d70463 beq a4,a3,800006cc -800003c8: c8178793 addi a5,a5,-895 -800003cc: 2cf71c63 bne a4,a5,800006a4 -800003d0: 330000ef jal ra,80000700 -800003d4: 00050913 mv s2,a0 -800003d8: 02098463 beqz s3,80000400 -800003dc: 30c000ef jal ra,800006e8 -800003e0: 343027f3 csrr a5,mbadaddr -800003e4: 14379073 csrw sbadaddr,a5 -800003e8: 341027f3 csrr a5,mepc -800003ec: 14179073 csrw sepc,a5 -800003f0: 342027f3 csrr a5,mcause -800003f4: 14279073 csrw scause,a5 -800003f8: 105027f3 csrr a5,stvec -800003fc: 34179073 csrw mepc,a5 -80000400: 00545413 srli s0,s0,0x5 -80000404: 800017b7 lui a5,0x80001 -80000408: fb078793 addi a5,a5,-80 # 80000fb0 <_sp+0xffffff80> -8000040c: 07c47413 andi s0,s0,124 -80000410: 00f40433 add s0,s0,a5 -80000414: 01242023 sw s2,0(s0) -80000418: 00448493 addi s1,s1,4 -8000041c: 34149073 csrw mepc,s1 -80000420: 0280006f j 80000448 -80000424: 2c4000ef jal ra,800006e8 -80000428: 343027f3 csrr a5,mbadaddr -8000042c: 14379073 csrw sbadaddr,a5 -80000430: 341027f3 csrr a5,mepc -80000434: 14179073 csrw sepc,a5 -80000438: 342027f3 csrr a5,mcause -8000043c: 14279073 csrw scause,a5 -80000440: 105027f3 csrr a5,stvec -80000444: 34179073 csrw mepc,a5 -80000448: 01c12083 lw ra,28(sp) -8000044c: 01812403 lw s0,24(sp) -80000450: 01412483 lw s1,20(sp) -80000454: 01012903 lw s2,16(sp) -80000458: 00c12983 lw s3,12(sp) -8000045c: 02010113 addi sp,sp,32 -80000460: 00008067 ret -80000464: 0ff7f793 andi a5,a5,255 -80000468: 00700713 li a4,7 -8000046c: fae79ce3 bne a5,a4,80000424 -80000470: 02000793 li a5,32 -80000474: 1447a073 csrs sip,a5 -80000478: 08000793 li a5,128 -8000047c: 3047b073 csrc mie,a5 -80000480: 01c12083 lw ra,28(sp) -80000484: 01812403 lw s0,24(sp) -80000488: 01412483 lw s1,20(sp) -8000048c: 01012903 lw s2,16(sp) -80000490: 00c12983 lw s3,12(sp) -80000494: 02010113 addi sp,sp,32 -80000498: 00008067 ret -8000049c: 00777713 andi a4,a4,7 -800004a0: f8f712e3 bne a4,a5,80000424 -800004a4: 00d45713 srli a4,s0,0xd -800004a8: 01245793 srli a5,s0,0x12 -800004ac: 800016b7 lui a3,0x80001 -800004b0: fb068693 addi a3,a3,-80 # 80000fb0 <_sp+0xffffff80> -800004b4: 07c77713 andi a4,a4,124 -800004b8: 07c7f793 andi a5,a5,124 -800004bc: 00d70733 add a4,a4,a3 -800004c0: 00d787b3 add a5,a5,a3 -800004c4: 00072703 lw a4,0(a4) # 20000 <__stack_size+0x1f800> -800004c8: 0007a603 lw a2,0(a5) -800004cc: 00020537 lui a0,0x20 -800004d0: 30052073 csrs mstatus,a0 -800004d4: 00000517 auipc a0,0x0 -800004d8: 01850513 addi a0,a0,24 # 800004ec -800004dc: 30551073 csrw mtvec,a0 -800004e0: 00100793 li a5,1 -800004e4: 00072803 lw a6,0(a4) -800004e8: 00000793 li a5,0 -800004ec: 00020537 lui a0,0x20 -800004f0: 30053073 csrc mstatus,a0 -800004f4: 08079063 bnez a5,80000574 -800004f8: 01b45793 srli a5,s0,0x1b -800004fc: 01c00513 li a0,28 -80000500: f2f562e3 bltu a0,a5,80000424 -80000504: 80000537 lui a0,0x80000 -80000508: 00279793 slli a5,a5,0x2 -8000050c: 7b850513 addi a0,a0,1976 # 800007b8 <_sp+0xfffff788> -80000510: 00a787b3 add a5,a5,a0 -80000514: 0007a783 lw a5,0(a5) -80000518: 00078067 jr a5 -8000051c: 0ff57513 andi a0,a0,255 -80000520: 1d0000ef jal ra,800006f0 -80000524: 341027f3 csrr a5,mepc -80000528: 00478793 addi a5,a5,4 -8000052c: 34179073 csrw mepc,a5 -80000530: f19ff06f j 80000448 -80000534: fac7a583 lw a1,-84(a5) -80000538: 1d0000ef jal ra,80000708 -8000053c: 08000793 li a5,128 -80000540: 3047a073 csrs mie,a5 -80000544: 02000793 li a5,32 -80000548: 1447b073 csrc sip,a5 -8000054c: 341027f3 csrr a5,mepc -80000550: 00478793 addi a5,a5,4 -80000554: 34179073 csrw mepc,a5 -80000558: ef1ff06f j 80000448 -8000055c: fff00713 li a4,-1 -80000560: fae7a423 sw a4,-88(a5) -80000564: 341027f3 csrr a5,mepc -80000568: 00478793 addi a5,a5,4 -8000056c: 34179073 csrw mepc,a5 -80000570: ed9ff06f j 80000448 -80000574: 800007b7 lui a5,0x80000 -80000578: 07c78793 addi a5,a5,124 # 8000007c <_sp+0xfffff04c> -8000057c: 30579073 csrw mtvec,a5 -80000580: 343027f3 csrr a5,mbadaddr -80000584: 14379073 csrw sbadaddr,a5 -80000588: 342027f3 csrr a5,mcause -8000058c: 14279073 csrw scause,a5 -80000590: 14149073 csrw sepc,s1 -80000594: 105027f3 csrr a5,stvec -80000598: 34179073 csrw mepc,a5 -8000059c: 10000793 li a5,256 -800005a0: 1007b073 csrc sstatus,a5 -800005a4: 0035d593 srli a1,a1,0x3 -800005a8: 1005f593 andi a1,a1,256 -800005ac: 1005a073 csrs sstatus,a1 -800005b0: 000027b7 lui a5,0x2 -800005b4: 80078793 addi a5,a5,-2048 # 1800 <__stack_size+0x1000> -800005b8: 3007b073 csrc mstatus,a5 -800005bc: 000017b7 lui a5,0x1 -800005c0: 88078793 addi a5,a5,-1920 # 880 <__stack_size+0x80> -800005c4: 3007a073 csrs mstatus,a5 -800005c8: e81ff06f j 80000448 -800005cc: 00f45993 srli s3,s0,0xf -800005d0: 01f9f993 andi s3,s3,31 -800005d4: 013039b3 snez s3,s3 -800005d8: de1ff06f j 800003b8 -800005dc: 01060633 add a2,a2,a6 -800005e0: 00545413 srli s0,s0,0x5 -800005e4: 07c47413 andi s0,s0,124 -800005e8: 00d406b3 add a3,s0,a3 -800005ec: 0106a023 sw a6,0(a3) -800005f0: 000207b7 lui a5,0x20 -800005f4: 3007a073 csrs mstatus,a5 -800005f8: 00000797 auipc a5,0x0 -800005fc: 01878793 addi a5,a5,24 # 80000610 -80000600: 30579073 csrw mtvec,a5 -80000604: 00100693 li a3,1 -80000608: 00c72023 sw a2,0(a4) -8000060c: 00000693 li a3,0 -80000610: 000207b7 lui a5,0x20 -80000614: 3007b073 csrc mstatus,a5 -80000618: 800007b7 lui a5,0x80000 -8000061c: 07c78793 addi a5,a5,124 # 8000007c <_sp+0xfffff04c> -80000620: 0a068c63 beqz a3,800006d8 -80000624: 30579073 csrw mtvec,a5 -80000628: 343027f3 csrr a5,mbadaddr -8000062c: 14379073 csrw sbadaddr,a5 -80000630: 342027f3 csrr a5,mcause -80000634: 14279073 csrw scause,a5 -80000638: 14149073 csrw sepc,s1 -8000063c: 105027f3 csrr a5,stvec -80000640: 34179073 csrw mepc,a5 -80000644: 10000793 li a5,256 -80000648: 1007b073 csrc sstatus,a5 -8000064c: 0035d793 srli a5,a1,0x3 -80000650: 1007f793 andi a5,a5,256 -80000654: 1007a073 csrs sstatus,a5 -80000658: f59ff06f j 800005b0 -8000065c: f90672e3 bleu a6,a2,800005e0 -80000660: 00080613 mv a2,a6 -80000664: f7dff06f j 800005e0 -80000668: f6c87ce3 bleu a2,a6,800005e0 -8000066c: 00080613 mv a2,a6 -80000670: f71ff06f j 800005e0 -80000674: 01066633 or a2,a2,a6 -80000678: f69ff06f j 800005e0 -8000067c: 01064633 xor a2,a2,a6 -80000680: f61ff06f j 800005e0 -80000684: f4c85ee3 ble a2,a6,800005e0 -80000688: 00080613 mv a2,a6 -8000068c: f55ff06f j 800005e0 -80000690: 01067633 and a2,a2,a6 -80000694: f4dff06f j 800005e0 -80000698: f50654e3 ble a6,a2,800005e0 -8000069c: 00080613 mv a2,a6 -800006a0: f41ff06f j 800005e0 -800006a4: 044000ef jal ra,800006e8 -800006a8: 343027f3 csrr a5,mbadaddr -800006ac: 14379073 csrw sbadaddr,a5 -800006b0: 341027f3 csrr a5,mepc -800006b4: 14179073 csrw sepc,a5 -800006b8: 342027f3 csrr a5,mcause -800006bc: 14279073 csrw scause,a5 -800006c0: 105027f3 csrr a5,stvec -800006c4: 34179073 csrw mepc,a5 -800006c8: d11ff06f j 800003d8 -800006cc: 02c000ef jal ra,800006f8 -800006d0: 00050913 mv s2,a0 -800006d4: d05ff06f j 800003d8 -800006d8: 00448493 addi s1,s1,4 -800006dc: 34149073 csrw mepc,s1 -800006e0: 30579073 csrw mtvec,a5 -800006e4: d65ff06f j 80000448 +80000354: 3600006f j 800006b4 +80000358: 00777713 andi a4,a4,7 +8000035c: 14f70063 beq a4,a5,8000049c +80000360: 354000ef jal ra,800006b4 +80000364: 343027f3 csrr a5,mtval +80000368: 14379073 csrw stval,a5 +8000036c: 341027f3 csrr a5,mepc +80000370: 14179073 csrw sepc,a5 +80000374: 342027f3 csrr a5,mcause +80000378: 14279073 csrw scause,a5 +8000037c: 105027f3 csrr a5,stvec +80000380: 34179073 csrw mepc,a5 +80000384: 01c12083 lw ra,28(sp) +80000388: 01812403 lw s0,24(sp) +8000038c: 01412483 lw s1,20(sp) +80000390: 01012903 lw s2,16(sp) +80000394: 00c12983 lw s3,12(sp) +80000398: 02010113 addi sp,sp,32 +8000039c: 00008067 ret +800003a0: 0ff7f793 andi a5,a5,255 +800003a4: 00700713 li a4,7 +800003a8: fae79ce3 bne a5,a4,80000360 +800003ac: 02000793 li a5,32 +800003b0: 1447a073 csrs sip,a5 +800003b4: 08000793 li a5,128 +800003b8: 3047b073 csrc mie,a5 +800003bc: 01c12083 lw ra,28(sp) +800003c0: 01812403 lw s0,24(sp) +800003c4: 01412483 lw s1,20(sp) +800003c8: 01012903 lw s2,16(sp) +800003cc: 00c12983 lw s3,12(sp) +800003d0: 02010113 addi sp,sp,32 +800003d4: 00008067 ret +800003d8: 341024f3 csrr s1,mepc +800003dc: 300025f3 csrr a1,mstatus +800003e0: 34302473 csrr s0,mtval +800003e4: 02f00613 li a2,47 +800003e8: 07f47693 andi a3,s0,127 +800003ec: 00c45713 srli a4,s0,0xc +800003f0: f6c684e3 beq a3,a2,80000358 +800003f4: 07300613 li a2,115 +800003f8: f6c694e3 bne a3,a2,80000360 +800003fc: 00377713 andi a4,a4,3 +80000400: 12f70063 beq a4,a5,80000520 +80000404: 00300793 li a5,3 +80000408: 10f70c63 beq a4,a5,80000520 +8000040c: 00100993 li s3,1 +80000410: 03370463 beq a4,s3,80000438 +80000414: 2a0000ef jal ra,800006b4 +80000418: 343027f3 csrr a5,mtval +8000041c: 14379073 csrw stval,a5 +80000420: 341027f3 csrr a5,mepc +80000424: 14179073 csrw sepc,a5 +80000428: 342027f3 csrr a5,mcause +8000042c: 14279073 csrw scause,a5 +80000430: 105027f3 csrr a5,stvec +80000434: 34179073 csrw mepc,a5 +80000438: 000017b7 lui a5,0x1 +8000043c: 01445713 srli a4,s0,0x14 +80000440: c0178693 addi a3,a5,-1023 # c01 <__stack_size+0x401> +80000444: 0ed70663 beq a4,a3,80000530 +80000448: c8178793 addi a5,a5,-895 +8000044c: 0cf70463 beq a4,a5,80000514 +80000450: 264000ef jal ra,800006b4 +80000454: 343027f3 csrr a5,mtval +80000458: 14379073 csrw stval,a5 +8000045c: 341027f3 csrr a5,mepc +80000460: 14179073 csrw sepc,a5 +80000464: 342027f3 csrr a5,mcause +80000468: 14279073 csrw scause,a5 +8000046c: 105027f3 csrr a5,stvec +80000470: 34179073 csrw mepc,a5 +80000474: 1c099063 bnez s3,80000634 +80000478: 00545413 srli s0,s0,0x5 +8000047c: 800017b7 lui a5,0x80001 +80000480: f8878793 addi a5,a5,-120 # 80000f88 <_sp+0xffffff80> +80000484: 07c47413 andi s0,s0,124 +80000488: 00f40433 add s0,s0,a5 +8000048c: 01242023 sw s2,0(s0) +80000490: 00448493 addi s1,s1,4 +80000494: 34149073 csrw mepc,s1 +80000498: eedff06f j 80000384 +8000049c: 00d45713 srli a4,s0,0xd +800004a0: 01245793 srli a5,s0,0x12 +800004a4: 800016b7 lui a3,0x80001 +800004a8: f8868693 addi a3,a3,-120 # 80000f88 <_sp+0xffffff80> +800004ac: 07c77713 andi a4,a4,124 +800004b0: 07c7f793 andi a5,a5,124 +800004b4: 00d70733 add a4,a4,a3 +800004b8: 00d787b3 add a5,a5,a3 +800004bc: 00072703 lw a4,0(a4) # 20000 <__stack_size+0x1f800> +800004c0: 0007a603 lw a2,0(a5) +800004c4: 00020537 lui a0,0x20 +800004c8: 30052073 csrs mstatus,a0 +800004cc: 00000517 auipc a0,0x0 +800004d0: 01850513 addi a0,a0,24 # 800004e4 +800004d4: 30551073 csrw mtvec,a0 +800004d8: 00100793 li a5,1 +800004dc: 00072803 lw a6,0(a4) +800004e0: 00000793 li a5,0 +800004e4: 00020537 lui a0,0x20 +800004e8: 30053073 csrc mstatus,a0 +800004ec: 16079863 bnez a5,8000065c +800004f0: 01b45793 srli a5,s0,0x1b +800004f4: 01c00513 li a0,28 +800004f8: e6f564e3 bltu a0,a5,80000360 +800004fc: 80000537 lui a0,0x80000 +80000500: 00279793 slli a5,a5,0x2 +80000504: 79450513 addi a0,a0,1940 # 80000794 <_sp+0xfffff78c> +80000508: 00a787b3 add a5,a5,a0 +8000050c: 0007a783 lw a5,0(a5) +80000510: 00078067 jr a5 +80000514: 1b8000ef jal ra,800006cc +80000518: 00050913 mv s2,a0 +8000051c: f59ff06f j 80000474 +80000520: 00f45993 srli s3,s0,0xf +80000524: 01f9f993 andi s3,s3,31 +80000528: 013039b3 snez s3,s3 +8000052c: f0dff06f j 80000438 +80000530: 194000ef jal ra,800006c4 +80000534: 00050913 mv s2,a0 +80000538: f3dff06f j 80000474 +8000053c: 01067463 bgeu a2,a6,80000544 +80000540: 00080613 mv a2,a6 +80000544: 00545413 srli s0,s0,0x5 +80000548: 07c47413 andi s0,s0,124 +8000054c: 00d406b3 add a3,s0,a3 +80000550: 0106a023 sw a6,0(a3) +80000554: 000207b7 lui a5,0x20 +80000558: 3007a073 csrs mstatus,a5 +8000055c: 00000797 auipc a5,0x0 +80000560: 01878793 addi a5,a5,24 # 80000574 +80000564: 30579073 csrw mtvec,a5 +80000568: 00100693 li a3,1 +8000056c: 00c72023 sw a2,0(a4) +80000570: 00000693 li a3,0 +80000574: 000207b7 lui a5,0x20 +80000578: 3007b073 csrc mstatus,a5 +8000057c: 800007b7 lui a5,0x80000 +80000580: 07c78793 addi a5,a5,124 # 8000007c <_sp+0xfffff074> +80000584: 0e069063 bnez a3,80000664 +80000588: 00448493 addi s1,s1,4 +8000058c: 34149073 csrw mepc,s1 +80000590: 30579073 csrw mtvec,a5 +80000594: df1ff06f j 80000384 +80000598: 01064633 xor a2,a2,a6 +8000059c: fa9ff06f j 80000544 +800005a0: 01060633 add a2,a2,a6 +800005a4: fa1ff06f j 80000544 +800005a8: 01067633 and a2,a2,a6 +800005ac: f99ff06f j 80000544 +800005b0: 01066633 or a2,a2,a6 +800005b4: f91ff06f j 80000544 +800005b8: f8c876e3 bgeu a6,a2,80000544 +800005bc: 00080613 mv a2,a6 +800005c0: f85ff06f j 80000544 +800005c4: f90650e3 bge a2,a6,80000544 +800005c8: 00080613 mv a2,a6 +800005cc: f79ff06f j 80000544 +800005d0: f6c85ae3 bge a6,a2,80000544 +800005d4: 00080613 mv a2,a6 +800005d8: f6dff06f j 80000544 +800005dc: fff00713 li a4,-1 +800005e0: fae7a423 sw a4,-88(a5) +800005e4: 341027f3 csrr a5,mepc +800005e8: 00478793 addi a5,a5,4 +800005ec: 34179073 csrw mepc,a5 +800005f0: d95ff06f j 80000384 +800005f4: fac7a583 lw a1,-84(a5) +800005f8: 0dc000ef jal ra,800006d4 +800005fc: 08000793 li a5,128 +80000600: 3047a073 csrs mie,a5 +80000604: 02000793 li a5,32 +80000608: 1447b073 csrc sip,a5 +8000060c: 341027f3 csrr a5,mepc +80000610: 00478793 addi a5,a5,4 +80000614: 34179073 csrw mepc,a5 +80000618: d6dff06f j 80000384 +8000061c: 0ff57513 andi a0,a0,255 +80000620: 09c000ef jal ra,800006bc +80000624: 341027f3 csrr a5,mepc +80000628: 00478793 addi a5,a5,4 +8000062c: 34179073 csrw mepc,a5 +80000630: d55ff06f j 80000384 +80000634: 080000ef jal ra,800006b4 +80000638: 343027f3 csrr a5,mtval +8000063c: 14379073 csrw stval,a5 +80000640: 341027f3 csrr a5,mepc +80000644: 14179073 csrw sepc,a5 +80000648: 342027f3 csrr a5,mcause +8000064c: 14279073 csrw scause,a5 +80000650: 105027f3 csrr a5,stvec +80000654: 34179073 csrw mepc,a5 +80000658: e21ff06f j 80000478 +8000065c: 800007b7 lui a5,0x80000 +80000660: 07c78793 addi a5,a5,124 # 8000007c <_sp+0xfffff074> +80000664: 30579073 csrw mtvec,a5 +80000668: 343027f3 csrr a5,mtval +8000066c: 14379073 csrw stval,a5 +80000670: 342027f3 csrr a5,mcause +80000674: 14279073 csrw scause,a5 +80000678: 14149073 csrw sepc,s1 +8000067c: 105027f3 csrr a5,stvec +80000680: 34179073 csrw mepc,a5 +80000684: 10000793 li a5,256 +80000688: 1007b073 csrc sstatus,a5 +8000068c: 0035d793 srli a5,a1,0x3 +80000690: 1007f793 andi a5,a5,256 +80000694: 1007a073 csrs sstatus,a5 +80000698: 000027b7 lui a5,0x2 +8000069c: 80078793 addi a5,a5,-2048 # 1800 <__stack_size+0x1000> +800006a0: 3007b073 csrc mstatus,a5 +800006a4: 000017b7 lui a5,0x1 +800006a8: 88078793 addi a5,a5,-1920 # 880 <__stack_size+0x80> +800006ac: 3007a073 csrs mstatus,a5 +800006b0: cd5ff06f j 80000384 -800006e8 : -800006e8: fe002e23 sw zero,-4(zero) # fffffffc <_sp+0x7fffefcc> -800006ec: 00008067 ret +800006b4 : +800006b4: fe002e23 sw zero,-4(zero) # fffffffc <_sp+0x7fffeff4> +800006b8: 00008067 ret -800006f0 : -800006f0: fea02c23 sw a0,-8(zero) # fffffff8 <_sp+0x7fffefc8> -800006f4: 00008067 ret +800006bc : +800006bc: fea02c23 sw a0,-8(zero) # fffffff8 <_sp+0x7fffeff0> +800006c0: 00008067 ret -800006f8 : -800006f8: fe002503 lw a0,-32(zero) # ffffffe0 <_sp+0x7fffefb0> -800006fc: 00008067 ret +800006c4 : +800006c4: fe002503 lw a0,-32(zero) # ffffffe0 <_sp+0x7fffefd8> +800006c8: 00008067 ret -80000700 : -80000700: fe402503 lw a0,-28(zero) # ffffffe4 <_sp+0x7fffefb4> -80000704: 00008067 ret +800006cc : +800006cc: fe402503 lw a0,-28(zero) # ffffffe4 <_sp+0x7fffefdc> +800006d0: 00008067 ret -80000708 : -80000708: fec00793 li a5,-20 -8000070c: fff00713 li a4,-1 -80000710: 00e7a023 sw a4,0(a5) -80000714: fea02423 sw a0,-24(zero) # ffffffe8 <_sp+0x7fffefb8> -80000718: 00b7a023 sw a1,0(a5) -8000071c: 00008067 ret +800006d4 : +800006d4: fec00793 li a5,-20 +800006d8: fff00713 li a4,-1 +800006dc: 00e7a023 sw a4,0(a5) +800006e0: fea02423 sw a0,-24(zero) # ffffffe8 <_sp+0x7fffefe0> +800006e4: 00b7a023 sw a1,0(a5) +800006e8: 00008067 ret -80000720 <__libc_init_array>: -80000720: ff010113 addi sp,sp,-16 -80000724: 00812423 sw s0,8(sp) -80000728: 00912223 sw s1,4(sp) -8000072c: 00000417 auipc s0,0x0 -80000730: 08c40413 addi s0,s0,140 # 800007b8 <__init_array_end> -80000734: 00000497 auipc s1,0x0 -80000738: 08448493 addi s1,s1,132 # 800007b8 <__init_array_end> -8000073c: 408484b3 sub s1,s1,s0 -80000740: 01212023 sw s2,0(sp) -80000744: 00112623 sw ra,12(sp) -80000748: 4024d493 srai s1,s1,0x2 -8000074c: 00000913 li s2,0 -80000750: 04991063 bne s2,s1,80000790 <__libc_init_array+0x70> -80000754: 00000417 auipc s0,0x0 -80000758: 06440413 addi s0,s0,100 # 800007b8 <__init_array_end> -8000075c: 00000497 auipc s1,0x0 -80000760: 05c48493 addi s1,s1,92 # 800007b8 <__init_array_end> -80000764: 408484b3 sub s1,s1,s0 -80000768: 911ff0ef jal ra,80000078 <_init> -8000076c: 4024d493 srai s1,s1,0x2 -80000770: 00000913 li s2,0 -80000774: 02991863 bne s2,s1,800007a4 <__libc_init_array+0x84> -80000778: 00c12083 lw ra,12(sp) -8000077c: 00812403 lw s0,8(sp) -80000780: 00412483 lw s1,4(sp) -80000784: 00012903 lw s2,0(sp) -80000788: 01010113 addi sp,sp,16 -8000078c: 00008067 ret -80000790: 00042783 lw a5,0(s0) -80000794: 00190913 addi s2,s2,1 -80000798: 00440413 addi s0,s0,4 -8000079c: 000780e7 jalr a5 -800007a0: fb1ff06f j 80000750 <__libc_init_array+0x30> -800007a4: 00042783 lw a5,0(s0) -800007a8: 00190913 addi s2,s2,1 -800007ac: 00440413 addi s0,s0,4 -800007b0: 000780e7 jalr a5 -800007b4: fc1ff06f j 80000774 <__libc_init_array+0x54> +800006ec <__libc_init_array>: +800006ec: ff010113 addi sp,sp,-16 +800006f0: 00000797 auipc a5,0x0 +800006f4: 0a478793 addi a5,a5,164 # 80000794 <__init_array_end> +800006f8: 00812423 sw s0,8(sp) +800006fc: 00000417 auipc s0,0x0 +80000700: 09840413 addi s0,s0,152 # 80000794 <__init_array_end> +80000704: 40f40433 sub s0,s0,a5 +80000708: 00912223 sw s1,4(sp) +8000070c: 01212023 sw s2,0(sp) +80000710: 00112623 sw ra,12(sp) +80000714: 40245413 srai s0,s0,0x2 +80000718: 00000493 li s1,0 +8000071c: 00078913 mv s2,a5 +80000720: 04849263 bne s1,s0,80000764 <__libc_init_array+0x78> +80000724: 955ff0ef jal ra,80000078 <_init> +80000728: 00000797 auipc a5,0x0 +8000072c: 06c78793 addi a5,a5,108 # 80000794 <__init_array_end> +80000730: 00000417 auipc s0,0x0 +80000734: 06440413 addi s0,s0,100 # 80000794 <__init_array_end> +80000738: 40f40433 sub s0,s0,a5 +8000073c: 40245413 srai s0,s0,0x2 +80000740: 00000493 li s1,0 +80000744: 00078913 mv s2,a5 +80000748: 02849a63 bne s1,s0,8000077c <__libc_init_array+0x90> +8000074c: 00c12083 lw ra,12(sp) +80000750: 00812403 lw s0,8(sp) +80000754: 00412483 lw s1,4(sp) +80000758: 00012903 lw s2,0(sp) +8000075c: 01010113 addi sp,sp,16 +80000760: 00008067 ret +80000764: 00249793 slli a5,s1,0x2 +80000768: 00f907b3 add a5,s2,a5 +8000076c: 0007a783 lw a5,0(a5) +80000770: 00148493 addi s1,s1,1 +80000774: 000780e7 jalr a5 +80000778: fa9ff06f j 80000720 <__libc_init_array+0x34> +8000077c: 00249793 slli a5,s1,0x2 +80000780: 00f907b3 add a5,s2,a5 +80000784: 0007a783 lw a5,0(a5) +80000788: 00148493 addi s1,s1,1 +8000078c: 000780e7 jalr a5 +80000790: fb9ff06f j 80000748 <__libc_init_array+0x5c> diff --git a/src/main/c/emulator/build/emulator.bin b/src/main/c/emulator/build/emulator.bin new file mode 100755 index 0000000000000000000000000000000000000000..acae91a4b81c9c2f735ca7ec1334985ddf37d76b GIT binary patch literal 2056 zcmah~QD|I66ut9i=S?E9ed*hF5ru3rZ?nlZ-9Fi^LGU9Bsr%tigqB5rqC8OqAjKr{hW+83zQ9+?K_!V@a@yo0v=_aux-g%oeaW&-Qap&H- z=g!8R`a$IheM;B_z%#ml&VQSCwHkJ~$SfA&$` zfBZvdbQVOI`976*W_MPh@9kB9QfX7s zPUD1o@f4@$v)nsh<|=PhhZ2V|nP1>;A!C<9YMtM73p|Nyka_+Iu5EXqPx;Ncg;26o z^6iFOh}x2eJKRDq?%P3C%YD3gIsyr{0W`w=8Y{c9so2Uc!n3~JBxF}~wgT4SrM0M? z#8|<#sDUzsGK?~casbZ?CB1MNIYNkk&Y?RW;OhRaar!YvaxmO!Zpix=KyEO@Ei$7N z_3uB1c9m~E$0D~?++MDM8|HS1Bky>gxJJg7x&dC4fkZC)`!=`DaUHq1;pgzb7;gAE z;`xU#d_U(M5l6oDWRYuEk#p??xkFUG&RyPQ@-R5Ll@_TNz`3>**sCdcH`9+yybHaN z-*zVM#GTxOnDdz)qZaZdTqejBLc0k;E~q+b$nWROkr8m97R35qIH=Q+^+nEMtcEzM zF0xiTY4UfW^3}>V=A^mBbP#2eJDs-G*+=2lEF-xV0o%3gq^VamIlRuz%sf<;{%i01@@FkeZ zF9D5mpf@@6GQ}Nc*Jsi=a_2Jk2fkMq2cHLO-)6RRou84J?{OB*k;)qz4|*BKos6oP z^}$U37I?Q5PdN6(*wbb+gQ4owhJ0lm?rz+<6RDExG&AFlzQ*Q#5i-|eR z==YGDIw>hGBd;fsgV=XO^|#`(2ru|t_V-l}?DdjU&`<2=t$c^7ZOe%lbv$osJE1Gt zww)OE^{vF4zP?o%Uffh?4^;;@D+BsgeLYpHyt;_*tL)1UOht_zLxnk)-{B6 z9sJe1v9P@gb5Hs_DyFek$gAnJ-~R`G%fFcKZ=6KG<_7$Ii&tGFYIrTzZj zt-ne731Q(sFMu2lXsvA14f?kY R`cDn|e1rZ&gZ={Q{{U(PSS|nn literal 0 HcmV?d00001 diff --git a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala index 7f47e805..269f76a6 100644 --- a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala @@ -309,7 +309,7 @@ class IBusSimplePlugin(resetVector : BigInt, if(catchSomething){ decodeExceptionPort.code.assignDontCare() - decodeExceptionPort.badAddr := join.pc //TODO Should it be the physical address insted ? + decodeExceptionPort.badAddr := join.pc(31 downto 2) @@ "00" if(catchAccessFault) when(join.valid && join.rsp.error){ decodeExceptionPort.code := 1 From 1a36f2689df5ed65f8bf650fdcffc4d2940bdae6 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Sat, 30 Mar 2019 11:24:29 +0100 Subject: [PATCH 092/951] #60 Fix software model. Forgot physical address for on RVC instruction --- src/test/cpp/regression/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 53553337..ca8d6cf3 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -930,7 +930,7 @@ public: trap(0, 4, address); } else { if(v2p(address, &pAddr, READ)){ trap(0, 13, address); return; } - if(dRead(address, 4, &data)) { + if(dRead(pAddr, 4, &data)) { trap(0, 5, address); } else { rfWrite(i16_addr2, data); pcWrite(pc + 2); From 9383445e0b965757a5d7b170b6037318ffc00445 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sat, 30 Mar 2019 18:26:29 +0100 Subject: [PATCH 093/951] Add a qemu option (wip) --- src/main/c/emulator/src/config.h | 2 + src/main/c/emulator/src/hal.c | 106 ++++++++++++++++++++++++++++++- src/main/c/emulator/src/hal.h | 1 + src/main/c/emulator/src/main.c | 14 +++- 4 files changed, 121 insertions(+), 2 deletions(-) diff --git a/src/main/c/emulator/src/config.h b/src/main/c/emulator/src/config.h index 3c1f1aa3..ac6fd014 100644 --- a/src/main/c/emulator/src/config.h +++ b/src/main/c/emulator/src/config.h @@ -1,6 +1,8 @@ #ifndef CONFIG_H #define CONFIG_H +//#define QEMU +#define SIM #define OS_CALL 0xC0000000 #define DTB 0x81000000 diff --git a/src/main/c/emulator/src/hal.c b/src/main/c/emulator/src/hal.c index cdb052df..b2db19e0 100644 --- a/src/main/c/emulator/src/hal.c +++ b/src/main/c/emulator/src/hal.c @@ -1,5 +1,7 @@ #include "hal.h" +#include "config.h" +#ifdef SIM void stopSim(){ *((volatile uint32_t*) 0xFFFFFFFC) = 0; } @@ -16,10 +18,112 @@ uint32_t rdtimeh(){ return *((volatile uint32_t*) 0xFFFFFFE4); } - void setMachineTimerCmp(uint32_t low, uint32_t high){ volatile uint32_t* base = (volatile uint32_t*) 0xFFFFFFE8; base[1] = 0xffffffff; base[0] = low; base[1] = high; } + + +void halInit(){ + +} +#endif + +#ifdef QEMU +#define VIRT_CLINT 0x2000000 +#define SIFIVE_TIMECMP_BASE VIRT_CLINT + 0x4000 +#define SIFIVE_TIME_BASE VIRT_CLINT + 0xBFF8 +#define NS16550A_UART0_CTRL_ADDR 0x10000000 +#define UART0_CLOCK_FREQ 32000000 +#define UART0_BAUD_RATE 115200 +enum { + UART_RBR = 0x00, /* Receive Buffer Register */ + UART_THR = 0x00, /* Transmit Hold Register */ + UART_IER = 0x01, /* Interrupt Enable Register */ + UART_DLL = 0x00, /* Divisor LSB (LCR_DLAB) */ + UART_DLM = 0x01, /* Divisor MSB (LCR_DLAB) */ + UART_FCR = 0x02, /* FIFO Control Register */ + UART_LCR = 0x03, /* Line Control Register */ + UART_MCR = 0x04, /* Modem Control Register */ + UART_LSR = 0x05, /* Line Status Register */ + UART_MSR = 0x06, /* Modem Status Register */ + UART_SCR = 0x07, /* Scratch Register */ + + UART_LCR_DLAB = 0x80, /* Divisor Latch Bit */ + UART_LCR_8BIT = 0x03, /* 8-bit */ + UART_LCR_PODD = 0x08, /* Parity Odd */ + + UART_LSR_DA = 0x01, /* Data Available */ + UART_LSR_OE = 0x02, /* Overrun Error */ + UART_LSR_PE = 0x04, /* Parity Error */ + UART_LSR_FE = 0x08, /* Framing Error */ + UART_LSR_BI = 0x10, /* Break indicator */ + UART_LSR_RE = 0x20, /* THR is empty */ + UART_LSR_RI = 0x40, /* THR is empty and line is idle */ + UART_LSR_EF = 0x80, /* Erroneous data in FIFO */ +}; + +static volatile uint8_t *uart; + +static void ns16550a_init() +{ + uart = (uint8_t *)(void *)(NS16550A_UART0_CTRL_ADDR); + uint32_t uart_freq = (UART0_CLOCK_FREQ); + uint32_t baud_rate = (UART0_BAUD_RATE); + uint32_t divisor = uart_freq / (16 * baud_rate); + uart[UART_LCR] = UART_LCR_DLAB; + uart[UART_DLL] = divisor & 0xff; + uart[UART_DLM] = (divisor >> 8) & 0xff; + uart[UART_LCR] = UART_LCR_PODD | UART_LCR_8BIT; +} + +//static int ns16550a_getchar() +//{ +// if (uart[UART_LSR] & UART_LSR_DA) { +// return uart[UART_RBR]; +// } else { +// return -1; +// } +//} +// +//static int ns16550a_putchar(int ch) +//{ +// while ((uart[UART_LSR] & UART_LSR_RI) == 0); +// return uart[UART_THR] = ch & 0xff; +//} + +void stopSim(){ + *((volatile uint32_t*) 0xFFFFFFFC) = 0; +} + +void putC(char ch){ + while ((uart[UART_LSR] & UART_LSR_RI) == 0); + uart[UART_THR] = ch & 0xff; +} + + +uint32_t rdtime(){ + return *((volatile uint32_t*) SIFIVE_TIME_BASE); +} + +uint32_t rdtimeh(){ + return *((volatile uint32_t*) (SIFIVE_TIME_BASE + 4)); +} + +void setMachineTimerCmp(uint32_t low, uint32_t high){ + volatile uint32_t* base = (volatile uint32_t*) SIFIVE_TIMECMP_BASE; + base[1] = 0xffffffff; + base[0] = low; + base[1] = high; +} + +void halInit(){ + ns16550a_init(); +} +#endif + + + + diff --git a/src/main/c/emulator/src/hal.h b/src/main/c/emulator/src/hal.h index c5cb70ae..90e3df9e 100644 --- a/src/main/c/emulator/src/hal.h +++ b/src/main/c/emulator/src/hal.h @@ -14,6 +14,7 @@ #define SBI_REMOTE_SFENCE_VMA_ASID 7 #define SBI_SHUTDOWN 8 +void halInit(); void stopSim(); void putC(char c); uint32_t rdtime(); diff --git a/src/main/c/emulator/src/main.c b/src/main/c/emulator/src/main.c index bcaf82f0..c637fba0 100755 --- a/src/main/c/emulator/src/main.c +++ b/src/main/c/emulator/src/main.c @@ -7,16 +7,28 @@ extern const uint32_t _sp; extern void trapEntry(); extern void emulationTrap(); +void putString(char* s){ + while(*s){ + putC(*s); + s++; + } +} + void init() { + halInit(); + putString("*** VexRiscv BIOS ***\n"); uint32_t sp = (uint32_t) (&_sp); csr_write(mtvec, trapEntry); csr_write(mscratch, sp -32*4); csr_write(mstatus, 0x0800 | MSTATUS_MPIE); csr_write(mie, 0); csr_write(mepc, OS_CALL); + //In future it would probably need to manage missaligned stuff, now it will stop the simulation csr_write(medeleg, MEDELEG_INSTRUCTION_PAGE_FAULT | MEDELEG_LOAD_PAGE_FAULT | MEDELEG_STORE_PAGE_FAULT | MEDELEG_USER_ENVIRONNEMENT_CALL); csr_write(mideleg, MIDELEG_SUPERVISOR_TIMER | MIDELEG_SUPERVISOR_EXTERNAL | MIDELEG_SUPERVISOR_SOFTWARE); csr_write(sbadaddr, 0); //Used to avoid simulation missmatch + + putString("*** Supervisor ***\n"); } int readRegister(uint32_t id){ @@ -29,7 +41,7 @@ void writeRegister(uint32_t id, int value){ } - +//Currently, this should not happen, unless kernel things are going wrong void redirectTrap(){ stopSim(); csr_write(sbadaddr, csr_read(mbadaddr)); From de500ad8f92ef93a0d5106c4553b6d1d25ac922f Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sat, 30 Mar 2019 18:29:17 +0100 Subject: [PATCH 094/951] Add qemu command --- src/main/scala/vexriscv/demo/Linux.scala | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/scala/vexriscv/demo/Linux.scala b/src/main/scala/vexriscv/demo/Linux.scala index e96260d5..f1790a4c 100644 --- a/src/main/scala/vexriscv/demo/Linux.scala +++ b/src/main/scala/vexriscv/demo/Linux.scala @@ -96,6 +96,10 @@ make run DBUS=SIMPLE IBUS=SIMPLE SUPERVISOR=yes CSR=yes COMPRESSED=yes REDO=0 DH +Qemu => +qemu-system-riscv32 -nographic -machine virt -m 1536M -device loader,file=/home/spinalvm/hdl/VexRiscv/src/main/c/emulator/build/emulator.bin,addr=0x80000000,cpu-num=0 -device loader,file=/home/spinalvm/hdl/riscv-linux/rv32.dtb,addr=0x81000000 -device loader,file=/home/spinalvm/hdl/linux/buildroot/output/images/Image,addr=0xC0000000 + + */ From c7314cc6060dbd09beeea2e7df93c0f456285c2b Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Sun, 31 Mar 2019 15:17:45 +0200 Subject: [PATCH 095/951] Got buildroot login, userspace, commands working Moved location of DTB, initrd. Will move again Added getChar SBI in emulator Added an QEMU mode in the emulator config.h, work with qemu riscv32 virt --- src/main/c/emulator/build/emulator.asm | 900 ++++++++++++----------- src/main/c/emulator/build/emulator.bin | Bin 2056 -> 2320 bytes src/main/c/emulator/src/config.h | 2 +- src/main/c/emulator/src/hal.c | 27 +- src/main/c/emulator/src/hal.h | 1 + src/main/c/emulator/src/main.c | 37 +- src/main/c/emulator/src/riscv.h | 11 + src/main/scala/vexriscv/demo/Linux.scala | 42 +- src/test/cpp/regression/fail.gtkw | 91 +-- src/test/cpp/regression/main.cpp | 80 +- src/test/python/tool/disasm.s | 1 - 11 files changed, 715 insertions(+), 477 deletions(-) delete mode 100644 src/test/python/tool/disasm.s diff --git a/src/main/c/emulator/build/emulator.asm b/src/main/c/emulator/build/emulator.asm index 3a5b2a03..cec2458d 100644 --- a/src/main/c/emulator/build/emulator.asm +++ b/src/main/c/emulator/build/emulator.asm @@ -6,33 +6,33 @@ Disassembly of section .init: 80000000 <_start>: 80000000: 00001117 auipc sp,0x1 -80000004: 00810113 addi sp,sp,8 # 80001008 <_sp> -80000008: 00000517 auipc a0,0x0 -8000000c: 78c50513 addi a0,a0,1932 # 80000794 <__init_array_end> -80000010: 00000597 auipc a1,0x0 -80000014: 78458593 addi a1,a1,1924 # 80000794 <__init_array_end> -80000018: 00000617 auipc a2,0x0 -8000001c: 7f060613 addi a2,a2,2032 # 80000808 <__bss_start> +80000004: 11010113 addi sp,sp,272 # 80001110 <_sp> +80000008: 00001517 auipc a0,0x1 +8000000c: 86450513 addi a0,a0,-1948 # 8000086c <__init_array_end> +80000010: 00001597 auipc a1,0x1 +80000014: 85c58593 addi a1,a1,-1956 # 8000086c <__init_array_end> +80000018: 00001617 auipc a2,0x1 +8000001c: 8f860613 addi a2,a2,-1800 # 80000910 <__bss_start> 80000020: 00c5fc63 bgeu a1,a2,80000038 <_start+0x38> 80000024: 00052283 lw t0,0(a0) 80000028: 0055a023 sw t0,0(a1) 8000002c: 00450513 addi a0,a0,4 80000030: 00458593 addi a1,a1,4 80000034: fec5e8e3 bltu a1,a2,80000024 <_start+0x24> -80000038: 00000517 auipc a0,0x0 -8000003c: 7d050513 addi a0,a0,2000 # 80000808 <__bss_start> -80000040: 00000597 auipc a1,0x0 -80000044: 7c858593 addi a1,a1,1992 # 80000808 <__bss_start> +80000038: 00001517 auipc a0,0x1 +8000003c: 8d850513 addi a0,a0,-1832 # 80000910 <__bss_start> +80000040: 00001597 auipc a1,0x1 +80000044: 8d058593 addi a1,a1,-1840 # 80000910 <__bss_start> 80000048: 00b57863 bgeu a0,a1,80000058 <_start+0x58> 8000004c: 00052023 sw zero,0(a0) 80000050: 00450513 addi a0,a0,4 80000054: feb56ce3 bltu a0,a1,8000004c <_start+0x4c> -80000058: 694000ef jal ra,800006ec <__libc_init_array> -8000005c: 120000ef jal ra,8000017c +80000058: 76c000ef jal ra,800007c4 <__libc_init_array> +8000005c: 17c000ef jal ra,800001d8 80000060: 00000097 auipc ra,0x0 80000064: 01408093 addi ra,ra,20 # 80000074 80000068: 00000513 li a0,0 -8000006c: 810005b7 lui a1,0x81000 +8000006c: c40005b7 lui a1,0xc4000 80000070: 30200073 mret 80000074 : @@ -73,7 +73,7 @@ Disassembly of section .init: 800000ec: 07d12a23 sw t4,116(sp) 800000f0: 07e12c23 sw t5,120(sp) 800000f4: 07f12e23 sw t6,124(sp) -800000f8: 1f4000ef jal ra,800002ec +800000f8: 2c4000ef jal ra,800003bc 800000fc: 00412083 lw ra,4(sp) 80000100: 00c12183 lw gp,12(sp) 80000104: 01012203 lw tp,16(sp) @@ -109,420 +109,482 @@ Disassembly of section .init: Disassembly of section .text: -8000017c : -8000017c: 800007b7 lui a5,0x80000 -80000180: 07c78793 addi a5,a5,124 # 8000007c <_sp+0xfffff074> -80000184: 30579073 csrw mtvec,a5 -80000188: 800017b7 lui a5,0x80001 -8000018c: f8878793 addi a5,a5,-120 # 80000f88 <_sp+0xffffff80> -80000190: 34079073 csrw mscratch,a5 -80000194: 000017b7 lui a5,0x1 -80000198: 88078793 addi a5,a5,-1920 # 880 <__stack_size+0x80> -8000019c: 30079073 csrw mstatus,a5 -800001a0: 30405073 csrwi mie,0 -800001a4: c00007b7 lui a5,0xc0000 -800001a8: 34179073 csrw mepc,a5 -800001ac: 0000b7b7 lui a5,0xb -800001b0: 10078793 addi a5,a5,256 # b100 <__stack_size+0xa900> -800001b4: 30279073 csrw medeleg,a5 -800001b8: 22200793 li a5,546 -800001bc: 30379073 csrw mideleg,a5 -800001c0: 14305073 csrwi stval,0 -800001c4: 00008067 ret +8000017c : +8000017c: ff010113 addi sp,sp,-16 +80000180: 00812423 sw s0,8(sp) +80000184: 00112623 sw ra,12(sp) +80000188: 00050413 mv s0,a0 +8000018c: 00054503 lbu a0,0(a0) +80000190: 00050a63 beqz a0,800001a4 +80000194: 00140413 addi s0,s0,1 +80000198: 5f0000ef jal ra,80000788 +8000019c: 00044503 lbu a0,0(s0) +800001a0: fe051ae3 bnez a0,80000194 +800001a4: 00c12083 lw ra,12(sp) +800001a8: 00812403 lw s0,8(sp) +800001ac: 01010113 addi sp,sp,16 +800001b0: 00008067 ret -800001c8 : -800001c8: 800017b7 lui a5,0x80001 -800001cc: f8878793 addi a5,a5,-120 # 80000f88 <_sp+0xffffff80> -800001d0: 00251513 slli a0,a0,0x2 -800001d4: 00f50533 add a0,a0,a5 -800001d8: 00052503 lw a0,0(a0) -800001dc: 00008067 ret +800001b4 : +800001b4: 01f00793 li a5,31 +800001b8: fff00713 li a4,-1 +800001bc: 00000297 auipc t0,0x0 +800001c0: 01428293 addi t0,t0,20 # 800001d0 +800001c4: 305292f3 csrrw t0,mtvec,t0 +800001c8: 3b071073 csrw pmpaddr0,a4 +800001cc: 3a079073 csrw pmpcfg0,a5 +800001d0: 30529073 csrw mtvec,t0 +800001d4: 00008067 ret -800001e0 : -800001e0: 800017b7 lui a5,0x80001 -800001e4: 00251513 slli a0,a0,0x2 -800001e8: f8878793 addi a5,a5,-120 # 80000f88 <_sp+0xffffff80> -800001ec: 00f50533 add a0,a0,a5 -800001f0: 00b52023 sw a1,0(a0) -800001f4: 00008067 ret +800001d8 : +800001d8: ff010113 addi sp,sp,-16 +800001dc: 00112623 sw ra,12(sp) +800001e0: 00812423 sw s0,8(sp) +800001e4: 01f00793 li a5,31 +800001e8: fff00713 li a4,-1 +800001ec: 00000297 auipc t0,0x0 +800001f0: 01428293 addi t0,t0,20 # 80000200 +800001f4: 305292f3 csrrw t0,mtvec,t0 +800001f8: 3b071073 csrw pmpaddr0,a4 +800001fc: 3a079073 csrw pmpcfg0,a5 +80000200: 30529073 csrw mtvec,t0 +80000204: 80001437 lui s0,0x80001 +80000208: 5b8000ef jal ra,800007c0 +8000020c: 8e040413 addi s0,s0,-1824 # 800008e0 <_sp+0xfffff7d0> +80000210: 02a00513 li a0,42 +80000214: 00140413 addi s0,s0,1 +80000218: 570000ef jal ra,80000788 +8000021c: 00044503 lbu a0,0(s0) +80000220: fe051ae3 bnez a0,80000214 +80000224: 800007b7 lui a5,0x80000 +80000228: 07c78793 addi a5,a5,124 # 8000007c <_sp+0xffffef6c> +8000022c: 30579073 csrw mtvec,a5 +80000230: 800017b7 lui a5,0x80001 +80000234: 09078793 addi a5,a5,144 # 80001090 <_sp+0xffffff80> +80000238: 34079073 csrw mscratch,a5 +8000023c: 000017b7 lui a5,0x1 +80000240: 88078793 addi a5,a5,-1920 # 880 <__stack_size+0x80> +80000244: 30079073 csrw mstatus,a5 +80000248: 30405073 csrwi mie,0 +8000024c: c00007b7 lui a5,0xc0000 +80000250: 34179073 csrw mepc,a5 +80000254: 0000b7b7 lui a5,0xb +80000258: 10078793 addi a5,a5,256 # b100 <__stack_size+0xa900> +8000025c: 30279073 csrw medeleg,a5 +80000260: 22200793 li a5,546 +80000264: 30379073 csrw mideleg,a5 +80000268: 14305073 csrwi stval,0 +8000026c: 80001437 lui s0,0x80001 +80000270: 8f840413 addi s0,s0,-1800 # 800008f8 <_sp+0xfffff7e8> +80000274: 02a00513 li a0,42 +80000278: 00140413 addi s0,s0,1 +8000027c: 50c000ef jal ra,80000788 +80000280: 00044503 lbu a0,0(s0) +80000284: fe051ae3 bnez a0,80000278 +80000288: 00c12083 lw ra,12(sp) +8000028c: 00812403 lw s0,8(sp) +80000290: 01010113 addi sp,sp,16 +80000294: 00008067 ret -800001f8 : -800001f8: ff010113 addi sp,sp,-16 -800001fc: 00112623 sw ra,12(sp) -80000200: 4b4000ef jal ra,800006b4 -80000204: 343027f3 csrr a5,mtval -80000208: 14379073 csrw stval,a5 -8000020c: 341027f3 csrr a5,mepc -80000210: 14179073 csrw sepc,a5 -80000214: 342027f3 csrr a5,mcause -80000218: 14279073 csrw scause,a5 -8000021c: 105027f3 csrr a5,stvec -80000220: 34179073 csrw mepc,a5 -80000224: 00c12083 lw ra,12(sp) -80000228: 01010113 addi sp,sp,16 -8000022c: 00008067 ret +80000298 : +80000298: 800017b7 lui a5,0x80001 +8000029c: 09078793 addi a5,a5,144 # 80001090 <_sp+0xffffff80> +800002a0: 00251513 slli a0,a0,0x2 +800002a4: 00f50533 add a0,a0,a5 +800002a8: 00052503 lw a0,0(a0) +800002ac: 00008067 ret -80000230 : -80000230: 800007b7 lui a5,0x80000 -80000234: 07c78793 addi a5,a5,124 # 8000007c <_sp+0xfffff074> -80000238: 30579073 csrw mtvec,a5 -8000023c: 343027f3 csrr a5,mtval -80000240: 14379073 csrw stval,a5 -80000244: 342027f3 csrr a5,mcause -80000248: 14279073 csrw scause,a5 -8000024c: 14151073 csrw sepc,a0 -80000250: 105027f3 csrr a5,stvec -80000254: 34179073 csrw mepc,a5 -80000258: 10000793 li a5,256 -8000025c: 1007b073 csrc sstatus,a5 -80000260: 0035d593 srli a1,a1,0x3 -80000264: 1005f593 andi a1,a1,256 -80000268: 1005a073 csrs sstatus,a1 -8000026c: 000027b7 lui a5,0x2 -80000270: 80078793 addi a5,a5,-2048 # 1800 <__stack_size+0x1000> -80000274: 3007b073 csrc mstatus,a5 -80000278: 000017b7 lui a5,0x1 -8000027c: 88078793 addi a5,a5,-1920 # 880 <__stack_size+0x80> -80000280: 3007a073 csrs mstatus,a5 -80000284: 00008067 ret +800002b0 : +800002b0: 800017b7 lui a5,0x80001 +800002b4: 00251513 slli a0,a0,0x2 +800002b8: 09078793 addi a5,a5,144 # 80001090 <_sp+0xffffff80> +800002bc: 00f50533 add a0,a0,a5 +800002c0: 00b52023 sw a1,0(a0) +800002c4: 00008067 ret -80000288 : -80000288: 00020737 lui a4,0x20 -8000028c: 30072073 csrs mstatus,a4 -80000290: 00000717 auipc a4,0x0 -80000294: 01870713 addi a4,a4,24 # 800002a8 -80000298: 30571073 csrw mtvec,a4 -8000029c: 00100693 li a3,1 -800002a0: 00052783 lw a5,0(a0) -800002a4: 00000693 li a3,0 -800002a8: 00020737 lui a4,0x20 -800002ac: 30073073 csrc mstatus,a4 -800002b0: 00068513 mv a0,a3 -800002b4: 00f5a023 sw a5,0(a1) # 81000000 <_sp+0xffeff8> -800002b8: 00008067 ret +800002c8 : +800002c8: ff010113 addi sp,sp,-16 +800002cc: 00112623 sw ra,12(sp) +800002d0: 4b0000ef jal ra,80000780 +800002d4: 343027f3 csrr a5,mtval +800002d8: 14379073 csrw stval,a5 +800002dc: 341027f3 csrr a5,mepc +800002e0: 14179073 csrw sepc,a5 +800002e4: 342027f3 csrr a5,mcause +800002e8: 14279073 csrw scause,a5 +800002ec: 105027f3 csrr a5,stvec +800002f0: 34179073 csrw mepc,a5 +800002f4: 00c12083 lw ra,12(sp) +800002f8: 01010113 addi sp,sp,16 +800002fc: 00008067 ret -800002bc : -800002bc: 00020737 lui a4,0x20 -800002c0: 30072073 csrs mstatus,a4 -800002c4: 00000717 auipc a4,0x0 -800002c8: 01870713 addi a4,a4,24 # 800002dc -800002cc: 30571073 csrw mtvec,a4 -800002d0: 00100793 li a5,1 -800002d4: 00b52023 sw a1,0(a0) -800002d8: 00000793 li a5,0 -800002dc: 00020737 lui a4,0x20 -800002e0: 30073073 csrc mstatus,a4 -800002e4: 00078513 mv a0,a5 -800002e8: 00008067 ret +80000300 : +80000300: 800007b7 lui a5,0x80000 +80000304: 07c78793 addi a5,a5,124 # 8000007c <_sp+0xffffef6c> +80000308: 30579073 csrw mtvec,a5 +8000030c: 343027f3 csrr a5,mtval +80000310: 14379073 csrw stval,a5 +80000314: 342027f3 csrr a5,mcause +80000318: 14279073 csrw scause,a5 +8000031c: 14151073 csrw sepc,a0 +80000320: 105027f3 csrr a5,stvec +80000324: 34179073 csrw mepc,a5 +80000328: 10000793 li a5,256 +8000032c: 1007b073 csrc sstatus,a5 +80000330: 0035d593 srli a1,a1,0x3 +80000334: 1005f593 andi a1,a1,256 +80000338: 1005a073 csrs sstatus,a1 +8000033c: 000027b7 lui a5,0x2 +80000340: 80078793 addi a5,a5,-2048 # 1800 <__stack_size+0x1000> +80000344: 3007b073 csrc mstatus,a5 +80000348: 000017b7 lui a5,0x1 +8000034c: 88078793 addi a5,a5,-1920 # 880 <__stack_size+0x80> +80000350: 3007a073 csrs mstatus,a5 +80000354: 00008067 ret -800002ec : -800002ec: fe010113 addi sp,sp,-32 -800002f0: 00112e23 sw ra,28(sp) -800002f4: 00812c23 sw s0,24(sp) -800002f8: 00912a23 sw s1,20(sp) -800002fc: 01212823 sw s2,16(sp) -80000300: 01312623 sw s3,12(sp) -80000304: 342027f3 csrr a5,mcause -80000308: 0807cc63 bltz a5,800003a0 -8000030c: 00200713 li a4,2 -80000310: 0ce78463 beq a5,a4,800003d8 -80000314: 00900693 li a3,9 -80000318: 04d79463 bne a5,a3,80000360 -8000031c: 800017b7 lui a5,0x80001 -80000320: 00878793 addi a5,a5,8 # 80001008 <_sp+0x0> -80000324: fc47a683 lw a3,-60(a5) -80000328: 00100613 li a2,1 -8000032c: fa87a503 lw a0,-88(a5) -80000330: 2ec68663 beq a3,a2,8000061c -80000334: 2ae68463 beq a3,a4,800005dc -80000338: 2a068e63 beqz a3,800005f4 -8000033c: 01812403 lw s0,24(sp) -80000340: 01c12083 lw ra,28(sp) -80000344: 01412483 lw s1,20(sp) -80000348: 01012903 lw s2,16(sp) -8000034c: 00c12983 lw s3,12(sp) -80000350: 02010113 addi sp,sp,32 -80000354: 3600006f j 800006b4 -80000358: 00777713 andi a4,a4,7 -8000035c: 14f70063 beq a4,a5,8000049c -80000360: 354000ef jal ra,800006b4 -80000364: 343027f3 csrr a5,mtval -80000368: 14379073 csrw stval,a5 -8000036c: 341027f3 csrr a5,mepc -80000370: 14179073 csrw sepc,a5 -80000374: 342027f3 csrr a5,mcause -80000378: 14279073 csrw scause,a5 -8000037c: 105027f3 csrr a5,stvec -80000380: 34179073 csrw mepc,a5 -80000384: 01c12083 lw ra,28(sp) -80000388: 01812403 lw s0,24(sp) -8000038c: 01412483 lw s1,20(sp) -80000390: 01012903 lw s2,16(sp) -80000394: 00c12983 lw s3,12(sp) -80000398: 02010113 addi sp,sp,32 -8000039c: 00008067 ret -800003a0: 0ff7f793 andi a5,a5,255 -800003a4: 00700713 li a4,7 -800003a8: fae79ce3 bne a5,a4,80000360 -800003ac: 02000793 li a5,32 -800003b0: 1447a073 csrs sip,a5 -800003b4: 08000793 li a5,128 -800003b8: 3047b073 csrc mie,a5 -800003bc: 01c12083 lw ra,28(sp) -800003c0: 01812403 lw s0,24(sp) -800003c4: 01412483 lw s1,20(sp) -800003c8: 01012903 lw s2,16(sp) -800003cc: 00c12983 lw s3,12(sp) -800003d0: 02010113 addi sp,sp,32 -800003d4: 00008067 ret -800003d8: 341024f3 csrr s1,mepc -800003dc: 300025f3 csrr a1,mstatus -800003e0: 34302473 csrr s0,mtval -800003e4: 02f00613 li a2,47 -800003e8: 07f47693 andi a3,s0,127 -800003ec: 00c45713 srli a4,s0,0xc -800003f0: f6c684e3 beq a3,a2,80000358 -800003f4: 07300613 li a2,115 -800003f8: f6c694e3 bne a3,a2,80000360 -800003fc: 00377713 andi a4,a4,3 -80000400: 12f70063 beq a4,a5,80000520 -80000404: 00300793 li a5,3 -80000408: 10f70c63 beq a4,a5,80000520 -8000040c: 00100993 li s3,1 -80000410: 03370463 beq a4,s3,80000438 -80000414: 2a0000ef jal ra,800006b4 -80000418: 343027f3 csrr a5,mtval -8000041c: 14379073 csrw stval,a5 -80000420: 341027f3 csrr a5,mepc -80000424: 14179073 csrw sepc,a5 -80000428: 342027f3 csrr a5,mcause -8000042c: 14279073 csrw scause,a5 -80000430: 105027f3 csrr a5,stvec -80000434: 34179073 csrw mepc,a5 -80000438: 000017b7 lui a5,0x1 -8000043c: 01445713 srli a4,s0,0x14 -80000440: c0178693 addi a3,a5,-1023 # c01 <__stack_size+0x401> -80000444: 0ed70663 beq a4,a3,80000530 -80000448: c8178793 addi a5,a5,-895 -8000044c: 0cf70463 beq a4,a5,80000514 -80000450: 264000ef jal ra,800006b4 -80000454: 343027f3 csrr a5,mtval -80000458: 14379073 csrw stval,a5 -8000045c: 341027f3 csrr a5,mepc -80000460: 14179073 csrw sepc,a5 -80000464: 342027f3 csrr a5,mcause -80000468: 14279073 csrw scause,a5 -8000046c: 105027f3 csrr a5,stvec -80000470: 34179073 csrw mepc,a5 -80000474: 1c099063 bnez s3,80000634 -80000478: 00545413 srli s0,s0,0x5 -8000047c: 800017b7 lui a5,0x80001 -80000480: f8878793 addi a5,a5,-120 # 80000f88 <_sp+0xffffff80> -80000484: 07c47413 andi s0,s0,124 -80000488: 00f40433 add s0,s0,a5 -8000048c: 01242023 sw s2,0(s0) -80000490: 00448493 addi s1,s1,4 -80000494: 34149073 csrw mepc,s1 -80000498: eedff06f j 80000384 -8000049c: 00d45713 srli a4,s0,0xd -800004a0: 01245793 srli a5,s0,0x12 -800004a4: 800016b7 lui a3,0x80001 -800004a8: f8868693 addi a3,a3,-120 # 80000f88 <_sp+0xffffff80> -800004ac: 07c77713 andi a4,a4,124 -800004b0: 07c7f793 andi a5,a5,124 -800004b4: 00d70733 add a4,a4,a3 -800004b8: 00d787b3 add a5,a5,a3 -800004bc: 00072703 lw a4,0(a4) # 20000 <__stack_size+0x1f800> -800004c0: 0007a603 lw a2,0(a5) -800004c4: 00020537 lui a0,0x20 -800004c8: 30052073 csrs mstatus,a0 -800004cc: 00000517 auipc a0,0x0 -800004d0: 01850513 addi a0,a0,24 # 800004e4 -800004d4: 30551073 csrw mtvec,a0 -800004d8: 00100793 li a5,1 -800004dc: 00072803 lw a6,0(a4) -800004e0: 00000793 li a5,0 -800004e4: 00020537 lui a0,0x20 -800004e8: 30053073 csrc mstatus,a0 -800004ec: 16079863 bnez a5,8000065c -800004f0: 01b45793 srli a5,s0,0x1b -800004f4: 01c00513 li a0,28 -800004f8: e6f564e3 bltu a0,a5,80000360 -800004fc: 80000537 lui a0,0x80000 -80000500: 00279793 slli a5,a5,0x2 -80000504: 79450513 addi a0,a0,1940 # 80000794 <_sp+0xfffff78c> -80000508: 00a787b3 add a5,a5,a0 -8000050c: 0007a783 lw a5,0(a5) -80000510: 00078067 jr a5 -80000514: 1b8000ef jal ra,800006cc -80000518: 00050913 mv s2,a0 -8000051c: f59ff06f j 80000474 -80000520: 00f45993 srli s3,s0,0xf -80000524: 01f9f993 andi s3,s3,31 -80000528: 013039b3 snez s3,s3 -8000052c: f0dff06f j 80000438 -80000530: 194000ef jal ra,800006c4 -80000534: 00050913 mv s2,a0 -80000538: f3dff06f j 80000474 -8000053c: 01067463 bgeu a2,a6,80000544 -80000540: 00080613 mv a2,a6 -80000544: 00545413 srli s0,s0,0x5 -80000548: 07c47413 andi s0,s0,124 -8000054c: 00d406b3 add a3,s0,a3 -80000550: 0106a023 sw a6,0(a3) -80000554: 000207b7 lui a5,0x20 -80000558: 3007a073 csrs mstatus,a5 -8000055c: 00000797 auipc a5,0x0 -80000560: 01878793 addi a5,a5,24 # 80000574 -80000564: 30579073 csrw mtvec,a5 -80000568: 00100693 li a3,1 -8000056c: 00c72023 sw a2,0(a4) -80000570: 00000693 li a3,0 -80000574: 000207b7 lui a5,0x20 -80000578: 3007b073 csrc mstatus,a5 -8000057c: 800007b7 lui a5,0x80000 -80000580: 07c78793 addi a5,a5,124 # 8000007c <_sp+0xfffff074> -80000584: 0e069063 bnez a3,80000664 -80000588: 00448493 addi s1,s1,4 -8000058c: 34149073 csrw mepc,s1 -80000590: 30579073 csrw mtvec,a5 -80000594: df1ff06f j 80000384 -80000598: 01064633 xor a2,a2,a6 -8000059c: fa9ff06f j 80000544 -800005a0: 01060633 add a2,a2,a6 -800005a4: fa1ff06f j 80000544 -800005a8: 01067633 and a2,a2,a6 -800005ac: f99ff06f j 80000544 -800005b0: 01066633 or a2,a2,a6 -800005b4: f91ff06f j 80000544 -800005b8: f8c876e3 bgeu a6,a2,80000544 -800005bc: 00080613 mv a2,a6 -800005c0: f85ff06f j 80000544 -800005c4: f90650e3 bge a2,a6,80000544 -800005c8: 00080613 mv a2,a6 -800005cc: f79ff06f j 80000544 -800005d0: f6c85ae3 bge a6,a2,80000544 -800005d4: 00080613 mv a2,a6 -800005d8: f6dff06f j 80000544 -800005dc: fff00713 li a4,-1 -800005e0: fae7a423 sw a4,-88(a5) -800005e4: 341027f3 csrr a5,mepc -800005e8: 00478793 addi a5,a5,4 -800005ec: 34179073 csrw mepc,a5 -800005f0: d95ff06f j 80000384 -800005f4: fac7a583 lw a1,-84(a5) -800005f8: 0dc000ef jal ra,800006d4 -800005fc: 08000793 li a5,128 -80000600: 3047a073 csrs mie,a5 -80000604: 02000793 li a5,32 -80000608: 1447b073 csrc sip,a5 -8000060c: 341027f3 csrr a5,mepc -80000610: 00478793 addi a5,a5,4 -80000614: 34179073 csrw mepc,a5 -80000618: d6dff06f j 80000384 -8000061c: 0ff57513 andi a0,a0,255 -80000620: 09c000ef jal ra,800006bc -80000624: 341027f3 csrr a5,mepc -80000628: 00478793 addi a5,a5,4 -8000062c: 34179073 csrw mepc,a5 -80000630: d55ff06f j 80000384 -80000634: 080000ef jal ra,800006b4 -80000638: 343027f3 csrr a5,mtval -8000063c: 14379073 csrw stval,a5 -80000640: 341027f3 csrr a5,mepc -80000644: 14179073 csrw sepc,a5 -80000648: 342027f3 csrr a5,mcause -8000064c: 14279073 csrw scause,a5 -80000650: 105027f3 csrr a5,stvec -80000654: 34179073 csrw mepc,a5 -80000658: e21ff06f j 80000478 -8000065c: 800007b7 lui a5,0x80000 -80000660: 07c78793 addi a5,a5,124 # 8000007c <_sp+0xfffff074> -80000664: 30579073 csrw mtvec,a5 -80000668: 343027f3 csrr a5,mtval -8000066c: 14379073 csrw stval,a5 -80000670: 342027f3 csrr a5,mcause -80000674: 14279073 csrw scause,a5 -80000678: 14149073 csrw sepc,s1 -8000067c: 105027f3 csrr a5,stvec -80000680: 34179073 csrw mepc,a5 -80000684: 10000793 li a5,256 -80000688: 1007b073 csrc sstatus,a5 -8000068c: 0035d793 srli a5,a1,0x3 -80000690: 1007f793 andi a5,a5,256 -80000694: 1007a073 csrs sstatus,a5 -80000698: 000027b7 lui a5,0x2 -8000069c: 80078793 addi a5,a5,-2048 # 1800 <__stack_size+0x1000> -800006a0: 3007b073 csrc mstatus,a5 -800006a4: 000017b7 lui a5,0x1 -800006a8: 88078793 addi a5,a5,-1920 # 880 <__stack_size+0x80> -800006ac: 3007a073 csrs mstatus,a5 -800006b0: cd5ff06f j 80000384 +80000358 : +80000358: 00020737 lui a4,0x20 +8000035c: 30072073 csrs mstatus,a4 +80000360: 00000717 auipc a4,0x0 +80000364: 01870713 addi a4,a4,24 # 80000378 +80000368: 30571073 csrw mtvec,a4 +8000036c: 00100693 li a3,1 +80000370: 00052783 lw a5,0(a0) +80000374: 00000693 li a3,0 +80000378: 00020737 lui a4,0x20 +8000037c: 30073073 csrc mstatus,a4 +80000380: 00068513 mv a0,a3 +80000384: 00f5a023 sw a5,0(a1) # c4000000 <_sp+0x43ffeef0> +80000388: 00008067 ret -800006b4 : -800006b4: fe002e23 sw zero,-4(zero) # fffffffc <_sp+0x7fffeff4> -800006b8: 00008067 ret +8000038c : +8000038c: 00020737 lui a4,0x20 +80000390: 30072073 csrs mstatus,a4 +80000394: 00000717 auipc a4,0x0 +80000398: 01870713 addi a4,a4,24 # 800003ac +8000039c: 30571073 csrw mtvec,a4 +800003a0: 00100793 li a5,1 +800003a4: 00b52023 sw a1,0(a0) +800003a8: 00000793 li a5,0 +800003ac: 00020737 lui a4,0x20 +800003b0: 30073073 csrc mstatus,a4 +800003b4: 00078513 mv a0,a5 +800003b8: 00008067 ret -800006bc : -800006bc: fea02c23 sw a0,-8(zero) # fffffff8 <_sp+0x7fffeff0> -800006c0: 00008067 ret +800003bc : +800003bc: fe010113 addi sp,sp,-32 +800003c0: 00112e23 sw ra,28(sp) +800003c4: 00812c23 sw s0,24(sp) +800003c8: 00912a23 sw s1,20(sp) +800003cc: 01212823 sw s2,16(sp) +800003d0: 01312623 sw s3,12(sp) +800003d4: 342027f3 csrr a5,mcause +800003d8: 0807cc63 bltz a5,80000470 +800003dc: 00200713 li a4,2 +800003e0: 0ce78463 beq a5,a4,800004a8 +800003e4: 00900693 li a3,9 +800003e8: 04d79463 bne a5,a3,80000430 +800003ec: 80001437 lui s0,0x80001 +800003f0: 11040413 addi s0,s0,272 # 80001110 <_sp+0x0> +800003f4: fc442783 lw a5,-60(s0) +800003f8: 00100693 li a3,1 +800003fc: fa842503 lw a0,-88(s0) +80000400: 2ed78863 beq a5,a3,800006f0 +80000404: 2ae78663 beq a5,a4,800006b0 +80000408: 2c078063 beqz a5,800006c8 +8000040c: 01812403 lw s0,24(sp) +80000410: 01c12083 lw ra,28(sp) +80000414: 01412483 lw s1,20(sp) +80000418: 01012903 lw s2,16(sp) +8000041c: 00c12983 lw s3,12(sp) +80000420: 02010113 addi sp,sp,32 +80000424: 35c0006f j 80000780 +80000428: 0076f693 andi a3,a3,7 +8000042c: 14f68663 beq a3,a5,80000578 +80000430: 350000ef jal ra,80000780 +80000434: 343027f3 csrr a5,mtval +80000438: 14379073 csrw stval,a5 +8000043c: 341027f3 csrr a5,mepc +80000440: 14179073 csrw sepc,a5 +80000444: 342027f3 csrr a5,mcause +80000448: 14279073 csrw scause,a5 +8000044c: 105027f3 csrr a5,stvec +80000450: 34179073 csrw mepc,a5 +80000454: 01c12083 lw ra,28(sp) +80000458: 01812403 lw s0,24(sp) +8000045c: 01412483 lw s1,20(sp) +80000460: 01012903 lw s2,16(sp) +80000464: 00c12983 lw s3,12(sp) +80000468: 02010113 addi sp,sp,32 +8000046c: 00008067 ret +80000470: 0ff7f793 andi a5,a5,255 +80000474: 00700713 li a4,7 +80000478: fae79ce3 bne a5,a4,80000430 +8000047c: 02000793 li a5,32 +80000480: 1447a073 csrs sip,a5 +80000484: 08000793 li a5,128 +80000488: 3047b073 csrc mie,a5 +8000048c: 01c12083 lw ra,28(sp) +80000490: 01812403 lw s0,24(sp) +80000494: 01412483 lw s1,20(sp) +80000498: 01012903 lw s2,16(sp) +8000049c: 00c12983 lw s3,12(sp) +800004a0: 02010113 addi sp,sp,32 +800004a4: 00008067 ret +800004a8: 34102973 csrr s2,mepc +800004ac: 30002573 csrr a0,mstatus +800004b0: 34302473 csrr s0,mtval +800004b4: 80000737 lui a4,0x80000 +800004b8: 07c70713 addi a4,a4,124 # 8000007c <_sp+0xffffef6c> +800004bc: 30571073 csrw mtvec,a4 +800004c0: 02f00593 li a1,47 +800004c4: 07f47613 andi a2,s0,127 +800004c8: 00c45693 srli a3,s0,0xc +800004cc: f4b60ee3 beq a2,a1,80000428 +800004d0: 07300713 li a4,115 +800004d4: f4e61ee3 bne a2,a4,80000430 +800004d8: 0036f693 andi a3,a3,3 +800004dc: 12f68063 beq a3,a5,800005fc +800004e0: 00300793 li a5,3 +800004e4: 10f68c63 beq a3,a5,800005fc +800004e8: 00100993 li s3,1 +800004ec: 03368463 beq a3,s3,80000514 +800004f0: 290000ef jal ra,80000780 +800004f4: 343027f3 csrr a5,mtval +800004f8: 14379073 csrw stval,a5 +800004fc: 341027f3 csrr a5,mepc +80000500: 14179073 csrw sepc,a5 +80000504: 342027f3 csrr a5,mcause +80000508: 14279073 csrw scause,a5 +8000050c: 105027f3 csrr a5,stvec +80000510: 34179073 csrw mepc,a5 +80000514: 000017b7 lui a5,0x1 +80000518: 01445713 srli a4,s0,0x14 +8000051c: c0178693 addi a3,a5,-1023 # c01 <__stack_size+0x401> +80000520: 0ed70663 beq a4,a3,8000060c +80000524: c8178793 addi a5,a5,-895 +80000528: 0cf70463 beq a4,a5,800005f0 +8000052c: 254000ef jal ra,80000780 +80000530: 343027f3 csrr a5,mtval +80000534: 14379073 csrw stval,a5 +80000538: 341027f3 csrr a5,mepc +8000053c: 14179073 csrw sepc,a5 +80000540: 342027f3 csrr a5,mcause +80000544: 14279073 csrw scause,a5 +80000548: 105027f3 csrr a5,stvec +8000054c: 34179073 csrw mepc,a5 +80000550: 1a099c63 bnez s3,80000708 +80000554: 00545413 srli s0,s0,0x5 +80000558: 800017b7 lui a5,0x80001 +8000055c: 09078793 addi a5,a5,144 # 80001090 <_sp+0xffffff80> +80000560: 07c47413 andi s0,s0,124 +80000564: 00f40433 add s0,s0,a5 +80000568: 00942023 sw s1,0(s0) +8000056c: 00490793 addi a5,s2,4 +80000570: 34179073 csrw mepc,a5 +80000574: ee1ff06f j 80000454 +80000578: 00d45693 srli a3,s0,0xd +8000057c: 01245793 srli a5,s0,0x12 +80000580: 80001637 lui a2,0x80001 +80000584: 09060613 addi a2,a2,144 # 80001090 <_sp+0xffffff80> +80000588: 07c6f693 andi a3,a3,124 +8000058c: 07c7f793 andi a5,a5,124 +80000590: 00c686b3 add a3,a3,a2 +80000594: 00c787b3 add a5,a5,a2 +80000598: 0006a683 lw a3,0(a3) +8000059c: 0007a583 lw a1,0(a5) +800005a0: 00020837 lui a6,0x20 +800005a4: 30082073 csrs mstatus,a6 +800005a8: 00000817 auipc a6,0x0 +800005ac: 01880813 addi a6,a6,24 # 800005c0 +800005b0: 30581073 csrw mtvec,a6 +800005b4: 00100793 li a5,1 +800005b8: 0006a883 lw a7,0(a3) +800005bc: 00000793 li a5,0 +800005c0: 00020837 lui a6,0x20 +800005c4: 30083073 csrc mstatus,a6 +800005c8: 16079463 bnez a5,80000730 +800005cc: 01b45793 srli a5,s0,0x1b +800005d0: 01c00813 li a6,28 +800005d4: e4f86ee3 bltu a6,a5,80000430 +800005d8: 80001837 lui a6,0x80001 +800005dc: 00279793 slli a5,a5,0x2 +800005e0: 86c80813 addi a6,a6,-1940 # 8000086c <_sp+0xfffff75c> +800005e4: 010787b3 add a5,a5,a6 +800005e8: 0007a783 lw a5,0(a5) +800005ec: 00078067 jr a5 +800005f0: 1b0000ef jal ra,800007a0 +800005f4: 00050493 mv s1,a0 +800005f8: f59ff06f j 80000550 +800005fc: 00f45993 srli s3,s0,0xf +80000600: 01f9f993 andi s3,s3,31 +80000604: 013039b3 snez s3,s3 +80000608: f0dff06f j 80000514 +8000060c: 18c000ef jal ra,80000798 +80000610: 00050493 mv s1,a0 +80000614: f3dff06f j 80000550 +80000618: 0115f463 bgeu a1,a7,80000620 +8000061c: 00088593 mv a1,a7 +80000620: 00545413 srli s0,s0,0x5 +80000624: 07c47413 andi s0,s0,124 +80000628: 00c40633 add a2,s0,a2 +8000062c: 01162023 sw a7,0(a2) +80000630: 00020637 lui a2,0x20 +80000634: 30062073 csrs mstatus,a2 +80000638: 00000617 auipc a2,0x0 +8000063c: 01860613 addi a2,a2,24 # 80000650 +80000640: 30561073 csrw mtvec,a2 +80000644: 00100793 li a5,1 +80000648: 00b6a023 sw a1,0(a3) +8000064c: 00000793 li a5,0 +80000650: 00020637 lui a2,0x20 +80000654: 30063073 csrc mstatus,a2 +80000658: 0c079c63 bnez a5,80000730 +8000065c: 00490793 addi a5,s2,4 +80000660: 34179073 csrw mepc,a5 +80000664: 30571073 csrw mtvec,a4 +80000668: dedff06f j 80000454 +8000066c: 0115c5b3 xor a1,a1,a7 +80000670: fb1ff06f j 80000620 +80000674: 011585b3 add a1,a1,a7 +80000678: fa9ff06f j 80000620 +8000067c: 0115f5b3 and a1,a1,a7 +80000680: fa1ff06f j 80000620 +80000684: 0115e5b3 or a1,a1,a7 +80000688: f99ff06f j 80000620 +8000068c: f8b8fae3 bgeu a7,a1,80000620 +80000690: 00088593 mv a1,a7 +80000694: f8dff06f j 80000620 +80000698: f915d4e3 bge a1,a7,80000620 +8000069c: 00088593 mv a1,a7 +800006a0: f81ff06f j 80000620 +800006a4: f6b8dee3 bge a7,a1,80000620 +800006a8: 00088593 mv a1,a7 +800006ac: f75ff06f j 80000620 +800006b0: 0e0000ef jal ra,80000790 +800006b4: faa42423 sw a0,-88(s0) +800006b8: 341027f3 csrr a5,mepc +800006bc: 00478793 addi a5,a5,4 +800006c0: 34179073 csrw mepc,a5 +800006c4: d91ff06f j 80000454 +800006c8: fac42583 lw a1,-84(s0) +800006cc: 0dc000ef jal ra,800007a8 +800006d0: 08000793 li a5,128 +800006d4: 3047a073 csrs mie,a5 +800006d8: 02000793 li a5,32 +800006dc: 1447b073 csrc sip,a5 +800006e0: 341027f3 csrr a5,mepc +800006e4: 00478793 addi a5,a5,4 +800006e8: 34179073 csrw mepc,a5 +800006ec: d69ff06f j 80000454 +800006f0: 0ff57513 andi a0,a0,255 +800006f4: 094000ef jal ra,80000788 +800006f8: 341027f3 csrr a5,mepc +800006fc: 00478793 addi a5,a5,4 +80000700: 34179073 csrw mepc,a5 +80000704: d51ff06f j 80000454 +80000708: 078000ef jal ra,80000780 +8000070c: 343027f3 csrr a5,mtval +80000710: 14379073 csrw stval,a5 +80000714: 341027f3 csrr a5,mepc +80000718: 14179073 csrw sepc,a5 +8000071c: 342027f3 csrr a5,mcause +80000720: 14279073 csrw scause,a5 +80000724: 105027f3 csrr a5,stvec +80000728: 34179073 csrw mepc,a5 +8000072c: e29ff06f j 80000554 +80000730: 30571073 csrw mtvec,a4 +80000734: 343027f3 csrr a5,mtval +80000738: 14379073 csrw stval,a5 +8000073c: 342027f3 csrr a5,mcause +80000740: 14279073 csrw scause,a5 +80000744: 14191073 csrw sepc,s2 +80000748: 105027f3 csrr a5,stvec +8000074c: 34179073 csrw mepc,a5 +80000750: 10000793 li a5,256 +80000754: 1007b073 csrc sstatus,a5 +80000758: 00355793 srli a5,a0,0x3 +8000075c: 1007f793 andi a5,a5,256 +80000760: 1007a073 csrs sstatus,a5 +80000764: 000027b7 lui a5,0x2 +80000768: 80078793 addi a5,a5,-2048 # 1800 <__stack_size+0x1000> +8000076c: 3007b073 csrc mstatus,a5 +80000770: 000017b7 lui a5,0x1 +80000774: 88078793 addi a5,a5,-1920 # 880 <__stack_size+0x80> +80000778: 3007a073 csrs mstatus,a5 +8000077c: cd9ff06f j 80000454 -800006c4 : -800006c4: fe002503 lw a0,-32(zero) # ffffffe0 <_sp+0x7fffefd8> -800006c8: 00008067 ret +80000780 : +80000780: fe002e23 sw zero,-4(zero) # fffffffc <_sp+0x7fffeeec> +80000784: 0000006f j 80000784 -800006cc : -800006cc: fe402503 lw a0,-28(zero) # ffffffe4 <_sp+0x7fffefdc> -800006d0: 00008067 ret +80000788 : +80000788: fea02c23 sw a0,-8(zero) # fffffff8 <_sp+0x7fffeee8> +8000078c: 00008067 ret -800006d4 : -800006d4: fec00793 li a5,-20 -800006d8: fff00713 li a4,-1 -800006dc: 00e7a023 sw a4,0(a5) -800006e0: fea02423 sw a0,-24(zero) # ffffffe8 <_sp+0x7fffefe0> -800006e4: 00b7a023 sw a1,0(a5) -800006e8: 00008067 ret +80000790 : +80000790: ff802503 lw a0,-8(zero) # fffffff8 <_sp+0x7fffeee8> +80000794: 00008067 ret -800006ec <__libc_init_array>: -800006ec: ff010113 addi sp,sp,-16 -800006f0: 00000797 auipc a5,0x0 -800006f4: 0a478793 addi a5,a5,164 # 80000794 <__init_array_end> -800006f8: 00812423 sw s0,8(sp) -800006fc: 00000417 auipc s0,0x0 -80000700: 09840413 addi s0,s0,152 # 80000794 <__init_array_end> -80000704: 40f40433 sub s0,s0,a5 -80000708: 00912223 sw s1,4(sp) -8000070c: 01212023 sw s2,0(sp) -80000710: 00112623 sw ra,12(sp) -80000714: 40245413 srai s0,s0,0x2 -80000718: 00000493 li s1,0 -8000071c: 00078913 mv s2,a5 -80000720: 04849263 bne s1,s0,80000764 <__libc_init_array+0x78> -80000724: 955ff0ef jal ra,80000078 <_init> -80000728: 00000797 auipc a5,0x0 -8000072c: 06c78793 addi a5,a5,108 # 80000794 <__init_array_end> -80000730: 00000417 auipc s0,0x0 -80000734: 06440413 addi s0,s0,100 # 80000794 <__init_array_end> -80000738: 40f40433 sub s0,s0,a5 -8000073c: 40245413 srai s0,s0,0x2 -80000740: 00000493 li s1,0 -80000744: 00078913 mv s2,a5 -80000748: 02849a63 bne s1,s0,8000077c <__libc_init_array+0x90> -8000074c: 00c12083 lw ra,12(sp) -80000750: 00812403 lw s0,8(sp) -80000754: 00412483 lw s1,4(sp) -80000758: 00012903 lw s2,0(sp) -8000075c: 01010113 addi sp,sp,16 -80000760: 00008067 ret -80000764: 00249793 slli a5,s1,0x2 -80000768: 00f907b3 add a5,s2,a5 -8000076c: 0007a783 lw a5,0(a5) -80000770: 00148493 addi s1,s1,1 -80000774: 000780e7 jalr a5 -80000778: fa9ff06f j 80000720 <__libc_init_array+0x34> -8000077c: 00249793 slli a5,s1,0x2 -80000780: 00f907b3 add a5,s2,a5 -80000784: 0007a783 lw a5,0(a5) -80000788: 00148493 addi s1,s1,1 -8000078c: 000780e7 jalr a5 -80000790: fb9ff06f j 80000748 <__libc_init_array+0x5c> +80000798 : +80000798: fe002503 lw a0,-32(zero) # ffffffe0 <_sp+0x7fffeed0> +8000079c: 00008067 ret + +800007a0 : +800007a0: fe402503 lw a0,-28(zero) # ffffffe4 <_sp+0x7fffeed4> +800007a4: 00008067 ret + +800007a8 : +800007a8: fec00793 li a5,-20 +800007ac: fff00713 li a4,-1 +800007b0: 00e7a023 sw a4,0(a5) +800007b4: fea02423 sw a0,-24(zero) # ffffffe8 <_sp+0x7fffeed8> +800007b8: 00b7a023 sw a1,0(a5) +800007bc: 00008067 ret + +800007c0 : +800007c0: 00008067 ret + +800007c4 <__libc_init_array>: +800007c4: ff010113 addi sp,sp,-16 +800007c8: 00000797 auipc a5,0x0 +800007cc: 0a478793 addi a5,a5,164 # 8000086c <__init_array_end> +800007d0: 00812423 sw s0,8(sp) +800007d4: 00000417 auipc s0,0x0 +800007d8: 09840413 addi s0,s0,152 # 8000086c <__init_array_end> +800007dc: 40f40433 sub s0,s0,a5 +800007e0: 00912223 sw s1,4(sp) +800007e4: 01212023 sw s2,0(sp) +800007e8: 00112623 sw ra,12(sp) +800007ec: 40245413 srai s0,s0,0x2 +800007f0: 00000493 li s1,0 +800007f4: 00078913 mv s2,a5 +800007f8: 04849263 bne s1,s0,8000083c <__libc_init_array+0x78> +800007fc: 87dff0ef jal ra,80000078 <_init> +80000800: 00000797 auipc a5,0x0 +80000804: 06c78793 addi a5,a5,108 # 8000086c <__init_array_end> +80000808: 00000417 auipc s0,0x0 +8000080c: 06440413 addi s0,s0,100 # 8000086c <__init_array_end> +80000810: 40f40433 sub s0,s0,a5 +80000814: 40245413 srai s0,s0,0x2 +80000818: 00000493 li s1,0 +8000081c: 00078913 mv s2,a5 +80000820: 02849a63 bne s1,s0,80000854 <__libc_init_array+0x90> +80000824: 00c12083 lw ra,12(sp) +80000828: 00812403 lw s0,8(sp) +8000082c: 00412483 lw s1,4(sp) +80000830: 00012903 lw s2,0(sp) +80000834: 01010113 addi sp,sp,16 +80000838: 00008067 ret +8000083c: 00249793 slli a5,s1,0x2 +80000840: 00f907b3 add a5,s2,a5 +80000844: 0007a783 lw a5,0(a5) +80000848: 00148493 addi s1,s1,1 +8000084c: 000780e7 jalr a5 +80000850: fa9ff06f j 800007f8 <__libc_init_array+0x34> +80000854: 00249793 slli a5,s1,0x2 +80000858: 00f907b3 add a5,s2,a5 +8000085c: 0007a783 lw a5,0(a5) +80000860: 00148493 addi s1,s1,1 +80000864: 000780e7 jalr a5 +80000868: fb9ff06f j 80000820 <__libc_init_array+0x5c> diff --git a/src/main/c/emulator/build/emulator.bin b/src/main/c/emulator/build/emulator.bin index acae91a4b81c9c2f735ca7ec1334985ddf37d76b..8358c0e2cfd98b8520151bde95970e5519349abc 100755 GIT binary patch delta 1213 zcmZ`&O^8!h6h1e3@7+XXeB;X`V+7~bB&H5QE*Opfh&YI}pp3($;=;v4iZC?d)8L|z z*XD1)zl>KH7eZ#?-%^ONa&eD^!& zo;$7P*6W@@0F97A&k*kNSY{S?o_?D4xDhLv>ofX>NXM1F+I7iSjZ5?3(`6A3<*E6V z3KZkGJhOnQ)e*fo$ zhzqO=Sf?~ex~9o<&z~S4?M1Gl+p60 zKkB@(6AY`do>Kd4=G@+I)7pG4evwW2tA;~C{27HJ{#3<}vrNZwN*d6z=OVFOclFpmQt%rQ+& z^*hF?3dsiw@c?K16uh0iu{r5lRV*aFd841S!m;bfz2yO?CwN z<{qP<1S%2%Oku`ty0%xbXe?gvrtowKFBrs4Hp?%E zT3vgjS$^}R(X~&1zybz*{yXhjP!03!kzPlCPX!5DWMh2KH}m delta 929 zcmZ8fUr19?82`?;dyWIKt7kdX%EetSB;>+YtLVW8&4*rmSd4sGaH9x>1v6(*Y~r5< zK}?S^-`qoLkHV7m=)-bC1U*>N)1ZO9<%MnT52Af{%cwnEzVCOw?>pc5{eCyz@ltl! z+W|P42D^k&`Z$%qDCUNz>=ZGjkp)MWw_cK7G)i;NwW&=|91^wa_ z(4cI?*{k(gpT##=aLS&-B~U|7)x)W75|c&7{Tay5ZXa^0viuUpu-6#u5KINFwJZy( z44TDjMuz?Mi)>O4>BH<|ByK&&eZId8_(X=eEk%63lZe?N2*qulpq~51{ktIiPLl3K z>htpz9?mjR&N4UKgH&t}%q|AzH3nYE1R;l{+Ut7Hk&t{>6$}|(W*`_e>Z+t_%dAuQ z-;)TJwn+X#X&()WiiFEBaeD>XMYVsFhoS;tlP!#b|!CwD5w@}M55k*}2VV>{@Hah^NmOg~ZH z{;U;TvPZ;5P+2=FD+RvKtY*b0s$9r@<4;Rx4q(gre@oyi+SX#&X2IP*7R~3+#%;EO zYg9I_KvCt;29w2}7-P=1z-MIuj*TBrxsp5 0) putC(c); +// } } #endif #ifdef QEMU #define VIRT_CLINT 0x2000000 -#define SIFIVE_TIMECMP_BASE VIRT_CLINT + 0x4000 -#define SIFIVE_TIME_BASE VIRT_CLINT + 0xBFF8 +#define SIFIVE_TIMECMP_BASE (VIRT_CLINT + 0x4000) +#define SIFIVE_TIME_BASE (VIRT_CLINT + 0xBFF8) #define NS16550A_UART0_CTRL_ADDR 0x10000000 #define UART0_CLOCK_FREQ 32000000 #define UART0_BAUD_RATE 115200 @@ -95,7 +106,7 @@ static void ns16550a_init() //} void stopSim(){ - *((volatile uint32_t*) 0xFFFFFFFC) = 0; + while(1); } void putC(char ch){ @@ -103,6 +114,14 @@ void putC(char ch){ uart[UART_THR] = ch & 0xff; } +int32_t getC(){ + if (uart[UART_LSR] & UART_LSR_DA) { + return uart[UART_RBR]; + } else { + return -1; + } +} + uint32_t rdtime(){ return *((volatile uint32_t*) SIFIVE_TIME_BASE); diff --git a/src/main/c/emulator/src/hal.h b/src/main/c/emulator/src/hal.h index 90e3df9e..8b4e1c27 100644 --- a/src/main/c/emulator/src/hal.h +++ b/src/main/c/emulator/src/hal.h @@ -17,6 +17,7 @@ void halInit(); void stopSim(); void putC(char c); +int32_t getC(); uint32_t rdtime(); uint32_t rdtimeh(); void setMachineTimerCmp(uint32_t low, uint32_t high); diff --git a/src/main/c/emulator/src/main.c b/src/main/c/emulator/src/main.c index c637fba0..574a05ec 100755 --- a/src/main/c/emulator/src/main.c +++ b/src/main/c/emulator/src/main.c @@ -14,7 +14,22 @@ void putString(char* s){ } } +void setup_pmp(void) +{ + // Set up a PMP to permit access to all of memory. + // Ignore the illegal-instruction trap if PMPs aren't supported. + uintptr_t pmpc = PMP_NAPOT | PMP_R | PMP_W | PMP_X; + asm volatile ("la t0, 1f\n\t" + "csrrw t0, mtvec, t0\n\t" + "csrw pmpaddr0, %1\n\t" + "csrw pmpcfg0, %0\n\t" + ".align 2\n\t" + "1: csrw mtvec, t0" + : : "r" (pmpc), "r" (-1UL) : "t0"); +} + void init() { + setup_pmp(); halInit(); putString("*** VexRiscv BIOS ***\n"); uint32_t sp = (uint32_t) (&_sp); @@ -140,7 +155,27 @@ void trap(){ case CAUSE_ILLEGAL_INSTRUCTION:{ uint32_t mepc = csr_read(mepc); uint32_t mstatus = csr_read(mstatus); +#ifdef SIM uint32_t instruction = csr_read(mbadaddr); +#endif +#ifdef QEMU + uint32_t instruction = 0; + uint32_t i; + if (mepc & 2) { + readWord(mepc - 2, &i); + i >>= 16; + if (i & 3 == 3) { + uint32_t u32Buf; + readWord(mepc+2, &u32Buf); + i |= u32Buf << 16; + } + } else { + readWord(mepc, &i); + } + instruction = i; + csr_write(mtvec, trapEntry); //Restore mtvec +#endif + uint32_t opcode = instruction & 0x7F; uint32_t funct3 = (instruction >> 12) & 0x7; switch(opcode){ @@ -227,7 +262,7 @@ void trap(){ csr_write(mepc, csr_read(mepc) + 4); }break; case SBI_CONSOLE_GETCHAR:{ - writeRegister(10, -1); //no char + writeRegister(10, getC()); //no char csr_write(mepc, csr_read(mepc) + 4); }break; case SBI_SET_TIMER:{ diff --git a/src/main/c/emulator/src/riscv.h b/src/main/c/emulator/src/riscv.h index facb90d8..488b1728 100644 --- a/src/main/c/emulator/src/riscv.h +++ b/src/main/c/emulator/src/riscv.h @@ -54,6 +54,17 @@ #define SSTATUS64_SD 0x8000000000000000 +#define PMP_R 0x01 +#define PMP_W 0x02 +#define PMP_X 0x04 +#define PMP_A 0x18 +#define PMP_L 0x80 +#define PMP_SHIFT 2 + +#define PMP_TOR 0x08 +#define PMP_NA4 0x10 +#define PMP_NAPOT 0x18 + #define RDCYCLE 0xC00 //Read-only cycle Cycle counter for RDCYCLE instruction. #define RDTIME 0xC01 //Read-only time Timer for RDTIME instruction. #define RDINSTRET 0xC02 //Read-only instret Instructions-retired counter for RDINSTRET instruction. diff --git a/src/main/scala/vexriscv/demo/Linux.scala b/src/main/scala/vexriscv/demo/Linux.scala index f1790a4c..6578dd7c 100644 --- a/src/main/scala/vexriscv/demo/Linux.scala +++ b/src/main/scala/vexriscv/demo/Linux.scala @@ -49,6 +49,13 @@ make run DBUS=SIMPLE IBUS=SIMPLE SUPERVISOR=yes CSR=yes COMPRESSED=yes REDO=0 DH +make run DBUS=SIMPLE IBUS=SIMPLE SUPERVISOR=yes CSR=yes COMPRESSED=yes REDO=0 DHRYSTONE=no LINUX_SOC=yes EMULATOR=../../../main/c/emulator/build/emulator.bin VMLINUX=/home/miaou/Downloads/tmp/Image DTB=/home/miaou/Downloads/tmp/rv32.dtb RAMDISK=/home/miaou/Downloads/tmp/rootfs.cpio TRACE=no FLOW_INFO=yes TRACE_START=9570000099 + + + + + + @@ -101,6 +108,37 @@ qemu-system-riscv32 -nographic -machine virt -m 1536M -device loader,file=/home/ + + + + +make linux-dirclean linux-rebuild riscv-pk-dirclean riscv-pk-rebuild + +qemu-system-riscv32 -M virt -kernel output/images/bbl -append "root=/dev/vda ro console=ttyS0" -drive file=output/images/rootfs.ext2,format=raw,id=hd0 -device virtio-blk-device,drive=hd0 -netdev user,id=net0 -device virtio-net-device,netdev=net0 -nographic +qemu-system-riscv32 -M virt -kernel output/images/bbl -append "root=/dev/vda ro console=ttyS0" -drive file=output/images/rootfs.ext2,format=raw,id=hd0 -device virtio-blk-device,drive=hd0 -netdev user,id=net0 -device virtio-net-device,netdev=net0 -nographic -dtb virt.dtb + + +Compile +make spinal_vexriscv_sim_defconfig +make linux-dirclean linux-rebuild -j8; output/host/bin/riscv32-linux-objcopy -O binary output/images/vmlinux output/images/vmlinux.bin + +output/host/bin/riscv32-linux-objcopy -O binary output/images/vmlinux output/images/vmlinux.bin +output/host/bin/riscv32-linux-objdump -S -d output/images/vmlinux > output/images/vmlinux.asm; split -b 1M output/images/vmlinux.asm + +make clean +make spinal_vexriscv_sim_defconfig +make -j8; output/host/bin/riscv32-linux-objcopy -O binary output/images/vmlinux output/images/vmlinux.bin + + +Run Qemu +qemu-system-riscv32 -nographic -machine virt -m 1536M -device loader,file=/home/miaou/pro/VexRiscv/src/main/c/emulator/build/emulator.bin,addr=0x80000000,cpu-num=0 -device loader,file=board/spinal/vexriscv_sim/rv32.dtb,addr=0xC4000000 -device loader,file=output/images/vmlinux.bin,addr=0xC0000000 -device loader,file=output/images/rootfs.cpio,addr=0xc5000000 + +Run sim +export BUILDROOT=/home/miaou/pro/riscv/buildrootSpinal +make run DBUS=SIMPLE IBUS=SIMPLE SUPERVISOR=yes CSR=yes COMPRESSED=yes REDO=0 DHRYSTONE=no LINUX_SOC=yes EMULATOR=../../../main/c/emulator/build/emulator.bin VMLINUX=$BUILDROOT/output/images/vmlinux.bin DTB=$BUILDROOT/board/spinal/vexriscv_sim/rv32.dtb RAMDISK=$BUILDROOT/output/images/rootfs.cpio TRACE=no FLOW_INFO=yes TRACE_START=9570000099 + + + */ @@ -251,8 +289,8 @@ object LinuxGen { ) ) if(withMmu) config.plugins += new MmuPlugin( -// virtualRange = a => True, - virtualRange = x => x(31 downto 24) =/= 0x81, //TODO It fix the DTB kernel access (workaround) + virtualRange = a => True, + // virtualRange = x => x(31 downto 24) =/= 0x81, //TODO It fix the DTB kernel access (workaround) ioRange = (x => if(litex) x(31 downto 28) === 0xB || x(31 downto 28) === 0xE || x(31 downto 28) === 0xF else x(31 downto 28) === 0xF), allowUserIo = true ) diff --git a/src/test/cpp/regression/fail.gtkw b/src/test/cpp/regression/fail.gtkw index cf9bed0d..788713e2 100644 --- a/src/test/cpp/regression/fail.gtkw +++ b/src/test/cpp/regression/fail.gtkw @@ -1,56 +1,63 @@ [*] -[*] GTKWave Analyzer v3.3.58 (w)1999-2014 BSI -[*] Tue Jul 25 21:44:42 2017 +[*] GTKWave Analyzer v3.3.100 (w)1999-2019 BSI +[*] Sat Mar 30 09:33:33 2019 [*] -[dumpfile] "/home/spinalvm/Spinal/VexRiscv/src/test/cpp/regression/debugPluginExternal.vcd" -[dumpfile_mtime] "Tue Jul 25 21:44:34 2017" -[dumpfile_size] 961355289 -[savefile] "/home/spinalvm/Spinal/VexRiscv/src/test/cpp/regression/fail.gtkw" -[timestart] 3644000 -[size] 1776 953 -[pos] -775 -353 -*-19.000000 4619595 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 +[dumpfile] "/home/miaou/pro/VexRiscv/src/test/cpp/regression/linux.vcd" +[dumpfile_mtime] "Sat Mar 30 09:16:30 2019" +[dumpfile_size] 249834424 +[savefile] "/home/miaou/pro/VexRiscv/src/test/cpp/regression/fail.gtkw" +[timestart] 106663042 +[size] 1920 1030 +[pos] -458 -215 +*-5.000000 106541900 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 [treeopen] TOP. [treeopen] TOP.VexRiscv. -[treeopen] TOP.VexRiscv.mixedDivider_1. -[sst_width] 201 -[signals_width] 418 +[sst_width] 287 +[signals_width] 465 [sst_expanded] 1 [sst_vpaned_height] 279 @28 -TOP.VexRiscv.DebugPlugin_haltIt +TOP.VexRiscv.writeBack_arbitration_isFiring @22 -TOP.VexRiscv.debug_bus_cmd_payload_address[7:0] -TOP.VexRiscv.debug_bus_cmd_payload_data[31:0] +TOP.VexRiscv.writeBack_PC[31:0] +TOP.VexRiscv.writeBack_INSTRUCTION[31:0] @28 -TOP.VexRiscv.debug_bus_cmd_payload_wr -TOP.VexRiscv.debug_bus_cmd_ready +TOP.VexRiscv.CsrPlugin_exception +TOP.VexRiscv.CsrPlugin_privilege[1:0] +@22 +TOP.VexRiscv.CsrPlugin_scause_exceptionCode[3:0] +@28 +TOP.VexRiscv.CsrPlugin_scause_interrupt +@22 +TOP.VexRiscv.IBusSimplePlugin_jump_pcLoad_payload[31:0] +@28 +TOP.VexRiscv.IBusSimplePlugin_jump_pcLoad_valid +@22 +TOP.VexRiscv.CsrPlugin_mepc[31:0] +TOP.VexRiscv.CsrPlugin_sepc[31:0] +@28 +TOP.VexRiscv.decode_IS_RVC +@24 +TOP.VexRiscv.CsrPlugin_mcycle[63:0] +@28 +TOP.VexRiscv.decode_IS_RVC +TOP.VexRiscv.decode_arbitration_isValid +@22 +TOP.VexRiscv.RegFilePlugin_regFile(10)[31:0] +@28 +TOP.dBus_cmd_valid +TOP.dBus_cmd_ready +@22 +TOP.dBus_cmd_payload_address[31:0] +@28 +TOP.dBus_cmd_payload_wr @29 -TOP.VexRiscv.debug_bus_cmd_valid +TOP.dBus_cmd_payload_size[1:0] @22 -TOP.VexRiscv.debug_bus_rsp_data[31:0] -[color] 2 -TOP.VexRiscv.dBus_cmd_payload_address[31:0] -[color] 2 -TOP.VexRiscv.dBus_cmd_payload_data[31:0] +TOP.dBus_cmd_payload_data[31:0] +TOP.dBus_rsp_data[31:0] @28 -[color] 2 -TOP.VexRiscv.dBus_cmd_payload_size[1:0] -[color] 2 -TOP.VexRiscv.dBus_cmd_payload_wr -[color] 2 -TOP.VexRiscv.dBus_cmd_ready -[color] 2 -TOP.VexRiscv.dBus_cmd_valid -@22 -[color] 2 -TOP.VexRiscv.dBus_rsp_data[31:0] -@28 -[color] 2 -TOP.VexRiscv.dBus_rsp_error -[color] 2 -TOP.VexRiscv.dBus_rsp_ready -@22 -TOP.VexRiscv.DebugPlugin_busReadDataReg[31:0] +TOP.dBus_rsp_error +TOP.dBus_rsp_ready [pattern_trace] 1 [pattern_trace] 0 diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index ca8d6cf3..85f08e31 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -3001,16 +3001,40 @@ public: //#endif +#include +#include +#include + +void stdinNonBuffered(){ + static struct termios old, new1; + tcgetattr(0, &old); /* grab old terminal i/o settings */ + new1 = old; /* make new settings same as old settings */ + new1.c_lflag &= ~ICANON; /* disable buffered i/o */ + new1.c_lflag &= ~ECHO; + tcsetattr(0, TCSANOW, &new1); /* use these new terminal i/o settings now */ +} + +bool stdinNonEmpty(){ + struct timeval tv; + fd_set fds; + tv.tv_sec = 0; + tv.tv_usec = 0; + FD_ZERO(&fds); + FD_SET(STDIN_FILENO, &fds); + select(STDIN_FILENO+1, &fds, NULL, NULL, &tv); + return (FD_ISSET(0, &fds)); +} + #ifdef LINUX_SOC class LinuxSoc : public Workspace{ public: LinuxSoc(string name) : Workspace(name) { - + stdinNonBuffered(); } virtual bool isDBusCheckedRegion(uint32_t address){ return true;} virtual bool isPerifRegion(uint32_t addr) { return (addr & 0xF0000000) == 0xB0000000 || (addr & 0xE0000000) == 0xE0000000;} - virtual bool isMmuRegion(uint32_t addr) { return (addr & 0xFF000000) != 0x81000000;} + virtual bool isMmuRegion(uint32_t addr) { return true; } virtual void dBusAccess(uint32_t addr,bool wr, uint32_t size,uint32_t mask, uint32_t *data, bool *error) { if(isPerifRegion(addr)) switch(addr){ @@ -3024,7 +3048,15 @@ public: cout << (char)*data; logTraces << (char)*data; logTraces.flush(); - } else fail(); + } else { + if(stdinNonEmpty()){ + char c; + read(0, &c, 1); + *data = c; + } else { + *data = -1; + } + } break; case 0xFFFFFFFC: fail(); break; //Simulation end default: cout << "Unmapped peripheral access : addr=0x" << hex << addr << " wr=" << wr << " mask=0x" << mask << " data=0x" << data << dec << endl; fail(); break; @@ -3290,7 +3322,6 @@ static void multiThreadedExecute(queue> &lambdas){ } } - int main(int argc, char **argv, char **env) { #ifdef SEED srand48(SEED); @@ -3317,14 +3348,49 @@ int main(int argc, char **argv, char **env) { // ->run(0); //#endif +// { +// static struct termios old, new1; +// tcgetattr(0, &old); /* grab old terminal i/o settings */ +// new1 = old; /* make new settings same as old settings */ +// new1.c_lflag &= ~ICANON; /* disable buffered i/o */ +// new1.c_lflag &= ~ECHO; +// tcsetattr(0, TCSANOW, &new1); /* use these new terminal i/o settings now */ +// } +// +// std::string initialCommand; +// +// while(true){ +// if(!inputAvailable()) { +// std::cout << "Waiting for input (Ctrl-C to cancel)..." << std::endl; +// sleep(1); +// } else { +// char c; +// read(0, &c, 1); printf("%d\n", c); +//// std::getline(std::cin, initialCommand); +// } +// } +// + +// char c; +// while (1) { read(0, &c, 1); printf("%d\n", c); } +// while(true){ +// char c = getchar(); +// if(c > 0) +// { +// putchar(c); +// } else { +// putchar('*'); +// sleep(500); +// } +// } #ifdef LINUX_SOC LinuxSoc("linux") .withRiscvRef() ->loadBin(EMULATOR, 0x80000000) - ->loadBin(DTB, 0x81000000) - ->loadBin(VMLINUX, 0xc0000000) - ->loadBin(RAMDISK, 0xc2000000) + ->loadBin(VMLINUX, 0xC0000000) + ->loadBin(DTB, 0xC4000000) + ->loadBin(RAMDISK, 0xC5000000) ->setIStall(false) //TODO It currently improve speed but should be removed later ->setDStall(false) ->bootAt(0x80000000) diff --git a/src/test/python/tool/disasm.s b/src/test/python/tool/disasm.s deleted file mode 100644 index 07919dc3..00000000 --- a/src/test/python/tool/disasm.s +++ /dev/null @@ -1 +0,0 @@ -.word 0x28488b3 From 369a3d0f5f81fa7c846c2861ef918fed00abc18d Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Sun, 31 Mar 2019 23:43:06 +0200 Subject: [PATCH 096/951] #60 Sync everything, added much comment on the top of Linux.scala to help reproduce --- src/main/c/emulator/build/emulator.asm | 535 ++++++++++++----------- src/main/c/emulator/build/emulator.bin | Bin 2320 -> 2320 bytes src/main/c/emulator/src/config.h | 2 +- src/main/scala/vexriscv/demo/Linux.scala | 106 ++--- src/test/cpp/regression/main.cpp | 18 +- 5 files changed, 308 insertions(+), 353 deletions(-) diff --git a/src/main/c/emulator/build/emulator.asm b/src/main/c/emulator/build/emulator.asm index cec2458d..62f76935 100644 --- a/src/main/c/emulator/build/emulator.asm +++ b/src/main/c/emulator/build/emulator.asm @@ -8,9 +8,9 @@ Disassembly of section .init: 80000000: 00001117 auipc sp,0x1 80000004: 11010113 addi sp,sp,272 # 80001110 <_sp> 80000008: 00001517 auipc a0,0x1 -8000000c: 86450513 addi a0,a0,-1948 # 8000086c <__init_array_end> +8000000c: 86850513 addi a0,a0,-1944 # 80000870 <__init_array_end> 80000010: 00001597 auipc a1,0x1 -80000014: 85c58593 addi a1,a1,-1956 # 8000086c <__init_array_end> +80000014: 86058593 addi a1,a1,-1952 # 80000870 <__init_array_end> 80000018: 00001617 auipc a2,0x1 8000001c: 8f860613 addi a2,a2,-1800 # 80000910 <__bss_start> 80000020: 00c5fc63 bgeu a1,a2,80000038 <_start+0x38> @@ -27,12 +27,12 @@ Disassembly of section .init: 8000004c: 00052023 sw zero,0(a0) 80000050: 00450513 addi a0,a0,4 80000054: feb56ce3 bltu a0,a1,8000004c <_start+0x4c> -80000058: 76c000ef jal ra,800007c4 <__libc_init_array> +80000058: 770000ef jal ra,800007c8 <__libc_init_array> 8000005c: 17c000ef jal ra,800001d8 80000060: 00000097 auipc ra,0x0 80000064: 01408093 addi ra,ra,20 # 80000074 80000068: 00000513 li a0,0 -8000006c: c40005b7 lui a1,0xc4000 +8000006c: c30005b7 lui a1,0xc3000 80000070: 30200073 mret 80000074 : @@ -117,7 +117,7 @@ Disassembly of section .text: 8000018c: 00054503 lbu a0,0(a0) 80000190: 00050a63 beqz a0,800001a4 80000194: 00140413 addi s0,s0,1 -80000198: 5f0000ef jal ra,80000788 +80000198: 5f4000ef jal ra,8000078c 8000019c: 00044503 lbu a0,0(s0) 800001a0: fe051ae3 bnez a0,80000194 800001a4: 00c12083 lw ra,12(sp) @@ -149,11 +149,11 @@ Disassembly of section .text: 800001fc: 3a079073 csrw pmpcfg0,a5 80000200: 30529073 csrw mtvec,t0 80000204: 80001437 lui s0,0x80001 -80000208: 5b8000ef jal ra,800007c0 -8000020c: 8e040413 addi s0,s0,-1824 # 800008e0 <_sp+0xfffff7d0> +80000208: 5bc000ef jal ra,800007c4 +8000020c: 8e440413 addi s0,s0,-1820 # 800008e4 <_sp+0xfffff7d4> 80000210: 02a00513 li a0,42 80000214: 00140413 addi s0,s0,1 -80000218: 570000ef jal ra,80000788 +80000218: 574000ef jal ra,8000078c 8000021c: 00044503 lbu a0,0(s0) 80000220: fe051ae3 bnez a0,80000214 80000224: 800007b7 lui a5,0x80000 @@ -175,10 +175,10 @@ Disassembly of section .text: 80000264: 30379073 csrw mideleg,a5 80000268: 14305073 csrwi stval,0 8000026c: 80001437 lui s0,0x80001 -80000270: 8f840413 addi s0,s0,-1800 # 800008f8 <_sp+0xfffff7e8> +80000270: 8fc40413 addi s0,s0,-1796 # 800008fc <_sp+0xfffff7ec> 80000274: 02a00513 li a0,42 80000278: 00140413 addi s0,s0,1 -8000027c: 50c000ef jal ra,80000788 +8000027c: 510000ef jal ra,8000078c 80000280: 00044503 lbu a0,0(s0) 80000284: fe051ae3 bnez a0,80000278 80000288: 00c12083 lw ra,12(sp) @@ -205,7 +205,7 @@ Disassembly of section .text: 800002c8 : 800002c8: ff010113 addi sp,sp,-16 800002cc: 00112623 sw ra,12(sp) -800002d0: 4b0000ef jal ra,80000780 +800002d0: 4b4000ef jal ra,80000784 800002d4: 343027f3 csrr a5,mtval 800002d8: 14379073 csrw stval,a5 800002dc: 341027f3 csrr a5,mepc @@ -254,7 +254,7 @@ Disassembly of section .text: 80000378: 00020737 lui a4,0x20 8000037c: 30073073 csrc mstatus,a4 80000380: 00068513 mv a0,a3 -80000384: 00f5a023 sw a5,0(a1) # c4000000 <_sp+0x43ffeef0> +80000384: 00f5a023 sw a5,0(a1) # c3000000 <_sp+0x42ffeef0> 80000388: 00008067 ret 8000038c : @@ -289,19 +289,19 @@ Disassembly of section .text: 800003f4: fc442783 lw a5,-60(s0) 800003f8: 00100693 li a3,1 800003fc: fa842503 lw a0,-88(s0) -80000400: 2ed78863 beq a5,a3,800006f0 -80000404: 2ae78663 beq a5,a4,800006b0 -80000408: 2c078063 beqz a5,800006c8 +80000400: 2ed78663 beq a5,a3,800006ec +80000404: 2ae78463 beq a5,a4,800006ac +80000408: 2a078e63 beqz a5,800006c4 8000040c: 01812403 lw s0,24(sp) 80000410: 01c12083 lw ra,28(sp) 80000414: 01412483 lw s1,20(sp) 80000418: 01012903 lw s2,16(sp) 8000041c: 00c12983 lw s3,12(sp) 80000420: 02010113 addi sp,sp,32 -80000424: 35c0006f j 80000780 -80000428: 0076f693 andi a3,a3,7 -8000042c: 14f68663 beq a3,a5,80000578 -80000430: 350000ef jal ra,80000780 +80000424: 3600006f j 80000784 +80000428: 00777713 andi a4,a4,7 +8000042c: 14f70063 beq a4,a5,8000056c +80000430: 354000ef jal ra,80000784 80000434: 343027f3 csrr a5,mtval 80000438: 14379073 csrw stval,a5 8000043c: 341027f3 csrr a5,mepc @@ -331,260 +331,261 @@ Disassembly of section .text: 8000049c: 00c12983 lw s3,12(sp) 800004a0: 02010113 addi sp,sp,32 800004a4: 00008067 ret -800004a8: 34102973 csrr s2,mepc -800004ac: 30002573 csrr a0,mstatus +800004a8: 341024f3 csrr s1,mepc +800004ac: 300025f3 csrr a1,mstatus 800004b0: 34302473 csrr s0,mtval -800004b4: 80000737 lui a4,0x80000 -800004b8: 07c70713 addi a4,a4,124 # 8000007c <_sp+0xffffef6c> -800004bc: 30571073 csrw mtvec,a4 -800004c0: 02f00593 li a1,47 -800004c4: 07f47613 andi a2,s0,127 -800004c8: 00c45693 srli a3,s0,0xc -800004cc: f4b60ee3 beq a2,a1,80000428 -800004d0: 07300713 li a4,115 -800004d4: f4e61ee3 bne a2,a4,80000430 -800004d8: 0036f693 andi a3,a3,3 -800004dc: 12f68063 beq a3,a5,800005fc -800004e0: 00300793 li a5,3 -800004e4: 10f68c63 beq a3,a5,800005fc -800004e8: 00100993 li s3,1 -800004ec: 03368463 beq a3,s3,80000514 -800004f0: 290000ef jal ra,80000780 -800004f4: 343027f3 csrr a5,mtval -800004f8: 14379073 csrw stval,a5 -800004fc: 341027f3 csrr a5,mepc -80000500: 14179073 csrw sepc,a5 -80000504: 342027f3 csrr a5,mcause -80000508: 14279073 csrw scause,a5 -8000050c: 105027f3 csrr a5,stvec -80000510: 34179073 csrw mepc,a5 -80000514: 000017b7 lui a5,0x1 -80000518: 01445713 srli a4,s0,0x14 -8000051c: c0178693 addi a3,a5,-1023 # c01 <__stack_size+0x401> -80000520: 0ed70663 beq a4,a3,8000060c -80000524: c8178793 addi a5,a5,-895 -80000528: 0cf70463 beq a4,a5,800005f0 -8000052c: 254000ef jal ra,80000780 -80000530: 343027f3 csrr a5,mtval -80000534: 14379073 csrw stval,a5 -80000538: 341027f3 csrr a5,mepc -8000053c: 14179073 csrw sepc,a5 -80000540: 342027f3 csrr a5,mcause -80000544: 14279073 csrw scause,a5 -80000548: 105027f3 csrr a5,stvec -8000054c: 34179073 csrw mepc,a5 -80000550: 1a099c63 bnez s3,80000708 -80000554: 00545413 srli s0,s0,0x5 -80000558: 800017b7 lui a5,0x80001 -8000055c: 09078793 addi a5,a5,144 # 80001090 <_sp+0xffffff80> -80000560: 07c47413 andi s0,s0,124 -80000564: 00f40433 add s0,s0,a5 -80000568: 00942023 sw s1,0(s0) -8000056c: 00490793 addi a5,s2,4 -80000570: 34179073 csrw mepc,a5 -80000574: ee1ff06f j 80000454 -80000578: 00d45693 srli a3,s0,0xd -8000057c: 01245793 srli a5,s0,0x12 -80000580: 80001637 lui a2,0x80001 -80000584: 09060613 addi a2,a2,144 # 80001090 <_sp+0xffffff80> -80000588: 07c6f693 andi a3,a3,124 -8000058c: 07c7f793 andi a5,a5,124 -80000590: 00c686b3 add a3,a3,a2 -80000594: 00c787b3 add a5,a5,a2 -80000598: 0006a683 lw a3,0(a3) -8000059c: 0007a583 lw a1,0(a5) -800005a0: 00020837 lui a6,0x20 -800005a4: 30082073 csrs mstatus,a6 -800005a8: 00000817 auipc a6,0x0 -800005ac: 01880813 addi a6,a6,24 # 800005c0 -800005b0: 30581073 csrw mtvec,a6 -800005b4: 00100793 li a5,1 -800005b8: 0006a883 lw a7,0(a3) -800005bc: 00000793 li a5,0 -800005c0: 00020837 lui a6,0x20 -800005c4: 30083073 csrc mstatus,a6 -800005c8: 16079463 bnez a5,80000730 -800005cc: 01b45793 srli a5,s0,0x1b -800005d0: 01c00813 li a6,28 -800005d4: e4f86ee3 bltu a6,a5,80000430 -800005d8: 80001837 lui a6,0x80001 -800005dc: 00279793 slli a5,a5,0x2 -800005e0: 86c80813 addi a6,a6,-1940 # 8000086c <_sp+0xfffff75c> -800005e4: 010787b3 add a5,a5,a6 -800005e8: 0007a783 lw a5,0(a5) -800005ec: 00078067 jr a5 -800005f0: 1b0000ef jal ra,800007a0 -800005f4: 00050493 mv s1,a0 -800005f8: f59ff06f j 80000550 -800005fc: 00f45993 srli s3,s0,0xf -80000600: 01f9f993 andi s3,s3,31 -80000604: 013039b3 snez s3,s3 -80000608: f0dff06f j 80000514 -8000060c: 18c000ef jal ra,80000798 -80000610: 00050493 mv s1,a0 -80000614: f3dff06f j 80000550 -80000618: 0115f463 bgeu a1,a7,80000620 -8000061c: 00088593 mv a1,a7 -80000620: 00545413 srli s0,s0,0x5 -80000624: 07c47413 andi s0,s0,124 -80000628: 00c40633 add a2,s0,a2 -8000062c: 01162023 sw a7,0(a2) -80000630: 00020637 lui a2,0x20 -80000634: 30062073 csrs mstatus,a2 -80000638: 00000617 auipc a2,0x0 -8000063c: 01860613 addi a2,a2,24 # 80000650 -80000640: 30561073 csrw mtvec,a2 -80000644: 00100793 li a5,1 -80000648: 00b6a023 sw a1,0(a3) -8000064c: 00000793 li a5,0 -80000650: 00020637 lui a2,0x20 -80000654: 30063073 csrc mstatus,a2 -80000658: 0c079c63 bnez a5,80000730 -8000065c: 00490793 addi a5,s2,4 -80000660: 34179073 csrw mepc,a5 -80000664: 30571073 csrw mtvec,a4 -80000668: dedff06f j 80000454 -8000066c: 0115c5b3 xor a1,a1,a7 -80000670: fb1ff06f j 80000620 -80000674: 011585b3 add a1,a1,a7 -80000678: fa9ff06f j 80000620 -8000067c: 0115f5b3 and a1,a1,a7 -80000680: fa1ff06f j 80000620 -80000684: 0115e5b3 or a1,a1,a7 -80000688: f99ff06f j 80000620 -8000068c: f8b8fae3 bgeu a7,a1,80000620 -80000690: 00088593 mv a1,a7 -80000694: f8dff06f j 80000620 -80000698: f915d4e3 bge a1,a7,80000620 -8000069c: 00088593 mv a1,a7 -800006a0: f81ff06f j 80000620 -800006a4: f6b8dee3 bge a7,a1,80000620 -800006a8: 00088593 mv a1,a7 -800006ac: f75ff06f j 80000620 -800006b0: 0e0000ef jal ra,80000790 -800006b4: faa42423 sw a0,-88(s0) -800006b8: 341027f3 csrr a5,mepc -800006bc: 00478793 addi a5,a5,4 -800006c0: 34179073 csrw mepc,a5 -800006c4: d91ff06f j 80000454 -800006c8: fac42583 lw a1,-84(s0) -800006cc: 0dc000ef jal ra,800007a8 -800006d0: 08000793 li a5,128 -800006d4: 3047a073 csrs mie,a5 -800006d8: 02000793 li a5,32 -800006dc: 1447b073 csrc sip,a5 -800006e0: 341027f3 csrr a5,mepc -800006e4: 00478793 addi a5,a5,4 -800006e8: 34179073 csrw mepc,a5 -800006ec: d69ff06f j 80000454 -800006f0: 0ff57513 andi a0,a0,255 -800006f4: 094000ef jal ra,80000788 -800006f8: 341027f3 csrr a5,mepc -800006fc: 00478793 addi a5,a5,4 -80000700: 34179073 csrw mepc,a5 -80000704: d51ff06f j 80000454 -80000708: 078000ef jal ra,80000780 -8000070c: 343027f3 csrr a5,mtval -80000710: 14379073 csrw stval,a5 -80000714: 341027f3 csrr a5,mepc -80000718: 14179073 csrw sepc,a5 -8000071c: 342027f3 csrr a5,mcause -80000720: 14279073 csrw scause,a5 -80000724: 105027f3 csrr a5,stvec -80000728: 34179073 csrw mepc,a5 -8000072c: e29ff06f j 80000554 -80000730: 30571073 csrw mtvec,a4 -80000734: 343027f3 csrr a5,mtval -80000738: 14379073 csrw stval,a5 -8000073c: 342027f3 csrr a5,mcause -80000740: 14279073 csrw scause,a5 -80000744: 14191073 csrw sepc,s2 -80000748: 105027f3 csrr a5,stvec -8000074c: 34179073 csrw mepc,a5 -80000750: 10000793 li a5,256 -80000754: 1007b073 csrc sstatus,a5 -80000758: 00355793 srli a5,a0,0x3 -8000075c: 1007f793 andi a5,a5,256 -80000760: 1007a073 csrs sstatus,a5 -80000764: 000027b7 lui a5,0x2 -80000768: 80078793 addi a5,a5,-2048 # 1800 <__stack_size+0x1000> -8000076c: 3007b073 csrc mstatus,a5 -80000770: 000017b7 lui a5,0x1 -80000774: 88078793 addi a5,a5,-1920 # 880 <__stack_size+0x80> -80000778: 3007a073 csrs mstatus,a5 -8000077c: cd9ff06f j 80000454 +800004b4: 02f00613 li a2,47 +800004b8: 07f47693 andi a3,s0,127 +800004bc: 00c45713 srli a4,s0,0xc +800004c0: f6c684e3 beq a3,a2,80000428 +800004c4: 07300613 li a2,115 +800004c8: f6c694e3 bne a3,a2,80000430 +800004cc: 00377713 andi a4,a4,3 +800004d0: 12f70063 beq a4,a5,800005f0 +800004d4: 00300793 li a5,3 +800004d8: 10f70c63 beq a4,a5,800005f0 +800004dc: 00100993 li s3,1 +800004e0: 03370463 beq a4,s3,80000508 +800004e4: 2a0000ef jal ra,80000784 +800004e8: 343027f3 csrr a5,mtval +800004ec: 14379073 csrw stval,a5 +800004f0: 341027f3 csrr a5,mepc +800004f4: 14179073 csrw sepc,a5 +800004f8: 342027f3 csrr a5,mcause +800004fc: 14279073 csrw scause,a5 +80000500: 105027f3 csrr a5,stvec +80000504: 34179073 csrw mepc,a5 +80000508: 000017b7 lui a5,0x1 +8000050c: 01445713 srli a4,s0,0x14 +80000510: c0178693 addi a3,a5,-1023 # c01 <__stack_size+0x401> +80000514: 0ed70663 beq a4,a3,80000600 +80000518: c8178793 addi a5,a5,-895 +8000051c: 0cf70463 beq a4,a5,800005e4 +80000520: 264000ef jal ra,80000784 +80000524: 343027f3 csrr a5,mtval +80000528: 14379073 csrw stval,a5 +8000052c: 341027f3 csrr a5,mepc +80000530: 14179073 csrw sepc,a5 +80000534: 342027f3 csrr a5,mcause +80000538: 14279073 csrw scause,a5 +8000053c: 105027f3 csrr a5,stvec +80000540: 34179073 csrw mepc,a5 +80000544: 1c099063 bnez s3,80000704 +80000548: 00545413 srli s0,s0,0x5 +8000054c: 800017b7 lui a5,0x80001 +80000550: 09078793 addi a5,a5,144 # 80001090 <_sp+0xffffff80> +80000554: 07c47413 andi s0,s0,124 +80000558: 00f40433 add s0,s0,a5 +8000055c: 01242023 sw s2,0(s0) +80000560: 00448493 addi s1,s1,4 +80000564: 34149073 csrw mepc,s1 +80000568: eedff06f j 80000454 +8000056c: 00d45713 srli a4,s0,0xd +80000570: 01245793 srli a5,s0,0x12 +80000574: 800016b7 lui a3,0x80001 +80000578: 09068693 addi a3,a3,144 # 80001090 <_sp+0xffffff80> +8000057c: 07c77713 andi a4,a4,124 +80000580: 07c7f793 andi a5,a5,124 +80000584: 00d70733 add a4,a4,a3 +80000588: 00d787b3 add a5,a5,a3 +8000058c: 00072703 lw a4,0(a4) # 20000 <__stack_size+0x1f800> +80000590: 0007a603 lw a2,0(a5) +80000594: 00020537 lui a0,0x20 +80000598: 30052073 csrs mstatus,a0 +8000059c: 00000517 auipc a0,0x0 +800005a0: 01850513 addi a0,a0,24 # 800005b4 +800005a4: 30551073 csrw mtvec,a0 +800005a8: 00100793 li a5,1 +800005ac: 00072803 lw a6,0(a4) +800005b0: 00000793 li a5,0 +800005b4: 00020537 lui a0,0x20 +800005b8: 30053073 csrc mstatus,a0 +800005bc: 16079863 bnez a5,8000072c +800005c0: 01b45793 srli a5,s0,0x1b +800005c4: 01c00513 li a0,28 +800005c8: e6f564e3 bltu a0,a5,80000430 +800005cc: 80001537 lui a0,0x80001 +800005d0: 00279793 slli a5,a5,0x2 +800005d4: 87050513 addi a0,a0,-1936 # 80000870 <_sp+0xfffff760> +800005d8: 00a787b3 add a5,a5,a0 +800005dc: 0007a783 lw a5,0(a5) +800005e0: 00078067 jr a5 +800005e4: 1c0000ef jal ra,800007a4 +800005e8: 00050913 mv s2,a0 +800005ec: f59ff06f j 80000544 +800005f0: 00f45993 srli s3,s0,0xf +800005f4: 01f9f993 andi s3,s3,31 +800005f8: 013039b3 snez s3,s3 +800005fc: f0dff06f j 80000508 +80000600: 19c000ef jal ra,8000079c +80000604: 00050913 mv s2,a0 +80000608: f3dff06f j 80000544 +8000060c: 01067463 bgeu a2,a6,80000614 +80000610: 00080613 mv a2,a6 +80000614: 00545413 srli s0,s0,0x5 +80000618: 07c47413 andi s0,s0,124 +8000061c: 00d406b3 add a3,s0,a3 +80000620: 0106a023 sw a6,0(a3) +80000624: 000207b7 lui a5,0x20 +80000628: 3007a073 csrs mstatus,a5 +8000062c: 00000797 auipc a5,0x0 +80000630: 01878793 addi a5,a5,24 # 80000644 +80000634: 30579073 csrw mtvec,a5 +80000638: 00100693 li a3,1 +8000063c: 00c72023 sw a2,0(a4) +80000640: 00000693 li a3,0 +80000644: 000207b7 lui a5,0x20 +80000648: 3007b073 csrc mstatus,a5 +8000064c: 800007b7 lui a5,0x80000 +80000650: 07c78793 addi a5,a5,124 # 8000007c <_sp+0xffffef6c> +80000654: 0e069063 bnez a3,80000734 +80000658: 00448493 addi s1,s1,4 +8000065c: 34149073 csrw mepc,s1 +80000660: 30579073 csrw mtvec,a5 +80000664: df1ff06f j 80000454 +80000668: 01064633 xor a2,a2,a6 +8000066c: fa9ff06f j 80000614 +80000670: 01060633 add a2,a2,a6 +80000674: fa1ff06f j 80000614 +80000678: 01067633 and a2,a2,a6 +8000067c: f99ff06f j 80000614 +80000680: 01066633 or a2,a2,a6 +80000684: f91ff06f j 80000614 +80000688: f8c876e3 bgeu a6,a2,80000614 +8000068c: 00080613 mv a2,a6 +80000690: f85ff06f j 80000614 +80000694: f90650e3 bge a2,a6,80000614 +80000698: 00080613 mv a2,a6 +8000069c: f79ff06f j 80000614 +800006a0: f6c85ae3 bge a6,a2,80000614 +800006a4: 00080613 mv a2,a6 +800006a8: f6dff06f j 80000614 +800006ac: 0e8000ef jal ra,80000794 +800006b0: faa42423 sw a0,-88(s0) +800006b4: 341027f3 csrr a5,mepc +800006b8: 00478793 addi a5,a5,4 +800006bc: 34179073 csrw mepc,a5 +800006c0: d95ff06f j 80000454 +800006c4: fac42583 lw a1,-84(s0) +800006c8: 0e4000ef jal ra,800007ac +800006cc: 08000793 li a5,128 +800006d0: 3047a073 csrs mie,a5 +800006d4: 02000793 li a5,32 +800006d8: 1447b073 csrc sip,a5 +800006dc: 341027f3 csrr a5,mepc +800006e0: 00478793 addi a5,a5,4 +800006e4: 34179073 csrw mepc,a5 +800006e8: d6dff06f j 80000454 +800006ec: 0ff57513 andi a0,a0,255 +800006f0: 09c000ef jal ra,8000078c +800006f4: 341027f3 csrr a5,mepc +800006f8: 00478793 addi a5,a5,4 +800006fc: 34179073 csrw mepc,a5 +80000700: d55ff06f j 80000454 +80000704: 080000ef jal ra,80000784 +80000708: 343027f3 csrr a5,mtval +8000070c: 14379073 csrw stval,a5 +80000710: 341027f3 csrr a5,mepc +80000714: 14179073 csrw sepc,a5 +80000718: 342027f3 csrr a5,mcause +8000071c: 14279073 csrw scause,a5 +80000720: 105027f3 csrr a5,stvec +80000724: 34179073 csrw mepc,a5 +80000728: e21ff06f j 80000548 +8000072c: 800007b7 lui a5,0x80000 +80000730: 07c78793 addi a5,a5,124 # 8000007c <_sp+0xffffef6c> +80000734: 30579073 csrw mtvec,a5 +80000738: 343027f3 csrr a5,mtval +8000073c: 14379073 csrw stval,a5 +80000740: 342027f3 csrr a5,mcause +80000744: 14279073 csrw scause,a5 +80000748: 14149073 csrw sepc,s1 +8000074c: 105027f3 csrr a5,stvec +80000750: 34179073 csrw mepc,a5 +80000754: 10000793 li a5,256 +80000758: 1007b073 csrc sstatus,a5 +8000075c: 0035d793 srli a5,a1,0x3 +80000760: 1007f793 andi a5,a5,256 +80000764: 1007a073 csrs sstatus,a5 +80000768: 000027b7 lui a5,0x2 +8000076c: 80078793 addi a5,a5,-2048 # 1800 <__stack_size+0x1000> +80000770: 3007b073 csrc mstatus,a5 +80000774: 000017b7 lui a5,0x1 +80000778: 88078793 addi a5,a5,-1920 # 880 <__stack_size+0x80> +8000077c: 3007a073 csrs mstatus,a5 +80000780: cd5ff06f j 80000454 -80000780 : -80000780: fe002e23 sw zero,-4(zero) # fffffffc <_sp+0x7fffeeec> -80000784: 0000006f j 80000784 +80000784 : +80000784: fe002e23 sw zero,-4(zero) # fffffffc <_sp+0x7fffeeec> +80000788: 0000006f j 80000788 -80000788 : -80000788: fea02c23 sw a0,-8(zero) # fffffff8 <_sp+0x7fffeee8> -8000078c: 00008067 ret +8000078c : +8000078c: fea02c23 sw a0,-8(zero) # fffffff8 <_sp+0x7fffeee8> +80000790: 00008067 ret -80000790 : -80000790: ff802503 lw a0,-8(zero) # fffffff8 <_sp+0x7fffeee8> -80000794: 00008067 ret +80000794 : +80000794: ff802503 lw a0,-8(zero) # fffffff8 <_sp+0x7fffeee8> +80000798: 00008067 ret -80000798 : -80000798: fe002503 lw a0,-32(zero) # ffffffe0 <_sp+0x7fffeed0> -8000079c: 00008067 ret +8000079c : +8000079c: fe002503 lw a0,-32(zero) # ffffffe0 <_sp+0x7fffeed0> +800007a0: 00008067 ret -800007a0 : -800007a0: fe402503 lw a0,-28(zero) # ffffffe4 <_sp+0x7fffeed4> -800007a4: 00008067 ret +800007a4 : +800007a4: fe402503 lw a0,-28(zero) # ffffffe4 <_sp+0x7fffeed4> +800007a8: 00008067 ret -800007a8 : -800007a8: fec00793 li a5,-20 -800007ac: fff00713 li a4,-1 -800007b0: 00e7a023 sw a4,0(a5) -800007b4: fea02423 sw a0,-24(zero) # ffffffe8 <_sp+0x7fffeed8> -800007b8: 00b7a023 sw a1,0(a5) -800007bc: 00008067 ret - -800007c0 : +800007ac : +800007ac: fec00793 li a5,-20 +800007b0: fff00713 li a4,-1 +800007b4: 00e7a023 sw a4,0(a5) +800007b8: fea02423 sw a0,-24(zero) # ffffffe8 <_sp+0x7fffeed8> +800007bc: 00b7a023 sw a1,0(a5) 800007c0: 00008067 ret -800007c4 <__libc_init_array>: -800007c4: ff010113 addi sp,sp,-16 -800007c8: 00000797 auipc a5,0x0 -800007cc: 0a478793 addi a5,a5,164 # 8000086c <__init_array_end> -800007d0: 00812423 sw s0,8(sp) -800007d4: 00000417 auipc s0,0x0 -800007d8: 09840413 addi s0,s0,152 # 8000086c <__init_array_end> -800007dc: 40f40433 sub s0,s0,a5 -800007e0: 00912223 sw s1,4(sp) -800007e4: 01212023 sw s2,0(sp) -800007e8: 00112623 sw ra,12(sp) -800007ec: 40245413 srai s0,s0,0x2 -800007f0: 00000493 li s1,0 -800007f4: 00078913 mv s2,a5 -800007f8: 04849263 bne s1,s0,8000083c <__libc_init_array+0x78> -800007fc: 87dff0ef jal ra,80000078 <_init> -80000800: 00000797 auipc a5,0x0 -80000804: 06c78793 addi a5,a5,108 # 8000086c <__init_array_end> -80000808: 00000417 auipc s0,0x0 -8000080c: 06440413 addi s0,s0,100 # 8000086c <__init_array_end> -80000810: 40f40433 sub s0,s0,a5 -80000814: 40245413 srai s0,s0,0x2 -80000818: 00000493 li s1,0 -8000081c: 00078913 mv s2,a5 -80000820: 02849a63 bne s1,s0,80000854 <__libc_init_array+0x90> -80000824: 00c12083 lw ra,12(sp) -80000828: 00812403 lw s0,8(sp) -8000082c: 00412483 lw s1,4(sp) -80000830: 00012903 lw s2,0(sp) -80000834: 01010113 addi sp,sp,16 -80000838: 00008067 ret -8000083c: 00249793 slli a5,s1,0x2 -80000840: 00f907b3 add a5,s2,a5 -80000844: 0007a783 lw a5,0(a5) -80000848: 00148493 addi s1,s1,1 -8000084c: 000780e7 jalr a5 -80000850: fa9ff06f j 800007f8 <__libc_init_array+0x34> -80000854: 00249793 slli a5,s1,0x2 -80000858: 00f907b3 add a5,s2,a5 -8000085c: 0007a783 lw a5,0(a5) -80000860: 00148493 addi s1,s1,1 -80000864: 000780e7 jalr a5 -80000868: fb9ff06f j 80000820 <__libc_init_array+0x5c> +800007c4 : +800007c4: 00008067 ret + +800007c8 <__libc_init_array>: +800007c8: ff010113 addi sp,sp,-16 +800007cc: 00000797 auipc a5,0x0 +800007d0: 0a478793 addi a5,a5,164 # 80000870 <__init_array_end> +800007d4: 00812423 sw s0,8(sp) +800007d8: 00000417 auipc s0,0x0 +800007dc: 09840413 addi s0,s0,152 # 80000870 <__init_array_end> +800007e0: 40f40433 sub s0,s0,a5 +800007e4: 00912223 sw s1,4(sp) +800007e8: 01212023 sw s2,0(sp) +800007ec: 00112623 sw ra,12(sp) +800007f0: 40245413 srai s0,s0,0x2 +800007f4: 00000493 li s1,0 +800007f8: 00078913 mv s2,a5 +800007fc: 04849263 bne s1,s0,80000840 <__libc_init_array+0x78> +80000800: 879ff0ef jal ra,80000078 <_init> +80000804: 00000797 auipc a5,0x0 +80000808: 06c78793 addi a5,a5,108 # 80000870 <__init_array_end> +8000080c: 00000417 auipc s0,0x0 +80000810: 06440413 addi s0,s0,100 # 80000870 <__init_array_end> +80000814: 40f40433 sub s0,s0,a5 +80000818: 40245413 srai s0,s0,0x2 +8000081c: 00000493 li s1,0 +80000820: 00078913 mv s2,a5 +80000824: 02849a63 bne s1,s0,80000858 <__libc_init_array+0x90> +80000828: 00c12083 lw ra,12(sp) +8000082c: 00812403 lw s0,8(sp) +80000830: 00412483 lw s1,4(sp) +80000834: 00012903 lw s2,0(sp) +80000838: 01010113 addi sp,sp,16 +8000083c: 00008067 ret +80000840: 00249793 slli a5,s1,0x2 +80000844: 00f907b3 add a5,s2,a5 +80000848: 0007a783 lw a5,0(a5) +8000084c: 00148493 addi s1,s1,1 +80000850: 000780e7 jalr a5 +80000854: fa9ff06f j 800007fc <__libc_init_array+0x34> +80000858: 00249793 slli a5,s1,0x2 +8000085c: 00f907b3 add a5,s2,a5 +80000860: 0007a783 lw a5,0(a5) +80000864: 00148493 addi s1,s1,1 +80000868: 000780e7 jalr a5 +8000086c: fb9ff06f j 80000824 <__libc_init_array+0x5c> diff --git a/src/main/c/emulator/build/emulator.bin b/src/main/c/emulator/build/emulator.bin index 8358c0e2cfd98b8520151bde95970e5519349abc..009fa6849feab3afbd5957392fe81dde601a6baf 100755 GIT binary patch delta 853 zcmZ8eJ#11@6h8Oy-n~UDzV^PBYHLeVDu%(l1eCZD)9Bz*8!WL74A0-e(1cpLLDH7z zRMFD}HyDgvYiPpSL?Rs>s>F#z5*D<-Ul%%!_7J0x!?KwPI@>!Jmwq%;Dii0 zM}$>2QyF1#Q%SuXyFLo>8tgkWAR@^i;R--Of%os0y+jH|Fe#1U9$6gPzsKddEw1Dw zE^APOAdX96NAbnq2;3Ir1u1w7b;Xr$N@vLFRQa;8@!e}|F)t3v=N)jB$Kzl?OA`gI zSUe2Lpm#YyN1x@{@-T0mE)m7!|w} zwext1VXMS^tPFXx3^oq~+gk(T&$^6vKNY z!Igbdy?^vAFd_$&t(Hu>a#L{6MsVWvM0a8dnm$1w90<#n-F(XYK ze>S(s(fU-ycY}(C*^ZA|cB7i(33iVJ(5B2A$Y-xMUA#FW)tcsTwjDIH+NSY?`;@gCx<>;>GimHv|UOs^N6YK)N}7ecYdw}dCxNNiZMY{8^ERw3hy3_^$`K*@y8PW_oirr$rBR__< zIndHICl?sAco-F<*Ypu3tPcaz11ub&V5oGL>PnoUtt_Z>Rf@3!6dfB?l`>i!{87c) zIA}(#4=Dp}v8JG10d0P~i;IqM(Fj|RDc~X2({}%Cb1It1F(fhQSp(Od5!X1NJTO2^q1~cW{ zA>OD0HX6h{&&W*qpv>RI+rB%fXjK=%lnmA|ts$fWAHq!{l4VF@9*G;0(%ew2Wyrs} z!3`z2Ba6T!rmfKKKd{!U1eGvmE+237OLDl-EOkM?2R}%IgSk)Yqr;OWn6P*7K9<0s zDAO~exv!S3N|1&1Y{Xd!`gjaFb>$S#Cl%|V_<|MvEmbg%w`hRmFi8{S0K4S-iCGB@ vA3scNpL_r1R&BlmKk2}09r#5DUhKeLjzgi4FLwL!)LmV}l6+d^e-HcxyhRj> diff --git a/src/main/c/emulator/src/config.h b/src/main/c/emulator/src/config.h index 203644ce..191ae9f0 100644 --- a/src/main/c/emulator/src/config.h +++ b/src/main/c/emulator/src/config.h @@ -4,6 +4,6 @@ //#define QEMU #define SIM #define OS_CALL 0xC0000000 -#define DTB 0xC4000000 +#define DTB 0xC3000000 #endif diff --git a/src/main/scala/vexriscv/demo/Linux.scala b/src/main/scala/vexriscv/demo/Linux.scala index 6578dd7c..1d2cb02b 100644 --- a/src/main/scala/vexriscv/demo/Linux.scala +++ b/src/main/scala/vexriscv/demo/Linux.scala @@ -42,103 +42,49 @@ sbt "runMain vexriscv.demo.LinuxGen -r" cd src/test/cpp/regression make run DBUS=SIMPLE IBUS=SIMPLE DHRYSTONE=yes SUPERVISOR=yes CSR=yes COMPRESSED=yes REDO=10 TRACE=no -Run linux => +Run linux in simulation (Require the machime mode emulator compiled in SIM mode) => sbt "runMain vexriscv.demo.LinuxGen" cd src/test/cpp/regression -make run DBUS=SIMPLE IBUS=SIMPLE SUPERVISOR=yes CSR=yes COMPRESSED=yes REDO=0 DHRYSTONE=no LINUX_SOC=yes EMULATOR=../../../main/c/emulator/build/emulator.bin VMLINUX=???/vmlinux.bin DTB=???/rv32.dtb RAMDISK=???/initramdisk TRACE=no FLOW_INFO=yes TRACE_START=9570000099 +export BUILDROOT=/home/miaou/pro/riscv/buildrootSpinal +make run DBUS=SIMPLE IBUS=SIMPLE SUPERVISOR=yes CSR=yes COMPRESSED=yes REDO=0 DHRYSTONE=no LINUX_SOC=yes EMULATOR=../../../main/c/emulator/build/emulator.bin VMLINUX=$BUILDROOT/output/images/vmlinux.bin DTB=$BUILDROOT/board/spinal/vexriscv_sim/rv32.dtb RAMDISK=$BUILDROOT/output/images/rootfs.cpio TRACE=no FLOW_INFO=no + +Run linux with QEMU (Require the machime mode emulator compiled in QEMU mode) +export BUILDROOT=/home/miaou/pro/riscv/buildrootSpinal +qemu-system-riscv32 -nographic -machine virt -m 1536M -device loader,file=src/main/c/emulator/build/emulator.bin,addr=0x80000000,cpu-num=0 -device loader,file=$BUILDROOT/board/spinal/vexriscv_sim/rv32.dtb,addr=0xC3000000 -device loader,file=$BUILDROOT/output/images/vmlinux.bin,addr=0xC0000000 -device loader,file=$BUILDROOT/output/images/rootfs.cpio,addr=0xc2000000 +Buildroot => +git clone https://github.com/SpinalHDL/buildroot.git -b vexriscv +cd buildroot +make spinal_vexriscv_sim_defconfig +make -j$(nproc) +output/host/bin/riscv32-linux-objcopy -O binary output/images/vmlinux output/images/vmlinux.bin -make run DBUS=SIMPLE IBUS=SIMPLE SUPERVISOR=yes CSR=yes COMPRESSED=yes REDO=0 DHRYSTONE=no LINUX_SOC=yes EMULATOR=../../../main/c/emulator/build/emulator.bin VMLINUX=/home/miaou/Downloads/tmp/Image DTB=/home/miaou/Downloads/tmp/rv32.dtb RAMDISK=/home/miaou/Downloads/tmp/rootfs.cpio TRACE=no FLOW_INFO=yes TRACE_START=9570000099 - - - - - - - - - -make run DBUS=SIMPLE IBUS=SIMPLE SUPERVISOR=yes CSR=yes COMPRESSED=yes REDO=0 DHRYSTONE=no LINUX_SOC=yes EMULATOR=/home/spinalvm/hdl/VexRiscv/src/main/c/emulator/build/emulator.bin VMLINUX=/home/spinalvm/hdl/riscv-linux/vmlinux.bin DTB=/home/spinalvm/hdl/riscv-linux/rv32.dtb RAMDISK=/home/spinalvm/hdl/linuxDave/initramdisk_dave TRACE=yes0 FLOW_INFO=yes TRACE_START=9570000099 -make run DBUS=SIMPLE IBUS=SIMPLE SUPERVISOR=yes CSR=yes COMPRESSED=yes REDO=0 DHRYSTONE=no LINUX_SOC=yes EMULATOR=/home/spinalvm/hdl/VexRiscv/src/main/c/emulator/build/emulator.bin VMLINUX=/home/spinalvm/hdl/riscv-linux/vmlinux.bin DTB=/home/spinalvm/hdl/riscv-linux/rv32.dtb RAMDISK=/home/spinalvm/hdl/linux/fs/rootfs.ext2 TRACE=yes0 FLOW_INFO=yes TRACE_START=9570000099 - - -make run DBUS=SIMPLE IBUS=SIMPLE SUPERVISOR=yes CSR=yes COMPRESSED=yes REDO=0 DHRYSTONE=no LINUX_SOC=yes EMULATOR=/home/spinalvm/hdl/VexRiscv/src/main/c/emulator/build/emulator.bin VMLINUX=/home/spinalvm/hdl/linux/linux-1c163f4c7b3f621efff9b28a47abb36f7378d783/vmlinux.bin DTB=/home/spinalvm/hdl/linux/linux-1c163f4c7b3f621efff9b28a47abb36f7378d783/rv32.dtb RAMDISK=/home/spinalvm/hdl/linuxDave/initramdisk_dave TRACE=yes0 FLOW_INFO=yes TRACE_START=9570000099 - -make run DBUS=SIMPLE IBUS=SIMPLE SUPERVISOR=yes CSR=yes COMPRESSED=yes REDO=0 DHRYSTONE=no LINUX_SOC=yes EMULATOR=/home/spinalvm/hdl/VexRiscv/src/main/c/emulator/build/emulator.bin VMLINUX=/home/spinalvm/hdl/linux/linux-1c163f4c7b3f621efff9b28a47abb36f7378d783/vmlinux.bin DTB=/home/spinalvm/hdl/linux/linux-1c163f4c7b3f621efff9b28a47abb36f7378d783/rv32.dtb RAMDISK=/home/spinalvm/hdl/linux/fs/rootfs.ext2 TRACE=yes0 FLOW_INFO=yes TRACE_START=9570000099 - - -make run DBUS=SIMPLE IBUS=SIMPLE SUPERVISOR=yes CSR=yes COMPRESSED=yes REDO=0 DHRYSTONE=no LINUX_SOC=yes EMULATOR=/home/spinalvm/hdl/VexRiscv/src/main/c/emulator/build/emulator.bin VMLINUX=/home/spinalvm/hdl/linux/linux-1c163f4c7b3f621efff9b28a47abb36f7378d783/vmlinux.bin DTB=/home/spinalvm/hdl/linux/linux-1c163f4c7b3f621efff9b28a47abb36f7378d783/rv32.dtb RAMDISK=/home/spinalvm/hdl/linux/debug/rootfs.cpio.lzma TRACE=yes0 FLOW_INFO=yes TRACE_START=9570000099 - +After changing a kernel config into buildroot => +cd buildroot +make spinal_vexriscv_sim_defconfig +make linux-dirclean linux-rebuild -j8 +output/host/bin/riscv32-linux-objcopy -O binary output/images/vmlinux output/images/vmlinux.bin +Compiling the machine mode emulator (check the config.h file to know the mode) => +cd src/main/c/emulator +make clean all +Changing the emulator mode => +Edit the src/main/c/emulator/src/config.h file, and comment/uncomment the SIM/QEMU flags Other commands (Memo): -cp litex_default_configuration .config -ARCH=riscv CROSS_COMPILE=riscv64-unknown-elf- make -j`nproc`; riscv64-unknown-elf-objcopy -O binary vmlinux vmlinux.bin -ARCH=riscv CROSS_COMPILE=riscv32-unknown-linux-gnu- make -j`nproc`; riscv32-unknown-linux-gnu-objcopy -O binary vmlinux vmlinux.bin +decompile file and split it riscv64-unknown-elf-objdump -S -d vmlinux > vmlinux.asm; split -b 1M vmlinux.asm -riscv32-unknown-linux-gnu-objdump -S -d vmlinux > vmlinux.asm; split -b 1M vmlinux.asm -Linux => +Kernel compilation command => ARCH=riscv CROSS_COMPILE=riscv32-unknown-linux-gnu- make menuconfig - ARCH=riscv CROSS_COMPILE=riscv32-unknown-linux-gnu- make -j`nproc`; riscv32-unknown-linux-gnu-objcopy -O binary vmlinux vmlinux.bin - - -split -b 1M vmlinux.asm +Generate a DTB from a DTS => dtc -O dtb -o rv32.dtb rv32.dts -make run DBUS=SIMPLE IBUS=SIMPLE SUPERVISOR=yes CSR=yes COMPRESSED=yes REDO=0 DHRYSTONE=no LITEX=yes EMULATOR=/home/spinalvm/hdl/VexRiscv/src/main/c/emulator/build/emulator.bin VMLINUX=/home/spinalvm/hdl/riscv-linux/vmlinux.bin DTB=/home/spinalvm/hdl/riscv-linux/rv32.dtb RAMDISK=/home/spinalvm/hdl/linuxDave/initramdisk_dave TRACE=yes0 FLOW_INFO=yes TRACE_START=9570000099 - https://github.com/riscv/riscv-qemu/wiki#build-and-install - - -buildroot => -make spinalhdl_vexriscv_sim_defconfig -make -j - -make run DBUS=SIMPLE IBUS=SIMPLE SUPERVISOR=yes CSR=yes COMPRESSED=yes REDO=0 DHRYSTONE=no LINUX_SOC=yes EMULATOR=/home/spinalvm/hdl/VexRiscv/src/main/c/emulator/build/emulator.bin VMLINUX=/home/spinalvm/hdl/linux/buildroot/output/images/Image DTB=/home/spinalvm/hdl/linux/linux-1c163f4c7b3f621efff9b28a47abb36f7378d783/rv32.dtb RAMDISK=/home/spinalvm/hdl/linux/buildroot/output/images/rootfs.tar TRACE=yes0 FLOW_INFO=yes TRACE_START=9570000099 - - - -Qemu => -qemu-system-riscv32 -nographic -machine virt -m 1536M -device loader,file=/home/spinalvm/hdl/VexRiscv/src/main/c/emulator/build/emulator.bin,addr=0x80000000,cpu-num=0 -device loader,file=/home/spinalvm/hdl/riscv-linux/rv32.dtb,addr=0x81000000 -device loader,file=/home/spinalvm/hdl/linux/buildroot/output/images/Image,addr=0xC0000000 - - - - - - - -make linux-dirclean linux-rebuild riscv-pk-dirclean riscv-pk-rebuild - -qemu-system-riscv32 -M virt -kernel output/images/bbl -append "root=/dev/vda ro console=ttyS0" -drive file=output/images/rootfs.ext2,format=raw,id=hd0 -device virtio-blk-device,drive=hd0 -netdev user,id=net0 -device virtio-net-device,netdev=net0 -nographic -qemu-system-riscv32 -M virt -kernel output/images/bbl -append "root=/dev/vda ro console=ttyS0" -drive file=output/images/rootfs.ext2,format=raw,id=hd0 -device virtio-blk-device,drive=hd0 -netdev user,id=net0 -device virtio-net-device,netdev=net0 -nographic -dtb virt.dtb - - -Compile -make spinal_vexriscv_sim_defconfig -make linux-dirclean linux-rebuild -j8; output/host/bin/riscv32-linux-objcopy -O binary output/images/vmlinux output/images/vmlinux.bin - -output/host/bin/riscv32-linux-objcopy -O binary output/images/vmlinux output/images/vmlinux.bin -output/host/bin/riscv32-linux-objdump -S -d output/images/vmlinux > output/images/vmlinux.asm; split -b 1M output/images/vmlinux.asm - -make clean -make spinal_vexriscv_sim_defconfig -make -j8; output/host/bin/riscv32-linux-objcopy -O binary output/images/vmlinux output/images/vmlinux.bin - - -Run Qemu -qemu-system-riscv32 -nographic -machine virt -m 1536M -device loader,file=/home/miaou/pro/VexRiscv/src/main/c/emulator/build/emulator.bin,addr=0x80000000,cpu-num=0 -device loader,file=board/spinal/vexriscv_sim/rv32.dtb,addr=0xC4000000 -device loader,file=output/images/vmlinux.bin,addr=0xC0000000 -device loader,file=output/images/rootfs.cpio,addr=0xc5000000 - -Run sim -export BUILDROOT=/home/miaou/pro/riscv/buildrootSpinal -make run DBUS=SIMPLE IBUS=SIMPLE SUPERVISOR=yes CSR=yes COMPRESSED=yes REDO=0 DHRYSTONE=no LINUX_SOC=yes EMULATOR=../../../main/c/emulator/build/emulator.bin VMLINUX=$BUILDROOT/output/images/vmlinux.bin DTB=$BUILDROOT/board/spinal/vexriscv_sim/rv32.dtb RAMDISK=$BUILDROOT/output/images/rootfs.cpio TRACE=no FLOW_INFO=yes TRACE_START=9570000099 - - - */ diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 85f08e31..ab3cde9d 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -3007,11 +3007,16 @@ public: void stdinNonBuffered(){ static struct termios old, new1; - tcgetattr(0, &old); /* grab old terminal i/o settings */ + tcgetattr(STDIN_FILENO, &old); /* grab old terminal i/o settings */ new1 = old; /* make new settings same as old settings */ new1.c_lflag &= ~ICANON; /* disable buffered i/o */ new1.c_lflag &= ~ECHO; - tcsetattr(0, TCSANOW, &new1); /* use these new terminal i/o settings now */ + tcsetattr(STDIN_FILENO, TCSANOW, &new1); /* use these new terminal i/o settings now */ + setvbuf(stdin, NULL, _IONBF, 0); +} + +void stdoutNonBuffered(){ + setvbuf(stdout, NULL, _IONBF, 0); } bool stdinNonEmpty(){ @@ -3031,9 +3036,10 @@ public: LinuxSoc(string name) : Workspace(name) { stdinNonBuffered(); + stdoutNonBuffered(); } virtual bool isDBusCheckedRegion(uint32_t address){ return true;} - virtual bool isPerifRegion(uint32_t addr) { return (addr & 0xF0000000) == 0xB0000000 || (addr & 0xE0000000) == 0xE0000000;} + virtual bool isPerifRegion(uint32_t addr) { return (addr & 0xF0000000) == 0xF0000000 || (addr & 0xE0000000) == 0xE0000000;} virtual bool isMmuRegion(uint32_t addr) { return true; } virtual void dBusAccess(uint32_t addr,bool wr, uint32_t size,uint32_t mask, uint32_t *data, bool *error) { @@ -3053,8 +3059,10 @@ public: char c; read(0, &c, 1); *data = c; + //cout << "getchar " << c << endl; } else { *data = -1; + //cout << "getchar NONE" << endl; } } break; @@ -3389,8 +3397,8 @@ int main(int argc, char **argv, char **env) { .withRiscvRef() ->loadBin(EMULATOR, 0x80000000) ->loadBin(VMLINUX, 0xC0000000) - ->loadBin(DTB, 0xC4000000) - ->loadBin(RAMDISK, 0xC5000000) + ->loadBin(DTB, 0xC3000000) + ->loadBin(RAMDISK, 0xC2000000) ->setIStall(false) //TODO It currently improve speed but should be removed later ->setDStall(false) ->bootAt(0x80000000) From e74a5a71eb76512debc7c99ef0643b61b2f2114c Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Mon, 1 Apr 2019 10:31:55 +0200 Subject: [PATCH 097/951] Better simulation console integration --- src/test/cpp/regression/main.cpp | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index ab3cde9d..e137a8c6 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -3005,6 +3005,7 @@ public: #include #include +termios stdinRestoreSettings; void stdinNonBuffered(){ static struct termios old, new1; tcgetattr(STDIN_FILENO, &old); /* grab old terminal i/o settings */ @@ -3013,12 +3014,17 @@ void stdinNonBuffered(){ new1.c_lflag &= ~ECHO; tcsetattr(STDIN_FILENO, TCSANOW, &new1); /* use these new terminal i/o settings now */ setvbuf(stdin, NULL, _IONBF, 0); + stdinRestoreSettings = old; } void stdoutNonBuffered(){ setvbuf(stdout, NULL, _IONBF, 0); } +void stdinRestore(){ + tcsetattr(STDIN_FILENO, TCSANOW, &stdinRestoreSettings); /* use these new terminal i/o settings now */ +} + bool stdinNonEmpty(){ struct timeval tv; fd_set fds; @@ -3030,6 +3036,23 @@ bool stdinNonEmpty(){ return (FD_ISSET(0, &fds)); } +void my_handler(int s){ + printf("Caught signal %d\n",s); + stdinRestore(); + exit(1); +} +#include + +void captureCtrlC(){ + struct sigaction sigIntHandler; + + sigIntHandler.sa_handler = my_handler; + sigemptyset(&sigIntHandler.sa_mask); + sigIntHandler.sa_flags = 0; + + sigaction(SIGINT, &sigIntHandler, NULL); +} + #ifdef LINUX_SOC class LinuxSoc : public Workspace{ public: @@ -3037,6 +3060,11 @@ public: LinuxSoc(string name) : Workspace(name) { stdinNonBuffered(); stdoutNonBuffered(); + captureCtrlC(); + } + + virtual ~LinuxSoc(){ + stdinRestore(); } virtual bool isDBusCheckedRegion(uint32_t address){ return true;} virtual bool isPerifRegion(uint32_t addr) { return (addr & 0xF0000000) == 0xF0000000 || (addr & 0xE0000000) == 0xE0000000;} @@ -3399,8 +3427,8 @@ int main(int argc, char **argv, char **env) { ->loadBin(VMLINUX, 0xC0000000) ->loadBin(DTB, 0xC3000000) ->loadBin(RAMDISK, 0xC2000000) - ->setIStall(false) //TODO It currently improve speed but should be removed later - ->setDStall(false) + ->setIStall(true) //TODO It currently improve speed but should be removed later + ->setDStall(true) ->bootAt(0x80000000) ->run(0); // ->run(1173000000l ); From 1dff9aff8a31f7f8cbdb25236464044eb656329c Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Mon, 1 Apr 2019 10:47:54 +0200 Subject: [PATCH 098/951] #60 Fix interrupt causing fetch privilege issues --- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index b904f6b3..a7eb19ea 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -767,6 +767,8 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception } when(hadException || interruptJump){ + fetcher.haltIt() //Avoid having the fetch confused by the incomming privilege switch + jumpInterface.valid := True jumpInterface.payload := (if(!xtvecModeGen) xtvec.base @@ "00" else (xtvec.mode === 0 || hadException) ? (xtvec.base @@ "00") | ((xtvec.base + trapCause) @@ "00") ) beforeLastStage.arbitration.flushAll := True @@ -800,10 +802,6 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception } } - //Avoid having the fetch confused by the incomming privilege switch - when(hadException){ - fetcher.haltIt() - } lastStage plug new Area{ import lastStage._ From bc0af02c974226752195f8cea27382aa7af82ba2 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Mon, 1 Apr 2019 11:59:04 +0200 Subject: [PATCH 099/951] #60 Got instruction cache running linux :D --- src/main/scala/vexriscv/TestsWorkspace.scala | 1 - src/main/scala/vexriscv/demo/Briey.scala | 1 - src/main/scala/vexriscv/demo/GenFull.scala | 1 - .../scala/vexriscv/demo/GenFullNoMmu.scala | 1 - .../vexriscv/demo/GenFullNoMmuMaxPerf.scala | 1 - .../demo/GenSmallAndProductiveICache.scala | 1 - src/main/scala/vexriscv/demo/Linux.scala | 71 ++++++++++--------- .../vexriscv/demo/VexRiscvAvalonForSim.scala | 1 - .../VexRiscvAvalonWithIntegratedJtag.scala | 1 - .../demo/VexRiscvAxi4WithIntegratedJtag.scala | 1 - .../demo/VexRiscvCachedWishboneForSim.scala | 1 - .../scala/vexriscv/ip/InstructionCache.scala | 21 +++--- .../scala/vexriscv/plugin/CsrPlugin.scala | 2 +- .../vexriscv/plugin/IBusCachedPlugin.scala | 32 +++++---- src/test/cpp/regression/main.cpp | 8 ++- src/test/cpp/regression/makefile | 2 +- .../vexriscv/TestIndividualFeatures.scala | 1 - 17 files changed, 74 insertions(+), 73 deletions(-) diff --git a/src/main/scala/vexriscv/TestsWorkspace.scala b/src/main/scala/vexriscv/TestsWorkspace.scala index 75e59345..73576ba5 100644 --- a/src/main/scala/vexriscv/TestsWorkspace.scala +++ b/src/main/scala/vexriscv/TestsWorkspace.scala @@ -56,7 +56,6 @@ object TestsWorkspace { memDataWidth = 32, catchIllegalAccess = true, catchAccessFault = true, - catchMemoryTranslationMiss = true, asyncTagMemory = false, twoCycleRam = false, twoCycleCache = true diff --git a/src/main/scala/vexriscv/demo/Briey.scala b/src/main/scala/vexriscv/demo/Briey.scala index 31c74602..d7bb91c8 100644 --- a/src/main/scala/vexriscv/demo/Briey.scala +++ b/src/main/scala/vexriscv/demo/Briey.scala @@ -65,7 +65,6 @@ object BrieyConfig{ memDataWidth = 32, catchIllegalAccess = true, catchAccessFault = true, - catchMemoryTranslationMiss = true, asyncTagMemory = false, twoCycleRam = true, twoCycleCache = true diff --git a/src/main/scala/vexriscv/demo/GenFull.scala b/src/main/scala/vexriscv/demo/GenFull.scala index 2030b05f..e1df08b0 100644 --- a/src/main/scala/vexriscv/demo/GenFull.scala +++ b/src/main/scala/vexriscv/demo/GenFull.scala @@ -23,7 +23,6 @@ object GenFull extends App{ memDataWidth = 32, catchIllegalAccess = true, catchAccessFault = true, - catchMemoryTranslationMiss = true, asyncTagMemory = false, twoCycleRam = true, twoCycleCache = true diff --git a/src/main/scala/vexriscv/demo/GenFullNoMmu.scala b/src/main/scala/vexriscv/demo/GenFullNoMmu.scala index e1aa7226..167735cf 100644 --- a/src/main/scala/vexriscv/demo/GenFullNoMmu.scala +++ b/src/main/scala/vexriscv/demo/GenFullNoMmu.scala @@ -27,7 +27,6 @@ object GenFullNoMmu extends App{ memDataWidth = 32, catchIllegalAccess = true, catchAccessFault = true, - catchMemoryTranslationMiss = true, asyncTagMemory = false, twoCycleRam = true, twoCycleCache = true diff --git a/src/main/scala/vexriscv/demo/GenFullNoMmuMaxPerf.scala b/src/main/scala/vexriscv/demo/GenFullNoMmuMaxPerf.scala index e675aa05..b15d0784 100644 --- a/src/main/scala/vexriscv/demo/GenFullNoMmuMaxPerf.scala +++ b/src/main/scala/vexriscv/demo/GenFullNoMmuMaxPerf.scala @@ -28,7 +28,6 @@ object GenFullNoMmuMaxPerf extends App{ memDataWidth = 32, catchIllegalAccess = true, catchAccessFault = true, - catchMemoryTranslationMiss = false, asyncTagMemory = false, twoCycleRam = true, twoCycleCache = true diff --git a/src/main/scala/vexriscv/demo/GenSmallAndProductiveICache.scala b/src/main/scala/vexriscv/demo/GenSmallAndProductiveICache.scala index 29d179db..9cad30d2 100644 --- a/src/main/scala/vexriscv/demo/GenSmallAndProductiveICache.scala +++ b/src/main/scala/vexriscv/demo/GenSmallAndProductiveICache.scala @@ -26,7 +26,6 @@ object GenSmallAndProductiveICache extends App{ memDataWidth = 32, catchIllegalAccess = false, catchAccessFault = false, - catchMemoryTranslationMiss = false, asyncTagMemory = false, twoCycleRam = false, twoCycleCache = true diff --git a/src/main/scala/vexriscv/demo/Linux.scala b/src/main/scala/vexriscv/demo/Linux.scala index 1d2cb02b..bbd5ecd1 100644 --- a/src/main/scala/vexriscv/demo/Linux.scala +++ b/src/main/scala/vexriscv/demo/Linux.scala @@ -40,13 +40,13 @@ cd VexRiscv Run regressions => sbt "runMain vexriscv.demo.LinuxGen -r" cd src/test/cpp/regression -make run DBUS=SIMPLE IBUS=SIMPLE DHRYSTONE=yes SUPERVISOR=yes CSR=yes COMPRESSED=yes REDO=10 TRACE=no +make run IBUS=CACHED DBUS=SIMPLE DEBUG_PLUGIN=no DHRYSTONE=yes SUPERVISOR=yes CSR=yes COMPRESSED=yes REDO=10 TRACE=no Run linux in simulation (Require the machime mode emulator compiled in SIM mode) => sbt "runMain vexriscv.demo.LinuxGen" cd src/test/cpp/regression export BUILDROOT=/home/miaou/pro/riscv/buildrootSpinal -make run DBUS=SIMPLE IBUS=SIMPLE SUPERVISOR=yes CSR=yes COMPRESSED=yes REDO=0 DHRYSTONE=no LINUX_SOC=yes EMULATOR=../../../main/c/emulator/build/emulator.bin VMLINUX=$BUILDROOT/output/images/vmlinux.bin DTB=$BUILDROOT/board/spinal/vexriscv_sim/rv32.dtb RAMDISK=$BUILDROOT/output/images/rootfs.cpio TRACE=no FLOW_INFO=no +make run IBUS=CACHED DBUS=SIMPLE DEBUG_PLUGIN=no SUPERVISOR=yes CSR=yes COMPRESSED=yes REDO=0 DHRYSTONE=no LINUX_SOC=yes EMULATOR=../../../main/c/emulator/build/emulator.bin VMLINUX=$BUILDROOT/output/images/vmlinux.bin DTB=$BUILDROOT/board/spinal/vexriscv_sim/rv32.dtb RAMDISK=$BUILDROOT/output/images/rootfs.cpio TRACE=no FLOW_INFO=no Run linux with QEMU (Require the machime mode emulator compiled in QEMU mode) export BUILDROOT=/home/miaou/pro/riscv/buildrootSpinal @@ -94,43 +94,46 @@ object LinuxGen { val config = VexRiscvConfig( plugins = List( new DummyFencePlugin(), //TODO should be removed for design with caches - new IBusSimplePlugin( + + //Uncomment the whole IBusSimplePlugin and comment IBusCachedPlugin if you want uncached iBus config +// new IBusSimplePlugin( +// resetVector = 0x80000000l, +// cmdForkOnSecondStage = false, +// cmdForkPersistence = false, +// prediction = NONE, +// historyRamSizeLog2 = 10, +// catchAccessFault = true, +// compressedGen = true, +// busLatencyMin = 1, +// injectorStage = true, +// memoryTranslatorPortConfig = withMmu generate MmuPortConfig( +// portTlbSize = 4 +// ) +// ), + + //Uncomment the whole IBusCachedPlugin and comment IBusSimplePlugin if you want cached iBus config + new IBusCachedPlugin( resetVector = 0x80000000l, - cmdForkOnSecondStage = false, - cmdForkPersistence = false, - prediction = NONE, - historyRamSizeLog2 = 10, - catchAccessFault = true, compressedGen = true, - busLatencyMin = 1, + prediction = NONE, injectorStage = true, - memoryTranslatorPortConfig = withMmu generate MmuPortConfig( + config = InstructionCacheConfig( + cacheSize = 4096, + bytePerLine = 32, + wayCount = 1, + addressWidth = 32, + cpuDataWidth = 32, + memDataWidth = 32, + catchIllegalAccess = true, + catchAccessFault = true, + asyncTagMemory = false, + twoCycleRam = false, + twoCycleCache = true + ), + memoryTranslatorPortConfig = MmuPortConfig( portTlbSize = 4 ) ), - // new IBusCachedPlugin( - // resetVector = 0x80000000l, - // compressedGen = false, - // prediction = NONE, - // injectorStage = true, - // config = InstructionCacheConfig( - // cacheSize = 4096, - // bytePerLine = 32, - // wayCount = 1, - // addressWidth = 32, - // cpuDataWidth = 32, - // memDataWidth = 32, - // catchIllegalAccess = true, - // catchAccessFault = true, - // catchMemoryTranslationMiss = true, - // asyncTagMemory = false, - // twoCycleRam = false, - // twoCycleCache = true - // ), - // memoryTranslatorPortConfig = MemoryTranslatorPortConfig( - // portTlbSize = 4 - // ) - // ), // ).newTightlyCoupledPort(TightlyCoupledPortParameter("iBusTc", a => a(30 downto 28) === 0x0 && a(5))), new DBusSimplePlugin( catchAddressMisaligned = true, @@ -225,7 +228,7 @@ object LinuxGen { // wfiGenAsNop = true, // ucycleAccess = CsrAccess.NONE // )), - new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))), +// new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))), new BranchPlugin( earlyBranch = true, catchAddressMisaligned = true, diff --git a/src/main/scala/vexriscv/demo/VexRiscvAvalonForSim.scala b/src/main/scala/vexriscv/demo/VexRiscvAvalonForSim.scala index cbb76aed..84f90a40 100644 --- a/src/main/scala/vexriscv/demo/VexRiscvAvalonForSim.scala +++ b/src/main/scala/vexriscv/demo/VexRiscvAvalonForSim.scala @@ -48,7 +48,6 @@ object VexRiscvAvalonForSim{ memDataWidth = 32, catchIllegalAccess = true, catchAccessFault = true, - catchMemoryTranslationMiss = true, asyncTagMemory = false, twoCycleRam = true ) diff --git a/src/main/scala/vexriscv/demo/VexRiscvAvalonWithIntegratedJtag.scala b/src/main/scala/vexriscv/demo/VexRiscvAvalonWithIntegratedJtag.scala index 8908cad8..5621b2ef 100644 --- a/src/main/scala/vexriscv/demo/VexRiscvAvalonWithIntegratedJtag.scala +++ b/src/main/scala/vexriscv/demo/VexRiscvAvalonWithIntegratedJtag.scala @@ -44,7 +44,6 @@ object VexRiscvAvalonWithIntegratedJtag{ memDataWidth = 32, catchIllegalAccess = true, catchAccessFault = true, - catchMemoryTranslationMiss = true, asyncTagMemory = false, twoCycleRam = true, twoCycleCache = true diff --git a/src/main/scala/vexriscv/demo/VexRiscvAxi4WithIntegratedJtag.scala b/src/main/scala/vexriscv/demo/VexRiscvAxi4WithIntegratedJtag.scala index 89476360..37ad5520 100644 --- a/src/main/scala/vexriscv/demo/VexRiscvAxi4WithIntegratedJtag.scala +++ b/src/main/scala/vexriscv/demo/VexRiscvAxi4WithIntegratedJtag.scala @@ -45,7 +45,6 @@ object VexRiscvAxi4WithIntegratedJtag{ memDataWidth = 32, catchIllegalAccess = true, catchAccessFault = true, - catchMemoryTranslationMiss = true, asyncTagMemory = false, twoCycleRam = true, twoCycleCache = true diff --git a/src/main/scala/vexriscv/demo/VexRiscvCachedWishboneForSim.scala b/src/main/scala/vexriscv/demo/VexRiscvCachedWishboneForSim.scala index ebf5e820..422e8194 100644 --- a/src/main/scala/vexriscv/demo/VexRiscvCachedWishboneForSim.scala +++ b/src/main/scala/vexriscv/demo/VexRiscvCachedWishboneForSim.scala @@ -44,7 +44,6 @@ object VexRiscvCachedWishboneForSim{ memDataWidth = 32, catchIllegalAccess = true, catchAccessFault = true, - catchMemoryTranslationMiss = true, asyncTagMemory = false, twoCycleRam = true ) diff --git a/src/main/scala/vexriscv/ip/InstructionCache.scala b/src/main/scala/vexriscv/ip/InstructionCache.scala index e7afa73d..c36dcdbf 100644 --- a/src/main/scala/vexriscv/ip/InstructionCache.scala +++ b/src/main/scala/vexriscv/ip/InstructionCache.scala @@ -17,7 +17,6 @@ case class InstructionCacheConfig( cacheSize : Int, memDataWidth : Int, catchIllegalAccess : Boolean, catchAccessFault : Boolean, - catchMemoryTranslationMiss : Boolean, asyncTagMemory : Boolean, twoCycleCache : Boolean = true, twoCycleRam : Boolean = false, @@ -26,7 +25,7 @@ case class InstructionCacheConfig( cacheSize : Int, assert(!(twoCycleRam && !twoCycleCache)) def burstSize = bytePerLine*8/memDataWidth - def catchSomething = catchAccessFault || catchMemoryTranslationMiss || catchIllegalAccess + def catchSomething = catchAccessFault || catchIllegalAccess def getAxi4Config() = Axi4Config( addressWidth = addressWidth, @@ -86,7 +85,7 @@ trait InstructionCacheCommons{ val pc : UInt val physicalAddress : UInt val data : Bits - val cacheMiss, error, mmuMiss, illegalAccess, isUser : Bool + val cacheMiss, error, mmuRefilling, mmuException, isUser : Bool } case class InstructionCacheCpuFetch(p : InstructionCacheConfig) extends Bundle with IMasterSlave with InstructionCacheCommons { @@ -99,11 +98,11 @@ case class InstructionCacheCpuFetch(p : InstructionCacheConfig) extends Bundle w val dataBypass = Bits(p.cpuDataWidth bits) val mmuBus = MemoryTranslatorBus() val physicalAddress = UInt(p.addressWidth bits) - val cacheMiss, error, mmuMiss, illegalAccess,isUser = ifGen(!p.twoCycleCache)(Bool) + val cacheMiss, error, mmuRefilling, mmuException, isUser = ifGen(!p.twoCycleCache)(Bool) override def asMaster(): Unit = { out(isValid, isStuck, isRemoved, pc) - inWithNull(error,mmuMiss,illegalAccess,data, cacheMiss,physicalAddress) + inWithNull(error,mmuRefilling,mmuException,data, cacheMiss,physicalAddress) outWithNull(isUser, dataBypass, dataBypassValid) slaveWithNull(mmuBus) } @@ -116,12 +115,12 @@ case class InstructionCacheCpuDecode(p : InstructionCacheConfig) extends Bundle val pc = UInt(p.addressWidth bits) val physicalAddress = UInt(p.addressWidth bits) val data = Bits(p.cpuDataWidth bits) - val cacheMiss, error, mmuMiss, illegalAccess, isUser = ifGen(p.twoCycleCache)(Bool) + val cacheMiss, error, mmuRefilling, mmuException, isUser = ifGen(p.twoCycleCache)(Bool) override def asMaster(): Unit = { out(isValid, isStuck, pc) outWithNull(isUser) - inWithNull(error,mmuMiss,illegalAccess,data, cacheMiss, physicalAddress) + inWithNull(error, mmuRefilling, mmuException,data, cacheMiss, physicalAddress) } } @@ -411,8 +410,8 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{ io.cpu.fetch.cacheMiss := !hit.valid io.cpu.fetch.error := hit.error - io.cpu.fetch.mmuMiss := ??? //TODO mmuRsp.miss - io.cpu.fetch.illegalAccess := !mmuRsp.allowExecute || (io.cpu.fetch.isUser && !mmuRsp.allowUser) + io.cpu.fetch.mmuRefilling := mmuRsp.refilling + io.cpu.fetch.mmuException := !mmuRsp.refilling && (mmuRsp.exception || !mmuRsp.allowExecute || (!mmuRsp.allowUser && io.cpu.fetch.isUser)) //TODO Do not allow supervisor if it's a user page ? }) } @@ -441,8 +440,8 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{ io.cpu.decode.cacheMiss := !hit.valid io.cpu.decode.error := hit.error - io.cpu.decode.mmuMiss := ??? //TODO mmuRsp.miss - io.cpu.decode.illegalAccess := !mmuRsp.allowExecute || (io.cpu.decode.isUser && !mmuRsp.allowUser) + io.cpu.decode.mmuRefilling := mmuRsp.refilling + io.cpu.decode.mmuException := !mmuRsp.refilling && (mmuRsp.exception || !mmuRsp.allowExecute || (!mmuRsp.allowUser && io.cpu.decode.isUser)) //TODO Do not allow supervisor if it's a user page ? io.cpu.decode.physicalAddress := mmuRsp.physicalAddress }) } diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index a7eb19ea..452aa8d2 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -807,7 +807,7 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception import lastStage._ //Manage MRET / SRET instructions - when(arbitration.isValid && input(ENV_CTRL) === EnvCtrlEnum.XRET) { + when(arbitration.isValid && input(ENV_CTRL) === EnvCtrlEnum.XRET) { //TODO do not allow user mode already implemented somewhere else ? fetcher.haltIt() jumpInterface.valid := True beforeLastStage.arbitration.flushAll := True diff --git a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala index 3b8d4614..ca74a0d8 100644 --- a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala @@ -74,11 +74,11 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l, super.setup(pipeline) - def MANAGEMENT = M"-----------------100-----0001111" + //def MANAGEMENT = M"-----------------100-----0001111" val decoderService = pipeline.service(classOf[DecoderService]) decoderService.addDefault(FLUSH_ALL, False) - decoderService.add(MANAGEMENT, List( + decoderService.add(FENCE_I, List( FLUSH_ALL -> True )) @@ -101,7 +101,7 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l, val e = new BusReport() val c = new CacheReport() e.kind = "cached" - e.flushInstructions.add(0x400F) //invalid instruction cache + e.flushInstructions.add(0x100F) //FENCE.I e.flushInstructions.add(0x13) e.flushInstructions.add(0x13) e.flushInstructions.add(0x13) @@ -187,7 +187,7 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l, val cacheRspArbitration = stages(if (twoCycleCache) 2 else 1) var issueDetected = False val redoFetch = False //RegNext(False) init(False) - when(cacheRsp.isValid && cacheRsp.cacheMiss && !issueDetected) { + when(cacheRsp.isValid && (cacheRsp.cacheMiss || cacheRsp.mmuRefilling) && !issueDetected) { issueDetected \= True redoFetch := iBusRsp.readyForError } @@ -201,19 +201,25 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l, redoBranch.payload := (if (decodePcGen) decode.input(PC) else cacheRsp.pc) if (catchSomething) { - val accessFault = if (catchAccessFault) cacheRsp.error else False - val mmuMiss = if (catchMemoryTranslationMiss) cacheRsp.mmuMiss else False - val illegalAccess = if (catchIllegalAccess) cacheRsp.illegalAccess else False - decodeExceptionPort.valid := False - decodeExceptionPort.code := mmuMiss ? U(14) | 1 + decodeExceptionPort.code.assignDontCare() decodeExceptionPort.badAddr := cacheRsp.pc - when(cacheRsp.isValid && (accessFault || mmuMiss || illegalAccess) && !issueDetected) { + + if(catchIllegalAccess) when(cacheRsp.isValid && cacheRsp.mmuException && !issueDetected) { issueDetected \= True decodeExceptionPort.valid := iBusRsp.readyForError + decodeExceptionPort.code := 12 + } + + if(catchAccessFault) when(cacheRsp.isValid && cacheRsp.error && !issueDetected) { + issueDetected \= True + decodeExceptionPort.valid := iBusRsp.readyForError + decodeExceptionPort.code := 1 } } + decodeExceptionPort.valid clearWhen(fetcherHalt) + cacheRspArbitration.halt setWhen (issueDetected || iBusRspOutputHalt) iBusRsp.output.valid := cacheRspArbitration.output.valid cacheRspArbitration.output.ready := iBusRsp.output.ready @@ -223,7 +229,6 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l, if (mmuBus != null) { cache.io.cpu.fetch.mmuBus <> mmuBus - (if (twoCycleCache) stages(1).halt else rsp.iBusRspOutputHalt) setWhen (mmuBus.cmd.isValid && ???) //TODO !mmuBus.rsp.hit && !mmuBus.rsp.miss } else { cache.io.cpu.fetch.mmuBus.rsp.physicalAddress := cache.io.cpu.fetch.mmuBus.cmd.virtualAddress cache.io.cpu.fetch.mmuBus.rsp.allowExecute := True @@ -231,9 +236,8 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l, cache.io.cpu.fetch.mmuBus.rsp.allowWrite := True cache.io.cpu.fetch.mmuBus.rsp.allowUser := True cache.io.cpu.fetch.mmuBus.rsp.isIoAccess := False - ??? //TODO -// cache.io.cpu.fetch.mmuBus.rsp.miss := False -// cache.io.cpu.fetch.mmuBus.rsp.hit := False + cache.io.cpu.fetch.mmuBus.rsp.exception := False + cache.io.cpu.fetch.mmuBus.rsp.refilling := False } val flushStage = if(memory != null) memory else execute diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index e137a8c6..11011576 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -232,6 +232,7 @@ class success : public std::exception { }; class RiscvGolden { public: int32_t pc, lastPc; + uint32_t lastInstruction; int32_t regs[32]; uint32_t mscratch, sscratch; @@ -706,6 +707,7 @@ public: return; } } + lastInstruction = i; currentInstruction = i; if ((i & 0x3) == 0x3) { //32 bit @@ -1584,7 +1586,11 @@ public: staticMutex.unlock(); } catch (const std::exception& e) { staticMutex.lock(); - cout << "FAIL " << name << " at PC=" << hex << setw(8) << top->VexRiscv->writeBack_PC << dec << endl; //<< " seed : " << seed << + + cout << "FAIL " << name << " at PC=" << hex << setw(8) << top->VexRiscv->writeBack_PC << dec; //<< " seed : " << seed << + if(riscvRefEnable) cout << hex << " REF PC=" << riscvRef.lastPc << " REF I=" << riscvRef.lastInstruction << dec; + cout << endl; + cycles += instanceCycles; staticMutex.unlock(); failed = true; diff --git a/src/test/cpp/regression/makefile b/src/test/cpp/regression/makefile index 62981797..b4330c51 100644 --- a/src/test/cpp/regression/makefile +++ b/src/test/cpp/regression/makefile @@ -27,7 +27,7 @@ REDO?=10 REF=no TRACE_WITH_TIME=no REF_TIME=no -THREAD_COUNT?=4 +THREAD_COUNT?=$(shell nproc) MTIME_INSTR_FACTOR?=no COMPRESSED?=no SUPERVISOR?=no diff --git a/src/test/scala/vexriscv/TestIndividualFeatures.scala b/src/test/scala/vexriscv/TestIndividualFeatures.scala index 7654b4bd..8e85c601 100644 --- a/src/test/scala/vexriscv/TestIndividualFeatures.scala +++ b/src/test/scala/vexriscv/TestIndividualFeatures.scala @@ -315,7 +315,6 @@ class IBusDimension extends VexRiscvDimension("IBus") { memDataWidth = 32, catchIllegalAccess = catchAll, catchAccessFault = catchAll, - catchMemoryTranslationMiss = catchAll, asyncTagMemory = false, twoCycleRam = twoCycleRam, twoCycleCache = twoCycleCache From fd4da77084247c45b9c61cb153ee363405860906 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Tue, 2 Apr 2019 00:26:53 +0200 Subject: [PATCH 100/951] #60 Got the new instruction cache design passing the standard regressions --- src/main/scala/vexriscv/Pipeline.scala | 2 +- src/main/scala/vexriscv/TestsWorkspace.scala | 1 - src/main/scala/vexriscv/demo/Briey.scala | 3 +- src/main/scala/vexriscv/demo/GenFull.scala | 3 +- .../scala/vexriscv/demo/GenFullNoMmu.scala | 3 +- .../vexriscv/demo/GenFullNoMmuMaxPerf.scala | 3 +- src/main/scala/vexriscv/demo/Linux.scala | 141 ++--- .../vexriscv/demo/VexRiscvAvalonForSim.scala | 3 +- .../VexRiscvAvalonWithIntegratedJtag.scala | 3 +- .../demo/VexRiscvAxi4WithIntegratedJtag.scala | 3 +- .../demo/VexRiscvCachedWishboneForSim.scala | 3 +- src/main/scala/vexriscv/ip/DataCache.scala | 591 ++++++------------ .../vexriscv/plugin/DBusCachedPlugin.scala | 61 +- .../plugin/StaticMemoryTranslatorPlugin.scala | 5 +- src/test/cpp/regression/fail.gtkw | 72 +-- src/test/cpp/regression/main.cpp | 1 + .../vexriscv/TestIndividualFeatures.scala | 1 - 17 files changed, 353 insertions(+), 546 deletions(-) diff --git a/src/main/scala/vexriscv/Pipeline.scala b/src/main/scala/vexriscv/Pipeline.scala index 6cbf1c7b..cde5ae8c 100644 --- a/src/main/scala/vexriscv/Pipeline.scala +++ b/src/main/scala/vexriscv/Pipeline.scala @@ -21,7 +21,7 @@ trait Pipeline { def service[T](clazz : Class[T]) = { val filtered = plugins.filter(o => clazz.isAssignableFrom(o.getClass)) - assert(filtered.length == 1) + assert(filtered.length == 1, s"??? ${clazz.getName}") filtered.head.asInstanceOf[T] } diff --git a/src/main/scala/vexriscv/TestsWorkspace.scala b/src/main/scala/vexriscv/TestsWorkspace.scala index 73576ba5..387691aa 100644 --- a/src/main/scala/vexriscv/TestsWorkspace.scala +++ b/src/main/scala/vexriscv/TestsWorkspace.scala @@ -81,7 +81,6 @@ object TestsWorkspace { catchAccessError = true, catchIllegal = true, catchUnaligned = true, - catchMemoryTranslationMiss = true, atomicEntriesCount = 2 ), // memoryTranslatorPortConfig = null diff --git a/src/main/scala/vexriscv/demo/Briey.scala b/src/main/scala/vexriscv/demo/Briey.scala index d7bb91c8..053abf85 100644 --- a/src/main/scala/vexriscv/demo/Briey.scala +++ b/src/main/scala/vexriscv/demo/Briey.scala @@ -88,8 +88,7 @@ object BrieyConfig{ memDataWidth = 32, catchAccessError = true, catchIllegal = true, - catchUnaligned = true, - catchMemoryTranslationMiss = true + catchUnaligned = true ), memoryTranslatorPortConfig = null // memoryTranslatorPortConfig = MemoryTranslatorPortConfig( diff --git a/src/main/scala/vexriscv/demo/GenFull.scala b/src/main/scala/vexriscv/demo/GenFull.scala index e1df08b0..ae753975 100644 --- a/src/main/scala/vexriscv/demo/GenFull.scala +++ b/src/main/scala/vexriscv/demo/GenFull.scala @@ -41,8 +41,7 @@ object GenFull extends App{ memDataWidth = 32, catchAccessError = true, catchIllegal = true, - catchUnaligned = true, - catchMemoryTranslationMiss = true + catchUnaligned = true ), memoryTranslatorPortConfig = MemoryTranslatorPortConfig( portTlbSize = 6 diff --git a/src/main/scala/vexriscv/demo/GenFullNoMmu.scala b/src/main/scala/vexriscv/demo/GenFullNoMmu.scala index 167735cf..00ba8c9e 100644 --- a/src/main/scala/vexriscv/demo/GenFullNoMmu.scala +++ b/src/main/scala/vexriscv/demo/GenFullNoMmu.scala @@ -42,8 +42,7 @@ object GenFullNoMmu extends App{ memDataWidth = 32, catchAccessError = true, catchIllegal = true, - catchUnaligned = true, - catchMemoryTranslationMiss = true + catchUnaligned = true ) ), new StaticMemoryTranslatorPlugin( diff --git a/src/main/scala/vexriscv/demo/GenFullNoMmuMaxPerf.scala b/src/main/scala/vexriscv/demo/GenFullNoMmuMaxPerf.scala index b15d0784..28843d8c 100644 --- a/src/main/scala/vexriscv/demo/GenFullNoMmuMaxPerf.scala +++ b/src/main/scala/vexriscv/demo/GenFullNoMmuMaxPerf.scala @@ -43,8 +43,7 @@ object GenFullNoMmuMaxPerf extends App{ memDataWidth = 32, catchAccessError = true, catchIllegal = true, - catchUnaligned = true, - catchMemoryTranslationMiss = false + catchUnaligned = true ) ), new StaticMemoryTranslatorPlugin( diff --git a/src/main/scala/vexriscv/demo/Linux.scala b/src/main/scala/vexriscv/demo/Linux.scala index bbd5ecd1..cc0c5f79 100644 --- a/src/main/scala/vexriscv/demo/Linux.scala +++ b/src/main/scala/vexriscv/demo/Linux.scala @@ -96,76 +96,77 @@ object LinuxGen { new DummyFencePlugin(), //TODO should be removed for design with caches //Uncomment the whole IBusSimplePlugin and comment IBusCachedPlugin if you want uncached iBus config -// new IBusSimplePlugin( -// resetVector = 0x80000000l, -// cmdForkOnSecondStage = false, -// cmdForkPersistence = false, -// prediction = NONE, -// historyRamSizeLog2 = 10, -// catchAccessFault = true, -// compressedGen = true, -// busLatencyMin = 1, -// injectorStage = true, -// memoryTranslatorPortConfig = withMmu generate MmuPortConfig( -// portTlbSize = 4 -// ) -// ), - - //Uncomment the whole IBusCachedPlugin and comment IBusSimplePlugin if you want cached iBus config - new IBusCachedPlugin( + new IBusSimplePlugin( resetVector = 0x80000000l, - compressedGen = true, + cmdForkOnSecondStage = false, + cmdForkPersistence = false, prediction = NONE, - injectorStage = true, - config = InstructionCacheConfig( - cacheSize = 4096, - bytePerLine = 32, - wayCount = 1, - addressWidth = 32, - cpuDataWidth = 32, - memDataWidth = 32, - catchIllegalAccess = true, - catchAccessFault = true, - asyncTagMemory = false, - twoCycleRam = false, - twoCycleCache = true - ), - memoryTranslatorPortConfig = MmuPortConfig( - portTlbSize = 4 - ) - ), - // ).newTightlyCoupledPort(TightlyCoupledPortParameter("iBusTc", a => a(30 downto 28) === 0x0 && a(5))), - new DBusSimplePlugin( - catchAddressMisaligned = true, + historyRamSizeLog2 = 10, catchAccessFault = true, - earlyInjection = false, - atomicEntriesCount = 1, + compressedGen = true, + busLatencyMin = 1, + injectorStage = true, memoryTranslatorPortConfig = withMmu generate MmuPortConfig( portTlbSize = 4 ) ), - // new DBusCachedPlugin( - // config = new DataCacheConfig( - // cacheSize = 4096, - // bytePerLine = 32, - // wayCount = 1, - // addressWidth = 32, - // cpuDataWidth = 32, - // memDataWidth = 32, - // catchAccessError = true, - // catchIllegal = true, - // catchUnaligned = true, - // catchMemoryTranslationMiss = true, - // atomicEntriesCount = 2 - // ), - // // memoryTranslatorPortConfig = null - // memoryTranslatorPortConfig = MemoryTranslatorPortConfig( - // portTlbSize = 6 - // ) - // ), - // new StaticMemoryTranslatorPlugin( - // ioRange = _(31 downto 28) === 0xF - // ), + + //Uncomment the whole IBusCachedPlugin and comment IBusSimplePlugin if you want cached iBus config +// new IBusCachedPlugin( +// resetVector = 0x80000000l, +// compressedGen = true, +// prediction = NONE, +// injectorStage = true, +// config = InstructionCacheConfig( +// cacheSize = 4096, +// bytePerLine = 32, +// wayCount = 1, +// addressWidth = 32, +// cpuDataWidth = 32, +// memDataWidth = 32, +// catchIllegalAccess = true, +// catchAccessFault = true, +// asyncTagMemory = false, +// twoCycleRam = false, +// twoCycleCache = true +// ) +// ), +// memoryTranslatorPortConfig = MmuPortConfig( +// portTlbSize = 4 +// ) +// ), + // ).newTightlyCoupledPort(TightlyCoupledPortParameter("iBusTc", a => a(30 downto 28) === 0x0 && a(5))), +// new DBusSimplePlugin( +// catchAddressMisaligned = true, +// catchAccessFault = true, +// earlyInjection = false, +// atomicEntriesCount = 1, +// memoryTranslatorPortConfig = withMmu generate MmuPortConfig( +// portTlbSize = 4 +// ) +// ), + new DBusCachedPlugin( + config = new DataCacheConfig( + cacheSize = 4096, + bytePerLine = 32, + wayCount = 1, + addressWidth = 32, + cpuDataWidth = 32, + memDataWidth = 32, + catchAccessError = true, + catchIllegal = true, + catchUnaligned = true, + atomicEntriesCount = 2 + ) +// ), + // memoryTranslatorPortConfig = null +// memoryTranslatorPortConfig = MmuPortConfig( +// portTlbSize = 4 +// ) + ), + new StaticMemoryTranslatorPlugin( + ioRange = _(31 downto 28) === 0xF + ), // new MemoryTranslatorPlugin( // tlbSize = 32, // virtualRange = _(31 downto 28) === 0xC, @@ -237,12 +238,12 @@ object LinuxGen { new YamlPlugin("cpu0.yaml") ) ) - if(withMmu) config.plugins += new MmuPlugin( - virtualRange = a => True, - // virtualRange = x => x(31 downto 24) =/= 0x81, //TODO It fix the DTB kernel access (workaround) - ioRange = (x => if(litex) x(31 downto 28) === 0xB || x(31 downto 28) === 0xE || x(31 downto 28) === 0xF else x(31 downto 28) === 0xF), - allowUserIo = true - ) +// if(withMmu) config.plugins += new MmuPlugin( +// virtualRange = a => True, +// // virtualRange = x => x(31 downto 24) =/= 0x81, //TODO It fix the DTB kernel access (workaround) +// ioRange = (x => if(litex) x(31 downto 28) === 0xB || x(31 downto 28) === 0xE || x(31 downto 28) === 0xF else x(31 downto 28) === 0xF), +// allowUserIo = true +// ) config } @@ -265,7 +266,7 @@ object LinuxGen { // } // } - SpinalConfig(mergeAsyncProcess = true).generateVerilog { + SpinalConfig(mergeAsyncProcess = true, anonymSignalPrefix = "zz").generateVerilog { val toplevel = new VexRiscv(configFull( diff --git a/src/main/scala/vexriscv/demo/VexRiscvAvalonForSim.scala b/src/main/scala/vexriscv/demo/VexRiscvAvalonForSim.scala index 84f90a40..4245cd15 100644 --- a/src/main/scala/vexriscv/demo/VexRiscvAvalonForSim.scala +++ b/src/main/scala/vexriscv/demo/VexRiscvAvalonForSim.scala @@ -66,8 +66,7 @@ object VexRiscvAvalonForSim{ memDataWidth = 32, catchAccessError = true, catchIllegal = true, - catchUnaligned = true, - catchMemoryTranslationMiss = true + catchUnaligned = true ), memoryTranslatorPortConfig = null // memoryTranslatorPortConfig = MemoryTranslatorPortConfig( diff --git a/src/main/scala/vexriscv/demo/VexRiscvAvalonWithIntegratedJtag.scala b/src/main/scala/vexriscv/demo/VexRiscvAvalonWithIntegratedJtag.scala index 5621b2ef..bba065e1 100644 --- a/src/main/scala/vexriscv/demo/VexRiscvAvalonWithIntegratedJtag.scala +++ b/src/main/scala/vexriscv/demo/VexRiscvAvalonWithIntegratedJtag.scala @@ -63,8 +63,7 @@ object VexRiscvAvalonWithIntegratedJtag{ memDataWidth = 32, catchAccessError = true, catchIllegal = true, - catchUnaligned = true, - catchMemoryTranslationMiss = true + catchUnaligned = true ), memoryTranslatorPortConfig = null // memoryTranslatorPortConfig = MemoryTranslatorPortConfig( diff --git a/src/main/scala/vexriscv/demo/VexRiscvAxi4WithIntegratedJtag.scala b/src/main/scala/vexriscv/demo/VexRiscvAxi4WithIntegratedJtag.scala index 37ad5520..b002c065 100644 --- a/src/main/scala/vexriscv/demo/VexRiscvAxi4WithIntegratedJtag.scala +++ b/src/main/scala/vexriscv/demo/VexRiscvAxi4WithIntegratedJtag.scala @@ -64,8 +64,7 @@ object VexRiscvAxi4WithIntegratedJtag{ memDataWidth = 32, catchAccessError = true, catchIllegal = true, - catchUnaligned = true, - catchMemoryTranslationMiss = true + catchUnaligned = true ), memoryTranslatorPortConfig = null // memoryTranslatorPortConfig = MemoryTranslatorPortConfig( diff --git a/src/main/scala/vexriscv/demo/VexRiscvCachedWishboneForSim.scala b/src/main/scala/vexriscv/demo/VexRiscvCachedWishboneForSim.scala index 422e8194..2a834287 100644 --- a/src/main/scala/vexriscv/demo/VexRiscvCachedWishboneForSim.scala +++ b/src/main/scala/vexriscv/demo/VexRiscvCachedWishboneForSim.scala @@ -62,8 +62,7 @@ object VexRiscvCachedWishboneForSim{ memDataWidth = 32, catchAccessError = true, catchIllegal = true, - catchUnaligned = true, - catchMemoryTranslationMiss = true + catchUnaligned = true ), memoryTranslatorPortConfig = null // memoryTranslatorPortConfig = MemoryTranslatorPortConfig( diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index 21f1c38b..96dea4c7 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -8,23 +8,24 @@ import spinal.lib.bus.avalon.{AvalonMM, AvalonMMConfig} import spinal.lib.bus.wishbone.{Wishbone, WishboneConfig} import spinal.lib.bus.simple._ -case class DataCacheConfig( cacheSize : Int, - bytePerLine : Int, - wayCount : Int, - addressWidth : Int, - cpuDataWidth : Int, - memDataWidth : Int, - catchAccessError : Boolean, - catchIllegal : Boolean, - catchUnaligned : Boolean, - catchMemoryTranslationMiss : Boolean, - clearTagsAfterReset : Boolean = true, - waysHitRetime : Boolean = true, - tagSizeShift : Int = 0, //Used to force infering ram - atomicEntriesCount : Int = 0){ +case class DataCacheConfig(cacheSize : Int, + bytePerLine : Int, + wayCount : Int, + addressWidth : Int, + cpuDataWidth : Int, + memDataWidth : Int, + catchAccessError : Boolean, + catchIllegal : Boolean, + catchUnaligned : Boolean, + earlyWaysHits : Boolean = true, + earlyDataMux : Boolean = false, + tagSizeShift : Int = 0, //Used to force infering ram + atomicEntriesCount : Int = 0){ + + assert(!(earlyDataMux && !earlyWaysHits)) def burstSize = bytePerLine*8/memDataWidth val burstLength = bytePerLine/(memDataWidth/8) - def catchSomething = catchUnaligned || catchMemoryTranslationMiss || catchIllegal || catchAccessError + def catchSomething = catchUnaligned || catchIllegal || catchAccessError def genAtomic = atomicEntriesCount != 0 def getAxi4SharedConfig() = Axi4Config( @@ -64,83 +65,6 @@ case class DataCacheConfig( cacheSize : Int, ) } - -object Bypasser{ - - //shot readValid path - def writeFirstMemWrap[T <: Data](readValid : Bool, readLastAddress : UInt, readLastData : 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 | readLastData - } - - - //short readValid path - def writeFirstMemWrap(readValid : Bool, readLastAddress : UInt, readLastData : Bits,writeValid : Bool, writeAddress : UInt, writeData : Bits,writeMask : Bits) : Bits = { - val writeHit = writeValid && writeAddress === readLastAddress - val writeSample = readValid || writeHit - val writeValidReg = RegNextWhen(writeValid,writeSample) - val writeAddressReg = RegNextWhen(writeAddress,writeSample) - val writeDataReg = Reg(writeData) - val writeMaskReg = Reg(Bits(widthOf(writeData)/8 bits)) - val writeDataRegBytes = writeDataReg.subdivideIn(8 bits) - val writeDataBytes = writeData.subdivideIn(8 bits) - val ret = cloneOf(readLastData) - val retBytes = ret.subdivideIn(8 bits) - val readLastDataBytes = readLastData.subdivideIn(8 bits) - val writeRegHit = writeValidReg && writeAddressReg === readLastAddress - for(b <- writeMask.range){ - when(writeHit && writeMask(b)){ - writeMaskReg(b) := True - } - when(readValid) { - writeMaskReg(b) := writeMask(b) - } - when(readValid || (writeHit && writeMask(b))){ - writeDataRegBytes(b) := writeDataBytes(b) - } - - retBytes(b) := (writeRegHit && writeMaskReg(b)) ? writeDataRegBytes(b) | readLastDataBytes(b) - } - ret - } - - //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, sampleData : T, writeValid : Bool, writeAddress : UInt, writeData : T) = { - val bypass = (!sample || (writeValid && sampleAddress === writeAddress)) ? writeData | sampleData - val regEn = sample || (writeValid && sampleLastAddress === writeAddress) - val reg = RegNextWhen(bypass,regEn) - reg - } - - def writeFirstRegWrap(sample : Bool, sampleAddress : UInt,sampleLastAddress : UInt, sampleData : Bits, writeValid : Bool, writeAddress : UInt, writeData : Bits,writeMask : Bits) = { - val byteCount = widthOf(writeMask) - val sampleWriteHit = writeValid && sampleAddress === writeAddress - val sampleLastHit = writeValid && sampleLastAddress === writeAddress - val regBytes = Vec(Bits(8 bits),byteCount) - for(b <- writeMask.range){ - val bypass = Mux(!sample || (sampleWriteHit && writeMask(b)), writeData(b*8, 8 bits), sampleData(b*8, 8 bits)) - val regEn = sample || (sampleLastHit && writeMask(b)) - regBytes(b) := RegNextWhen(bypass,regEn) - } - regBytes.asBits - } -} - -object DataCacheCpuCmdKind extends SpinalEnum{ - val MEMORY,MANAGMENT = newElement() -} - object DataCacheCpuExecute{ implicit def implArgs(that : DataCacheCpuExecute) = that.args } @@ -148,23 +72,22 @@ object DataCacheCpuExecute{ case class DataCacheCpuExecute(p : DataCacheConfig) extends Bundle with IMasterSlave{ val isValid = Bool val isStuck = Bool + val address = UInt(p.addressWidth bit) // val haltIt = Bool val args = DataCacheCpuExecuteArgs(p) override def asMaster(): Unit = { - out(isValid, isStuck, args) + out(isValid, isStuck, args, address) // in(haltIt) } } case class DataCacheCpuExecuteArgs(p : DataCacheConfig) extends Bundle{ - val kind = DataCacheCpuCmdKind() val wr = Bool - val address = UInt(p.addressWidth bit) + //val address = UInt(p.addressWidth bit) Given on the side, as it's also part of the main pipeline val data = Bits(p.cpuDataWidth bit) 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,12 +96,11 @@ case class DataCacheCpuMemory(p : DataCacheConfig) extends Bundle with IMasterSl val isValid = Bool val isStuck = Bool val isRemoved = Bool - val haltIt = Bool + val address = UInt(p.addressWidth bit) val mmuBus = MemoryTranslatorBus() override def asMaster(): Unit = { - out(isValid, isStuck, isRemoved) - in(haltIt) + out(isValid, isStuck, isRemoved, address) slave(mmuBus) } } @@ -190,14 +112,15 @@ case class DataCacheCpuWriteBack(p : DataCacheConfig) extends Bundle with IMaste val isUser = Bool val haltIt = Bool val data = Bits(p.cpuDataWidth bit) - val mmuMiss, illegalAccess, unalignedAccess , accessError = Bool - val badAddr = UInt(32 bits) + val address = UInt(p.addressWidth bit) + val mmuException, unalignedAccess , accessError = Bool 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) + out(isValid,isStuck,isUser, address) + in(haltIt, data, mmuException, unalignedAccess, accessError) outWithNull(clearAtomicEntries) } } @@ -207,10 +130,13 @@ case class DataCacheCpuBus(p : DataCacheConfig) extends Bundle with IMasterSlave val memory = DataCacheCpuMemory(p) val writeBack = DataCacheCpuWriteBack(p) + val redo = Bool() + override def asMaster(): Unit = { master(execute) master(memory) master(writeBack) + in(redo) } } @@ -370,7 +296,6 @@ case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave class DataCache(p : DataCacheConfig) extends Component{ import p._ - import DataCacheCpuCmdKind._ assert(wayCount == 1) assert(cpuDataWidth == memDataWidth) @@ -379,6 +304,7 @@ class DataCache(p : DataCacheConfig) extends Component{ val mem = master(DataCacheMemBus(p)) // val flushDone = out Bool //It pulse at the same time than the manager.request.fire } + val haltCpu = False val lineWidth = bytePerLine*8 val lineCount = cacheSize/bytePerLine @@ -397,14 +323,13 @@ class DataCache(p : DataCacheConfig) extends Component{ class LineInfo() extends Bundle{ - val used = Bool - val dirty = Bool + val valid, error = Bool() val address = UInt(tagRange.length bit) } val tagsReadCmd = Flow(UInt(log2Up(wayLineCount) bits)) val tagsWriteCmd = Flow(new Bundle{ - // val way = UInt(log2Up(wayCount) bits) + val way = Bits(wayCount bits) val address = UInt(log2Up(wayLineCount) bits) val data = new LineInfo() }) @@ -413,13 +338,39 @@ class DataCache(p : DataCacheConfig) extends Component{ val dataReadCmd = Flow(UInt(log2Up(wayWordCount) bits)) val dataWriteCmd = Flow(new Bundle{ - // val way = UInt(log2Up(wayCount) bits) + val way = Bits(wayCount bits) val address = UInt(log2Up(wayWordCount) bits) val data = Bits(wordWidth bits) val mask = Bits(wordWidth/8 bits) }) + + io.mem.cmd.valid := False + io.mem.cmd.payload.assignDontCare() + + val ways = for(i <- 0 until wayCount) yield new Area{ + val tags = Mem(new LineInfo(), wayLineCount) + val data = Mem(Bits(wordWidth bit), wayWordCount) + + //Reads + val tagsReadRsp = tags.readSync(tagsReadCmd.payload, tagsReadCmd.valid && !io.cpu.execute.isStuck) + val dataReadRsp = data.readSync(dataReadCmd.payload, dataReadCmd.valid && !io.cpu.execute.isStuck) + + //Writes + when(tagsWriteCmd.valid && tagsWriteCmd.way(i)){ + tags(tagsWriteCmd.address) := tagsWriteCmd.data + } + when(dataWriteCmd.valid && dataWriteCmd.way(i)){ + data.write( + address = dataWriteCmd.address, + data = dataWriteCmd.data, + mask = dataWriteCmd.mask + ) + } + } + + tagsReadCmd.valid := False tagsReadCmd.payload.assignDontCare() dataReadCmd.valid := False @@ -428,219 +379,74 @@ class DataCache(p : DataCacheConfig) extends Component{ tagsWriteCmd.payload.assignDontCare() dataWriteCmd.valid := False dataWriteCmd.payload.assignDontCare() - io.mem.cmd.valid := False - io.mem.cmd.payload.assignDontCare() - - - val way = new Area{ - val tags = Mem(new LineInfo(),wayLineCount) - val data = Mem(Bits(wordWidth bit),wayWordCount) - - when(tagsWriteCmd.valid){ - tags(tagsWriteCmd.address) := tagsWriteCmd.data - } - when(dataWriteCmd.valid){ - data.write( - address = dataWriteCmd.address, - data = dataWriteCmd.data, - mask = dataWriteCmd.mask - ) - } - - val tagReadRspOneAddress = RegNextWhen(tagsReadCmd.payload, tagsReadCmd.valid) - val tagReadRspOne = Bypasser.writeFirstMemWrap( - readValid = tagsReadCmd.valid, - readLastAddress = tagReadRspOneAddress, - readLastData = tags.readSync(tagsReadCmd.payload,enable = tagsReadCmd.valid), - writeValid = tagsWriteCmd.valid, - writeAddress = tagsWriteCmd.address, - writeData = tagsWriteCmd.data - ) - - val dataReadRspOneKeepAddress = False - val dataReadRspOneAddress = RegNextWhen(dataReadCmd.payload, dataReadCmd.valid && !dataReadRspOneKeepAddress) - val dataReadRspOneWithoutBypass = data.readSync(dataReadCmd.payload,enable = dataReadCmd.valid) - val dataReadRspOne = Bypasser.writeFirstMemWrap( - readValid = dataReadCmd.valid, - readLastAddress = dataReadRspOneAddress, - readLastData = dataReadRspOneWithoutBypass, - writeValid = dataWriteCmd.valid, - writeAddress = dataWriteCmd.address, - writeData = dataWriteCmd.data, - writeMask = dataWriteCmd.mask - ) - - val tagReadRspTwoEnable = !io.cpu.writeBack.isStuck - val tagReadRspTwoRegIn = (tagsWriteCmd.valid && tagsWriteCmd.address === tagReadRspOneAddress) ? tagsWriteCmd.data | tagReadRspOne - val tagReadRspTwo = RegNextWhen(tagReadRspTwoRegIn ,tagReadRspTwoEnable) - - - val dataReadRspTwoEnable = !io.cpu.writeBack.isStuck - val dataReadRspTwo = Bypasser.writeFirstRegWrap( - sample = dataReadRspTwoEnable, - sampleAddress = dataReadRspOneAddress, - sampleLastAddress = RegNextWhen(dataReadRspOneAddress, dataReadRspTwoEnable), - sampleData = dataReadRspOne, - writeValid = dataWriteCmd.valid, - writeAddress = dataWriteCmd.address, - writeData = dataWriteCmd.data, - writeMask = dataWriteCmd.mask - ) - } when(io.cpu.execute.isValid && !io.cpu.execute.isStuck){ - tagsReadCmd.valid := True + tagsReadCmd.valid := True + dataReadCmd.valid := True tagsReadCmd.payload := io.cpu.execute.address(lineRange) - - dataReadCmd.valid := True - dataReadCmd.payload := io.cpu.execute.address(lineRange.high downto wordRange.low) //TODO FMAX maybe critical path could be default + dataReadCmd.payload := io.cpu.execute.address(lineRange.high downto wordRange.low) } - - val cpuMemoryStageNeedReadData = Bool() - - val victim = new Area{ - val requestIn = Stream(cloneable(new Bundle{ - // val way = UInt(log2Up(wayCount) bits) - val address = UInt(p.addressWidth bits) - })) - requestIn.valid := False - requestIn.payload.assignDontCare() - - val request = requestIn.halfPipe() - request.ready := False - - val buffer = Mem(Bits(p.memDataWidth bits),memTransactionPerLine << tagSizeShift) // WARNING << tagSizeShift could resolve cyclone II issue, //.add(new AttributeString("ramstyle","M4K")) - - //Send line read commands to fill the buffer - val readLineCmdCounter = Reg(UInt(log2Up(memTransactionPerLine + 1) bits)) init(0) - val dataReadCmdOccure = False - val dataReadRestored = RegInit(False) - when(request.valid){ - when(!readLineCmdCounter.msb) { - readLineCmdCounter := readLineCmdCounter + 1 - //dataReadCmd := request.address(lineRange.high downto wordRange.low) Done in the manager - dataReadCmdOccure := True - dataReadCmd.valid := True - dataReadCmd.payload := request.address(lineRange) @@ readLineCmdCounter(readLineCmdCounter.high - 1 downto 0) - way.dataReadRspOneKeepAddress := True - } otherwise { - when(!dataReadRestored && cpuMemoryStageNeedReadData) { - dataReadCmd.valid := True - dataReadCmd.payload := way.dataReadRspOneAddress //Restore stage one readed value - } - dataReadRestored := True - } - } - - dataReadRestored clearWhen(request.ready) - io.cpu.memory.haltIt := cpuMemoryStageNeedReadData && request.valid && !dataReadRestored - - //Fill the buffer with line read responses - val readLineRspCounter = Reg(UInt(log2Up(memTransactionPerLine + 1) bits)) init(0) - when(Delay(dataReadCmdOccure,1, init=False)){ - buffer(readLineRspCounter.resized) := way.dataReadRspOneWithoutBypass - readLineRspCounter := readLineRspCounter + 1 - } - - //Send buffer read commands - val bufferReadCounter = Reg(UInt(log2Up(memTransactionPerLine + 1) bits)) init(0) - val bufferReadStream = Stream(buffer.addressType) - bufferReadStream.valid := readLineRspCounter > bufferReadCounter - bufferReadStream.payload := bufferReadCounter.resized - when(bufferReadStream.fire){ - bufferReadCounter := bufferReadCounter + 1 - } - val bufferReaded = buffer.streamReadSync(bufferReadStream).stage - bufferReaded.ready := False - - //Send memory writes from bufffer read responses - val bufferReadedCounter = Reg(UInt(log2Up(memTransactionPerLine) bits)) init(0) - val memCmdAlreadyUsed = False - when(bufferReaded.valid) { - io.mem.cmd.valid := True - io.mem.cmd.wr := True - io.mem.cmd.address := request.address(tagRange.high downto lineRange.low) @@ U(0,lineRange.low bit) - io.mem.cmd.length := p.burstLength-1 - io.mem.cmd.data := bufferReaded.payload - io.mem.cmd.mask := (1<<(wordWidth/8))-1 - io.mem.cmd.last := bufferReadedCounter === bufferReadedCounter.maxValue - - when(!memCmdAlreadyUsed && io.mem.cmd.ready){ - bufferReaded.ready := True - bufferReadedCounter := bufferReadedCounter + 1 - when(bufferReadedCounter === bufferReadedCounter.maxValue){ - request.ready := True - } - } - } - - - val counter = Counter(memTransactionPerLine) - when(request.ready){ - readLineCmdCounter.msb := False - readLineRspCounter.msb := False - bufferReadCounter.msb := False + def collisionProcess(readAddress : UInt, readMask : Bits): Bits ={ + val ret = Bits(wayCount bits) + for(i <- 0 until wayCount){ + ret(i) := dataWriteCmd.valid && dataWriteCmd.way(i) && dataWriteCmd.address === readAddress && (readMask & dataWriteCmd.mask) =/= 0 } + ret } - - - val stageA = new Area{ - val request = RegNextWhen(io.cpu.execute.args, !io.cpu.memory.isStuck) - io.cpu.memory.mmuBus.cmd.isValid := io.cpu.memory.isValid && request.kind === MEMORY //TODO filter request kind - io.cpu.memory.mmuBus.cmd.virtualAddress := request.address - io.cpu.memory.mmuBus.cmd.bypassTranslation := request.way - io.cpu.memory.mmuBus.end := !io.cpu.memory.isStuck || io.cpu.memory.isRemoved - cpuMemoryStageNeedReadData := io.cpu.memory.isValid && request.kind === MEMORY && !request.wr - } - - val stageB = new Area { - val request = RegNextWhen(stageA.request, !io.cpu.writeBack.isStuck) - val mmuRsp = RegNextWhen(io.cpu.memory.mmuBus.rsp, !io.cpu.writeBack.isStuck) - val waysHit = if(waysHitRetime) - RegNextWhen(way.tagReadRspTwoRegIn.used && io.cpu.memory.mmuBus.rsp.physicalAddress(tagRange) === way.tagReadRspTwoRegIn.address,!io.cpu.writeBack.isStuck) //Manual retiming - else - way.tagReadRspTwo.used && mmuRsp.physicalAddress(tagRange) === way.tagReadRspTwo.address - - - //Loader interface - val loaderValid = False - val loaderReady = False - val loadingDone = RegNext(loaderValid && loaderReady) init(False) //one cycle pulse - - //delayedXX are used to relax logic timings in flush and evict modes - val delayedIsStuck = RegNext(io.cpu.writeBack.isStuck) - val delayedWaysHitValid = RegNext(waysHit) - - val victimNotSent = RegInit(False) clearWhen(victim.requestIn.ready) setWhen(!io.cpu.memory.isStuck) - val loadingNotDone = RegInit(False) clearWhen(loaderReady) setWhen(!io.cpu.memory.isStuck) - - val writeMask = request.size.mux ( + val stage0 = new Area{ + val mask = io.cpu.execute.size.mux ( U(0) -> B"0001", U(1) -> B"0011", default -> B"1111" - ) |<< mmuRsp.physicalAddress(1 downto 0) + ) |<< io.cpu.execute.address(1 downto 0) + val colisions = collisionProcess(io.cpu.execute.address(lineRange.high downto wordRange.low), mask) + } + + val stageA = new Area{ + def stagePipe[T <: Data](that : T) = RegNextWhen(that, !io.cpu.memory.isStuck) + val request = stagePipe(io.cpu.execute.args) + val mask = stagePipe(stage0.mask) + io.cpu.memory.mmuBus.cmd.isValid := io.cpu.memory.isValid + io.cpu.memory.mmuBus.cmd.virtualAddress := io.cpu.memory.address + io.cpu.memory.mmuBus.cmd.bypassTranslation := False + io.cpu.memory.mmuBus.end := !io.cpu.memory.isStuck || io.cpu.memory.isRemoved + + val wayHits = earlyWaysHits generate ways.map(way => (io.cpu.memory.mmuBus.rsp.physicalAddress(tagRange) === way.tagsReadRsp.address && way.tagsReadRsp.valid)) + val dataMux = earlyDataMux generate MuxOH(wayHits, ways.map(_.dataReadRsp)) + val colisions = stagePipe(stage0.colisions) | collisionProcess(io.cpu.memory.address(lineRange.high downto wordRange.low), mask) //Assume the writeback stage will never be unstall memory acces while memory stage is stalled + } + + val stageB = new Area { + def stagePipe[T <: Data](that : T) = RegNextWhen(that, !io.cpu.writeBack.isStuck) + val request = RegNextWhen(stageA.request, !io.cpu.writeBack.isStuck) + val mmuRspFreeze = False + val mmuRsp = RegNextWhen(io.cpu.memory.mmuBus.rsp, !io.cpu.writeBack.isStuck && !mmuRspFreeze) + val tagsReadRsp = ways.map(w => stagePipe(w.tagsReadRsp)) + val dataReadRsp = !earlyDataMux generate ways.map(w => stagePipe(w.dataReadRsp)) + val waysHits = if(earlyWaysHits) stagePipe(B(stageA.wayHits)) else B(tagsReadRsp.map(tag => mmuRsp.physicalAddress(tagRange) === tag.address && tag.valid).asBits()) + val waysHit = waysHits.orR + val dataMux = if(earlyDataMux) stagePipe(stageA.dataMux) else MuxOH(waysHits, dataReadRsp) + val mask = stagePipe(stageA.mask) + val colisions = stagePipe(stageA.colisions) + + //Loader interface + val loaderValid = False + - val hadMemRspErrorReg = RegInit(False) - val hadMemRspError = (io.mem.rsp.valid && io.mem.rsp.error) || hadMemRspErrorReg - hadMemRspErrorReg := hadMemRspError && io.cpu.writeBack.haltIt io.cpu.writeBack.haltIt := io.cpu.writeBack.isValid - io.cpu.writeBack.mmuMiss := False - io.cpu.writeBack.illegalAccess := False - io.cpu.writeBack.unalignedAccess := False - io.cpu.writeBack.accessError := (if(catchAccessError) hadMemRspError && !io.cpu.writeBack.haltIt else False) - io.cpu.writeBack.badAddr := request.address //Evict the cache after reset logics - val bootEvicts = if(clearTagsAfterReset) new Area { + val flusher = new Area { val valid = RegInit(True) mmuRsp.physicalAddress init (0) when(valid) { tagsWriteCmd.valid := valid tagsWriteCmd.address := mmuRsp.physicalAddress(lineRange) - tagsWriteCmd.data.used := False + tagsWriteCmd.way.setAll() + tagsWriteCmd.data.valid := False when(mmuRsp.physicalAddress(lineRange) =/= lineCount - 1) { mmuRsp.physicalAddress.getDrivingReg(lineRange) := mmuRsp.physicalAddress(lineRange) + 1 io.cpu.writeBack.haltIt := True @@ -651,7 +457,7 @@ class DataCache(p : DataCacheConfig) extends Component{ } - val atomic = if(genAtomic) new Area{ + val atomic = genAtomic generate new Area{ case class AtomicEntry() extends Bundle{ val valid = Bool() val size = UInt(2 bits) @@ -664,11 +470,11 @@ class DataCache(p : DataCacheConfig) extends Component{ } 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 + val entriesHit = entries.map(e => e.valid && e.size === request.size && e.address === io.cpu.writeBack.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 + entries(entriesAllocCounter).size := request.size //TODO remove size stuff + entries(entriesAllocCounter).address := io.cpu.writeBack.address when(!io.cpu.writeBack.isStuck){ entriesAllocCounter.increment() } @@ -676,128 +482,127 @@ class DataCache(p : DataCacheConfig) extends Component{ when(io.cpu.writeBack.clearAtomicEntries){ entries.foreach(_.valid := False) } + } + + val memCmdSent = RegInit(False) setWhen (io.mem.cmd.ready) clearWhen (!io.cpu.writeBack.isStuck) + + io.cpu.redo := mmuRsp.refilling + io.cpu.writeBack.accessError := False + io.cpu.writeBack.mmuException := io.cpu.writeBack.isValid && (if(catchIllegal) mmuRsp.exception || (!mmuRsp.allowWrite && request.wr) || (!mmuRsp.allowRead && !request.wr) || (!mmuRsp.allowUser && io.cpu.writeBack.isUser) else False) + io.cpu.writeBack.unalignedAccess := io.cpu.writeBack.isValid && (if(catchUnaligned) ((request.size === 2 && mmuRsp.physicalAddress(1 downto 0) =/= 0) || (request.size === 1 && mmuRsp.physicalAddress(0 downto 0) =/= 0)) else False) - when(request.isAtomic && ! entriesHit){ - writeMask := 0 - } - } else null when(io.cpu.writeBack.isValid) { - if (catchMemoryTranslationMiss) { - io.cpu.writeBack.mmuMiss := ??? //TODO mmuRsp.miss - } - switch(request.kind) { - is(MANAGMENT) { - when(delayedIsStuck && ???){ //TODO!mmuRsp.miss) { - when(delayedWaysHitValid || (request.way && way.tagReadRspTwo.used)) { - io.cpu.writeBack.haltIt.clearWhen(!(victim.requestIn.valid && !victim.requestIn.ready)) - victim.requestIn.valid := request.clean && way.tagReadRspTwo.dirty - tagsWriteCmd.valid := victim.requestIn.ready - } otherwise{ - io.cpu.writeBack.haltIt := False - } - } + when(request.forceUncachedAccess || mmuRsp.isIoAccess) { + io.cpu.writeBack.haltIt.clearWhen(request.wr ? io.mem.cmd.ready | io.mem.rsp.valid) - victim.requestIn.address := way.tagReadRspTwo.address @@ mmuRsp.physicalAddress(lineRange) @@ U((lineRange.low - 1 downto 0) -> false) - tagsWriteCmd.address := mmuRsp.physicalAddress(lineRange) - tagsWriteCmd.data.used := !request.invalidate - tagsWriteCmd.data.dirty := !request.clean - } - is(MEMORY) { - val illegal = if(catchIllegal) (request.wr && !mmuRsp.allowWrite) || (!request.wr && !mmuRsp.allowRead) || (io.cpu.writeBack.isUser && !mmuRsp.allowUser) else False - val unaligned = if(catchUnaligned) ((request.size === 2 && mmuRsp.physicalAddress(1 downto 0) =/= 0) || (request.size === 1 && mmuRsp.physicalAddress(0 downto 0) =/= 0)) else False - io.cpu.writeBack.illegalAccess := illegal - io.cpu.writeBack.unalignedAccess := unaligned - when((Bool(!catchMemoryTranslationMiss) || ???) && !illegal && !unaligned) { //TODO !mmuRsp.miss - when(request.forceUncachedAccess || mmuRsp.isIoAccess) { - val memCmdSent = RegInit(False) - when(!victim.request.valid) { - //Avoid mixing memory request while victim is pending - io.mem.cmd.wr := request.wr - io.mem.cmd.address := mmuRsp.physicalAddress(tagRange.high downto wordRange.low) @@ U(0, wordRange.low bit) - io.mem.cmd.mask := writeMask - io.mem.cmd.data := request.data - io.mem.cmd.length := 0 - io.mem.cmd.last := True + io.mem.cmd.valid := !memCmdSent + io.mem.cmd.wr := request.wr + io.mem.cmd.address := mmuRsp.physicalAddress(tagRange.high downto wordRange.low) @@ U(0, wordRange.low bit) + io.mem.cmd.mask := mask + io.mem.cmd.data := request.data + io.mem.cmd.length := 0 + io.mem.cmd.last := True + } otherwise { + when(waysHit || request.wr) { //Do not require a cache refill ? + //Data cache update + dataWriteCmd.valid setWhen(request.wr && waysHit) + dataWriteCmd.address := mmuRsp.physicalAddress(lineRange.high downto wordRange.low) + dataWriteCmd.data := request.data + dataWriteCmd.mask := mask + dataWriteCmd.way := waysHits - when(!memCmdSent) { - io.mem.cmd.valid := True - memCmdSent setWhen (io.mem.cmd.ready) - } + //Write through + io.mem.cmd.valid setWhen(request.wr) + io.mem.cmd.wr := True + io.mem.cmd.address := mmuRsp.physicalAddress(tagRange.high downto wordRange.low) @@ U(0, wordRange.low bit) + io.mem.cmd.mask := mask + io.mem.cmd.data := request.data + io.mem.cmd.length := 0 + io.mem.cmd.last := True + io.cpu.writeBack.haltIt clearWhen(!request.wr || io.mem.cmd.ready) - io.cpu.writeBack.haltIt.clearWhen(memCmdSent && (io.mem.rsp.fire || request.wr)) //Cut mem.cmd.ready path but insert one cycle stall when write - } - memCmdSent clearWhen (!io.cpu.writeBack.isStuck) - } otherwise { - when(waysHit || !loadingNotDone) { - io.cpu.writeBack.haltIt := False - dataWriteCmd.valid := request.wr - dataWriteCmd.address := mmuRsp.physicalAddress(lineRange.high downto wordRange.low) - dataWriteCmd.data := request.data - dataWriteCmd.mask := writeMask + //On write to read colisions + io.cpu.redo := !request.wr && (colisions & waysHits) =/= 0 + } otherwise { //Do refill - tagsWriteCmd.valid := (!loadingNotDone) || request.wr - tagsWriteCmd.address := mmuRsp.physicalAddress(lineRange) - tagsWriteCmd.data.used := True - tagsWriteCmd.data.dirty := request.wr - tagsWriteCmd.data.address := mmuRsp.physicalAddress(tagRange) - } otherwise { - val victimRequired = way.tagReadRspTwo.used && way.tagReadRspTwo.dirty - loaderValid := loadingNotDone && !(victimNotSent && victim.request.isStall) //Additional condition used to be sure of that all previous victim are written into the RAM - victim.requestIn.valid := victimRequired && victimNotSent - victim.requestIn.address := way.tagReadRspTwo.address @@ mmuRsp.physicalAddress(lineRange) @@ U((lineRange.low - 1 downto 0) -> false) - } - } - } + //Emit cmd + io.mem.cmd.valid setWhen(!memCmdSent) + io.mem.cmd.wr := False + io.mem.cmd.address := mmuRsp.physicalAddress(tagRange.high downto lineRange.low) @@ U(0,lineRange.low bit) + io.mem.cmd.length := p.burstLength-1 + io.mem.cmd.last := True + + loaderValid setWhen(io.mem.cmd.ready) } } } + when(request.forceUncachedAccess || mmuRsp.isIoAccess){ + io.cpu.writeBack.data := io.mem.rsp.data + if(catchAccessError) io.cpu.writeBack.accessError := io.mem.rsp.valid && io.mem.rsp.error + } otherwise { + io.cpu.writeBack.data := dataMux + if(catchAccessError) io.cpu.writeBack.accessError := (waysHits & B(tagsReadRsp.map(_.error))) =/= 0 + } + + //remove side effects on exceptions + when(mmuRsp.refilling || io.cpu.writeBack.accessError || io.cpu.writeBack.mmuException || io.cpu.writeBack.unalignedAccess){ + io.mem.cmd.valid := False + tagsWriteCmd.valid := False + dataWriteCmd.valid := False + loaderValid := False + io.cpu.writeBack.haltIt := False + } 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 } + when(request.isAtomic && !atomic.entriesHit){ + io.mem.cmd.mask := 0 + } } } - //The whole life of a loading task, the corresponding manager request is present val loader = new Area{ - val valid = RegNext(stageB.loaderValid) init(False) + val valid = RegInit(False) setWhen(stageB.loaderValid) val baseAddress = stageB.mmuRsp.physicalAddress - val memCmdSent = RegInit(False) - when(valid && !memCmdSent) { - io.mem.cmd.valid := True - io.mem.cmd.wr := False - io.mem.cmd.address := baseAddress(tagRange.high downto lineRange.low) @@ U(0,lineRange.low bit) - io.mem.cmd.length := p.burstLength-1 - io.mem.cmd.last := True - } - - when(valid && io.mem.cmd.ready){ - memCmdSent := True - } - - when(valid && !memCmdSent) { - victim.memCmdAlreadyUsed := True - } - val counter = Counter(memTransactionPerLine) + val waysAllocator = Reg(Bits(wayCount bits)) init(1) + val error = RegInit(False) + when(valid && io.mem.rsp.valid){ dataWriteCmd.valid := True dataWriteCmd.address := baseAddress(lineRange) @@ counter dataWriteCmd.data := io.mem.rsp.data - dataWriteCmd.mask := (1<<(wordWidth/8))-1 + dataWriteCmd.mask.setAll() + dataWriteCmd.way := waysAllocator + error := error | io.mem.rsp.error counter.increment() } + when(counter.willOverflow){ - memCmdSent := False valid := False - stageB.loaderReady := True + + //Update tags + tagsWriteCmd.valid := True + tagsWriteCmd.address := baseAddress(lineRange) + tagsWriteCmd.data.valid := True + tagsWriteCmd.data.address := baseAddress(tagRange) + tagsWriteCmd.data.error := error || io.mem.rsp.error + tagsWriteCmd.way := waysAllocator + + waysAllocator := (waysAllocator ## waysAllocator.msb).resized + + error := False } + + io.cpu.redo setWhen(valid) + stageB.mmuRspFreeze setWhen(stageB.loaderValid || valid) } } \ No newline at end of file diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index b5eca04b..c62984aa 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -26,6 +26,7 @@ class DBusCachedPlugin(config : DataCacheConfig, var mmuBus : MemoryTranslatorBus = null var exceptionBus : Flow[ExceptionCause] = null var privilegeService : PrivilegeService = null + var redoBranch : Flow[UInt] = null object MEMORY_ENABLE extends Stageable(Bool) object MEMORY_MANAGMENT extends Stageable(Bool) @@ -44,7 +45,7 @@ class DBusCachedPlugin(config : DataCacheConfig, SRC_USE_SUB_LESS -> False, MEMORY_ENABLE -> True, RS1_USE -> True - ) ++ (if (catchUnaligned) List(IntAluPlugin.ALU_CTRL -> IntAluPlugin.AluCtrlEnum.ADD_SUB) else Nil) //Used for access fault bad address in memory stage + ) ++ (if (catchSomething) List(IntAluPlugin.ALU_CTRL -> IntAluPlugin.AluCtrlEnum.ADD_SUB) else Nil) //Used for access fault bad address in memory stage val loadActions = stdActions ++ List( SRC2_CTRL -> Src2CtrlEnum.IMI, @@ -75,13 +76,14 @@ class DBusCachedPlugin(config : DataCacheConfig, decoderService.add( key = LR, values = loadActions.filter(_._1 != SRC2_CTRL) ++ Seq( - SRC2_CTRL -> Src2CtrlEnum.RS, + SRC_ADD_ZERO -> True, MEMORY_ATOMIC -> True ) ) decoderService.add( key = SC, values = storeActions.filter(_._1 != SRC2_CTRL) ++ Seq( + SRC_ADD_ZERO -> True, REGFILE_WRITE_VALID -> True, BYPASSABLE_EXECUTE_STAGE -> False, BYPASSABLE_MEMORY_STAGE -> False, @@ -98,6 +100,7 @@ class DBusCachedPlugin(config : DataCacheConfig, )) mmuBus = pipeline.service(classOf[MemoryTranslator]).newTranslationPort(MemoryTranslatorPort.PRIORITY_DATA ,memoryTranslatorPortConfig) + redoBranch = pipeline.service(classOf[JumpService]).createJumpInterface(pipeline.writeBack) if(catchSomething) exceptionBus = pipeline.service(classOf[ExceptionService]).newExceptionPort(pipeline.writeBack) @@ -141,28 +144,27 @@ class DBusCachedPlugin(config : DataCacheConfig, val size = input(INSTRUCTION)(13 downto 12).asUInt cache.io.cpu.execute.isValid := arbitration.isValid && input(MEMORY_ENABLE) cache.io.cpu.execute.isStuck := arbitration.isStuck + cache.io.cpu.execute.address := input(SRC_ADD).asUInt cache.io.cpu.execute.args.wr := input(MEMORY_WR) - cache.io.cpu.execute.args.address := input(SRC_ADD).asUInt cache.io.cpu.execute.args.data := size.mux( U(0) -> input(RS2)( 7 downto 0) ## input(RS2)( 7 downto 0) ## input(RS2)(7 downto 0) ## input(RS2)(7 downto 0), U(1) -> input(RS2)(15 downto 0) ## input(RS2)(15 downto 0), default -> input(RS2)(31 downto 0) ) cache.io.cpu.execute.args.size := size - cache.io.cpu.execute.args.forceUncachedAccess := False - cache.io.cpu.execute.args.kind := input(MEMORY_MANAGMENT) ? DataCacheCpuCmdKind.MANAGMENT | DataCacheCpuCmdKind.MEMORY - 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) + cache.io.cpu.execute.args.forceUncachedAccess := False if(genAtomic) { cache.io.cpu.execute.args.isAtomic := False when(input(MEMORY_ATOMIC)){ cache.io.cpu.execute.args.isAtomic := True - cache.io.cpu.execute.args.address := input(SRC1).asUInt } } - insert(MEMORY_ADDRESS_LOW) := cache.io.cpu.execute.args.address(1 downto 0) + insert(MEMORY_ADDRESS_LOW) := cache.io.cpu.execute.address(1 downto 0) + + when(cache.io.cpu.redo && arbitration.isValid && input(MEMORY_ENABLE)){ + arbitration.haltItself := True + } } memory plug new Area{ @@ -170,10 +172,9 @@ class DBusCachedPlugin(config : DataCacheConfig, cache.io.cpu.memory.isValid := arbitration.isValid && input(MEMORY_ENABLE) cache.io.cpu.memory.isStuck := arbitration.isStuck cache.io.cpu.memory.isRemoved := arbitration.removeIt - arbitration.haltItself setWhen(cache.io.cpu.memory.haltIt) + cache.io.cpu.memory.address := U(input(REGFILE_WRITE_DATA)) cache.io.cpu.memory.mmuBus <> mmuBus - arbitration.haltItself setWhen (mmuBus.cmd.isValid && ???) //TODO !mmuBus.rsp.hit && !mmuBus.rsp.miss } writeBack plug new Area{ @@ -181,20 +182,36 @@ class DBusCachedPlugin(config : DataCacheConfig, 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() else False) + cache.io.cpu.writeBack.address := U(input(REGFILE_WRITE_DATA)) 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 - exceptionBus.badAddr := cache.io.cpu.writeBack.badAddr + exceptionBus.valid := False //cache.io.cpu.writeBack.mmuMiss || cache.io.cpu.writeBack.accessError || cache.io.cpu.writeBack.illegalAccess || cache.io.cpu.writeBack.unalignedAccess + exceptionBus.badAddr := U(input(REGFILE_WRITE_DATA)) exceptionBus.code.assignDontCare() - when(cache.io.cpu.writeBack.illegalAccess || cache.io.cpu.writeBack.accessError){ - exceptionBus.code := (input(MEMORY_WR) ? U(7) | U(5)).resized - } - when(cache.io.cpu.writeBack.unalignedAccess){ - exceptionBus.code := (input(MEMORY_WR) ? U(6) | U(4)).resized - } - when(cache.io.cpu.writeBack.mmuMiss){ - exceptionBus.code := 13 + + redoBranch.valid := False + redoBranch.payload := input(PC) + arbitration.flushAll setWhen(redoBranch.valid) + + when(cache.io.cpu.writeBack.isValid) { + if (catchAccessError) when(cache.io.cpu.writeBack.accessError) { + exceptionBus.valid := True + exceptionBus.code := (input(MEMORY_WR) ? U(7) | U(5)).resized + } + + if (catchUnaligned) when(cache.io.cpu.writeBack.unalignedAccess) { + exceptionBus.valid := True + exceptionBus.code := (input(MEMORY_WR) ? U(6) | U(4)).resized + } + when (cache.io.cpu.writeBack.mmuException) { + exceptionBus.valid := True + exceptionBus.code := (input(MEMORY_WR) ? U(15) | U(13)).resized + } + when(cache.io.cpu.redo) { + redoBranch.valid := True + exceptionBus.valid := False + } } } arbitration.haltItself.setWhen(cache.io.cpu.writeBack.haltIt) diff --git a/src/main/scala/vexriscv/plugin/StaticMemoryTranslatorPlugin.scala b/src/main/scala/vexriscv/plugin/StaticMemoryTranslatorPlugin.scala index d190ef07..a2a6bbc3 100644 --- a/src/main/scala/vexriscv/plugin/StaticMemoryTranslatorPlugin.scala +++ b/src/main/scala/vexriscv/plugin/StaticMemoryTranslatorPlugin.scala @@ -33,9 +33,8 @@ class StaticMemoryTranslatorPlugin(ioRange : UInt => Bool) extends Plugin[VexRis port.bus.rsp.allowExecute := True port.bus.rsp.allowUser := True port.bus.rsp.isIoAccess := ioRange(port.bus.rsp.physicalAddress) - ??? -// port.bus.rsp.miss := False -// port.bus.rsp.hit := True + port.bus.rsp.exception := False + port.bus.rsp.refilling := False } } } diff --git a/src/test/cpp/regression/fail.gtkw b/src/test/cpp/regression/fail.gtkw index 788713e2..be474029 100644 --- a/src/test/cpp/regression/fail.gtkw +++ b/src/test/cpp/regression/fail.gtkw @@ -1,19 +1,19 @@ [*] [*] GTKWave Analyzer v3.3.100 (w)1999-2019 BSI -[*] Sat Mar 30 09:33:33 2019 +[*] Mon Apr 1 21:53:07 2019 [*] -[dumpfile] "/home/miaou/pro/VexRiscv/src/test/cpp/regression/linux.vcd" -[dumpfile_mtime] "Sat Mar 30 09:16:30 2019" -[dumpfile_size] 249834424 +[dumpfile] "/home/miaou/pro/VexRiscv/src/test/cpp/regression/rv32ui-p-lw.vcd" +[dumpfile_mtime] "Mon Apr 1 21:52:20 2019" +[dumpfile_size] 1974526 [savefile] "/home/miaou/pro/VexRiscv/src/test/cpp/regression/fail.gtkw" -[timestart] 106663042 +[timestart] 348 [size] 1920 1030 -[pos] -458 -215 -*-5.000000 106541900 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 +[pos] -1 -1 +*-2.000000 357 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 [treeopen] TOP. [treeopen] TOP.VexRiscv. [sst_width] 287 -[signals_width] 465 +[signals_width] 563 [sst_expanded] 1 [sst_vpaned_height] 279 @28 @@ -21,43 +21,37 @@ TOP.VexRiscv.writeBack_arbitration_isFiring @22 TOP.VexRiscv.writeBack_PC[31:0] TOP.VexRiscv.writeBack_INSTRUCTION[31:0] +TOP.VexRiscv.writeBack_RegFilePlugin_regFileWrite_payload_address[4:0] +TOP.VexRiscv.writeBack_RegFilePlugin_regFileWrite_payload_data[31:0] @28 -TOP.VexRiscv.CsrPlugin_exception -TOP.VexRiscv.CsrPlugin_privilege[1:0] +TOP.VexRiscv.writeBack_RegFilePlugin_regFileWrite_valid +[color] 1 +TOP.VexRiscv.dataCache_1_.io_mem_cmd_valid +[color] 1 +TOP.VexRiscv.dataCache_1_.io_mem_cmd_ready @22 -TOP.VexRiscv.CsrPlugin_scause_exceptionCode[3:0] +[color] 1 +TOP.VexRiscv.dataCache_1_.io_mem_cmd_payload_address[31:0] +[color] 1 +TOP.VexRiscv.dataCache_1_.io_mem_cmd_payload_data[31:0] @28 -TOP.VexRiscv.CsrPlugin_scause_interrupt +[color] 1 +TOP.VexRiscv.dataCache_1_.io_mem_cmd_payload_last +[color] 1 +TOP.VexRiscv.dataCache_1_.io_mem_cmd_payload_length[2:0] @22 -TOP.VexRiscv.IBusSimplePlugin_jump_pcLoad_payload[31:0] +[color] 1 +TOP.VexRiscv.dataCache_1_.io_mem_cmd_payload_mask[3:0] @28 -TOP.VexRiscv.IBusSimplePlugin_jump_pcLoad_valid +[color] 1 +TOP.VexRiscv.dataCache_1_.io_mem_cmd_payload_wr +[color] 1 +TOP.VexRiscv.dataCache_1_.io_mem_rsp_valid @22 -TOP.VexRiscv.CsrPlugin_mepc[31:0] -TOP.VexRiscv.CsrPlugin_sepc[31:0] +[color] 1 +TOP.VexRiscv.dataCache_1_.io_mem_rsp_payload_data[31:0] @28 -TOP.VexRiscv.decode_IS_RVC -@24 -TOP.VexRiscv.CsrPlugin_mcycle[63:0] -@28 -TOP.VexRiscv.decode_IS_RVC -TOP.VexRiscv.decode_arbitration_isValid -@22 -TOP.VexRiscv.RegFilePlugin_regFile(10)[31:0] -@28 -TOP.dBus_cmd_valid -TOP.dBus_cmd_ready -@22 -TOP.dBus_cmd_payload_address[31:0] -@28 -TOP.dBus_cmd_payload_wr -@29 -TOP.dBus_cmd_payload_size[1:0] -@22 -TOP.dBus_cmd_payload_data[31:0] -TOP.dBus_rsp_data[31:0] -@28 -TOP.dBus_rsp_error -TOP.dBus_rsp_ready +[color] 1 +TOP.VexRiscv.dataCache_1_.io_mem_rsp_payload_error [pattern_trace] 1 [pattern_trace] 0 diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 11011576..82c54292 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -3446,6 +3446,7 @@ int main(int argc, char **argv, char **env) { // redo(REDO,WorkspaceRegression("deleg").withRiscvRef()->loadHex("../raw/deleg/build/deleg.hex")->bootAt(0x80000000u)->run(50e3);); // return 0; + for(int idx = 0;idx < 1;idx++){ #if defined(DEBUG_PLUGIN_EXTERNAL) || defined(RUN_HEX) diff --git a/src/test/scala/vexriscv/TestIndividualFeatures.scala b/src/test/scala/vexriscv/TestIndividualFeatures.scala index 8e85c601..9be96b4d 100644 --- a/src/test/scala/vexriscv/TestIndividualFeatures.scala +++ b/src/test/scala/vexriscv/TestIndividualFeatures.scala @@ -366,7 +366,6 @@ class DBusDimension extends VexRiscvDimension("DBus") { catchAccessError = catchAll, catchIllegal = catchAll, catchUnaligned = catchAll, - catchMemoryTranslationMiss = catchAll, atomicEntriesCount = 0 ), memoryTranslatorPortConfig = null From 8be40e637b60ab48cef5ec8c665ec62b6c1207f5 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Tue, 2 Apr 2019 23:44:53 +0200 Subject: [PATCH 101/951] #60 Got the new data cache design passing all tests and running linux --- src/main/scala/vexriscv/Services.scala | 1 + src/main/scala/vexriscv/demo/Linux.scala | 95 +++++++++---------- src/main/scala/vexriscv/ip/DataCache.scala | 37 +++++--- .../scala/vexriscv/plugin/CsrPlugin.scala | 8 +- .../vexriscv/plugin/DBusCachedPlugin.scala | 59 ++++++++++-- .../plugin/HaltOnExceptionPlugin.scala | 2 + src/test/cpp/regression/main.cpp | 11 +++ 7 files changed, 143 insertions(+), 70 deletions(-) diff --git a/src/main/scala/vexriscv/Services.scala b/src/main/scala/vexriscv/Services.scala index fb2a29a0..38a6b70f 100644 --- a/src/main/scala/vexriscv/Services.scala +++ b/src/main/scala/vexriscv/Services.scala @@ -33,6 +33,7 @@ case class ExceptionCause() extends Bundle{ trait ExceptionService{ def newExceptionPort(stage : Stage, priority : Int = 0) : Flow[ExceptionCause] + def isExceptionPending() : Bool } trait PrivilegeService{ diff --git a/src/main/scala/vexriscv/demo/Linux.scala b/src/main/scala/vexriscv/demo/Linux.scala index cc0c5f79..f7c9fe6c 100644 --- a/src/main/scala/vexriscv/demo/Linux.scala +++ b/src/main/scala/vexriscv/demo/Linux.scala @@ -96,45 +96,45 @@ object LinuxGen { new DummyFencePlugin(), //TODO should be removed for design with caches //Uncomment the whole IBusSimplePlugin and comment IBusCachedPlugin if you want uncached iBus config - new IBusSimplePlugin( - resetVector = 0x80000000l, - cmdForkOnSecondStage = false, - cmdForkPersistence = false, - prediction = NONE, - historyRamSizeLog2 = 10, - catchAccessFault = true, - compressedGen = true, - busLatencyMin = 1, - injectorStage = true, - memoryTranslatorPortConfig = withMmu generate MmuPortConfig( - portTlbSize = 4 - ) - ), - - //Uncomment the whole IBusCachedPlugin and comment IBusSimplePlugin if you want cached iBus config -// new IBusCachedPlugin( +// new IBusSimplePlugin( // resetVector = 0x80000000l, -// compressedGen = true, +// cmdForkOnSecondStage = false, +// cmdForkPersistence = false, // prediction = NONE, +// historyRamSizeLog2 = 10, +// catchAccessFault = true, +// compressedGen = true, +// busLatencyMin = 1, // injectorStage = true, -// config = InstructionCacheConfig( -// cacheSize = 4096, -// bytePerLine = 32, -// wayCount = 1, -// addressWidth = 32, -// cpuDataWidth = 32, -// memDataWidth = 32, -// catchIllegalAccess = true, -// catchAccessFault = true, -// asyncTagMemory = false, -// twoCycleRam = false, -// twoCycleCache = true -// ) -// ), -// memoryTranslatorPortConfig = MmuPortConfig( +// memoryTranslatorPortConfig = withMmu generate MmuPortConfig( // portTlbSize = 4 // ) // ), + + //Uncomment the whole IBusCachedPlugin and comment IBusSimplePlugin if you want cached iBus config + new IBusCachedPlugin( + resetVector = 0x80000000l, + compressedGen = true, + prediction = NONE, + injectorStage = true, + config = InstructionCacheConfig( + cacheSize = 4096, + bytePerLine = 32, + wayCount = 1, + addressWidth = 32, + cpuDataWidth = 32, + memDataWidth = 32, + catchIllegalAccess = true, + catchAccessFault = true, + asyncTagMemory = false, + twoCycleRam = false, + twoCycleCache = true +// ) + ), + memoryTranslatorPortConfig = MmuPortConfig( + portTlbSize = 4 + ) + ), // ).newTightlyCoupledPort(TightlyCoupledPortParameter("iBusTc", a => a(30 downto 28) === 0x0 && a(5))), // new DBusSimplePlugin( // catchAddressMisaligned = true, @@ -156,17 +156,16 @@ object LinuxGen { catchAccessError = true, catchIllegal = true, catchUnaligned = true, - atomicEntriesCount = 2 - ) -// ), - // memoryTranslatorPortConfig = null -// memoryTranslatorPortConfig = MmuPortConfig( -// portTlbSize = 4 + atomicEntriesCount = 1 // ) + ), + memoryTranslatorPortConfig = withMmu generate MmuPortConfig( + portTlbSize = 4 + ) ), - new StaticMemoryTranslatorPlugin( - ioRange = _(31 downto 28) === 0xF - ), +// new StaticMemoryTranslatorPlugin( +// ioRange = _(31 downto 28) === 0xF +// ), // new MemoryTranslatorPlugin( // tlbSize = 32, // virtualRange = _(31 downto 28) === 0xC, @@ -238,12 +237,12 @@ object LinuxGen { new YamlPlugin("cpu0.yaml") ) ) -// if(withMmu) config.plugins += new MmuPlugin( -// virtualRange = a => True, -// // virtualRange = x => x(31 downto 24) =/= 0x81, //TODO It fix the DTB kernel access (workaround) -// ioRange = (x => if(litex) x(31 downto 28) === 0xB || x(31 downto 28) === 0xE || x(31 downto 28) === 0xF else x(31 downto 28) === 0xF), -// allowUserIo = true -// ) + if(withMmu) config.plugins += new MmuPlugin( + virtualRange = a => True, + // virtualRange = x => x(31 downto 24) =/= 0x81, //TODO It fix the DTB kernel access (workaround) + ioRange = (x => if(litex) x(31 downto 28) === 0xB || x(31 downto 28) === 0xE || x(31 downto 28) === 0xF else x(31 downto 28) === 0xF), + allowUserIo = true + ) config } diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index 96dea4c7..941874f3 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -8,6 +8,8 @@ import spinal.lib.bus.avalon.{AvalonMM, AvalonMMConfig} import spinal.lib.bus.wishbone.{Wishbone, WishboneConfig} import spinal.lib.bus.simple._ +//TODO flush + case class DataCacheConfig(cacheSize : Int, bytePerLine : Int, wayCount : Int, @@ -71,13 +73,12 @@ object DataCacheCpuExecute{ case class DataCacheCpuExecute(p : DataCacheConfig) extends Bundle with IMasterSlave{ val isValid = Bool - val isStuck = Bool val address = UInt(p.addressWidth bit) // val haltIt = Bool val args = DataCacheCpuExecuteArgs(p) override def asMaster(): Unit = { - out(isValid, isStuck, args, address) + out(isValid, args, address) // in(haltIt) } } @@ -111,6 +112,7 @@ case class DataCacheCpuWriteBack(p : DataCacheConfig) extends Bundle with IMaste val isStuck = Bool val isUser = Bool val haltIt = Bool + val isWrite = Bool val data = Bits(p.cpuDataWidth bit) val address = UInt(p.addressWidth bit) val mmuException, unalignedAccess , accessError = Bool @@ -120,7 +122,7 @@ case class DataCacheCpuWriteBack(p : DataCacheConfig) extends Bundle with IMaste override def asMaster(): Unit = { out(isValid,isStuck,isUser, address) - in(haltIt, data, mmuException, unalignedAccess, accessError) + in(haltIt, data, mmuException, unalignedAccess, accessError, isWrite) outWithNull(clearAtomicEntries) } } @@ -354,8 +356,8 @@ class DataCache(p : DataCacheConfig) extends Component{ val data = Mem(Bits(wordWidth bit), wayWordCount) //Reads - val tagsReadRsp = tags.readSync(tagsReadCmd.payload, tagsReadCmd.valid && !io.cpu.execute.isStuck) - val dataReadRsp = data.readSync(dataReadCmd.payload, dataReadCmd.valid && !io.cpu.execute.isStuck) + val tagsReadRsp = tags.readSync(tagsReadCmd.payload, tagsReadCmd.valid && !io.cpu.memory.isStuck) + val dataReadRsp = data.readSync(dataReadCmd.payload, dataReadCmd.valid && !io.cpu.memory.isStuck) //Writes when(tagsWriteCmd.valid && tagsWriteCmd.way(i)){ @@ -380,7 +382,7 @@ class DataCache(p : DataCacheConfig) extends Component{ dataWriteCmd.valid := False dataWriteCmd.payload.assignDontCare() - when(io.cpu.execute.isValid && !io.cpu.execute.isStuck){ + when(io.cpu.execute.isValid && !io.cpu.memory.isStuck){ tagsReadCmd.valid := True dataReadCmd.valid := True tagsReadCmd.payload := io.cpu.execute.address(lineRange) @@ -460,7 +462,6 @@ class DataCache(p : DataCacheConfig) extends Component{ val atomic = genAtomic generate new Area{ case class AtomicEntry() extends Bundle{ val valid = Bool() - val size = UInt(2 bits) val address = UInt(addressWidth bits) def init: this.type ={ @@ -470,10 +471,9 @@ class DataCache(p : DataCacheConfig) extends Component{ } val entries = Vec(Reg(AtomicEntry()).init, atomicEntriesCount) val entriesAllocCounter = Counter(atomicEntriesCount) - val entriesHit = entries.map(e => e.valid && e.size === request.size && e.address === io.cpu.writeBack.address).orR + val entriesHit = entries.map(e => e.valid && e.address === io.cpu.writeBack.address).orR when(io.cpu.writeBack.isValid && request.isAtomic && !request.wr){ entries(entriesAllocCounter).valid := True - entries(entriesAllocCounter).size := request.size //TODO remove size stuff entries(entriesAllocCounter).address := io.cpu.writeBack.address when(!io.cpu.writeBack.isStuck){ entriesAllocCounter.increment() @@ -486,11 +486,11 @@ class DataCache(p : DataCacheConfig) extends Component{ val memCmdSent = RegInit(False) setWhen (io.mem.cmd.ready) clearWhen (!io.cpu.writeBack.isStuck) - io.cpu.redo := mmuRsp.refilling + io.cpu.redo := False io.cpu.writeBack.accessError := False io.cpu.writeBack.mmuException := io.cpu.writeBack.isValid && (if(catchIllegal) mmuRsp.exception || (!mmuRsp.allowWrite && request.wr) || (!mmuRsp.allowRead && !request.wr) || (!mmuRsp.allowUser && io.cpu.writeBack.isUser) else False) io.cpu.writeBack.unalignedAccess := io.cpu.writeBack.isValid && (if(catchUnaligned) ((request.size === 2 && mmuRsp.physicalAddress(1 downto 0) =/= 0) || (request.size === 1 && mmuRsp.physicalAddress(0 downto 0) =/= 0)) else False) - + io.cpu.writeBack.isWrite := request.wr when(io.cpu.writeBack.isValid) { when(request.forceUncachedAccess || mmuRsp.isIoAccess) { @@ -503,6 +503,11 @@ class DataCache(p : DataCacheConfig) extends Component{ io.mem.cmd.data := request.data io.mem.cmd.length := 0 io.mem.cmd.last := True + + if(genAtomic) when(request.isAtomic && !atomic.entriesHit){ + io.mem.cmd.valid := False + io.cpu.writeBack.haltIt := False + } } otherwise { when(waysHit || request.wr) { //Do not require a cache refill ? //Data cache update @@ -524,6 +529,12 @@ class DataCache(p : DataCacheConfig) extends Component{ //On write to read colisions io.cpu.redo := !request.wr && (colisions & waysHits) =/= 0 + + if(genAtomic) when(request.isAtomic && !atomic.entriesHit){ + io.mem.cmd.valid := False + dataWriteCmd.valid := False + io.cpu.writeBack.haltIt := False + } } otherwise { //Do refill //Emit cmd @@ -554,6 +565,7 @@ class DataCache(p : DataCacheConfig) extends Component{ loaderValid := False io.cpu.writeBack.haltIt := False } + io.cpu.redo setWhen(io.cpu.writeBack.isValid && mmuRsp.refilling) assert(!(io.cpu.writeBack.isValid && !io.cpu.writeBack.haltIt && io.cpu.writeBack.isStuck), "writeBack stuck by another plugin is not allowed") @@ -561,9 +573,6 @@ class DataCache(p : DataCacheConfig) extends Component{ when(request.isAtomic && request.wr){ io.cpu.writeBack.data := (!atomic.entriesHit).asBits.resized } - when(request.isAtomic && !atomic.entriesHit){ - io.mem.cmd.mask := 0 - } } } diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 452aa8d2..4df02b9f 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -285,6 +285,9 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception interface } + var exceptionPending : Bool = null + override def isExceptionPending(): Bool = exceptionPending + var jumpInterface : Flow[UInt] = null var timerInterrupt, externalInterrupt, softwareInterrupt : Bool = null var externalInterruptS : Bool = null @@ -378,7 +381,7 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception jumpInterface.valid := False jumpInterface.payload.assignDontCare() - + exceptionPending = False timerInterrupt = in Bool() setName("timerInterrupt") externalInterrupt = in Bool() setName("externalInterrupt") softwareInterrupt = in Bool() setName("softwareInterrupt") @@ -677,7 +680,7 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception else exceptionValidsRegs(stageId) := False } - if(stage != stages.last) when(stage.arbitration.isFlushed){ + when(stage.arbitration.isFlushed){ exceptionValids(stageId) := False } } @@ -688,6 +691,7 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception //Avoid the PC register of the last stage to change durring an exception handleing (Used to fill Xepc) stages.last.dontSample.getOrElseUpdate(PC, ArrayBuffer[Bool]()) += exceptionValids.last + exceptionPending setWhen(exceptionValidsRegs.orR) } else null diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index c62984aa..837cdc71 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -7,7 +7,7 @@ import spinal.lib._ import spinal.lib.bus.amba4.axi.Axi4 -class DAxiCachedPlugin(config : DataCacheConfig, memoryTranslatorPortConfig : Any = null) extends DBusCachedPlugin(config, memoryTranslatorPortConfig){ +class DAxiCachedPlugin(config : DataCacheConfig, memoryTranslatorPortConfig : Any = null) extends DBusCachedPlugin(config, memoryTranslatorPortConfig) { var dAxi : Axi4 = null override def build(pipeline: VexRiscv): Unit = { @@ -20,7 +20,7 @@ class DAxiCachedPlugin(config : DataCacheConfig, memoryTranslatorPortConfig : An class DBusCachedPlugin(config : DataCacheConfig, memoryTranslatorPortConfig : Any = null, - csrInfo : Boolean = false) extends Plugin[VexRiscv]{ + csrInfo : Boolean = false) extends Plugin[VexRiscv] with DBusAccessService { import config._ var dBus : DataCacheMemBus = null var mmuBus : MemoryTranslatorBus = null @@ -28,11 +28,19 @@ class DBusCachedPlugin(config : DataCacheConfig, var privilegeService : PrivilegeService = null var redoBranch : Flow[UInt] = null + @dontName var dBusAccess : DBusAccess = null + override def newDBusAccess(): DBusAccess = { + assert(dBusAccess == null) + dBusAccess = DBusAccess() + dBusAccess + } + object MEMORY_ENABLE extends Stageable(Bool) object MEMORY_MANAGMENT extends Stageable(Bool) object MEMORY_WR extends Stageable(Bool) object MEMORY_ADDRESS_LOW extends Stageable(UInt(2 bits)) object MEMORY_ATOMIC extends Stageable(Bool) + object IS_DBUS_SHARING extends Stageable(Bool()) override def setup(pipeline: VexRiscv): Unit = { import Riscv._ @@ -44,8 +52,9 @@ class DBusCachedPlugin(config : DataCacheConfig, SRC1_CTRL -> Src1CtrlEnum.RS, SRC_USE_SUB_LESS -> False, MEMORY_ENABLE -> True, - RS1_USE -> True - ) ++ (if (catchSomething) List(IntAluPlugin.ALU_CTRL -> IntAluPlugin.AluCtrlEnum.ADD_SUB) else Nil) //Used for access fault bad address in memory stage + RS1_USE -> True, + IntAluPlugin.ALU_CTRL -> IntAluPlugin.AluCtrlEnum.ADD_SUB + ) val loadActions = stdActions ++ List( SRC2_CTRL -> Src2CtrlEnum.IMI, @@ -143,7 +152,6 @@ class DBusCachedPlugin(config : DataCacheConfig, val size = input(INSTRUCTION)(13 downto 12).asUInt cache.io.cpu.execute.isValid := arbitration.isValid && input(MEMORY_ENABLE) - cache.io.cpu.execute.isStuck := arbitration.isStuck cache.io.cpu.execute.address := input(SRC_ADD).asUInt cache.io.cpu.execute.args.wr := input(MEMORY_WR) cache.io.cpu.execute.args.data := size.mux( @@ -194,7 +202,7 @@ class DBusCachedPlugin(config : DataCacheConfig, redoBranch.payload := input(PC) arbitration.flushAll setWhen(redoBranch.valid) - when(cache.io.cpu.writeBack.isValid) { + when(arbitration.isValid && input(MEMORY_ENABLE)) { if (catchAccessError) when(cache.io.cpu.writeBack.accessError) { exceptionBus.valid := True exceptionBus.code := (input(MEMORY_WR) ? U(7) | U(5)).resized @@ -235,6 +243,45 @@ class DBusCachedPlugin(config : DataCacheConfig, } } + //Share access to the dBus (used by self refilled MMU) + val dBusSharing = (dBusAccess != null) generate pipeline plug new Area{ + dBusAccess.cmd.ready := False + val forceDatapath = False + when(dBusAccess.cmd.valid){ + decode.arbitration.haltByOther := True + when(!stagesFromExecute.map(_.arbitration.isValid).orR && !pipeline.service(classOf[ExceptionService]).isExceptionPending()){ + when(!cache.io.cpu.redo) { + cache.io.cpu.execute.isValid := True + dBusAccess.cmd.ready := !execute.arbitration.isStuck + } + cache.io.cpu.execute.args.wr := dBusAccess.cmd.write + cache.io.cpu.execute.args.data := dBusAccess.cmd.data + cache.io.cpu.execute.args.size := dBusAccess.cmd.size + cache.io.cpu.execute.args.forceUncachedAccess := True //TODO Cached and redo management + if(genAtomic) cache.io.cpu.execute.args.isAtomic := False + cache.io.cpu.execute.address := dBusAccess.cmd.address //Will only be 12 muxes + forceDatapath := True + } + } + execute.insert(IS_DBUS_SHARING) := dBusAccess.cmd.fire + + + mmuBus.cmd.bypassTranslation setWhen(memory.input(IS_DBUS_SHARING)) + cache.io.cpu.memory.isValid setWhen(memory.input(IS_DBUS_SHARING)) + cache.io.cpu.writeBack.isValid setWhen(writeBack.input(IS_DBUS_SHARING)) + dBusAccess.rsp.valid := writeBack.input(IS_DBUS_SHARING) && !cache.io.cpu.writeBack.isWrite && !cache.io.cpu.writeBack.haltIt + dBusAccess.rsp.data := cache.io.cpu.writeBack.data + dBusAccess.rsp.error := cache.io.cpu.writeBack.unalignedAccess || cache.io.cpu.writeBack.accessError + + component.addPrePopTask{() => + when(forceDatapath){ + execute.output(REGFILE_WRITE_DATA) := dBusAccess.cmd.address.asBits + } + memory.input(IS_DBUS_SHARING) init(False) + writeBack.input(IS_DBUS_SHARING) init(False) + } + } + if(csrInfo){ val csr = service(classOf[CsrPlugin]) csr.r(0xCC0, 0 -> U(cacheSize/wayCount), 20 -> U(bytePerLine)) diff --git a/src/main/scala/vexriscv/plugin/HaltOnExceptionPlugin.scala b/src/main/scala/vexriscv/plugin/HaltOnExceptionPlugin.scala index e6761de8..fb51f104 100644 --- a/src/main/scala/vexriscv/plugin/HaltOnExceptionPlugin.scala +++ b/src/main/scala/vexriscv/plugin/HaltOnExceptionPlugin.scala @@ -21,6 +21,8 @@ class HaltOnExceptionPlugin() extends Plugin[VexRiscv] with ExceptionService { exceptionPortsInfos += ExceptionPortInfo(interface,stage,priority) interface } + override def isExceptionPending(): Bool = False + override def build(pipeline: VexRiscv): Unit = { import pipeline._ diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 82c54292..907b2c4a 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -1316,6 +1316,16 @@ public: if(isDBusCheckedRegion(addr)){ CpuRef::MemWrite w; w.address = addr; + while((mask & 1) == 0){ + mask >>= 1; + w.address++; + w.data >>= 8; + } + switch(mask){ + case 1: size = 0; break; + case 3: size = min(1u, size); break; + case 15: size = min(2u, size); break; + } w.size = 1 << size; switch(size){ case 0: w.data = *data & 0xFF; break; @@ -3446,6 +3456,7 @@ int main(int argc, char **argv, char **env) { // redo(REDO,WorkspaceRegression("deleg").withRiscvRef()->loadHex("../raw/deleg/build/deleg.hex")->bootAt(0x80000000u)->run(50e3);); // return 0; + redo(REDO,WorkspaceRegression("mmu").withRiscvRef()->loadHex("../raw/mmu/build/mmu.hex")->bootAt(0x80000000u)->run(50e3);); for(int idx = 0;idx < 1;idx++){ From 066f562c5efb7db0deca0b0208f99ceb4c6a45f2 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Wed, 3 Apr 2019 14:32:21 +0200 Subject: [PATCH 102/951] Got the MMU refilling itself with datacache cached memory access instead of io accesses --- .../scala/vexriscv/plugin/DBusCachedPlugin.scala | 9 ++++++--- .../scala/vexriscv/plugin/DBusSimplePlugin.scala | 1 + src/main/scala/vexriscv/plugin/MmuPlugin.scala | 14 ++++++++++---- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index 837cdc71..3793ae44 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -257,7 +257,7 @@ class DBusCachedPlugin(config : DataCacheConfig, cache.io.cpu.execute.args.wr := dBusAccess.cmd.write cache.io.cpu.execute.args.data := dBusAccess.cmd.data cache.io.cpu.execute.args.size := dBusAccess.cmd.size - cache.io.cpu.execute.args.forceUncachedAccess := True //TODO Cached and redo management + cache.io.cpu.execute.args.forceUncachedAccess := False if(genAtomic) cache.io.cpu.execute.args.isAtomic := False cache.io.cpu.execute.address := dBusAccess.cmd.address //Will only be 12 muxes forceDatapath := True @@ -269,16 +269,19 @@ class DBusCachedPlugin(config : DataCacheConfig, mmuBus.cmd.bypassTranslation setWhen(memory.input(IS_DBUS_SHARING)) cache.io.cpu.memory.isValid setWhen(memory.input(IS_DBUS_SHARING)) cache.io.cpu.writeBack.isValid setWhen(writeBack.input(IS_DBUS_SHARING)) - dBusAccess.rsp.valid := writeBack.input(IS_DBUS_SHARING) && !cache.io.cpu.writeBack.isWrite && !cache.io.cpu.writeBack.haltIt + dBusAccess.rsp.valid := writeBack.input(IS_DBUS_SHARING) && !cache.io.cpu.writeBack.isWrite && (cache.io.cpu.redo || !cache.io.cpu.writeBack.haltIt) dBusAccess.rsp.data := cache.io.cpu.writeBack.data dBusAccess.rsp.error := cache.io.cpu.writeBack.unalignedAccess || cache.io.cpu.writeBack.accessError - + dBusAccess.rsp.redo := cache.io.cpu.redo component.addPrePopTask{() => when(forceDatapath){ execute.output(REGFILE_WRITE_DATA) := dBusAccess.cmd.address.asBits } memory.input(IS_DBUS_SHARING) init(False) writeBack.input(IS_DBUS_SHARING) init(False) + when(dBusAccess.rsp.valid){ + writeBack.input(IS_DBUS_SHARING).getDrivingReg := False + } } } diff --git a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala index e775767c..79818506 100644 --- a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala @@ -497,6 +497,7 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, dBusAccess.rsp.valid := False dBusAccess.rsp.data := dBus.rsp.data dBusAccess.rsp.error := dBus.rsp.error + dBusAccess.rsp.redo := False switch(state){ is(0){ diff --git a/src/main/scala/vexriscv/plugin/MmuPlugin.scala b/src/main/scala/vexriscv/plugin/MmuPlugin.scala index f4aad4f7..dfcced59 100644 --- a/src/main/scala/vexriscv/plugin/MmuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/MmuPlugin.scala @@ -21,6 +21,7 @@ case class DBusAccessCmd() extends Bundle { case class DBusAccessRsp() extends Bundle { val data = Bits(32 bits) val error = Bool() + val redo = Bool() } case class DBusAccess() extends Bundle { @@ -161,7 +162,7 @@ class MmuPlugin(virtualRange : UInt => Bool, val leaf = pte.R || pte.X } - val pteBuffer = RegNextWhen(dBusRsp.pte, dBusAccess.rsp.valid) + val pteBuffer = RegNextWhen(dBusRsp.pte, dBusAccess.rsp.valid && !dBusAccess.rsp.redo) dBusAccess.cmd.valid := False dBusAccess.cmd.write := False @@ -190,10 +191,12 @@ class MmuPlugin(virtualRange : UInt => Bool, } is(State.L1_RSP){ when(dBusAccess.rsp.valid){ + state := State.L0_CMD when(dBusRsp.leaf || dBusRsp.exception){ state := State.IDLE - } otherwise { - state := State.L0_CMD + } + when(dBusAccess.rsp.redo){ + state := State.L1_CMD } } } @@ -207,11 +210,14 @@ class MmuPlugin(virtualRange : UInt => Bool, is(State.L0_RSP){ when(dBusAccess.rsp.valid) { state := State.IDLE + when(dBusAccess.rsp.redo){ + state := State.L0_CMD + } } } } - when(dBusAccess.rsp.valid && (dBusRsp.leaf || dBusRsp.exception)){ + when(dBusAccess.rsp.valid && !dBusAccess.rsp.redo && (dBusRsp.leaf || dBusRsp.exception)){ for(port <- ports){ when(portId === port.id) { port.entryToReplace.increment() From 922c18ee495a76f0a41e63691ccdf2324c3eab56 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Wed, 3 Apr 2019 15:56:58 +0200 Subject: [PATCH 103/951] Add data cache flush feature --- src/main/scala/vexriscv/ip/DataCache.scala | 12 ++++++++++-- .../scala/vexriscv/plugin/DBusCachedPlugin.scala | 16 +++++++++------- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index 941874f3..a43e55fa 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -133,11 +133,13 @@ case class DataCacheCpuBus(p : DataCacheConfig) extends Bundle with IMasterSlave val writeBack = DataCacheCpuWriteBack(p) val redo = Bool() + val flush = Event override def asMaster(): Unit = { master(execute) master(memory) master(writeBack) + master(flush) in(redo) } } @@ -298,7 +300,6 @@ case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave class DataCache(p : DataCacheConfig) extends Component{ import p._ - assert(wayCount == 1) assert(cpuDataWidth == memDataWidth) val io = new Bundle{ @@ -449,13 +450,20 @@ class DataCache(p : DataCacheConfig) extends Component{ tagsWriteCmd.address := mmuRsp.physicalAddress(lineRange) tagsWriteCmd.way.setAll() tagsWriteCmd.data.valid := False - when(mmuRsp.physicalAddress(lineRange) =/= lineCount - 1) { + when(mmuRsp.physicalAddress(lineRange) =/= wayLineCount - 1) { mmuRsp.physicalAddress.getDrivingReg(lineRange) := mmuRsp.physicalAddress(lineRange) + 1 io.cpu.writeBack.haltIt := True } otherwise { valid := False } } + + io.cpu.flush.ready := False + when(io.cpu.flush.valid && !io.cpu.execute.isValid && !io.cpu.memory.isValid && !io.cpu.writeBack.isValid && !io.cpu.redo){ + io.cpu.flush.ready := True + mmuRsp.physicalAddress.getDrivingReg(lineRange) := 0 + valid := True + } } diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index 3793ae44..e7bde27a 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -61,15 +61,13 @@ class DBusCachedPlugin(config : DataCacheConfig, REGFILE_WRITE_VALID -> True, BYPASSABLE_EXECUTE_STAGE -> False, BYPASSABLE_MEMORY_STAGE -> False, - MEMORY_WR -> False, - MEMORY_MANAGMENT -> False + MEMORY_WR -> False ) ++ (if(catchSomething) List(HAS_SIDE_EFFECT -> True) else Nil) val storeActions = stdActions ++ List( SRC2_CTRL -> Src2CtrlEnum.IMS, RS2_USE -> True, - MEMORY_WR -> True, - MEMORY_MANAGMENT -> False + MEMORY_WR -> True ) decoderService.addDefault(MEMORY_ENABLE, False) @@ -102,9 +100,9 @@ class DBusCachedPlugin(config : DataCacheConfig, } def MANAGEMENT = M"-------00000-----101-----0001111" - decoderService.add(MANAGEMENT, stdActions ++ List( - SRC2_CTRL -> Src2CtrlEnum.RS, - RS2_USE -> True, + + decoderService.addDefault(MEMORY_MANAGMENT, False) + decoderService.add(MANAGEMENT, List( MEMORY_MANAGMENT -> True )) @@ -161,6 +159,10 @@ class DBusCachedPlugin(config : DataCacheConfig, ) cache.io.cpu.execute.args.size := size cache.io.cpu.execute.args.forceUncachedAccess := False + + cache.io.cpu.flush.valid := arbitration.isValid && input(MEMORY_MANAGMENT) + arbitration.haltItself setWhen(cache.io.cpu.flush.isStall) + if(genAtomic) { cache.io.cpu.execute.args.isAtomic := False when(input(MEMORY_ATOMIC)){ From 3f7a859e07ddcbcdb562eefd9929c0d58635cb2e Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Wed, 3 Apr 2019 14:33:35 +0200 Subject: [PATCH 104/951] Got multiway I$ D$ running linux fine. --- src/main/scala/vexriscv/demo/Linux.scala | 12 ++++++------ .../scala/vexriscv/plugin/DBusCachedPlugin.scala | 4 ++++ .../scala/vexriscv/plugin/IBusCachedPlugin.scala | 4 ++++ 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/main/scala/vexriscv/demo/Linux.scala b/src/main/scala/vexriscv/demo/Linux.scala index f7c9fe6c..ff3fa0e2 100644 --- a/src/main/scala/vexriscv/demo/Linux.scala +++ b/src/main/scala/vexriscv/demo/Linux.scala @@ -40,13 +40,13 @@ cd VexRiscv Run regressions => sbt "runMain vexriscv.demo.LinuxGen -r" cd src/test/cpp/regression -make run IBUS=CACHED DBUS=SIMPLE DEBUG_PLUGIN=no DHRYSTONE=yes SUPERVISOR=yes CSR=yes COMPRESSED=yes REDO=10 TRACE=no +make run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=no DHRYSTONE=yes SUPERVISOR=yes CSR=yes COMPRESSED=yes REDO=10 TRACE=no Run linux in simulation (Require the machime mode emulator compiled in SIM mode) => sbt "runMain vexriscv.demo.LinuxGen" cd src/test/cpp/regression export BUILDROOT=/home/miaou/pro/riscv/buildrootSpinal -make run IBUS=CACHED DBUS=SIMPLE DEBUG_PLUGIN=no SUPERVISOR=yes CSR=yes COMPRESSED=yes REDO=0 DHRYSTONE=no LINUX_SOC=yes EMULATOR=../../../main/c/emulator/build/emulator.bin VMLINUX=$BUILDROOT/output/images/vmlinux.bin DTB=$BUILDROOT/board/spinal/vexriscv_sim/rv32.dtb RAMDISK=$BUILDROOT/output/images/rootfs.cpio TRACE=no FLOW_INFO=no +make run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=no SUPERVISOR=yes CSR=yes COMPRESSED=yes REDO=0 DHRYSTONE=no LINUX_SOC=yes EMULATOR=../../../main/c/emulator/build/emulator.bin VMLINUX=$BUILDROOT/output/images/vmlinux.bin DTB=$BUILDROOT/board/spinal/vexriscv_sim/rv32.dtb RAMDISK=$BUILDROOT/output/images/rootfs.cpio TRACE=no FLOW_INFO=no Run linux with QEMU (Require the machime mode emulator compiled in QEMU mode) export BUILDROOT=/home/miaou/pro/riscv/buildrootSpinal @@ -118,9 +118,9 @@ object LinuxGen { prediction = NONE, injectorStage = true, config = InstructionCacheConfig( - cacheSize = 4096, + cacheSize = 4096*2, bytePerLine = 32, - wayCount = 1, + wayCount = 2, addressWidth = 32, cpuDataWidth = 32, memDataWidth = 32, @@ -147,9 +147,9 @@ object LinuxGen { // ), new DBusCachedPlugin( config = new DataCacheConfig( - cacheSize = 4096, + cacheSize = 4096*2, bytePerLine = 32, - wayCount = 1, + wayCount = 2, addressWidth = 32, cpuDataWidth = 32, memDataWidth = 32, diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index e7bde27a..55bd7dfe 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -22,6 +22,10 @@ class DBusCachedPlugin(config : DataCacheConfig, memoryTranslatorPortConfig : Any = null, csrInfo : Boolean = false) extends Plugin[VexRiscv] with DBusAccessService { import config._ + + assert(isPow2(cacheSize)) + assert(!(memoryTranslatorPortConfig != null && config.cacheSize/config.wayCount > 4096), "When the D$ is used with MMU, each way can't be bigger than a page (4096 bytes)") + var dBus : DataCacheMemBus = null var mmuBus : MemoryTranslatorBus = null var exceptionBus : Flow[ExceptionCause] = null diff --git a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala index ca74a0d8..2b8c89c5 100644 --- a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala @@ -47,6 +47,10 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l, injectorStage = (!config.twoCycleCache && !withoutInjectorStage) || injectorStage){ import config._ + assert(isPow2(cacheSize)) + assert(!(memoryTranslatorPortConfig != null && config.cacheSize/config.wayCount > 4096), "When the I$ is used with MMU, each way can't be bigger than a page (4096 bytes)") + + assert(!(withoutInjectorStage && injectorStage)) var iBus : InstructionCacheMemBus = null From de1c9c6fea049fabb38cadd03596799f5bcf0d90 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Wed, 3 Apr 2019 14:47:00 +0200 Subject: [PATCH 105/951] Removing D$ reports --- .../vexriscv/plugin/DBusCachedPlugin.scala | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index 55bd7dfe..defe9f39 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -119,25 +119,25 @@ class DBusCachedPlugin(config : DataCacheConfig, if(pipeline.serviceExist(classOf[PrivilegeService])) privilegeService = pipeline.service(classOf[PrivilegeService]) - if(pipeline.serviceExist(classOf[ReportService])){ - val report = pipeline.service(classOf[ReportService]) - report.add("dBus" -> { - val e = new BusReport() - val c = new CacheReport() - e.kind = "cached" - e.flushInstructions.add(0x13 | (1 << 7)) ////ADDI x1, x0, 0 - for(idx <- 0 until cacheSize by bytePerLine){ - e.flushInstructions.add(0x7000500F + (1 << 15)) //Clean invalid data cache way x1 - e.flushInstructions.add(0x13 + (1 << 7) + (1 << 15) + (bytePerLine << 20)) //ADDI x1, x1, 32 - } - - e.info = c - c.size = cacheSize - c.bytePerLine = bytePerLine - - e - }) - } +// if(pipeline.serviceExist(classOf[ReportService])){ +// val report = pipeline.service(classOf[ReportService]) +// report.add("dBus" -> { +// val e = new BusReport() +// val c = new CacheReport() +// e.kind = "cached" +// e.flushInstructions.add(0x13 | (1 << 7)) ////ADDI x1, x0, 0 +// for(idx <- 0 until cacheSize by bytePerLine){ +// e.flushInstructions.add(0x7000500F + (1 << 15)) //Clean invalid data cache way x1 +// e.flushInstructions.add(0x13 + (1 << 7) + (1 << 15) + (bytePerLine << 20)) //ADDI x1, x1, 32 +// } +// +// e.info = c +// c.size = cacheSize +// c.bytePerLine = bytePerLine +// +// e +// }) +// } } override def build(pipeline: VexRiscv): Unit = { From f8b438d9dce1926adc155821759d3ed3a7c5bf1e Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Thu, 4 Apr 2019 12:59:08 +0200 Subject: [PATCH 106/951] cleaning --- src/main/scala/vexriscv/demo/Linux.scala | 2 +- src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/demo/Linux.scala b/src/main/scala/vexriscv/demo/Linux.scala index ff3fa0e2..c9fa9e3e 100644 --- a/src/main/scala/vexriscv/demo/Linux.scala +++ b/src/main/scala/vexriscv/demo/Linux.scala @@ -131,7 +131,7 @@ object LinuxGen { twoCycleCache = true // ) ), - memoryTranslatorPortConfig = MmuPortConfig( + memoryTranslatorPortConfig = withMmu generate MmuPortConfig( portTlbSize = 4 ) ), diff --git a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala index 79818506..a59e79dd 100644 --- a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala @@ -280,7 +280,7 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, MEMORY_ATOMIC -> True ) ) - //TODO probably the cached implemention of SC is bugy (address calculation) + decoderService.add( key = SC, values = storeActions.filter(_._1 != SRC2_CTRL) ++ Seq( From 4f0a02594cc40ea923aa1134c40a22af55b90513 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Thu, 4 Apr 2019 20:34:35 +0200 Subject: [PATCH 107/951] Change LR/SC to reserve the whole memory Fix MPP access from other plugins Got all the common configuration to compile and pass regression excepted the debugger one First synthesis results --- src/main/scala/vexriscv/TestsWorkspace.scala | 2 +- src/main/scala/vexriscv/demo/GenFull.scala | 10 ++-- src/main/scala/vexriscv/demo/Linux.scala | 48 ++++++++++--------- .../scala/vexriscv/demo/SynthesisBench.scala | 19 ++------ src/main/scala/vexriscv/ip/DataCache.scala | 31 +++++------- .../scala/vexriscv/plugin/CsrPlugin.scala | 4 +- .../vexriscv/plugin/DBusCachedPlugin.scala | 22 ++++++--- .../vexriscv/plugin/DBusSimplePlugin.scala | 34 ++++--------- .../vexriscv/plugin/IBusCachedPlugin.scala | 2 +- src/test/cpp/regression/main.cpp | 4 +- .../vexriscv/TestIndividualFeatures.scala | 2 +- 11 files changed, 80 insertions(+), 98 deletions(-) diff --git a/src/main/scala/vexriscv/TestsWorkspace.scala b/src/main/scala/vexriscv/TestsWorkspace.scala index 387691aa..8db43167 100644 --- a/src/main/scala/vexriscv/TestsWorkspace.scala +++ b/src/main/scala/vexriscv/TestsWorkspace.scala @@ -81,7 +81,7 @@ object TestsWorkspace { catchAccessError = true, catchIllegal = true, catchUnaligned = true, - atomicEntriesCount = 2 + withLrSc = true ), // memoryTranslatorPortConfig = null memoryTranslatorPortConfig = MemoryTranslatorPortConfig( diff --git a/src/main/scala/vexriscv/demo/GenFull.scala b/src/main/scala/vexriscv/demo/GenFull.scala index ae753975..97ae71a3 100644 --- a/src/main/scala/vexriscv/demo/GenFull.scala +++ b/src/main/scala/vexriscv/demo/GenFull.scala @@ -27,7 +27,7 @@ object GenFull extends App{ twoCycleRam = true, twoCycleCache = true ), - memoryTranslatorPortConfig = MemoryTranslatorPortConfig( + memoryTranslatorPortConfig = MmuPortConfig( portTlbSize = 4 ) ), @@ -43,14 +43,14 @@ object GenFull extends App{ catchIllegal = true, catchUnaligned = true ), - memoryTranslatorPortConfig = MemoryTranslatorPortConfig( + memoryTranslatorPortConfig = MmuPortConfig( portTlbSize = 6 ) ), - new MemoryTranslatorPlugin( - tlbSize = 32, + new MmuPlugin( virtualRange = _(31 downto 28) === 0xC, - ioRange = _(31 downto 28) === 0xF + ioRange = _(31 downto 28) === 0xF, + allowUserIo = false ), new DecoderSimplePlugin( catchIllegalInstruction = true diff --git a/src/main/scala/vexriscv/demo/Linux.scala b/src/main/scala/vexriscv/demo/Linux.scala index c9fa9e3e..92130311 100644 --- a/src/main/scala/vexriscv/demo/Linux.scala +++ b/src/main/scala/vexriscv/demo/Linux.scala @@ -118,9 +118,9 @@ object LinuxGen { prediction = NONE, injectorStage = true, config = InstructionCacheConfig( - cacheSize = 4096*2, + cacheSize = 4096*1, bytePerLine = 32, - wayCount = 2, + wayCount = 1, addressWidth = 32, cpuDataWidth = 32, memDataWidth = 32, @@ -140,32 +140,33 @@ object LinuxGen { // catchAddressMisaligned = true, // catchAccessFault = true, // earlyInjection = false, -// atomicEntriesCount = 1, +// withLrSc = true, // memoryTranslatorPortConfig = withMmu generate MmuPortConfig( // portTlbSize = 4 // ) // ), new DBusCachedPlugin( + dBusCmdMasterPipe = true, + dBusCmdSlavePipe = true, + dBusRspSlavePipe = true, config = new DataCacheConfig( - cacheSize = 4096*2, + cacheSize = 4096*1, bytePerLine = 32, - wayCount = 2, + wayCount = 1, addressWidth = 32, cpuDataWidth = 32, memDataWidth = 32, catchAccessError = true, catchIllegal = true, catchUnaligned = true, - atomicEntriesCount = 1 + withLrSc = true // ) ), memoryTranslatorPortConfig = withMmu generate MmuPortConfig( portTlbSize = 4 ) ), -// new StaticMemoryTranslatorPlugin( -// ioRange = _(31 downto 28) === 0xF -// ), + // new MemoryTranslatorPlugin( // tlbSize = 32, // virtualRange = _(31 downto 28) === 0xC, @@ -177,13 +178,13 @@ object LinuxGen { ), new RegFilePlugin( regFileReadyKind = plugin.SYNC, - zeroBoot = true + zeroBoot = false //TODO ), new IntAluPlugin, new SrcPlugin( separatedAddSub = false ), - new FullBarrelShifterPlugin(earlyInjection = true), + new FullBarrelShifterPlugin(earlyInjection = false), // new LightShifterPlugin, new HazardSimplePlugin( bypassExecute = true, @@ -230,7 +231,7 @@ object LinuxGen { // )), // new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))), new BranchPlugin( - earlyBranch = true, + earlyBranch = false, catchAddressMisaligned = true, fenceiGenAsAJump = true ), @@ -239,10 +240,14 @@ object LinuxGen { ) if(withMmu) config.plugins += new MmuPlugin( virtualRange = a => True, - // virtualRange = x => x(31 downto 24) =/= 0x81, //TODO It fix the DTB kernel access (workaround) + // virtualRange = x => x(31 downto 24) =/= 0x81, ioRange = (x => if(litex) x(31 downto 28) === 0xB || x(31 downto 28) === 0xE || x(31 downto 28) === 0xF else x(31 downto 28) === 0xF), - allowUserIo = true - ) + allowUserIo = true //TODO ?? + ) else { + config.plugins += new StaticMemoryTranslatorPlugin( + ioRange = _(31 downto 28) === 0xF + ) + } config } @@ -375,14 +380,13 @@ object LinuxSyntesisBench extends App{ // val rtls = List(fullNoMmu) val targets = XilinxStdTargets( - vivadoArtix7Path = "/eda/Xilinx/Vivado/2017.2/bin" - )/* ++ AlteraStdTargets( - quartusCycloneIVPath = "/eda/intelFPGA_lite/17.0/quartus/bin", - quartusCycloneVPath = "/eda/intelFPGA_lite/17.0/quartus/bin" - ) ++ IcestormStdTargets().take(1)*/ + vivadoArtix7Path = "/media/miaou/HD/linux/Xilinx/Vivado/2018.3/bin" + ) ++ AlteraStdTargets( + quartusCycloneIVPath = "/media/miaou/HD/linux/intelFPGA_lite/18.1/quartus/bin", + quartusCycloneVPath = "/media/miaou/HD/linux/intelFPGA_lite/18.1/quartus/bin" + ) ++ IcestormStdTargets().take(1) - - Bench(rtls, targets, "/eda/tmp") + Bench(rtls, targets, "/media/miaou/HD/linux/tmp") } object LinuxSim extends App{ diff --git a/src/main/scala/vexriscv/demo/SynthesisBench.scala b/src/main/scala/vexriscv/demo/SynthesisBench.scala index 13ebde3c..29ee27e5 100644 --- a/src/main/scala/vexriscv/demo/SynthesisBench.scala +++ b/src/main/scala/vexriscv/demo/SynthesisBench.scala @@ -107,25 +107,14 @@ object VexRiscvSynthesisBench { // val rtls = List(fullNoMmu) val targets = XilinxStdTargets( - vivadoArtix7Path = "/eda/Xilinx/Vivado/2017.2/bin" + vivadoArtix7Path = "/media/miaou/HD/linux/Xilinx/Vivado/2018.3/bin" ) ++ AlteraStdTargets( - quartusCycloneIVPath = "/eda/intelFPGA_lite/17.0/quartus/bin", - quartusCycloneVPath = "/eda/intelFPGA_lite/17.0/quartus/bin" + quartusCycloneIVPath = "/media/miaou/HD/linux/intelFPGA_lite/18.1/quartus/bin", + quartusCycloneVPath = "/media/miaou/HD/linux/intelFPGA_lite/18.1/quartus/bin" ) ++ IcestormStdTargets().take(1) - -// val targets = XilinxStdTargets( -// vivadoArtix7Path = "/eda/Xilinx/Vivado/2017.2/bin" -// ) - -// val targets = AlteraStdTargets( -// quartusCycloneIVPath = "/eda/intelFPGA_lite/17.0/quartus/bin", -// quartusCycloneVPath = null -// ) - - // val targets = IcestormStdTargets() - Bench(rtls, targets, "/eda/tmp") + Bench(rtls, targets, "/media/miaou/HD/linux/tmp") } } diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index a43e55fa..66f6999d 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -22,13 +22,12 @@ case class DataCacheConfig(cacheSize : Int, earlyWaysHits : Boolean = true, earlyDataMux : Boolean = false, tagSizeShift : Int = 0, //Used to force infering ram - atomicEntriesCount : Int = 0){ + withLrSc : Boolean = false){ assert(!(earlyDataMux && !earlyWaysHits)) def burstSize = bytePerLine*8/memDataWidth val burstLength = bytePerLine/(memDataWidth/8) def catchSomething = catchUnaligned || catchIllegal || catchAccessError - def genAtomic = atomicEntriesCount != 0 def getAxi4SharedConfig() = Axi4Config( addressWidth = addressWidth, @@ -89,7 +88,7 @@ case class DataCacheCpuExecuteArgs(p : DataCacheConfig) extends Bundle{ val data = Bits(p.cpuDataWidth bit) val size = UInt(2 bits) val forceUncachedAccess = Bool - val isAtomic = ifGen(p.genAtomic){Bool} + val isAtomic = ifGen(p.withLrSc){Bool} // val all = Bool //Address should be zero when "all" is used } @@ -116,7 +115,7 @@ case class DataCacheCpuWriteBack(p : DataCacheConfig) extends Bundle with IMaste val data = Bits(p.cpuDataWidth bit) val address = UInt(p.addressWidth bit) val mmuException, unalignedAccess , accessError = Bool - val clearAtomicEntries = ifGen(p.genAtomic) {Bool} + val clearAtomicEntries = ifGen(p.withLrSc) {Bool} // val exceptionBus = if(p.catchSomething) Flow(ExceptionCause()) else null @@ -467,7 +466,7 @@ class DataCache(p : DataCacheConfig) extends Component{ } - val atomic = genAtomic generate new Area{ + val atomic = withLrSc generate new Area{ case class AtomicEntry() extends Bundle{ val valid = Bool() val address = UInt(addressWidth bits) @@ -477,18 +476,12 @@ class DataCache(p : DataCacheConfig) extends Component{ this } } - val entries = Vec(Reg(AtomicEntry()).init, atomicEntriesCount) - val entriesAllocCounter = Counter(atomicEntriesCount) - val entriesHit = entries.map(e => e.valid && e.address === io.cpu.writeBack.address).orR - when(io.cpu.writeBack.isValid && request.isAtomic && !request.wr){ - entries(entriesAllocCounter).valid := True - entries(entriesAllocCounter).address := io.cpu.writeBack.address - when(!io.cpu.writeBack.isStuck){ - entriesAllocCounter.increment() - } + val reserved = RegInit(False) + when(io.cpu.writeBack.isValid && !io.cpu.writeBack.isStuck && !io.cpu.redo && request.isAtomic && !request.wr){ + reserved := True } when(io.cpu.writeBack.clearAtomicEntries){ - entries.foreach(_.valid := False) + reserved := False } } @@ -512,7 +505,7 @@ class DataCache(p : DataCacheConfig) extends Component{ io.mem.cmd.length := 0 io.mem.cmd.last := True - if(genAtomic) when(request.isAtomic && !atomic.entriesHit){ + if(withLrSc) when(request.isAtomic && !atomic.reserved){ io.mem.cmd.valid := False io.cpu.writeBack.haltIt := False } @@ -538,7 +531,7 @@ class DataCache(p : DataCacheConfig) extends Component{ //On write to read colisions io.cpu.redo := !request.wr && (colisions & waysHits) =/= 0 - if(genAtomic) when(request.isAtomic && !atomic.entriesHit){ + if(withLrSc) when(request.isAtomic && !atomic.reserved){ io.mem.cmd.valid := False dataWriteCmd.valid := False io.cpu.writeBack.haltIt := False @@ -577,9 +570,9 @@ 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") - if(genAtomic){ + if(withLrSc){ when(request.isAtomic && request.wr){ - io.cpu.writeBack.data := (!atomic.entriesHit).asBits.resized + io.cpu.writeBack.data := (!atomic.reserved).asBits.resized } } } diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 4df02b9f..59410f7f 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -403,6 +403,8 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception source <- privilege.sources){ source.cond = source.cond.pull() } + + pipeline.update(MPP, UInt(2 bits)) } def inhibateInterrupts() : Unit = allowInterrupts := False @@ -503,7 +505,7 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception ucycleAccess(CSR.UCYCLE, mcycle(31 downto 0)) ucycleAccess(CSR.UCYCLEH, mcycle(63 downto 32)) - pipeline.update(MPP, mstatus.MPP) + pipeline(MPP) := mstatus.MPP } val supervisorCsr = ifGen(supervisorGen) { diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index defe9f39..fcf807bd 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -20,6 +20,9 @@ class DAxiCachedPlugin(config : DataCacheConfig, memoryTranslatorPortConfig : An class DBusCachedPlugin(config : DataCacheConfig, memoryTranslatorPortConfig : Any = null, + dBusCmdMasterPipe : Boolean = false, + dBusCmdSlavePipe : Boolean = false, + dBusRspSlavePipe : Boolean = false, csrInfo : Boolean = false) extends Plugin[VexRiscv] with DBusAccessService { import config._ @@ -80,7 +83,7 @@ class DBusCachedPlugin(config : DataCacheConfig, List(SB, SH, SW).map(_ -> storeActions) ) - if(genAtomic){ + if(withLrSc){ List(LB, LH, LW, LBU, LHU, LWU, SB, SH, SW).foreach(e => decoderService.add(e, Seq(MEMORY_ATOMIC -> False)) ) @@ -147,7 +150,14 @@ class DBusCachedPlugin(config : DataCacheConfig, dBus = master(DataCacheMemBus(this.config)).setName("dBus") val cache = new DataCache(this.config) - cache.io.mem <> dBus + + //Interconnect the plugin dBus with the cache dBus with some optional pipelining + def optionPipe[T](cond : Boolean, on : T)(f : T => T) : T = if(cond) f(on) else on + def cmdBuf = optionPipe(dBusCmdSlavePipe, cache.io.mem.cmd)(_.s2mPipe()) + dBus.cmd << optionPipe(dBusCmdMasterPipe, cmdBuf)(_.m2sPipe()) + cache.io.mem.rsp << optionPipe(dBusRspSlavePipe,dBus.rsp)(_.m2sPipe()) + + execute plug new Area { import execute._ @@ -167,7 +177,7 @@ class DBusCachedPlugin(config : DataCacheConfig, cache.io.cpu.flush.valid := arbitration.isValid && input(MEMORY_MANAGMENT) arbitration.haltItself setWhen(cache.io.cpu.flush.isStall) - if(genAtomic) { + if(withLrSc) { cache.io.cpu.execute.args.isAtomic := False when(input(MEMORY_ATOMIC)){ cache.io.cpu.execute.args.isAtomic := True @@ -197,7 +207,7 @@ class DBusCachedPlugin(config : DataCacheConfig, cache.io.cpu.writeBack.isStuck := arbitration.isStuck cache.io.cpu.writeBack.isUser := (if(privilegeService != null) privilegeService.isUser() else False) cache.io.cpu.writeBack.address := U(input(REGFILE_WRITE_DATA)) - if(genAtomic) cache.io.cpu.writeBack.clearAtomicEntries := service(classOf[IContextSwitching]).isContextSwitching + if(withLrSc) cache.io.cpu.writeBack.clearAtomicEntries := service(classOf[IContextSwitching]).isContextSwitching if(catchSomething) { exceptionBus.valid := False //cache.io.cpu.writeBack.mmuMiss || cache.io.cpu.writeBack.accessError || cache.io.cpu.writeBack.illegalAccess || cache.io.cpu.writeBack.unalignedAccess @@ -250,7 +260,7 @@ class DBusCachedPlugin(config : DataCacheConfig, } //Share access to the dBus (used by self refilled MMU) - val dBusSharing = (dBusAccess != null) generate pipeline plug new Area{ + if(dBusAccess != null) pipeline plug new Area{ dBusAccess.cmd.ready := False val forceDatapath = False when(dBusAccess.cmd.valid){ @@ -264,7 +274,7 @@ class DBusCachedPlugin(config : DataCacheConfig, cache.io.cpu.execute.args.data := dBusAccess.cmd.data cache.io.cpu.execute.args.size := dBusAccess.cmd.size cache.io.cpu.execute.args.forceUncachedAccess := False - if(genAtomic) cache.io.cpu.execute.args.isAtomic := False + if(withLrSc) cache.io.cpu.execute.args.isAtomic := False cache.io.cpu.execute.address := dBusAccess.cmd.address //Will only be 12 muxes forceDatapath := True } diff --git a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala index a59e79dd..54b7f19b 100644 --- a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala @@ -205,12 +205,11 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, earlyInjection : Boolean = false, /*, idempotentRegions : (UInt) => Bool = (x) => False*/ emitCmdInMemoryStage : Boolean = false, onlyLoadWords : Boolean = false, - atomicEntriesCount : Int = 0, + withLrSc : Boolean = false, memoryTranslatorPortConfig : Any = null) extends Plugin[VexRiscv] with DBusAccessService { var dBus : DBusSimpleBus = null assert(!(emitCmdInMemoryStage && earlyInjection)) - def genAtomic = atomicEntriesCount != 0 object MEMORY_ENABLE extends Stageable(Bool) object MEMORY_READ_DATA extends Stageable(Bits(32 bits)) object MEMORY_ADDRESS_LOW extends Stageable(UInt(2 bits)) @@ -269,7 +268,7 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, ) - if(genAtomic){ + if(withLrSc){ List(LB, LH, LW, LBU, LHU, LWU, SB, SH, SW).foreach(e => decoderService.add(e, Seq(MEMORY_ATOMIC -> False)) ) @@ -373,29 +372,14 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, } - val atomic = genAtomic generate new Area{ - val address = input(SRC_ADD).asUInt - case class AtomicEntry() extends Bundle{ - val valid = Bool() - val address = UInt(32 bits) - - def init: this.type ={ - valid init(False) - this - } - } - val entries = Vec(Reg(AtomicEntry()).init, atomicEntriesCount) - val entriesAllocCounter = Counter(atomicEntriesCount) - insert(ATOMIC_HIT) := entries.map(e => e.valid && e.address === address).orR - when(arbitration.isValid && input(MEMORY_ENABLE) && input(MEMORY_ATOMIC) && !input(MEMORY_STORE)){ - entries(entriesAllocCounter).valid := True - entries(entriesAllocCounter).address := address - when(!arbitration.isStuck){ - entriesAllocCounter.increment() - } + val atomic = withLrSc generate new Area{ + val reserved = RegInit(False) + insert(ATOMIC_HIT) := reserved + when(arbitration.isFiring && input(MEMORY_ENABLE) && input(MEMORY_ATOMIC) && !input(MEMORY_STORE)){ + reserved := True } when(service(classOf[IContextSwitching]).isContextSwitching){ - entries.foreach(_.valid := False) + reserved := False } when(input(MEMORY_STORE) && input(MEMORY_ATOMIC) && !input(ATOMIC_HIT)){ @@ -476,7 +460,7 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, when(arbitration.isValid && input(MEMORY_ENABLE)) { output(REGFILE_WRITE_DATA) := (if(!onlyLoadWords) rspFormated else input(MEMORY_READ_DATA)) - if(genAtomic){ + if(withLrSc){ when(input(MEMORY_ATOMIC) && input(MEMORY_STORE)){ output(REGFILE_WRITE_DATA) := (!input(ATOMIC_HIT)).asBits.resized } diff --git a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala index 2b8c89c5..ec1025cc 100644 --- a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala @@ -220,9 +220,9 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l, decodeExceptionPort.valid := iBusRsp.readyForError decodeExceptionPort.code := 1 } + decodeExceptionPort.valid clearWhen(fetcherHalt) } - decodeExceptionPort.valid clearWhen(fetcherHalt) cacheRspArbitration.halt setWhen (issueDetected || iBusRspOutputHalt) iBusRsp.output.valid := cacheRspArbitration.output.valid diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 907b2c4a..83a22042 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -3456,7 +3456,6 @@ int main(int argc, char **argv, char **env) { // redo(REDO,WorkspaceRegression("deleg").withRiscvRef()->loadHex("../raw/deleg/build/deleg.hex")->bootAt(0x80000000u)->run(50e3);); // return 0; - redo(REDO,WorkspaceRegression("mmu").withRiscvRef()->loadHex("../raw/mmu/build/mmu.hex")->bootAt(0x80000000u)->run(50e3);); for(int idx = 0;idx < 1;idx++){ @@ -3568,7 +3567,8 @@ int main(int argc, char **argv, char **env) { #endif #ifdef DEBUG_PLUGIN - redo(REDO,DebugPluginTest().run(1e6);); + //TODO +// redo(REDO,DebugPluginTest().run(1e6);); #endif #endif diff --git a/src/test/scala/vexriscv/TestIndividualFeatures.scala b/src/test/scala/vexriscv/TestIndividualFeatures.scala index 9be96b4d..d57f9bd4 100644 --- a/src/test/scala/vexriscv/TestIndividualFeatures.scala +++ b/src/test/scala/vexriscv/TestIndividualFeatures.scala @@ -366,7 +366,7 @@ class DBusDimension extends VexRiscvDimension("DBus") { catchAccessError = catchAll, catchIllegal = catchAll, catchUnaligned = catchAll, - atomicEntriesCount = 0 + withLrSc = false ), memoryTranslatorPortConfig = null ) From 8e6010fd712b4c966ad1638cea5a56059cf64b33 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Fri, 5 Apr 2019 00:25:27 +0200 Subject: [PATCH 108/951] Got the debug plugin working with the linux config (had to disable CSR ebreak) --- src/main/scala/vexriscv/demo/Linux.scala | 11 ++++++----- src/test/cpp/regression/main.cpp | 3 +-- src/test/scala/vexriscv/DhrystoneBench.scala | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/main/scala/vexriscv/demo/Linux.scala b/src/main/scala/vexriscv/demo/Linux.scala index 92130311..4bfeb951 100644 --- a/src/main/scala/vexriscv/demo/Linux.scala +++ b/src/main/scala/vexriscv/demo/Linux.scala @@ -40,13 +40,13 @@ cd VexRiscv Run regressions => sbt "runMain vexriscv.demo.LinuxGen -r" cd src/test/cpp/regression -make run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=no DHRYSTONE=yes SUPERVISOR=yes CSR=yes COMPRESSED=yes REDO=10 TRACE=no +make run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD DHRYSTONE=yes SUPERVISOR=yes CSR=yes COMPRESSED=yes REDO=10 TRACE=no Run linux in simulation (Require the machime mode emulator compiled in SIM mode) => sbt "runMain vexriscv.demo.LinuxGen" cd src/test/cpp/regression export BUILDROOT=/home/miaou/pro/riscv/buildrootSpinal -make run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=no SUPERVISOR=yes CSR=yes COMPRESSED=yes REDO=0 DHRYSTONE=no LINUX_SOC=yes EMULATOR=../../../main/c/emulator/build/emulator.bin VMLINUX=$BUILDROOT/output/images/vmlinux.bin DTB=$BUILDROOT/board/spinal/vexriscv_sim/rv32.dtb RAMDISK=$BUILDROOT/output/images/rootfs.cpio TRACE=no FLOW_INFO=no +make run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD SUPERVISOR=yes CSR=yes COMPRESSED=yes REDO=0 DHRYSTONE=no LINUX_SOC=yes EMULATOR=../../../main/c/emulator/build/emulator.bin VMLINUX=$BUILDROOT/output/images/vmlinux.bin DTB=$BUILDROOT/board/spinal/vexriscv_sim/rv32.dtb RAMDISK=$BUILDROOT/output/images/rootfs.cpio TRACE=no FLOW_INFO=no Run linux with QEMU (Require the machime mode emulator compiled in QEMU mode) export BUILDROOT=/home/miaou/pro/riscv/buildrootSpinal @@ -88,6 +88,7 @@ https://github.com/riscv/riscv-qemu/wiki#build-and-install */ +//TODO test dcache flush //TODO have to check, look like supervisor can't get interrupt if the machine mod didn't delegated it, have to check exactly object LinuxGen { def configFull(litex : Boolean, withMmu : Boolean) = { @@ -178,7 +179,7 @@ object LinuxGen { ), new RegFilePlugin( regFileReadyKind = plugin.SYNC, - zeroBoot = false //TODO + zeroBoot = true //TODO ), new IntAluPlugin, new SrcPlugin( @@ -205,7 +206,7 @@ object LinuxGen { divUnrollFactor = 1 ), // new DivPlugin, - new CsrPlugin(CsrPluginConfig.linux(0x80000020l)), + new CsrPlugin(CsrPluginConfig.linux(0x80000020l).copy(ebreakGen = false)), // new CsrPlugin(//CsrPluginConfig.all2(0x80000020l).copy(ebreakGen = true)/* // CsrPluginConfig( // catchIllegalAccess = false, @@ -229,7 +230,7 @@ object LinuxGen { // wfiGenAsNop = true, // ucycleAccess = CsrAccess.NONE // )), -// new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))), + new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))), new BranchPlugin( earlyBranch = false, catchAddressMisaligned = true, diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 83a22042..f13fd6a4 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -3567,8 +3567,7 @@ int main(int argc, char **argv, char **env) { #endif #ifdef DEBUG_PLUGIN - //TODO -// redo(REDO,DebugPluginTest().run(1e6);); + redo(REDO,DebugPluginTest().run(1e6);); #endif #endif diff --git a/src/test/scala/vexriscv/DhrystoneBench.scala b/src/test/scala/vexriscv/DhrystoneBench.scala index 0302b944..085eaa17 100644 --- a/src/test/scala/vexriscv/DhrystoneBench.scala +++ b/src/test/scala/vexriscv/DhrystoneBench.scala @@ -92,7 +92,7 @@ class DhrystoneBench extends FunSuite{ getDmips( name = "GenFull", gen = GenFull.main(null), - testCmd = "make clean run REDO=10 CSR=no" + testCmd = "make clean run REDO=10 CSR=no MMU=no" ) test("final_report") { From 888e1c0b8a3a59c724d73f3cd5be4bf56d2218f7 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Fri, 5 Apr 2019 01:08:57 +0200 Subject: [PATCH 109/951] Fix RVC instruction cache xtval allignement --- src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala index ec1025cc..1ecde553 100644 --- a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala @@ -207,7 +207,7 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l, if (catchSomething) { decodeExceptionPort.valid := False decodeExceptionPort.code.assignDontCare() - decodeExceptionPort.badAddr := cacheRsp.pc + decodeExceptionPort.badAddr := cacheRsp.pc(31 downto 2) @@ "00" if(catchIllegalAccess) when(cacheRsp.isValid && cacheRsp.mmuException && !issueDetected) { issueDetected \= True From 446e9625af01e29ec24ba96c2d22d254b88d7b14 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Fri, 5 Apr 2019 12:17:29 +0200 Subject: [PATCH 110/951] Centralised all todo in linux.scala Sorted out fence fence.i instruction in iBus/dBus plugins. Fixed MMU permitions while in used mode and bypassing the MMU --- src/main/scala/vexriscv/demo/GenFull.scala | 3 +-- src/main/scala/vexriscv/demo/Linux.scala | 10 +++------- src/main/scala/vexriscv/ip/DataCache.scala | 1 - .../scala/vexriscv/ip/InstructionCache.scala | 4 ++-- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 3 +-- .../vexriscv/plugin/DBusCachedPlugin.scala | 3 +++ .../vexriscv/plugin/DBusSimplePlugin.scala | 1 + .../vexriscv/plugin/IBusCachedPlugin.scala | 2 -- .../vexriscv/plugin/IBusSimplePlugin.scala | 4 ++++ src/main/scala/vexriscv/plugin/MmuPlugin.scala | 17 ++++++++--------- 10 files changed, 23 insertions(+), 25 deletions(-) diff --git a/src/main/scala/vexriscv/demo/GenFull.scala b/src/main/scala/vexriscv/demo/GenFull.scala index 97ae71a3..dfa7b1e8 100644 --- a/src/main/scala/vexriscv/demo/GenFull.scala +++ b/src/main/scala/vexriscv/demo/GenFull.scala @@ -49,8 +49,7 @@ object GenFull extends App{ ), new MmuPlugin( virtualRange = _(31 downto 28) === 0xC, - ioRange = _(31 downto 28) === 0xF, - allowUserIo = false + ioRange = _(31 downto 28) === 0xF ), new DecoderSimplePlugin( catchIllegalInstruction = true diff --git a/src/main/scala/vexriscv/demo/Linux.scala b/src/main/scala/vexriscv/demo/Linux.scala index 4bfeb951..a1bd0f74 100644 --- a/src/main/scala/vexriscv/demo/Linux.scala +++ b/src/main/scala/vexriscv/demo/Linux.scala @@ -90,12 +90,11 @@ https://github.com/riscv/riscv-qemu/wiki#build-and-install //TODO test dcache flush //TODO have to check, look like supervisor can't get interrupt if the machine mod didn't delegated it, have to check exactly +//TODO IBus cached and uncached, do not allow supervisor if it's a user page ? io.cpu.fetch.mmuException object LinuxGen { def configFull(litex : Boolean, withMmu : Boolean) = { val config = VexRiscvConfig( plugins = List( - new DummyFencePlugin(), //TODO should be removed for design with caches - //Uncomment the whole IBusSimplePlugin and comment IBusCachedPlugin if you want uncached iBus config // new IBusSimplePlugin( // resetVector = 0x80000000l, @@ -179,7 +178,7 @@ object LinuxGen { ), new RegFilePlugin( regFileReadyKind = plugin.SYNC, - zeroBoot = true //TODO + zeroBoot = true ), new IntAluPlugin, new SrcPlugin( @@ -240,10 +239,7 @@ object LinuxGen { ) ) if(withMmu) config.plugins += new MmuPlugin( - virtualRange = a => True, - // virtualRange = x => x(31 downto 24) =/= 0x81, - ioRange = (x => if(litex) x(31 downto 28) === 0xB || x(31 downto 28) === 0xE || x(31 downto 28) === 0xF else x(31 downto 28) === 0xF), - allowUserIo = true //TODO ?? + ioRange = (x => if(litex) x(31 downto 28) === 0xB || x(31 downto 28) === 0xE || x(31 downto 28) === 0xF else x(31 downto 28) === 0xF) ) else { config.plugins += new StaticMemoryTranslatorPlugin( ioRange = _(31 downto 28) === 0xF diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index 66f6999d..8c50d40c 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -8,7 +8,6 @@ import spinal.lib.bus.avalon.{AvalonMM, AvalonMMConfig} import spinal.lib.bus.wishbone.{Wishbone, WishboneConfig} import spinal.lib.bus.simple._ -//TODO flush case class DataCacheConfig(cacheSize : Int, bytePerLine : Int, diff --git a/src/main/scala/vexriscv/ip/InstructionCache.scala b/src/main/scala/vexriscv/ip/InstructionCache.scala index c36dcdbf..08683c44 100644 --- a/src/main/scala/vexriscv/ip/InstructionCache.scala +++ b/src/main/scala/vexriscv/ip/InstructionCache.scala @@ -411,7 +411,7 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{ io.cpu.fetch.cacheMiss := !hit.valid io.cpu.fetch.error := hit.error io.cpu.fetch.mmuRefilling := mmuRsp.refilling - io.cpu.fetch.mmuException := !mmuRsp.refilling && (mmuRsp.exception || !mmuRsp.allowExecute || (!mmuRsp.allowUser && io.cpu.fetch.isUser)) //TODO Do not allow supervisor if it's a user page ? + io.cpu.fetch.mmuException := !mmuRsp.refilling && (mmuRsp.exception || !mmuRsp.allowExecute || (!mmuRsp.allowUser && io.cpu.fetch.isUser)) }) } @@ -441,7 +441,7 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{ io.cpu.decode.cacheMiss := !hit.valid io.cpu.decode.error := hit.error io.cpu.decode.mmuRefilling := mmuRsp.refilling - io.cpu.decode.mmuException := !mmuRsp.refilling && (mmuRsp.exception || !mmuRsp.allowExecute || (!mmuRsp.allowUser && io.cpu.decode.isUser)) //TODO Do not allow supervisor if it's a user page ? + io.cpu.decode.mmuException := !mmuRsp.refilling && (mmuRsp.exception || !mmuRsp.allowExecute || (!mmuRsp.allowUser && io.cpu.decode.isUser)) io.cpu.decode.physicalAddress := mmuRsp.physicalAddress }) } diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 59410f7f..3b45cca3 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -813,7 +813,7 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception import lastStage._ //Manage MRET / SRET instructions - when(arbitration.isValid && input(ENV_CTRL) === EnvCtrlEnum.XRET) { //TODO do not allow user mode already implemented somewhere else ? + when(arbitration.isValid && input(ENV_CTRL) === EnvCtrlEnum.XRET) { fetcher.haltIt() jumpInterface.valid := True beforeLastStage.arbitration.flushAll := True @@ -885,7 +885,6 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception //Manage MRET / SRET instructions when(arbitration.isValid && input(ENV_CTRL) === EnvCtrlEnum.XRET) { - //TODO check MPP value too when(input(INSTRUCTION)(29 downto 28).asUInt > privilege) { illegalInstruction := True } diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index fcf807bd..530ba8a8 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -113,6 +113,8 @@ class DBusCachedPlugin(config : DataCacheConfig, MEMORY_MANAGMENT -> True )) + decoderService.add(FENCE, Nil) + mmuBus = pipeline.service(classOf[MemoryTranslator]).newTranslationPort(MemoryTranslatorPort.PRIORITY_DATA ,memoryTranslatorPortConfig) redoBranch = pipeline.service(classOf[JumpService]).createJumpInterface(pipeline.writeBack) @@ -284,6 +286,7 @@ class DBusCachedPlugin(config : DataCacheConfig, mmuBus.cmd.bypassTranslation setWhen(memory.input(IS_DBUS_SHARING)) cache.io.cpu.memory.isValid setWhen(memory.input(IS_DBUS_SHARING)) + cache.io.cpu.memory.mmuBus.rsp.allowUser setWhen(memory.input(IS_DBUS_SHARING)) cache.io.cpu.writeBack.isValid setWhen(writeBack.input(IS_DBUS_SHARING)) dBusAccess.rsp.valid := writeBack.input(IS_DBUS_SHARING) && !cache.io.cpu.writeBack.isWrite && (cache.io.cpu.redo || !cache.io.cpu.writeBack.haltIt) dBusAccess.rsp.data := cache.io.cpu.writeBack.data diff --git a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala index 54b7f19b..a1ad3dd0 100644 --- a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala @@ -292,6 +292,7 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, ) } + decoderService.add(FENCE, Nil) rspStage = if(stages.last == execute) execute else (if(emitCmdInMemoryStage) writeBack else memory) if(catchSomething) { diff --git a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala index 1ecde553..07babf92 100644 --- a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala @@ -78,8 +78,6 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l, super.setup(pipeline) - //def MANAGEMENT = M"-----------------100-----0001111" - val decoderService = pipeline.service(classOf[DecoderService]) decoderService.addDefault(FLUSH_ALL, False) decoderService.add(FENCE_I, List( diff --git a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala index 269f76a6..af77a89b 100644 --- a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala @@ -7,6 +7,7 @@ import spinal.lib.bus.amba4.axi._ import spinal.lib.bus.avalon.{AvalonMM, AvalonMMConfig} import spinal.lib.bus.wishbone.{Wishbone, WishboneConfig} import spinal.lib.bus.simple._ +import vexriscv.Riscv.{FENCE, FENCE_I} case class IBusSimpleCmd() extends Bundle{ @@ -192,6 +193,9 @@ class IBusSimplePlugin(resetVector : BigInt, super.setup(pipeline) iBus = master(IBusSimpleBus(false)).setName("iBus") + val decoderService = pipeline.service(classOf[DecoderService]) + decoderService.add(FENCE_I, Nil) + if(catchSomething) { decodeExceptionPort = pipeline.service(classOf[ExceptionService]).newExceptionPort(pipeline.decode,1) } diff --git a/src/main/scala/vexriscv/plugin/MmuPlugin.scala b/src/main/scala/vexriscv/plugin/MmuPlugin.scala index dfcced59..5d14978a 100644 --- a/src/main/scala/vexriscv/plugin/MmuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/MmuPlugin.scala @@ -38,17 +38,16 @@ case class MmuPort(bus : MemoryTranslatorBus, priority : Int, args : MmuPortConf case class MmuPortConfig(portTlbSize : Int) -class MmuPlugin(virtualRange : UInt => Bool, - ioRange : UInt => Bool, - allowUserIo : Boolean, - allowMachineModeMmu : Boolean = false) extends Plugin[VexRiscv] with MemoryTranslator { +class MmuPlugin(ioRange : UInt => Bool, + virtualRange : UInt => Bool = address => True, +// allowUserIo : Boolean = false, + enableMmuInMachineMode : Boolean = false) extends Plugin[VexRiscv] with MemoryTranslator { var dBusAccess : DBusAccess = null val portsInfo = ArrayBuffer[MmuPort]() override def newTranslationPort(priority : Int,args : Any): MemoryTranslatorBus = { -// val exceptionBus = pipeline.service(classOf[ExceptionService]).newExceptionPort(stage) - val port = MmuPort(MemoryTranslatorBus(),priority,args.asInstanceOf[MmuPortConfig], portsInfo.length /*,exceptionBus*/) + val port = MmuPort(MemoryTranslatorBus(),priority,args.asInstanceOf[MmuPortConfig], portsInfo.length) portsInfo += port port.bus } @@ -96,7 +95,7 @@ class MmuPlugin(virtualRange : UInt => Bool, } for(offset <- List(CSR.MSTATUS, CSR.SSTATUS)) csrService.rw(offset, 19 -> status.mxr, 18 -> status.sum, 17 -> status.mprv) - csrService.rw(CSR.SATP, 31 -> satp.mode, 0 -> satp.ppn) //TODO write only ? + csrService.rw(CSR.SATP, 31 -> satp.mode, 0 -> satp.ppn) } val core = pipeline plug new Area { @@ -109,7 +108,7 @@ class MmuPlugin(virtualRange : UInt => Bool, val privilegeService = pipeline.serviceElse(classOf[PrivilegeService], PrivilegeServiceDefault()) val entryToReplace = Counter(port.args.portTlbSize) val requireMmuLockup = virtualRange(port.bus.cmd.virtualAddress) && !port.bus.cmd.bypassTranslation && csr.satp.mode - if(!allowMachineModeMmu) { + if(!enableMmuInMachineMode) { requireMmuLockup clearWhen(!csr.status.mprv && privilegeService.isMachine()) when(privilegeService.isMachine()) { if (port.priority == MmuPort.PRIORITY_DATA) { @@ -133,7 +132,7 @@ class MmuPlugin(virtualRange : UInt => Bool, port.bus.rsp.allowRead := True port.bus.rsp.allowWrite := True port.bus.rsp.allowExecute := True - port.bus.rsp.allowUser := Bool(allowUserIo) + port.bus.rsp.allowUser := True port.bus.rsp.exception := False port.bus.rsp.refilling := False } From f5d4e745c70d06369aec4562daa9ebe0cfc5910f Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Fri, 5 Apr 2019 18:08:25 +0200 Subject: [PATCH 111/951] Look like precise fence.i isn't required in practice --- src/main/scala/vexriscv/demo/Linux.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/demo/Linux.scala b/src/main/scala/vexriscv/demo/Linux.scala index a1bd0f74..1f6513de 100644 --- a/src/main/scala/vexriscv/demo/Linux.scala +++ b/src/main/scala/vexriscv/demo/Linux.scala @@ -233,7 +233,7 @@ object LinuxGen { new BranchPlugin( earlyBranch = false, catchAddressMisaligned = true, - fenceiGenAsAJump = true + fenceiGenAsAJump = false ), new YamlPlugin("cpu0.yaml") ) From 60a41bfc75a3dd1e6f2945545d9348bc4c809007 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Fri, 5 Apr 2019 18:11:10 +0200 Subject: [PATCH 112/951] rework i$ flush --- .../scala/vexriscv/ip/InstructionCache.scala | 22 +++++++++---------- .../vexriscv/plugin/IBusCachedPlugin.scala | 15 ++----------- 2 files changed, 13 insertions(+), 24 deletions(-) diff --git a/src/main/scala/vexriscv/ip/InstructionCache.scala b/src/main/scala/vexriscv/ip/InstructionCache.scala index 08683c44..b5b4e230 100644 --- a/src/main/scala/vexriscv/ip/InstructionCache.scala +++ b/src/main/scala/vexriscv/ip/InstructionCache.scala @@ -249,7 +249,7 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{ import p._ assert(cpuDataWidth == memDataWidth, "Need testing") val io = new Bundle{ - val flush = slave(InstructionCacheFlushBus()) + val flush = in Bool() val cpu = slave(InstructionCacheCpuBus(p)) val mem = master(InstructionCacheMemBus(p)) } @@ -300,15 +300,16 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{ val valid = RegInit(False) clearWhen(fire) val address = Reg(UInt(addressWidth bits)) val hadError = RegInit(False) clearWhen(fire) + val flushPending = RegInit(True) when(io.cpu.fill.valid){ valid := True address := io.cpu.fill.payload } - io.cpu.prefetch.haltIt setWhen(valid) + io.cpu.prefetch.haltIt setWhen(valid || flushPending) - val flushCounter = Reg(UInt(log2Up(wayLineCount) + 1 bit)) init(if(preResetFlush) wayLineCount else 0) + val flushCounter = Reg(UInt(log2Up(wayLineCount) + 1 bit)) when(!flushCounter.msb){ io.cpu.prefetch.haltIt := True flushCounter := flushCounter + 1 @@ -316,17 +317,16 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{ when(!RegNext(flushCounter.msb)){ 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){ + + when(io.flush){ io.cpu.prefetch.haltIt := True - when(io.flush.cmd.ready){ - flushCounter := 0 - flushFromInterface := True - } + flushPending := True } - io.flush.rsp := flushCounter.msb.rise && flushFromInterface + when(flushPending && !(valid || io.cpu.fetch.isValid) ){ + flushCounter := 0 + flushPending := False + } diff --git a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala index 07babf92..e7256094 100644 --- a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala @@ -242,19 +242,8 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l, cache.io.cpu.fetch.mmuBus.rsp.refilling := False } - val flushStage = if(memory != null) memory else execute - flushStage plug new Area { - import flushStage._ - - cache.io.flush.cmd.valid := False - when(arbitration.isValid && input(FLUSH_ALL)) { - cache.io.flush.cmd.valid := True - - when(!cache.io.flush.cmd.ready) { - arbitration.haltItself := True - } - } - } + val flushStage = decode + cache.io.flush := flushStage.arbitration.isValid && flushStage.input(FLUSH_ALL) } } } From 8459d423b823bcd00152b74d015135647e5a3fdb Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Fri, 5 Apr 2019 18:11:33 +0200 Subject: [PATCH 113/951] add icache flush test --- src/test/cpp/raw/icache/.gitignore | 4 ++ src/test/cpp/raw/icache/build/icache.asm | 53 ++++++++++++++++++++++++ src/test/cpp/raw/icache/build/icache.hex | 11 +++++ src/test/cpp/raw/icache/makefile | 3 ++ src/test/cpp/raw/icache/src/crt.S | 44 ++++++++++++++++++++ src/test/cpp/raw/icache/src/ld | 16 +++++++ src/test/cpp/regression/main.cpp | 4 ++ 7 files changed, 135 insertions(+) create mode 100644 src/test/cpp/raw/icache/.gitignore create mode 100644 src/test/cpp/raw/icache/build/icache.asm create mode 100644 src/test/cpp/raw/icache/build/icache.hex create mode 100644 src/test/cpp/raw/icache/makefile create mode 100644 src/test/cpp/raw/icache/src/crt.S create mode 100644 src/test/cpp/raw/icache/src/ld diff --git a/src/test/cpp/raw/icache/.gitignore b/src/test/cpp/raw/icache/.gitignore new file mode 100644 index 00000000..c12cb2c2 --- /dev/null +++ b/src/test/cpp/raw/icache/.gitignore @@ -0,0 +1,4 @@ +*.map +*.v +*.elf +*.o \ No newline at end of file diff --git a/src/test/cpp/raw/icache/build/icache.asm b/src/test/cpp/raw/icache/build/icache.asm new file mode 100644 index 00000000..edcd947a --- /dev/null +++ b/src/test/cpp/raw/icache/build/icache.asm @@ -0,0 +1,53 @@ + +build/icache.elf: file format elf32-littleriscv + + +Disassembly of section .crt_section: + +80000000 <_start>: +80000000: 00000097 auipc ra,0x0 +80000004: 05408093 addi ra,ra,84 # 80000054 +80000008: 30509073 csrw mtvec,ra + +8000000c : +8000000c: 00100e13 li t3,1 +80000010: 00100093 li ra,1 +80000014: 00300113 li sp,3 +80000018: 00208093 addi ra,ra,2 +8000001c: 02209c63 bne ra,sp,80000054 + +80000020 : +80000020: 00100e13 li t3,1 +80000024: 01300093 li ra,19 +80000028: 00000117 auipc sp,0x0 +8000002c: 02410113 addi sp,sp,36 # 8000004c +80000030: 0100006f j 80000040 +80000034: 00000013 nop +80000038: 00000013 nop +8000003c: 00000013 nop + +80000040 : +80000040: 00112023 sw ra,0(sp) +80000044: 0000100f fence.i +80000048: 0040006f j 8000004c + +8000004c : +8000004c: 0080006f j 80000054 +80000050: 0100006f j 80000060 + +80000054 : +80000054: f0100137 lui sp,0xf0100 +80000058: f2410113 addi sp,sp,-220 # f00fff24 +8000005c: 01c12023 sw t3,0(sp) + +80000060 : +80000060: f0100137 lui sp,0xf0100 +80000064: f2010113 addi sp,sp,-224 # f00fff20 +80000068: 00012023 sw zero,0(sp) +8000006c: 00000013 nop +80000070: 00000013 nop +80000074: 00000013 nop +80000078: 00000013 nop +8000007c: 00000013 nop +80000080: 00000013 nop + ... diff --git a/src/test/cpp/raw/icache/build/icache.hex b/src/test/cpp/raw/icache/build/icache.hex new file mode 100644 index 00000000..ea4a88ce --- /dev/null +++ b/src/test/cpp/raw/icache/build/icache.hex @@ -0,0 +1,11 @@ +:0200000480007A +:10000000970000009380400573905030130E10004D +:10001000930010001301300093802000639C2002A5 +:10002000130E10009300300117010000130141026C +:100030006F00000113000000130000001300000017 +:10004000232011000F1000006F0040006F0080009F +:100050006F000001370110F0130141F22320C101AC +:10006000370110F0130101F22320010013000000FA +:100070001300000013000000130000001300000034 +:10008000130000000000000000000000000000005D +:00000001FF diff --git a/src/test/cpp/raw/icache/makefile b/src/test/cpp/raw/icache/makefile new file mode 100644 index 00000000..08779a26 --- /dev/null +++ b/src/test/cpp/raw/icache/makefile @@ -0,0 +1,3 @@ +PROJ_NAME=icache + +include ../common/asm.mk \ No newline at end of file diff --git a/src/test/cpp/raw/icache/src/crt.S b/src/test/cpp/raw/icache/src/crt.S new file mode 100644 index 00000000..97b29b93 --- /dev/null +++ b/src/test/cpp/raw/icache/src/crt.S @@ -0,0 +1,44 @@ +.globl _star +#define TEST_ID x28 + +_start: + la x1, fail + csrw mtvec, x1 + +test1: //Dummy test + li TEST_ID, 1 + li x1, 1 + li x2, 3 + addi x1, x1, 2 + bne x1, x2, fail + +test2: + li TEST_ID, 1 + li x1, 0x13 //nop + la x2, test2_trigger + j test2_aligned +.align(4) +test2_aligned: + sw x1, 0(x2) + fence.i + j test2_trigger +test2_trigger: + j fail + + + j pass + +fail: + li x2, 0xF00FFF24 + sw TEST_ID, 0(x2) + +pass: + li x2, 0xF00FFF20 + sw x0, 0(x2) + + nop + nop + nop + nop + nop + nop diff --git a/src/test/cpp/raw/icache/src/ld b/src/test/cpp/raw/icache/src/ld new file mode 100644 index 00000000..93d8de8e --- /dev/null +++ b/src/test/cpp/raw/icache/src/ld @@ -0,0 +1,16 @@ +OUTPUT_ARCH( "riscv" ) + +MEMORY { + onChipRam (W!RX)/*(RX)*/ : ORIGIN = 0x80000000, LENGTH = 128K +} + +SECTIONS +{ + + .crt_section : + { + . = ALIGN(4); + *crt.o(.text) + } > onChipRam + +} diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index f13fd6a4..665763c2 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -3559,6 +3559,10 @@ int main(int argc, char **argv, char **env) { // redo(REDO,TestX28("mmu",mmuRef, sizeof(mmuRef)/4).noInstructionReadCheck()->run(4e4);) // #endif + #ifdef IBUS_CACHED + redo(REDO,WorkspaceRegression("icache").withRiscvRef()->loadHex("../raw/icache/build/icache.hex")->bootAt(0x80000000u)->run(50e3);); + #endif + #ifdef MMU redo(REDO,WorkspaceRegression("mmu").withRiscvRef()->loadHex("../raw/mmu/build/mmu.hex")->bootAt(0x80000000u)->run(50e3);); #endif From 5a6665e57f8b140baca0401134ff59a0574102f8 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Fri, 5 Apr 2019 20:02:57 +0200 Subject: [PATCH 114/951] Fix DataCache flush on the last line --- src/main/scala/vexriscv/ip/DataCache.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index 8c50d40c..d4d6f147 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -448,9 +448,9 @@ class DataCache(p : DataCacheConfig) extends Component{ tagsWriteCmd.address := mmuRsp.physicalAddress(lineRange) tagsWriteCmd.way.setAll() tagsWriteCmd.data.valid := False + io.cpu.writeBack.haltIt := True when(mmuRsp.physicalAddress(lineRange) =/= wayLineCount - 1) { mmuRsp.physicalAddress.getDrivingReg(lineRange) := mmuRsp.physicalAddress(lineRange) + 1 - io.cpu.writeBack.haltIt := True } otherwise { valid := False } From aeb418a99e749b29853e2c84bb395f76fde5ee29 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Fri, 5 Apr 2019 20:03:22 +0200 Subject: [PATCH 115/951] Add dcache tests --- src/test/cpp/raw/dcache/.gitignore | 4 ++ src/test/cpp/raw/dcache/build/dcache.asm | 79 ++++++++++++++++++++++++ src/test/cpp/raw/dcache/build/dcache.hex | 17 +++++ src/test/cpp/raw/dcache/makefile | 3 + src/test/cpp/raw/dcache/src/crt.S | 75 ++++++++++++++++++++++ src/test/cpp/raw/dcache/src/ld | 16 +++++ src/test/cpp/raw/icache/build/icache.asm | 2 +- src/test/cpp/raw/icache/build/icache.hex | 2 +- src/test/cpp/raw/icache/src/crt.S | 2 +- src/test/cpp/regression/main.cpp | 12 ++++ 10 files changed, 209 insertions(+), 3 deletions(-) create mode 100644 src/test/cpp/raw/dcache/.gitignore create mode 100644 src/test/cpp/raw/dcache/build/dcache.asm create mode 100644 src/test/cpp/raw/dcache/build/dcache.hex create mode 100644 src/test/cpp/raw/dcache/makefile create mode 100644 src/test/cpp/raw/dcache/src/crt.S create mode 100644 src/test/cpp/raw/dcache/src/ld diff --git a/src/test/cpp/raw/dcache/.gitignore b/src/test/cpp/raw/dcache/.gitignore new file mode 100644 index 00000000..c12cb2c2 --- /dev/null +++ b/src/test/cpp/raw/dcache/.gitignore @@ -0,0 +1,4 @@ +*.map +*.v +*.elf +*.o \ No newline at end of file diff --git a/src/test/cpp/raw/dcache/build/dcache.asm b/src/test/cpp/raw/dcache/build/dcache.asm new file mode 100644 index 00000000..698e5dc3 --- /dev/null +++ b/src/test/cpp/raw/dcache/build/dcache.asm @@ -0,0 +1,79 @@ + +build/dcache.elf: file format elf32-littleriscv + + +Disassembly of section .crt_section: + +80000000 <_start>: +80000000: 00000097 auipc ra,0x0 +80000004: 0b808093 addi ra,ra,184 # 800000b8 +80000008: 30509073 csrw mtvec,ra + +8000000c : +8000000c: 00100e13 li t3,1 +80000010: 00100093 li ra,1 +80000014: 00300113 li sp,3 +80000018: 00208093 addi ra,ra,2 +8000001c: 08209e63 bne ra,sp,800000b8 + +80000020 : +80000020: 00200e13 li t3,2 +80000024: f56700b7 lui ra,0xf5670 +80000028: 900ff137 lui sp,0x900ff +8000002c: 40000313 li t1,1024 + +80000030 : +80000030: 00100193 li gp,1 +80000034: 00200293 li t0,2 +80000038: 006303b3 add t2,t1,t1 +8000003c: 007181b3 add gp,gp,t2 +80000040: 007282b3 add t0,t0,t2 +80000044: 00312023 sw gp,0(sp) # 900ff000 +80000048: 0000a023 sw zero,0(ra) # f5670000 +8000004c: 00012203 lw tp,0(sp) +80000050: 06429463 bne t0,tp,800000b8 +80000054: fff30313 addi t1,t1,-1 +80000058: 00408093 addi ra,ra,4 +8000005c: 00410113 addi sp,sp,4 +80000060: 0000500f 0x500f +80000064: fc0316e3 bnez t1,80000030 + +80000068 : +80000068: 00300e13 li t3,3 +8000006c: f56700b7 lui ra,0xf5670 +80000070: 900ff137 lui sp,0x900ff +80000074: 40000313 li t1,1024 + +80000078 : +80000078: 00200193 li gp,2 +8000007c: 00300293 li t0,3 +80000080: 006303b3 add t2,t1,t1 +80000084: 007181b3 add gp,gp,t2 +80000088: 007282b3 add t0,t0,t2 +8000008c: 00012203 lw tp,0(sp) # 900ff000 +80000090: 00312023 sw gp,0(sp) +80000094: 0000a023 sw zero,0(ra) # f5670000 +80000098: 0000500f 0x500f +8000009c: 00012203 lw tp,0(sp) +800000a0: 00429c63 bne t0,tp,800000b8 +800000a4: fff30313 addi t1,t1,-1 +800000a8: 00408093 addi ra,ra,4 +800000ac: 00410113 addi sp,sp,4 +800000b0: fc0314e3 bnez t1,80000078 +800000b4: 0100006f j 800000c4 + +800000b8 : +800000b8: f0100137 lui sp,0xf0100 +800000bc: f2410113 addi sp,sp,-220 # f00fff24 +800000c0: 01c12023 sw t3,0(sp) + +800000c4 : +800000c4: f0100137 lui sp,0xf0100 +800000c8: f2010113 addi sp,sp,-224 # f00fff20 +800000cc: 00012023 sw zero,0(sp) +800000d0: 00000013 nop +800000d4: 00000013 nop +800000d8: 00000013 nop +800000dc: 00000013 nop +800000e0: 00000013 nop +800000e4: 00000013 nop diff --git a/src/test/cpp/raw/dcache/build/dcache.hex b/src/test/cpp/raw/dcache/build/dcache.hex new file mode 100644 index 00000000..6e9ef5db --- /dev/null +++ b/src/test/cpp/raw/dcache/build/dcache.hex @@ -0,0 +1,17 @@ +:0200000480007A +:10000000970000009380800B73905030130E100007 +:10001000930010001301300093802000639E20089D +:10002000130E2000B70067F537F10F90130300405F +:100030009301100093022000B3036300B3817100A9 +:10004000B38272002320310023A0000003220100AC +:10005000639442061303F3FF9380400013014100B1 +:100060000F500000E31603FC130E3000B70067F5D5 +:1000700037F10F90130300409301200093023000EA +:10008000B3036300B3817100B382720003220100E5 +:100090002320310023A000000F50000003220100A4 +:1000A000639C42001303F3FF93804000130141005F +:1000B000E31403FC6F000001370110F0130141F25B +:1000C0002320C101370110F0130101F223200100A8 +:1000D00013000000130000001300000013000000D4 +:0800E0001300000013000000F2 +:00000001FF diff --git a/src/test/cpp/raw/dcache/makefile b/src/test/cpp/raw/dcache/makefile new file mode 100644 index 00000000..5ebb9425 --- /dev/null +++ b/src/test/cpp/raw/dcache/makefile @@ -0,0 +1,3 @@ +PROJ_NAME=dcache + +include ../common/asm.mk \ No newline at end of file diff --git a/src/test/cpp/raw/dcache/src/crt.S b/src/test/cpp/raw/dcache/src/crt.S new file mode 100644 index 00000000..8476c09e --- /dev/null +++ b/src/test/cpp/raw/dcache/src/crt.S @@ -0,0 +1,75 @@ +.globl _star +#define TEST_ID x28 + +_start: + la x1, fail + csrw mtvec, x1 + +test1: //Dummy test + li TEST_ID, 1 + li x1, 1 + li x2, 3 + addi x1, x1, 2 + bne x1, x2, fail + +test2: //No invalidate, without load => new one + li TEST_ID, 2 + li x1, 0xF5670000 + li x2, 0x900FF000 + li x6, 4096/4 +test2_repeat: + la x3, 1 + la x5, 2 + add x7, x6, x6 + add x3, x3, x7 + add x5, x5, x7 + sw x3, 0(x2) + sw x0, 0(x1) + lw x4, 0(x2) + bne x5,x4, fail + addi x6, x6, -1 + addi x1, x1, 4 + addi x2, x2, 4 +.word 0x000500F // dcache flush + bnez x6, test2_repeat + +test3: //with invalidate, with preload + li TEST_ID, 3 + li x1, 0xF5670000 + li x2, 0x900FF000 + li x6, 4096/4 +test3_repeat: + la x3, 2 + la x5, 3 + add x7, x6, x6 + add x3, x3, x7 + add x5, x5, x7 + lw x4, 0(x2) + sw x3, 0(x2) + sw x0, 0(x1) +.word 0x000500F // dcache flush + lw x4, 0(x2) + bne x5,x4, fail + addi x6, x6, -1 + addi x1, x1, 4 + addi x2, x2, 4 + bnez x6, test3_repeat + + + + j pass + +fail: + li x2, 0xF00FFF24 + sw TEST_ID, 0(x2) + +pass: + li x2, 0xF00FFF20 + sw x0, 0(x2) + + nop + nop + nop + nop + nop + nop diff --git a/src/test/cpp/raw/dcache/src/ld b/src/test/cpp/raw/dcache/src/ld new file mode 100644 index 00000000..93d8de8e --- /dev/null +++ b/src/test/cpp/raw/dcache/src/ld @@ -0,0 +1,16 @@ +OUTPUT_ARCH( "riscv" ) + +MEMORY { + onChipRam (W!RX)/*(RX)*/ : ORIGIN = 0x80000000, LENGTH = 128K +} + +SECTIONS +{ + + .crt_section : + { + . = ALIGN(4); + *crt.o(.text) + } > onChipRam + +} diff --git a/src/test/cpp/raw/icache/build/icache.asm b/src/test/cpp/raw/icache/build/icache.asm index edcd947a..75214113 100644 --- a/src/test/cpp/raw/icache/build/icache.asm +++ b/src/test/cpp/raw/icache/build/icache.asm @@ -17,7 +17,7 @@ Disassembly of section .crt_section: 8000001c: 02209c63 bne ra,sp,80000054 80000020 : -80000020: 00100e13 li t3,1 +80000020: 00200e13 li t3,2 80000024: 01300093 li ra,19 80000028: 00000117 auipc sp,0x0 8000002c: 02410113 addi sp,sp,36 # 8000004c diff --git a/src/test/cpp/raw/icache/build/icache.hex b/src/test/cpp/raw/icache/build/icache.hex index ea4a88ce..25eb34e0 100644 --- a/src/test/cpp/raw/icache/build/icache.hex +++ b/src/test/cpp/raw/icache/build/icache.hex @@ -1,7 +1,7 @@ :0200000480007A :10000000970000009380400573905030130E10004D :10001000930010001301300093802000639C2002A5 -:10002000130E10009300300117010000130141026C +:10002000130E20009300300117010000130141025C :100030006F00000113000000130000001300000017 :10004000232011000F1000006F0040006F0080009F :100050006F000001370110F0130141F22320C101AC diff --git a/src/test/cpp/raw/icache/src/crt.S b/src/test/cpp/raw/icache/src/crt.S index 97b29b93..695c45bb 100644 --- a/src/test/cpp/raw/icache/src/crt.S +++ b/src/test/cpp/raw/icache/src/crt.S @@ -13,7 +13,7 @@ test1: //Dummy test bne x1, x2, fail test2: - li TEST_ID, 1 + li TEST_ID, 2 li x1, 0x13 //nop la x2, test2_trigger j test2_aligned diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 665763c2..5630ba64 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -1676,6 +1676,15 @@ public: case 0xF00FFF48u: mTimeCmp = (mTimeCmp & 0xFFFFFFFF00000000) | *data;break; case 0xF00FFF4Cu: mTimeCmp = (mTimeCmp & 0x00000000FFFFFFFF) | (((uint64_t)*data) << 32); break; } + if((addr & 0xFFFFF000) == 0xF5670000){ + uint32_t t = 0x900FF000 | (addr & 0xFFF); + uint32_t old = (*mem.get(t + 3) << 24) | (*mem.get(t + 2) << 16) | (*mem.get(t + 1) << 8) | (*mem.get(t + 0) << 0); + old++; + *mem.get(t + 0) = old & 0xFF; old >>= 8; + *mem.get(t + 1) = old & 0xFF; old >>= 8; + *mem.get(t + 2) = old & 0xFF; old >>= 8; + *mem.get(t + 3) = old & 0xFF; old >>= 8; + } }else{ switch(addr){ case 0xF00FFF10u: @@ -3562,6 +3571,9 @@ int main(int argc, char **argv, char **env) { #ifdef IBUS_CACHED redo(REDO,WorkspaceRegression("icache").withRiscvRef()->loadHex("../raw/icache/build/icache.hex")->bootAt(0x80000000u)->run(50e3);); #endif + #ifdef DBUS_CACHED + redo(REDO,WorkspaceRegression("dcache").loadHex("../raw/dcache/build/dcache.hex")->bootAt(0x80000000u)->run(500e3);); + #endif #ifdef MMU redo(REDO,WorkspaceRegression("mmu").withRiscvRef()->loadHex("../raw/mmu/build/mmu.hex")->bootAt(0x80000000u)->run(50e3);); From 82c894932a577871e60acf7eb4809994ccb5df6b Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Fri, 5 Apr 2019 20:04:28 +0200 Subject: [PATCH 116/951] update todolist --- src/main/scala/vexriscv/demo/Linux.scala | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/scala/vexriscv/demo/Linux.scala b/src/main/scala/vexriscv/demo/Linux.scala index 1f6513de..96ace430 100644 --- a/src/main/scala/vexriscv/demo/Linux.scala +++ b/src/main/scala/vexriscv/demo/Linux.scala @@ -88,7 +88,6 @@ https://github.com/riscv/riscv-qemu/wiki#build-and-install */ -//TODO test dcache flush //TODO have to check, look like supervisor can't get interrupt if the machine mod didn't delegated it, have to check exactly //TODO IBus cached and uncached, do not allow supervisor if it's a user page ? io.cpu.fetch.mmuException object LinuxGen { From 9e72971ff0df45d79f9643d14db2bd611a4522c1 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Fri, 5 Apr 2019 21:34:44 +0200 Subject: [PATCH 117/951] Move user mode page fault checkes from iBus/dBus plugin into the MmuPlugin SUM was in fact already supported --- src/main/scala/vexriscv/Services.scala | 2 +- src/main/scala/vexriscv/demo/Linux.scala | 1 - src/main/scala/vexriscv/ip/DataCache.scala | 2 +- src/main/scala/vexriscv/ip/InstructionCache.scala | 4 ++-- src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala | 1 - src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala | 2 +- src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala | 1 - src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala | 2 +- src/main/scala/vexriscv/plugin/MemoryTranslatorPlugin.scala | 2 -- src/main/scala/vexriscv/plugin/MmuPlugin.scala | 4 +--- .../scala/vexriscv/plugin/StaticMemoryTranslatorPlugin.scala | 1 - 11 files changed, 7 insertions(+), 15 deletions(-) diff --git a/src/main/scala/vexriscv/Services.scala b/src/main/scala/vexriscv/Services.scala index 38a6b70f..666cb472 100644 --- a/src/main/scala/vexriscv/Services.scala +++ b/src/main/scala/vexriscv/Services.scala @@ -69,7 +69,7 @@ case class MemoryTranslatorCmd() extends Bundle{ case class MemoryTranslatorRsp() extends Bundle{ val physicalAddress = UInt(32 bits) val isIoAccess = Bool - val allowRead, allowWrite, allowExecute, allowUser = Bool + val allowRead, allowWrite, allowExecute = Bool val exception = Bool val refilling = Bool } diff --git a/src/main/scala/vexriscv/demo/Linux.scala b/src/main/scala/vexriscv/demo/Linux.scala index 96ace430..0d6fe551 100644 --- a/src/main/scala/vexriscv/demo/Linux.scala +++ b/src/main/scala/vexriscv/demo/Linux.scala @@ -89,7 +89,6 @@ https://github.com/riscv/riscv-qemu/wiki#build-and-install //TODO have to check, look like supervisor can't get interrupt if the machine mod didn't delegated it, have to check exactly -//TODO IBus cached and uncached, do not allow supervisor if it's a user page ? io.cpu.fetch.mmuException object LinuxGen { def configFull(litex : Boolean, withMmu : Boolean) = { val config = VexRiscvConfig( diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index d4d6f147..0932b54a 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -488,7 +488,7 @@ class DataCache(p : DataCacheConfig) extends Component{ io.cpu.redo := False io.cpu.writeBack.accessError := False - io.cpu.writeBack.mmuException := io.cpu.writeBack.isValid && (if(catchIllegal) mmuRsp.exception || (!mmuRsp.allowWrite && request.wr) || (!mmuRsp.allowRead && !request.wr) || (!mmuRsp.allowUser && io.cpu.writeBack.isUser) else False) + io.cpu.writeBack.mmuException := io.cpu.writeBack.isValid && (if(catchIllegal) mmuRsp.exception || (!mmuRsp.allowWrite && request.wr) || (!mmuRsp.allowRead && !request.wr) else False) io.cpu.writeBack.unalignedAccess := io.cpu.writeBack.isValid && (if(catchUnaligned) ((request.size === 2 && mmuRsp.physicalAddress(1 downto 0) =/= 0) || (request.size === 1 && mmuRsp.physicalAddress(0 downto 0) =/= 0)) else False) io.cpu.writeBack.isWrite := request.wr diff --git a/src/main/scala/vexriscv/ip/InstructionCache.scala b/src/main/scala/vexriscv/ip/InstructionCache.scala index b5b4e230..29df3afd 100644 --- a/src/main/scala/vexriscv/ip/InstructionCache.scala +++ b/src/main/scala/vexriscv/ip/InstructionCache.scala @@ -411,7 +411,7 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{ io.cpu.fetch.cacheMiss := !hit.valid io.cpu.fetch.error := hit.error io.cpu.fetch.mmuRefilling := mmuRsp.refilling - io.cpu.fetch.mmuException := !mmuRsp.refilling && (mmuRsp.exception || !mmuRsp.allowExecute || (!mmuRsp.allowUser && io.cpu.fetch.isUser)) + io.cpu.fetch.mmuException := !mmuRsp.refilling && (mmuRsp.exception || !mmuRsp.allowExecute) }) } @@ -441,7 +441,7 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{ io.cpu.decode.cacheMiss := !hit.valid io.cpu.decode.error := hit.error io.cpu.decode.mmuRefilling := mmuRsp.refilling - io.cpu.decode.mmuException := !mmuRsp.refilling && (mmuRsp.exception || !mmuRsp.allowExecute || (!mmuRsp.allowUser && io.cpu.decode.isUser)) + io.cpu.decode.mmuException := !mmuRsp.refilling && (mmuRsp.exception || !mmuRsp.allowExecute) io.cpu.decode.physicalAddress := mmuRsp.physicalAddress }) } diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index 530ba8a8..917d50d1 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -286,7 +286,6 @@ class DBusCachedPlugin(config : DataCacheConfig, mmuBus.cmd.bypassTranslation setWhen(memory.input(IS_DBUS_SHARING)) cache.io.cpu.memory.isValid setWhen(memory.input(IS_DBUS_SHARING)) - cache.io.cpu.memory.mmuBus.rsp.allowUser setWhen(memory.input(IS_DBUS_SHARING)) cache.io.cpu.writeBack.isValid setWhen(writeBack.input(IS_DBUS_SHARING)) dBusAccess.rsp.valid := writeBack.input(IS_DBUS_SHARING) && !cache.io.cpu.writeBack.isWrite && (cache.io.cpu.redo || !cache.io.cpu.writeBack.haltIt) dBusAccess.rsp.data := cache.io.cpu.writeBack.data diff --git a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala index a1ad3dd0..9e1de8cb 100644 --- a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala @@ -362,7 +362,7 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, dBus.cmd.address := mmuBus.rsp.physicalAddress //do not emit memory request if MMU refilling - insert(MMU_FAULT) := input(MMU_RSP).exception || (!input(MMU_RSP).allowWrite && input(MEMORY_STORE)) || (!input(MMU_RSP).allowRead && !input(MEMORY_STORE)) || (!input(MMU_RSP).allowUser && privilegeService.isUser()) + insert(MMU_FAULT) := input(MMU_RSP).exception || (!input(MMU_RSP).allowWrite && input(MEMORY_STORE)) || (!input(MMU_RSP).allowRead && !input(MEMORY_STORE)) skipCmd.setWhen(input(MMU_FAULT) || input(MMU_RSP).refilling) insert(MMU_RSP) := mmuBus.rsp diff --git a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala index e7256094..f55d92e6 100644 --- a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala @@ -236,7 +236,6 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l, 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.exception := False cache.io.cpu.fetch.mmuBus.rsp.refilling := False diff --git a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala index af77a89b..ddd3ff37 100644 --- a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala @@ -321,7 +321,7 @@ class IBusSimplePlugin(resetVector : BigInt, } if(memoryTranslatorPortConfig != null) { val privilegeService = pipeline.serviceElse(classOf[PrivilegeService], PrivilegeServiceDefault()) - when(stages.last.input.valid && !mmu.joinCtx.refilling && (mmu.joinCtx.exception || !mmu.joinCtx.allowExecute || (!mmu.joinCtx.allowUser && privilegeService.isUser()))){ + when(stages.last.input.valid && !mmu.joinCtx.refilling && (mmu.joinCtx.exception || !mmu.joinCtx.allowExecute)){ decodeExceptionPort.code := 12 exceptionDetected := True } diff --git a/src/main/scala/vexriscv/plugin/MemoryTranslatorPlugin.scala b/src/main/scala/vexriscv/plugin/MemoryTranslatorPlugin.scala index c5da539a..623d872e 100644 --- a/src/main/scala/vexriscv/plugin/MemoryTranslatorPlugin.scala +++ b/src/main/scala/vexriscv/plugin/MemoryTranslatorPlugin.scala @@ -112,7 +112,6 @@ class MemoryTranslatorPlugin(tlbSize : Int, port.bus.rsp.allowRead := cacheLine.allowRead port.bus.rsp.allowWrite := cacheLine.allowWrite port.bus.rsp.allowExecute := cacheLine.allowExecute - port.bus.rsp.allowUser := cacheLine.allowUser ??? // port.bus.rsp.hit := cacheHit // port.stage.arbitration.haltItself setWhen (port.bus.cmd.isValid && !cacheHit && !sharedMiss) @@ -121,7 +120,6 @@ class MemoryTranslatorPlugin(tlbSize : Int, port.bus.rsp.allowRead := True port.bus.rsp.allowWrite := True port.bus.rsp.allowExecute := True - port.bus.rsp.allowUser := True ??? // port.bus.rsp.hit := True } diff --git a/src/main/scala/vexriscv/plugin/MmuPlugin.scala b/src/main/scala/vexriscv/plugin/MmuPlugin.scala index 5d14978a..60fc94f0 100644 --- a/src/main/scala/vexriscv/plugin/MmuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/MmuPlugin.scala @@ -124,15 +124,13 @@ class MmuPlugin(ioRange : UInt => Bool, port.bus.rsp.allowRead := cacheLine.allowRead || csr.status.mxr && cacheLine.allowExecute port.bus.rsp.allowWrite := cacheLine.allowWrite port.bus.rsp.allowExecute := cacheLine.allowExecute - port.bus.rsp.allowUser := cacheLine.allowUser - port.bus.rsp.exception := cacheHit && (cacheLine.exception || cacheLine.allowUser && privilegeService.isSupervisor() && !csr.status.sum) + port.bus.rsp.exception := cacheHit && (cacheLine.exception || cacheLine.allowUser && privilegeService.isSupervisor() && !csr.status.sum || !cacheLine.allowUser && privilegeService.isUser()) port.bus.rsp.refilling := !cacheHit } otherwise { port.bus.rsp.physicalAddress := port.bus.cmd.virtualAddress port.bus.rsp.allowRead := True port.bus.rsp.allowWrite := True port.bus.rsp.allowExecute := True - port.bus.rsp.allowUser := True port.bus.rsp.exception := False port.bus.rsp.refilling := False } diff --git a/src/main/scala/vexriscv/plugin/StaticMemoryTranslatorPlugin.scala b/src/main/scala/vexriscv/plugin/StaticMemoryTranslatorPlugin.scala index a2a6bbc3..36db9e25 100644 --- a/src/main/scala/vexriscv/plugin/StaticMemoryTranslatorPlugin.scala +++ b/src/main/scala/vexriscv/plugin/StaticMemoryTranslatorPlugin.scala @@ -31,7 +31,6 @@ class StaticMemoryTranslatorPlugin(ioRange : UInt => Bool) extends Plugin[VexRis port.bus.rsp.allowRead := True port.bus.rsp.allowWrite := True port.bus.rsp.allowExecute := True - port.bus.rsp.allowUser := True port.bus.rsp.isIoAccess := ioRange(port.bus.rsp.physicalAddress) port.bus.rsp.exception := False port.bus.rsp.refilling := False From acaa931e1179c8aa45c20b0755ecde8bbb0560d2 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Fri, 5 Apr 2019 22:55:42 +0200 Subject: [PATCH 118/951] Rework CsrPlugin interrupt delegation --- .../scala/vexriscv/plugin/CsrPlugin.scala | 97 ++++++++----------- 1 file changed, 40 insertions(+), 57 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 3b45cca3..faec4ae6 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -314,21 +314,15 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception val csrMapping = new CsrMapping() + //Interruption specification data model + case class Delegator(var enable : Bool, privilege : Int) + case class InterruptSource(var cond : Bool, id : Int, privilege : Int, delegators : List[Delegator]) + var interruptSpecs = ArrayBuffer[InterruptSource]() - - case class InterruptSource(var cond : Bool, id : Int) - case class InterruptPrivilege(privilege : Int){ - var privilegeCond : Bool = null - val sources = ArrayBuffer[InterruptSource]() + def addInterrupt(cond : Bool, id : Int, privilege : Int, delegators : List[Delegator]): Unit = { + interruptSpecs += InterruptSource(cond, id, privilege, delegators) } - def getInterruptPrivilege(privilege : Int) = customInterrupts.getOrElseUpdate(privilege, InterruptPrivilege(privilege)) - var customInterrupts = mutable.LinkedHashMap[Int, InterruptPrivilege]() - def addInterrupt(cond : Bool, id : Int, privilege : Int): Unit = { - getInterruptPrivilege(privilege).sources += InterruptSource(cond, id) - } - def createInterrupt(id : Int, privilege : Int) : Bool = { val ret = Bool(); addInterrupt(ret, id, privilege); ret} - override def r(csrAddress: Int, bitOffset: Int, that: Data): Unit = csrMapping.r(csrAddress, bitOffset, that) override def w(csrAddress: Int, bitOffset: Int, that: Data): Unit = csrMapping.w(csrAddress, bitOffset, that) override def r2w(csrAddress: Int, bitOffset: Int, that: Data): Unit = csrMapping.r2w(csrAddress, bitOffset, that) @@ -399,10 +393,8 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception allowInterrupts = True allowException = True - for (privilege <- customInterrupts.values; - source <- privilege.sources){ - source.cond = source.cond.pull() - } + for (i <- interruptSpecs) i.cond = i.cond.pull() + pipeline.update(MPP, UInt(2 bits)) } @@ -474,7 +466,9 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception val medeleg = Reg(Bits(32 bits)) init(0) - val mideleg = Reg(Bits(32 bits)) init(0) + val mideleg = supervisorGen generate new Area { + val ST, SE, SS = RegInit(False) + } if(mvendorid != null) READ_ONLY(CSR.MVENDORID, U(mvendorid)) if(marchid != null) READ_ONLY(CSR.MARCHID , U(marchid )) @@ -498,8 +492,10 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception minstretAccess(CSR.MINSTRET, minstret(31 downto 0)) minstretAccess(CSR.MINSTRETH, minstret(63 downto 32)) - medelegAccess(CSR.MEDELEG, medeleg) - midelegAccess(CSR.MIDELEG, mideleg) + if(supervisorGen) { + medelegAccess(CSR.MEDELEG, medeleg) + midelegAccess(CSR.MIDELEG, 9 -> mideleg.SE, 5 -> mideleg.ST, 1 -> mideleg.SS) + } //User CSR ucycleAccess(CSR.UCYCLE, mcycle(31 downto 0)) @@ -579,20 +575,14 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception if(supervisorGen) { - getInterruptPrivilege(1).privilegeCond = (sstatus.SIE && privilege === "01") || privilege === "00" - getInterruptPrivilege(1).sources ++= List( - InterruptSource(sip.STIP && sie.STIE, 5), - InterruptSource(sip.SSIP && sie.SSIE, 1), - InterruptSource(sip.SEIP_OR && sie.SEIE, 9) - ) + addInterrupt(sip.STIP && sie.STIE, id = 5, privilege = 1, delegators = List(Delegator(mideleg.ST, 3))) + addInterrupt(sip.SSIP && sie.SSIE, id = 1, privilege = 1, delegators = List(Delegator(mideleg.SS, 3))) + addInterrupt(sip.SEIP_OR && sie.SEIE, id = 9, privilege = 1, delegators = List(Delegator(mideleg.SE, 3))) } - getInterruptPrivilege(3).privilegeCond = mstatus.MIE || privilege =/= "11" - getInterruptPrivilege(3).sources ++= List( - InterruptSource(mip.MTIP && mie.MTIE, 7), - InterruptSource(mip.MSIP && mie.MSIE, 3), - InterruptSource(mip.MEIP && mie.MEIE, 11) - ) + addInterrupt(mip.MTIP && mie.MTIE, id = 7, privilege = 3, delegators = Nil) + addInterrupt(mip.MSIP && mie.MSIE, id = 3, privilege = 3, delegators = Nil) + addInterrupt(mip.MEIP && mie.MEIE, id = 11, privilege = 3, delegators = Nil) case class DelegatorModel(value : Bits, source : Int, target : Int) // def solveDelegators(delegators : Seq[DelegatorModel], id : Int, lowerBound : Int): UInt = { @@ -626,9 +616,6 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception // ret.max(lowerBound) } - val interruptDelegators = ArrayBuffer[DelegatorModel]() - if(midelegAccess.canWrite) interruptDelegators += DelegatorModel(mideleg,3, 1) - val exceptionDelegators = ArrayBuffer[DelegatorModel]() if(medelegAccess.canWrite) exceptionDelegators += DelegatorModel(medeleg,3, 1) @@ -703,32 +690,28 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception //Process interrupt request, code and privilege val interrupt = False val interruptCode = UInt(4 bits).assignDontCare().addTag(Verilator.public) - val interruptDelegatorHit = interruptDelegators.map(d => (d -> False)).toMap - for(model <- customInterrupts.values.toSeq.sortBy(_.privilege)){ - when(model.privilegeCond){ - when(model.sources.map(_.cond).orR){ - interrupt := True - } - for(source <- model.sources){ - when(source.cond){ - interruptCode := source.id - for(interruptDelegator <- interruptDelegators){ - interruptDelegatorHit(interruptDelegator) := (if(interruptDelegator.target < model.privilege){ - False - } else { - interruptDelegator.value(source.id) - }) - } + val privilegeAllowInterrupts = mutable.HashMap( + 1 -> ((sstatus.SIE && privilege === "01") || privilege < "01"), + 3 -> (mstatus.MIE || privilege < "11") + ) + var interruptPrivilegs = if (supervisorGen) List(1, 3) else List(3) + val interruptTargetPrivilege = UInt(2 bits).assignDontCare() + while(interruptPrivilegs.nonEmpty){ + val p = interruptPrivilegs.head + when(privilegeAllowInterrupts(p)){ + for(i <- interruptSpecs + if i.privilege <= p //EX : Machine timer interrupt can't go into supervisor mode + if interruptPrivilegs.tail.forall(e => i.delegators.exists(_.privilege == e))){ // EX : Supervisor timer need to have machine mode delegator + val delegUpOn = i.delegators.filter(_.privilege > p).map(_.enable).fold(True)(_ && _) + val delegDownOff = !i.delegators.filter(_.privilege <= p).map(_.enable).orR + when(i.cond && delegUpOn && delegDownOff){ + interrupt := True + interruptCode := i.id + interruptTargetPrivilege := p } } } - } - - val interruptTargetPrivilege = U(if(interruptDelegators.isEmpty) 3 else interruptDelegators.last.target, 2 bits) - for(interruptDelegator <- interruptDelegators){ - when(!interruptDelegatorHit(interruptDelegator)){ - interruptTargetPrivilege := interruptDelegator.source - } + interruptPrivilegs = interruptPrivilegs.tail } interrupt.clearWhen(!allowInterrupts) From ddf0f0683424d8d0fe7efff735ed3f5ea65f63bc Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Fri, 5 Apr 2019 22:56:12 +0200 Subject: [PATCH 119/951] Add more delegation tests Reduce dcache test duration --- src/test/cpp/raw/dcache/build/dcache.asm | 12 +- src/test/cpp/raw/dcache/build/dcache.hex | 4 +- src/test/cpp/raw/dcache/src/crt.S | 12 +- src/test/cpp/raw/deleg/build/deleg.asm | 226 +++++++++++++---------- src/test/cpp/raw/deleg/build/deleg.hex | 84 +++++---- src/test/cpp/raw/deleg/src/crt.S | 25 +++ 6 files changed, 217 insertions(+), 146 deletions(-) diff --git a/src/test/cpp/raw/dcache/build/dcache.asm b/src/test/cpp/raw/dcache/build/dcache.asm index 698e5dc3..9bc434d1 100644 --- a/src/test/cpp/raw/dcache/build/dcache.asm +++ b/src/test/cpp/raw/dcache/build/dcache.asm @@ -32,9 +32,9 @@ Disassembly of section .crt_section: 80000048: 0000a023 sw zero,0(ra) # f5670000 8000004c: 00012203 lw tp,0(sp) 80000050: 06429463 bne t0,tp,800000b8 -80000054: fff30313 addi t1,t1,-1 -80000058: 00408093 addi ra,ra,4 -8000005c: 00410113 addi sp,sp,4 +80000054: ffc30313 addi t1,t1,-4 +80000058: 01008093 addi ra,ra,16 +8000005c: 01010113 addi sp,sp,16 80000060: 0000500f 0x500f 80000064: fc0316e3 bnez t1,80000030 @@ -56,9 +56,9 @@ Disassembly of section .crt_section: 80000098: 0000500f 0x500f 8000009c: 00012203 lw tp,0(sp) 800000a0: 00429c63 bne t0,tp,800000b8 -800000a4: fff30313 addi t1,t1,-1 -800000a8: 00408093 addi ra,ra,4 -800000ac: 00410113 addi sp,sp,4 +800000a4: ffc30313 addi t1,t1,-4 +800000a8: 01008093 addi ra,ra,16 +800000ac: 01010113 addi sp,sp,16 800000b0: fc0314e3 bnez t1,80000078 800000b4: 0100006f j 800000c4 diff --git a/src/test/cpp/raw/dcache/build/dcache.hex b/src/test/cpp/raw/dcache/build/dcache.hex index 6e9ef5db..9cbd4458 100644 --- a/src/test/cpp/raw/dcache/build/dcache.hex +++ b/src/test/cpp/raw/dcache/build/dcache.hex @@ -4,12 +4,12 @@ :10002000130E2000B70067F537F10F90130300405F :100030009301100093022000B3036300B3817100A9 :10004000B38272002320310023A0000003220100AC -:10005000639442061303F3FF9380400013014100B1 +:10005000639442061303C3FF93800001130101015F :100060000F500000E31603FC130E3000B70067F5D5 :1000700037F10F90130300409301200093023000EA :10008000B3036300B3817100B382720003220100E5 :100090002320310023A000000F50000003220100A4 -:1000A000639C42001303F3FF93804000130141005F +:1000A000639C42001303C3FF93800001130101010D :1000B000E31403FC6F000001370110F0130141F25B :1000C0002320C101370110F0130101F223200100A8 :1000D00013000000130000001300000013000000D4 diff --git a/src/test/cpp/raw/dcache/src/crt.S b/src/test/cpp/raw/dcache/src/crt.S index 8476c09e..b5606946 100644 --- a/src/test/cpp/raw/dcache/src/crt.S +++ b/src/test/cpp/raw/dcache/src/crt.S @@ -27,9 +27,9 @@ test2_repeat: sw x0, 0(x1) lw x4, 0(x2) bne x5,x4, fail - addi x6, x6, -1 - addi x1, x1, 4 - addi x2, x2, 4 + addi x6, x6, -4 + addi x1, x1, 16 + addi x2, x2, 16 .word 0x000500F // dcache flush bnez x6, test2_repeat @@ -50,9 +50,9 @@ test3_repeat: .word 0x000500F // dcache flush lw x4, 0(x2) bne x5,x4, fail - addi x6, x6, -1 - addi x1, x1, 4 - addi x2, x2, 4 + addi x6, x6, -4 + addi x1, x1, 16 + addi x2, x2, 16 bnez x6, test3_repeat diff --git a/src/test/cpp/raw/deleg/build/deleg.asm b/src/test/cpp/raw/deleg/build/deleg.asm index 4084d8cf..9e3098f2 100644 --- a/src/test/cpp/raw/deleg/build/deleg.asm +++ b/src/test/cpp/raw/deleg/build/deleg.asm @@ -7,14 +7,14 @@ Disassembly of section .crt_section: 80000000 <_start>: 80000000: 00100e93 li t4,1 80000004: 00000097 auipc ra,0x0 -80000008: 68408093 addi ra,ra,1668 # 80000688 +80000008: 6fc08093 addi ra,ra,1788 # 80000700 8000000c: 30509073 csrw mtvec,ra 80000010: 00000097 auipc ra,0x0 -80000014: 6b008093 addi ra,ra,1712 # 800006c0 +80000014: 72808093 addi ra,ra,1832 # 80000738 80000018: 10509073 csrw stvec,ra 8000001c: f00110b7 lui ra,0xf0011 80000020: 00000113 li sp,0 -80000024: 0020a023 sw sp,0(ra) # f0011000 +80000024: 0020a023 sw sp,0(ra) # f0011000 80000028 : 80000028: 00100e13 li t3,1 @@ -33,18 +33,18 @@ Disassembly of section .crt_section: 80000054: 01408093 addi ra,ra,20 # 80000064 80000058: 34109073 csrw mepc,ra 8000005c: 30200073 mret -80000060: 6100006f j 80000670 +80000060: 6880006f j 800006e8 80000064: 00000f17 auipc t5,0x0 80000068: 024f0f13 addi t5,t5,36 # 80000088 8000006c: 00000073 ecall -80000070: 6000006f j 80000670 +80000070: 6780006f j 800006e8 80000074 : 80000074: 00300e13 li t3,3 80000078: 00000f17 auipc t5,0x0 8000007c: 010f0f13 addi t5,t5,16 # 80000088 80000080: 00102083 lw ra,1(zero) # 1 <_start-0x7fffffff> -80000084: 5ec0006f j 80000670 +80000084: 6640006f j 800006e8 80000088 : 80000088: 00400e13 li t3,4 @@ -58,11 +58,11 @@ Disassembly of section .crt_section: 800000a8: 01408093 addi ra,ra,20 # 800000b8 800000ac: 34109073 csrw mepc,ra 800000b0: 30200073 mret -800000b4: 5bc0006f j 80000670 +800000b4: 6340006f j 800006e8 800000b8: 00000f17 auipc t5,0x0 800000bc: 010f0f13 addi t5,t5,16 # 800000c8 800000c0: 00102083 lw ra,1(zero) # 1 <_start-0x7fffffff> -800000c4: 5ac0006f j 80000670 +800000c4: 6240006f j 800006e8 800000c8 : 800000c8: 00500e13 li t3,5 @@ -75,11 +75,11 @@ Disassembly of section .crt_section: 800000e4: 01408093 addi ra,ra,20 # 800000f4 800000e8: 34109073 csrw mepc,ra 800000ec: 30200073 mret -800000f0: 5800006f j 80000670 +800000f0: 5f80006f j 800006e8 800000f4: 00000f17 auipc t5,0x0 800000f8: 010f0f13 addi t5,t5,16 # 80000104 800000fc: 00102083 lw ra,1(zero) # 1 <_start-0x7fffffff> -80000100: 5700006f j 80000670 +80000100: 5e80006f j 800006e8 80000104 : 80000104: 00600e13 li t3,6 @@ -91,7 +91,7 @@ Disassembly of section .crt_section: 80000114: 00000f17 auipc t5,0x0 80000118: 010f0f13 addi t5,t5,16 # 80000124 8000011c: 00102083 lw ra,1(zero) # 1 <_start-0x7fffffff> -80000120: 5500006f j 80000670 +80000120: 5c80006f j 800006e8 80000124 : 80000124: 00800e13 li t3,8 @@ -107,9 +107,9 @@ Disassembly of section .crt_section: 8000014c: 01408093 addi ra,ra,20 # 8000015c 80000150: 34109073 csrw mepc,ra 80000154: 30200073 mret -80000158: 5180006f j 80000670 +80000158: 5900006f j 800006e8 8000015c: 00102083 lw ra,1(zero) # 1 <_start-0x7fffffff> -80000160: 5100006f j 80000670 +80000160: 5880006f j 800006e8 80000164 : 80000164: 00900e13 li t3,9 @@ -124,9 +124,9 @@ Disassembly of section .crt_section: 80000188: 01408093 addi ra,ra,20 # 80000198 8000018c: 34109073 csrw mepc,ra 80000190: 30200073 mret -80000194: 4dc0006f j 80000670 +80000194: 5540006f j 800006e8 80000198: 00102083 lw ra,1(zero) # 1 <_start-0x7fffffff> -8000019c: 4d40006f j 80000670 +8000019c: 54c0006f j 800006e8 800001a0 : 800001a0: 00a00e13 li t3,10 @@ -134,7 +134,7 @@ Disassembly of section .crt_section: 800001a8: 03cf0f13 addi t5,t5,60 # 800001e0 800001ac: f00110b7 lui ra,0xf0011 800001b0: 00000113 li sp,0 -800001b4: 0020a023 sw sp,0(ra) # f0011000 +800001b4: 0020a023 sw sp,0(ra) # f0011000 800001b8: 00800093 li ra,8 800001bc: 30009073 csrw mstatus,ra 800001c0: 000010b7 lui ra,0x1 @@ -142,9 +142,9 @@ Disassembly of section .crt_section: 800001c8: 30409073 csrw mie,ra 800001cc: f00110b7 lui ra,0xf0011 800001d0: 00100113 li sp,1 -800001d4: 0020a023 sw sp,0(ra) # f0011000 +800001d4: 0020a023 sw sp,0(ra) # f0011000 800001d8: 10500073 wfi -800001dc: 4940006f j 80000670 +800001dc: 50c0006f j 800006e8 800001e0 : 800001e0: 00b00e13 li t3,11 @@ -152,7 +152,7 @@ Disassembly of section .crt_section: 800001e8: 068f0f13 addi t5,t5,104 # 8000024c 800001ec: f00110b7 lui ra,0xf0011 800001f0: 00000113 li sp,0 -800001f4: 0020a023 sw sp,0(ra) # f0011000 +800001f4: 0020a023 sw sp,0(ra) # f0011000 800001f8: 00800093 li ra,8 800001fc: 30009073 csrw mstatus,ra 80000200: 000010b7 lui ra,0x1 @@ -168,12 +168,12 @@ Disassembly of section .crt_section: 80000228: 01408093 addi ra,ra,20 # 80000238 8000022c: 34109073 csrw mepc,ra 80000230: 30200073 mret -80000234: 43c0006f j 80000670 +80000234: 4b40006f j 800006e8 80000238: f00110b7 lui ra,0xf0011 8000023c: 00100113 li sp,1 -80000240: 0020a023 sw sp,0(ra) # f0011000 +80000240: 0020a023 sw sp,0(ra) # f0011000 80000244: 10500073 wfi -80000248: 4280006f j 80000670 +80000248: 4a00006f j 800006e8 8000024c : 8000024c: 00c00e13 li t3,12 @@ -181,7 +181,7 @@ Disassembly of section .crt_section: 80000254: 064f0f13 addi t5,t5,100 # 800002b4 80000258: f00110b7 lui ra,0xf0011 8000025c: 00000113 li sp,0 -80000260: 0020a023 sw sp,0(ra) # f0011000 +80000260: 0020a023 sw sp,0(ra) # f0011000 80000264: 00800093 li ra,8 80000268: 30009073 csrw mstatus,ra 8000026c: 000010b7 lui ra,0x1 @@ -196,12 +196,12 @@ Disassembly of section .crt_section: 80000290: 01408093 addi ra,ra,20 # 800002a0 80000294: 34109073 csrw mepc,ra 80000298: 30200073 mret -8000029c: 3d40006f j 80000670 +8000029c: 44c0006f j 800006e8 800002a0: f00110b7 lui ra,0xf0011 800002a4: 00100113 li sp,1 -800002a8: 0020a023 sw sp,0(ra) # f0011000 +800002a8: 0020a023 sw sp,0(ra) # f0011000 800002ac: 10500073 wfi -800002b0: 3c00006f j 80000670 +800002b0: 4380006f j 800006e8 800002b4 : 800002b4: 00200093 li ra,2 @@ -211,7 +211,7 @@ Disassembly of section .crt_section: 800002c4: 040f0f13 addi t5,t5,64 # 80000300 800002c8: f00120b7 lui ra,0xf0012 800002cc: 00000113 li sp,0 -800002d0: 0020a023 sw sp,0(ra) # f0012000 +800002d0: 0020a023 sw sp,0(ra) # f0012000 800002d4: 00200093 li ra,2 800002d8: 30009073 csrw mstatus,ra 800002dc: 20000093 li ra,512 @@ -219,7 +219,7 @@ Disassembly of section .crt_section: 800002e4: 00000e93 li t4,0 800002e8: f00120b7 lui ra,0xf0012 800002ec: 00100113 li sp,1 -800002f0: 0020a023 sw sp,0(ra) # f0012000 +800002f0: 0020a023 sw sp,0(ra) # f0012000 800002f4: 06400093 li ra,100 800002f8: fff08093 addi ra,ra,-1 800002fc: fe104ee3 bgtz ra,800002f8 @@ -230,7 +230,7 @@ Disassembly of section .crt_section: 80000308: 068f0f13 addi t5,t5,104 # 8000036c 8000030c: f00120b7 lui ra,0xf0012 80000310: 00000113 li sp,0 -80000314: 0020a023 sw sp,0(ra) # f0012000 +80000314: 0020a023 sw sp,0(ra) # f0012000 80000318: 00200093 li ra,2 8000031c: 30009073 csrw mstatus,ra 80000320: 20000093 li ra,512 @@ -245,13 +245,13 @@ Disassembly of section .crt_section: 80000344: 01408093 addi ra,ra,20 # 80000354 80000348: 34109073 csrw mepc,ra 8000034c: 30200073 mret -80000350: 3200006f j 80000670 +80000350: 3980006f j 800006e8 80000354: 00100e93 li t4,1 80000358: f00120b7 lui ra,0xf0012 8000035c: 00100113 li sp,1 -80000360: 0020a023 sw sp,0(ra) # f0012000 +80000360: 0020a023 sw sp,0(ra) # f0012000 80000364: 10500073 wfi -80000368: 3080006f j 80000670 +80000368: 3800006f j 800006e8 8000036c : 8000036c: 01000e13 li t3,16 @@ -259,7 +259,7 @@ Disassembly of section .crt_section: 80000374: 060f0f13 addi t5,t5,96 # 800003d0 80000378: f00120b7 lui ra,0xf0012 8000037c: 00000113 li sp,0 -80000380: 0020a023 sw sp,0(ra) # f0012000 +80000380: 0020a023 sw sp,0(ra) # f0012000 80000384: 00200093 li ra,2 80000388: 30009073 csrw mstatus,ra 8000038c: 20000093 li ra,512 @@ -273,12 +273,12 @@ Disassembly of section .crt_section: 800003ac: 01408093 addi ra,ra,20 # 800003bc 800003b0: 34109073 csrw mepc,ra 800003b4: 30200073 mret -800003b8: 2b80006f j 80000670 +800003b8: 3300006f j 800006e8 800003bc: f00120b7 lui ra,0xf0012 800003c0: 00100113 li sp,1 -800003c4: 0020a023 sw sp,0(ra) # f0012000 +800003c4: 0020a023 sw sp,0(ra) # f0012000 800003c8: 10500073 wfi -800003cc: 2a40006f j 80000670 +800003cc: 31c0006f j 800006e8 800003d0 : 800003d0: 01100e13 li t3,17 @@ -288,7 +288,7 @@ Disassembly of section .crt_section: 800003e0: 040f0f13 addi t5,t5,64 # 8000041c 800003e4: f00120b7 lui ra,0xf0012 800003e8: 00000113 li sp,0 -800003ec: 0020a023 sw sp,0(ra) # f0012000 +800003ec: 0020a023 sw sp,0(ra) # f0012000 800003f0: 00200093 li ra,2 800003f4: 30009073 csrw mstatus,ra 800003f8: 20000093 li ra,512 @@ -296,7 +296,7 @@ Disassembly of section .crt_section: 80000400: 00000e93 li t4,0 80000404: f00120b7 lui ra,0xf0012 80000408: 00100113 li sp,1 -8000040c: 0020a023 sw sp,0(ra) # f0012000 +8000040c: 0020a023 sw sp,0(ra) # f0012000 80000410: 06400093 li ra,100 80000414: fff08093 addi ra,ra,-1 80000418: fe104ee3 bgtz ra,80000414 @@ -307,7 +307,7 @@ Disassembly of section .crt_section: 80000424: 068f0f13 addi t5,t5,104 # 80000488 80000428: f00120b7 lui ra,0xf0012 8000042c: 00000113 li sp,0 -80000430: 0020a023 sw sp,0(ra) # f0012000 +80000430: 0020a023 sw sp,0(ra) # f0012000 80000434: 00200093 li ra,2 80000438: 30009073 csrw mstatus,ra 8000043c: 20000093 li ra,512 @@ -322,13 +322,13 @@ Disassembly of section .crt_section: 80000460: 01408093 addi ra,ra,20 # 80000470 80000464: 34109073 csrw mepc,ra 80000468: 30200073 mret -8000046c: 2040006f j 80000670 +8000046c: 27c0006f j 800006e8 80000470: 00100e93 li t4,1 80000474: f00120b7 lui ra,0xf0012 80000478: 00100113 li sp,1 -8000047c: 0020a023 sw sp,0(ra) # f0012000 +8000047c: 0020a023 sw sp,0(ra) # f0012000 80000480: 10500073 wfi -80000484: 1ec0006f j 80000670 +80000484: 2640006f j 800006e8 80000488 : 80000488: 01300e13 li t3,19 @@ -336,7 +336,7 @@ Disassembly of section .crt_section: 80000490: 060f0f13 addi t5,t5,96 # 800004ec 80000494: f00120b7 lui ra,0xf0012 80000498: 00000113 li sp,0 -8000049c: 0020a023 sw sp,0(ra) # f0012000 +8000049c: 0020a023 sw sp,0(ra) # f0012000 800004a0: 00200093 li ra,2 800004a4: 30009073 csrw mstatus,ra 800004a8: 20000093 li ra,512 @@ -350,17 +350,17 @@ Disassembly of section .crt_section: 800004c8: 01408093 addi ra,ra,20 # 800004d8 800004cc: 34109073 csrw mepc,ra 800004d0: 30200073 mret -800004d4: 19c0006f j 80000670 +800004d4: 2140006f j 800006e8 800004d8: f00120b7 lui ra,0xf0012 800004dc: 00100113 li sp,1 -800004e0: 0020a023 sw sp,0(ra) # f0012000 +800004e0: 0020a023 sw sp,0(ra) # f0012000 800004e4: 10500073 wfi -800004e8: 1880006f j 80000670 +800004e8: 2000006f j 800006e8 800004ec : 800004ec: f00120b7 lui ra,0xf0012 800004f0: 00000113 li sp,0 -800004f4: 0020a023 sw sp,0(ra) # f0012000 +800004f4: 0020a023 sw sp,0(ra) # f0012000 800004f8: 01400e13 li t3,20 800004fc: 00000f17 auipc t5,0x0 80000500: 030f0f13 addi t5,t5,48 # 8000052c @@ -395,12 +395,12 @@ Disassembly of section .crt_section: 8000056c: 01408093 addi ra,ra,20 # 8000057c 80000570: 34109073 csrw mepc,ra 80000574: 30200073 mret -80000578: 0f80006f j 80000670 +80000578: 1700006f j 800006e8 8000057c: 00100e93 li t4,1 80000580: 20000093 li ra,512 80000584: 1440a073 csrs sip,ra 80000588: 10500073 wfi -8000058c: 0e40006f j 80000670 +8000058c: 15c0006f j 800006e8 80000590 : 80000590: 01600e13 li t3,22 @@ -423,81 +423,119 @@ Disassembly of section .crt_section: 800005d4: 01408093 addi ra,ra,20 # 800005e4 800005d8: 34109073 csrw mepc,ra 800005dc: 30200073 mret -800005e0: 0900006f j 80000670 +800005e0: 1080006f j 800006e8 800005e4: 10500073 wfi -800005e8: 0880006f j 80000670 +800005e8: 1000006f j 800006e8 800005ec : 800005ec: 01700e13 li t3,23 800005f0: 00000e93 li t4,0 800005f4: f00120b7 lui ra,0xf0012 800005f8: 00000113 li sp,0 -800005fc: 0020a023 sw sp,0(ra) # f0012000 +800005fc: 0020a023 sw sp,0(ra) # f0012000 80000600: 20000093 li ra,512 80000604: 1440b073 csrc sip,ra 80000608: 344021f3 csrr gp,mip 8000060c: f00120b7 lui ra,0xf0012 80000610: 00100113 li sp,1 -80000614: 0020a023 sw sp,0(ra) # f0012000 +80000614: 0020a023 sw sp,0(ra) # f0012000 80000618: 20000093 li ra,512 8000061c: 1440b073 csrc sip,ra 80000620: 344021f3 csrr gp,mip 80000624: f00120b7 lui ra,0xf0012 80000628: 00000113 li sp,0 -8000062c: 0020a023 sw sp,0(ra) # f0012000 +8000062c: 0020a023 sw sp,0(ra) # f0012000 80000630: 20000093 li ra,512 80000634: 1440b073 csrc sip,ra 80000638: 344021f3 csrr gp,mip 8000063c: f00120b7 lui ra,0xf0012 80000640: 00000113 li sp,0 -80000644: 0020a023 sw sp,0(ra) # f0012000 +80000644: 0020a023 sw sp,0(ra) # f0012000 80000648: 20000093 li ra,512 8000064c: 1440a073 csrs sip,ra 80000650: 344021f3 csrr gp,mip 80000654: f00120b7 lui ra,0xf0012 80000658: 00100113 li sp,1 -8000065c: 0020a023 sw sp,0(ra) # f0012000 +8000065c: 0020a023 sw sp,0(ra) # f0012000 80000660: 20000093 li ra,512 80000664: 1440a073 csrs sip,ra 80000668: 344021f3 csrr gp,mip -8000066c: 0100006f j 8000067c +8000066c: f00120b7 lui ra,0xf0012 +80000670: 00000113 li sp,0 +80000674: 0020a023 sw sp,0(ra) # f0012000 -80000670 : -80000670: f0100137 lui sp,0xf0100 -80000674: f2410113 addi sp,sp,-220 # f00fff24 -80000678: 01c12023 sw t3,0(sp) - -8000067c : -8000067c: f0100137 lui sp,0xf0100 -80000680: f2010113 addi sp,sp,-224 # f00fff20 -80000684: 00012023 sw zero,0(sp) - -80000688 : -80000688: fe0e84e3 beqz t4,80000670 -8000068c: 342020f3 csrr ra,mcause -80000690: 341020f3 csrr ra,mepc -80000694: 300020f3 csrr ra,mstatus -80000698: 343020f3 csrr ra,mbadaddr -8000069c: 08000093 li ra,128 -800006a0: 3000b073 csrc mstatus,ra -800006a4: 00200093 li ra,2 -800006a8: fc1e8ae3 beq t4,ra,8000067c -800006ac: 000020b7 lui ra,0x2 -800006b0: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800> -800006b4: 3000a073 csrs mstatus,ra -800006b8: 341f1073 csrw mepc,t5 +80000678 : +80000678: 01800e13 li t3,24 +8000067c: 00200093 li ra,2 +80000680: 3040a073 csrs mie,ra +80000684: 3440a073 csrs mip,ra +80000688: 3000a073 csrs mstatus,ra +8000068c: 00100e93 li t4,1 +80000690: 00000f17 auipc t5,0x0 +80000694: 03cf0f13 addi t5,t5,60 # 800006cc +80000698: 000020b7 lui ra,0x2 +8000069c: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800> +800006a0: 00001137 lui sp,0x1 +800006a4: 80010113 addi sp,sp,-2048 # 800 <_start-0x7ffff800> +800006a8: 3000b073 csrc mstatus,ra +800006ac: 30012073 csrs mstatus,sp +800006b0: 00000097 auipc ra,0x0 +800006b4: 01408093 addi ra,ra,20 # 800006c4 +800006b8: 34109073 csrw mepc,ra 800006bc: 30200073 mret +800006c0: 0280006f j 800006e8 -800006c0 : -800006c0: fa0e88e3 beqz t4,80000670 -800006c4: 142020f3 csrr ra,scause -800006c8: 141020f3 csrr ra,sepc -800006cc: 100020f3 csrr ra,sstatus -800006d0: 143020f3 csrr ra,sbadaddr -800006d4: 00000073 ecall -800006d8: 00000013 nop -800006dc: 00000013 nop -800006e0: 00000013 nop -800006e4: 00000013 nop -800006e8: 00000013 nop -800006ec: 00000013 nop +800006c4 : +800006c4: 10500073 wfi +800006c8: 0200006f j 800006e8 + +800006cc : +800006cc: 01900e13 li t3,25 +800006d0: 00000f17 auipc t5,0x0 +800006d4: 014f0f13 addi t5,t5,20 # 800006e4 +800006d8: 30046073 csrsi mstatus,8 +800006dc: 10500073 wfi +800006e0: 0080006f j 800006e8 + +800006e4 : +800006e4: 0100006f j 800006f4 + +800006e8 : +800006e8: f0100137 lui sp,0xf0100 +800006ec: f2410113 addi sp,sp,-220 # f00fff24 +800006f0: 01c12023 sw t3,0(sp) + +800006f4 : +800006f4: f0100137 lui sp,0xf0100 +800006f8: f2010113 addi sp,sp,-224 # f00fff20 +800006fc: 00012023 sw zero,0(sp) + +80000700 : +80000700: fe0e84e3 beqz t4,800006e8 +80000704: 342020f3 csrr ra,mcause +80000708: 341020f3 csrr ra,mepc +8000070c: 300020f3 csrr ra,mstatus +80000710: 343020f3 csrr ra,mtval +80000714: 08000093 li ra,128 +80000718: 3000b073 csrc mstatus,ra +8000071c: 00200093 li ra,2 +80000720: fc1e8ae3 beq t4,ra,800006f4 +80000724: 000020b7 lui ra,0x2 +80000728: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800> +8000072c: 3000a073 csrs mstatus,ra +80000730: 341f1073 csrw mepc,t5 +80000734: 30200073 mret + +80000738 : +80000738: fa0e88e3 beqz t4,800006e8 +8000073c: 142020f3 csrr ra,scause +80000740: 141020f3 csrr ra,sepc +80000744: 100020f3 csrr ra,sstatus +80000748: 143020f3 csrr ra,stval +8000074c: 00000073 ecall +80000750: 00000013 nop +80000754: 00000013 nop +80000758: 00000013 nop +8000075c: 00000013 nop +80000760: 00000013 nop +80000764: 00000013 nop diff --git a/src/test/cpp/raw/deleg/build/deleg.hex b/src/test/cpp/raw/deleg/build/deleg.hex index eff4ff20..ba5fc068 100644 --- a/src/test/cpp/raw/deleg/build/deleg.hex +++ b/src/test/cpp/raw/deleg/build/deleg.hex @@ -1,48 +1,48 @@ :0200000480007A -:10000000930E10009700000093804068739050306A -:10001000970000009380006B73905010B71001F0B0 +:10000000930E1000970000009380C06F73905030E3 +:10001000970000009380807273905010B71001F029 :100020001301000023A02000130E1000170F000082 :10003000130FCF0073000000130E2000B720000044 :10004000938000801301000073B0003073200130F2 :1000500097000000938040017390103473002030AB -:100060006F000061170F0000130F4F0273000000B4 -:100070006F000060130E3000170F0000130F0F0108 -:10008000832010006F00C05E130E4000B7200000F8 +:100060006F008068170F0000130F4F02730000002D +:100070006F008067130E3000170F0000130F0F0181 +:10008000832010006F004066130E4000B720000070 :1000900093800080371100001301018073B000309D :1000A000732001309700000093804001739010345A -:1000B000730020306F00C05B170F0000130F0F019B -:1000C000832010006F00C05A130E5000B7200000AC +:1000B000730020306F004063170F0000130F0F0113 +:1000C000832010006F004062130E5000B720000024 :1000D000938000801301000073B000307320013062 :1000E000970000009380400173901034730020301B -:1000F0006F000058170F0000130F0F01832010002E -:100100006F000057130E60009300000173902030C1 +:1000F0006F00805F170F0000130F0F0183201000A7 +:100100006F00805E130E600093000001739020303A :10011000130E7000170F0000130F0F018320100043 -:100120006F000055130E8000170F0000130FCF0350 +:100120006F00805C130E8000170F0000130FCF03C9 :10013000B720000093800080371100001301018078 :1001400073B00030732001309700000093804001AD -:1001500073901034730020306F00805183201000A2 -:100160006F000051130E9000170F0000130F8F0344 +:1001500073901034730020306F000059832010001A +:100160006F008058130E9000170F0000130F8F03BD :10017000B7200000938000801301000073B00030AE :100180007320013097000000938040017390103479 -:10019000730020306F00C04D832010006F00404D71 +:10019000730020306F004055832010006F00C05462 :1001A000130EA000170F0000130FCF03B71001F0BC :1001B0001301000023A02000930080007390003002 :1001C000B71000009380008073904030B71001F0AA -:1001D0001301100023A02000730050106F0040494D +:1001D0001301100023A02000730050106F00C050C6 :1001E000130EB000170F0000130F8F06B71001F0A9 :1001F0001301000023A020009300800073900030C2 :10020000B71000009380008073904030B72000004A :1002100093800080371100001301018073B000301B :1002200073200130970000009380400173901034D8 -:10023000730020306F00C043B71001F013011000AD -:1002400023A02000730050106F008042130EC000E6 +:10023000730020306F00404BB71001F01301100025 +:1002400023A02000730050106F00004A130EC0005E :10025000170F0000130F4F06B71001F01301000035 :1002600023A020009300800073900030B71000009E :100270009380008073904030B7200000938000800E :100280001301000073B000307320013097000000AC -:100290009380400173901034730020306F00403D14 +:100290009380400173901034730020306F00C0448D :1002A000B71001F01301100023A0200073005010BC -:1002B0006F00003C9300200073900010130EE000CC +:1002B0006F0080439300200073900010130EE00045 :1002C000170F0000130F0F04B72001F013010000F7 :1002D00023A02000930020007390003093000020A2 :1002E00073904030930E0000B72001F0130110000E @@ -52,14 +52,14 @@ :100320009300002073904030B7200000938000803D :10033000371100001301018073B0003073200130C9 :1003400097000000938040017390103473002030B8 -:100350006F000032930E1000B72001F0130110005F -:1003600023A02000730050106F008030130E000196 +:100350006F008039930E1000B72001F013011000D8 +:1003600023A02000730050106F000038130E00010E :10037000170F0000130F0F06B72001F01301000044 :1003800023A02000930020007390003093000020F1 :1003900073904030B720000093800080130100006C :1003A00073B000307320013097000000938040014B -:1003B00073901034730020306F00802BB72001F051 -:1003C0001301100023A02000730050106F00402A7A +:1003B00073901034730020306F000033B72001F0C9 +:1003C0001301100023A02000730050106F00C031F3 :1003D000130E10019300002073903030170F0000AF :1003E000130F0F04B72001F01301000023A0200019 :1003F00093002000739000309300002073904030F1 @@ -69,15 +69,15 @@ :1004300023A0200093002000739000309300002040 :1004400073904030B7200000938000803711000087 :100450001301018073B00030732001309700000059 -:100460009380400173901034730020306F0040205F +:100460009380400173901034730020306F00C027D8 :10047000930E1000B72001F01301100023A02000FC -:10048000730050106F00C01E130E3001170F0000D4 +:10048000730050106F004026130E3001170F00004C :10049000130F0F06B72001F01301000023A0200066 :1004A0009300200073900030930000207390403040 :1004B000B7200000938000801301000073B000306B :1004C0007320013097000000938040017390103436 -:1004D000730020306F00C019B72001F01301100025 -:1004E00023A02000730050106F008018B72001F087 +:1004D000730020306F004021B72001F0130110009D +:1004E00023A02000730050106F000020B72001F0FF :1004F0001301000023A02000130E4001170F00007D :10050000130F0F039300200073900030930000201E :1005100073904030930E00009300002073A04014AD @@ -86,14 +86,14 @@ :10054000930020007390003093000020739040309F :10055000B720000093800080371100001301018054 :1005600073B0003073200130970000009380400189 -:1005700073901034730020306F00800F930E1000C2 -:100580009300002073A04014730050106F00400EC1 +:1005700073901034730020306F000017930E10003A +:100580009300002073A04014730050106F00C0153A :10059000130E6001170F0000130F8F05930000204A :1005A00073B040149300200073900030930000203B :1005B000739040309300002073A04014B7200000D7 :1005C000938000801301000073B00030732001306D :1005D0009700000093804001739010347300203026 -:1005E0006F000009730050106F008008130E700137 +:1005E0006F008010730050106F000010130E700128 :1005F000930E0000B72001F01301000023A020009B :100600009300002073B04014F3214034B72001F070 :100610001301100023A020009300002073B04014A9 @@ -101,14 +101,22 @@ :100630009300002073B04014F3214034B72001F040 :100640001301000023A020009300002073A0401499 :10065000F3214034B72001F01301100023A0200043 -:100660009300002073A04014F32140346F00000178 -:10067000370110F0130141F22320C101370110F0BE -:10068000130101F223200100E3840EFEF320203445 -:10069000F3201034F3200030F320303493000008AE -:1006A00073B0003093002000E38A1EFCB7200000E6 -:1006B0009380008073A0003073101F3473002030CB -:1006C000E3880EFAF3202014F3201014F320001016 -:1006D000F32030147300000013000000130000002A -:1006E00013000000130000001300000013000000BE +:100660009300002073A04014F3214034B72001F020 +:100670001301000023A02000130E8001930020002E +:1006800073A0403073A0403473A00030930E10006C +:10069000170F0000130FCF03B720000093800080D6 +:1006A000371100001301018073B000307320013056 +:1006B0009700000093804001739010347300203045 +:1006C0006F008002730050106F000002130E900143 +:1006D000170F0000130F4F017360043073005010A8 +:1006E0006F0080006F000001370110F0130141F22C +:1006F0002320C101370110F0130101F22320010072 +:10070000E3840EFEF3202034F3201034F320003075 +:10071000F32030349300000873B0003093002000C1 +:10072000E38A1EFCB72000009380008073A0003095 +:1007300073101F3473002030E3880EFAF320201466 +:10074000F3201014F3200010F32030147300000085 +:10075000130000001300000013000000130000004D +:0807600013000000130000006B :040000058000000077 :00000001FF diff --git a/src/test/cpp/raw/deleg/src/crt.S b/src/test/cpp/raw/deleg/src/crt.S index f91981ff..86dd58f8 100644 --- a/src/test/cpp/raw/deleg/src/crt.S +++ b/src/test/cpp/raw/deleg/src/crt.S @@ -310,7 +310,32 @@ test23: //Test software and hardware setting inettrupt csrs sip, x1 csrr x3, mip + externalInterruptS(0) +test24: //test supervisor software interrupt + li TEST_ID, 24 + li x1, 2 + csrs mie, x1 + csrs mip, x1 + csrs mstatus, x1 + + li TRAP_OK, 1 + la TRAP_RET, test25 + setPriv(1) +test24_s: + wfi + j fail + + +test25: //test undelegated supervisor interrupt in machine mode (continue test24) + li TEST_ID, 25 + la TRAP_RET, test26 + csrsi mstatus, 1 << 3 //mie + wfi + j fail + + +test26: j pass From e7f3dd55537ae64dc919cacb6f63ff2b935dbccd Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Fri, 5 Apr 2019 23:40:39 +0200 Subject: [PATCH 120/951] Rework CsrPlugin exception delegation --- .../scala/vexriscv/plugin/CsrPlugin.scala | 77 ++++++++----------- 1 file changed, 34 insertions(+), 43 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index faec4ae6..98b4ca0c 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -314,13 +314,15 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception val csrMapping = new CsrMapping() - //Interruption specification data model + //Interruption and exception data model case class Delegator(var enable : Bool, privilege : Int) - case class InterruptSource(var cond : Bool, id : Int, privilege : Int, delegators : List[Delegator]) - var interruptSpecs = ArrayBuffer[InterruptSource]() + case class InterruptSpec(var cond : Bool, id : Int, privilege : Int, delegators : List[Delegator]) + case class ExceptionSpec(id : Int, delegators : List[Delegator]) + var interruptSpecs = ArrayBuffer[InterruptSpec]() + var exceptionSpecs = ArrayBuffer[ExceptionSpec]() def addInterrupt(cond : Bool, id : Int, privilege : Int, delegators : List[Delegator]): Unit = { - interruptSpecs += InterruptSource(cond, id, privilege, delegators) + interruptSpecs += InterruptSpec(cond, id, privilege, delegators) } override def r(csrAddress: Int, bitOffset: Int, that: Data): Unit = csrMapping.r(csrAddress, bitOffset, that) @@ -464,8 +466,10 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception val minstret = Reg(UInt(64 bits)) randBoot() - - val medeleg = Reg(Bits(32 bits)) init(0) + val medeleg = supervisorGen generate new Area { + val IAM, IAF, II, LAM, LAF, SAM, SAF, EU, ES, IPF, LPF, SPF = RegInit(False) + val mapping = mutable.HashMap(0 -> IAM, 1 -> IAF, 2 -> II, 4 -> LAM, 5 -> LAF, 6 -> SAM, 7 -> SAF, 8 -> EU, 9 -> ES, 12 -> IPF, 13 -> LPF, 15 -> SPF) + } val mideleg = supervisorGen generate new Area { val ST, SE, SS = RegInit(False) } @@ -493,7 +497,7 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception minstretAccess(CSR.MINSTRETH, minstret(63 downto 32)) if(supervisorGen) { - medelegAccess(CSR.MEDELEG, medeleg) + for((id, enable) <- medeleg.mapping) medelegAccess(CSR.MEDELEG, id -> enable) midelegAccess(CSR.MIDELEG, 9 -> mideleg.SE, 5 -> mideleg.ST, 1 -> mideleg.SS) } @@ -578,47 +582,14 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception addInterrupt(sip.STIP && sie.STIE, id = 5, privilege = 1, delegators = List(Delegator(mideleg.ST, 3))) addInterrupt(sip.SSIP && sie.SSIE, id = 1, privilege = 1, delegators = List(Delegator(mideleg.SS, 3))) addInterrupt(sip.SEIP_OR && sie.SEIE, id = 9, privilege = 1, delegators = List(Delegator(mideleg.SE, 3))) + + for((id, enable) <- medeleg.mapping) exceptionSpecs += ExceptionSpec(id, List(Delegator(enable, 3))) } addInterrupt(mip.MTIP && mie.MTIE, id = 7, privilege = 3, delegators = Nil) addInterrupt(mip.MSIP && mie.MSIE, id = 3, privilege = 3, delegators = Nil) addInterrupt(mip.MEIP && mie.MEIE, id = 11, privilege = 3, delegators = Nil) - case class DelegatorModel(value : Bits, source : Int, target : Int) -// def solveDelegators(delegators : Seq[DelegatorModel], id : Int, lowerBound : Int): UInt = { -// val filtredDelegators = delegators.filter(_.target >= lowerBound) -// val ret = U(lowerBound, 2 bits) -// for(d <- filtredDelegators){ -// when(!d.value(id)){ -// ret := d.source -// } -// } -// ret -// } - - def solveDelegators(delegators : Seq[DelegatorModel], id : UInt, lowerBound : UInt): UInt = { - if(delegators.isEmpty) return U"11" - val ret = U(delegators.last.target, 2 bits) - for(d <- delegators){ - when(!d.value(id) || d.target < lowerBound){ - ret := d.source - } - } - ret -// val ret = U"11" -// var continue = True -// for(d <- delegators){ -// continue = continue && d.value(id) -// when(continue){ -// ret := d.source -// } -// } -// ret.max(lowerBound) - } - - val exceptionDelegators = ArrayBuffer[DelegatorModel]() - if(medelegAccess.canWrite) exceptionDelegators += DelegatorModel(medeleg,3, 1) - val mepcCaptureStage = if(exceptionPortsInfos.nonEmpty) lastStage else decode @@ -629,7 +600,27 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception val exceptionValids = Vec(stages.map(s => Bool().setPartialName(s.getName()))) val exceptionValidsRegs = Vec(stages.map(s => Reg(Bool).init(False).setPartialName(s.getName()))).allowUnsetRegToAvoidLatch val exceptionContext = Reg(ExceptionCause()) - val exceptionTargetPrivilege = solveDelegators(exceptionDelegators, exceptionContext.code, privilege) + val exceptionTargetPrivilegeUncapped = U"11" + + switch(exceptionContext.code){ + for(s <- exceptionSpecs){ + is(s.id){ + var exceptionPrivilegs = if (supervisorGen) List(1, 3) else List(3) + while(exceptionPrivilegs.length != 1){ + val p = exceptionPrivilegs.head + if (exceptionPrivilegs.tail.forall(e => s.delegators.exists(_.privilege == e))) { + val delegUpOn = s.delegators.filter(_.privilege > p).map(_.enable).fold(True)(_ && _) + val delegDownOff = !s.delegators.filter(_.privilege <= p).map(_.enable).orR + when(delegUpOn && delegDownOff) { + exceptionTargetPrivilegeUncapped := p + } + } + exceptionPrivilegs = exceptionPrivilegs.tail + } + } + } + } + val exceptionTargetPrivilege = exceptionTargetPrivilegeUncapped.max(privilege) val groupedByStage = exceptionPortsInfos.map(_.stage).distinct.map(s => { val stagePortsInfos = exceptionPortsInfos.filter(_.stage == s).sortWith(_.priority > _.priority) From 21b4ae8f2ff6de6d86138238bf35586bf1d5320c Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Sat, 6 Apr 2019 01:42:01 +0200 Subject: [PATCH 121/951] update todo, nothing todo ? everything done ? --- src/main/scala/vexriscv/demo/Linux.scala | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/scala/vexriscv/demo/Linux.scala b/src/main/scala/vexriscv/demo/Linux.scala index 0d6fe551..31e9198b 100644 --- a/src/main/scala/vexriscv/demo/Linux.scala +++ b/src/main/scala/vexriscv/demo/Linux.scala @@ -88,7 +88,6 @@ https://github.com/riscv/riscv-qemu/wiki#build-and-install */ -//TODO have to check, look like supervisor can't get interrupt if the machine mod didn't delegated it, have to check exactly object LinuxGen { def configFull(litex : Boolean, withMmu : Boolean) = { val config = VexRiscvConfig( From 6df3e578431eecde590035b62dafa2d78f902b1b Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Sat, 6 Apr 2019 02:00:47 +0200 Subject: [PATCH 122/951] workaround Verilator comparaison linting --- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 98b4ca0c..02877f07 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -620,7 +620,7 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception } } } - val exceptionTargetPrivilege = exceptionTargetPrivilegeUncapped.max(privilege) + val exceptionTargetPrivilege = privilege.max(exceptionTargetPrivilegeUncapped) val groupedByStage = exceptionPortsInfos.map(_.stage).distinct.map(s => { val stagePortsInfos = exceptionPortsInfos.filter(_.stage == s).sortWith(_.priority > _.priority) @@ -681,12 +681,11 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception //Process interrupt request, code and privilege val interrupt = False val interruptCode = UInt(4 bits).assignDontCare().addTag(Verilator.public) - val privilegeAllowInterrupts = mutable.HashMap( - 1 -> ((sstatus.SIE && privilege === "01") || privilege < "01"), - 3 -> (mstatus.MIE || privilege < "11") - ) var interruptPrivilegs = if (supervisorGen) List(1, 3) else List(3) val interruptTargetPrivilege = UInt(2 bits).assignDontCare() + val privilegeAllowInterrupts = mutable.HashMap[Int, Bool]() + if(supervisorGen) privilegeAllowInterrupts += 1 -> ((sstatus.SIE && privilege === "01") || privilege < "01") + privilegeAllowInterrupts += 3 -> (mstatus.MIE || privilege < "11") while(interruptPrivilegs.nonEmpty){ val p = interruptPrivilegs.head when(privilegeAllowInterrupts(p)){ From 39a4aa5e2627525b75b41a8ec2fca0a961861937 Mon Sep 17 00:00:00 2001 From: Tom Verbeure Date: Sat, 6 Apr 2019 12:38:54 -0700 Subject: [PATCH 123/951] GenMicroNoCsr: no memory stage, no write-back stage --- .../scala/vexriscv/demo/GenMicroNoCsr.scala | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 src/main/scala/vexriscv/demo/GenMicroNoCsr.scala diff --git a/src/main/scala/vexriscv/demo/GenMicroNoCsr.scala b/src/main/scala/vexriscv/demo/GenMicroNoCsr.scala new file mode 100644 index 00000000..bcd1b775 --- /dev/null +++ b/src/main/scala/vexriscv/demo/GenMicroNoCsr.scala @@ -0,0 +1,61 @@ +package vexriscv.demo + +import vexriscv.plugin._ +import vexriscv.{plugin, VexRiscv, VexRiscvConfig} +import spinal.core._ + +/** + * Created by spinalvm on 15.06.17. + */ +object GenMicroNoCsr extends App{ + def cpu() = new VexRiscv( + config = VexRiscvConfig( + withMemoryStage = false, + withWriteBackStage = false, + plugins = List( + new IBusSimplePlugin( + resetVector = 0x80000000l, + cmdForkOnSecondStage = false, + cmdForkPersistence = false, + prediction = NONE, + catchAccessFault = false, + compressedGen = false + ), + new DBusSimplePlugin( + catchAddressMisaligned = false, + catchAccessFault = false, + earlyInjection = false + ), + new DecoderSimplePlugin( + catchIllegalInstruction = false + ), + new RegFilePlugin( + regFileReadyKind = plugin.SYNC, + zeroBoot = false, + writeRfInMemoryStage = false + ), + new IntAluPlugin, + new SrcPlugin( + separatedAddSub = false, + executeInsertion = false + ), + new LightShifterPlugin, + new HazardSimplePlugin( + bypassExecute = false, + bypassMemory = false, + bypassWriteBack = false, + bypassWriteBackBuffer = false, + pessimisticUseSrc = false, + pessimisticWriteRegFile = false, + pessimisticAddressMatch = false + ), + new BranchPlugin( + earlyBranch = true, + catchAddressMisaligned = false + ), + new YamlPlugin("cpu0.yaml") + ) + ) + ) + SpinalConfig(mergeAsyncProcess = false).generateVerilog(cpu()) +} From 4fd36454d7cce7e47d41762ac9a25977dd55c4d3 Mon Sep 17 00:00:00 2001 From: Tom Verbeure Date: Sat, 6 Apr 2019 12:58:19 -0700 Subject: [PATCH 124/951] Complain about wrong earlyBranch settings. --- src/main/scala/vexriscv/plugin/BranchPlugin.scala | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/plugin/BranchPlugin.scala b/src/main/scala/vexriscv/plugin/BranchPlugin.scala index 46e28979..0c1dd0ba 100644 --- a/src/main/scala/vexriscv/plugin/BranchPlugin.scala +++ b/src/main/scala/vexriscv/plugin/BranchPlugin.scala @@ -55,6 +55,7 @@ class BranchPlugin(earlyBranch : Boolean, fenceiGenAsAJump : Boolean = false, fenceiGenAsANop : Boolean = false) extends Plugin[VexRiscv] with PredictionInterface{ + def catchAddressMisalignedForReal = catchAddressMisaligned && !pipeline(RVC_GEN) lazy val branchStage = if(earlyBranch) pipeline.execute else pipeline.memory @@ -88,6 +89,8 @@ class BranchPlugin(earlyBranch : Boolean, import pipeline.config._ import IntAluPlugin._ + assert(earlyBranch || withMemoryStage, "earlyBranch must be true when memory stage is disabled!") + val bActions = List[(Stageable[_ <: BaseType],Any)]( SRC1_CTRL -> Src1CtrlEnum.RS, SRC2_CTRL -> Src2CtrlEnum.RS, @@ -375,4 +378,4 @@ class BranchPlugin(earlyBranch : Boolean, } } } -} \ No newline at end of file +} From f89ee0d422a36188ddeaf82659dffd492aa3b2e9 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Sun, 7 Apr 2019 15:44:25 +0200 Subject: [PATCH 125/951] #60 Fix MMU holding invalid tlb, while linux is assuming it isn't doing so. --- src/main/scala/vexriscv/plugin/MmuPlugin.scala | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/plugin/MmuPlugin.scala b/src/main/scala/vexriscv/plugin/MmuPlugin.scala index 60fc94f0..b6b7d443 100644 --- a/src/main/scala/vexriscv/plugin/MmuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/MmuPlugin.scala @@ -135,6 +135,16 @@ class MmuPlugin(ioRange : UInt => Bool, port.bus.rsp.refilling := False } port.bus.rsp.isIoAccess := ioRange(port.bus.rsp.physicalAddress) + + // Avoid keeping any invalid line in the cache more than one memory translation. + // https://github.com/riscv/riscv-linux/blob/8fe28cb58bcb235034b64cbbb7550a8a43fd88be/arch/riscv/include/asm/pgtable.h#L276 + when(port.bus.cmd.isValid && port.bus.end) { + for (line <- cache) { + when(line.valid && line.exception) { + line.valid := False + } + } + } } val shared = new Area { @@ -241,7 +251,7 @@ class MmuPlugin(ioRange : UInt => Bool, execute plug new Area{ import execute._ val tlbWriteBuffer = Reg(UInt(20 bits)) - when(arbitration.isFiring && input(IS_SFENCE_VMA)){ + when(arbitration.isFiring && input(IS_SFENCE_VMA)){ // || csrService.isWriting(CSR.SATP) for(port <- core.ports; line <- port.cache) line.valid := False //Assume that the instruction already fetched into the pipeline are ok } } From c2595273ec4c3e1e3dd405e9424e554168fd54ae Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Mon, 8 Apr 2019 11:38:40 +0200 Subject: [PATCH 126/951] Add a busy flag from MMU ports iBus/dBus now halt on MMU busy, which avoid looping forever on page fault --- src/main/scala/vexriscv/Services.scala | 3 +- .../scala/vexriscv/ip/InstructionCache.scala | 10 ++-- .../vexriscv/plugin/DBusCachedPlugin.scala | 6 ++ .../vexriscv/plugin/DBusSimplePlugin.scala | 10 ++++ .../vexriscv/plugin/IBusCachedPlugin.scala | 55 ++++++++++++------- .../vexriscv/plugin/IBusSimplePlugin.scala | 4 ++ .../scala/vexriscv/plugin/MmuPlugin.scala | 5 ++ 7 files changed, 65 insertions(+), 28 deletions(-) diff --git a/src/main/scala/vexriscv/Services.scala b/src/main/scala/vexriscv/Services.scala index 666cb472..0e041278 100644 --- a/src/main/scala/vexriscv/Services.scala +++ b/src/main/scala/vexriscv/Services.scala @@ -78,10 +78,11 @@ case class MemoryTranslatorBus() extends Bundle with IMasterSlave{ val cmd = MemoryTranslatorCmd() val rsp = MemoryTranslatorRsp() val end = Bool + val busy = Bool override def asMaster() : Unit = { out(cmd, end) - in(rsp) + in(rsp, busy) } } diff --git a/src/main/scala/vexriscv/ip/InstructionCache.scala b/src/main/scala/vexriscv/ip/InstructionCache.scala index 29df3afd..e3722d66 100644 --- a/src/main/scala/vexriscv/ip/InstructionCache.scala +++ b/src/main/scala/vexriscv/ip/InstructionCache.scala @@ -99,10 +99,11 @@ case class InstructionCacheCpuFetch(p : InstructionCacheConfig) extends Bundle w val mmuBus = MemoryTranslatorBus() val physicalAddress = UInt(p.addressWidth bits) val cacheMiss, error, mmuRefilling, mmuException, isUser = ifGen(!p.twoCycleCache)(Bool) + val haltIt = Bool override def asMaster(): Unit = { out(isValid, isStuck, isRemoved, pc) - inWithNull(error,mmuRefilling,mmuException,data, cacheMiss,physicalAddress) + inWithNull(error,mmuRefilling,mmuException,data, cacheMiss,physicalAddress, haltIt) outWithNull(isUser, dataBypass, dataBypassValid) slaveWithNull(mmuBus) } @@ -290,10 +291,7 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{ } }) - io.cpu.prefetch.haltIt := False - - - + io.cpu.fetch.haltIt := io.cpu.fetch.mmuBus.busy val lineLoader = new Area{ val fire = False @@ -307,7 +305,7 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{ address := io.cpu.fill.payload } - io.cpu.prefetch.haltIt setWhen(valid || flushPending) + io.cpu.prefetch.haltIt := valid || flushPending val flushCounter = Reg(UInt(log2Up(wayLineCount) + 1 bit)) when(!flushCounter.msb){ diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index 917d50d1..89779ad4 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -159,7 +159,13 @@ class DBusCachedPlugin(config : DataCacheConfig, dBus.cmd << optionPipe(dBusCmdMasterPipe, cmdBuf)(_.m2sPipe()) cache.io.mem.rsp << optionPipe(dBusRspSlavePipe,dBus.rsp)(_.m2sPipe()) + decode plug new Area { + import decode._ + when(mmuBus.busy && arbitration.isValid && input(MEMORY_ENABLE)) { + arbitration.haltItself := True + } + } execute plug new Area { import execute._ diff --git a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala index 9e1de8cb..32e6f379 100644 --- a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala @@ -312,6 +312,15 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, dBus = master(DBusSimpleBus()).setName("dBus") + + decode plug new Area { + import decode._ + + if(mmuBus != null) when(mmuBus.busy && arbitration.isValid && input(MEMORY_ENABLE)) { + arbitration.haltItself := True + } + } + //Emit dBus.cmd request val cmdStage = if(emitCmdInMemoryStage) memory else execute cmdStage plug new Area{ @@ -359,6 +368,7 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, mmuBus.cmd.isValid := arbitration.isValid && input(MEMORY_ENABLE) mmuBus.cmd.virtualAddress := input(SRC_ADD).asUInt mmuBus.cmd.bypassTranslation := False + mmuBus.end := !arbitration.isStuck || arbitration.isRemoved dBus.cmd.address := mmuBus.rsp.physicalAddress //do not emit memory request if MMU refilling diff --git a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala index f55d92e6..ed74c867 100644 --- a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala @@ -165,6 +165,9 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l, cache.io.cpu.fetch.isStuck := !stages(1).input.ready cache.io.cpu.fetch.pc := stages(1).input.payload + + stages(1).halt setWhen(cache.io.cpu.fetch.haltIt) + if (!twoCycleCache) { cache.io.cpu.fetch.isUser := privilegeService.isUser() } @@ -188,39 +191,49 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l, val cacheRsp = if (twoCycleCache) cache.io.cpu.decode else cache.io.cpu.fetch val cacheRspArbitration = stages(if (twoCycleCache) 2 else 1) var issueDetected = False - val redoFetch = False //RegNext(False) init(False) - when(cacheRsp.isValid && (cacheRsp.cacheMiss || cacheRsp.mmuRefilling) && !issueDetected) { - issueDetected \= True - redoFetch := iBusRsp.readyForError - } + val redoFetch = False //Refill / redo assert(decodePcGen == compressedGen) - cache.io.cpu.fill.valid := redoFetch + cache.io.cpu.fill.valid := redoFetch && !cacheRsp.mmuRefilling cache.io.cpu.fill.payload := cacheRsp.physicalAddress - redoBranch.valid := redoFetch - redoBranch.payload := (if (decodePcGen) decode.input(PC) else cacheRsp.pc) + if (catchSomething) { decodeExceptionPort.valid := False decodeExceptionPort.code.assignDontCare() decodeExceptionPort.badAddr := cacheRsp.pc(31 downto 2) @@ "00" - - if(catchIllegalAccess) when(cacheRsp.isValid && cacheRsp.mmuException && !issueDetected) { - issueDetected \= True - decodeExceptionPort.valid := iBusRsp.readyForError - decodeExceptionPort.code := 12 - } - - if(catchAccessFault) when(cacheRsp.isValid && cacheRsp.error && !issueDetected) { - issueDetected \= True - decodeExceptionPort.valid := iBusRsp.readyForError - decodeExceptionPort.code := 1 - } - decodeExceptionPort.valid clearWhen(fetcherHalt) } + when(cacheRsp.isValid && cacheRsp.mmuRefilling && !issueDetected) { + issueDetected \= True + redoFetch := True + } + + if(catchIllegalAccess) when(cacheRsp.isValid && cacheRsp.mmuException && !issueDetected) { + issueDetected \= True + decodeExceptionPort.valid := iBusRsp.readyForError + decodeExceptionPort.code := 12 + } + + when(cacheRsp.isValid && cacheRsp.cacheMiss && !issueDetected) { + issueDetected \= True + cache.io.cpu.fill.valid := True + redoFetch := True + } + + if(catchAccessFault) when(cacheRsp.isValid && cacheRsp.error && !issueDetected) { + issueDetected \= True + decodeExceptionPort.valid := iBusRsp.readyForError + decodeExceptionPort.code := 1 + } + + redoFetch clearWhen(!iBusRsp.readyForError) + if (catchSomething) decodeExceptionPort.valid clearWhen(fetcherHalt) + + redoBranch.valid := redoFetch + redoBranch.payload := (if (decodePcGen) decode.input(PC) else cacheRsp.pc) cacheRspArbitration.halt setWhen (issueDetected || iBusRspOutputHalt) iBusRsp.output.valid := cacheRspArbitration.output.valid diff --git a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala index ddd3ff37..fb296fbd 100644 --- a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala @@ -247,6 +247,8 @@ class IBusSimplePlugin(resetVector : BigInt, mmuBus.cmd.isValid := cmdForkStage.input.valid mmuBus.cmd.virtualAddress := cmdForkStage.input.payload mmuBus.cmd.bypassTranslation := False + mmuBus.end := !cmdForkStage.output.fire || flush + cmd.pc := mmuBus.rsp.physicalAddress(31 downto 2) @@ "00" //do not emit memory request if MMU miss @@ -255,6 +257,8 @@ class IBusSimplePlugin(resetVector : BigInt, cmd.valid := False } + cmdForkStage.halt.setWhen(mmuBus.busy) + val joinCtx = stageXToIBusRsp(cmdForkStage, mmuBus.rsp) } diff --git a/src/main/scala/vexriscv/plugin/MmuPlugin.scala b/src/main/scala/vexriscv/plugin/MmuPlugin.scala index b6b7d443..9fce74ee 100644 --- a/src/main/scala/vexriscv/plugin/MmuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/MmuPlugin.scala @@ -100,6 +100,7 @@ class MmuPlugin(ioRange : UInt => Bool, val core = pipeline plug new Area { val ports = for (port <- sortedPortsInfo) yield new Area { + val handle = port val id = port.id val cache = Vec(Reg(CacheLine()) init, port.args.portTlbSize) val cacheHits = cache.map(line => line.valid && line.virtualAddress(1) === port.bus.cmd.virtualAddress(31 downto 22) && (line.superPage || line.virtualAddress(0) === port.bus.cmd.virtualAddress(21 downto 12))) @@ -224,6 +225,10 @@ class MmuPlugin(ioRange : UInt => Bool, } } + for(port <- ports) { + port.handle.bus.busy := state =/= State.IDLE && portId === port.id + } + when(dBusAccess.rsp.valid && !dBusAccess.rsp.redo && (dBusRsp.leaf || dBusRsp.exception)){ for(port <- ports){ when(portId === port.id) { From fd15a938c5a366ff0fa65aa976e213a012ab79be Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Mon, 8 Apr 2019 13:20:56 +0200 Subject: [PATCH 127/951] #60 Fix machine mode emulator atomic emulation. Do not write regfile if the page was set as read only. --- src/main/c/emulator/build/emulator.asm | 238 ++++++++++++------------ src/main/c/emulator/build/emulator.bin | Bin 2320 -> 2328 bytes src/main/c/emulator/build/emulator.hex | 244 +++++++++++++------------ src/main/c/emulator/src/main.c | 2 +- 4 files changed, 250 insertions(+), 234 deletions(-) diff --git a/src/main/c/emulator/build/emulator.asm b/src/main/c/emulator/build/emulator.asm index 62f76935..88cbbf9f 100644 --- a/src/main/c/emulator/build/emulator.asm +++ b/src/main/c/emulator/build/emulator.asm @@ -6,13 +6,13 @@ Disassembly of section .init: 80000000 <_start>: 80000000: 00001117 auipc sp,0x1 -80000004: 11010113 addi sp,sp,272 # 80001110 <_sp> +80000004: 11810113 addi sp,sp,280 # 80001118 <_sp> 80000008: 00001517 auipc a0,0x1 -8000000c: 86850513 addi a0,a0,-1944 # 80000870 <__init_array_end> +8000000c: 87050513 addi a0,a0,-1936 # 80000878 <__init_array_end> 80000010: 00001597 auipc a1,0x1 -80000014: 86058593 addi a1,a1,-1952 # 80000870 <__init_array_end> +80000014: 86858593 addi a1,a1,-1944 # 80000878 <__init_array_end> 80000018: 00001617 auipc a2,0x1 -8000001c: 8f860613 addi a2,a2,-1800 # 80000910 <__bss_start> +8000001c: 90060613 addi a2,a2,-1792 # 80000918 <__bss_start> 80000020: 00c5fc63 bgeu a1,a2,80000038 <_start+0x38> 80000024: 00052283 lw t0,0(a0) 80000028: 0055a023 sw t0,0(a1) @@ -20,14 +20,14 @@ Disassembly of section .init: 80000030: 00458593 addi a1,a1,4 80000034: fec5e8e3 bltu a1,a2,80000024 <_start+0x24> 80000038: 00001517 auipc a0,0x1 -8000003c: 8d850513 addi a0,a0,-1832 # 80000910 <__bss_start> +8000003c: 8e050513 addi a0,a0,-1824 # 80000918 <__bss_start> 80000040: 00001597 auipc a1,0x1 -80000044: 8d058593 addi a1,a1,-1840 # 80000910 <__bss_start> +80000044: 8d858593 addi a1,a1,-1832 # 80000918 <__bss_start> 80000048: 00b57863 bgeu a0,a1,80000058 <_start+0x58> 8000004c: 00052023 sw zero,0(a0) 80000050: 00450513 addi a0,a0,4 80000054: feb56ce3 bltu a0,a1,8000004c <_start+0x4c> -80000058: 770000ef jal ra,800007c8 <__libc_init_array> +80000058: 778000ef jal ra,800007d0 <__libc_init_array> 8000005c: 17c000ef jal ra,800001d8 80000060: 00000097 auipc ra,0x0 80000064: 01408093 addi ra,ra,20 # 80000074 @@ -117,7 +117,7 @@ Disassembly of section .text: 8000018c: 00054503 lbu a0,0(a0) 80000190: 00050a63 beqz a0,800001a4 80000194: 00140413 addi s0,s0,1 -80000198: 5f4000ef jal ra,8000078c +80000198: 5fc000ef jal ra,80000794 8000019c: 00044503 lbu a0,0(s0) 800001a0: fe051ae3 bnez a0,80000194 800001a4: 00c12083 lw ra,12(sp) @@ -149,18 +149,18 @@ Disassembly of section .text: 800001fc: 3a079073 csrw pmpcfg0,a5 80000200: 30529073 csrw mtvec,t0 80000204: 80001437 lui s0,0x80001 -80000208: 5bc000ef jal ra,800007c4 -8000020c: 8e440413 addi s0,s0,-1820 # 800008e4 <_sp+0xfffff7d4> +80000208: 5c4000ef jal ra,800007cc +8000020c: 8ec40413 addi s0,s0,-1812 # 800008ec <_sp+0xfffff7d4> 80000210: 02a00513 li a0,42 80000214: 00140413 addi s0,s0,1 -80000218: 574000ef jal ra,8000078c +80000218: 57c000ef jal ra,80000794 8000021c: 00044503 lbu a0,0(s0) 80000220: fe051ae3 bnez a0,80000214 80000224: 800007b7 lui a5,0x80000 -80000228: 07c78793 addi a5,a5,124 # 8000007c <_sp+0xffffef6c> +80000228: 07c78793 addi a5,a5,124 # 8000007c <_sp+0xffffef64> 8000022c: 30579073 csrw mtvec,a5 80000230: 800017b7 lui a5,0x80001 -80000234: 09078793 addi a5,a5,144 # 80001090 <_sp+0xffffff80> +80000234: 09878793 addi a5,a5,152 # 80001098 <_sp+0xffffff80> 80000238: 34079073 csrw mscratch,a5 8000023c: 000017b7 lui a5,0x1 80000240: 88078793 addi a5,a5,-1920 # 880 <__stack_size+0x80> @@ -175,10 +175,10 @@ Disassembly of section .text: 80000264: 30379073 csrw mideleg,a5 80000268: 14305073 csrwi stval,0 8000026c: 80001437 lui s0,0x80001 -80000270: 8fc40413 addi s0,s0,-1796 # 800008fc <_sp+0xfffff7ec> +80000270: 90440413 addi s0,s0,-1788 # 80000904 <_sp+0xfffff7ec> 80000274: 02a00513 li a0,42 80000278: 00140413 addi s0,s0,1 -8000027c: 510000ef jal ra,8000078c +8000027c: 518000ef jal ra,80000794 80000280: 00044503 lbu a0,0(s0) 80000284: fe051ae3 bnez a0,80000278 80000288: 00c12083 lw ra,12(sp) @@ -188,7 +188,7 @@ Disassembly of section .text: 80000298 : 80000298: 800017b7 lui a5,0x80001 -8000029c: 09078793 addi a5,a5,144 # 80001090 <_sp+0xffffff80> +8000029c: 09878793 addi a5,a5,152 # 80001098 <_sp+0xffffff80> 800002a0: 00251513 slli a0,a0,0x2 800002a4: 00f50533 add a0,a0,a5 800002a8: 00052503 lw a0,0(a0) @@ -197,7 +197,7 @@ Disassembly of section .text: 800002b0 : 800002b0: 800017b7 lui a5,0x80001 800002b4: 00251513 slli a0,a0,0x2 -800002b8: 09078793 addi a5,a5,144 # 80001090 <_sp+0xffffff80> +800002b8: 09878793 addi a5,a5,152 # 80001098 <_sp+0xffffff80> 800002bc: 00f50533 add a0,a0,a5 800002c0: 00b52023 sw a1,0(a0) 800002c4: 00008067 ret @@ -205,7 +205,7 @@ Disassembly of section .text: 800002c8 : 800002c8: ff010113 addi sp,sp,-16 800002cc: 00112623 sw ra,12(sp) -800002d0: 4b4000ef jal ra,80000784 +800002d0: 4bc000ef jal ra,8000078c 800002d4: 343027f3 csrr a5,mtval 800002d8: 14379073 csrw stval,a5 800002dc: 341027f3 csrr a5,mepc @@ -220,7 +220,7 @@ Disassembly of section .text: 80000300 : 80000300: 800007b7 lui a5,0x80000 -80000304: 07c78793 addi a5,a5,124 # 8000007c <_sp+0xffffef6c> +80000304: 07c78793 addi a5,a5,124 # 8000007c <_sp+0xffffef64> 80000308: 30579073 csrw mtvec,a5 8000030c: 343027f3 csrr a5,mtval 80000310: 14379073 csrw stval,a5 @@ -254,7 +254,7 @@ Disassembly of section .text: 80000378: 00020737 lui a4,0x20 8000037c: 30073073 csrc mstatus,a4 80000380: 00068513 mv a0,a3 -80000384: 00f5a023 sw a5,0(a1) # c3000000 <_sp+0x42ffeef0> +80000384: 00f5a023 sw a5,0(a1) # c3000000 <_sp+0x42ffeee8> 80000388: 00008067 ret 8000038c : @@ -285,7 +285,7 @@ Disassembly of section .text: 800003e4: 00900693 li a3,9 800003e8: 04d79463 bne a5,a3,80000430 800003ec: 80001437 lui s0,0x80001 -800003f0: 11040413 addi s0,s0,272 # 80001110 <_sp+0x0> +800003f0: 11840413 addi s0,s0,280 # 80001118 <_sp+0x0> 800003f4: fc442783 lw a5,-60(s0) 800003f8: 00100693 li a3,1 800003fc: fa842503 lw a0,-88(s0) @@ -298,10 +298,10 @@ Disassembly of section .text: 80000418: 01012903 lw s2,16(sp) 8000041c: 00c12983 lw s3,12(sp) 80000420: 02010113 addi sp,sp,32 -80000424: 3600006f j 80000784 +80000424: 3680006f j 8000078c 80000428: 00777713 andi a4,a4,7 8000042c: 14f70063 beq a4,a5,8000056c -80000430: 354000ef jal ra,80000784 +80000430: 35c000ef jal ra,8000078c 80000434: 343027f3 csrr a5,mtval 80000438: 14379073 csrw stval,a5 8000043c: 341027f3 csrr a5,mepc @@ -346,7 +346,7 @@ Disassembly of section .text: 800004d8: 10f70c63 beq a4,a5,800005f0 800004dc: 00100993 li s3,1 800004e0: 03370463 beq a4,s3,80000508 -800004e4: 2a0000ef jal ra,80000784 +800004e4: 2a8000ef jal ra,8000078c 800004e8: 343027f3 csrr a5,mtval 800004ec: 14379073 csrw stval,a5 800004f0: 341027f3 csrr a5,mepc @@ -361,7 +361,7 @@ Disassembly of section .text: 80000514: 0ed70663 beq a4,a3,80000600 80000518: c8178793 addi a5,a5,-895 8000051c: 0cf70463 beq a4,a5,800005e4 -80000520: 264000ef jal ra,80000784 +80000520: 26c000ef jal ra,8000078c 80000524: 343027f3 csrr a5,mtval 80000528: 14379073 csrw stval,a5 8000052c: 341027f3 csrr a5,mepc @@ -373,7 +373,7 @@ Disassembly of section .text: 80000544: 1c099063 bnez s3,80000704 80000548: 00545413 srli s0,s0,0x5 8000054c: 800017b7 lui a5,0x80001 -80000550: 09078793 addi a5,a5,144 # 80001090 <_sp+0xffffff80> +80000550: 09878793 addi a5,a5,152 # 80001098 <_sp+0xffffff80> 80000554: 07c47413 andi s0,s0,124 80000558: 00f40433 add s0,s0,a5 8000055c: 01242023 sw s2,0(s0) @@ -383,7 +383,7 @@ Disassembly of section .text: 8000056c: 00d45713 srli a4,s0,0xd 80000570: 01245793 srli a5,s0,0x12 80000574: 800016b7 lui a3,0x80001 -80000578: 09068693 addi a3,a3,144 # 80001090 <_sp+0xffffff80> +80000578: 09868693 addi a3,a3,152 # 80001098 <_sp+0xffffff80> 8000057c: 07c77713 andi a4,a4,124 80000580: 07c7f793 andi a5,a5,124 80000584: 00d70733 add a4,a4,a3 @@ -406,42 +406,42 @@ Disassembly of section .text: 800005c8: e6f564e3 bltu a0,a5,80000430 800005cc: 80001537 lui a0,0x80001 800005d0: 00279793 slli a5,a5,0x2 -800005d4: 87050513 addi a0,a0,-1936 # 80000870 <_sp+0xfffff760> +800005d4: 87850513 addi a0,a0,-1928 # 80000878 <_sp+0xfffff760> 800005d8: 00a787b3 add a5,a5,a0 800005dc: 0007a783 lw a5,0(a5) 800005e0: 00078067 jr a5 -800005e4: 1c0000ef jal ra,800007a4 +800005e4: 1c8000ef jal ra,800007ac 800005e8: 00050913 mv s2,a0 800005ec: f59ff06f j 80000544 800005f0: 00f45993 srli s3,s0,0xf 800005f4: 01f9f993 andi s3,s3,31 800005f8: 013039b3 snez s3,s3 800005fc: f0dff06f j 80000508 -80000600: 19c000ef jal ra,8000079c +80000600: 1a4000ef jal ra,800007a4 80000604: 00050913 mv s2,a0 80000608: f3dff06f j 80000544 8000060c: 01067463 bgeu a2,a6,80000614 80000610: 00080613 mv a2,a6 -80000614: 00545413 srli s0,s0,0x5 -80000618: 07c47413 andi s0,s0,124 -8000061c: 00d406b3 add a3,s0,a3 -80000620: 0106a023 sw a6,0(a3) -80000624: 000207b7 lui a5,0x20 -80000628: 3007a073 csrs mstatus,a5 -8000062c: 00000797 auipc a5,0x0 -80000630: 01878793 addi a5,a5,24 # 80000644 -80000634: 30579073 csrw mtvec,a5 -80000638: 00100693 li a3,1 -8000063c: 00c72023 sw a2,0(a4) -80000640: 00000693 li a3,0 -80000644: 000207b7 lui a5,0x20 -80000648: 3007b073 csrc mstatus,a5 -8000064c: 800007b7 lui a5,0x80000 -80000650: 07c78793 addi a5,a5,124 # 8000007c <_sp+0xffffef6c> -80000654: 0e069063 bnez a3,80000734 +80000614: 00020537 lui a0,0x20 +80000618: 30052073 csrs mstatus,a0 +8000061c: 00000517 auipc a0,0x0 +80000620: 01850513 addi a0,a0,24 # 80000634 +80000624: 30551073 csrw mtvec,a0 +80000628: 00100793 li a5,1 +8000062c: 00c72023 sw a2,0(a4) +80000630: 00000793 li a5,0 +80000634: 00020537 lui a0,0x20 +80000638: 30053073 csrc mstatus,a0 +8000063c: 80000737 lui a4,0x80000 +80000640: 07c70713 addi a4,a4,124 # 8000007c <_sp+0xffffef64> +80000644: 14079063 bnez a5,80000784 +80000648: 00545793 srli a5,s0,0x5 +8000064c: 07c7f793 andi a5,a5,124 +80000650: 00d786b3 add a3,a5,a3 +80000654: 0106a023 sw a6,0(a3) 80000658: 00448493 addi s1,s1,4 8000065c: 34149073 csrw mepc,s1 -80000660: 30579073 csrw mtvec,a5 +80000660: 30571073 csrw mtvec,a4 80000664: df1ff06f j 80000454 80000668: 01064633 xor a2,a2,a6 8000066c: fa9ff06f j 80000614 @@ -460,14 +460,14 @@ Disassembly of section .text: 800006a0: f6c85ae3 bge a6,a2,80000614 800006a4: 00080613 mv a2,a6 800006a8: f6dff06f j 80000614 -800006ac: 0e8000ef jal ra,80000794 +800006ac: 0f0000ef jal ra,8000079c 800006b0: faa42423 sw a0,-88(s0) 800006b4: 341027f3 csrr a5,mepc 800006b8: 00478793 addi a5,a5,4 800006bc: 34179073 csrw mepc,a5 800006c0: d95ff06f j 80000454 800006c4: fac42583 lw a1,-84(s0) -800006c8: 0e4000ef jal ra,800007ac +800006c8: 0ec000ef jal ra,800007b4 800006cc: 08000793 li a5,128 800006d0: 3047a073 csrs mie,a5 800006d4: 02000793 li a5,32 @@ -477,12 +477,12 @@ Disassembly of section .text: 800006e4: 34179073 csrw mepc,a5 800006e8: d6dff06f j 80000454 800006ec: 0ff57513 andi a0,a0,255 -800006f0: 09c000ef jal ra,8000078c +800006f0: 0a4000ef jal ra,80000794 800006f4: 341027f3 csrr a5,mepc 800006f8: 00478793 addi a5,a5,4 800006fc: 34179073 csrw mepc,a5 80000700: d55ff06f j 80000454 -80000704: 080000ef jal ra,80000784 +80000704: 088000ef jal ra,8000078c 80000708: 343027f3 csrr a5,mtval 8000070c: 14379073 csrw stval,a5 80000710: 341027f3 csrr a5,mepc @@ -493,7 +493,7 @@ Disassembly of section .text: 80000724: 34179073 csrw mepc,a5 80000728: e21ff06f j 80000548 8000072c: 800007b7 lui a5,0x80000 -80000730: 07c78793 addi a5,a5,124 # 8000007c <_sp+0xffffef6c> +80000730: 07c78793 addi a5,a5,124 # 8000007c <_sp+0xffffef64> 80000734: 30579073 csrw mtvec,a5 80000738: 343027f3 csrr a5,mtval 8000073c: 14379073 csrw stval,a5 @@ -514,78 +514,80 @@ Disassembly of section .text: 80000778: 88078793 addi a5,a5,-1920 # 880 <__stack_size+0x80> 8000077c: 3007a073 csrs mstatus,a5 80000780: cd5ff06f j 80000454 +80000784: 30571073 csrw mtvec,a4 +80000788: fb1ff06f j 80000738 -80000784 : -80000784: fe002e23 sw zero,-4(zero) # fffffffc <_sp+0x7fffeeec> -80000788: 0000006f j 80000788 +8000078c : +8000078c: fe002e23 sw zero,-4(zero) # fffffffc <_sp+0x7fffeee4> +80000790: 0000006f j 80000790 -8000078c : -8000078c: fea02c23 sw a0,-8(zero) # fffffff8 <_sp+0x7fffeee8> -80000790: 00008067 ret - -80000794 : -80000794: ff802503 lw a0,-8(zero) # fffffff8 <_sp+0x7fffeee8> +80000794 : +80000794: fea02c23 sw a0,-8(zero) # fffffff8 <_sp+0x7fffeee0> 80000798: 00008067 ret -8000079c : -8000079c: fe002503 lw a0,-32(zero) # ffffffe0 <_sp+0x7fffeed0> +8000079c : +8000079c: ff802503 lw a0,-8(zero) # fffffff8 <_sp+0x7fffeee0> 800007a0: 00008067 ret -800007a4 : -800007a4: fe402503 lw a0,-28(zero) # ffffffe4 <_sp+0x7fffeed4> +800007a4 : +800007a4: fe002503 lw a0,-32(zero) # ffffffe0 <_sp+0x7fffeec8> 800007a8: 00008067 ret -800007ac : -800007ac: fec00793 li a5,-20 -800007b0: fff00713 li a4,-1 -800007b4: 00e7a023 sw a4,0(a5) -800007b8: fea02423 sw a0,-24(zero) # ffffffe8 <_sp+0x7fffeed8> -800007bc: 00b7a023 sw a1,0(a5) -800007c0: 00008067 ret +800007ac : +800007ac: fe402503 lw a0,-28(zero) # ffffffe4 <_sp+0x7fffeecc> +800007b0: 00008067 ret -800007c4 : -800007c4: 00008067 ret +800007b4 : +800007b4: fec00793 li a5,-20 +800007b8: fff00713 li a4,-1 +800007bc: 00e7a023 sw a4,0(a5) +800007c0: fea02423 sw a0,-24(zero) # ffffffe8 <_sp+0x7fffeed0> +800007c4: 00b7a023 sw a1,0(a5) +800007c8: 00008067 ret -800007c8 <__libc_init_array>: -800007c8: ff010113 addi sp,sp,-16 -800007cc: 00000797 auipc a5,0x0 -800007d0: 0a478793 addi a5,a5,164 # 80000870 <__init_array_end> -800007d4: 00812423 sw s0,8(sp) -800007d8: 00000417 auipc s0,0x0 -800007dc: 09840413 addi s0,s0,152 # 80000870 <__init_array_end> -800007e0: 40f40433 sub s0,s0,a5 -800007e4: 00912223 sw s1,4(sp) -800007e8: 01212023 sw s2,0(sp) -800007ec: 00112623 sw ra,12(sp) -800007f0: 40245413 srai s0,s0,0x2 -800007f4: 00000493 li s1,0 -800007f8: 00078913 mv s2,a5 -800007fc: 04849263 bne s1,s0,80000840 <__libc_init_array+0x78> -80000800: 879ff0ef jal ra,80000078 <_init> -80000804: 00000797 auipc a5,0x0 -80000808: 06c78793 addi a5,a5,108 # 80000870 <__init_array_end> -8000080c: 00000417 auipc s0,0x0 -80000810: 06440413 addi s0,s0,100 # 80000870 <__init_array_end> -80000814: 40f40433 sub s0,s0,a5 -80000818: 40245413 srai s0,s0,0x2 -8000081c: 00000493 li s1,0 -80000820: 00078913 mv s2,a5 -80000824: 02849a63 bne s1,s0,80000858 <__libc_init_array+0x90> -80000828: 00c12083 lw ra,12(sp) -8000082c: 00812403 lw s0,8(sp) -80000830: 00412483 lw s1,4(sp) -80000834: 00012903 lw s2,0(sp) -80000838: 01010113 addi sp,sp,16 -8000083c: 00008067 ret -80000840: 00249793 slli a5,s1,0x2 -80000844: 00f907b3 add a5,s2,a5 -80000848: 0007a783 lw a5,0(a5) -8000084c: 00148493 addi s1,s1,1 -80000850: 000780e7 jalr a5 -80000854: fa9ff06f j 800007fc <__libc_init_array+0x34> -80000858: 00249793 slli a5,s1,0x2 -8000085c: 00f907b3 add a5,s2,a5 -80000860: 0007a783 lw a5,0(a5) -80000864: 00148493 addi s1,s1,1 -80000868: 000780e7 jalr a5 -8000086c: fb9ff06f j 80000824 <__libc_init_array+0x5c> +800007cc : +800007cc: 00008067 ret + +800007d0 <__libc_init_array>: +800007d0: ff010113 addi sp,sp,-16 +800007d4: 00000797 auipc a5,0x0 +800007d8: 0a478793 addi a5,a5,164 # 80000878 <__init_array_end> +800007dc: 00812423 sw s0,8(sp) +800007e0: 00000417 auipc s0,0x0 +800007e4: 09840413 addi s0,s0,152 # 80000878 <__init_array_end> +800007e8: 40f40433 sub s0,s0,a5 +800007ec: 00912223 sw s1,4(sp) +800007f0: 01212023 sw s2,0(sp) +800007f4: 00112623 sw ra,12(sp) +800007f8: 40245413 srai s0,s0,0x2 +800007fc: 00000493 li s1,0 +80000800: 00078913 mv s2,a5 +80000804: 04849263 bne s1,s0,80000848 <__libc_init_array+0x78> +80000808: 871ff0ef jal ra,80000078 <_init> +8000080c: 00000797 auipc a5,0x0 +80000810: 06c78793 addi a5,a5,108 # 80000878 <__init_array_end> +80000814: 00000417 auipc s0,0x0 +80000818: 06440413 addi s0,s0,100 # 80000878 <__init_array_end> +8000081c: 40f40433 sub s0,s0,a5 +80000820: 40245413 srai s0,s0,0x2 +80000824: 00000493 li s1,0 +80000828: 00078913 mv s2,a5 +8000082c: 02849a63 bne s1,s0,80000860 <__libc_init_array+0x90> +80000830: 00c12083 lw ra,12(sp) +80000834: 00812403 lw s0,8(sp) +80000838: 00412483 lw s1,4(sp) +8000083c: 00012903 lw s2,0(sp) +80000840: 01010113 addi sp,sp,16 +80000844: 00008067 ret +80000848: 00249793 slli a5,s1,0x2 +8000084c: 00f907b3 add a5,s2,a5 +80000850: 0007a783 lw a5,0(a5) +80000854: 00148493 addi s1,s1,1 +80000858: 000780e7 jalr a5 +8000085c: fa9ff06f j 80000804 <__libc_init_array+0x34> +80000860: 00249793 slli a5,s1,0x2 +80000864: 00f907b3 add a5,s2,a5 +80000868: 0007a783 lw a5,0(a5) +8000086c: 00148493 addi s1,s1,1 +80000870: 000780e7 jalr a5 +80000874: fb9ff06f j 8000082c <__libc_init_array+0x5c> diff --git a/src/main/c/emulator/build/emulator.bin b/src/main/c/emulator/build/emulator.bin index 009fa6849feab3afbd5957392fe81dde601a6baf..e87b1abeed90cabb41b185657c6197b6c7df1324 100755 GIT binary patch delta 445 zcmYLFF=$#*6us~H-+x-LetnuBG^rnixPFMO6o)vZWJtG~NJv1)AG#DAejtI+`byP5 zCH(Xb$)=lYiI! zSeFVd31b*yhGvL|MOuok`u}-}4VqPahi1}VWSLD>@BrS*SsikpTZ+$i*YQfT@S5I{ zCQd@jPvr}-zYh-FB$fF5L9A$>iNs5-M2AZ=BIfv!1yQNMxd{?I58tpnY2zW=ZnV6< z*MmOt+Ns)(Gw54%Ryt_Rsa*yJBbwjT;d$zMzMh8_R_ delta 436 zcmYLFJxGF46us~Dz4w&R(x-iu{Rl#?LRN%B4n;$4Nf8b~-_Q~`7!*V)lzvO)S9h>Y zH`l_%)j@D*t+}D0HU*Vvsh$=zUG6#Oo_p@Sbz5$~?gEg6xOA_oER)TviW!#GM^w+V zxoiK_Wajb@y)=$05b!glT!Gj9%2yNMKE6a~bO+OP6d%Z@s}`5q@|9#oDm4!@A&Nfg zBLWv_#8J=vnh_4?4|p0z5_F^-s~E_Ykus|FQQ?4VAcuq^6(H0 z`0yxlu206a8v^*IMQC)U2MigOeL}`!P}L!groasrBpi=fJjKkiS%R~YP-}#;hY4wC zkZ2XUxZMH#{3PYY5J|LNT1}{p{c Date: Mon, 8 Apr 2019 14:24:37 +0200 Subject: [PATCH 128/951] #60 Fix instruction cache refill --- src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala index ed74c867..0823eaed 100644 --- a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala @@ -230,6 +230,7 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l, } redoFetch clearWhen(!iBusRsp.readyForError) + cache.io.cpu.fill.valid clearWhen(!iBusRsp.readyForError) if (catchSomething) decodeExceptionPort.valid clearWhen(fetcherHalt) redoBranch.valid := redoFetch From 21cb8615fdbca1b8d77d6366bd9c6b6f4fd72ffc Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Mon, 8 Apr 2019 16:06:05 +0200 Subject: [PATCH 129/951] Clean and fix things to get all the non-linux configs and machine only configs working --- .../scala/vexriscv/plugin/CsrPlugin.scala | 4 +- .../vexriscv/plugin/DBusCachedPlugin.scala | 43 ++++--- .../vexriscv/plugin/IBusCachedPlugin.scala | 1 + .../plugin/StaticMemoryTranslatorPlugin.scala | 1 + src/test/cpp/raw/dcache/build/dcache.asm | 117 +++++++++--------- src/test/cpp/raw/dcache/build/dcache.hex | 28 ++--- src/test/cpp/raw/dcache/src/crt.S | 2 +- src/test/cpp/raw/icache/build/icache.asm | 69 +++++------ src/test/cpp/raw/icache/build/icache.hex | 17 ++- src/test/cpp/raw/icache/src/crt.S | 2 +- .../cpp/raw/machineCsr/build/machineCsr.asm | 39 +++--- .../cpp/raw/machineCsr/build/machineCsr.hex | 8 +- src/test/cpp/raw/machineCsr/makefile | 1 + src/test/cpp/raw/machineCsr/src/crt.S | 2 +- 14 files changed, 168 insertions(+), 166 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 02877f07..377b95b2 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -380,7 +380,7 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception exceptionPending = False timerInterrupt = in Bool() setName("timerInterrupt") externalInterrupt = in Bool() setName("externalInterrupt") - softwareInterrupt = in Bool() setName("softwareInterrupt") + softwareInterrupt = in Bool() setName("softwareInterrupt") default(False) if(supervisorGen){ // timerInterruptS = in Bool() setName("timerInterruptS") externalInterruptS = in Bool() setName("externalInterruptS") @@ -714,7 +714,7 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception //Used to make the pipeline empty softly (for interrupts) val pipelineLiberator = new Area{ when(interrupt){ - decode.arbitration.haltByOther := True + decode.arbitration.haltByOther := decode.arbitration.isValid } val done = !stagesFromExecute.map(_.arbitration.isValid).orR && fetcher.pcValid(mepcCaptureStage) diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index 89779ad4..dc0dc162 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -217,35 +217,38 @@ class DBusCachedPlugin(config : DataCacheConfig, cache.io.cpu.writeBack.address := U(input(REGFILE_WRITE_DATA)) if(withLrSc) cache.io.cpu.writeBack.clearAtomicEntries := service(classOf[IContextSwitching]).isContextSwitching + redoBranch.valid := False + redoBranch.payload := input(PC) + arbitration.flushAll setWhen(redoBranch.valid) + if(catchSomething) { exceptionBus.valid := False //cache.io.cpu.writeBack.mmuMiss || cache.io.cpu.writeBack.accessError || cache.io.cpu.writeBack.illegalAccess || cache.io.cpu.writeBack.unalignedAccess exceptionBus.badAddr := U(input(REGFILE_WRITE_DATA)) exceptionBus.code.assignDontCare() + } - redoBranch.valid := False - redoBranch.payload := input(PC) - arbitration.flushAll setWhen(redoBranch.valid) - when(arbitration.isValid && input(MEMORY_ENABLE)) { - if (catchAccessError) when(cache.io.cpu.writeBack.accessError) { - exceptionBus.valid := True - exceptionBus.code := (input(MEMORY_WR) ? U(7) | U(5)).resized - } + when(arbitration.isValid && input(MEMORY_ENABLE)) { + if (catchAccessError) when(cache.io.cpu.writeBack.accessError) { + exceptionBus.valid := True + exceptionBus.code := (input(MEMORY_WR) ? U(7) | U(5)).resized + } - if (catchUnaligned) when(cache.io.cpu.writeBack.unalignedAccess) { - exceptionBus.valid := True - exceptionBus.code := (input(MEMORY_WR) ? U(6) | U(4)).resized - } - when (cache.io.cpu.writeBack.mmuException) { - exceptionBus.valid := True - exceptionBus.code := (input(MEMORY_WR) ? U(15) | U(13)).resized - } - when(cache.io.cpu.redo) { - redoBranch.valid := True - exceptionBus.valid := False - } + if (catchUnaligned) when(cache.io.cpu.writeBack.unalignedAccess) { + exceptionBus.valid := True + exceptionBus.code := (input(MEMORY_WR) ? U(6) | U(4)).resized + } + if(catchIllegal) when (cache.io.cpu.writeBack.mmuException) { + exceptionBus.valid := True + exceptionBus.code := (input(MEMORY_WR) ? U(15) | U(13)).resized + } + + when(cache.io.cpu.redo) { + redoBranch.valid := True + if(catchSomething) exceptionBus.valid := False } } + arbitration.haltItself.setWhen(cache.io.cpu.writeBack.haltIt) val rspShifted = Bits(32 bits) diff --git a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala index 0823eaed..40323a59 100644 --- a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala @@ -253,6 +253,7 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l, cache.io.cpu.fetch.mmuBus.rsp.isIoAccess := False cache.io.cpu.fetch.mmuBus.rsp.exception := False cache.io.cpu.fetch.mmuBus.rsp.refilling := False + cache.io.cpu.fetch.mmuBus.busy := False } val flushStage = decode diff --git a/src/main/scala/vexriscv/plugin/StaticMemoryTranslatorPlugin.scala b/src/main/scala/vexriscv/plugin/StaticMemoryTranslatorPlugin.scala index 36db9e25..351ebc55 100644 --- a/src/main/scala/vexriscv/plugin/StaticMemoryTranslatorPlugin.scala +++ b/src/main/scala/vexriscv/plugin/StaticMemoryTranslatorPlugin.scala @@ -34,6 +34,7 @@ class StaticMemoryTranslatorPlugin(ioRange : UInt => Bool) extends Plugin[VexRis port.bus.rsp.isIoAccess := ioRange(port.bus.rsp.physicalAddress) port.bus.rsp.exception := False port.bus.rsp.refilling := False + port.bus.busy := False } } } diff --git a/src/test/cpp/raw/dcache/build/dcache.asm b/src/test/cpp/raw/dcache/build/dcache.asm index 9bc434d1..202a1e65 100644 --- a/src/test/cpp/raw/dcache/build/dcache.asm +++ b/src/test/cpp/raw/dcache/build/dcache.asm @@ -6,74 +6,73 @@ Disassembly of section .crt_section: 80000000 <_start>: 80000000: 00000097 auipc ra,0x0 -80000004: 0b808093 addi ra,ra,184 # 800000b8 -80000008: 30509073 csrw mtvec,ra +80000004: 0b408093 addi ra,ra,180 # 800000b4 -8000000c : -8000000c: 00100e13 li t3,1 -80000010: 00100093 li ra,1 -80000014: 00300113 li sp,3 -80000018: 00208093 addi ra,ra,2 -8000001c: 08209e63 bne ra,sp,800000b8 +80000008 : +80000008: 00100e13 li t3,1 +8000000c: 00100093 li ra,1 +80000010: 00300113 li sp,3 +80000014: 00208093 addi ra,ra,2 +80000018: 08209e63 bne ra,sp,800000b4 -80000020 : -80000020: 00200e13 li t3,2 -80000024: f56700b7 lui ra,0xf5670 -80000028: 900ff137 lui sp,0x900ff -8000002c: 40000313 li t1,1024 +8000001c : +8000001c: 00200e13 li t3,2 +80000020: f56700b7 lui ra,0xf5670 +80000024: 900ff137 lui sp,0x900ff +80000028: 40000313 li t1,1024 -80000030 : -80000030: 00100193 li gp,1 -80000034: 00200293 li t0,2 -80000038: 006303b3 add t2,t1,t1 -8000003c: 007181b3 add gp,gp,t2 -80000040: 007282b3 add t0,t0,t2 -80000044: 00312023 sw gp,0(sp) # 900ff000 -80000048: 0000a023 sw zero,0(ra) # f5670000 -8000004c: 00012203 lw tp,0(sp) -80000050: 06429463 bne t0,tp,800000b8 -80000054: ffc30313 addi t1,t1,-4 -80000058: 01008093 addi ra,ra,16 -8000005c: 01010113 addi sp,sp,16 -80000060: 0000500f 0x500f -80000064: fc0316e3 bnez t1,80000030 +8000002c : +8000002c: 00100193 li gp,1 +80000030: 00200293 li t0,2 +80000034: 006303b3 add t2,t1,t1 +80000038: 007181b3 add gp,gp,t2 +8000003c: 007282b3 add t0,t0,t2 +80000040: 00312023 sw gp,0(sp) # 900ff000 +80000044: 0000a023 sw zero,0(ra) # f5670000 +80000048: 00012203 lw tp,0(sp) +8000004c: 06429463 bne t0,tp,800000b4 +80000050: ffc30313 addi t1,t1,-4 +80000054: 01008093 addi ra,ra,16 +80000058: 01010113 addi sp,sp,16 +8000005c: 0000500f 0x500f +80000060: fc0316e3 bnez t1,8000002c -80000068 : -80000068: 00300e13 li t3,3 -8000006c: f56700b7 lui ra,0xf5670 -80000070: 900ff137 lui sp,0x900ff -80000074: 40000313 li t1,1024 +80000064 : +80000064: 00300e13 li t3,3 +80000068: f56700b7 lui ra,0xf5670 +8000006c: 900ff137 lui sp,0x900ff +80000070: 40000313 li t1,1024 -80000078 : -80000078: 00200193 li gp,2 -8000007c: 00300293 li t0,3 -80000080: 006303b3 add t2,t1,t1 -80000084: 007181b3 add gp,gp,t2 -80000088: 007282b3 add t0,t0,t2 -8000008c: 00012203 lw tp,0(sp) # 900ff000 -80000090: 00312023 sw gp,0(sp) -80000094: 0000a023 sw zero,0(ra) # f5670000 -80000098: 0000500f 0x500f -8000009c: 00012203 lw tp,0(sp) -800000a0: 00429c63 bne t0,tp,800000b8 -800000a4: ffc30313 addi t1,t1,-4 -800000a8: 01008093 addi ra,ra,16 -800000ac: 01010113 addi sp,sp,16 -800000b0: fc0314e3 bnez t1,80000078 -800000b4: 0100006f j 800000c4 +80000074 : +80000074: 00200193 li gp,2 +80000078: 00300293 li t0,3 +8000007c: 006303b3 add t2,t1,t1 +80000080: 007181b3 add gp,gp,t2 +80000084: 007282b3 add t0,t0,t2 +80000088: 00012203 lw tp,0(sp) # 900ff000 +8000008c: 00312023 sw gp,0(sp) +80000090: 0000a023 sw zero,0(ra) # f5670000 +80000094: 0000500f 0x500f +80000098: 00012203 lw tp,0(sp) +8000009c: 00429c63 bne t0,tp,800000b4 +800000a0: ffc30313 addi t1,t1,-4 +800000a4: 01008093 addi ra,ra,16 +800000a8: 01010113 addi sp,sp,16 +800000ac: fc0314e3 bnez t1,80000074 +800000b0: 0100006f j 800000c0 -800000b8 : -800000b8: f0100137 lui sp,0xf0100 -800000bc: f2410113 addi sp,sp,-220 # f00fff24 -800000c0: 01c12023 sw t3,0(sp) +800000b4 : +800000b4: f0100137 lui sp,0xf0100 +800000b8: f2410113 addi sp,sp,-220 # f00fff24 +800000bc: 01c12023 sw t3,0(sp) -800000c4 : -800000c4: f0100137 lui sp,0xf0100 -800000c8: f2010113 addi sp,sp,-224 # f00fff20 -800000cc: 00012023 sw zero,0(sp) +800000c0 : +800000c0: f0100137 lui sp,0xf0100 +800000c4: f2010113 addi sp,sp,-224 # f00fff20 +800000c8: 00012023 sw zero,0(sp) +800000cc: 00000013 nop 800000d0: 00000013 nop 800000d4: 00000013 nop 800000d8: 00000013 nop 800000dc: 00000013 nop 800000e0: 00000013 nop -800000e4: 00000013 nop diff --git a/src/test/cpp/raw/dcache/build/dcache.hex b/src/test/cpp/raw/dcache/build/dcache.hex index 9cbd4458..2bc8fe94 100644 --- a/src/test/cpp/raw/dcache/build/dcache.hex +++ b/src/test/cpp/raw/dcache/build/dcache.hex @@ -1,17 +1,17 @@ :0200000480007A -:10000000970000009380800B73905030130E100007 -:10001000930010001301300093802000639E20089D -:10002000130E2000B70067F537F10F90130300405F -:100030009301100093022000B3036300B3817100A9 -:10004000B38272002320310023A0000003220100AC -:10005000639442061303C3FF93800001130101015F -:100060000F500000E31603FC130E3000B70067F5D5 -:1000700037F10F90130300409301200093023000EA -:10008000B3036300B3817100B382720003220100E5 -:100090002320310023A000000F50000003220100A4 -:1000A000639C42001303C3FF93800001130101010D -:1000B000E31403FC6F000001370110F0130141F25B -:1000C0002320C101370110F0130101F223200100A8 +:10000000970000009380400B130E10009300100027 +:100010001301300093802000639E2008130E2000FF +:10002000B70067F537F10F901303004093011000FC +:1000300093022000B3036300B3817100B3827200A6 +:100040002320310023A00000032201006394420614 +:100050001303C3FF93800001130101010F5000003F +:10006000E31603FC130E3000B70067F537F10F906D +:10007000130300409301200093023000B303630098 +:10008000B3817100B382720003220100232031008A +:1000900023A000000F50000003220100639C4200D7 +:1000A0001303C3FF9380000113010101E31403FC58 +:1000B0006F000001370110F0130141F22320C1014C +:1000C000370110F0130101F223200100130000009A :1000D00013000000130000001300000013000000D4 -:0800E0001300000013000000F2 +:0400E0001300000009 :00000001FF diff --git a/src/test/cpp/raw/dcache/src/crt.S b/src/test/cpp/raw/dcache/src/crt.S index b5606946..054b1dd2 100644 --- a/src/test/cpp/raw/dcache/src/crt.S +++ b/src/test/cpp/raw/dcache/src/crt.S @@ -3,7 +3,7 @@ _start: la x1, fail - csrw mtvec, x1 + //csrw mtvec, x1 test1: //Dummy test li TEST_ID, 1 diff --git a/src/test/cpp/raw/icache/build/icache.asm b/src/test/cpp/raw/icache/build/icache.asm index 75214113..52808b95 100644 --- a/src/test/cpp/raw/icache/build/icache.asm +++ b/src/test/cpp/raw/icache/build/icache.asm @@ -6,48 +6,43 @@ Disassembly of section .crt_section: 80000000 <_start>: 80000000: 00000097 auipc ra,0x0 -80000004: 05408093 addi ra,ra,84 # 80000054 -80000008: 30509073 csrw mtvec,ra +80000004: 04408093 addi ra,ra,68 # 80000044 -8000000c : -8000000c: 00100e13 li t3,1 -80000010: 00100093 li ra,1 -80000014: 00300113 li sp,3 -80000018: 00208093 addi ra,ra,2 -8000001c: 02209c63 bne ra,sp,80000054 +80000008 : +80000008: 00100e13 li t3,1 +8000000c: 00100093 li ra,1 +80000010: 00300113 li sp,3 +80000014: 00208093 addi ra,ra,2 +80000018: 02209663 bne ra,sp,80000044 -80000020 : -80000020: 00200e13 li t3,2 -80000024: 01300093 li ra,19 -80000028: 00000117 auipc sp,0x0 -8000002c: 02410113 addi sp,sp,36 # 8000004c -80000030: 0100006f j 80000040 -80000034: 00000013 nop -80000038: 00000013 nop -8000003c: 00000013 nop +8000001c : +8000001c: 00200e13 li t3,2 +80000020: 01300093 li ra,19 +80000024: 00000117 auipc sp,0x0 +80000028: 01810113 addi sp,sp,24 # 8000003c +8000002c: 0040006f j 80000030 -80000040 : -80000040: 00112023 sw ra,0(sp) -80000044: 0000100f fence.i -80000048: 0040006f j 8000004c +80000030 : +80000030: 00112023 sw ra,0(sp) +80000034: 0000100f fence.i +80000038: 0040006f j 8000003c -8000004c : -8000004c: 0080006f j 80000054 -80000050: 0100006f j 80000060 +8000003c : +8000003c: 0080006f j 80000044 +80000040: 0100006f j 80000050 -80000054 : -80000054: f0100137 lui sp,0xf0100 -80000058: f2410113 addi sp,sp,-220 # f00fff24 -8000005c: 01c12023 sw t3,0(sp) +80000044 : +80000044: f0100137 lui sp,0xf0100 +80000048: f2410113 addi sp,sp,-220 # f00fff24 +8000004c: 01c12023 sw t3,0(sp) -80000060 : -80000060: f0100137 lui sp,0xf0100 -80000064: f2010113 addi sp,sp,-224 # f00fff20 -80000068: 00012023 sw zero,0(sp) +80000050 : +80000050: f0100137 lui sp,0xf0100 +80000054: f2010113 addi sp,sp,-224 # f00fff20 +80000058: 00012023 sw zero,0(sp) +8000005c: 00000013 nop +80000060: 00000013 nop +80000064: 00000013 nop +80000068: 00000013 nop 8000006c: 00000013 nop 80000070: 00000013 nop -80000074: 00000013 nop -80000078: 00000013 nop -8000007c: 00000013 nop -80000080: 00000013 nop - ... diff --git a/src/test/cpp/raw/icache/build/icache.hex b/src/test/cpp/raw/icache/build/icache.hex index 25eb34e0..50b97969 100644 --- a/src/test/cpp/raw/icache/build/icache.hex +++ b/src/test/cpp/raw/icache/build/icache.hex @@ -1,11 +1,10 @@ :0200000480007A -:10000000970000009380400573905030130E10004D -:10001000930010001301300093802000639C2002A5 -:10002000130E20009300300117010000130141025C -:100030006F00000113000000130000001300000017 -:10004000232011000F1000006F0040006F0080009F -:100050006F000001370110F0130141F22320C101AC -:10006000370110F0130101F22320010013000000FA -:100070001300000013000000130000001300000034 -:10008000130000000000000000000000000000005D +:100000009700000093804004130E1000930010002E +:10001000130130009380200063962002130E20000D +:100020009300300117010000130181016F004000AF +:10003000232011000F1000006F0040006F008000AF +:100040006F000001370110F0130141F22320C101BC +:10005000370110F0130101F223200100130000000A +:100060001300000013000000130000001300000044 +:040070001300000079 :00000001FF diff --git a/src/test/cpp/raw/icache/src/crt.S b/src/test/cpp/raw/icache/src/crt.S index 695c45bb..986a741c 100644 --- a/src/test/cpp/raw/icache/src/crt.S +++ b/src/test/cpp/raw/icache/src/crt.S @@ -3,7 +3,7 @@ _start: la x1, fail - csrw mtvec, x1 + // csrw mtvec, x1 test1: //Dummy test li TEST_ID, 1 diff --git a/src/test/cpp/raw/machineCsr/build/machineCsr.asm b/src/test/cpp/raw/machineCsr/build/machineCsr.asm index c480c266..4d80d753 100644 --- a/src/test/cpp/raw/machineCsr/build/machineCsr.asm +++ b/src/test/cpp/raw/machineCsr/build/machineCsr.asm @@ -29,26 +29,26 @@ Disassembly of section .crt_section: 80000044: 01de7f33 and t5,t3,t4 80000048: 000f1863 bnez t5,80000058 8000004c: 34102ef3 csrr t4,mepc -80000050: 004e8e93 addi t4,t4,4 # 80000004 <_start+0xffffff70> +80000050: 004e8e93 addi t4,t4,4 # 80000004 80000054: 341e9073 csrw mepc,t4 80000058 : 80000058: 80000eb7 lui t4,0x80000 -8000005c: 003e8e93 addi t4,t4,3 # 80000003 <_start+0xffffff6f> +8000005c: 003e8e93 addi t4,t4,3 # 80000003 80000060: 01ce9863 bne t4,t3,80000070 80000064: f0013c37 lui s8,0xf0013 80000068: 00000c93 li s9,0 -8000006c: 019c2023 sw s9,0(s8) # f0013000 <_start+0x70012f6c> +8000006c: 019c2023 sw s9,0(s8) # f0013000 80000070 : 80000070: 80000eb7 lui t4,0x80000 -80000074: 007e8e93 addi t4,t4,7 # 80000007 <_start+0xffffff73> +80000074: 007e8e93 addi t4,t4,7 # 80000007 80000078: 01ce9463 bne t4,t3,80000080 8000007c: 30405073 csrwi mie,0 80000080 : 80000080: 80000eb7 lui t4,0x80000 -80000084: 00be8e93 addi t4,t4,11 # 8000000b <_start+0xffffff77> +80000084: 00be8e93 addi t4,t4,11 # 8000000b 80000088: 01ce9463 bne t4,t3,80000090 8000008c: 30405073 csrwi mie,0 @@ -65,7 +65,7 @@ Disassembly of section .crt_section: 800000ac: 30429073 csrw mie,t0 800000b0: f0013c37 lui s8,0xf0013 800000b4: 00100c93 li s9,1 -800000b8: 019c2023 sw s9,0(s8) # f0013000 <_start+0x70012f6c> +800000b8: 019c2023 sw s9,0(s8) # f0013000 800000bc: 00000013 nop 800000c0: 00000013 nop 800000c4: 00000013 nop @@ -101,7 +101,7 @@ Disassembly of section .crt_section: 8000013c: 00000013 nop 80000140: 00500e13 li t3,5 80000144: f01001b7 lui gp,0xf0100 -80000148: f4018193 addi gp,gp,-192 # f00fff40 <_start+0x700ffeac> +80000148: f4018193 addi gp,gp,-192 # f00fff40 8000014c: 0001a203 lw tp,0(gp) 80000150: 0041a283 lw t0,4(gp) 80000154: 3ff20213 addi tp,tp,1023 # 3ff @@ -124,15 +124,18 @@ Disassembly of section .crt_section: 80000198: 00c00e13 li t3,12 8000019c: 00d00e13 li t3,13 800001a0: 00002083 lw ra,0(zero) # 0 -800001a4: 00002083 lw ra,0(zero) # 0 -800001a8: 00e00e13 li t3,14 -800001ac: 20200073 hret -800001b0: 00f00e13 li t3,15 -800001b4: f01000b7 lui ra,0xf0100 -800001b8: f6008093 addi ra,ra,-160 # f00fff60 <_start+0x700ffecc> -800001bc: 0000a103 lw sp,0(ra) -800001c0: 01000e13 li t3,16 -800001c4: 0020a023 sw sp,0(ra) -800001c8: 01100e13 li t3,17 -800001cc: 00008067 ret + +800001a4 : +800001a4: 0020006f j 800001a6 +800001a8: 00002083 lw ra,0(zero) # 0 +800001ac: 00e00e13 li t3,14 +800001b0: 20200073 hret +800001b4: 00f00e13 li t3,15 +800001b8: f01000b7 lui ra,0xf0100 +800001bc: f6008093 addi ra,ra,-160 # f00fff60 +800001c0: 0000a103 lw sp,0(ra) +800001c4: 01000e13 li t3,16 +800001c8: 0020a023 sw sp,0(ra) +800001cc: 01100e13 li t3,17 +800001d0: 00008067 ret ... diff --git a/src/test/cpp/raw/machineCsr/build/machineCsr.hex b/src/test/cpp/raw/machineCsr/build/machineCsr.hex index 9a59bd18..d104c88d 100644 --- a/src/test/cpp/raw/machineCsr/build/machineCsr.hex +++ b/src/test/cpp/raw/machineCsr/build/machineCsr.hex @@ -25,9 +25,9 @@ :1001700073005010130E80009301100023A0410063 :10018000130E900023904100130EA00003A2010063 :10019000130EB00003920100130EC000130ED00026 -:1001A0008320000083200000130EE0007300202055 -:1001B000130EF000B70010F0938000F603A10000CA -:1001C000130E000123A02000130E10016780000011 -:1001D000000000000000000000000000000000001F +:1001A000832000006F00200083200000130EE00079 +:1001B00073002020130EF000B70010F0938000F6BB +:1001C00003A10000130E000123A02000130E100154 +:1001D0006780000000000000000000000000000038 :0400000580000094E3 :00000001FF diff --git a/src/test/cpp/raw/machineCsr/makefile b/src/test/cpp/raw/machineCsr/makefile index f43d48d7..4fc2c845 100644 --- a/src/test/cpp/raw/machineCsr/makefile +++ b/src/test/cpp/raw/machineCsr/makefile @@ -1,5 +1,6 @@ ifeq ($(COMPRESSED),yes) PROJ_NAME=machineCsrCompressed + CFLAGS=-DCOMPRESSED else PROJ_NAME=machineCsr endif diff --git a/src/test/cpp/raw/machineCsr/src/crt.S b/src/test/cpp/raw/machineCsr/src/crt.S index 9d1ee5fd..bbe966d5 100644 --- a/src/test/cpp/raw/machineCsr/src/crt.S +++ b/src/test/cpp/raw/machineCsr/src/crt.S @@ -124,7 +124,7 @@ _start: li x28, 13 lw x1,0(x0) -#ifdef COMPRESSED +#ifndef COMPRESSED unalignedPcA: j unalignedPcA+2 #endif From fd42e7701e1246cc7ae04a920baa1403897dc761 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Tue, 9 Apr 2019 01:22:32 +0200 Subject: [PATCH 130/951] Add hardware AMO, require AMO=yes in sim and withAmo=true in linux.scala --- src/main/scala/vexriscv/Riscv.scala | 10 ++ src/main/scala/vexriscv/ip/DataCache.scala | 110 +++++++++++------- .../vexriscv/plugin/DBusCachedPlugin.scala | 73 +++++++----- src/test/cpp/regression/main.cpp | 69 +++++++++-- src/test/cpp/regression/makefile | 14 ++- 5 files changed, 196 insertions(+), 80 deletions(-) diff --git a/src/main/scala/vexriscv/Riscv.scala b/src/main/scala/vexriscv/Riscv.scala index 06e666d8..91cf876b 100644 --- a/src/main/scala/vexriscv/Riscv.scala +++ b/src/main/scala/vexriscv/Riscv.scala @@ -62,6 +62,16 @@ object Riscv{ def LR = M"00010--00000-----010-----0101111" def SC = M"00011------------010-----0101111" + def AMOSWAP = M"00001------------010-----0101111" + def AMOADD = M"00000------------010-----0101111" + def AMOXOR = M"00100------------010-----0101111" + def AMOAND = M"01100------------010-----0101111" + def AMOOR = M"01000------------010-----0101111" + def AMOMIN = M"10000------------010-----0101111" + def AMOMAX = M"10100------------010-----0101111" + def AMOMINU = M"11000------------010-----0101111" + def AMOMAXU = M"11100------------010-----0101111" + def BEQ (rvc : Boolean) = if(rvc) M"-----------------000-----1100011" else M"-----------------000---0-1100011" def BNE (rvc : Boolean) = if(rvc) M"-----------------001-----1100011" else M"-----------------001---0-1100011" def BLT (rvc : Boolean) = if(rvc) M"-----------------100-----1100011" else M"-----------------100---0-1100011" diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index 0932b54a..5726cdd0 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -21,7 +21,8 @@ case class DataCacheConfig(cacheSize : Int, earlyWaysHits : Boolean = true, earlyDataMux : Boolean = false, tagSizeShift : Int = 0, //Used to force infering ram - withLrSc : Boolean = false){ + withLrSc : Boolean = false, + withAmo : Boolean = false){ assert(!(earlyDataMux && !earlyWaysHits)) def burstSize = bytePerLine*8/memDataWidth @@ -83,12 +84,15 @@ case class DataCacheCpuExecute(p : DataCacheConfig) extends Bundle with IMasterS case class DataCacheCpuExecuteArgs(p : DataCacheConfig) extends Bundle{ val wr = Bool - //val address = UInt(p.addressWidth bit) Given on the side, as it's also part of the main pipeline val data = Bits(p.cpuDataWidth bit) val size = UInt(2 bits) - val forceUncachedAccess = Bool - val isAtomic = ifGen(p.withLrSc){Bool} - // val all = Bool //Address should be zero when "all" is used + val forceUncachedAccess = Bool() + val isLrsc = p.withLrSc generate Bool() + val isAmo = p.withAmo generate Bool() + val amoCtrl = p.withAmo generate new Bundle { + val swap = Bool() + val alu = Bits(3 bits) + } } case class DataCacheCpuMemory(p : DataCacheConfig) extends Bundle with IMasterSlave{ @@ -114,14 +118,14 @@ case class DataCacheCpuWriteBack(p : DataCacheConfig) extends Bundle with IMaste val data = Bits(p.cpuDataWidth bit) val address = UInt(p.addressWidth bit) val mmuException, unalignedAccess , accessError = Bool - val clearAtomicEntries = ifGen(p.withLrSc) {Bool} + val clearLrsc = ifGen(p.withLrSc) {Bool} // val exceptionBus = if(p.catchSomething) Flow(ExceptionCause()) else null override def asMaster(): Unit = { out(isValid,isStuck,isUser, address) in(haltIt, data, mmuException, unalignedAccess, accessError, isWrite) - outWithNull(clearAtomicEntries) + outWithNull(clearLrsc) } } @@ -347,9 +351,6 @@ class DataCache(p : DataCacheConfig) extends Component{ - io.mem.cmd.valid := False - io.mem.cmd.payload.assignDontCare() - val ways = for(i <- 0 until wayCount) yield new Area{ val tags = Mem(new LineInfo(), wayLineCount) val data = Mem(Bits(wordWidth bit), wayWordCount) @@ -465,78 +466,104 @@ class DataCache(p : DataCacheConfig) extends Component{ } - val atomic = withLrSc generate new Area{ - case class AtomicEntry() extends Bundle{ - val valid = Bool() - val address = UInt(addressWidth bits) - - def init: this.type ={ - valid init(False) - this - } - } + val lrsc = withLrSc generate new Area{ val reserved = RegInit(False) - when(io.cpu.writeBack.isValid && !io.cpu.writeBack.isStuck && !io.cpu.redo && request.isAtomic && !request.wr){ + when(io.cpu.writeBack.isValid && !io.cpu.writeBack.isStuck && !io.cpu.redo && request.isLrsc && !request.wr){ reserved := True } - when(io.cpu.writeBack.clearAtomicEntries){ + when(io.cpu.writeBack.clearLrsc){ reserved := False } } - val memCmdSent = RegInit(False) setWhen (io.mem.cmd.ready) clearWhen (!io.cpu.writeBack.isStuck) + val requestDataBypass = CombInit(request.data) + val isAmo = if(withAmo) request.isAmo else False + val amo = withAmo generate new Area{ + def rf = request.data + def mem = dataMux + val compare = request.amoCtrl.alu.msb + val unsigned = request.amoCtrl.alu(2 downto 1) === B"11" + val addSub = (rf.asSInt + Mux(compare, ~mem, mem).asSInt + Mux(compare, S(1), S(0))).asBits + val less = Mux(rf.msb === mem.msb, addSub.msb, Mux(unsigned, mem.msb, rf.msb)) + val selectRf = request.amoCtrl.swap ? True | (request.amoCtrl.alu.lsb ^ less) + + val result = (request.amoCtrl.alu | (request.amoCtrl.swap ## B"00")).mux( + B"000" -> addSub, + B"001" -> (rf ^ mem), + B"010" -> (rf | mem), + B"011" -> (rf & mem), + default -> (selectRf ? rf | mem) + ) + val resultRegValid = RegNext(True) clearWhen(!io.cpu.writeBack.isStuck) + val resultReg = RegNext(result) + } + + + val memCmdSent = RegInit(False) setWhen (io.mem.cmd.ready) clearWhen (!io.cpu.writeBack.isStuck) io.cpu.redo := False io.cpu.writeBack.accessError := False - io.cpu.writeBack.mmuException := io.cpu.writeBack.isValid && (if(catchIllegal) mmuRsp.exception || (!mmuRsp.allowWrite && request.wr) || (!mmuRsp.allowRead && !request.wr) else False) + io.cpu.writeBack.mmuException := io.cpu.writeBack.isValid && (if(catchIllegal) mmuRsp.exception || (!mmuRsp.allowWrite && request.wr) || (!mmuRsp.allowRead && (!request.wr || isAmo)) else False) io.cpu.writeBack.unalignedAccess := io.cpu.writeBack.isValid && (if(catchUnaligned) ((request.size === 2 && mmuRsp.physicalAddress(1 downto 0) =/= 0) || (request.size === 1 && mmuRsp.physicalAddress(0 downto 0) =/= 0)) else False) io.cpu.writeBack.isWrite := request.wr + io.mem.cmd.valid := False + io.mem.cmd.address.assignDontCare() + io.mem.cmd.length.assignDontCare() + io.mem.cmd.last.assignDontCare() + io.mem.cmd.wr := request.wr + io.mem.cmd.mask := mask + io.mem.cmd.data := requestDataBypass + when(io.cpu.writeBack.isValid) { when(request.forceUncachedAccess || mmuRsp.isIoAccess) { io.cpu.writeBack.haltIt.clearWhen(request.wr ? io.mem.cmd.ready | io.mem.rsp.valid) io.mem.cmd.valid := !memCmdSent - io.mem.cmd.wr := request.wr io.mem.cmd.address := mmuRsp.physicalAddress(tagRange.high downto wordRange.low) @@ U(0, wordRange.low bit) - io.mem.cmd.mask := mask - io.mem.cmd.data := request.data io.mem.cmd.length := 0 io.mem.cmd.last := True - if(withLrSc) when(request.isAtomic && !atomic.reserved){ + if(withLrSc) when(request.isLrsc && !lrsc.reserved){ io.mem.cmd.valid := False io.cpu.writeBack.haltIt := False } } otherwise { - when(waysHit || request.wr) { //Do not require a cache refill ? + when(waysHit || request.wr && !isAmo) { //Do not require a cache refill ? //Data cache update dataWriteCmd.valid setWhen(request.wr && waysHit) dataWriteCmd.address := mmuRsp.physicalAddress(lineRange.high downto wordRange.low) - dataWriteCmd.data := request.data + dataWriteCmd.data := requestDataBypass dataWriteCmd.mask := mask dataWriteCmd.way := waysHits //Write through io.mem.cmd.valid setWhen(request.wr) - io.mem.cmd.wr := True io.mem.cmd.address := mmuRsp.physicalAddress(tagRange.high downto wordRange.low) @@ U(0, wordRange.low bit) - io.mem.cmd.mask := mask - io.mem.cmd.data := request.data io.mem.cmd.length := 0 io.mem.cmd.last := True io.cpu.writeBack.haltIt clearWhen(!request.wr || io.mem.cmd.ready) - //On write to read colisions - io.cpu.redo := !request.wr && (colisions & waysHits) =/= 0 + if(withAmo) when(isAmo){ + when(!amo.resultRegValid) { + io.mem.cmd.valid := False + dataWriteCmd.valid := False + io.cpu.writeBack.haltIt := True + } + } - if(withLrSc) when(request.isAtomic && !atomic.reserved){ + //On write to read colisions + when((!request.wr || isAmo) && (colisions & waysHits) =/= 0){ + io.cpu.redo := True + if(withAmo) io.mem.cmd.valid := False + } + + if(withLrSc) when(request.isLrsc && !lrsc.reserved){ io.mem.cmd.valid := False dataWriteCmd.valid := False io.cpu.writeBack.haltIt := False } } otherwise { //Do refill - //Emit cmd io.mem.cmd.valid setWhen(!memCmdSent) io.mem.cmd.wr := False @@ -570,8 +597,13 @@ 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") if(withLrSc){ - when(request.isAtomic && request.wr){ - io.cpu.writeBack.data := (!atomic.reserved).asBits.resized + when(request.isLrsc && request.wr){ + io.cpu.writeBack.data := (!lrsc.reserved).asBits.resized + } + } + if(withAmo){ + when(request.isAmo){ + requestDataBypass := amo.resultReg } } } diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index dc0dc162..8b8d8072 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -46,7 +46,8 @@ class DBusCachedPlugin(config : DataCacheConfig, object MEMORY_MANAGMENT extends Stageable(Bool) object MEMORY_WR extends Stageable(Bool) object MEMORY_ADDRESS_LOW extends Stageable(UInt(2 bits)) - object MEMORY_ATOMIC extends Stageable(Bool) + object MEMORY_LRSC extends Stageable(Bool) + object MEMORY_AMO extends Stageable(Bool) object IS_DBUS_SHARING extends Stageable(Bool()) override def setup(pipeline: VexRiscv): Unit = { @@ -85,13 +86,13 @@ class DBusCachedPlugin(config : DataCacheConfig, if(withLrSc){ List(LB, LH, LW, LBU, LHU, LWU, SB, SH, SW).foreach(e => - decoderService.add(e, Seq(MEMORY_ATOMIC -> False)) + decoderService.add(e, Seq(MEMORY_LRSC -> False)) ) decoderService.add( key = LR, values = loadActions.filter(_._1 != SRC2_CTRL) ++ Seq( SRC_ADD_ZERO -> True, - MEMORY_ATOMIC -> True + MEMORY_LRSC -> True ) ) decoderService.add( @@ -101,11 +102,37 @@ class DBusCachedPlugin(config : DataCacheConfig, REGFILE_WRITE_VALID -> True, BYPASSABLE_EXECUTE_STAGE -> False, BYPASSABLE_MEMORY_STAGE -> False, - MEMORY_ATOMIC -> True + MEMORY_LRSC -> True ) ) } + if(withAmo){ + List(LB, LH, LW, LBU, LHU, LWU, SB, SH, SW).foreach(e => + decoderService.add(e, Seq(MEMORY_AMO -> False)) + ) + val amoActions = storeActions.filter(_._1 != SRC2_CTRL) ++ Seq( + SRC_ADD_ZERO -> True, + REGFILE_WRITE_VALID -> True, + BYPASSABLE_EXECUTE_STAGE -> False, + BYPASSABLE_MEMORY_STAGE -> False, + MEMORY_AMO -> True + ) + + for(i <- List(AMOSWAP, AMOADD, AMOXOR, AMOAND, AMOOR, AMOMIN, AMOMAX, AMOMINU, AMOMAXU)){ + decoderService.add(i, amoActions) + } + } + + if(withAmo && withLrSc){ + for(i <- List(AMOSWAP, AMOADD, AMOXOR, AMOAND, AMOOR, AMOMIN, AMOMAX, AMOMINU, AMOMAXU)){ + decoderService.add(i, List(MEMORY_LRSC -> False)) + } + for(i <- List(LR, SC)){ + decoderService.add(i, List(MEMORY_AMO -> False)) + } + } + def MANAGEMENT = M"-------00000-----101-----0001111" decoderService.addDefault(MEMORY_MANAGMENT, False) @@ -123,26 +150,6 @@ class DBusCachedPlugin(config : DataCacheConfig, if(pipeline.serviceExist(classOf[PrivilegeService])) privilegeService = pipeline.service(classOf[PrivilegeService]) - -// if(pipeline.serviceExist(classOf[ReportService])){ -// val report = pipeline.service(classOf[ReportService]) -// report.add("dBus" -> { -// val e = new BusReport() -// val c = new CacheReport() -// e.kind = "cached" -// e.flushInstructions.add(0x13 | (1 << 7)) ////ADDI x1, x0, 0 -// for(idx <- 0 until cacheSize by bytePerLine){ -// e.flushInstructions.add(0x7000500F + (1 << 15)) //Clean invalid data cache way x1 -// e.flushInstructions.add(0x13 + (1 << 7) + (1 << 15) + (bytePerLine << 20)) //ADDI x1, x1, 32 -// } -// -// e.info = c -// c.size = cacheSize -// c.bytePerLine = bytePerLine -// -// e -// }) -// } } override def build(pipeline: VexRiscv): Unit = { @@ -182,16 +189,23 @@ class DBusCachedPlugin(config : DataCacheConfig, cache.io.cpu.execute.args.size := size cache.io.cpu.execute.args.forceUncachedAccess := False + cache.io.cpu.flush.valid := arbitration.isValid && input(MEMORY_MANAGMENT) arbitration.haltItself setWhen(cache.io.cpu.flush.isStall) if(withLrSc) { - cache.io.cpu.execute.args.isAtomic := False - when(input(MEMORY_ATOMIC)){ - cache.io.cpu.execute.args.isAtomic := True + cache.io.cpu.execute.args.isLrsc := False + when(input(MEMORY_LRSC)){ + cache.io.cpu.execute.args.isLrsc := True } } + if(withAmo){ + cache.io.cpu.execute.isAmo := input(MEMORY_AMO) + cache.io.cpu.execute.amoCtrl.alu := input(INSTRUCTION)(31 downto 29) + cache.io.cpu.execute.amoCtrl.swap := input(INSTRUCTION)(27) + } + insert(MEMORY_ADDRESS_LOW) := cache.io.cpu.execute.address(1 downto 0) when(cache.io.cpu.redo && arbitration.isValid && input(MEMORY_ENABLE)){ @@ -215,7 +229,7 @@ class DBusCachedPlugin(config : DataCacheConfig, cache.io.cpu.writeBack.isStuck := arbitration.isStuck cache.io.cpu.writeBack.isUser := (if(privilegeService != null) privilegeService.isUser() else False) cache.io.cpu.writeBack.address := U(input(REGFILE_WRITE_DATA)) - if(withLrSc) cache.io.cpu.writeBack.clearAtomicEntries := service(classOf[IContextSwitching]).isContextSwitching + if(withLrSc) cache.io.cpu.writeBack.clearLrsc := service(classOf[IContextSwitching]).isContextSwitching redoBranch.valid := False redoBranch.payload := input(PC) @@ -285,7 +299,8 @@ class DBusCachedPlugin(config : DataCacheConfig, cache.io.cpu.execute.args.data := dBusAccess.cmd.data cache.io.cpu.execute.args.size := dBusAccess.cmd.size cache.io.cpu.execute.args.forceUncachedAccess := False - if(withLrSc) cache.io.cpu.execute.args.isAtomic := False + if(withLrSc) cache.io.cpu.execute.args.isLrsc := False + if(withAmo) cache.io.cpu.execute.args.isAmo := False cache.io.cpu.execute.address := dBusAccess.cmd.address //Will only be 12 muxes forceDatapath := True } diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 5630ba64..a6f43bf5 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -234,6 +234,7 @@ public: int32_t pc, lastPc; uint32_t lastInstruction; int32_t regs[32]; + uint64_t stepCounter; uint32_t mscratch, sscratch; uint32_t misa; @@ -400,6 +401,7 @@ public: satp.mode = 0; ipSoft = 0; ipInput = 0; + stepCounter = 0; } virtual void rfWrite(int32_t address, int32_t data) { @@ -422,7 +424,7 @@ public: virtual bool dRead(int32_t address, int32_t size, uint32_t *data) = 0; virtual void dWrite(int32_t address, int32_t size, uint32_t data) = 0; - enum AccessKind {READ,WRITE,EXECUTE}; + enum AccessKind {READ,WRITE,EXECUTE,READ_WRITE}; virtual bool isMmuRegion(uint32_t v) = 0; bool v2p(uint32_t v, uint32_t *p, AccessKind kind){ uint32_t effectivePrivilege = status.mprv && kind != EXECUTE ? status.mpp : privilege; @@ -441,11 +443,10 @@ public: if(!tlb.u && effectivePrivilege == 0) return true; if( tlb.u && effectivePrivilege == 1 && !status.sum) return true; if(superPage && tlb.ppn0 != 0) return true; - switch(kind){ - case READ: if(!tlb.r && !(status.mxr && tlb.x)) return true; break; - case WRITE: if(!tlb.w) return true; break; - case EXECUTE: if(!tlb.x) return true; break; - } + if(kind == READ || kind == READ_WRITE) if(!tlb.r && !(status.mxr && tlb.x)) return true; + if(kind == WRITE || kind == READ_WRITE) if(!tlb.w) return true; + if(kind == EXECUTE) if(!tlb.x) return true; + *p = (tlb.ppn1 << 22) | (superPage ? v & 0x3FF000 : tlb.ppn0 << 12) | (v & 0xFFF); } return false; @@ -654,6 +655,7 @@ public: virtual void step() { + stepCounter++; livenessStep = 0; #define rd32 ((i >> 7) & 0x1F) #define iBits(lo, len) ((i >> lo) & ((1 << len)-1)) @@ -907,7 +909,39 @@ public: pcWrite(pc + 4); } } break; - default: ilegalInstruction(); break; + default: { + #ifndef AMO + ilegalInstruction(); + #else + uint32_t sel = (i >> 27) & 0x1F; + uint32_t addr = i32_rs1; + int32_t src = i32_rs2; + int32_t readValue; + + uint32_t pAddr; + if(v2p(addr, &pAddr, READ_WRITE)){ trap(0, 15, addr); return; } + if(dRead(pAddr, 4, (uint32_t*)&readValue)){ + trap(0, 15, addr); return; + return; + } + int writeValue; + switch(sel){ + case 0x0: writeValue = src + readValue; break; + case 0x1: writeValue = src; break; + case 0x4: writeValue = src ^ readValue; break; + case 0xC: writeValue = src & readValue; break; + case 0x8: writeValue = src | readValue; break; + case 0x10: writeValue = min(src, readValue); break; + case 0x14: writeValue = max(src, readValue); break; + case 0x18: writeValue = min((unsigned int)src, (unsigned int)readValue); break; + case 0x1C: writeValue = max((unsigned int)src, (unsigned int)readValue); break; + default: ilegalInstruction(); return; break; + } + dWrite(pAddr, 4, writeValue); + rfWrite(rd32, readValue); + pcWrite(pc + 4); + #endif + } break; } break; default: ilegalInstruction(); break; @@ -1374,6 +1408,8 @@ public: if(i >= TRACE_START) tfp->dump(i); #endif } + + uint64_t privilegeCounters[4] = {0,0,0,0}; Workspace* run(uint64_t timeout = 5000){ // cout << "Start " << name << endl; if(timeout == 0) timeout = 0x7FFFFFFFFFFFFFFF; @@ -1513,6 +1549,13 @@ public: #endif if(top->VexRiscv->writeBack_arbitration_isFiring){ if(riscvRefEnable) { +// privilegeCounters[riscvRef.privilege]++; +// if((riscvRef.stepCounter & 0xFFFFF) == 0){ +// cout << "privilege report" << endl; +// cout << "- U " << privilegeCounters[0] << endl; +// cout << "- S " << privilegeCounters[1] << endl; +// cout << "- M " << privilegeCounters[3] << endl; +// } riscvRef.step(); bool mIntTimer = false; bool mIntExt = false; @@ -3456,7 +3499,8 @@ int main(int argc, char **argv, char **env) { ->setDStall(true) ->bootAt(0x80000000) ->run(0); -// ->run(1173000000l ); +// ->run((496300000l + 2000000) / 2); +// ->run(438700000l/2); #endif // #ifdef MMU @@ -3474,6 +3518,7 @@ int main(int argc, char **argv, char **env) { #ifdef RUN_HEX //w.loadHex("/home/spinalvm/hdl/zephyr/zephyrSpinalHdl/samples/synchronization/build/zephyr/zephyr.hex"); w.loadHex(RUN_HEX); + w.withRiscvRef(); #endif w.noInstructionReadCheck(); //w.setIStall(false); @@ -3611,18 +3656,22 @@ int main(int argc, char **argv, char **env) { Dhrystone("dhrystoneO3MC_Stall","dhrystoneO3MC",true,true).run(1.9e6); #endif #endif - Dhrystone("dhrystoneO3","dhrystoneO3",false,false).run(1.9e6); #if defined(COMPRESSED) Dhrystone("dhrystoneO3C","dhrystoneO3C",false,false).run(1.9e6); #endif + Dhrystone("dhrystoneO3","dhrystoneO3",false,false).run(1.9e6); #if defined(MUL) && defined(DIV) - Dhrystone("dhrystoneO3M","dhrystoneO3M",false,false).run(1.9e6); #if defined(COMPRESSED) Dhrystone("dhrystoneO3MC","dhrystoneO3MC",false,false).run(1.9e6); #endif + Dhrystone("dhrystoneO3M","dhrystoneO3M",false,false).run(1.9e6); #endif #endif + #ifdef COREMARK + Dhrystone("coremark","/home/miaou/pro/riscv/coremark/coremark",false,false).run(1.9e6); + + #endif #ifdef FREERTOS #ifdef SEED diff --git a/src/test/cpp/regression/makefile b/src/test/cpp/regression/makefile index b4330c51..b178fee5 100644 --- a/src/test/cpp/regression/makefile +++ b/src/test/cpp/regression/makefile @@ -15,6 +15,7 @@ FENCEI?=no MMU?=yes SEED?=no ATOMIC?=no +AMO?=no NO_STALL?=no DEBUG_PLUGIN?=STD DEBUG_PLUGIN_EXTERNAL?=no @@ -32,7 +33,7 @@ MTIME_INSTR_FACTOR?=no COMPRESSED?=no SUPERVISOR?=no STOP_ON_ERROR?=no - +COREMARK=no ADDCFLAGS += -CFLAGS -DIBUS_${IBUS} ADDCFLAGS += -CFLAGS -DDBUS_${DBUS} @@ -42,7 +43,7 @@ ADDCFLAGS += -CFLAGS -pthread ADDCFLAGS += -CFLAGS -DTHREAD_COUNT=${THREAD_COUNT} ifeq ($(DEBUG),yes) - ADDCFLAGS += -CFLAGS -O0 -CFLAGS -g + ADDCFLAGS += -CFLAGS -Og -CFLAGS -g else ADDCFLAGS += -CFLAGS -O3 -O3 endif @@ -70,6 +71,11 @@ ifeq ($(FLOW_INFO),yes) endif +ifeq ($(COREMARK),yes) + ADDCFLAGS += -CFLAGS -DCOREMARK +endif + + ifneq ($(shell grep timerInterrupt ../../../../VexRiscv.v -w),) ADDCFLAGS += -CFLAGS -DTIMER_INTERRUPT @@ -141,6 +147,10 @@ ifeq ($(ATOMIC),yes) ADDCFLAGS += -CFLAGS -DATOMIC endif +ifeq ($(AMO),yes) + ADDCFLAGS += -CFLAGS -DAMO +endif + ifeq ($(CUSTOM_SIMD_ADD),yes) ADDCFLAGS += -CFLAGS -DCUSTOM_SIMD_ADD endif From a6dc53044140971f1427c451f159fcea61931784 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Tue, 9 Apr 2019 19:27:42 +0200 Subject: [PATCH 131/951] Added lrsc/amo tests --- src/test/cpp/raw/amo/.gitignore | 4 + src/test/cpp/raw/amo/build/amo.asm | 247 +++++++++++++++++++++++++ src/test/cpp/raw/amo/build/amo.hex | 45 +++++ src/test/cpp/raw/amo/makefile | 5 + src/test/cpp/raw/amo/src/crt.S | 174 ++++++++++++++++++ src/test/cpp/raw/amo/src/ld | 16 ++ src/test/cpp/raw/common/asm.mk | 5 +- src/test/cpp/raw/lrsc/.gitignore | 4 + src/test/cpp/raw/lrsc/build/lrsc.asm | 217 ++++++++++++++++++++++ src/test/cpp/raw/lrsc/build/lrsc.hex | 53 ++++++ src/test/cpp/raw/lrsc/makefile | 5 + src/test/cpp/raw/lrsc/src/crt.S | 265 +++++++++++++++++++++++++++ src/test/cpp/raw/lrsc/src/ld | 16 ++ src/test/cpp/regression/main.cpp | 8 +- src/test/cpp/regression/makefile | 6 +- 15 files changed, 1064 insertions(+), 6 deletions(-) create mode 100644 src/test/cpp/raw/amo/.gitignore create mode 100644 src/test/cpp/raw/amo/build/amo.asm create mode 100644 src/test/cpp/raw/amo/build/amo.hex create mode 100644 src/test/cpp/raw/amo/makefile create mode 100644 src/test/cpp/raw/amo/src/crt.S create mode 100644 src/test/cpp/raw/amo/src/ld create mode 100644 src/test/cpp/raw/lrsc/.gitignore create mode 100644 src/test/cpp/raw/lrsc/build/lrsc.asm create mode 100644 src/test/cpp/raw/lrsc/build/lrsc.hex create mode 100644 src/test/cpp/raw/lrsc/makefile create mode 100644 src/test/cpp/raw/lrsc/src/crt.S create mode 100644 src/test/cpp/raw/lrsc/src/ld diff --git a/src/test/cpp/raw/amo/.gitignore b/src/test/cpp/raw/amo/.gitignore new file mode 100644 index 00000000..c12cb2c2 --- /dev/null +++ b/src/test/cpp/raw/amo/.gitignore @@ -0,0 +1,4 @@ +*.map +*.v +*.elf +*.o \ No newline at end of file diff --git a/src/test/cpp/raw/amo/build/amo.asm b/src/test/cpp/raw/amo/build/amo.asm new file mode 100644 index 00000000..d86b61ca --- /dev/null +++ b/src/test/cpp/raw/amo/build/amo.asm @@ -0,0 +1,247 @@ + +build/amo.elf: file format elf32-littleriscv + + +Disassembly of section .crt_section: + +80000000 <_start>: +80000000: 00100e13 li t3,1 +80000004: 00000097 auipc ra,0x0 +80000008: 27408093 addi ra,ra,628 # 80000278 +8000000c: 02d00113 li sp,45 +80000010: 0820a1af amoswap.w gp,sp,(ra) +80000014: 0000a203 lw tp,0(ra) +80000018: 02d00a13 li s4,45 +8000001c: 224a1663 bne s4,tp,80000248 +80000020: 00b00a13 li s4,11 +80000024: 223a1263 bne s4,gp,80000248 + +80000028 : +80000028: 00200e13 li t3,2 +8000002c: 00000097 auipc ra,0x0 +80000030: 25008093 addi ra,ra,592 # 8000027c +80000034: 03700113 li sp,55 +80000038: 0820a1af amoswap.w gp,sp,(ra) +8000003c: 0000a203 lw tp,0(ra) +80000040: 03700a13 li s4,55 +80000044: 204a1263 bne s4,tp,80000248 +80000048: 01600a13 li s4,22 +8000004c: 1e3a1e63 bne s4,gp,80000248 + +80000050 : +80000050: 00300e13 li t3,3 +80000054: 00000097 auipc ra,0x0 +80000058: 22c08093 addi ra,ra,556 # 80000280 +8000005c: 04200113 li sp,66 +80000060: 0020a1af amoadd.w gp,sp,(ra) +80000064: 0000a203 lw tp,0(ra) +80000068: 08b00a13 li s4,139 +8000006c: 1c4a1e63 bne s4,tp,80000248 +80000070: 04900a13 li s4,73 +80000074: 1c3a1a63 bne s4,gp,80000248 + +80000078 : +80000078: 00400e13 li t3,4 +8000007c: 00000097 auipc ra,0x0 +80000080: 20808093 addi ra,ra,520 # 80000284 +80000084: 05700113 li sp,87 +80000088: 2020a1af amoxor.w gp,sp,(ra) +8000008c: 0000a203 lw tp,0(ra) +80000090: 06d00a13 li s4,109 +80000094: 1a4a1a63 bne s4,tp,80000248 +80000098: 03a00a13 li s4,58 +8000009c: 1a3a1663 bne s4,gp,80000248 + +800000a0 : +800000a0: 00500e13 li t3,5 +800000a4: 00000097 auipc ra,0x0 +800000a8: 1e408093 addi ra,ra,484 # 80000288 +800000ac: 02c00113 li sp,44 +800000b0: 6020a1af amoand.w gp,sp,(ra) +800000b4: 0000a203 lw tp,0(ra) +800000b8: 02800a13 li s4,40 +800000bc: 184a1663 bne s4,tp,80000248 +800000c0: 03800a13 li s4,56 +800000c4: 183a1263 bne s4,gp,80000248 + +800000c8 : +800000c8: 00600e13 li t3,6 +800000cc: 00000097 auipc ra,0x0 +800000d0: 1c008093 addi ra,ra,448 # 8000028c +800000d4: 01800113 li sp,24 +800000d8: 4020a1af amoor.w gp,sp,(ra) +800000dc: 0000a203 lw tp,0(ra) +800000e0: 05b00a13 li s4,91 +800000e4: 164a1263 bne s4,tp,80000248 +800000e8: 04b00a13 li s4,75 +800000ec: 143a1e63 bne s4,gp,80000248 + +800000f0 : +800000f0: 00700e13 li t3,7 +800000f4: 00000097 auipc ra,0x0 +800000f8: 19c08093 addi ra,ra,412 # 80000290 +800000fc: 01800113 li sp,24 +80000100: 8020a1af amomin.w gp,sp,(ra) +80000104: 0000a203 lw tp,0(ra) +80000108: 01800a13 li s4,24 +8000010c: 124a1e63 bne s4,tp,80000248 +80000110: 03800a13 li s4,56 +80000114: 123a1a63 bne s4,gp,80000248 + +80000118 : +80000118: 00800e13 li t3,8 +8000011c: 00000097 auipc ra,0x0 +80000120: 17808093 addi ra,ra,376 # 80000294 +80000124: 05800113 li sp,88 +80000128: 8020a1af amomin.w gp,sp,(ra) +8000012c: 0000a203 lw tp,0(ra) +80000130: 05300a13 li s4,83 +80000134: 104a1a63 bne s4,tp,80000248 +80000138: 05300a13 li s4,83 +8000013c: 103a1663 bne s4,gp,80000248 + +80000140 : +80000140: 00900e13 li t3,9 +80000144: 00000097 auipc ra,0x0 +80000148: 15408093 addi ra,ra,340 # 80000298 +8000014c: fca00113 li sp,-54 +80000150: 8020a1af amomin.w gp,sp,(ra) +80000154: 0000a203 lw tp,0(ra) +80000158: fca00a13 li s4,-54 +8000015c: 0e4a1663 bne s4,tp,80000248 +80000160: 02100a13 li s4,33 +80000164: 0e3a1263 bne s4,gp,80000248 + +80000168 : +80000168: 00a00e13 li t3,10 +8000016c: 00000097 auipc ra,0x0 +80000170: 13008093 addi ra,ra,304 # 8000029c +80000174: 03400113 li sp,52 +80000178: 8020a1af amomin.w gp,sp,(ra) +8000017c: 0000a203 lw tp,0(ra) +80000180: fbf00a13 li s4,-65 +80000184: 0c4a1263 bne s4,tp,80000248 +80000188: fbf00a13 li s4,-65 +8000018c: 0a3a1e63 bne s4,gp,80000248 + +80000190 : +80000190: 00b00e13 li t3,11 +80000194: 00000097 auipc ra,0x0 +80000198: 10c08093 addi ra,ra,268 # 800002a0 +8000019c: fcc00113 li sp,-52 +800001a0: a020a1af amomax.w gp,sp,(ra) +800001a4: 0000a203 lw tp,0(ra) +800001a8: fcc00a13 li s4,-52 +800001ac: 084a1e63 bne s4,tp,80000248 +800001b0: fa900a13 li s4,-87 +800001b4: 083a1a63 bne s4,gp,80000248 + +800001b8 : +800001b8: 00c00e13 li t3,12 +800001bc: 00000097 auipc ra,0x0 +800001c0: 0e808093 addi ra,ra,232 # 800002a4 +800001c4: 03400113 li sp,52 +800001c8: a020a1af amomax.w gp,sp,(ra) +800001cc: 0000a203 lw tp,0(ra) +800001d0: 03400a13 li s4,52 +800001d4: 064a1a63 bne s4,tp,80000248 +800001d8: fc900a13 li s4,-55 +800001dc: 063a1663 bne s4,gp,80000248 + +800001e0 : +800001e0: 00d00e13 li t3,13 +800001e4: 00000097 auipc ra,0x0 +800001e8: 0c408093 addi ra,ra,196 # 800002a8 +800001ec: ffff0137 lui sp,0xffff0 +800001f0: c020a1af amominu.w gp,sp,(ra) +800001f4: 0000a203 lw tp,0(ra) +800001f8: ffff0a37 lui s4,0xffff0 +800001fc: 044a1663 bne s4,tp,80000248 +80000200: ffff0a37 lui s4,0xffff0 +80000204: 004a0a13 addi s4,s4,4 # ffff0004 +80000208: 043a1063 bne s4,gp,80000248 +8000020c: 0480006f j 80000254 + +80000210 : +80000210: 00e00e13 li t3,14 +80000214: 00000097 auipc ra,0x0 +80000218: 09808093 addi ra,ra,152 # 800002ac +8000021c: ffff0137 lui sp,0xffff0 +80000220: 00c10113 addi sp,sp,12 # ffff000c +80000224: e020a1af amomaxu.w gp,sp,(ra) +80000228: 0000a203 lw tp,0(ra) +8000022c: ffff0a37 lui s4,0xffff0 +80000230: 00ca0a13 addi s4,s4,12 # ffff000c +80000234: 004a1a63 bne s4,tp,80000248 +80000238: ffff0a37 lui s4,0xffff0 +8000023c: 005a0a13 addi s4,s4,5 # ffff0005 +80000240: 003a1463 bne s4,gp,80000248 +80000244: 0100006f j 80000254 + +80000248 : +80000248: f0100137 lui sp,0xf0100 +8000024c: f2410113 addi sp,sp,-220 # f00fff24 +80000250: 01c12023 sw t3,0(sp) + +80000254 : +80000254: f0100137 lui sp,0xf0100 +80000258: f2010113 addi sp,sp,-224 # f00fff20 +8000025c: 00012023 sw zero,0(sp) +80000260: 00000013 nop +80000264: 00000013 nop +80000268: 00000013 nop +8000026c: 00000013 nop +80000270: 00000013 nop +80000274: 00000013 nop + +80000278 : +80000278: 0000000b 0xb + +8000027c : +8000027c: 0016 c.slli zero,0x5 + ... + +80000280 : +80000280: 0049 c.nop 18 + ... + +80000284 : +80000284: 003a c.slli zero,0xe + ... + +80000288 : +80000288: 0038 addi a4,sp,8 + ... + +8000028c : +8000028c: 0000004b fnmsub.s ft0,ft0,ft0,ft0,rne + +80000290 : +80000290: 0038 addi a4,sp,8 + ... + +80000294 : +80000294: 00000053 fadd.s ft0,ft0,ft0,rne + +80000298 : +80000298: 0021 c.nop 8 + ... + +8000029c : +8000029c: ffffffbf 0xffffffbf + +800002a0 : +800002a0: ffa9 bnez a5,800001fa +800002a2: ffff 0xffff + +800002a4 : +800002a4: ffc9 bnez a5,8000023e +800002a6: ffff 0xffff + +800002a8 : +800002a8: 0004 0x4 +800002aa: ffff 0xffff + +800002ac : +800002ac: 0005 c.nop 1 +800002ae: ffff 0xffff diff --git a/src/test/cpp/raw/amo/build/amo.hex b/src/test/cpp/raw/amo/build/amo.hex new file mode 100644 index 00000000..74d35678 --- /dev/null +++ b/src/test/cpp/raw/amo/build/amo.hex @@ -0,0 +1,45 @@ +:0200000480007A +:10000000130E100097000000938040271301D002C8 +:10001000AFA1200803A20000130AD00263164A22EF +:10002000130AB00063123A22130E2000970000005A +:100030009380002513017003AFA1200803A20000E4 +:10004000130A700363124A20130A6001631E3A1EEA +:10005000130E3000970000009380C022130120048B +:10006000AFA1200003A20000130AB008631E4A1CBF +:10007000130A9004631A3A1C130E40009700000004 +:100080009380802013017005AFA1202003A20000FF +:10009000130AD006631A4A1A130AA00363163A1AFF +:1000A000130E5000970000009380401E1301C00201 +:1000B000AFA1206003A20000130A800263164A1851 +:1000C000130A800363123A18130E600097000000B1 +:1000D0009380001C13018001AFA1204003A2000007 +:1000E000130AB00563124A16130AB004631E3A14C9 +:1000F000130E7000970000009380C0191301800157 +:10010000AFA1208003A20000130A8001631E4A12DF +:10011000130A8003631A3A12130E8000970000003E +:100120009380801713018005AFA1208003A20000F7 +:10013000130A3005631A4A10130A300563163A1081 +:10014000130E900097000000938040151301A0FC4F +:10015000AFA1208003A20000130AA0FC63164A0E80 +:10016000130A100263123A0E130EA000970000004B +:100170009380001313014003AFA1208003A200006D +:10018000130AF0FB63124A0C130AF0FB631E3A0ACF +:10019000130EB000970000009380C0101301C0FC44 +:1001A000AFA120A003A20000130AC0FC631E4A08EE +:1001B000130A90FA631A3A08130EC0009700000061 +:1001C0009380800E13014003AFA120A003A2000082 +:1001D000130A4003631A4A06130A90FC63163A0690 +:1001E000130ED000970000009380400C3701FFFFF2 +:1001F000AFA120C003A20000370AFFFF63164A0424 +:10020000370AFFFF130A4A0063103A046F008004A4 +:10021000130EE00097000000938080093701FFFF74 +:100220001301C100AFA120E003A20000370AFFFFC5 +:10023000130ACA00631A4A00370AFFFF130A5A005A +:1002400063143A006F000001370110F0130141F20E +:100250002320C101370110F0130101F22320010016 +:100260001300000013000000130000001300000042 +:1002700013000000130000000B0000001600000037 +:10028000490000003A000000380000004B00000068 +:10029000380000005300000021000000BFFFFFFFF6 +:1002A000A9FFFFFFC9FFFFFF0400FFFF0500FFFFDD +:00000001FF diff --git a/src/test/cpp/raw/amo/makefile b/src/test/cpp/raw/amo/makefile new file mode 100644 index 00000000..6e9afc5d --- /dev/null +++ b/src/test/cpp/raw/amo/makefile @@ -0,0 +1,5 @@ +PROJ_NAME=amo + +ATOMIC=yes + +include ../common/asm.mk \ No newline at end of file diff --git a/src/test/cpp/raw/amo/src/crt.S b/src/test/cpp/raw/amo/src/crt.S new file mode 100644 index 00000000..5696f1d7 --- /dev/null +++ b/src/test/cpp/raw/amo/src/crt.S @@ -0,0 +1,174 @@ +.globl _star +#define TEST_ID x28 + +_start: + +#define assert(reg, value) \ + li x20, value; \ + bne x20, reg, fail; + +test1: + li TEST_ID, 1 + la x1, test1_data + li x2, 45 + amoswap.w x3,x2,(x1) + lw x4, 0(x1) + assert(x4, 45) + assert(x3, 11) + +test2: + li TEST_ID, 2 + la x1, test2_data + li x2, 55 + amoswap.w x3,x2,(x1) + lw x4, 0(x1) + assert(x4, 55) + assert(x3, 22) + + +test3: + li TEST_ID,3 + la x1, test3_data + li x2, 66 + amoadd.w x3,x2,(x1) + lw x4, 0(x1) + assert(x4, 66+73) + assert(x3, 73) + +test4: + li TEST_ID,4 + la x1, test4_data + li x2, 87 + amoxor.w x3,x2,(x1) + lw x4, 0(x1) + assert(x4, 87^58) + assert(x3, 58) + +test5: + li TEST_ID,5 + la x1, test5_data + li x2, 44 + amoand.w x3,x2,(x1) + lw x4, 0(x1) + assert(x4, 44 & 56) + assert(x3, 56) + +test6: + li TEST_ID,6 + la x1, test6_data + li x2, 24 + amoor.w x3,x2,(x1) + lw x4, 0(x1) + assert(x4, 24 | 75) + assert(x3, 75) + +test7: + li TEST_ID,7 + la x1, test7_data + li x2, 24 + amomin.w x3,x2,(x1) + lw x4, 0(x1) + assert(x4, 24) + assert(x3, 56) + + +test8: + li TEST_ID,8 + la x1, test8_data + li x2, 88 + amomin.w x3,x2,(x1) + lw x4, 0(x1) + assert(x4, 83) + assert(x3, 83) + +test9: + li TEST_ID,9 + la x1, test9_data + li x2, -54 + amomin.w x3,x2,(x1) + lw x4, 0(x1) + assert(x4, -54) + assert(x3, 33) + +test10: + li TEST_ID,10 + la x1, test10_data + li x2, 52 + amomin.w x3,x2,(x1) + lw x4, 0(x1) + assert(x4, -65) + assert(x3, -65) + +test11: + li TEST_ID,11 + la x1, test11_data + li x2, -52 + amomax.w x3,x2,(x1) + lw x4, 0(x1) + assert(x4, -52) + assert(x3, -87) + +test12: + li TEST_ID,12 + la x1, test12_data + li x2, 52 + amomax.w x3,x2,(x1) + lw x4, 0(x1) + assert(x4, 52) + assert(x3, -55) + + +test13: + li TEST_ID,13 + la x1, test13_data + li x2, 0xFFFF0000 + amominu.w x3,x2,(x1) + lw x4, 0(x1) + assert(x4, 0xFFFF0000) + assert(x3, 0xFFFF0004) + + j pass + + +test14: + li TEST_ID,14 + la x1, test14_data + li x2, 0xFFFF000C + amomaxu.w x3,x2,(x1) + lw x4, 0(x1) + assert(x4, 0xFFFF000C) + assert(x3, 0xFFFF0005) + + j pass + + +fail: + li x2, 0xF00FFF24 + sw TEST_ID, 0(x2) + +pass: + li x2, 0xF00FFF20 + sw x0, 0(x2) + + nop + nop + nop + nop + nop + nop + + +test1_data: .word 11 +test2_data: .word 22 +test3_data: .word 73 +test4_data: .word 58 +test5_data: .word 56 +test6_data: .word 75 +test7_data: .word 56 +test8_data: .word 83 +test9_data: .word 33 +test10_data: .word -65 +test11_data: .word -87 +test12_data: .word -55 +test13_data: .word 0xFFFF0004 +test14_data: .word 0xFFFF0005 \ No newline at end of file diff --git a/src/test/cpp/raw/amo/src/ld b/src/test/cpp/raw/amo/src/ld new file mode 100644 index 00000000..93d8de8e --- /dev/null +++ b/src/test/cpp/raw/amo/src/ld @@ -0,0 +1,16 @@ +OUTPUT_ARCH( "riscv" ) + +MEMORY { + onChipRam (W!RX)/*(RX)*/ : ORIGIN = 0x80000000, LENGTH = 128K +} + +SECTIONS +{ + + .crt_section : + { + . = ALIGN(4); + *crt.o(.text) + } > onChipRam + +} diff --git a/src/test/cpp/raw/common/asm.mk b/src/test/cpp/raw/common/asm.mk index f16774de..3d4b2050 100644 --- a/src/test/cpp/raw/common/asm.mk +++ b/src/test/cpp/raw/common/asm.mk @@ -12,8 +12,11 @@ MARCH := rv32i ifeq ($(MULDIV),yes) MARCH := $(MARCH)m endif +ifeq ($(ATOMIC),yes) + MARCH := $(MARCH)a +endif ifeq ($(COMPRESSED),yes) - MARCH := $(MARCH)ac + MARCH := $(MARCH)c endif CFLAGS += -march=$(MARCH) -mabi=$(MABI) diff --git a/src/test/cpp/raw/lrsc/.gitignore b/src/test/cpp/raw/lrsc/.gitignore new file mode 100644 index 00000000..c12cb2c2 --- /dev/null +++ b/src/test/cpp/raw/lrsc/.gitignore @@ -0,0 +1,4 @@ +*.map +*.v +*.elf +*.o \ No newline at end of file diff --git a/src/test/cpp/raw/lrsc/build/lrsc.asm b/src/test/cpp/raw/lrsc/build/lrsc.asm new file mode 100644 index 00000000..95b4751d --- /dev/null +++ b/src/test/cpp/raw/lrsc/build/lrsc.asm @@ -0,0 +1,217 @@ + +build/lrsc.elf: file format elf32-littleriscv + + +Disassembly of section .crt_section: + +80000000 : +80000000: 04c0006f j 8000004c <_start> +80000004: 00000013 nop +80000008: 00000013 nop +8000000c: 00000013 nop +80000010: 00000013 nop +80000014: 00000013 nop +80000018: 00000013 nop +8000001c: 00000013 nop + +80000020 : +80000020: 30002ef3 csrr t4,mstatus +80000024: 080efe93 andi t4,t4,128 +80000028: 000e8a63 beqz t4,8000003c +8000002c: 00002eb7 lui t4,0x2 +80000030: 800e8e93 addi t4,t4,-2048 # 1800 +80000034: 300e9073 csrw mstatus,t4 +80000038: 30200073 mret + +8000003c : +8000003c: 34102ef3 csrr t4,mepc +80000040: 004e8e93 addi t4,t4,4 +80000044: 341e9073 csrw mepc,t4 +80000048: 30200073 mret + +8000004c <_start>: +8000004c: 00100e13 li t3,1 +80000050: 10000537 lui a0,0x10000 +80000054: 06400593 li a1,100 +80000058: 06500613 li a2,101 +8000005c: 06600693 li a3,102 +80000060: 00d52023 sw a3,0(a0) # 10000000 +80000064: 18b5262f sc.w a2,a1,(a0) +80000068: 00100713 li a4,1 +8000006c: 26e61e63 bne a2,a4,800002e8 +80000070: 00052703 lw a4,0(a0) +80000074: 26e69a63 bne a3,a4,800002e8 +80000078: 00200e13 li t3,2 +8000007c: 10000537 lui a0,0x10000 +80000080: 00450513 addi a0,a0,4 # 10000004 +80000084: 06700593 li a1,103 +80000088: 06800613 li a2,104 +8000008c: 06900693 li a3,105 +80000090: 00d52023 sw a3,0(a0) +80000094: 18b5262f sc.w a2,a1,(a0) +80000098: 00100713 li a4,1 +8000009c: 24e61663 bne a2,a4,800002e8 +800000a0: 00052703 lw a4,0(a0) +800000a4: 24e69263 bne a3,a4,800002e8 +800000a8: 00300e13 li t3,3 +800000ac: 10000537 lui a0,0x10000 +800000b0: 00450513 addi a0,a0,4 # 10000004 +800000b4: 06700593 li a1,103 +800000b8: 06800613 li a2,104 +800000bc: 06900693 li a3,105 +800000c0: 18b5262f sc.w a2,a1,(a0) +800000c4: 00100713 li a4,1 +800000c8: 22e61063 bne a2,a4,800002e8 +800000cc: 00052703 lw a4,0(a0) +800000d0: 20e69c63 bne a3,a4,800002e8 +800000d4: 00400e13 li t3,4 +800000d8: 10000537 lui a0,0x10000 +800000dc: 00850513 addi a0,a0,8 # 10000008 +800000e0: 06a00593 li a1,106 +800000e4: 06b00613 li a2,107 +800000e8: 06c00693 li a3,108 +800000ec: 00d52023 sw a3,0(a0) +800000f0: 100527af lr.w a5,(a0) +800000f4: 18b5262f sc.w a2,a1,(a0) +800000f8: 1ed79863 bne a5,a3,800002e8 +800000fc: 1e061663 bnez a2,800002e8 +80000100: 00052703 lw a4,0(a0) +80000104: 1ee59263 bne a1,a4,800002e8 +80000108: 00500e13 li t3,5 +8000010c: 10000537 lui a0,0x10000 +80000110: 00850513 addi a0,a0,8 # 10000008 +80000114: 06d00593 li a1,109 +80000118: 06e00613 li a2,110 +8000011c: 06f00693 li a3,111 +80000120: 00d52023 sw a3,0(a0) +80000124: 18b5262f sc.w a2,a1,(a0) +80000128: 1c061063 bnez a2,800002e8 +8000012c: 00052703 lw a4,0(a0) +80000130: 1ae59c63 bne a1,a4,800002e8 +80000134: 00600e13 li t3,6 +80000138: 10000537 lui a0,0x10000 +8000013c: 00c50513 addi a0,a0,12 # 1000000c +80000140: 07000593 li a1,112 +80000144: 07100613 li a2,113 +80000148: 07200693 li a3,114 +8000014c: 10000437 lui s0,0x10000 +80000150: 01040413 addi s0,s0,16 # 10000010 +80000154: 07300493 li s1,115 +80000158: 07400913 li s2,116 +8000015c: 07500993 li s3,117 +80000160: 00d52023 sw a3,0(a0) +80000164: 01342023 sw s3,0(s0) +80000168: 100527af lr.w a5,(a0) +8000016c: 10042aaf lr.w s5,(s0) +80000170: 18b5262f sc.w a2,a1,(a0) +80000174: 1894292f sc.w s2,s1,(s0) +80000178: 16d79863 bne a5,a3,800002e8 +8000017c: 16061663 bnez a2,800002e8 +80000180: 00052703 lw a4,0(a0) +80000184: 16e59263 bne a1,a4,800002e8 +80000188: 173a9063 bne s5,s3,800002e8 +8000018c: 14091e63 bnez s2,800002e8 +80000190: 00042a03 lw s4,0(s0) +80000194: 15449a63 bne s1,s4,800002e8 +80000198: 00700e13 li t3,7 +8000019c: 10000537 lui a0,0x10000 +800001a0: 01450513 addi a0,a0,20 # 10000014 +800001a4: 07800593 li a1,120 +800001a8: 07900613 li a2,121 +800001ac: 07a00693 li a3,122 +800001b0: 01000e93 li t4,16 + +800001b4 : +800001b4: 00d52023 sw a3,0(a0) +800001b8: 100527af lr.w a5,(a0) +800001bc: 18b5262f sc.w a2,a1,(a0) +800001c0: 12d79463 bne a5,a3,800002e8 +800001c4: 12061263 bnez a2,800002e8 +800001c8: 00052703 lw a4,0(a0) +800001cc: 10e59e63 bne a1,a4,800002e8 +800001d0: fffe8e93 addi t4,t4,-1 +800001d4: 00450513 addi a0,a0,4 +800001d8: 00358593 addi a1,a1,3 +800001dc: 00360613 addi a2,a2,3 +800001e0: 00368693 addi a3,a3,3 +800001e4: fc0e98e3 bnez t4,800001b4 +800001e8: 00900e13 li t3,9 +800001ec: 10000537 lui a0,0x10000 +800001f0: 10050513 addi a0,a0,256 # 10000100 +800001f4: 07b00593 li a1,123 +800001f8: 07c00613 li a2,124 +800001fc: 07d00693 li a3,125 +80000200: 00d52023 sw a3,0(a0) +80000204: 100527af lr.w a5,(a0) +80000208: 00000073 ecall +8000020c: 18b5262f sc.w a2,a1,(a0) +80000210: 00100713 li a4,1 +80000214: 0ce61a63 bne a2,a4,800002e8 +80000218: 00052703 lw a4,0(a0) +8000021c: 0ce69663 bne a3,a4,800002e8 +80000220: 00b00e13 li t3,11 +80000224: 10000537 lui a0,0x10000 +80000228: 30050513 addi a0,a0,768 # 10000300 +8000022c: 08200593 li a1,130 +80000230: 08300613 li a2,131 +80000234: 08400693 li a3,132 +80000238: 00d52023 sw a3,0(a0) +8000023c: 00001eb7 lui t4,0x1 +80000240: 800e8e93 addi t4,t4,-2048 # 800 +80000244: 304e9073 csrw mie,t4 +80000248: 00800e93 li t4,8 +8000024c: 100527af lr.w a5,(a0) +80000250: 300e9073 csrw mstatus,t4 +80000254: 00000013 nop +80000258: 00000013 nop +8000025c: 00000013 nop +80000260: 00000013 nop +80000264: 00000013 nop +80000268: 00000013 nop +8000026c: 18b5262f sc.w a2,a1,(a0) +80000270: 00100713 li a4,1 +80000274: 06e61a63 bne a2,a4,800002e8 +80000278: 00052703 lw a4,0(a0) +8000027c: 06e69663 bne a3,a4,800002e8 +80000280: 00c00e13 li t3,12 +80000284: 10000537 lui a0,0x10000 +80000288: 40050513 addi a0,a0,1024 # 10000400 +8000028c: 08c00593 li a1,140 +80000290: 08d00613 li a2,141 +80000294: 08e00693 li a3,142 +80000298: 00d52023 sw a3,0(a0) +8000029c: 00001eb7 lui t4,0x1 +800002a0: 800e8e93 addi t4,t4,-2048 # 800 +800002a4: 304e9073 csrw mie,t4 +800002a8: 00002eb7 lui t4,0x2 +800002ac: 808e8e93 addi t4,t4,-2040 # 1808 +800002b0: 100527af lr.w a5,(a0) +800002b4: 300e9073 csrw mstatus,t4 +800002b8: 00000013 nop +800002bc: 00000013 nop +800002c0: 00000013 nop +800002c4: 00000013 nop +800002c8: 00000013 nop +800002cc: 00000013 nop +800002d0: 18b5262f sc.w a2,a1,(a0) +800002d4: 00100713 li a4,1 +800002d8: 00e61863 bne a2,a4,800002e8 +800002dc: 00052703 lw a4,0(a0) +800002e0: 00e69463 bne a3,a4,800002e8 +800002e4: 0100006f j 800002f4 + +800002e8 : +800002e8: f0100137 lui sp,0xf0100 +800002ec: f2410113 addi sp,sp,-220 # f00fff24 +800002f0: 01c12023 sw t3,0(sp) + +800002f4 : +800002f4: f0100137 lui sp,0xf0100 +800002f8: f2010113 addi sp,sp,-224 # f00fff20 +800002fc: 00012023 sw zero,0(sp) +80000300: 00000013 nop +80000304: 00000013 nop +80000308: 00000013 nop +8000030c: 00000013 nop +80000310: 00000013 nop +80000314: 00000013 nop diff --git a/src/test/cpp/raw/lrsc/build/lrsc.hex b/src/test/cpp/raw/lrsc/build/lrsc.hex new file mode 100644 index 00000000..7b96205d --- /dev/null +++ b/src/test/cpp/raw/lrsc/build/lrsc.hex @@ -0,0 +1,53 @@ +:0200000480007A +:100000006F00C00413000000130000001300000084 +:100010001300000013000000130000001300000094 +:10002000F32E003093FE0E08638A0E00B72E0000F8 +:10003000938E0E8073900E3073002030F32E1034A8 +:10004000938E4E0073901E3473002030130E1000F8 +:100050003705001093054006130650069306600608 +:100060002320D5002F26B51813071000631EE6269F +:1000700003270500639AE626130E200037050010BB +:100080001305450093057006130680069306900637 +:100090002320D5002F26B518130710006316E62479 +:1000A000032705006392E624130E30003705001085 +:1000B0001305450093057006130680069306900607 +:1000C0002F26B518130710006310E622032705003A +:1000D000639CE620130E40003705001013058500D1 +:1000E0009305A0061306B0069306C0062320D5008C +:1000F000AF2705102F26B5186398D71E6316061E66 +:10010000032705006392E51E130E5000370500100B +:10011000130585009305D0061306E0069306F00646 +:100120002320D5002F26B5186310061C03270500D1 +:10013000639CE51A130E6000370500101305C50017 +:1001400093050007130610079306200737040010D5 +:10015000130404019304300713094007930950075F +:100160002320D50023203401AF270510AF2A041027 +:100170002F26B5182F2994186398D71663160616DC +:10018000032705006392E51663903A17631E09146E +:10019000032A0400639A4415130E700037050010FB +:1001A0001305450193058007130690079306A007E2 +:1001B000930E00012320D500AF2705102F26B51878 +:1001C0006394D7126312061203270500639EE5109D +:1001D000938EFEFF13054500938535001306360008 +:1001E00093863600E3980EFC130E9000370500103E +:1001F000130505109305B0071306C0079306D00733 +:100200002320D500AF270510730000002F26B51856 +:1002100013071000631AE60C032705006396E60C2B +:10022000130EB000370500101305053093052008A4 +:1002300013063008930640082320D500B71E00009F +:10024000938E0E8073904E30930E8000AF27051072 +:1002500073900E3013000000130000001300000024 +:100260001300000013000000130000002F26B51833 +:1002700013071000631AE606032705006396E606D7 +:10028000130EC00037050010130505409305C00884 +:100290001306D0089306E0082320D500B71E0000FF +:1002A000938E0E8073904E30B72E0000938E8E800A +:1002B000AF27051073900E301300000013000000EC +:1002C00013000000130000001300000013000000E2 +:1002D0002F26B518130710006318E6000327050042 +:1002E0006394E6006F000001370110F0130141F242 +:1002F0002320C101370110F0130101F22320010076 +:1003000013000000130000001300000013000000A1 +:080310001300000013000000BF +:040000058000004C2B +:00000001FF diff --git a/src/test/cpp/raw/lrsc/makefile b/src/test/cpp/raw/lrsc/makefile new file mode 100644 index 00000000..eafdb266 --- /dev/null +++ b/src/test/cpp/raw/lrsc/makefile @@ -0,0 +1,5 @@ +PROJ_NAME=lrsc + +ATOMIC=yes + +include ../common/asm.mk \ No newline at end of file diff --git a/src/test/cpp/raw/lrsc/src/crt.S b/src/test/cpp/raw/lrsc/src/crt.S new file mode 100644 index 00000000..7fef5e35 --- /dev/null +++ b/src/test/cpp/raw/lrsc/src/crt.S @@ -0,0 +1,265 @@ +.globl _start + + + j _start + nop + nop + nop + nop + nop + nop + nop + +.global trap_entry +trap_entry: + csrr x29, mstatus + and x29, x29, 0x080 + beqz x29, notExternalInterrupt + li x29, 0x1800 //000 disable interrupts + csrw mstatus,x29 + mret + +notExternalInterrupt: + csrr x29, mepc + addi x29, x29, 4 + csrw mepc, x29 + mret + +_start: +//Test 1 SC on unreserved area should fail and not write memory + li x28, 1 + li a0, 0x10000000 + li a1, 100 + li a2, 101 + li a3, 102 + sw a3, 0(a0) + sc.w a2, a1, (a0) + li a4, 1 + bne a2, a4, fail + lw a4, 0(a0) + bne a3, a4, fail + +//Test 2 SC on another unreserved area should fail and not write memory + li x28, 2 + li a0, 0x10000004 + li a1, 103 + li a2, 104 + li a3, 105 + sw a3, 0(a0) + sc.w a2, a1, (a0) + li a4, 1 + bne a2, a4, fail + lw a4, 0(a0) + bne a3, a4, fail + + +//Test 3 retrying SC on unreserved area should fail and not write memory + li x28, 3 + li a0, 0x10000004 + li a1, 103 + li a2, 104 + li a3, 105 + sc.w a2, a1, (a0) + li a4, 1 + bne a2, a4, fail + lw a4, 0(a0) + bne a3, a4, fail + + +//Test 4 SC on reserved area should pass and should be written write memory + li x28, 4 + li a0, 0x10000008 + li a1, 106 + li a2, 107 + li a3, 108 + sw a3, 0(a0) + lr.w a5, (a0) + sc.w a2, a1, (a0) + bne a5, a3, fail + bne a2, x0, fail + lw a4, 0(a0) + bne a1, a4, fail + + +//Test 5 redo SC on reserved area should pass and should be written write memory + li x28, 5 + li a0, 0x10000008 + li a1, 109 + li a2, 110 + li a3, 111 + sw a3, 0(a0) + sc.w a2, a1, (a0) + bne a2, x0, fail + lw a4, 0(a0) + bne a1, a4, fail + +//Test 6 Allow two entries at the same time + li x28, 6 + li a0, 0x1000000C + li a1, 112 + li a2, 113 + li a3, 114 + li s0, 0x10000010 + li s1, 115 + li s2, 116 + li s3, 117 + + sw a3, 0(a0) + sw s3, 0(s0) + lr.w a5, (a0) + lr.w s5, (s0) + sc.w a2, a1, (a0) + sc.w s2, s1, (s0) + bne a5, a3, fail + bne a2, x0, fail + lw a4, 0(a0) + bne a1, a4, fail + + bne s5, s3, fail + bne s2, x0, fail + lw s4, 0(s0) + bne s1, s4, fail + +//Test 7 do a lot of allocation to clear the entries + li x28, 7 + li a0, 0x10000014 + li a1, 120 + li a2, 121 + li a3, 122 + li x29, 16 +test7: + sw a3, 0(a0) + lr.w a5, (a0) + sc.w a2, a1, (a0) + bne a5, a3, fail + bne a2, x0, fail + lw a4, 0(a0) + bne a1, a4, fail + add x29, x29, -1 + add a0, a0, 4 + add a1, a1, 3 + add a2, a2, 3 + add a3, a3, 3 + bnez x29, test7 + + +//Test 8 SC on discarded entries should fail + /* li x28, 8 + li a0, 0x10000018 + li a1, 120 + li a2, 121 + li a3, 122 + lw a5, 0(a0) + sc.w a2, a1, (a0) + li a4, 1 + bne a2, a4, fail + lw a4, 0(a0) + bne a5, a4, fail*/ + + +//Test 9 SC should fail after a context switching + li x28, 9 + li a0, 0x10000100 + li a1, 123 + li a2, 124 + li a3, 125 + sw a3, 0(a0) + lr.w a5, (a0) + scall + sc.w a2, a1, (a0) + li a4, 1 + bne a2, a4, fail + lw a4, 0(a0) + bne a3, a4, fail + + + +//Test 10 SC should fail if the address doesn't match + /* li x28, 10 + li a0, 0x10000200 + li a6, 0x10000204 + li a1, 126 + li a2, 127 + li a3, 128 + li a7, 129 + sw a3, 0(a0) + sw a7, 0(a6) + lr.w a5, (a6) + sc.w a2, a1, (a0) + li a4, 1 + bne a2, a4, fail + lw a4, 0(a6) + bne a7, a4, fail*/ + + + +//Test 11 SC should fail after a external interrupt context switching + li x28, 11 + li a0, 0x10000300 + li a1, 130 + li a2, 131 + li a3, 132 + sw a3, 0(a0) + li x29, 0x800 //800 external interrupts + csrw mie,x29 + li x29, 0x008 //008 enable interrupts + lr.w a5, (a0) + csrw mstatus,x29 //Enable external interrupt (will jump instantly due to testbench setup) + nop + nop + nop + nop + nop + nop + sc.w a2, a1, (a0) + li a4, 1 + bne a2, a4, fail + lw a4, 0(a0) + bne a3, a4, fail + + +//Test 12 SC should fail after a external interrupt context switching (callback on lr) + li x28, 12 + li a0, 0x10000400 + li a1, 140 + li a2, 141 + li a3, 142 + sw a3, 0(a0) + li x29, 0x800 //800 external interrupts + csrw mie,x29 + li x29, 0x1808 //008 enable interrupts + lr.w a5, (a0) + csrw mstatus,x29 //Enable external interrupt (will jump instantly due to testbench setup) + nop + nop + nop + nop + nop + nop + sc.w a2, a1, (a0) + li a4, 1 + bne a2, a4, fail + lw a4, 0(a0) + bne a3, a4, fail + + + + j pass + + +fail: //x28 => error code + li x2, 0xF00FFF24 + sw x28, 0(x2) + +pass: + li x2, 0xF00FFF20 + sw x0, 0(x2) + + + + nop + nop + nop + nop + nop + nop diff --git a/src/test/cpp/raw/lrsc/src/ld b/src/test/cpp/raw/lrsc/src/ld new file mode 100644 index 00000000..93d8de8e --- /dev/null +++ b/src/test/cpp/raw/lrsc/src/ld @@ -0,0 +1,16 @@ +OUTPUT_ARCH( "riscv" ) + +MEMORY { + onChipRam (W!RX)/*(RX)*/ : ORIGIN = 0x80000000, LENGTH = 128K +} + +SECTIONS +{ + + .crt_section : + { + . = ALIGN(4); + *crt.o(.text) + } > onChipRam + +} diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index a6f43bf5..8e1c1468 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -3641,8 +3641,12 @@ int main(int argc, char **argv, char **env) { #endif - #ifdef ATOMIC - redo(REDO,WorkspaceRegression("atomic").loadHex("../custom/atomic/build/atomic.hex")->bootAt(0x00000000u)->run(10e3);); + #ifdef LRSC + redo(REDO,WorkspaceRegression("lrsc").loadHex("../raw/lrsc/build/lrsc.hex")->bootAt(0x00000000u)->run(10e3);); + #endif + + #ifdef AMO + redo(REDO,WorkspaceRegression("amo").loadHex("../raw/amo/build/amo.hex")->bootAt(0x00000000u)->run(10e3);); #endif #ifdef DHRYSTONE diff --git a/src/test/cpp/regression/makefile b/src/test/cpp/regression/makefile index b178fee5..1ffc036d 100644 --- a/src/test/cpp/regression/makefile +++ b/src/test/cpp/regression/makefile @@ -14,7 +14,7 @@ EBREAK?=no FENCEI?=no MMU?=yes SEED?=no -ATOMIC?=no +LRSC?=no AMO?=no NO_STALL?=no DEBUG_PLUGIN?=STD @@ -143,8 +143,8 @@ ifeq ($(CSR),yes) endif -ifeq ($(ATOMIC),yes) - ADDCFLAGS += -CFLAGS -DATOMIC +ifeq ($(LRSC),yes) + ADDCFLAGS += -CFLAGS -DLRSC endif ifeq ($(AMO),yes) From 9b6b65b8b41c03b8fd21ebc3f5e5c04d2acb2f17 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Tue, 9 Apr 2019 19:37:18 +0200 Subject: [PATCH 132/951] Fix icache test when dynamic target branch prediction is enabled --- src/test/cpp/raw/icache/build/icache.asm | 37 +++++++++++++----------- src/test/cpp/raw/icache/build/icache.hex | 17 ++++++----- src/test/cpp/raw/icache/src/crt.S | 7 ++++- 3 files changed, 35 insertions(+), 26 deletions(-) diff --git a/src/test/cpp/raw/icache/build/icache.asm b/src/test/cpp/raw/icache/build/icache.asm index 52808b95..993f21bb 100644 --- a/src/test/cpp/raw/icache/build/icache.asm +++ b/src/test/cpp/raw/icache/build/icache.asm @@ -6,43 +6,46 @@ Disassembly of section .crt_section: 80000000 <_start>: 80000000: 00000097 auipc ra,0x0 -80000004: 04408093 addi ra,ra,68 # 80000044 +80000004: 04c08093 addi ra,ra,76 # 8000004c 80000008 : 80000008: 00100e13 li t3,1 8000000c: 00100093 li ra,1 80000010: 00300113 li sp,3 80000014: 00208093 addi ra,ra,2 -80000018: 02209663 bne ra,sp,80000044 +80000018: 02209a63 bne ra,sp,8000004c 8000001c : 8000001c: 00200e13 li t3,2 80000020: 01300093 li ra,19 80000024: 00000117 auipc sp,0x0 -80000028: 01810113 addi sp,sp,24 # 8000003c +80000028: 02010113 addi sp,sp,32 # 80000044 8000002c: 0040006f j 80000030 80000030 : 80000030: 00112023 sw ra,0(sp) 80000034: 0000100f fence.i -80000038: 0040006f j 8000003c +80000038: 00800a13 li s4,8 +8000003c: fffa0a13 addi s4,s4,-1 +80000040: fe0a1ee3 bnez s4,8000003c -8000003c : -8000003c: 0080006f j 80000044 -80000040: 0100006f j 80000050 +80000044 : +80000044: 0080006f j 8000004c +80000048: 0100006f j 80000058 -80000044 : -80000044: f0100137 lui sp,0xf0100 -80000048: f2410113 addi sp,sp,-220 # f00fff24 -8000004c: 01c12023 sw t3,0(sp) +8000004c : +8000004c: f0100137 lui sp,0xf0100 +80000050: f2410113 addi sp,sp,-220 # f00fff24 +80000054: 01c12023 sw t3,0(sp) -80000050 : -80000050: f0100137 lui sp,0xf0100 -80000054: f2010113 addi sp,sp,-224 # f00fff20 -80000058: 00012023 sw zero,0(sp) -8000005c: 00000013 nop -80000060: 00000013 nop +80000058 : +80000058: f0100137 lui sp,0xf0100 +8000005c: f2010113 addi sp,sp,-224 # f00fff20 +80000060: 00012023 sw zero,0(sp) 80000064: 00000013 nop 80000068: 00000013 nop 8000006c: 00000013 nop 80000070: 00000013 nop +80000074: 00000013 nop +80000078: 00000013 nop + ... diff --git a/src/test/cpp/raw/icache/build/icache.hex b/src/test/cpp/raw/icache/build/icache.hex index 50b97969..2588f0ed 100644 --- a/src/test/cpp/raw/icache/build/icache.hex +++ b/src/test/cpp/raw/icache/build/icache.hex @@ -1,10 +1,11 @@ :0200000480007A -:100000009700000093804004130E1000930010002E -:10001000130130009380200063962002130E20000D -:100020009300300117010000130181016F004000AF -:10003000232011000F1000006F0040006F008000AF -:100040006F000001370110F0130141F22320C101BC -:10005000370110F0130101F223200100130000000A -:100060001300000013000000130000001300000044 -:040070001300000079 +:10000000970000009380C004130E100093001000AE +:100010001301300093802000639A2002130E200009 +:100020009300300117010000130101026F0040002E +:10003000232011000F100000130A8000130AFAFF9A +:10004000E31E0AFE6F0080006F000001370110F010 +:10005000130141F22320C101370110F0130101F215 +:100060002320010013000000130000001300000013 +:100070001300000013000000130000000000000047 +:04008000000000007C :00000001FF diff --git a/src/test/cpp/raw/icache/src/crt.S b/src/test/cpp/raw/icache/src/crt.S index 986a741c..b0b2425b 100644 --- a/src/test/cpp/raw/icache/src/crt.S +++ b/src/test/cpp/raw/icache/src/crt.S @@ -1,6 +1,11 @@ .globl _star #define TEST_ID x28 +#define delay \ + li x20, 8; \ +1: addi x20, x20, -1; \ + bne x20, x0, 1b; + _start: la x1, fail // csrw mtvec, x1 @@ -21,7 +26,7 @@ test2: test2_aligned: sw x1, 0(x2) fence.i - j test2_trigger + delay test2_trigger: j fail From d7f6c18c0ab5513ce3ee2c0a6f92e8d89ca6addd Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Wed, 10 Apr 2019 00:35:15 +0200 Subject: [PATCH 133/951] Fix DebugPlugin -> force machine mode, force uncached memory load --- src/main/scala/vexriscv/Pipeline.scala | 6 +-- src/main/scala/vexriscv/Services.scala | 3 ++ src/main/scala/vexriscv/Stage.scala | 1 - src/main/scala/vexriscv/VexRiscv.scala | 1 + src/main/scala/vexriscv/demo/Linux.scala | 44 ++++++++++++++++--- src/main/scala/vexriscv/ip/DataCache.scala | 8 ++-- .../scala/vexriscv/plugin/CsrPlugin.scala | 15 +++++-- .../vexriscv/plugin/DBusCachedPlugin.scala | 5 ++- .../scala/vexriscv/plugin/DebugPlugin.scala | 22 ++++++---- src/test/cpp/regression/main.cpp | 30 ++++++++----- 10 files changed, 94 insertions(+), 41 deletions(-) diff --git a/src/main/scala/vexriscv/Pipeline.scala b/src/main/scala/vexriscv/Pipeline.scala index cde5ae8c..14fe0713 100644 --- a/src/main/scala/vexriscv/Pipeline.scala +++ b/src/main/scala/vexriscv/Pipeline.scala @@ -14,7 +14,7 @@ trait Pipeline { val plugins = ArrayBuffer[Plugin[T]]() var stages = ArrayBuffer[Stage]() var unremovableStages = mutable.Set[Stage]() - val configs = mutable.HashMap[PipelineThing[_], Any]() + val things = mutable.HashMap[PipelineThing[_], Any]() // val services = ArrayBuffer[Any]() def indexOf(stage : Stage) = stages.indexOf(stage) @@ -37,8 +37,8 @@ trait Pipeline { filtered.head.asInstanceOf[T] } - def update[T](that : PipelineThing[T], value : T) : Unit = configs(that) = value - def apply[T](that : PipelineThing[T]) : T = configs(that).asInstanceOf[T] + def update[T](that : PipelineThing[T], value : T) : Unit = things(that) = value + def apply[T](that : PipelineThing[T]) : T = things(that).asInstanceOf[T] def build(): Unit ={ plugins.foreach(_.pipeline = this.asInstanceOf[T]) diff --git a/src/main/scala/vexriscv/Services.scala b/src/main/scala/vexriscv/Services.scala index 0e041278..26ecf845 100644 --- a/src/main/scala/vexriscv/Services.scala +++ b/src/main/scala/vexriscv/Services.scala @@ -40,12 +40,14 @@ trait PrivilegeService{ def isUser() : Bool def isSupervisor() : Bool def isMachine() : Bool + def forceMachine() : Unit } case class PrivilegeServiceDefault() extends PrivilegeService{ override def isUser(): Bool = False override def isSupervisor(): Bool = False override def isMachine(): Bool = True + override def forceMachine(): Unit = {} } trait InterruptionInhibitor{ @@ -56,6 +58,7 @@ trait ExceptionInhibitor{ def inhibateException() : Unit } + trait RegFileService{ def readStage() : Stage } diff --git a/src/main/scala/vexriscv/Stage.scala b/src/main/scala/vexriscv/Stage.scala index 504b0d36..e293f495 100644 --- a/src/main/scala/vexriscv/Stage.scala +++ b/src/main/scala/vexriscv/Stage.scala @@ -50,7 +50,6 @@ 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 = Bool //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 diff --git a/src/main/scala/vexriscv/VexRiscv.scala b/src/main/scala/vexriscv/VexRiscv.scala index c0da1d4a..be5505f8 100644 --- a/src/main/scala/vexriscv/VexRiscv.scala +++ b/src/main/scala/vexriscv/VexRiscv.scala @@ -43,6 +43,7 @@ case class VexRiscvConfig(){ object REGFILE_WRITE_DATA extends Stageable(Bits(32 bits)) object MPP extends PipelineThing[UInt] + object DEBUG_BYPASS_CACHE extends PipelineThing[Bool] object SRC1 extends Stageable(Bits(32 bits)) object SRC2 extends Stageable(Bits(32 bits)) diff --git a/src/main/scala/vexriscv/demo/Linux.scala b/src/main/scala/vexriscv/demo/Linux.scala index 31e9198b..09ed5142 100644 --- a/src/main/scala/vexriscv/demo/Linux.scala +++ b/src/main/scala/vexriscv/demo/Linux.scala @@ -40,13 +40,13 @@ cd VexRiscv Run regressions => sbt "runMain vexriscv.demo.LinuxGen -r" cd src/test/cpp/regression -make run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD DHRYSTONE=yes SUPERVISOR=yes CSR=yes COMPRESSED=yes REDO=10 TRACE=no +make run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD DHRYSTONE=yes SUPERVISOR=yes CSR=yes COMPRESSED=yes LRSC=yes AMO=yes REDO=10 TRACE=no Run linux in simulation (Require the machime mode emulator compiled in SIM mode) => sbt "runMain vexriscv.demo.LinuxGen" cd src/test/cpp/regression export BUILDROOT=/home/miaou/pro/riscv/buildrootSpinal -make run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD SUPERVISOR=yes CSR=yes COMPRESSED=yes REDO=0 DHRYSTONE=no LINUX_SOC=yes EMULATOR=../../../main/c/emulator/build/emulator.bin VMLINUX=$BUILDROOT/output/images/vmlinux.bin DTB=$BUILDROOT/board/spinal/vexriscv_sim/rv32.dtb RAMDISK=$BUILDROOT/output/images/rootfs.cpio TRACE=no FLOW_INFO=no +make run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD SUPERVISOR=yes CSR=yes COMPRESSED=yes LRSC=yes AMO=yes REDO=0 DHRYSTONE=no LINUX_SOC=yes EMULATOR=../../../main/c/emulator/build/emulator.bin VMLINUX=$BUILDROOT/output/images/Image DTB=$BUILDROOT/board/spinal/vexriscv_sim/rv32.dtb RAMDISK=$BUILDROOT/output/images/rootfs.cpio TRACE=no FLOW_INFO=no Run linux with QEMU (Require the machime mode emulator compiled in QEMU mode) export BUILDROOT=/home/miaou/pro/riscv/buildrootSpinal @@ -85,6 +85,35 @@ Generate a DTB from a DTS => dtc -O dtb -o rv32.dtb rv32.dts https://github.com/riscv/riscv-qemu/wiki#build-and-install + + +memo : +export DATA=/home/miaou/Downloads/Binaries-master +cd src/test/cpp/regression +rm VexRiscv.v +cp $DATA/VexRiscv.v ../../../.. +make run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD SUPERVISOR=yes CSR=yes COMPRESSED=yes REDO=0 DHRYSTONE=no LINUX_SOC=yes EMULATOR=$DATA/emulator.bin VMLINUX=$DATA/vmlinux.bin DTB=$DATA/rv32.dtb RAMDISK=$DATA/rootfs.cpio TRACE=no FLOW_INFO=no + + +qemu-system-riscv32 -nographic -machine virt -m 1536M -device loader,file=$DATA/emulator.bin,addr=0x80000000,cpu-num=0 -device loader,file=$DATA/rv32.dtb,addr=0xC3000000 -device loader,file=$DATA/vmlinux.bin,addr=0xC0000000 -device loader,file=$DATA/rootfs.cpio,addr=0xc2000000 + + + +program ../../../main/c/emulator/build/emulator.bin 0x80000000 verify + soc.loadBin(EMULATOR, 0x80000000); + soc.loadBin(VMLINUX, 0xC0000000); + soc.loadBin(DTB, 0xC3000000); + soc.loadBin(RAMDISK, 0xC2000000); + +export BUILDROOT=/home/miaou/pro/riscv/buildrootSpinal +make run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD SUPERVISOR=yes CSR=yes COMPRESSED=yes LRSC=yes AMO=yes REDO=0 DHRYSTONE=no LINUX_SOC=yes +EMULATOR=../../../main/c/emulator/build/emulator.bin +VMLINUX=/home/miaou/pro/riscv/buildrootSpinal/output/images/Image +DTB=/home/miaou/pro/riscv/buildrootSpinal/board/spinal/vexriscv_sim/rv32.dtb +RAMDISK=/home/miaou/pro/riscv/buildrootSpinal/output/images/rootfs.cpio TRACE=no FLOW_INFO=no + +make run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD SUPERVISOR=yes CSR=yes COMPRESSED=yes LRSC=yes AMO=yes REDO=0 DHRYSTONE=no LINUX_SOC=yes DEBUG_PLUGIN_EXTERNAL=yes + */ @@ -97,7 +126,7 @@ object LinuxGen { // resetVector = 0x80000000l, // cmdForkOnSecondStage = false, // cmdForkPersistence = false, -// prediction = NONE, +// prediction = DYNAMIC_TARGET, // historyRamSizeLog2 = 10, // catchAccessFault = true, // compressedGen = true, @@ -156,7 +185,8 @@ object LinuxGen { catchAccessError = true, catchIllegal = true, catchUnaligned = true, - withLrSc = true + withLrSc = true, + withAmo = true // ) ), memoryTranslatorPortConfig = withMmu generate MmuPortConfig( @@ -264,7 +294,7 @@ object LinuxGen { // } // } - SpinalConfig(mergeAsyncProcess = true, anonymSignalPrefix = "zz").generateVerilog { + SpinalConfig(mergeAsyncProcess = true, anonymSignalPrefix = "_zz").generateVerilog { val toplevel = new VexRiscv(configFull( @@ -359,13 +389,13 @@ object LinuxSyntesisBench extends App{ val withoutMmu = new Rtl { override def getName(): String = "VexRiscv Without Mmu" override def getRtlPath(): String = "VexRiscvWithoutMmu.v" - SpinalVerilog(new VexRiscv(LinuxGen.configFull(litex = false, withMmu = false)).setDefinitionName(getRtlPath().split("\\.").head)) + SpinalConfig(inlineRom=true).generateVerilog(new VexRiscv(LinuxGen.configFull(litex = false, withMmu = false)).setDefinitionName(getRtlPath().split("\\.").head)) } val withMmu = new Rtl { override def getName(): String = "VexRiscv With Mmu" override def getRtlPath(): String = "VexRiscvWithMmu.v" - SpinalVerilog(new VexRiscv(LinuxGen.configFull(litex = false, withMmu = true)).setDefinitionName(getRtlPath().split("\\.").head)) + SpinalConfig(inlineRom=true).generateVerilog(new VexRiscv(LinuxGen.configFull(litex = false, withMmu = true)).setDefinitionName(getRtlPath().split("\\.").head)) } val rtls = List(withoutMmu, withMmu) diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index 5726cdd0..04c84bef 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -86,7 +86,6 @@ case class DataCacheCpuExecuteArgs(p : DataCacheConfig) extends Bundle{ val wr = Bool val data = Bits(p.cpuDataWidth bit) val size = UInt(2 bits) - val forceUncachedAccess = Bool() val isLrsc = p.withLrSc generate Bool() val isAmo = p.withAmo generate Bool() val amoCtrl = p.withAmo generate new Bundle { @@ -99,11 +98,13 @@ case class DataCacheCpuMemory(p : DataCacheConfig) extends Bundle with IMasterSl val isValid = Bool val isStuck = Bool val isRemoved = Bool + val isWrite = Bool val address = UInt(p.addressWidth bit) val mmuBus = MemoryTranslatorBus() override def asMaster(): Unit = { out(isValid, isStuck, isRemoved, address) + in(isWrite) slave(mmuBus) } } @@ -414,6 +415,7 @@ class DataCache(p : DataCacheConfig) extends Component{ io.cpu.memory.mmuBus.cmd.virtualAddress := io.cpu.memory.address io.cpu.memory.mmuBus.cmd.bypassTranslation := False io.cpu.memory.mmuBus.end := !io.cpu.memory.isStuck || io.cpu.memory.isRemoved + io.cpu.memory.isWrite := request.wr val wayHits = earlyWaysHits generate ways.map(way => (io.cpu.memory.mmuBus.rsp.physicalAddress(tagRange) === way.tagsReadRsp.address && way.tagsReadRsp.valid)) val dataMux = earlyDataMux generate MuxOH(wayHits, ways.map(_.dataReadRsp)) @@ -516,7 +518,7 @@ class DataCache(p : DataCacheConfig) extends Component{ io.mem.cmd.data := requestDataBypass when(io.cpu.writeBack.isValid) { - when(request.forceUncachedAccess || mmuRsp.isIoAccess) { + when(mmuRsp.isIoAccess) { io.cpu.writeBack.haltIt.clearWhen(request.wr ? io.mem.cmd.ready | io.mem.rsp.valid) io.mem.cmd.valid := !memCmdSent @@ -576,7 +578,7 @@ class DataCache(p : DataCacheConfig) extends Component{ } } - when(request.forceUncachedAccess || mmuRsp.isIoAccess){ + when(mmuRsp.isIoAccess){ io.cpu.writeBack.data := io.mem.rsp.data if(catchAccessError) io.cpu.writeBack.accessError := io.mem.rsp.valid && io.mem.rsp.error } otherwise { diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 377b95b2..751106a6 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -291,6 +291,7 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception var jumpInterface : Flow[UInt] = null var timerInterrupt, externalInterrupt, softwareInterrupt : Bool = null var externalInterruptS : Bool = null + var forceMachineWire : Bool = null var privilege : UInt = null var selfException : Flow[ExceptionCause] = null var contextSwitching : Bool = null @@ -387,7 +388,8 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception } contextSwitching = Bool().setName("contextSwitching") - privilege = RegInit(U"11").setName("CsrPlugin_privilege") + privilege = UInt(2 bits).setName("CsrPlugin_privilege") + forceMachineWire = False if(catchIllegalAccess || ecallGen || ebreakGen) selfException = newExceptionPort(pipeline.execute) @@ -407,6 +409,7 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception override def isUser() : Bool = privilege === 0 override def isSupervisor(): Bool = privilege === 1 override def isMachine(): Bool = privilege === 3 + override def forceMachine(): Unit = forceMachineWire := True override def build(pipeline: VexRiscv): Unit = { import pipeline._ @@ -431,6 +434,10 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception val base = UInt(xlen-2 bits) } + val privilegeReg = RegInit(U"11") + privilege := privilegeReg + when(forceMachineWire) { privilege := 3 } + val machineCsr = pipeline plug new Area{ //Define CSR registers // Status => MXR, SUM, TVM, TW, TSE ? @@ -752,7 +759,7 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception jumpInterface.payload := (if(!xtvecModeGen) xtvec.base @@ "00" else (xtvec.mode === 0 || hadException) ? (xtvec.base @@ "00") | ((xtvec.base + trapCause) @@ "00") ) beforeLastStage.arbitration.flushAll := True - privilege := targetPrivilege + privilegeReg := targetPrivilege switch(targetPrivilege){ if(supervisorGen) is(1) { @@ -795,14 +802,14 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception mstatus.MPP := U"00" mstatus.MIE := mstatus.MPIE mstatus.MPIE := True - privilege := mstatus.MPP + privilegeReg := mstatus.MPP jumpInterface.payload := mepc } if(supervisorGen) is(1){ sstatus.SPP := U"0" sstatus.SIE := sstatus.SPIE sstatus.SPIE := True - privilege := U"0" @@ sstatus.SPP + privilegeReg := U"0" @@ sstatus.SPP jumpInterface.payload := sepc } } diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index 8b8d8072..b48386c5 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -150,6 +150,8 @@ class DBusCachedPlugin(config : DataCacheConfig, if(pipeline.serviceExist(classOf[PrivilegeService])) privilegeService = pipeline.service(classOf[PrivilegeService]) + + pipeline.update(DEBUG_BYPASS_CACHE, False) } override def build(pipeline: VexRiscv): Unit = { @@ -187,7 +189,6 @@ class DBusCachedPlugin(config : DataCacheConfig, default -> input(RS2)(31 downto 0) ) cache.io.cpu.execute.args.size := size - cache.io.cpu.execute.args.forceUncachedAccess := False cache.io.cpu.flush.valid := arbitration.isValid && input(MEMORY_MANAGMENT) @@ -221,6 +222,7 @@ class DBusCachedPlugin(config : DataCacheConfig, cache.io.cpu.memory.address := U(input(REGFILE_WRITE_DATA)) cache.io.cpu.memory.mmuBus <> mmuBus + cache.io.cpu.memory.mmuBus.rsp.isIoAccess setWhen(pipeline(DEBUG_BYPASS_CACHE) && !cache.io.cpu.memory.isWrite) } writeBack plug new Area{ @@ -298,7 +300,6 @@ class DBusCachedPlugin(config : DataCacheConfig, cache.io.cpu.execute.args.wr := dBusAccess.cmd.write cache.io.cpu.execute.args.data := dBusAccess.cmd.data cache.io.cpu.execute.args.size := dBusAccess.cmd.size - cache.io.cpu.execute.args.forceUncachedAccess := False if(withLrSc) cache.io.cpu.execute.args.isLrsc := False if(withAmo) cache.io.cpu.execute.args.isAmo := False cache.io.cpu.execute.address := dBusAccess.cmd.address //Will only be 12 muxes diff --git a/src/main/scala/vexriscv/plugin/DebugPlugin.scala b/src/main/scala/vexriscv/plugin/DebugPlugin.scala index 4915eea6..454d3523 100644 --- a/src/main/scala/vexriscv/plugin/DebugPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DebugPlugin.scala @@ -141,8 +141,8 @@ class DebugPlugin(val debugClockDomain : ClockDomain, hardwareBreakpointCount : val haltIt = RegInit(False) val stepIt = RegInit(False) - val isPipActive = RegNext(stages.map(_.arbitration.isValid).orR) - val isPipBusy = isPipActive || RegNext(isPipActive) + val isPipBusy = RegNext(stages.map(_.arbitration.isValid).orR || iBusFetcher.incoming()) + val godmode = RegInit(False) setWhen(haltIt && !isPipBusy) val haltedByBreak = RegInit(False) val hardwareBreakpoints = Vec(Reg(new Bundle{ @@ -176,6 +176,7 @@ class DebugPlugin(val debugClockDomain : ClockDomain, hardwareBreakpointCount : resetIt setWhen (io.bus.cmd.data(16)) clearWhen (io.bus.cmd.data(24)) haltIt setWhen (io.bus.cmd.data(17)) clearWhen (io.bus.cmd.data(25)) haltedByBreak clearWhen (io.bus.cmd.data(25)) + godmode clearWhen(io.bus.cmd.data(25)) } } is(0x1) { @@ -219,10 +220,6 @@ class DebugPlugin(val debugClockDomain : ClockDomain, hardwareBreakpointCount : } } - when(stepIt && Cat(pipeline.stages.map(_.arbitration.redoIt)).asBits.orR) { - haltIt := False - } - //Avoid having two C instruction executed in a single step if(pipeline(RVC_GEN)){ val cleanStep = RegNext(stepIt && decode.arbitration.isFiring) init(False) @@ -236,10 +233,17 @@ class DebugPlugin(val debugClockDomain : ClockDomain, hardwareBreakpointCount : service(classOf[InterruptionInhibitor]).inhibateInterrupts() } } - if(serviceExist(classOf[ExceptionInhibitor])) { - when(haltIt) { - service(classOf[ExceptionInhibitor]).inhibateException() + + when(godmode) { + pipeline.plugins.foreach{ + case p : ExceptionInhibitor => p.inhibateException() + case _ => } + pipeline.plugins.foreach{ + case p : PrivilegeService => p.forceMachine() + case _ => + } + if(pipeline.things.contains(DEBUG_BYPASS_CACHE)) pipeline(DEBUG_BYPASS_CACHE) := True } }} } diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 8e1c1468..78f15a3f 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -3489,18 +3489,24 @@ int main(int argc, char **argv, char **env) { // } #ifdef LINUX_SOC - LinuxSoc("linux") - .withRiscvRef() - ->loadBin(EMULATOR, 0x80000000) - ->loadBin(VMLINUX, 0xC0000000) - ->loadBin(DTB, 0xC3000000) - ->loadBin(RAMDISK, 0xC2000000) - ->setIStall(true) //TODO It currently improve speed but should be removed later - ->setDStall(true) - ->bootAt(0x80000000) - ->run(0); -// ->run((496300000l + 2000000) / 2); -// ->run(438700000l/2); + { + + LinuxSoc soc("linux"); + #ifndef DEBUG_PLUGIN_EXTERNAL + soc.withRiscvRef(); + soc.loadBin(EMULATOR, 0x80000000); + soc.loadBin(VMLINUX, 0xC0000000); + soc.loadBin(DTB, 0xC3000000); + soc.loadBin(RAMDISK, 0xC2000000); + #endif + soc.setIStall(true); //TODO It currently improve speed but should be removed later + soc.setDStall(true); + soc.bootAt(0x80000000); + soc.run(0); +// soc.run((496300000l + 2000000) / 2); +// soc.run(438700000l/2); + return -1; + } #endif // #ifdef MMU From 189cadfbb33b328724e2fe3f08b356ed458ba0da Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Wed, 10 Apr 2019 15:41:38 +0200 Subject: [PATCH 134/951] Add coremark --- src/test/cpp/regression/main.cpp | 24 ++++++++++++++++---- src/test/resources/.gitignore | 1 + src/test/resources/bin/.gitignore | 1 + src/test/resources/bin/coremark_rv32i.bin | Bin 0 -> 24376 bytes src/test/resources/bin/coremark_rv32ic.bin | Bin 0 -> 17832 bytes src/test/resources/bin/coremark_rv32im.bin | Bin 0 -> 22776 bytes src/test/resources/bin/coremark_rv32imc.bin | Bin 0 -> 17080 bytes 7 files changed, 22 insertions(+), 4 deletions(-) create mode 100644 src/test/resources/.gitignore create mode 100644 src/test/resources/bin/.gitignore create mode 100755 src/test/resources/bin/coremark_rv32i.bin create mode 100755 src/test/resources/bin/coremark_rv32ic.bin create mode 100755 src/test/resources/bin/coremark_rv32im.bin create mode 100755 src/test/resources/bin/coremark_rv32imc.bin diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 78f15a3f..e71b2507 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -3499,8 +3499,8 @@ int main(int argc, char **argv, char **env) { soc.loadBin(DTB, 0xC3000000); soc.loadBin(RAMDISK, 0xC2000000); #endif - soc.setIStall(true); //TODO It currently improve speed but should be removed later - soc.setDStall(true); + //soc.setIStall(true); //TODO It currently improve speed but should be removed later + //soc.setDStall(true); soc.bootAt(0x80000000); soc.run(0); // soc.run((496300000l + 2000000) / 2); @@ -3679,8 +3679,24 @@ int main(int argc, char **argv, char **env) { #endif #ifdef COREMARK - Dhrystone("coremark","/home/miaou/pro/riscv/coremark/coremark",false,false).run(1.9e6); - + for(int withStall = 1; true ;withStall--){ + string rv = "rv32i"; + #if defined(MUL) && defined(DIV) + rv += "m"; + #endif + #if defined(COMPRESSED) + if(withStall == -2) break; + if(withStall != -1) rv += "c"; + #else + if(withStall == -1) break; + #endif + WorkspaceRegression("coremark_" + rv + (withStall > 0 ? "_stall" : "_nostall")).withRiscvRef() + ->loadBin("../../resources/bin/coremark_" + rv + ".bin", 0x80000000) + ->bootAt(0x80000000) + ->setIStall(withStall > 0) + ->setDStall(withStall > 0) + ->run(50e6); + } #endif #ifdef FREERTOS diff --git a/src/test/resources/.gitignore b/src/test/resources/.gitignore new file mode 100644 index 00000000..38afe6e0 --- /dev/null +++ b/src/test/resources/.gitignore @@ -0,0 +1 @@ +!bin diff --git a/src/test/resources/bin/.gitignore b/src/test/resources/bin/.gitignore new file mode 100644 index 00000000..1eb37dcc --- /dev/null +++ b/src/test/resources/bin/.gitignore @@ -0,0 +1 @@ +!*.bin diff --git a/src/test/resources/bin/coremark_rv32i.bin b/src/test/resources/bin/coremark_rv32i.bin new file mode 100755 index 0000000000000000000000000000000000000000..62cb11107f99a845bd6f2ed2403ce44582dceb56 GIT binary patch literal 24376 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%0A-Gc9~nX))t0IJm+4UC2A!?~m&4nVB)sz^pJ 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 bDM^LUEe*;-Fju7T;CcccY>dnC2mJjnVdoBr literal 0 HcmV?d00001 diff --git a/src/test/resources/bin/coremark_rv32im.bin b/src/test/resources/bin/coremark_rv32im.bin new file mode 100755 index 0000000000000000000000000000000000000000..23f9b10ae001f95a95333d993b392d4db2f67658 GIT binary patch literal 22776 zcmc(H4|Eh&n(wWuuBuK5N%WFGGAy)K5+Y(I+Gre)Gt;37K}BVhf8#nL79qNWgn{s9 zP%uzQIv^9!tKhmm!Hp1ij=SSbsqM_$Wk3z#IUZ%7k}$JAai&ee^Y|bN`2)uE`+c{% zlb{I9*|+EAoH|`~@2&5C_xt~S_f~Qis*Eej<2iE}<9f@bJMb&&$}Y`WjAz4WvA$eoyvnSAF2}@{ygImpp}nR?S+Om1%86Mu z>Iue_Dzwp6S%Y^KWkX30V^+Z>>#e*E>#ZvuUvC92f7B|vW}P*;be%QnN9(M@h3l+> zpRGgxI`prz0?)6rihliYv@agV`~BQB9T90=7c?g_UJo1#o@cJ!2OR#apD5lpm+P7A zL}1$(Yy9(Q3*i0`wH=A$`W zvyWMMpEIYqb-i70-oVXFWzDeY)_BDyddgX_?f|nJ zh^|?TXXy%`gUev+f^+t$CH^!v}D}RHHSW2-J+iIyCzkGgV++*5uFCDApf66_1Mu=v@2OdN%?Z)b5})YTO6@ z=HNNf#l(&rIsQa(&5hcX8#HT@;ENYR;{-m}>5Zw{3FJ=)AGciCw@4@CQ9|4#eTo`RA& ztR^~%^rdW^*u3_ul1~}t+m^yp{wXFNOJzLumY+o*Vl`UxFBav40_N7YGuQZ#Ic*0v1{?M$A~KHgF@8nc1DLaYig?yk z_}}37!!(8eWOS)L@Xk2?wA_td)}(Cw)-}U-fYN^p=xc5HrncR zEjo|Y2qP8xo(7(pSAY)doVK?%iu!D3ZU127x547Q1T(>R#|UjUoMuJ!c-& zh=&QCtLi>_FsZ|&zof^c!`k-N_0I0dqmu7z)^gHK*cKn@V$3k#IoCThmS8(Ox}?r% z*?^JX`l#4pD#6ZHCX7kJc#(T9+3>w-(cSiPmDfp@=p^v9dp)_5ZoV zr!ek26(<>joGK113H@4Xbl^M`nzNA%=&Oy>q5Xevz(=9iHuW&C^V4tK2AbALMrva1H&4Yz?hPt{ZEPEjl&e%{g&+PQO|B zpPMt1nDgc^=yS`r&6%**2H|6GG}Hcbb2caDOeq8Xr=Dw0f-l!@!p5BTd>qlS6-(G zeggmPcLMv@bJ$-E{@=+fU9VlKtaq;5zfPO9VVyInbe(pUvd+0`|0CMu4UagJOCQm$ zRvvM#-v2P(eUxGdVJ>4<(dR1kt*#^+_SG<)pi#hrhM|y8wet4EFBy+=Ba_8^W@8oG zrv!~Xs?Zf9Sl_~|!u@J&i?IcE;@^V)Ju24}BPxArHsjfVG1pLneoZOifURjxP_vlp z=ZckgiDLbW|IyeMy`idm!k6Cq>TbvSCgb@F>pSpo@S!nw`bqA~WPralF=ht%KMBt# z5;VC6&sP%d(Dt^o8+w%o-wOS6YhO{}D{poWzo2?!TfPhU1)L1;_^gnnuC3OnMJ|oAzEyr@Pc~VEogBbfKX@3Gd<>#Ly z#@>oKb|mndKt9d$S2g2dqmGEwWz}NTvTB|>_9ozr^}!c)AAKD>8MG#EVA>eOVTG3~ zR?#I)%&QJrlO9K0c8wzXav1;lDHAc0Pt@v6%$X7rJw4FPGR9X|Gq)qk$d@|pwVIuV zG2oe<+V1CButya0r1)S9O~5#9@@ilAi2%DKxM&lzo_#^(i+p}-+a?BiQXosPUnvao zq(Gh&$P>kys+1Qapz;X(^#_L$*9BB(dmem&k2$-iDcbH@g|F_*IFY&SM^5`E8ovy4 z{y3%7e$r&t&KFd|3pDKK^}wO7Ry~nfbG_64*3h`vHgk~1SkJvc^4N10J%|RNiKGYc zBH9emWD{uNGZ`^;h52lX3EN75d; z{MXX|dy@WRLI1l`zefL^pNos);jHTjh5!%6AHUASohOHR7#b^in3xOkL;o-jkA6Bl zZeI?KOTvpiYn~Y%xAVB2YA`J;AF)9`3+g=~k~Jp>F*{-dK94T=pgyzP?Lz#P*@JP2 zF){v}{oAO27>YnL9bT&>2NJ1ARlBjd;805+C%;2N}~LSGtu~s#{n5 zNVftDb*t!Sh{qq-titCttKioZn=_t<`SZ$Ddv50U&<48+n~+X+0hb@RPu$PMs@@E1 z(!VqNfH}!d^WCdWoW=xXUzk3oA?~-wwIc@Ir)bUP%qiIKwHfX3Cnk$+HwOh^q91V) ze65f2A|LX@4_GYM97Il1Nbe`8nWZ1vF!)H5IOnqU9F|A*$=y8 z(m3ei=ghw4F@(*%N}6=NqYf&_4$e<{zH7-cR8(5@^uXO8rZMH|LCxPI(&}~-{XV*^Es1B zeTZdzh-EYl`ifXaLoA~qmQkU{2H6YJL#s$(v3p)_vzc$K%)ya!2y+YNxQvem%~P;m z$b?l09Zt=JJSvJ9J(`J8kP*m(Rron`{u$4YeFw5J8vPrXXq(JGChei|3cOc~_0uoDd|#2T=PsBK*5%zH-@V_?IO1KHb6AJNSk{}N(>1t-7Zv$7{M zEjtbNVWy(xZ%M=*>=tLmpym;eTf5-b8ce^a$NZ5x*zk_H7=Ime8xJei zKOR;DY>f4II@}#!R+d|&V^s$cWH`Sz5;wHft*E5 zzG4Mnb~3lC62FM=c0^!L4aKcQ%`USazH>g~5!fMr2JC1$6AihjF=c(}z{c2{k>i-N z7_G4+j5!hiaP4H=f$g-r_gqSL$a?$;{9iV73i9Rwg2cA3*p9}iMvi+Yzwm#!^x{PJW*7F9xq!;G; zSSy5Y^EWWN_n41-J=eg4WhZ@BAX{-JA{KfYvCDSISO7c?=!$j4F{~Bi2>(bqc;5>i z&4B#nDAwbxUac8&MEzuE35HgH_z664b|ZG#gZaTP>x!u7>jUk8Val=Eo-+9OGQVq_YEL|U@J{i}w zLiXhNkoP`4Hw=#lJ-(uMl9$bNmE@|5)kvIaErbuP1^!pU2QFjaQ@%p|T(JrlDyW|$ zU)=zE_B`${QE{)LmJVBaIpW4^6l-!RX!y87^-%E`(Pt=YfpU7g*%#MpqsqoJ})ox6YF@S@ZL(9JfGM2`=YDO`VOBp-Tdz((5 zZLhcc2JFo#Dq;udq1W%l4zSmcfj>j`8gtj4iffZnJ$sGZCzkE&l`+}omlW~LSUit9 zm6T2RV-@}wb^TG4532CVDtxj6pRB+qEAYt*d@_SiX7I@jKAGZbjp&_(f#*1Agq2zz-kj26_zDx^>jLyE6_rb858{nfnT?aWA0WfLga~-};u<9?GY7 ziW7;3u`z!?09-*+;E@MBt^^)rPZULwxcm)ZP(302^nj4{gq^1)kBN`qDb?sDUjrj} z`gQ(;$0P&pq8+GL>(lvVS*T^~3h^z#|1wi?^#Vmm-h=78Zc!>s=vLzqRoWD^Q@-IgcLCo{)cki- z-o|1_-WuRf4ZkDd;=S1RBLkv-Jm_^CYdfNdMzV`LPYdt}^#XqH(&8|q7l}DHBtUVu`Tx_ zruT9wxgMF*U_IPF1LLr!W%WL7BJAggHM#XzlRvShwhyo-_zKE}hzvpUp*9r!G=p~SCx;6wMo(V?}CCtrcQ3u{Aeg|!tZ zL4QAs-5(i5%ntugvJ}R;@>%TTh5_=AZetN*gFBSi{aerc|6g-Wh2$T}P$SlwXB_~34ttOV0$DzOLZ`@hL=;P79~?@_lV`8|i`5)s%{T4Q@sPO~AW zC8gHRuEAJm{h-8o^CY}ePjl>XX2O1u zog>?Z*bO@7GY~Vkz$e#9A5QTV+2Rx33w}j4eQ7^oN6BthWwIIa-2&L`JlO0jE=Nrm zan~5gE8;uh^u)!TZ>z1}C1ll)27q z)W&pwNjhxwm@Fo?LeEK0{F#vJ>JU#KjEg!?Ur>kEL=Ivv)ER=#UgS0TGVbJl=)}C< zQmPG+EeNhUK)<12q?Pd;Q`U^+Uh~e5LC92wl?i$J^u;q$ceZY2vHN~?#*N$sz9C0O zja&4!VviQF&p&Qw)~*7?*Q=Pd2XPSSrd?S&KBZnkk)EyUU056tT0&vpt{-={fOCJof|G)(Nov=@fr>wiR=dO`*8jZtPcOES0cB!HL+9 ztV0|w?NA4c&3|oxXMq-pcL*lE7u()1ZIJ8#s5F*Yb%y*M@q>Pm5BP$>i|2yQ$on~R zi=ZF13$j1si(og8NZ%w(4f<(?O5nIv=~Xm-NSK_8y(9Tatt4XhHum_<)n}0q{30cs|`P zu;!%v@(crO&Bh)mBQ8Qnc z@VV*8EgEkJ-QW94II#U06O^FF6?fxC(*HVKgburDWO(bQ+GP&u z8+=1umO?i3oc5CZ#n?9otX=T&N&KFD@5^uCH-2UR*YV?i=rNtcIAvO*9&)lBJZ!_& zw+b|9k5ip5Iv@Lycd;7Yem!UuVx*6xv!bD49(>bWkzND3>{I#b5@vVyq{{umNTruU z<$#WnW76&mbth;78;LoP>&SWRGwLW|)-We*GB=}Bv1%S=+8sHpspf>D-7%3_8|b%$ zHR0E;jjGxm(9@07Hjg#Q-%4gV=-b|o`qXOHi9uzq_`g|3DuPU%hHs}fyepQ=6f+Fzv;u0gZA6mp2zXcpwTqg1ZH z*EEHm0o^lItA=t_*h+l@Y+j%0>aPJW*g>-xZQo^fZXeFuB-->JlFfuJb%tEC7w1|I z;LHqiZ{$*>^RZ{UV9U_9HH!LVyW!D_-~;xlW`o|bh_)u+4mA6QpMOaGBcAV|el^+8 zGZvsG@GCV)v}YMoW)thxj2f7dbSuY-DG~V856mk=A@SeS~^9t^t zF}@PLy`yQ53Ug%GXO4|^_LM0cFeQ%&&M&?El=4|xFE?IBu7AMCjYFzkPro0dCUzhf z?}0C{^Tb1>M0ojrgXnfI0GYtN8t*@HUuW)Js~b2;T0-(aS5vj99aGn_qju+b*o>yz&h zovoJ+v)Cv71I~1eX*6&S>UxroQQUwWKt=?3N9(iKx1nxOCV4wVBhV1|{vXNrh6LX? z8-~3x8}@oRnruYuV9Gk>QKDUvPJ-ma z0G*ydz9o4-i{9^~oB{K9c(hxF`w1Pwybr%SKk>#DQ-93sr?C@a!VFOVUpVliy>#^d z+3P2m6aMVI7sCC5kKq>rh<>@k_xV=}G0Qqu}7G_k*gJ*G@gYGb251?^s0s8 zGQ?elii!*8)9{OZC!7gGEgQc@_(iST3Mi=S;Qk8yUV+~{{N~}e0KWx_Do~T)qaYh3 zA1UA|>Hv0)o-KTeCQ=di)S)I`mrC*9o5ECd>3{2*VFUM5oo9gR{jx3|=oyHOH3tYM zcT~0Fl%bYiUCo7*IUftQRw(wy!?1U>ue2ZbcOq&f*cTdHtvD^F?2kQhcre)>>s%do z%6)Q;goivMF@(#`-(4&&z(FG%2v)GQT){q)VX;pT$L_~Dr##@W0eMt)ock1oZ$f;V zPjz>kjqy!G&6(Xyv9gwr=aif2c?Rth$HqTNF}jIZ*mS@n)Dle8JPg!43};fQftrVb znuiX4`pHHN&9k(+k8)af)C;I*C>rKHf#?3%llm8s1)RN`#q7_TeezsVB(hl28aXrQ zEPZ0MlGSLt&20qJyN`^xFCTGlZXF)e+9>T*BHnYSzsl&$8J`C~-kv4*`=WbL3x8gjv@JYU^n(`douVc(61dfhUkZSP6_BI z^S9R4A-YKVtpfc(JKhdkcfN6;GjBuObRIef4yqiMCbe zg-7SdJp9|wDJOhR9Sa_4hD>?%6LS;v23?Z$4wix5$r{UnJyNd3yotzv&X&_)+2P@F z;E_CYF}EZ!&OA4~>4y{W$}bY$yo-cac~S8Ayw&H0CsrdDk?ZU_C;n3Y4kqL;2eHE% z%5Nc?ZAm%wv*>QfE#*zE(P24++=!Jl2J~)&9HJKaZR1G3#Nq4DD-Ui9VD|vmwuBsB z5Z>I2gqM)R3&9(b!*k0&haP)!*mh1kMCU}@1F&Dc&|$=R9C9eff1BM(=$)85@%-yZ z+Cj+S#lb7TNOF9)_3D=L^C+zdjGcOX%~3;Qc4{S+v))Ao-Wo zpf|LY0JE*+{O}U?mA5D8H$whL+Sg%t3Hp5- zenapQ^t%we_SNUbk0V4u|8Kv*?qQ>$wR!ew*AR`8PK~$8V$05WEB(F9dH$4$qCBSe5iE!}>f@ zu0(s}uam(*?yt9cGgN?;p zsQY|DeaJJ;SVbFfP7&u5Cta@deiQq{{u$BxS&i8E#%6KSMD0tP&iiv1Kb@n945rzt zAJ5?7DHD6b{^|C+*sts_XLhE4CeC_z`>pjR>J7bd?7h;yF>qjt?eCo_%=);9B0jF~ z4cX7=)6lM22F_7Y%^2tGs7^0T)HpNJah~lseo?op?=0mG&a;h6Nweo4ni(`v8`ft* zMoN$aR?HMCYUJrA_HmhNu~)Iz2pB44*XfMooUGO)+ltYakG8hBo!gFD+;z-SpxX{= zUYj~YV*UR>J*>mfBs0W}nHV$>lmFSQB26bLHWUIgRd2>aXeb0Sr z6N}0@?Y5<=rO@P4d2&*?(HfES1_rINQ9GHQ_#}A4W~;EvmBi_a-vyU=k@l}TDm>=&`o0c$+&3iEp=DD&xi)x01av>76Bb*FTM%i zUfjS_PR7A&>?e9O5E{-ys;$70+B_NvEe0C2f*wSJ9@MJekBjHFGS~M>$US~k5l>|( zZU<`7+qWu26EXN!JlNTS8u4+|1X>d`i4O8!v`5}RJ^js)UGtXDVttB7k3KoSJ$Eta zLHD4?ti_-Q-Gd%?F9tp69`u;K81(2{+N^`7<7Ng|#2jXDg;4g-EV)|w8RoN)sDehq7-Hmo&0A8kjm*4J=PYejp;d#G`~ z5fUr$YqYSElHy{wt_5o{@r_X@>Ri*o@7D(TD)dL*MJ@k5@cTW~foLw!td4LSgiPVS z5%bO7i#1X^=DGJHrHSshz8AOW@5LHhvA#j23BNcK#DeuXsFmrSoFf-@$_&(GkB8hy zj?$D79dyke%-VTS zW37G{-?w#u&&NTFRvmPgwHV3knl3r7f-D$hOr*0V`d@lD6k*I-wuHugJLe>vpYnL}!9 zyzh0gBV<453=W-_3Z87iS*lzX+zS8RNVG?rb3fC<8gmb~s7)DFgRy~k2T()#tq132 zoC%!pYErhKizdkv?F(VPR*|lOp0Zx}nW*oK0~dE_Ec6$(xE7&d3~UnVBHnqM&QM_7 zXT*Cv|A#z#fb(m(|92kggbl!YHFN)c>EEZf1z)3AI6!Yhpobe==<5j=zAD_57Rjj(DuKVWPvW}s8gkv?GL7ZgtI2t z??inH-+%3gEy8mPYTr86*0LY_f(o6{69(0NjW>eW`;xj5F(7->-*D^kysH;lo*-a>T!>t9`^|9agU%L z_Xz5752GIUFzRs+qaOD#>Tzqe$s5)>lS|iPy!^JwDdT|6ux|LRhz=b=K4@@eAL~?U z-zR96(;gJ7WF`|`@SPg=#__g+YYa9yEy3l`I;Cl|-lTB851J3F1##!JLKkCePoOD{p z!iV6T*%Ri682i6yEH`$M-hD;)+KU)VFw^~0wCOl=sTylz%v?)2)Atar-WdYD;hVB0 zezB)@?2DNS&I**q8qAPAYhNliXFzw#Sg@pnx!1i8J?M?|@*E~w;De$&Sg;blz7;V} zUl+qWYuw5gk*8r#@CkE`SaSgTp+p}Yb`al9>^5;%HS|Rta@sWwFsiuS3ZLQFaLfG^k_!#JL18~9m?YrC3T*L@L^I(W# zCAZ-~Na8Ti@d)WX)x=@95HEE|eOkHLTT!hb?8 z(vQG@zQ&qxFU*7Rp9d66ZHNEtMSReXwPAk`yv149y^!U79$&lTv0Chxf&U~6#8;f{ zdw)m^1xOTkmxKZ!M(W1MElgde=a`($gR{LKIOZr98#<^Dd{ zXT%=q&|~nBx;CGFD>|1Xw%COf8bon$^-DZufdMI94$TBA=7TZ0e*c3(`L+P;!kC$ zHTFP{OhC$dBaze)v5T z@8ew9owyc+5d#l0zJ3sUO21~oQI(3DI!|%6)yz$AS6p=-&giu&ZbqNNSDa+pclRSt zsASr$IM@1iDs$e{nDZ{qj=!M-NBq8rBr1#;LEojpjx)<&6>joB8n#k?KeZ`kLD)*& z8g5Gc{Zwnzqf?tk9SvJ)Xir-()f)X?xM?)n)8pYF;nJ&ysC3dKND%kmAfBN%*z-t7h-_X{2F{$}{7LLU@1Rp&06&Tgx?(?Vo~r8J+B+n#uqXDj z9o6*h7wphs&ko`Ltl+!cq#x4Cac*BVmtx(9{XaWaaV=y7t14BIzKcca|B)bO6Ak{o zZo@%E%4OZ_QU)E!nDB>)UKkTV9i~zZhL37N6Z?}S6AdS(2F*o~GZX&ksMgd_H8naO z`-$imjp=)NhN4g(a$Ti_{(njYxn04Z(ch|A{>rKHn`(*|HEnNDd(#_Z#^e~y!dYne zAfEm)&QiLd+nZtAXWj>&Vc7GJFXkB`gYe^6gS&Nt;x6sdM8kE!u}gDX-u)VmufQe% z$F6rZE5)4}MVu;etkd_>+9i&4EeRaqZ*_b(06eXRim5!3>(NL{(&zzCcatAf;@laNO^pTRZI^=@}Q>IX*f_+gFg z3)gnRUS%j;;(Azf%a*D`y!R9DUtw;=QdQ!*>6pY-+O{OFghO2g^LS5mh3$}Z%?fi9 z@da#&s6)-=34H%`cl%lyOEh$Zgx|9vcEA5&yT)8YIszYoGk>rj$iY4PkpuruZ6upX z`vF@kb8y5~WIq~vLy$eGPof{WXCdN<2IR1Q`W^;zN6K*~3FiaR7xa%;T$7jD8;|J7 z?=W93VDur5=!2cYeIxwf>`M4vYKI@Zw-tGKE?~e9&aXrso~zii`w&OuDnWlc@@?e3 z#_Q4t(;CTs;G63i0^ih#XaxT=$ecm{3kaVvfxiB|6#II%q#yAk>3ck0 zf_C^$OZuLO4&AH-PqUOE-xC?>doVVF`1xQT{Lc~40yKv2i55V1;CqluKz7B$j)Y*lR?}>e$)1W zp17AWHgYno??cfD{kXU72B{m7cSA}4YWH@`M0`CX8DC4^s%0UMqWF4*Z`JbAmRO&b zs87lG8o6rvyPj^W^y)I_@~r}WLDL1l5hJR5eaV`nXdvC_1s&nD9ny_#e8CXKT%;SQ zx6!@S4SZLuMiVi16mSkeFWN#Bn^KMsUjEw2hpjOuGPe$Ti{rLdgC0g4y?3}Bypru% zXrJ&K4f5|&Tou9E5IR~7uTO=)+bwM*^oi^woi$C`9kMwdET##60Cv4&D$xtDo<^CN z;^MvBgdU=1fb*${UzHs5%Ac;wQVdmH})*q?qIl8bBZv3<9PVYeAu)_@~l&^ zvK4sj1s)5Y5jyhhLmgwuzXrqYnt&fHiDT~@`U_tVdzFb;Wf6R4yGH&}#%b`EZsVXr zzS1iAcg1R0O0XWI960vD>%Syh>>jL8HOw7M#~E2a^wu0Bzh`zkD&TjHWBh~{JzQN6 z*Ed^+ah2oYtKqlZjuzlb;}<;htv2XAGwi&Z6V~3H7}nk_2|EYN!`i`liMXaRY_Sfd ziJ^w0^`Pe20$Yd}O3gwY686emhHtF<{*~;Mc5roApw`@^=}IiM?{{8X1Z_BL=R+Gy zw(UUMF4jbCM&Ik+xMsAy%q$&kX??GGZBexCV@=eiCfi!kc8FO9+WdX5c;nj9*3Fuz zZG7KvsLg5Z3R}=;$O`g+0C++EgmR7dPVrt7_!$Q|Y6(@{8Bd%mUz0f>>T)^)|Ni+Bn1wUHDPD^`Oqjkx6vk!cE z3Vf+kEM+C}1iCi|JXy&sZ4P+QqgX!h%?G~e;2H8=qFIxH*wpM`O`wfOC&aDrDTp%< zQ~t(L3ny8mdID&*$*VPP{cnQmiuF3;640Z2!V?0vmFzC=w+Q-nMx*^}_0k3%wEsb#DW819v^RwjzMP8w2@ER;IGqRn-fZ1gamjf4YKNztR3s zMWAp+g}vfRj9&y?Zw9|4iC290t_s^5Pwk2I-nJ6!tyoiGuLMfO)rHl8B^3+NcujGD z;CPK5Ed$FdR;*l7eK|3F7_P)(2#@k`_=ciui;77m!c`9~1D}@%RzYS+EP&GrynOW? z!NAp(fvcy5XWkLM^{xf8%I;inS6TS`*A&Y?>bT?1vIW!1rp_tI z6R_@@T^ha>18%E$sA~Do152uGPoR?hD=I1$5kH6iZXC(SML$8GB-1)cpvM<43 z>itHa$4B|%H~JPoxD;&qS|512yuz*yR6(;mEE6JHv8X6;S4BnO&a%>Jx0Mw=v`A8& zbZ+6&MWFh!s^!%WF0F)GEvZ=H>08gI}tcECpPYah<1Xe#-{Xl}pD*|BG!oW|LR;`BOFIiYkmVjoy z3&Q)Ljf1!q3zyNHc(#9v-zgTWq3e^x^+6u1nK75u%)&Jv*L}EhapmDE#&r{}WB9*b zr*JXcr{Q`X_iy1kgzH0Gvx|#@6<1#~o#wfEcG2vsuA2Qby1!<2uxLuf6#Q2~Tn z;yyDmS7^kX?*O(h%xV^4{C~xji@7cY_Z8qkV`c-_&(49zx!P#_42&O#D+zyAVy3z9tB#S{R#8Oh7nWq0 zB!GZ)2%*+bsM`AMx|UR_?uvpCC{?sp0sHIPZd1f|cg1P}wLkwjT@sI<4C6PW9u7`KIJchqpkAz4XaeEe^5W1Ll ze_!9{gVjCmgVl}aGmjunNyE5%?U6nQ0u0$|V&k^pCp#z2i5#OO_7Ho_*~2%`sg^6{ zU+({+sja!?!o`*gU!1?v{LPuGP2V?OclBlh6(*Kp1j*WvLE_ zK-;<}crO_Otx5A@z6^!m!*h9xUK(?SPQ}=IGyNUM z9SL>9frc%-$i&bFzPN)dHwX^qEmLQtp=w&_lah6jhKugmA~DP5Ttv^7n~UgGtV|~O zm-KEbx3fLtPs3M@ z^95fbpUa0c^ZA|hTxgHwLz(E}{Ni(isY+ZZ*c-OYU64@M8N4U`n?;|vMMJ`uVrp-O zWCc0o)NRRgRF|w=L?lV!l(yxy0OLKEn_3BSl@b*ooFFgasP9GkDHC zZp2<$?*iO6iShLX&&7TGP+1Bsa}UqG2eSMP;Ftu@_#MqZl z5Lacv`Z6KU!P0eG66~G9%gIh9n$W5IdV;UN+!2#c0p%tgP_9&mlp79;l)Yn1r!qU( z*Jj@8RGtcg-cSwIsZ<8-O$8YrKA6i>T{HRa0})YcBxd{`KA>yn2|Ti!59=B^O^32` zUt($cV=3?T-ltyz%o|z158N&JtpAJ+RkKhwb)X=Im}Q#DQ%s5o^B5s3GtaAC`jx2n z%MDI>36UqSF8!udXmOcUw*7=;9f{as3WC~S5TnVKb}$4xN=8Uu4kg%S0UF+OW*A#C z6TwUw%#>A^d{ZLqugm62Wo9wYUQ4yCGV?)tqRN1>FIcXMtk`e@q_9S4sWXdmuJoe$ z!I^A#G@@NpOOBZ*HdA@u4mnD>}ETI;@XXe@H zA;Q8s^E*{O`*iPMS|SYtR{1BV&vyJBy_v@yRB6K&VW0Ia&;U9=`R1a7r?8#6gP69# zPziOBVCfxTV^kQxM>V`v%PcFrh&qFnV{R@I|B?$*99P8qcTKgwBw6o%&;P1RhV{VG z^&d%jdCQ+(GYa%@YANeCeJR$%_5=G)V6K|HTrr@1v;DAG{w$YYK> znjBP1s<|9&WBT7B9|z!>Pf zZ$N(WgD|Z7@m_r+zhs*N%MWDv9gIKajn=`zYay1u)jfyMt)Aa9U%%w&lIW$SOXa`s zes=ZDmYMolM`!u1FlX;HBwYFMuk>ojGJ=0;Vrh18Tpc&TvW3>W<;)-b-dD-@lUsvh zOXJ$yX89jOoGQhBGCR2URa%}X*O(*A24b|nB(jc+mA&OIpx^(Y%14dvd*Jss1t+;* z@0E!LxBSjwI_a~&_K$trsoXR1os<1^p9TAwK+9%1g?(UO^OuUwoR3JzFfTYSy+`_B z#81JVV(fn@&Uagwe~$OAA>v3?DdlY+9T4Z0l!>}2$8{qXDRI73kx8psMT_sa++j7xO^~$6f;)SHd>6O!I(268i zlCf6);w8i~N>V5ti>Oi=I+JXh$!7Khbp~fA3$5Q$>~NZ3m-uPkadW%hBk`(hP9|7b zF^B9#+m;Beb@w5&r&`r&)ZE%7-K>S3ph9=?zn(Wb?<7ZuJRjY--Zj!aEa zRyse?!A3x)U#uWXw8gHn#In;P)jMj3ovJkOjSOP*!;us|gs8D5xV*8%;@;8NErmxR zr?o*->!@XFgoI{ZeR$+Zb$Jf;0fXAKRP=NtMEjxhr@6@QP|4{^1E=&u{5fXmm+DHr z-~fs(ttdzRuiG+p?wLQRZ|W#J16elvtsHesb361>K$r2g^Rq5+D>uGJ5W=P zB?zr4$&@0_76Z#ICPPW0$e3L2QGIYau&msI)LCJC z00mY1=U}LpJpoMtjpdfCFr;>eQ+-EsrV3qEU#c(Yg$4$>b6aovI1_(-=HzipZ+L|E zv#K$-IVFYot$nmSkk6BijLtEoU|yn5@|5iH#cI%_fkFH`SJ4MY+O!w+_|1)4zr}it zI?h@>|S{ITb`5+gG#ziVz!bAXCe!T=|mFQNYAJ>d|zOC zR%8+yg+B!#aR@I4K<($={!?H1Ox`wRC@%~ROzW8f`8~I04x~70wJAx3l zLuBglS4cnJWj=6Am*NMachBqn_?9*BjKPn!`vbO?9E=TxNk9Gw*!*ueuMHc7Z8+hS zy{qPzZX>T-F*m&O|`)~_!iCn5Jz)%VukUsDqU zP|eA81#U;c^+c~NLzeXGIbUvoJw}~7T=q{+i4eJMr7pqJiI%@9EILC;!)U0sK5%2c zxzT?l3m%MQVG|G)HWUd_GYKkcE8)!-Xq!=3^w0jekS!kjBZ=pas=}C$jKg@@Uqg)i z{SeKE_c50QjdJ(}R8KJ@fiiIo$7PnSNY2vf3Dd(*=fS`feC3e5&3BR?vbHCjno#LwtHz0;YEEG zD}ev=UHgYdXu0AxB+5r>dwU>eXb)LU$tE2!n+{4434=mIGsA1#qk25mmMxZp)~JSw z&HK(#hxCZ5Fd!--5DCBHAhO3IX*5KJD}e<2s^W%pr4XrJY=h_!NKg?JQqc?4ER18X z#N+Jqc)StDDS}_HhfJ{T&_eVmP(b`r5Vf}FJR!}+=MrpLVLP;LhoY}mthIGjO|@l( zmn437^29BGLVVC$q$TKsJ3gzrADfs66rn9=RLPCt7tDHR2gHNN8RYCq1&!PWKHb9< zH^!Wd70ublEqWVaSaXDWT#h7#4e_39WLY9hfm~j{1$G}sjMNBakhe-fn@W(Vk|wyw zYiLJeqFBuAs1?Q~gNDNiuDAiR6_K0>I7e#cXkx5qv?baEapvjsr-z;9_AoGdUNc`) zrkPW7u_mI%R%6blAk*<0h739T2aPw@mvx{~@AtQJI*>xM>5e%&>u-P1c=IB}OdcSH zV+h<9eGqp}nzQkL#3zIyWKV)PQWH@VV{P}CvzMKHZNtK*rH#+KR@S|AO5PHAG5W%c z^C``9&#bPE$v>1Iw^f`$&sv&inhBBYS#jvx98(ffi?ZRT+&kxcT5`oYzR-`P&&*U) zQ8Um=i}_uC;U2QwiqyTs`9MFA1&#_o+~czW>QuS4cR0lPFo*~F3Az8Ox?t@cM#cD} z%O@lA7ToaWHQOHvi@!T!2*h~oMU`_Rp)P)VKDp%P^p!I%%t(B;^4Z9lZ_gxW=^*O* zU^F2!PEq6QiO9O>TDgmxK$Bc7O~wGFygxpth!i_-boL4hawyoZCUYa-BYPL%zCYjd z^=&iYzIPf$nR~=L_bSzqNpB~S(+Qo1fE7l)M|!LHJ~3(8$=5bSUy!%-W<*}}$!I`w zt7~66b$Kg4l#XSGha#t9k2-d%G@K!vbTm=9wK7lI6@g-eqxn!(5wR8`IZvUYTZn^J zp@l)YOmiu>yS2|fqPvfkMIez6lwe6q$(&|&5jt0R_3o1i4>Oo4RYG5QH;f9 z6-pTtBF|-pv0>cpc<5u_XwtJFgH1KsD zC~G5*78*~Qba3|b+Cg!(pc0=TzOh}gZnqG6${|No8RjWhu3{J}zSJGw)yM5=M8%33 zl6&;1-j#)z8k3&TrrV$vdq0t;VU-XC(2{8(sc{N4K+W+|N#UjDtBdzoyMn-QCOw99 zueIExskyt{X~Nx36ujY}_)XE(LSpvw;ugV_9AoJQ2@`Pk0JMyjBN}Ld>WZ3Cno#Cm zZS8~Ffe;lTlppQ>hwUC6)U@luZZ}_a@Bckz>r)Sc{H_#Y%-y!tHmFfRLJA~=DhQyJSjPHne7lP~r3Fixh2Opx5yE%!L(Iz-bUfw_ThUc5)kn|93I;eOe2cR+ee z|8J%Du1|WCmJ#|EE6~-7wI+hrrfIm{9ewU=7AUWpw!2qa`mhfs(vR{%jflMv+rr_+ zz$^St>i<2wsQ-P@Csmq|$huf-T+U40Fx?!DLL+w>pDq_8lPc93A`JyEfN@uJ-Hh58 zTgW%GUJ|-I(yh}TDMyP49Y0Kg*1R7tvJChY(?J$8?(Z3oliWwf0sAzNnyLS|KW2?Q=)m?h_Sv?JC7-jeB%xuQ{7O zi=&ei7K#$(he}x~0%^=99mFHW=cv}|vw}E~2Ux)N?mm%r$|E%HUmfYgGo{g?$e&gf z?n5e}g*a-B6NzLh9Cl+~kN2ZhOgI%^<_^CF9uLuj-dyS)T@93vKPv&nSj%xmDk_X% zhk=aD&Z02Fq@7w=T9|IRYc=UG?No#utWaNyW5;p34^uVr3oH(F?>g5jQu^I`sr+qs z*rt1NNm%~o?1}aNd)zn0*C85sb7Qz1`N>^&>~#wHE|I&D*;*@)c(%sO-zNR`8U!s=A3;|MF8eJ+%??Ku*_{M6 zdmQ3S_;(trfL}hRilk;65NF1Hi%^C47b+G3#!6cW%8-dFgih4w;IbQt0qQVSH9}ZX zK)&14)$I>nu6NV|1usAa1gqa6iDJX_DxhUvjoJNAvWL(3^H5BQin*atDXwYkaJt>D z0Uqu#^j$Hafy)j;qCuh`gW9SGRoc018Wq6%ZxA0o@GjB6!~ROVQ&{O>dt9Cb2d;05 z8TZZ(@HCf4RaAv|Q>)y^aS)Oiz;@?=tP&_^;0L&mMtC3Ua*Mo| zg>!%?t*GE%KCR&Pgc5=a#&hMtxePDLL%a}*ugQJMECq7`mKWp{|9zuE(8KQ05{?qA z|ElGM)uSt|1K8Zfa!<*0QC{*1hT+Zfkt_pq0hYI3jbIgXWc}Ez@?NRCI{@!i0BQ(- z=i09>PLH#S22pb_v1-nfrSrmB9pr~Y8&cD%yB#h787PzfmH2Cmrs~243;537k zpCTpLA-i|Gt|wTF4Qs2~rqfK@CqhFw`tF=pl1vz2Wdbhh;2xz{>S+xEy6bZr1~3VR zFm$PbWug%;Fhfda!L12E^#Ihq<(0P$%lm^SUJPSut(Q+?U9mt#rPbcV=dC8=Et`%E=+IuvT7c_9IdR;& z;m81264rzqxGL@Li?iAdpPeunYEC3rcN)Gs@{Zy1kvMCCq2@?})nr(EBG<6&L?Vpn zVBBt43uDEG1xJQ&DF4!Ti-_+KEm!t`(Q+X+N2sS!q>F4L8_6%oCh|-240(lYHlHHT zn`_An<~s7C*+sS-%#X{Tnirp2oy%M4Kv{(3UxW6G3&msqV~4_@PO!%rgmLsed|n|k zoU-fQrdyG&@^=ND4Dp*X0wmB#xmDF*B>19Bh|BIkm4+rqf{VYGNeJ}}!Xs|`r9Rx} zzLx0`3^Jezud(wqUZwr%|Me>Th71bh$8%H-27))Y$~g2bic6YN66taqGdxHUovTnc ziy^WF6X13&$`6J3tsQ$X*Bw^U*FERK({_By?w$E!#!r{4oI~D2vIzI`jIOmOPuy8{ z(r)102W0p*N3t47%=t)-*^1w(ear-Nwy$Nq-!j~9F;5JPHpKXHqEmkaiFxcI$ce3? zsMz)0W>J2m2%n@qQ$*)W3!{)Igfy(lq?u#h-V=owdJ6PD46A!2?1D$a8XpO}=>b@L zcgtP^FSK1n-(`x-2SuzM&OA-#Y?W&tk~Vh*(RplZn3wht*P6|={KJ0QSvXS^1-3OB z{j#6VXIrK|u=X>B7>geF{sISvUHC}Y)sKMPY5t|8@NJYR@JuWES$bnkD%Sxx^T%{c z3w^wWxG-nW6yS>H1CXw?XdI$VKIu;J^%lX2_`+$px8Xrp!y{oAJrXwc5wN3#Ut*Oq zLjj7nc6jCOqY9+m=#w@Z4yQ1$Le(R%Ek3F9i~@bPNu>YelY61GDGaz~TcS~M{osD! z_mWrcgCu;SK+I)Zu-qSp^~(JrSSL6QzU1hz`R-`bR5OZtH zm~!k5Ac6Z9Gal3KwHP1mlkZy$`;f)>V6nwK4EvzP_+YWcJP7-rSd7$aK`KKRf(QZ` zOKJ(nc)U^M>HBsLRV4Hdw)62g;!3x-7e%TN9<&(KLiu!!lE60VH`d`QqN702| znLh-JsecgGEAv5+(q^BR`s~Fg)4js~j}piGvMMI{24pU%IK8a{%#S#Oafdn}NByGb zkKP_{p0hrIVT1z>PvG0IDg)HOR%R?dGd5?71`gqyEe_EL&xhLira2q#xSIE$X=-9` zGcq125~>m*f11tF(k+JIcT(}}ZSbx;;e-@~D2QtCJ`S-zG9(|Qi09AI@NPhSgd$;Y zKHU2>^oB_?MEW(>82F&>1c|YDq^fYVvyd;Q<0aUNaq=IKDVa{8lix(?Mf|+$D82|z zn>4J@?csmz=g%)bpP*v)sO>t~8T@2SIA|XAsYD}^Ly(VCBr+7S!c`AXv{Dt&Qvf|t z(9`1KBU%ZGoPs#w2)x5iAor?T+VY7f#!(feR36_2Ux1NAPlqt>(XAe7(eDxs5phc2z}6+YJY8B z??O`@hwN~wGQ4h#foHBx(inL9YApW_HI#qh{3J<#%hPLdZvGr$u0r)}P8b5tmad+} zGfXV&cgq7hA>e!hIBODkq5&xAA_Cw&3Q3e3_-a5tzPbpB`rIS!Dnd@#w`%A0uL#K= zL^#{45nEbB#5knBI?t>^r+6I&d-<&DW4r5s&sx}5pH}l*>p+G*gpbD_SdpK%8hGp> z{Pg_utAWQJSe0M08hGp>LiGH6=!2G1epwx9$J&vCJRbh}>qDI6IgLsVyM6JdC)5y- z$G=_`d9ZL)6N|Nr+L5S}0-I5wv1#a3=0rUVjL0J}ur5(QApdxBRPzrpKWv5}^IvP%AGn+k5YddJ^I#^=^ z1#*NnI(*g$zx|prb)bGtL91U=<_^@aDQF!n+njVYY2kFeh;I(>ygND>Gf8H z0_7g_`8GK=^g~n9hsT`sVKw&G^Q3#Ytj+`;8M3F=rn*&6vNkv|E@Fs7g^7h>5~Zb( z^HM!o5tP>FzR}#b_d`7EFggC%fX-Pao57m)qsKV67rMmBRd>Rk{%~NFrq3SRE*vyt zYd1Mv)~8R#SOZRMw`8%KoUHY#XS*d{SbHqSipM|vON>=K=8H}TZop0zzMxn z1kLOCdnNdWLC2yRy~)5@X|OY>@#HMx-B(F}X09VbOIoFla1H?7>>+y>@;U88Sva-GTEyqk412pP0Cv_gJ}81>ZCyXHuig%l6zeJeYsJ(4 zis&-xaRnl665N2r39p@$It;MV68L3Ec(0N=toXf((n7rqvn2m8#42uivG9LaOu=Vg zaIb7rgz5V+3A!)@CmafZ>!*#sb?r$^8EPsASd=jgFVnatoY9Vo%3A z|A86q^lN?3oD}x^0lyp)bQ~)7bGOQGI_2lpn9_hMxK-(3WEwqdgYP5u`Jvj}`bk2= z2*@cTkh_feCih5X-gy04fTP~`!?P(x7^PPrx4(R*Tfxjsw2a^5q_3)ZxR<5nc>RCf zsmX^^V~x9r8O_f>rC^z4B+)vgn%0h-Q$B`MscsKzfG;@eA!=4R(5xb>N&zZ>q6GT{`g%t?14p6(`vWCchk9Cq=c z1i!2S>?{IKJ}a`@5#Q1PHuyM1r7jd_XKk=1aKyjR;_rmKq+%K&<2r3FHLP~Cea=B~ z=cnE{1U^ltNHk>aD>4Z4bXx4w#`$U-R(uyCI&pA~vuM^374mOcjeeu?)|WbdNsW0>o_M9tYH;B9=kriupmFt;{KcbcW#l1 zgZu;8tRCk#c@&&7RsoguIJe2CfaP|8EUMt#O9%AU!+WboCGSzgml<{zG*kuBfDCPA z$dNVhP5EfJ7ue*2sDBiyf{)dFc0FXb9*LtyYg;bA`9n z;31kgb1Mqf^Rfmwt8GP?QE>u9V1HVlym-)->pt(P!w)M-w zxLM|7LT5Zm7}&6JD9%AEtX(18UpOfPEz|A%u)_szz>L`%pq3S=edVE5|BCii&Q z#kV!8Oos52|En5efL!W;nh-o@yxwgIJsa{TIGL1V|G>TkKC-i&oCZ}X%UGiYT?E2b zDx^G)sFbG=rA8@S+JOxQ};dw!eq`p4HZs|j@uK0J4Z$B;_-*x=$_+7_$vm0-rxY_X% z_3RKNH2EXpG=+p__;R3@1Pb8y92B;Y;Uszw1u+b9iZpG7;w>%bcQUcU?*%RAU!<+@ zKbgo4c`LDE$X8l!DD)3~A(0C>r>zKp{y>j5(NPhYmWWT-xF8q}dQ4lB&!NsFTsQsQ zU2kw-ZXJpJ46^lB_Op+PIu`8ETiJqLVIM1ip8m=f?21+N`xsQVPFuJ7 zM8rXd)Ya&%CaQ7Oi8>0xB=)upXvC^MmYcPK$mpPH3H~dvU`Pg^=<4+}e3##@ zJ_wZ;!2jt6xi{1P|o`1 zU#$NTcoVGO(M)lE&P34&>x*u}QHM7)c$853D+1OomjAAj2i_)8Xa zk3-#f4WiiBB&T4tk|G>IZq|EgnP1&ci}QLrh3SzL)8G`g{SmY{+nXt`Z2a7b<#y^c zjYQ)BJ&&dZ%Nf%%K#QPz3dJQm71u!1K#NVGWic&V>EE&x$mRFWWGN6db^Q_*H+#G` zaX0IwHW0e)%xYac;ynRWtj+6lP`(jW&hy+ z(7MW-%WUmxdvZZOe@9`2dxVwP@*wIFVloT+5}%KSL$;xb0_Yj=v2cR*?n~et5BpeQ zx7t~F9qd%P4K@4Ykju(gg@VM@A--+8-G}>CiqV9VVKuy|jh4KtM8NDG*q!u%4@0{U zvckMn$P>7~6?P{Lusew$ehB9m!|fUwLGbf?AeTiDDn+Z>X@z}){A2i10`r5tjxS|k z&kT8?%8K}HOg#M}e1Js&9o71>-ppEu*Z;r|6I|Hm@M#zJzkp@ymz3AYIBhO7qKrybXe+W61mD_$ zwmZPHwRkt9QnaH)k$)cYF>ovDY1(PsuRa969O|icxTp7kFGF=k!TpWIoKL$^^w~gO zsLaEedAzXUvbL4(zWBKX?dlnNRMCHkYN6;~<)Q8bibtuBw$ z*yA}`=8K|L(V$;D)QMyX-jnUB>XW*06m3JHMSOM`J&>0r8g#q(us1hLbce@YgLAV) zw|a8V;@m9J4Ia}cI5*pMysXNbo8#wwS_IT{kLGD@dK3> zWC03lKyRgWKMPQ>bM{tRKtI*LbM{tR-D*`}Gq%u8zFp-n^8oHuF;3*PLVZD0%LdLk zBpbHRZjcV(6R>@TQTU`ovSItg=Kxg*+b4W`OIG#QT2+9>1-99uPOx{ErrkLAd8N*e zsf8~LU`KAFwI`0@cb6Ts0PmsNvq$3$kg=^mIc#+}+sBE;N5O}|c5zH`d3`wERjI@K z!`x)f)}AQpHvHB5@1Lq86nI|+|Gv!*Qv1_F3-Q+|t@}Cmq46myZ39)A;@TzI;Jape z6%ycXOqJRI_^T6ZKH8__FSQT*0H9ha38Hw`TLsCvIyxm%Ql++1;yQ1JhX~)d>+Y`2 z5L4GBPX1_LvitnU$H!}(jYcvqC2<$47zg#(Fu3n#kh2|fq~dzwiE3DXkrS_fy56_G z7Yg!+7pflCzn=KRM-TbtIYuiqhij?kaa!v1G_BBR&{BNJ%b|9n0$n0Fste9S z>LDsX_9a8%q=F`P8r(yB8Y>M{W2Sbmp@O0bx6Jo$)$TKJGI$@_-(@}C_Xh0|11I;6*W&S3?FmB#ejnBY??OX|mSeim_+z=r zqK-)EI?Q%6Fjsz&(5Kx9I`MF|jO$Ll$nRvffla*KZ2=FhjJLVqH|@NWZbS#Iw1P6+ z_J~YH5q$YE;^RIT`S^i4;tZpu&V*})PeD$ff}EP5rZ~MwE7YcHg>#u&>YNqi=m0q$ z&RYuGP>XAh9+0ISWGNCHu?fo&>~;ajaTDUG1*n4RA~+eyS_ZPFLC!SP zC%|!q{0QQhc2oiUV$Pv*ffxz&cf|@Zg?=B!SfPE?1^@4KNpM1O$Wkqy_~?)|#x~}! z-L@EE`iHo8yCp#Yxa$W2?$6&HwEn%i8+K?*j%h;RqZ2rHZIDOSh0EYyoyx|_M{SL+ zopDO;@`LXO6LR@7_;)3zg1+>@8Du`FI%?F`{_)*8XyA)M{6&i77>k(rLSGFjyEdPH?32yUy;6Itue!xzEKJNNlGz zUsM}%1N(AO?vWGMQT{KoMBzY1ub z4*K$nc;j#88F?Q(?(gS!)+XTB_^J`E?2TTnuE38LyX$`*awz+NWaUVkcpn(59_j4|+~lZU&pdW&t#9gvk?UtCSN{l@pV+GiPg` zo%g~V-P{-E>9o&Gp5*;g;*r^NbuT385*HYrnWR(>#-aKUj~emcf`;=f3fu2Y(;s9qZRG9(`!cr$_I^hsIW~ zSqEx*U<`DcZsaqRY2aBtD*H{;xGGjT&uCQ6)oGGu>0;Ne@=6{1+=_LpKAs)KZX6z+z}{SrbgLA;TZx;4Y)mdzAE-f4(0PXTAC>#CezvoGq@bB@qP4>Zzj0OEXf|f`1VS2*={>O Date: Wed, 10 Apr 2019 15:41:58 +0200 Subject: [PATCH 135/951] shorter coremark --- src/test/resources/bin/coremark_rv32i.bin | Bin 24376 -> 24368 bytes src/test/resources/bin/coremark_rv32ic.bin | Bin 17832 -> 17824 bytes src/test/resources/bin/coremark_rv32im.bin | Bin 22776 -> 22776 bytes src/test/resources/bin/coremark_rv32imc.bin | Bin 17080 -> 17080 bytes 4 files changed, 0 insertions(+), 0 deletions(-) diff --git a/src/test/resources/bin/coremark_rv32i.bin b/src/test/resources/bin/coremark_rv32i.bin index 62cb11107f99a845bd6f2ed2403ce44582dceb56..71e2911cae6050dafcdcbd344790d33169e28ef9 100755 GIT binary patch delta 635 zcmdn7k8#63Mg{RiCI(@~#xLTb3=G1ot!2}J^yF67GVwGZpRMiVLL87f6 zHhTCmGxAQJ&K%6hyZJS9I1`ZL%;s!)bpCsT36k4W85+!icyg=jLSfdU3*Q?ANI>|U zK(k#J1Nq|3>Ia#Hzl$>@bFi~9FXx@SpUqp3b16_pP?$x8p?Nv)Ct(p5M&S?^#>XjN z{ye8CLhTTrIy=gKl3xja$$z|^i1h}ADCwH?;10A%S-CMD9#e0JbOxTPx z7iR!jGg+9!p4V&DdxHZtFx~MS(o9D;Os?U0$H+Q4n^PG`_H)VuJ-VKAy$l=2Zeixb zJ2$7O8L@k^pAr^TWiV#_%FwLN%8=f`&age5p@Dg6`{(oq1}K~T3xa(dNxc0NLfn1x zecdK*`&G{&V(bDRn3uDE0hy(|0xAYJm;EzHta-WnXP})9VEwI(z-VLq4~(j;$qOvI z7`--YTkU3HI`w+<3p*($uI|&5J5Qb$<~;d&GmqmmMy8{8H!pEo#lq;m+27rsgXz?V z%@h2ixC9k+U7Y=cT;p9_okHDh4HOhM|Bu|tXxk9O(9i+I6M%RI5C;Hp3=n4kaS0GB x0I?1bTL7^O5PyhfX!rxf96+|n=8w_p%rY%NZVwPo0b)i51_mx51|}&m003um(c1t3 delta 643 zcmdn6k8#I7Mg{RiCI(?f#;@X`3=G1ot!2}J^yF67GVwGZpN;L)LdgoRN!goW{O%9lS7 z)#@&D479Pb!iCuegi1Id0)d7wwvbFPZ}au4eSit(-|6=m$H9JZ(xA3+mYDrNNo1c2sOty-`8#8 zwqN)B6IhI0-~;n=_Ael_l-EGTz~;7p28lH3~uU|?X_{5x_hqistJLqiV`PXXdNKpXlPDYy-p|K>Q_|p@9KN^8m5L=C{%6%nBVqp$R}d10)3mj6iGz#K5El1_0*z(IEf; diff --git a/src/test/resources/bin/coremark_rv32ic.bin b/src/test/resources/bin/coremark_rv32ic.bin index 762126df90455edb5319addbc770c450d5cd24d8..24975db5818995df4908043ac267ea759f685bba 100755 GIT binary patch delta 2023 zcmcIleN0nV6o0qv?HB7Pd18f7xr#spJBxw}5iHebBf81R3Kk4nj51J}n?Z0}YyqDP z3JG|}$fhQUVc0Ha(WnwE$`LQepx2c(R(sZ*?31JBO1C;J_k37BH2Q>%D>g|0ovTW zHnYMA>m{g**2eJ+`sWK!9$T)s*8DeCir-XWwHN}NErI1 z!syaD%ItKK0-e|ieW4fm=OS@$=?AT(r#y#PjAh{P!Ap*pgO3t?s$O!O8aTB`1~*A{ z7o^>_(ALKLMeIWZGjj+gbEKWb<*Z88@U%wTIY2Y;v-+|IU&Z2USUNhVa(VP{*)uCMRONDp-ja%2F`)rQyN^D zg{f8??w96*86QJ$%dx`oLqm^rf})v}_;$h>>qlyRd=k`?)#0<`{)XYWh!>*U#p2pYp8ga}E$S&?oVgq+BBeR5t%mmn9j?AL(^Sw7*WxS>6PZLPsS1$GTGT8LAyXL zGx=wX^Mu_JlbRw*TYW9vwj)cck0#pIz1L}wnw)n!=aii;%8Ey$bWPSY)Jp5JqD}T$ zDM4k=_ldTEqw`SCsoge7owIM=>AF{(ox;g1gN$BTcpR-1_GJGgV+k=WS-i4ZkeaxXxCgn6`w2h+cLTwHvKFubAbtJ;3%-zW delta 2008 zcmcIl4@?tR7=Q1s?~be1mYi5okwZ`d$Sev&h+x5;oqx8tIfSCHqMHg+#^RWNw%Ch! z0SYAIlaT$(n2M}SGu_FU&N+@q?kQO~x*N>y^!J{z7n&fP4HNt6pitX#BgZ5N7{ z2#O@Z)m`^n5oi@BUbDrPt~(Yqm$`6Hv;SkfmlohIVZoGN3JB31r>Mx(#*jk?W|=bI)al3Tjud?Qmv%8x2ca9fu=)x|1s@tvx{iiF(JC5gUm zit#qNmln{GCVXTw^o1YfkuJ4Wb%WN>Q&q(xks0uL^&xkR1s@)KDj#xc1aN{bom*wp z^%}dIp{-Rn3dP%YloWu;+-YBv6(Y~q+*@mIJxDW1+^{*rL9>#WYGCd%BEsC&BrR4L z0qnAV)}3$4Q-Z5+-n~)S-0)!lbnb6y5=o5h*tA_0)e}~jt@NKtvchm1#w88&MM96o zA@`YFl!c6j=OU4uC&tm0ar2_2W$)Q?TawQNEkbACfkozv&y zi!jyveci@fFyme5Z9Xx%zo=<9PEdDv7I$ujGqzn@*Qri|de4%9vsC|t?&hdkb3?F+ zzkKma!$GY8kMq>`PIP3s1wKNjOBC+BYuo^Hdd^`(vCmNaOnu20qsucY^zo7;i^BQ~ z{gQcU{Spvdo>*>NAdlA0zry2dG}3wiFVId}{VZI$YH<%fMdL>{L)@V z0anXE)-RW;JNk1~G&6mLql$zw;i`zMP_#%jKkQfwdQ=q&;sWuZIyFB&bgV7l)C`aETjwv9EJE4;3vSZ zfNg*_z;3|jfR_MOfVTj3v?Twe_fRTQO2gPcC?4Pjue-zfor82wL3}zBDO}org7>k7 z&p+{a{9}XDsSHgR32(QFQ6wxGkvGhkCQV`sW2mt*5A`F-cSZ+MP F>u=6Bel!38 diff --git a/src/test/resources/bin/coremark_rv32im.bin b/src/test/resources/bin/coremark_rv32im.bin index 23f9b10ae001f95a95333d993b392d4db2f67658..6b5b8850c2e3c0fc4f0c4403676b73b2bae2c363 100755 GIT binary patch delta 305 zcmXBPJxjw-6b9fNlbf5XlcbB2fg%M_2nelUQY0U3{QyOcRuH-=sL-L{Y7j%frQjJl z_$OMfrE9@S@dpSFF79z_!6F{piMV81a`J~Uj$b=ZQAL$OsD|wUs UsGwRks=K646bg`Oa{4zYzl;-G!vFvP delta 305 zcmeydk@3ey#tmg`s;)Ng4H_c1hcYyn1M%e6qqf4Vu6FMY93mimP6lDtqmyT|#WQwJ z{>@g*=s7u`y_k*D^}WFXr%CK0lmD>0F`k<2%%RTcIysx;K4a@-Z%$>#*3J2x{gSL5 z;lj+$o0*l3*%{k6n``~!W_RajnB2~;GTFw=iSf|pdb7zaj82<{t#31Oa%D_zamf*8 zaoPOcrk|0~V{^ORbQZ?ro8_ISvom^b-tP6CL)1V)*TvaC$Ti-@)hX27)<8jlfq`N3 z{@|^QwjN;&4FNzL0mKPFECIwSKx_cSHbDFW=({gK%m8Hb0PzkW`v?$U0OC8FH-@S+ X%lH79AwV1h#Ed|Ljes}}h(Q1VkZE3O diff --git a/src/test/resources/bin/coremark_rv32imc.bin b/src/test/resources/bin/coremark_rv32imc.bin index 543d14d4f57cdcecd07ada12b0e12742bd07196e..c09b83bebb6a6255886d537b32bc014ad806d0c7 100755 GIT binary patch delta 868 zcmdnd%DAJIaY6#4!Nf#YMu&~dzcMl^OrFa$mGQu2V`g(khsoK@JLMKc33GZzUF#O+ znzelC-tF!T4X4_kwFv|f*47j66&ymNT7gm=t6D*# z!mO;P-YYOn?q@OeUJ$SyC;}3l+}e6cnAP?2dxZplgxJw5K-D+iD=7FO#9D6x#cl!3 z^8x8Q2eRWf$UJ^ldq#%I{;d8$az3j!(6O&s9f8i*Ws~Ppun=Z_$ogL3L(b$dwick& zZ8mBC2HlzaK}Gtz%Fysnk1SkIP@|0wVS}$3LexkB9npowG1$aF4i?d?XK47O zi?ARCYFQkTr5AvPH|aApFwp|n0}ZtUT1Lq5eLzQm)W`r`orlFC*u+5U#enL+06hpZ cKMiVE0+eP2NjOcmb;{@AVqjoM17Z*W01iC~aR2}S delta 867 zcmdnd%DAJIaY6!Pz{EsX#)OT_zcMm9OrFa$mGQx3V`g*4gvr^=JLL{U33GZzUF#O+ znzelC-tF!T4X4_kwFNHVC{>dw?TsMEPs$vp0P*BiyarO^#jdyW%3U#*y@;BGo?q{lBrp?gc2F3G` z*f2355mmP afZCM=rCC7|E|YDY@_CFH7#Pxk7z6+&PTj`< From 6b225949614498eab9521620c980b891ce0420e0 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Wed, 10 Apr 2019 15:42:39 +0200 Subject: [PATCH 136/951] Flush MMU line with exception on context switching instead than on cmd fire --- src/main/scala/vexriscv/plugin/MmuPlugin.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/MmuPlugin.scala b/src/main/scala/vexriscv/plugin/MmuPlugin.scala index 9fce74ee..a243484b 100644 --- a/src/main/scala/vexriscv/plugin/MmuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/MmuPlugin.scala @@ -137,11 +137,11 @@ class MmuPlugin(ioRange : UInt => Bool, } port.bus.rsp.isIoAccess := ioRange(port.bus.rsp.physicalAddress) - // Avoid keeping any invalid line in the cache more than one memory translation. + // Avoid keeping any invalid line in the cache after an exception. // https://github.com/riscv/riscv-linux/blob/8fe28cb58bcb235034b64cbbb7550a8a43fd88be/arch/riscv/include/asm/pgtable.h#L276 - when(port.bus.cmd.isValid && port.bus.end) { + when(service(classOf[IContextSwitching]).isContextSwitching) { for (line <- cache) { - when(line.valid && line.exception) { + when(line.exception) { line.valid := False } } From caa37a8028e2b91c02205842ff3f0f70e74ecc5d Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Wed, 10 Apr 2019 19:04:52 +0200 Subject: [PATCH 137/951] Reduce machine mode emulator CSR requirements and emulate more CSR (in the case they aren't supporter in hardware) --- src/main/c/emulator/build/emulator.asm | 905 +++++++++++++------------ src/main/c/emulator/build/emulator.bin | Bin 2328 -> 2344 bytes src/main/c/emulator/build/emulator.hex | 252 +++---- src/main/c/emulator/src/main.c | 9 +- 4 files changed, 588 insertions(+), 578 deletions(-) diff --git a/src/main/c/emulator/build/emulator.asm b/src/main/c/emulator/build/emulator.asm index 88cbbf9f..38d2e999 100644 --- a/src/main/c/emulator/build/emulator.asm +++ b/src/main/c/emulator/build/emulator.asm @@ -6,13 +6,13 @@ Disassembly of section .init: 80000000 <_start>: 80000000: 00001117 auipc sp,0x1 -80000004: 11810113 addi sp,sp,280 # 80001118 <_sp> +80000004: 12810113 addi sp,sp,296 # 80001128 <_sp> 80000008: 00001517 auipc a0,0x1 -8000000c: 87050513 addi a0,a0,-1936 # 80000878 <__init_array_end> +8000000c: 87c50513 addi a0,a0,-1924 # 80000884 <__init_array_end> 80000010: 00001597 auipc a1,0x1 -80000014: 86858593 addi a1,a1,-1944 # 80000878 <__init_array_end> +80000014: 87458593 addi a1,a1,-1932 # 80000884 <__init_array_end> 80000018: 00001617 auipc a2,0x1 -8000001c: 90060613 addi a2,a2,-1792 # 80000918 <__bss_start> +8000001c: 91060613 addi a2,a2,-1776 # 80000928 <__bss_start> 80000020: 00c5fc63 bgeu a1,a2,80000038 <_start+0x38> 80000024: 00052283 lw t0,0(a0) 80000028: 0055a023 sw t0,0(a1) @@ -20,15 +20,15 @@ Disassembly of section .init: 80000030: 00458593 addi a1,a1,4 80000034: fec5e8e3 bltu a1,a2,80000024 <_start+0x24> 80000038: 00001517 auipc a0,0x1 -8000003c: 8e050513 addi a0,a0,-1824 # 80000918 <__bss_start> +8000003c: 8f050513 addi a0,a0,-1808 # 80000928 <__bss_start> 80000040: 00001597 auipc a1,0x1 -80000044: 8d858593 addi a1,a1,-1832 # 80000918 <__bss_start> +80000044: 8e858593 addi a1,a1,-1816 # 80000928 <__bss_start> 80000048: 00b57863 bgeu a0,a1,80000058 <_start+0x58> 8000004c: 00052023 sw zero,0(a0) 80000050: 00450513 addi a0,a0,4 80000054: feb56ce3 bltu a0,a1,8000004c <_start+0x4c> -80000058: 778000ef jal ra,800007d0 <__libc_init_array> -8000005c: 17c000ef jal ra,800001d8 +80000058: 784000ef jal ra,800007dc <__libc_init_array> +8000005c: 178000ef jal ra,800001d4 80000060: 00000097 auipc ra,0x0 80000064: 01408093 addi ra,ra,20 # 80000074 80000068: 00000513 li a0,0 @@ -73,7 +73,7 @@ Disassembly of section .init: 800000ec: 07d12a23 sw t4,116(sp) 800000f0: 07e12c23 sw t5,120(sp) 800000f4: 07f12e23 sw t6,124(sp) -800000f8: 2c4000ef jal ra,800003bc +800000f8: 2bc000ef jal ra,800003b4 800000fc: 00412083 lw ra,4(sp) 80000100: 00c12183 lw gp,12(sp) 80000104: 01012203 lw tp,16(sp) @@ -117,7 +117,7 @@ Disassembly of section .text: 8000018c: 00054503 lbu a0,0(a0) 80000190: 00050a63 beqz a0,800001a4 80000194: 00140413 addi s0,s0,1 -80000198: 5fc000ef jal ra,80000794 +80000198: 608000ef jal ra,800007a0 8000019c: 00044503 lbu a0,0(s0) 800001a0: fe051ae3 bnez a0,80000194 800001a4: 00c12083 lw ra,12(sp) @@ -130,464 +130,467 @@ Disassembly of section .text: 800001b8: fff00713 li a4,-1 800001bc: 00000297 auipc t0,0x0 800001c0: 01428293 addi t0,t0,20 # 800001d0 -800001c4: 305292f3 csrrw t0,mtvec,t0 +800001c4: 30529073 csrw mtvec,t0 800001c8: 3b071073 csrw pmpaddr0,a4 800001cc: 3a079073 csrw pmpcfg0,a5 -800001d0: 30529073 csrw mtvec,t0 -800001d4: 00008067 ret +800001d0: 00008067 ret -800001d8 : -800001d8: ff010113 addi sp,sp,-16 -800001dc: 00112623 sw ra,12(sp) -800001e0: 00812423 sw s0,8(sp) -800001e4: 01f00793 li a5,31 -800001e8: fff00713 li a4,-1 -800001ec: 00000297 auipc t0,0x0 -800001f0: 01428293 addi t0,t0,20 # 80000200 -800001f4: 305292f3 csrrw t0,mtvec,t0 -800001f8: 3b071073 csrw pmpaddr0,a4 -800001fc: 3a079073 csrw pmpcfg0,a5 -80000200: 30529073 csrw mtvec,t0 -80000204: 80001437 lui s0,0x80001 -80000208: 5c4000ef jal ra,800007cc -8000020c: 8ec40413 addi s0,s0,-1812 # 800008ec <_sp+0xfffff7d4> -80000210: 02a00513 li a0,42 -80000214: 00140413 addi s0,s0,1 -80000218: 57c000ef jal ra,80000794 -8000021c: 00044503 lbu a0,0(s0) -80000220: fe051ae3 bnez a0,80000214 -80000224: 800007b7 lui a5,0x80000 -80000228: 07c78793 addi a5,a5,124 # 8000007c <_sp+0xffffef64> -8000022c: 30579073 csrw mtvec,a5 -80000230: 800017b7 lui a5,0x80001 -80000234: 09878793 addi a5,a5,152 # 80001098 <_sp+0xffffff80> -80000238: 34079073 csrw mscratch,a5 -8000023c: 000017b7 lui a5,0x1 -80000240: 88078793 addi a5,a5,-1920 # 880 <__stack_size+0x80> -80000244: 30079073 csrw mstatus,a5 -80000248: 30405073 csrwi mie,0 -8000024c: c00007b7 lui a5,0xc0000 -80000250: 34179073 csrw mepc,a5 -80000254: 0000b7b7 lui a5,0xb -80000258: 10078793 addi a5,a5,256 # b100 <__stack_size+0xa900> -8000025c: 30279073 csrw medeleg,a5 -80000260: 22200793 li a5,546 -80000264: 30379073 csrw mideleg,a5 -80000268: 14305073 csrwi stval,0 -8000026c: 80001437 lui s0,0x80001 -80000270: 90440413 addi s0,s0,-1788 # 80000904 <_sp+0xfffff7ec> -80000274: 02a00513 li a0,42 -80000278: 00140413 addi s0,s0,1 -8000027c: 518000ef jal ra,80000794 -80000280: 00044503 lbu a0,0(s0) -80000284: fe051ae3 bnez a0,80000278 -80000288: 00c12083 lw ra,12(sp) -8000028c: 00812403 lw s0,8(sp) -80000290: 01010113 addi sp,sp,16 -80000294: 00008067 ret +800001d4 : +800001d4: ff010113 addi sp,sp,-16 +800001d8: 00112623 sw ra,12(sp) +800001dc: 00812423 sw s0,8(sp) +800001e0: 01f00793 li a5,31 +800001e4: fff00713 li a4,-1 +800001e8: 00000297 auipc t0,0x0 +800001ec: 01428293 addi t0,t0,20 # 800001fc +800001f0: 30529073 csrw mtvec,t0 +800001f4: 3b071073 csrw pmpaddr0,a4 +800001f8: 3a079073 csrw pmpcfg0,a5 +800001fc: 80001437 lui s0,0x80001 +80000200: 5d8000ef jal ra,800007d8 +80000204: 8f840413 addi s0,s0,-1800 # 800008f8 <_sp+0xfffff7d0> +80000208: 02a00513 li a0,42 +8000020c: 00140413 addi s0,s0,1 +80000210: 590000ef jal ra,800007a0 +80000214: 00044503 lbu a0,0(s0) +80000218: fe051ae3 bnez a0,8000020c +8000021c: 800007b7 lui a5,0x80000 +80000220: 07c78793 addi a5,a5,124 # 8000007c <_sp+0xffffef54> +80000224: 30579073 csrw mtvec,a5 +80000228: 800017b7 lui a5,0x80001 +8000022c: 0a878793 addi a5,a5,168 # 800010a8 <_sp+0xffffff80> +80000230: 34079073 csrw mscratch,a5 +80000234: 000017b7 lui a5,0x1 +80000238: 88078793 addi a5,a5,-1920 # 880 <__stack_size+0x80> +8000023c: 30079073 csrw mstatus,a5 +80000240: 30405073 csrwi mie,0 +80000244: c00007b7 lui a5,0xc0000 +80000248: 34179073 csrw mepc,a5 +8000024c: 0000b7b7 lui a5,0xb +80000250: 10078793 addi a5,a5,256 # b100 <__stack_size+0xa900> +80000254: 30279073 csrw medeleg,a5 +80000258: 22200793 li a5,546 +8000025c: 30379073 csrw mideleg,a5 +80000260: 14305073 csrwi stval,0 +80000264: 80001437 lui s0,0x80001 +80000268: 91040413 addi s0,s0,-1776 # 80000910 <_sp+0xfffff7e8> +8000026c: 02a00513 li a0,42 +80000270: 00140413 addi s0,s0,1 +80000274: 52c000ef jal ra,800007a0 +80000278: 00044503 lbu a0,0(s0) +8000027c: fe051ae3 bnez a0,80000270 +80000280: 00c12083 lw ra,12(sp) +80000284: 00812403 lw s0,8(sp) +80000288: 01010113 addi sp,sp,16 +8000028c: 00008067 ret -80000298 : -80000298: 800017b7 lui a5,0x80001 -8000029c: 09878793 addi a5,a5,152 # 80001098 <_sp+0xffffff80> -800002a0: 00251513 slli a0,a0,0x2 -800002a4: 00f50533 add a0,a0,a5 -800002a8: 00052503 lw a0,0(a0) -800002ac: 00008067 ret +80000290 : +80000290: 800017b7 lui a5,0x80001 +80000294: 0a878793 addi a5,a5,168 # 800010a8 <_sp+0xffffff80> +80000298: 00251513 slli a0,a0,0x2 +8000029c: 00f50533 add a0,a0,a5 +800002a0: 00052503 lw a0,0(a0) +800002a4: 00008067 ret -800002b0 : -800002b0: 800017b7 lui a5,0x80001 -800002b4: 00251513 slli a0,a0,0x2 -800002b8: 09878793 addi a5,a5,152 # 80001098 <_sp+0xffffff80> -800002bc: 00f50533 add a0,a0,a5 -800002c0: 00b52023 sw a1,0(a0) -800002c4: 00008067 ret +800002a8 : +800002a8: 800017b7 lui a5,0x80001 +800002ac: 00251513 slli a0,a0,0x2 +800002b0: 0a878793 addi a5,a5,168 # 800010a8 <_sp+0xffffff80> +800002b4: 00f50533 add a0,a0,a5 +800002b8: 00b52023 sw a1,0(a0) +800002bc: 00008067 ret -800002c8 : -800002c8: ff010113 addi sp,sp,-16 -800002cc: 00112623 sw ra,12(sp) -800002d0: 4bc000ef jal ra,8000078c -800002d4: 343027f3 csrr a5,mtval -800002d8: 14379073 csrw stval,a5 -800002dc: 341027f3 csrr a5,mepc -800002e0: 14179073 csrw sepc,a5 -800002e4: 342027f3 csrr a5,mcause -800002e8: 14279073 csrw scause,a5 -800002ec: 105027f3 csrr a5,stvec -800002f0: 34179073 csrw mepc,a5 -800002f4: 00c12083 lw ra,12(sp) -800002f8: 01010113 addi sp,sp,16 -800002fc: 00008067 ret +800002c0 : +800002c0: ff010113 addi sp,sp,-16 +800002c4: 00112623 sw ra,12(sp) +800002c8: 4d0000ef jal ra,80000798 +800002cc: 343027f3 csrr a5,mtval +800002d0: 14379073 csrw stval,a5 +800002d4: 341027f3 csrr a5,mepc +800002d8: 14179073 csrw sepc,a5 +800002dc: 342027f3 csrr a5,mcause +800002e0: 14279073 csrw scause,a5 +800002e4: 105027f3 csrr a5,stvec +800002e8: 34179073 csrw mepc,a5 +800002ec: 00c12083 lw ra,12(sp) +800002f0: 01010113 addi sp,sp,16 +800002f4: 00008067 ret -80000300 : -80000300: 800007b7 lui a5,0x80000 -80000304: 07c78793 addi a5,a5,124 # 8000007c <_sp+0xffffef64> -80000308: 30579073 csrw mtvec,a5 -8000030c: 343027f3 csrr a5,mtval -80000310: 14379073 csrw stval,a5 -80000314: 342027f3 csrr a5,mcause -80000318: 14279073 csrw scause,a5 -8000031c: 14151073 csrw sepc,a0 -80000320: 105027f3 csrr a5,stvec -80000324: 34179073 csrw mepc,a5 -80000328: 10000793 li a5,256 -8000032c: 1007b073 csrc sstatus,a5 -80000330: 0035d593 srli a1,a1,0x3 -80000334: 1005f593 andi a1,a1,256 -80000338: 1005a073 csrs sstatus,a1 -8000033c: 000027b7 lui a5,0x2 -80000340: 80078793 addi a5,a5,-2048 # 1800 <__stack_size+0x1000> -80000344: 3007b073 csrc mstatus,a5 -80000348: 000017b7 lui a5,0x1 -8000034c: 88078793 addi a5,a5,-1920 # 880 <__stack_size+0x80> -80000350: 3007a073 csrs mstatus,a5 -80000354: 00008067 ret +800002f8 : +800002f8: 800007b7 lui a5,0x80000 +800002fc: 07c78793 addi a5,a5,124 # 8000007c <_sp+0xffffef54> +80000300: 30579073 csrw mtvec,a5 +80000304: 343027f3 csrr a5,mtval +80000308: 14379073 csrw stval,a5 +8000030c: 342027f3 csrr a5,mcause +80000310: 14279073 csrw scause,a5 +80000314: 14151073 csrw sepc,a0 +80000318: 105027f3 csrr a5,stvec +8000031c: 34179073 csrw mepc,a5 +80000320: 10000793 li a5,256 +80000324: 1007b073 csrc sstatus,a5 +80000328: 0035d593 srli a1,a1,0x3 +8000032c: 1005f593 andi a1,a1,256 +80000330: 1005a073 csrs sstatus,a1 +80000334: 000027b7 lui a5,0x2 +80000338: 80078793 addi a5,a5,-2048 # 1800 <__stack_size+0x1000> +8000033c: 3007b073 csrc mstatus,a5 +80000340: 000017b7 lui a5,0x1 +80000344: 88078793 addi a5,a5,-1920 # 880 <__stack_size+0x80> +80000348: 3007a073 csrs mstatus,a5 +8000034c: 00008067 ret -80000358 : -80000358: 00020737 lui a4,0x20 -8000035c: 30072073 csrs mstatus,a4 -80000360: 00000717 auipc a4,0x0 -80000364: 01870713 addi a4,a4,24 # 80000378 -80000368: 30571073 csrw mtvec,a4 -8000036c: 00100693 li a3,1 -80000370: 00052783 lw a5,0(a0) -80000374: 00000693 li a3,0 -80000378: 00020737 lui a4,0x20 -8000037c: 30073073 csrc mstatus,a4 -80000380: 00068513 mv a0,a3 -80000384: 00f5a023 sw a5,0(a1) # c3000000 <_sp+0x42ffeee8> -80000388: 00008067 ret +80000350 : +80000350: 00020737 lui a4,0x20 +80000354: 30072073 csrs mstatus,a4 +80000358: 00000717 auipc a4,0x0 +8000035c: 01870713 addi a4,a4,24 # 80000370 +80000360: 30571073 csrw mtvec,a4 +80000364: 00100693 li a3,1 +80000368: 00052783 lw a5,0(a0) +8000036c: 00000693 li a3,0 +80000370: 00020737 lui a4,0x20 +80000374: 30073073 csrc mstatus,a4 +80000378: 00068513 mv a0,a3 +8000037c: 00f5a023 sw a5,0(a1) # c3000000 <_sp+0x42ffeed8> +80000380: 00008067 ret -8000038c : -8000038c: 00020737 lui a4,0x20 -80000390: 30072073 csrs mstatus,a4 -80000394: 00000717 auipc a4,0x0 -80000398: 01870713 addi a4,a4,24 # 800003ac -8000039c: 30571073 csrw mtvec,a4 -800003a0: 00100793 li a5,1 -800003a4: 00b52023 sw a1,0(a0) -800003a8: 00000793 li a5,0 -800003ac: 00020737 lui a4,0x20 -800003b0: 30073073 csrc mstatus,a4 -800003b4: 00078513 mv a0,a5 -800003b8: 00008067 ret +80000384 : +80000384: 00020737 lui a4,0x20 +80000388: 30072073 csrs mstatus,a4 +8000038c: 00000717 auipc a4,0x0 +80000390: 01870713 addi a4,a4,24 # 800003a4 +80000394: 30571073 csrw mtvec,a4 +80000398: 00100793 li a5,1 +8000039c: 00b52023 sw a1,0(a0) +800003a0: 00000793 li a5,0 +800003a4: 00020737 lui a4,0x20 +800003a8: 30073073 csrc mstatus,a4 +800003ac: 00078513 mv a0,a5 +800003b0: 00008067 ret -800003bc : -800003bc: fe010113 addi sp,sp,-32 -800003c0: 00112e23 sw ra,28(sp) -800003c4: 00812c23 sw s0,24(sp) -800003c8: 00912a23 sw s1,20(sp) -800003cc: 01212823 sw s2,16(sp) -800003d0: 01312623 sw s3,12(sp) -800003d4: 342027f3 csrr a5,mcause -800003d8: 0807cc63 bltz a5,80000470 -800003dc: 00200713 li a4,2 -800003e0: 0ce78463 beq a5,a4,800004a8 -800003e4: 00900693 li a3,9 -800003e8: 04d79463 bne a5,a3,80000430 -800003ec: 80001437 lui s0,0x80001 -800003f0: 11840413 addi s0,s0,280 # 80001118 <_sp+0x0> -800003f4: fc442783 lw a5,-60(s0) -800003f8: 00100693 li a3,1 -800003fc: fa842503 lw a0,-88(s0) -80000400: 2ed78663 beq a5,a3,800006ec -80000404: 2ae78463 beq a5,a4,800006ac -80000408: 2a078e63 beqz a5,800006c4 -8000040c: 01812403 lw s0,24(sp) -80000410: 01c12083 lw ra,28(sp) -80000414: 01412483 lw s1,20(sp) -80000418: 01012903 lw s2,16(sp) -8000041c: 00c12983 lw s3,12(sp) -80000420: 02010113 addi sp,sp,32 -80000424: 3680006f j 8000078c -80000428: 00777713 andi a4,a4,7 -8000042c: 14f70063 beq a4,a5,8000056c -80000430: 35c000ef jal ra,8000078c -80000434: 343027f3 csrr a5,mtval -80000438: 14379073 csrw stval,a5 -8000043c: 341027f3 csrr a5,mepc -80000440: 14179073 csrw sepc,a5 -80000444: 342027f3 csrr a5,mcause -80000448: 14279073 csrw scause,a5 -8000044c: 105027f3 csrr a5,stvec -80000450: 34179073 csrw mepc,a5 -80000454: 01c12083 lw ra,28(sp) -80000458: 01812403 lw s0,24(sp) -8000045c: 01412483 lw s1,20(sp) -80000460: 01012903 lw s2,16(sp) -80000464: 00c12983 lw s3,12(sp) -80000468: 02010113 addi sp,sp,32 -8000046c: 00008067 ret -80000470: 0ff7f793 andi a5,a5,255 -80000474: 00700713 li a4,7 -80000478: fae79ce3 bne a5,a4,80000430 -8000047c: 02000793 li a5,32 -80000480: 1447a073 csrs sip,a5 -80000484: 08000793 li a5,128 -80000488: 3047b073 csrc mie,a5 -8000048c: 01c12083 lw ra,28(sp) -80000490: 01812403 lw s0,24(sp) -80000494: 01412483 lw s1,20(sp) -80000498: 01012903 lw s2,16(sp) -8000049c: 00c12983 lw s3,12(sp) -800004a0: 02010113 addi sp,sp,32 -800004a4: 00008067 ret -800004a8: 341024f3 csrr s1,mepc -800004ac: 300025f3 csrr a1,mstatus -800004b0: 34302473 csrr s0,mtval -800004b4: 02f00613 li a2,47 -800004b8: 07f47693 andi a3,s0,127 -800004bc: 00c45713 srli a4,s0,0xc -800004c0: f6c684e3 beq a3,a2,80000428 -800004c4: 07300613 li a2,115 -800004c8: f6c694e3 bne a3,a2,80000430 -800004cc: 00377713 andi a4,a4,3 -800004d0: 12f70063 beq a4,a5,800005f0 -800004d4: 00300793 li a5,3 -800004d8: 10f70c63 beq a4,a5,800005f0 -800004dc: 00100993 li s3,1 -800004e0: 03370463 beq a4,s3,80000508 -800004e4: 2a8000ef jal ra,8000078c -800004e8: 343027f3 csrr a5,mtval -800004ec: 14379073 csrw stval,a5 -800004f0: 341027f3 csrr a5,mepc -800004f4: 14179073 csrw sepc,a5 -800004f8: 342027f3 csrr a5,mcause -800004fc: 14279073 csrw scause,a5 -80000500: 105027f3 csrr a5,stvec -80000504: 34179073 csrw mepc,a5 -80000508: 000017b7 lui a5,0x1 -8000050c: 01445713 srli a4,s0,0x14 -80000510: c0178693 addi a3,a5,-1023 # c01 <__stack_size+0x401> -80000514: 0ed70663 beq a4,a3,80000600 -80000518: c8178793 addi a5,a5,-895 -8000051c: 0cf70463 beq a4,a5,800005e4 -80000520: 26c000ef jal ra,8000078c -80000524: 343027f3 csrr a5,mtval -80000528: 14379073 csrw stval,a5 -8000052c: 341027f3 csrr a5,mepc -80000530: 14179073 csrw sepc,a5 -80000534: 342027f3 csrr a5,mcause -80000538: 14279073 csrw scause,a5 -8000053c: 105027f3 csrr a5,stvec -80000540: 34179073 csrw mepc,a5 -80000544: 1c099063 bnez s3,80000704 -80000548: 00545413 srli s0,s0,0x5 -8000054c: 800017b7 lui a5,0x80001 -80000550: 09878793 addi a5,a5,152 # 80001098 <_sp+0xffffff80> -80000554: 07c47413 andi s0,s0,124 -80000558: 00f40433 add s0,s0,a5 -8000055c: 01242023 sw s2,0(s0) -80000560: 00448493 addi s1,s1,4 -80000564: 34149073 csrw mepc,s1 -80000568: eedff06f j 80000454 -8000056c: 00d45713 srli a4,s0,0xd -80000570: 01245793 srli a5,s0,0x12 -80000574: 800016b7 lui a3,0x80001 -80000578: 09868693 addi a3,a3,152 # 80001098 <_sp+0xffffff80> -8000057c: 07c77713 andi a4,a4,124 -80000580: 07c7f793 andi a5,a5,124 -80000584: 00d70733 add a4,a4,a3 -80000588: 00d787b3 add a5,a5,a3 -8000058c: 00072703 lw a4,0(a4) # 20000 <__stack_size+0x1f800> -80000590: 0007a603 lw a2,0(a5) -80000594: 00020537 lui a0,0x20 -80000598: 30052073 csrs mstatus,a0 -8000059c: 00000517 auipc a0,0x0 -800005a0: 01850513 addi a0,a0,24 # 800005b4 -800005a4: 30551073 csrw mtvec,a0 -800005a8: 00100793 li a5,1 -800005ac: 00072803 lw a6,0(a4) -800005b0: 00000793 li a5,0 -800005b4: 00020537 lui a0,0x20 -800005b8: 30053073 csrc mstatus,a0 -800005bc: 16079863 bnez a5,8000072c -800005c0: 01b45793 srli a5,s0,0x1b -800005c4: 01c00513 li a0,28 -800005c8: e6f564e3 bltu a0,a5,80000430 -800005cc: 80001537 lui a0,0x80001 -800005d0: 00279793 slli a5,a5,0x2 -800005d4: 87850513 addi a0,a0,-1928 # 80000878 <_sp+0xfffff760> -800005d8: 00a787b3 add a5,a5,a0 -800005dc: 0007a783 lw a5,0(a5) -800005e0: 00078067 jr a5 -800005e4: 1c8000ef jal ra,800007ac -800005e8: 00050913 mv s2,a0 -800005ec: f59ff06f j 80000544 -800005f0: 00f45993 srli s3,s0,0xf -800005f4: 01f9f993 andi s3,s3,31 -800005f8: 013039b3 snez s3,s3 -800005fc: f0dff06f j 80000508 -80000600: 1a4000ef jal ra,800007a4 -80000604: 00050913 mv s2,a0 -80000608: f3dff06f j 80000544 -8000060c: 01067463 bgeu a2,a6,80000614 -80000610: 00080613 mv a2,a6 -80000614: 00020537 lui a0,0x20 -80000618: 30052073 csrs mstatus,a0 -8000061c: 00000517 auipc a0,0x0 -80000620: 01850513 addi a0,a0,24 # 80000634 -80000624: 30551073 csrw mtvec,a0 -80000628: 00100793 li a5,1 -8000062c: 00c72023 sw a2,0(a4) -80000630: 00000793 li a5,0 -80000634: 00020537 lui a0,0x20 -80000638: 30053073 csrc mstatus,a0 -8000063c: 80000737 lui a4,0x80000 -80000640: 07c70713 addi a4,a4,124 # 8000007c <_sp+0xffffef64> -80000644: 14079063 bnez a5,80000784 -80000648: 00545793 srli a5,s0,0x5 -8000064c: 07c7f793 andi a5,a5,124 -80000650: 00d786b3 add a3,a5,a3 -80000654: 0106a023 sw a6,0(a3) -80000658: 00448493 addi s1,s1,4 -8000065c: 34149073 csrw mepc,s1 -80000660: 30571073 csrw mtvec,a4 -80000664: df1ff06f j 80000454 -80000668: 01064633 xor a2,a2,a6 -8000066c: fa9ff06f j 80000614 -80000670: 01060633 add a2,a2,a6 -80000674: fa1ff06f j 80000614 -80000678: 01067633 and a2,a2,a6 -8000067c: f99ff06f j 80000614 -80000680: 01066633 or a2,a2,a6 -80000684: f91ff06f j 80000614 -80000688: f8c876e3 bgeu a6,a2,80000614 +800003b4 : +800003b4: fe010113 addi sp,sp,-32 +800003b8: 00112e23 sw ra,28(sp) +800003bc: 00812c23 sw s0,24(sp) +800003c0: 00912a23 sw s1,20(sp) +800003c4: 01212823 sw s2,16(sp) +800003c8: 01312623 sw s3,12(sp) +800003cc: 342027f3 csrr a5,mcause +800003d0: 0807cc63 bltz a5,80000468 +800003d4: 00200713 li a4,2 +800003d8: 0ce78463 beq a5,a4,800004a0 +800003dc: 00900693 li a3,9 +800003e0: 04d79463 bne a5,a3,80000428 +800003e4: 80001437 lui s0,0x80001 +800003e8: 12840413 addi s0,s0,296 # 80001128 <_sp+0x0> +800003ec: fc442783 lw a5,-60(s0) +800003f0: 00100693 li a3,1 +800003f4: fa842503 lw a0,-88(s0) +800003f8: 2ed78463 beq a5,a3,800006e0 +800003fc: 2ee78e63 beq a5,a4,800006f8 +80000400: 2a078c63 beqz a5,800006b8 +80000404: 01812403 lw s0,24(sp) +80000408: 01c12083 lw ra,28(sp) +8000040c: 01412483 lw s1,20(sp) +80000410: 01012903 lw s2,16(sp) +80000414: 00c12983 lw s3,12(sp) +80000418: 02010113 addi sp,sp,32 +8000041c: 37c0006f j 80000798 +80000420: 00777713 andi a4,a4,7 +80000424: 12f70c63 beq a4,a5,8000055c +80000428: 370000ef jal ra,80000798 +8000042c: 343027f3 csrr a5,mtval +80000430: 14379073 csrw stval,a5 +80000434: 341027f3 csrr a5,mepc +80000438: 14179073 csrw sepc,a5 +8000043c: 342027f3 csrr a5,mcause +80000440: 14279073 csrw scause,a5 +80000444: 105027f3 csrr a5,stvec +80000448: 34179073 csrw mepc,a5 +8000044c: 01c12083 lw ra,28(sp) +80000450: 01812403 lw s0,24(sp) +80000454: 01412483 lw s1,20(sp) +80000458: 01012903 lw s2,16(sp) +8000045c: 00c12983 lw s3,12(sp) +80000460: 02010113 addi sp,sp,32 +80000464: 00008067 ret +80000468: 0ff7f793 andi a5,a5,255 +8000046c: 00700713 li a4,7 +80000470: fae79ce3 bne a5,a4,80000428 +80000474: 02000793 li a5,32 +80000478: 1447a073 csrs sip,a5 +8000047c: 08000793 li a5,128 +80000480: 3047b073 csrc mie,a5 +80000484: 01c12083 lw ra,28(sp) +80000488: 01812403 lw s0,24(sp) +8000048c: 01412483 lw s1,20(sp) +80000490: 01012903 lw s2,16(sp) +80000494: 00c12983 lw s3,12(sp) +80000498: 02010113 addi sp,sp,32 +8000049c: 00008067 ret +800004a0: 341024f3 csrr s1,mepc +800004a4: 300025f3 csrr a1,mstatus +800004a8: 34302473 csrr s0,mtval +800004ac: 02f00613 li a2,47 +800004b0: 07f47693 andi a3,s0,127 +800004b4: 00c45713 srli a4,s0,0xc +800004b8: f6c684e3 beq a3,a2,80000420 +800004bc: 07300613 li a2,115 +800004c0: f6c694e3 bne a3,a2,80000428 +800004c4: 00377713 andi a4,a4,3 +800004c8: 10f70c63 beq a4,a5,800005e0 +800004cc: 00300793 li a5,3 +800004d0: 10f70863 beq a4,a5,800005e0 +800004d4: 00100993 li s3,1 +800004d8: 03370463 beq a4,s3,80000500 +800004dc: 2bc000ef jal ra,80000798 +800004e0: 343027f3 csrr a5,mtval +800004e4: 14379073 csrw stval,a5 +800004e8: 341027f3 csrr a5,mepc +800004ec: 14179073 csrw sepc,a5 +800004f0: 342027f3 csrr a5,mcause +800004f4: 14279073 csrw scause,a5 +800004f8: 105027f3 csrr a5,stvec +800004fc: 34179073 csrw mepc,a5 +80000500: 00001737 lui a4,0x1 +80000504: 01445793 srli a5,s0,0x14 +80000508: c0070693 addi a3,a4,-1024 # c00 <__stack_size+0x400> +8000050c: 0ed7e263 bltu a5,a3,800005f0 +80000510: c0270713 addi a4,a4,-1022 +80000514: 0cf77063 bgeu a4,a5,800005d4 +80000518: fffff737 lui a4,0xfffff +8000051c: 38070713 addi a4,a4,896 # fffff380 <_sp+0x7fffe258> +80000520: 00e787b3 add a5,a5,a4 +80000524: 00200713 li a4,2 +80000528: 0cf76463 bltu a4,a5,800005f0 +8000052c: 28c000ef jal ra,800007b8 +80000530: 00050913 mv s2,a0 +80000534: 1c099e63 bnez s3,80000710 +80000538: 00545413 srli s0,s0,0x5 +8000053c: 800017b7 lui a5,0x80001 +80000540: 0a878793 addi a5,a5,168 # 800010a8 <_sp+0xffffff80> +80000544: 07c47413 andi s0,s0,124 +80000548: 00f40433 add s0,s0,a5 +8000054c: 01242023 sw s2,0(s0) +80000550: 00448493 addi s1,s1,4 +80000554: 34149073 csrw mepc,s1 +80000558: ef5ff06f j 8000044c +8000055c: 00d45713 srli a4,s0,0xd +80000560: 01245793 srli a5,s0,0x12 +80000564: 800016b7 lui a3,0x80001 +80000568: 0a868693 addi a3,a3,168 # 800010a8 <_sp+0xffffff80> +8000056c: 07c77713 andi a4,a4,124 +80000570: 07c7f793 andi a5,a5,124 +80000574: 00d70733 add a4,a4,a3 +80000578: 00d787b3 add a5,a5,a3 +8000057c: 00072703 lw a4,0(a4) +80000580: 0007a603 lw a2,0(a5) +80000584: 00020537 lui a0,0x20 +80000588: 30052073 csrs mstatus,a0 +8000058c: 00000517 auipc a0,0x0 +80000590: 01850513 addi a0,a0,24 # 800005a4 +80000594: 30551073 csrw mtvec,a0 +80000598: 00100793 li a5,1 +8000059c: 00072803 lw a6,0(a4) +800005a0: 00000793 li a5,0 +800005a4: 00020537 lui a0,0x20 +800005a8: 30053073 csrc mstatus,a0 +800005ac: 18079663 bnez a5,80000738 +800005b0: 01b45793 srli a5,s0,0x1b +800005b4: 01c00513 li a0,28 +800005b8: e6f568e3 bltu a0,a5,80000428 +800005bc: 80001537 lui a0,0x80001 +800005c0: 00279793 slli a5,a5,0x2 +800005c4: 88450513 addi a0,a0,-1916 # 80000884 <_sp+0xfffff75c> +800005c8: 00a787b3 add a5,a5,a0 +800005cc: 0007a783 lw a5,0(a5) +800005d0: 00078067 jr a5 +800005d4: 1dc000ef jal ra,800007b0 +800005d8: 00050913 mv s2,a0 +800005dc: f59ff06f j 80000534 +800005e0: 00f45993 srli s3,s0,0xf +800005e4: 01f9f993 andi s3,s3,31 +800005e8: 013039b3 snez s3,s3 +800005ec: f15ff06f j 80000500 +800005f0: 1a8000ef jal ra,80000798 +800005f4: 343027f3 csrr a5,mtval +800005f8: 14379073 csrw stval,a5 +800005fc: 341027f3 csrr a5,mepc +80000600: 14179073 csrw sepc,a5 +80000604: 342027f3 csrr a5,mcause +80000608: 14279073 csrw scause,a5 +8000060c: 105027f3 csrr a5,stvec +80000610: 34179073 csrw mepc,a5 +80000614: f21ff06f j 80000534 +80000618: 01067463 bgeu a2,a6,80000620 +8000061c: 00080613 mv a2,a6 +80000620: 00020537 lui a0,0x20 +80000624: 30052073 csrs mstatus,a0 +80000628: 00000517 auipc a0,0x0 +8000062c: 01850513 addi a0,a0,24 # 80000640 +80000630: 30551073 csrw mtvec,a0 +80000634: 00100793 li a5,1 +80000638: 00c72023 sw a2,0(a4) +8000063c: 00000793 li a5,0 +80000640: 00020537 lui a0,0x20 +80000644: 30053073 csrc mstatus,a0 +80000648: 80000737 lui a4,0x80000 +8000064c: 07c70713 addi a4,a4,124 # 8000007c <_sp+0xffffef54> +80000650: 14079063 bnez a5,80000790 +80000654: 00545793 srli a5,s0,0x5 +80000658: 07c7f793 andi a5,a5,124 +8000065c: 00d786b3 add a3,a5,a3 +80000660: 0106a023 sw a6,0(a3) +80000664: 00448493 addi s1,s1,4 +80000668: 34149073 csrw mepc,s1 +8000066c: 30571073 csrw mtvec,a4 +80000670: dddff06f j 8000044c +80000674: 01064633 xor a2,a2,a6 +80000678: fa9ff06f j 80000620 +8000067c: fac872e3 bgeu a6,a2,80000620 +80000680: 00080613 mv a2,a6 +80000684: f9dff06f j 80000620 +80000688: f9065ce3 bge a2,a6,80000620 8000068c: 00080613 mv a2,a6 -80000690: f85ff06f j 80000614 -80000694: f90650e3 bge a2,a6,80000614 +80000690: f91ff06f j 80000620 +80000694: f8c856e3 bge a6,a2,80000620 80000698: 00080613 mv a2,a6 -8000069c: f79ff06f j 80000614 -800006a0: f6c85ae3 bge a6,a2,80000614 -800006a4: 00080613 mv a2,a6 -800006a8: f6dff06f j 80000614 -800006ac: 0f0000ef jal ra,8000079c -800006b0: faa42423 sw a0,-88(s0) -800006b4: 341027f3 csrr a5,mepc -800006b8: 00478793 addi a5,a5,4 -800006bc: 34179073 csrw mepc,a5 -800006c0: d95ff06f j 80000454 -800006c4: fac42583 lw a1,-84(s0) -800006c8: 0ec000ef jal ra,800007b4 -800006cc: 08000793 li a5,128 -800006d0: 3047a073 csrs mie,a5 -800006d4: 02000793 li a5,32 -800006d8: 1447b073 csrc sip,a5 -800006dc: 341027f3 csrr a5,mepc -800006e0: 00478793 addi a5,a5,4 -800006e4: 34179073 csrw mepc,a5 -800006e8: d6dff06f j 80000454 -800006ec: 0ff57513 andi a0,a0,255 -800006f0: 0a4000ef jal ra,80000794 -800006f4: 341027f3 csrr a5,mepc -800006f8: 00478793 addi a5,a5,4 -800006fc: 34179073 csrw mepc,a5 -80000700: d55ff06f j 80000454 -80000704: 088000ef jal ra,8000078c -80000708: 343027f3 csrr a5,mtval -8000070c: 14379073 csrw stval,a5 -80000710: 341027f3 csrr a5,mepc -80000714: 14179073 csrw sepc,a5 -80000718: 342027f3 csrr a5,mcause -8000071c: 14279073 csrw scause,a5 -80000720: 105027f3 csrr a5,stvec -80000724: 34179073 csrw mepc,a5 -80000728: e21ff06f j 80000548 -8000072c: 800007b7 lui a5,0x80000 -80000730: 07c78793 addi a5,a5,124 # 8000007c <_sp+0xffffef64> -80000734: 30579073 csrw mtvec,a5 -80000738: 343027f3 csrr a5,mtval -8000073c: 14379073 csrw stval,a5 -80000740: 342027f3 csrr a5,mcause -80000744: 14279073 csrw scause,a5 -80000748: 14149073 csrw sepc,s1 -8000074c: 105027f3 csrr a5,stvec -80000750: 34179073 csrw mepc,a5 -80000754: 10000793 li a5,256 -80000758: 1007b073 csrc sstatus,a5 -8000075c: 0035d793 srli a5,a1,0x3 -80000760: 1007f793 andi a5,a5,256 -80000764: 1007a073 csrs sstatus,a5 -80000768: 000027b7 lui a5,0x2 -8000076c: 80078793 addi a5,a5,-2048 # 1800 <__stack_size+0x1000> -80000770: 3007b073 csrc mstatus,a5 -80000774: 000017b7 lui a5,0x1 -80000778: 88078793 addi a5,a5,-1920 # 880 <__stack_size+0x80> -8000077c: 3007a073 csrs mstatus,a5 -80000780: cd5ff06f j 80000454 -80000784: 30571073 csrw mtvec,a4 -80000788: fb1ff06f j 80000738 +8000069c: f85ff06f j 80000620 +800006a0: 01067633 and a2,a2,a6 +800006a4: f7dff06f j 80000620 +800006a8: 01066633 or a2,a2,a6 +800006ac: f75ff06f j 80000620 +800006b0: 01060633 add a2,a2,a6 +800006b4: f6dff06f j 80000620 +800006b8: fac42583 lw a1,-84(s0) +800006bc: 104000ef jal ra,800007c0 +800006c0: 08000793 li a5,128 +800006c4: 3047a073 csrs mie,a5 +800006c8: 02000793 li a5,32 +800006cc: 1447b073 csrc sip,a5 +800006d0: 341027f3 csrr a5,mepc +800006d4: 00478793 addi a5,a5,4 +800006d8: 34179073 csrw mepc,a5 +800006dc: d71ff06f j 8000044c +800006e0: 0ff57513 andi a0,a0,255 +800006e4: 0bc000ef jal ra,800007a0 +800006e8: 341027f3 csrr a5,mepc +800006ec: 00478793 addi a5,a5,4 +800006f0: 34179073 csrw mepc,a5 +800006f4: d59ff06f j 8000044c +800006f8: 0b0000ef jal ra,800007a8 +800006fc: faa42423 sw a0,-88(s0) +80000700: 341027f3 csrr a5,mepc +80000704: 00478793 addi a5,a5,4 +80000708: 34179073 csrw mepc,a5 +8000070c: d41ff06f j 8000044c +80000710: 088000ef jal ra,80000798 +80000714: 343027f3 csrr a5,mtval +80000718: 14379073 csrw stval,a5 +8000071c: 341027f3 csrr a5,mepc +80000720: 14179073 csrw sepc,a5 +80000724: 342027f3 csrr a5,mcause +80000728: 14279073 csrw scause,a5 +8000072c: 105027f3 csrr a5,stvec +80000730: 34179073 csrw mepc,a5 +80000734: e05ff06f j 80000538 +80000738: 800007b7 lui a5,0x80000 +8000073c: 07c78793 addi a5,a5,124 # 8000007c <_sp+0xffffef54> +80000740: 30579073 csrw mtvec,a5 +80000744: 343027f3 csrr a5,mtval +80000748: 14379073 csrw stval,a5 +8000074c: 342027f3 csrr a5,mcause +80000750: 14279073 csrw scause,a5 +80000754: 14149073 csrw sepc,s1 +80000758: 105027f3 csrr a5,stvec +8000075c: 34179073 csrw mepc,a5 +80000760: 10000793 li a5,256 +80000764: 1007b073 csrc sstatus,a5 +80000768: 0035d793 srli a5,a1,0x3 +8000076c: 1007f793 andi a5,a5,256 +80000770: 1007a073 csrs sstatus,a5 +80000774: 000027b7 lui a5,0x2 +80000778: 80078793 addi a5,a5,-2048 # 1800 <__stack_size+0x1000> +8000077c: 3007b073 csrc mstatus,a5 +80000780: 000017b7 lui a5,0x1 +80000784: 88078793 addi a5,a5,-1920 # 880 <__stack_size+0x80> +80000788: 3007a073 csrs mstatus,a5 +8000078c: cc1ff06f j 8000044c +80000790: 30571073 csrw mtvec,a4 +80000794: fb1ff06f j 80000744 -8000078c : -8000078c: fe002e23 sw zero,-4(zero) # fffffffc <_sp+0x7fffeee4> -80000790: 0000006f j 80000790 +80000798 : +80000798: fe002e23 sw zero,-4(zero) # fffffffc <_sp+0x7fffeed4> +8000079c: 0000006f j 8000079c -80000794 : -80000794: fea02c23 sw a0,-8(zero) # fffffff8 <_sp+0x7fffeee0> -80000798: 00008067 ret +800007a0 : +800007a0: fea02c23 sw a0,-8(zero) # fffffff8 <_sp+0x7fffeed0> +800007a4: 00008067 ret -8000079c : -8000079c: ff802503 lw a0,-8(zero) # fffffff8 <_sp+0x7fffeee0> -800007a0: 00008067 ret +800007a8 : +800007a8: ff802503 lw a0,-8(zero) # fffffff8 <_sp+0x7fffeed0> +800007ac: 00008067 ret -800007a4 : -800007a4: fe002503 lw a0,-32(zero) # ffffffe0 <_sp+0x7fffeec8> -800007a8: 00008067 ret +800007b0 : +800007b0: fe002503 lw a0,-32(zero) # ffffffe0 <_sp+0x7fffeeb8> +800007b4: 00008067 ret -800007ac : -800007ac: fe402503 lw a0,-28(zero) # ffffffe4 <_sp+0x7fffeecc> -800007b0: 00008067 ret +800007b8 : +800007b8: fe402503 lw a0,-28(zero) # ffffffe4 <_sp+0x7fffeebc> +800007bc: 00008067 ret -800007b4 : -800007b4: fec00793 li a5,-20 -800007b8: fff00713 li a4,-1 -800007bc: 00e7a023 sw a4,0(a5) -800007c0: fea02423 sw a0,-24(zero) # ffffffe8 <_sp+0x7fffeed0> -800007c4: 00b7a023 sw a1,0(a5) -800007c8: 00008067 ret +800007c0 : +800007c0: fec00793 li a5,-20 +800007c4: fff00713 li a4,-1 +800007c8: 00e7a023 sw a4,0(a5) +800007cc: fea02423 sw a0,-24(zero) # ffffffe8 <_sp+0x7fffeec0> +800007d0: 00b7a023 sw a1,0(a5) +800007d4: 00008067 ret -800007cc : -800007cc: 00008067 ret +800007d8 : +800007d8: 00008067 ret -800007d0 <__libc_init_array>: -800007d0: ff010113 addi sp,sp,-16 -800007d4: 00000797 auipc a5,0x0 -800007d8: 0a478793 addi a5,a5,164 # 80000878 <__init_array_end> -800007dc: 00812423 sw s0,8(sp) -800007e0: 00000417 auipc s0,0x0 -800007e4: 09840413 addi s0,s0,152 # 80000878 <__init_array_end> -800007e8: 40f40433 sub s0,s0,a5 -800007ec: 00912223 sw s1,4(sp) -800007f0: 01212023 sw s2,0(sp) -800007f4: 00112623 sw ra,12(sp) -800007f8: 40245413 srai s0,s0,0x2 -800007fc: 00000493 li s1,0 -80000800: 00078913 mv s2,a5 -80000804: 04849263 bne s1,s0,80000848 <__libc_init_array+0x78> -80000808: 871ff0ef jal ra,80000078 <_init> -8000080c: 00000797 auipc a5,0x0 -80000810: 06c78793 addi a5,a5,108 # 80000878 <__init_array_end> -80000814: 00000417 auipc s0,0x0 -80000818: 06440413 addi s0,s0,100 # 80000878 <__init_array_end> -8000081c: 40f40433 sub s0,s0,a5 -80000820: 40245413 srai s0,s0,0x2 -80000824: 00000493 li s1,0 -80000828: 00078913 mv s2,a5 -8000082c: 02849a63 bne s1,s0,80000860 <__libc_init_array+0x90> -80000830: 00c12083 lw ra,12(sp) -80000834: 00812403 lw s0,8(sp) -80000838: 00412483 lw s1,4(sp) -8000083c: 00012903 lw s2,0(sp) -80000840: 01010113 addi sp,sp,16 -80000844: 00008067 ret -80000848: 00249793 slli a5,s1,0x2 -8000084c: 00f907b3 add a5,s2,a5 -80000850: 0007a783 lw a5,0(a5) -80000854: 00148493 addi s1,s1,1 -80000858: 000780e7 jalr a5 -8000085c: fa9ff06f j 80000804 <__libc_init_array+0x34> -80000860: 00249793 slli a5,s1,0x2 -80000864: 00f907b3 add a5,s2,a5 -80000868: 0007a783 lw a5,0(a5) -8000086c: 00148493 addi s1,s1,1 -80000870: 000780e7 jalr a5 -80000874: fb9ff06f j 8000082c <__libc_init_array+0x5c> +800007dc <__libc_init_array>: +800007dc: ff010113 addi sp,sp,-16 +800007e0: 00000797 auipc a5,0x0 +800007e4: 0a478793 addi a5,a5,164 # 80000884 <__init_array_end> +800007e8: 00812423 sw s0,8(sp) +800007ec: 00000417 auipc s0,0x0 +800007f0: 09840413 addi s0,s0,152 # 80000884 <__init_array_end> +800007f4: 40f40433 sub s0,s0,a5 +800007f8: 00912223 sw s1,4(sp) +800007fc: 01212023 sw s2,0(sp) +80000800: 00112623 sw ra,12(sp) +80000804: 40245413 srai s0,s0,0x2 +80000808: 00000493 li s1,0 +8000080c: 00078913 mv s2,a5 +80000810: 04849263 bne s1,s0,80000854 <__libc_init_array+0x78> +80000814: 865ff0ef jal ra,80000078 <_init> +80000818: 00000797 auipc a5,0x0 +8000081c: 06c78793 addi a5,a5,108 # 80000884 <__init_array_end> +80000820: 00000417 auipc s0,0x0 +80000824: 06440413 addi s0,s0,100 # 80000884 <__init_array_end> +80000828: 40f40433 sub s0,s0,a5 +8000082c: 40245413 srai s0,s0,0x2 +80000830: 00000493 li s1,0 +80000834: 00078913 mv s2,a5 +80000838: 02849a63 bne s1,s0,8000086c <__libc_init_array+0x90> +8000083c: 00c12083 lw ra,12(sp) +80000840: 00812403 lw s0,8(sp) +80000844: 00412483 lw s1,4(sp) +80000848: 00012903 lw s2,0(sp) +8000084c: 01010113 addi sp,sp,16 +80000850: 00008067 ret +80000854: 00249793 slli a5,s1,0x2 +80000858: 00f907b3 add a5,s2,a5 +8000085c: 0007a783 lw a5,0(a5) +80000860: 00148493 addi s1,s1,1 +80000864: 000780e7 jalr a5 +80000868: fa9ff06f j 80000810 <__libc_init_array+0x34> +8000086c: 00249793 slli a5,s1,0x2 +80000870: 00f907b3 add a5,s2,a5 +80000874: 0007a783 lw a5,0(a5) +80000878: 00148493 addi s1,s1,1 +8000087c: 000780e7 jalr a5 +80000880: fb9ff06f j 80000838 <__libc_init_array+0x5c> diff --git a/src/main/c/emulator/build/emulator.bin b/src/main/c/emulator/build/emulator.bin index e87b1abeed90cabb41b185657c6197b6c7df1324..9c56f673544853d533ea2dfb223c008cb4059b7a 100755 GIT binary patch delta 808 zcmZ8fO-vI(6n?wi?v%2@r2{Mq*flMbKthO1vVa#4An~9FLLeATP1fIp1Y=P+XsDrd zIT)ah5fc;OU;;;zLb&b$0|$4}+v*}(_sX;7?iG=D`=ZeYcSz}@y0;(Gudm%lt{wD*MCo&LCgx~R2 zYvOp3kKSfczLu?VvJ{!`Z;#02Qe>WVvt3RNo=)gh5JloGD#Yffdzq&~6=VR0Sv_CJ zd08jlT_Gg?6|8>T){li{zV577b7ygib+{jOM&}BFrb>r=jeQqXcE}eL-&CmQn29pD z8e@4QmTEI*_uGt@%q!GaSUMda2Sc)bNYPIy1HyAfvSmiv!SJ9jlfe*lR|c$Br#`7G zD9KO{$3$WoUsDy7ge>EcE$MclKndwgn)^VB3dS8OT;KbwT@kUclutk2&QsBYq`h4FrkE?n{#<%+`=}U)kF=*w@1CvQb9~s= z#1s5`s&O-qzd&X?;`xjI6n&CCgEN%>3dtSJ?89p+c+I6xsC9WD_&)!C-oMKP(!__q zymB?LtE7wf@30t&^Wiv?JR_4IM2M QyA%BnBL=fQ7X-ld7nfuKhX4Qo delta 839 zcmZ8ePe>GD6o23B%zRFW&ibv6h_n;CYAz82t7&#oSnE(wiL@la9;U27FxXNr(a7pf zmt^b<6pHi^*xkhI3PN6j4wZD;XrV6A3c9Yli1ubTDCY3--tYI``@KKk+lIvkUGoDl zGVRwI(MpoNfR@kBrnM%-vh2+3L4EEo`OKVJgODy^;vnS4){gREP39pppLi+spP4^= zEo2h>6*;Z$J|8lYD!q_&XkXG9GWbWL$Gl`u0IWRp-(uqC9Fvv>CI$e-;=Vx?zPgz6FWtJ14V$?m&~Ak_wn0=XfUix0yB2_3H;W|#RlQRlye;{kuFBX-DT6{}~;W_tUqIrB4O&e4c3JWW#i21$hnh_927 zRObdBj0odkonw=eU_vo~O5GKuE8=4fiVd6^VAd8@uBc#&JwCis#ErM&NWkJT!qZyD zl(*}+t!a{!%eFvbA6Jv-^2~`cU{ydACFD;`Sw6L&G%^UsG+HW!$}vXXKMD*)Qx-p&lnV z;Ys_W{tJ$WF56~JeR)pzed-{mY1p7P*j4}RgnPd&I6 TaU>GaZ`_$0x}P+;PdW7m+UpDU diff --git a/src/main/c/emulator/build/emulator.hex b/src/main/c/emulator/build/emulator.hex index f8938324..feaa02b6 100644 --- a/src/main/c/emulator/build/emulator.hex +++ b/src/main/c/emulator/build/emulator.hex @@ -1,10 +1,10 @@ :0200000480007A -:100000001711000013018111171500001305058752 -:100010009715000093858586171600001306069035 +:100000001711000013018112171500001305C58791 +:100010009715000093854587171600001306069173 :1000200063FCC5008322050023A05500130545008D -:1000300093854500E3E8C5FE171500001305058EFE -:10004000971500009385858D6378B5002320050002 -:1000500013054500E36CB5FEEF008077EF00C01795 +:1000300093854500E3E8C5FE171500001305058FFD +:10004000971500009385858E6378B5002320050001 +:1000500013054500E36CB5FEEF004078EF00801714 :10006000970000009380400113050000B70500C30E :10007000730020306F0000006780000073110134AE :10008000232211002326310023284100232A510076 @@ -14,7 +14,7 @@ :1000C000232421052326310523284105232A510510 :1000D000232C6105232E71052320810723229107FC :1000E0002324A1072326B1072328C107232AD107E8 -:1000F000232CE107232EF107EF00402C8320410041 +:1000F000232CE107232EF107EF00C02B83204100C2 :100100008321C100032201018322410103238101D4 :100110008323C101032401028324410203258102B8 :100120008325C1020326010383264103032781039C @@ -24,126 +24,128 @@ :10016000832DC106032E0107832E4107032F81072C :0C017000832FC10773110134730020308D :10017C00130101FF23248100232611001304050021 -:10018C0003450500630A050013041400EF00C05F6B +:10018C0003450500630A050013041400EF008060AA :10019C0003450400E31A05FE8320C10003248100FB :1001AC0013010101678000009307F0011307F0FFB2 -:1001BC009702000093824201F39252307310073B76 -:1001CC007390073A7390523067800000130101FF5F -:1001DC0023261100232481009307F0011307F0FF5D -:1001EC009702000093824201F39252307310073B46 -:1001FC007390073A7390523037140080EF00405CD4 -:10020C001304C48E1305A00213041400EF00C0578E -:10021C0003450400E31A05FEB70700809387C70760 -:10022C0073905730B7170080938787097390073402 -:10023C00B7170000938707887390073073504030CE -:10024C00B70700C073901734B7B700009387071037 -:10025C0073902730930720227390373073503014EB -:10026C0037140080130444901305A00213041400E7 -:10027C00EF00805103450400E31A05FE8320C10002 -:10028C00032481001301010167800000B71700806F -:10029C0093878709131525003305F5000325050001 -:1002AC0067800000B7170080131525009387870916 -:1002BC003305F5002320B50067800000130101FF12 -:1002CC0023261100EF00C04BF32730347390371402 -:1002DC00F327103473901714F327203473902714DA -:1002EC00F3275010739017348320C10013010101C0 -:1002FC0067800000B70700809387C707739057305B -:10030C00F327303473903714F32720347390271469 -:10031C0073101514F32750107390173493070010B3 -:10032C0073B0071093D5350093F5051073A0051025 -:10033C00B72700009387078073B00730B71700000A -:10034C009387078873A00730678000003707020087 -:10035C0073200730170700001307870173105730FD -:10036C009306100083270500930600003707020050 -:10037C00733007301385060023A0F500678000005A -:10038C003707020073200730170700001307870197 -:10039C0073105730930710002320B500930700000B -:1003AC0037070200733007301385070067800000A1 -:1003BC00130101FE232E1100232C8100232A91000E -:1003CC002328210123263101F327203463CC07088D -:1003DC00130720006384E70C930690006394D70402 -:1003EC003714008013048411832744FC93061000F7 -:1003FC00032584FA6386D72E6384E72A638E072A43 -:10040C00032481018320C1018324410103290101BB -:10041C008329C100130101026F0080361377770026 -:10042C006300F714EF00C035F327303473903714A2 -:10043C00F327103473901714F32720347390271478 -:10044C00F3275010739017348320C10103248101CA -:10045C0083244101032901018329C10013010102F5 -:10046C006780000093F7F70F13077000E39CE7FA1F -:10047C009307000273A047149307000873B047302A -:10048C008320C1010324810183244101032901013B -:10049C008329C1001301010267800000F32410348A -:1004AC00F3250030732430341306F0029376F407EE -:1004BC001357C400E384C6F613063007E394C6F65C -:1004CC00137737006300F71293073000630CF710B3 -:1004DC009309100063043703EF00802AF3273034AC -:1004EC0073903714F327103473901714F3272034B8 -:1004FC0073902714F327501073901734B71700001C -:10050C0013574401938617C06306D70E938717C8F9 -:10051C006304F70CEF00C026F327303473903714C4 -:10052C00F327103473901714F32720347390271487 -:10053C00F3275010739017346390091C1354540014 -:10054C00B7170080938787091374C4073304F4002A -:10055C002320240193844400739014346FF0DFEE55 -:10056C001357D40093572401B7160080938686093D -:10057C001377C70793F7C7073307D700B387D7009D -:10058C000327070003A60700370502007320053078 -:10059C0017050000130585017310553093071000E3 -:1005AC00032807009307000037050200733005305D -:1005BC00639807169357B4011305C001E364F5E67D -:1005CC00371500809397270013058587B387A700FD -:1005DC0083A7070067800700EF00801C1309050044 -:1005EC006FF09FF59359F40093F9F901B339300189 -:1005FC006FF0DFF0EF00401A130905006FF0DFF326 -:10060C0063740601130608003705020073200530D9 -:10061C001705000013058501731055309307100062 -:10062C002320C70093070000370502007330053004 -:10063C00370700801307C7076390071493575400BC -:10064C0093F7C707B386D70023A006019384440011 -:10065C0073901434731057306FF01FDF334606015C -:10066C006FF09FFA330606016FF01FFA337606011E -:10067C006FF09FF9336606016FF01FF9E376C8F847 -:10068C00130608006FF05FF8E35006F91306080034 -:10069C006FF09FF7E35AC8F6130608006FF0DFF609 -:1006AC00EF00000F2324A4FAF3271034938747009C -:1006BC00739017346FF05FD98325C4FAEF00C00E26 -:1006CC009307000873A047309307000273B04714D8 -:1006DC00F327103493874700739017346FF0DFD6ED -:1006EC001375F50FEF00400AF3271034938747007A -:1006FC00739017346FF05FD5EF008008F327303418 -:10070C0073903714F327103473901714F327203495 -:10071C0073902714F3275010739017346FF01FE267 -:10072C00B70700809387C70773905730F32730348F -:10073C0073903714F3272034739027147390141488 -:10074C00F3275010739017349307001073B00710F1 -:10075C0093D7350093F7071073A00710B727000045 -:10076C009387078073B00730B7170000938707880B -:10077C0073A007306FF05FCD731057306FF01FFB15 -:10078C00232E00FE6F000000232CA0FE67800000CB -:10079C00032580FF67800000032500FE67800000B2 -:1007AC00032540FE678000009307C0FE1307F0FF8F -:1007BC0023A0E7002324A0FE23A0B700678000003D -:1007CC0067800000130101FF970700009387470A19 -:1007DC002324810017040000130484093304F4401B -:1007EC00232291002320210123261100135424409D -:1007FC00930400001389070063928404EFF01F87B1 -:10080C00970700009387C7061704000013044406DB -:10081C003304F4401354244093040000138907005C -:10082C00639A84028320C100032481008324410045 -:10083C000329010013010101678000009397240034 -:10084C00B307F90083A7070093841400E78007001F -:10085C006FF09FFA93972400B307F90083A7070062 -:0C086C0093841400E78007006FF09FFBEE -:100878007006008014060080300400803004008078 -:100888006806008030040080300400803004008056 -:10089800800600803004008030040080300400802E -:1008A8007806008030040080300400803004008026 -:1008B800A0060080300400803004008030040080EE -:1008C80094060080300400803004008030040080EA -:1008D80088060080300400803004008030040080E6 -:1008E8000C0600802A2A2A20566578526973637696 -:1008F8002042494F53202A2A2A0A00002A2A2A205D -:1009080053757065727669736F72202A2A2A0A00F5 +:1001BC009702000093824201739052307310073BF8 +:1001CC007390073A67800000130101FF232611008A +:1001DC00232481009307F0011307F0FF970200001E +:1001EC0093824201739052307310073B7390073A1D +:1001FC0037140080EF00805D1304848F1305A00278 +:10020C0013041400EF00005903450400E31A05FE23 +:10021C00B70700809387C70773905730B7170080D4 +:10022C009387870A73900734B71700009387078862 +:10023C007390073073504030B70700C07390173479 +:10024C00B7B70000938707107390273093072022CD +:10025C0073903730735030143714008013040491AA +:10026C001305A00213041400EF00C0520345040050 +:10027C00E31A05FE8320C100032481001301010150 +:10028C0067800000B71700809387870A1315250035 +:10029C003305F5000325050067800000B7170080C3 +:1002AC00131525009387870A3305F5002320B50025 +:1002BC0067800000130101FF23261100EF00004DA1 +:1002CC00F327303473903714F327103473901714CA +:1002DC00F327203473902714F3275010739017349E +:1002EC008320C1001301010167800000B707008063 +:1002FC009387C70773905730F327303473903714B4 +:10030C00F32720347390271473101514F32750100F +:10031C00739017349307001073B0071093D5350002 +:10032C0093F5051073A00510B7270000938707807D +:10033C0073B00730B71700009387078873A0073096 +:10034C006780000037070200732007301707000092 +:10035C00130787017310573093061000832705008D +:10036C009306000037070200733007301385060030 +:10037C0023A0F500678000003707020073200730C8 +:10038C0017070000130787017310573093071000ED +:10039C002320B500930700003707020073300730A5 +:1003AC001385070067800000130101FE232E110046 +:1003BC00232C8100232A910023282101232631019B +:1003CC00F327203463CC0708130720006384E70C61 +:1003DC00930690006394D70437140080130484129E +:1003EC00832744FC93061000032584FA6384D72EDC +:1003FC00638EE72E638C072A032481018320C101BD +:10040C0083244101032901018329C1001301010245 +:10041C006F00C03713777700630CF712EF000037CB +:10042C00F327303473903714F32710347390171468 +:10043C00F327203473902714F3275010739017343C +:10044C008320C1010324810183244101032901017B +:10045C008329C100130101026780000093F7F70F95 +:10046C0013077000E39CE7FA9307000273A047148C +:10047C009307000873B047308320C1010324810126 +:10048C0083244101032901018329C10013010102C5 +:10049C0067800000F3241034F325003073243034CB +:1004AC001306F0029376F4071357C400E384C6F6E0 +:1004BC0013063007E394C6F613773700630CF71076 +:1004CC00930730006308F710930910006304370397 +:1004DC00EF00C02BF327303473903714F32710340C +:1004EC0073901714F327203473902714F3275010AC +:1004FC00739017343717000093574401930607C0C5 +:10050C0063E2D70E130727C06370F70C37F7FFFFB2 +:10051C0013070738B387E700130720006364F70C51 +:10052C00EF00C02813090500639E091C13545400E6 +:10053C00B71700809387870A1374C4073304F40039 +:10054C002320240193844400739014346FF05FEFE4 +:10055C001357D40093572401B71600809386860A4C +:10056C001377C70793F7C7073307D700B387D700AD +:10057C000327070003A60700370502007320053088 +:10058C0017050000130585017310553093071000F3 +:10059C00032807009307000037050200733005306D +:1005AC00639607189357B4011305C001E368F5E689 +:1005BC00371500809397270013054588B387A7004C +:1005CC0083A7070067800700EF00C01D1309050013 +:1005DC006FF09FF59359F40093F9F901B339300199 +:1005EC006FF05FF1EF00801AF327303473903714FB +:1005FC00F327103473901714F327203473902714B7 +:10060C00F3275010739017346FF01FF263740601C8 +:10061C00130608003705020073200530170500008B +:10062C001305850173105530930710002320C70064 +:10063C009307000037050200733005303707008040 +:10064C001307C707639007149357540093F7C70712 +:10065C00B386D70023A0060193844400739014340E +:10066C00731057306FF0DFDD334606016FF09FFAE1 +:10067C00E372C8FA130608006FF0DFF9E35C06F9C1 +:10068C00130608006FF01FF9E356C8F813060800AC +:10069C006FF05FF8337606016FF0DFF73366060113 +:1006AC006FF05FF7330606016FF0DFF68325C4FAAF +:1006BC00EF0040109307000873A047309307000227 +:1006CC0073B04714F3271034938747007390173493 +:1006DC006FF01FD71375F50FEF00C00BF327103415 +:1006EC0093874700739017346FF09FD5EF00000B82 +:1006FC002324A4FAF32710349387470073901734FC +:10070C006FF01FD4EF008008F32730347390371448 +:10071C00F327103473901714F32720347390271495 +:10072C00F3275010739017346FF05FE0B707008019 +:10073C009387C70773905730F3273034739037146F +:10074C00F32720347390271473901414F32750104C +:10075C00739017349307001073B0071093D73500BC +:10076C0093F7071073A00710B72700009387078033 +:10077C0073B00730B71700009387078873A0073052 +:10078C006FF01FCC731057306FF01FFB232E00FE41 +:10079C006F000000232CA0FE67800000032580FF63 +:1007AC0067800000032500FE67800000032540FEE3 +:1007BC00678000009307C0FE1307F0FF23A0E7003B +:1007CC002324A0FE23A0B7006780000067800000F0 +:1007DC00130101FF970700009387470A2324810028 +:1007EC0017040000130484093304F44023229100FD +:1007FC0023202101232611001354244093040000CC +:10080C001389070063928404EFF05F86970700005A +:10081C009387C70617040000130444063304F440FE +:10082C00135424409304000013890700639A840234 +:10083C008320C1000324810083244100032901008B +:10084C00130101016780000093972400B307F9009E +:10085C0083A7070093841400E78007006FF09FFACA +:10086C0093972400B307F90083A70700938414001F +:08087C00E78007006FF09FFB0D +:10088400B006008020060080280400802804008030 +:100894007406008028040080280400802804008056 +:1008A400A806008028040080280400802804008012 +:1008B400A00600802804008028040080280400800A +:1008C4009406008028040080280400802804008006 +:1008D4008806008028040080280400802804008002 +:1008E4007C060080280400802804008028040080FE +:1008F400180600802A2A2A2056657852697363767E +:100904002042494F53202A2A2A0A00002A2A2A2050 +:1009140053757065727669736F72202A2A2A0A00E9 +:0409240000000000CF :040000058000000077 :00000001FF diff --git a/src/main/c/emulator/src/main.c b/src/main/c/emulator/src/main.c index f61212ff..29067d22 100755 --- a/src/main/c/emulator/src/main.c +++ b/src/main/c/emulator/src/main.c @@ -14,17 +14,18 @@ void putString(char* s){ } } +//Affect mtvec void setup_pmp(void) { // Set up a PMP to permit access to all of memory. // Ignore the illegal-instruction trap if PMPs aren't supported. uintptr_t pmpc = PMP_NAPOT | PMP_R | PMP_W | PMP_X; asm volatile ("la t0, 1f\n\t" - "csrrw t0, mtvec, t0\n\t" + "csrw mtvec, t0\n\t" "csrw pmpaddr0, %1\n\t" "csrw pmpcfg0, %0\n\t" ".align 2\n\t" - "1: csrw mtvec, t0" + "1:" : : "r" (pmpc), "r" (-1UL) : "t0"); } @@ -233,7 +234,11 @@ void trap(){ uint32_t csrAddress = instruction >> 20; uint32_t old; switch(csrAddress){ + case RDCYCLE : + case RDINSTRET: case RDTIME : old = rdtime(); break; + case RDCYCLEH : + case RDINSTRETH: case RDTIMEH : old = rdtimeh(); break; default: redirectTrap(); break; } From ece1e735475d3b5a9284e0aa4905849622e9119d Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Thu, 11 Apr 2019 01:18:15 +0200 Subject: [PATCH 138/951] Default linux config is now without RVC Remove all linux usless CSR from the config Remove verilator instruction fetch check --- src/main/scala/vexriscv/demo/Linux.scala | 20 +++++---- .../scala/vexriscv/plugin/CsrPlugin.scala | 41 ++++++++++++++++++- src/test/cpp/regression/main.cpp | 23 ++--------- 3 files changed, 57 insertions(+), 27 deletions(-) diff --git a/src/main/scala/vexriscv/demo/Linux.scala b/src/main/scala/vexriscv/demo/Linux.scala index 09ed5142..5fa43309 100644 --- a/src/main/scala/vexriscv/demo/Linux.scala +++ b/src/main/scala/vexriscv/demo/Linux.scala @@ -40,13 +40,13 @@ cd VexRiscv Run regressions => sbt "runMain vexriscv.demo.LinuxGen -r" cd src/test/cpp/regression -make run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD DHRYSTONE=yes SUPERVISOR=yes CSR=yes COMPRESSED=yes LRSC=yes AMO=yes REDO=10 TRACE=no +make run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD DHRYSTONE=yes SUPERVISOR=yes CSR=yes COMPRESSED=no LRSC=yes AMO=yes REDO=10 TRACE=no Run linux in simulation (Require the machime mode emulator compiled in SIM mode) => sbt "runMain vexriscv.demo.LinuxGen" cd src/test/cpp/regression export BUILDROOT=/home/miaou/pro/riscv/buildrootSpinal -make run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD SUPERVISOR=yes CSR=yes COMPRESSED=yes LRSC=yes AMO=yes REDO=0 DHRYSTONE=no LINUX_SOC=yes EMULATOR=../../../main/c/emulator/build/emulator.bin VMLINUX=$BUILDROOT/output/images/Image DTB=$BUILDROOT/board/spinal/vexriscv_sim/rv32.dtb RAMDISK=$BUILDROOT/output/images/rootfs.cpio TRACE=no FLOW_INFO=no +make run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD SUPERVISOR=yes CSR=yes COMPRESSED=no LRSC=yes AMO=yes REDO=0 DHRYSTONE=no LINUX_SOC=yes EMULATOR=../../../main/c/emulator/build/emulator.bin VMLINUX=$BUILDROOT/output/images/Image DTB=$BUILDROOT/board/spinal/vexriscv_sim/rv32.dtb RAMDISK=$BUILDROOT/output/images/rootfs.cpio TRACE=no FLOW_INFO=no Run linux with QEMU (Require the machime mode emulator compiled in QEMU mode) export BUILDROOT=/home/miaou/pro/riscv/buildrootSpinal @@ -114,6 +114,12 @@ RAMDISK=/home/miaou/pro/riscv/buildrootSpinal/output/images/rootfs.cpio TRACE=no make run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD SUPERVISOR=yes CSR=yes COMPRESSED=yes LRSC=yes AMO=yes REDO=0 DHRYSTONE=no LINUX_SOC=yes DEBUG_PLUGIN_EXTERNAL=yes +rm -rf cpio +mkdir cpio +cd cpio +ls | cpio -ov > ../rootfs.cpio +cpio -idv < ../rootfs.cpio + */ @@ -140,9 +146,9 @@ object LinuxGen { //Uncomment the whole IBusCachedPlugin and comment IBusSimplePlugin if you want cached iBus config new IBusCachedPlugin( resetVector = 0x80000000l, - compressedGen = true, + compressedGen = false, prediction = NONE, - injectorStage = true, + injectorStage = false, config = InstructionCacheConfig( cacheSize = 4096*1, bytePerLine = 32, @@ -232,7 +238,7 @@ object LinuxGen { divUnrollFactor = 1 ), // new DivPlugin, - new CsrPlugin(CsrPluginConfig.linux(0x80000020l).copy(ebreakGen = false)), + new CsrPlugin(CsrPluginConfig.linuxMinimal(0x80000020l).copy(ebreakGen = false)), // new CsrPlugin(//CsrPluginConfig.all2(0x80000020l).copy(ebreakGen = true)/* // CsrPluginConfig( // catchIllegalAccess = false, @@ -398,7 +404,7 @@ object LinuxSyntesisBench extends App{ SpinalConfig(inlineRom=true).generateVerilog(new VexRiscv(LinuxGen.configFull(litex = false, withMmu = true)).setDefinitionName(getRtlPath().split("\\.").head)) } - val rtls = List(withoutMmu, withMmu) + val rtls = List(/*withoutMmu, */withMmu) // val rtls = List(smallestNoCsr, smallest, smallAndProductive, smallAndProductiveWithICache) // val rtls = List(smallAndProductive, smallAndProductiveWithICache, fullNoMmuMaxPerf, fullNoMmu, full) // val rtls = List(fullNoMmu) @@ -408,7 +414,7 @@ object LinuxSyntesisBench extends App{ ) ++ AlteraStdTargets( quartusCycloneIVPath = "/media/miaou/HD/linux/intelFPGA_lite/18.1/quartus/bin", quartusCycloneVPath = "/media/miaou/HD/linux/intelFPGA_lite/18.1/quartus/bin" - ) ++ IcestormStdTargets().take(1) + ) //++ IcestormStdTargets().take(1) Bench(rtls, targets, "/media/miaou/HD/linux/tmp") } diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 751106a6..635a5b80 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -78,7 +78,46 @@ object CsrPluginConfig{ def all : CsrPluginConfig = all(0x00000020l) def small : CsrPluginConfig = small(0x00000020l) def smallest : CsrPluginConfig = smallest(0x00000020l) - def linux(mtVecInit : BigInt) = CsrPluginConfig( + def linuxMinimal(mtVecInit : BigInt) = CsrPluginConfig( + catchIllegalAccess = true, + mvendorid = 1, + marchid = 2, + mimpid = 3, + mhartid = 0, + misaExtensionsInit = 0, //TODO + misaAccess = CsrAccess.NONE, //Read required by some regressions + mtvecAccess = CsrAccess.WRITE_ONLY, //Read required by some regressions + mtvecInit = mtVecInit, + mepcAccess = CsrAccess.READ_WRITE, + mscratchGen = true, + mcauseAccess = CsrAccess.READ_ONLY, + mbadaddrAccess = CsrAccess.READ_ONLY, + mcycleAccess = CsrAccess.NONE, + minstretAccess = CsrAccess.NONE, + ucycleAccess = CsrAccess.NONE, + wfiGenAsWait = true, + ecallGen = false, + xtvecModeGen = false, + noCsrAlu = false, + wfiGenAsNop = false, + ebreakGen = true, + supervisorGen = true, + sscratchGen = true, + stvecAccess = CsrAccess.READ_WRITE, + sepcAccess = CsrAccess.READ_WRITE, + scauseAccess = CsrAccess.READ_WRITE, + sbadaddrAccess = CsrAccess.READ_WRITE, + scycleAccess = CsrAccess.NONE, + sinstretAccess = CsrAccess.NONE, + satpAccess = CsrAccess.NONE, //Implemented into the MMU plugin + medelegAccess = CsrAccess.WRITE_ONLY, + midelegAccess = CsrAccess.WRITE_ONLY, + pipelineCsrRead = false, + deterministicInteruptionEntry = false + ) + + + def linuxFull(mtVecInit : BigInt) = CsrPluginConfig( catchIllegalAccess = true, mvendorid = 1, marchid = 2, diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index e71b2507..84b50a8b 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -1093,7 +1093,6 @@ public: uint32_t seed; - bool withInstructionReadCheck = true; Workspace* setIStall(bool enable) { iStall = enable; return this; } Workspace* setDStall(bool enable) { dStall = enable; return this; } @@ -1402,9 +1401,9 @@ public: virtual void pass(){ throw success();} virtual void fail(){ throw std::exception();} virtual void fillSimELements(); - Workspace* noInstructionReadCheck(){withInstructionReadCheck = false; return this;} void dump(int i){ #ifdef TRACE + if(i == TRACE_START) cout << "START TRACE" << endl; if(i >= TRACE_START) tfp->dump(i); #endif } @@ -1513,7 +1512,7 @@ public: currentTime = i; #ifdef FLOW_INFO - if(i % 100000 == 0) cout << "PROGRESS TRACE_START=" << i << endl; + if(i % 2000000 == 0) cout << "PROGRESS TRACE_START=" << i << endl; #endif @@ -1604,17 +1603,6 @@ public: dump(i + 1); - #ifndef COMPRESSED - if(withInstructionReadCheck){ - 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); - assertEq(top->VexRiscv->decode_INSTRUCTION,expectedData); - } - } - #endif - checks(); //top->eval(); top->clk = 1; @@ -2808,7 +2796,6 @@ public: loadHex("../../resources/hex/" + name + ".elf.hex"); out32.open (name + ".out32"); this->name = name; - if(name == "I-FENCE.I-01") withInstructionReadCheck = false; } @@ -3018,7 +3005,6 @@ public: DebugPluginTest() : WorkspaceRegression("DebugPluginTest") { loadHex("../../resources/hex/debugPlugin.hex"); pthread_create(&clientThreadId, NULL, &clientThreadWrapper, this); - noInstructionReadCheck(); } virtual ~DebugPluginTest(){ @@ -3526,7 +3512,6 @@ int main(int argc, char **argv, char **env) { w.loadHex(RUN_HEX); w.withRiscvRef(); #endif - w.noInstructionReadCheck(); //w.setIStall(false); //w.setDStall(false); @@ -3604,11 +3589,11 @@ int main(int argc, char **argv, char **env) { #ifndef COMPRESSED 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("../../cpp/raw/machineCsr/build/machineCsr",machineCsrRef, sizeof(machineCsrRef)/4).withRiscvRef()->noInstructionReadCheck()->run(10e4);) + redo(REDO,TestX28("../../cpp/raw/machineCsr/build/machineCsr",machineCsrRef, sizeof(machineCsrRef)/4).withRiscvRef()->run(10e4);) #else 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, 14,2, 15,5,16,17,1 }; - redo(REDO,TestX28("../../cpp/raw/machineCsr/build/machineCsrCompressed",machineCsrRef, sizeof(machineCsrRef)/4).withRiscvRef()->noInstructionReadCheck()->run(10e4);) + redo(REDO,TestX28("../../cpp/raw/machineCsr/build/machineCsrCompressed",machineCsrRef, sizeof(machineCsrRef)/4).withRiscvRef()->run(10e4);) #endif #endif // #ifdef MMU From b329ee85ad036255554f3869ae1cd50c5d3fbf08 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Thu, 11 Apr 2019 15:30:54 +0200 Subject: [PATCH 139/951] #60 Fix missing ecallGen flag --- src/main/scala/vexriscv/demo/Linux.scala | 6 +++--- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/scala/vexriscv/demo/Linux.scala b/src/main/scala/vexriscv/demo/Linux.scala index 5fa43309..d075725a 100644 --- a/src/main/scala/vexriscv/demo/Linux.scala +++ b/src/main/scala/vexriscv/demo/Linux.scala @@ -58,13 +58,13 @@ git clone https://github.com/SpinalHDL/buildroot.git -b vexriscv cd buildroot make spinal_vexriscv_sim_defconfig make -j$(nproc) -output/host/bin/riscv32-linux-objcopy -O binary output/images/vmlinux output/images/vmlinux.bin +output/host/bin/riscv32-linux-objcopy -O binary output/images/vmlinux output/images/Image After changing a kernel config into buildroot => cd buildroot make spinal_vexriscv_sim_defconfig make linux-dirclean linux-rebuild -j8 -output/host/bin/riscv32-linux-objcopy -O binary output/images/vmlinux output/images/vmlinux.bin +output/host/bin/riscv32-linux-objcopy -O binary output/images/vmlinux output/images/Image Compiling the machine mode emulator (check the config.h file to know the mode) => cd src/main/c/emulator @@ -92,7 +92,7 @@ export DATA=/home/miaou/Downloads/Binaries-master cd src/test/cpp/regression rm VexRiscv.v cp $DATA/VexRiscv.v ../../../.. -make run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD SUPERVISOR=yes CSR=yes COMPRESSED=yes REDO=0 DHRYSTONE=no LINUX_SOC=yes EMULATOR=$DATA/emulator.bin VMLINUX=$DATA/vmlinux.bin DTB=$DATA/rv32.dtb RAMDISK=$DATA/rootfs.cpio TRACE=no FLOW_INFO=no +make run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD SUPERVISOR=yes CSR=yes COMPRESSED=yess LRSC=yes AMO=yes REDO=0 DHRYSTONE=no LINUX_SOC=yes EMULATOR=$DATA/emulator.bin VMLINUX=$DATA/vmlinux.bin DTB=$DATA/rv32.dtb RAMDISK=$DATA/rootfs.cpio TRACE=no FLOW_INFO=no qemu-system-riscv32 -nographic -machine virt -m 1536M -device loader,file=$DATA/emulator.bin,addr=0x80000000,cpu-num=0 -device loader,file=$DATA/rv32.dtb,addr=0xC3000000 -device loader,file=$DATA/vmlinux.bin,addr=0xC0000000 -device loader,file=$DATA/rootfs.cpio,addr=0xc2000000 diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 635a5b80..c83e5d6a 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -96,7 +96,7 @@ object CsrPluginConfig{ minstretAccess = CsrAccess.NONE, ucycleAccess = CsrAccess.NONE, wfiGenAsWait = true, - ecallGen = false, + ecallGen = true, xtvecModeGen = false, noCsrAlu = false, wfiGenAsNop = false, From 63cd5f42aff00661f68c1139228ac1800af4ee14 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Fri, 12 Apr 2019 15:24:33 +0200 Subject: [PATCH 140/951] Fix #69 discoverd fmax issue with decode stage branch predictions --- src/main/scala/vexriscv/plugin/BranchPlugin.scala | 2 +- src/main/scala/vexriscv/plugin/Fetcher.scala | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/plugin/BranchPlugin.scala b/src/main/scala/vexriscv/plugin/BranchPlugin.scala index 0c1dd0ba..6885f2ae 100644 --- a/src/main/scala/vexriscv/plugin/BranchPlugin.scala +++ b/src/main/scala/vexriscv/plugin/BranchPlugin.scala @@ -268,7 +268,7 @@ class BranchPlugin(earlyBranch : Boolean, default{ branch_src1 := input(PC) branch_src2 := ((input(BRANCH_CTRL) === BranchCtrlEnum.JAL) ? imm.j_sext | imm.b_sext).asUInt - when(input(PREDICTION_HAD_BRANCHED) && ! missAlignedTarget){ + when(input(PREDICTION_HAD_BRANCHED)){ //Assume the predictor never predict missaligned stuff, this avoid the need to know if the instruction should branch or not branch_src2 := (if(pipeline(RVC_GEN)) Mux(input(IS_RVC), B(2), B(4)) else B(4)).asUInt.resized } } diff --git a/src/main/scala/vexriscv/plugin/Fetcher.scala b/src/main/scala/vexriscv/plugin/Fetcher.scala index 27a22e0c..4e0d8b41 100644 --- a/src/main/scala/vexriscv/plugin/Fetcher.scala +++ b/src/main/scala/vexriscv/plugin/Fetcher.scala @@ -488,6 +488,15 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, decodePrediction.cmd.hadBranch := decode.input(BRANCH_CTRL) === BranchCtrlEnum.JAL || (decode.input(BRANCH_CTRL) === BranchCtrlEnum.B && conditionalBranchPrediction) + val noPredictionOnMissaligned = (!pipeline(RVC_GEN)) generate new Area{ + val missaligned = decode.input(BRANCH_CTRL).mux( + BranchCtrlEnum.JALR -> (imm.i_sext(1) ^ decode.input(RS1)(1)), + BranchCtrlEnum.JAL -> imm.j_sext(1), + default -> imm.b_sext(1) + ) + decodePrediction.cmd.hadBranch clearWhen(missaligned) + } + predictionJumpInterface.valid := decodePrediction.cmd.hadBranch && decode.arbitration.isFiring //TODO OH Doublon de priorité predictionJumpInterface.payload := decode.input(PC) + ((decode.input(BRANCH_CTRL) === BranchCtrlEnum.JAL) ? imm.j_sext | imm.b_sext).asUInt From 41ff87f83b4d82b22723fef4b17f8f826823214f Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Fri, 12 Apr 2019 15:27:10 +0200 Subject: [PATCH 141/951] Remove jalr from decode branch prediction missaligned inibition --- src/main/scala/vexriscv/plugin/Fetcher.scala | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/scala/vexriscv/plugin/Fetcher.scala b/src/main/scala/vexriscv/plugin/Fetcher.scala index 4e0d8b41..6caac479 100644 --- a/src/main/scala/vexriscv/plugin/Fetcher.scala +++ b/src/main/scala/vexriscv/plugin/Fetcher.scala @@ -490,7 +490,6 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, val noPredictionOnMissaligned = (!pipeline(RVC_GEN)) generate new Area{ val missaligned = decode.input(BRANCH_CTRL).mux( - BranchCtrlEnum.JALR -> (imm.i_sext(1) ^ decode.input(RS1)(1)), BranchCtrlEnum.JAL -> imm.j_sext(1), default -> imm.b_sext(1) ) From 13b774b535626ea9ab469ad6029ca3f5cbb3e984 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Fri, 12 Apr 2019 15:56:22 +0200 Subject: [PATCH 142/951] #69 Relax address calculation of decode branch predictor by adding KEEP synthesis attribut --- src/main/scala/vexriscv/plugin/Fetcher.scala | 4 +++- src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala | 6 ++++-- src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala | 6 ++++-- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/Fetcher.scala b/src/main/scala/vexriscv/plugin/Fetcher.scala index 6caac479..d70a71a4 100644 --- a/src/main/scala/vexriscv/plugin/Fetcher.scala +++ b/src/main/scala/vexriscv/plugin/Fetcher.scala @@ -20,7 +20,8 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, val injectorReadyCutGen : Boolean, val prediction : BranchPrediction, val historyRamSizeLog2 : Int, - val injectorStage : Boolean) extends Plugin[VexRiscv] with JumpService with IBusFetcher{ + val injectorStage : Boolean, + val relaxPredictorAddress : Boolean) extends Plugin[VexRiscv] with JumpService with IBusFetcher{ var prefetchExceptionPort : Flow[ExceptionCause] = null var decodePrediction : DecodePredictionBus = null var fetchPrediction : FetchPredictionBus = null @@ -498,6 +499,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, predictionJumpInterface.valid := decodePrediction.cmd.hadBranch && decode.arbitration.isFiring //TODO OH Doublon de priorité predictionJumpInterface.payload := decode.input(PC) + ((decode.input(BRANCH_CTRL) === BranchCtrlEnum.JAL) ? imm.j_sext | imm.b_sext).asUInt + if(relaxPredictorAddress) KeepAttribute(predictionJumpInterface.payload) // when(predictionJumpInterface.payload((if(pipeline(RVC_GEN)) 0 else 1) downto 0) =/= 0){ // decodePrediction.cmd.hadBranch := False diff --git a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala index 03285f0f..d2fffc65 100644 --- a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala @@ -34,7 +34,8 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l, config : InstructionCacheConfig, memoryTranslatorPortConfig : Any = null, injectorStage : Boolean = false, - withoutInjectorStage : Boolean = false) extends IBusFetcherImpl( + withoutInjectorStage : Boolean = false, + relaxPredictorAddress : Boolean = true) extends IBusFetcherImpl( resetVector = resetVector, keepPcPlus4 = keepPcPlus4, decodePcGen = compressedGen, @@ -44,7 +45,8 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l, injectorReadyCutGen = false, prediction = prediction, historyRamSizeLog2 = historyRamSizeLog2, - injectorStage = (!config.twoCycleCache && !withoutInjectorStage) || injectorStage){ + injectorStage = (!config.twoCycleCache && !withoutInjectorStage) || injectorStage, + relaxPredictorAddress = relaxPredictorAddress){ import config._ assert(!(withoutInjectorStage && injectorStage)) diff --git a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala index 5d6ad0b1..8f0c909d 100644 --- a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala @@ -172,7 +172,8 @@ class IBusSimplePlugin(resetVector : BigInt, pendingMax : Int = 7, injectorStage : Boolean = true, rspHoldValue : Boolean = false, - singleInstructionPipeline : Boolean = false + singleInstructionPipeline : Boolean = false, + relaxPredictorAddress : Boolean = true ) extends IBusFetcherImpl( resetVector = resetVector, keepPcPlus4 = keepPcPlus4, @@ -183,7 +184,8 @@ class IBusSimplePlugin(resetVector : BigInt, injectorReadyCutGen = false, prediction = prediction, historyRamSizeLog2 = historyRamSizeLog2, - injectorStage = injectorStage){ + injectorStage = injectorStage, + relaxPredictorAddress = relaxPredictorAddress){ var iBus : IBusSimpleBus = null var decodeExceptionPort : Flow[ExceptionCause] = null From 8421328ee127587b7c6cda27530fe46d6ca799ff Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Fri, 12 Apr 2019 16:09:20 +0200 Subject: [PATCH 143/951] restore freertos tests --- src/test/cpp/regression/main.cpp | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 984d424b..8c3f6d62 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -2491,20 +2491,14 @@ string freeRtosTests[] = { // "test1","test1","test1","test1","test1","test1","test1","test1", // "test1","test1","test1","test1","test1","test1","test1","test1" -// "AltQTest", "AltBlock", "AltPollQ", "blocktim", "countsem", "dead", "EventGroupsDemo", "flop", "integer", "QPeek", -// "QueueSet", "recmutex", "semtest", "TaskNotify", "BlockQ", "crhook", "dynamic", -// "GenQTest", "PollQ", "QueueOverwrite", "QueueSetPolling", "sp_flop", "test1" + "AltQTest", "AltBlock", "AltPollQ", "blocktim", "countsem", "dead", "EventGroupsDemo", "flop", "integer", "QPeek", + "QueueSet", "recmutex", "semtest", "TaskNotify", "BlockQ", "crhook", "dynamic", + "GenQTest", "PollQ", "QueueOverwrite", "QueueSetPolling", "sp_flop", "test1" //"BlockQ","BlockQ","BlockQ","BlockQ","BlockQ","BlockQ","BlockQ","BlockQ" // "flop" // "flop", "sp_flop" // <- Simple test // "AltBlckQ" ??? - "TaskNotify","TaskNotify","TaskNotify","TaskNotify","TaskNotify","TaskNotify","TaskNotify","TaskNotify", - "TaskNotify","TaskNotify","TaskNotify","TaskNotify","TaskNotify","TaskNotify","TaskNotify","TaskNotify", - "TaskNotify","TaskNotify","TaskNotify","TaskNotify","TaskNotify","TaskNotify","TaskNotify","TaskNotify", - "TaskNotify","TaskNotify","TaskNotify","TaskNotify","TaskNotify","TaskNotify","TaskNotify","TaskNotify", - "TaskNotify","TaskNotify","TaskNotify","TaskNotify","TaskNotify","TaskNotify","TaskNotify","TaskNotify", - "TaskNotify","TaskNotify","TaskNotify","TaskNotify","TaskNotify","TaskNotify","TaskNotify","TaskNotify" }; @@ -2843,18 +2837,18 @@ int main(int argc, char **argv, char **env) { /*for(int redo = 0;redo < 4;redo++)*/{ for(const string &name : freeRtosTests){ -// tasks.push_back([=]() { Workspace(name + "_rv32i_O0").withRiscvRef()->loadHex("../../resources/freertos/" + name + "_rv32i_O0.hex")->bootAt(0x80000000u)->run(4e6*15);}); -// tasks.push_back([=]() { Workspace(name + "_rv32i_O3").withRiscvRef()->loadHex("../../resources/freertos/" + name + "_rv32i_O3.hex")->bootAt(0x80000000u)->run(4e6*15);}); + tasks.push_back([=]() { Workspace(name + "_rv32i_O0").withRiscvRef()->loadHex("../../resources/freertos/" + name + "_rv32i_O0.hex")->bootAt(0x80000000u)->run(4e6*15);}); + tasks.push_back([=]() { Workspace(name + "_rv32i_O3").withRiscvRef()->loadHex("../../resources/freertos/" + name + "_rv32i_O3.hex")->bootAt(0x80000000u)->run(4e6*15);}); #ifdef COMPRESSED // tasks.push_back([=]() { Workspace(name + "_rv32ic_O0").withRiscvRef()->loadHex("../../resources/freertos/" + name + "_rv32ic_O0.hex")->bootAt(0x80000000u)->run(5e6*15);}); -// tasks.push_back([=]() { Workspace(name + "_rv32ic_O3").withRiscvRef()->loadHex("../../resources/freertos/" + name + "_rv32ic_O3.hex")->bootAt(0x80000000u)->run(4e6*15);}); + tasks.push_back([=]() { Workspace(name + "_rv32ic_O3").withRiscvRef()->loadHex("../../resources/freertos/" + name + "_rv32ic_O3.hex")->bootAt(0x80000000u)->run(4e6*15);}); #endif #if defined(MUL) && defined(DIV) - #ifdef COMPRESSED - tasks.push_back([=]() { Workspace(name + "_rv32imac_O3").withRiscvRef()->loadHex("../../resources/freertos/" + name + "_rv32imac_O3.hex")->bootAt(0x80000000u)->run(4e6*15);}); - #else -// tasks.push_back([=]() { Workspace(name + "_rv32im_O3").withRiscvRef()->loadHex("../../resources/freertos/" + name + "_rv32im_O3.hex")->bootAt(0x80000000u)->run(4e6*15);}); - #endif +// #ifdef COMPRESSED +// tasks.push_back([=]() { Workspace(name + "_rv32imac_O3").withRiscvRef()->loadHex("../../resources/freertos/" + name + "_rv32imac_O3.hex")->bootAt(0x80000000u)->run(4e6*15);}); +// #else + tasks.push_back([=]() { Workspace(name + "_rv32im_O3").withRiscvRef()->loadHex("../../resources/freertos/" + name + "_rv32im_O3.hex")->bootAt(0x80000000u)->run(4e6*15);}); +// #endif #endif } } From 3301a1b3640febece00f45cd693c9c149d75c40c Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Fri, 12 Apr 2019 16:37:26 +0200 Subject: [PATCH 144/951] Add CsrPlugin.userGen option which now remove privilegeReg when not set --- README.md | 6 ++--- src/main/scala/vexriscv/demo/Linux.scala | 26 +++++++++++-------- .../scala/vexriscv/demo/SynthesisBench.scala | 17 ++++++------ .../scala/vexriscv/plugin/CsrPlugin.scala | 16 +++++++----- .../scala/vexriscv/plugin/SrcPlugin.scala | 2 +- 5 files changed, 37 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index 0a901cb0..1a3b9083 100644 --- a/README.md +++ b/README.md @@ -282,9 +282,9 @@ You can find some FPGA projects which instantiate the Briey SoC here (DE1-SoC, D Here are some measurements of Briey SoC timings and area : ``` - Artix 7 -> 239 Mhz 3227 LUT 3410 FF - Cyclone V -> 125 Mhz 2,207 ALMs - Cyclone IV -> 112 Mhz 4,594 LUT 3,620 + Artix 7 -> 233 Mhz 3035 LUT 3289 FF + Cyclone V -> 114 Mhz 2,073 ALMs + Cyclone IV -> 101 Mhz 4,279 LUT 3,167 FF ``` ## Murax SoC diff --git a/src/main/scala/vexriscv/demo/Linux.scala b/src/main/scala/vexriscv/demo/Linux.scala index d075725a..85fc2ed1 100644 --- a/src/main/scala/vexriscv/demo/Linux.scala +++ b/src/main/scala/vexriscv/demo/Linux.scala @@ -50,7 +50,7 @@ make run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD SUPERVISOR=yes CSR=yes COMPRE Run linux with QEMU (Require the machime mode emulator compiled in QEMU mode) export BUILDROOT=/home/miaou/pro/riscv/buildrootSpinal -qemu-system-riscv32 -nographic -machine virt -m 1536M -device loader,file=src/main/c/emulator/build/emulator.bin,addr=0x80000000,cpu-num=0 -device loader,file=$BUILDROOT/board/spinal/vexriscv_sim/rv32.dtb,addr=0xC3000000 -device loader,file=$BUILDROOT/output/images/vmlinux.bin,addr=0xC0000000 -device loader,file=$BUILDROOT/output/images/rootfs.cpio,addr=0xc2000000 +qemu-system-riscv32 -nographic -machine virt -m 1536M -device loader,file=src/main/c/emulator/build/emulator.bin,addr=0x80000000,cpu-num=0 -device loader,file=$BUILDROOT/board/spinal/vexriscv_sim/rv32.dtb,addr=0xC3000000 -device loader,file=$BUILDROOT/output/images/Image,addr=0xC0000000 -device loader,file=$BUILDROOT/output/images/rootfs.cpio,addr=0xc2000000 Buildroot => @@ -92,7 +92,7 @@ export DATA=/home/miaou/Downloads/Binaries-master cd src/test/cpp/regression rm VexRiscv.v cp $DATA/VexRiscv.v ../../../.. -make run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD SUPERVISOR=yes CSR=yes COMPRESSED=yess LRSC=yes AMO=yes REDO=0 DHRYSTONE=no LINUX_SOC=yes EMULATOR=$DATA/emulator.bin VMLINUX=$DATA/vmlinux.bin DTB=$DATA/rv32.dtb RAMDISK=$DATA/rootfs.cpio TRACE=no FLOW_INFO=no +make run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD SUPERVISOR=yes CSR=yes COMPRESSED=no LRSC=yes AMO=yes REDO=0 DHRYSTONE=no LINUX_SOC=yes EMULATOR=$DATA/emulator.bin VMLINUX=$DATA/vmlinux.bin DTB=$DATA/rv32.dtb RAMDISK=$DATA/rootfs.cpio TRACE=no FLOW_INFO=no qemu-system-riscv32 -nographic -machine virt -m 1536M -device loader,file=$DATA/emulator.bin,addr=0x80000000,cpu-num=0 -device loader,file=$DATA/rv32.dtb,addr=0xC3000000 -device loader,file=$DATA/vmlinux.bin,addr=0xC0000000 -device loader,file=$DATA/rootfs.cpio,addr=0xc2000000 @@ -106,19 +106,23 @@ program ../../../main/c/emulator/build/emulator.bin 0x80000000 verify soc.loadBin(RAMDISK, 0xC2000000); export BUILDROOT=/home/miaou/pro/riscv/buildrootSpinal -make run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD SUPERVISOR=yes CSR=yes COMPRESSED=yes LRSC=yes AMO=yes REDO=0 DHRYSTONE=no LINUX_SOC=yes +make run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD SUPERVISOR=yes CSR=yes COMPRESSED=no LRSC=yes AMO=yes REDO=0 DHRYSTONE=no LINUX_SOC=yes EMULATOR=../../../main/c/emulator/build/emulator.bin VMLINUX=/home/miaou/pro/riscv/buildrootSpinal/output/images/Image DTB=/home/miaou/pro/riscv/buildrootSpinal/board/spinal/vexriscv_sim/rv32.dtb RAMDISK=/home/miaou/pro/riscv/buildrootSpinal/output/images/rootfs.cpio TRACE=no FLOW_INFO=no -make run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD SUPERVISOR=yes CSR=yes COMPRESSED=yes LRSC=yes AMO=yes REDO=0 DHRYSTONE=no LINUX_SOC=yes DEBUG_PLUGIN_EXTERNAL=yes +make run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD SUPERVISOR=yes CSR=yes COMPRESSED=no LRSC=yes AMO=yes REDO=0 DHRYSTONE=no LINUX_SOC=yes DEBUG_PLUGIN_EXTERNAL=yes rm -rf cpio mkdir cpio cd cpio -ls | cpio -ov > ../rootfs.cpio cpio -idv < ../rootfs.cpio +cd .. + + +ls | cpio -ov > ../rootfs.cpio + */ @@ -147,12 +151,12 @@ object LinuxGen { new IBusCachedPlugin( resetVector = 0x80000000l, compressedGen = false, - prediction = NONE, + prediction = DYNAMIC_TARGET, injectorStage = false, config = InstructionCacheConfig( - cacheSize = 4096*1, + cacheSize = 4096*4, bytePerLine = 32, - wayCount = 1, + wayCount = 4, addressWidth = 32, cpuDataWidth = 32, memDataWidth = 32, @@ -182,9 +186,9 @@ object LinuxGen { dBusCmdSlavePipe = true, dBusRspSlavePipe = true, config = new DataCacheConfig( - cacheSize = 4096*1, + cacheSize = 4096*4, bytePerLine = 32, - wayCount = 1, + wayCount = 4, addressWidth = 32, cpuDataWidth = 32, memDataWidth = 32, @@ -404,7 +408,7 @@ object LinuxSyntesisBench extends App{ SpinalConfig(inlineRom=true).generateVerilog(new VexRiscv(LinuxGen.configFull(litex = false, withMmu = true)).setDefinitionName(getRtlPath().split("\\.").head)) } - val rtls = List(/*withoutMmu, */withMmu) + val rtls = List(withoutMmu,withMmu) // val rtls = List(smallestNoCsr, smallest, smallAndProductive, smallAndProductiveWithICache) // val rtls = List(smallAndProductive, smallAndProductiveWithICache, fullNoMmuMaxPerf, fullNoMmu, full) // val rtls = List(fullNoMmu) diff --git a/src/main/scala/vexriscv/demo/SynthesisBench.scala b/src/main/scala/vexriscv/demo/SynthesisBench.scala index 29ee27e5..7976ac08 100644 --- a/src/main/scala/vexriscv/demo/SynthesisBench.scala +++ b/src/main/scala/vexriscv/demo/SynthesisBench.scala @@ -135,13 +135,13 @@ object BrieySynthesisBench { val rtls = List(briey) val targets = XilinxStdTargets( - vivadoArtix7Path = "/eda/Xilinx/Vivado/2017.2/bin" + vivadoArtix7Path = "/media/miaou/HD/linux/Xilinx/Vivado/2018.3/bin" ) ++ AlteraStdTargets( - quartusCycloneIVPath = "/eda/intelFPGA_lite/17.0/quartus/bin/", - quartusCycloneVPath = "/eda/intelFPGA_lite/17.0/quartus/bin/" + quartusCycloneIVPath = "/media/miaou/HD/linux/intelFPGA_lite/18.1/quartus/bin", + quartusCycloneVPath = "/media/miaou/HD/linux/intelFPGA_lite/18.1/quartus/bin" ) - Bench(rtls, targets, "/eda/tmp/") + Bench(rtls, targets, "/media/miaou/HD/linux/tmp") } } @@ -174,14 +174,13 @@ object MuraxSynthesisBench { val rtls = List(murax, muraxFast) val targets = IcestormStdTargets().take(1) ++ XilinxStdTargets( - vivadoArtix7Path = "/eda/Xilinx/Vivado/2017.2/bin" + vivadoArtix7Path = "/media/miaou/HD/linux/Xilinx/Vivado/2018.3/bin" ) ++ AlteraStdTargets( - quartusCycloneIVPath = "/eda/intelFPGA_lite/17.0/quartus/bin/", - quartusCycloneVPath = "/eda/intelFPGA_lite/17.0/quartus/bin/" + quartusCycloneIVPath = "/media/miaou/HD/linux/intelFPGA_lite/18.1/quartus/bin", + quartusCycloneVPath = "/media/miaou/HD/linux/intelFPGA_lite/18.1/quartus/bin" ) - - Bench(rtls, targets, "/eda/tmp/") + Bench(rtls, targets, "/media/miaou/HD/linux/tmp") } } diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index c83e5d6a..5b1a6fc2 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -55,6 +55,7 @@ case class CsrPluginConfig( noCsrAlu : Boolean = false, wfiGenAsNop : Boolean = false, ebreakGen : Boolean = false, + userGen : Boolean = false, supervisorGen : Boolean = false, sscratchGen : Boolean = false, stvecAccess : CsrAccess = CsrAccess.NONE, @@ -70,7 +71,7 @@ case class CsrPluginConfig( deterministicInteruptionEntry : Boolean = false //Only used for simulatation purposes ){ assert(!ucycleAccess.canWrite) - + def privilegeGen = userGen || supervisorGen def noException = this.copy(ecallGen = false, ebreakGen = false, catchIllegalAccess = false) } @@ -101,6 +102,7 @@ object CsrPluginConfig{ noCsrAlu = false, wfiGenAsNop = false, ebreakGen = true, + userGen = true, supervisorGen = true, sscratchGen = true, stvecAccess = CsrAccess.READ_WRITE, @@ -140,6 +142,7 @@ object CsrPluginConfig{ noCsrAlu = false, wfiGenAsNop = false, ebreakGen = true, + userGen = true, supervisorGen = true, sscratchGen = true, stvecAccess = CsrAccess.READ_WRITE, @@ -473,8 +476,9 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception val base = UInt(xlen-2 bits) } - val privilegeReg = RegInit(U"11") - privilege := privilegeReg + val privilegeReg = privilegeGen generate RegInit(U"11") + privilege := (if(privilegeGen) privilegeReg else U"11") + when(forceMachineWire) { privilege := 3 } val machineCsr = pipeline plug new Area{ @@ -798,7 +802,7 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception jumpInterface.payload := (if(!xtvecModeGen) xtvec.base @@ "00" else (xtvec.mode === 0 || hadException) ? (xtvec.base @@ "00") | ((xtvec.base + trapCause) @@ "00") ) beforeLastStage.arbitration.flushAll := True - privilegeReg := targetPrivilege + if(privilegeGen) privilegeReg := targetPrivilege switch(targetPrivilege){ if(supervisorGen) is(1) { @@ -841,15 +845,15 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception mstatus.MPP := U"00" mstatus.MIE := mstatus.MPIE mstatus.MPIE := True - privilegeReg := mstatus.MPP jumpInterface.payload := mepc + if(privilegeGen) privilegeReg := mstatus.MPP } if(supervisorGen) is(1){ sstatus.SPP := U"0" sstatus.SIE := sstatus.SPIE sstatus.SPIE := True - privilegeReg := U"0" @@ sstatus.SPP jumpInterface.payload := sepc + if(privilegeGen) privilegeReg := U"0" @@ sstatus.SPP } } } diff --git a/src/main/scala/vexriscv/plugin/SrcPlugin.scala b/src/main/scala/vexriscv/plugin/SrcPlugin.scala index 79bc763b..9085ed1f 100644 --- a/src/main/scala/vexriscv/plugin/SrcPlugin.scala +++ b/src/main/scala/vexriscv/plugin/SrcPlugin.scala @@ -64,7 +64,7 @@ class SrcPlugin(separatedAddSub : Boolean = false, executeInsertion : Boolean = import addSubStage._ // ADD, SUB - val addSub = (input(SRC1).asSInt + Mux(input(SRC_USE_SUB_LESS), ~input(SRC2), input(SRC2)).asSInt + Mux(input(SRC_USE_SUB_LESS), S(1), S(0))).asBits + val addSub = (input(SRC1).asSInt + Mux(input(SRC_USE_SUB_LESS), ~input(SRC2), input(SRC2)).asSInt + Mux(input(SRC_USE_SUB_LESS), S(1, 32 bits), S(0, 32 bits))).asBits when(input(SRC2_FORCE_ZERO)){ addSub := input(SRC1) } From a12ca43284eba978b42b54e49077a39c6b32b447 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Fri, 12 Apr 2019 17:41:15 +0200 Subject: [PATCH 145/951] README.md Update eclipse install --- README.md | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 1a3b9083..3476e36a 100644 --- a/README.md +++ b/README.md @@ -223,7 +223,19 @@ continue ## Using Eclipse to run the software and debug it -### By using Zylin plugin +### By using gnu-mcu-eclipse + +You can download releases of the IDE here : https://github.com/gnu-mcu-eclipse/org.eclipse.epp.packages/releases + +In the IDE, you can import a makefile project by : +- file -> import -> C/C++ -> existing Code as Makefile Project +- Select the folder which contain the makefile, select Cross GCC + +To create a new debug configuration : +- run -> Debug Configurations -> GDB OpenOCD Debugging double click +- Look at https://drive.google.com/open?id=1c46tyEV0xLwOsk76b0y2qqs8CYy7Zq3f for a configuration example + +### By using Zylin plugin (old) You can use the Eclipse + Zylin embedded CDT plugin to do it (http://opensource.zylin.com/embeddedcdt.html). Tested with Helios Service Release 2 (http://www.Eclipse.org/downloads/download.php?file=/technology/epp/downloads/release/helios/SR2/Eclipse-cpp-helios-SR2-linux-gtk-x86_64.tar.gz) and the corresponding zylin plugin. To following commands will download Eclipse and install the plugin. @@ -238,13 +250,6 @@ See https://drive.google.com/drive/folders/1NseNHH05B6lmIXqQFVwK8xRjWE4ydeG-?usp Note that sometime this Eclipse need to be restarted in order to be able to place new breakpoints. -### By using FreedomStudio - -You can get FreedomStudio (which is package with Eclipse and some plugins) here: https://www.sifive.com/products/tools/ - -See https://drive.google.com/drive/folders/1a7FyMOYgFc9UDhfsWUSCjyqDCvOrts2J?usp=sharing to import a makefile project and create a debug configuration. - - ## Briey SoC As a demonstrator, a SoC named Briey is implemented in `src/main/scala/vexriscv/demo/Briey.scala`. This SoC is very similar to the [Pinsec SOC](https://spinalhdl.github.io/SpinalDoc/spinal/lib/pinsec/hardware/): From 9ac1d3d59eec26ff6a2904b3dc845d00d3926412 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Sat, 13 Apr 2019 10:40:53 +0200 Subject: [PATCH 146/951] riscv software model without RVC now trap on RVC instruction before pcWrite + 2 --- src/test/cpp/regression/main.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 4cddfe78..d42f56c4 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -957,6 +957,9 @@ public: default: ilegalInstruction(); break; } } else { + #ifndef COMPRESSED + ilegalInstruction(); return; + #endif switch((iBits(0, 2) << 3) + iBits(13, 3)){ case 0: rfWrite(i16_addr2, rf_sp + i16_addi4spn_imm); pcWrite(pc + 2); break; case 2: { From 5d1ec604b2527c9155d9e1aab48f05064039499c Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Sat, 13 Apr 2019 10:41:15 +0200 Subject: [PATCH 147/951] Make regression sim great again --- src/test/cpp/regression/makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/cpp/regression/makefile b/src/test/cpp/regression/makefile index 1ffc036d..d82a3e47 100644 --- a/src/test/cpp/regression/makefile +++ b/src/test/cpp/regression/makefile @@ -43,7 +43,7 @@ ADDCFLAGS += -CFLAGS -pthread ADDCFLAGS += -CFLAGS -DTHREAD_COUNT=${THREAD_COUNT} ifeq ($(DEBUG),yes) - ADDCFLAGS += -CFLAGS -Og -CFLAGS -g + ADDCFLAGS += -CFLAGS -O0 -CFLAGS -g else ADDCFLAGS += -CFLAGS -O3 -O3 endif From 61d25e931e45dc00a5e497a7e4c7619e20ac1c7f Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Sat, 13 Apr 2019 10:44:06 +0200 Subject: [PATCH 148/951] #60 Add sim error message on RVC instruction without RVC capabilities --- src/test/cpp/regression/main.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index d42f56c4..518f30ce 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -958,6 +958,7 @@ public: } } else { #ifndef COMPRESSED + cout << "ERROR : RiscvGolden got a RVC instruction while the CPU isn't RVC ready" << endl; ilegalInstruction(); return; #endif switch((iBits(0, 2) << 3) + iBits(13, 3)){ From 8c7407967eee7d394c827134be3945edf30b3f08 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Sun, 14 Apr 2019 23:04:30 +0200 Subject: [PATCH 149/951] Fix non RVC fetcher exception PC capture --- src/main/scala/vexriscv/plugin/Fetcher.scala | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/Fetcher.scala b/src/main/scala/vexriscv/plugin/Fetcher.scala index 21c90901..62d4aa79 100644 --- a/src/main/scala/vexriscv/plugin/Fetcher.scala +++ b/src/main/scala/vexriscv/plugin/Fetcher.scala @@ -285,7 +285,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, bufferData := input.rsp.inst(31 downto 16) } bufferValid.clearWhen(flush) - iBusRsp.readyForError.clearWhen(bufferValid && isRvc) + iBusRsp.readyForError.clearWhen(bufferValid && isRvc) //Can't emit error, as there is a earlier instruction pending incomingInstruction setWhen(bufferValid && bufferData(1 downto 0) =/= 3) }) @@ -294,19 +294,21 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, val injector = new Area { val inputBeforeStage = condApply(if (decodePcGen) decompressor.output else iBusRsp.output, injectorReadyCutGen)(_.s2mPipe(flush)) if (injectorReadyCutGen) { - iBusRsp.readyForError.clearWhen(inputBeforeStage.valid) + iBusRsp.readyForError.clearWhen(inputBeforeStage.valid) //Can't emit error if there is a instruction pending in the s2mPipe incomingInstruction setWhen (inputBeforeStage.valid) } val decodeInput = (if (injectorStage) { val decodeInput = inputBeforeStage.m2sPipeWithFlush(flush, collapsBubble = false) decode.insert(INSTRUCTION_ANTICIPATED) := Mux(decode.arbitration.isStuck, decode.input(INSTRUCTION), inputBeforeStage.rsp.inst) - iBusRsp.readyForError.clearWhen(decodeInput.valid) + iBusRsp.readyForError.clearWhen(decodeInput.valid) //Can't emit error when there is a instruction pending in the injector stage buffer incomingInstruction setWhen (decodeInput.valid) decodeInput } else { inputBeforeStage }) + if(!decodePcGen) iBusRsp.readyForError.clearWhen(!pcValid(decode)) //Need to wait a valid PC on the decode stage, as it is use to fill CSR xEPC + def pcUpdatedGen(input : Bool, stucks : Seq[Bool], relaxedInput : Boolean) : Seq[Bool] = { stucks.scanLeft(input)((i, stuck) => { From 6f04c02cd25a88ba997ea0dd50fb9d848b933e4e Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Sun, 14 Apr 2019 23:06:04 +0200 Subject: [PATCH 150/951] TestInduvidualFeatures now use the linux config + MMU --- README.md | 2 +- src/main/scala/vexriscv/demo/Linux.scala | 2 - .../scala/vexriscv/plugin/CsrPlugin.scala | 2 +- src/test/cpp/regression/fail.gtkw | 40 +++------- .../vexriscv/TestIndividualFeatures.scala | 76 ++++++++++++++----- 5 files changed, 71 insertions(+), 51 deletions(-) diff --git a/README.md b/README.md index 3476e36a..4ac9b680 100644 --- a/README.md +++ b/README.md @@ -229,7 +229,7 @@ You can download releases of the IDE here : https://github.com/gnu-mcu-eclipse/o In the IDE, you can import a makefile project by : - file -> import -> C/C++ -> existing Code as Makefile Project -- Select the folder which contain the makefile, select Cross GCC +- Select the folder which contain the makefile, select "Cross GCC" (not "RISC-V Cross GCC") To create a new debug configuration : - run -> Debug Configurations -> GDB OpenOCD Debugging double click diff --git a/src/main/scala/vexriscv/demo/Linux.scala b/src/main/scala/vexriscv/demo/Linux.scala index 85fc2ed1..fe60056b 100644 --- a/src/main/scala/vexriscv/demo/Linux.scala +++ b/src/main/scala/vexriscv/demo/Linux.scala @@ -121,8 +121,6 @@ cpio -idv < ../rootfs.cpio cd .. -ls | cpio -ov > ../rootfs.cpio - */ diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 5b1a6fc2..8057071b 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -141,7 +141,7 @@ object CsrPluginConfig{ xtvecModeGen = false, noCsrAlu = false, wfiGenAsNop = false, - ebreakGen = true, + ebreakGen = false, userGen = true, supervisorGen = true, sscratchGen = true, diff --git a/src/test/cpp/regression/fail.gtkw b/src/test/cpp/regression/fail.gtkw index be474029..2f3ba231 100644 --- a/src/test/cpp/regression/fail.gtkw +++ b/src/test/cpp/regression/fail.gtkw @@ -1,14 +1,14 @@ [*] [*] GTKWave Analyzer v3.3.100 (w)1999-2019 BSI -[*] Mon Apr 1 21:53:07 2019 +[*] Sun Apr 14 19:28:23 2019 [*] -[dumpfile] "/home/miaou/pro/VexRiscv/src/test/cpp/regression/rv32ui-p-lw.vcd" -[dumpfile_mtime] "Mon Apr 1 21:52:20 2019" -[dumpfile_size] 1974526 +[dumpfile] "/home/miaou/pro/VexRiscv/src/test/cpp/regression/mmu.vcd" +[dumpfile_mtime] "Sun Apr 14 19:27:24 2019" +[dumpfile_size] 1551340 [savefile] "/home/miaou/pro/VexRiscv/src/test/cpp/regression/fail.gtkw" [timestart] 348 [size] 1920 1030 -[pos] -1 -1 +[pos] -458 -215 *-2.000000 357 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 [treeopen] TOP. [treeopen] TOP.VexRiscv. @@ -25,33 +25,15 @@ TOP.VexRiscv.writeBack_RegFilePlugin_regFileWrite_payload_address[4:0] TOP.VexRiscv.writeBack_RegFilePlugin_regFileWrite_payload_data[31:0] @28 TOP.VexRiscv.writeBack_RegFilePlugin_regFileWrite_valid -[color] 1 -TOP.VexRiscv.dataCache_1_.io_mem_cmd_valid -[color] 1 -TOP.VexRiscv.dataCache_1_.io_mem_cmd_ready -@22 -[color] 1 -TOP.VexRiscv.dataCache_1_.io_mem_cmd_payload_address[31:0] -[color] 1 -TOP.VexRiscv.dataCache_1_.io_mem_cmd_payload_data[31:0] +@29 +TOP.VexRiscv.CsrPlugin_interrupt @28 -[color] 1 -TOP.VexRiscv.dataCache_1_.io_mem_cmd_payload_last -[color] 1 -TOP.VexRiscv.dataCache_1_.io_mem_cmd_payload_length[2:0] +TOP.VexRiscv.CsrPlugin_exception @22 -[color] 1 -TOP.VexRiscv.dataCache_1_.io_mem_cmd_payload_mask[3:0] +TOP.VexRiscv.CsrPlugin_mcause_exceptionCode[3:0] @28 -[color] 1 -TOP.VexRiscv.dataCache_1_.io_mem_cmd_payload_wr -[color] 1 -TOP.VexRiscv.dataCache_1_.io_mem_rsp_valid +TOP.VexRiscv.CsrPlugin_mcause_interrupt @22 -[color] 1 -TOP.VexRiscv.dataCache_1_.io_mem_rsp_payload_data[31:0] -@28 -[color] 1 -TOP.VexRiscv.dataCache_1_.io_mem_rsp_payload_error +TOP.VexRiscv.CsrPlugin_mepc[31:0] [pattern_trace] 1 [pattern_trace] 0 diff --git a/src/test/scala/vexriscv/TestIndividualFeatures.scala b/src/test/scala/vexriscv/TestIndividualFeatures.scala index d57f9bd4..5275cfa8 100644 --- a/src/test/scala/vexriscv/TestIndividualFeatures.scala +++ b/src/test/scala/vexriscv/TestIndividualFeatures.scala @@ -260,6 +260,9 @@ class IBusDimension extends VexRiscvDimension("IBus") { override def randomPositionImpl(universes: Seq[ConfigUniverse], r: Random) = { + val catchAll = universes.contains(VexRiscvUniverse.CATCH_ALL) + val mmuConfig = if(catchAll) MmuPortConfig( portTlbSize = 4) else null + if(r.nextDouble() < 0.5){ val latency = r.nextInt(5) + 1 val compressed = r.nextBoolean() @@ -278,7 +281,8 @@ class IBusDimension extends VexRiscvDimension("IBus") { catchAccessFault = catchAll, compressedGen = compressed, busLatencyMin = latency, - injectorStage = injectorStage + injectorStage = injectorStage, + memoryTranslatorPortConfig = mmuConfig ) override def instructionAnticipatedOk() = injectorStage } @@ -295,7 +299,7 @@ class IBusDimension extends VexRiscvDimension("IBus") { do{ cacheSize = 512 << r.nextInt(5) wayCount = 1 << r.nextInt(3) - }while(cacheSize/wayCount < 512) + }while(cacheSize/wayCount < 512 || (catchAll && cacheSize/wayCount > 4096)) new VexRiscvPosition("Cached" + (if(twoCycleCache) "2cc" else "") + (if(injectorStage) "Injstage" else "") + (if(twoCycleRam) "2cr" else "") + "S" + cacheSize + "W" + wayCount + (if(relaxedPcCalculation) "Relax" else "") + (if(compressed) "Rvc" else "") + prediction.getClass.getTypeName().replace("$","")+ (if(tighlyCoupled)"Tc" else "")) with InstructionAnticipatedPosition{ override def testParam = "IBUS=CACHED" + (if(compressed) " COMPRESSED=yes" else "") + (if(tighlyCoupled)" IBUS_TC=yes" else "") @@ -306,6 +310,7 @@ class IBusDimension extends VexRiscvDimension("IBus") { prediction = prediction, relaxedPcCalculation = relaxedPcCalculation, injectorStage = injectorStage, + memoryTranslatorPortConfig = mmuConfig, config = InstructionCacheConfig( cacheSize = cacheSize, bytePerLine = 32, @@ -335,22 +340,28 @@ class IBusDimension extends VexRiscvDimension("IBus") { class DBusDimension extends VexRiscvDimension("DBus") { override def randomPositionImpl(universes: Seq[ConfigUniverse], r: Random) = { + val catchAll = universes.contains(VexRiscvUniverse.CATCH_ALL) + val mmuConfig = if(catchAll) MmuPortConfig( portTlbSize = 4) else null + if(r.nextDouble() < 0.4){ - val catchAll = universes.contains(VexRiscvUniverse.CATCH_ALL) val earlyInjection = r.nextBoolean() new VexRiscvPosition("Simple" + (if(earlyInjection) "Early" else "Late")) { override def testParam = "DBUS=SIMPLE" override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new DBusSimplePlugin( catchAddressMisaligned = catchAll, catchAccessFault = catchAll, - earlyInjection = earlyInjection + earlyInjection = earlyInjection, + memoryTranslatorPortConfig = mmuConfig ) // override def isCompatibleWith(positions: Seq[ConfigPosition[VexRiscvConfig]]) = catchAll == positions.exists(_.isInstanceOf[CatchAllPosition]) } } else { - val cacheSize = 512 << r.nextInt(5) - val wayCount = 1 - val catchAll = universes.contains(VexRiscvUniverse.CATCH_ALL) + var cacheSize = 0 + var wayCount = 0 + do{ + cacheSize = 512 << r.nextInt(5) + wayCount = 1 << r.nextInt(3) + }while(cacheSize/wayCount < 512 || (catchAll && cacheSize/wayCount > 4096)) new VexRiscvPosition("Cached" + "S" + cacheSize + "W" + wayCount) { override def testParam = "DBUS=CACHED" @@ -368,8 +379,35 @@ class DBusDimension extends VexRiscvDimension("DBus") { catchUnaligned = catchAll, withLrSc = false ), - memoryTranslatorPortConfig = null + memoryTranslatorPortConfig = mmuConfig ) + } + } + } + } +} + + +class MmuDimension extends VexRiscvDimension("DBus") { + + override def randomPositionImpl(universes: Seq[ConfigUniverse], r: Random) = { + + val catchAll = universes.contains(VexRiscvUniverse.CATCH_ALL) + if(catchAll) { + new VexRiscvPosition("WithMmu") { + override def testParam = "MMU=yes" + + override def applyOn(config: VexRiscvConfig): Unit = { + config.plugins += new MmuPlugin( + ioRange = (x => x(31 downto 28) === 0xF) + ) + } + } + } else { + new VexRiscvPosition("NoMmu") { + override def testParam = "MMU=no" + + override def applyOn(config: VexRiscvConfig): Unit = { config.plugins += new StaticMemoryTranslatorPlugin( ioRange = _ (31 downto 28) === 0xF ) @@ -389,7 +427,7 @@ class CsrDimension(freertos : String) extends VexRiscvDimension("Csr") { val catchAll = universes.contains(VexRiscvUniverse.CATCH_ALL) if(catchAll){ new VexRiscvPosition("All") with CatchAllPosition{ - override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new CsrPlugin(CsrPluginConfig.all(0x80000020l)) + override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new CsrPlugin(CsrPluginConfig.linuxFull(0x80000020l)) override def testParam = s"FREERTOS=$freertos" } } else if(r.nextDouble() < 0.2){ @@ -468,7 +506,8 @@ class TestIndividualFeatures extends FunSuite { new SrcDimension, new CsrDimension(sys.env.getOrElse("VEXRISCV_REGRESSION_FREERTOS_COUNT", "yes")), new DecoderDimension, - new DebugDimension + new DebugDimension, + new MmuDimension ) @@ -503,13 +542,13 @@ class TestIndividualFeatures extends FunSuite { test(prefix + name + "_test") { val debug = false - val stdCmd = (if(debug) "make clean run REDO=1 TRACE=yes TRACE_ACCESS=yes MMU=no STOP_ON_ERROR=yes DHRYSTONE=no THREAD_COUNT=1 TRACE_START=0 " else s"make clean run REDO=10 TRACE=no MMU=no THREAD_COUNT=${sys.env.getOrElse("VEXRISCV_REGRESSION_THREAD_COUNT", Runtime.getRuntime().availableProcessors().toString)} ") + s" SEED=${testSeed} " -// val stdCmd = "make clean run REDO=40 DHRYSTONE=no STOP_ON_ERROR=yes TRACE=yess MMU=no" + val stdCmd = (if(debug) "make clean run REDO=1 TRACE=yes TRACE_ACCESS=yes STOP_ON_ERROR=yes DHRYSTONE=no THREAD_COUNT=1 TRACE_START=0 " else s"make clean run REDO=10 TRACE=no THREAD_COUNT=${sys.env.getOrElse("VEXRISCV_REGRESSION_THREAD_COUNT", Runtime.getRuntime().availableProcessors().toString)} ") + s" SEED=${testSeed} " +// val stdCmd = "make clean run REDO=40 DHRYSTONE=no STOP_ON_ERROR=yes TRACE=yess " val testCmd = stdCmd + (positionsToApply).map(_.testParam).mkString(" ") println(testCmd) val str = doCmd(testCmd) - assert(!str.contains("FAIL")) + assert(!str.contains("FAIL") && !str.contains("Broken pipe")) // val intFind = "(\\d+\\.?)+".r // val dmips = intFind.findFirstIn("DMIPS per Mhz\\: (\\d+.?)+".r.findAllIn(str).toList.last).get.toDouble } @@ -517,8 +556,8 @@ class TestIndividualFeatures extends FunSuite { // dimensions.foreach(d => d.positions.foreach(p => p.dimension = d)) - val testId : Option[mutable.HashSet[Int]] = None - val seed = Random.nextLong() +// val testId : Option[mutable.HashSet[Int]] = None +// val seed = Random.nextLong() // val testId = Some(mutable.HashSet(18,34,77,85,118,129,132,134,152,167,175,188,191,198,199)) //37/29 sp_flop_rv32i_O3 //val testId = Some(mutable.HashSet(18)) @@ -526,9 +565,10 @@ class TestIndividualFeatures extends FunSuite { // val seed = -2412372746600605141l -// val testId = Some(mutable.HashSet[Int](0,28,45,93)) -// val testId = Some(mutable.HashSet[Int](31)) -// val seed = -7716775349351274630l +//// val testId = Some(mutable.HashSet[Int](0,28,45,93)) + val testId = Some(mutable.HashSet[Int](69, 43)) +//val testId = Some(mutable.HashSet[Int]( 43)) + val seed = -8485282932516819277l From d2b324e32bf88713e27257c191976e772db3cd48 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 15 Apr 2019 11:01:51 +0200 Subject: [PATCH 151/951] Add jtag and vhdl option --- ...te3ForSim.scala => VexRiscvAhbLite3.scala} | 23 ++++++++----------- 1 file changed, 10 insertions(+), 13 deletions(-) rename src/main/scala/vexriscv/demo/{VexRiscvAhbLite3ForSim.scala => VexRiscvAhbLite3.scala} (88%) diff --git a/src/main/scala/vexriscv/demo/VexRiscvAhbLite3ForSim.scala b/src/main/scala/vexriscv/demo/VexRiscvAhbLite3.scala similarity index 88% rename from src/main/scala/vexriscv/demo/VexRiscvAhbLite3ForSim.scala rename to src/main/scala/vexriscv/demo/VexRiscvAhbLite3.scala index d11994b3..593d399d 100644 --- a/src/main/scala/vexriscv/demo/VexRiscvAhbLite3ForSim.scala +++ b/src/main/scala/vexriscv/demo/VexRiscvAhbLite3.scala @@ -1,8 +1,10 @@ package vexriscv.demo + import spinal.core._ import spinal.lib._ import spinal.lib.bus.avalon.AvalonMM +import spinal.lib.com.jtag.Jtag import spinal.lib.eda.altera.{InterruptReceiverTag, QSysify, ResetEmitterTag} import vexriscv.ip.{DataCacheConfig, InstructionCacheConfig} import vexriscv.plugin._ @@ -15,11 +17,11 @@ import vexriscv.{VexRiscv, VexRiscvConfig, plugin} // //} -//make clean run DBUS=CACHED_AVALON IBUS=CACHED_AVALON MMU=no CSR=no DEBUG_PLUGIN=AVALON +//make clean run DBUS=SIMPLE_AHBLITE3 IBUS=SIMPLE_AHBLITE3 MMU=no CSR=no DEBUG_PLUGIN=STD -object VexRiscvAhbLite3ForSim{ +object VexRiscvAhbLite3{ def main(args: Array[String]) { - val report = SpinalVerilog{ + val report = SpinalConfig(mode = if(args.contains("--vhdl")) VHDL else Verilog).generate{ //CPU configuration val cpuConfig = VexRiscvConfig( @@ -157,16 +159,11 @@ object VexRiscvAhbLite3ForSim{ // .setName("dBusAvalon") // .addTag(ClockDomainTag(ClockDomain.current)) // } -// case plugin: DebugPlugin => plugin.debugClockDomain { -// plugin.io.bus.setAsDirectionLess() -// slave(plugin.io.bus.fromAvalon()) -// .setName("debugBusAvalon") -// .addTag(ClockDomainTag(plugin.debugClockDomain)) -// .parent = null //Avoid the io bundle to be interpreted as a QSys conduit -// plugin.io.resetOut -// .addTag(ResetEmitterTag(plugin.debugClockDomain)) -// .parent = null //Avoid the io bundle to be interpreted as a QSys conduit -// } + case plugin: DebugPlugin if args.contains("--jtag")=> plugin.debugClockDomain { + plugin.io.bus.setAsDirectionLess() + val jtag = slave(new Jtag()).setName("jtag") + jtag <> plugin.io.bus.fromJtag() + } case _ => } } From b79b02152b735bbbd4fafd4ebd2cb126457d0248 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Thu, 18 Apr 2019 18:33:06 +0200 Subject: [PATCH 152/951] #60 Fix SFENCE_VMA deadlock --- src/main/scala/vexriscv/plugin/MmuPlugin.scala | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/MmuPlugin.scala b/src/main/scala/vexriscv/plugin/MmuPlugin.scala index a243484b..f8a34183 100644 --- a/src/main/scala/vexriscv/plugin/MmuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/MmuPlugin.scala @@ -253,10 +253,9 @@ class MmuPlugin(ioRange : UInt => Bool, } } - execute plug new Area{ - import execute._ - val tlbWriteBuffer = Reg(UInt(20 bits)) - when(arbitration.isFiring && input(IS_SFENCE_VMA)){ // || csrService.isWriting(CSR.SATP) + writeBack plug new Area{ + import writeBack._ + when(arbitration.isValid && input(IS_SFENCE_VMA)){ // || csrService.isWriting(CSR.SATP) for(port <- core.ports; line <- port.cache) line.valid := False //Assume that the instruction already fetched into the pipeline are ok } } From 2810ff05b096a1780262f3bd7740ce06eaeacc37 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Fri, 19 Apr 2019 02:31:39 +0200 Subject: [PATCH 153/951] Fix emulator instruction emulation trap redirection to supervisor. Impact only AMO less configs --- src/main/c/emulator/build/emulator.asm | 774 +++++++++++++------------ src/main/c/emulator/build/emulator.bin | Bin 2344 -> 2440 bytes src/main/c/emulator/build/emulator.hex | 232 ++++---- src/main/c/emulator/src/main.c | 10 +- 4 files changed, 524 insertions(+), 492 deletions(-) diff --git a/src/main/c/emulator/build/emulator.asm b/src/main/c/emulator/build/emulator.asm index 38d2e999..5e5dfe26 100644 --- a/src/main/c/emulator/build/emulator.asm +++ b/src/main/c/emulator/build/emulator.asm @@ -6,13 +6,13 @@ Disassembly of section .init: 80000000 <_start>: 80000000: 00001117 auipc sp,0x1 -80000004: 12810113 addi sp,sp,296 # 80001128 <_sp> +80000004: 18810113 addi sp,sp,392 # 80001188 <_sp> 80000008: 00001517 auipc a0,0x1 -8000000c: 87c50513 addi a0,a0,-1924 # 80000884 <__init_array_end> +8000000c: 8dc50513 addi a0,a0,-1828 # 800008e4 <__init_array_end> 80000010: 00001597 auipc a1,0x1 -80000014: 87458593 addi a1,a1,-1932 # 80000884 <__init_array_end> +80000014: 8d458593 addi a1,a1,-1836 # 800008e4 <__init_array_end> 80000018: 00001617 auipc a2,0x1 -8000001c: 91060613 addi a2,a2,-1776 # 80000928 <__bss_start> +8000001c: 97060613 addi a2,a2,-1680 # 80000988 <__bss_start> 80000020: 00c5fc63 bgeu a1,a2,80000038 <_start+0x38> 80000024: 00052283 lw t0,0(a0) 80000028: 0055a023 sw t0,0(a1) @@ -20,14 +20,14 @@ Disassembly of section .init: 80000030: 00458593 addi a1,a1,4 80000034: fec5e8e3 bltu a1,a2,80000024 <_start+0x24> 80000038: 00001517 auipc a0,0x1 -8000003c: 8f050513 addi a0,a0,-1808 # 80000928 <__bss_start> +8000003c: 95050513 addi a0,a0,-1712 # 80000988 <__bss_start> 80000040: 00001597 auipc a1,0x1 -80000044: 8e858593 addi a1,a1,-1816 # 80000928 <__bss_start> +80000044: 94858593 addi a1,a1,-1720 # 80000988 <__bss_start> 80000048: 00b57863 bgeu a0,a1,80000058 <_start+0x58> 8000004c: 00052023 sw zero,0(a0) 80000050: 00450513 addi a0,a0,4 80000054: feb56ce3 bltu a0,a1,8000004c <_start+0x4c> -80000058: 784000ef jal ra,800007dc <__libc_init_array> +80000058: 7e4000ef jal ra,8000083c <__libc_init_array> 8000005c: 178000ef jal ra,800001d4 80000060: 00000097 auipc ra,0x0 80000064: 01408093 addi ra,ra,20 # 80000074 @@ -73,7 +73,7 @@ Disassembly of section .init: 800000ec: 07d12a23 sw t4,116(sp) 800000f0: 07e12c23 sw t5,120(sp) 800000f4: 07f12e23 sw t6,124(sp) -800000f8: 2bc000ef jal ra,800003b4 +800000f8: 2c4000ef jal ra,800003bc 800000fc: 00412083 lw ra,4(sp) 80000100: 00c12183 lw gp,12(sp) 80000104: 01012203 lw tp,16(sp) @@ -117,7 +117,7 @@ Disassembly of section .text: 8000018c: 00054503 lbu a0,0(a0) 80000190: 00050a63 beqz a0,800001a4 80000194: 00140413 addi s0,s0,1 -80000198: 608000ef jal ra,800007a0 +80000198: 668000ef jal ra,80000800 8000019c: 00044503 lbu a0,0(s0) 800001a0: fe051ae3 bnez a0,80000194 800001a4: 00c12083 lw ra,12(sp) @@ -147,18 +147,18 @@ Disassembly of section .text: 800001f4: 3b071073 csrw pmpaddr0,a4 800001f8: 3a079073 csrw pmpcfg0,a5 800001fc: 80001437 lui s0,0x80001 -80000200: 5d8000ef jal ra,800007d8 -80000204: 8f840413 addi s0,s0,-1800 # 800008f8 <_sp+0xfffff7d0> +80000200: 638000ef jal ra,80000838 +80000204: 95840413 addi s0,s0,-1704 # 80000958 <_sp+0xfffff7d0> 80000208: 02a00513 li a0,42 8000020c: 00140413 addi s0,s0,1 -80000210: 590000ef jal ra,800007a0 +80000210: 5f0000ef jal ra,80000800 80000214: 00044503 lbu a0,0(s0) 80000218: fe051ae3 bnez a0,8000020c 8000021c: 800007b7 lui a5,0x80000 -80000220: 07c78793 addi a5,a5,124 # 8000007c <_sp+0xffffef54> +80000220: 07c78793 addi a5,a5,124 # 8000007c <_sp+0xffffeef4> 80000224: 30579073 csrw mtvec,a5 80000228: 800017b7 lui a5,0x80001 -8000022c: 0a878793 addi a5,a5,168 # 800010a8 <_sp+0xffffff80> +8000022c: 10878793 addi a5,a5,264 # 80001108 <_sp+0xffffff80> 80000230: 34079073 csrw mscratch,a5 80000234: 000017b7 lui a5,0x1 80000238: 88078793 addi a5,a5,-1920 # 880 <__stack_size+0x80> @@ -173,10 +173,10 @@ Disassembly of section .text: 8000025c: 30379073 csrw mideleg,a5 80000260: 14305073 csrwi stval,0 80000264: 80001437 lui s0,0x80001 -80000268: 91040413 addi s0,s0,-1776 # 80000910 <_sp+0xfffff7e8> +80000268: 97040413 addi s0,s0,-1680 # 80000970 <_sp+0xfffff7e8> 8000026c: 02a00513 li a0,42 80000270: 00140413 addi s0,s0,1 -80000274: 52c000ef jal ra,800007a0 +80000274: 58c000ef jal ra,80000800 80000278: 00044503 lbu a0,0(s0) 8000027c: fe051ae3 bnez a0,80000270 80000280: 00c12083 lw ra,12(sp) @@ -186,7 +186,7 @@ Disassembly of section .text: 80000290 : 80000290: 800017b7 lui a5,0x80001 -80000294: 0a878793 addi a5,a5,168 # 800010a8 <_sp+0xffffff80> +80000294: 10878793 addi a5,a5,264 # 80001108 <_sp+0xffffff80> 80000298: 00251513 slli a0,a0,0x2 8000029c: 00f50533 add a0,a0,a5 800002a0: 00052503 lw a0,0(a0) @@ -195,7 +195,7 @@ Disassembly of section .text: 800002a8 : 800002a8: 800017b7 lui a5,0x80001 800002ac: 00251513 slli a0,a0,0x2 -800002b0: 0a878793 addi a5,a5,168 # 800010a8 <_sp+0xffffff80> +800002b0: 10878793 addi a5,a5,264 # 80001108 <_sp+0xffffff80> 800002b4: 00f50533 add a0,a0,a5 800002b8: 00b52023 sw a1,0(a0) 800002bc: 00008067 ret @@ -203,7 +203,7 @@ Disassembly of section .text: 800002c0 : 800002c0: ff010113 addi sp,sp,-16 800002c4: 00112623 sw ra,12(sp) -800002c8: 4d0000ef jal ra,80000798 +800002c8: 530000ef jal ra,800007f8 800002cc: 343027f3 csrr a5,mtval 800002d0: 14379073 csrw stval,a5 800002d4: 341027f3 csrr a5,mepc @@ -218,7 +218,7 @@ Disassembly of section .text: 800002f8 : 800002f8: 800007b7 lui a5,0x80000 -800002fc: 07c78793 addi a5,a5,124 # 8000007c <_sp+0xffffef54> +800002fc: 07c78793 addi a5,a5,124 # 8000007c <_sp+0xffffeef4> 80000300: 30579073 csrw mtvec,a5 80000304: 343027f3 csrr a5,mtval 80000308: 14379073 csrw stval,a5 @@ -227,370 +227,394 @@ Disassembly of section .text: 80000314: 14151073 csrw sepc,a0 80000318: 105027f3 csrr a5,stvec 8000031c: 34179073 csrw mepc,a5 -80000320: 10000793 li a5,256 -80000324: 1007b073 csrc sstatus,a5 -80000328: 0035d593 srli a1,a1,0x3 -8000032c: 1005f593 andi a1,a1,256 -80000330: 1005a073 csrs sstatus,a1 -80000334: 000027b7 lui a5,0x2 -80000338: 80078793 addi a5,a5,-2048 # 1800 <__stack_size+0x1000> -8000033c: 3007b073 csrc mstatus,a5 -80000340: 000017b7 lui a5,0x1 -80000344: 88078793 addi a5,a5,-1920 # 880 <__stack_size+0x80> -80000348: 3007a073 csrs mstatus,a5 -8000034c: 00008067 ret +80000320: 0035d793 srli a5,a1,0x3 +80000324: 00459713 slli a4,a1,0x4 +80000328: 02077713 andi a4,a4,32 +8000032c: 1007f793 andi a5,a5,256 +80000330: 00e7e7b3 or a5,a5,a4 +80000334: ffffe737 lui a4,0xffffe +80000338: 6dd70713 addi a4,a4,1757 # ffffe6dd <_sp+0x7fffd555> +8000033c: 00e5f5b3 and a1,a1,a4 +80000340: 00b7e7b3 or a5,a5,a1 +80000344: 000015b7 lui a1,0x1 +80000348: 88058593 addi a1,a1,-1920 # 880 <__stack_size+0x80> +8000034c: 00b7e7b3 or a5,a5,a1 +80000350: 30079073 csrw mstatus,a5 +80000354: 00008067 ret -80000350 : -80000350: 00020737 lui a4,0x20 -80000354: 30072073 csrs mstatus,a4 -80000358: 00000717 auipc a4,0x0 -8000035c: 01870713 addi a4,a4,24 # 80000370 -80000360: 30571073 csrw mtvec,a4 -80000364: 00100693 li a3,1 -80000368: 00052783 lw a5,0(a0) -8000036c: 00000693 li a3,0 -80000370: 00020737 lui a4,0x20 -80000374: 30073073 csrc mstatus,a4 -80000378: 00068513 mv a0,a3 -8000037c: 00f5a023 sw a5,0(a1) # c3000000 <_sp+0x42ffeed8> -80000380: 00008067 ret +80000358 : +80000358: 00020737 lui a4,0x20 +8000035c: 30072073 csrs mstatus,a4 +80000360: 00000717 auipc a4,0x0 +80000364: 01870713 addi a4,a4,24 # 80000378 +80000368: 30571073 csrw mtvec,a4 +8000036c: 00100693 li a3,1 +80000370: 00052783 lw a5,0(a0) +80000374: 00000693 li a3,0 +80000378: 00020737 lui a4,0x20 +8000037c: 30073073 csrc mstatus,a4 +80000380: 00068513 mv a0,a3 +80000384: 00f5a023 sw a5,0(a1) +80000388: 00008067 ret -80000384 : -80000384: 00020737 lui a4,0x20 -80000388: 30072073 csrs mstatus,a4 -8000038c: 00000717 auipc a4,0x0 -80000390: 01870713 addi a4,a4,24 # 800003a4 -80000394: 30571073 csrw mtvec,a4 -80000398: 00100793 li a5,1 -8000039c: 00b52023 sw a1,0(a0) -800003a0: 00000793 li a5,0 -800003a4: 00020737 lui a4,0x20 -800003a8: 30073073 csrc mstatus,a4 -800003ac: 00078513 mv a0,a5 -800003b0: 00008067 ret +8000038c : +8000038c: 00020737 lui a4,0x20 +80000390: 30072073 csrs mstatus,a4 +80000394: 00000717 auipc a4,0x0 +80000398: 01870713 addi a4,a4,24 # 800003ac +8000039c: 30571073 csrw mtvec,a4 +800003a0: 00100793 li a5,1 +800003a4: 00b52023 sw a1,0(a0) +800003a8: 00000793 li a5,0 +800003ac: 00020737 lui a4,0x20 +800003b0: 30073073 csrc mstatus,a4 +800003b4: 00078513 mv a0,a5 +800003b8: 00008067 ret -800003b4 : -800003b4: fe010113 addi sp,sp,-32 -800003b8: 00112e23 sw ra,28(sp) -800003bc: 00812c23 sw s0,24(sp) -800003c0: 00912a23 sw s1,20(sp) -800003c4: 01212823 sw s2,16(sp) -800003c8: 01312623 sw s3,12(sp) -800003cc: 342027f3 csrr a5,mcause -800003d0: 0807cc63 bltz a5,80000468 -800003d4: 00200713 li a4,2 -800003d8: 0ce78463 beq a5,a4,800004a0 -800003dc: 00900693 li a3,9 -800003e0: 04d79463 bne a5,a3,80000428 -800003e4: 80001437 lui s0,0x80001 -800003e8: 12840413 addi s0,s0,296 # 80001128 <_sp+0x0> -800003ec: fc442783 lw a5,-60(s0) -800003f0: 00100693 li a3,1 -800003f4: fa842503 lw a0,-88(s0) -800003f8: 2ed78463 beq a5,a3,800006e0 -800003fc: 2ee78e63 beq a5,a4,800006f8 -80000400: 2a078c63 beqz a5,800006b8 -80000404: 01812403 lw s0,24(sp) -80000408: 01c12083 lw ra,28(sp) -8000040c: 01412483 lw s1,20(sp) -80000410: 01012903 lw s2,16(sp) -80000414: 00c12983 lw s3,12(sp) -80000418: 02010113 addi sp,sp,32 -8000041c: 37c0006f j 80000798 -80000420: 00777713 andi a4,a4,7 -80000424: 12f70c63 beq a4,a5,8000055c -80000428: 370000ef jal ra,80000798 -8000042c: 343027f3 csrr a5,mtval -80000430: 14379073 csrw stval,a5 -80000434: 341027f3 csrr a5,mepc -80000438: 14179073 csrw sepc,a5 -8000043c: 342027f3 csrr a5,mcause -80000440: 14279073 csrw scause,a5 -80000444: 105027f3 csrr a5,stvec -80000448: 34179073 csrw mepc,a5 -8000044c: 01c12083 lw ra,28(sp) -80000450: 01812403 lw s0,24(sp) -80000454: 01412483 lw s1,20(sp) -80000458: 01012903 lw s2,16(sp) -8000045c: 00c12983 lw s3,12(sp) -80000460: 02010113 addi sp,sp,32 -80000464: 00008067 ret -80000468: 0ff7f793 andi a5,a5,255 -8000046c: 00700713 li a4,7 -80000470: fae79ce3 bne a5,a4,80000428 -80000474: 02000793 li a5,32 -80000478: 1447a073 csrs sip,a5 -8000047c: 08000793 li a5,128 -80000480: 3047b073 csrc mie,a5 -80000484: 01c12083 lw ra,28(sp) -80000488: 01812403 lw s0,24(sp) -8000048c: 01412483 lw s1,20(sp) -80000490: 01012903 lw s2,16(sp) -80000494: 00c12983 lw s3,12(sp) -80000498: 02010113 addi sp,sp,32 -8000049c: 00008067 ret -800004a0: 341024f3 csrr s1,mepc -800004a4: 300025f3 csrr a1,mstatus -800004a8: 34302473 csrr s0,mtval -800004ac: 02f00613 li a2,47 -800004b0: 07f47693 andi a3,s0,127 -800004b4: 00c45713 srli a4,s0,0xc -800004b8: f6c684e3 beq a3,a2,80000420 -800004bc: 07300613 li a2,115 -800004c0: f6c694e3 bne a3,a2,80000428 -800004c4: 00377713 andi a4,a4,3 -800004c8: 10f70c63 beq a4,a5,800005e0 -800004cc: 00300793 li a5,3 -800004d0: 10f70863 beq a4,a5,800005e0 -800004d4: 00100993 li s3,1 -800004d8: 03370463 beq a4,s3,80000500 -800004dc: 2bc000ef jal ra,80000798 -800004e0: 343027f3 csrr a5,mtval -800004e4: 14379073 csrw stval,a5 -800004e8: 341027f3 csrr a5,mepc -800004ec: 14179073 csrw sepc,a5 -800004f0: 342027f3 csrr a5,mcause -800004f4: 14279073 csrw scause,a5 -800004f8: 105027f3 csrr a5,stvec -800004fc: 34179073 csrw mepc,a5 -80000500: 00001737 lui a4,0x1 -80000504: 01445793 srli a5,s0,0x14 -80000508: c0070693 addi a3,a4,-1024 # c00 <__stack_size+0x400> -8000050c: 0ed7e263 bltu a5,a3,800005f0 -80000510: c0270713 addi a4,a4,-1022 -80000514: 0cf77063 bgeu a4,a5,800005d4 -80000518: fffff737 lui a4,0xfffff -8000051c: 38070713 addi a4,a4,896 # fffff380 <_sp+0x7fffe258> -80000520: 00e787b3 add a5,a5,a4 -80000524: 00200713 li a4,2 -80000528: 0cf76463 bltu a4,a5,800005f0 -8000052c: 28c000ef jal ra,800007b8 -80000530: 00050913 mv s2,a0 -80000534: 1c099e63 bnez s3,80000710 -80000538: 00545413 srli s0,s0,0x5 -8000053c: 800017b7 lui a5,0x80001 -80000540: 0a878793 addi a5,a5,168 # 800010a8 <_sp+0xffffff80> -80000544: 07c47413 andi s0,s0,124 -80000548: 00f40433 add s0,s0,a5 -8000054c: 01242023 sw s2,0(s0) -80000550: 00448493 addi s1,s1,4 -80000554: 34149073 csrw mepc,s1 -80000558: ef5ff06f j 8000044c -8000055c: 00d45713 srli a4,s0,0xd -80000560: 01245793 srli a5,s0,0x12 -80000564: 800016b7 lui a3,0x80001 -80000568: 0a868693 addi a3,a3,168 # 800010a8 <_sp+0xffffff80> -8000056c: 07c77713 andi a4,a4,124 -80000570: 07c7f793 andi a5,a5,124 -80000574: 00d70733 add a4,a4,a3 -80000578: 00d787b3 add a5,a5,a3 -8000057c: 00072703 lw a4,0(a4) -80000580: 0007a603 lw a2,0(a5) -80000584: 00020537 lui a0,0x20 -80000588: 30052073 csrs mstatus,a0 -8000058c: 00000517 auipc a0,0x0 -80000590: 01850513 addi a0,a0,24 # 800005a4 -80000594: 30551073 csrw mtvec,a0 -80000598: 00100793 li a5,1 -8000059c: 00072803 lw a6,0(a4) -800005a0: 00000793 li a5,0 -800005a4: 00020537 lui a0,0x20 -800005a8: 30053073 csrc mstatus,a0 -800005ac: 18079663 bnez a5,80000738 -800005b0: 01b45793 srli a5,s0,0x1b -800005b4: 01c00513 li a0,28 -800005b8: e6f568e3 bltu a0,a5,80000428 -800005bc: 80001537 lui a0,0x80001 -800005c0: 00279793 slli a5,a5,0x2 -800005c4: 88450513 addi a0,a0,-1916 # 80000884 <_sp+0xfffff75c> -800005c8: 00a787b3 add a5,a5,a0 -800005cc: 0007a783 lw a5,0(a5) -800005d0: 00078067 jr a5 -800005d4: 1dc000ef jal ra,800007b0 -800005d8: 00050913 mv s2,a0 -800005dc: f59ff06f j 80000534 -800005e0: 00f45993 srli s3,s0,0xf -800005e4: 01f9f993 andi s3,s3,31 -800005e8: 013039b3 snez s3,s3 -800005ec: f15ff06f j 80000500 -800005f0: 1a8000ef jal ra,80000798 -800005f4: 343027f3 csrr a5,mtval -800005f8: 14379073 csrw stval,a5 -800005fc: 341027f3 csrr a5,mepc -80000600: 14179073 csrw sepc,a5 -80000604: 342027f3 csrr a5,mcause -80000608: 14279073 csrw scause,a5 -8000060c: 105027f3 csrr a5,stvec -80000610: 34179073 csrw mepc,a5 -80000614: f21ff06f j 80000534 -80000618: 01067463 bgeu a2,a6,80000620 -8000061c: 00080613 mv a2,a6 -80000620: 00020537 lui a0,0x20 -80000624: 30052073 csrs mstatus,a0 -80000628: 00000517 auipc a0,0x0 -8000062c: 01850513 addi a0,a0,24 # 80000640 -80000630: 30551073 csrw mtvec,a0 -80000634: 00100793 li a5,1 -80000638: 00c72023 sw a2,0(a4) -8000063c: 00000793 li a5,0 -80000640: 00020537 lui a0,0x20 -80000644: 30053073 csrc mstatus,a0 -80000648: 80000737 lui a4,0x80000 -8000064c: 07c70713 addi a4,a4,124 # 8000007c <_sp+0xffffef54> -80000650: 14079063 bnez a5,80000790 -80000654: 00545793 srli a5,s0,0x5 -80000658: 07c7f793 andi a5,a5,124 -8000065c: 00d786b3 add a3,a5,a3 -80000660: 0106a023 sw a6,0(a3) -80000664: 00448493 addi s1,s1,4 -80000668: 34149073 csrw mepc,s1 -8000066c: 30571073 csrw mtvec,a4 -80000670: dddff06f j 8000044c -80000674: 01064633 xor a2,a2,a6 -80000678: fa9ff06f j 80000620 -8000067c: fac872e3 bgeu a6,a2,80000620 -80000680: 00080613 mv a2,a6 -80000684: f9dff06f j 80000620 -80000688: f9065ce3 bge a2,a6,80000620 -8000068c: 00080613 mv a2,a6 -80000690: f91ff06f j 80000620 -80000694: f8c856e3 bge a6,a2,80000620 -80000698: 00080613 mv a2,a6 -8000069c: f85ff06f j 80000620 -800006a0: 01067633 and a2,a2,a6 -800006a4: f7dff06f j 80000620 -800006a8: 01066633 or a2,a2,a6 -800006ac: f75ff06f j 80000620 -800006b0: 01060633 add a2,a2,a6 -800006b4: f6dff06f j 80000620 -800006b8: fac42583 lw a1,-84(s0) -800006bc: 104000ef jal ra,800007c0 -800006c0: 08000793 li a5,128 -800006c4: 3047a073 csrs mie,a5 -800006c8: 02000793 li a5,32 -800006cc: 1447b073 csrc sip,a5 -800006d0: 341027f3 csrr a5,mepc -800006d4: 00478793 addi a5,a5,4 -800006d8: 34179073 csrw mepc,a5 -800006dc: d71ff06f j 8000044c -800006e0: 0ff57513 andi a0,a0,255 -800006e4: 0bc000ef jal ra,800007a0 -800006e8: 341027f3 csrr a5,mepc -800006ec: 00478793 addi a5,a5,4 -800006f0: 34179073 csrw mepc,a5 -800006f4: d59ff06f j 8000044c -800006f8: 0b0000ef jal ra,800007a8 -800006fc: faa42423 sw a0,-88(s0) -80000700: 341027f3 csrr a5,mepc -80000704: 00478793 addi a5,a5,4 -80000708: 34179073 csrw mepc,a5 -8000070c: d41ff06f j 8000044c -80000710: 088000ef jal ra,80000798 -80000714: 343027f3 csrr a5,mtval -80000718: 14379073 csrw stval,a5 -8000071c: 341027f3 csrr a5,mepc -80000720: 14179073 csrw sepc,a5 -80000724: 342027f3 csrr a5,mcause -80000728: 14279073 csrw scause,a5 -8000072c: 105027f3 csrr a5,stvec -80000730: 34179073 csrw mepc,a5 -80000734: e05ff06f j 80000538 -80000738: 800007b7 lui a5,0x80000 -8000073c: 07c78793 addi a5,a5,124 # 8000007c <_sp+0xffffef54> -80000740: 30579073 csrw mtvec,a5 -80000744: 343027f3 csrr a5,mtval -80000748: 14379073 csrw stval,a5 -8000074c: 342027f3 csrr a5,mcause -80000750: 14279073 csrw scause,a5 -80000754: 14149073 csrw sepc,s1 -80000758: 105027f3 csrr a5,stvec -8000075c: 34179073 csrw mepc,a5 -80000760: 10000793 li a5,256 -80000764: 1007b073 csrc sstatus,a5 +800003bc : +800003bc: fe010113 addi sp,sp,-32 +800003c0: 00112e23 sw ra,28(sp) +800003c4: 00812c23 sw s0,24(sp) +800003c8: 00912a23 sw s1,20(sp) +800003cc: 01212823 sw s2,16(sp) +800003d0: 01312623 sw s3,12(sp) +800003d4: 342027f3 csrr a5,mcause +800003d8: 0807cc63 bltz a5,80000470 +800003dc: 00200713 li a4,2 +800003e0: 0ce78463 beq a5,a4,800004a8 +800003e4: 00900693 li a3,9 +800003e8: 04d79463 bne a5,a3,80000430 +800003ec: 80001437 lui s0,0x80001 +800003f0: 18840413 addi s0,s0,392 # 80001188 <_sp+0x0> +800003f4: fc442783 lw a5,-60(s0) +800003f8: 00100693 li a3,1 +800003fc: fa842503 lw a0,-88(s0) +80000400: 2ed78463 beq a5,a3,800006e8 +80000404: 2ee78e63 beq a5,a4,80000700 +80000408: 2a078c63 beqz a5,800006c0 +8000040c: 01812403 lw s0,24(sp) +80000410: 01c12083 lw ra,28(sp) +80000414: 01412483 lw s1,20(sp) +80000418: 01012903 lw s2,16(sp) +8000041c: 00c12983 lw s3,12(sp) +80000420: 02010113 addi sp,sp,32 +80000424: 3d40006f j 800007f8 +80000428: 00777713 andi a4,a4,7 +8000042c: 12f70c63 beq a4,a5,80000564 +80000430: 3c8000ef jal ra,800007f8 +80000434: 343027f3 csrr a5,mtval +80000438: 14379073 csrw stval,a5 +8000043c: 341027f3 csrr a5,mepc +80000440: 14179073 csrw sepc,a5 +80000444: 342027f3 csrr a5,mcause +80000448: 14279073 csrw scause,a5 +8000044c: 105027f3 csrr a5,stvec +80000450: 34179073 csrw mepc,a5 +80000454: 01c12083 lw ra,28(sp) +80000458: 01812403 lw s0,24(sp) +8000045c: 01412483 lw s1,20(sp) +80000460: 01012903 lw s2,16(sp) +80000464: 00c12983 lw s3,12(sp) +80000468: 02010113 addi sp,sp,32 +8000046c: 00008067 ret +80000470: 0ff7f793 andi a5,a5,255 +80000474: 00700713 li a4,7 +80000478: fae79ce3 bne a5,a4,80000430 +8000047c: 02000793 li a5,32 +80000480: 1447a073 csrs sip,a5 +80000484: 08000793 li a5,128 +80000488: 3047b073 csrc mie,a5 +8000048c: 01c12083 lw ra,28(sp) +80000490: 01812403 lw s0,24(sp) +80000494: 01412483 lw s1,20(sp) +80000498: 01012903 lw s2,16(sp) +8000049c: 00c12983 lw s3,12(sp) +800004a0: 02010113 addi sp,sp,32 +800004a4: 00008067 ret +800004a8: 341024f3 csrr s1,mepc +800004ac: 300025f3 csrr a1,mstatus +800004b0: 34302473 csrr s0,mtval +800004b4: 02f00613 li a2,47 +800004b8: 07f47693 andi a3,s0,127 +800004bc: 00c45713 srli a4,s0,0xc +800004c0: f6c684e3 beq a3,a2,80000428 +800004c4: 07300613 li a2,115 +800004c8: f6c694e3 bne a3,a2,80000430 +800004cc: 00377713 andi a4,a4,3 +800004d0: 10f70c63 beq a4,a5,800005e8 +800004d4: 00300793 li a5,3 +800004d8: 10f70863 beq a4,a5,800005e8 +800004dc: 00100993 li s3,1 +800004e0: 03370463 beq a4,s3,80000508 +800004e4: 314000ef jal ra,800007f8 +800004e8: 343027f3 csrr a5,mtval +800004ec: 14379073 csrw stval,a5 +800004f0: 341027f3 csrr a5,mepc +800004f4: 14179073 csrw sepc,a5 +800004f8: 342027f3 csrr a5,mcause +800004fc: 14279073 csrw scause,a5 +80000500: 105027f3 csrr a5,stvec +80000504: 34179073 csrw mepc,a5 +80000508: 00001737 lui a4,0x1 +8000050c: 01445793 srli a5,s0,0x14 +80000510: c0070693 addi a3,a4,-1024 # c00 <__stack_size+0x400> +80000514: 0ed7e263 bltu a5,a3,800005f8 +80000518: c0270713 addi a4,a4,-1022 +8000051c: 0cf77063 bgeu a4,a5,800005dc +80000520: fffff737 lui a4,0xfffff +80000524: 38070713 addi a4,a4,896 # fffff380 <_sp+0x7fffe1f8> +80000528: 00e787b3 add a5,a5,a4 +8000052c: 00200713 li a4,2 +80000530: 0cf76463 bltu a4,a5,800005f8 +80000534: 2e4000ef jal ra,80000818 +80000538: 00050913 mv s2,a0 +8000053c: 1c099e63 bnez s3,80000718 +80000540: 00545413 srli s0,s0,0x5 +80000544: 800017b7 lui a5,0x80001 +80000548: 10878793 addi a5,a5,264 # 80001108 <_sp+0xffffff80> +8000054c: 07c47413 andi s0,s0,124 +80000550: 00f40433 add s0,s0,a5 +80000554: 01242023 sw s2,0(s0) +80000558: 00448493 addi s1,s1,4 +8000055c: 34149073 csrw mepc,s1 +80000560: ef5ff06f j 80000454 +80000564: 00d45713 srli a4,s0,0xd +80000568: 01245793 srli a5,s0,0x12 +8000056c: 800016b7 lui a3,0x80001 +80000570: 10868693 addi a3,a3,264 # 80001108 <_sp+0xffffff80> +80000574: 07c77713 andi a4,a4,124 +80000578: 07c7f793 andi a5,a5,124 +8000057c: 00d70733 add a4,a4,a3 +80000580: 00d787b3 add a5,a5,a3 +80000584: 00072703 lw a4,0(a4) +80000588: 0007a603 lw a2,0(a5) +8000058c: 00020537 lui a0,0x20 +80000590: 30052073 csrs mstatus,a0 +80000594: 00000517 auipc a0,0x0 +80000598: 01850513 addi a0,a0,24 # 800005ac +8000059c: 30551073 csrw mtvec,a0 +800005a0: 00100793 li a5,1 +800005a4: 00072803 lw a6,0(a4) +800005a8: 00000793 li a5,0 +800005ac: 00020537 lui a0,0x20 +800005b0: 30053073 csrc mstatus,a0 +800005b4: 18079663 bnez a5,80000740 +800005b8: 01b45793 srli a5,s0,0x1b +800005bc: 01c00513 li a0,28 +800005c0: e6f568e3 bltu a0,a5,80000430 +800005c4: 80001537 lui a0,0x80001 +800005c8: 00279793 slli a5,a5,0x2 +800005cc: 8e450513 addi a0,a0,-1820 # 800008e4 <_sp+0xfffff75c> +800005d0: 00a787b3 add a5,a5,a0 +800005d4: 0007a783 lw a5,0(a5) +800005d8: 00078067 jr a5 +800005dc: 234000ef jal ra,80000810 +800005e0: 00050913 mv s2,a0 +800005e4: f59ff06f j 8000053c +800005e8: 00f45993 srli s3,s0,0xf +800005ec: 01f9f993 andi s3,s3,31 +800005f0: 013039b3 snez s3,s3 +800005f4: f15ff06f j 80000508 +800005f8: 200000ef jal ra,800007f8 +800005fc: 343027f3 csrr a5,mtval +80000600: 14379073 csrw stval,a5 +80000604: 341027f3 csrr a5,mepc +80000608: 14179073 csrw sepc,a5 +8000060c: 342027f3 csrr a5,mcause +80000610: 14279073 csrw scause,a5 +80000614: 105027f3 csrr a5,stvec +80000618: 34179073 csrw mepc,a5 +8000061c: f21ff06f j 8000053c +80000620: 01067463 bgeu a2,a6,80000628 +80000624: 00080613 mv a2,a6 +80000628: 00020537 lui a0,0x20 +8000062c: 30052073 csrs mstatus,a0 +80000630: 00000517 auipc a0,0x0 +80000634: 01850513 addi a0,a0,24 # 80000648 +80000638: 30551073 csrw mtvec,a0 +8000063c: 00100793 li a5,1 +80000640: 00c72023 sw a2,0(a4) +80000644: 00000793 li a5,0 +80000648: 00020537 lui a0,0x20 +8000064c: 30053073 csrc mstatus,a0 +80000650: 80000737 lui a4,0x80000 +80000654: 07c70713 addi a4,a4,124 # 8000007c <_sp+0xffffeef4> +80000658: 14079463 bnez a5,800007a0 +8000065c: 00545793 srli a5,s0,0x5 +80000660: 07c7f793 andi a5,a5,124 +80000664: 00d786b3 add a3,a5,a3 +80000668: 0106a023 sw a6,0(a3) +8000066c: 00448493 addi s1,s1,4 +80000670: 34149073 csrw mepc,s1 +80000674: 30571073 csrw mtvec,a4 +80000678: dddff06f j 80000454 +8000067c: 01064633 xor a2,a2,a6 +80000680: fa9ff06f j 80000628 +80000684: fac872e3 bgeu a6,a2,80000628 +80000688: 00080613 mv a2,a6 +8000068c: f9dff06f j 80000628 +80000690: f9065ce3 bge a2,a6,80000628 +80000694: 00080613 mv a2,a6 +80000698: f91ff06f j 80000628 +8000069c: f8c856e3 bge a6,a2,80000628 +800006a0: 00080613 mv a2,a6 +800006a4: f85ff06f j 80000628 +800006a8: 01067633 and a2,a2,a6 +800006ac: f7dff06f j 80000628 +800006b0: 01066633 or a2,a2,a6 +800006b4: f75ff06f j 80000628 +800006b8: 01060633 add a2,a2,a6 +800006bc: f6dff06f j 80000628 +800006c0: fac42583 lw a1,-84(s0) +800006c4: 15c000ef jal ra,80000820 +800006c8: 08000793 li a5,128 +800006cc: 3047a073 csrs mie,a5 +800006d0: 02000793 li a5,32 +800006d4: 1447b073 csrc sip,a5 +800006d8: 341027f3 csrr a5,mepc +800006dc: 00478793 addi a5,a5,4 +800006e0: 34179073 csrw mepc,a5 +800006e4: d71ff06f j 80000454 +800006e8: 0ff57513 andi a0,a0,255 +800006ec: 114000ef jal ra,80000800 +800006f0: 341027f3 csrr a5,mepc +800006f4: 00478793 addi a5,a5,4 +800006f8: 34179073 csrw mepc,a5 +800006fc: d59ff06f j 80000454 +80000700: 108000ef jal ra,80000808 +80000704: faa42423 sw a0,-88(s0) +80000708: 341027f3 csrr a5,mepc +8000070c: 00478793 addi a5,a5,4 +80000710: 34179073 csrw mepc,a5 +80000714: d41ff06f j 80000454 +80000718: 0e0000ef jal ra,800007f8 +8000071c: 343027f3 csrr a5,mtval +80000720: 14379073 csrw stval,a5 +80000724: 341027f3 csrr a5,mepc +80000728: 14179073 csrw sepc,a5 +8000072c: 342027f3 csrr a5,mcause +80000730: 14279073 csrw scause,a5 +80000734: 105027f3 csrr a5,stvec +80000738: 34179073 csrw mepc,a5 +8000073c: e05ff06f j 80000540 +80000740: 800007b7 lui a5,0x80000 +80000744: 07c78793 addi a5,a5,124 # 8000007c <_sp+0xffffeef4> +80000748: 30579073 csrw mtvec,a5 +8000074c: 343027f3 csrr a5,mtval +80000750: 14379073 csrw stval,a5 +80000754: 342027f3 csrr a5,mcause +80000758: 14279073 csrw scause,a5 +8000075c: 14149073 csrw sepc,s1 +80000760: 105027f3 csrr a5,stvec +80000764: 34179073 csrw mepc,a5 80000768: 0035d793 srli a5,a1,0x3 -8000076c: 1007f793 andi a5,a5,256 -80000770: 1007a073 csrs sstatus,a5 -80000774: 000027b7 lui a5,0x2 -80000778: 80078793 addi a5,a5,-2048 # 1800 <__stack_size+0x1000> -8000077c: 3007b073 csrc mstatus,a5 -80000780: 000017b7 lui a5,0x1 -80000784: 88078793 addi a5,a5,-1920 # 880 <__stack_size+0x80> -80000788: 3007a073 csrs mstatus,a5 -8000078c: cc1ff06f j 8000044c -80000790: 30571073 csrw mtvec,a4 -80000794: fb1ff06f j 80000744 +8000076c: 00459713 slli a4,a1,0x4 +80000770: 02077713 andi a4,a4,32 +80000774: 1007f793 andi a5,a5,256 +80000778: 00e7e7b3 or a5,a5,a4 +8000077c: ffffe737 lui a4,0xffffe +80000780: 6dd70713 addi a4,a4,1757 # ffffe6dd <_sp+0x7fffd555> +80000784: 00e5f5b3 and a1,a1,a4 +80000788: 00001737 lui a4,0x1 +8000078c: 00b7e7b3 or a5,a5,a1 +80000790: 88070713 addi a4,a4,-1920 # 880 <__stack_size+0x80> +80000794: 00e7e7b3 or a5,a5,a4 +80000798: 30079073 csrw mstatus,a5 +8000079c: cb9ff06f j 80000454 +800007a0: 30571073 csrw mtvec,a4 +800007a4: 343027f3 csrr a5,mtval +800007a8: 14379073 csrw stval,a5 +800007ac: 342027f3 csrr a5,mcause +800007b0: 14279073 csrw scause,a5 +800007b4: 14149073 csrw sepc,s1 +800007b8: 105027f3 csrr a5,stvec +800007bc: 34179073 csrw mepc,a5 +800007c0: 0035d793 srli a5,a1,0x3 +800007c4: 00459713 slli a4,a1,0x4 +800007c8: 02077713 andi a4,a4,32 +800007cc: 1007f793 andi a5,a5,256 +800007d0: 00e7e7b3 or a5,a5,a4 +800007d4: ffffe737 lui a4,0xffffe +800007d8: 6dd70713 addi a4,a4,1757 # ffffe6dd <_sp+0x7fffd555> +800007dc: 00e5f5b3 and a1,a1,a4 +800007e0: 00b7e5b3 or a1,a5,a1 +800007e4: 000017b7 lui a5,0x1 +800007e8: 88078793 addi a5,a5,-1920 # 880 <__stack_size+0x80> +800007ec: 00f5e7b3 or a5,a1,a5 +800007f0: 30079073 csrw mstatus,a5 +800007f4: c61ff06f j 80000454 -80000798 : -80000798: fe002e23 sw zero,-4(zero) # fffffffc <_sp+0x7fffeed4> -8000079c: 0000006f j 8000079c +800007f8 : +800007f8: fe002e23 sw zero,-4(zero) # fffffffc <_sp+0x7fffee74> +800007fc: 0000006f j 800007fc -800007a0 : -800007a0: fea02c23 sw a0,-8(zero) # fffffff8 <_sp+0x7fffeed0> -800007a4: 00008067 ret +80000800 : +80000800: fea02c23 sw a0,-8(zero) # fffffff8 <_sp+0x7fffee70> +80000804: 00008067 ret -800007a8 : -800007a8: ff802503 lw a0,-8(zero) # fffffff8 <_sp+0x7fffeed0> -800007ac: 00008067 ret +80000808 : +80000808: ff802503 lw a0,-8(zero) # fffffff8 <_sp+0x7fffee70> +8000080c: 00008067 ret -800007b0 : -800007b0: fe002503 lw a0,-32(zero) # ffffffe0 <_sp+0x7fffeeb8> -800007b4: 00008067 ret +80000810 : +80000810: fe002503 lw a0,-32(zero) # ffffffe0 <_sp+0x7fffee58> +80000814: 00008067 ret -800007b8 : -800007b8: fe402503 lw a0,-28(zero) # ffffffe4 <_sp+0x7fffeebc> -800007bc: 00008067 ret +80000818 : +80000818: fe402503 lw a0,-28(zero) # ffffffe4 <_sp+0x7fffee5c> +8000081c: 00008067 ret -800007c0 : -800007c0: fec00793 li a5,-20 -800007c4: fff00713 li a4,-1 -800007c8: 00e7a023 sw a4,0(a5) -800007cc: fea02423 sw a0,-24(zero) # ffffffe8 <_sp+0x7fffeec0> -800007d0: 00b7a023 sw a1,0(a5) -800007d4: 00008067 ret +80000820 : +80000820: fec00793 li a5,-20 +80000824: fff00713 li a4,-1 +80000828: 00e7a023 sw a4,0(a5) +8000082c: fea02423 sw a0,-24(zero) # ffffffe8 <_sp+0x7fffee60> +80000830: 00b7a023 sw a1,0(a5) +80000834: 00008067 ret -800007d8 : -800007d8: 00008067 ret +80000838 : +80000838: 00008067 ret -800007dc <__libc_init_array>: -800007dc: ff010113 addi sp,sp,-16 -800007e0: 00000797 auipc a5,0x0 -800007e4: 0a478793 addi a5,a5,164 # 80000884 <__init_array_end> -800007e8: 00812423 sw s0,8(sp) -800007ec: 00000417 auipc s0,0x0 -800007f0: 09840413 addi s0,s0,152 # 80000884 <__init_array_end> -800007f4: 40f40433 sub s0,s0,a5 -800007f8: 00912223 sw s1,4(sp) -800007fc: 01212023 sw s2,0(sp) -80000800: 00112623 sw ra,12(sp) -80000804: 40245413 srai s0,s0,0x2 -80000808: 00000493 li s1,0 -8000080c: 00078913 mv s2,a5 -80000810: 04849263 bne s1,s0,80000854 <__libc_init_array+0x78> -80000814: 865ff0ef jal ra,80000078 <_init> -80000818: 00000797 auipc a5,0x0 -8000081c: 06c78793 addi a5,a5,108 # 80000884 <__init_array_end> -80000820: 00000417 auipc s0,0x0 -80000824: 06440413 addi s0,s0,100 # 80000884 <__init_array_end> -80000828: 40f40433 sub s0,s0,a5 -8000082c: 40245413 srai s0,s0,0x2 -80000830: 00000493 li s1,0 -80000834: 00078913 mv s2,a5 -80000838: 02849a63 bne s1,s0,8000086c <__libc_init_array+0x90> -8000083c: 00c12083 lw ra,12(sp) -80000840: 00812403 lw s0,8(sp) -80000844: 00412483 lw s1,4(sp) -80000848: 00012903 lw s2,0(sp) -8000084c: 01010113 addi sp,sp,16 -80000850: 00008067 ret -80000854: 00249793 slli a5,s1,0x2 -80000858: 00f907b3 add a5,s2,a5 -8000085c: 0007a783 lw a5,0(a5) -80000860: 00148493 addi s1,s1,1 -80000864: 000780e7 jalr a5 -80000868: fa9ff06f j 80000810 <__libc_init_array+0x34> -8000086c: 00249793 slli a5,s1,0x2 -80000870: 00f907b3 add a5,s2,a5 -80000874: 0007a783 lw a5,0(a5) -80000878: 00148493 addi s1,s1,1 -8000087c: 000780e7 jalr a5 -80000880: fb9ff06f j 80000838 <__libc_init_array+0x5c> +8000083c <__libc_init_array>: +8000083c: ff010113 addi sp,sp,-16 +80000840: 00000797 auipc a5,0x0 +80000844: 0a478793 addi a5,a5,164 # 800008e4 <__init_array_end> +80000848: 00812423 sw s0,8(sp) +8000084c: 00000417 auipc s0,0x0 +80000850: 09840413 addi s0,s0,152 # 800008e4 <__init_array_end> +80000854: 40f40433 sub s0,s0,a5 +80000858: 00912223 sw s1,4(sp) +8000085c: 01212023 sw s2,0(sp) +80000860: 00112623 sw ra,12(sp) +80000864: 40245413 srai s0,s0,0x2 +80000868: 00000493 li s1,0 +8000086c: 00078913 mv s2,a5 +80000870: 04849263 bne s1,s0,800008b4 <__libc_init_array+0x78> +80000874: 805ff0ef jal ra,80000078 <_init> +80000878: 00000797 auipc a5,0x0 +8000087c: 06c78793 addi a5,a5,108 # 800008e4 <__init_array_end> +80000880: 00000417 auipc s0,0x0 +80000884: 06440413 addi s0,s0,100 # 800008e4 <__init_array_end> +80000888: 40f40433 sub s0,s0,a5 +8000088c: 40245413 srai s0,s0,0x2 +80000890: 00000493 li s1,0 +80000894: 00078913 mv s2,a5 +80000898: 02849a63 bne s1,s0,800008cc <__libc_init_array+0x90> +8000089c: 00c12083 lw ra,12(sp) +800008a0: 00812403 lw s0,8(sp) +800008a4: 00412483 lw s1,4(sp) +800008a8: 00012903 lw s2,0(sp) +800008ac: 01010113 addi sp,sp,16 +800008b0: 00008067 ret +800008b4: 00249793 slli a5,s1,0x2 +800008b8: 00f907b3 add a5,s2,a5 +800008bc: 0007a783 lw a5,0(a5) +800008c0: 00148493 addi s1,s1,1 +800008c4: 000780e7 jalr a5 +800008c8: fa9ff06f j 80000870 <__libc_init_array+0x34> +800008cc: 00249793 slli a5,s1,0x2 +800008d0: 00f907b3 add a5,s2,a5 +800008d4: 0007a783 lw a5,0(a5) +800008d8: 00148493 addi s1,s1,1 +800008dc: 000780e7 jalr a5 +800008e0: fb9ff06f j 80000898 <__libc_init_array+0x5c> diff --git a/src/main/c/emulator/build/emulator.bin b/src/main/c/emulator/build/emulator.bin index 9c56f673544853d533ea2dfb223c008cb4059b7a..83e0a0d5030d72b0540dc38d39bcdcac5a05456c 100755 GIT binary patch delta 757 zcmah_O=uHQ5T5;g2DEJYl5P|w3o%UzrmQw0h!*x>@FF6$SfxS_p)EqBhdrbRF)OyF zm&(T15)Y;IAhbte3GtYVdhn|BDwL8-A(a?PMH=UA1vQr*9y8y^%s1cnw)&T-p$7q| z@GPQ-u__;yt614$Zdo5dtg6+D5xuZ_OfIhE=W7r%6dcUKPN8&!#Tdk`Iu4jc`69q*kF*~y34-F2HO)eBik9E)f~_w5!nIJ zyk--!&2E>H?Z;kc7rbU2>V8sXiTAckOy)>u*|hWm@9#-h`m9k}EJFVDL4OOJ>%QG-&B&5v_KNeCJ%D3hs|UU?IqZxXaf(3%zF^K<(f9roY{ zu){;ayJ`w^`%~Z1w&AOX)KOuDjj08(5oQf_aM%jA6Iz;;Z=yXtjk{mbi59!~_UHe6 z^b2bA`5I}GDxDBLtAih(5`xj2est9SY-@_I~4vU;Bl-{f04B<27%ndhUg*IF;$$*u P+?$>sdt~RC6o~%@+-mYO delta 625 zcmeAWULm9)F37+j%-AR-E()YskG4+-(vw?V+r`Czd^Wa;6BXoT`yqm@eaRJD8I%=R zfeKw29_MWR_nyI_Vq(lZrUTj&|IBAhm^_CuT{l*krKMk(bpewwiwMJe28KvxR~ClH zQmp^BvokbIZa>amJR#g*yEus5&NbP9$(nZ}LiK?lpcxXACor*_atVv7G8nUdWnfli zWk_#eU;ya>iGlQi#FZ7cg2jay8UHJ*34-kMoqUEVRFj=Spm+njz~rl@43odI3KTD3 z71*v0^i?~115g}fH;CO)ykK$=^Fl_U$zPa__zsv0mzOgn^L!Tq8eI?zww*@1py$KfY-gZvNjXNm>FLG> 3) & MSTATUS_SPP); - csr_clear(mstatus, MSTATUS_MPP); - csr_set(mstatus, 0x0800 | MSTATUS_MPIE); + csr_write(mstatus, + (mstatus & ~(MSTATUS_SPP | MSTATUS_MPP | MSTATUS_SIE | MSTATUS_SPIE)) + | ((mstatus >> 3) & MSTATUS_SPP) + | (0x0800 | MSTATUS_MPIE) + | ((mstatus & MSTATUS_SIE) << 4) + ); } #define max(a,b) \ From e47b76fa677926f9c06150fd8b7cea7722692a2e Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Fri, 19 Apr 2019 17:35:48 +0200 Subject: [PATCH 154/951] #60 Added automated linux regression in travis Fix DBusCached plugin access sharing for the MMU deadlock when exception is in the decode stage Fix IBusSimplePlugin issues with used with non regular configs + MMU Bring back the LinuxGen config into a light one --- .gitmodules | 3 + .travis.yml | 15 +- src/main/scala/vexriscv/Services.scala | 2 +- src/main/scala/vexriscv/demo/Linux.scala | 16 ++- .../scala/vexriscv/demo/MuraxUtiles.scala | 5 + .../scala/vexriscv/plugin/CsrPlugin.scala | 8 +- .../vexriscv/plugin/DBusCachedPlugin.scala | 3 +- .../vexriscv/plugin/DecoderSimplePlugin.scala | 10 +- .../plugin/HaltOnExceptionPlugin.scala | 2 +- .../vexriscv/plugin/IBusSimplePlugin.scala | 20 +-- .../scala/vexriscv/plugin/MmuPlugin.scala | 3 - src/test/cpp/regression/main.cpp | 130 +++++++++++++++--- src/test/cpp/regression/makefile | 30 ++++ src/test/resources/VexRiscvRegressionData | 1 + .../vexriscv/TestIndividualFeatures.scala | 56 ++++---- 15 files changed, 222 insertions(+), 82 deletions(-) create mode 100644 .gitmodules create mode 160000 src/test/resources/VexRiscvRegressionData diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..ab5c2daa --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "src/test/resources/VexRiscvRegressionData"] + path = src/test/resources/VexRiscvRegressionData + url = ../VexRiscvRegressionData.git diff --git a/.travis.yml b/.travis.yml index ee009743..832ba005 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,8 +11,8 @@ scala: sbt_args: -no-colors -J-Xss2m script: - - export VEXRISCV_REGRESSION_CONFIG_COUNT=100 - export VEXRISCV_REGRESSION_FREERTOS_COUNT=no + - export VEXRISCV_REGRESSION_THREAD_COUNT=1 - sbt -jvm-opts travis/jvmopts.compile compile - sbt -jvm-opts travis/jvmopts.test test @@ -22,7 +22,11 @@ jdk: # - openjdk7 env: - - secure: "v7FHP8yK/zixpv1ML05qcRhZfDVDFdTmTPjfMZHL7gmrJveVDgze22x4tY4tB1+JEXhKuVTYvimOrX/Ok+rOOT5gVKLowv4PUQwCR+HgWVIbqjcfZNLsa369v03/p4K/zbjJSiXFahZYOXa0ApED2KWHcVfCrNsPv0UF7YZGiIa1Q/lPBwfmpN1rLih2Mpgn4KVaJky22t7JXJyVrNdGVmIA51slVbyFwFAE8Ww/0tkC+i2PUcWWRMIxtXP4iyq/9Npcq5VdqOatKfWHqAElLfKSPNMYLMlcyxyNpNx4paq8cL6fQxFcBLi9M2msz2i/qpKv30a0tzNo5bQQgucAXOQJB2Buks728upLuqsr+k25hwcqrtjyMOr9UQkt7qXAJH/0kimW7aW1yoMxbm/6mNG98X9D1EzNRewHAKatwJeFy1bw5qIuSQxPBwQMGloManrHOHGotmHKk7Y+dgM/z1UlaAdxSQuKWGXBc8QlQvif8puPYEdJMoInJNRxiWfYu06XnmzTXgMketK7RdULM9DVYzw8hzS2EIWKu8Oa0zn0PTevD2YeJNd4G8mDqO0vz5hloIc7pFsq/exQUB/kFozfCsnvhW8P+MPN0LpuSpptBQTsLWbM5BH0hd46HoWcneDdlMvVrUcgsTPmmSroIkLIEUo+Y2iN5eQHPPp85Cw=" + - VEXRISCV_REGRESSION_CONFIG_COUNT=0 + - VEXRISCV_REGRESSION_CONFIG_COUNT=5 + - VEXRISCV_REGRESSION_CONFIG_COUNT=5 + - VEXRISCV_REGRESSION_CONFIG_COUNT=5 + - VEXRISCV_REGRESSION_CONFIG_COUNT=5 before_install: # JDK fix @@ -34,11 +38,9 @@ before_install: # Verilator - sudo apt-get install git make autoconf g++ flex bison -y # First time prerequisites - - git clone http://git.veripool.org/git/verilator # Only first time - - unset VERILATOR_ROOT # For bash + - wget https://www.veripool.org/ftp/verilator-4.012.tgz + - tar xvzf verilator*.t*gz - cd verilator - - git pull # Make sure we're up-to-date - - git checkout verilator_3_916 - autoconf # Create ./configure script - ./configure - make -j$(nproc) @@ -48,6 +50,7 @@ before_install: - git clone https://github.com/SpinalHDL/SpinalHDL.git -b dev - cd VexRiscv + - git submodule update --init --recursive #- curl -T README.md -udolu1990:$BINTRAY_KEY https://api.bintray.com/content/spinalhdl/VexRiscv/test/0.0.4/README.md #- curl -X POST -udolu1990:$BINTRAY_KEY https://api.bintray.com/content/spinalhdl/VexRiscv/test/0.0.4/publish #- sbt compile diff --git a/src/main/scala/vexriscv/Services.scala b/src/main/scala/vexriscv/Services.scala index 26ecf845..09cd0982 100644 --- a/src/main/scala/vexriscv/Services.scala +++ b/src/main/scala/vexriscv/Services.scala @@ -33,7 +33,7 @@ case class ExceptionCause() extends Bundle{ trait ExceptionService{ def newExceptionPort(stage : Stage, priority : Int = 0) : Flow[ExceptionCause] - def isExceptionPending() : Bool + def isExceptionPending(stage : Stage) : Bool } trait PrivilegeService{ diff --git a/src/main/scala/vexriscv/demo/Linux.scala b/src/main/scala/vexriscv/demo/Linux.scala index fe60056b..9b32dc94 100644 --- a/src/main/scala/vexriscv/demo/Linux.scala +++ b/src/main/scala/vexriscv/demo/Linux.scala @@ -40,13 +40,13 @@ cd VexRiscv Run regressions => sbt "runMain vexriscv.demo.LinuxGen -r" cd src/test/cpp/regression -make run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD DHRYSTONE=yes SUPERVISOR=yes CSR=yes COMPRESSED=no LRSC=yes AMO=yes REDO=10 TRACE=no +make clean run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD DHRYSTONE=yes SUPERVISOR=yes MMU=yes CSR=yes COMPRESSED=no MUL=yes DIV=yes LRSC=yes AMO=yes REDO=10 TRACE=no COREMARK=yes LINUX_REGRESSION=yes Run linux in simulation (Require the machime mode emulator compiled in SIM mode) => sbt "runMain vexriscv.demo.LinuxGen" cd src/test/cpp/regression export BUILDROOT=/home/miaou/pro/riscv/buildrootSpinal -make run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD SUPERVISOR=yes CSR=yes COMPRESSED=no LRSC=yes AMO=yes REDO=0 DHRYSTONE=no LINUX_SOC=yes EMULATOR=../../../main/c/emulator/build/emulator.bin VMLINUX=$BUILDROOT/output/images/Image DTB=$BUILDROOT/board/spinal/vexriscv_sim/rv32.dtb RAMDISK=$BUILDROOT/output/images/rootfs.cpio TRACE=no FLOW_INFO=no +make clean run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD SUPERVISOR=yes CSR=yes COMPRESSED=no LRSC=yes AMO=yes REDO=0 DHRYSTONE=no LINUX_SOC=yes EMULATOR=../../../main/c/emulator/build/emulator.bin VMLINUX=$BUILDROOT/output/images/Image DTB=$BUILDROOT/board/spinal/vexriscv_sim/rv32.dtb RAMDISK=$BUILDROOT/output/images/rootfs.cpio WITH_USER_IO=yes TRACE=no FLOW_INFO=no Run linux with QEMU (Require the machime mode emulator compiled in QEMU mode) export BUILDROOT=/home/miaou/pro/riscv/buildrootSpinal @@ -94,10 +94,12 @@ rm VexRiscv.v cp $DATA/VexRiscv.v ../../../.. make run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD SUPERVISOR=yes CSR=yes COMPRESSED=no LRSC=yes AMO=yes REDO=0 DHRYSTONE=no LINUX_SOC=yes EMULATOR=$DATA/emulator.bin VMLINUX=$DATA/vmlinux.bin DTB=$DATA/rv32.dtb RAMDISK=$DATA/rootfs.cpio TRACE=no FLOW_INFO=no +make clean run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD DHRYSTONE=no SUPERVISOR=yes CSR=yes COMPRESSED=no MUL=yes DIV=yes LRSC=yes AMO=yes MMU=yes REDO=1 TRACE=no LINUX_REGRESSION=yes qemu-system-riscv32 -nographic -machine virt -m 1536M -device loader,file=$DATA/emulator.bin,addr=0x80000000,cpu-num=0 -device loader,file=$DATA/rv32.dtb,addr=0xC3000000 -device loader,file=$DATA/vmlinux.bin,addr=0xC0000000 -device loader,file=$DATA/rootfs.cpio,addr=0xc2000000 +make run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD DHRYSTONE=yess SUPERVISOR=yes CSR=yes COMPRESSED=yes MUL=yes DIV=yes LRSC=yes AMO=yes REDO=1 TRACE=no LINUX_REGRESSION=yes program ../../../main/c/emulator/build/emulator.bin 0x80000000 verify soc.loadBin(EMULATOR, 0x80000000); @@ -149,12 +151,12 @@ object LinuxGen { new IBusCachedPlugin( resetVector = 0x80000000l, compressedGen = false, - prediction = DYNAMIC_TARGET, + prediction = NONE, injectorStage = false, config = InstructionCacheConfig( - cacheSize = 4096*4, + cacheSize = 4096*1, bytePerLine = 32, - wayCount = 4, + wayCount = 1, addressWidth = 32, cpuDataWidth = 32, memDataWidth = 32, @@ -184,9 +186,9 @@ object LinuxGen { dBusCmdSlavePipe = true, dBusRspSlavePipe = true, config = new DataCacheConfig( - cacheSize = 4096*4, + cacheSize = 4096*1, bytePerLine = 32, - wayCount = 4, + wayCount = 1, addressWidth = 32, cpuDataWidth = 32, memDataWidth = 32, diff --git a/src/main/scala/vexriscv/demo/MuraxUtiles.scala b/src/main/scala/vexriscv/demo/MuraxUtiles.scala index 24224507..4e650d38 100644 --- a/src/main/scala/vexriscv/demo/MuraxUtiles.scala +++ b/src/main/scala/vexriscv/demo/MuraxUtiles.scala @@ -163,3 +163,8 @@ class MuraxApb3Timer extends Component{ 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 diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 8057071b..3c7b036f 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -327,8 +327,8 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception interface } - var exceptionPending : Bool = null - override def isExceptionPending(): Bool = exceptionPending + var exceptionPendings : Vec[Bool] = null + override def isExceptionPending(stage : Stage): Bool = exceptionPendings(pipeline.stages.indexOf(stage)) var jumpInterface : Flow[UInt] = null var timerInterrupt, externalInterrupt, softwareInterrupt : Bool = null @@ -420,7 +420,7 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception jumpInterface.valid := False jumpInterface.payload.assignDontCare() - exceptionPending = False + exceptionPendings = Vec(Bool, pipeline.stages.length) timerInterrupt = in Bool() setName("timerInterrupt") externalInterrupt = in Bool() setName("externalInterrupt") softwareInterrupt = in Bool() setName("softwareInterrupt") default(False) @@ -721,7 +721,7 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception //Avoid the PC register of the last stage to change durring an exception handleing (Used to fill Xepc) stages.last.dontSample.getOrElseUpdate(PC, ArrayBuffer[Bool]()) += exceptionValids.last - exceptionPending setWhen(exceptionValidsRegs.orR) + exceptionPendings := exceptionValidsRegs } else null diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index b48386c5..78af84f9 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -292,7 +292,8 @@ class DBusCachedPlugin(config : DataCacheConfig, val forceDatapath = False when(dBusAccess.cmd.valid){ decode.arbitration.haltByOther := True - when(!stagesFromExecute.map(_.arbitration.isValid).orR && !pipeline.service(classOf[ExceptionService]).isExceptionPending()){ + val exceptionService = pipeline.service(classOf[ExceptionService]) + when(!stagesFromExecute.map(s => s.arbitration.isValid || exceptionService.isExceptionPending(s)).orR){ when(!cache.io.cpu.redo) { cache.io.cpu.execute.isValid := True dBusAccess.cmd.ready := !execute.arbitration.isStuck diff --git a/src/main/scala/vexriscv/plugin/DecoderSimplePlugin.scala b/src/main/scala/vexriscv/plugin/DecoderSimplePlugin.scala index c7135579..22afa269 100644 --- a/src/main/scala/vexriscv/plugin/DecoderSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/DecoderSimplePlugin.scala @@ -66,8 +66,8 @@ class DecoderSimplePlugin(catchIllegalInstruction : Boolean = false, forceLegalI } } - val defaults = mutable.HashMap[Stageable[_ <: BaseType], BaseType]() - val encodings = mutable.HashMap[MaskedLiteral,ArrayBuffer[(Stageable[_ <: BaseType], BaseType)]]() + val defaults = mutable.LinkedHashMap[Stageable[_ <: BaseType], BaseType]() + val encodings = mutable.LinkedHashMap[MaskedLiteral,ArrayBuffer[(Stageable[_ <: BaseType], BaseType)]]() var decodeExceptionPort : Flow[ExceptionCause] = null @@ -105,7 +105,7 @@ class DecoderSimplePlugin(catchIllegalInstruction : Boolean = false, forceLegalI } else { var offset = 0 var defaultValue, defaultCare = BigInt(0) - val offsetOf = mutable.HashMap[Stageable[_ <: BaseType], Int]() + val offsetOf = mutable.LinkedHashMap[Stageable[_ <: BaseType], Int]() //Build defaults value and field offset map stageables.foreach(e => { @@ -191,8 +191,8 @@ object DecodingBench extends App{ object Symplify{ - val cache = mutable.HashMap[Bits,mutable.HashMap[Masked,Bool]]() - def getCache(addr : Bits) = cache.getOrElseUpdate(addr,mutable.HashMap[Masked,Bool]()) + val cache = mutable.LinkedHashMap[Bits,mutable.LinkedHashMap[Masked,Bool]]() + def getCache(addr : Bits) = cache.getOrElseUpdate(addr,mutable.LinkedHashMap[Masked,Bool]()) //Generate terms logic for the given input def logicOf(input : Bits,terms : Seq[Masked]) = terms.map(t => getCache(input).getOrElseUpdate(t,t === input)).asBits.orR diff --git a/src/main/scala/vexriscv/plugin/HaltOnExceptionPlugin.scala b/src/main/scala/vexriscv/plugin/HaltOnExceptionPlugin.scala index fb51f104..6e39948a 100644 --- a/src/main/scala/vexriscv/plugin/HaltOnExceptionPlugin.scala +++ b/src/main/scala/vexriscv/plugin/HaltOnExceptionPlugin.scala @@ -21,7 +21,7 @@ class HaltOnExceptionPlugin() extends Plugin[VexRiscv] with ExceptionService { exceptionPortsInfos += ExceptionPortInfo(interface,stage,priority) interface } - override def isExceptionPending(): Bool = False + override def isExceptionPending(stage : Stage): Bool = False override def build(pipeline: VexRiscv): Unit = { diff --git a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala index 0532d269..5b1d7ef9 100644 --- a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala @@ -220,17 +220,18 @@ class IBusSimplePlugin(resetVector : BigInt, pipeline plug new FetchArea(pipeline) { var cmd = Stream(IBusSimpleCmd()) - iBus.cmd << (if(cmdForkPersistence && !cmdForkOnSecondStage) cmd.s2mPipe() else cmd) + val cmdWithS2mPipe = cmdForkPersistence && (!cmdForkOnSecondStage || mmuBus != null) + iBus.cmd << (if(cmdWithS2mPipe) cmd.s2mPipe() else cmd) //Avoid sending to many iBus cmd val pendingCmd = Reg(UInt(log2Up(pendingMax + 1) bits)) init (0) val pendingCmdNext = pendingCmd + cmd.fire.asUInt - iBus.rsp.fire.asUInt pendingCmd := pendingCmdNext - def cmdForkStage = if(!cmdForkPersistence || !cmdForkOnSecondStage) iBusRsp.stages(if(cmdForkOnSecondStage) 1 else 0) else iBusRsp.stages(1) + val secondStagePersistence = cmdForkPersistence && cmdForkOnSecondStage && !cmdWithS2mPipe + def cmdForkStage = if(!secondStagePersistence) iBusRsp.stages(if(cmdForkOnSecondStage) 1 else 0) else iBusRsp.stages(1) - - val cmdFork = if(!cmdForkPersistence || !cmdForkOnSecondStage) new Area { + val cmdFork = if(!secondStagePersistence) new Area { //This implementation keep the cmd on the bus until it's executed or the the pipeline is flushed def stage = cmdForkStage stage.halt setWhen(stage.input.valid && (!cmd.valid || !cmd.ready)) @@ -255,7 +256,7 @@ class IBusSimplePlugin(resetVector : BigInt, mmuBus.cmd.isValid := cmdForkStage.input.valid mmuBus.cmd.virtualAddress := cmdForkStage.input.payload mmuBus.cmd.bypassTranslation := False - mmuBus.end := !cmdForkStage.output.fire || flush + mmuBus.end := cmdForkStage.output.fire || flush cmd.pc := mmuBus.rsp.physicalAddress(31 downto 2) @@ "00" @@ -265,7 +266,10 @@ class IBusSimplePlugin(resetVector : BigInt, cmd.valid := False } - cmdForkStage.halt.setWhen(mmuBus.busy) + when(mmuBus.busy){ + cmdForkStage.input.valid := False + cmdForkStage.input.ready := False + } val joinCtx = stageXToIBusRsp(cmdForkStage, mmuBus.rsp) } @@ -280,7 +284,7 @@ class IBusSimplePlugin(resetVector : BigInt, val discardCounter = Reg(UInt(log2Up(pendingMax + 1) bits)) init (0) discardCounter := discardCounter - (iBus.rsp.fire && discardCounter =/= 0).asUInt when(flush) { - if(cmdForkOnSecondStage && cmdForkPersistence) + if(secondStagePersistence) discardCounter := pendingCmd + cmd.valid.asUInt - iBus.rsp.fire.asUInt else discardCounter := (if(cmdForkOnSecondStage) pendingCmdNext else pendingCmd - iBus.rsp.fire.asUInt) @@ -318,7 +322,7 @@ class IBusSimplePlugin(resetVector : BigInt, if(memoryTranslatorPortConfig != null){ redoRequired setWhen( stages.last.input.valid && mmu.joinCtx.refilling) redoBranch.valid := redoRequired && iBusRsp.readyForError - redoBranch.payload := stages.last.input.payload + redoBranch.payload := decode.input(PC) decode.arbitration.flushAll setWhen(redoBranch.valid) } diff --git a/src/main/scala/vexriscv/plugin/MmuPlugin.scala b/src/main/scala/vexriscv/plugin/MmuPlugin.scala index f8a34183..ebf46c42 100644 --- a/src/main/scala/vexriscv/plugin/MmuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/MmuPlugin.scala @@ -149,8 +149,6 @@ class MmuPlugin(ioRange : UInt => Bool, } val shared = new Area { - val busy = Reg(Bool) init(False) - val State = new SpinalEnum{ val IDLE, L1_CMD, L1_RSP, L0_CMD, L0_RSP = newElement() } @@ -182,7 +180,6 @@ class MmuPlugin(ioRange : UInt => Bool, is(State.IDLE){ for(port <- portsInfo.sortBy(_.priority)){ when(port.bus.cmd.isValid && port.bus.rsp.refilling){ - busy := True vpn(1) := port.bus.cmd.virtualAddress(31 downto 22) vpn(0) := port.bus.cmd.virtualAddress(21 downto 12) portId := port.id diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 518f30ce..5097a267 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -1634,6 +1634,7 @@ public: cout << "FAIL " << name << " at PC=" << hex << setw(8) << top->VexRiscv->writeBack_PC << dec; //<< " seed : " << seed << if(riscvRefEnable) cout << hex << " REF PC=" << riscvRef.lastPc << " REF I=" << riscvRef.lastInstruction << dec; + cout << " time=" << i; cout << endl; cycles += instanceCycles; @@ -3059,29 +3060,22 @@ public: //#endif + #include #include #include - termios stdinRestoreSettings; void stdinNonBuffered(){ static struct termios old, new1; - tcgetattr(STDIN_FILENO, &old); /* grab old terminal i/o settings */ - new1 = old; /* make new settings same as old settings */ - new1.c_lflag &= ~ICANON; /* disable buffered i/o */ + tcgetattr(STDIN_FILENO, &old); // grab old terminal i/o settings + new1 = old; // make new settings same as old settings + new1.c_lflag &= ~ICANON; // disable buffered i/o new1.c_lflag &= ~ECHO; - tcsetattr(STDIN_FILENO, TCSANOW, &new1); /* use these new terminal i/o settings now */ + tcsetattr(STDIN_FILENO, TCSANOW, &new1); // use these new terminal i/o settings now setvbuf(stdin, NULL, _IONBF, 0); stdinRestoreSettings = old; } -void stdoutNonBuffered(){ - setvbuf(stdout, NULL, _IONBF, 0); -} - -void stdinRestore(){ - tcsetattr(STDIN_FILENO, TCSANOW, &stdinRestoreSettings); /* use these new terminal i/o settings now */ -} bool stdinNonEmpty(){ struct timeval tv; @@ -3094,6 +3088,17 @@ bool stdinNonEmpty(){ return (FD_ISSET(0, &fds)); } + +void stdoutNonBuffered(){ + setvbuf(stdout, NULL, _IONBF, 0); +} + +void stdinRestore(){ + tcsetattr(STDIN_FILENO, TCSANOW, &stdinRestoreSettings); +} + + + void my_handler(int s){ printf("Caught signal %d\n",s); stdinRestore(); @@ -3111,23 +3116,39 @@ void captureCtrlC(){ sigaction(SIGINT, &sigIntHandler, NULL); } -#ifdef LINUX_SOC + + + +#if defined(LINUX_SOC) || defined(LINUX_REGRESSION) +#include class LinuxSoc : public Workspace{ public: + queue customCin; + void pushCin(string m){ + for(char& c : m) { + customCin.push(c); + } + } LinuxSoc(string name) : Workspace(name) { + #ifdef WITH_USER_IO stdinNonBuffered(); - stdoutNonBuffered(); captureCtrlC(); + #endif + stdoutNonBuffered(); } virtual ~LinuxSoc(){ + #ifdef WITH_USER_IO stdinRestore(); + #endif } virtual bool isDBusCheckedRegion(uint32_t address){ return true;} virtual bool isPerifRegion(uint32_t addr) { return (addr & 0xF0000000) == 0xF0000000 || (addr & 0xE0000000) == 0xE0000000;} virtual bool isMmuRegion(uint32_t addr) { return true; } + + virtual void dBusAccess(uint32_t addr,bool wr, uint32_t size,uint32_t mask, uint32_t *data, bool *error) { if(isPerifRegion(addr)) switch(addr){ //TODO Emulate peripherals here @@ -3137,18 +3158,24 @@ public: case 0xFFFFFFEC: if(wr) mTimeCmp = (mTimeCmp & 0x00000000FFFFFFFF) | (((uint64_t)*data) << 32); else *data = mTimeCmp >> 32; break; case 0xFFFFFFF8: if(wr){ - cout << (char)*data; - logTraces << (char)*data; + char c = (char)*data; + cout << c; + logTraces << c; logTraces.flush(); + onStdout(c); } else { + #ifdef WITH_USER_IO if(stdinNonEmpty()){ char c; read(0, &c, 1); *data = c; - //cout << "getchar " << c << endl; + } else + #endif + if(!customCin.empty()){ + *data = customCin.front(); + customCin.pop(); } else { *data = -1; - //cout << "getchar NONE" << endl; } } break; @@ -3158,7 +3185,43 @@ public: Workspace::dBusAccess(addr,wr,size,mask,data,error); } + + virtual void onStdout(char c){ + + } }; + + +class LinuxRegression: public LinuxSoc{ +public: + string pendingLine = ""; + bool pendingLineContain(string m) { + return strstr(pendingLine.c_str(), m.c_str()) != NULL; + } + + enum State{LOGIN, ECHO_FILE, HEXDUMP, HEXDUMP_CHECK, PASS}; + State state = LOGIN; + LinuxRegression(string name) : LinuxSoc(name) { + + } + + ~LinuxRegression() { + } + + + virtual void onStdout(char c){ + pendingLine += c; + switch(state){ + case LOGIN: if (pendingLineContain("buildroot login:")) { pushCin("root\n"); state = ECHO_FILE; } break; + case ECHO_FILE: if (pendingLineContain("# ")) { pushCin("echo \"miaou\" > test.txt\n"); state = HEXDUMP; pendingLine = "";} break; + case HEXDUMP: if (pendingLineContain("# ")) { pushCin("hexdump -C test.txt\n"); state = HEXDUMP_CHECK; pendingLine = "";} break; + case HEXDUMP_CHECK: if (pendingLineContain("00000000 6d 69 61 6f 75 0a ")) { pushCin(""); state = PASS; pendingLine = "";} break; + case PASS: if (pendingLineContain("# ")) { pass(); } break; + } + if(c == '\n' || pendingLine.length() > 200) pendingLine = ""; + } +}; + #endif string riscvTestMain[] = { @@ -3490,7 +3553,7 @@ int main(int argc, char **argv, char **env) { soc.loadBin(DTB, 0xC3000000); soc.loadBin(RAMDISK, 0xC2000000); #endif - //soc.setIStall(true); //TODO It currently improve speed but should be removed later + //soc.setIStall(true); //soc.setDStall(true); soc.bootAt(0x80000000); soc.run(0); @@ -3500,6 +3563,10 @@ int main(int argc, char **argv, char **env) { } #endif + + + + // #ifdef MMU // redo(REDO,WorkspaceRegression("mmu").withRiscvRef()->loadHex("../raw/mmu/build/mmu.hex")->bootAt(0x80000000u)->run(50e3);); // #endif @@ -3722,15 +3789,36 @@ int main(int argc, char **argv, char **env) { queue > tasksSelected(std::deque>(tasks.begin(), tasks.end())); multiThreadedExecute(tasksSelected); #endif + + #if defined(LINUX_REGRESSION) + { + + LinuxRegression soc("linux"); + #ifndef DEBUG_PLUGIN_EXTERNAL + soc.withRiscvRef(); + soc.loadBin(EMULATOR, 0x80000000); + soc.loadBin(VMLINUX, 0xC0000000); + soc.loadBin(DTB, 0xC3000000); + soc.loadBin(RAMDISK, 0xC2000000); + #endif + //soc.setIStall(true); + //soc.setDStall(true); + soc.bootAt(0x80000000); + soc.run(153995602l*6); +// soc.run((470000000l + 2000000) / 2); +// soc.run(438700000l/2); + } + #endif + } uint64_t duration = timer_end(startedAt); cout << endl << "****************************************************************" << endl; cout << "Had simulate " << Workspace::cycles << " clock cycles in " << duration*1e-9 << " s (" << Workspace::cycles / (duration*1e-6) << " Khz)" << endl; if(Workspace::successCounter == Workspace::testsCounter) - cout << "SUCCESS " << Workspace::successCounter << "/" << Workspace::testsCounter << endl; + cout << "REGRESSION SUCCESS " << Workspace::successCounter << "/" << Workspace::testsCounter << endl; else - cout<< "FAILURE " << Workspace::testsCounter - Workspace::successCounter << "/" << Workspace::testsCounter << endl; + cout<< "REGRESSION FAILURE " << Workspace::testsCounter - Workspace::successCounter << "/" << Workspace::testsCounter << endl; cout << "****************************************************************" << endl << endl; diff --git a/src/test/cpp/regression/makefile b/src/test/cpp/regression/makefile index d82a3e47..9c4294fe 100644 --- a/src/test/cpp/regression/makefile +++ b/src/test/cpp/regression/makefile @@ -34,6 +34,7 @@ COMPRESSED?=no SUPERVISOR?=no STOP_ON_ERROR?=no COREMARK=no +WITH_USER_IO?=no ADDCFLAGS += -CFLAGS -DIBUS_${IBUS} ADDCFLAGS += -CFLAGS -DDBUS_${DBUS} @@ -66,6 +67,31 @@ ifeq ($(LINUX_SOC),yes) ADDCFLAGS += -CFLAGS -DEMULATOR='\"$(EMULATOR)\"' endif +ARCH_LINUX=rv32i +ifeq ($(MUL),yes) +ifeq ($(DIV),yes) +ARCH_LINUX:=$(ARCH_LINUX)m +endif +endif +ARCH_LINUX:=$(ARCH_LINUX)a +ifeq ($(COMPRESSED),yes) +ARCH_LINUX:=$(ARCH_LINUX)c +endif + +ifeq ($(LINUX_REGRESSION),yes) +ifneq ($(ARCH_LINUX),rv32iac) +ifneq ($(ARCH_LINUX),rv32ia) + ADDCFLAGS += -CFLAGS -DLINUX_REGRESSION + ADDCFLAGS += -CFLAGS -DARCH_LINUX='\"$(ARCH_LINUX)\"' + ADDCFLAGS += -CFLAGS -DVMLINUX='\"../../resources/VexRiscvRegressionData/sim/linux/$(ARCH_LINUX)/Image\"' + ADDCFLAGS += -CFLAGS -DDTB='\"../../resources/VexRiscvRegressionData/sim/linux/$(ARCH_LINUX)/rv32.dtb\"' + ADDCFLAGS += -CFLAGS -DRAMDISK='\"../../resources/VexRiscvRegressionData/sim/linux/$(ARCH_LINUX)/rootfs.cpio\"' + ADDCFLAGS += -CFLAGS -DEMULATOR='\"../../resources/VexRiscvRegressionData/sim/linux/emulator/emulator.bin\"' +endif +endif +endif + + ifeq ($(FLOW_INFO),yes) ADDCFLAGS += -CFLAGS -DFLOW_INFO endif @@ -93,6 +119,10 @@ endif ifeq ($(IBUS_TC),yes) ADDCFLAGS += -CFLAGS -DIBUS_TC=yes endif +ifeq ($(WITH_USER_IO),yes) + ADDCFLAGS += -CFLAGS -DWITH_USER_IO=yes +endif + ifeq ($(COMPRESSED),yes) ADDCFLAGS += -CFLAGS -DCOMPRESSED diff --git a/src/test/resources/VexRiscvRegressionData b/src/test/resources/VexRiscvRegressionData new file mode 160000 index 00000000..77b66d30 --- /dev/null +++ b/src/test/resources/VexRiscvRegressionData @@ -0,0 +1 @@ +Subproject commit 77b66d304f888369176fb9ac2f9d6302dd4d276d diff --git a/src/test/scala/vexriscv/TestIndividualFeatures.scala b/src/test/scala/vexriscv/TestIndividualFeatures.scala index 5275cfa8..034527c6 100644 --- a/src/test/scala/vexriscv/TestIndividualFeatures.scala +++ b/src/test/scala/vexriscv/TestIndividualFeatures.scala @@ -49,6 +49,11 @@ object VexRiscvUniverse{ val universes = List(CATCH_ALL, MMU) } + +object Hack{ + var dCounter = 0 +} + class ShiftDimension extends VexRiscvDimension("Shift") { override def randomPositionImpl(universes: Seq[ConfigUniverse], r: Random) = random(r, List( new VexRiscvPosition("FullLate") { @@ -287,13 +292,14 @@ class IBusDimension extends VexRiscvDimension("IBus") { override def instructionAnticipatedOk() = injectorStage } } else { + val catchAll = universes.contains(VexRiscvUniverse.CATCH_ALL) val compressed = r.nextBoolean() - val tighlyCoupled = r.nextBoolean() + val tighlyCoupled = r.nextBoolean() && !catchAll // val tighlyCoupled = false val prediction = random(r, List(NONE, STATIC, DYNAMIC, DYNAMIC_TARGET)) - val catchAll = universes.contains(VexRiscvUniverse.CATCH_ALL) val relaxedPcCalculation, twoCycleCache, injectorStage = r.nextBoolean() val twoCycleRam = r.nextBoolean() && twoCycleCache + val bytePerLine = List(8,16,32,64)(r.nextInt(4)) var cacheSize = 0 var wayCount = 0 do{ @@ -301,7 +307,7 @@ class IBusDimension extends VexRiscvDimension("IBus") { wayCount = 1 << r.nextInt(3) }while(cacheSize/wayCount < 512 || (catchAll && cacheSize/wayCount > 4096)) - new VexRiscvPosition("Cached" + (if(twoCycleCache) "2cc" else "") + (if(injectorStage) "Injstage" else "") + (if(twoCycleRam) "2cr" else "") + "S" + cacheSize + "W" + wayCount + (if(relaxedPcCalculation) "Relax" else "") + (if(compressed) "Rvc" else "") + prediction.getClass.getTypeName().replace("$","")+ (if(tighlyCoupled)"Tc" else "")) with InstructionAnticipatedPosition{ + new VexRiscvPosition("Cached" + (if(twoCycleCache) "2cc" else "") + (if(injectorStage) "Injstage" else "") + (if(twoCycleRam) "2cr" else "") + "S" + cacheSize + "W" + wayCount + "BPL" + bytePerLine + (if(relaxedPcCalculation) "Relax" else "") + (if(compressed) "Rvc" else "") + prediction.getClass.getTypeName().replace("$","")+ (if(tighlyCoupled)"Tc" else "")) with InstructionAnticipatedPosition{ override def testParam = "IBUS=CACHED" + (if(compressed) " COMPRESSED=yes" else "") + (if(tighlyCoupled)" IBUS_TC=yes" else "") override def applyOn(config: VexRiscvConfig): Unit = { val p = new IBusCachedPlugin( @@ -313,7 +319,7 @@ class IBusDimension extends VexRiscvDimension("IBus") { memoryTranslatorPortConfig = mmuConfig, config = InstructionCacheConfig( cacheSize = cacheSize, - bytePerLine = 32, + bytePerLine = bytePerLine, wayCount = wayCount, addressWidth = 32, cpuDataWidth = 32, @@ -344,32 +350,37 @@ class DBusDimension extends VexRiscvDimension("DBus") { val mmuConfig = if(catchAll) MmuPortConfig( portTlbSize = 4) else null if(r.nextDouble() < 0.4){ + val withLrSc = catchAll val earlyInjection = r.nextBoolean() new VexRiscvPosition("Simple" + (if(earlyInjection) "Early" else "Late")) { - override def testParam = "DBUS=SIMPLE" + override def testParam = "DBUS=SIMPLE " + (if(withLrSc) "LRSC=yes " else "") override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new DBusSimplePlugin( catchAddressMisaligned = catchAll, catchAccessFault = catchAll, earlyInjection = earlyInjection, - memoryTranslatorPortConfig = mmuConfig + memoryTranslatorPortConfig = mmuConfig, + withLrSc = withLrSc ) // override def isCompatibleWith(positions: Seq[ConfigPosition[VexRiscvConfig]]) = catchAll == positions.exists(_.isInstanceOf[CatchAllPosition]) } } else { + val bytePerLine = List(8,16,32,64)(r.nextInt(4)) var cacheSize = 0 var wayCount = 0 + val withLrSc = catchAll + val withAmo = catchAll && r.nextBoolean() do{ cacheSize = 512 << r.nextInt(5) wayCount = 1 << r.nextInt(3) }while(cacheSize/wayCount < 512 || (catchAll && cacheSize/wayCount > 4096)) - new VexRiscvPosition("Cached" + "S" + cacheSize + "W" + wayCount) { - override def testParam = "DBUS=CACHED" + new VexRiscvPosition("Cached" + "S" + cacheSize + "W" + wayCount + "BPL" + bytePerLine) { + override def testParam = "DBUS=CACHED " + (if(withLrSc) "LRSC=yes " else "") + (if(withAmo) "AMO=yes " else "") override def applyOn(config: VexRiscvConfig): Unit = { config.plugins += new DBusCachedPlugin( config = new DataCacheConfig( cacheSize = cacheSize, - bytePerLine = 32, + bytePerLine = bytePerLine, wayCount = wayCount, addressWidth = 32, cpuDataWidth = 32, @@ -377,7 +388,8 @@ class DBusDimension extends VexRiscvDimension("DBus") { catchAccessError = catchAll, catchIllegal = catchAll, catchUnaligned = catchAll, - withLrSc = false + withLrSc = withLrSc, + withAmo = withAmo ), memoryTranslatorPortConfig = mmuConfig ) @@ -421,14 +433,14 @@ class MmuDimension extends VexRiscvDimension("DBus") { trait CatchAllPosition -//TODO CSR without exception + class CsrDimension(freertos : String) extends VexRiscvDimension("Csr") { override def randomPositionImpl(universes: Seq[ConfigUniverse], r: Random) = { val catchAll = universes.contains(VexRiscvUniverse.CATCH_ALL) if(catchAll){ new VexRiscvPosition("All") with CatchAllPosition{ override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new CsrPlugin(CsrPluginConfig.linuxFull(0x80000020l)) - override def testParam = s"FREERTOS=$freertos" + override def testParam = s"FREERTOS=$freertos LINUX_REGRESSION=yes SUPERVISOR=yes" } } else if(r.nextDouble() < 0.2){ new VexRiscvPosition("AllNoException") with CatchAllPosition{ @@ -504,7 +516,7 @@ class TestIndividualFeatures extends FunSuite { new HazardDimension, new RegFileDimension, new SrcDimension, - new CsrDimension(sys.env.getOrElse("VEXRISCV_REGRESSION_FREERTOS_COUNT", "yes")), + new CsrDimension("no"),//sys.env.getOrElse("VEXRISCV_REGRESSION_FREERTOS_COUNT", "4")), TODO new DecoderDimension, new DebugDimension, new MmuDimension @@ -541,14 +553,14 @@ class TestIndividualFeatures extends FunSuite { test(prefix + name + "_test") { - val debug = false - val stdCmd = (if(debug) "make clean run REDO=1 TRACE=yes TRACE_ACCESS=yes STOP_ON_ERROR=yes DHRYSTONE=no THREAD_COUNT=1 TRACE_START=0 " else s"make clean run REDO=10 TRACE=no THREAD_COUNT=${sys.env.getOrElse("VEXRISCV_REGRESSION_THREAD_COUNT", Runtime.getRuntime().availableProcessors().toString)} ") + s" SEED=${testSeed} " + val debug = true + val stdCmd = (s"make clean run WITH_USER_IO=no REDO=10 TRACE=${if(debug) "yes" else "no"} TRACE_START=9999924910246l FLOW_INFO=no STOP_ON_ERROR=no DHRYSTONE=yes COREMARK=yes THREAD_COUNT=${sys.env.getOrElse("VEXRISCV_REGRESSION_THREAD_COUNT", Runtime.getRuntime().availableProcessors().toString)} ") + s" SEED=${testSeed} " // val stdCmd = "make clean run REDO=40 DHRYSTONE=no STOP_ON_ERROR=yes TRACE=yess " val testCmd = stdCmd + (positionsToApply).map(_.testParam).mkString(" ") println(testCmd) val str = doCmd(testCmd) - assert(!str.contains("FAIL") && !str.contains("Broken pipe")) + assert(str.contains("REGRESSION SUCCESS") && !str.contains("Broken pipe")) // val intFind = "(\\d+\\.?)+".r // val dmips = intFind.findFirstIn("DMIPS per Mhz\\: (\\d+.?)+".r.findAllIn(str).toList.last).get.toDouble } @@ -556,8 +568,8 @@ class TestIndividualFeatures extends FunSuite { // dimensions.foreach(d => d.positions.foreach(p => p.dimension = d)) -// val testId : Option[mutable.HashSet[Int]] = None -// val seed = Random.nextLong() + val testId : Option[mutable.HashSet[Int]] = None + val seed = Random.nextLong() // val testId = Some(mutable.HashSet(18,34,77,85,118,129,132,134,152,167,175,188,191,198,199)) //37/29 sp_flop_rv32i_O3 //val testId = Some(mutable.HashSet(18)) @@ -565,13 +577,6 @@ class TestIndividualFeatures extends FunSuite { // val seed = -2412372746600605141l -//// val testId = Some(mutable.HashSet[Int](0,28,45,93)) - val testId = Some(mutable.HashSet[Int](69, 43)) -//val testId = Some(mutable.HashSet[Int]( 43)) - val seed = -8485282932516819277l - - - val rand = new Random(seed) test("Info"){ @@ -589,6 +594,7 @@ class TestIndividualFeatures extends FunSuite { val testSeed = rand.nextInt() if(testId.isEmpty || testId.get.contains(i)) doTest(positions," random_" + i + "_", testSeed) + Hack.dCounter += 1 } // println(s"${usedPositions.size}/$positionsCount positions") From a496638c7255449b8604f8a62e4ac7979d4aaf1a Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Fri, 19 Apr 2019 17:38:51 +0200 Subject: [PATCH 155/951] fix travis --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 832ba005..d060307f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -40,8 +40,7 @@ before_install: - sudo apt-get install git make autoconf g++ flex bison -y # First time prerequisites - wget https://www.veripool.org/ftp/verilator-4.012.tgz - tar xvzf verilator*.t*gz - - cd verilator - - autoconf # Create ./configure script + - cd verilator* - ./configure - make -j$(nproc) - sudo make install From 728a5ff20fe811d0a0c19bf59751645d6e6d6203 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Fri, 19 Apr 2019 18:28:46 +0200 Subject: [PATCH 156/951] Fix coremark binaries (no csr) --- .travis.yml | 9 +++++---- src/test/cpp/regression/main.cpp | 4 ++-- src/test/scala/vexriscv/TestIndividualFeatures.scala | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index d060307f..a23c57c7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,10 +23,10 @@ jdk: env: - VEXRISCV_REGRESSION_CONFIG_COUNT=0 - - VEXRISCV_REGRESSION_CONFIG_COUNT=5 - - VEXRISCV_REGRESSION_CONFIG_COUNT=5 - - VEXRISCV_REGRESSION_CONFIG_COUNT=5 - - VEXRISCV_REGRESSION_CONFIG_COUNT=5 + # - VEXRISCV_REGRESSION_CONFIG_COUNT=5 + #- VEXRISCV_REGRESSION_CONFIG_COUNT=5 + #- VEXRISCV_REGRESSION_CONFIG_COUNT=5 + #- VEXRISCV_REGRESSION_CONFIG_COUNT=5 before_install: # JDK fix @@ -64,3 +64,4 @@ cache: directories: - $HOME/.ivy2/cache - $HOME/.sbt/boot/ + - verilator-4.012 \ No newline at end of file diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 5097a267..415ed67a 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -1821,7 +1821,7 @@ public: virtual void preCycle(){ if (top->iBusTc_enable) { - if((top->iBusTc_address & 0x70000000) != 0 || (top->iBusTc_address & 0x20) == 0){ + if((top->iBusTc_address & 0x70000000) != 0){ printf("IBusTc access out of range\n"); ws->fail(); } @@ -1921,7 +1921,7 @@ public: top->iBus_rsp_valid = 0; if(pendingCount != 0 && (!ws->iStall || VL_RANDOM_I(7) < 100)){ #ifdef IBUS_TC - if((address & 0x70000000) == 0 && (address & 0x20) != 0){ + if((address & 0x70000000) == 0){ printf("IBUS_CACHED access out of range\n"); ws->fail(); } diff --git a/src/test/scala/vexriscv/TestIndividualFeatures.scala b/src/test/scala/vexriscv/TestIndividualFeatures.scala index 034527c6..1c72c51f 100644 --- a/src/test/scala/vexriscv/TestIndividualFeatures.scala +++ b/src/test/scala/vexriscv/TestIndividualFeatures.scala @@ -331,7 +331,7 @@ class IBusDimension extends VexRiscvDimension("IBus") { twoCycleCache = twoCycleCache ) ) - if(tighlyCoupled) p.newTightlyCoupledPort(TightlyCoupledPortParameter("iBusTc", a => a(30 downto 28) === 0x0 && a(5))) + if(tighlyCoupled) p.newTightlyCoupledPort(TightlyCoupledPortParameter("iBusTc", a => a(30 downto 28) === 0x0)) config.plugins += p } override def instructionAnticipatedOk() = !twoCycleCache || ((!twoCycleRam || wayCount == 1) && !compressed) From ac5517f19952093574ee4ae40453021998a6c8a8 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Fri, 19 Apr 2019 18:33:04 +0200 Subject: [PATCH 157/951] Travis : Bring back random regressions --- .travis.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index a23c57c7..d4b1155b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,10 +23,10 @@ jdk: env: - VEXRISCV_REGRESSION_CONFIG_COUNT=0 - # - VEXRISCV_REGRESSION_CONFIG_COUNT=5 - #- VEXRISCV_REGRESSION_CONFIG_COUNT=5 - #- VEXRISCV_REGRESSION_CONFIG_COUNT=5 - #- VEXRISCV_REGRESSION_CONFIG_COUNT=5 + - VEXRISCV_REGRESSION_CONFIG_COUNT=5 + - VEXRISCV_REGRESSION_CONFIG_COUNT=5 + - VEXRISCV_REGRESSION_CONFIG_COUNT=5 + - VEXRISCV_REGRESSION_CONFIG_COUNT=5 before_install: # JDK fix From b49076ecab7aafc3142d05e654d833026d3b0bac Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Fri, 19 Apr 2019 19:41:05 +0200 Subject: [PATCH 158/951] add missing coremark patch --- src/test/resources/bin/coremark_rv32i.bin | Bin 24368 -> 24352 bytes src/test/resources/bin/coremark_rv32ic.bin | Bin 17824 -> 17808 bytes src/test/resources/bin/coremark_rv32im.bin | Bin 22776 -> 22760 bytes src/test/resources/bin/coremark_rv32imc.bin | Bin 17080 -> 17064 bytes 4 files changed, 0 insertions(+), 0 deletions(-) diff --git a/src/test/resources/bin/coremark_rv32i.bin b/src/test/resources/bin/coremark_rv32i.bin index 71e2911cae6050dafcdcbd344790d33169e28ef9..eb6e7e73b239040b488d9e362d0a0f9eede58e3b 100755 GIT binary patch delta 1353 zcmbW1ZAep57{|}?-n+ZaNt0{Ma^Ym^h9(UZq!)CWYe<5NlmsOV=Sv{ihYTxWSGTny zDfI+eK@L$Y3{q}lZ-^CA>qGd#k3xbU3Q_N-hJFy~xqD&zuoN2ncF*~r|MUExdl;LT z!QL6H(_BqJ9PZlGR3pSO?)CwA5;xPXX@b4%uD?&0u3H~yltj1K&@qMdItGjuwA?zi zC)!Yxh-N3-_7W1S5kH+H^0^hf3XRDET_T#*w+X`_$qE63P^O)Rb+FX! zeggA66;1QUqT1Xuj+uKdntG2$HH#NCuV}KRhUyd$X&HvS#%cIOaoZZyAZKONSW=*Y zCZA>Hc_VO^%+V>x2^t5pa8)#3wr}l*{D!Ds&gPI;Y|#-E9A)?2&EYzT23`vm}C%qI+vz-wash6kW*Q8S};z`n~&}WQ`CUmXM|8re> z4Y-cSuy2vvZT=yjb2KSHCKS22pDZfU@h!3o>zl-=G~jN*raYu&-gDHKw}L%8pDp)s zhqF*V^9MN%3~J_CG~JANYSgpQ%%kv{-Hfik#^|0vRJR6%rM#}h+~Hp#1FQB^W9*jH zOz#bA!N%-{q&df|8>Hvd5MC2boc=)L72$VLT7u#`x$pbIDSRt}s$>A;MPa0LoCc50 zS}ez+&|9feU36t5UZTJdBGZWY>vf3l0C?aYU7C;yB3g&vV_meH#bs zcFIGZ77OBaafZ=VI^s8}g90-UnZ7<8RuvPv3e7XEaQE1;%Sn<9{gp%@koF@999z(Y9#Nj)M{_QZ>1A(0T>~q1mF)c`1uRe1Hv`{ delta 1370 zcmbW1Ur19?9LLY`-s`>d4^6H$%Y~Dn3r)JFC8(5X)`NKy2|TD-bGY2m z1w6fgb(-rbh{wG_&1Hmm#@*$GCvh`fnpRk+-u?YRmnX>H7DaUXo4RL_UdMp37Ol6> z?s^gEqKI#L)JEB2YLyYf9SFU-wwsdPg2cHZr6wa18%J_g^<|Jrm~>?t5Aib^{E%>|#m)d#&`XhQ8k4Vdm26V?5QagD z7dkwKJnbCB;as=-2@LpD7FLeLwWVR6SsIZA&*8XMI|kaAELd_Pc`D^#&tR=_8QxR; zjs`VxY$`R88EB%(Oln=pIP7KdbT)E<#=|Up1C7_4gQ1Au5chLz5gBGH4)xt842^iV z?*)vQ7E2`#HW#j9h&`V_31gg zwJe|;9sciI$}!+N9>LnCxI6qKKG%3=fQ+h&F(J#UJlsQmL41qkq#3YFGNm2RGV?t3 z;hoe_SjyIY;tv*}QsxhG85q9~1PxKwLKmq?MB1^x~kd1miIzidH1{10G-qumD!T2G{`|a2zNHY5;#D z5<>t7aW+|Nl$;wSNPG({0?WWEFbUYJ!C4i-mJr9Z#HTg7Z%Od|fZPl9Fx}ZbaqegM z=e}@e&%)t6?p(yvU5i8^$uL5_GkKAANU#90={uv%niHCa>X2wO!`;IP{~PBX$wp|l zU*QcHLh(3YSZ$JFl4**+6Z{Rp(O3g}w3#iTX*qd$wNZNq-j@Mj5Ww&iOatJH8UFnR Doxsi6 diff --git a/src/test/resources/bin/coremark_rv32ic.bin b/src/test/resources/bin/coremark_rv32ic.bin index 24975db5818995df4908043ac267ea759f685bba..a4a13918aba69050b933c2a7e36fb36c8fcfae17 100755 GIT binary patch delta 1367 zcmbV|TS!zv7{_OJclP8h%&jc7_ADEUn7Uh(`cSB`S|p^Dx?bu*!Ikp%klIswQcogQ zXk%?egi5lpPs%|QHLy&~7b)l=N=UqrUGS(ZX;RWR?yhcO3LW^JnfZVJ?=sWch?^QQ zADpB>8hj%+*o2UVn8t0eQgQf0a0;B&H?y1hP+g{5%qpzzMtYv0U1X}XdsQ~PPT$Yt z)*7L!BvyfE=p#iaHq%~30{j;hCj6DgE93AStx!sMk{(j&@d7=qiqbn}p0A2CA>q9U zEx*frVr8xff4xIws)h_N(fcZ$)m)HCcdPL8I@!>K*JGkW-05xl*oUDSvTJK^S+ z{&W%xb5VbFq+cLRoa>6xMD-rLmu9JLcpsfphn^3D$7im{1psuudc+VHTJNmVr)S0C)ww1q9$0 z@BnxMqyzatF>sY$OqQ&ZS|s!VFM%=O9nc9lqLGm1rrm4r(Y)7(?)Y6V-x1gk#v#FJ z*b?h@hJVHrW40{3miOYQ%M%DgI5ru^5og`Jh%Y28$8N+*+|7!-nhrqmDkJ!q_kXc& zk(dn4wkzy_A($r!DA;6}%{1os2Ug&M2RseR+|7!;nx@c5Q(o9~5)!@vP5>i>e1Rf> GeZK)3Uhvxh delta 1383 zcmbu9T}TvB7>3W;nX|KQO4<~QuI1>0W@YVGw0V)JwMt}|hT85*h=L2H7KP?Tw3F^A zV#&%O_NEIJMDb215tP6X5ksQFi-;7-{)}KuET!z{8+TW?FuiEtnK|=*@Aq>K!+4u< zTQe3685+dn+fIWGA)eT#eDI{w=qp1OylWdSv-P;c=e4Sq-OXpGoSyEUnBf330MPjoM1#R@H9WIRiEvL?Jh zkF)ztUlc*8vD%RMQi2hd6d}FZA;I0$BdID+Mwe*=8}GK47C;t$<05Q5L^Ih8akg@CMa@V;memYePAq#Oz*G9Sr?t6#OwD>m zqe+s`Ro5Z$Qqy+W`Ncn-#HG6E3Q67;1rs~`QEJxi!Ume9_2Fnbtu>zKVe*{b0d;oR z$9L#>hOqXb`pyVACB-Z_dpvN4k@K}ZQlbR!#liEkeS@B-CAqbE_AdAF?L)PKbO~zA z&>SuvPthta4$sLg+~*x6foDbp*%MEagEL{r`SRC&5)L~| zo5qjvVdMF-=RhvTr{u|$AqG5Ni%W}(f)U3Oq1jf&2Vn@+lK{hB+o0A)n(B`QzaH2fY;Y^ktTv=+A&s^< WV;3`!xB{^7&0zQ`>Va}Vy?z7kd7pp) diff --git a/src/test/resources/bin/coremark_rv32im.bin b/src/test/resources/bin/coremark_rv32im.bin index 6b5b8850c2e3c0fc4f0c4403676b73b2bae2c363..5c45806a9c498e3d860bf6cb001466fd8dc6b042 100755 GIT binary patch delta 1346 zcmbu7O-vI(7=~xqnQj*_0T(PuRZ3b?Xhk=nLK8|UKMhzhfj|M33-V_o2_8IPqUmC7 zs*wU_4)x&01cZYJ$%1&`fQbZRJb2)y2^viFU{Vqx_F#$U!2;vj#sxBHbvA!jpx(g@zH>>vWOFrc%?R=&&l%slkaAWHwPSdeQFK z%AZ(=Cntv1pN(_a$Zm3_IKpPRF8KY*_2M$-BCXiM?vtOmgiX+M*vb}ZU8OB1tzWD4 zBbm`WwWS^Q10t+rlFTtmk$MIls#w0x9*6|XC%Kg3P(lYetcYN?O&Vho>R$zCA}O?S zUZkNKNV<~Is8gi04pJ{?w2%w5`k3VDOV$Z6LC6jJ-k|jjC;l>^K|QbI79x>B!s}`c z?3K=2<$?1~krbgI=pytNy9wSM+W(!bv1V%YdTyHAAgF-nja5}II4U%Hgt;f?Te zp70mTnqkzYw62Y;HK0TrM)VEGyx?-BU93ZI#O-WMzk@HacEMcM3fZ>ty`7kP6?kD1 z>?>6_Xzzma5%@C%BRmUdF<0{!hQ;D?R80?1 z&`Qy$%%jy&By;op%&3e~>#%0ss#){X8P8@!k!_QC_UGS{B44n_E%5tln0YRxC4$4# zsuo<>oMvZgy6{6qu3-d+m7=^B!8$+;?k_sn)WHB&Mg|>GSm+FV5+7=2^?kk=Q(LOG&oVW`R~FFP|!zPyhe` delta 1362 zcmbV~Ur19?9LLY`-m|-_1jD^p4apsB#_PG7_2npEY^&`S)qu`>viVY*b`YK;h~8&WY7~ZI?=v= z?N1DWE{gd1oT?%25ewo7;ZcMZ9x+%;2N)fWP?70^-yNn8SI}Da7Ote@>`#1wJ|%Uy zioPaI)uy<4?#M);*c zLrPA;EQKROET^z&=v#&JGW4={3alChK^LIE(9Pog;lxR*#+a>9a#eJevz1K0q=ZF6 zh;N56-I-GA=gQ#a%y4(g9WZKJM$e73Xi%~ZO>iyeZi362aZ$Un4Bw^w$~}CKT6sgc z3$klQkM`p7qreNh3g>Fs4ch16Vi^7mz6{sVH@ps)&=0%`3-pjTVx6Qa+$$x00>ku5 ziHdse_K0x464jGq6f_d#6FIc*Ln5=t&G|%>-cRT3Z{_T{Xx6h8k;ZB!i%jpoN0K6^ zI%1Z%gdApgm)4TO(@|LqE^S4rwy_JplExY-i)SRZ=_}@abc*#0EIT6|TB8`hkS1&~ z7Cfr<7>C2svU|C(v%!EwnS(Stmyqb_MPdig4fF$QKo8Uc*MS3gOGm&7poH@(tQ){K zuuB(uq`*`SR09KmAD94KfY*k^Z_Oz>a`qW5ceSVQ8*+S~pmy91Q?;E+;4H&G@6|1* z1}E!wohgr}6&@(hFkW{ce~1GLN`cJu9qDHFoTl3l&bA|Q7@qLI37k?~3eC<6UWFlK qPd5zvBTrU7P4>IMuLUk<8hFyp963$3^qKb|?}Bf|19<5dujVi6yrtm) diff --git a/src/test/resources/bin/coremark_rv32imc.bin b/src/test/resources/bin/coremark_rv32imc.bin index c09b83bebb6a6255886d537b32bc014ad806d0c7..69efed77e700db9989404ad9f7362b0a79706e10 100755 GIT binary patch delta 1376 zcmbV~ZAepL6vv-uyU*^F5am{LzFr-&?wq-SCI-!yoR(NwkY#;HFe(J2C=f#0MZFrC zkv*9NeQ=Ojk)d2-VuF;_DoV7#%A&VPZv-$ z3G=!f72+^9>+A?|MCxpXCzVL2E+5VsjnK?T#~OV}`-<|a>&U_ zdryig)X+AEThmcUZN)B7DHSS7!yK_c_VQ($=5u$RK!>L=W8-{IdIq`YFr!HE4Jva-y*w(K*v5U= zA;GO|ZXFe!;9Mfl##uPaA77h)2zXyWNJIyCaO(ZgOlX^ zq!(&zkQ0Sc9HOFi49hW$L9R2c$9S1MnEXf$n)9id8oWXtNslD*_-YHYc`_1-3ZmXe zUKE_OkT?Y}*+^Uh+=h4vcnN$2&H!z|RiFph4IBWffn)Swmh4E211GQ?-~kh$0?sBQ zah0Ew0r6}u@LBJ#9}UpOKzuqKiQ_95#Icy*pY@gI1sl)!?pb}BC9p(wkY%dV9l@Ju zz%Z6FUn}tsD-IZX3z{EJg*yQ4f8$udY=L2mHSU5X6ipaV7G#-VIYqAp-op#V&JNh_ aAGRf6Xc}FUyEEj64T%W;7cF(>>V5-CYwAb< delta 1400 zcmbu7Ye*DP6vyw~nY*K6WQ@4Joo!9qSy$Icd|;+q+tZ$4r9~M=lAusVQXkquodnIu zZec+mR0=D?9+N0pW|XWMMwUovk)#oYuwh0K6`j#lw=n(ChaYq9|NPHm=FTM=KoPtoudtM&wt>C@Z>~C6!B&NPnq;;A^EYepR8@@~D zGx4~MW-&MLE$Yo0@Iz{0O$G;4Zi%-csZWNLI-EjkMwaXp20X6Fs>&16NsqF6yZAQ4 zb?#Q=FBY1O9_a7_W~`smlJ!HjgZ?uk0L z-zlK$~XX($N`dkwBtge`%*l}(cd^GAQEHIXQG ztcLC&v7v9kv+QqARYk2st?H(8Nu*F;TqpDLqXBr=ls}y$S9Q@5V${Edos-c#)Jd!D+>1O)KG=FLF`E(s)!h8Lga*IMYPdAu5YPYqgOL??sR}pHECZH>wsI zu8t{V&B{!wQc~|Q(eL3)aD?TbBl2lH(*c^x?HWf+UfG-dX^ejcv05A-E11n6x& From 3b0f2e9551be3da0f7ef89f0db5223f89d665feb Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Sat, 20 Apr 2019 13:59:39 +0200 Subject: [PATCH 159/951] better travis timings travis job naming reduce verilator cache size Fix dcache test timeout travis cleaning travis wip verilator wip fix java 10 compilation Travis wip travis rework --- .travis.yml | 103 ++++++++++-------- scripts/regression/.gitignore | 2 + scripts/regression/makefile | 7 ++ scripts/regression/regression.mk | 32 ++++++ scripts/regression/verilator.mk | 20 ++++ src/test/cpp/regression/main.cpp | 2 +- src/test/scala/vexriscv/MuraxSim.scala | 2 +- .../vexriscv/TestIndividualFeatures.scala | 5 +- 8 files changed, 126 insertions(+), 47 deletions(-) create mode 100644 scripts/regression/.gitignore create mode 100644 scripts/regression/makefile create mode 100644 scripts/regression/regression.mk create mode 100644 scripts/regression/verilator.mk diff --git a/.travis.yml b/.travis.yml index d4b1155b..bf645b41 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,67 +1,84 @@ language: scala +dist: xenial + notifications: email: on_success: never -# See 'project/Version.scala' scala: - - 2.11.6 + - 2.11.12 sbt_args: -no-colors -J-Xss2m -script: - - export VEXRISCV_REGRESSION_FREERTOS_COUNT=no - - export VEXRISCV_REGRESSION_THREAD_COUNT=1 - - sbt -jvm-opts travis/jvmopts.compile compile - - sbt -jvm-opts travis/jvmopts.test test +addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - git + - make + - autoconf + - g++ + - flex + - bison jdk: - - oraclejdk8 -# - oraclejdk7 -# - openjdk7 + - openjdk10 -env: - - VEXRISCV_REGRESSION_CONFIG_COUNT=0 - - VEXRISCV_REGRESSION_CONFIG_COUNT=5 - - VEXRISCV_REGRESSION_CONFIG_COUNT=5 - - VEXRISCV_REGRESSION_CONFIG_COUNT=5 - - VEXRISCV_REGRESSION_CONFIG_COUNT=5 +jobs: + include: + - stage: prepare cache-verilator + script: + - cp scripts/regression/verilator.mk $HOME/makefile + - cd $HOME + - make verilator_binary + - &test + stage: Test + name: TEST_DHRYSTONE + script: + - make regression_dhrystone -C scripts/regression + - <<: *test + stage: Test + name: TEST_BAREMETAL + script: + - make regression_random_baremetal -C scripts/regression + - <<: *test + stage: Test + name: TEST_BAREMETAL + script: + - make regression_random_baremetal -C scripts/regression + - <<: *test + stage: Test + name: TEST_MIXED + script: + - make regression_random -C scripts/regression + - <<: *test + stage: Test + name: TEST_LINUX + script: + - make regression_random_linux -C scripts/regression + - <<: *test + stage: Test + name: TEST_LINUX + script: + - make regression_random_linux -C scripts/regression before_install: - # JDK fix - - cat /etc/hosts # optionally check the content *before* - - sudo hostname "$(hostname | cut -c1-63)" - - sed -e "s/^\\(127\\.0\\.0\\.1.*\\)/\\1 $(hostname | cut -c1-63)/" /etc/hosts | sudo tee /etc/hosts - - cat /etc/hosts # optionally check the content *after* - cd .. - - # Verilator - - sudo apt-get install git make autoconf g++ flex bison -y # First time prerequisites - - wget https://www.veripool.org/ftp/verilator-4.012.tgz - - tar xvzf verilator*.t*gz - - cd verilator* - - ./configure - - make -j$(nproc) - - sudo make install - - cd .. - - git clone https://github.com/SpinalHDL/SpinalHDL.git -b dev - - cd VexRiscv - - git submodule update --init --recursive - #- curl -T README.md -udolu1990:$BINTRAY_KEY https://api.bintray.com/content/spinalhdl/VexRiscv/test/0.0.4/README.md - #- curl -X POST -udolu1990:$BINTRAY_KEY https://api.bintray.com/content/spinalhdl/VexRiscv/test/0.0.4/publish - #- sbt compile - + - export VERILATOR_ROOT=$HOME/verilator + - export PATH=$VERILATOR_ROOT/bin:$PATH before_cache: - # Tricks to avoid unnecessary cache updates - - find $HOME/.ivy2 -name "ivydata-*.properties" -delete - - find $HOME/.sbt -name "*.lock" -delete + - rm -fv $HOME/.ivy2/.sbt.ivy.lock + - find $HOME/.ivy2/cache -name "ivydata-*.properties" -print -delete + - find $HOME/.sbt -name "*.lock" -print -delete cache: directories: - $HOME/.ivy2/cache - - $HOME/.sbt/boot/ - - verilator-4.012 \ No newline at end of file + - $HOME/.sbt + - $HOME/verilator + diff --git a/scripts/regression/.gitignore b/scripts/regression/.gitignore new file mode 100644 index 00000000..319b95a2 --- /dev/null +++ b/scripts/regression/.gitignore @@ -0,0 +1,2 @@ +verilator* +!verilator.mk diff --git a/scripts/regression/makefile b/scripts/regression/makefile new file mode 100644 index 00000000..11ef24f4 --- /dev/null +++ b/scripts/regression/makefile @@ -0,0 +1,7 @@ +.ONESHELL: + +include verilator.mk +include regression.mk + + + diff --git a/scripts/regression/regression.mk b/scripts/regression/regression.mk new file mode 100644 index 00000000..a9d8e310 --- /dev/null +++ b/scripts/regression/regression.mk @@ -0,0 +1,32 @@ +.ONESHELL: + + +regression_random: + cd ../.. + export VEXRISCV_REGRESSION_CONFIG_COUNT=4 + export VEXRISCV_REGRESSION_FREERTOS_COUNT=no + export VEXRISCV_REGRESSION_THREAD_COUNT=1 + sbt "testOnly vexriscv.TestIndividualFeatures" + +regression_random_linux: + cd ../.. + export VEXRISCV_REGRESSION_CONFIG_LINUX_RATE=1.0 + export VEXRISCV_REGRESSION_CONFIG_COUNT=3 + export VEXRISCV_REGRESSION_FREERTOS_COUNT=no + export VEXRISCV_REGRESSION_THREAD_COUNT=1 + sbt "testOnly vexriscv.TestIndividualFeatures" + + +regression_random_baremetal: + cd ../.. + export VEXRISCV_REGRESSION_CONFIG_LINUX_RATE=0.0 + export VEXRISCV_REGRESSION_CONFIG_COUNT=50 + export VEXRISCV_REGRESSION_FREERTOS_COUNT=no + export VEXRISCV_REGRESSION_THREAD_COUNT=1 + sbt "testOnly vexriscv.TestIndividualFeatures" + + + +regression_dhrystone: + cd ../.. + sbt "testOnly vexriscv.DhrystoneBench" diff --git a/scripts/regression/verilator.mk b/scripts/regression/verilator.mk new file mode 100644 index 00000000..b13ca4c8 --- /dev/null +++ b/scripts/regression/verilator.mk @@ -0,0 +1,20 @@ + +.ONESHELL: + +verilator/configure: + rm -rf verilator* + wget https://www.veripool.org/ftp/verilator-4.012.tgz + tar xvzf verilator*.t*gz + mv verilator-4.012 verilator + +verilator/Makefile: verilator/configure + cd verilator + ./configure + +verilator/bin/verilator_bin: verilator/Makefile + cd verilator + make -j$(shell nproc) + rm -rf src/obj_dbg + rm -rf src/obj_opt + +verilator_binary: verilator/bin/verilator_bin diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 415ed67a..8631351b 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -3680,7 +3680,7 @@ int main(int argc, char **argv, char **env) { redo(REDO,WorkspaceRegression("icache").withRiscvRef()->loadHex("../raw/icache/build/icache.hex")->bootAt(0x80000000u)->run(50e3);); #endif #ifdef DBUS_CACHED - redo(REDO,WorkspaceRegression("dcache").loadHex("../raw/dcache/build/dcache.hex")->bootAt(0x80000000u)->run(500e3);); + redo(REDO,WorkspaceRegression("dcache").loadHex("../raw/dcache/build/dcache.hex")->bootAt(0x80000000u)->run(2500e3);); #endif #ifdef MMU diff --git a/src/test/scala/vexriscv/MuraxSim.scala b/src/test/scala/vexriscv/MuraxSim.scala index 2cb78021..6a6a19c6 100644 --- a/src/test/scala/vexriscv/MuraxSim.scala +++ b/src/test/scala/vexriscv/MuraxSim.scala @@ -75,7 +75,7 @@ object MuraxSim { }) setAlignmentX(awt.Component.CENTER_ALIGNMENT) }) - setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE) + setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE) pack() setVisible(true) diff --git a/src/test/scala/vexriscv/TestIndividualFeatures.scala b/src/test/scala/vexriscv/TestIndividualFeatures.scala index 1c72c51f..65bbfcd9 100644 --- a/src/test/scala/vexriscv/TestIndividualFeatures.scala +++ b/src/test/scala/vexriscv/TestIndividualFeatures.scala @@ -585,10 +585,11 @@ class TestIndividualFeatures extends FunSuite { println(s"Seed=$seed") for(i <- 0 until sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_COUNT", "100").toInt){ var positions : List[VexRiscvPosition] = null - val universe = VexRiscvUniverse.universes.filter(e => rand.nextBoolean()) + var universe = mutable.HashSet[VexRiscvUniverse]() + if(sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_LINUX_RATE", "0.5").toDouble > Math.random()) universe += VexRiscvUniverse.CATCH_ALL do{ - positions = dimensions.map(d => d.randomPosition(universe, rand)) + positions = dimensions.map(d => d.randomPosition(universe.toList, rand)) }while(!positions.forall(_.isCompatibleWith(positions))) val testSeed = rand.nextInt() From edde3e3011e4f3dfe04dcd885ebc80ead3aacddd Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Sun, 21 Apr 2019 02:56:44 +0200 Subject: [PATCH 160/951] Add zephyr tests --- src/main/scala/vexriscv/demo/Linux.scala | 1 + src/test/cpp/regression/main.cpp | 88 ++++++++++++++++++- src/test/cpp/regression/makefile | 14 ++- src/test/resources/VexRiscvRegressionData | 2 +- .../vexriscv/TestIndividualFeatures.scala | 8 +- 5 files changed, 103 insertions(+), 10 deletions(-) diff --git a/src/main/scala/vexriscv/demo/Linux.scala b/src/main/scala/vexriscv/demo/Linux.scala index 9b32dc94..f5bad23f 100644 --- a/src/main/scala/vexriscv/demo/Linux.scala +++ b/src/main/scala/vexriscv/demo/Linux.scala @@ -122,6 +122,7 @@ cd cpio cpio -idv < ../rootfs.cpio cd .. +make clean run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD DHRYSTONE=yes SUPERVISOR=yes MMU=yes CSR=yes COMPRESSED=no MUL=yes DIV=yes LRSC=yes AMO=yes REDO=10 TRACE=no COREMARK=yes LINUX_REGRESSION=yes RUN_HEX=~/pro/riscv/zephyr/samples/synchronization/build/zephyr/zephyr.hex */ diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 8631351b..7a170a91 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -1675,12 +1675,15 @@ public: *error = addr == 0xF00FFF60u; } + virtual void dutPutChar(char c){} + virtual void dBusAccess(uint32_t addr,bool wr, uint32_t size,uint32_t mask, uint32_t *data, bool *error) { if(wr){ switch(addr){ case 0xF0010000u: { cout << (char)*data; logTraces << (char)*data; + dutPutChar((char)*data); break; } #ifdef EXTERNAL_INTERRUPT @@ -1695,6 +1698,7 @@ public: case 0xF00FFF00u: { cout << (char)*data; logTraces << (char)*data; + dutPutChar((char)*data); break; } #ifndef DEBUG_PLUGIN_EXTERNAL @@ -1755,6 +1759,34 @@ public: }; + +class ZephyrRegression : public WorkspaceRegression{ +public: + + + uint32_t regFileWriteRefIndex = 0; + char *target = "PROJECT EXECUTION SUCCESSFUL", *hit = target; + + ZephyrRegression(string name) : WorkspaceRegression(name) { + cout << endl << endl; + + } + + virtual void dutPutChar(char c){ + if(*hit == c) hit++; else hit = target; + if(*hit == NULL) { + cout << endl << "T=" << i <loadHex("../../resources/freertos/" + name + "_rv32i_O0.hex")->bootAt(0x80000000u)->run(4e6*15);}); tasks.push_back([=]() { WorkspaceRegression(name + "_rv32i_O3").withRiscvRef()->loadHex("../../resources/freertos/" + name + "_rv32i_O3.hex")->bootAt(0x80000000u)->run(4e6*15);}); #ifdef COMPRESSED -// tasks.push_back([=]() { Workspace(name + "_rv32ic_O0").withRiscvRef()->loadHex("../../resources/freertos/" + name + "_rv32ic_O0.hex")->bootAt(0x80000000u)->run(5e6*15);}); - tasks.push_back([=]() { Workspace(name + "_rv32ic_O3").withRiscvRef()->loadHex("../../resources/freertos/" + name + "_rv32ic_O3.hex")->bootAt(0x80000000u)->run(4e6*15);}); +// tasks.push_back([=]() { WorkspaceRegression(name + "_rv32ic_O0").withRiscvRef()->loadHex("../../resources/freertos/" + name + "_rv32ic_O0.hex")->bootAt(0x80000000u)->run(5e6*15);}); + tasks.push_back([=]() { WorkspaceRegression(name + "_rv32ic_O3").withRiscvRef()->loadHex("../../resources/freertos/" + name + "_rv32ic_O3.hex")->bootAt(0x80000000u)->run(4e6*15);}); #endif #if defined(MUL) && defined(DIV) // #ifdef COMPRESSED -// tasks.push_back([=]() { Workspace(name + "_rv32imac_O3").withRiscvRef()->loadHex("../../resources/freertos/" + name + "_rv32imac_O3.hex")->bootAt(0x80000000u)->run(4e6*15);}); +// tasks.push_back([=]() { WorkspaceRegression(name + "_rv32imac_O3").withRiscvRef()->loadHex("../../resources/freertos/" + name + "_rv32imac_O3.hex")->bootAt(0x80000000u)->run(4e6*15);}); // #else - tasks.push_back([=]() { Workspace(name + "_rv32im_O3").withRiscvRef()->loadHex("../../resources/freertos/" + name + "_rv32im_O3.hex")->bootAt(0x80000000u)->run(4e6*15);}); + tasks.push_back([=]() { WorkspaceRegression(name + "_rv32im_O3").withRiscvRef()->loadHex("../../resources/freertos/" + name + "_rv32im_O3.hex")->bootAt(0x80000000u)->run(4e6*15);}); // #endif #endif } @@ -3788,8 +3836,40 @@ int main(int argc, char **argv, char **env) { queue > tasksSelected(std::deque>(tasks.begin(), tasks.end())); multiThreadedExecute(tasksSelected); + } #endif + #ifdef ZEPHYR + { + #ifdef SEED + srand48(SEED); + #endif + //redo(1,WorkspaceRegression("freeRTOS_demo").loadHex("../../resources/hex/freeRTOS_demo.hex")->bootAt(0x80000000u)->run(100e6);) + vector > tasks; + + /*for(int redo = 0;redo < 4;redo++)*/{ + for(const string &name : zephyrTests){ + #ifdef COMPRESSED + tasks.push_back([=]() { ZephyrRegression(name + "_rv32ic").withRiscvRef()->loadHex("../../resources/VexRiscvRegressionData/sim/zephyr/" + name + "_rv32ic.hex")->bootAt(0x80000000u)->run(180e6);}); + #else + tasks.push_back([=]() { ZephyrRegression(name + "_rv32i").withRiscvRef()->loadHex("../../resources/VexRiscvRegressionData/sim/zephyr/" + name + "_rv32i.hex")->bootAt(0x80000000u)->run(180e6);}); + #endif + #if defined(MUL) && defined(DIV) + tasks.push_back([=]() { ZephyrRegression(name + "_rv32im").withRiscvRef()->loadHex("../../resources/VexRiscvRegressionData/sim/zephyr/" + name + "_rv32im.hex")->bootAt(0x80000000u)->run(180e6);}); + #endif + } + } + + while(tasks.size() > ZEPHYR_COUNT){ + tasks.erase(tasks.begin() + (VL_RANDOM_I(32)%tasks.size())); + } + + + queue > tasksSelected(std::deque>(tasks.begin(), tasks.end())); + multiThreadedExecute(tasksSelected); + } + #endif + #if defined(LINUX_REGRESSION) { diff --git a/src/test/cpp/regression/makefile b/src/test/cpp/regression/makefile index 9c4294fe..9b0418b8 100644 --- a/src/test/cpp/regression/makefile +++ b/src/test/cpp/regression/makefile @@ -23,7 +23,8 @@ RUN_HEX=no CUSTOM_SIMD_ADD?=no CUSTOM_CSR?=no DHRYSTONE=yes -FREERTOS=no +FREERTOS?=no +ZEPHYR?=no REDO?=10 REF=no TRACE_WITH_TIME=no @@ -241,6 +242,17 @@ ifneq ($(FREERTOS),no) endif endif + +ifeq ($(ZEPHYR),yes) + ADDCFLAGS += -CFLAGS -DZEPHYR + ADDCFLAGS += -CFLAGS -DZEPHYR_COUNT=99999 +else +ifneq ($(ZEPHYR),no) + ADDCFLAGS += -CFLAGS -DZEPHYR + ADDCFLAGS += -CFLAGS -DZEPHYR_COUNT=$(ZEPHYR) +endif +endif + all: clean run run: compile diff --git a/src/test/resources/VexRiscvRegressionData b/src/test/resources/VexRiscvRegressionData index 77b66d30..f9dff468 160000 --- a/src/test/resources/VexRiscvRegressionData +++ b/src/test/resources/VexRiscvRegressionData @@ -1 +1 @@ -Subproject commit 77b66d304f888369176fb9ac2f9d6302dd4d276d +Subproject commit f9dff4688dea851f41892a3f88cae8d1e513cc93 diff --git a/src/test/scala/vexriscv/TestIndividualFeatures.scala b/src/test/scala/vexriscv/TestIndividualFeatures.scala index 65bbfcd9..ee933a9c 100644 --- a/src/test/scala/vexriscv/TestIndividualFeatures.scala +++ b/src/test/scala/vexriscv/TestIndividualFeatures.scala @@ -434,13 +434,13 @@ class MmuDimension extends VexRiscvDimension("DBus") { trait CatchAllPosition -class CsrDimension(freertos : String) extends VexRiscvDimension("Csr") { +class CsrDimension(freertos : String, zephyr : String) extends VexRiscvDimension("Csr") { override def randomPositionImpl(universes: Seq[ConfigUniverse], r: Random) = { val catchAll = universes.contains(VexRiscvUniverse.CATCH_ALL) if(catchAll){ new VexRiscvPosition("All") with CatchAllPosition{ override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new CsrPlugin(CsrPluginConfig.linuxFull(0x80000020l)) - override def testParam = s"FREERTOS=$freertos LINUX_REGRESSION=yes SUPERVISOR=yes" + override def testParam = s"FREERTOS=$freertos ZEPHYR=$zephyr LINUX_REGRESSION=yes SUPERVISOR=yes" } } else if(r.nextDouble() < 0.2){ new VexRiscvPosition("AllNoException") with CatchAllPosition{ @@ -516,7 +516,7 @@ class TestIndividualFeatures extends FunSuite { new HazardDimension, new RegFileDimension, new SrcDimension, - new CsrDimension("no"),//sys.env.getOrElse("VEXRISCV_REGRESSION_FREERTOS_COUNT", "4")), TODO + new CsrDimension("no", sys.env.getOrElse("VEXRISCV_REGRESSION_ZEPHYR_COUNT", "4")),//sys.env.getOrElse("VEXRISCV_REGRESSION_FREERTOS_COUNT", "4")), TODO new DecoderDimension, new DebugDimension, new MmuDimension @@ -554,7 +554,7 @@ class TestIndividualFeatures extends FunSuite { test(prefix + name + "_test") { val debug = true - val stdCmd = (s"make clean run WITH_USER_IO=no REDO=10 TRACE=${if(debug) "yes" else "no"} TRACE_START=9999924910246l FLOW_INFO=no STOP_ON_ERROR=no DHRYSTONE=yes COREMARK=yes THREAD_COUNT=${sys.env.getOrElse("VEXRISCV_REGRESSION_THREAD_COUNT", Runtime.getRuntime().availableProcessors().toString)} ") + s" SEED=${testSeed} " + val stdCmd = (s"make clean run WITH_USER_IO=no REDO=10 TRACE=${if(debug) "yes" else "no"} TRACE_START=9999924910246l FLOW_INFO=no STOP_ON_ERROR=no DHRYSTONE=yes COREMARK=yes THREAD_COUNT=${sys.env.getOrElse("VEXRISCV_REGRESSION_THREAD_COUNT", 1)} ") + s" SEED=${testSeed} " // val stdCmd = "make clean run REDO=40 DHRYSTONE=no STOP_ON_ERROR=yes TRACE=yess " val testCmd = stdCmd + (positionsToApply).map(_.testParam).mkString(" ") From 963805ad48682a09516a00d6d07623561e6dfac4 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Sun, 21 Apr 2019 12:50:28 +0200 Subject: [PATCH 161/951] Bring freertos back in tests Better travis test range --- .travis.yml | 14 +- scripts/regression/regression.mk | 25 ++- src/test/cpp/regression/main.cpp | 15 +- src/test/cpp/regression/makefile | 5 + .../vexriscv/TestIndividualFeatures.scala | 145 ++++++++++-------- 5 files changed, 123 insertions(+), 81 deletions(-) diff --git a/.travis.yml b/.travis.yml index bf645b41..8a2446bf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -35,32 +35,32 @@ jobs: - make verilator_binary - &test stage: Test - name: TEST_DHRYSTONE + name: Dhrystone script: - make regression_dhrystone -C scripts/regression - <<: *test stage: Test - name: TEST_BAREMETAL + name: Baremetal script: - make regression_random_baremetal -C scripts/regression - <<: *test stage: Test - name: TEST_BAREMETAL + name: Machine OS script: - - make regression_random_baremetal -C scripts/regression + - make regression_random_machine_os -C scripts/regression - <<: *test stage: Test - name: TEST_MIXED + name: Mixed script: - make regression_random -C scripts/regression - <<: *test stage: Test - name: TEST_LINUX + name: Linux script: - make regression_random_linux -C scripts/regression - <<: *test stage: Test - name: TEST_LINUX + name: Linux script: - make regression_random_linux -C scripts/regression diff --git a/scripts/regression/regression.mk b/scripts/regression/regression.mk index a9d8e310..1c29bdfc 100644 --- a/scripts/regression/regression.mk +++ b/scripts/regression/regression.mk @@ -4,29 +4,42 @@ regression_random: cd ../.. export VEXRISCV_REGRESSION_CONFIG_COUNT=4 - export VEXRISCV_REGRESSION_FREERTOS_COUNT=no + export VEXRISCV_REGRESSION_FREERTOS_COUNT=1 + export VEXRISCV_REGRESSION_ZEPHYR_COUNT=4 export VEXRISCV_REGRESSION_THREAD_COUNT=1 sbt "testOnly vexriscv.TestIndividualFeatures" regression_random_linux: cd ../.. - export VEXRISCV_REGRESSION_CONFIG_LINUX_RATE=1.0 export VEXRISCV_REGRESSION_CONFIG_COUNT=3 - export VEXRISCV_REGRESSION_FREERTOS_COUNT=no + export VEXRISCV_REGRESSION_CONFIG_LINUX_RATE=1.0 + export VEXRISCV_REGRESSION_FREERTOS_COUNT=2 + export VEXRISCV_REGRESSION_ZEPHYR_COUNT=4 export VEXRISCV_REGRESSION_THREAD_COUNT=1 sbt "testOnly vexriscv.TestIndividualFeatures" +regression_random_machine_os: + cd ../.. + export VEXRISCV_REGRESSION_CONFIG_COUNT=30 + export VEXRISCV_REGRESSION_CONFIG_LINUX_RATE=0.0 + export VEXRISCV_REGRESSION_CONFIG_MACHINE_OS_RATE = 1.0 + export VEXRISCV_REGRESSION_FREERTOS_COUNT=2 + export VEXRISCV_REGRESSION_ZEPHYR_COUNT=4 + export VEXRISCV_REGRESSION_THREAD_COUNT=1 + sbt "testOnly vexriscv.TestIndividualFeatures" + regression_random_baremetal: cd ../.. + export VEXRISCV_REGRESSION_CONFIG_COUNT=40 export VEXRISCV_REGRESSION_CONFIG_LINUX_RATE=0.0 - export VEXRISCV_REGRESSION_CONFIG_COUNT=50 - export VEXRISCV_REGRESSION_FREERTOS_COUNT=no + export VEXRISCV_REGRESSION_CONFIG_MACHINE_OS_RATE = 0.0 + export VEXRISCV_REGRESSION_FREERTOS_COUNT=1 + export VEXRISCV_REGRESSION_ZEPHYR_COUNT=no export VEXRISCV_REGRESSION_THREAD_COUNT=1 sbt "testOnly vexriscv.TestIndividualFeatures" - regression_dhrystone: cd ../.. sbt "testOnly vexriscv.DhrystoneBench" diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 7a170a91..507e4530 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -229,6 +229,13 @@ class success : public std::exception { }; #define SSTATUS_SPIE 0x00000020 #define SSTATUS_SPP 0x00000100 +#ifdef SUPERVISOR +#define MSTATUS_READ_MASK 0xFFFFFFFF +#else +#define MSTATUS_READ_MASK 0x1888 +#endif + + class RiscvGolden { public: int32_t pc, lastPc; @@ -528,7 +535,7 @@ public: virtual bool csrRead(int32_t csr, uint32_t *value){ if(((csr >> 8) & 0x3) > privilege) return true; switch(csr){ - case MSTATUS: *value = status.raw; break; + case MSTATUS: *value = status.raw & MSTATUS_READ_MASK; break; case MIP: *value = getIp().raw; break; case MIE: *value = ie.raw; break; case MTVEC: *value = mtvec.raw; break; @@ -3502,7 +3509,7 @@ static void multiThreading(queue> *lambdas, std::mutex *mu uint32_t seed = SEED + counter; counter++; srand48(seed); - printf("FREERTOS_SEED=%d \n", seed); + printf("MT_SEED=%d \n", seed); #endif std::function lambda = lambdas->front(); lambdas->pop(); @@ -3667,7 +3674,7 @@ int main(int argc, char **argv, char **env) { redo(REDO, Compliance(name).run();) } #endif - #ifdef CSR + #if defined(CSR) && !defined(CSR_SKIP_TEST) for(const string &name : complianceTestCsr){ redo(REDO, Compliance(name).run();) } @@ -3702,7 +3709,7 @@ int main(int argc, char **argv, char **env) { redo(REDO,RiscvTest("rv32uc-p-rvc").bootAt(0x800000FCu)->run()); #endif - #ifdef CSR + #if defined(CSR) && !defined(CSR_SKIP_TEST) #ifndef COMPRESSED 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 }; diff --git a/src/test/cpp/regression/makefile b/src/test/cpp/regression/makefile index 9b0418b8..a657f1c2 100644 --- a/src/test/cpp/regression/makefile +++ b/src/test/cpp/regression/makefile @@ -10,6 +10,7 @@ ISA_TEST?=yes MUL?=yes DIV?=yes CSR?=yes +CSR_SKIP_TEST?=no EBREAK?=no FENCEI?=no MMU?=yes @@ -173,6 +174,10 @@ ifeq ($(CSR),yes) ADDCFLAGS += -CFLAGS -DCSR endif +ifeq ($(CSR_SKIP_TEST),yes) + ADDCFLAGS += -CFLAGS -DCSR_SKIP_TEST +endif + ifeq ($(LRSC),yes) ADDCFLAGS += -CFLAGS -DLRSC diff --git a/src/test/scala/vexriscv/TestIndividualFeatures.scala b/src/test/scala/vexriscv/TestIndividualFeatures.scala index ee933a9c..2493aaf7 100644 --- a/src/test/scala/vexriscv/TestIndividualFeatures.scala +++ b/src/test/scala/vexriscv/TestIndividualFeatures.scala @@ -45,8 +45,8 @@ class VexRiscvUniverse extends ConfigUniverse object VexRiscvUniverse{ val CATCH_ALL = new VexRiscvUniverse val MMU = new VexRiscvUniverse - - val universes = List(CATCH_ALL, MMU) + val FORCE_MULDIV = new VexRiscvUniverse + val SUPERVISOR = new VexRiscvUniverse } @@ -86,57 +86,62 @@ class BranchDimension extends VexRiscvDimension("Branch") { class MulDivDimension extends VexRiscvDimension("MulDiv") { - override def randomPositionImpl(universes: Seq[ConfigUniverse], r: Random) = random(r, List( - new VexRiscvPosition("NoMulDiv") { + override def randomPositionImpl(universes: Seq[ConfigUniverse], r: Random) = { + var l = List( + new VexRiscvPosition("MulDivFpga") { + override def testParam = "MUL=yes DIV=yes" + override def applyOn(config: VexRiscvConfig): Unit = { + config.plugins += new MulPlugin + config.plugins += new MulDivIterativePlugin( + genMul = false, + genDiv = true, + mulUnrollFactor = 32, + divUnrollFactor = 1 + ) + } + }, + new VexRiscvPosition("MulDivAsic") { + override def testParam = "MUL=yes DIV=yes" + override def applyOn(config: VexRiscvConfig): Unit = { + config.plugins += new MulDivIterativePlugin( + genMul = true, + genDiv = true, + mulUnrollFactor = 32, + divUnrollFactor = 4 + ) + } + }, + new VexRiscvPosition("MulDivFpgaNoDsp") { + override def testParam = "MUL=yes DIV=yes" + override def applyOn(config: VexRiscvConfig): Unit = { + config.plugins += new MulDivIterativePlugin( + genMul = true, + genDiv = true, + mulUnrollFactor = 1, + divUnrollFactor = 1 + ) + } + }, + new VexRiscvPosition("MulDivFpgaNoDspFastMul") { + override def testParam = "MUL=yes DIV=yes" + override def applyOn(config: VexRiscvConfig): Unit = { + config.plugins += new MulDivIterativePlugin( + genMul = true, + genDiv = true, + mulUnrollFactor = 8, + divUnrollFactor = 1 + ) + } + } + ) + + if(!universes.contains(VexRiscvUniverse.FORCE_MULDIV)) l = new VexRiscvPosition("NoMulDiv") { override def applyOn(config: VexRiscvConfig): Unit = {} override def testParam = "MUL=no DIV=no" - }, - new VexRiscvPosition("MulDivFpga") { - override def testParam = "MUL=yes DIV=yes" - override def applyOn(config: VexRiscvConfig): Unit = { - config.plugins += new MulPlugin - config.plugins += new MulDivIterativePlugin( - genMul = false, - genDiv = true, - mulUnrollFactor = 32, - divUnrollFactor = 1 - ) - } - }, - new VexRiscvPosition("MulDivAsic") { - override def testParam = "MUL=yes DIV=yes" - override def applyOn(config: VexRiscvConfig): Unit = { - config.plugins += new MulDivIterativePlugin( - genMul = true, - genDiv = true, - mulUnrollFactor = 32, - divUnrollFactor = 4 - ) - } - }, - new VexRiscvPosition("MulDivFpgaNoDsp") { - override def testParam = "MUL=yes DIV=yes" - override def applyOn(config: VexRiscvConfig): Unit = { - config.plugins += new MulDivIterativePlugin( - genMul = true, - genDiv = true, - mulUnrollFactor = 1, - divUnrollFactor = 1 - ) - } - }, - new VexRiscvPosition("MulDivFpgaNoDspFastMul") { - override def testParam = "MUL=yes DIV=yes" - override def applyOn(config: VexRiscvConfig): Unit = { - config.plugins += new MulDivIterativePlugin( - genMul = true, - genDiv = true, - mulUnrollFactor = 8, - divUnrollFactor = 1 - ) - } - } - )) + } :: l + + random(r, l) + } } trait InstructionAnticipatedPosition{ @@ -266,7 +271,7 @@ class IBusDimension extends VexRiscvDimension("IBus") { override def randomPositionImpl(universes: Seq[ConfigUniverse], r: Random) = { val catchAll = universes.contains(VexRiscvUniverse.CATCH_ALL) - val mmuConfig = if(catchAll) MmuPortConfig( portTlbSize = 4) else null + val mmuConfig = if(universes.contains(VexRiscvUniverse.MMU)) MmuPortConfig( portTlbSize = 4) else null if(r.nextDouble() < 0.5){ val latency = r.nextInt(5) + 1 @@ -347,7 +352,7 @@ class DBusDimension extends VexRiscvDimension("DBus") { override def randomPositionImpl(universes: Seq[ConfigUniverse], r: Random) = { val catchAll = universes.contains(VexRiscvUniverse.CATCH_ALL) - val mmuConfig = if(catchAll) MmuPortConfig( portTlbSize = 4) else null + val mmuConfig = if(universes.contains(VexRiscvUniverse.MMU)) MmuPortConfig( portTlbSize = 4) else null if(r.nextDouble() < 0.4){ val withLrSc = catchAll @@ -403,9 +408,7 @@ class DBusDimension extends VexRiscvDimension("DBus") { class MmuDimension extends VexRiscvDimension("DBus") { override def randomPositionImpl(universes: Seq[ConfigUniverse], r: Random) = { - - val catchAll = universes.contains(VexRiscvUniverse.CATCH_ALL) - if(catchAll) { + if(universes.contains(VexRiscvUniverse.MMU)) { new VexRiscvPosition("WithMmu") { override def testParam = "MMU=yes" @@ -437,15 +440,21 @@ trait CatchAllPosition class CsrDimension(freertos : String, zephyr : String) extends VexRiscvDimension("Csr") { override def randomPositionImpl(universes: Seq[ConfigUniverse], r: Random) = { val catchAll = universes.contains(VexRiscvUniverse.CATCH_ALL) - if(catchAll){ - new VexRiscvPosition("All") with CatchAllPosition{ + val supervisor = universes.contains(VexRiscvUniverse.SUPERVISOR) + if(supervisor){ + new VexRiscvPosition("Supervisor") with CatchAllPosition{ override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new CsrPlugin(CsrPluginConfig.linuxFull(0x80000020l)) override def testParam = s"FREERTOS=$freertos ZEPHYR=$zephyr LINUX_REGRESSION=yes SUPERVISOR=yes" } - } else if(r.nextDouble() < 0.2){ + } else if(catchAll){ + new VexRiscvPosition("MachineOs") with CatchAllPosition{ + override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new CsrPlugin(CsrPluginConfig.all(0x80000020l)) + override def testParam = s"CSR=yes FREERTOS=$freertos ZEPHYR=$zephyr" + } + } else if(r.nextDouble() < 0.3){ new VexRiscvPosition("AllNoException") with CatchAllPosition{ override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new CsrPlugin(CsrPluginConfig.all(0x80000020l).noException) - override def testParam = "CSR=no FREERTOS=no" + override def testParam = s"CSR=yes CSR_SKIP_TEST=yes FREERTOS=$freertos" } } else { new VexRiscvPosition("None") { @@ -516,7 +525,7 @@ class TestIndividualFeatures extends FunSuite { new HazardDimension, new RegFileDimension, new SrcDimension, - new CsrDimension("no", sys.env.getOrElse("VEXRISCV_REGRESSION_ZEPHYR_COUNT", "4")),//sys.env.getOrElse("VEXRISCV_REGRESSION_FREERTOS_COUNT", "4")), TODO + new CsrDimension(sys.env.getOrElse("VEXRISCV_REGRESSION_FREERTOS_COUNT", "1"), sys.env.getOrElse("VEXRISCV_REGRESSION_ZEPHYR_COUNT", "4")), new DecoderDimension, new DebugDimension, new MmuDimension @@ -572,9 +581,9 @@ class TestIndividualFeatures extends FunSuite { val seed = Random.nextLong() // val testId = Some(mutable.HashSet(18,34,77,85,118,129,132,134,152,167,175,188,191,198,199)) //37/29 sp_flop_rv32i_O3 -//val testId = Some(mutable.HashSet(18)) +//val testId = Some(mutable.HashSet(3)) // val testId = Some(mutable.HashSet(129, 134)) -// val seed = -2412372746600605141l +// val seed = -1580866821569084523l val rand = new Random(seed) @@ -586,7 +595,15 @@ class TestIndividualFeatures extends FunSuite { for(i <- 0 until sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_COUNT", "100").toInt){ var positions : List[VexRiscvPosition] = null var universe = mutable.HashSet[VexRiscvUniverse]() - if(sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_LINUX_RATE", "0.5").toDouble > Math.random()) universe += VexRiscvUniverse.CATCH_ALL + if(sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_LINUX_RATE", "0.3").toDouble > Math.random()) { + universe += VexRiscvUniverse.CATCH_ALL + universe += VexRiscvUniverse.MMU + universe += VexRiscvUniverse.FORCE_MULDIV + universe += VexRiscvUniverse.SUPERVISOR + } + if(sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_MACHINE_OS_RATE", "0.5").toDouble > Math.random()) { + universe += VexRiscvUniverse.CATCH_ALL + } do{ positions = dimensions.map(d => d.randomPosition(universe.toList, rand)) From 7e91b5e44666b55d24aecd8636da4154e3231190 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Sun, 21 Apr 2019 12:55:01 +0200 Subject: [PATCH 162/951] Fix travis --- scripts/regression/regression.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/regression/regression.mk b/scripts/regression/regression.mk index 1c29bdfc..1ebb27fc 100644 --- a/scripts/regression/regression.mk +++ b/scripts/regression/regression.mk @@ -23,7 +23,7 @@ regression_random_machine_os: cd ../.. export VEXRISCV_REGRESSION_CONFIG_COUNT=30 export VEXRISCV_REGRESSION_CONFIG_LINUX_RATE=0.0 - export VEXRISCV_REGRESSION_CONFIG_MACHINE_OS_RATE = 1.0 + export VEXRISCV_REGRESSION_CONFIG_MACHINE_OS_RATE=1.0 export VEXRISCV_REGRESSION_FREERTOS_COUNT=2 export VEXRISCV_REGRESSION_ZEPHYR_COUNT=4 export VEXRISCV_REGRESSION_THREAD_COUNT=1 @@ -33,7 +33,7 @@ regression_random_baremetal: cd ../.. export VEXRISCV_REGRESSION_CONFIG_COUNT=40 export VEXRISCV_REGRESSION_CONFIG_LINUX_RATE=0.0 - export VEXRISCV_REGRESSION_CONFIG_MACHINE_OS_RATE = 0.0 + export VEXRISCV_REGRESSION_CONFIG_MACHINE_OS_RATE=0.0 export VEXRISCV_REGRESSION_FREERTOS_COUNT=1 export VEXRISCV_REGRESSION_ZEPHYR_COUNT=no export VEXRISCV_REGRESSION_THREAD_COUNT=1 From fc4c078f177f51a1c1271a9986d5c9d93843bb67 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sun, 21 Apr 2019 13:36:25 +0200 Subject: [PATCH 163/951] Update regression.mk Reduce machine os time --- scripts/regression/regression.mk | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/regression/regression.mk b/scripts/regression/regression.mk index 1ebb27fc..d132bd5c 100644 --- a/scripts/regression/regression.mk +++ b/scripts/regression/regression.mk @@ -21,11 +21,11 @@ regression_random_linux: regression_random_machine_os: cd ../.. - export VEXRISCV_REGRESSION_CONFIG_COUNT=30 + export VEXRISCV_REGRESSION_CONFIG_COUNT=25 export VEXRISCV_REGRESSION_CONFIG_LINUX_RATE=0.0 export VEXRISCV_REGRESSION_CONFIG_MACHINE_OS_RATE=1.0 - export VEXRISCV_REGRESSION_FREERTOS_COUNT=2 - export VEXRISCV_REGRESSION_ZEPHYR_COUNT=4 + export VEXRISCV_REGRESSION_FREERTOS_COUNT=1 + export VEXRISCV_REGRESSION_ZEPHYR_COUNT=2 export VEXRISCV_REGRESSION_THREAD_COUNT=1 sbt "testOnly vexriscv.TestIndividualFeatures" From d18dcc0540025b5a8bf9923b2ea82ab436cd03bc Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sun, 21 Apr 2019 13:49:05 +0200 Subject: [PATCH 164/951] Update regression.mk reduce linux regression time a bit --- scripts/regression/regression.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/regression/regression.mk b/scripts/regression/regression.mk index d132bd5c..299b31b3 100644 --- a/scripts/regression/regression.mk +++ b/scripts/regression/regression.mk @@ -13,8 +13,8 @@ regression_random_linux: cd ../.. export VEXRISCV_REGRESSION_CONFIG_COUNT=3 export VEXRISCV_REGRESSION_CONFIG_LINUX_RATE=1.0 - export VEXRISCV_REGRESSION_FREERTOS_COUNT=2 - export VEXRISCV_REGRESSION_ZEPHYR_COUNT=4 + export VEXRISCV_REGRESSION_FREERTOS_COUNT=1 + export VEXRISCV_REGRESSION_ZEPHYR_COUNT=2 export VEXRISCV_REGRESSION_THREAD_COUNT=1 sbt "testOnly vexriscv.TestIndividualFeatures" From 4efa3b0d45aafea488433ce2067ff781f9296372 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Sun, 21 Apr 2019 14:41:27 +0200 Subject: [PATCH 165/951] Update readme --- README.md | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 4ac9b680..4cd69f24 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ * [By using FreedomStudio](#by-using-freedomstudio) - [Briey SoC](#briey-soc) - [Murax SoC](#murax-soc) +- [Running Linux](#running-linux) - [Build the RISC-V GCC](#build-the-risc-v-gcc) - [CPU parametrization and instantiation example](#cpu-parametrization-and-instantiation-example) - [Add a custom instruction to the CPU via the plugin system](#add-a-custom-instruction-to-the-cpu-via-the-plugin-system) @@ -33,11 +34,12 @@ This repository hosts a RISC-V implementation written in SpinalHDL. Here are som - AXI4 and Avalon ready - Optional MUL/DIV extensions - Optional instruction and data caches -- Optional MMU +- Optional hardware refilled MMU - Optional debug extension allowing Eclipse debugging via a GDB >> openOCD >> JTAG connection - Optional interrupts and exception handling with Machine and User modes as defined in the [RISC-V Privileged ISA Specification v1.9](https://riscv.org/specifications/privileged-isa/). - Two implementations of shift instructions: Single cycle and shiftNumber cycles - Each stage can have optional bypass or interlock hazard logic +- Compatible with the mainstream RISC-V linux port - Zephyr RISC-V port compatible - [FreeRTOS port](https://github.com/Dolu1990/FreeRTOS-RISCV) - The data cache supports atomic LR/SC @@ -177,6 +179,9 @@ NOTES: do a "sbt clean compile publish-local" in it as described in the dependencies chapter. ## Regression tests + +[![Build Status](https://travis-ci.org/SpinalHDL/VexRiscv.svg?branch=master)](https://travis-ci.org/SpinalHDL/VexRiscv) + To run tests (need the verilator simulator), go in the src/test/cpp/regression folder and run : ```sh @@ -367,6 +372,18 @@ To run it : sbt "test:runMain vexriscv.MuraxSim" ``` +## Running Linux + +A default configuration is located in src/main/scala/vexriscv/demo/Linux.scala + +This file also contains +- The commands to compile the buildroot image +- How to run the Verilator simulation in interative mode + +There is currently no SoC to run it on hardware, it is WIP. But the CPU simulation can already boot linux and run user space application (even python). + +Note that VexRiscv can run Linux on both cache full and cache less design. + ## Build the RISC-V GCC A prebuild GCC toolsuite can be found here: @@ -860,7 +877,7 @@ The down side is that this predictor has a long combinatorial path coming from t #### DBusSimplePlugin -This plugin implements the load and store instructions (LB/LH/LW/LBU/LHU/LWU/SB/SH/SW) via a simple and neutral memory bus going out of the CPU. +This plugin implements the load and store instructions (LB/LH/LW/LBU/LHU/LWU/SB/SH/SW) via a simple memory bus going out of the CPU. | Parameters | type | description | | ------ | ----------- | ------ | @@ -906,7 +923,7 @@ There is at least one cycle latency between a cmd and the corresponding rsp. The #### DBusCachedPlugin -Single way cache implementation with a victim buffer. (Documentation is WIP) +Multi way cache implementation with writh-through and allocate on read strategy. (Documentation is WIP) #### MulPlugin @@ -975,10 +992,10 @@ stage before jumping to mtvec. Static memory translator plugin which allows one to specify which range of the memory addresses is IO mapped and shouldn't be cached. -#### MemoryTranslatorPlugin +#### MmuPlugin -Simple software refilled MMU implementation. Allows others plugins such as DBusCachedPlugin/IBusCachedPlugin to instanciate memory address translation ports. Each port has a small dedicated -fully associative TLB cache which is refilled from a larger software filled TLB cache via a query which looks up one entry per cycle. +Hardware refilled MMU implementation. Allows others plugins such as DBusCachedPlugin/IBusCachedPlugin to instanciate memory address translation ports. Each port has a small dedicated +fully associative TLB cache which is refilled automaticaly via a dbus access sharing. #### DebugPlugin From 1c86bf7514235fcc735b7d0f05633ed0e575fddc Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sun, 21 Apr 2019 15:25:39 +0200 Subject: [PATCH 166/951] Increase liveness trigger to allow large instruction cache flush --- src/test/cpp/regression/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 507e4530..c9ace12d 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -614,7 +614,7 @@ public: if(pendingInterrupt) livenessInterrupt++; else livenessInterrupt = 0; if(!inWfi) livenessStep++; else livenessStep = 0; - if(livenessStep > 1000){ + if(livenessStep > 10000){ cout << "Liveness step failure" << endl; fail(); } From 4cbb93cfc80bc68c39fa8af1cc19789b545eda3f Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Sun, 21 Apr 2019 17:48:08 +0200 Subject: [PATCH 167/951] Look like zephyr mem_pool_threadsafe is a broken test --- src/test/cpp/regression/main.cpp | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index c9ace12d..c754cc93 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -494,8 +494,17 @@ public: targetPrivilege = max(targetPrivilege, privilege); Xtvec xtvec = targetPrivilege == 3 ? mtvec : stvec; + + switch(targetPrivilege){ case 3: + if(interrupt){ + if(!status.mie || !(ie.raw & (1 << cause)) || !(getIp().raw & (1 << cause))){ + cout << "DUT had trigger an interrupts which isnt pending in REF" << endl; + fail(); + } + } + if(valueWrite) mbadaddr = value; mcause.interrupt = interrupt; mcause.exceptionCode = cause; @@ -505,6 +514,12 @@ public: mepc = pc; break; case 1: + if(interrupt){ + if(!status.sie || !(ie.raw & (1 << cause)) || !(getIp().raw & (1 << cause))){ + cout << "DUT had trigger an interrupts which isnt pending in REF" << endl; + fail(); + } + } if(valueWrite) sbadaddr = value; scause.interrupt = interrupt; scause.exceptionCode = cause; @@ -3350,12 +3365,11 @@ string freeRtosTests[] = { string zephyrTests[] = { "tests_kernel_stack_stack_api", -// "tests_kernel_mutex_mutex", //Too long "tests_kernel_context", // "tests_kernel_critical", //Too long "tests_kernel_fifo_fifo_api", "tests_kernel_mbox_mbox_usage", - "tests_kernel_mem_pool_mem_pool_threadsafe", +// "tests_kernel_mem_pool_mem_pool_threadsafe", //Lock like it's a zephyr issue ? "tests_kernel_sleep", "tests_kernel_timer_timer_api" }; From 0e10c460c301e63218d6f9043691f105a7faa2eb Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Sun, 21 Apr 2019 17:58:42 +0200 Subject: [PATCH 168/951] Update Zephyr tests, the mem_pool_threadsafe one was bugy by the past, and now it is just too long --- src/test/cpp/regression/main.cpp | 2 +- src/test/resources/VexRiscvRegressionData | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index c754cc93..d0455aae 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -3369,7 +3369,7 @@ string zephyrTests[] = { // "tests_kernel_critical", //Too long "tests_kernel_fifo_fifo_api", "tests_kernel_mbox_mbox_usage", -// "tests_kernel_mem_pool_mem_pool_threadsafe", //Lock like it's a zephyr issue ? +// "tests_kernel_mem_pool_mem_pool_threadsafe", //Too long "tests_kernel_sleep", "tests_kernel_timer_timer_api" }; diff --git a/src/test/resources/VexRiscvRegressionData b/src/test/resources/VexRiscvRegressionData index f9dff468..539398c1 160000 --- a/src/test/resources/VexRiscvRegressionData +++ b/src/test/resources/VexRiscvRegressionData @@ -1 +1 @@ -Subproject commit f9dff4688dea851f41892a3f88cae8d1e513cc93 +Subproject commit 539398c1481203a51115b5f1228ea961f0ac9bd3 From d7ca153c8b3e47e5b4bdad7749c6ab41235dd22c Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Sun, 21 Apr 2019 19:45:24 +0200 Subject: [PATCH 169/951] remove interrupt assertion --- src/test/cpp/regression/main.cpp | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index d0455aae..c77854c5 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -498,13 +498,6 @@ public: switch(targetPrivilege){ case 3: - if(interrupt){ - if(!status.mie || !(ie.raw & (1 << cause)) || !(getIp().raw & (1 << cause))){ - cout << "DUT had trigger an interrupts which isnt pending in REF" << endl; - fail(); - } - } - if(valueWrite) mbadaddr = value; mcause.interrupt = interrupt; mcause.exceptionCode = cause; @@ -514,12 +507,6 @@ public: mepc = pc; break; case 1: - if(interrupt){ - if(!status.sie || !(ie.raw & (1 << cause)) || !(getIp().raw & (1 << cause))){ - cout << "DUT had trigger an interrupts which isnt pending in REF" << endl; - fail(); - } - } if(valueWrite) sbadaddr = value; scause.interrupt = interrupt; scause.exceptionCode = cause; @@ -3370,8 +3357,8 @@ string zephyrTests[] = { "tests_kernel_fifo_fifo_api", "tests_kernel_mbox_mbox_usage", // "tests_kernel_mem_pool_mem_pool_threadsafe", //Too long - "tests_kernel_sleep", - "tests_kernel_timer_timer_api" + "tests_kernel_sleep" +// "tests_kernel_timer_timer_api" //Lock like if the CPU is too slow, it will make it fail }; From 14efe6ffda7830d7e222159487b5966aba37336e Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Sun, 21 Apr 2019 20:01:39 +0200 Subject: [PATCH 170/951] Riscv software model now implement interrupt priority accordingly to https://github.com/riscv/riscv-isa-sim/commit/496c59d064961bb81e63e2bba1bdadd4abf05a52#diff-a38d447c5232bd448697af4c6c8adb1a changes --- src/test/cpp/regression/main.cpp | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index c77854c5..fdb3a4c0 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -637,15 +637,19 @@ public: masked = getIp().raw & mideleg & -sEnabled & ie.raw & 0x333; if (masked) { - if (masked & (MIP_MEIP | MIP_SEIP)) - masked &= (MIP_MEIP | MIP_SEIP); - // software interrupts have next-highest priority - else if (masked & (MIP_MSIP | MIP_SSIP)) - masked &= (MIP_MSIP | MIP_SSIP); - // timer interrupts have next-highest priority - else if (masked & (MIP_MTIP | MIP_STIP)) - masked &= (MIP_MTIP | MIP_STIP); - else + if (masked & MIP_MEIP) + masked &= MIP_MEIP; + else if (masked & MIP_MSIP) + masked &= MIP_MSIP; + else if (masked & MIP_MTIP) + masked &= MIP_MTIP; + else if (masked & MIP_SEIP) + masked &= MIP_SEIP; + else if (masked & MIP_SSIP) + masked &= MIP_SSIP; + else if (masked & MIP_STIP) + masked &= MIP_STIP; + else fail(); } From 633e057d112368156a958185f23e81da3f884f2a Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Sun, 21 Apr 2019 20:30:58 +0200 Subject: [PATCH 171/951] Split machine os regression in two smaller parts --- .travis.yml | 5 +++++ scripts/regression/.gitignore | 1 + scripts/regression/regression.mk | 2 +- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 8a2446bf..65168b3c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -48,6 +48,11 @@ jobs: name: Machine OS script: - make regression_random_machine_os -C scripts/regression + - <<: *test + stage: Test + name: Machine OS + script: + - make regression_random_machine_os -C scripts/regression - <<: *test stage: Test name: Mixed diff --git a/scripts/regression/.gitignore b/scripts/regression/.gitignore index 319b95a2..67869c2d 100644 --- a/scripts/regression/.gitignore +++ b/scripts/regression/.gitignore @@ -1,2 +1,3 @@ verilator* +verilator !verilator.mk diff --git a/scripts/regression/regression.mk b/scripts/regression/regression.mk index 299b31b3..b1899aa0 100644 --- a/scripts/regression/regression.mk +++ b/scripts/regression/regression.mk @@ -21,7 +21,7 @@ regression_random_linux: regression_random_machine_os: cd ../.. - export VEXRISCV_REGRESSION_CONFIG_COUNT=25 + export VEXRISCV_REGRESSION_CONFIG_COUNT=15 export VEXRISCV_REGRESSION_CONFIG_LINUX_RATE=0.0 export VEXRISCV_REGRESSION_CONFIG_MACHINE_OS_RATE=1.0 export VEXRISCV_REGRESSION_FREERTOS_COUNT=1 From c6dbaa52f68e75a9b5c7809135508ad54c59a2c2 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Sun, 21 Apr 2019 22:16:42 +0200 Subject: [PATCH 172/951] Longer linux regression timeout for very slow configs --- src/test/cpp/regression/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index fdb3a4c0..48a24ba6 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -3896,7 +3896,7 @@ int main(int argc, char **argv, char **env) { //soc.setIStall(true); //soc.setDStall(true); soc.bootAt(0x80000000); - soc.run(153995602l*6); + soc.run(153995602l*9); // soc.run((470000000l + 2000000) / 2); // soc.run(438700000l/2); } From 4078f84e8fc8aadd88b5b2a6bdd066721672eca0 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Tue, 23 Apr 2019 21:54:42 +0200 Subject: [PATCH 173/951] Dhrystone regression now also run coremark --- src/test/scala/vexriscv/DhrystoneBench.scala | 32 ++++++++++++++------ 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/src/test/scala/vexriscv/DhrystoneBench.scala b/src/test/scala/vexriscv/DhrystoneBench.scala index 085eaa17..1034aed0 100644 --- a/src/test/scala/vexriscv/DhrystoneBench.scala +++ b/src/test/scala/vexriscv/DhrystoneBench.scala @@ -33,7 +33,11 @@ class DhrystoneBench extends FunSuite{ assert(!str.contains("FAIL")) val intFind = "(\\d+\\.?)+".r val dmips = intFind.findFirstIn("DMIPS per Mhz\\: (\\d+.?)+".r.findAllIn(str).toList.last).get.toDouble - report ++= name + " -> " + dmips + "\n" + val coremarkTicks = intFind.findFirstIn("Total ticks \\: (\\d+.?)+".r.findAllIn(str).toList.last).get.toDouble + val coremarkIterations = intFind.findFirstIn("Iterations \\: (\\d+.?)+".r.findAllIn(str).toList.last).get.toDouble + val coremarkHzs = intFind.findFirstIn("DCLOCKS_PER_SEC=(\\d+.?)+".r.findAllIn(str).toList.last).get.toDouble + val coremarkPerMhz =1e6*coremarkIterations/coremarkTicks + report ++= s"$name -> $dmips DMIPS/Mhz $coremarkPerMhz Coremark/Mhz\n" } } @@ -41,60 +45,68 @@ class DhrystoneBench extends FunSuite{ getDmips( name = "GenSmallestNoCsr", gen = GenSmallestNoCsr.main(null), - testCmd = "make clean run REDO=10 IBUS=SIMPLE DBUS=SIMPLE CSR=no MMU=no DEBUG_PLUGIN=no MUL=no DIV=no" + testCmd = "make clean run REDO=10 IBUS=SIMPLE DBUS=SIMPLE CSR=no MMU=no DEBUG_PLUGIN=no MUL=no DIV=no COREMARK=yes" ) getDmips( name = "GenSmallest", gen = GenSmallest.main(null), - testCmd = "make clean run REDO=10 IBUS=SIMPLE DBUS=SIMPLE CSR=no MMU=no DEBUG_PLUGIN=no MUL=no DIV=no" + testCmd = "make clean run REDO=10 IBUS=SIMPLE DBUS=SIMPLE CSR=no MMU=no DEBUG_PLUGIN=no MUL=no DIV=no COREMARK=yes" ) getDmips( name = "GenSmallAndProductive", gen = GenSmallAndProductive.main(null), - testCmd = "make clean run REDO=10 IBUS=SIMPLE DBUS=SIMPLE CSR=no MMU=no DEBUG_PLUGIN=no MUL=no DIV=no" + testCmd = "make clean run REDO=10 IBUS=SIMPLE DBUS=SIMPLE CSR=no MMU=no DEBUG_PLUGIN=no MUL=no DIV=no COREMARK=yes" ) getDmips( name = "GenSmallAndProductiveWithICache", gen = GenSmallAndProductiveICache.main(null), - testCmd = "make clean run REDO=10 IBUS=CACHED DBUS=SIMPLE CSR=no MMU=no DEBUG_PLUGIN=no MUL=no DIV=no" + testCmd = "make clean run REDO=10 IBUS=CACHED DBUS=SIMPLE CSR=no MMU=no DEBUG_PLUGIN=no MUL=no DIV=no COREMARK=yes" ) getDmips( name = "GenFullNoMmuNoCache", gen = GenFullNoMmuNoCache.main(null), - testCmd = "make clean run REDO=10 IBUS=SIMPLE DBUS=SIMPLE CSR=no MMU=no" + testCmd = "make clean run REDO=10 IBUS=SIMPLE DBUS=SIMPLE CSR=no MMU=no COREMARK=yes" ) getDmips( name = "GenNoCacheNoMmuMaxPerf", gen = GenNoCacheNoMmuMaxPerf.main(null), - testCmd = "make clean run REDO=10 MMU=no CSR=no DBUS=SIMPLE IBUS=SIMPLE" + testCmd = "make clean run REDO=10 MMU=no CSR=no DBUS=SIMPLE IBUS=SIMPLE COREMARK=yes" ) getDmips( name = "GenFullNoMmuMaxPerf", gen = GenFullNoMmuMaxPerf.main(null), - testCmd = "make clean run REDO=10 MMU=no CSR=no" + testCmd = "make clean run REDO=10 MMU=no CSR=no COREMARK=yes" ) getDmips( name = "GenFullNoMmu", gen = GenFullNoMmu.main(null), - testCmd = "make clean run REDO=10 MMU=no CSR=no" + testCmd = "make clean run REDO=10 MMU=no CSR=no COREMARK=yes" ) getDmips( name = "GenFull", gen = GenFull.main(null), - testCmd = "make clean run REDO=10 CSR=no MMU=no" + testCmd = "make clean run REDO=10 CSR=no MMU=no COREMARK=yes" ) + getDmips( + name = "GenLinuxBalenced", + gen = LinuxGen.main(Array.fill[String](0)("")), + testCmd = "make clean run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD DHRYSTONE=yes SUPERVISOR=yes MMU=no CSR=yes CSR_SKIP_TEST=yes DEBUG_PLUGIN=no COMPRESSED=no MUL=yes DIV=yes LRSC=yes AMO=yes REDO=10 TRACE=no COREMARK=yes LINUX_REGRESSION=no" + ) + + + test("final_report") { println(report) } From 266bdccc2e50188c0443e12bd450a385dcc8e6a2 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Tue, 23 Apr 2019 21:55:07 +0200 Subject: [PATCH 174/951] update Riscv software model lrsc implementation --- src/test/cpp/regression/main.cpp | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 48a24ba6..3f6c0f09 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -374,14 +374,8 @@ public: }; }; -#define RESERVED_ENTRY_COUNT 1 - struct ReservedEntry{ - bool valid; - uint32_t address; - }; - ReservedEntry reservedEntries[RESERVED_ENTRY_COUNT]; - int reservedEntriesPtr = 0; + bool lrscReserved; RiscvGolden() { pc = 0x80000000; @@ -389,9 +383,6 @@ public: for (int i = 0; i < 32; i++) regs[i] = 0; - for(int i = 0;i < RESERVED_ENTRY_COUNT;i++) reservedEntries[i].valid = false; - - status.raw = 0; ie.raw = 0; mtvec.raw = 0x80000020; @@ -409,6 +400,7 @@ public: ipSoft = 0; ipInput = 0; stepCounter = 0; + lrscReserved = false; } virtual void rfWrite(int32_t address, int32_t data) { @@ -472,7 +464,7 @@ public: cout << hex << " a7=0x" << regs[17] << " a0=0x" << regs[10] << " a1=0x" << regs[11] << " a2=0x" << regs[12] << dec << endl; } #endif - for(int i = 0;i < RESERVED_ENTRY_COUNT;i++) reservedEntries[i].valid = false; + lrscReserved = false; //Check leguality of the interrupt if(interrupt) { bool hit = false; @@ -843,6 +835,7 @@ public: status.mpie = 1; status.mpp = 0; pcWrite(mepc); + lrscReserved = false; }break; case 0x10200073:{ //SRET if(privilege < 1){ ilegalInstruction(); return;} @@ -851,6 +844,7 @@ public: status.spie = 1; status.spp = 0; pcWrite(sepc); + lrscReserved = false; }break; case 0x00000073:{ //ECALL trap(0, 8+privilege, 0x00000073); //To follow the VexRiscv area saving implementation @@ -899,9 +893,7 @@ public: if(dRead(pAddr, 4, &data)){ trap(0, 5, address); } else { - reservedEntries[reservedEntriesPtr].valid = true; - reservedEntries[reservedEntriesPtr].address = address; - reservedEntriesPtr = (reservedEntriesPtr + 1) % RESERVED_ENTRY_COUNT; + lrscReserved = true; rfWrite(rd32, data); pcWrite(pc + 4); } @@ -913,8 +905,7 @@ public: trap(0, 6, address); } else { if(v2p(address, &pAddr, WRITE)){ trap(0, 15, address); return; } - bool hit = false; - for(int i = 0;i < RESERVED_ENTRY_COUNT;i++) hit |= reservedEntries[i].valid && reservedEntries[i].address == address; + bool hit = lrscReserved; if(hit){ dWrite(pAddr, 4, i32_rs2); } @@ -3762,11 +3753,11 @@ int main(int argc, char **argv, char **env) { #ifdef LRSC - redo(REDO,WorkspaceRegression("lrsc").loadHex("../raw/lrsc/build/lrsc.hex")->bootAt(0x00000000u)->run(10e3);); + redo(REDO,WorkspaceRegression("lrsc").withRiscvRef()->loadHex("../raw/lrsc/build/lrsc.hex")->bootAt(0x00000000u)->run(10e3);); #endif #ifdef AMO - redo(REDO,WorkspaceRegression("amo").loadHex("../raw/amo/build/amo.hex")->bootAt(0x00000000u)->run(10e3);); + redo(REDO,WorkspaceRegression("amo").withRiscvRef()->loadHex("../raw/amo/build/amo.hex")->bootAt(0x00000000u)->run(10e3);); #endif #ifdef DHRYSTONE From b654d824ad6ea2c73f450d42fe36098b575ffac9 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Tue, 23 Apr 2019 21:55:48 +0200 Subject: [PATCH 175/951] remove DebugPlugin from linux.scala, and set static branch prediction --- src/main/scala/vexriscv/demo/Linux.scala | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/scala/vexriscv/demo/Linux.scala b/src/main/scala/vexriscv/demo/Linux.scala index f5bad23f..235338a3 100644 --- a/src/main/scala/vexriscv/demo/Linux.scala +++ b/src/main/scala/vexriscv/demo/Linux.scala @@ -40,13 +40,13 @@ cd VexRiscv Run regressions => sbt "runMain vexriscv.demo.LinuxGen -r" cd src/test/cpp/regression -make clean run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD DHRYSTONE=yes SUPERVISOR=yes MMU=yes CSR=yes COMPRESSED=no MUL=yes DIV=yes LRSC=yes AMO=yes REDO=10 TRACE=no COREMARK=yes LINUX_REGRESSION=yes +make clean run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD DHRYSTONE=yes SUPERVISOR=yes MMU=yes CSR=yes DEBUG_PLUGIN=no COMPRESSED=no MUL=yes DIV=yes LRSC=yes AMO=yes REDO=10 TRACE=no COREMARK=yes LINUX_REGRESSION=yes Run linux in simulation (Require the machime mode emulator compiled in SIM mode) => sbt "runMain vexriscv.demo.LinuxGen" cd src/test/cpp/regression export BUILDROOT=/home/miaou/pro/riscv/buildrootSpinal -make clean run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD SUPERVISOR=yes CSR=yes COMPRESSED=no LRSC=yes AMO=yes REDO=0 DHRYSTONE=no LINUX_SOC=yes EMULATOR=../../../main/c/emulator/build/emulator.bin VMLINUX=$BUILDROOT/output/images/Image DTB=$BUILDROOT/board/spinal/vexriscv_sim/rv32.dtb RAMDISK=$BUILDROOT/output/images/rootfs.cpio WITH_USER_IO=yes TRACE=no FLOW_INFO=no +make clean run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD SUPERVISOR=yes CSR=yes DEBUG_PLUGIN=no COMPRESSED=no LRSC=yes AMO=yes REDO=0 DHRYSTONE=no LINUX_SOC=yes EMULATOR=../../../main/c/emulator/build/emulator.bin VMLINUX=$BUILDROOT/output/images/Image DTB=$BUILDROOT/board/spinal/vexriscv_sim/rv32.dtb RAMDISK=$BUILDROOT/output/images/rootfs.cpio WITH_USER_IO=yes TRACE=no FLOW_INFO=no Run linux with QEMU (Require the machime mode emulator compiled in QEMU mode) export BUILDROOT=/home/miaou/pro/riscv/buildrootSpinal @@ -152,7 +152,7 @@ object LinuxGen { new IBusCachedPlugin( resetVector = 0x80000000l, compressedGen = false, - prediction = NONE, + prediction = STATIC, injectorStage = false, config = InstructionCacheConfig( cacheSize = 4096*1, @@ -267,7 +267,7 @@ object LinuxGen { // wfiGenAsNop = true, // ucycleAccess = CsrAccess.NONE // )), - new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))), +// new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))), new BranchPlugin( earlyBranch = false, catchAddressMisaligned = true, From a331f3572403c0a99d72dc10ff08eb0f352321c8 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Wed, 24 Apr 2019 12:32:24 +0200 Subject: [PATCH 176/951] Icestorm flow now use nextpnr --- .../lib/eda/icestorm/IcestormFlow.scala | 26 +++++++++++++++---- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/src/main/scala/spinal/lib/eda/icestorm/IcestormFlow.scala b/src/main/scala/spinal/lib/eda/icestorm/IcestormFlow.scala index 08f08212..b6ab7b52 100644 --- a/src/main/scala/spinal/lib/eda/icestorm/IcestormFlow.scala +++ b/src/main/scala/spinal/lib/eda/icestorm/IcestormFlow.scala @@ -43,14 +43,30 @@ object IcestormFlow { def apply(workspacePath : String,toplevelPath : String,family : String,device : String, pack : String) : Report = { val projectName = toplevelPath.split("/").last.split("[.]").head - +//ifeq ($(NEXTPNR),yes) +//%.json: ${VERILOGS} +// rm -f ${TOPLEVEL}.v*.bin +// cp -f ${ROOT}/hardware/netlist/${TOPLEVEL}.v*.bin . | true +// yosys -p 'synth_ice40 -top $(TOPLEVEL) -json $@' $< +// +//%.asc: $(PIN_DEF) %.json constraint.py +// nextpnr-ice40 --$(DEVICE) --json $(TOPLEVEL).json --pcf $(PIN_DEF) --asc $(TOPLEVEL).asc --pre-pack constraint.py $(NEXTPNR_ARG) +//else +//%.blif: ${VERILOGS} +// rm -f ${TOPLEVEL}.v*.bin +// cp -f ${ROOT}/hardware/netlist/${TOPLEVEL}.v*.bin . | true +// yosys -p 'synth_ice40 -top ${TOPLEVEL} -blif $@' $< +// +//%.asc: $(PIN_DEF) %.blif +// arachne-pnr -d $(subst up,,$(subst hx,,$(subst lp,,$(DEVICE)))) -o $@ -p $^ +//endif val workspacePathFile = new File(workspacePath) FileUtils.deleteDirectory(workspacePathFile) workspacePathFile.mkdir() FileUtils.copyFileToDirectory(new File(toplevelPath), workspacePathFile) - doCmd(List("yosys", "-v3", "-p", s"synth_ice40 -top $projectName -blif ${projectName}.blif", s"$projectName.v" ), workspacePath) - val arachne = doCmd(List("arachne-pnr", "-d", device.replace("hx","").replace("up",""), "--max-passes", "600", "-P", pack, s"$projectName.blif" ,"-o", s"$projectName.asc"), workspacePath) + doCmd(List("yosys", "-v3", "-p", s"synth_ice40 -top $projectName -json ${projectName}.json", s"$projectName.v" ), workspacePath) + val arachne = doCmd(List("nextpnr-ice40", s"--$device", "--json", s"${projectName}.json","--asc", s"$projectName.asc"), workspacePath) doCmd(List("icepack", s"$projectName.asc", s"$projectName.bin"), workspacePath) val icetime = doCmd(List("icetime", "-tmd", device, s"${projectName}.asc"), workspacePath) new Report{ @@ -65,7 +81,7 @@ object IcestormFlow { } override def getArea() = { try { - intFind.findFirstIn("LCs[^\\n]*\\/".r.findFirstIn(arachne).get).get.toString() + " LC" + intFind.findFirstIn("ICESTORM_LC\\:[^\\n]*\\/".r.findFirstIn(arachne).get).get.toString() + " LC" } catch { case e : Throwable => "error" } @@ -151,7 +167,7 @@ object IcestormFlow { // } SpinalVerilog(StreamFifo(Bits(8 bits), 64)) val report = IcestormFlow( - workspacePath="/home/spinalvm/tmp", + workspacePath="/media/miaou/HD/linux/tmp", toplevelPath="StreamFifo.v", family="iCE40", device="up5k", From 74e5cc49f958078aea7866463c17d938abac0c41 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Wed, 24 Apr 2019 12:32:37 +0200 Subject: [PATCH 177/951] Add the linux config into the synthesis bench --- src/main/scala/vexriscv/demo/SynthesisBench.scala | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/demo/SynthesisBench.scala b/src/main/scala/vexriscv/demo/SynthesisBench.scala index 7976ac08..2413cf33 100644 --- a/src/main/scala/vexriscv/demo/SynthesisBench.scala +++ b/src/main/scala/vexriscv/demo/SynthesisBench.scala @@ -101,10 +101,16 @@ object VexRiscvSynthesisBench { } - val rtls = List(smallestNoCsr, smallest, smallAndProductive, smallAndProductiveWithICache, fullNoMmuNoCache, noCacheNoMmuMaxPerf, fullNoMmuMaxPerf, fullNoMmu, full) + val linuxBalanced = new Rtl { + override def getName(): String = "VexRiscv linux balanced" + override def getRtlPath(): String = "VexRiscvLinuxBalanced.v" + SpinalConfig(inlineRom = true).generateVerilog(wrap(new VexRiscv(LinuxGen.configFull(false, true))).setDefinitionName(getRtlPath().split("\\.").head)) + } + + val rtls = List(smallestNoCsr, smallest, smallAndProductive, smallAndProductiveWithICache, fullNoMmuNoCache, noCacheNoMmuMaxPerf, fullNoMmuMaxPerf, fullNoMmu, full, linuxBalanced) // val rtls = List(smallestNoCsr, smallest, smallAndProductive, smallAndProductiveWithICache) // val rtls = List(smallAndProductive, smallAndProductiveWithICache, fullNoMmuMaxPerf, fullNoMmu, full) -// val rtls = List(fullNoMmu) +// val rtls = List(smallAndProductive) val targets = XilinxStdTargets( vivadoArtix7Path = "/media/miaou/HD/linux/Xilinx/Vivado/2018.3/bin" From 017e17f9fa224f53cd5ffd32a8bf381bfef26017 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Wed, 24 Apr 2019 12:32:57 +0200 Subject: [PATCH 178/951] Update synthesis results in the readme --- README.md | 88 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 46 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index 4cd69f24..35c7a1d0 100644 --- a/README.md +++ b/README.md @@ -68,48 +68,54 @@ The CPU configurations used below can be found in the `src/scala/vexriscv/demo` ``` VexRiscv smallest (RV32I, 0.52 DMIPS/Mhz, no datapath bypass, no interrupt) -> - Artix 7 -> 346 Mhz 481 LUT 539 FF - Cyclone V -> 201 Mhz 347 ALMs - Cyclone IV -> 190 Mhz 673 LUT 529 FF - iCE40 -> 81 Mhz 1130 LC + Artix 7 -> 366 Mhz 488 LUT 505 FF + Cyclone V -> 181 Mhz 350 ALMs + Cyclone IV -> 177 Mhz 732 LUT 494 FF + iCE40 -> 85 Mhz 1131 LC VexRiscv smallest (RV32I, 0.52 DMIPS/Mhz, no datapath bypass) -> - Artix 7 -> 340 Mhz 562 LUT 589 FF - Cyclone V -> 202 Mhz 387 ALMs - Cyclone IV -> 180 Mhz 780 LUT 579 FF - iCE40 -> 71 Mhz 1278 LC + Artix 7 -> 317 Mhz 539 LUT 559 FF + Cyclone V -> 191 Mhz 393 ALMs + Cyclone IV -> 171 Mhz 826 LUT 547 FF + iCE40 -> 72 Mhz 1284 LC VexRiscv small and productive (RV32I, 0.82 DMIPS/Mhz) -> - Artix 7 -> 327 Mhz 698 LUT 558 FF - Cyclone V -> 158 Mhz 524 ALMs - Cyclone IV -> 146 Mhz 1,061 LUT 552 FF - iCE40 -> 55 Mhz 1541 LC + Artix 7 -> 338 Mhz 697 LUT 527 FF + Cyclone V -> 149 Mhz 495 ALMs + Cyclone IV -> 137 Mhz 1,103 LUT 522 FF + iCE40 -> 65 Mhz 1593 LC VexRiscv small and productive with I$ (RV32I, 0.72 DMIPS/Mhz, 4KB-I$) -> - Artix 7 -> 331 Mhz 727 LUT 600 FF - Cyclone V -> 152 Mhz 536 ALMs - Cyclone IV -> 156 Mhz 1,075 LUT 565 FF - iCE40 -> 54 Mhz 1686 LC + Artix 7 -> 314 Mhz 721 LUT 562 FF + Cyclone V -> 152 Mhz 504 ALMs + Cyclone IV -> 142 Mhz 1,146 LUT 528 FF + iCE40 -> 69 Mhz 1661 LC VexRiscv full no cache (RV32IM, 1.22 DMIPS/Mhz, single cycle barrel shifter, debug module, catch exceptions, static branch) -> - Artix 7 -> 295 Mhz 1399 LUT 971 FF - Cyclone V -> 151 Mhz 922 ALMs - Cyclone IV -> 136 Mhz 1,859 LUT 992 FF + Artix 7 -> 325 Mhz 1448 LUT 976 FF + Cyclone V -> 141 Mhz 957 ALMs + Cyclone IV -> 139 Mhz 2,001 LUT 966 FF VexRiscv full (RV32IM, 1.21 DMIPS/Mhz with cache trashing, 4KB-I$,4KB-D$, single cycle barrel shifter, debug module, catch exceptions, static branch) -> - Artix 7 -> 253 Mhz 1840 LUT 1394 FF - Cyclone V -> 126 Mhz 1,172 ALMs - Cyclone IV -> 117 Mhz 2,548 LUT 1,703 FF + Artix 7 -> 241 Mhz 1692 LUT 1202 FF + Cyclone V -> 132 Mhz 1,127 ALMs + Cyclone IV -> 124 Mhz 2,296 LUT 1,115 FF -VexRiscv full max perf -> (RV32IM, 1.44 DMIPS/Mhz, 16KB-I$,16KB-D$, single cycle barrel shifter, debug module, catch exceptions, dynamic branch prediction in the fetch stage, branch and shift operations done in the Execute stage) -> - Artix 7 -> 183 Mhz 1813 LUT 1424 FF - Cyclone V -> 93 Mhz 1,253 ALMs - Cyclone IV -> 84 Mhz 2,642 LUT 1,711 FF +VexRiscv full max dmips/mhz -> (RV32IM, 1.44 DMIPS/Mhz, 16KB-I$,16KB-D$, single cycle barrel shifter, debug module, catch exceptions, dynamic branch prediction in the fetch stage, branch and shift operations done in the Execute stage) -> + Artix 7 -> 195 Mhz 1824 LUT 1110 FF + Cyclone V -> 83 Mhz 1,067 ALMs + Cyclone IV -> 78 Mhz 2,335 LUT 1,045 FF VexRiscv full with MMU (RV32IM, 1.26 DMIPS/Mhz with cache trashing, 4KB-I$, 4KB-D$, single cycle barrel shifter, debug module, catch exceptions, dynamic branch, MMU) -> - Artix 7 -> 214 Mhz 2070 LUT 1913 FF - Cyclone V -> 108 Mhz 1,430 ALMs - Cyclone IV -> 100 Mhz 2,976 LUT 2,201 FF + Artix 7 -> 218 Mhz 1966 LUT 1551 FF + Cyclone V -> 123 Mhz 1,298 ALMs + Cyclone IV -> 109 Mhz 2,703 LUT 1,498 FF + +VexRiscv linux balanced (RV32IMA, 1.21 DMIPS/Mhz with cache trashing, 4KB-I$, 4KB-D$, single cycle barrel shifter, catch exceptions, static branch, MMU, Supervisor, Compatible with mainstream linux) -> + Artix 7 -> 239 Mhz 2483 LUT 2134 FF + Cyclone V -> 130 Mhz 1,636 ALMs + Cyclone IV -> 116 Mhz 3,324 LUT 2,010 FF + ``` The following configuration results in 1.44 DMIPS/MHz: @@ -292,9 +298,9 @@ You can find some FPGA projects which instantiate the Briey SoC here (DE1-SoC, D Here are some measurements of Briey SoC timings and area : ``` - Artix 7 -> 233 Mhz 3035 LUT 3289 FF - Cyclone V -> 114 Mhz 2,073 ALMs - Cyclone IV -> 101 Mhz 4,279 LUT 3,167 FF + Artix 7 -> 232 Mhz 3042 LUT 3281 FF + Cyclone V -> 138 Mhz 2,179 ALMs + Cyclone IV -> 120 Mhz 4,333 LUT 3,167 FF ``` ## Murax SoC @@ -347,18 +353,16 @@ Here are some timing and area measurements of the Murax SoC: ``` Murax interlocked stages (0.45 DMIPS/Mhz, 8 bits GPIO) -> - Artix 7 -> 299 Mhz 984 LUT 1186 FF - Cyclone V -> 175 Mhz 710 ALMs - Cyclone IV -> 137 Mhz 1,436 LUT 1,193 FF - iCE40 -> 48 Mhz 2337 LC (icestorm) - iCE40Ultra -> 20 Mhz 2337 LC (icestorm) + Artix 7 - > 301 Mhz 1032 LUT 1199 FF + Cyclone V -> 183 Mhz 736 ALMs + Cyclone IV -> 148 Mhz 1,481 LUT 1,204 FF + iCE40 -> 69 Mhz 2403 LC (nextpnr) MuraxFast bypassed stages (0.65 DMIPS/Mhz, 8 bits GPIO) -> - Artix 7 -> 294 Mhz 1128 LUT 1219 FF - Cyclone V -> 165 Mhz 840 ALMs - Cyclone IV -> 141 Mhz 1,680 LUT 1,227 FF - iCE40 -> 48 Mhz 2702 LC (icestorm) - iCE40Ultra -> 22 Mhz 2702 LC (icestorm) + Artix 7 -> 321 Mhz 1198 LUT 1298 FF + Cyclone V -> 165 Mhz 873 ALMs + Cyclone IV -> 145 Mhz 1,691 LUT 1,239 FF + iCE40 -> 61 Mhz 2778 LC (nextpnr) ``` Some scripts to generate the SoC and call the icestorm toolchain can be found here: `scripts/Murax/` From 431bec84fbfeb19cba3303da307eb991c51fbca7 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Wed, 24 Apr 2019 22:17:46 +0200 Subject: [PATCH 179/951] Switch to SpinalHDL 1.3.3 (release) --- build.sbt | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/build.sbt b/build.sbt index 64be7cf7..29cebe0c 100644 --- a/build.sbt +++ b/build.sbt @@ -4,19 +4,19 @@ lazy val root = (project in file(".")). inThisBuild(List( organization := "com.github.spinalhdl", scalaVersion := "2.11.12", - version := "1.0.0" + version := "2.0.0" )), libraryDependencies ++= Seq( -// "com.github.spinalhdl" % "spinalhdl-core_2.11" % "1.3.2", -// "com.github.spinalhdl" % "spinalhdl-lib_2.11" % "1.3.2", + "com.github.spinalhdl" % "spinalhdl-core_2.11" % "1.3.3", + "com.github.spinalhdl" % "spinalhdl-lib_2.11" % "1.3.3", "org.scalatest" % "scalatest_2.11" % "2.2.1", "org.yaml" % "snakeyaml" % "1.8" ), name := "VexRiscv" - ).dependsOn(spinalHdlSim,spinalHdlCore,spinalHdlLib) -lazy val spinalHdlSim = ProjectRef(file("../SpinalHDL"), "sim") -lazy val spinalHdlCore = ProjectRef(file("../SpinalHDL"), "core") -lazy val spinalHdlLib = ProjectRef(file("../SpinalHDL"), "lib") + )//.dependsOn(spinalHdlSim,spinalHdlCore,spinalHdlLib) +//lazy val spinalHdlSim = ProjectRef(file("../SpinalHDL"), "sim") +//lazy val spinalHdlCore = ProjectRef(file("../SpinalHDL"), "core") +//lazy val spinalHdlLib = ProjectRef(file("../SpinalHDL"), "lib") fork := true \ No newline at end of file From d64589cc48a74bfe7e979060efd910c8399ab617 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Thu, 25 Apr 2019 17:36:10 +0200 Subject: [PATCH 180/951] Add configs without memory/writeback stages in regressions Add rfReadInExecute configs in regressions Fix ShiftPluginLight and DBusSimplePlugin for configs with rfReadInExecute stage configs --- src/main/scala/vexriscv/Stage.scala | 3 + src/main/scala/vexriscv/VexRiscv.scala | 19 +- .../vexriscv/plugin/DBusSimplePlugin.scala | 4 +- .../scala/vexriscv/plugin/RegFilePlugin.scala | 2 +- .../scala/vexriscv/plugin/ShiftPlugins.scala | 15 +- src/test/cpp/regression/fail.gtkw | 42 ++-- src/test/cpp/regression/main.cpp | 38 ++-- .../vexriscv/TestIndividualFeatures.scala | 207 ++++++++++-------- 8 files changed, 177 insertions(+), 153 deletions(-) diff --git a/src/main/scala/vexriscv/Stage.scala b/src/main/scala/vexriscv/Stage.scala index e293f495..f036dfb3 100644 --- a/src/main/scala/vexriscv/Stage.scala +++ b/src/main/scala/vexriscv/Stage.scala @@ -70,6 +70,9 @@ class Stage() extends Area{ val dontSample = mutable.HashMap[Stageable[_], ArrayBuffer[Bool]]() + def dontSampleStageable(s : Stageable[_], cond : Bool): Unit ={ + dontSample.getOrElseUpdate(s, ArrayBuffer[Bool]()) += cond + } def inputInit[T <: BaseType](stageable : Stageable[T],initValue : T) = Component.current.addPrePopTask(() => inputsDefault(stageable.asInstanceOf[Stageable[Data]]).asInstanceOf[T].getDrivingReg.init(initValue)) } \ No newline at end of file diff --git a/src/main/scala/vexriscv/VexRiscv.scala b/src/main/scala/vexriscv/VexRiscv.scala index be5505f8..26d9489e 100644 --- a/src/main/scala/vexriscv/VexRiscv.scala +++ b/src/main/scala/vexriscv/VexRiscv.scala @@ -99,18 +99,13 @@ class VexRiscv(val config : VexRiscvConfig) extends Component with Pipeline{ plugins ++= config.plugins //regression usage - 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) - if(withWriteBackStage) { - writeBack.input(config.INSTRUCTION) keep() addAttribute (Verilator.public) - writeBack.input(config.PC) keep() addAttribute (Verilator.public) - writeBack.arbitration.isValid keep() addAttribute (Verilator.public) - writeBack.arbitration.isFiring keep() addAttribute (Verilator.public) - } - decode.arbitration.removeIt.noBackendCombMerge //Verilator perf + val lastStageInstruction = CombInit(stages.last.input(config.INSTRUCTION)) keep() addAttribute (Verilator.public) + val lastStagePc = CombInit(stages.last.input(config.PC)) keep() addAttribute (Verilator.public) + val lastStageIsValid = CombInit(stages.last.arbitration.isValid) keep() addAttribute (Verilator.public) + val lastStageIsFiring = CombInit(stages.last.arbitration.isFiring) keep() addAttribute (Verilator.public) + + //Verilator perf + decode.arbitration.removeIt.noBackendCombMerge if(withMemoryStage){ memory.arbitration.removeIt.noBackendCombMerge } diff --git a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala index 140fbebf..aba2e886 100644 --- a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala @@ -329,12 +329,12 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, } //Emit dBus.cmd request + val cmdSent = if(rspStage == execute) RegInit(False) setWhen(dBus.cmd.fire) clearWhen(!execute.arbitration.isStuck) else False val cmdStage = if(emitCmdInMemoryStage) memory else execute cmdStage plug new Area{ import cmdStage._ val privilegeService = pipeline.serviceElse(classOf[PrivilegeService], PrivilegeServiceDefault()) - val cmdSent = if(rspStage == execute) RegInit(False) setWhen(dBus.cmd.fire) clearWhen(!execute.arbitration.isStuck) else False if (catchAddressMisaligned) insert(ALIGNEMENT_FAULT) := (dBus.cmd.size === 2 && dBus.cmd.address(1 downto 0) =/= 0) || (dBus.cmd.size === 1 && dBus.cmd.address(0 downto 0) =/= 0) @@ -413,7 +413,7 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, insert(MEMORY_READ_DATA) := dBus.rsp.data - arbitration.haltItself setWhen(arbitration.isValid && input(MEMORY_ENABLE) && !input(MEMORY_STORE) && !dBus.rsp.ready) + arbitration.haltItself setWhen(arbitration.isValid && input(MEMORY_ENABLE) && !input(MEMORY_STORE) && (!dBus.rsp.ready || (if(rspStage == execute) !cmdSent else False))) if(catchSomething) { memoryExceptionPort.valid := False diff --git a/src/main/scala/vexriscv/plugin/RegFilePlugin.scala b/src/main/scala/vexriscv/plugin/RegFilePlugin.scala index 8bc561d0..2da66dea 100644 --- a/src/main/scala/vexriscv/plugin/RegFilePlugin.scala +++ b/src/main/scala/vexriscv/plugin/RegFilePlugin.scala @@ -91,7 +91,7 @@ class RegFilePlugin(regFileReadyKind : RegFileReadKind, import writeStage._ def shadowPrefix(that : Bits) = if(withShadow) global.shadow.write ## that else that - val regFileWrite = global.regFile.writePort.addAttribute(Verilator.public) + val regFileWrite = global.regFile.writePort.addAttribute(Verilator.public).setName("lastStageRegFileWrite") regFileWrite.valid := output(REGFILE_WRITE_VALID) && arbitration.isFiring regFileWrite.address := U(shadowPrefix(output(INSTRUCTION)(rdRange))) regFileWrite.data := output(REGFILE_WRITE_DATA) diff --git a/src/main/scala/vexriscv/plugin/ShiftPlugins.scala b/src/main/scala/vexriscv/plugin/ShiftPlugins.scala index 6fa26d78..fcebe3aa 100644 --- a/src/main/scala/vexriscv/plugin/ShiftPlugins.scala +++ b/src/main/scala/vexriscv/plugin/ShiftPlugins.scala @@ -69,12 +69,14 @@ class FullBarrelShifterPlugin(earlyInjection : Boolean = false) extends Plugin[V val injectionStage = if(earlyInjection) execute else memory injectionStage plug new Area{ import injectionStage._ - switch(input(SHIFT_CTRL)){ - is(ShiftCtrlEnum.SLL){ - output(REGFILE_WRITE_DATA) := Reverse(input(SHIFT_RIGHT)) - } - is(ShiftCtrlEnum.SRL,ShiftCtrlEnum.SRA){ - output(REGFILE_WRITE_DATA) := input(SHIFT_RIGHT) + when(arbitration.isValid){ + switch(input(SHIFT_CTRL)) { + is(ShiftCtrlEnum.SLL) { + output(REGFILE_WRITE_DATA) := Reverse(input(SHIFT_RIGHT)) + } + is(ShiftCtrlEnum.SRL, ShiftCtrlEnum.SRA) { + output(REGFILE_WRITE_DATA) := input(SHIFT_RIGHT) + } } } } @@ -162,6 +164,7 @@ class LightShifterPlugin extends Plugin[VexRiscv]{ val shiftInput = isActive ? (if(withMemoryStage) memory.input(REGFILE_WRITE_DATA) else shiftReg) | input(SRC1) val done = amplitude(4 downto 1) === 0 + if(withMemoryStage) memory.dontSampleStageable(REGFILE_WRITE_DATA, arbitration.isStuckByOthers) when(arbitration.isValid && isShift && input(SRC2)(4 downto 0) =/= 0){ output(REGFILE_WRITE_DATA) := input(SHIFT_CTRL).mux( diff --git a/src/test/cpp/regression/fail.gtkw b/src/test/cpp/regression/fail.gtkw index 2f3ba231..d0fff464 100644 --- a/src/test/cpp/regression/fail.gtkw +++ b/src/test/cpp/regression/fail.gtkw @@ -1,39 +1,29 @@ [*] [*] GTKWave Analyzer v3.3.100 (w)1999-2019 BSI -[*] Sun Apr 14 19:28:23 2019 +[*] Thu Apr 25 14:41:35 2019 [*] -[dumpfile] "/home/miaou/pro/VexRiscv/src/test/cpp/regression/mmu.vcd" -[dumpfile_mtime] "Sun Apr 14 19:27:24 2019" -[dumpfile_size] 1551340 +[dumpfile] "/home/miaou/pro/VexRiscv/src/test/cpp/regression/C.SLLI.vcd" +[dumpfile_mtime] "Thu Apr 25 14:39:03 2019" +[dumpfile_size] 295925 [savefile] "/home/miaou/pro/VexRiscv/src/test/cpp/regression/fail.gtkw" -[timestart] 348 +[timestart] 0 [size] 1920 1030 [pos] -458 -215 -*-2.000000 357 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 +*-2.000000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 [treeopen] TOP. -[treeopen] TOP.VexRiscv. -[sst_width] 287 -[signals_width] 563 +[sst_width] 196 +[signals_width] 366 [sst_expanded] 1 -[sst_vpaned_height] 279 +[sst_vpaned_height] 299 @28 -TOP.VexRiscv.writeBack_arbitration_isFiring +TOP.VexRiscv.lastStageIsValid +TOP.VexRiscv.lastStageIsFiring @22 -TOP.VexRiscv.writeBack_PC[31:0] -TOP.VexRiscv.writeBack_INSTRUCTION[31:0] -TOP.VexRiscv.writeBack_RegFilePlugin_regFileWrite_payload_address[4:0] -TOP.VexRiscv.writeBack_RegFilePlugin_regFileWrite_payload_data[31:0] +TOP.VexRiscv.lastStageInstruction[31:0] +TOP.VexRiscv.lastStagePc[31:0] +TOP.VexRiscv.lastStageRegFileWrite_payload_address[4:0] +TOP.VexRiscv.lastStageRegFileWrite_payload_data[31:0] @28 -TOP.VexRiscv.writeBack_RegFilePlugin_regFileWrite_valid -@29 -TOP.VexRiscv.CsrPlugin_interrupt -@28 -TOP.VexRiscv.CsrPlugin_exception -@22 -TOP.VexRiscv.CsrPlugin_mcause_exceptionCode[3:0] -@28 -TOP.VexRiscv.CsrPlugin_mcause_interrupt -@22 -TOP.VexRiscv.CsrPlugin_mepc[31:0] +TOP.VexRiscv.lastStageRegFileWrite_valid [pattern_trace] 1 [pattern_trace] 0 diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 3f6c0f09..27c0c4ef 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -1411,7 +1411,7 @@ public: virtual void fillSimELements(); void dump(int i){ #ifdef TRACE - if(i == TRACE_START) cout << "START TRACE" << endl; + if(i == TRACE_START && i != 0) cout << "START TRACE" << endl; if(i >= TRACE_START) tfp->dump(i); #endif } @@ -1509,7 +1509,7 @@ public: #ifndef MTIME_INSTR_FACTOR mTime = i/2; #else - mTime += top->VexRiscv->writeBack_arbitration_isFiring*MTIME_INSTR_FACTOR; + mTime += top->VexRiscv->lastStageIsFiring*MTIME_INSTR_FACTOR; #endif #endif #ifdef TIMER_INTERRUPT @@ -1554,7 +1554,7 @@ public: } } #endif - if(top->VexRiscv->writeBack_arbitration_isFiring){ + if(top->VexRiscv->lastStageIsFiring){ if(riscvRefEnable) { // privilegeCounters[riscvRef.privilege]++; // if((riscvRef.stepCounter & 0xFFFFF) == 0){ @@ -1568,8 +1568,8 @@ public: bool mIntExt = false; } - if(riscvRefEnable && top->VexRiscv->writeBack_PC != riscvRef.lastPc){ - cout << hex << " pc missmatch " << top->VexRiscv->writeBack_PC << " should be " << riscvRef.lastPc << dec << endl; + if(riscvRefEnable && top->VexRiscv->lastStagePc != riscvRef.lastPc){ + cout << hex << " pc missmatch " << top->VexRiscv->lastStagePc << " should be " << riscvRef.lastPc << dec << endl; fail(); } @@ -1578,16 +1578,16 @@ public: int32_t rfWriteAddress; int32_t rfWriteData; - if(top->VexRiscv->writeBack_RegFilePlugin_regFileWrite_valid == 1 && top->VexRiscv->writeBack_RegFilePlugin_regFileWrite_payload_address != 0){ + if(top->VexRiscv->lastStageRegFileWrite_valid == 1 && top->VexRiscv->lastStageRegFileWrite_payload_address != 0){ rfWriteValid = true; - rfWriteAddress = top->VexRiscv->writeBack_RegFilePlugin_regFileWrite_payload_address; - rfWriteData = top->VexRiscv->writeBack_RegFilePlugin_regFileWrite_payload_data; + rfWriteAddress = top->VexRiscv->lastStageRegFileWrite_payload_address; + rfWriteData = top->VexRiscv->lastStageRegFileWrite_payload_data; #ifdef TRACE_ACCESS regTraces << #ifdef TRACE_WITH_TIME currentTime << #endif - " PC " << hex << setw(8) << top->VexRiscv->writeBack_PC << " : reg[" << dec << setw(2) << (uint32_t)top->VexRiscv->writeBack_RegFilePlugin_regFileWrite_payload_address << "] = " << hex << setw(8) << top->VexRiscv->writeBack_RegFilePlugin_regFileWrite_payload_data << dec << endl; + " PC " << hex << setw(8) << top->VexRiscv->lastStagePc << " : reg[" << dec << setw(2) << (uint32_t)top->VexRiscv->lastStageRegFileWrite_payload_address << "] = " << hex << setw(8) << top->VexRiscv->lastStageRegFileWrite_payload_data << dec << endl; #endif } else { #ifdef TRACE_ACCESS @@ -1595,7 +1595,7 @@ public: #ifdef TRACE_WITH_TIME currentTime << #endif - " PC " << hex << setw(8) << top->VexRiscv->writeBack_PC << dec << endl; + " PC " << hex << setw(8) << top->VexRiscv->lastStagePc << dec << endl; #endif } if(riscvRefEnable) if(rfWriteValid != riscvRef.rfWriteValid || @@ -1636,7 +1636,7 @@ public: } catch (const std::exception& e) { staticMutex.lock(); - cout << "FAIL " << name << " at PC=" << hex << setw(8) << top->VexRiscv->writeBack_PC << dec; //<< " seed : " << seed << + cout << "FAIL " << name << " at PC=" << hex << setw(8) << top->VexRiscv->lastStagePc << dec; //<< " seed : " << seed << if(riscvRefEnable) cout << hex << " REF PC=" << riscvRef.lastPc << " REF I=" << riscvRef.lastInstruction << dec; cout << " time=" << i; cout << endl; @@ -2701,9 +2701,9 @@ public: } virtual void checks(){ - if(top->VexRiscv->writeBack_RegFilePlugin_regFileWrite_valid == 1 && top->VexRiscv->writeBack_RegFilePlugin_regFileWrite_payload_address != 0){ - assertEq(top->VexRiscv->writeBack_RegFilePlugin_regFileWrite_payload_address, regFileWriteRefArray[regFileWriteRefIndex][0]); - assertEq(top->VexRiscv->writeBack_RegFilePlugin_regFileWrite_payload_data, regFileWriteRefArray[regFileWriteRefIndex][1]); + if(top->VexRiscv->lastStageRegFileWrite_valid == 1 && top->VexRiscv->lastStageRegFileWrite_payload_address != 0){ + assertEq(top->VexRiscv->lastStageRegFileWrite_payload_address, regFileWriteRefArray[regFileWriteRefIndex][0]); + assertEq(top->VexRiscv->lastStageRegFileWrite_payload_data, regFileWriteRefArray[regFileWriteRefIndex][1]); //printf("%d\n",i); regFileWriteRefIndex++; @@ -2727,8 +2727,8 @@ public: } virtual void checks(){ - if(top->VexRiscv->writeBack_RegFilePlugin_regFileWrite_valid == 1 && top->VexRiscv->writeBack_RegFilePlugin_regFileWrite_payload_address == 28){ - assertEq(top->VexRiscv->writeBack_RegFilePlugin_regFileWrite_payload_data, ref[refIndex]); + if(top->VexRiscv->lastStageRegFileWrite_valid == 1 && top->VexRiscv->lastStageRegFileWrite_payload_address == 28){ + assertEq(top->VexRiscv->lastStageRegFileWrite_payload_data, ref[refIndex]); //printf("%d\n",i); refIndex++; @@ -2755,11 +2755,11 @@ public: } virtual void checks(){ - if(top->VexRiscv->writeBack_arbitration_isFiring && top->VexRiscv->writeBack_INSTRUCTION == 0x00000013){ + if(top->VexRiscv->lastStageIsFiring && top->VexRiscv->lastStageInstruction == 0x00000013){ uint32_t instruction; bool error; - Workspace::mem.read(top->VexRiscv->writeBack_PC, 4, (uint8_t*)&instruction); - //printf("%x => %x\n", top->VexRiscv->writeBack_PC, instruction ); + Workspace::mem.read(top->VexRiscv->lastStagePc, 4, (uint8_t*)&instruction); + //printf("%x => %x\n", top->VexRiscv->lastStagePc, instruction ); if(instruction == 0x00000073){ uint32_t code = top->VexRiscv->RegFilePlugin_regFile[28]; uint32_t code2 = top->VexRiscv->RegFilePlugin_regFile[3]; diff --git a/src/test/scala/vexriscv/TestIndividualFeatures.scala b/src/test/scala/vexriscv/TestIndividualFeatures.scala index 2493aaf7..cedf989c 100644 --- a/src/test/scala/vexriscv/TestIndividualFeatures.scala +++ b/src/test/scala/vexriscv/TestIndividualFeatures.scala @@ -47,6 +47,9 @@ object VexRiscvUniverse{ val MMU = new VexRiscvUniverse val FORCE_MULDIV = new VexRiscvUniverse val SUPERVISOR = new VexRiscvUniverse + val NO_WRITEBACK = new VexRiscvUniverse + val NO_MEMORY = new VexRiscvUniverse + val EXECUTE_RF = new VexRiscvUniverse } @@ -55,24 +58,29 @@ object Hack{ } class ShiftDimension extends VexRiscvDimension("Shift") { - override def randomPositionImpl(universes: Seq[ConfigUniverse], r: Random) = random(r, List( - new VexRiscvPosition("FullLate") { + override def randomPositionImpl(universes: Seq[ConfigUniverse], r: Random) = { + var l = List( + new VexRiscvPosition("FullEarly") { + override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new FullBarrelShifterPlugin(earlyInjection = true) + }, + new VexRiscvPosition("Light") { + override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new LightShifterPlugin + } + ) + + if(!universes.contains(VexRiscvUniverse.NO_MEMORY)) l = new VexRiscvPosition("FullLate") { override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new FullBarrelShifterPlugin(earlyInjection = false) - }, - new VexRiscvPosition("FullEarly") { - override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new FullBarrelShifterPlugin(earlyInjection = true) - }, - new VexRiscvPosition("Light") { - override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new LightShifterPlugin - } - )) + } :: l + + random(r, l) + } } class BranchDimension extends VexRiscvDimension("Branch") { override def randomPositionImpl(universes: Seq[ConfigUniverse], r: Random) = { val catchAll = universes.contains(VexRiscvUniverse.CATCH_ALL) - val early = r.nextBoolean() + val early = r.nextBoolean() || universes.contains(VexRiscvUniverse.NO_MEMORY) new VexRiscvPosition(if(early) "Early" else "Late") { override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new BranchPlugin( earlyBranch = early, @@ -87,7 +95,51 @@ class BranchDimension extends VexRiscvDimension("Branch") { class MulDivDimension extends VexRiscvDimension("MulDiv") { override def randomPositionImpl(universes: Seq[ConfigUniverse], r: Random) = { - var l = List( + val noMemory = universes.contains(VexRiscvUniverse.NO_MEMORY) + val noWriteBack = universes.contains(VexRiscvUniverse.NO_WRITEBACK) + + var l = List[VexRiscvPosition]() + if(!noMemory) { + l = new VexRiscvPosition("MulDivAsic") { + override def testParam = "MUL=yes DIV=yes" + override def applyOn(config: VexRiscvConfig): Unit = { + config.plugins += new MulDivIterativePlugin( + genMul = true, + genDiv = true, + mulUnrollFactor = 32, + divUnrollFactor = 4 + ) + } + } :: new VexRiscvPosition("MulDivFpgaNoDsp") { + override def testParam = "MUL=yes DIV=yes" + override def applyOn(config: VexRiscvConfig): Unit = { + config.plugins += new MulDivIterativePlugin( + genMul = true, + genDiv = true, + mulUnrollFactor = 1, + divUnrollFactor = 1 + ) + } + } :: new VexRiscvPosition("MulDivFpgaNoDspFastMul") { + override def testParam = "MUL=yes DIV=yes" + override def applyOn(config: VexRiscvConfig): Unit = { + config.plugins += new MulDivIterativePlugin( + genMul = true, + genDiv = true, + mulUnrollFactor = 8, + divUnrollFactor = 1 + ) + } + } :: l + } + + if(!universes.contains(VexRiscvUniverse.FORCE_MULDIV)) l = new VexRiscvPosition("NoMulDiv") { + override def applyOn(config: VexRiscvConfig): Unit = {} + override def testParam = "MUL=no DIV=no" + } :: l + + + if(!noMemory && !noWriteBack) l = new VexRiscvPosition("MulDivFpga") { override def testParam = "MUL=yes DIV=yes" override def applyOn(config: VexRiscvConfig): Unit = { @@ -99,46 +151,7 @@ class MulDivDimension extends VexRiscvDimension("MulDiv") { divUnrollFactor = 1 ) } - }, - new VexRiscvPosition("MulDivAsic") { - override def testParam = "MUL=yes DIV=yes" - override def applyOn(config: VexRiscvConfig): Unit = { - config.plugins += new MulDivIterativePlugin( - genMul = true, - genDiv = true, - mulUnrollFactor = 32, - divUnrollFactor = 4 - ) - } - }, - new VexRiscvPosition("MulDivFpgaNoDsp") { - override def testParam = "MUL=yes DIV=yes" - override def applyOn(config: VexRiscvConfig): Unit = { - config.plugins += new MulDivIterativePlugin( - genMul = true, - genDiv = true, - mulUnrollFactor = 1, - divUnrollFactor = 1 - ) - } - }, - new VexRiscvPosition("MulDivFpgaNoDspFastMul") { - override def testParam = "MUL=yes DIV=yes" - override def applyOn(config: VexRiscvConfig): Unit = { - config.plugins += new MulDivIterativePlugin( - genMul = true, - genDiv = true, - mulUnrollFactor = 8, - divUnrollFactor = 1 - ) - } - } - ) - - if(!universes.contains(VexRiscvUniverse.FORCE_MULDIV)) l = new VexRiscvPosition("NoMulDiv") { - override def applyOn(config: VexRiscvConfig): Unit = {} - override def testParam = "MUL=no DIV=no" - } :: l + } :: l random(r, l) } @@ -149,26 +162,30 @@ trait InstructionAnticipatedPosition{ } class RegFileDimension extends VexRiscvDimension("RegFile") { + override def randomPositionImpl(universes: Seq[ConfigUniverse], r: Random) = { + val executeRf = universes.contains(VexRiscvUniverse.EXECUTE_RF) + random(r, List( + new VexRiscvPosition("Async" + (if(executeRf) "ER" else "DR")) { + override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new RegFilePlugin( + regFileReadyKind = plugin.ASYNC, + zeroBoot = true, + readInExecute = executeRf + ) + }, + new VexRiscvPosition("Sync" + (if(executeRf) "ER" else "DR")) { + override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new RegFilePlugin( + regFileReadyKind = plugin.SYNC, + zeroBoot = true, + readInExecute = executeRf + ) - override def randomPositionImpl(universes: Seq[ConfigUniverse], r: Random) = random(r, List( - new VexRiscvPosition("Async") { - override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new RegFilePlugin( - regFileReadyKind = plugin.ASYNC, - zeroBoot = true - ) - }, - new VexRiscvPosition("Sync") { - override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new RegFilePlugin( - regFileReadyKind = plugin.SYNC, - zeroBoot = true - ) - - override def isCompatibleWith(positions: Seq[ConfigPosition[VexRiscvConfig]]) = positions.exists{ - case p : InstructionAnticipatedPosition => p.instructionAnticipatedOk() - case _ => false + override def isCompatibleWith(positions: Seq[ConfigPosition[VexRiscvConfig]]) = executeRf || positions.exists{ + case p : InstructionAnticipatedPosition => p.instructionAnticipatedOk() + case _ => false + } } - } - )) + )) + } } @@ -255,7 +272,8 @@ class HazardDimension extends VexRiscvDimension("Hazard") { class SrcDimension extends VexRiscvDimension("Src") { override def randomPositionImpl(universes: Seq[ConfigUniverse], r: Random) = { - val separatedAddSub, executeInsertion = r.nextBoolean() + val separatedAddSub = r.nextBoolean() + val executeInsertion = universes.contains(VexRiscvUniverse.EXECUTE_RF) || r.nextBoolean() new VexRiscvPosition((if (separatedAddSub) "AddSub" else "") + (if (executeInsertion) "Execute" else "")) { override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new SrcPlugin( separatedAddSub = separatedAddSub, @@ -353,10 +371,14 @@ class DBusDimension extends VexRiscvDimension("DBus") { override def randomPositionImpl(universes: Seq[ConfigUniverse], r: Random) = { val catchAll = universes.contains(VexRiscvUniverse.CATCH_ALL) val mmuConfig = if(universes.contains(VexRiscvUniverse.MMU)) MmuPortConfig( portTlbSize = 4) else null + val noMemory = universes.contains(VexRiscvUniverse.NO_MEMORY) + val noWriteBack = universes.contains(VexRiscvUniverse.NO_WRITEBACK) - if(r.nextDouble() < 0.4){ + + + if(r.nextDouble() < 0.4 || noMemory || noWriteBack){ val withLrSc = catchAll - val earlyInjection = r.nextBoolean() + val earlyInjection = r.nextBoolean() && !universes.contains(VexRiscvUniverse.NO_WRITEBACK) new VexRiscvPosition("Simple" + (if(earlyInjection) "Early" else "Late")) { override def testParam = "DBUS=SIMPLE " + (if(withLrSc) "LRSC=yes " else "") override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new DBusSimplePlugin( @@ -540,12 +562,16 @@ class TestIndividualFeatures extends FunSuite { // val usedPositions = mutable.HashSet[VexRiscvPosition](); // val positionsCount = dimensions.map(d => d.positions.length).sum - def doTest(positionsToApply : List[VexRiscvPosition], prefix : String = "", testSeed : Int): Unit ={ + def doTest(positionsToApply : List[VexRiscvPosition], prefix : String = "", testSeed : Int, universes : mutable.HashSet[VexRiscvUniverse]): Unit ={ // usedPositions ++= positionsToApply + val noMemory = universes.contains(VexRiscvUniverse.NO_MEMORY) + val noWriteback = universes.contains(VexRiscvUniverse.NO_WRITEBACK) def gen = { FileUtils.deleteQuietly(new File("VexRiscv.v")) SpinalVerilog{ val config = VexRiscvConfig( + withMemoryStage = !noMemory, + withWriteBackStage = !noWriteback, plugins = List( new IntAluPlugin, new YamlPlugin("cpu0.yaml") @@ -555,7 +581,8 @@ class TestIndividualFeatures extends FunSuite { new VexRiscv(config) } } - val name = positionsToApply.map(d => d.dimension.name + "_" + d.name).mkString("_") + + val name = (if(noMemory) "noMemoryStage_" else "") + (if(noWriteback) "noWritebackStage_" else "") + positionsToApply.map(d => d.dimension.name + "_" + d.name).mkString("_") test(prefix + name + "_gen") { gen } @@ -564,14 +591,10 @@ class TestIndividualFeatures extends FunSuite { test(prefix + name + "_test") { val debug = true val stdCmd = (s"make clean run WITH_USER_IO=no REDO=10 TRACE=${if(debug) "yes" else "no"} TRACE_START=9999924910246l FLOW_INFO=no STOP_ON_ERROR=no DHRYSTONE=yes COREMARK=yes THREAD_COUNT=${sys.env.getOrElse("VEXRISCV_REGRESSION_THREAD_COUNT", 1)} ") + s" SEED=${testSeed} " -// val stdCmd = "make clean run REDO=40 DHRYSTONE=no STOP_ON_ERROR=yes TRACE=yess " - val testCmd = stdCmd + (positionsToApply).map(_.testParam).mkString(" ") println(testCmd) val str = doCmd(testCmd) assert(str.contains("REGRESSION SUCCESS") && !str.contains("Broken pipe")) -// val intFind = "(\\d+\\.?)+".r -// val dmips = intFind.findFirstIn("DMIPS per Mhz\\: (\\d+.?)+".r.findAllIn(str).toList.last).get.toDouble } } @@ -581,9 +604,9 @@ class TestIndividualFeatures extends FunSuite { val seed = Random.nextLong() // val testId = Some(mutable.HashSet(18,34,77,85,118,129,132,134,152,167,175,188,191,198,199)) //37/29 sp_flop_rv32i_O3 -//val testId = Some(mutable.HashSet(3)) -// val testId = Some(mutable.HashSet(129, 134)) -// val seed = -1580866821569084523l +//val testId = Some(mutable.HashSet(0)) +// val testId = Some(mutable.HashSet(4)) +// val seed = -8309068850561113754l val rand = new Random(seed) @@ -595,14 +618,24 @@ class TestIndividualFeatures extends FunSuite { for(i <- 0 until sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_COUNT", "100").toInt){ var positions : List[VexRiscvPosition] = null var universe = mutable.HashSet[VexRiscvUniverse]() - if(sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_LINUX_RATE", "0.3").toDouble > Math.random()) { + if(rand.nextDouble() < 0.5) universe += VexRiscvUniverse.EXECUTE_RF + if(sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_LINUX_RATE", "0.3").toDouble > rand.nextDouble()) { universe += VexRiscvUniverse.CATCH_ALL universe += VexRiscvUniverse.MMU universe += VexRiscvUniverse.FORCE_MULDIV universe += VexRiscvUniverse.SUPERVISOR - } - if(sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_MACHINE_OS_RATE", "0.5").toDouble > Math.random()) { - universe += VexRiscvUniverse.CATCH_ALL + } else { + if(sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_MACHINE_OS_RATE", "0.5").toDouble > rand.nextDouble()) { + universe += VexRiscvUniverse.CATCH_ALL + } + var tmp = rand.nextDouble() + if(sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_DEMW_RATE", "0.6").toDouble > rand.nextDouble()){ + }else if(sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_DEM_RATE", "0.5").toDouble > rand.nextDouble()){ + universe += VexRiscvUniverse.NO_WRITEBACK + } else { + universe += VexRiscvUniverse.NO_WRITEBACK + universe += VexRiscvUniverse.NO_MEMORY + } } do{ @@ -611,7 +644,7 @@ class TestIndividualFeatures extends FunSuite { val testSeed = rand.nextInt() if(testId.isEmpty || testId.get.contains(i)) - doTest(positions," random_" + i + "_", testSeed) + doTest(positions," random_" + i + "_", testSeed, universe) Hack.dCounter += 1 } From 10255f2f8127700e2ac01c10e7fc1b6301c4e6fe Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Thu, 25 Apr 2019 21:11:23 +0200 Subject: [PATCH 181/951] Update readme --- README.md | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 35c7a1d0..acdad8b8 100644 --- a/README.md +++ b/README.md @@ -27,23 +27,21 @@ This repository hosts a RISC-V implementation written in SpinalHDL. Here are some specs : -- RV32I[M][C] instruction set -- Pipelined with 5 stages (Fetch, Decode, Execute, Memory, WriteBack) +- RV32I[M][C][A] instruction set (Atomic only inside a single core) +- Pipelined from 2 to 5+ stages ([Fetch*X], Decode, Execute, [Memory], [WriteBack]) - 1.44 DMIPS/Mhz --no-inline when nearly all features are enabled (1.57 DMIPS/Mhz when the divider lookup table is enabled) -- Optimized for FPGA, fully portable -- AXI4 and Avalon ready +- Optimized for FPGA, do not use any vendor specific IP block / primitive +- AXI4, Avalon, wishbone ready - Optional MUL/DIV extensions - Optional instruction and data caches - Optional hardware refilled MMU - Optional debug extension allowing Eclipse debugging via a GDB >> openOCD >> JTAG connection -- Optional interrupts and exception handling with Machine and User modes as defined in the [RISC-V Privileged ISA Specification v1.9](https://riscv.org/specifications/privileged-isa/). +- Optional interrupts and exception handling with Machine, [Supervisor] and [User] modes as defined in the [RISC-V Privileged ISA Specification v1.10](https://riscv.org/specifications/privileged-isa/). - Two implementations of shift instructions: Single cycle and shiftNumber cycles - Each stage can have optional bypass or interlock hazard logic -- Compatible with the mainstream RISC-V linux port -- Zephyr RISC-V port compatible +- Linux compatible +- Zephyr compatible - [FreeRTOS port](https://github.com/Dolu1990/FreeRTOS-RISCV) -- The data cache supports atomic LR/SC -- Optional RV32 compressed instruction support in the reworkFetch branch for configurations without instruction cache (will be merge in master, WIP) The hardware description of this CPU is done by using a very software oriented approach (without any overhead in the generated hardware). Here is a list of software concepts used: From 0edc781b365c5584819300cdd9275d208ad03f83 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 25 Apr 2019 23:18:45 +0200 Subject: [PATCH 182/951] Add some coremark results --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index acdad8b8..b6f56ac7 100644 --- a/README.md +++ b/README.md @@ -83,33 +83,33 @@ VexRiscv small and productive (RV32I, 0.82 DMIPS/Mhz) -> Cyclone IV -> 137 Mhz 1,103 LUT 522 FF iCE40 -> 65 Mhz 1593 LC -VexRiscv small and productive with I$ (RV32I, 0.72 DMIPS/Mhz, 4KB-I$) -> +VexRiscv small and productive with I$ (RV32I, 0.70 DMIPS/Mhz, 4KB-I$) -> Artix 7 -> 314 Mhz 721 LUT 562 FF Cyclone V -> 152 Mhz 504 ALMs Cyclone IV -> 142 Mhz 1,146 LUT 528 FF iCE40 -> 69 Mhz 1661 LC -VexRiscv full no cache (RV32IM, 1.22 DMIPS/Mhz, single cycle barrel shifter, debug module, catch exceptions, static branch) -> +VexRiscv full no cache (RV32IM, 1.21 DMIPS/Mhz 2.30 Coremark/Mhz, single cycle barrel shifter, debug module, catch exceptions, static branch) -> Artix 7 -> 325 Mhz 1448 LUT 976 FF Cyclone V -> 141 Mhz 957 ALMs Cyclone IV -> 139 Mhz 2,001 LUT 966 FF -VexRiscv full (RV32IM, 1.21 DMIPS/Mhz with cache trashing, 4KB-I$,4KB-D$, single cycle barrel shifter, debug module, catch exceptions, static branch) -> +VexRiscv full (RV32IM, 1.21 DMIPS/Mhz 2.30 Coremark/Mhz with cache trashing, 4KB-I$,4KB-D$, single cycle barrel shifter, debug module, catch exceptions, static branch) -> Artix 7 -> 241 Mhz 1692 LUT 1202 FF Cyclone V -> 132 Mhz 1,127 ALMs Cyclone IV -> 124 Mhz 2,296 LUT 1,115 FF -VexRiscv full max dmips/mhz -> (RV32IM, 1.44 DMIPS/Mhz, 16KB-I$,16KB-D$, single cycle barrel shifter, debug module, catch exceptions, dynamic branch prediction in the fetch stage, branch and shift operations done in the Execute stage) -> +VexRiscv full max dmips/mhz -> (RV32IM, 1.44 DMIPS/Mhz 2.70 Coremark/Mhz,, 16KB-I$,16KB-D$, single cycle barrel shifter, debug module, catch exceptions, dynamic branch prediction in the fetch stage, branch and shift operations done in the Execute stage) -> Artix 7 -> 195 Mhz 1824 LUT 1110 FF Cyclone V -> 83 Mhz 1,067 ALMs Cyclone IV -> 78 Mhz 2,335 LUT 1,045 FF -VexRiscv full with MMU (RV32IM, 1.26 DMIPS/Mhz with cache trashing, 4KB-I$, 4KB-D$, single cycle barrel shifter, debug module, catch exceptions, dynamic branch, MMU) -> +VexRiscv full with MMU (RV32IM, 1.24 DMIPS/Mhz 2.35 Coremark/Mhz, with cache trashing, 4KB-I$, 4KB-D$, single cycle barrel shifter, debug module, catch exceptions, dynamic branch, MMU) -> Artix 7 -> 218 Mhz 1966 LUT 1551 FF Cyclone V -> 123 Mhz 1,298 ALMs Cyclone IV -> 109 Mhz 2,703 LUT 1,498 FF -VexRiscv linux balanced (RV32IMA, 1.21 DMIPS/Mhz with cache trashing, 4KB-I$, 4KB-D$, single cycle barrel shifter, catch exceptions, static branch, MMU, Supervisor, Compatible with mainstream linux) -> +VexRiscv linux balanced (RV32IMA, 1.21 DMIPS/Mhz 2.27 Coremark/Mhz, with cache trashing, 4KB-I$, 4KB-D$, single cycle barrel shifter, catch exceptions, static branch, MMU, Supervisor, Compatible with mainstream linux) -> Artix 7 -> 239 Mhz 2483 LUT 2134 FF Cyclone V -> 130 Mhz 1,636 ALMs Cyclone IV -> 116 Mhz 3,324 LUT 2,010 FF From b2f387ccac81742912f97889c381639bae600818 Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Fri, 26 Apr 2019 18:01:35 +0800 Subject: [PATCH 183/951] MmuPlugin: fix generation without writeBack stage If there is no writeBack stage, the elaboration step would hit a NullPointerException when trying to insert into the writeBack stage. Instead, pull from the most recent stage, which is where MMU access should reside. Signed-off-by: Sean Cross --- src/main/scala/vexriscv/plugin/MmuPlugin.scala | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/MmuPlugin.scala b/src/main/scala/vexriscv/plugin/MmuPlugin.scala index ebf46c42..9dedde5d 100644 --- a/src/main/scala/vexriscv/plugin/MmuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/MmuPlugin.scala @@ -250,8 +250,9 @@ class MmuPlugin(ioRange : UInt => Bool, } } - writeBack plug new Area{ - import writeBack._ + val fenceStage = stages.last + fenceStage plug new Area{ + import fenceStage._ when(arbitration.isValid && input(IS_SFENCE_VMA)){ // || csrService.isWriting(CSR.SATP) for(port <- core.ports; line <- port.cache) line.valid := False //Assume that the instruction already fetched into the pipeline are ok } From d1e215e312493517fbc4f2986857a80af600752b Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Fri, 26 Apr 2019 18:02:43 +0800 Subject: [PATCH 184/951] caches: work without writeBack stage In the case of an MMU miss, the data caches will create a retry branch port. These currently implicitly go into the memory/writeBack stage, however not all CPUs have this stage. Place the retry branch port into the correct stage. Signed-off-by: Sean Cross --- src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala | 2 +- src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index 78af84f9..b8f2ba11 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -143,7 +143,7 @@ class DBusCachedPlugin(config : DataCacheConfig, decoderService.add(FENCE, Nil) mmuBus = pipeline.service(classOf[MemoryTranslator]).newTranslationPort(MemoryTranslatorPort.PRIORITY_DATA ,memoryTranslatorPortConfig) - redoBranch = pipeline.service(classOf[JumpService]).createJumpInterface(pipeline.writeBack) + redoBranch = pipeline.service(classOf[JumpService]).createJumpInterface(if(pipeline.writeBack != null) pipeline.writeBack else pipeline.execute) if(catchSomething) exceptionBus = pipeline.service(classOf[ExceptionService]).newExceptionPort(pipeline.writeBack) diff --git a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala index aba2e886..8d23548d 100644 --- a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala @@ -309,7 +309,7 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, if(memoryTranslatorPortConfig != null) { mmuBus = pipeline.service(classOf[MemoryTranslator]).newTranslationPort(MemoryTranslatorPort.PRIORITY_DATA, memoryTranslatorPortConfig) - redoBranch = pipeline.service(classOf[JumpService]).createJumpInterface(pipeline.memory) + redoBranch = pipeline.service(classOf[JumpService]).createJumpInterface(if(pipeline.memory != null) pipeline.memory else pipeline.execute) } } From 7d99a70e9c3b95d6d2a9bfe481c4115e929ff119 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Wed, 1 May 2019 12:02:27 +0200 Subject: [PATCH 185/951] Switch to released SpinalHDL --- build.sbt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/build.sbt b/build.sbt index 29cebe0c..f61c4ab5 100644 --- a/build.sbt +++ b/build.sbt @@ -7,16 +7,16 @@ lazy val root = (project in file(".")). version := "2.0.0" )), libraryDependencies ++= Seq( - "com.github.spinalhdl" % "spinalhdl-core_2.11" % "1.3.3", - "com.github.spinalhdl" % "spinalhdl-lib_2.11" % "1.3.3", +// "com.github.spinalhdl" % "spinalhdl-core_2.11" % "1.3.3", +// "com.github.spinalhdl" % "spinalhdl-lib_2.11" % "1.3.3", "org.scalatest" % "scalatest_2.11" % "2.2.1", "org.yaml" % "snakeyaml" % "1.8" ), name := "VexRiscv" - )//.dependsOn(spinalHdlSim,spinalHdlCore,spinalHdlLib) -//lazy val spinalHdlSim = ProjectRef(file("../SpinalHDL"), "sim") -//lazy val spinalHdlCore = ProjectRef(file("../SpinalHDL"), "core") -//lazy val spinalHdlLib = ProjectRef(file("../SpinalHDL"), "lib") + ).dependsOn(spinalHdlSim,spinalHdlCore,spinalHdlLib) +lazy val spinalHdlSim = ProjectRef(file("../SpinalHDL"), "sim") +lazy val spinalHdlCore = ProjectRef(file("../SpinalHDL"), "core") +lazy val spinalHdlLib = ProjectRef(file("../SpinalHDL"), "lib") fork := true \ No newline at end of file From c7382466107697899daf80e55f7604fa2086e201 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Wed, 1 May 2019 12:03:01 +0200 Subject: [PATCH 186/951] Remove the legacy pipelining from Axi4 cacheless bridges --- .../scala/vexriscv/plugin/DBusSimplePlugin.scala | 15 +++------------ .../scala/vexriscv/plugin/IBusSimplePlugin.scala | 16 +++++----------- 2 files changed, 8 insertions(+), 23 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala index 8d23548d..75b034d8 100644 --- a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala @@ -82,7 +82,7 @@ case class DBusSimpleBus() extends Bundle with IMasterSlave{ slave(rsp) } - def toAxi4Shared(stageCmd : Boolean = true): Axi4Shared = { + def toAxi4Shared(stageCmd : Boolean = false): Axi4Shared = { val axi = Axi4Shared(DBusSimpleBus.getAxi4Config()) val pendingWritesMax = 7 val pendingWrites = CounterUpDown( @@ -92,7 +92,7 @@ case class DBusSimpleBus() extends Bundle with IMasterSlave{ ) val cmdPreFork = if (stageCmd) cmd.stage.stage().s2mPipe() else cmd - val (cmdFork, dataFork) = StreamFork2(cmdPreFork.haltWhen((pendingWrites =/= 0 && !cmdPreFork.wr) || pendingWrites === pendingWritesMax)) + val (cmdFork, dataFork) = StreamFork2(cmdPreFork.haltWhen((pendingWrites =/= 0 && cmdPreFork.valid && !cmdPreFork.wr) || pendingWrites === pendingWritesMax)) axi.sharedCmd.arbitrationFrom(cmdFork) axi.sharedCmd.write := cmdFork.wr axi.sharedCmd.prot := "010" @@ -117,16 +117,7 @@ case class DBusSimpleBus() extends Bundle with IMasterSlave{ axi.r.ready := True axi.b.ready := True - - - //TODO remove - val axi2 = Axi4Shared(DBusSimpleBus.getAxi4Config()) - axi.arw >-> axi2.arw - axi.w >> axi2.w - axi.r << axi2.r - axi.b << axi2.b -// axi2 << axi - axi2 + axi } def toAxi4(stageCmd : Boolean = true) = this.toAxi4Shared(stageCmd).toAxi4() diff --git a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala index 5b1d7ef9..eef8d267 100644 --- a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala @@ -68,7 +68,7 @@ object IBusSimpleBus{ } -case class IBusSimpleBus(interfaceKeepData : Boolean = false) extends Bundle with IMasterSlave { +case class IBusSimpleBus(cmdIsPersistente : Boolean = false) extends Bundle with IMasterSlave { var cmd = Stream(IBusSimpleCmd()) var rsp = Flow(IBusSimpleRsp()) @@ -79,7 +79,7 @@ case class IBusSimpleBus(interfaceKeepData : Boolean = false) extends Bundle wit def toAxi4ReadOnly(): Axi4ReadOnly = { - assert(!interfaceKeepData) + assert(cmdIsPersistente) val axi = Axi4ReadOnly(IBusSimpleBus.getAxi4Config()) axi.ar.valid := cmd.valid @@ -94,17 +94,11 @@ case class IBusSimpleBus(interfaceKeepData : Boolean = false) extends Bundle wit rsp.error := !axi.r.isOKAY() axi.r.ready := True - - //TODO remove - val axi2 = Axi4ReadOnly(IBusSimpleBus.getAxi4Config()) - axi.ar >-> axi2.ar - axi.r << axi2.r -// axi2 << axi - axi2 + axi } def toAvalon(): AvalonMM = { - assert(!interfaceKeepData) + assert(cmdIsPersistente) val avalonConfig = IBusSimpleBus.getAvalonConfig() val mm = AvalonMM(avalonConfig) @@ -199,7 +193,7 @@ class IBusSimplePlugin(resetVector : BigInt, override def setup(pipeline: VexRiscv): Unit = { super.setup(pipeline) - iBus = master(IBusSimpleBus(false)).setName("iBus") + iBus = master(IBusSimpleBus(cmdForkPersistence)).setName("iBus") val decoderService = pipeline.service(classOf[DecoderService]) decoderService.add(FENCE_I, Nil) From 5f187053584da0ff522ecf68082bdce7bd88c780 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Sun, 5 May 2019 21:19:48 +0200 Subject: [PATCH 187/951] Add DBusCachedPlugin.relaxedMemoryTranslationRegister option --- src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala | 6 +++++- src/test/scala/vexriscv/TestIndividualFeatures.scala | 8 +++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index b8f2ba11..8584a8c4 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -23,6 +23,7 @@ class DBusCachedPlugin(config : DataCacheConfig, dBusCmdMasterPipe : Boolean = false, dBusCmdSlavePipe : Boolean = false, dBusRspSlavePipe : Boolean = false, + relaxedMemoryTranslationRegister : Boolean = false, csrInfo : Boolean = false) extends Plugin[VexRiscv] with DBusAccessService { import config._ @@ -49,6 +50,7 @@ class DBusCachedPlugin(config : DataCacheConfig, object MEMORY_LRSC extends Stageable(Bool) object MEMORY_AMO extends Stageable(Bool) object IS_DBUS_SHARING extends Stageable(Bool()) + object MEMORY_VIRTUAL_ADDRESS extends Stageable(UInt(32 bits)) override def setup(pipeline: VexRiscv): Unit = { import Riscv._ @@ -212,6 +214,8 @@ class DBusCachedPlugin(config : DataCacheConfig, when(cache.io.cpu.redo && arbitration.isValid && input(MEMORY_ENABLE)){ arbitration.haltItself := True } + + if(relaxedMemoryTranslationRegister) insert(MEMORY_VIRTUAL_ADDRESS) := cache.io.cpu.execute.address } memory plug new Area{ @@ -219,7 +223,7 @@ class DBusCachedPlugin(config : DataCacheConfig, cache.io.cpu.memory.isValid := arbitration.isValid && input(MEMORY_ENABLE) cache.io.cpu.memory.isStuck := arbitration.isStuck cache.io.cpu.memory.isRemoved := arbitration.removeIt - cache.io.cpu.memory.address := U(input(REGFILE_WRITE_DATA)) + cache.io.cpu.memory.address := (if(relaxedMemoryTranslationRegister) input(MEMORY_VIRTUAL_ADDRESS) else U(input(REGFILE_WRITE_DATA))) cache.io.cpu.memory.mmuBus <> mmuBus cache.io.cpu.memory.mmuBus.rsp.isIoAccess setWhen(pipeline(DEBUG_BYPASS_CACHE) && !cache.io.cpu.memory.isWrite) diff --git a/src/test/scala/vexriscv/TestIndividualFeatures.scala b/src/test/scala/vexriscv/TestIndividualFeatures.scala index cedf989c..03cf8ee2 100644 --- a/src/test/scala/vexriscv/TestIndividualFeatures.scala +++ b/src/test/scala/vexriscv/TestIndividualFeatures.scala @@ -396,11 +396,13 @@ class DBusDimension extends VexRiscvDimension("DBus") { var wayCount = 0 val withLrSc = catchAll val withAmo = catchAll && r.nextBoolean() + val dBusCmdMasterPipe, dBusCmdSlavePipe, dBusRspSlavePipe, relaxedMemoryTranslationRegister = r.nextBoolean() + do{ cacheSize = 512 << r.nextInt(5) wayCount = 1 << r.nextInt(3) }while(cacheSize/wayCount < 512 || (catchAll && cacheSize/wayCount > 4096)) - new VexRiscvPosition("Cached" + "S" + cacheSize + "W" + wayCount + "BPL" + bytePerLine) { + new VexRiscvPosition("Cached" + "S" + cacheSize + "W" + wayCount + "BPL" + bytePerLine + (if(dBusCmdMasterPipe) "Cmp " else "") + (if(dBusCmdSlavePipe) "Csp " else "") + (if(dBusRspSlavePipe) "Rsp " else "") + (if(relaxedMemoryTranslationRegister) "Rmtr " else "")) { override def testParam = "DBUS=CACHED " + (if(withLrSc) "LRSC=yes " else "") + (if(withAmo) "AMO=yes " else "") override def applyOn(config: VexRiscvConfig): Unit = { @@ -418,6 +420,10 @@ class DBusDimension extends VexRiscvDimension("DBus") { withLrSc = withLrSc, withAmo = withAmo ), + dBusCmdMasterPipe = dBusCmdMasterPipe, + dBusCmdSlavePipe = dBusCmdSlavePipe, + dBusRspSlavePipe = dBusRspSlavePipe, + relaxedMemoryTranslationRegister = relaxedMemoryTranslationRegister, memoryTranslatorPortConfig = mmuConfig ) } From 8f1b980337ef881ac03f6748c63ac1cb7bbdfc1f Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Sun, 5 May 2019 22:29:33 +0200 Subject: [PATCH 188/951] Revert "Add DBusCachedPlugin.relaxedMemoryTranslationRegister option" This reverts commit 5f187053584da0ff522ecf68082bdce7bd88c780. --- src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala | 6 +----- src/test/scala/vexriscv/TestIndividualFeatures.scala | 8 +------- 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index 8584a8c4..b8f2ba11 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -23,7 +23,6 @@ class DBusCachedPlugin(config : DataCacheConfig, dBusCmdMasterPipe : Boolean = false, dBusCmdSlavePipe : Boolean = false, dBusRspSlavePipe : Boolean = false, - relaxedMemoryTranslationRegister : Boolean = false, csrInfo : Boolean = false) extends Plugin[VexRiscv] with DBusAccessService { import config._ @@ -50,7 +49,6 @@ class DBusCachedPlugin(config : DataCacheConfig, object MEMORY_LRSC extends Stageable(Bool) object MEMORY_AMO extends Stageable(Bool) object IS_DBUS_SHARING extends Stageable(Bool()) - object MEMORY_VIRTUAL_ADDRESS extends Stageable(UInt(32 bits)) override def setup(pipeline: VexRiscv): Unit = { import Riscv._ @@ -214,8 +212,6 @@ class DBusCachedPlugin(config : DataCacheConfig, when(cache.io.cpu.redo && arbitration.isValid && input(MEMORY_ENABLE)){ arbitration.haltItself := True } - - if(relaxedMemoryTranslationRegister) insert(MEMORY_VIRTUAL_ADDRESS) := cache.io.cpu.execute.address } memory plug new Area{ @@ -223,7 +219,7 @@ class DBusCachedPlugin(config : DataCacheConfig, cache.io.cpu.memory.isValid := arbitration.isValid && input(MEMORY_ENABLE) cache.io.cpu.memory.isStuck := arbitration.isStuck cache.io.cpu.memory.isRemoved := arbitration.removeIt - cache.io.cpu.memory.address := (if(relaxedMemoryTranslationRegister) input(MEMORY_VIRTUAL_ADDRESS) else U(input(REGFILE_WRITE_DATA))) + cache.io.cpu.memory.address := U(input(REGFILE_WRITE_DATA)) cache.io.cpu.memory.mmuBus <> mmuBus cache.io.cpu.memory.mmuBus.rsp.isIoAccess setWhen(pipeline(DEBUG_BYPASS_CACHE) && !cache.io.cpu.memory.isWrite) diff --git a/src/test/scala/vexriscv/TestIndividualFeatures.scala b/src/test/scala/vexriscv/TestIndividualFeatures.scala index 03cf8ee2..cedf989c 100644 --- a/src/test/scala/vexriscv/TestIndividualFeatures.scala +++ b/src/test/scala/vexriscv/TestIndividualFeatures.scala @@ -396,13 +396,11 @@ class DBusDimension extends VexRiscvDimension("DBus") { var wayCount = 0 val withLrSc = catchAll val withAmo = catchAll && r.nextBoolean() - val dBusCmdMasterPipe, dBusCmdSlavePipe, dBusRspSlavePipe, relaxedMemoryTranslationRegister = r.nextBoolean() - do{ cacheSize = 512 << r.nextInt(5) wayCount = 1 << r.nextInt(3) }while(cacheSize/wayCount < 512 || (catchAll && cacheSize/wayCount > 4096)) - new VexRiscvPosition("Cached" + "S" + cacheSize + "W" + wayCount + "BPL" + bytePerLine + (if(dBusCmdMasterPipe) "Cmp " else "") + (if(dBusCmdSlavePipe) "Csp " else "") + (if(dBusRspSlavePipe) "Rsp " else "") + (if(relaxedMemoryTranslationRegister) "Rmtr " else "")) { + new VexRiscvPosition("Cached" + "S" + cacheSize + "W" + wayCount + "BPL" + bytePerLine) { override def testParam = "DBUS=CACHED " + (if(withLrSc) "LRSC=yes " else "") + (if(withAmo) "AMO=yes " else "") override def applyOn(config: VexRiscvConfig): Unit = { @@ -420,10 +418,6 @@ class DBusDimension extends VexRiscvDimension("DBus") { withLrSc = withLrSc, withAmo = withAmo ), - dBusCmdMasterPipe = dBusCmdMasterPipe, - dBusCmdSlavePipe = dBusCmdSlavePipe, - dBusRspSlavePipe = dBusRspSlavePipe, - relaxedMemoryTranslationRegister = relaxedMemoryTranslationRegister, memoryTranslatorPortConfig = mmuConfig ) } From d12decde800c24cbd216a0b4611f540a524eaa4b Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Sun, 5 May 2019 22:46:46 +0200 Subject: [PATCH 189/951] Remove test which had issues with the testbench ref checks because of getting passed delayed --- src/test/scala/vexriscv/TestIndividualFeatures.scala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/test/scala/vexriscv/TestIndividualFeatures.scala b/src/test/scala/vexriscv/TestIndividualFeatures.scala index 03cf8ee2..d24f2398 100644 --- a/src/test/scala/vexriscv/TestIndividualFeatures.scala +++ b/src/test/scala/vexriscv/TestIndividualFeatures.scala @@ -396,7 +396,8 @@ class DBusDimension extends VexRiscvDimension("DBus") { var wayCount = 0 val withLrSc = catchAll val withAmo = catchAll && r.nextBoolean() - val dBusCmdMasterPipe, dBusCmdSlavePipe, dBusRspSlavePipe, relaxedMemoryTranslationRegister = r.nextBoolean() + val dBusRspSlavePipe, relaxedMemoryTranslationRegister = r.nextBoolean() + val dBusCmdMasterPipe, dBusCmdSlavePipe = false //As it create test bench issues do{ cacheSize = 512 << r.nextInt(5) From d27fa4766d99cef3043c57afc3b3a17d642c6a98 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Mon, 6 May 2019 00:05:40 +0200 Subject: [PATCH 190/951] DBusCachedPlugin add earlyWaysHits in regressions --- src/test/scala/vexriscv/TestIndividualFeatures.scala | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/test/scala/vexriscv/TestIndividualFeatures.scala b/src/test/scala/vexriscv/TestIndividualFeatures.scala index d24f2398..52097e9e 100644 --- a/src/test/scala/vexriscv/TestIndividualFeatures.scala +++ b/src/test/scala/vexriscv/TestIndividualFeatures.scala @@ -396,14 +396,14 @@ class DBusDimension extends VexRiscvDimension("DBus") { var wayCount = 0 val withLrSc = catchAll val withAmo = catchAll && r.nextBoolean() - val dBusRspSlavePipe, relaxedMemoryTranslationRegister = r.nextBoolean() + val dBusRspSlavePipe, relaxedMemoryTranslationRegister, earlyWaysHits = r.nextBoolean() val dBusCmdMasterPipe, dBusCmdSlavePipe = false //As it create test bench issues do{ cacheSize = 512 << r.nextInt(5) wayCount = 1 << r.nextInt(3) }while(cacheSize/wayCount < 512 || (catchAll && cacheSize/wayCount > 4096)) - new VexRiscvPosition("Cached" + "S" + cacheSize + "W" + wayCount + "BPL" + bytePerLine + (if(dBusCmdMasterPipe) "Cmp " else "") + (if(dBusCmdSlavePipe) "Csp " else "") + (if(dBusRspSlavePipe) "Rsp " else "") + (if(relaxedMemoryTranslationRegister) "Rmtr " else "")) { + new VexRiscvPosition("Cached" + "S" + cacheSize + "W" + wayCount + "BPL" + bytePerLine + (if(dBusCmdMasterPipe) "Cmp " else "") + (if(dBusCmdSlavePipe) "Csp " else "") + (if(dBusRspSlavePipe) "Rsp " else "") + (if(relaxedMemoryTranslationRegister) "Rmtr " else "") + (if(earlyWaysHits) "Ewh " else "")) { override def testParam = "DBUS=CACHED " + (if(withLrSc) "LRSC=yes " else "") + (if(withAmo) "AMO=yes " else "") override def applyOn(config: VexRiscvConfig): Unit = { @@ -419,7 +419,8 @@ class DBusDimension extends VexRiscvDimension("DBus") { catchIllegal = catchAll, catchUnaligned = catchAll, withLrSc = withLrSc, - withAmo = withAmo + withAmo = withAmo, + earlyWaysHits = earlyWaysHits ), dBusCmdMasterPipe = dBusCmdMasterPipe, dBusCmdSlavePipe = dBusCmdSlavePipe, From 01db217ab927dd1f415f28d6ac726edb73ae2ee0 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Mon, 6 May 2019 16:23:43 +0200 Subject: [PATCH 191/951] Add supervisor support in the ExternalInterruptArrayPlugin --- .../scala/vexriscv/plugin/CsrPlugin.scala | 2 +- .../plugin/ExternalInterruptArrayPlugin.scala | 21 +++++++++++++------ 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 3c7b036f..467dc76a 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -310,7 +310,7 @@ trait IContextSwitching{ def isContextSwitching : Bool } -class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with ExceptionService with PrivilegeService with InterruptionInhibitor with ExceptionInhibitor with IContextSwitching with CsrInterface{ +class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with ExceptionService with PrivilegeService with InterruptionInhibitor with ExceptionInhibitor with IContextSwitching with CsrInterface{ import config._ import CsrAccess._ diff --git a/src/main/scala/vexriscv/plugin/ExternalInterruptArrayPlugin.scala b/src/main/scala/vexriscv/plugin/ExternalInterruptArrayPlugin.scala index fd1a5615..43d32f00 100644 --- a/src/main/scala/vexriscv/plugin/ExternalInterruptArrayPlugin.scala +++ b/src/main/scala/vexriscv/plugin/ExternalInterruptArrayPlugin.scala @@ -3,7 +3,11 @@ package vexriscv.plugin import spinal.core._ import vexriscv.VexRiscv -class ExternalInterruptArrayPlugin(arrayWidth : Int = 32, maskCsrId : Int = 0xBC0, pendingsCsrId : Int = 0xFC0) extends Plugin[VexRiscv]{ +class ExternalInterruptArrayPlugin(arrayWidth : Int = 32, + machineMaskCsrId : Int = 0xBC0, + machinePendingsCsrId : Int = 0xFC0, + supervisorMaskCsrId : Int = 0x9C0, + supervisorPendingsCsrId : Int = 0xDC0) extends Plugin[VexRiscv]{ var externalInterruptArray : Bits = null override def setup(pipeline: VexRiscv): Unit = { @@ -12,10 +16,15 @@ class ExternalInterruptArrayPlugin(arrayWidth : Int = 32, maskCsrId : Int = 0xBC override def build(pipeline: VexRiscv): Unit = { val csr = pipeline.service(classOf[CsrPlugin]) - val mask = Reg(Bits(arrayWidth bits)) init(0) - val pendings = mask & RegNext(externalInterruptArray) - csr.externalInterrupt.setAsDirectionLess() := pendings.orR - csr.rw(maskCsrId, mask) - csr.r(pendingsCsrId, pendings) + val externalInterruptArrayBuffer = RegNext(externalInterruptArray) + def gen(maskCsrId : Int, pendingsCsrId : Int, interruptPin : Bool) = new Area { + val mask = Reg(Bits(arrayWidth bits)) init(0) + val pendings = mask & externalInterruptArrayBuffer + interruptPin.setAsDirectionLess() := pendings.orR + csr.rw(maskCsrId, mask) + csr.r(pendingsCsrId, pendings) + } + gen(machineMaskCsrId, machinePendingsCsrId, csr.externalInterrupt) + if(csr.config.supervisorGen) gen(supervisorMaskCsrId, supervisorPendingsCsrId, csr.externalInterruptS) } } From 8201cff7ff64395a9429ceb433dad1bb2b982440 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Fri, 10 May 2019 14:27:14 +0200 Subject: [PATCH 192/951] SpinalHDL 1.3.4 --- build.sbt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/build.sbt b/build.sbt index f61c4ab5..1db07922 100644 --- a/build.sbt +++ b/build.sbt @@ -7,16 +7,16 @@ lazy val root = (project in file(".")). version := "2.0.0" )), libraryDependencies ++= Seq( -// "com.github.spinalhdl" % "spinalhdl-core_2.11" % "1.3.3", -// "com.github.spinalhdl" % "spinalhdl-lib_2.11" % "1.3.3", + "com.github.spinalhdl" % "spinalhdl-core_2.11" % "1.3.4", + "com.github.spinalhdl" % "spinalhdl-lib_2.11" % "1.3.4", "org.scalatest" % "scalatest_2.11" % "2.2.1", "org.yaml" % "snakeyaml" % "1.8" ), name := "VexRiscv" - ).dependsOn(spinalHdlSim,spinalHdlCore,spinalHdlLib) -lazy val spinalHdlSim = ProjectRef(file("../SpinalHDL"), "sim") -lazy val spinalHdlCore = ProjectRef(file("../SpinalHDL"), "core") -lazy val spinalHdlLib = ProjectRef(file("../SpinalHDL"), "lib") + )//.dependsOn(spinalHdlSim,spinalHdlCore,spinalHdlLib) +//lazy val spinalHdlSim = ProjectRef(file("../SpinalHDL"), "sim") +//lazy val spinalHdlCore = ProjectRef(file("../SpinalHDL"), "core") +//lazy val spinalHdlLib = ProjectRef(file("../SpinalHDL"), "lib") fork := true \ No newline at end of file From 3753f64429495c9f433aa99345a9a227e29b87fa Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Mon, 13 May 2019 23:44:20 +0200 Subject: [PATCH 193/951] Fix Bmb compilation --- .../scala/vexriscv/demo/MuraxUtiles.scala | 2 +- .../vexriscv/plugin/DBusSimplePlugin.scala | 39 +++++++++- .../vexriscv/plugin/IBusSimplePlugin.scala | 71 +++++++++++++------ 3 files changed, 89 insertions(+), 23 deletions(-) diff --git a/src/main/scala/vexriscv/demo/MuraxUtiles.scala b/src/main/scala/vexriscv/demo/MuraxUtiles.scala index 4e650d38..1c45bc37 100644 --- a/src/main/scala/vexriscv/demo/MuraxUtiles.scala +++ b/src/main/scala/vexriscv/demo/MuraxUtiles.scala @@ -12,7 +12,7 @@ import vexriscv.plugin.{DBusSimpleBus, IBusSimpleBus} class MuraxMasterArbiter(pipelinedMemoryBusConfig : PipelinedMemoryBusConfig) extends Component{ val io = new Bundle{ - val iBus = slave(IBusSimpleBus(false)) + val iBus = slave(IBusSimpleBus(null)) val dBus = slave(DBusSimpleBus()) val masterBus = master(PipelinedMemoryBus(pipelinedMemoryBusConfig)) } diff --git a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala index 661b5247..b2f141db 100644 --- a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala @@ -6,6 +6,7 @@ import spinal.lib._ import spinal.lib.bus.amba3.ahblite.{AhbLite3Config, AhbLite3Master} import spinal.lib.bus.amba4.axi._ import spinal.lib.bus.avalon.{AvalonMM, AvalonMMConfig} +import spinal.lib.bus.bmb.{Bmb, BmbParameter} import spinal.lib.bus.wishbone.{Wishbone, WishboneConfig} import spinal.lib.bus.simple._ import vexriscv.ip.DataCacheMemCmd @@ -76,6 +77,18 @@ object DBusSimpleBus{ addressWidth = 32, dataWidth = 32 ) + def getBmbParameter() = BmbParameter( + addressWidth = 32, + dataWidth = 32, + lengthWidth = 2, + sourceWidth = 0, + contextWidth = 1, + canRead = true, + canWrite = true, + allowUnalignedWordBurst = false, + allowUnalignedByteBurst = false, + maximumPendingTransactionPerId = Int.MaxValue + ) } case class DBusSimpleBus() extends Bundle with IMasterSlave{ @@ -208,8 +221,6 @@ case class DBusSimpleBus() extends Bundle with IMasterSlave{ bus } - - def toAhbLite3Master(avoidWriteToReadHazard : Boolean): AhbLite3Master = { val bus = AhbLite3Master(DBusSimpleBus.getAhbLite3Config()) bus.HADDR := this.cmd.address @@ -235,6 +246,30 @@ case class DBusSimpleBus() extends Bundle with IMasterSlave{ this.cmd.ready := False } } + bus + } + + def toBmb() : Bmb = { + val pipelinedMemoryBusConfig = DBusSimpleBus.getBmbParameter() + val bus = Bmb(pipelinedMemoryBusConfig) + + bus.cmd.valid := cmd.valid + bus.cmd.last := True + bus.cmd.context(0) := cmd.wr + bus.cmd.opcode := (cmd.wr ? B(Bmb.Cmd.Opcode.WRITE) | B(Bmb.Cmd.Opcode.READ)) + bus.cmd.address := cmd.address.resized + bus.cmd.data := cmd.data + bus.cmd.mask := cmd.size.mux( + 0 -> B"0001", + 1 -> B"0011", + default -> B"1111" + ) |<< cmd.address(1 downto 0) + cmd.ready := bus.cmd.ready + + rsp.ready := bus.rsp.valid && !bus.rsp.context(0) + rsp.data := bus.rsp.data + rsp.error := bus.rsp.isError + bus.rsp.ready := True bus } diff --git a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala index 67dc7864..0492b737 100644 --- a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala @@ -6,6 +6,7 @@ import spinal.lib._ import spinal.lib.bus.amba3.ahblite.{AhbLite3, AhbLite3Config, AhbLite3Master} import spinal.lib.bus.amba4.axi._ import spinal.lib.bus.avalon.{AvalonMM, AvalonMMConfig} +import spinal.lib.bus.bmb.{Bmb, BmbParameter} import spinal.lib.bus.wishbone.{Wishbone, WishboneConfig} import spinal.lib.bus.simple._ import vexriscv.Riscv.{FENCE, FENCE_I} @@ -67,14 +68,28 @@ object IBusSimpleBus{ dataWidth = 32 ) + def getAhbLite3Config() = AhbLite3Config( addressWidth = 32, dataWidth = 32 ) + + def getBmbParameter(plugin : IBusSimplePlugin = null) = BmbParameter( + addressWidth = 32, + dataWidth = 32, + lengthWidth = 2, + sourceWidth = 0, + contextWidth = 0, + canRead = true, + canWrite = false, + allowUnalignedWordBurst = false, + allowUnalignedByteBurst = false, + maximumPendingTransactionPerId = if(plugin != null) plugin.pendingMax else Int.MaxValue + ) } -case class IBusSimpleBus(cmdIsPersistente : Boolean = false) extends Bundle with IMasterSlave { +case class IBusSimpleBus(plugin: IBusSimplePlugin) extends Bundle with IMasterSlave { var cmd = Stream(IBusSimpleCmd()) var rsp = Flow(IBusSimpleRsp()) @@ -85,7 +100,7 @@ case class IBusSimpleBus(cmdIsPersistente : Boolean = false) extends Bundle with def cmdS2mPipe() : IBusSimpleBus = { - val s = IBusSimpleBus() + val s = IBusSimpleBus(plugin) s.cmd << this.cmd.s2mPipe() this.rsp << s.rsp s @@ -93,7 +108,7 @@ case class IBusSimpleBus(cmdIsPersistente : Boolean = false) extends Bundle with def toAxi4ReadOnly(): Axi4ReadOnly = { - assert(cmdIsPersistente) + assert(plugin.cmdForkPersistence) val axi = Axi4ReadOnly(IBusSimpleBus.getAxi4Config()) axi.ar.valid := cmd.valid @@ -112,7 +127,7 @@ case class IBusSimpleBus(cmdIsPersistente : Boolean = false) extends Bundle with } def toAvalon(): AvalonMM = { - assert(cmdIsPersistente) + assert(plugin.cmdForkPersistence) val avalonConfig = IBusSimpleBus.getAvalonConfig() val mm = AvalonMM(avalonConfig) @@ -163,6 +178,7 @@ case class IBusSimpleBus(cmdIsPersistente : Boolean = false) extends Bundle with bus } + //cmdForkPersistence need to bet set def toAhbLite3Master(): AhbLite3Master = { val bus = AhbLite3Master(IBusSimpleBus.getAhbLite3Config()) @@ -182,6 +198,21 @@ case class IBusSimpleBus(cmdIsPersistente : Boolean = false) extends Bundle with this.rsp.error := bus.HRESP bus } + + def toBmb() : Bmb = { + val pipelinedMemoryBusConfig = IBusSimpleBus.getBmbParameter(plugin) + val bus = Bmb(pipelinedMemoryBusConfig) + bus.cmd.arbitrationFrom(cmd) + bus.cmd.opcode := Bmb.Cmd.Opcode.READ + bus.cmd.address := cmd.pc.resized + bus.cmd.length := 3 + bus.cmd.last := True + rsp.valid := bus.rsp.valid + rsp.inst := bus.rsp.data + rsp.error := bus.rsp.isError + bus.rsp.ready := True + bus + } } @@ -189,21 +220,21 @@ case class IBusSimpleBus(cmdIsPersistente : Boolean = false) extends Bundle with -class IBusSimplePlugin(resetVector : BigInt, - cmdForkOnSecondStage : Boolean, - cmdForkPersistence : Boolean, - catchAccessFault : Boolean = false, - prediction : BranchPrediction = NONE, - historyRamSizeLog2 : Int = 10, - keepPcPlus4 : Boolean = false, - compressedGen : Boolean = false, - busLatencyMin : Int = 1, - pendingMax : Int = 7, - injectorStage : Boolean = true, - rspHoldValue : Boolean = false, - singleInstructionPipeline : Boolean = false, - memoryTranslatorPortConfig : Any = null, - relaxPredictorAddress : Boolean = true +class IBusSimplePlugin( resetVector : BigInt, + val cmdForkOnSecondStage : Boolean, + val cmdForkPersistence : Boolean, + val catchAccessFault : Boolean = false, + prediction : BranchPrediction = NONE, + historyRamSizeLog2 : Int = 10, + keepPcPlus4 : Boolean = false, + compressedGen : Boolean = false, + val busLatencyMin : Int = 1, + val pendingMax : Int = 7, + injectorStage : Boolean = true, + val rspHoldValue : Boolean = false, + val singleInstructionPipeline : Boolean = false, + val memoryTranslatorPortConfig : Any = null, + relaxPredictorAddress : Boolean = true ) extends IBusFetcherImpl( resetVector = resetVector, keepPcPlus4 = keepPcPlus4, @@ -227,7 +258,7 @@ class IBusSimplePlugin(resetVector : BigInt, override def setup(pipeline: VexRiscv): Unit = { super.setup(pipeline) - iBus = master(IBusSimpleBus(cmdForkPersistence)).setName("iBus") + iBus = master(IBusSimpleBus(this)).setName("iBus") val decoderService = pipeline.service(classOf[DecoderService]) decoderService.add(FENCE_I, Nil) From 4ce9d805b47ed95b1fc7322392d544bd059210f2 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Tue, 14 May 2019 00:41:14 +0200 Subject: [PATCH 194/951] Switch to unreleased SpinalHDL --- build.sbt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/build.sbt b/build.sbt index 1db07922..aa017862 100644 --- a/build.sbt +++ b/build.sbt @@ -7,16 +7,16 @@ lazy val root = (project in file(".")). version := "2.0.0" )), libraryDependencies ++= Seq( - "com.github.spinalhdl" % "spinalhdl-core_2.11" % "1.3.4", - "com.github.spinalhdl" % "spinalhdl-lib_2.11" % "1.3.4", +// "com.github.spinalhdl" % "spinalhdl-core_2.11" % "1.3.4", +// "com.github.spinalhdl" % "spinalhdl-lib_2.11" % "1.3.4", "org.scalatest" % "scalatest_2.11" % "2.2.1", "org.yaml" % "snakeyaml" % "1.8" ), name := "VexRiscv" - )//.dependsOn(spinalHdlSim,spinalHdlCore,spinalHdlLib) -//lazy val spinalHdlSim = ProjectRef(file("../SpinalHDL"), "sim") -//lazy val spinalHdlCore = ProjectRef(file("../SpinalHDL"), "core") -//lazy val spinalHdlLib = ProjectRef(file("../SpinalHDL"), "lib") + ).dependsOn(spinalHdlSim,spinalHdlCore,spinalHdlLib) +lazy val spinalHdlSim = ProjectRef(file("../SpinalHDL"), "sim") +lazy val spinalHdlCore = ProjectRef(file("../SpinalHDL"), "core") +lazy val spinalHdlLib = ProjectRef(file("../SpinalHDL"), "lib") fork := true \ No newline at end of file From 0301ced00095b072332d8d4af081dd18ae3fdcba Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Thu, 16 May 2019 19:49:13 +0200 Subject: [PATCH 195/951] Fix dBusSimplePlugin to bmb bridge --- src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala index b2f141db..9e84ea27 100644 --- a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala @@ -259,11 +259,17 @@ case class DBusSimpleBus() extends Bundle with IMasterSlave{ bus.cmd.opcode := (cmd.wr ? B(Bmb.Cmd.Opcode.WRITE) | B(Bmb.Cmd.Opcode.READ)) bus.cmd.address := cmd.address.resized bus.cmd.data := cmd.data + bus.cmd.length := cmd.size.mux( + 0 -> U"00", + 1 -> U"01", + default -> U"11" + ) bus.cmd.mask := cmd.size.mux( - 0 -> B"0001", - 1 -> B"0011", + 0 -> B"0001", + 1 -> B"0011", default -> B"1111" ) |<< cmd.address(1 downto 0) + cmd.ready := bus.cmd.ready rsp.ready := bus.rsp.valid && !bus.rsp.context(0) From b40dc06b2942d17a08a9268f3d135cb0c6d6e4f2 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Sat, 18 May 2019 19:56:03 +0200 Subject: [PATCH 196/951] SpinalHDL 1.3.5 --- build.sbt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.sbt b/build.sbt index 1db07922..82b7e083 100644 --- a/build.sbt +++ b/build.sbt @@ -7,8 +7,8 @@ lazy val root = (project in file(".")). version := "2.0.0" )), libraryDependencies ++= Seq( - "com.github.spinalhdl" % "spinalhdl-core_2.11" % "1.3.4", - "com.github.spinalhdl" % "spinalhdl-lib_2.11" % "1.3.4", + "com.github.spinalhdl" % "spinalhdl-core_2.11" % "1.3.5", + "com.github.spinalhdl" % "spinalhdl-lib_2.11" % "1.3.5", "org.scalatest" % "scalatest_2.11" % "2.2.1", "org.yaml" % "snakeyaml" % "1.8" ), From 49b4b61a1a1c5616ec685136b8522ef3f5dc244a Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Mon, 20 May 2019 14:14:42 +0200 Subject: [PATCH 197/951] Update Bmb bridges --- src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala | 3 +-- src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala | 3 +-- src/test/cpp/regression/makefile | 2 ++ 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala index 9e84ea27..0ded35ee 100644 --- a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala @@ -85,8 +85,7 @@ object DBusSimpleBus{ contextWidth = 1, canRead = true, canWrite = true, - allowUnalignedWordBurst = false, - allowUnalignedByteBurst = false, + alignment = BmbParameter.BurstAlignement.LENGTH, maximumPendingTransactionPerId = Int.MaxValue ) } diff --git a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala index 0492b737..00338823 100644 --- a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala @@ -82,8 +82,7 @@ object IBusSimpleBus{ contextWidth = 0, canRead = true, canWrite = false, - allowUnalignedWordBurst = false, - allowUnalignedByteBurst = false, + alignment = BmbParameter.BurstAlignement.LENGTH, maximumPendingTransactionPerId = if(plugin != null) plugin.pendingMax else Int.MaxValue ) } diff --git a/src/test/cpp/regression/makefile b/src/test/cpp/regression/makefile index a657f1c2..f8db6db5 100644 --- a/src/test/cpp/regression/makefile +++ b/src/test/cpp/regression/makefile @@ -110,8 +110,10 @@ ifneq ($(shell grep timerInterrupt ../../../../VexRiscv.v -w),) endif ifneq ($(shell grep externalInterrupt ../../../../VexRiscv.v -w),) +ifneq ($(EXTERNAL_INTERRUPT),no) ADDCFLAGS += -CFLAGS -DEXTERNAL_INTERRUPT endif +endif ifneq ($(RUN_HEX),no) ADDCFLAGS += -CFLAGS -DRUN_HEX='\"$(RUN_HEX)\"' From 8abc06c8f27732553f838286a25de0d7040ad672 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Wed, 22 May 2019 17:04:36 +0200 Subject: [PATCH 198/951] Add Bmb support for i$/d$ --- src/main/scala/vexriscv/ip/DataCache.scala | 38 +++++++++++++++++++ .../scala/vexriscv/ip/InstructionCache.scala | 29 ++++++++++++++ .../vexriscv/plugin/DBusCachedPlugin.scala | 2 +- .../vexriscv/plugin/IBusCachedPlugin.scala | 2 +- 4 files changed, 69 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index 04c84bef..d34fcebf 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -5,8 +5,10 @@ import spinal.core._ import spinal.lib._ import spinal.lib.bus.amba4.axi.{Axi4Config, Axi4Shared} import spinal.lib.bus.avalon.{AvalonMM, AvalonMMConfig} +import spinal.lib.bus.bmb.{Bmb, BmbParameter} import spinal.lib.bus.wishbone.{Wishbone, WishboneConfig} import spinal.lib.bus.simple._ +import vexriscv.plugin.DBusSimpleBus case class DataCacheConfig(cacheSize : Int, @@ -64,6 +66,18 @@ case class DataCacheConfig(cacheSize : Int, useBTE = true, useCTI = true ) + + def getBmbParameter() = BmbParameter( + addressWidth = 32, + dataWidth = 32, + lengthWidth = log2Up(this.bytePerLine), + sourceWidth = 0, + contextWidth = 1, + canRead = true, + canWrite = true, + alignment = BmbParameter.BurstAlignement.LENGTH, + maximumPendingTransactionPerId = Int.MaxValue + ) } object DataCacheCpuExecute{ @@ -298,6 +312,30 @@ case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave bus } + + def toBmb() : Bmb = { + val pipelinedMemoryBusConfig = p.getBmbParameter() + val bus = Bmb(pipelinedMemoryBusConfig) + + bus.cmd.valid := cmd.valid + bus.cmd.last := cmd.last + bus.cmd.context(0) := cmd.wr + bus.cmd.opcode := (cmd.wr ? B(Bmb.Cmd.Opcode.WRITE) | B(Bmb.Cmd.Opcode.READ)) + bus.cmd.address := cmd.address.resized + bus.cmd.data := cmd.data + bus.cmd.length := cmd.length << 2 //TODO better sub word access + bus.cmd.mask := cmd.mask + + cmd.ready := bus.cmd.ready + + rsp.valid := bus.rsp.valid && !bus.rsp.context(0) + rsp.data := bus.rsp.data + rsp.error := bus.rsp.isError + bus.rsp.ready := True + + bus + } + } diff --git a/src/main/scala/vexriscv/ip/InstructionCache.scala b/src/main/scala/vexriscv/ip/InstructionCache.scala index e3722d66..1a26dd3d 100644 --- a/src/main/scala/vexriscv/ip/InstructionCache.scala +++ b/src/main/scala/vexriscv/ip/InstructionCache.scala @@ -5,8 +5,10 @@ import spinal.core._ import spinal.lib._ import spinal.lib.bus.amba4.axi.{Axi4Config, Axi4ReadOnly} import spinal.lib.bus.avalon.{AvalonMM, AvalonMMConfig} +import spinal.lib.bus.bmb.{Bmb, BmbParameter} import spinal.lib.bus.wishbone.{Wishbone, WishboneConfig} import spinal.lib.bus.simple._ +import vexriscv.plugin.{IBusSimpleBus, IBusSimplePlugin} case class InstructionCacheConfig( cacheSize : Int, @@ -64,6 +66,18 @@ case class InstructionCacheConfig( cacheSize : Int, useBTE = true, useCTI = true ) + + def getBmbParameter() = BmbParameter( + addressWidth = 32, + dataWidth = 32, + lengthWidth = log2Up(this.bytePerLine), + sourceWidth = 0, + contextWidth = 0, + canRead = true, + canWrite = false, + alignment = BmbParameter.BurstAlignement.LENGTH, + maximumPendingTransactionPerId = 1 + ) } @@ -233,6 +247,21 @@ case class InstructionCacheMemBus(p : InstructionCacheConfig) extends Bundle wit rsp.error := False //TODO bus } + + def toBmb() : Bmb = { + val busParameter = p.getBmbParameter + val bus = Bmb(busParameter) + bus.cmd.arbitrationFrom(cmd) + bus.cmd.opcode := Bmb.Cmd.Opcode.READ + bus.cmd.address := cmd.address.resized + bus.cmd.length := (1 << p.bytePerLine) - 1 + bus.cmd.last := True + rsp.valid := bus.rsp.valid + rsp.data := bus.rsp.data + rsp.error := bus.rsp.isError + bus.rsp.ready := True + bus + } } diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index b8f2ba11..baf9adad 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -18,7 +18,7 @@ class DAxiCachedPlugin(config : DataCacheConfig, memoryTranslatorPortConfig : An } } -class DBusCachedPlugin(config : DataCacheConfig, +class DBusCachedPlugin(val config : DataCacheConfig, memoryTranslatorPortConfig : Any = null, dBusCmdMasterPipe : Boolean = false, dBusCmdSlavePipe : Boolean = false, diff --git a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala index 92722e96..362ac8d4 100644 --- a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala @@ -31,7 +31,7 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l, historyRamSizeLog2 : Int = 10, compressedGen : Boolean = false, keepPcPlus4 : Boolean = false, - config : InstructionCacheConfig, + val config : InstructionCacheConfig, memoryTranslatorPortConfig : Any = null, injectorStage : Boolean = false, withoutInjectorStage : Boolean = false, From 9b49638654a5d1b17f2c47f8dfbefcb142e1acb4 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Wed, 22 May 2019 17:27:47 +0200 Subject: [PATCH 199/951] Allow CsrPlugin config access --- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 3c7b036f..467dc76a 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -310,7 +310,7 @@ trait IContextSwitching{ def isContextSwitching : Bool } -class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with ExceptionService with PrivilegeService with InterruptionInhibitor with ExceptionInhibitor with IContextSwitching with CsrInterface{ +class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with ExceptionService with PrivilegeService with InterruptionInhibitor with ExceptionInhibitor with IContextSwitching with CsrInterface{ import config._ import CsrAccess._ From f6f94ad7c18ea9f90ceed11babcaaf1228d2f4cc Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Wed, 22 May 2019 19:03:26 +0200 Subject: [PATCH 200/951] Fix InstructionCache Bmb bridge --- src/main/scala/vexriscv/ip/InstructionCache.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/ip/InstructionCache.scala b/src/main/scala/vexriscv/ip/InstructionCache.scala index 1a26dd3d..55b9f1a7 100644 --- a/src/main/scala/vexriscv/ip/InstructionCache.scala +++ b/src/main/scala/vexriscv/ip/InstructionCache.scala @@ -254,7 +254,7 @@ case class InstructionCacheMemBus(p : InstructionCacheConfig) extends Bundle wit bus.cmd.arbitrationFrom(cmd) bus.cmd.opcode := Bmb.Cmd.Opcode.READ bus.cmd.address := cmd.address.resized - bus.cmd.length := (1 << p.bytePerLine) - 1 + bus.cmd.length := p.bytePerLine - 1 bus.cmd.last := True rsp.valid := bus.rsp.valid rsp.data := bus.rsp.data From 206c7ca638f94752a42a74138472c177151c9516 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Fri, 24 May 2019 00:22:58 +0200 Subject: [PATCH 201/951] Fix Bmb datacache bridge --- src/main/scala/vexriscv/ip/DataCache.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index d34fcebf..9239cf52 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -323,7 +323,7 @@ case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave bus.cmd.opcode := (cmd.wr ? B(Bmb.Cmd.Opcode.WRITE) | B(Bmb.Cmd.Opcode.READ)) bus.cmd.address := cmd.address.resized bus.cmd.data := cmd.data - bus.cmd.length := cmd.length << 2 //TODO better sub word access + bus.cmd.length := (cmd.length << 2) | 3 //TODO better sub word access bus.cmd.mask := cmd.mask cmd.ready := bus.cmd.ready From 94606d38e2dab3436e4a2ff98a1de14de60cb1bb Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Sat, 25 May 2019 00:21:48 +0200 Subject: [PATCH 202/951] Add cache bandwidth counter --- src/main/scala/vexriscv/ip/InstructionCache.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/ip/InstructionCache.scala b/src/main/scala/vexriscv/ip/InstructionCache.scala index 55b9f1a7..edc33d83 100644 --- a/src/main/scala/vexriscv/ip/InstructionCache.scala +++ b/src/main/scala/vexriscv/ip/InstructionCache.scala @@ -362,7 +362,7 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{ 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 wayToAllocate = Counter(wayCount, !valid) val wordIndex = Reg(UInt(log2Up(memWordPerLine) bits)) init(0) From 4a40184b353c85a3d6fa491f427be5ea6cadf6ce Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Sat, 25 May 2019 00:22:27 +0200 Subject: [PATCH 203/951] Add cache Bandwidth counter, previous commit was about random instruction cache way allocation --- src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala | 8 ++++++++ src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala | 8 +++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index baf9adad..c981922d 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -168,6 +168,14 @@ class DBusCachedPlugin(val config : DataCacheConfig, dBus.cmd << optionPipe(dBusCmdMasterPipe, cmdBuf)(_.m2sPipe()) cache.io.mem.rsp << optionPipe(dBusRspSlavePipe,dBus.rsp)(_.m2sPipe()) + pipeline plug new Area{ + //Memory bandwidth counter + val rspCounter = RegInit(UInt(32 bits)) init(0) + when(dBus.rsp.valid){ + rspCounter := rspCounter + 1 + } + } + decode plug new Area { import decode._ diff --git a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala index 362ac8d4..4005fb9b 100644 --- a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala @@ -129,7 +129,13 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l, iBus = master(new InstructionCacheMemBus(IBusCachedPlugin.this.config)).setName("iBus") iBus <> cache.io.mem iBus.cmd.address.allowOverride := cache.io.mem.cmd.address - + + //Memory bandwidth counter + val rspCounter = RegInit(UInt(32 bits)) init(0) + when(iBus.rsp.valid){ + rspCounter := rspCounter + 1 + } + val stageOffset = if(relaxedPcCalculation) 1 else 0 def stages = iBusRsp.stages.drop(stageOffset) From 38a464a8296c3cb2b2b5fca84163c76790d13a72 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Sat, 25 May 2019 00:28:30 +0200 Subject: [PATCH 204/951] DataCache now allocate ways randomly --- src/main/scala/vexriscv/ip/DataCache.scala | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index 9239cf52..f6926806 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -678,11 +678,13 @@ class DataCache(p : DataCacheConfig) extends Component{ tagsWriteCmd.data.error := error || io.mem.rsp.error tagsWriteCmd.way := waysAllocator - waysAllocator := (waysAllocator ## waysAllocator.msb).resized - error := False } + when(!valid){ + waysAllocator := (waysAllocator ## waysAllocator.msb).resized + } + io.cpu.redo setWhen(valid) stageB.mmuRspFreeze setWhen(stageB.loaderValid || valid) } From 64e8919e89ed647c4bea87be27bf3e5f2ce72a6b Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 28 May 2019 11:28:07 +0200 Subject: [PATCH 205/951] Update README.md Add litex repo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b6f56ac7..3fbfef08 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ This repository hosts a RISC-V implementation written in SpinalHDL. Here are som - Optional interrupts and exception handling with Machine, [Supervisor] and [User] modes as defined in the [RISC-V Privileged ISA Specification v1.10](https://riscv.org/specifications/privileged-isa/). - Two implementations of shift instructions: Single cycle and shiftNumber cycles - Each stage can have optional bypass or interlock hazard logic -- Linux compatible +- Linux compatible (SoC : https://github.com/enjoy-digital/linux-on-litex-vexriscv) - Zephyr compatible - [FreeRTOS port](https://github.com/Dolu1990/FreeRTOS-RISCV) From 56f7c27d18589f10d143e9e615eb4fc06f10376d Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Wed, 5 Jun 2019 00:32:38 +0200 Subject: [PATCH 206/951] Fix WFI. Not sensitive anymore to global interrupt enables, delegation and privilege --- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 467dc76a..5f81f6fb 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -879,9 +879,10 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep import execute._ //Manage WFI instructions val inWfi = False.addTag(Verilator.public) + val wfiWake = RegNext(interruptSpecs.map(_.cond).orR) init(False) if(wfiGenAsWait) when(arbitration.isValid && input(ENV_CTRL) === EnvCtrlEnum.WFI){ inWfi := True - when(!interrupt){ + when(!wfiWake){ arbitration.haltItself := True } } From 357681a5c67ed61fac5514a8637574745c2583a9 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Sat, 8 Jun 2019 22:22:16 +0200 Subject: [PATCH 207/951] csrPlugin add pipelinedInterrupt, set by default --- .../scala/vexriscv/plugin/CsrPlugin.scala | 56 ++++++++++--------- src/test/cpp/regression/main.cpp | 2 +- 2 files changed, 32 insertions(+), 26 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 5f81f6fb..4030ab7f 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -68,6 +68,7 @@ case class CsrPluginConfig( medelegAccess : CsrAccess = CsrAccess.NONE, midelegAccess : CsrAccess = CsrAccess.NONE, pipelineCsrRead : Boolean = false, + pipelinedInterrupt : Boolean = true, deterministicInteruptionEntry : Boolean = false //Only used for simulatation purposes ){ assert(!ucycleAccess.canWrite) @@ -729,32 +730,37 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep //Process interrupt request, code and privilege - val interrupt = False - val interruptCode = UInt(4 bits).assignDontCare().addTag(Verilator.public) - var interruptPrivilegs = if (supervisorGen) List(1, 3) else List(3) - val interruptTargetPrivilege = UInt(2 bits).assignDontCare() - val privilegeAllowInterrupts = mutable.HashMap[Int, Bool]() - if(supervisorGen) privilegeAllowInterrupts += 1 -> ((sstatus.SIE && privilege === "01") || privilege < "01") - privilegeAllowInterrupts += 3 -> (mstatus.MIE || privilege < "11") - while(interruptPrivilegs.nonEmpty){ - val p = interruptPrivilegs.head - when(privilegeAllowInterrupts(p)){ - for(i <- interruptSpecs - if i.privilege <= p //EX : Machine timer interrupt can't go into supervisor mode - if interruptPrivilegs.tail.forall(e => i.delegators.exists(_.privilege == e))){ // EX : Supervisor timer need to have machine mode delegator - val delegUpOn = i.delegators.filter(_.privilege > p).map(_.enable).fold(True)(_ && _) - val delegDownOff = !i.delegators.filter(_.privilege <= p).map(_.enable).orR - when(i.cond && delegUpOn && delegDownOff){ - interrupt := True - interruptCode := i.id - interruptTargetPrivilege := p + val interrupt = new Area { + val valid = if(pipelinedInterrupt) RegNext(False) init(False) else False + val code = if(pipelinedInterrupt) Reg(UInt(4 bits)) else UInt(4 bits).assignDontCare() + var privilegs = if (supervisorGen) List(1, 3) else List(3) + val targetPrivilege = if(pipelinedInterrupt) Reg(UInt(2 bits)) else UInt(2 bits).assignDontCare() + val privilegeAllowInterrupts = mutable.HashMap[Int, Bool]() + if (supervisorGen) privilegeAllowInterrupts += 1 -> ((sstatus.SIE && privilege === "01") || privilege < "01") + privilegeAllowInterrupts += 3 -> (mstatus.MIE || privilege < "11") + while (privilegs.nonEmpty) { + val p = privilegs.head + when(privilegeAllowInterrupts(p)) { + for (i <- interruptSpecs + if i.privilege <= p //EX : Machine timer interrupt can't go into supervisor mode + if privilegs.tail.forall(e => i.delegators.exists(_.privilege == e))) { // EX : Supervisor timer need to have machine mode delegator + val delegUpOn = i.delegators.filter(_.privilege > p).map(_.enable).fold(True)(_ && _) + val delegDownOff = !i.delegators.filter(_.privilege <= p).map(_.enable).orR + when(i.cond && delegUpOn && delegDownOff) { + valid := True + code := i.id + targetPrivilege := p + } } } + privilegs = privilegs.tail } - interruptPrivilegs = interruptPrivilegs.tail + + code.addTag(Verilator.public) } - interrupt.clearWhen(!allowInterrupts) + + val exception = if(exceptionPortCtrl != null) exceptionPortCtrl.exceptionValids.last && allowException else False val lastStageWasWfi = if(wfiGenAsWait) RegNext(lastStage.arbitration.isFiring && lastStage.input(ENV_CTRL) === EnvCtrlEnum.WFI) init(False) else False @@ -763,7 +769,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep //Used to make the pipeline empty softly (for interrupts) val pipelineLiberator = new Area{ - when(interrupt){ + when(interrupt.valid && allowInterrupts){ decode.arbitration.haltByOther := decode.arbitration.isValid } @@ -773,18 +779,18 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep //Interrupt/Exception entry logic val interruptJump = Bool.addTag(Verilator.public) - interruptJump := interrupt && pipelineLiberator.done + interruptJump := interrupt.valid && pipelineLiberator.done && allowInterrupts val hadException = RegNext(exception) init(False) pipelineLiberator.done.clearWhen(hadException) - val targetPrivilege = CombInit(interruptTargetPrivilege) + val targetPrivilege = CombInit(interrupt.targetPrivilege) if(exceptionPortCtrl != null) when(hadException) { targetPrivilege := exceptionPortCtrl.exceptionTargetPrivilege } - val trapCause = CombInit(interruptCode) + val trapCause = CombInit(interrupt.code) if(exceptionPortCtrl != null) when( hadException){ trapCause := exceptionPortCtrl.exceptionContext.code } diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 6f50a1cd..2730c464 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -1550,7 +1550,7 @@ public: riscvRef.liveness(top->VexRiscv->execute_CsrPlugin_inWfi); if(top->VexRiscv->CsrPlugin_interruptJump){ - if(riscvRefEnable) riscvRef.trap(true, top->VexRiscv->CsrPlugin_interruptCode); + if(riscvRefEnable) riscvRef.trap(true, top->VexRiscv->CsrPlugin_interrupt_code); } } #endif From af0755d8cf1807a190bd6153444140ab2c9b67a5 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Sun, 9 Jun 2019 15:44:05 +0200 Subject: [PATCH 208/951] rework flush with flushNext and flushIt static branch prediction jump do not depend on stage fireing anymore --- src/main/scala/vexriscv/Pipeline.scala | 4 +++- src/main/scala/vexriscv/Stage.scala | 3 ++- src/main/scala/vexriscv/VexRiscv.scala | 2 +- .../scala/vexriscv/plugin/BranchPlugin.scala | 18 +++++++++--------- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 6 +++--- .../vexriscv/plugin/DBusCachedPlugin.scala | 3 ++- .../vexriscv/plugin/DBusSimplePlugin.scala | 3 ++- .../scala/vexriscv/plugin/DebugPlugin.scala | 3 ++- src/main/scala/vexriscv/plugin/Fetcher.scala | 9 +++++++-- .../vexriscv/plugin/IBusCachedPlugin.scala | 3 +++ .../vexriscv/plugin/IBusSimplePlugin.scala | 4 +++- 11 files changed, 37 insertions(+), 21 deletions(-) diff --git a/src/main/scala/vexriscv/Pipeline.scala b/src/main/scala/vexriscv/Pipeline.scala index 14fe0713..2a04ef2b 100644 --- a/src/main/scala/vexriscv/Pipeline.scala +++ b/src/main/scala/vexriscv/Pipeline.scala @@ -17,6 +17,8 @@ trait Pipeline { val things = mutable.HashMap[PipelineThing[_], Any]() // val services = ArrayBuffer[Any]() + def stageBefore(stage : Stage) = stages(indexOf(stage)-1) + def indexOf(stage : Stage) = stages.indexOf(stage) def service[T](clazz : Class[T]) = { @@ -127,7 +129,7 @@ trait Pipeline { //Arbitration for(stageIndex <- 0 until stages.length; stage = stages(stageIndex)) { - stage.arbitration.isFlushed := stages.drop(stageIndex).map(_.arbitration.flushAll).orR + stage.arbitration.isFlushed := stages.drop(stageIndex+1).map(_.arbitration.flushNext).orR || stages.drop(stageIndex).map(_.arbitration.flushIt).orR if(!unremovableStages.contains(stage)) stage.arbitration.removeIt setWhen stage.arbitration.isFlushed else diff --git a/src/main/scala/vexriscv/Stage.scala b/src/main/scala/vexriscv/Stage.scala index f036dfb3..d86c2567 100644 --- a/src/main/scala/vexriscv/Stage.scala +++ b/src/main/scala/vexriscv/Stage.scala @@ -49,7 +49,8 @@ class Stage() extends Area{ val haltItself = False //user settable, stuck the instruction, should only be set by the instruction itself 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 flushIt = False //When settable, unschedule the current instruction + val flushNext = False //When settable, unschedule instruction above in the pipeline val isValid = Bool //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 diff --git a/src/main/scala/vexriscv/VexRiscv.scala b/src/main/scala/vexriscv/VexRiscv.scala index 26d9489e..1e387915 100644 --- a/src/main/scala/vexriscv/VexRiscv.scala +++ b/src/main/scala/vexriscv/VexRiscv.scala @@ -109,7 +109,7 @@ class VexRiscv(val config : VexRiscvConfig) extends Component with Pipeline{ if(withMemoryStage){ memory.arbitration.removeIt.noBackendCombMerge } - execute.arbitration.flushAll.noBackendCombMerge + execute.arbitration.flushNext.noBackendCombMerge this(RVC_GEN) = false } diff --git a/src/main/scala/vexriscv/plugin/BranchPlugin.scala b/src/main/scala/vexriscv/plugin/BranchPlugin.scala index 6885f2ae..30341d39 100644 --- a/src/main/scala/vexriscv/plugin/BranchPlugin.scala +++ b/src/main/scala/vexriscv/plugin/BranchPlugin.scala @@ -200,11 +200,11 @@ class BranchPlugin(earlyBranch : Boolean, //Apply branchs (JAL,JALR, Bxx) branchStage plug new Area { import branchStage._ - jumpInterface.valid := arbitration.isValid && !arbitration.isStuckByOthers && input(BRANCH_DO) + jumpInterface.valid := arbitration.isValid && input(BRANCH_DO) jumpInterface.payload := input(BRANCH_CALC) - when(jumpInterface.valid) { - stages(indexOf(branchStage) - 1).arbitration.flushAll := True + when(jumpInterface.valid && !arbitration.isStuckByOthers) { + arbitration.flushNext := True } if(catchAddressMisalignedForReal) { @@ -282,11 +282,11 @@ class BranchPlugin(earlyBranch : Boolean, val branchStage = if(earlyBranch) execute else memory branchStage plug new Area { import branchStage._ - jumpInterface.valid := arbitration.isValid && !arbitration.isStuckByOthers && input(BRANCH_DO) + jumpInterface.valid := arbitration.isValid && input(BRANCH_DO) jumpInterface.payload := input(BRANCH_CALC) - when(jumpInterface.valid) { - stages(indexOf(branchStage) - 1).arbitration.flushAll := True + when(jumpInterface.valid && !arbitration.isStuckByOthers) { + arbitration.flushNext := True } if(catchAddressMisalignedForReal) { @@ -361,12 +361,12 @@ class BranchPlugin(earlyBranch : Boolean, input(PC) } - jumpInterface.valid := arbitration.isValid && !arbitration.isStuckByOthers && predictionMissmatch //Probably just isValid instead of isFiring is better + jumpInterface.valid := arbitration.isValid && predictionMissmatch //Probably just isValid instead of isFiring is better jumpInterface.payload := (input(BRANCH_DO) ? input(BRANCH_CALC) | input(NEXT_PC)) - when(jumpInterface.valid) { - stages(indexOf(branchStage) - 1).arbitration.flushAll := True + when(jumpInterface.valid && !arbitration.isStuckByOthers) { + arbitration.flushNext := True } if(catchAddressMisalignedForReal) { diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 4030ab7f..756156c4 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -694,7 +694,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep exceptionValids := exceptionValidsRegs for(portInfo <- sortedByStage; port = portInfo.port ; stage = portInfo.stage; stageId = indexOf(portInfo.stage)) { when(port.valid) { - if(indexOf(stage) != 0) stages(indexOf(stage) - 1).arbitration.flushAll := True + stage.arbitration.flushNext := True stage.arbitration.removeIt := True exceptionValids(stageId) := True exceptionContext := port.payload @@ -806,7 +806,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep jumpInterface.valid := True jumpInterface.payload := (if(!xtvecModeGen) xtvec.base @@ "00" else (xtvec.mode === 0 || hadException) ? (xtvec.base @@ "00") | ((xtvec.base + trapCause) @@ "00") ) - beforeLastStage.arbitration.flushAll := True + lastStage.arbitration.flushNext := True if(privilegeGen) privilegeReg := targetPrivilege @@ -845,7 +845,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep when(arbitration.isValid && input(ENV_CTRL) === EnvCtrlEnum.XRET) { fetcher.haltIt() jumpInterface.valid := True - beforeLastStage.arbitration.flushAll := True + lastStage.arbitration.flushNext := True switch(input(INSTRUCTION)(29 downto 28)){ is(3){ mstatus.MPP := U"00" diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index 8584a8c4..a8aa7403 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -239,7 +239,8 @@ class DBusCachedPlugin(config : DataCacheConfig, redoBranch.valid := False redoBranch.payload := input(PC) - arbitration.flushAll setWhen(redoBranch.valid) + arbitration.flushIt setWhen(redoBranch.valid) + arbitration.flushNext setWhen(redoBranch.valid) if(catchSomething) { exceptionBus.valid := False //cache.io.cpu.writeBack.mmuMiss || cache.io.cpu.writeBack.accessError || cache.io.cpu.writeBack.illegalAccess || cache.io.cpu.writeBack.unalignedAccess diff --git a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala index 661b5247..a17874cd 100644 --- a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala @@ -476,7 +476,8 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, memoryExceptionPort.code := (input(MEMORY_STORE) ? U(15) | U(13)).resized } - arbitration.flushAll setWhen(redoBranch.valid) + arbitration.flushIt setWhen(redoBranch.valid) + arbitration.flushNext setWhen(redoBranch.valid) } when(!(arbitration.isValid && input(MEMORY_ENABLE) && (Bool(cmdStage != rspStage) || !arbitration.isStuckByOthers))){ diff --git a/src/main/scala/vexriscv/plugin/DebugPlugin.scala b/src/main/scala/vexriscv/plugin/DebugPlugin.scala index 454d3523..4088cecd 100644 --- a/src/main/scala/vexriscv/plugin/DebugPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DebugPlugin.scala @@ -203,7 +203,8 @@ class DebugPlugin(val debugClockDomain : ClockDomain, hardwareBreakpointCount : when(stagesFromExecute.tail.map(_.arbitration.isValid).orR === False){ iBusFetcher.flushIt() iBusFetcher.haltIt() - execute.arbitration.flushAll := True + execute.arbitration.flushIt := True + execute.arbitration.flushNext := True haltIt := True haltedByBreak := True } diff --git a/src/main/scala/vexriscv/plugin/Fetcher.scala b/src/main/scala/vexriscv/plugin/Fetcher.scala index 62d4aa79..aa1daae8 100644 --- a/src/main/scala/vexriscv/plugin/Fetcher.scala +++ b/src/main/scala/vexriscv/plugin/Fetcher.scala @@ -103,7 +103,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, pcLoad.payload := MuxOH(OHMasking.first(valids.asBits), pcs) } - def flush = jump.pcLoad.valid || fetcherflushIt + def flush = fetcherflushIt || stages.map(_.arbitration.flushNext).orR class PcFetch extends Area{ val preOutput = Stream(UInt(32 bits)) @@ -499,10 +499,15 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, decodePrediction.cmd.hadBranch clearWhen(missaligned) } - predictionJumpInterface.valid := decodePrediction.cmd.hadBranch && decode.arbitration.isFiring //TODO OH Doublon de priorité + //TODO no more fireing depedancies + predictionJumpInterface.valid := decodePrediction.cmd.hadBranch && decode.arbitration.isValid //TODO OH Doublon de priorité predictionJumpInterface.payload := decode.input(PC) + ((decode.input(BRANCH_CTRL) === BranchCtrlEnum.JAL) ? imm.j_sext | imm.b_sext).asUInt if(relaxPredictorAddress) KeepAttribute(predictionJumpInterface.payload) + when(predictionJumpInterface.valid && decode.arbitration.isFiring){ + flushIt() + } + // when(predictionJumpInterface.payload((if(pipeline(RVC_GEN)) 0 else 1) downto 0) =/= 0){ // decodePrediction.cmd.hadBranch := False // } diff --git a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala index 92722e96..65c210a1 100644 --- a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala @@ -237,6 +237,9 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l, redoBranch.valid := redoFetch redoBranch.payload := (if (decodePcGen) decode.input(PC) else cacheRsp.pc) + when(redoBranch.valid) { + decode.arbitration.flushNext := True + } cacheRspArbitration.halt setWhen (issueDetected || iBusRspOutputHalt) iBusRsp.output.valid := cacheRspArbitration.output.valid diff --git a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala index 67dc7864..e00e122e 100644 --- a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala @@ -351,7 +351,9 @@ class IBusSimplePlugin(resetVector : BigInt, redoRequired setWhen( stages.last.input.valid && mmu.joinCtx.refilling) redoBranch.valid := redoRequired && iBusRsp.readyForError redoBranch.payload := decode.input(PC) - decode.arbitration.flushAll setWhen(redoBranch.valid) + + decode.arbitration.flushIt setWhen(redoBranch.valid) + decode.arbitration.flushNext setWhen(redoBranch.valid) } From 5243e46ffb5c528f22d91af880833aade8a24d14 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Sun, 9 Jun 2019 20:15:36 +0200 Subject: [PATCH 209/951] Fix BranchPlugin when SRC can have hazard in execute stage --- src/main/scala/vexriscv/plugin/BranchPlugin.scala | 8 +++++--- src/main/scala/vexriscv/plugin/HazardSimplePlugin.scala | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/BranchPlugin.scala b/src/main/scala/vexriscv/plugin/BranchPlugin.scala index 30341d39..281063b9 100644 --- a/src/main/scala/vexriscv/plugin/BranchPlugin.scala +++ b/src/main/scala/vexriscv/plugin/BranchPlugin.scala @@ -84,6 +84,8 @@ class BranchPlugin(earlyBranch : Boolean, decodePrediction } + def hasHazardOnBranch = if(earlyBranch) pipeline.service(classOf[HazardService]).hazardOnExecuteRS else False + override def setup(pipeline: VexRiscv): Unit = { import Riscv._ import pipeline.config._ @@ -200,7 +202,7 @@ class BranchPlugin(earlyBranch : Boolean, //Apply branchs (JAL,JALR, Bxx) branchStage plug new Area { import branchStage._ - jumpInterface.valid := arbitration.isValid && input(BRANCH_DO) + jumpInterface.valid := arbitration.isValid && input(BRANCH_DO) && !hasHazardOnBranch jumpInterface.payload := input(BRANCH_CALC) when(jumpInterface.valid && !arbitration.isStuckByOthers) { @@ -282,7 +284,7 @@ class BranchPlugin(earlyBranch : Boolean, val branchStage = if(earlyBranch) execute else memory branchStage plug new Area { import branchStage._ - jumpInterface.valid := arbitration.isValid && input(BRANCH_DO) + jumpInterface.valid := arbitration.isValid && input(BRANCH_DO) && !hasHazardOnBranch jumpInterface.payload := input(BRANCH_CALC) when(jumpInterface.valid && !arbitration.isStuckByOthers) { @@ -361,7 +363,7 @@ class BranchPlugin(earlyBranch : Boolean, input(PC) } - jumpInterface.valid := arbitration.isValid && predictionMissmatch //Probably just isValid instead of isFiring is better + jumpInterface.valid := arbitration.isValid && predictionMissmatch && !hasHazardOnBranch jumpInterface.payload := (input(BRANCH_DO) ? input(BRANCH_CALC) | input(NEXT_PC)) diff --git a/src/main/scala/vexriscv/plugin/HazardSimplePlugin.scala b/src/main/scala/vexriscv/plugin/HazardSimplePlugin.scala index c051aa03..f674ae87 100644 --- a/src/main/scala/vexriscv/plugin/HazardSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/HazardSimplePlugin.scala @@ -19,7 +19,7 @@ class HazardSimplePlugin(bypassExecute : Boolean = false, def hazardOnExecuteRS = { - if(pipeline.service(classOf[RegFileService]).readStage() == pipeline.execute) pipeline.execute.arbitration.isStuckByOthers else False + if(pipeline.service(classOf[RegFileService]).readStage() == pipeline.execute) pipeline.execute.arbitration.isStuckByOthers else False //TODO not so nice } override def setup(pipeline: VexRiscv): Unit = { From 24e1e3018ce1586b7d92a3aa651b95f69d3fc3a9 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Sun, 9 Jun 2019 23:40:37 +0200 Subject: [PATCH 210/951] Fix exception handeling --- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 2 +- src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala | 1 - src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 756156c4..6c3e4a39 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -716,7 +716,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep } } - when(exceptionValidsRegs.orR){ + when(exceptionValids.orR){ fetcher.haltIt() } diff --git a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala index 65c210a1..a9dd8894 100644 --- a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala @@ -233,7 +233,6 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l, redoFetch clearWhen(!iBusRsp.readyForError) cache.io.cpu.fill.valid clearWhen(!iBusRsp.readyForError) - if (catchSomething) decodeExceptionPort.valid clearWhen(fetcherHalt) redoBranch.valid := redoFetch redoBranch.payload := (if (decodePcGen) decode.input(PC) else cacheRsp.pc) diff --git a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala index e00e122e..688dce52 100644 --- a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala @@ -372,7 +372,7 @@ class IBusSimplePlugin(resetVector : BigInt, exceptionDetected := True } } - decodeExceptionPort.valid := exceptionDetected && iBusRsp.readyForError && !fetcherHalt + decodeExceptionPort.valid := exceptionDetected && iBusRsp.readyForError } } } From bd46dd88aa298ae055ee68932ea1509712628e5c Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Mon, 10 Jun 2019 20:48:04 +0200 Subject: [PATCH 211/951] Fix RVC fetcher pc branches --- src/main/scala/vexriscv/plugin/Fetcher.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/plugin/Fetcher.scala b/src/main/scala/vexriscv/plugin/Fetcher.scala index aa1daae8..8d3f5b77 100644 --- a/src/main/scala/vexriscv/plugin/Fetcher.scala +++ b/src/main/scala/vexriscv/plugin/Fetcher.scala @@ -185,7 +185,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, } //application of the selected jump request - when(jump.pcLoad.valid) { + when(jump.pcLoad.valid && (!decode.arbitration.isValid || !decode.arbitration.isStuck || decode.arbitration.isRemoved)) { pcReg := jump.pcLoad.payload } }) From 0e95154869a82f986ca72ca97dd2e2ec2cf79ad5 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Mon, 10 Jun 2019 21:01:41 +0200 Subject: [PATCH 212/951] individual regression : more env control --- src/test/scala/vexriscv/TestIndividualFeatures.scala | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/test/scala/vexriscv/TestIndividualFeatures.scala b/src/test/scala/vexriscv/TestIndividualFeatures.scala index 52097e9e..93353f05 100644 --- a/src/test/scala/vexriscv/TestIndividualFeatures.scala +++ b/src/test/scala/vexriscv/TestIndividualFeatures.scala @@ -474,7 +474,7 @@ class CsrDimension(freertos : String, zephyr : String) extends VexRiscvDimension if(supervisor){ new VexRiscvPosition("Supervisor") with CatchAllPosition{ override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new CsrPlugin(CsrPluginConfig.linuxFull(0x80000020l)) - override def testParam = s"FREERTOS=$freertos ZEPHYR=$zephyr LINUX_REGRESSION=yes SUPERVISOR=yes" + override def testParam = s"FREERTOS=$freertos ZEPHYR=$zephyr LINUX_REGRESSION=${sys.env.getOrElse("VEXRISCV_REGRESSION_LINUX_REGRESSION", "yes")} SUPERVISOR=yes" } } else if(catchAll){ new VexRiscvPosition("MachineOs") with CatchAllPosition{ @@ -598,7 +598,7 @@ class TestIndividualFeatures extends FunSuite { test(prefix + name + "_test") { val debug = true - val stdCmd = (s"make clean run WITH_USER_IO=no REDO=10 TRACE=${if(debug) "yes" else "no"} TRACE_START=9999924910246l FLOW_INFO=no STOP_ON_ERROR=no DHRYSTONE=yes COREMARK=yes THREAD_COUNT=${sys.env.getOrElse("VEXRISCV_REGRESSION_THREAD_COUNT", 1)} ") + s" SEED=${testSeed} " + val stdCmd = (s"make clean run WITH_USER_IO=no REDO=10 TRACE=${if(debug) "yes" else "no"} TRACE_START=9999924910246l STOP_ON_ERROR=no FLOW_INFO=no STOP_ON_ERROR=no DHRYSTONE=yes COREMARK=${sys.env.getOrElse("VEXRISCV_REGRESSION_COREMARK", "yes")} THREAD_COUNT=${sys.env.getOrElse("VEXRISCV_REGRESSION_THREAD_COUNT", 1)} ") + s" SEED=${testSeed} " val testCmd = stdCmd + (positionsToApply).map(_.testParam).mkString(" ") println(testCmd) val str = doCmd(testCmd) @@ -609,11 +609,11 @@ class TestIndividualFeatures extends FunSuite { // dimensions.foreach(d => d.positions.foreach(p => p.dimension = d)) val testId : Option[mutable.HashSet[Int]] = None - val seed = Random.nextLong() + val seed = sys.env.getOrElse("VEXRISCV_REGRESSION_SEED", Random.nextLong().toString).toLong -// val testId = Some(mutable.HashSet(18,34,77,85,118,129,132,134,152,167,175,188,191,198,199)) //37/29 sp_flop_rv32i_O3 -//val testId = Some(mutable.HashSet(0)) -// val testId = Some(mutable.HashSet(4)) +// val testId = Some(mutable.HashSet(3,4,9,11,13,16,18,19,20,21)) +// val testId = Some(mutable.HashSet(24, 43, 49)) +// val testId = Some(mutable.HashSet(11)) // val seed = -8309068850561113754l From 5b53440d272d16383f2a96b1c1b2531886070250 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Mon, 10 Jun 2019 22:20:32 +0200 Subject: [PATCH 213/951] DYNAMIC_TARGET prediction datapath/control path are now splited --- src/main/scala/vexriscv/plugin/Fetcher.scala | 36 +++++++++---------- .../vexriscv/plugin/IBusCachedPlugin.scala | 2 +- .../vexriscv/plugin/IBusSimplePlugin.scala | 6 ++-- 3 files changed, 20 insertions(+), 24 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/Fetcher.scala b/src/main/scala/vexriscv/plugin/Fetcher.scala index 8d3f5b77..26e91c1e 100644 --- a/src/main/scala/vexriscv/plugin/Fetcher.scala +++ b/src/main/scala/vexriscv/plugin/Fetcher.scala @@ -103,7 +103,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, pcLoad.payload := MuxOH(OHMasking.first(valids.asBits), pcs) } - def flush = fetcherflushIt || stages.map(_.arbitration.flushNext).orR + fetcherflushIt setWhen(stages.map(_.arbitration.flushNext).orR) class PcFetch extends Area{ val preOutput = Stream(UInt(32 bits)) @@ -225,12 +225,12 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, } for((s,sNext) <- (stages, stages.tail).zipped) { - if(s == stages.head && pcRegReusedForSecondStage) { - sNext.input.arbitrationFrom(s.output.toEvent().m2sPipeWithFlush(flush, s != stages.head, collapsBubble = false)) + if(s == stages.head && pcRegReusedForSecondStage && prediction != DYNAMIC_TARGET) { //DYNAMIC_TARGET realy need PC state for both stage(0) and stage(1) + sNext.input.arbitrationFrom(s.output.toEvent().m2sPipeWithFlush(fetcherflushIt, s != stages.head, collapsBubble = false)) sNext.input.payload := fetchPc.pcReg fetchPc.propagatePc setWhen(sNext.input.fire) } else { - sNext.input << s.output.m2sPipeWithFlush(flush, s != stages.head, collapsBubble = false) + sNext.input << s.output.m2sPipeWithFlush(fetcherflushIt, s != stages.head, collapsBubble = false) } } @@ -273,7 +273,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, // input.ready := (bufferValid ? (!isRvc && output.ready) | (input.pc(1) || output.ready)) input.ready := !output.valid || !(!output.ready || (isRvc && !input.pc(1) && input.rsp.inst(16, 2 bits) =/= 3) || (!isRvc && bufferValid && input.rsp.inst(16, 2 bits) =/= 3)) addPrePopTask(() => { - when(!input.ready && output.fire && !flush /* && ((isRvc && !bufferValid && !input.pc(1)) || (!isRvc && bufferValid && input.rsp.inst(16, 2 bits) =/= 3))*/) { + when(!input.ready && output.fire && !fetcherflushIt /* && ((isRvc && !bufferValid && !input.pc(1)) || (!isRvc && bufferValid && input.rsp.inst(16, 2 bits) =/= 3))*/) { input.pc.getDrivingReg(1) := True } }) @@ -284,7 +284,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, bufferValid := !(!isRvc && !input.pc(1) && !bufferValid) && !(isRvc && input.pc(1) && output.ready) bufferData := input.rsp.inst(31 downto 16) } - bufferValid.clearWhen(flush) + bufferValid.clearWhen(fetcherflushIt) iBusRsp.readyForError.clearWhen(bufferValid && isRvc) //Can't emit error, as there is a earlier instruction pending incomingInstruction setWhen(bufferValid && bufferData(1 downto 0) =/= 3) }) @@ -292,13 +292,13 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, def condApply[T](that : T, cond : Boolean)(func : (T) => T) = if(cond)func(that) else that val injector = new Area { - val inputBeforeStage = condApply(if (decodePcGen) decompressor.output else iBusRsp.output, injectorReadyCutGen)(_.s2mPipe(flush)) + val inputBeforeStage = condApply(if (decodePcGen) decompressor.output else iBusRsp.output, injectorReadyCutGen)(_.s2mPipe(fetcherflushIt)) if (injectorReadyCutGen) { iBusRsp.readyForError.clearWhen(inputBeforeStage.valid) //Can't emit error if there is a instruction pending in the s2mPipe incomingInstruction setWhen (inputBeforeStage.valid) } val decodeInput = (if (injectorStage) { - val decodeInput = inputBeforeStage.m2sPipeWithFlush(flush, collapsBubble = false) + val decodeInput = inputBeforeStage.m2sPipeWithFlush(fetcherflushIt, collapsBubble = false) decode.insert(INSTRUCTION_ANTICIPATED) := Mux(decode.arbitration.isStuck, decode.input(INSTRUCTION), inputBeforeStage.rsp.inst) iBusRsp.readyForError.clearWhen(decodeInput.valid) //Can't emit error when there is a instruction pending in the injector stage buffer incomingInstruction setWhen (decodeInput.valid) @@ -313,13 +313,13 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, def pcUpdatedGen(input : Bool, stucks : Seq[Bool], relaxedInput : Boolean) : Seq[Bool] = { stucks.scanLeft(input)((i, stuck) => { val reg = RegInit(False) - if(!relaxedInput) when(flush) { + if(!relaxedInput) when(fetcherflushIt) { reg := False } when(!stuck) { reg := i } - if(relaxedInput || i != input) when(flush) { + if(relaxedInput || i != input) when(fetcherflushIt) { reg := False } reg @@ -335,7 +335,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, pcValids := Vec(valids.takeRight(stages.size)) } - val decodeRemoved = RegInit(False) setWhen(decode.arbitration.isRemoved) clearWhen(flush) //!decode.arbitration.isStuck || decode.arbitration.isFlushed + val decodeRemoved = RegInit(False) setWhen(decode.arbitration.isRemoved) clearWhen(fetcherflushIt) //!decode.arbitration.isStuck || decode.arbitration.isFlushed decodeInput.ready := !decode.arbitration.isStuck decode.arbitration.isValid := decodeInput.valid && !decodeRemoved @@ -461,7 +461,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, } val fetchContext = DynamicContext() fetchContext.hazard := hazard - fetchContext.line := historyCache.readSync((fetchPc.output.payload >> 2).resized, iBusRsp.stages(0).output.ready || flush) + fetchContext.line := historyCache.readSync((fetchPc.output.payload >> 2).resized, iBusRsp.stages(0).output.ready || fetcherflushIt) object PREDICTION_CONTEXT extends Stageable(DynamicContext()) decode.insert(PREDICTION_CONTEXT) := stage1ToInjectorPipe(fetchContext)._2 @@ -500,17 +500,13 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, } //TODO no more fireing depedancies - predictionJumpInterface.valid := decodePrediction.cmd.hadBranch && decode.arbitration.isValid //TODO OH Doublon de priorité + predictionJumpInterface.valid := decode.arbitration.isValid && decodePrediction.cmd.hadBranch //TODO OH Doublon de priorité predictionJumpInterface.payload := decode.input(PC) + ((decode.input(BRANCH_CTRL) === BranchCtrlEnum.JAL) ? imm.j_sext | imm.b_sext).asUInt if(relaxPredictorAddress) KeepAttribute(predictionJumpInterface.payload) when(predictionJumpInterface.valid && decode.arbitration.isFiring){ flushIt() } - -// when(predictionJumpInterface.payload((if(pipeline(RVC_GEN)) 0 else 1) downto 0) =/= 0){ -// decodePrediction.cmd.hadBranch := False -// } } case DYNAMIC_TARGET => new Area{ // assert(!compressedGen || cmdToRspStageCount == 1, "Can't combine DYNAMIC_TARGET and RVC as it could stop the instruction fetch mid-air") @@ -525,7 +521,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, val history = Mem(BranchPredictorLine(), 1 << historyRamSizeLog2) val historyWrite = history.writePort - val line = history.readSync((iBusRsp.stages(0).input.payload >> 2).resized, iBusRsp.stages(0).output.ready || flush) + val line = history.readSync((iBusRsp.stages(0).input.payload >> 2).resized, iBusRsp.stages(0).output.ready || fetcherflushIt) val hit = line.source === (iBusRsp.stages(1).input.payload.asBits >> 2 + historyRamSizeLog2) && (if(compressedGen)(!(!line.unaligned && iBusRsp.stages(1).input.payload(1))) else True) //Avoid stoping instruction fetch in the middle patch @@ -537,7 +533,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, val historyWriteLast = RegNextWhen(historyWrite, iBusRsp.stages(0).output.ready) val hazard = historyWriteLast.valid && historyWriteLast.address === (iBusRsp.stages(1).input.payload >> 2).resized //TODO improve predictionPcLoad way of doing things - fetchPc.predictionPcLoad.valid := line.branchWish.msb && hit && !hazard && iBusRsp.stages(1).output.fire //XXX && !(!line.unaligned && iBusRsp.inputPipeline(0).payload(1)) + fetchPc.predictionPcLoad.valid := line.branchWish.msb && hit && !hazard && iBusRsp.stages(1).output.valid //XXX && !(!line.unaligned && iBusRsp.inputPipeline(0).payload(1)) fetchPc.predictionPcLoad.payload := line.target case class PredictionResult() extends Bundle{ @@ -605,7 +601,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, when(decompressor.input.fire){ decompressorFailure := decompressorContext.hit && !decompressorContext.hazard && !decompressor.output.valid && decompressorContext.line.branchWish(1) } - decompressorFailure clearWhen(flush || decompressor.output.fire) + decompressorFailure clearWhen(fetcherflushIt || decompressor.output.fire) val injectorFailure = Delay(decompressorFailure, cycleCount=if(injectorStage) 1 else 0, when=injector.decodeInput.ready) diff --git a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala index a9dd8894..4b75d65b 100644 --- a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala @@ -151,7 +151,7 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l, stages(0).halt setWhen (cache.io.cpu.prefetch.haltIt) - cache.io.cpu.fetch.isRemoved := flush + cache.io.cpu.fetch.isRemoved := fetcherflushIt } diff --git a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala index 688dce52..bf7930d4 100644 --- a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala @@ -284,7 +284,7 @@ class IBusSimplePlugin(resetVector : BigInt, mmuBus.cmd.isValid := cmdForkStage.input.valid mmuBus.cmd.virtualAddress := cmdForkStage.input.payload mmuBus.cmd.bypassTranslation := False - mmuBus.end := cmdForkStage.output.fire || flush + mmuBus.end := cmdForkStage.output.fire || fetcherflushIt cmd.pc := mmuBus.rsp.physicalAddress(31 downto 2) @@ "00" @@ -311,7 +311,7 @@ class IBusSimplePlugin(resetVector : BigInt, //Manage flush for iBus transactions in flight val discardCounter = Reg(UInt(log2Up(pendingMax + 1) bits)) init (0) discardCounter := discardCounter - (iBus.rsp.fire && discardCounter =/= 0).asUInt - when(flush) { + when(fetcherflushIt) { if(secondStagePersistence) discardCounter := pendingCmd + cmd.valid.asUInt - iBus.rsp.fire.asUInt else @@ -323,7 +323,7 @@ class IBusSimplePlugin(resetVector : BigInt, val rspBuffer = if(!rspHoldValue) new Area{ val c = StreamFifoLowLatency(IBusSimpleRsp(), busLatencyMin + (if(cmdForkOnSecondStage && cmdForkPersistence) 1 else 0)) c.io.push << iBus.rsp.throwWhen(discardCounter =/= 0).toStream - c.io.flush := flush + c.io.flush := fetcherflushIt rspBufferOutput << c.io.pop } else new Area{ val rspStream = iBus.rsp.throwWhen(discardCounter =/= 0).toStream From 21c8933bbbdb31be2f96d03593f63154dfbf3634 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Tue, 11 Jun 2019 00:12:29 +0200 Subject: [PATCH 214/951] Fix DYNAMIC_TARGET prediction correction in BranchPlugin --- src/main/scala/vexriscv/plugin/BranchPlugin.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/plugin/BranchPlugin.scala b/src/main/scala/vexriscv/plugin/BranchPlugin.scala index 281063b9..cf740ca3 100644 --- a/src/main/scala/vexriscv/plugin/BranchPlugin.scala +++ b/src/main/scala/vexriscv/plugin/BranchPlugin.scala @@ -345,7 +345,7 @@ class BranchPlugin(earlyBranch : Boolean, val branchAdder = branch_src1 + branch_src2 insert(BRANCH_CALC) := branchAdder(31 downto 1) @@ "0" insert(NEXT_PC) := input(PC) + (if(pipeline(RVC_GEN)) ((input(IS_RVC)) ? U(2) | U(4)) else 4) - insert(TARGET_MISSMATCH) := decode.input(PC) =/= input(BRANCH_CALC) + insert(TARGET_MISSMATCH) := input(PC) =/= input(BRANCH_CALC) } //Apply branchs (JAL,JALR, Bxx) From 066ddc23e6eb67eeec824c640af6b18f70c3fab6 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Tue, 11 Jun 2019 00:22:38 +0200 Subject: [PATCH 215/951] Add regression concurrent os executions flag to avoid running debug plugin tests --- src/test/cpp/regression/main.cpp | 2 ++ src/test/cpp/regression/makefile | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 2730c464..1714946e 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -3847,7 +3847,9 @@ int main(int argc, char **argv, char **env) { #endif #ifdef DEBUG_PLUGIN + #ifndef CONCURRENT_OS_EXECUTIONS redo(REDO,DebugPluginTest().run(1e6);); + #endif #endif #endif diff --git a/src/test/cpp/regression/makefile b/src/test/cpp/regression/makefile index a657f1c2..76d43dce 100644 --- a/src/test/cpp/regression/makefile +++ b/src/test/cpp/regression/makefile @@ -51,7 +51,9 @@ else ADDCFLAGS += -CFLAGS -O3 -O3 endif - +ifeq ($(CONCURRENT_OS_EXECUTIONS),yes) + ADDCFLAGS += -CCONCURRENT_OS_EXECUTIONS +endif ifeq ($(LITEX),yes) ADDCFLAGS += -CFLAGS -DLITEX From afbf0ea777c9d1194c05abc4d7c984ce452d827d Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Tue, 11 Jun 2019 01:05:49 +0200 Subject: [PATCH 216/951] Fix regression makefile --- src/test/cpp/regression/makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/cpp/regression/makefile b/src/test/cpp/regression/makefile index 76d43dce..59af8af8 100644 --- a/src/test/cpp/regression/makefile +++ b/src/test/cpp/regression/makefile @@ -52,7 +52,7 @@ else endif ifeq ($(CONCURRENT_OS_EXECUTIONS),yes) - ADDCFLAGS += -CCONCURRENT_OS_EXECUTIONS + ADDCFLAGS += -CFLAGS -DCONCURRENT_OS_EXECUTIONS endif ifeq ($(LITEX),yes) From 21ec368927b8ccf81d5ddd2a2aa9a1d9dae6ad9c Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Tue, 11 Jun 2019 19:56:33 +0200 Subject: [PATCH 217/951] Fix DYNAMIC_TARGET by fixing decode PC updates --- src/main/scala/vexriscv/plugin/BranchPlugin.scala | 2 +- src/main/scala/vexriscv/plugin/Fetcher.scala | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/BranchPlugin.scala b/src/main/scala/vexriscv/plugin/BranchPlugin.scala index cf740ca3..281063b9 100644 --- a/src/main/scala/vexriscv/plugin/BranchPlugin.scala +++ b/src/main/scala/vexriscv/plugin/BranchPlugin.scala @@ -345,7 +345,7 @@ class BranchPlugin(earlyBranch : Boolean, val branchAdder = branch_src1 + branch_src2 insert(BRANCH_CALC) := branchAdder(31 downto 1) @@ "0" insert(NEXT_PC) := input(PC) + (if(pipeline(RVC_GEN)) ((input(IS_RVC)) ? U(2) | U(4)) else 4) - insert(TARGET_MISSMATCH) := input(PC) =/= input(BRANCH_CALC) + insert(TARGET_MISSMATCH) := decode.input(PC) =/= input(BRANCH_CALC) } //Apply branchs (JAL,JALR, Bxx) diff --git a/src/main/scala/vexriscv/plugin/Fetcher.scala b/src/main/scala/vexriscv/plugin/Fetcher.scala index 26e91c1e..a7ab2680 100644 --- a/src/main/scala/vexriscv/plugin/Fetcher.scala +++ b/src/main/scala/vexriscv/plugin/Fetcher.scala @@ -185,7 +185,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, } //application of the selected jump request - when(jump.pcLoad.valid && (!decode.arbitration.isValid || !decode.arbitration.isStuck || decode.arbitration.isRemoved)) { + when(jump.pcLoad.valid && (!decode.arbitration.isStuck || decode.arbitration.isRemoved)) { pcReg := jump.pcLoad.payload } }) From c8ab99cd0bcee318d0d0acdfb2742476ee43ee86 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Wed, 12 Jun 2019 00:00:38 +0200 Subject: [PATCH 218/951] Cleaning and remove BlockQ regression --- src/test/cpp/regression/main.cpp | 22 ++++++---- .../vexriscv/TestIndividualFeatures.scala | 41 +------------------ 2 files changed, 14 insertions(+), 49 deletions(-) diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 1714946e..421a4335 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -3443,7 +3443,7 @@ string freeRtosTests[] = { // "test1","test1","test1","test1","test1","test1","test1","test1" "AltQTest", "AltBlock", "AltPollQ", "blocktim", "countsem", "dead", "EventGroupsDemo", "flop", "integer", "QPeek", - "QueueSet", "recmutex", "semtest", "TaskNotify", "BlockQ", "crhook", "dynamic", + "QueueSet", "recmutex", "semtest", "TaskNotify", "crhook", "dynamic", "GenQTest", "PollQ", "QueueOverwrite", "QueueSetPolling", "sp_flop", "test1" //"BlockQ","BlockQ","BlockQ","BlockQ","BlockQ","BlockQ","BlockQ","BlockQ" // "flop" @@ -3625,14 +3625,18 @@ static void multiThreading(queue> *lambdas, std::mutex *mu static void multiThreadedExecute(queue> &lambdas){ - std::mutex mutex; - std::thread * t[THREAD_COUNT]; - for(int id = 0;id < THREAD_COUNT;id++){ - t[id] = new thread(multiThreading,&lambdas,&mutex); - } - for(int id = 0;id < THREAD_COUNT;id++){ - t[id]->join(); - delete t[id]; + std::mutex mutex; + if(THREAD_COUNT == 1){ + multiThreading(&lambdas, &mutex); + } else { + std::thread * t[THREAD_COUNT]; + for(int id = 0;id < THREAD_COUNT;id++){ + t[id] = new thread(multiThreading,&lambdas,&mutex); + } + for(int id = 0;id < THREAD_COUNT;id++){ + t[id]->join(); + delete t[id]; + } } } diff --git a/src/test/scala/vexriscv/TestIndividualFeatures.scala b/src/test/scala/vexriscv/TestIndividualFeatures.scala index 93353f05..e397a670 100644 --- a/src/test/scala/vexriscv/TestIndividualFeatures.scala +++ b/src/test/scala/vexriscv/TestIndividualFeatures.scala @@ -561,17 +561,7 @@ class TestIndividualFeatures extends FunSuite { new MmuDimension ) - -// def genDefaultsPositions(dims : Seq[VexRiscvDimension], stack : List[VexRiscvPosition] = Nil) : Seq[List[VexRiscvPosition]] = dims match { -// case head :: tail => head.default.flatMap(p => genDefaultsPositions(tail, p :: stack)) -// case Nil => List(stack) -// } - -// val usedPositions = mutable.HashSet[VexRiscvPosition](); -// val positionsCount = dimensions.map(d => d.positions.length).sum - def doTest(positionsToApply : List[VexRiscvPosition], prefix : String = "", testSeed : Int, universes : mutable.HashSet[VexRiscvUniverse]): Unit ={ -// usedPositions ++= positionsToApply val noMemory = universes.contains(VexRiscvUniverse.NO_MEMORY) val noWriteback = universes.contains(VexRiscvUniverse.NO_WRITEBACK) def gen = { @@ -606,8 +596,6 @@ class TestIndividualFeatures extends FunSuite { } } -// dimensions.foreach(d => d.positions.foreach(p => p.dimension = d)) - val testId : Option[mutable.HashSet[Int]] = None val seed = sys.env.getOrElse("VEXRISCV_REGRESSION_SEED", Random.nextLong().toString).toLong @@ -655,31 +643,4 @@ class TestIndividualFeatures extends FunSuite { doTest(positions," random_" + i + "_", testSeed, universe) Hack.dCounter += 1 } - -// println(s"${usedPositions.size}/$positionsCount positions") - -// for (dimension <- dimensions) { -// for (position <- dimension.positions/* if position.name.contains("Cached")*/) { -// for(defaults <- genDefaultsPositions(dimensions.filter(_ != dimension))){ -// doTest(position :: defaults) -// } -// } -// } -} - - - -/* -val seed = -2412372746600605141l - -129 -FAIL AltQTest_rv32i_O3 -FAIL AltQTest_rv32ic_O3 -FAIL GenQTest_rv32i_O0 - -134 -FAIL AltQTest_rv32i_O3 - - val seed = 4331444545509090137l -1 => flops i O0 - */ \ No newline at end of file +} \ No newline at end of file From d603de1bfe0d3b05bbff80e8b9cdf5f93c7626af Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Thu, 13 Jun 2019 16:55:24 +0200 Subject: [PATCH 219/951] Fix recent changes --- .../scala/vexriscv/plugin/BranchPlugin.scala | 15 +---- src/main/scala/vexriscv/plugin/Fetcher.scala | 55 +++++++------------ .../vexriscv/plugin/IBusCachedPlugin.scala | 16 ++++-- 3 files changed, 33 insertions(+), 53 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/BranchPlugin.scala b/src/main/scala/vexriscv/plugin/BranchPlugin.scala index 281063b9..6559a7f8 100644 --- a/src/main/scala/vexriscv/plugin/BranchPlugin.scala +++ b/src/main/scala/vexriscv/plugin/BranchPlugin.scala @@ -204,10 +204,7 @@ class BranchPlugin(earlyBranch : Boolean, import branchStage._ jumpInterface.valid := arbitration.isValid && input(BRANCH_DO) && !hasHazardOnBranch jumpInterface.payload := input(BRANCH_CALC) - - when(jumpInterface.valid && !arbitration.isStuckByOthers) { - arbitration.flushNext := True - } + arbitration.flushNext setWhen(jumpInterface.valid) if(catchAddressMisalignedForReal) { branchExceptionPort.valid := arbitration.isValid && input(BRANCH_DO) && jumpInterface.payload(1) @@ -286,10 +283,7 @@ class BranchPlugin(earlyBranch : Boolean, import branchStage._ jumpInterface.valid := arbitration.isValid && input(BRANCH_DO) && !hasHazardOnBranch jumpInterface.payload := input(BRANCH_CALC) - - when(jumpInterface.valid && !arbitration.isStuckByOthers) { - arbitration.flushNext := True - } + arbitration.flushNext setWhen(jumpInterface.valid) if(catchAddressMisalignedForReal) { val unalignedJump = input(BRANCH_DO) && input(BRANCH_CALC)(1) @@ -365,12 +359,9 @@ class BranchPlugin(earlyBranch : Boolean, jumpInterface.valid := arbitration.isValid && predictionMissmatch && !hasHazardOnBranch jumpInterface.payload := (input(BRANCH_DO) ? input(BRANCH_CALC) | input(NEXT_PC)) + arbitration.flushNext setWhen(jumpInterface.valid) - when(jumpInterface.valid && !arbitration.isStuckByOthers) { - arbitration.flushNext := True - } - if(catchAddressMisalignedForReal) { branchExceptionPort.valid := arbitration.isValid && input(BRANCH_DO) && input(BRANCH_CALC)(1) branchExceptionPort.code := 0 diff --git a/src/main/scala/vexriscv/plugin/Fetcher.scala b/src/main/scala/vexriscv/plugin/Fetcher.scala index a7ab2680..5b9c3ac5 100644 --- a/src/main/scala/vexriscv/plugin/Fetcher.scala +++ b/src/main/scala/vexriscv/plugin/Fetcher.scala @@ -105,62 +105,45 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, fetcherflushIt setWhen(stages.map(_.arbitration.flushNext).orR) - class PcFetch extends Area{ - val preOutput = Stream(UInt(32 bits)) - val output = preOutput.haltWhen(fetcherHalt) - val predictionPcLoad = ifGen(prediction == DYNAMIC_TARGET) (Flow(UInt(32 bits))) - } - - val fetchPc = new PcFetch{ + //The fetchPC pcReg can also be use for the second stage of the fetch + //When the fetcherHalt is set and the pipeline isn't stalled,, the pc is propagated to to the pcReg, which allow + //using the pc pipeline to get the next PC value for interrupts + val fetchPc = new Area{ //PC calculation without Jump + val output = Stream(UInt(32 bits)) val pcReg = Reg(UInt(32 bits)) init(if(resetVector != null) resetVector else externalResetVector) addAttribute(Verilator.public) - val inc = RegInit(False) - val propagatePc = False - + val corrected = False + val pcRegPropagate = False + val booted = RegNext(True) init (False) + val inc = RegInit(False) clearWhen(corrected || pcRegPropagate) setWhen(output.fire) clearWhen(!output.valid && output.ready) val pc = pcReg + (inc ## B"00").asUInt - val samplePcNext = False + val predictionPcLoad = ifGen(prediction == DYNAMIC_TARGET) (Flow(UInt(32 bits))) - if(compressedGen) { - when(inc) { - pc(1) := False - } - } - - when(propagatePc){ - samplePcNext := True - inc := False + if(compressedGen) when(inc) { + pc(1) := False } if(predictionPcLoad != null) { when(predictionPcLoad.valid) { - inc := False - samplePcNext := True + corrected := True pc := predictionPcLoad.payload } } when(jump.pcLoad.valid) { - inc := False - samplePcNext := True + corrected := True pc := jump.pcLoad.payload } - when(preOutput.fire){ - inc := True - samplePcNext := True - } - - - when(samplePcNext) { + when(booted && (output.ready || fetcherflushIt || pcRegPropagate)){ pcReg := pc } pc(0) := False if(!pipeline(RVC_GEN)) pc(1) := False - preOutput.valid := RegNext(True) init (False) - preOutput.payload := pc - + output.valid := !fetcherHalt && booted + output.payload := pc } val decodePc = ifGen(decodePcGen)(new Area { @@ -225,10 +208,10 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, } for((s,sNext) <- (stages, stages.tail).zipped) { - if(s == stages.head && pcRegReusedForSecondStage && prediction != DYNAMIC_TARGET) { //DYNAMIC_TARGET realy need PC state for both stage(0) and stage(1) + if(s == stages.head && pcRegReusedForSecondStage) { sNext.input.arbitrationFrom(s.output.toEvent().m2sPipeWithFlush(fetcherflushIt, s != stages.head, collapsBubble = false)) sNext.input.payload := fetchPc.pcReg - fetchPc.propagatePc setWhen(sNext.input.fire) + fetchPc.pcRegPropagate setWhen(sNext.input.ready) } else { sNext.input << s.output.m2sPipeWithFlush(fetcherflushIt, s != stages.head, collapsBubble = false) } diff --git a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala index 4b75d65b..9b949267 100644 --- a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala @@ -231,14 +231,20 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l, decodeExceptionPort.code := 1 } - redoFetch clearWhen(!iBusRsp.readyForError) - cache.io.cpu.fill.valid clearWhen(!iBusRsp.readyForError) + when(!iBusRsp.readyForError){ + redoFetch := False + cache.io.cpu.fill.valid := False + } +// when(pipeline.stages.map(_.arbitration.flushIt).orR){ +// cache.io.cpu.fill.valid := False +// } + + redoBranch.valid := redoFetch redoBranch.payload := (if (decodePcGen) decode.input(PC) else cacheRsp.pc) - when(redoBranch.valid) { - decode.arbitration.flushNext := True - } + decode.arbitration.flushNext setWhen(redoBranch.valid) + cacheRspArbitration.halt setWhen (issueDetected || iBusRspOutputHalt) iBusRsp.output.valid := cacheRspArbitration.output.valid From 617f4742cd2936f9e1cf988257fcaa7ec9ddc509 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Fri, 14 Jun 2019 08:13:22 +0200 Subject: [PATCH 220/951] Fix dynamic branch prediction correction on misspredicted fetch which are done on a 32 bits instruction crossing two words in configs which have at least 2 cycle latency fetch --- .../vexriscv/plugin/DecoderSimplePlugin.scala | 48 +++++++++++++------ src/main/scala/vexriscv/plugin/Fetcher.scala | 1 + .../vexriscv/TestIndividualFeatures.scala | 4 +- 3 files changed, 37 insertions(+), 16 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/DecoderSimplePlugin.scala b/src/main/scala/vexriscv/plugin/DecoderSimplePlugin.scala index 22afa269..a1076e76 100644 --- a/src/main/scala/vexriscv/plugin/DecoderSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/DecoderSimplePlugin.scala @@ -28,7 +28,7 @@ case class Masked(value : BigInt,care : BigInt){ def mergeOneBitDifSmaller(x: Masked) = { val bit = value - x.value val ret = new Masked(value &~ bit, care & ~bit) -// ret.isPrime = isPrime || x.isPrime + // ret.isPrime = isPrime || x.isPrime isPrime = false x.isPrime = false ret @@ -44,7 +44,10 @@ case class Masked(value : BigInt,care : BigInt){ def toString(bitCount : Int) = (0 until bitCount).map(i => if(care.testBit(i)) (if(value.testBit(i)) "1" else "0") else "-").reverseIterator.reduce(_+_) } -class DecoderSimplePlugin(catchIllegalInstruction : Boolean = false, forceLegalInstructionComputation : Boolean = false) extends Plugin[VexRiscv] with DecoderService { +class DecoderSimplePlugin(catchIllegalInstruction : Boolean = false, + throwIllegalInstruction : Boolean = false, + assertIllegalInstruction : Boolean = false, + forceLegalInstructionComputation : Boolean = false) extends Plugin[VexRiscv] with DecoderService { override def add(encoding: Seq[(MaskedLiteral, Seq[(Stageable[_ <: BaseType], Any)])]): Unit = encoding.foreach(e => this.add(e._1,e._2)) override def add(key: MaskedLiteral, values: Seq[(Stageable[_ <: BaseType], Any)]): Unit = { val instructionModel = encodings.getOrElseUpdate(key,ArrayBuffer[(Stageable[_ <: BaseType], BaseType)]()) @@ -78,6 +81,10 @@ class DecoderSimplePlugin(catchIllegalInstruction : Boolean = false, forceLegalI } } + val detectLegalInstructions = catchIllegalInstruction || throwIllegalInstruction || forceLegalInstructionComputation || assertIllegalInstruction + + object ASSERT_ERROR extends Stageable(Bool) + override def build(pipeline: VexRiscv): Unit = { import pipeline.config._ import pipeline.decode._ @@ -86,7 +93,7 @@ class DecoderSimplePlugin(catchIllegalInstruction : Boolean = false, forceLegalI val stupidDecoder = false if(stupidDecoder){ - if (catchIllegalInstruction || forceLegalInstructionComputation) insert(LEGAL_INSTRUCTION) := False + if (detectLegalInstructions) insert(LEGAL_INSTRUCTION) := False for(stageable <- stageables){ if(defaults.contains(stageable)){ insert(stageable).assignFrom(defaults(stageable)) @@ -96,7 +103,7 @@ class DecoderSimplePlugin(catchIllegalInstruction : Boolean = false, forceLegalI } for((key, tasks) <- encodings){ when(input(INSTRUCTION) === key){ - if (catchIllegalInstruction || forceLegalInstructionComputation) insert(LEGAL_INSTRUCTION) := True + if (detectLegalInstructions) insert(LEGAL_INSTRUCTION) := True for((stageable, value) <- tasks){ insert(stageable).assignFrom(value) } @@ -145,8 +152,15 @@ class DecoderSimplePlugin(catchIllegalInstruction : Boolean = false, forceLegalI // logic implementation val decodedBits = Bits(stageables.foldLeft(0)(_ + _.dataType.getBitsWidth) bits) decodedBits := Symplify(input(INSTRUCTION), spec, decodedBits.getWidth) - if (catchIllegalInstruction || forceLegalInstructionComputation) insert(LEGAL_INSTRUCTION) := Symplify.logicOf(input(INSTRUCTION), SymplifyBit.getPrimeImplicantsByTrueAndDontCare(spec.unzip._1.toSeq, Nil, 32)) - + if (detectLegalInstructions) insert(LEGAL_INSTRUCTION) := Symplify.logicOf(input(INSTRUCTION), SymplifyBit.getPrimeImplicantsByTrueAndDontCare(spec.unzip._1.toSeq, Nil, 32)) + if (throwIllegalInstruction) { + input(LEGAL_INSTRUCTION) //Fill the request for later (prePopTask) + Component.current.addPrePopTask(() => arbitration.isValid clearWhen(!input(LEGAL_INSTRUCTION))) + } + if(assertIllegalInstruction){ + val reg = RegInit(False) setWhen(arbitration.isValid) clearWhen(arbitration.isRemoved || !arbitration.isStuck) + insert(ASSERT_ERROR) := arbitration.isValid || reg + } //Unpack decodedBits and insert fields in the pipeline offset = 0 @@ -162,6 +176,10 @@ class DecoderSimplePlugin(catchIllegalInstruction : Boolean = false, forceLegalI decodeExceptionPort.code := 2 decodeExceptionPort.badAddr := input(INSTRUCTION).asUInt } + if(assertIllegalInstruction){ + pipeline.stages.tail.foreach(s => s.output(ASSERT_ERROR) clearWhen(s.arbitration.isRemoved)) + assert(!pipeline.stages.last.output(ASSERT_ERROR)) + } } def bench(toplevel : VexRiscv): Unit ={ @@ -176,7 +194,7 @@ class DecoderSimplePlugin(catchIllegalInstruction : Boolean = false, forceLegalI val stageables = encodings.flatMap(_._2.map(_._1)).toSet stageables.foreach(e => out(RegNext(RegNext(toplevel.decode.insert(e)).setName(e.getName())))) if(catchIllegalInstruction) out(RegNext(RegNext(toplevel.decode.insert(LEGAL_INSTRUCTION)).setName(LEGAL_INSTRUCTION.getName()))) - // toplevel.getAdditionalNodesRoot.clear() + // toplevel.getAdditionalNodesRoot.clear() } } } @@ -345,14 +363,14 @@ object SymplifyBit{ def main(args: Array[String]) { { -// val default = Masked(0, 0xF) -// val primeImplicants = List(4, 8, 10, 11, 12, 15).map(v => Masked(v, 0xF)) -// val dcImplicants = List(9, 14).map(v => Masked(v, 0xF).setPrime(false)) -// val reducedPrimeImplicants = getPrimeImplicantsByTrueAndDontCare(primeImplicants, dcImplicants, 4) -// println("UUT") -// println(reducedPrimeImplicants.map(_.toString(4)).mkString("\n")) -// println("REF") -// println("-100\n10--\n1--0\n1-1-") + // val default = Masked(0, 0xF) + // val primeImplicants = List(4, 8, 10, 11, 12, 15).map(v => Masked(v, 0xF)) + // val dcImplicants = List(9, 14).map(v => Masked(v, 0xF).setPrime(false)) + // val reducedPrimeImplicants = getPrimeImplicantsByTrueAndDontCare(primeImplicants, dcImplicants, 4) + // println("UUT") + // println(reducedPrimeImplicants.map(_.toString(4)).mkString("\n")) + // println("REF") + // println("-100\n10--\n1--0\n1-1-") } { diff --git a/src/main/scala/vexriscv/plugin/Fetcher.scala b/src/main/scala/vexriscv/plugin/Fetcher.scala index 5b9c3ac5..5df80e72 100644 --- a/src/main/scala/vexriscv/plugin/Fetcher.scala +++ b/src/main/scala/vexriscv/plugin/Fetcher.scala @@ -596,6 +596,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, historyWrite.data.branchWish := 0 decode.arbitration.isValid := False + decode.arbitration.flushNext := True dynamicTargetFailureCorrection.valid := True } }) diff --git a/src/test/scala/vexriscv/TestIndividualFeatures.scala b/src/test/scala/vexriscv/TestIndividualFeatures.scala index e397a670..1c741ad3 100644 --- a/src/test/scala/vexriscv/TestIndividualFeatures.scala +++ b/src/test/scala/vexriscv/TestIndividualFeatures.scala @@ -514,7 +514,8 @@ class DecoderDimension extends VexRiscvDimension("Decoder") { val catchAll = universes.contains(VexRiscvUniverse.CATCH_ALL) new VexRiscvPosition("") { override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new DecoderSimplePlugin( - catchIllegalInstruction = catchAll + catchIllegalInstruction = catchAll, + throwIllegalInstruction = false ) // override def isCompatibleWith(positions: Seq[ConfigPosition[VexRiscvConfig]]) = catchAll == positions.exists(_.isInstanceOf[CatchAllPosition]) @@ -587,6 +588,7 @@ class TestIndividualFeatures extends FunSuite { test(prefix + name + "_test") { + println("START TEST " + prefix + name) val debug = true val stdCmd = (s"make clean run WITH_USER_IO=no REDO=10 TRACE=${if(debug) "yes" else "no"} TRACE_START=9999924910246l STOP_ON_ERROR=no FLOW_INFO=no STOP_ON_ERROR=no DHRYSTONE=yes COREMARK=${sys.env.getOrElse("VEXRISCV_REGRESSION_COREMARK", "yes")} THREAD_COUNT=${sys.env.getOrElse("VEXRISCV_REGRESSION_THREAD_COUNT", 1)} ") + s" SEED=${testSeed} " val testCmd = stdCmd + (positionsToApply).map(_.testParam).mkString(" ") From a3a0c402bc346b3d144f3c56551a9eab15b097d6 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Sat, 15 Jun 2019 10:46:10 +0200 Subject: [PATCH 221/951] Remove broken freertos test and add zephyr instead --- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 1 + src/test/scala/vexriscv/TestIndividualFeatures.scala | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 6c3e4a39..5c7e0326 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -74,6 +74,7 @@ case class CsrPluginConfig( assert(!ucycleAccess.canWrite) def privilegeGen = userGen || supervisorGen def noException = this.copy(ecallGen = false, ebreakGen = false, catchIllegalAccess = false) + def noExceptionButEcall = this.copy(ecallGen = true, ebreakGen = false, catchIllegalAccess = false) } object CsrPluginConfig{ diff --git a/src/test/scala/vexriscv/TestIndividualFeatures.scala b/src/test/scala/vexriscv/TestIndividualFeatures.scala index 1c741ad3..33e4aa6e 100644 --- a/src/test/scala/vexriscv/TestIndividualFeatures.scala +++ b/src/test/scala/vexriscv/TestIndividualFeatures.scala @@ -483,8 +483,8 @@ class CsrDimension(freertos : String, zephyr : String) extends VexRiscvDimension } } else if(r.nextDouble() < 0.3){ new VexRiscvPosition("AllNoException") with CatchAllPosition{ - override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new CsrPlugin(CsrPluginConfig.all(0x80000020l).noException) - override def testParam = s"CSR=yes CSR_SKIP_TEST=yes FREERTOS=$freertos" + override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new CsrPlugin(CsrPluginConfig.all(0x80000020l).noExceptionButEcall) + override def testParam = s"CSR=yes CSR_SKIP_TEST=yes FREERTOS=$freertos ZEPHYR=$zephyr" } } else { new VexRiscvPosition("None") { @@ -556,7 +556,7 @@ class TestIndividualFeatures extends FunSuite { new HazardDimension, new RegFileDimension, new SrcDimension, - new CsrDimension(sys.env.getOrElse("VEXRISCV_REGRESSION_FREERTOS_COUNT", "1"), sys.env.getOrElse("VEXRISCV_REGRESSION_ZEPHYR_COUNT", "4")), + new CsrDimension(/*sys.env.getOrElse("VEXRISCV_REGRESSION_FREERTOS_COUNT", "1")*/ "0", sys.env.getOrElse("VEXRISCV_REGRESSION_ZEPHYR_COUNT", "4")), //Freertos old port software is broken new DecoderDimension, new DebugDimension, new MmuDimension From 7c3c4e8c8126afe3b957a7779223fa8cdfcd660e Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Sat, 15 Jun 2019 14:23:09 +0200 Subject: [PATCH 222/951] Update readme benches --- README.md | 84 +++++++++++++++++++++++++++---------------------------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index 3fbfef08..6ed4a4fc 100644 --- a/README.md +++ b/README.md @@ -66,53 +66,53 @@ The CPU configurations used below can be found in the `src/scala/vexriscv/demo` ``` VexRiscv smallest (RV32I, 0.52 DMIPS/Mhz, no datapath bypass, no interrupt) -> - Artix 7 -> 366 Mhz 488 LUT 505 FF - Cyclone V -> 181 Mhz 350 ALMs - Cyclone IV -> 177 Mhz 732 LUT 494 FF - iCE40 -> 85 Mhz 1131 LC + Artix 7 -> 324 Mhz 496 LUT 505 FF + Cyclone V -> 193 Mhz 347 ALMs + Cyclone IV -> 179 Mhz 730 LUT 494 FF + iCE40 -> 92 Mhz 1130 LC VexRiscv smallest (RV32I, 0.52 DMIPS/Mhz, no datapath bypass) -> - Artix 7 -> 317 Mhz 539 LUT 559 FF - Cyclone V -> 191 Mhz 393 ALMs - Cyclone IV -> 171 Mhz 826 LUT 547 FF - iCE40 -> 72 Mhz 1284 LC + Artix 7 -> 328 Mhz 539 LUT 562 FF + Cyclone V -> 189 Mhz 387 ALMs + Cyclone IV -> 175 Mhz 829 LUT 550 FF + iCE40 -> 85 Mhz 1292 LC VexRiscv small and productive (RV32I, 0.82 DMIPS/Mhz) -> - Artix 7 -> 338 Mhz 697 LUT 527 FF - Cyclone V -> 149 Mhz 495 ALMs - Cyclone IV -> 137 Mhz 1,103 LUT 522 FF - iCE40 -> 65 Mhz 1593 LC + Artix 7 -> 324 Mhz 701 LUT 531 FF + Cyclone V -> 145 Mhz 499 ALMs + Cyclone IV -> 150 Mhz 1,111 LUT 525 FF + iCE40 -> 63 Mhz 1596 LC VexRiscv small and productive with I$ (RV32I, 0.70 DMIPS/Mhz, 4KB-I$) -> - Artix 7 -> 314 Mhz 721 LUT 562 FF - Cyclone V -> 152 Mhz 504 ALMs - Cyclone IV -> 142 Mhz 1,146 LUT 528 FF - iCE40 -> 69 Mhz 1661 LC + Artix 7 -> 336 Mhz 764 LUT 562 FF + Cyclone V -> 145 Mhz 511 ALMs + Cyclone IV -> 144 Mhz 1,145 LUT 531 FF + iCE40 -> 66 Mhz 1680 LC VexRiscv full no cache (RV32IM, 1.21 DMIPS/Mhz 2.30 Coremark/Mhz, single cycle barrel shifter, debug module, catch exceptions, static branch) -> - Artix 7 -> 325 Mhz 1448 LUT 976 FF - Cyclone V -> 141 Mhz 957 ALMs - Cyclone IV -> 139 Mhz 2,001 LUT 966 FF + Artix 7 -> 326 Mhz 1544 LUT 977 FF + Cyclone V -> 139 Mhz 958 ALMs + Cyclone IV -> 135 Mhz 2,011 LUT 968 FF VexRiscv full (RV32IM, 1.21 DMIPS/Mhz 2.30 Coremark/Mhz with cache trashing, 4KB-I$,4KB-D$, single cycle barrel shifter, debug module, catch exceptions, static branch) -> - Artix 7 -> 241 Mhz 1692 LUT 1202 FF - Cyclone V -> 132 Mhz 1,127 ALMs - Cyclone IV -> 124 Mhz 2,296 LUT 1,115 FF + Artix 7 -> 279 Mhz 1686 LUT 1172 FF + Cyclone V -> 144 Mhz 1,128 ALMs + Cyclone IV -> 133 Mhz 2,298 LUT 1,096 FF VexRiscv full max dmips/mhz -> (RV32IM, 1.44 DMIPS/Mhz 2.70 Coremark/Mhz,, 16KB-I$,16KB-D$, single cycle barrel shifter, debug module, catch exceptions, dynamic branch prediction in the fetch stage, branch and shift operations done in the Execute stage) -> - Artix 7 -> 195 Mhz 1824 LUT 1110 FF - Cyclone V -> 83 Mhz 1,067 ALMs - Cyclone IV -> 78 Mhz 2,335 LUT 1,045 FF + Artix 7 -> 195 Mhz 1943 LUT 1111 FF + Cyclone V -> 90 Mhz 1,089 ALMs + Cyclone IV -> 80 Mhz 2,335 LUT 1,048 FF VexRiscv full with MMU (RV32IM, 1.24 DMIPS/Mhz 2.35 Coremark/Mhz, with cache trashing, 4KB-I$, 4KB-D$, single cycle barrel shifter, debug module, catch exceptions, dynamic branch, MMU) -> - Artix 7 -> 218 Mhz 1966 LUT 1551 FF - Cyclone V -> 123 Mhz 1,298 ALMs - Cyclone IV -> 109 Mhz 2,703 LUT 1,498 FF + Artix 7 -> 239 Mhz 2029 LUT 1585 FF + Cyclone V -> 124 Mhz 1,319 ALMs + Cyclone IV -> 122 Mhz 2,710 LUT 1,501 FF VexRiscv linux balanced (RV32IMA, 1.21 DMIPS/Mhz 2.27 Coremark/Mhz, with cache trashing, 4KB-I$, 4KB-D$, single cycle barrel shifter, catch exceptions, static branch, MMU, Supervisor, Compatible with mainstream linux) -> - Artix 7 -> 239 Mhz 2483 LUT 2134 FF - Cyclone V -> 130 Mhz 1,636 ALMs - Cyclone IV -> 116 Mhz 3,324 LUT 2,010 FF + Artix 7 -> 249 Mhz 2549 LUT 2014 FF + Cyclone V -> 125 Mhz 1,618 ALMs + Cyclone IV -> 116 Mhz 3,314 LUT 2,016 FF ``` @@ -296,9 +296,9 @@ You can find some FPGA projects which instantiate the Briey SoC here (DE1-SoC, D Here are some measurements of Briey SoC timings and area : ``` - Artix 7 -> 232 Mhz 3042 LUT 3281 FF - Cyclone V -> 138 Mhz 2,179 ALMs - Cyclone IV -> 120 Mhz 4,333 LUT 3,167 FF + Artix 7 -> 275 Mhz 3072 LUT 3291 FF + Cyclone V -> 139 Mhz 2,175 ALMs + Cyclone IV -> 129 Mhz 4,337 LUT 3,170 FF ``` ## Murax SoC @@ -351,16 +351,16 @@ Here are some timing and area measurements of the Murax SoC: ``` Murax interlocked stages (0.45 DMIPS/Mhz, 8 bits GPIO) -> - Artix 7 - > 301 Mhz 1032 LUT 1199 FF - Cyclone V -> 183 Mhz 736 ALMs - Cyclone IV -> 148 Mhz 1,481 LUT 1,204 FF - iCE40 -> 69 Mhz 2403 LC (nextpnr) + Artix 7 -> 313 Mhz 1039 LUT 1200 FF + Cyclone V -> 173 Mhz 737 ALMs + Cyclone IV -> 144 Mhz 1,484 LUT 1,206 FF + iCE40 -> 64 Mhz 2422 LC (nextpnr) MuraxFast bypassed stages (0.65 DMIPS/Mhz, 8 bits GPIO) -> - Artix 7 -> 321 Mhz 1198 LUT 1298 FF - Cyclone V -> 165 Mhz 873 ALMs - Cyclone IV -> 145 Mhz 1,691 LUT 1,239 FF - iCE40 -> 61 Mhz 2778 LC (nextpnr) + Artix 7 -> 323 Mhz 1241 LUT 1301 FF + Cyclone V -> 159 Mhz 864 ALMs + Cyclone IV -> 137 Mhz 1,688 LUT 1,241 FF + iCE40 -> 66 Mhz 2799 LC (nextpnr) ``` Some scripts to generate the SoC and call the icestorm toolchain can be found here: `scripts/Murax/` From 4cf7e5b98f5e9802a8077a998297c3e15c35e712 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Sun, 16 Jun 2019 00:42:59 +0200 Subject: [PATCH 223/951] SpinalHDL 1.3.6 --- build.sbt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/build.sbt b/build.sbt index aa017862..a767c35a 100644 --- a/build.sbt +++ b/build.sbt @@ -7,16 +7,16 @@ lazy val root = (project in file(".")). version := "2.0.0" )), libraryDependencies ++= Seq( -// "com.github.spinalhdl" % "spinalhdl-core_2.11" % "1.3.4", -// "com.github.spinalhdl" % "spinalhdl-lib_2.11" % "1.3.4", + "com.github.spinalhdl" % "spinalhdl-core_2.11" % "1.3.6", + "com.github.spinalhdl" % "spinalhdl-lib_2.11" % "1.3.6", "org.scalatest" % "scalatest_2.11" % "2.2.1", "org.yaml" % "snakeyaml" % "1.8" ), name := "VexRiscv" - ).dependsOn(spinalHdlSim,spinalHdlCore,spinalHdlLib) -lazy val spinalHdlSim = ProjectRef(file("../SpinalHDL"), "sim") -lazy val spinalHdlCore = ProjectRef(file("../SpinalHDL"), "core") -lazy val spinalHdlLib = ProjectRef(file("../SpinalHDL"), "lib") + )//.dependsOn(spinalHdlSim,spinalHdlCore,spinalHdlLib) +//lazy val spinalHdlSim = ProjectRef(file("../SpinalHDL"), "sim") +//lazy val spinalHdlCore = ProjectRef(file("../SpinalHDL"), "core") +//lazy val spinalHdlLib = ProjectRef(file("../SpinalHDL"), "lib") fork := true \ No newline at end of file From 965660484861b4024030d970838069f27293231e Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Sun, 16 Jun 2019 17:42:39 +0200 Subject: [PATCH 224/951] rework dynamic_target failure correction --- src/main/scala/vexriscv/plugin/Fetcher.scala | 21 +++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/Fetcher.scala b/src/main/scala/vexriscv/plugin/Fetcher.scala index 5df80e72..8aa351e9 100644 --- a/src/main/scala/vexriscv/plugin/Fetcher.scala +++ b/src/main/scala/vexriscv/plugin/Fetcher.scala @@ -262,9 +262,14 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, }) bufferValid clearWhen(output.fire) + val bufferFill = False when(input.fire){ -// bufferValid := !(!isRvc && !input.pc(1) && !bufferValid) && !(isRvc && input.pc(1) && output.ready) - bufferValid := !(!isRvc && !input.pc(1) && !bufferValid) && !(isRvc && input.pc(1) && output.ready) + when(!(!isRvc && !input.pc(1) && !bufferValid) && !(isRvc && input.pc(1) && output.ready)) { + bufferValid := True + bufferFill := True + } otherwise { + bufferValid := False + } bufferData := input.rsp.inst(31 downto 16) } bufferValid.clearWhen(fetcherflushIt) @@ -580,17 +585,15 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, val predictionFailure = ifGen(compressedGen && cmdToRspStageCount > 1)(new Area{ - val decompressorFailure = RegInit(False) - when(decompressor.input.fire){ - decompressorFailure := decompressorContext.hit && !decompressorContext.hazard && !decompressor.output.valid && decompressorContext.line.branchWish(1) - } - decompressorFailure clearWhen(fetcherflushIt || decompressor.output.fire) - + val predictionBranch = decompressorContext.hit && !decompressorContext.hazard && decompressorContext.line.branchWish(1) + val unalignedWordIssue = decompressor.bufferFill && decompressor.input.rsp.inst(17 downto 16) === 3 && predictionBranch + val decompressorFailure = RegInit(False) setWhen(unalignedWordIssue) clearWhen(fetcherflushIt) val injectorFailure = Delay(decompressorFailure, cycleCount=if(injectorStage) 1 else 0, when=injector.decodeInput.ready) + val bypassFailure = if(!injectorStage) False else decompressorFailure && !injector.decodeInput.valid dynamicTargetFailureCorrection.valid := False dynamicTargetFailureCorrection.payload := decode.input(PC) - when(injector.decodeInput.valid && injectorFailure){ + when(injectorFailure || bypassFailure){ historyWrite.valid := True historyWrite.address := (decode.input(PC) >> 2).resized historyWrite.data.branchWish := 0 From 635ef51f82750bdbb304cec54253d303df72e46f Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Sun, 16 Jun 2019 17:43:07 +0200 Subject: [PATCH 225/951] test only dynamic_target for intensive test --- .../scala/vexriscv/TestIndividualFeatures.scala | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/test/scala/vexriscv/TestIndividualFeatures.scala b/src/test/scala/vexriscv/TestIndividualFeatures.scala index 33e4aa6e..5204927c 100644 --- a/src/test/scala/vexriscv/TestIndividualFeatures.scala +++ b/src/test/scala/vexriscv/TestIndividualFeatures.scala @@ -293,9 +293,9 @@ class IBusDimension extends VexRiscvDimension("IBus") { if(r.nextDouble() < 0.5){ val latency = r.nextInt(5) + 1 - val compressed = r.nextBoolean() + val compressed = true val injectorStage = r.nextBoolean() || latency == 1 - val prediction = random(r, List(NONE, STATIC, DYNAMIC, DYNAMIC_TARGET)) + val prediction = random(r, List(DYNAMIC_TARGET)) val catchAll = universes.contains(VexRiscvUniverse.CATCH_ALL) val cmdForkOnSecondStage = r.nextBoolean() val cmdForkPersistence = r.nextBoolean() @@ -316,10 +316,10 @@ class IBusDimension extends VexRiscvDimension("IBus") { } } else { val catchAll = universes.contains(VexRiscvUniverse.CATCH_ALL) - val compressed = r.nextBoolean() + val compressed = true val tighlyCoupled = r.nextBoolean() && !catchAll // val tighlyCoupled = false - val prediction = random(r, List(NONE, STATIC, DYNAMIC, DYNAMIC_TARGET)) + val prediction = random(r, List(DYNAMIC_TARGET)) val relaxedPcCalculation, twoCycleCache, injectorStage = r.nextBoolean() val twoCycleRam = r.nextBoolean() && twoCycleCache val bytePerLine = List(8,16,32,64)(r.nextInt(4)) @@ -590,7 +590,7 @@ class TestIndividualFeatures extends FunSuite { test(prefix + name + "_test") { println("START TEST " + prefix + name) val debug = true - val stdCmd = (s"make clean run WITH_USER_IO=no REDO=10 TRACE=${if(debug) "yes" else "no"} TRACE_START=9999924910246l STOP_ON_ERROR=no FLOW_INFO=no STOP_ON_ERROR=no DHRYSTONE=yes COREMARK=${sys.env.getOrElse("VEXRISCV_REGRESSION_COREMARK", "yes")} THREAD_COUNT=${sys.env.getOrElse("VEXRISCV_REGRESSION_THREAD_COUNT", 1)} ") + s" SEED=${testSeed} " + val stdCmd = (s"make clean run WITH_USER_IO=no REDO=10 TRACE=${if(debug) "yes" else "no"} TRACE_START=9999924910246l STOP_ON_ERROR=no FLOW_INFO=no DHRYSTONE=yes COREMARK=${sys.env.getOrElse("VEXRISCV_REGRESSION_COREMARK", "yes")} THREAD_COUNT=${sys.env.getOrElse("VEXRISCV_REGRESSION_THREAD_COUNT", 1)} ") + s" SEED=${testSeed} " val testCmd = stdCmd + (positionsToApply).map(_.testParam).mkString(" ") println(testCmd) val str = doCmd(testCmd) @@ -603,8 +603,8 @@ class TestIndividualFeatures extends FunSuite { // val testId = Some(mutable.HashSet(3,4,9,11,13,16,18,19,20,21)) // val testId = Some(mutable.HashSet(24, 43, 49)) -// val testId = Some(mutable.HashSet(11)) -// val seed = -8309068850561113754l +// val testId = Some(mutable.HashSet(55)) +// val seed = 5354442454996442984l val rand = new Random(seed) From 12c3ab16ae5cdfed63d1742e8bf2b6945ab738c0 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Sun, 16 Jun 2019 18:07:04 +0200 Subject: [PATCH 226/951] Update readme perf --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6ed4a4fc..e595cbe1 100644 --- a/README.md +++ b/README.md @@ -100,9 +100,9 @@ VexRiscv full (RV32IM, 1.21 DMIPS/Mhz 2.30 Coremark/Mhz with cache trashing, 4KB Cyclone IV -> 133 Mhz 2,298 LUT 1,096 FF VexRiscv full max dmips/mhz -> (RV32IM, 1.44 DMIPS/Mhz 2.70 Coremark/Mhz,, 16KB-I$,16KB-D$, single cycle barrel shifter, debug module, catch exceptions, dynamic branch prediction in the fetch stage, branch and shift operations done in the Execute stage) -> - Artix 7 -> 195 Mhz 1943 LUT 1111 FF + Artix 7 -> 193 Mhz 1758 LUT 1094 FF Cyclone V -> 90 Mhz 1,089 ALMs - Cyclone IV -> 80 Mhz 2,335 LUT 1,048 FF + Cyclone IV -> 79 Mhz 2,336 LUT 1,048 FF VexRiscv full with MMU (RV32IM, 1.24 DMIPS/Mhz 2.35 Coremark/Mhz, with cache trashing, 4KB-I$, 4KB-D$, single cycle barrel shifter, debug module, catch exceptions, dynamic branch, MMU) -> Artix 7 -> 239 Mhz 2029 LUT 1585 FF From 1257b056dc2e440a69f9fbe6510a7c5b33070cb6 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Sun, 16 Jun 2019 18:24:59 +0200 Subject: [PATCH 227/951] Revert "test only dynamic_target for intensive test" This reverts commit 635ef51f82750bdbb304cec54253d303df72e46f. --- .../scala/vexriscv/TestIndividualFeatures.scala | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/test/scala/vexriscv/TestIndividualFeatures.scala b/src/test/scala/vexriscv/TestIndividualFeatures.scala index 5204927c..33e4aa6e 100644 --- a/src/test/scala/vexriscv/TestIndividualFeatures.scala +++ b/src/test/scala/vexriscv/TestIndividualFeatures.scala @@ -293,9 +293,9 @@ class IBusDimension extends VexRiscvDimension("IBus") { if(r.nextDouble() < 0.5){ val latency = r.nextInt(5) + 1 - val compressed = true + val compressed = r.nextBoolean() val injectorStage = r.nextBoolean() || latency == 1 - val prediction = random(r, List(DYNAMIC_TARGET)) + val prediction = random(r, List(NONE, STATIC, DYNAMIC, DYNAMIC_TARGET)) val catchAll = universes.contains(VexRiscvUniverse.CATCH_ALL) val cmdForkOnSecondStage = r.nextBoolean() val cmdForkPersistence = r.nextBoolean() @@ -316,10 +316,10 @@ class IBusDimension extends VexRiscvDimension("IBus") { } } else { val catchAll = universes.contains(VexRiscvUniverse.CATCH_ALL) - val compressed = true + val compressed = r.nextBoolean() val tighlyCoupled = r.nextBoolean() && !catchAll // val tighlyCoupled = false - val prediction = random(r, List(DYNAMIC_TARGET)) + val prediction = random(r, List(NONE, STATIC, DYNAMIC, DYNAMIC_TARGET)) val relaxedPcCalculation, twoCycleCache, injectorStage = r.nextBoolean() val twoCycleRam = r.nextBoolean() && twoCycleCache val bytePerLine = List(8,16,32,64)(r.nextInt(4)) @@ -590,7 +590,7 @@ class TestIndividualFeatures extends FunSuite { test(prefix + name + "_test") { println("START TEST " + prefix + name) val debug = true - val stdCmd = (s"make clean run WITH_USER_IO=no REDO=10 TRACE=${if(debug) "yes" else "no"} TRACE_START=9999924910246l STOP_ON_ERROR=no FLOW_INFO=no DHRYSTONE=yes COREMARK=${sys.env.getOrElse("VEXRISCV_REGRESSION_COREMARK", "yes")} THREAD_COUNT=${sys.env.getOrElse("VEXRISCV_REGRESSION_THREAD_COUNT", 1)} ") + s" SEED=${testSeed} " + val stdCmd = (s"make clean run WITH_USER_IO=no REDO=10 TRACE=${if(debug) "yes" else "no"} TRACE_START=9999924910246l STOP_ON_ERROR=no FLOW_INFO=no STOP_ON_ERROR=no DHRYSTONE=yes COREMARK=${sys.env.getOrElse("VEXRISCV_REGRESSION_COREMARK", "yes")} THREAD_COUNT=${sys.env.getOrElse("VEXRISCV_REGRESSION_THREAD_COUNT", 1)} ") + s" SEED=${testSeed} " val testCmd = stdCmd + (positionsToApply).map(_.testParam).mkString(" ") println(testCmd) val str = doCmd(testCmd) @@ -603,8 +603,8 @@ class TestIndividualFeatures extends FunSuite { // val testId = Some(mutable.HashSet(3,4,9,11,13,16,18,19,20,21)) // val testId = Some(mutable.HashSet(24, 43, 49)) -// val testId = Some(mutable.HashSet(55)) -// val seed = 5354442454996442984l +// val testId = Some(mutable.HashSet(11)) +// val seed = -8309068850561113754l val rand = new Random(seed) From b2e06ae198dd047f78a01be0ec11227eb60e0ef4 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Mon, 17 Jun 2019 17:19:11 +0200 Subject: [PATCH 228/951] Back into unreleased SpinalHDL --- build.sbt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/build.sbt b/build.sbt index a767c35a..ccb19f17 100644 --- a/build.sbt +++ b/build.sbt @@ -7,16 +7,16 @@ lazy val root = (project in file(".")). version := "2.0.0" )), libraryDependencies ++= Seq( - "com.github.spinalhdl" % "spinalhdl-core_2.11" % "1.3.6", - "com.github.spinalhdl" % "spinalhdl-lib_2.11" % "1.3.6", +// "com.github.spinalhdl" % "spinalhdl-core_2.11" % "1.3.6", +// "com.github.spinalhdl" % "spinalhdl-lib_2.11" % "1.3.6", "org.scalatest" % "scalatest_2.11" % "2.2.1", "org.yaml" % "snakeyaml" % "1.8" ), name := "VexRiscv" - )//.dependsOn(spinalHdlSim,spinalHdlCore,spinalHdlLib) -//lazy val spinalHdlSim = ProjectRef(file("../SpinalHDL"), "sim") -//lazy val spinalHdlCore = ProjectRef(file("../SpinalHDL"), "core") -//lazy val spinalHdlLib = ProjectRef(file("../SpinalHDL"), "lib") + ).dependsOn(spinalHdlSim,spinalHdlCore,spinalHdlLib) +lazy val spinalHdlSim = ProjectRef(file("../SpinalHDL"), "sim") +lazy val spinalHdlCore = ProjectRef(file("../SpinalHDL"), "core") +lazy val spinalHdlLib = ProjectRef(file("../SpinalHDL"), "lib") fork := true \ No newline at end of file From 624c641af50701a1b20f9d569d867968d86458b8 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Fri, 28 Jun 2019 10:23:39 +0200 Subject: [PATCH 229/951] xip refractoring --- src/main/scala/vexriscv/demo/Linux.scala | 7 ++++++- src/main/scala/vexriscv/demo/Murax.scala | 10 ++-------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/main/scala/vexriscv/demo/Linux.scala b/src/main/scala/vexriscv/demo/Linux.scala index 235338a3..906b5b22 100644 --- a/src/main/scala/vexriscv/demo/Linux.scala +++ b/src/main/scala/vexriscv/demo/Linux.scala @@ -119,7 +119,12 @@ make run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD SUPERVISOR=yes CSR=yes COMPRE rm -rf cpio mkdir cpio cd cpio -cpio -idv < ../rootfs.cpio +sudo cpio -i < ../rootfs.cpio +cd .. + +rm rootfs.cpio +cd cpio +sudo find | sudo cpio -H newc -o > ../rootfs.cpio cd .. make clean run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD DHRYSTONE=yes SUPERVISOR=yes MMU=yes CSR=yes COMPRESSED=no MUL=yes DIV=yes LRSC=yes AMO=yes REDO=10 TRACE=no COREMARK=yes LINUX_REGRESSION=yes RUN_HEX=~/pro/riscv/zephyr/samples/synchronization/build/zephyr/zephyr.hex diff --git a/src/main/scala/vexriscv/demo/Murax.scala b/src/main/scala/vexriscv/demo/Murax.scala index d78beeb1..42a3d7ef 100644 --- a/src/main/scala/vexriscv/demo/Murax.scala +++ b/src/main/scala/vexriscv/demo/Murax.scala @@ -65,7 +65,7 @@ object MuraxConfig{ SpiXdrMasterCtrl.Parameters(8, 12, SpiXdrParameter(2, 2, 1)).addFullDuplex(0,1,false), cmdFifoDepth = 32, rspFifoDepth = 32, - xip = SpiXdrMasterCtrl.XipBusParameters(addressWidth = 24, dataWidth = 32) + xip = SpiXdrMasterCtrl.XipBusParameters(addressWidth = 24, lengthWidth = 2) )), hardwareBreakpointCount = if(withXip) 3 else 0, cpuPlugins = ArrayBuffer( //DebugPlugin added by the toplevel @@ -298,13 +298,7 @@ case class Murax(config : MuraxConfig) extends Component{ val accessBus = new PipelinedMemoryBus(PipelinedMemoryBusConfig(24,32)) mainBusMapping += accessBus -> (0xE0000000l, 16 MB) - ctrl.io.xip.cmd.valid <> (accessBus.cmd.valid && !accessBus.cmd.write) - ctrl.io.xip.cmd.ready <> accessBus.cmd.ready - ctrl.io.xip.cmd.payload <> accessBus.cmd.address - - ctrl.io.xip.rsp.valid <> accessBus.rsp.valid - ctrl.io.xip.rsp.payload <> accessBus.rsp.data - + ctrl.io.xip.fromPipelinedMemoryBus() << accessBus val bootloader = Apb3Rom("src/main/c/murax/xipBootloader/crt.bin") apbMapping += bootloader.io.apb -> (0x1E000, 4 kB) }) From a2569e76c0c2af622fa75c914253e44e748a2b65 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Mon, 8 Jul 2019 11:23:48 +0200 Subject: [PATCH 230/951] Update sdram ctrl package --- src/main/scala/vexriscv/demo/Briey.scala | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/scala/vexriscv/demo/Briey.scala b/src/main/scala/vexriscv/demo/Briey.scala index 053abf85..57872a95 100644 --- a/src/main/scala/vexriscv/demo/Briey.scala +++ b/src/main/scala/vexriscv/demo/Briey.scala @@ -14,6 +14,7 @@ import spinal.lib.graphic.RgbConfig import spinal.lib.graphic.vga.{Axi4VgaCtrl, Axi4VgaCtrlGenerics, Vga} import spinal.lib.io.TriStateArray import spinal.lib.memory.sdram._ +import spinal.lib.memory.sdram.sdr.{Axi4SharedSdramCtrl, IS42x320D, SdramInterface, SdramLayout, SdramTimings} import spinal.lib.misc.HexTools import spinal.lib.soc.pinsec.{PinsecTimerCtrl, PinsecTimerCtrlExternal} import spinal.lib.system.debugger.{JtagAxi4SharedDebugger, JtagBridge, SystemDebugger, SystemDebuggerConfig} From 28a11976daa0376db37766f807f5b234cc508dfb Mon Sep 17 00:00:00 2001 From: Mateusz Holenko Date: Wed, 10 Jul 2019 10:38:38 +0200 Subject: [PATCH 231/951] Allow to set custom RAM base address for emulator This is needed when loading the emulator to RAM with an offset. --- src/main/c/common/ram.ld | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/c/common/ram.ld b/src/main/c/common/ram.ld index 19dc3d95..2ebf8587 100755 --- a/src/main/c/common/ram.ld +++ b/src/main/c/common/ram.ld @@ -4,7 +4,7 @@ ENTRY( _start ) MEMORY { - ram : ORIGIN = 0x80000000, LENGTH = 64k + ram : ORIGIN = DEFINED(__ram_origin) ? __ram_origin : 0x80000000, LENGTH = 64k } From 423355ecbff46ef0dddc5e7a48ae10af2a2d1bea Mon Sep 17 00:00:00 2001 From: Mateusz Holenko Date: Wed, 10 Jul 2019 10:38:58 +0200 Subject: [PATCH 232/951] Allow to set custom DTB/OS_CALL addresses Setting those from command line during compilation allows to create a custom setup without the need of modifying the sources. --- src/main/c/emulator/src/config.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/c/emulator/src/config.h b/src/main/c/emulator/src/config.h index 191ae9f0..6e251ade 100644 --- a/src/main/c/emulator/src/config.h +++ b/src/main/c/emulator/src/config.h @@ -3,7 +3,13 @@ //#define QEMU #define SIM + +#ifndef OS_CALL #define OS_CALL 0xC0000000 +#endif + +#ifndef DTB #define DTB 0xC3000000 +#endif #endif From 39c3f408e58bd0eb6b62638071f8de3e2659465b Mon Sep 17 00:00:00 2001 From: Mateusz Holenko Date: Wed, 10 Jul 2019 10:39:47 +0200 Subject: [PATCH 233/951] Create makefile targets Allow to change build target without modifiying the sources. In order to keep compatibilty `sim` target is built by default. --- src/main/c/emulator/makefile | 6 ++++++ src/main/c/emulator/src/config.h | 3 --- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/c/emulator/makefile b/src/main/c/emulator/makefile index e861785c..d9d90987 100755 --- a/src/main/c/emulator/makefile +++ b/src/main/c/emulator/makefile @@ -12,6 +12,12 @@ SRCS = $(wildcard src/*.c) \ LDSCRIPT = ${STANDALONE}/common/ram.ld +sim: CFLAGS += -DSIM +sim: all + +qemu: CFLAGS += -DQEMU +qemu: all + include ${STANDALONE}/common/riscv64-unknown-elf.mk include ${STANDALONE}/common/standalone.mk diff --git a/src/main/c/emulator/src/config.h b/src/main/c/emulator/src/config.h index 6e251ade..afce2d5e 100644 --- a/src/main/c/emulator/src/config.h +++ b/src/main/c/emulator/src/config.h @@ -1,9 +1,6 @@ #ifndef CONFIG_H #define CONFIG_H -//#define QEMU -#define SIM - #ifndef OS_CALL #define OS_CALL 0xC0000000 #endif From 6a2584b840a172f39b6c7882276a25a76874047c Mon Sep 17 00:00:00 2001 From: Mateusz Holenko Date: Wed, 10 Jul 2019 10:39:26 +0200 Subject: [PATCH 234/951] Add `litex` target Use configuration from the `csr.h` file generated dynamically when building a LiteX platform. --- src/main/c/emulator/makefile | 5 +++ src/main/c/emulator/src/hal.c | 71 ++++++++++++++++++++++++++++++++++ src/main/c/emulator/src/main.c | 2 +- 3 files changed, 77 insertions(+), 1 deletion(-) diff --git a/src/main/c/emulator/makefile b/src/main/c/emulator/makefile index d9d90987..7534d083 100755 --- a/src/main/c/emulator/makefile +++ b/src/main/c/emulator/makefile @@ -18,6 +18,11 @@ sim: all qemu: CFLAGS += -DQEMU qemu: all +litex: CFLAGS += -DLITEX -I${LITEX_BASE}/software/include +litex: | check_litex_base all +check_litex_base: + @[ "${LITEX_BASE}" ] || ( echo ">> LITEX_BASE is not set"; exit 1 ) + include ${STANDALONE}/common/riscv64-unknown-elf.mk include ${STANDALONE}/common/standalone.mk diff --git a/src/main/c/emulator/src/hal.c b/src/main/c/emulator/src/hal.c index 52bb0e49..a9189f2e 100644 --- a/src/main/c/emulator/src/hal.c +++ b/src/main/c/emulator/src/hal.c @@ -144,5 +144,76 @@ void halInit(){ #endif +#ifdef LITEX + +// this is copied from LiteX +#define CSR_ACCESSORS_DEFINED +static inline void csr_writeb(uint8_t value, unsigned long addr) +{ + *((volatile uint8_t *)addr) = value; +} + +static inline uint8_t csr_readb(unsigned long addr) +{ + return *(volatile uint8_t *)addr; +} + +static inline void csr_writew(uint16_t value, unsigned long addr) +{ + *((volatile uint16_t *)addr) = value; +} + +static inline uint16_t csr_readw(unsigned long addr) +{ + return *(volatile uint16_t *)addr; +} + +static inline void csr_writel(uint32_t value, unsigned long addr) +{ + *((volatile uint32_t *)addr) = value; +} + +static inline uint32_t csr_readl(unsigned long addr) +{ + return *(volatile uint32_t *)addr; +} + +// this is a file generated by LiteX +#include + +#if !defined(CSR_UART_BASE) || !defined(CSR_CPU_BASE) + #error LiteX configuration with uart and cpu_timer is required. +#endif + +void stopSim(){ + while(1); +} + +void putC(char ch){ + uart_rxtx_write(ch); +} + +int32_t getC(){ + return uart_rxempty_read() + ? -1 + : uart_rxtx_read(); +} + +uint32_t rdtime(){ + return (uint32_t)cpu_timer_time_read(); +} + +uint32_t rdtimeh(){ + return (uint32_t)(cpu_timer_time_read() >> 32); +} + +void setMachineTimerCmp(uint32_t low, uint32_t high){ + cpu_timer_time_cmp_write((((unsigned long long int)high) << 32) | low); +} + +void halInit(){ +} + +#endif diff --git a/src/main/c/emulator/src/main.c b/src/main/c/emulator/src/main.c index 2102818e..dc12fb81 100755 --- a/src/main/c/emulator/src/main.c +++ b/src/main/c/emulator/src/main.c @@ -161,7 +161,7 @@ void trap(){ #ifdef SIM uint32_t instruction = csr_read(mbadaddr); #endif -#ifdef QEMU +#if defined(QEMU) || defined(LITEX) uint32_t instruction = 0; uint32_t i; if (mepc & 2) { From 5085877eed6f965476f832d60c9c55080d8a7f63 Mon Sep 17 00:00:00 2001 From: Mateusz Holenko Date: Wed, 24 Jul 2019 14:55:47 +0200 Subject: [PATCH 235/951] Fix handling LiteX uart and timer. --- src/main/c/emulator/src/hal.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/src/main/c/emulator/src/hal.c b/src/main/c/emulator/src/hal.c index a9189f2e..5a151bb2 100644 --- a/src/main/c/emulator/src/hal.c +++ b/src/main/c/emulator/src/hal.c @@ -190,28 +190,44 @@ void stopSim(){ } void putC(char ch){ + // protect against writing to a full tx fifo + while(uart_txfull_read()); uart_rxtx_write(ch); } int32_t getC(){ - return uart_rxempty_read() - ? -1 - : uart_rxtx_read(); + if(uart_rxempty_read()) + { + return -1; + } + + // this is required to refresh rexempty status + uart_ev_pending_write(1 << 1); + return uart_rxtx_read(); } uint32_t rdtime(){ - return (uint32_t)cpu_timer_time_read(); + cpu_timer_latch_write(0); + uint32_t result = (uint32_t)cpu_timer_time_read(); + cpu_timer_latch_write(1); + return result; } uint32_t rdtimeh(){ - return (uint32_t)(cpu_timer_time_read() >> 32); + cpu_timer_latch_write(0); + uint32_t result = (uint32_t)(cpu_timer_time_read() >> 32); + cpu_timer_latch_write(1); + return result; } void setMachineTimerCmp(uint32_t low, uint32_t high){ + cpu_timer_latch_write(0); cpu_timer_time_cmp_write((((unsigned long long int)high) << 32) | low); + cpu_timer_latch_write(1); } void halInit(){ + cpu_timer_latch_write(1); } #endif From 955e70206c646fc1a19f4605dd3363aa8eeee17e Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Fri, 26 Apr 2019 18:01:35 +0800 Subject: [PATCH 236/951] MmuPlugin: fix generation without writeBack stage If there is no writeBack stage, the elaboration step would hit a NullPointerException when trying to insert into the writeBack stage. Instead, pull from the most recent stage, which is where MMU access should reside. Signed-off-by: Sean Cross --- src/main/scala/vexriscv/plugin/MmuPlugin.scala | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/MmuPlugin.scala b/src/main/scala/vexriscv/plugin/MmuPlugin.scala index ebf46c42..9dedde5d 100644 --- a/src/main/scala/vexriscv/plugin/MmuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/MmuPlugin.scala @@ -250,8 +250,9 @@ class MmuPlugin(ioRange : UInt => Bool, } } - writeBack plug new Area{ - import writeBack._ + val fenceStage = stages.last + fenceStage plug new Area{ + import fenceStage._ when(arbitration.isValid && input(IS_SFENCE_VMA)){ // || csrService.isWriting(CSR.SATP) for(port <- core.ports; line <- port.cache) line.valid := False //Assume that the instruction already fetched into the pipeline are ok } From b0199297fdc1d58793fa18fd0f81af03c6a8252d Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Fri, 26 Apr 2019 18:02:43 +0800 Subject: [PATCH 237/951] caches: work without writeBack stage In the case of an MMU miss, the data caches will create a retry branch port. These currently implicitly go into the memory/writeBack stage, however not all CPUs have this stage. Place the retry branch port into the correct stage. Signed-off-by: Sean Cross --- src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala | 2 +- src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index 78af84f9..b8f2ba11 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -143,7 +143,7 @@ class DBusCachedPlugin(config : DataCacheConfig, decoderService.add(FENCE, Nil) mmuBus = pipeline.service(classOf[MemoryTranslator]).newTranslationPort(MemoryTranslatorPort.PRIORITY_DATA ,memoryTranslatorPortConfig) - redoBranch = pipeline.service(classOf[JumpService]).createJumpInterface(pipeline.writeBack) + redoBranch = pipeline.service(classOf[JumpService]).createJumpInterface(if(pipeline.writeBack != null) pipeline.writeBack else pipeline.execute) if(catchSomething) exceptionBus = pipeline.service(classOf[ExceptionService]).newExceptionPort(pipeline.writeBack) diff --git a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala index aba2e886..8d23548d 100644 --- a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala @@ -309,7 +309,7 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, if(memoryTranslatorPortConfig != null) { mmuBus = pipeline.service(classOf[MemoryTranslator]).newTranslationPort(MemoryTranslatorPort.PRIORITY_DATA, memoryTranslatorPortConfig) - redoBranch = pipeline.service(classOf[JumpService]).createJumpInterface(pipeline.memory) + redoBranch = pipeline.service(classOf[JumpService]).createJumpInterface(if(pipeline.memory != null) pipeline.memory else pipeline.execute) } } From b65ef189eb11bf5b9229ab944da5a73cb595f7be Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Thu, 29 Aug 2019 16:03:20 +0200 Subject: [PATCH 238/951] sync with SpinalHDL SDRAM changes --- src/main/scala/vexriscv/demo/Briey.scala | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/demo/Briey.scala b/src/main/scala/vexriscv/demo/Briey.scala index 57872a95..2bf5947e 100644 --- a/src/main/scala/vexriscv/demo/Briey.scala +++ b/src/main/scala/vexriscv/demo/Briey.scala @@ -13,8 +13,9 @@ import spinal.lib.com.uart.{Apb3UartCtrl, Uart, UartCtrlGenerics, UartCtrlMemory import spinal.lib.graphic.RgbConfig import spinal.lib.graphic.vga.{Axi4VgaCtrl, Axi4VgaCtrlGenerics, Vga} import spinal.lib.io.TriStateArray +import spinal.lib.memory.sdram.SdramGeneration.SDR import spinal.lib.memory.sdram._ -import spinal.lib.memory.sdram.sdr.{Axi4SharedSdramCtrl, IS42x320D, SdramInterface, SdramLayout, SdramTimings} +import spinal.lib.memory.sdram.sdr.{Axi4SharedSdramCtrl, IS42x320D, SdramInterface, SdramTimings} import spinal.lib.misc.HexTools import spinal.lib.soc.pinsec.{PinsecTimerCtrl, PinsecTimerCtrlExternal} import spinal.lib.system.debugger.{JtagAxi4SharedDebugger, JtagBridge, SystemDebugger, SystemDebuggerConfig} @@ -413,6 +414,7 @@ object BrieyDe0Nano{ def main(args: Array[String]) { object IS42x160G { def layout = SdramLayout( + generation = SDR, bankWidth = 2, columnWidth = 9, rowWidth = 13, From c8280a9a88498473cfd0f18fb5e674d494245894 Mon Sep 17 00:00:00 2001 From: Mateusz Holenko Date: Wed, 10 Jul 2019 10:38:38 +0200 Subject: [PATCH 239/951] Allow to set custom RAM base address for emulator This is needed when loading the emulator to RAM with an offset. --- src/main/c/common/ram.ld | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/c/common/ram.ld b/src/main/c/common/ram.ld index 19dc3d95..2ebf8587 100755 --- a/src/main/c/common/ram.ld +++ b/src/main/c/common/ram.ld @@ -4,7 +4,7 @@ ENTRY( _start ) MEMORY { - ram : ORIGIN = 0x80000000, LENGTH = 64k + ram : ORIGIN = DEFINED(__ram_origin) ? __ram_origin : 0x80000000, LENGTH = 64k } From e76435c6c60bf1247d6bb91fe8cf5e57a896da55 Mon Sep 17 00:00:00 2001 From: Mateusz Holenko Date: Wed, 10 Jul 2019 10:38:58 +0200 Subject: [PATCH 240/951] Allow to set custom DTB/OS_CALL addresses Setting those from command line during compilation allows to create a custom setup without the need of modifying the sources. --- src/main/c/emulator/src/config.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/c/emulator/src/config.h b/src/main/c/emulator/src/config.h index 191ae9f0..6e251ade 100644 --- a/src/main/c/emulator/src/config.h +++ b/src/main/c/emulator/src/config.h @@ -3,7 +3,13 @@ //#define QEMU #define SIM + +#ifndef OS_CALL #define OS_CALL 0xC0000000 +#endif + +#ifndef DTB #define DTB 0xC3000000 +#endif #endif From 64a28155440ef286ece6027cf00393b6b7919e47 Mon Sep 17 00:00:00 2001 From: Mateusz Holenko Date: Wed, 10 Jul 2019 10:39:47 +0200 Subject: [PATCH 241/951] Create makefile targets Allow to change build target without modifiying the sources. In order to keep compatibilty `sim` target is built by default. --- src/main/c/emulator/makefile | 6 ++++++ src/main/c/emulator/src/config.h | 3 --- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/c/emulator/makefile b/src/main/c/emulator/makefile index e861785c..d9d90987 100755 --- a/src/main/c/emulator/makefile +++ b/src/main/c/emulator/makefile @@ -12,6 +12,12 @@ SRCS = $(wildcard src/*.c) \ LDSCRIPT = ${STANDALONE}/common/ram.ld +sim: CFLAGS += -DSIM +sim: all + +qemu: CFLAGS += -DQEMU +qemu: all + include ${STANDALONE}/common/riscv64-unknown-elf.mk include ${STANDALONE}/common/standalone.mk diff --git a/src/main/c/emulator/src/config.h b/src/main/c/emulator/src/config.h index 6e251ade..afce2d5e 100644 --- a/src/main/c/emulator/src/config.h +++ b/src/main/c/emulator/src/config.h @@ -1,9 +1,6 @@ #ifndef CONFIG_H #define CONFIG_H -//#define QEMU -#define SIM - #ifndef OS_CALL #define OS_CALL 0xC0000000 #endif From 8813e071bc853b07fc76dcabfa977cf7ff00f575 Mon Sep 17 00:00:00 2001 From: Mateusz Holenko Date: Wed, 10 Jul 2019 10:39:26 +0200 Subject: [PATCH 242/951] Add `litex` target Use configuration from the `csr.h` file generated dynamically when building a LiteX platform. --- src/main/c/emulator/makefile | 5 +++ src/main/c/emulator/src/hal.c | 71 ++++++++++++++++++++++++++++++++++ src/main/c/emulator/src/main.c | 2 +- 3 files changed, 77 insertions(+), 1 deletion(-) diff --git a/src/main/c/emulator/makefile b/src/main/c/emulator/makefile index d9d90987..7534d083 100755 --- a/src/main/c/emulator/makefile +++ b/src/main/c/emulator/makefile @@ -18,6 +18,11 @@ sim: all qemu: CFLAGS += -DQEMU qemu: all +litex: CFLAGS += -DLITEX -I${LITEX_BASE}/software/include +litex: | check_litex_base all +check_litex_base: + @[ "${LITEX_BASE}" ] || ( echo ">> LITEX_BASE is not set"; exit 1 ) + include ${STANDALONE}/common/riscv64-unknown-elf.mk include ${STANDALONE}/common/standalone.mk diff --git a/src/main/c/emulator/src/hal.c b/src/main/c/emulator/src/hal.c index 52bb0e49..a9189f2e 100644 --- a/src/main/c/emulator/src/hal.c +++ b/src/main/c/emulator/src/hal.c @@ -144,5 +144,76 @@ void halInit(){ #endif +#ifdef LITEX + +// this is copied from LiteX +#define CSR_ACCESSORS_DEFINED +static inline void csr_writeb(uint8_t value, unsigned long addr) +{ + *((volatile uint8_t *)addr) = value; +} + +static inline uint8_t csr_readb(unsigned long addr) +{ + return *(volatile uint8_t *)addr; +} + +static inline void csr_writew(uint16_t value, unsigned long addr) +{ + *((volatile uint16_t *)addr) = value; +} + +static inline uint16_t csr_readw(unsigned long addr) +{ + return *(volatile uint16_t *)addr; +} + +static inline void csr_writel(uint32_t value, unsigned long addr) +{ + *((volatile uint32_t *)addr) = value; +} + +static inline uint32_t csr_readl(unsigned long addr) +{ + return *(volatile uint32_t *)addr; +} + +// this is a file generated by LiteX +#include + +#if !defined(CSR_UART_BASE) || !defined(CSR_CPU_BASE) + #error LiteX configuration with uart and cpu_timer is required. +#endif + +void stopSim(){ + while(1); +} + +void putC(char ch){ + uart_rxtx_write(ch); +} + +int32_t getC(){ + return uart_rxempty_read() + ? -1 + : uart_rxtx_read(); +} + +uint32_t rdtime(){ + return (uint32_t)cpu_timer_time_read(); +} + +uint32_t rdtimeh(){ + return (uint32_t)(cpu_timer_time_read() >> 32); +} + +void setMachineTimerCmp(uint32_t low, uint32_t high){ + cpu_timer_time_cmp_write((((unsigned long long int)high) << 32) | low); +} + +void halInit(){ +} + +#endif diff --git a/src/main/c/emulator/src/main.c b/src/main/c/emulator/src/main.c index 2102818e..dc12fb81 100755 --- a/src/main/c/emulator/src/main.c +++ b/src/main/c/emulator/src/main.c @@ -161,7 +161,7 @@ void trap(){ #ifdef SIM uint32_t instruction = csr_read(mbadaddr); #endif -#ifdef QEMU +#if defined(QEMU) || defined(LITEX) uint32_t instruction = 0; uint32_t i; if (mepc & 2) { From 86f5af5ca9214d3681058c5252747097fbd6f3d4 Mon Sep 17 00:00:00 2001 From: Mateusz Holenko Date: Wed, 24 Jul 2019 14:55:47 +0200 Subject: [PATCH 243/951] Fix handling LiteX uart and timer. --- src/main/c/emulator/src/hal.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/src/main/c/emulator/src/hal.c b/src/main/c/emulator/src/hal.c index a9189f2e..5a151bb2 100644 --- a/src/main/c/emulator/src/hal.c +++ b/src/main/c/emulator/src/hal.c @@ -190,28 +190,44 @@ void stopSim(){ } void putC(char ch){ + // protect against writing to a full tx fifo + while(uart_txfull_read()); uart_rxtx_write(ch); } int32_t getC(){ - return uart_rxempty_read() - ? -1 - : uart_rxtx_read(); + if(uart_rxempty_read()) + { + return -1; + } + + // this is required to refresh rexempty status + uart_ev_pending_write(1 << 1); + return uart_rxtx_read(); } uint32_t rdtime(){ - return (uint32_t)cpu_timer_time_read(); + cpu_timer_latch_write(0); + uint32_t result = (uint32_t)cpu_timer_time_read(); + cpu_timer_latch_write(1); + return result; } uint32_t rdtimeh(){ - return (uint32_t)(cpu_timer_time_read() >> 32); + cpu_timer_latch_write(0); + uint32_t result = (uint32_t)(cpu_timer_time_read() >> 32); + cpu_timer_latch_write(1); + return result; } void setMachineTimerCmp(uint32_t low, uint32_t high){ + cpu_timer_latch_write(0); cpu_timer_time_cmp_write((((unsigned long long int)high) << 32) | low); + cpu_timer_latch_write(1); } void halInit(){ + cpu_timer_latch_write(1); } #endif From 6951f5b8e6358104fc41ca0226628168dbbd33d7 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 29 Jul 2019 14:17:51 +0200 Subject: [PATCH 244/951] CfuPlugin addition --- .../scala/vexriscv/plugin/CfuPlugin.scala | 120 ++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 src/main/scala/vexriscv/plugin/CfuPlugin.scala diff --git a/src/main/scala/vexriscv/plugin/CfuPlugin.scala b/src/main/scala/vexriscv/plugin/CfuPlugin.scala new file mode 100644 index 00000000..968580d2 --- /dev/null +++ b/src/main/scala/vexriscv/plugin/CfuPlugin.scala @@ -0,0 +1,120 @@ +package vexriscv.plugin + +import vexriscv.{DecoderService, Stageable, VexRiscv} +import spinal.core._ +import spinal.lib._ + +case class CfuParameter(latency : Int, + dropWidth : Int, + CFU_VERSION : Int, + CFU_INTERFACE_ID_W : Int, + CFU_FUNCTION_ID_W : Int, + CFU_REORDER_ID_W : Int, + CFU_REQ_RESP_ID_W : Int, + CFU_INPUTS : Int, + CFU_INPUT_DATA_W : Int, + CFU_OUTPUTS : Int, + CFU_OUTPUT_DATA_W : Int, + CFU_FLOW_REQ_READY_ALWAYS : Int, + CFU_FLOW_RESP_READY_ALWAYS : Int) + +case class CfuCmd(p : CfuParameter) extends Bundle{ + val function_id = UInt(p.CFU_FUNCTION_ID_W bits) + val reorder_id = UInt(p.CFU_REORDER_ID_W bits) + val request_id = UInt(p.CFU_REQ_RESP_ID_W bits) + val inputs = Vec(Bits(p.CFU_INPUT_DATA_W bits), p.CFU_INPUTS) +} + +case class CfuRsp(p : CfuParameter) extends Bundle{ + val response_ok = Bool() + val response_id = UInt(p.CFU_REQ_RESP_ID_W bits) + val outputs = Vec(Bits(p.CFU_OUTPUT_DATA_W bits), p.CFU_OUTPUTS) +} + +case class CfuBus(p : CfuParameter) extends Bundle with IMasterSlave{ + val interface_id = UInt(p.CFU_INTERFACE_ID_W bits) + val cmd = Stream(CfuCmd(p)) + val rsp = Stream(CfuRsp(p)) + + override def asMaster(): Unit = { + out(interface_id) + master(cmd) + slave(rsp) + } +} + +class CfuPlugin(val p: CfuParameter) extends Plugin[VexRiscv]{ + assert(p.CFU_INPUTS <= 2) + assert(p.CFU_OUTPUTS == 1) + assert(p.CFU_FLOW_REQ_READY_ALWAYS == false) + assert(p.CFU_FLOW_RESP_READY_ALWAYS == false) + + var bus : CfuBus = null + + object CFU_ENABLE extends Stageable(Bool()) + object CFU_FUNCTION extends Stageable(UInt(p.CFU_FUNCTION_ID_W bits)) + object CFU_IN_FLIGHT extends Stageable(Bool()) + + override def setup(pipeline: VexRiscv): Unit = { + import pipeline.config._ + + bus = CfuBus(p) + + val decoderService = pipeline.service(classOf[DecoderService]) + decoderService.add(List( + M"000000-----------000-----0010011" -> List( + CFU_ENABLE -> True, + CFU_FUNCTION -> U"00", + REGFILE_WRITE_VALID -> ???, + BYPASSABLE_EXECUTE_STAGE -> ???, + BYPASSABLE_MEMORY_STAGE -> ???, + RS1_USE -> ???, + RS2_USE -> ??? + ), + M"000000-----------001-----0010011" -> List( + CFU_ENABLE -> True, + CFU_FUNCTION -> U"01", + REGFILE_WRITE_VALID -> ???, + BYPASSABLE_EXECUTE_STAGE -> ???, + BYPASSABLE_MEMORY_STAGE -> ???, + RS1_USE -> ???, + RS2_USE -> ??? + ) + )) + } + + override def build(pipeline: VexRiscv): Unit = { + import pipeline._ + import pipeline.config._ + + val forkStage = execute + val joinStageId = Math.min(stages.length - 1, pipeline.indexOf(execute) + p.latency - 1) + val joinStage = stages(joinStageId) + + forkStage plug new Area{ + import forkStage._ + val schedule = arbitration.isValid && input(CFU_ENABLE) + val hold = RegInit(False) setWhen(schedule) clearWhen(bus.cmd.ready) + val fired = RegInit(False) setWhen(bus.cmd.fire) clearWhen(!arbitration.isStuckByOthers) + insert(CFU_IN_FLIGHT) := schedule || hold || fired + + bus.cmd.valid := (schedule || hold) && !fired + arbitration.haltItself setWhen(bus.cmd.valid && !bus.cmd.ready) + + bus.cmd.function_id := input(CFU_FUNCTION) + bus.cmd.reorder_id := 0 + bus.cmd.request_id := 0 + if(p.CFU_INPUTS >= 1) bus.cmd.inputs(0) := input(RS1) + if(p.CFU_INPUTS >= 2) bus.cmd.inputs(1) := input(RS2) + } + + joinStage plug new Area{ + import joinStage._ + when(input(CFU_IN_FLIGHT)){ + arbitration.haltItself setWhen(!bus.rsp.valid) + bus.rsp.ready := arbitration.isStuckByOthers + output(REGFILE_WRITE_DATA) := bus.rsp.outputs(0) + } + } + } +} From 5ac443b74541b252cbf71f2603c88fb44a7ae978 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Thu, 5 Sep 2019 10:30:33 +0200 Subject: [PATCH 245/951] Manage cases where a rsp buffer is required --- src/main/scala/vexriscv/plugin/CfuPlugin.scala | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/CfuPlugin.scala b/src/main/scala/vexriscv/plugin/CfuPlugin.scala index 968580d2..e34b2e74 100644 --- a/src/main/scala/vexriscv/plugin/CfuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CfuPlugin.scala @@ -4,7 +4,8 @@ import vexriscv.{DecoderService, Stageable, VexRiscv} import spinal.core._ import spinal.lib._ -case class CfuParameter(latency : Int, +case class CfuParameter(stageCount : Int, + allowZeroLatency : Boolean, dropWidth : Int, CFU_VERSION : Int, CFU_INTERFACE_ID_W : Int, @@ -88,7 +89,7 @@ class CfuPlugin(val p: CfuParameter) extends Plugin[VexRiscv]{ import pipeline.config._ val forkStage = execute - val joinStageId = Math.min(stages.length - 1, pipeline.indexOf(execute) + p.latency - 1) + val joinStageId = Math.min(stages.length - 1, pipeline.indexOf(execute) + p.stageCount - 1) val joinStage = stages(joinStageId) forkStage plug new Area{ @@ -110,10 +111,16 @@ class CfuPlugin(val p: CfuParameter) extends Plugin[VexRiscv]{ joinStage plug new Area{ import joinStage._ + + //If the CFU interface can produce a result combinatorialy and the fork stage isn't the same than the join stage + //Then it is required to add a buffer on rsp to not propagate the fork stage ready := False in the CPU pipeline. + val rsp = if(forkStage != joinStage && p.allowZeroLatency) bus.rsp.m2sPipe() else bus.rsp + + when(input(CFU_IN_FLIGHT)){ - arbitration.haltItself setWhen(!bus.rsp.valid) - bus.rsp.ready := arbitration.isStuckByOthers - output(REGFILE_WRITE_DATA) := bus.rsp.outputs(0) + arbitration.haltItself setWhen(!rsp.valid) + rsp.ready := arbitration.isStuckByOthers + output(REGFILE_WRITE_DATA) := rsp.outputs(0) } } } From d94cee13f0a21caa893367d33b12e24cab6e3b4c Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Thu, 5 Sep 2019 19:06:28 +0200 Subject: [PATCH 246/951] Add dummy decoding, exception code/tval Add Cpu generation code Add support for always ready rsp --- .../demo/GenSmallAndProductiveCfu.scala | 76 +++++++++++++++++++ .../scala/vexriscv/plugin/CfuPlugin.scala | 69 ++++++++++------- 2 files changed, 119 insertions(+), 26 deletions(-) create mode 100644 src/main/scala/vexriscv/demo/GenSmallAndProductiveCfu.scala diff --git a/src/main/scala/vexriscv/demo/GenSmallAndProductiveCfu.scala b/src/main/scala/vexriscv/demo/GenSmallAndProductiveCfu.scala new file mode 100644 index 00000000..99838143 --- /dev/null +++ b/src/main/scala/vexriscv/demo/GenSmallAndProductiveCfu.scala @@ -0,0 +1,76 @@ +package vexriscv.demo + +import spinal.core._ +import vexriscv.plugin._ +import vexriscv.{VexRiscv, VexRiscvConfig, plugin} + +/** + * Created by spinalvm on 15.06.17. + */ +object GenSmallAndProductiveCfu extends App{ + def cpu() = new VexRiscv( + config = VexRiscvConfig( + plugins = List( + new IBusSimplePlugin( + resetVector = 0x80000000l, + cmdForkOnSecondStage = false, + cmdForkPersistence = false, + prediction = NONE, + catchAccessFault = false, + compressedGen = false + ), + new DBusSimplePlugin( + catchAddressMisaligned = false, + catchAccessFault = false + ), + new CsrPlugin(CsrPluginConfig.smallest), + new DecoderSimplePlugin( + catchIllegalInstruction = false + ), + new RegFilePlugin( + regFileReadyKind = plugin.SYNC, + zeroBoot = false + ), + new IntAluPlugin, + new SrcPlugin( + separatedAddSub = false, + executeInsertion = true + ), + new LightShifterPlugin, + new HazardSimplePlugin( + bypassExecute = true, + bypassMemory = true, + bypassWriteBack = true, + bypassWriteBackBuffer = true, + pessimisticUseSrc = false, + pessimisticWriteRegFile = false, + pessimisticAddressMatch = false + ), + new BranchPlugin( + earlyBranch = false, + catchAddressMisaligned = false + ), + new CfuPlugin( + p = CfuParameter( + stageCount = 1, + allowZeroLatency = true, + CFU_VERSION = 0, + CFU_INTERFACE_ID_W = 0, + CFU_FUNCTION_ID_W = 2, + CFU_REORDER_ID_W = 0, + CFU_REQ_RESP_ID_W = 0, + CFU_INPUTS = 2, + CFU_INPUT_DATA_W = 32, + CFU_OUTPUTS = 1, + CFU_OUTPUT_DATA_W = 32, + CFU_FLOW_REQ_READY_ALWAYS = false, + CFU_FLOW_RESP_READY_ALWAYS = false + ) + ), + new YamlPlugin("cpu0.yaml") + ) + ) + ) + + SpinalVerilog(cpu()) +} diff --git a/src/main/scala/vexriscv/plugin/CfuPlugin.scala b/src/main/scala/vexriscv/plugin/CfuPlugin.scala index e34b2e74..334fc25b 100644 --- a/src/main/scala/vexriscv/plugin/CfuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CfuPlugin.scala @@ -1,12 +1,11 @@ package vexriscv.plugin -import vexriscv.{DecoderService, Stageable, VexRiscv} +import vexriscv.{DecoderService, ExceptionCause, ExceptionService, Stage, Stageable, VexRiscv} import spinal.core._ import spinal.lib._ case class CfuParameter(stageCount : Int, allowZeroLatency : Boolean, - dropWidth : Int, CFU_VERSION : Int, CFU_INTERFACE_ID_W : Int, CFU_FUNCTION_ID_W : Int, @@ -16,8 +15,8 @@ case class CfuParameter(stageCount : Int, CFU_INPUT_DATA_W : Int, CFU_OUTPUTS : Int, CFU_OUTPUT_DATA_W : Int, - CFU_FLOW_REQ_READY_ALWAYS : Int, - CFU_FLOW_RESP_READY_ALWAYS : Int) + CFU_FLOW_REQ_READY_ALWAYS : Boolean, + CFU_FLOW_RESP_READY_ALWAYS : Boolean) case class CfuCmd(p : CfuParameter) extends Bundle{ val function_id = UInt(p.CFU_FUNCTION_ID_W bits) @@ -33,12 +32,10 @@ case class CfuRsp(p : CfuParameter) extends Bundle{ } case class CfuBus(p : CfuParameter) extends Bundle with IMasterSlave{ - val interface_id = UInt(p.CFU_INTERFACE_ID_W bits) val cmd = Stream(CfuCmd(p)) val rsp = Stream(CfuRsp(p)) override def asMaster(): Unit = { - out(interface_id) master(cmd) slave(rsp) } @@ -47,39 +44,46 @@ case class CfuBus(p : CfuParameter) extends Bundle with IMasterSlave{ class CfuPlugin(val p: CfuParameter) extends Plugin[VexRiscv]{ assert(p.CFU_INPUTS <= 2) assert(p.CFU_OUTPUTS == 1) - assert(p.CFU_FLOW_REQ_READY_ALWAYS == false) - assert(p.CFU_FLOW_RESP_READY_ALWAYS == false) var bus : CfuBus = null + var joinException : Flow[ExceptionCause] = null + + lazy val forkStage = pipeline.execute + lazy val joinStage = pipeline.stages(Math.min(pipeline.stages.length - 1, pipeline.indexOf(forkStage) + p.stageCount - 1)) + object CFU_ENABLE extends Stageable(Bool()) object CFU_FUNCTION extends Stageable(UInt(p.CFU_FUNCTION_ID_W bits)) object CFU_IN_FLIGHT extends Stageable(Bool()) override def setup(pipeline: VexRiscv): Unit = { + import pipeline._ import pipeline.config._ - bus = CfuBus(p) + bus = master(CfuBus(p)) + joinException = pipeline.service(classOf[ExceptionService]).newExceptionPort(joinStage) val decoderService = pipeline.service(classOf[DecoderService]) + + //custom-0 decoderService.add(List( - M"000000-----------000-----0010011" -> List( + M"000000-----------000-----0001011" -> List( CFU_ENABLE -> True, CFU_FUNCTION -> U"00", - REGFILE_WRITE_VALID -> ???, - BYPASSABLE_EXECUTE_STAGE -> ???, - BYPASSABLE_MEMORY_STAGE -> ???, - RS1_USE -> ???, - RS2_USE -> ??? + REGFILE_WRITE_VALID -> True, + BYPASSABLE_EXECUTE_STAGE -> Bool(p.stageCount == 0), + BYPASSABLE_MEMORY_STAGE -> Bool(p.stageCount <= 1), + RS1_USE -> True, + RS2_USE -> True ), - M"000000-----------001-----0010011" -> List( + M"000000-----------001-----0001011" -> List( CFU_ENABLE -> True, CFU_FUNCTION -> U"01", - REGFILE_WRITE_VALID -> ???, - BYPASSABLE_EXECUTE_STAGE -> ???, - BYPASSABLE_MEMORY_STAGE -> ???, - RS1_USE -> ???, - RS2_USE -> ??? + REGFILE_WRITE_VALID -> True, + BYPASSABLE_EXECUTE_STAGE -> Bool(p.stageCount == 0), + BYPASSABLE_MEMORY_STAGE -> Bool(p.stageCount <= 1), + RS1_USE -> True, + RS2_USE -> True ) )) } @@ -88,10 +92,6 @@ class CfuPlugin(val p: CfuParameter) extends Plugin[VexRiscv]{ import pipeline._ import pipeline.config._ - val forkStage = execute - val joinStageId = Math.min(stages.length - 1, pipeline.indexOf(execute) + p.stageCount - 1) - val joinStage = stages(joinStageId) - forkStage plug new Area{ import forkStage._ val schedule = arbitration.isValid && input(CFU_ENABLE) @@ -114,13 +114,30 @@ class CfuPlugin(val p: CfuParameter) extends Plugin[VexRiscv]{ //If the CFU interface can produce a result combinatorialy and the fork stage isn't the same than the join stage //Then it is required to add a buffer on rsp to not propagate the fork stage ready := False in the CPU pipeline. - val rsp = if(forkStage != joinStage && p.allowZeroLatency) bus.rsp.m2sPipe() else bus.rsp + val rsp = if(p.CFU_FLOW_RESP_READY_ALWAYS){ + bus.rsp.toFlow.toStream.queueLowLatency( + size = p.stageCount + 1, + latency = 0 + ) + } else if(forkStage != joinStage && p.allowZeroLatency) { + bus.rsp.m2sPipe() + } else { + bus.rsp.combStage() + } + joinException.valid := False + joinException.code := 15 + joinException.badAddr := 0 + rsp.ready := False when(input(CFU_IN_FLIGHT)){ arbitration.haltItself setWhen(!rsp.valid) rsp.ready := arbitration.isStuckByOthers output(REGFILE_WRITE_DATA) := rsp.outputs(0) + + when(arbitration.isValid){ + joinException.valid := !rsp.response_ok + } } } } From 6ed41f7361d4ddb7ea4f3cb2804986a459e6c5b4 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Mon, 16 Sep 2019 13:53:55 +0200 Subject: [PATCH 247/951] Improve CSR FMax --- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 5c7e0326..b6b43ca9 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -945,9 +945,14 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep val readData = B(0, 32 bits) val writeInstruction = arbitration.isValid && input(IS_CSR) && input(CSR_WRITE_OPCODE) val readInstruction = arbitration.isValid && input(IS_CSR) && input(CSR_READ_OPCODE) - val writeEnable = writeInstruction && ! blockedBySideEffects && !arbitration.isStuckByOthers// && readDataRegValid - val readEnable = readInstruction && ! blockedBySideEffects && !arbitration.isStuckByOthers// && !readDataRegValid + val writeEnable = writeInstruction && ! blockedBySideEffects // && readDataRegValid + val readEnable = readInstruction && ! blockedBySideEffects // && !readDataRegValid //arbitration.isStuckByOthers, in case of the hazardPlugin is in the executeStage + val hazardStage = service(classOf[RegFileService]).readStage() + if(hazardStage == execute) when (arbitration.isStuckByOthers){ + writeEnable := False + readEnable := False + } // def readDataReg = memory.input(REGFILE_WRITE_DATA) //PIPE OPT From 88eb8e4e47df50e136ead2d3c5aed5df0d6438e9 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Mon, 16 Sep 2019 14:22:33 +0200 Subject: [PATCH 248/951] Fix Artix7 FMax, my apologies for that, was due to a bad scripting using Kintex 7 instead --- README.md | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index e595cbe1..2af47aa5 100644 --- a/README.md +++ b/README.md @@ -66,51 +66,51 @@ The CPU configurations used below can be found in the `src/scala/vexriscv/demo` ``` VexRiscv smallest (RV32I, 0.52 DMIPS/Mhz, no datapath bypass, no interrupt) -> - Artix 7 -> 324 Mhz 496 LUT 505 FF + Artix 7 -> 233 Mhz 494 LUT 505 FF Cyclone V -> 193 Mhz 347 ALMs Cyclone IV -> 179 Mhz 730 LUT 494 FF iCE40 -> 92 Mhz 1130 LC VexRiscv smallest (RV32I, 0.52 DMIPS/Mhz, no datapath bypass) -> - Artix 7 -> 328 Mhz 539 LUT 562 FF + Artix 7 -> 232 Mhz 538 LUT 562 FF Cyclone V -> 189 Mhz 387 ALMs Cyclone IV -> 175 Mhz 829 LUT 550 FF iCE40 -> 85 Mhz 1292 LC VexRiscv small and productive (RV32I, 0.82 DMIPS/Mhz) -> - Artix 7 -> 324 Mhz 701 LUT 531 FF + Artix 7 -> 226 Mhz 689 LUT 531 FF Cyclone V -> 145 Mhz 499 ALMs Cyclone IV -> 150 Mhz 1,111 LUT 525 FF iCE40 -> 63 Mhz 1596 LC VexRiscv small and productive with I$ (RV32I, 0.70 DMIPS/Mhz, 4KB-I$) -> - Artix 7 -> 336 Mhz 764 LUT 562 FF + Artix 7 -> 230 Mhz 734 LUT 564 FF Cyclone V -> 145 Mhz 511 ALMs Cyclone IV -> 144 Mhz 1,145 LUT 531 FF iCE40 -> 66 Mhz 1680 LC VexRiscv full no cache (RV32IM, 1.21 DMIPS/Mhz 2.30 Coremark/Mhz, single cycle barrel shifter, debug module, catch exceptions, static branch) -> - Artix 7 -> 326 Mhz 1544 LUT 977 FF + Artix 7 -> 219 Mhz 1537 LUT 977 FF Cyclone V -> 139 Mhz 958 ALMs - Cyclone IV -> 135 Mhz 2,011 LUT 968 FF + Cyclone IV -> 135 Mhz 2,011 LUT 968 FF VexRiscv full (RV32IM, 1.21 DMIPS/Mhz 2.30 Coremark/Mhz with cache trashing, 4KB-I$,4KB-D$, single cycle barrel shifter, debug module, catch exceptions, static branch) -> - Artix 7 -> 279 Mhz 1686 LUT 1172 FF + Artix 7 -> 193 Mhz 1706 LUT 1172 FF Cyclone V -> 144 Mhz 1,128 ALMs Cyclone IV -> 133 Mhz 2,298 LUT 1,096 FF VexRiscv full max dmips/mhz -> (RV32IM, 1.44 DMIPS/Mhz 2.70 Coremark/Mhz,, 16KB-I$,16KB-D$, single cycle barrel shifter, debug module, catch exceptions, dynamic branch prediction in the fetch stage, branch and shift operations done in the Execute stage) -> - Artix 7 -> 193 Mhz 1758 LUT 1094 FF + Artix 7 -> 140 Mhz 1767 LUT 1128 FF Cyclone V -> 90 Mhz 1,089 ALMs Cyclone IV -> 79 Mhz 2,336 LUT 1,048 FF VexRiscv full with MMU (RV32IM, 1.24 DMIPS/Mhz 2.35 Coremark/Mhz, with cache trashing, 4KB-I$, 4KB-D$, single cycle barrel shifter, debug module, catch exceptions, dynamic branch, MMU) -> - Artix 7 -> 239 Mhz 2029 LUT 1585 FF + Artix 7 -> 161 Mhz 1985 LUT 1585 FF Cyclone V -> 124 Mhz 1,319 ALMs Cyclone IV -> 122 Mhz 2,710 LUT 1,501 FF VexRiscv linux balanced (RV32IMA, 1.21 DMIPS/Mhz 2.27 Coremark/Mhz, with cache trashing, 4KB-I$, 4KB-D$, single cycle barrel shifter, catch exceptions, static branch, MMU, Supervisor, Compatible with mainstream linux) -> - Artix 7 -> 249 Mhz 2549 LUT 2014 FF + Artix 7 -> 170 Mhz 2530 LUT 2013 FF Cyclone V -> 125 Mhz 1,618 ALMs Cyclone IV -> 116 Mhz 3,314 LUT 2,016 FF @@ -296,7 +296,7 @@ You can find some FPGA projects which instantiate the Briey SoC here (DE1-SoC, D Here are some measurements of Briey SoC timings and area : ``` - Artix 7 -> 275 Mhz 3072 LUT 3291 FF + Artix 7 -> 186 Mhz 3138 LUT 3328 FF Cyclone V -> 139 Mhz 2,175 ALMs Cyclone IV -> 129 Mhz 4,337 LUT 3,170 FF ``` @@ -351,13 +351,13 @@ Here are some timing and area measurements of the Murax SoC: ``` Murax interlocked stages (0.45 DMIPS/Mhz, 8 bits GPIO) -> - Artix 7 -> 313 Mhz 1039 LUT 1200 FF + Artix 7 -> 215 Mhz 1044 LUT 1202 FF Cyclone V -> 173 Mhz 737 ALMs Cyclone IV -> 144 Mhz 1,484 LUT 1,206 FF iCE40 -> 64 Mhz 2422 LC (nextpnr) MuraxFast bypassed stages (0.65 DMIPS/Mhz, 8 bits GPIO) -> - Artix 7 -> 323 Mhz 1241 LUT 1301 FF + Artix 7 -> 229 Mhz 1269 LUT 1302 FF Cyclone V -> 159 Mhz 864 ALMs Cyclone IV -> 137 Mhz 1,688 LUT 1,241 FF iCE40 -> 66 Mhz 2799 LC (nextpnr) From fe385da850d7bcff8f6a416fe44cd21a7ac82a45 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Mon, 16 Sep 2019 14:22:33 +0200 Subject: [PATCH 249/951] Fix Artix7 FMax, my apologies for that, was due to a bad scripting using Kintex 7 instead --- README.md | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index e595cbe1..2af47aa5 100644 --- a/README.md +++ b/README.md @@ -66,51 +66,51 @@ The CPU configurations used below can be found in the `src/scala/vexriscv/demo` ``` VexRiscv smallest (RV32I, 0.52 DMIPS/Mhz, no datapath bypass, no interrupt) -> - Artix 7 -> 324 Mhz 496 LUT 505 FF + Artix 7 -> 233 Mhz 494 LUT 505 FF Cyclone V -> 193 Mhz 347 ALMs Cyclone IV -> 179 Mhz 730 LUT 494 FF iCE40 -> 92 Mhz 1130 LC VexRiscv smallest (RV32I, 0.52 DMIPS/Mhz, no datapath bypass) -> - Artix 7 -> 328 Mhz 539 LUT 562 FF + Artix 7 -> 232 Mhz 538 LUT 562 FF Cyclone V -> 189 Mhz 387 ALMs Cyclone IV -> 175 Mhz 829 LUT 550 FF iCE40 -> 85 Mhz 1292 LC VexRiscv small and productive (RV32I, 0.82 DMIPS/Mhz) -> - Artix 7 -> 324 Mhz 701 LUT 531 FF + Artix 7 -> 226 Mhz 689 LUT 531 FF Cyclone V -> 145 Mhz 499 ALMs Cyclone IV -> 150 Mhz 1,111 LUT 525 FF iCE40 -> 63 Mhz 1596 LC VexRiscv small and productive with I$ (RV32I, 0.70 DMIPS/Mhz, 4KB-I$) -> - Artix 7 -> 336 Mhz 764 LUT 562 FF + Artix 7 -> 230 Mhz 734 LUT 564 FF Cyclone V -> 145 Mhz 511 ALMs Cyclone IV -> 144 Mhz 1,145 LUT 531 FF iCE40 -> 66 Mhz 1680 LC VexRiscv full no cache (RV32IM, 1.21 DMIPS/Mhz 2.30 Coremark/Mhz, single cycle barrel shifter, debug module, catch exceptions, static branch) -> - Artix 7 -> 326 Mhz 1544 LUT 977 FF + Artix 7 -> 219 Mhz 1537 LUT 977 FF Cyclone V -> 139 Mhz 958 ALMs - Cyclone IV -> 135 Mhz 2,011 LUT 968 FF + Cyclone IV -> 135 Mhz 2,011 LUT 968 FF VexRiscv full (RV32IM, 1.21 DMIPS/Mhz 2.30 Coremark/Mhz with cache trashing, 4KB-I$,4KB-D$, single cycle barrel shifter, debug module, catch exceptions, static branch) -> - Artix 7 -> 279 Mhz 1686 LUT 1172 FF + Artix 7 -> 193 Mhz 1706 LUT 1172 FF Cyclone V -> 144 Mhz 1,128 ALMs Cyclone IV -> 133 Mhz 2,298 LUT 1,096 FF VexRiscv full max dmips/mhz -> (RV32IM, 1.44 DMIPS/Mhz 2.70 Coremark/Mhz,, 16KB-I$,16KB-D$, single cycle barrel shifter, debug module, catch exceptions, dynamic branch prediction in the fetch stage, branch and shift operations done in the Execute stage) -> - Artix 7 -> 193 Mhz 1758 LUT 1094 FF + Artix 7 -> 140 Mhz 1767 LUT 1128 FF Cyclone V -> 90 Mhz 1,089 ALMs Cyclone IV -> 79 Mhz 2,336 LUT 1,048 FF VexRiscv full with MMU (RV32IM, 1.24 DMIPS/Mhz 2.35 Coremark/Mhz, with cache trashing, 4KB-I$, 4KB-D$, single cycle barrel shifter, debug module, catch exceptions, dynamic branch, MMU) -> - Artix 7 -> 239 Mhz 2029 LUT 1585 FF + Artix 7 -> 161 Mhz 1985 LUT 1585 FF Cyclone V -> 124 Mhz 1,319 ALMs Cyclone IV -> 122 Mhz 2,710 LUT 1,501 FF VexRiscv linux balanced (RV32IMA, 1.21 DMIPS/Mhz 2.27 Coremark/Mhz, with cache trashing, 4KB-I$, 4KB-D$, single cycle barrel shifter, catch exceptions, static branch, MMU, Supervisor, Compatible with mainstream linux) -> - Artix 7 -> 249 Mhz 2549 LUT 2014 FF + Artix 7 -> 170 Mhz 2530 LUT 2013 FF Cyclone V -> 125 Mhz 1,618 ALMs Cyclone IV -> 116 Mhz 3,314 LUT 2,016 FF @@ -296,7 +296,7 @@ You can find some FPGA projects which instantiate the Briey SoC here (DE1-SoC, D Here are some measurements of Briey SoC timings and area : ``` - Artix 7 -> 275 Mhz 3072 LUT 3291 FF + Artix 7 -> 186 Mhz 3138 LUT 3328 FF Cyclone V -> 139 Mhz 2,175 ALMs Cyclone IV -> 129 Mhz 4,337 LUT 3,170 FF ``` @@ -351,13 +351,13 @@ Here are some timing and area measurements of the Murax SoC: ``` Murax interlocked stages (0.45 DMIPS/Mhz, 8 bits GPIO) -> - Artix 7 -> 313 Mhz 1039 LUT 1200 FF + Artix 7 -> 215 Mhz 1044 LUT 1202 FF Cyclone V -> 173 Mhz 737 ALMs Cyclone IV -> 144 Mhz 1,484 LUT 1,206 FF iCE40 -> 64 Mhz 2422 LC (nextpnr) MuraxFast bypassed stages (0.65 DMIPS/Mhz, 8 bits GPIO) -> - Artix 7 -> 323 Mhz 1241 LUT 1301 FF + Artix 7 -> 229 Mhz 1269 LUT 1302 FF Cyclone V -> 159 Mhz 864 ALMs Cyclone IV -> 137 Mhz 1,688 LUT 1,241 FF iCE40 -> 66 Mhz 2799 LC (nextpnr) From 0b79c637b672af5e0ff77b4dd7fe04859b34f419 Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Fri, 20 Sep 2019 08:35:23 +0800 Subject: [PATCH 250/951] mulsimpleplugin: fix build for short pipelines Signed-off-by: Sean Cross --- src/main/scala/vexriscv/plugin/MulSimplePlugin.scala | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/MulSimplePlugin.scala b/src/main/scala/vexriscv/plugin/MulSimplePlugin.scala index 41ed3916..1be6da78 100644 --- a/src/main/scala/vexriscv/plugin/MulSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/MulSimplePlugin.scala @@ -66,14 +66,16 @@ class MulSimplePlugin extends Plugin[VexRiscv]{ insert(MUL_OPB) := ((bSigned ? b.msb | False) ## b).asSInt } - memory plug new Area { - import memory._ + val injectionStage = if(pipeline.memory != null) pipeline.memory else pipeline.execute + injectionStage plug new Area { + import injectionStage._ insert(MUL) := (input(MUL_OPA) * input(MUL_OPB))(63 downto 0).asBits } - writeBack plug new Area { - import writeBack._ + val memStage = stages.last + memStage plug new Area { + import memStage._ when(arbitration.isValid && input(IS_MUL)){ switch(input(INSTRUCTION)(13 downto 12)){ From fdc95debef1e898e419d435cc73448073f86a547 Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Fri, 20 Sep 2019 08:35:49 +0800 Subject: [PATCH 251/951] dbuscached: fix build for short pipelines Signed-off-by: Sean Cross --- .../vexriscv/plugin/DBusCachedPlugin.scala | 25 +++++++++++-------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index 10e45507..8b1ceb49 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -226,8 +226,10 @@ class DBusCachedPlugin(val config : DataCacheConfig, if(relaxedMemoryTranslationRegister) insert(MEMORY_VIRTUAL_ADDRESS) := cache.io.cpu.execute.address } - memory plug new Area{ - import memory._ + val flushStage = if(memory != null) memory else execute + flushStage plug new Area { + import flushStage._ + cache.io.cpu.memory.isValid := arbitration.isValid && input(MEMORY_ENABLE) cache.io.cpu.memory.isStuck := arbitration.isStuck cache.io.cpu.memory.isRemoved := arbitration.removeIt @@ -237,8 +239,9 @@ class DBusCachedPlugin(val config : DataCacheConfig, cache.io.cpu.memory.mmuBus.rsp.isIoAccess setWhen(pipeline(DEBUG_BYPASS_CACHE) && !cache.io.cpu.memory.isWrite) } - writeBack plug new Area{ - import writeBack._ + val fenceStage = stages.last + fenceStage plug new Area{ + import fenceStage._ 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() else False) @@ -323,10 +326,10 @@ class DBusCachedPlugin(val config : DataCacheConfig, execute.insert(IS_DBUS_SHARING) := dBusAccess.cmd.fire - mmuBus.cmd.bypassTranslation setWhen(memory.input(IS_DBUS_SHARING)) - cache.io.cpu.memory.isValid setWhen(memory.input(IS_DBUS_SHARING)) - cache.io.cpu.writeBack.isValid setWhen(writeBack.input(IS_DBUS_SHARING)) - dBusAccess.rsp.valid := writeBack.input(IS_DBUS_SHARING) && !cache.io.cpu.writeBack.isWrite && (cache.io.cpu.redo || !cache.io.cpu.writeBack.haltIt) + mmuBus.cmd.bypassTranslation setWhen(flushStage.input(IS_DBUS_SHARING)) + cache.io.cpu.memory.isValid setWhen(flushStage.input(IS_DBUS_SHARING)) + cache.io.cpu.writeBack.isValid setWhen(fenceStage.input(IS_DBUS_SHARING)) + dBusAccess.rsp.valid := fenceStage.input(IS_DBUS_SHARING) && !cache.io.cpu.writeBack.isWrite && (cache.io.cpu.redo || !cache.io.cpu.writeBack.haltIt) dBusAccess.rsp.data := cache.io.cpu.writeBack.data dBusAccess.rsp.error := cache.io.cpu.writeBack.unalignedAccess || cache.io.cpu.writeBack.accessError dBusAccess.rsp.redo := cache.io.cpu.redo @@ -334,10 +337,10 @@ class DBusCachedPlugin(val config : DataCacheConfig, when(forceDatapath){ execute.output(REGFILE_WRITE_DATA) := dBusAccess.cmd.address.asBits } - memory.input(IS_DBUS_SHARING) init(False) - writeBack.input(IS_DBUS_SHARING) init(False) + flushStage.input(IS_DBUS_SHARING) init(False) + fenceStage.input(IS_DBUS_SHARING) init(False) when(dBusAccess.rsp.valid){ - writeBack.input(IS_DBUS_SHARING).getDrivingReg := False + fenceStage.input(IS_DBUS_SHARING).getDrivingReg := False } } } From b8b053e706a66d4baf936d42104db43eab4fbf21 Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Fri, 20 Sep 2019 08:36:01 +0800 Subject: [PATCH 252/951] muldiviterative: fix build for short pipelines Signed-off-by: Sean Cross --- src/main/scala/vexriscv/plugin/MulDivIterativePlugin.scala | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/MulDivIterativePlugin.scala b/src/main/scala/vexriscv/plugin/MulDivIterativePlugin.scala index f366854c..11af4ab7 100644 --- a/src/main/scala/vexriscv/plugin/MulDivIterativePlugin.scala +++ b/src/main/scala/vexriscv/plugin/MulDivIterativePlugin.scala @@ -69,8 +69,9 @@ class MulDivIterativePlugin(genMul : Boolean = true, import pipeline.config._ if(!genMul && !genDiv) return - memory plug new Area { - import memory._ + val flushStage = if(memory != null) memory else execute + flushStage plug new Area { + import flushStage._ //Shared ressources val rs1 = Reg(UInt(33 bits)) From be18d8fa5a4b0152c92d6882ad26929f6ee1d2ba Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Sat, 21 Sep 2019 10:28:52 +0200 Subject: [PATCH 253/951] CSR access enables are also impacted by the MMU memory access --- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index b6b43ca9..5c7e0326 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -945,14 +945,9 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep val readData = B(0, 32 bits) val writeInstruction = arbitration.isValid && input(IS_CSR) && input(CSR_WRITE_OPCODE) val readInstruction = arbitration.isValid && input(IS_CSR) && input(CSR_READ_OPCODE) - val writeEnable = writeInstruction && ! blockedBySideEffects // && readDataRegValid - val readEnable = readInstruction && ! blockedBySideEffects // && !readDataRegValid + val writeEnable = writeInstruction && ! blockedBySideEffects && !arbitration.isStuckByOthers// && readDataRegValid + val readEnable = readInstruction && ! blockedBySideEffects && !arbitration.isStuckByOthers// && !readDataRegValid //arbitration.isStuckByOthers, in case of the hazardPlugin is in the executeStage - val hazardStage = service(classOf[RegFileService]).readStage() - if(hazardStage == execute) when (arbitration.isStuckByOthers){ - writeEnable := False - readEnable := False - } // def readDataReg = memory.input(REGFILE_WRITE_DATA) //PIPE OPT From e8236dfebed0a55a955f87223cf1ffffabee009d Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Sat, 21 Sep 2019 12:49:46 +0200 Subject: [PATCH 254/951] Add MulSimplePlugin regressions --- .../scala/vexriscv/TestIndividualFeatures.scala | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/test/scala/vexriscv/TestIndividualFeatures.scala b/src/test/scala/vexriscv/TestIndividualFeatures.scala index 33e4aa6e..7c11b14c 100644 --- a/src/test/scala/vexriscv/TestIndividualFeatures.scala +++ b/src/test/scala/vexriscv/TestIndividualFeatures.scala @@ -99,6 +99,22 @@ class MulDivDimension extends VexRiscvDimension("MulDiv") { val noWriteBack = universes.contains(VexRiscvUniverse.NO_WRITEBACK) var l = List[VexRiscvPosition]() + + + + new VexRiscvPosition("MulDivFpgaSimple") { + override def testParam = "MUL=yes DIV=yes" + override def applyOn(config: VexRiscvConfig): Unit = { + config.plugins += new MulSimplePlugin + config.plugins += new MulDivIterativePlugin( + genMul = false, + genDiv = true, + mulUnrollFactor = 32, + divUnrollFactor = 1 + ) + } + } :: l + if(!noMemory) { l = new VexRiscvPosition("MulDivAsic") { override def testParam = "MUL=yes DIV=yes" From e1795e59d5660f627bfde5d13a1622866de8495f Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Sat, 21 Sep 2019 13:00:54 +0200 Subject: [PATCH 255/951] Enable RF bypass on MUL DIV with pipeline wihout writeback/memory stages --- src/main/scala/vexriscv/plugin/MulDivIterativePlugin.scala | 2 +- src/main/scala/vexriscv/plugin/MulSimplePlugin.scala | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/MulDivIterativePlugin.scala b/src/main/scala/vexriscv/plugin/MulDivIterativePlugin.scala index 11af4ab7..1bd8fb4d 100644 --- a/src/main/scala/vexriscv/plugin/MulDivIterativePlugin.scala +++ b/src/main/scala/vexriscv/plugin/MulDivIterativePlugin.scala @@ -31,7 +31,7 @@ class MulDivIterativePlugin(genMul : Boolean = true, SRC1_CTRL -> Src1CtrlEnum.RS, SRC2_CTRL -> Src2CtrlEnum.RS, REGFILE_WRITE_VALID -> True, - BYPASSABLE_EXECUTE_STAGE -> False, + BYPASSABLE_EXECUTE_STAGE -> Bool(pipeline.stages.last == pipeline.execute), BYPASSABLE_MEMORY_STAGE -> True, RS1_USE -> True, RS2_USE -> True diff --git a/src/main/scala/vexriscv/plugin/MulSimplePlugin.scala b/src/main/scala/vexriscv/plugin/MulSimplePlugin.scala index 1be6da78..3b407e1d 100644 --- a/src/main/scala/vexriscv/plugin/MulSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/MulSimplePlugin.scala @@ -19,8 +19,8 @@ class MulSimplePlugin extends Plugin[VexRiscv]{ SRC1_CTRL -> Src1CtrlEnum.RS, SRC2_CTRL -> Src2CtrlEnum.RS, REGFILE_WRITE_VALID -> True, - BYPASSABLE_EXECUTE_STAGE -> False, - BYPASSABLE_MEMORY_STAGE -> False, + BYPASSABLE_EXECUTE_STAGE -> Bool(pipeline.stages.last == pipeline.execute), + BYPASSABLE_MEMORY_STAGE -> Bool(pipeline.stages.last == pipeline.memory), RS1_USE -> True, RS2_USE -> True, IS_MUL -> True From ace963b542b773584f45158339b3e48e355bee7a Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Sat, 21 Sep 2019 14:13:28 +0200 Subject: [PATCH 256/951] Hazard on memory stage do not need to know if that's bypassable if the memory stage is the last one --- src/main/scala/vexriscv/plugin/HazardSimplePlugin.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/plugin/HazardSimplePlugin.scala b/src/main/scala/vexriscv/plugin/HazardSimplePlugin.scala index f674ae87..1ed1d83e 100644 --- a/src/main/scala/vexriscv/plugin/HazardSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/HazardSimplePlugin.scala @@ -95,7 +95,7 @@ class HazardSimplePlugin(bypassExecute : Boolean = false, } if(withWriteBackStage) trackHazardWithStage(writeBack,bypassWriteBack,null) - if(withMemoryStage) trackHazardWithStage(memory ,bypassMemory ,BYPASSABLE_MEMORY_STAGE) + if(withMemoryStage) trackHazardWithStage(memory ,bypassMemory, if(stages.last == memory) null else BYPASSABLE_MEMORY_STAGE) if(readStage != execute) trackHazardWithStage(execute ,bypassExecute , if(stages.last == execute) null else BYPASSABLE_EXECUTE_STAGE) From bf82829e9edeb68545036bfbd8667bb8280bd465 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Mon, 23 Sep 2019 15:20:20 +0200 Subject: [PATCH 257/951] Data cache can now be used without writeback stage --- src/main/scala/vexriscv/ip/DataCache.scala | 19 +++++++---- .../vexriscv/plugin/DBusCachedPlugin.scala | 34 ++++++++++--------- 2 files changed, 31 insertions(+), 22 deletions(-) diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index f6926806..17c4bf60 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -24,8 +24,9 @@ case class DataCacheConfig(cacheSize : Int, earlyDataMux : Boolean = false, tagSizeShift : Int = 0, //Used to force infering ram withLrSc : Boolean = false, - withAmo : Boolean = false){ - + withAmo : Boolean = false, + mergeExecuteMemory : Boolean = false){ + assert(!(mergeExecuteMemory && (earlyDataMux || earlyWaysHits))) assert(!(earlyDataMux && !earlyWaysHits)) def burstSize = bytePerLine*8/memDataWidth val burstLength = bytePerLine/(memDataWidth/8) @@ -446,7 +447,7 @@ class DataCache(p : DataCacheConfig) extends Component{ } val stageA = new Area{ - def stagePipe[T <: Data](that : T) = RegNextWhen(that, !io.cpu.memory.isStuck) + def stagePipe[T <: Data](that : T) = if(mergeExecuteMemory) CombInit(that) else RegNextWhen(that, !io.cpu.memory.isStuck) val request = stagePipe(io.cpu.execute.args) val mask = stagePipe(stage0.mask) io.cpu.memory.mmuBus.cmd.isValid := io.cpu.memory.isValid @@ -457,16 +458,22 @@ class DataCache(p : DataCacheConfig) extends Component{ val wayHits = earlyWaysHits generate ways.map(way => (io.cpu.memory.mmuBus.rsp.physicalAddress(tagRange) === way.tagsReadRsp.address && way.tagsReadRsp.valid)) val dataMux = earlyDataMux generate MuxOH(wayHits, ways.map(_.dataReadRsp)) - val colisions = stagePipe(stage0.colisions) | collisionProcess(io.cpu.memory.address(lineRange.high downto wordRange.low), mask) //Assume the writeback stage will never be unstall memory acces while memory stage is stalled + val colisions = if(mergeExecuteMemory){ + stagePipe(stage0.colisions) + } else { + //Assume the writeback stage will never be unstall memory acces while memory stage is stalled + stagePipe(stage0.colisions) | collisionProcess(io.cpu.memory.address(lineRange.high downto wordRange.low), mask) + } } val stageB = new Area { def stagePipe[T <: Data](that : T) = RegNextWhen(that, !io.cpu.writeBack.isStuck) + def ramPipe[T <: Data](that : T) = if(mergeExecuteMemory) CombInit(that) else RegNextWhen(that, !io.cpu.writeBack.isStuck) val request = RegNextWhen(stageA.request, !io.cpu.writeBack.isStuck) val mmuRspFreeze = False val mmuRsp = RegNextWhen(io.cpu.memory.mmuBus.rsp, !io.cpu.writeBack.isStuck && !mmuRspFreeze) - val tagsReadRsp = ways.map(w => stagePipe(w.tagsReadRsp)) - val dataReadRsp = !earlyDataMux generate ways.map(w => stagePipe(w.dataReadRsp)) + val tagsReadRsp = ways.map(w => ramPipe(w.tagsReadRsp)) + val dataReadRsp = !earlyDataMux generate ways.map(w => ramPipe(w.dataReadRsp)) val waysHits = if(earlyWaysHits) stagePipe(B(stageA.wayHits)) else B(tagsReadRsp.map(tag => mmuRsp.physicalAddress(tagRange) === tag.address && tag.valid).asBits()) val waysHit = waysHits.orR val dataMux = if(earlyDataMux) stagePipe(stageA.dataMux) else MuxOH(waysHits, dataReadRsp) diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index 8b1ceb49..9102a727 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -148,7 +148,7 @@ class DBusCachedPlugin(val config : DataCacheConfig, redoBranch = pipeline.service(classOf[JumpService]).createJumpInterface(if(pipeline.writeBack != null) pipeline.writeBack else pipeline.execute) if(catchSomething) - exceptionBus = pipeline.service(classOf[ExceptionService]).newExceptionPort(pipeline.writeBack) + exceptionBus = pipeline.service(classOf[ExceptionService]).newExceptionPort(if(pipeline.writeBack == null) pipeline.memory else pipeline.writeBack) if(pipeline.serviceExist(classOf[PrivilegeService])) privilegeService = pipeline.service(classOf[PrivilegeService]) @@ -162,7 +162,9 @@ class DBusCachedPlugin(val config : DataCacheConfig, dBus = master(DataCacheMemBus(this.config)).setName("dBus") - val cache = new DataCache(this.config) + val cache = new DataCache(this.config.copy( + mergeExecuteMemory = writeBack == null + )) //Interconnect the plugin dBus with the cache dBus with some optional pipelining def optionPipe[T](cond : Boolean, on : T)(f : T => T) : T = if(cond) f(on) else on @@ -226,22 +228,22 @@ class DBusCachedPlugin(val config : DataCacheConfig, if(relaxedMemoryTranslationRegister) insert(MEMORY_VIRTUAL_ADDRESS) := cache.io.cpu.execute.address } - val flushStage = if(memory != null) memory else execute - flushStage plug new Area { - import flushStage._ + val mmuAndBufferStage = if(writeBack != null) memory else execute + mmuAndBufferStage plug new Area { + import mmuAndBufferStage._ cache.io.cpu.memory.isValid := arbitration.isValid && input(MEMORY_ENABLE) cache.io.cpu.memory.isStuck := arbitration.isStuck cache.io.cpu.memory.isRemoved := arbitration.removeIt - cache.io.cpu.memory.address := (if(relaxedMemoryTranslationRegister) input(MEMORY_VIRTUAL_ADDRESS) else U(input(REGFILE_WRITE_DATA))) + cache.io.cpu.memory.address := (if(relaxedMemoryTranslationRegister) input(MEMORY_VIRTUAL_ADDRESS) else if(mmuAndBufferStage == execute) cache.io.cpu.execute.address else U(input(REGFILE_WRITE_DATA))) cache.io.cpu.memory.mmuBus <> mmuBus cache.io.cpu.memory.mmuBus.rsp.isIoAccess setWhen(pipeline(DEBUG_BYPASS_CACHE) && !cache.io.cpu.memory.isWrite) } - val fenceStage = stages.last - fenceStage plug new Area{ - import fenceStage._ + val managementStage = stages.last + managementStage plug new Area{ + import managementStage._ 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() else False) @@ -326,10 +328,10 @@ class DBusCachedPlugin(val config : DataCacheConfig, execute.insert(IS_DBUS_SHARING) := dBusAccess.cmd.fire - mmuBus.cmd.bypassTranslation setWhen(flushStage.input(IS_DBUS_SHARING)) - cache.io.cpu.memory.isValid setWhen(flushStage.input(IS_DBUS_SHARING)) - cache.io.cpu.writeBack.isValid setWhen(fenceStage.input(IS_DBUS_SHARING)) - dBusAccess.rsp.valid := fenceStage.input(IS_DBUS_SHARING) && !cache.io.cpu.writeBack.isWrite && (cache.io.cpu.redo || !cache.io.cpu.writeBack.haltIt) + mmuBus.cmd.bypassTranslation setWhen(mmuAndBufferStage.input(IS_DBUS_SHARING)) + if(mmuAndBufferStage != execute) (cache.io.cpu.memory.isValid setWhen(mmuAndBufferStage.input(IS_DBUS_SHARING))) + cache.io.cpu.writeBack.isValid setWhen(managementStage.input(IS_DBUS_SHARING)) + dBusAccess.rsp.valid := managementStage.input(IS_DBUS_SHARING) && !cache.io.cpu.writeBack.isWrite && (cache.io.cpu.redo || !cache.io.cpu.writeBack.haltIt) dBusAccess.rsp.data := cache.io.cpu.writeBack.data dBusAccess.rsp.error := cache.io.cpu.writeBack.unalignedAccess || cache.io.cpu.writeBack.accessError dBusAccess.rsp.redo := cache.io.cpu.redo @@ -337,10 +339,10 @@ class DBusCachedPlugin(val config : DataCacheConfig, when(forceDatapath){ execute.output(REGFILE_WRITE_DATA) := dBusAccess.cmd.address.asBits } - flushStage.input(IS_DBUS_SHARING) init(False) - fenceStage.input(IS_DBUS_SHARING) init(False) + if(mmuAndBufferStage != execute) mmuAndBufferStage.input(IS_DBUS_SHARING) init(False) + managementStage.input(IS_DBUS_SHARING) init(False) when(dBusAccess.rsp.valid){ - fenceStage.input(IS_DBUS_SHARING).getDrivingReg := False + managementStage.input(IS_DBUS_SHARING).getDrivingReg := False } } } From 49944643d222fc72b800bb2fa1880f6ef91618c6 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Mon, 23 Sep 2019 15:20:51 +0200 Subject: [PATCH 258/951] Add regression for data cache without writeback stage, seem to pass tests, including linux ones --- .../vexriscv/TestIndividualFeatures.scala | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/test/scala/vexriscv/TestIndividualFeatures.scala b/src/test/scala/vexriscv/TestIndividualFeatures.scala index 7c11b14c..efa975ce 100644 --- a/src/test/scala/vexriscv/TestIndividualFeatures.scala +++ b/src/test/scala/vexriscv/TestIndividualFeatures.scala @@ -392,7 +392,7 @@ class DBusDimension extends VexRiscvDimension("DBus") { - if(r.nextDouble() < 0.4 || noMemory || noWriteBack){ + if(r.nextDouble() < 0.4 || noMemory){ val withLrSc = catchAll val earlyInjection = r.nextBoolean() && !universes.contains(VexRiscvUniverse.NO_WRITEBACK) new VexRiscvPosition("Simple" + (if(earlyInjection) "Early" else "Late")) { @@ -412,7 +412,8 @@ class DBusDimension extends VexRiscvDimension("DBus") { var wayCount = 0 val withLrSc = catchAll val withAmo = catchAll && r.nextBoolean() - val dBusRspSlavePipe, relaxedMemoryTranslationRegister, earlyWaysHits = r.nextBoolean() + val dBusRspSlavePipe, relaxedMemoryTranslationRegister = r.nextBoolean() + val earlyWaysHits = r.nextBoolean() && !noWriteBack val dBusCmdMasterPipe, dBusCmdSlavePipe = false //As it create test bench issues do{ @@ -616,11 +617,11 @@ class TestIndividualFeatures extends FunSuite { val testId : Option[mutable.HashSet[Int]] = None val seed = sys.env.getOrElse("VEXRISCV_REGRESSION_SEED", Random.nextLong().toString).toLong - +// // val testId = Some(mutable.HashSet(3,4,9,11,13,16,18,19,20,21)) -// val testId = Some(mutable.HashSet(24, 43, 49)) -// val testId = Some(mutable.HashSet(11)) -// val seed = -8309068850561113754l +// val testId = Some(mutable.HashSet(22)) +// val testId = Some(mutable.HashSet(22, 33 , 38, 47, 48)) +// val seed = 5426556825163943143l val rand = new Random(seed) @@ -638,11 +639,16 @@ class TestIndividualFeatures extends FunSuite { universe += VexRiscvUniverse.MMU universe += VexRiscvUniverse.FORCE_MULDIV universe += VexRiscvUniverse.SUPERVISOR + if(sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_DEMW_RATE", "0.6").toDouble < rand.nextDouble()){ + universe += VexRiscvUniverse.NO_WRITEBACK + } } else { if(sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_MACHINE_OS_RATE", "0.5").toDouble > rand.nextDouble()) { universe += VexRiscvUniverse.CATCH_ALL + if(sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_DEMW_RATE", "0.6").toDouble < rand.nextDouble()){ + universe += VexRiscvUniverse.NO_WRITEBACK + } } - var tmp = rand.nextDouble() if(sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_DEMW_RATE", "0.6").toDouble > rand.nextDouble()){ }else if(sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_DEM_RATE", "0.5").toDouble > rand.nextDouble()){ universe += VexRiscvUniverse.NO_WRITEBACK From 5df56bea79c4c84121143885800e14ef97c11a59 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Thu, 3 Oct 2019 00:20:33 +0200 Subject: [PATCH 259/951] Allow getDrivingReg to properly see i$ decode.input(INSTRUCTION) register (used to inject instruction from the debug plugin) --- .../scala/vexriscv/ip/InstructionCache.scala | 18 ++++++++++-------- .../vexriscv/plugin/IBusCachedPlugin.scala | 8 ++++---- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/main/scala/vexriscv/ip/InstructionCache.scala b/src/main/scala/vexriscv/ip/InstructionCache.scala index edc33d83..8f55093f 100644 --- a/src/main/scala/vexriscv/ip/InstructionCache.scala +++ b/src/main/scala/vexriscv/ip/InstructionCache.scala @@ -22,7 +22,8 @@ case class InstructionCacheConfig( cacheSize : Int, asyncTagMemory : Boolean, twoCycleCache : Boolean = true, twoCycleRam : Boolean = false, - preResetFlush : Boolean = false){ + preResetFlush : Boolean = false, + bypassGen : Boolean = false ){ assert(!(twoCycleRam && !twoCycleCache)) @@ -108,8 +109,8 @@ case class InstructionCacheCpuFetch(p : InstructionCacheConfig) extends Bundle w val isRemoved = Bool() val pc = UInt(p.addressWidth bits) val data = Bits(p.cpuDataWidth bits) - val dataBypassValid = Bool() - val dataBypass = Bits(p.cpuDataWidth bits) + val dataBypassValid = p.bypassGen generate Bool() + val dataBypass = p.bypassGen generate Bits(p.cpuDataWidth bits) val mmuBus = MemoryTranslatorBus() val physicalAddress = UInt(p.addressWidth bits) val cacheMiss, error, mmuRefilling, mmuException, isUser = ifGen(!p.twoCycleCache)(Bool) @@ -415,15 +416,16 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{ 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 := (io.cpu.fetch.dataBypassValid ? io.cpu.fetch.dataBypass | word) + val word = if(cpuDataWidth == memDataWidth) CombInit(data) else data.subdivideIn(cpuDataWidth bits).read(io.cpu.fetch.pc(memWordToCpuWordRange)) + io.cpu.fetch.data := (if(p.bypassGen) (io.cpu.fetch.dataBypassValid ? io.cpu.fetch.dataBypass | word) else word) if(twoCycleCache){ io.cpu.decode.data := RegNextWhen(io.cpu.fetch.data,!io.cpu.decode.isStuck) } } if(twoCycleRam && wayCount == 1){ - io.cpu.fetch.data := (io.cpu.fetch.dataBypassValid ? io.cpu.fetch.dataBypass | read.waysValues.head.data.subdivideIn(cpuDataWidth bits).read(io.cpu.fetch.pc(memWordToCpuWordRange))) + val cacheData = if(cpuDataWidth == memDataWidth) CombInit(read.waysValues.head.data) else read.waysValues.head.data.subdivideIn(cpuDataWidth bits).read(io.cpu.fetch.pc(memWordToCpuWordRange)) + io.cpu.fetch.data := (if(p.bypassGen) (io.cpu.fetch.dataBypassValid ? io.cpu.fetch.dataBypass | cacheData) else cacheData) } io.cpu.fetch.mmuBus.cmd.isValid := io.cpu.fetch.isValid @@ -458,8 +460,8 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{ val id = OHToUInt(hits) val error = tags(id).error val data = fetchStage.read.waysValues.map(way => stage(way.data)).read(id) - val word = data.subdivideIn(cpuDataWidth bits).read(io.cpu.decode.pc(memWordToCpuWordRange)) - when(stage(io.cpu.fetch.dataBypassValid)){ + val word = if(cpuDataWidth == memDataWidth) data else data.subdivideIn(cpuDataWidth bits).read(io.cpu.decode.pc(memWordToCpuWordRange)) + if(p.bypassGen) when(stage(io.cpu.fetch.dataBypassValid)){ word := stage(io.cpu.fetch.dataBypass) } io.cpu.decode.data := word diff --git a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala index 6a582c8d..a7b21940 100644 --- a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala @@ -61,7 +61,7 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l, var redoBranch : Flow[UInt] = null var decodeExceptionPort : Flow[ExceptionCause] = null val tightlyCoupledPorts = ArrayBuffer[TightlyCoupledPort]() - + def tightlyGen = tightlyCoupledPorts.nonEmpty def newTightlyCoupledPort(p : TightlyCoupledPortParameter) = { val port = TightlyCoupledPort(p, null) @@ -125,7 +125,7 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l, import pipeline.config._ pipeline plug new FetchArea(pipeline) { - val cache = new InstructionCache(IBusCachedPlugin.this.config) + val cache = new InstructionCache(IBusCachedPlugin.this.config.copy(bypassGen = tightlyGen)) iBus = master(new InstructionCacheMemBus(IBusCachedPlugin.this.config)).setName("iBus") iBus <> cache.io.mem iBus.cmd.address.allowOverride := cache.io.mem.cmd.address @@ -165,8 +165,8 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l, val tightlyCoupledHits = RegNextWhen(s0.tightlyCoupledHits, stages(1).input.ready) val tightlyCoupledHit = RegNextWhen(s0.tightlyCoupledHit, stages(1).input.ready) - cache.io.cpu.fetch.dataBypassValid := tightlyCoupledHit - cache.io.cpu.fetch.dataBypass := (if(tightlyCoupledPorts.isEmpty) B(0) else MuxOH(tightlyCoupledHits, tightlyCoupledPorts.map(e => CombInit(e.bus.data)))) + if(tightlyGen) cache.io.cpu.fetch.dataBypassValid := tightlyCoupledHit + if(tightlyGen) cache.io.cpu.fetch.dataBypass := MuxOH(tightlyCoupledHits, tightlyCoupledPorts.map(e => CombInit(e.bus.data))) //Connect fetch cache side cache.io.cpu.fetch.isValid := stages(1).input.valid && !tightlyCoupledHit From 3fc0a74102a3c244eef529b9e75c810df8af00c1 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Fri, 11 Oct 2019 00:22:44 +0200 Subject: [PATCH 260/951] Add Keep attribut on dBusCached relaxedMemoryTranslationRegister feature --- src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index 10e45507..978dd5db 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -223,7 +223,10 @@ class DBusCachedPlugin(val config : DataCacheConfig, arbitration.haltItself := True } - if(relaxedMemoryTranslationRegister) insert(MEMORY_VIRTUAL_ADDRESS) := cache.io.cpu.execute.address + if(relaxedMemoryTranslationRegister) { + insert(MEMORY_VIRTUAL_ADDRESS) := cache.io.cpu.execute.address + addPrePopTask( () => KeepAttribute(memory.input(MEMORY_VIRTUAL_ADDRESS).getDrivingReg)) + } } memory plug new Area{ From 711eed1e77230840233a8cbc502e83ee47a41990 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Fri, 11 Oct 2019 00:23:29 +0200 Subject: [PATCH 261/951] MulPlugin add withInputBuffer feature and now use RSx instead of SRCx --- .../scala/vexriscv/plugin/MulPlugin.scala | 29 +++++++++++++++---- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/MulPlugin.scala b/src/main/scala/vexriscv/plugin/MulPlugin.scala index ab4d828a..96db3e94 100644 --- a/src/main/scala/vexriscv/plugin/MulPlugin.scala +++ b/src/main/scala/vexriscv/plugin/MulPlugin.scala @@ -3,7 +3,8 @@ import vexriscv._ import vexriscv.VexRiscv import spinal.core._ -class MulPlugin extends Plugin[VexRiscv]{ +//Input buffer generaly avoid the FPGA synthesis to duplicate reg inside the DSP cell, which could stress timings quite much. +class MulPlugin(inputBuffer : Boolean = false) extends Plugin[VexRiscv]{ object MUL_LL extends Stageable(UInt(32 bits)) object MUL_LH extends Stageable(SInt(34 bits)) object MUL_HL extends Stageable(SInt(34 bits)) @@ -19,8 +20,8 @@ class MulPlugin extends Plugin[VexRiscv]{ val actions = List[(Stageable[_ <: BaseType],Any)]( - SRC1_CTRL -> Src1CtrlEnum.RS, - SRC2_CTRL -> Src2CtrlEnum.RS, +// SRC1_CTRL -> Src1CtrlEnum.RS, +// SRC2_CTRL -> Src2CtrlEnum.RS, REGFILE_WRITE_VALID -> True, BYPASSABLE_EXECUTE_STAGE -> False, BYPASSABLE_MEMORY_STAGE -> False, @@ -48,8 +49,26 @@ class MulPlugin extends Plugin[VexRiscv]{ val aSigned,bSigned = Bool val a,b = Bits(32 bit) - a := input(SRC1) - b := input(SRC2) +// a := input(SRC1) +// b := input(SRC2) + + val withInputBuffer = inputBuffer generate new Area{ + val rs1 = RegNext(input(RS1)) + val rs2 = RegNext(input(RS2)) + a := rs1 + b := rs2 + + val delay = RegNext(arbitration.isStuck) + when(arbitration.isValid && input(IS_MUL) && !delay){ + arbitration.haltItself := True + } + } + + val noInputBuffer = (!inputBuffer) generate new Area{ + a := input(RS1) + b := input(RS2) + } + switch(input(INSTRUCTION)(13 downto 12)) { is(B"01") { aSigned := True From 310c325eaa10fbf48ef838960e23ad78c4eb86df Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Fri, 11 Oct 2019 00:24:21 +0200 Subject: [PATCH 262/951] IBusCached add Keep attribut on the line loader to avoid Artix7 block ram merge, but do not seem to have effect --- src/main/scala/vexriscv/ip/InstructionCache.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/scala/vexriscv/ip/InstructionCache.scala b/src/main/scala/vexriscv/ip/InstructionCache.scala index edc33d83..dc5f6c13 100644 --- a/src/main/scala/vexriscv/ip/InstructionCache.scala +++ b/src/main/scala/vexriscv/ip/InstructionCache.scala @@ -8,7 +8,7 @@ import spinal.lib.bus.avalon.{AvalonMM, AvalonMMConfig} import spinal.lib.bus.bmb.{Bmb, BmbParameter} import spinal.lib.bus.wishbone.{Wishbone, WishboneConfig} import spinal.lib.bus.simple._ -import vexriscv.plugin.{IBusSimpleBus, IBusSimplePlugin} +import vexriscv.plugin.{IBusSimpleBus, IBusSimplePlugin, KeepAttribute} case class InstructionCacheConfig( cacheSize : Int, @@ -325,7 +325,7 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{ val lineLoader = new Area{ val fire = False val valid = RegInit(False) clearWhen(fire) - val address = Reg(UInt(addressWidth bits)) + val address = KeepAttribute(Reg(UInt(addressWidth bits))) val hadError = RegInit(False) clearWhen(fire) val flushPending = RegInit(True) @@ -363,7 +363,7 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{ io.mem.cmd.size := log2Up(p.bytePerLine) val wayToAllocate = Counter(wayCount, !valid) - val wordIndex = Reg(UInt(log2Up(memWordPerLine) bits)) init(0) + val wordIndex = KeepAttribute(Reg(UInt(log2Up(memWordPerLine) bits)) init(0)) val write = new Area{ From a2b49ae00021ff895df3274afaebef192cce9518 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Fri, 11 Oct 2019 00:25:22 +0200 Subject: [PATCH 263/951] Fix CFU arbitration, add CFU decoder, CFU now redirect custom-0 with func3 --- .../scala/vexriscv/plugin/CfuPlugin.scala | 130 ++++++++++++++++-- 1 file changed, 115 insertions(+), 15 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/CfuPlugin.scala b/src/main/scala/vexriscv/plugin/CfuPlugin.scala index 334fc25b..3da804f9 100644 --- a/src/main/scala/vexriscv/plugin/CfuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CfuPlugin.scala @@ -3,6 +3,8 @@ package vexriscv.plugin import vexriscv.{DecoderService, ExceptionCause, ExceptionService, Stage, Stageable, VexRiscv} import spinal.core._ import spinal.lib._ +import spinal.lib.bus.bmb.WeakConnector +import spinal.lib.bus.misc.{AddressMapping, DefaultMapping} case class CfuParameter(stageCount : Int, allowZeroLatency : Boolean, @@ -23,37 +25,63 @@ case class CfuCmd(p : CfuParameter) extends Bundle{ val reorder_id = UInt(p.CFU_REORDER_ID_W bits) val request_id = UInt(p.CFU_REQ_RESP_ID_W bits) val inputs = Vec(Bits(p.CFU_INPUT_DATA_W bits), p.CFU_INPUTS) + + def weakAssignFrom(m : CfuCmd): Unit ={ + def s = this + WeakConnector(m, s, m.function_id, s.function_id, defaultValue = null, allowUpSize = false, allowDownSize = true , allowDrop = true) + WeakConnector(m, s, m.reorder_id, s.reorder_id, defaultValue = null, allowUpSize = false , allowDownSize = false, allowDrop = false) + WeakConnector(m, s, m.request_id, s.request_id, defaultValue = null, allowUpSize = false, allowDownSize = false, allowDrop = false) + s.inputs := m.inputs + } } case class CfuRsp(p : CfuParameter) extends Bundle{ val response_ok = Bool() val response_id = UInt(p.CFU_REQ_RESP_ID_W bits) val outputs = Vec(Bits(p.CFU_OUTPUT_DATA_W bits), p.CFU_OUTPUTS) + + def weakAssignFrom(m : CfuRsp): Unit ={ + def s = this + s.response_ok := m.response_ok + s.response_id := m.response_id + s.outputs := m.outputs + } } case class CfuBus(p : CfuParameter) extends Bundle with IMasterSlave{ val cmd = Stream(CfuCmd(p)) val rsp = Stream(CfuRsp(p)) + def <<(m : CfuBus) : Unit = { + val s = this + s.cmd.arbitrationFrom(m.cmd) + m.rsp.arbitrationFrom(s.rsp) + + s.cmd.weakAssignFrom(m.cmd) + m.rsp.weakAssignFrom(s.rsp) + } + override def asMaster(): Unit = { master(cmd) slave(rsp) } } + + class CfuPlugin(val p: CfuParameter) extends Plugin[VexRiscv]{ assert(p.CFU_INPUTS <= 2) assert(p.CFU_OUTPUTS == 1) + assert(p.CFU_FUNCTION_ID_W == 3) var bus : CfuBus = null var joinException : Flow[ExceptionCause] = null lazy val forkStage = pipeline.execute - lazy val joinStage = pipeline.stages(Math.min(pipeline.stages.length - 1, pipeline.indexOf(forkStage) + p.stageCount - 1)) + lazy val joinStage = pipeline.stages(Math.min(pipeline.stages.length - 1, pipeline.indexOf(forkStage) + p.stageCount)) object CFU_ENABLE extends Stageable(Bool()) - object CFU_FUNCTION extends Stageable(UInt(p.CFU_FUNCTION_ID_W bits)) object CFU_IN_FLIGHT extends Stageable(Bool()) override def setup(pipeline: VexRiscv): Unit = { @@ -64,21 +92,12 @@ class CfuPlugin(val p: CfuParameter) extends Plugin[VexRiscv]{ joinException = pipeline.service(classOf[ExceptionService]).newExceptionPort(joinStage) val decoderService = pipeline.service(classOf[DecoderService]) + decoderService.addDefault(CFU_ENABLE, False) //custom-0 decoderService.add(List( - M"000000-----------000-----0001011" -> List( + M"000000-------------------0001011" -> List( CFU_ENABLE -> True, - CFU_FUNCTION -> U"00", - REGFILE_WRITE_VALID -> True, - BYPASSABLE_EXECUTE_STAGE -> Bool(p.stageCount == 0), - BYPASSABLE_MEMORY_STAGE -> Bool(p.stageCount <= 1), - RS1_USE -> True, - RS2_USE -> True - ), - M"000000-----------001-----0001011" -> List( - CFU_ENABLE -> True, - CFU_FUNCTION -> U"01", REGFILE_WRITE_VALID -> True, BYPASSABLE_EXECUTE_STAGE -> Bool(p.stageCount == 0), BYPASSABLE_MEMORY_STAGE -> Bool(p.stageCount <= 1), @@ -102,7 +121,7 @@ class CfuPlugin(val p: CfuParameter) extends Plugin[VexRiscv]{ bus.cmd.valid := (schedule || hold) && !fired arbitration.haltItself setWhen(bus.cmd.valid && !bus.cmd.ready) - bus.cmd.function_id := input(CFU_FUNCTION) + bus.cmd.function_id := U(input(INSTRUCTION)(14 downto 12)) bus.cmd.reorder_id := 0 bus.cmd.request_id := 0 if(p.CFU_INPUTS >= 1) bus.cmd.inputs(0) := input(RS1) @@ -132,7 +151,7 @@ class CfuPlugin(val p: CfuParameter) extends Plugin[VexRiscv]{ rsp.ready := False when(input(CFU_IN_FLIGHT)){ arbitration.haltItself setWhen(!rsp.valid) - rsp.ready := arbitration.isStuckByOthers + rsp.ready := !arbitration.isStuckByOthers output(REGFILE_WRITE_DATA) := rsp.outputs(0) when(arbitration.isValid){ @@ -142,3 +161,84 @@ class CfuPlugin(val p: CfuParameter) extends Plugin[VexRiscv]{ } } } + + +object CfuTest{ + def getCfuParameter() = CfuParameter( + stageCount = 0, + allowZeroLatency = true, + CFU_VERSION = 0, + CFU_INTERFACE_ID_W = 0, + CFU_FUNCTION_ID_W = 3, + CFU_REORDER_ID_W = 0, + CFU_REQ_RESP_ID_W = 0, + CFU_INPUTS = 2, + CFU_INPUT_DATA_W = 32, + CFU_OUTPUTS = 1, + CFU_OUTPUT_DATA_W = 32, + CFU_FLOW_REQ_READY_ALWAYS = false, + CFU_FLOW_RESP_READY_ALWAYS = false + ) +} +case class CfuTest() extends Component{ + val io = new Bundle { + val bus = slave(CfuBus(CfuTest.getCfuParameter())) + } + io.bus.rsp.arbitrationFrom(io.bus.cmd) + io.bus.rsp.response_ok := True + io.bus.rsp.response_id := io.bus.cmd.request_id + io.bus.rsp.outputs(0) := ~(io.bus.cmd.inputs(0) & io.bus.cmd.inputs(1)) +} + +case class CfuDecoder(p : CfuParameter, + mappings : Seq[AddressMapping], + pendingMax : Int = 3) extends Component{ + val io = new Bundle { + val input = slave(CfuBus(p)) + val outputs = Vec(master(CfuBus(p)), mappings.size) + } + val hasDefault = mappings.contains(DefaultMapping) + val logic = if(hasDefault && mappings.size == 1){ + io.outputs(0) << io.input + } else new Area { + val hits = Vec(Bool, mappings.size) + for (portId <- 0 until mappings.length) yield { + val slaveBus = io.outputs(portId) + val memorySpace = mappings(portId) + val hit = hits(portId) + hit := (memorySpace match { + case DefaultMapping => !hits.filterNot(_ == hit).orR + case _ => memorySpace.hit(io.input.cmd.function_id) + }) + slaveBus.cmd.valid := io.input.cmd.valid && hit + slaveBus.cmd.payload := io.input.cmd.payload.resized + } + val noHit = if (!hasDefault) !hits.orR else False + io.input.cmd.ready := (hits, io.outputs).zipped.map(_ && _.cmd.ready).orR || noHit + + val rspPendingCounter = Reg(UInt(log2Up(pendingMax + 1) bits)) init(0) + rspPendingCounter := rspPendingCounter + U(io.input.cmd.fire) - U(io.input.rsp.fire) + val rspHits = RegNextWhen(hits, io.input.cmd.fire) + val rspPending = rspPendingCounter =/= 0 + val rspNoHitValid = if (!hasDefault) !rspHits.orR else False + val rspNoHit = !hasDefault generate new Area{ + val doIt = RegInit(False) clearWhen(io.input.rsp.fire) setWhen(io.input.cmd.fire && noHit) + val response_id = RegNextWhen(io.input.cmd.request_id, io.input.cmd.fire) + } + + io.input.rsp.valid := io.outputs.map(_.rsp.valid).orR || (rspPending && rspNoHitValid) + io.input.rsp.payload := io.outputs.map(_.rsp.payload).read(OHToUInt(rspHits)) + if(!hasDefault) when(rspNoHit.doIt) { + io.input.rsp.valid := True + io.input.rsp.response_ok := False + io.input.rsp.response_id := rspNoHit.response_id + } + for(output <- io.outputs) output.rsp.ready := io.input.rsp.ready + + val cmdWait = (rspPending && (hits =/= rspHits || rspNoHitValid)) || rspPendingCounter === pendingMax + when(cmdWait) { + io.input.cmd.ready := False + io.outputs.foreach(_.cmd.valid := False) + } + } +} From 2d56c6738c8712621999e3c7fd75a8deb566aa91 Mon Sep 17 00:00:00 2001 From: Richard Petri Date: Sun, 20 Oct 2019 22:07:43 +0200 Subject: [PATCH 264/951] Multiplication Plugin using 16-bit DSPs --- .../scala/vexriscv/plugin/Mul16Plugin.scala | 119 ++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 src/main/scala/vexriscv/plugin/Mul16Plugin.scala diff --git a/src/main/scala/vexriscv/plugin/Mul16Plugin.scala b/src/main/scala/vexriscv/plugin/Mul16Plugin.scala new file mode 100644 index 00000000..f2a63c31 --- /dev/null +++ b/src/main/scala/vexriscv/plugin/Mul16Plugin.scala @@ -0,0 +1,119 @@ +package vexriscv.plugin + +import vexriscv._ +import vexriscv.plugin._ +import spinal.core._ + +/** + * A multiplication plugin using only 16-bit multiplications + */ +class Mul16Plugin extends Plugin[VexRiscv]{ + + object MUL_LL extends Stageable(UInt(32 bits)) + object MUL_LH extends Stageable(UInt(32 bits)) + object MUL_HL extends Stageable(UInt(32 bits)) + object MUL_HH extends Stageable(UInt(32 bits)) + + object MUL extends Stageable(Bits(64 bits)) + + object IS_MUL extends Stageable(Bool) + + override def setup(pipeline: VexRiscv): Unit = { + import Riscv._ + import pipeline.config._ + + + val actions = List[(Stageable[_ <: BaseType],Any)]( + SRC1_CTRL -> Src1CtrlEnum.RS, + SRC2_CTRL -> Src2CtrlEnum.RS, + REGFILE_WRITE_VALID -> True, + BYPASSABLE_EXECUTE_STAGE -> False, + BYPASSABLE_MEMORY_STAGE -> False, + RS1_USE -> True, + RS2_USE -> True, + IS_MUL -> True + ) + + val decoderService = pipeline.service(classOf[DecoderService]) + decoderService.addDefault(IS_MUL, False) + decoderService.add(List( + MULX -> actions + )) + + } + + override def build(pipeline: VexRiscv): Unit = { + import pipeline._ + import pipeline.config._ + + // Prepare signed inputs for the multiplier in the next stage. + // This will map them best to an FPGA DSP. + execute plug new Area { + import execute._ + val a,b = Bits(32 bit) + + a := input(SRC1) + b := input(SRC2) + + val aLow = a(15 downto 0).asUInt + val bLow = b(15 downto 0).asUInt + val aHigh = a(31 downto 16).asUInt + val bHigh = b(31 downto 16).asUInt + + insert(MUL_LL) := aLow * bLow + insert(MUL_LH) := aLow * bHigh + insert(MUL_HL) := aHigh * bLow + insert(MUL_HH) := aHigh * bHigh + } + + memory plug new Area { + import memory._ + + val ll = UInt(32 bits) + val lh = UInt(33 bits) + val hl = UInt(32 bits) + val hh = UInt(32 bits) + + ll := input(MUL_LL) + lh := input(MUL_LH).resized + hl := input(MUL_HL) + hh := input(MUL_HH) + + val hllh = lh + hl + insert(MUL) := ((hh ## ll(31 downto 16)).asUInt + hllh) ## ll(15 downto 0) + } + + writeBack plug new Area { + import writeBack._ + val aSigned,bSigned = Bool + switch(input(INSTRUCTION)(13 downto 12)) { + is(B"01") { + aSigned := True + bSigned := True + } + is(B"10") { + aSigned := True + bSigned := False + } + default { + aSigned := False + bSigned := False + } + } + + val a = (aSigned && input(SRC1).msb) ? input(SRC2).asUInt | U(0) + val b = (bSigned && input(SRC2).msb) ? input(SRC1).asUInt | U(0) + + when(arbitration.isValid && input(IS_MUL)){ + switch(input(INSTRUCTION)(13 downto 12)){ + is(B"00"){ + output(REGFILE_WRITE_DATA) := input(MUL)(31 downto 0) + } + is(B"01",B"10",B"11"){ + output(REGFILE_WRITE_DATA) := (((input(MUL)(63 downto 32)).asUInt + ~a) + (~b + 2)).asBits + } + } + } + } + } +} From 8091a872f3b4d2e01135c8f1e5e4f471b8ddaa41 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Mon, 21 Oct 2019 12:53:03 +0200 Subject: [PATCH 265/951] Fix muldiv plugin for CPU configs without memory/writeback stages --- .../plugin/MulDivIterativePlugin.scala | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/MulDivIterativePlugin.scala b/src/main/scala/vexriscv/plugin/MulDivIterativePlugin.scala index 1bd8fb4d..a97a0acb 100644 --- a/src/main/scala/vexriscv/plugin/MulDivIterativePlugin.scala +++ b/src/main/scala/vexriscv/plugin/MulDivIterativePlugin.scala @@ -78,13 +78,19 @@ class MulDivIterativePlugin(genMul : Boolean = true, val rs2 = Reg(UInt(32 bits)) val accumulator = Reg(UInt(65 bits)) + //FrontendOK is only used for CPU configs without memory/writeback stages, were it is required to wait one extra cycle + // to let's the frontend process rs1 rs2 registers + val frontendOk = if(flushStage != execute) True else RegInit(False) setWhen(arbitration.isValid && ((if(genDiv) input(IS_DIV) else False) || (if(genMul) input(IS_MUL) else False))) clearWhen(arbitration.isMoving) val mul = ifGen(genMul) (if(customMul != null) customMul(rs1,rs2,memory,pipeline) else new Area{ assert(isPow2(mulUnrollFactor)) val counter = Counter(32 / mulUnrollFactor + 1) val done = counter.willOverflowIfInc when(arbitration.isValid && input(IS_MUL)){ - when(!done){ + when(!frontendOk || !done){ + arbitration.haltItself := True + } + when(frontendOk && !done){ arbitration.haltItself := True counter.increment() rs2 := rs2 |>> mulUnrollFactor @@ -113,8 +119,10 @@ class MulDivIterativePlugin(genMul : Boolean = true, val done = Reg(Bool) setWhen(counter === counter.end-1) clearWhen(!arbitration.isStuck) val result = Reg(Bits(32 bits)) when(arbitration.isValid && input(IS_DIV)){ - when(!done){ + when(!frontendOk || !done){ arbitration.haltItself := True + } + when(frontendOk && !done){ counter.increment() def stages(inNumerator: UInt, inRemainder: UInt, stage: Int): Unit = stage match { @@ -140,16 +148,11 @@ class MulDivIterativePlugin(genMul : Boolean = true, } output(REGFILE_WRITE_DATA) := result -// when(input(INSTRUCTION)(13 downto 12) === "00" && counter === 0 && rs2 =/= 0 && rs1 < 16 && rs2 < 16 && !input(RS1).msb && !input(RS2).msb) { -// output(REGFILE_WRITE_DATA) := B(rs1(3 downto 0) / rs2(3 downto 0)).resized -// counter.willIncrement := False -// arbitration.haltItself := False -// } } }) //Execute stage logic to drive memory stage's input regs - when(!arbitration.isStuck){ + when(if(flushStage != execute) !arbitration.isStuck else !frontendOk){ accumulator := 0 def twoComplement(that : Bits, enable: Bool): UInt = (Mux(enable, ~that, that).asUInt + enable.asUInt) val rs2NeedRevert = execute.input(RS2).msb && execute.input(IS_RS2_SIGNED) From 67028cdb48ce9087aa6c5168d8b0c10584a3ce04 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Mon, 21 Oct 2019 12:53:53 +0200 Subject: [PATCH 266/951] Add Mul16Plugin to regression tests Fix missing MulSimplePlugin in regressions tests --- .../vexriscv/TestIndividualFeatures.scala | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/test/scala/vexriscv/TestIndividualFeatures.scala b/src/test/scala/vexriscv/TestIndividualFeatures.scala index efa975ce..005f3359 100644 --- a/src/test/scala/vexriscv/TestIndividualFeatures.scala +++ b/src/test/scala/vexriscv/TestIndividualFeatures.scala @@ -102,7 +102,7 @@ class MulDivDimension extends VexRiscvDimension("MulDiv") { - new VexRiscvPosition("MulDivFpgaSimple") { + l = new VexRiscvPosition("MulDivFpgaSimple") { override def testParam = "MUL=yes DIV=yes" override def applyOn(config: VexRiscvConfig): Unit = { config.plugins += new MulSimplePlugin @@ -115,6 +115,19 @@ class MulDivDimension extends VexRiscvDimension("MulDiv") { } } :: l + if(!noMemory && !noWriteBack) l = new VexRiscvPosition("MulDivFpga16BitsDsp") { + override def testParam = "MUL=yes DIV=yes" + override def applyOn(config: VexRiscvConfig): Unit = { + config.plugins += new Mul16Plugin + config.plugins += new MulDivIterativePlugin( + genMul = false, + genDiv = true, + mulUnrollFactor = 32, + divUnrollFactor = 1 + ) + } + } :: l + if(!noMemory) { l = new VexRiscvPosition("MulDivAsic") { override def testParam = "MUL=yes DIV=yes" @@ -619,9 +632,9 @@ class TestIndividualFeatures extends FunSuite { val seed = sys.env.getOrElse("VEXRISCV_REGRESSION_SEED", Random.nextLong().toString).toLong // // val testId = Some(mutable.HashSet(3,4,9,11,13,16,18,19,20,21)) -// val testId = Some(mutable.HashSet(22)) -// val testId = Some(mutable.HashSet(22, 33 , 38, 47, 48)) -// val seed = 5426556825163943143l +// val testId = Some(mutable.HashSet(11)) +// val testId = Some(mutable.HashSet(4, 11)) +// val seed = 6592877339343561798l val rand = new Random(seed) From bb9261773b26513e3e983e6951500307b3f8fe62 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Wed, 23 Oct 2019 00:02:08 +0200 Subject: [PATCH 267/951] Fix MulDiveIterative plugin when RSx have hazard in the execute stage --- src/main/scala/vexriscv/plugin/MulDivIterativePlugin.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/plugin/MulDivIterativePlugin.scala b/src/main/scala/vexriscv/plugin/MulDivIterativePlugin.scala index a97a0acb..6820f8ec 100644 --- a/src/main/scala/vexriscv/plugin/MulDivIterativePlugin.scala +++ b/src/main/scala/vexriscv/plugin/MulDivIterativePlugin.scala @@ -80,7 +80,7 @@ class MulDivIterativePlugin(genMul : Boolean = true, //FrontendOK is only used for CPU configs without memory/writeback stages, were it is required to wait one extra cycle // to let's the frontend process rs1 rs2 registers - val frontendOk = if(flushStage != execute) True else RegInit(False) setWhen(arbitration.isValid && ((if(genDiv) input(IS_DIV) else False) || (if(genMul) input(IS_MUL) else False))) clearWhen(arbitration.isMoving) + val frontendOk = if(flushStage != execute) True else RegInit(False) setWhen(arbitration.isValid && !pipeline.service(classOf[HazardService]).hazardOnExecuteRS && ((if(genDiv) input(IS_DIV) else False) || (if(genMul) input(IS_MUL) else False))) clearWhen(arbitration.isMoving) val mul = ifGen(genMul) (if(customMul != null) customMul(rs1,rs2,memory,pipeline) else new Area{ assert(isPow2(mulUnrollFactor)) From bd2787b562a66aa97b3e101cbcf91fc00dd2e73b Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Fri, 1 Nov 2019 16:24:07 +0100 Subject: [PATCH 268/951] RegFilePlugin project X0 against boot glitches if no x0Init but zeroBoot --- src/main/scala/vexriscv/plugin/RegFilePlugin.scala | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/scala/vexriscv/plugin/RegFilePlugin.scala b/src/main/scala/vexriscv/plugin/RegFilePlugin.scala index 2da66dea..a34dc462 100644 --- a/src/main/scala/vexriscv/plugin/RegFilePlugin.scala +++ b/src/main/scala/vexriscv/plugin/RegFilePlugin.scala @@ -96,6 +96,11 @@ class RegFilePlugin(regFileReadyKind : RegFileReadKind, regFileWrite.address := U(shadowPrefix(output(INSTRUCTION)(rdRange))) regFileWrite.data := output(REGFILE_WRITE_DATA) + //Ensure no boot glitches modify X0 + if(!x0Init && zeroBoot) when(regFileWrite.address === 0){ + regFileWrite.valid := False + } + //CPU will initialise constant register zero in the first cycle if(x0Init) { val boot = RegNext(False) init (True) From 2bf6a536c9ab1be9eac754dbf91e6d6a38b82820 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Sun, 3 Nov 2019 16:43:29 +0100 Subject: [PATCH 269/951] Fix DBus AXI bridges from writePending counter deadlock --- src/main/scala/vexriscv/ip/DataCache.scala | 9 +++++---- .../scala/vexriscv/plugin/DBusSimplePlugin.scala | 12 +++++++----- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index f6926806..591e36e2 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -184,16 +184,17 @@ case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave slave(rsp) } - def toAxi4Shared(stageCmd : Boolean = false): Axi4Shared = { + def toAxi4Shared(stageCmd : Boolean = false, pendingWritesMax : Int = 7): Axi4Shared = { val axi = Axi4Shared(p.getAxi4SharedConfig()) - val pendingWritesMax = 7 + + val cmdPreFork = if (stageCmd) cmd.stage.stage().s2mPipe() else cmd + val pendingWrites = CounterUpDown( stateCount = pendingWritesMax + 1, - incWhen = axi.sharedCmd.fire && axi.sharedCmd.write, + incWhen = cmdPreFork.fire && cmdPreFork.wr, decWhen = axi.writeRsp.fire ) - val cmdPreFork = if (stageCmd) cmd.stage.stage().s2mPipe() else cmd val hazard = (pendingWrites =/= 0 && !cmdPreFork.wr) || pendingWrites === pendingWritesMax val (cmdFork, dataFork) = StreamFork2(cmdPreFork.haltWhen(hazard)) val cmdStage = cmdFork.throwWhen(RegNextWhen(!cmdFork.last,cmdFork.fire).init(False)) diff --git a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala index fe5ac775..e08b6402 100644 --- a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala @@ -106,17 +106,19 @@ case class DBusSimpleBus() extends Bundle with IMasterSlave{ s } - def toAxi4Shared(stageCmd : Boolean = false): Axi4Shared = { + def toAxi4Shared(stageCmd : Boolean = false, pendingWritesMax : Int = 7): Axi4Shared = { val axi = Axi4Shared(DBusSimpleBus.getAxi4Config()) - val pendingWritesMax = 7 + + val cmdPreFork = if (stageCmd) cmd.stage.stage().s2mPipe() else cmd + val pendingWrites = CounterUpDown( stateCount = pendingWritesMax + 1, - incWhen = axi.sharedCmd.fire && axi.sharedCmd.write, + incWhen = cmdPreFork.fire && cmdPreFork.wr, decWhen = axi.writeRsp.fire ) - val cmdPreFork = if (stageCmd) cmd.stage.stage().s2mPipe() else cmd - val (cmdFork, dataFork) = StreamFork2(cmdPreFork.haltWhen((pendingWrites =/= 0 && cmdPreFork.valid && !cmdPreFork.wr) || pendingWrites === pendingWritesMax)) + val hazard = (pendingWrites =/= 0 && cmdPreFork.valid && !cmdPreFork.wr) || pendingWrites === pendingWritesMax + val (cmdFork, dataFork) = StreamFork2(cmdPreFork.haltWhen(hazard)) axi.sharedCmd.arbitrationFrom(cmdFork) axi.sharedCmd.write := cmdFork.wr axi.sharedCmd.prot := "010" From 8839f8a8e9c443e59c04291a00b1ee5c3cec6d62 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Sun, 3 Nov 2019 16:43:29 +0100 Subject: [PATCH 270/951] Fix DBus AXI bridges from writePending counter deadlock --- src/main/scala/vexriscv/ip/DataCache.scala | 9 +++++---- .../scala/vexriscv/plugin/DBusSimplePlugin.scala | 12 +++++++----- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index 17c4bf60..838489d2 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -185,16 +185,17 @@ case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave slave(rsp) } - def toAxi4Shared(stageCmd : Boolean = false): Axi4Shared = { + def toAxi4Shared(stageCmd : Boolean = false, pendingWritesMax : Int = 7): Axi4Shared = { val axi = Axi4Shared(p.getAxi4SharedConfig()) - val pendingWritesMax = 7 + + val cmdPreFork = if (stageCmd) cmd.stage.stage().s2mPipe() else cmd + val pendingWrites = CounterUpDown( stateCount = pendingWritesMax + 1, - incWhen = axi.sharedCmd.fire && axi.sharedCmd.write, + incWhen = cmdPreFork.fire && cmdPreFork.wr, decWhen = axi.writeRsp.fire ) - val cmdPreFork = if (stageCmd) cmd.stage.stage().s2mPipe() else cmd val hazard = (pendingWrites =/= 0 && !cmdPreFork.wr) || pendingWrites === pendingWritesMax val (cmdFork, dataFork) = StreamFork2(cmdPreFork.haltWhen(hazard)) val cmdStage = cmdFork.throwWhen(RegNextWhen(!cmdFork.last,cmdFork.fire).init(False)) diff --git a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala index fe5ac775..e08b6402 100644 --- a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala @@ -106,17 +106,19 @@ case class DBusSimpleBus() extends Bundle with IMasterSlave{ s } - def toAxi4Shared(stageCmd : Boolean = false): Axi4Shared = { + def toAxi4Shared(stageCmd : Boolean = false, pendingWritesMax : Int = 7): Axi4Shared = { val axi = Axi4Shared(DBusSimpleBus.getAxi4Config()) - val pendingWritesMax = 7 + + val cmdPreFork = if (stageCmd) cmd.stage.stage().s2mPipe() else cmd + val pendingWrites = CounterUpDown( stateCount = pendingWritesMax + 1, - incWhen = axi.sharedCmd.fire && axi.sharedCmd.write, + incWhen = cmdPreFork.fire && cmdPreFork.wr, decWhen = axi.writeRsp.fire ) - val cmdPreFork = if (stageCmd) cmd.stage.stage().s2mPipe() else cmd - val (cmdFork, dataFork) = StreamFork2(cmdPreFork.haltWhen((pendingWrites =/= 0 && cmdPreFork.valid && !cmdPreFork.wr) || pendingWrites === pendingWritesMax)) + val hazard = (pendingWrites =/= 0 && cmdPreFork.valid && !cmdPreFork.wr) || pendingWrites === pendingWritesMax + val (cmdFork, dataFork) = StreamFork2(cmdPreFork.haltWhen(hazard)) axi.sharedCmd.arbitrationFrom(cmdFork) axi.sharedCmd.write := cmdFork.wr axi.sharedCmd.prot := "010" From f6e707a6394be16a78efe6608019c9596bedd189 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Piku=C5=82a?= Date: Thu, 7 Nov 2019 14:47:36 +0100 Subject: [PATCH 271/951] Update index links in README Eclipse links in index were incorrect. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2af47aa5..d0deb166 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,8 @@ - [Regression tests](#regression-tests) - [Interactive debug of the simulated CPU via GDB OpenOCD and Verilator](#interactive-debug-of-the-simulated-cpu-via-gdb-openocd-and-verilator) - [Using Eclipse to run the software and debug it](#using-Eclipse-to-run-the-software-and-debug-it) - * [By using Zylin plugin](#by-using-zylin-plugin) - * [By using FreedomStudio](#by-using-freedomstudio) + * [By using gnu-mcu-eclipse](#by-using-gnu-mcu-eclipse) + * [By using Zylin plugin (old)](#by-using-zylin-plugin-old) - [Briey SoC](#briey-soc) - [Murax SoC](#murax-soc) - [Running Linux](#running-linux) From bb405e705b2b3550529e62840619837a0c5aa4a3 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Thu, 7 Nov 2019 19:52:32 +0100 Subject: [PATCH 272/951] Add UserInterruptPlugin --- .../vexriscv/demo/GenCustomInterrupt.scala | 67 +++++++++++++++++++ .../scala/vexriscv/plugin/CsrPlugin.scala | 23 +++++-- 2 files changed, 86 insertions(+), 4 deletions(-) create mode 100644 src/main/scala/vexriscv/demo/GenCustomInterrupt.scala diff --git a/src/main/scala/vexriscv/demo/GenCustomInterrupt.scala b/src/main/scala/vexriscv/demo/GenCustomInterrupt.scala new file mode 100644 index 00000000..cb8ef4ff --- /dev/null +++ b/src/main/scala/vexriscv/demo/GenCustomInterrupt.scala @@ -0,0 +1,67 @@ +package vexriscv.demo + +import spinal.core._ +import vexriscv.plugin._ +import vexriscv.{VexRiscv, VexRiscvConfig, plugin} + +/** + * Created by spinalvm on 15.06.17. + */ +object GenCustomInterrupt extends App{ + def cpu() = new VexRiscv( + config = VexRiscvConfig( + plugins = List( + new UserInterruptPlugin( + interruptName = "miaou", + code = 20 + ), + new UserInterruptPlugin( + interruptName = "rawrrr", + code = 24 + ), + new IBusSimplePlugin( + resetVector = 0x80000000l, + cmdForkOnSecondStage = false, + cmdForkPersistence = false, + prediction = NONE, + catchAccessFault = false, + compressedGen = false + ), + new DBusSimplePlugin( + catchAddressMisaligned = false, + catchAccessFault = false + ), + new CsrPlugin(CsrPluginConfig.smallest), + new DecoderSimplePlugin( + catchIllegalInstruction = false + ), + new RegFilePlugin( + regFileReadyKind = plugin.SYNC, + zeroBoot = false + ), + new IntAluPlugin, + new SrcPlugin( + separatedAddSub = false, + executeInsertion = true + ), + new LightShifterPlugin, + new HazardSimplePlugin( + bypassExecute = true, + bypassMemory = true, + bypassWriteBack = true, + bypassWriteBackBuffer = true, + pessimisticUseSrc = false, + pessimisticWriteRegFile = false, + pessimisticAddressMatch = false + ), + new BranchPlugin( + earlyBranch = false, + catchAddressMisaligned = false + ), + new YamlPlugin("cpu0.yaml") + ) + ) + ) + + SpinalVerilog(cpu()) +} diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 5c7e0326..c93eaf70 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -322,7 +322,6 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep //Mannage ExceptionService calls val exceptionPortsInfos = ArrayBuffer[ExceptionPortInfo]() - def exceptionCodeWidth = 4 override def newExceptionPort(stage : Stage, priority : Int = 0) = { val interface = Flow(ExceptionCause()) exceptionPortsInfos += ExceptionPortInfo(interface,stage,priority) @@ -459,6 +458,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep import pipeline._ import pipeline.config._ val fetcher = service(classOf[IBusFetcher]) + val trapCodeWidth = log2Up((List(16) ++ interruptSpecs.map(_.id + 1) ++ exceptionPortsInfos.map(p => 1 << widthOf(p.port.code))).max) //Define CSR mapping utilities implicit class CsrAccessPimper(csrAccess : CsrAccess){ @@ -511,7 +511,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep val mscratch = if(mscratchGen) Reg(Bits(xlen bits)) else null val mcause = new Area{ val interrupt = Reg(Bool) - val exceptionCode = Reg(UInt(exceptionCodeWidth bits)) + val exceptionCode = Reg(UInt(trapCodeWidth bits)) } val mtval = Reg(UInt(xlen bits)) val mcycle = Reg(UInt(64 bits)) randBoot() @@ -582,7 +582,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep val scause = new Area { val interrupt = Reg(Bool) - val exceptionCode = Reg(UInt(exceptionCodeWidth bits)) + val exceptionCode = Reg(UInt(trapCodeWidth bits)) } val stval = Reg(UInt(xlen bits)) val sepc = Reg(UInt(xlen bits)) @@ -733,7 +733,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep //Process interrupt request, code and privilege val interrupt = new Area { val valid = if(pipelinedInterrupt) RegNext(False) init(False) else False - val code = if(pipelinedInterrupt) Reg(UInt(4 bits)) else UInt(4 bits).assignDontCare() + val code = if(pipelinedInterrupt) Reg(UInt(trapCodeWidth bits)) else UInt(trapCodeWidth bits).assignDontCare() var privilegs = if (supervisorGen) List(1, 3) else List(3) val targetPrivilege = if(pipelinedInterrupt) Reg(UInt(2 bits)) else UInt(2 bits).assignDontCare() val privilegeAllowInterrupts = mutable.HashMap[Int, Bool]() @@ -1044,3 +1044,18 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep } } } + + +class UserInterruptPlugin(interruptName : String, code : Int, privilege : Int = 3) extends Plugin[VexRiscv]{ + var interrupt, interruptEnable : Bool = null + override def setup(pipeline: VexRiscv): Unit = { + val csr = pipeline.service(classOf[CsrPlugin]) + interrupt = in.Bool().setName(interruptName) + val interruptPending = RegNext(interrupt) init(False) + val interruptEnable = RegInit(False).setName(interruptName + "_enable") + csr.addInterrupt(interruptPending , code, privilege, Nil) + csr.r(csrAddress = CSR.MIP, bitOffset = code,interruptPending) + csr.rw(csrAddress = CSR.MIE, bitOffset = code, interruptEnable) + } + override def build(pipeline: VexRiscv): Unit = {} +} \ No newline at end of file From 4fe7fa56c788d641ce5be67a702b075b9a24c8c2 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Thu, 7 Nov 2019 19:55:26 +0100 Subject: [PATCH 273/951] GenCustomInterrupt demo now enabled vectored interrupt --- src/main/scala/vexriscv/demo/GenCustomInterrupt.scala | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/demo/GenCustomInterrupt.scala b/src/main/scala/vexriscv/demo/GenCustomInterrupt.scala index cb8ef4ff..d0d9e485 100644 --- a/src/main/scala/vexriscv/demo/GenCustomInterrupt.scala +++ b/src/main/scala/vexriscv/demo/GenCustomInterrupt.scala @@ -19,6 +19,12 @@ object GenCustomInterrupt extends App{ interruptName = "rawrrr", code = 24 ), + new CsrPlugin( + CsrPluginConfig.smallest.copy( + xtvecModeGen = true, + mtvecAccess = CsrAccess.WRITE_ONLY + ) + ), new IBusSimplePlugin( resetVector = 0x80000000l, cmdForkOnSecondStage = false, @@ -31,7 +37,6 @@ object GenCustomInterrupt extends App{ catchAddressMisaligned = false, catchAccessFault = false ), - new CsrPlugin(CsrPluginConfig.smallest), new DecoderSimplePlugin( catchIllegalInstruction = false ), From 6d0d70364c88307d48267cc272a4b210b2cc7094 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Thu, 7 Nov 2019 21:40:39 +0100 Subject: [PATCH 274/951] Add BranchPlugin.decodeBranchSrc2 for branch target configs --- src/main/scala/vexriscv/plugin/BranchPlugin.scala | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/BranchPlugin.scala b/src/main/scala/vexriscv/plugin/BranchPlugin.scala index 6559a7f8..77f72b8e 100644 --- a/src/main/scala/vexriscv/plugin/BranchPlugin.scala +++ b/src/main/scala/vexriscv/plugin/BranchPlugin.scala @@ -53,7 +53,8 @@ trait PredictionInterface{ class BranchPlugin(earlyBranch : Boolean, catchAddressMisaligned : Boolean = false, fenceiGenAsAJump : Boolean = false, - fenceiGenAsANop : Boolean = false) extends Plugin[VexRiscv] with PredictionInterface{ + fenceiGenAsANop : Boolean = false, + decodeBranchSrc2 : Boolean = false) extends Plugin[VexRiscv] with PredictionInterface{ def catchAddressMisalignedForReal = catchAddressMisaligned && !pipeline(RVC_GEN) @@ -310,6 +311,8 @@ class BranchPlugin(earlyBranch : Boolean, //Do branch calculations (conditions + target PC) object NEXT_PC extends Stageable(UInt(32 bits)) object TARGET_MISSMATCH extends Stageable(Bool) + object BRANCH_SRC2 extends Stageable(UInt(32 bits)) + val branchSrc2Stage = if(decodeBranchSrc2) decode else execute execute plug new Area { import execute._ @@ -328,15 +331,16 @@ class BranchPlugin(earlyBranch : Boolean, ) ) - val imm = IMM(input(INSTRUCTION)) val branch_src1 = (input(BRANCH_CTRL) === BranchCtrlEnum.JALR) ? input(RS1).asUInt | input(PC) - val branch_src2 = input(BRANCH_CTRL).mux( + + val imm = IMM(branchSrc2Stage.input(INSTRUCTION)) + branchSrc2Stage.insert(BRANCH_SRC2) := branchSrc2Stage.input(BRANCH_CTRL).mux( BranchCtrlEnum.JAL -> imm.j_sext, BranchCtrlEnum.JALR -> imm.i_sext, default -> imm.b_sext ).asUInt - val branchAdder = branch_src1 + branch_src2 + val branchAdder = branch_src1 + input(BRANCH_SRC2) insert(BRANCH_CALC) := branchAdder(31 downto 1) @@ "0" insert(NEXT_PC) := input(PC) + (if(pipeline(RVC_GEN)) ((input(IS_RVC)) ? U(2) | U(4)) else 4) insert(TARGET_MISSMATCH) := decode.input(PC) =/= input(BRANCH_CALC) From 7ae218704e0e1849395e9bd64f58f34ce391b88d Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Tue, 19 Nov 2019 18:36:42 +0100 Subject: [PATCH 275/951] CsrPlugin now implement a IWake interface DebugPlugin now wake the CPU if a halt is asked to flush the pipeline --- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 13 +++++++++++-- src/main/scala/vexriscv/plugin/DebugPlugin.scala | 5 +++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index c93eaf70..0c9b7dcc 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -311,8 +311,11 @@ trait CsrInterface{ trait IContextSwitching{ def isContextSwitching : Bool } +trait IWake{ + def askWake() : Unit +} -class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with ExceptionService with PrivilegeService with InterruptionInhibitor with ExceptionInhibitor with IContextSwitching with CsrInterface{ +class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with ExceptionService with PrivilegeService with InterruptionInhibitor with ExceptionInhibitor with IContextSwitching with CsrInterface with IWake{ import config._ import CsrAccess._ @@ -338,6 +341,10 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep var privilege : UInt = null var selfException : Flow[ExceptionCause] = null var contextSwitching : Bool = null + var thirdPartyWake : Bool = null + + override def askWake(): Unit = thirdPartyWake := True + override def isContextSwitching = contextSwitching object EnvCtrlEnum extends SpinalEnum(binarySequential){ @@ -378,6 +385,8 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep override def setup(pipeline: VexRiscv): Unit = { import pipeline.config._ + thirdPartyWake = False + val defaultEnv = List[(Stageable[_ <: BaseType],Any)]( ) @@ -886,7 +895,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep import execute._ //Manage WFI instructions val inWfi = False.addTag(Verilator.public) - val wfiWake = RegNext(interruptSpecs.map(_.cond).orR) init(False) + val wfiWake = RegNext(interruptSpecs.map(_.cond).orR || thirdPartyWake) init(False) if(wfiGenAsWait) when(arbitration.isValid && input(ENV_CTRL) === EnvCtrlEnum.WFI){ inWfi := True when(!wfiWake){ diff --git a/src/main/scala/vexriscv/plugin/DebugPlugin.scala b/src/main/scala/vexriscv/plugin/DebugPlugin.scala index 4088cecd..1b0084be 100644 --- a/src/main/scala/vexriscv/plugin/DebugPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DebugPlugin.scala @@ -246,6 +246,11 @@ class DebugPlugin(val debugClockDomain : ClockDomain, hardwareBreakpointCount : } if(pipeline.things.contains(DEBUG_BYPASS_CACHE)) pipeline(DEBUG_BYPASS_CACHE) := True } + + val wakeService = serviceElse(classOf[IWake], null) + if(wakeService != null) when(haltIt){ + wakeService.askWake() + } }} } } From 744b040c70448c082fd092ce972c07edd5dc1728 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Fri, 29 Nov 2019 11:50:00 +0100 Subject: [PATCH 276/951] Sync CFU progress --- .../demo/GenSmallAndProductiveCfu.scala | 7 +- .../scala/vexriscv/plugin/CfuPlugin.scala | 83 ++++++++++++++----- 2 files changed, 68 insertions(+), 22 deletions(-) diff --git a/src/main/scala/vexriscv/demo/GenSmallAndProductiveCfu.scala b/src/main/scala/vexriscv/demo/GenSmallAndProductiveCfu.scala index 99838143..c500452f 100644 --- a/src/main/scala/vexriscv/demo/GenSmallAndProductiveCfu.scala +++ b/src/main/scala/vexriscv/demo/GenSmallAndProductiveCfu.scala @@ -51,9 +51,10 @@ object GenSmallAndProductiveCfu extends App{ catchAddressMisaligned = false ), new CfuPlugin( - p = CfuParameter( - stageCount = 1, - allowZeroLatency = true, + stageCount = 1, + allowZeroLatency = true, + encoding = M"000000-------------------0001011", + busParameter = CfuBusParameter( CFU_VERSION = 0, CFU_INTERFACE_ID_W = 0, CFU_FUNCTION_ID_W = 2, diff --git a/src/main/scala/vexriscv/plugin/CfuPlugin.scala b/src/main/scala/vexriscv/plugin/CfuPlugin.scala index 3da804f9..d5aaf1c5 100644 --- a/src/main/scala/vexriscv/plugin/CfuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CfuPlugin.scala @@ -6,8 +6,7 @@ import spinal.lib._ import spinal.lib.bus.bmb.WeakConnector import spinal.lib.bus.misc.{AddressMapping, DefaultMapping} -case class CfuParameter(stageCount : Int, - allowZeroLatency : Boolean, +case class CfuPluginParameter( CFU_VERSION : Int, CFU_INTERFACE_ID_W : Int, CFU_FUNCTION_ID_W : Int, @@ -20,7 +19,19 @@ case class CfuParameter(stageCount : Int, CFU_FLOW_REQ_READY_ALWAYS : Boolean, CFU_FLOW_RESP_READY_ALWAYS : Boolean) -case class CfuCmd(p : CfuParameter) extends Bundle{ +case class CfuBusParameter(CFU_VERSION : Int, + CFU_INTERFACE_ID_W : Int, + CFU_FUNCTION_ID_W : Int, + CFU_REORDER_ID_W : Int, + CFU_REQ_RESP_ID_W : Int, + CFU_INPUTS : Int, + CFU_INPUT_DATA_W : Int, + CFU_OUTPUTS : Int, + CFU_OUTPUT_DATA_W : Int, + CFU_FLOW_REQ_READY_ALWAYS : Boolean, + CFU_FLOW_RESP_READY_ALWAYS : Boolean) + +case class CfuCmd( p : CfuBusParameter ) extends Bundle{ val function_id = UInt(p.CFU_FUNCTION_ID_W bits) val reorder_id = UInt(p.CFU_REORDER_ID_W bits) val request_id = UInt(p.CFU_REQ_RESP_ID_W bits) @@ -35,7 +46,7 @@ case class CfuCmd(p : CfuParameter) extends Bundle{ } } -case class CfuRsp(p : CfuParameter) extends Bundle{ +case class CfuRsp(p : CfuBusParameter) extends Bundle{ val response_ok = Bool() val response_id = UInt(p.CFU_REQ_RESP_ID_W bits) val outputs = Vec(Bits(p.CFU_OUTPUT_DATA_W bits), p.CFU_OUTPUTS) @@ -48,7 +59,7 @@ case class CfuRsp(p : CfuParameter) extends Bundle{ } } -case class CfuBus(p : CfuParameter) extends Bundle with IMasterSlave{ +case class CfuBus(p : CfuBusParameter) extends Bundle with IMasterSlave{ val cmd = Stream(CfuCmd(p)) val rsp = Stream(CfuRsp(p)) @@ -69,7 +80,12 @@ case class CfuBus(p : CfuParameter) extends Bundle with IMasterSlave{ -class CfuPlugin(val p: CfuParameter) extends Plugin[VexRiscv]{ +class CfuPlugin( val stageCount : Int, + val allowZeroLatency : Boolean, + val encoding : MaskedLiteral, + val busParameter : CfuBusParameter) extends Plugin[VexRiscv]{ + def p = busParameter + assert(p.CFU_INPUTS <= 2) assert(p.CFU_OUTPUTS == 1) assert(p.CFU_FUNCTION_ID_W == 3) @@ -78,11 +94,12 @@ class CfuPlugin(val p: CfuParameter) extends Plugin[VexRiscv]{ var joinException : Flow[ExceptionCause] = null lazy val forkStage = pipeline.execute - lazy val joinStage = pipeline.stages(Math.min(pipeline.stages.length - 1, pipeline.indexOf(forkStage) + p.stageCount)) + lazy val joinStage = pipeline.stages(Math.min(pipeline.stages.length - 1, pipeline.indexOf(forkStage) + stageCount)) - object CFU_ENABLE extends Stageable(Bool()) - object CFU_IN_FLIGHT extends Stageable(Bool()) + val CFU_ENABLE = new Stageable(Bool()).setCompositeName(this, "CFU_ENABLE") + val CFU_IN_FLIGHT = new Stageable(Bool()).setCompositeName(this, "CFU_IN_FLIGHT") + override def setup(pipeline: VexRiscv): Unit = { import pipeline._ @@ -96,11 +113,11 @@ class CfuPlugin(val p: CfuParameter) extends Plugin[VexRiscv]{ //custom-0 decoderService.add(List( - M"000000-------------------0001011" -> List( + encoding -> List( CFU_ENABLE -> True, REGFILE_WRITE_VALID -> True, - BYPASSABLE_EXECUTE_STAGE -> Bool(p.stageCount == 0), - BYPASSABLE_MEMORY_STAGE -> Bool(p.stageCount <= 1), + BYPASSABLE_EXECUTE_STAGE -> Bool(stageCount == 0), + BYPASSABLE_MEMORY_STAGE -> Bool(stageCount <= 1), RS1_USE -> True, RS2_USE -> True ) @@ -111,6 +128,7 @@ class CfuPlugin(val p: CfuParameter) extends Plugin[VexRiscv]{ import pipeline._ import pipeline.config._ + forkStage plug new Area{ import forkStage._ val schedule = arbitration.isValid && input(CFU_ENABLE) @@ -121,7 +139,7 @@ class CfuPlugin(val p: CfuParameter) extends Plugin[VexRiscv]{ bus.cmd.valid := (schedule || hold) && !fired arbitration.haltItself setWhen(bus.cmd.valid && !bus.cmd.ready) - bus.cmd.function_id := U(input(INSTRUCTION)(14 downto 12)) + bus.cmd.function_id := U(input(INSTRUCTION)(14 downto 12)).resized bus.cmd.reorder_id := 0 bus.cmd.request_id := 0 if(p.CFU_INPUTS >= 1) bus.cmd.inputs(0) := input(RS1) @@ -135,10 +153,10 @@ class CfuPlugin(val p: CfuParameter) extends Plugin[VexRiscv]{ //Then it is required to add a buffer on rsp to not propagate the fork stage ready := False in the CPU pipeline. val rsp = if(p.CFU_FLOW_RESP_READY_ALWAYS){ bus.rsp.toFlow.toStream.queueLowLatency( - size = p.stageCount + 1, + size = stageCount + 1, latency = 0 ) - } else if(forkStage != joinStage && p.allowZeroLatency) { + } else if(forkStage != joinStage && allowZeroLatency) { bus.rsp.m2sPipe() } else { bus.rsp.combStage() @@ -159,14 +177,17 @@ class CfuPlugin(val p: CfuParameter) extends Plugin[VexRiscv]{ } } } + + addPrePopTask(() => stages.dropWhile(_ != memory).reverse.dropWhile(_ != joinStage).foreach(s => s.input(CFU_IN_FLIGHT).init(False))) } } object CfuTest{ - def getCfuParameter() = CfuParameter( - stageCount = 0, - allowZeroLatency = true, + +// stageCount = 0, +// allowZeroLatency = true, + def getCfuParameter() = CfuBusParameter( CFU_VERSION = 0, CFU_INTERFACE_ID_W = 0, CFU_FUNCTION_ID_W = 3, @@ -190,7 +211,31 @@ case class CfuTest() extends Component{ io.bus.rsp.outputs(0) := ~(io.bus.cmd.inputs(0) & io.bus.cmd.inputs(1)) } -case class CfuDecoder(p : CfuParameter, + +case class CfuBb(p : CfuBusParameter) extends BlackBox{ + val io = new Bundle { + val clk, reset = in Bool() + val bus = slave(CfuBus(p)) + } + + mapCurrentClockDomain(io.clk, io.reset) +} + +//case class CfuGray(p : CfuBusParameter) extends BlackBox{ +// val req_function_id = in Bits(p.CFU_FUNCTION_ID_W) +// val req_data = in Bits(p.CFU_REQ_INPUTS) +// val resp_data = in Bits(p.CFU_FUNCTION_ID_W) +// input `CFU_FUNCTION_ID req_function_id, +// input [CFU_REQ_INPUTS-1:0]`CFU_REQ_DATA req_data, +// output [CFU_RESP_OUTPUTS-1:0]`CFU_RESP_DATA resp_data +// io.bus.rsp.arbitrationFrom(io.bus.cmd) +// io.bus.rsp.response_ok := True +// io.bus.rsp.response_id := io.bus.cmd.request_id +// io.bus.rsp.outputs(0) := ~(io.bus.cmd.inputs(0) & io.bus.cmd.inputs(1)) +//} + + +case class CfuDecoder(p : CfuBusParameter, mappings : Seq[AddressMapping], pendingMax : Int = 3) extends Component{ val io = new Bundle { From e25dfb4fbf1d11ab61710026797120c9034b9f86 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Mon, 9 Dec 2019 22:23:07 +0100 Subject: [PATCH 277/951] CsrPlugin now make SATP write rescheduling the next instruction --- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 0c9b7dcc..5cd161bb 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -334,6 +334,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep var exceptionPendings : Vec[Bool] = null override def isExceptionPending(stage : Stage): Bool = exceptionPendings(pipeline.stages.indexOf(stage)) + var redoInterface : Flow[UInt] = null var jumpInterface : Flow[UInt] = null var timerInterrupt, externalInterrupt, softwareInterrupt : Bool = null var externalInterruptS : Bool = null @@ -430,6 +431,13 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep jumpInterface.valid := False jumpInterface.payload.assignDontCare() + + if(supervisorGen) { + redoInterface = pcManagerService.createJumpInterface(pipeline.execute) + redoInterface.valid := False + redoInterface.payload.assignDontCare() + } + exceptionPendings = Vec(Bool, pipeline.stages.length) timerInterrupt = in Bool() setName("timerInterrupt") externalInterrupt = in Bool() setName("externalInterrupt") @@ -619,6 +627,13 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep scauseAccess(CSR.SCAUSE, xlen-1 -> scause.interrupt, 0 -> scause.exceptionCode) sbadaddrAccess(CSR.SBADADDR, stval) satpAccess(CSR.SATP, 31 -> satp.MODE, 22 -> satp.ASID, 0 -> satp.PPN) + + + if(supervisorGen) onWrite(CSR.SATP){ + execute.arbitration.flushNext := True + redoInterface.valid := True + redoInterface.payload := execute.input(PC) + 4 + } } } From 0702f978061c02904620658aa75ed72c7b3fc353 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Thu, 19 Dec 2019 22:55:17 +0100 Subject: [PATCH 278/951] CsrPlugin add wfiOutput --- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 5cd161bb..77ea0918 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -69,7 +69,8 @@ case class CsrPluginConfig( midelegAccess : CsrAccess = CsrAccess.NONE, pipelineCsrRead : Boolean = false, pipelinedInterrupt : Boolean = true, - deterministicInteruptionEntry : Boolean = false //Only used for simulatation purposes + deterministicInteruptionEntry : Boolean = false, //Only used for simulatation purposes + wfiOutput : Boolean = false ){ assert(!ucycleAccess.canWrite) def privilegeGen = userGen || supervisorGen @@ -343,6 +344,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep var selfException : Flow[ExceptionCause] = null var contextSwitching : Bool = null var thirdPartyWake : Bool = null + var inWfi : Bool = null override def askWake(): Unit = thirdPartyWake := True @@ -909,7 +911,8 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep execute plug new Area{ import execute._ //Manage WFI instructions - val inWfi = False.addTag(Verilator.public) + inWfi = False.addTag(Verilator.public) + if(wfiOutput) out(inWfi) val wfiWake = RegNext(interruptSpecs.map(_.cond).orR || thirdPartyWake) init(False) if(wfiGenAsWait) when(arbitration.isValid && input(ENV_CTRL) === EnvCtrlEnum.WFI){ inWfi := True From 052c8dd60222f18acf7461067d403ea1f53636f7 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Fri, 20 Dec 2019 00:21:55 +0100 Subject: [PATCH 279/951] Fix inWfi naming, fix regressions --- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 3 ++- src/test/cpp/regression/main.cpp | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 77ea0918..e707c01c 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -388,6 +388,8 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep override def setup(pipeline: VexRiscv): Unit = { import pipeline.config._ + inWfi = False.addTag(Verilator.public) + thirdPartyWake = False val defaultEnv = List[(Stageable[_ <: BaseType],Any)]( @@ -911,7 +913,6 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep execute plug new Area{ import execute._ //Manage WFI instructions - inWfi = False.addTag(Verilator.public) if(wfiOutput) out(inWfi) val wfiWake = RegNext(interruptSpecs.map(_.cond).orR || thirdPartyWake) init(False) if(wfiGenAsWait) when(arbitration.isValid && input(ENV_CTRL) === EnvCtrlEnum.WFI){ diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 421a4335..75f06bd9 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -1548,7 +1548,7 @@ public: riscvRef.ipInput |= top->externalInterruptS << 9; #endif - riscvRef.liveness(top->VexRiscv->execute_CsrPlugin_inWfi); + riscvRef.liveness(top->VexRiscv->CsrPlugin_inWfi); if(top->VexRiscv->CsrPlugin_interruptJump){ if(riscvRefEnable) riscvRef.trap(true, top->VexRiscv->CsrPlugin_interrupt_code); } From 3b494e97cdd880030c27f02b788b4aad383f054d Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Tue, 24 Dec 2019 00:43:36 +0100 Subject: [PATCH 280/951] Moved KeepAttribute to spinal.lib --- src/main/scala/vexriscv/ip/InstructionCache.scala | 2 +- .../vexriscv/plugin/PcManagerSimplePlugin.scala | 13 ------------- 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/src/main/scala/vexriscv/ip/InstructionCache.scala b/src/main/scala/vexriscv/ip/InstructionCache.scala index 073559ff..0a809c62 100644 --- a/src/main/scala/vexriscv/ip/InstructionCache.scala +++ b/src/main/scala/vexriscv/ip/InstructionCache.scala @@ -8,7 +8,7 @@ import spinal.lib.bus.avalon.{AvalonMM, AvalonMMConfig} import spinal.lib.bus.bmb.{Bmb, BmbParameter} import spinal.lib.bus.wishbone.{Wishbone, WishboneConfig} import spinal.lib.bus.simple._ -import vexriscv.plugin.{IBusSimpleBus, IBusSimplePlugin, KeepAttribute} +import vexriscv.plugin.{IBusSimpleBus, IBusSimplePlugin} case class InstructionCacheConfig( cacheSize : Int, diff --git a/src/main/scala/vexriscv/plugin/PcManagerSimplePlugin.scala b/src/main/scala/vexriscv/plugin/PcManagerSimplePlugin.scala index 08adb7fe..5b1226a6 100644 --- a/src/main/scala/vexriscv/plugin/PcManagerSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/PcManagerSimplePlugin.scala @@ -8,19 +8,6 @@ import scala.collection.mutable.ArrayBuffer -object KeepAttribute{ - object syn_keep_verilog extends AttributeFlag("synthesis syn_keep = 1", COMMENT_ATTRIBUTE){ - override def isLanguageReady(language: Language) : Boolean = language == Language.VERILOG || language == Language.SYSTEM_VERILOG - } - - object syn_keep_vhdl extends AttributeFlag("syn_keep"){ - override def isLanguageReady(language: Language) : Boolean = language == Language.VHDL - } - object keep extends AttributeFlag("keep") - - def apply[T <: Data](that : T) = that.addAttribute(keep).addAttribute(syn_keep_verilog).addAttribute(syn_keep_vhdl) -} - class PcManagerSimplePlugin(resetVector : BigInt, relaxedPcCalculation : Boolean = false, From 2a0690790211855fb198f5a89c1a1ae9a44235a5 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Tue, 24 Dec 2019 01:09:55 +0100 Subject: [PATCH 281/951] fix compilation --- src/main/scala/vexriscv/demo/SynthesisBench.scala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/demo/SynthesisBench.scala b/src/main/scala/vexriscv/demo/SynthesisBench.scala index 2413cf33..08a7d729 100644 --- a/src/main/scala/vexriscv/demo/SynthesisBench.scala +++ b/src/main/scala/vexriscv/demo/SynthesisBench.scala @@ -1,10 +1,11 @@ package vexriscv.demo import spinal.core._ +import spinal.lib._ import spinal.lib.eda.bench._ import spinal.lib.eda.icestorm.IcestormStdTargets import vexriscv.VexRiscv -import vexriscv.plugin.{DecoderSimplePlugin, KeepAttribute} +import vexriscv.plugin.{DecoderSimplePlugin} import scala.collection.mutable.ArrayBuffer import scala.util.Random From 4c7025b9643228244da896c2d87110f90915eedf Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Mon, 6 Jan 2020 20:07:23 +0100 Subject: [PATCH 282/951] Fix xtval when no exception and read_only --- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index e707c01c..686293e7 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -866,6 +866,10 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep } } + if(exceptionPortCtrl == null){ + if(mbadaddrAccess == CsrAccess.READ_ONLY) mtval := 0 + if(sbadaddrAccess == CsrAccess.READ_ONLY) stval := 0 + } lastStage plug new Area{ import lastStage._ From 061ebd1b2cc78e4ae6df070a2a75be14f636c3a8 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sun, 12 Jan 2020 13:27:45 +0100 Subject: [PATCH 283/951] Fix murax xip bootloader --- src/main/c/murax/xipBootloader/crt.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/c/murax/xipBootloader/crt.S b/src/main/c/murax/xipBootloader/crt.S index 178f7884..8da77ab7 100644 --- a/src/main/c/murax/xipBootloader/crt.S +++ b/src/main/c/murax/xipBootloader/crt.S @@ -49,6 +49,6 @@ spiWrite: sw a0,CTRL_DATA(CTRL) spiWrite_wait: lw t0,CTRL_STATUS(CTRL) - srli t0,t0,0x10 + slli t0,t0,0x10 beqz t0,spiWrite_wait ret From b866dcb07f3aca8fc86187b0ae3adb9df081537c Mon Sep 17 00:00:00 2001 From: sebastien-riou Date: Sun, 12 Jan 2020 16:08:14 +0100 Subject: [PATCH 284/951] XIP on Murax improvements --- .../iCE40-hx8k_breakout_board_xip/Makefile | 22 +-- .../iCE40-hx8k_breakout_board_xip/README.md | 135 ++++++++++++++++-- src/main/c/murax/xipBootloader/crt.S | 14 +- src/main/c/murax/xipBootloader/crt.bin | Bin 120 -> 176 bytes src/main/c/murax/xipBootloader/demo.S | 11 +- src/main/c/murax/xipBootloader/demo.bin | Bin 48 -> 0 bytes src/main/c/murax/xipBootloader/makefile | 22 ++- src/main/c/murax/xipBootloader/mapping_rom.ld | 96 +++++++++++++ src/main/c/murax/xipBootloader/mapping_xip.ld | 96 +++++++++++++ src/main/scala/vexriscv/demo/Murax.scala | 42 +----- 10 files changed, 373 insertions(+), 65 deletions(-) delete mode 100755 src/main/c/murax/xipBootloader/demo.bin create mode 100644 src/main/c/murax/xipBootloader/mapping_rom.ld create mode 100644 src/main/c/murax/xipBootloader/mapping_xip.ld diff --git a/scripts/Murax/iCE40-hx8k_breakout_board_xip/Makefile b/scripts/Murax/iCE40-hx8k_breakout_board_xip/Makefile index 88aa1a2f..8feef205 100644 --- a/scripts/Murax/iCE40-hx8k_breakout_board_xip/Makefile +++ b/scripts/Murax/iCE40-hx8k_breakout_board_xip/Makefile @@ -1,19 +1,21 @@ +VBASE = ../../.. +VNAME = Murax_iCE40_hx8k_breakout_board_xip +VERILOG = ${VBASE}/${VNAME}.v -VERILOG = ../../../Murax_iCE40_hx8k_breakout_board_xip.v +all: prog -generate : - #(cd ../../..; sbt "runMain vexriscv.demo.Murax_iCE40_hx8k_breakout_board_xip") +${VERILOG} : + (cd ${VBASE}; sbt "runMain vexriscv.demo.${VNAME}") -../../../Murax_iCE40_hx8k_breakout_board_xip.v : - #(cd ../../..; sbt "runMain vexriscv.demo.Murax_iCE40_hx8k_breakout_board_xip") +generate : ${VERILOG} -../../../Murax_iCE40_hx8k_breakout_board_xip.v*.bin: +${VERILOG}*.bin: -bin/Murax_iCE40_hx8k_breakout_board_xip.blif : ${VERILOG} ../../../Murax_iCE40_hx8k_breakout_board_xip.v*.bin +bin/Murax_iCE40_hx8k_breakout_board_xip.blif : ${VERILOG} ${VERILOG}*.bin mkdir -p bin rm -f Murax_iCE40_hx8k_breakout_board_xip.v*.bin - cp ../../../Murax_iCE40_hx8k_breakout_board_xip.v*.bin . | true + cp ${VERILOG}*.bin . | true yosys -v3 -p "synth_ice40 -top Murax_iCE40_hx8k_breakout_board_xip -blif bin/Murax_iCE40_hx8k_breakout_board_xip.blif" ${VERILOG} bin/Murax_iCE40_hx8k_breakout_board_xip.asc : Murax_iCE40_hx8k_breakout_board_xip.pcf bin/Murax_iCE40_hx8k_breakout_board_xip.blif @@ -28,11 +30,15 @@ time: bin/Murax_iCE40_hx8k_breakout_board_xip.bin icetime -tmd hx8k bin/Murax_iCE40_hx8k_breakout_board_xip.asc prog : bin/Murax_iCE40_hx8k_breakout_board_xip.bin + lsusb -d 0403:6010 iceprog -S bin/Murax_iCE40_hx8k_breakout_board_xip.bin sudo-prog : bin/Murax_iCE40_hx8k_breakout_board_xip.bin + sudo lsusb -d 0403:6010 sudo iceprog -S bin/Murax_iCE40_hx8k_breakout_board_xip.bin clean : rm -rf bin rm -f Murax_iCE40_hx8k_breakout_board_xip.v*.bin + rm -f ${VERILOG}*.bin + rm -f ${VERILOG} diff --git a/scripts/Murax/iCE40-hx8k_breakout_board_xip/README.md b/scripts/Murax/iCE40-hx8k_breakout_board_xip/README.md index 1e50a02f..06e94399 100644 --- a/scripts/Murax/iCE40-hx8k_breakout_board_xip/README.md +++ b/scripts/Murax/iCE40-hx8k_breakout_board_xip/README.md @@ -59,12 +59,29 @@ The process should take around 30 seconds on a reasonable fast computer. ## Programming +Make sure the FPGA board is the only USB peripheral with ID 0403:6010 + +For example, this is bad: +``` +user@lafite:~$ lsusb -d 0403:6010 +Bus 001 Device 088: ID 0403:6010 Future Technology Devices International, Ltd FT2232C Dual USB-UART/FIFO IC +Bus 001 Device 090: ID 0403:6010 Future Technology Devices International, Ltd FT2232C Dual USB-UART/FIFO IC +``` +This is good: +``` +user@lafite:~$ lsusb -d 0403:6010 +Bus 001 Device 088: ID 0403:6010 Future Technology Devices International, Ltd FT2232C Dual USB-UART/FIFO IC +``` + + After building you should be able to run `make prog`. You may need to run `make sudo-prog` if root is needed to access your USB devices. You should get output like the following; ``` -iceprog -S bin/toplevel.bin +lsusb -d 0403:6010 +Bus 001 Device 088: ID 0403:6010 Future Technology Devices International, Ltd FT2232C Dual USB-UART/FIFO IC +iceprog -S bin/Murax_iCE40_hx8k_breakout_board_xip.bin init.. cdone: high reset.. @@ -74,13 +91,115 @@ cdone: high Bye. ``` -After programming the LEDs at the top of the board should start flashing in an -interesting pattern. +WARNING: having this output does NOT guarantee you actually programmed anything in the FPGA! -## Connect +After programming nothing visual will happen, except the LEDs being off. +The bootloader is waiting for a valid content in the flash. "valid content" is +identified by a magic word at 0xE0040000: it shall be 0x12340fb7, which is the +value for the instruction "li x31, 0x12340000". -After programming you should be able to connect to the serial port and have the -output echoed back to you. +## Programming flash image -On Linux you can do this using a command like `screen /dev/ttyUSB1`. Then as -you type you should get back the same characters. +### Connect JTAG + +We will use vexrisc JTAG to program the flash, so you need openocd and a +suitable JTAG dongle. + +Pin-out: +``` +TCK: H16 aka J2.25 +TDO: G16 aka J2.26 +TDI: G15 aka J2.27 +TMS: F15 aka J2.28 +``` +In addition you need to connect the ground and VTarget aka VIO: J2.2 on the +board. + +### Start GDB server / OpenOCD +Make sure to use https://github.com/SpinalHDL/openocd_riscv +Make sure to select the configuration file which match your JTAG dongle. + +An example with the dongle "ft2232h_breakout": +``` +src/openocd -f tcl/interface/ftdi/ft2232h_breakout.cfg -c "set MURAX_CPU0_YAML ../VexRiscv/cpu0.yaml" -f tcl/target/murax_xip.cfg +``` + +You should get an output like below: +``` +Open On-Chip Debugger 0.10.0+dev-01214-g0ace94f (2019-10-02-18:23) +Licensed under GNU GPL v2 +For bug reports, read + http://openocd.org/doc/doxygen/bugs.html +../VexRiscv/cpu0.yaml +adapter speed: 100 kHz +adapter_nsrst_delay: 260 +Info : auto-selecting first available session transport "jtag". To override use 'transport select '. +jtag_ntrst_delay: 250 +Info : set servers polling period to 50ms +Error: libusb_get_string_descriptor_ascii() failed with LIBUSB_ERROR_INVALID_PARAM +Info : clock speed 100 kHz +Info : JTAG tap: fpga_spinal.bridge tap/device found: 0x10001fff (mfg: 0x7ff (), part: 0x0001, ver: 0x1) +Info : Listening on port 3333 for gdb connections +requesting target halt and executing a soft reset +Info : Listening on port 6666 for tcl connections +Info : Listening on port 4444 for telnet connections +``` + +### Loading the flash with telnet + +First we connect and stop execution on the device: +``` +user@lafite:~/Downloads/vexrisc_full/VexRiscv/src/main/c/murax/xipBootloader$ telnet 127.0.0.1 4444 +Trying 127.0.0.1... +Connected to 127.0.0.1. +Escape character is '^]'. +Open On-Chip Debugger +> reset +JTAG tap: fpga_spinal.bridge tap/device found: 0x10001fff (mfg: 0x7ff (), part: 0x0001, ver: 0x1) +> +``` + +Now we can safely connect the J7 jumper on the board to be able to access the flash. +After that, we can load the program in flash: +``` +> flash erase_sector 0 4 4 +erased sectors 4 through 4 on flash bank 0 in 0.872235s +> flash write_bank 0 /home/user/dev/vexrisc_fork/VexRiscv/src/main/c/murax/xipBootloader/demo_xip.bin 0x40000 +wrote 48 bytes from file /home/user/dev/vexrisc_fork/VexRiscv/src/main/c/murax/xipBootloader/demo_xip.bin to flash bank 0 at offset 0x00040000 in 0.285539s (0.164 KiB/s) +> flash verify_bank 0 /home/user/dev/vexrisc_fork/VexRiscv/src/main/c/murax/xipBootloader/demo_xip.bin 0x40000 +read 48 bytes from file /home/user/dev/vexrisc_fork/VexRiscv/src/main/c/murax/xipBootloader/demo_xip.bin and flash bank 0 at offset 0x00040000 in 0.192036s (0.244 KiB/s) +contents match +> reset +JTAG tap: fpga_spinal.bridge tap/device found: 0x10001fff (mfg: 0x7ff (), part: 0x0001, ver: 0x1) +> resume +> exit +Connection closed by foreign host. +``` + +From now the device runs the code from flash, LEDs shall display a dot moving from D9 to D2. + +### Loading flash using GDB / eclipse +- ``` +src/openocd -f tcl/interface/ftdi/ft2232h_breakout.cfg -c "set MURAX_CPU0_YAML ../VexRiscv/cpu0.yaml" -f tcl/target/murax_xip.cfg +``` +- Make sure J7 is connected. +- Connect to GDB / eclipse as usual. + +From there code loading, step, break points works as usual (including software break points in flash). + +## Update hardware/bootloader + +- Stop any OpenOCD connection +- Remove J7, then: +- ``` +make clean prog +``` +- Remember to check a single FTDI device is listed in the output. If not: + - Disconnect the other devices + - ``` + make prog + ``` +- Connect J7, flash software shall start executing. + +## Flash software +Refer to "Loading the flash with telnet" or "Loading flash using GDB / eclipse". diff --git a/src/main/c/murax/xipBootloader/crt.S b/src/main/c/murax/xipBootloader/crt.S index 178f7884..8668c8a9 100644 --- a/src/main/c/murax/xipBootloader/crt.S +++ b/src/main/c/murax/xipBootloader/crt.S @@ -42,13 +42,25 @@ crtStart: li t0, 0x1 sw t0, CTRL_XIP_CONFIG(CTRL) li t0, XIP_BASE + lw t1, (t0) + li t2, 0x12340fb7 + xor t1,t1,t2 + bnez t1,retry jr t0 +retry: + li a0, 0x800 + call spiWrite + li t1,100000 +loop: + addi t1,t1,-1 + bnez t1, loop + j crtStart spiWrite: sw a0,CTRL_DATA(CTRL) spiWrite_wait: lw t0,CTRL_STATUS(CTRL) - srli t0,t0,0x10 + slli t0,t0,0x10 beqz t0,spiWrite_wait ret diff --git a/src/main/c/murax/xipBootloader/crt.bin b/src/main/c/murax/xipBootloader/crt.bin index d64a1cb00efe30e57fa9ae8eb357f1590f780573..bf751967431a1eb58a39071360f4fe56c3dfae48 100755 GIT binary patch delta 141 zcmb=}z&Jsxo`GGMRY2lBLj#*Is{xQ^U^5qGU=U_yZFtY%z`C93Kf~mvO#;e`;#np$ z2{0%xh-cZ(#PWc7F%!dfVH2Ur&Becsor@WgMVJ}V8<-dndK(zcn;98|nVGYMnLq!3 jEXVvW|HJ)n$_v&rG%xaJm^_Jz@o^8+zjXEn1~32sem5w1 delta 84 zcmdnMSTRA%?*OwftANCN1_vN*0HhBvnTs+o2(z*_yk}rw+RpT!VRF+Z0p&&UER&f8 l7?c;pvutN#d63?~1Z1ygXkO&cF!>S_E<%Gcy-XZW030pZ`CWWB!-_Vg5e`AOHYn Cd=EPS diff --git a/src/main/c/murax/xipBootloader/makefile b/src/main/c/murax/xipBootloader/makefile index 56b8ab84..44211313 100644 --- a/src/main/c/murax/xipBootloader/makefile +++ b/src/main/c/murax/xipBootloader/makefile @@ -4,20 +4,34 @@ LFLAGS= -nostdlib -mcmodel=medany -nostartfiles -ffreestanding -fPIC -fPIE all: crt.S demo.S riscv64-unknown-elf-gcc -c $(CFLAGS) -o crt.o crt.S - riscv64-unknown-elf-gcc $(CFLAGS) -o crt.elf crt.o $(LFLAGS) -Wl,-Bstatic,-T,mapping.ld,-Map,crt.map,--print-memory-usage + riscv64-unknown-elf-gcc $(CFLAGS) -o crt.elf crt.o $(LFLAGS) -Wl,-Bstatic,-T,mapping_rom.ld,-Map,crt.map,--print-memory-usage riscv64-unknown-elf-objdump -S -d crt.elf > crt.asm riscv64-unknown-elf-objcopy -O binary crt.elf crt.bin + riscv64-unknown-elf-gcc $(CFLAGS) -o crt_ram.elf crt.o $(LFLAGS) -Wl,-Bstatic,-T,mapping.ld,-Map,crt_ram.map,--print-memory-usage + riscv64-unknown-elf-objdump -S -d crt_ram.elf > crt_ram.asm + riscv64-unknown-elf-objcopy -O binary crt_ram.elf crt_ram.bin + riscv64-unknown-elf-gcc -c $(CFLAGS) -o demo.o demo.S riscv64-unknown-elf-gcc $(CFLAGS) -o demo.elf demo.o $(LFLAGS) -Wl,-Bstatic,-T,mapping.ld,-Map,demo.map,--print-memory-usage riscv64-unknown-elf-objdump -S -d demo.elf > demo.asm riscv64-unknown-elf-objcopy -O binary demo.elf demo.bin + riscv64-unknown-elf-gcc $(CFLAGS) -o demo_rom.elf demo.o $(LFLAGS) -Wl,-Bstatic,-T,mapping_rom.ld,-Map,demo_rom.map,--print-memory-usage + riscv64-unknown-elf-objdump -S -d demo_rom.elf > demo_rom.asm + riscv64-unknown-elf-objcopy -O binary demo_rom.elf demo_rom.bin + riscv64-unknown-elf-gcc $(CFLAGS) -o demo_xip.elf demo.o $(LFLAGS) -Wl,-Bstatic,-T,mapping_xip.ld,-Map,demo_xip.map,--print-memory-usage + riscv64-unknown-elf-objdump -S -d demo_xip.elf > demo_xip.asm + riscv64-unknown-elf-objcopy -O binary demo_xip.elf demo_xip.bin -clean: +clean-for-commit: rm -f *.o - rm -f *.bin rm -f *.elf rm -f *.asm - rm -f *.map \ No newline at end of file + rm -f *.map + rm -f *.d + rm demo_rom.bin demo.bin crt_ram.bin + +clean: clean-tmp + rm -f *.bin diff --git a/src/main/c/murax/xipBootloader/mapping_rom.ld b/src/main/c/murax/xipBootloader/mapping_rom.ld new file mode 100644 index 00000000..aaa0c3ca --- /dev/null +++ b/src/main/c/murax/xipBootloader/mapping_rom.ld @@ -0,0 +1,96 @@ +/* +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. +*/ +OUTPUT_FORMAT("elf32-littleriscv", "elf32-littleriscv", "elf32-littleriscv") +OUTPUT_ARCH(riscv) +ENTRY(crtStart) + +MEMORY { + mem : ORIGIN = 0x80000000, LENGTH = 0x00000400 + rom : ORIGIN = 0xF001E000, LENGTH = 0x00000400 +} + +_stack_size = DEFINED(_stack_size) ? _stack_size : 0; + +SECTIONS { + + .vector : { + *crt.o(.text); + } > rom + + .memory : { + *(.text); + end = .; + } > rom + + .rodata : + { + *(.rdata) + *(.rodata .rodata.*) + *(.gnu.linkonce.r.*) + } > rom + + .ctors : + { + . = ALIGN(4); + _ctors_start = .; + KEEP(*(.init_array*)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + . = ALIGN(4); + _ctors_end = .; + } > rom + + .data : + { + *(.rdata) + *(.rodata .rodata.*) + *(.gnu.linkonce.r.*) + *(.data .data.*) + *(.gnu.linkonce.d.*) + . = ALIGN(8); + PROVIDE( __global_pointer$ = . + 0x800 ); + *(.sdata .sdata.*) + *(.gnu.linkonce.s.*) + . = ALIGN(8); + *(.srodata.cst16) + *(.srodata.cst8) + *(.srodata.cst4) + *(.srodata.cst2) + *(.srodata .srodata.*) + } > rom + + .bss (NOLOAD) : { + . = ALIGN(4); + /* This is used by the startup in order to initialize the .bss secion */ + _bss_start = .; + *(.sbss*) + *(.gnu.linkonce.sb.*) + *(.bss .bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(4); + _bss_end = .; + } > mem + + .noinit (NOLOAD) : { + . = ALIGN(4); + *(.noinit .noinit.*) + . = ALIGN(4); + } > mem + + ._stack (NOLOAD): + { + . = ALIGN(16); + PROVIDE (_stack_end = .); + . = . + _stack_size; + . = ALIGN(16); + PROVIDE (_stack_start = .); + } > mem + +} diff --git a/src/main/c/murax/xipBootloader/mapping_xip.ld b/src/main/c/murax/xipBootloader/mapping_xip.ld new file mode 100644 index 00000000..ed564007 --- /dev/null +++ b/src/main/c/murax/xipBootloader/mapping_xip.ld @@ -0,0 +1,96 @@ +/* +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. +*/ +OUTPUT_FORMAT("elf32-littleriscv", "elf32-littleriscv", "elf32-littleriscv") +OUTPUT_ARCH(riscv) +ENTRY(crtStart) + +MEMORY { + mem : ORIGIN = 0x80000000, LENGTH = 0x00000400 + xip : ORIGIN = 0xE0040000, LENGTH = 0x00000400 +} + +_stack_size = DEFINED(_stack_size) ? _stack_size : 0; + +SECTIONS { + + .vector : { + *crt.o(.text); + } > xip + + .memory : { + *(.text); + end = .; + } > xip + + .rodata : + { + *(.rdata) + *(.rodata .rodata.*) + *(.gnu.linkonce.r.*) + } > xip + + .ctors : + { + . = ALIGN(4); + _ctors_start = .; + KEEP(*(.init_array*)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + . = ALIGN(4); + _ctors_end = .; + } > xip + + .data : + { + *(.rdata) + *(.rodata .rodata.*) + *(.gnu.linkonce.r.*) + *(.data .data.*) + *(.gnu.linkonce.d.*) + . = ALIGN(8); + PROVIDE( __global_pointer$ = . + 0x800 ); + *(.sdata .sdata.*) + *(.gnu.linkonce.s.*) + . = ALIGN(8); + *(.srodata.cst16) + *(.srodata.cst8) + *(.srodata.cst4) + *(.srodata.cst2) + *(.srodata .srodata.*) + } > xip + + .bss (NOLOAD) : { + . = ALIGN(4); + /* This is used by the startup in order to initialize the .bss secion */ + _bss_start = .; + *(.sbss*) + *(.gnu.linkonce.sb.*) + *(.bss .bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(4); + _bss_end = .; + } > mem + + .noinit (NOLOAD) : { + . = ALIGN(4); + *(.noinit .noinit.*) + . = ALIGN(4); + } > mem + + ._stack (NOLOAD): + { + . = ALIGN(16); + PROVIDE (_stack_end = .); + . = . + _stack_size; + . = ALIGN(16); + PROVIDE (_stack_start = .); + } > mem + +} diff --git a/src/main/scala/vexriscv/demo/Murax.scala b/src/main/scala/vexriscv/demo/Murax.scala index d78beeb1..846fa046 100644 --- a/src/main/scala/vexriscv/demo/Murax.scala +++ b/src/main/scala/vexriscv/demo/Murax.scala @@ -385,7 +385,8 @@ object Murax_iCE40_hx8k_breakout_board_xip{ val led = out Bits(8 bits) } - val murax = Murax(MuraxConfig.default(withXip = true)) + //val murax = Murax(MuraxConfig.default(withXip = true)) + val murax = Murax(MuraxConfig.default(withXip = true).copy(onChipRamSize = 8 kB)) murax.io.asyncReset := False val mainClkBuffer = SB_GB() @@ -438,45 +439,6 @@ object Murax_iCE40_hx8k_breakout_board_xip{ def main(args: Array[String]) { SpinalVerilog(Murax_iCE40_hx8k_breakout_board_xip()) - /*SpinalVerilog{ - val c = Murax(MuraxConfig.default(withXip = true)) - - - - - c.rework { - c.resetCtrlClockDomain { - c.io.xip.setAsDirectionLess.allowDirectionLessIo.flattenForeach(_.unsetName()) - - out(RegNext(c.io.xip.ss)).setName("io_xip_ss") - - val sclk = SB_IO_SCLK() - sclk.PACKAGE_PIN := inout(Analog(Bool)).setName("io_xip_sclk") - sclk.CLOCK_ENABLE := True - - sclk.OUTPUT_CLK := ClockDomain.current.readClockWire - sclk.D_OUT_0 <> c.io.xip.sclk.write(0) - sclk.D_OUT_1 <> RegNext(c.io.xip.sclk.write(1)) - - for (i <- 0 until c.io.xip.p.dataWidth) { - val data = c.io.xip.data(i) - val bb = SB_IO_DATA() - bb.PACKAGE_PIN := inout(Analog(Bool)).setName(s"io_xip_data_$i" ) - bb.CLOCK_ENABLE := True - - bb.OUTPUT_CLK := ClockDomain.current.readClockWire - bb.OUTPUT_ENABLE <> data.writeEnable - bb.D_OUT_0 <> data.write(0) - bb.D_OUT_1 <> RegNext(data.write(1)) - - bb.INPUT_CLK := ClockDomain.current.readClockWire - data.read(0) := bb.D_IN_0 - data.read(1) := RegNext(bb.D_IN_1) - } - } - } - c - }*/ } } From bfb0b54f9b9893d96860b6e4169921391a7086da Mon Sep 17 00:00:00 2001 From: sebastien-riou Date: Sun, 12 Jan 2020 19:52:27 +0100 Subject: [PATCH 285/951] readme for XIP on Murax improved --- .../Murax/iCE40-hx8k_breakout_board_xip/README.md | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/scripts/Murax/iCE40-hx8k_breakout_board_xip/README.md b/scripts/Murax/iCE40-hx8k_breakout_board_xip/README.md index 06e94399..f7a4dac0 100644 --- a/scripts/Murax/iCE40-hx8k_breakout_board_xip/README.md +++ b/scripts/Murax/iCE40-hx8k_breakout_board_xip/README.md @@ -9,6 +9,11 @@ This board can be purchased for ~$USD 49 directly from Lattice and is supported by the IceStorm [`iceprog`](https://github.com/cliffordwolf/icestorm/tree/master/iceprog) tool. +# Bootloader operations + +A bootloader is implemented in a ROM within the FPGA bitfile. It configure the SPI and attempt to read the first word in 'XIP' area of the flash (0xE0040000 in CPU address space, 0x40000 in flash). If this first word is the magic word +then the bootloader jump at 0xE0040000. +The magic word is 0x12340fb7, which is the value for the instruction "li x31, 0x12340000" or "lui t6,0x12340". # Using the example @@ -94,9 +99,7 @@ Bye. WARNING: having this output does NOT guarantee you actually programmed anything in the FPGA! After programming nothing visual will happen, except the LEDs being off. -The bootloader is waiting for a valid content in the flash. "valid content" is -identified by a magic word at 0xE0040000: it shall be 0x12340fb7, which is the -value for the instruction "li x31, 0x12340000". +The bootloader is waiting for a valid content in the flash (see Bootloader operations). ## Programming flash image @@ -179,7 +182,7 @@ Connection closed by foreign host. From now the device runs the code from flash, LEDs shall display a dot moving from D9 to D2. ### Loading flash using GDB / eclipse -- ``` +``` src/openocd -f tcl/interface/ftdi/ft2232h_breakout.cfg -c "set MURAX_CPU0_YAML ../VexRiscv/cpu0.yaml" -f tcl/target/murax_xip.cfg ``` - Make sure J7 is connected. @@ -191,12 +194,12 @@ From there code loading, step, break points works as usual (including software b - Stop any OpenOCD connection - Remove J7, then: -- ``` +``` make clean prog ``` - Remember to check a single FTDI device is listed in the output. If not: - Disconnect the other devices - - ``` + ``` make prog ``` - Connect J7, flash software shall start executing. From f01da9c73b42897c3bd49b92401063b84edb84ef Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Mon, 13 Jan 2020 20:44:55 +0100 Subject: [PATCH 286/951] CsrPlugin add printCsr --- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 686293e7..8759df56 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -368,6 +368,16 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep val csrMapping = new CsrMapping() + //Print CSR mapping + def printCsr() { + for ((address, things) <- csrMapping.mapping) { + println("0x" + address.toHexString + " => ") + for (thing <- things) { + println(" - " + thing) + } + } + } + //Interruption and exception data model case class Delegator(var enable : Bool, privilege : Int) case class InterruptSpec(var cond : Bool, id : Int, privilege : Int, delegators : List[Delegator]) From de9f704de262ad7900940271a46df4d824d14c06 Mon Sep 17 00:00:00 2001 From: sebastien-riou Date: Mon, 13 Jan 2020 21:58:08 +0100 Subject: [PATCH 287/951] better pin names in scala, bootloader without magic word --- .../Murax_iCE40_hx8k_breakout_board_xip.pcf | 22 ++++----- .../iCE40-hx8k_breakout_board_xip/README.md | 3 +- src/main/c/murax/xipBootloader/crt.S | 14 ++++-- src/main/c/murax/xipBootloader/crt.bin | Bin 176 -> 192 bytes src/main/scala/vexriscv/demo/Murax.scala | 45 ++++++++---------- 5 files changed, 44 insertions(+), 40 deletions(-) diff --git a/scripts/Murax/iCE40-hx8k_breakout_board_xip/Murax_iCE40_hx8k_breakout_board_xip.pcf b/scripts/Murax/iCE40-hx8k_breakout_board_xip/Murax_iCE40_hx8k_breakout_board_xip.pcf index 4962e25b..510acf71 100644 --- a/scripts/Murax/iCE40-hx8k_breakout_board_xip/Murax_iCE40_hx8k_breakout_board_xip.pcf +++ b/scripts/Murax/iCE40-hx8k_breakout_board_xip/Murax_iCE40_hx8k_breakout_board_xip.pcf @@ -1,12 +1,12 @@ ## iCE40-hx8k breakout board -set_io io_J3 J3 -set_io io_H16 H16 -set_io io_G15 G15 -set_io io_G16 G16 -set_io io_F15 F15 -set_io io_B12 B12 -set_io io_B10 B10 +set_io io_mainClk J3 +set_io io_jtag_tck H16 +set_io io_jtag_tdi G15 +set_io io_jtag_tdo G16 +set_io io_jtag_tms F15 +set_io io_uart_txd B12 +set_io io_uart_rxd B10 set_io io_led[0] B5 set_io io_led[1] B4 set_io io_led[2] A2 @@ -17,7 +17,7 @@ set_io io_led[6] B3 set_io io_led[7] C3 #XIP -set_io io_P12 P12 -set_io io_P11 P11 -set_io io_R11 R11 -set_io io_R12 R12 \ No newline at end of file +set_io io_miso P12 +set_io io_mosi P11 +set_io io_sclk R11 +set_io io_spis R12 diff --git a/scripts/Murax/iCE40-hx8k_breakout_board_xip/README.md b/scripts/Murax/iCE40-hx8k_breakout_board_xip/README.md index f7a4dac0..3ed77c5e 100644 --- a/scripts/Murax/iCE40-hx8k_breakout_board_xip/README.md +++ b/scripts/Murax/iCE40-hx8k_breakout_board_xip/README.md @@ -11,9 +11,8 @@ by the IceStorm # Bootloader operations -A bootloader is implemented in a ROM within the FPGA bitfile. It configure the SPI and attempt to read the first word in 'XIP' area of the flash (0xE0040000 in CPU address space, 0x40000 in flash). If this first word is the magic word +A bootloader is implemented in a ROM within the FPGA bitfile. It configure the SPI and attempt to read the first word in 'XIP' area of the flash (0xE0040000 in CPU address space, 0x40000 in flash). If this first word is not 0xFFFFFFFF and the same value is read 3 times, then the bootloader jump at 0xE0040000. -The magic word is 0x12340fb7, which is the value for the instruction "li x31, 0x12340000" or "lui t6,0x12340". # Using the example diff --git a/src/main/c/murax/xipBootloader/crt.S b/src/main/c/murax/xipBootloader/crt.S index 8668c8a9..52687677 100644 --- a/src/main/c/murax/xipBootloader/crt.S +++ b/src/main/c/murax/xipBootloader/crt.S @@ -43,9 +43,17 @@ crtStart: sw t0, CTRL_XIP_CONFIG(CTRL) li t0, XIP_BASE lw t1, (t0) - li t2, 0x12340fb7 - xor t1,t1,t2 - bnez t1,retry + li t2, 0xFFFFFFFF + xor t3,t1,t2 + beqz t3,retry + //if we are here we have read a value from flash which is not all ones + lw t2, (t0) + xor t3,t1,t2 + bnez t3,retry + lw t2, (t0) + xor t3,t1,t2 + bnez t3,retry + //if we are here we have read the same value 3 times, so flash seems good, lets's jump jr t0 retry: diff --git a/src/main/c/murax/xipBootloader/crt.bin b/src/main/c/murax/xipBootloader/crt.bin index bf751967431a1eb58a39071360f4fe56c3dfae48..3584ff4b9d823a2b06f626f59e6ea53c5f120f29 100755 GIT binary patch delta 102 zcmdnMcz|(&mYf5JFsp#Xdxit-!mI{B+JW6%lz~B*m9^nLLj&7H4;kgj%pd+6`xP@J vGw?ArFJ@u@v!(bL;A|1TiN(rd^S>%DSkKVB$e&^IBqqkkJxu@78yFY>TtOWE delta 86 zcmX@WxPftkmK+1SFsp#Xdxi!!VO9em&A?_Z%D^DZ%G&Ur!GU$6hYbIAVH2Ur&Becs mor@WgMVKeHD@)z~ro3Q1L-QhkhRKtd7$5gA{Y!6P00RKO;}`+} diff --git a/src/main/scala/vexriscv/demo/Murax.scala b/src/main/scala/vexriscv/demo/Murax.scala index 846fa046..389b91f4 100644 --- a/src/main/scala/vexriscv/demo/Murax.scala +++ b/src/main/scala/vexriscv/demo/Murax.scala @@ -368,58 +368,55 @@ object Murax_iCE40_hx8k_breakout_board_xip{ case class Murax_iCE40_hx8k_breakout_board_xip() extends Component{ val io = new Bundle { - val J3 = in Bool() - val H16 = in Bool() - val G15 = in Bool() - val G16 = out Bool() - val F15 = in Bool() - val B12 = out Bool() - val B10 = in Bool() + val mainClk = in Bool() + val jtag_tck = in Bool() + val jtag_tdi = in Bool() + val jtag_tdo = out Bool() + val jtag_tms = in Bool() + val uart_txd = out Bool() + val uart_rxd = in Bool() - - //p12 as mosi mean flash config - val P12 = inout(Analog(Bool)) - val P11 = inout(Analog(Bool)) - val R11 = out Bool() - val R12 = out Bool() + val mosi = inout(Analog(Bool)) + val miso = inout(Analog(Bool)) + val sclk = out Bool() + val spis = out Bool() val led = out Bits(8 bits) } - //val murax = Murax(MuraxConfig.default(withXip = true)) val murax = Murax(MuraxConfig.default(withXip = true).copy(onChipRamSize = 8 kB)) murax.io.asyncReset := False val mainClkBuffer = SB_GB() - mainClkBuffer.USER_SIGNAL_TO_GLOBAL_BUFFER <> io.J3 + mainClkBuffer.USER_SIGNAL_TO_GLOBAL_BUFFER <> io.mainClk mainClkBuffer.GLOBAL_BUFFER_OUTPUT <> murax.io.mainClk val jtagClkBuffer = SB_GB() - jtagClkBuffer.USER_SIGNAL_TO_GLOBAL_BUFFER <> io.H16 + jtagClkBuffer.USER_SIGNAL_TO_GLOBAL_BUFFER <> io.jtag_tck jtagClkBuffer.GLOBAL_BUFFER_OUTPUT <> murax.io.jtag.tck io.led <> murax.io.gpioA.write(7 downto 0) - murax.io.jtag.tdi <> io.G15 - murax.io.jtag.tdo <> io.G16 - murax.io.jtag.tms <> io.F15 + murax.io.jtag.tdi <> io.jtag_tdi + murax.io.jtag.tdo <> io.jtag_tdo + murax.io.jtag.tms <> io.jtag_tms murax.io.gpioA.read <> 0 - murax.io.uart.txd <> io.B12 - murax.io.uart.rxd <> io.B10 + murax.io.uart.txd <> io.uart_txd + murax.io.uart.rxd <> io.uart_rxd val xip = new ClockingArea(murax.systemClockDomain) { - RegNext(murax.io.xip.ss.asBool) <> io.R12 + RegNext(murax.io.xip.ss.asBool) <> io.spis val sclkIo = SB_IO_SCLK() - sclkIo.PACKAGE_PIN <> io.R11 + sclkIo.PACKAGE_PIN <> io.sclk sclkIo.CLOCK_ENABLE := True sclkIo.OUTPUT_CLK := ClockDomain.current.readClockWire sclkIo.D_OUT_0 <> murax.io.xip.sclk.write(0) sclkIo.D_OUT_1 <> RegNext(murax.io.xip.sclk.write(1)) - val datas = for ((data, pin) <- (murax.io.xip.data, List(io.P12, io.P11).reverse).zipped) yield new Area { + val datas = for ((data, pin) <- (murax.io.xip.data, List(io.mosi, io.miso)).zipped) yield new Area { val dataIo = SB_IO_DATA() dataIo.PACKAGE_PIN := pin dataIo.CLOCK_ENABLE := True From 97b2838d1884b48a2c8a9dbbb7a613c50374bfea Mon Sep 17 00:00:00 2001 From: sebastien-riou Date: Thu, 16 Jan 2020 21:58:55 +0100 Subject: [PATCH 288/951] Murax on Digilent Arty A7-35 --- scripts/Murax/arty_a7/README.md | 129 +++++++ scripts/Murax/arty_a7/arty_a7.xdc | 366 +++++++++++++++++++ scripts/Murax/arty_a7/arty_a7_org.xdc | 350 ++++++++++++++++++ scripts/Murax/arty_a7/make_mcs_file | 6 + scripts/Murax/arty_a7/make_mmi_files | 4 + scripts/Murax/arty_a7/make_vivado_project | 9 + scripts/Murax/arty_a7/makefile | 62 ++++ scripts/Murax/arty_a7/open_vivado_project | 4 + scripts/Murax/arty_a7/picocom_arty | 1 + scripts/Murax/arty_a7/toplevel.v | 66 ++++ scripts/Murax/arty_a7/write_flash | 3 + scripts/Murax/arty_a7/write_fpga | 3 + src/main/c/murax/hello_world/makefile | 134 +++++++ src/main/c/murax/hello_world/src/crt.S | 98 +++++ src/main/c/murax/hello_world/src/gpio.h | 15 + src/main/c/murax/hello_world/src/interrupt.h | 17 + src/main/c/murax/hello_world/src/linker.ld | 110 ++++++ src/main/c/murax/hello_world/src/main.c | 42 +++ src/main/c/murax/hello_world/src/murax.h | 17 + src/main/c/murax/hello_world/src/prescaler.h | 16 + src/main/c/murax/hello_world/src/timer.h | 20 + src/main/c/murax/hello_world/src/uart.h | 42 +++ src/main/scala/vexriscv/demo/Murax.scala | 7 + 23 files changed, 1521 insertions(+) create mode 100644 scripts/Murax/arty_a7/README.md create mode 100644 scripts/Murax/arty_a7/arty_a7.xdc create mode 100644 scripts/Murax/arty_a7/arty_a7_org.xdc create mode 100755 scripts/Murax/arty_a7/make_mcs_file create mode 100755 scripts/Murax/arty_a7/make_mmi_files create mode 100755 scripts/Murax/arty_a7/make_vivado_project create mode 100644 scripts/Murax/arty_a7/makefile create mode 100755 scripts/Murax/arty_a7/open_vivado_project create mode 100644 scripts/Murax/arty_a7/picocom_arty create mode 100644 scripts/Murax/arty_a7/toplevel.v create mode 100755 scripts/Murax/arty_a7/write_flash create mode 100755 scripts/Murax/arty_a7/write_fpga create mode 100644 src/main/c/murax/hello_world/makefile create mode 100644 src/main/c/murax/hello_world/src/crt.S create mode 100644 src/main/c/murax/hello_world/src/gpio.h create mode 100644 src/main/c/murax/hello_world/src/interrupt.h create mode 100644 src/main/c/murax/hello_world/src/linker.ld create mode 100644 src/main/c/murax/hello_world/src/main.c create mode 100644 src/main/c/murax/hello_world/src/murax.h create mode 100644 src/main/c/murax/hello_world/src/prescaler.h create mode 100644 src/main/c/murax/hello_world/src/timer.h create mode 100644 src/main/c/murax/hello_world/src/uart.h diff --git a/scripts/Murax/arty_a7/README.md b/scripts/Murax/arty_a7/README.md new file mode 100644 index 00000000..ad781f3f --- /dev/null +++ b/scripts/Murax/arty_a7/README.md @@ -0,0 +1,129 @@ +This example is for the Digilent ARTY A7 35T board. + +# Using the example + +## Before Starting + +You should make sure you have the following tools installed: + * vivado 2018.1 or later + * riscv toolchain (riscv64-unknown-elf) + * sbt + +## Board setup +Make sure you have a rev E board. If you have a later version check that the +flash part is S25FL128SAGMF100. + +Jumper settings for board rev E: + * Disconnect anything from the connectors (Pmod, Arduino) + * Jumpers: JP1 and JP2 on, others off. + +## Building + +You should be able to just type `make` and get output similar to this; +``` +... +Memory region Used Size Region Size %age Used + RAM: 896 B 2 KB 43.75% +... +--------------------------------------------------------------------------------- +Finished RTL Elaboration : Time (s): cpu = 00:00:08 ; elapsed = 00:00:09 . Memory (MB): peak = 1457.785 ; gain = 243.430 ; free physical = 17940 ; free virtual = 57159 +--------------------------------------------------------------------------------- +... +--------------------------------------------------------------------------------- +Finished Technology Mapping : Time (s): cpu = 00:02:42 ; elapsed = 00:02:58 . Memory (MB): peak = 1986.879 ; gain = 772.523 ; free physical = 17454 ; free virtual = 56670 +--------------------------------------------------------------------------------- +... +--------------------------------------------------------------------------------- +Finished Writing Synthesis Report : Time (s): cpu = 00:02:45 ; elapsed = 00:03:01 . Memory (MB): peak = 1986.879 ; gain = 772.523 ; free physical = 17457 ; free virtual = 56673 +--------------------------------------------------------------------------------- +... +Writing bitstream ./toplevel.bit... +... +mmi files generated +... +******************************************** + ./soc_latest_sw.bit correctly generated +******************************************** +... +******************************************** + ./soc_latest_sw.mcs correctly generated +******************************************** + +INFO: [Common 17-206] Exiting Vivado at Thu Nov 28 04:00:50 2019... +``` + +The process should take around 8 minutes on a reasonably fast computer. + +## Programming + +### Direct FPGA RAM programming + +Run `make prog` to program the bit file directly to FPGA RAM. + +You should get output like the following; +``` +... +****** Xilinx hw_server v2018.1 + **** Build date : Apr 4 2018-18:56:09 + ** Copyright 1986-2018 Xilinx, Inc. All Rights Reserved. + +INFO: [Labtoolstcl 44-466] Opening hw_target localhost:3121/xilinx_tcf/Digilent/210319AB569AA +INFO: [Labtools 27-1434] Device xc7a35t (JTAG device index = 0) is programmed with a design that has no supported debug core(s) in it. +WARNING: [Labtools 27-3361] The debug hub core was not detected. +Resolution: +1. Make sure the clock connected to the debug hub (dbg_hub) core is a free running clock and is active. +2. Make sure the BSCAN_SWITCH_USER_MASK device property in Vivado Hardware Manager reflects the user scan chain setting in the design and refresh the device. To determine the user scan chain setting in the design, open the implemented design and use 'get_property C_USER_SCAN_CHAIN [get_debug_cores dbg_hub]'. +For more details on setting the scan chain property, consult the Vivado Debug and Programming User Guide (UG908). +INFO: [Labtools 27-3164] End of startup status: HIGH +INFO: [Common 17-206] Exiting Vivado at Thu Nov 28 04:01:36 2019... +``` + +After programming the LED4~LED7 shall show some activity. + +### QSPI flash programming + +Run `make flash` to program the bit file to the QSPI flash. + +You should get output like the following; +``` +... +****** Xilinx hw_server v2018.1 + **** Build date : Apr 4 2018-18:56:09 + ** Copyright 1986-2018 Xilinx, Inc. All Rights Reserved. + + +INFO: [Labtoolstcl 44-466] Opening hw_target localhost:3121/xilinx_tcf/Digilent/210319AB569AA +INFO: [Labtools 27-1434] Device xc7a35t (JTAG device index = 0) is programmed with a design that has no supported debug core(s) in it. +... +INFO: [Labtools 27-3164] End of startup status: HIGH +Mfg ID : 1 Memory Type : 20 Memory Capacity : 18 Device ID 1 : 0 Device ID 2 : 0 +Performing Erase Operation... +Erase Operation successful. +Performing Program and Verify Operations... +Program/Verify Operation successful. +INFO: [Labtoolstcl 44-377] Flash programming completed successfully +program_hw_cfgmem: Time (s): cpu = 00:00:00.11 ; elapsed = 00:00:52 . Memory (MB): peak = 1792.711 ; gain = 8.000 ; free physical = 17712 ; free virtual = 56943 +INFO: [Labtoolstcl 44-464] Closing hw_target localhost:3121/xilinx_tcf/Digilent/210319AB569AA +... +INFO: [Common 17-206] Exiting Vivado at Thu Nov 28 04:06:28 2019... +``` + +After programming the flash you need to press the "PROG" button on the board. Then after a second or so the "DONE" LED shall be ON and LED4~LED7 shall show some activity. + + +## Connect + +After programming you should be able to connect to the serial port and have some output. + +On Linux you can do this using a command like `screen /dev/ttyUSB1`. Other good alternatives: + +* moserial (GUI) +* picocom (can be launched via the file "picocom_arty") + +Parameters: +* port is : /dev/ttyUSB1 +* flowcontrol : none +* baudrate is : 115200 +* parity is : none +* databits are : 8 +* stopbits are : 1 diff --git a/scripts/Murax/arty_a7/arty_a7.xdc b/scripts/Murax/arty_a7/arty_a7.xdc new file mode 100644 index 00000000..5ddd8fe1 --- /dev/null +++ b/scripts/Murax/arty_a7/arty_a7.xdc @@ -0,0 +1,366 @@ +set_property PACKAGE_PIN F4 [get_ports tck] +set_property IOSTANDARD LVCMOS33 [get_ports tck] + +set_property PACKAGE_PIN D2 [get_ports tms] +set_property IOSTANDARD LVCMOS33 [get_ports tms] + +set_property PACKAGE_PIN D4 [get_ports tdo] +set_property IOSTANDARD LVCMOS33 [get_ports tdo] +set_property PULLUP true [get_ports tdo] + +set_property PACKAGE_PIN E2 [get_ports tdi] +set_property IOSTANDARD LVCMOS33 [get_ports tdi] + +set_property PACKAGE_PIN D3 [get_ports trst] +set_property IOSTANDARD LVCMOS33 [get_ports trst] +set_property PULLUP true [get_ports trst] + + +## serial:0.tx +set_property PACKAGE_PIN D10 [get_ports serial_tx] +set_property IOSTANDARD LVCMOS33 [get_ports serial_tx] +## serial:0.rx +set_property PACKAGE_PIN A9 [get_ports serial_rx] +set_property IOSTANDARD LVCMOS33 [get_ports serial_rx] +## clk100:0 +set_property PACKAGE_PIN E3 [get_ports clk100] +set_property IOSTANDARD LVCMOS33 [get_ports clk100] +## cpu_reset:0 +set_property PACKAGE_PIN C2 [get_ports cpu_reset] +set_property IOSTANDARD LVCMOS33 [get_ports cpu_reset] +## eth_ref_clk:0 +#set_property LOC G18 [get_ports eth_ref_clk] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_ref_clk] +## user_led:0 +set_property PACKAGE_PIN H5 [get_ports user_led0] +set_property IOSTANDARD LVCMOS33 [get_ports user_led0] +## user_led:1 +set_property PACKAGE_PIN J5 [get_ports user_led1] +set_property IOSTANDARD LVCMOS33 [get_ports user_led1] +## user_led:2 +set_property PACKAGE_PIN T9 [get_ports user_led2] +set_property IOSTANDARD LVCMOS33 [get_ports user_led2] +## user_led:3 +set_property PACKAGE_PIN T10 [get_ports user_led3] +set_property IOSTANDARD LVCMOS33 [get_ports user_led3] +## user_sw:0 +set_property PACKAGE_PIN A8 [get_ports user_sw0] +set_property IOSTANDARD LVCMOS33 [get_ports user_sw0] +## user_sw:1 +set_property PACKAGE_PIN C11 [get_ports user_sw1] +set_property IOSTANDARD LVCMOS33 [get_ports user_sw1] +## user_sw:2 +set_property PACKAGE_PIN C10 [get_ports user_sw2] +set_property IOSTANDARD LVCMOS33 [get_ports user_sw2] +## user_sw:3 +set_property PACKAGE_PIN A10 [get_ports user_sw3] +set_property IOSTANDARD LVCMOS33 [get_ports user_sw3] +## user_btn:0 +set_property PACKAGE_PIN D9 [get_ports user_btn0] +set_property IOSTANDARD LVCMOS33 [get_ports user_btn0] +## user_btn:1 +set_property PACKAGE_PIN C9 [get_ports user_btn1] +set_property IOSTANDARD LVCMOS33 [get_ports user_btn1] +## user_btn:2 +set_property PACKAGE_PIN B9 [get_ports user_btn2] +set_property IOSTANDARD LVCMOS33 [get_ports user_btn2] +## user_btn:3 +set_property PACKAGE_PIN B8 [get_ports user_btn3] +set_property IOSTANDARD LVCMOS33 [get_ports user_btn3] +## spiflash_1x:0.cs_n +#set_property LOC L13 [get_ports spiflash_1x_cs_n] +#set_property IOSTANDARD LVCMOS33 [get_ports spiflash_1x_cs_n] +# ## spiflash_1x:0.mosi +#set_property LOC K17 [get_ports spiflash_1x_mosi] +#set_property IOSTANDARD LVCMOS33 [get_ports spiflash_1x_mosi] +# ## spiflash_1x:0.miso +#set_property LOC K18 [get_ports spiflash_1x_miso] +#set_property IOSTANDARD LVCMOS33 [get_ports spiflash_1x_miso] +# ## spiflash_1x:0.wp +#set_property LOC L14 [get_ports spiflash_1x_wp] +#set_property IOSTANDARD LVCMOS33 [get_ports spiflash_1x_wp] +# ## spiflash_1x:0.hold +#set_property LOC M14 [get_ports spiflash_1x_hold] +#set_property IOSTANDARD LVCMOS33 [get_ports spiflash_1x_hold] +# ## ddram:0.a +#set_property LOC R2 [get_ports ddram_a[0]] +#set_property SLEW FAST [get_ports ddram_a[0]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_a[0]] +# ## ddram:0.a +#set_property LOC M6 [get_ports ddram_a[1]] +#set_property SLEW FAST [get_ports ddram_a[1]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_a[1]] +# ## ddram:0.a +#set_property LOC N4 [get_ports ddram_a[2]] +#set_property SLEW FAST [get_ports ddram_a[2]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_a[2]] +# ## ddram:0.a +#set_property LOC T1 [get_ports ddram_a[3]] +#set_property SLEW FAST [get_ports ddram_a[3]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_a[3]] +# ## ddram:0.a +#set_property LOC N6 [get_ports ddram_a[4]] +#set_property SLEW FAST [get_ports ddram_a[4]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_a[4]] +# ## ddram:0.a +#set_property LOC R7 [get_ports ddram_a[5]] +#set_property SLEW FAST [get_ports ddram_a[5]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_a[5]] +# ## ddram:0.a +#set_property LOC V6 [get_ports ddram_a[6]] +#set_property SLEW FAST [get_ports ddram_a[6]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_a[6]] +# ## ddram:0.a +#set_property LOC U7 [get_ports ddram_a[7]] +#set_property SLEW FAST [get_ports ddram_a[7]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_a[7]] +# ## ddram:0.a +#set_property LOC R8 [get_ports ddram_a[8]] +#set_property SLEW FAST [get_ports ddram_a[8]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_a[8]] +# ## ddram:0.a +#set_property LOC V7 [get_ports ddram_a[9]] +#set_property SLEW FAST [get_ports ddram_a[9]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_a[9]] +# ## ddram:0.a +#set_property LOC R6 [get_ports ddram_a[10]] +#set_property SLEW FAST [get_ports ddram_a[10]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_a[10]] +# ## ddram:0.a +#set_property LOC U6 [get_ports ddram_a[11]] +#set_property SLEW FAST [get_ports ddram_a[11]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_a[11]] +# ## ddram:0.a +#set_property LOC T6 [get_ports ddram_a[12]] +#set_property SLEW FAST [get_ports ddram_a[12]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_a[12]] +# ## ddram:0.a +#set_property LOC T8 [get_ports ddram_a[13]] +#set_property SLEW FAST [get_ports ddram_a[13]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_a[13]] +# ## ddram:0.ba +#set_property LOC R1 [get_ports ddram_ba[0]] +#set_property SLEW FAST [get_ports ddram_ba[0]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_ba[0]] +# ## ddram:0.ba +#set_property LOC P4 [get_ports ddram_ba[1]] +#set_property SLEW FAST [get_ports ddram_ba[1]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_ba[1]] +# ## ddram:0.ba +#set_property LOC P2 [get_ports ddram_ba[2]] +#set_property SLEW FAST [get_ports ddram_ba[2]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_ba[2]] +# ## ddram:0.ras_n +#set_property LOC P3 [get_ports ddram_ras_n] +#set_property SLEW FAST [get_ports ddram_ras_n] +#set_property IOSTANDARD SSTL15 [get_ports ddram_ras_n] +# ## ddram:0.cas_n +#set_property LOC M4 [get_ports ddram_cas_n] +#set_property SLEW FAST [get_ports ddram_cas_n] +#set_property IOSTANDARD SSTL15 [get_ports ddram_cas_n] +# ## ddram:0.we_n +#set_property LOC P5 [get_ports ddram_we_n] +#set_property SLEW FAST [get_ports ddram_we_n] +#set_property IOSTANDARD SSTL15 [get_ports ddram_we_n] +# ## ddram:0.cs_n +#set_property LOC U8 [get_ports ddram_cs_n] +#set_property SLEW FAST [get_ports ddram_cs_n] +#set_property IOSTANDARD SSTL15 [get_ports ddram_cs_n] +# ## ddram:0.dm +#set_property LOC L1 [get_ports ddram_dm[0]] +#set_property SLEW FAST [get_ports ddram_dm[0]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dm[0]] +# ## ddram:0.dm +#set_property LOC U1 [get_ports ddram_dm[1]] +#set_property SLEW FAST [get_ports ddram_dm[1]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dm[1]] +# ## ddram:0.dq +#set_property LOC K5 [get_ports ddram_dq[0]] +#set_property SLEW FAST [get_ports ddram_dq[0]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[0]] +#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[0]] +# ## ddram:0.dq +#set_property LOC L3 [get_ports ddram_dq[1]] +#set_property SLEW FAST [get_ports ddram_dq[1]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[1]] +#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[1]] +# ## ddram:0.dq +#set_property LOC K3 [get_ports ddram_dq[2]] +#set_property SLEW FAST [get_ports ddram_dq[2]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[2]] +#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[2]] +# ## ddram:0.dq +#set_property LOC L6 [get_ports ddram_dq[3]] +#set_property SLEW FAST [get_ports ddram_dq[3]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[3]] +#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[3]] +# ## ddram:0.dq +#set_property LOC M3 [get_ports ddram_dq[4]] +#set_property SLEW FAST [get_ports ddram_dq[4]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[4]] +#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[4]] +# ## ddram:0.dq +#set_property LOC M1 [get_ports ddram_dq[5]] +#set_property SLEW FAST [get_ports ddram_dq[5]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[5]] +#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[5]] +# ## ddram:0.dq +#set_property LOC L4 [get_ports ddram_dq[6]] +#set_property SLEW FAST [get_ports ddram_dq[6]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[6]] +#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[6]] +# ## ddram:0.dq +#set_property LOC M2 [get_ports ddram_dq[7]] +#set_property SLEW FAST [get_ports ddram_dq[7]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[7]] +#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[7]] +# ## ddram:0.dq +#set_property LOC V4 [get_ports ddram_dq[8]] +#set_property SLEW FAST [get_ports ddram_dq[8]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[8]] +#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[8]] +# ## ddram:0.dq +#set_property LOC T5 [get_ports ddram_dq[9]] +#set_property SLEW FAST [get_ports ddram_dq[9]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[9]] +#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[9]] +# ## ddram:0.dq +#set_property LOC U4 [get_ports ddram_dq[10]] +#set_property SLEW FAST [get_ports ddram_dq[10]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[10]] +#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[10]] +# ## ddram:0.dq +#set_property LOC V5 [get_ports ddram_dq[11]] +#set_property SLEW FAST [get_ports ddram_dq[11]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[11]] +#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[11]] +# ## ddram:0.dq +#set_property LOC V1 [get_ports ddram_dq[12]] +#set_property SLEW FAST [get_ports ddram_dq[12]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[12]] +#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[12]] +# ## ddram:0.dq +#set_property LOC T3 [get_ports ddram_dq[13]] +#set_property SLEW FAST [get_ports ddram_dq[13]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[13]] +#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[13]] +# ## ddram:0.dq +#set_property LOC U3 [get_ports ddram_dq[14]] +#set_property SLEW FAST [get_ports ddram_dq[14]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[14]] +#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[14]] +# ## ddram:0.dq +#set_property LOC R3 [get_ports ddram_dq[15]] +#set_property SLEW FAST [get_ports ddram_dq[15]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[15]] +#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[15]] +# ## ddram:0.dqs_p +#set_property LOC N2 [get_ports ddram_dqs_p[0]] +#set_property SLEW FAST [get_ports ddram_dqs_p[0]] +#set_property IOSTANDARD DIFF_SSTL15 [get_ports ddram_dqs_p[0]] +# ## ddram:0.dqs_p +#set_property LOC U2 [get_ports ddram_dqs_p[1]] +#set_property SLEW FAST [get_ports ddram_dqs_p[1]] +#set_property IOSTANDARD DIFF_SSTL15 [get_ports ddram_dqs_p[1]] +# ## ddram:0.dqs_n +#set_property LOC N1 [get_ports ddram_dqs_n[0]] +#set_property SLEW FAST [get_ports ddram_dqs_n[0]] +#set_property IOSTANDARD DIFF_SSTL15 [get_ports ddram_dqs_n[0]] +# ## ddram:0.dqs_n +#set_property LOC V2 [get_ports ddram_dqs_n[1]] +#set_property SLEW FAST [get_ports ddram_dqs_n[1]] +#set_property IOSTANDARD DIFF_SSTL15 [get_ports ddram_dqs_n[1]] +# ## ddram:0.clk_p +#set_property LOC U9 [get_ports ddram_clk_p] +#set_property SLEW FAST [get_ports ddram_clk_p] +#set_property IOSTANDARD DIFF_SSTL15 [get_ports ddram_clk_p] +# ## ddram:0.clk_n +#set_property LOC V9 [get_ports ddram_clk_n] +#set_property SLEW FAST [get_ports ddram_clk_n] +#set_property IOSTANDARD DIFF_SSTL15 [get_ports ddram_clk_n] +# ## ddram:0.cke +#set_property LOC N5 [get_ports ddram_cke] +#set_property SLEW FAST [get_ports ddram_cke] +#set_property IOSTANDARD SSTL15 [get_ports ddram_cke] +# ## ddram:0.odt +#set_property LOC R5 [get_ports ddram_odt] +#set_property SLEW FAST [get_ports ddram_odt] +#set_property IOSTANDARD SSTL15 [get_ports ddram_odt] +# ## ddram:0.reset_n +#set_property LOC K6 [get_ports ddram_reset_n] +#set_property SLEW FAST [get_ports ddram_reset_n] +#set_property IOSTANDARD SSTL15 [get_ports ddram_reset_n] +# ## eth_clocks:0.tx +#set_property LOC H16 [get_ports eth_clocks_tx] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_clocks_tx] +# ## eth_clocks:0.rx +#set_property LOC F15 [get_ports eth_clocks_rx] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_clocks_rx] +# ## eth:0.rst_n +#set_property LOC C16 [get_ports eth_rst_n] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_rst_n] +# ## eth:0.mdio +#set_property LOC K13 [get_ports eth_mdio] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_mdio] +# ## eth:0.mdc +#set_property LOC F16 [get_ports eth_mdc] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_mdc] +# ## eth:0.rx_dv +#set_property LOC G16 [get_ports eth_rx_dv] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_rx_dv] +# ## eth:0.rx_er +#set_property LOC C17 [get_ports eth_rx_er] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_rx_er] +# ## eth:0.rx_data +#set_property LOC D18 [get_ports eth_rx_data[0]] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_rx_data[0]] +# ## eth:0.rx_data +#set_property LOC E17 [get_ports eth_rx_data[1]] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_rx_data[1]] +# ## eth:0.rx_data +#set_property LOC E18 [get_ports eth_rx_data[2]] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_rx_data[2]] +# ## eth:0.rx_data +#set_property LOC G17 [get_ports eth_rx_data[3]] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_rx_data[3]] +# ## eth:0.tx_en +#set_property LOC H15 [get_ports eth_tx_en] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_tx_en] +# ## eth:0.tx_data +#set_property LOC H14 [get_ports eth_tx_data[0]] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_tx_data[0]] +# ## eth:0.tx_data +#set_property LOC J14 [get_ports eth_tx_data[1]] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_tx_data[1]] +# ## eth:0.tx_data +#set_property LOC J13 [get_ports eth_tx_data[2]] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_tx_data[2]] +# ## eth:0.tx_data +#set_property LOC H17 [get_ports eth_tx_data[3]] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_tx_data[3]] +# ## eth:0.col +#set_property LOC D17 [get_ports eth_col] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_col] +# ## eth:0.crs +#set_property LOC G14 [get_ports eth_crs] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_crs] + +set_property INTERNAL_VREF 0.75 [get_iobanks 34] + + +create_clock -period 10.000 -name clk100 [get_nets clk100] + +#create_clock -name eth_rx_clk -period 40.0 [get_nets eth_rx_clk] + +#create_clock -name eth_tx_clk -period 40.0 [get_nets eth_tx_clk] + +#set_clock_groups -group [get_clocks -include_generated_clocks -of [get_nets sys_clk]] -group [get_clocks -include_generated_clocks -of [get_nets eth_rx_clk]] -asynchronous + +#set_clock_groups -group [get_clocks -include_generated_clocks -of [get_nets sys_clk]] -group [get_clocks -include_generated_clocks -of [get_nets eth_tx_clk]] -asynchronous + +#set_clock_groups -group [get_clocks -include_generated_clocks -of [get_nets eth_rx_clk]] -group [get_clocks -include_generated_clocks -of [get_nets eth_tx_clk]] -asynchronous + + + + +set_property BITSTREAM.CONFIG.SPI_BUSWIDTH 4 [current_design] diff --git a/scripts/Murax/arty_a7/arty_a7_org.xdc b/scripts/Murax/arty_a7/arty_a7_org.xdc new file mode 100644 index 00000000..75c81b14 --- /dev/null +++ b/scripts/Murax/arty_a7/arty_a7_org.xdc @@ -0,0 +1,350 @@ + ## serial:0.tx +set_property LOC D10 [get_ports serial_tx] +set_property IOSTANDARD LVCMOS33 [get_ports serial_tx] + ## serial:0.rx +set_property LOC A9 [get_ports serial_rx] +set_property IOSTANDARD LVCMOS33 [get_ports serial_rx] + ## clk100:0 +set_property LOC E3 [get_ports clk100] +set_property IOSTANDARD LVCMOS33 [get_ports clk100] + ## cpu_reset:0 +set_property LOC C2 [get_ports cpu_reset] +set_property IOSTANDARD LVCMOS33 [get_ports cpu_reset] + ## eth_ref_clk:0 +#set_property LOC G18 [get_ports eth_ref_clk] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_ref_clk] + ## user_led:0 +set_property LOC H5 [get_ports user_led0] +set_property IOSTANDARD LVCMOS33 [get_ports user_led0] + ## user_led:1 +set_property LOC J5 [get_ports user_led1] +set_property IOSTANDARD LVCMOS33 [get_ports user_led1] + ## user_led:2 +set_property LOC T9 [get_ports user_led2] +set_property IOSTANDARD LVCMOS33 [get_ports user_led2] + ## user_led:3 +set_property LOC T10 [get_ports user_led3] +set_property IOSTANDARD LVCMOS33 [get_ports user_led3] + ## user_sw:0 +set_property LOC A8 [get_ports user_sw0] +set_property IOSTANDARD LVCMOS33 [get_ports user_sw0] + ## user_sw:1 +set_property LOC C11 [get_ports user_sw1] +set_property IOSTANDARD LVCMOS33 [get_ports user_sw1] + ## user_sw:2 +set_property LOC C10 [get_ports user_sw2] +set_property IOSTANDARD LVCMOS33 [get_ports user_sw2] + ## user_sw:3 +set_property LOC A10 [get_ports user_sw3] +set_property IOSTANDARD LVCMOS33 [get_ports user_sw3] + ## user_btn:0 +set_property LOC D9 [get_ports user_btn0] +set_property IOSTANDARD LVCMOS33 [get_ports user_btn0] + ## user_btn:1 +set_property LOC C9 [get_ports user_btn1] +set_property IOSTANDARD LVCMOS33 [get_ports user_btn1] + ## user_btn:2 +set_property LOC B9 [get_ports user_btn2] +set_property IOSTANDARD LVCMOS33 [get_ports user_btn2] + ## user_btn:3 +set_property LOC B8 [get_ports user_btn3] +set_property IOSTANDARD LVCMOS33 [get_ports user_btn3] + ## spiflash_1x:0.cs_n +#set_property LOC L13 [get_ports spiflash_1x_cs_n] +#set_property IOSTANDARD LVCMOS33 [get_ports spiflash_1x_cs_n] +# ## spiflash_1x:0.mosi +#set_property LOC K17 [get_ports spiflash_1x_mosi] +#set_property IOSTANDARD LVCMOS33 [get_ports spiflash_1x_mosi] +# ## spiflash_1x:0.miso +#set_property LOC K18 [get_ports spiflash_1x_miso] +#set_property IOSTANDARD LVCMOS33 [get_ports spiflash_1x_miso] +# ## spiflash_1x:0.wp +#set_property LOC L14 [get_ports spiflash_1x_wp] +#set_property IOSTANDARD LVCMOS33 [get_ports spiflash_1x_wp] +# ## spiflash_1x:0.hold +#set_property LOC M14 [get_ports spiflash_1x_hold] +#set_property IOSTANDARD LVCMOS33 [get_ports spiflash_1x_hold] +# ## ddram:0.a +#set_property LOC R2 [get_ports ddram_a[0]] +#set_property SLEW FAST [get_ports ddram_a[0]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_a[0]] +# ## ddram:0.a +#set_property LOC M6 [get_ports ddram_a[1]] +#set_property SLEW FAST [get_ports ddram_a[1]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_a[1]] +# ## ddram:0.a +#set_property LOC N4 [get_ports ddram_a[2]] +#set_property SLEW FAST [get_ports ddram_a[2]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_a[2]] +# ## ddram:0.a +#set_property LOC T1 [get_ports ddram_a[3]] +#set_property SLEW FAST [get_ports ddram_a[3]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_a[3]] +# ## ddram:0.a +#set_property LOC N6 [get_ports ddram_a[4]] +#set_property SLEW FAST [get_ports ddram_a[4]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_a[4]] +# ## ddram:0.a +#set_property LOC R7 [get_ports ddram_a[5]] +#set_property SLEW FAST [get_ports ddram_a[5]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_a[5]] +# ## ddram:0.a +#set_property LOC V6 [get_ports ddram_a[6]] +#set_property SLEW FAST [get_ports ddram_a[6]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_a[6]] +# ## ddram:0.a +#set_property LOC U7 [get_ports ddram_a[7]] +#set_property SLEW FAST [get_ports ddram_a[7]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_a[7]] +# ## ddram:0.a +#set_property LOC R8 [get_ports ddram_a[8]] +#set_property SLEW FAST [get_ports ddram_a[8]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_a[8]] +# ## ddram:0.a +#set_property LOC V7 [get_ports ddram_a[9]] +#set_property SLEW FAST [get_ports ddram_a[9]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_a[9]] +# ## ddram:0.a +#set_property LOC R6 [get_ports ddram_a[10]] +#set_property SLEW FAST [get_ports ddram_a[10]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_a[10]] +# ## ddram:0.a +#set_property LOC U6 [get_ports ddram_a[11]] +#set_property SLEW FAST [get_ports ddram_a[11]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_a[11]] +# ## ddram:0.a +#set_property LOC T6 [get_ports ddram_a[12]] +#set_property SLEW FAST [get_ports ddram_a[12]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_a[12]] +# ## ddram:0.a +#set_property LOC T8 [get_ports ddram_a[13]] +#set_property SLEW FAST [get_ports ddram_a[13]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_a[13]] +# ## ddram:0.ba +#set_property LOC R1 [get_ports ddram_ba[0]] +#set_property SLEW FAST [get_ports ddram_ba[0]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_ba[0]] +# ## ddram:0.ba +#set_property LOC P4 [get_ports ddram_ba[1]] +#set_property SLEW FAST [get_ports ddram_ba[1]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_ba[1]] +# ## ddram:0.ba +#set_property LOC P2 [get_ports ddram_ba[2]] +#set_property SLEW FAST [get_ports ddram_ba[2]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_ba[2]] +# ## ddram:0.ras_n +#set_property LOC P3 [get_ports ddram_ras_n] +#set_property SLEW FAST [get_ports ddram_ras_n] +#set_property IOSTANDARD SSTL15 [get_ports ddram_ras_n] +# ## ddram:0.cas_n +#set_property LOC M4 [get_ports ddram_cas_n] +#set_property SLEW FAST [get_ports ddram_cas_n] +#set_property IOSTANDARD SSTL15 [get_ports ddram_cas_n] +# ## ddram:0.we_n +#set_property LOC P5 [get_ports ddram_we_n] +#set_property SLEW FAST [get_ports ddram_we_n] +#set_property IOSTANDARD SSTL15 [get_ports ddram_we_n] +# ## ddram:0.cs_n +#set_property LOC U8 [get_ports ddram_cs_n] +#set_property SLEW FAST [get_ports ddram_cs_n] +#set_property IOSTANDARD SSTL15 [get_ports ddram_cs_n] +# ## ddram:0.dm +#set_property LOC L1 [get_ports ddram_dm[0]] +#set_property SLEW FAST [get_ports ddram_dm[0]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dm[0]] +# ## ddram:0.dm +#set_property LOC U1 [get_ports ddram_dm[1]] +#set_property SLEW FAST [get_ports ddram_dm[1]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dm[1]] +# ## ddram:0.dq +#set_property LOC K5 [get_ports ddram_dq[0]] +#set_property SLEW FAST [get_ports ddram_dq[0]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[0]] +#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[0]] +# ## ddram:0.dq +#set_property LOC L3 [get_ports ddram_dq[1]] +#set_property SLEW FAST [get_ports ddram_dq[1]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[1]] +#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[1]] +# ## ddram:0.dq +#set_property LOC K3 [get_ports ddram_dq[2]] +#set_property SLEW FAST [get_ports ddram_dq[2]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[2]] +#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[2]] +# ## ddram:0.dq +#set_property LOC L6 [get_ports ddram_dq[3]] +#set_property SLEW FAST [get_ports ddram_dq[3]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[3]] +#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[3]] +# ## ddram:0.dq +#set_property LOC M3 [get_ports ddram_dq[4]] +#set_property SLEW FAST [get_ports ddram_dq[4]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[4]] +#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[4]] +# ## ddram:0.dq +#set_property LOC M1 [get_ports ddram_dq[5]] +#set_property SLEW FAST [get_ports ddram_dq[5]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[5]] +#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[5]] +# ## ddram:0.dq +#set_property LOC L4 [get_ports ddram_dq[6]] +#set_property SLEW FAST [get_ports ddram_dq[6]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[6]] +#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[6]] +# ## ddram:0.dq +#set_property LOC M2 [get_ports ddram_dq[7]] +#set_property SLEW FAST [get_ports ddram_dq[7]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[7]] +#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[7]] +# ## ddram:0.dq +#set_property LOC V4 [get_ports ddram_dq[8]] +#set_property SLEW FAST [get_ports ddram_dq[8]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[8]] +#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[8]] +# ## ddram:0.dq +#set_property LOC T5 [get_ports ddram_dq[9]] +#set_property SLEW FAST [get_ports ddram_dq[9]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[9]] +#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[9]] +# ## ddram:0.dq +#set_property LOC U4 [get_ports ddram_dq[10]] +#set_property SLEW FAST [get_ports ddram_dq[10]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[10]] +#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[10]] +# ## ddram:0.dq +#set_property LOC V5 [get_ports ddram_dq[11]] +#set_property SLEW FAST [get_ports ddram_dq[11]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[11]] +#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[11]] +# ## ddram:0.dq +#set_property LOC V1 [get_ports ddram_dq[12]] +#set_property SLEW FAST [get_ports ddram_dq[12]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[12]] +#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[12]] +# ## ddram:0.dq +#set_property LOC T3 [get_ports ddram_dq[13]] +#set_property SLEW FAST [get_ports ddram_dq[13]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[13]] +#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[13]] +# ## ddram:0.dq +#set_property LOC U3 [get_ports ddram_dq[14]] +#set_property SLEW FAST [get_ports ddram_dq[14]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[14]] +#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[14]] +# ## ddram:0.dq +#set_property LOC R3 [get_ports ddram_dq[15]] +#set_property SLEW FAST [get_ports ddram_dq[15]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[15]] +#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[15]] +# ## ddram:0.dqs_p +#set_property LOC N2 [get_ports ddram_dqs_p[0]] +#set_property SLEW FAST [get_ports ddram_dqs_p[0]] +#set_property IOSTANDARD DIFF_SSTL15 [get_ports ddram_dqs_p[0]] +# ## ddram:0.dqs_p +#set_property LOC U2 [get_ports ddram_dqs_p[1]] +#set_property SLEW FAST [get_ports ddram_dqs_p[1]] +#set_property IOSTANDARD DIFF_SSTL15 [get_ports ddram_dqs_p[1]] +# ## ddram:0.dqs_n +#set_property LOC N1 [get_ports ddram_dqs_n[0]] +#set_property SLEW FAST [get_ports ddram_dqs_n[0]] +#set_property IOSTANDARD DIFF_SSTL15 [get_ports ddram_dqs_n[0]] +# ## ddram:0.dqs_n +#set_property LOC V2 [get_ports ddram_dqs_n[1]] +#set_property SLEW FAST [get_ports ddram_dqs_n[1]] +#set_property IOSTANDARD DIFF_SSTL15 [get_ports ddram_dqs_n[1]] +# ## ddram:0.clk_p +#set_property LOC U9 [get_ports ddram_clk_p] +#set_property SLEW FAST [get_ports ddram_clk_p] +#set_property IOSTANDARD DIFF_SSTL15 [get_ports ddram_clk_p] +# ## ddram:0.clk_n +#set_property LOC V9 [get_ports ddram_clk_n] +#set_property SLEW FAST [get_ports ddram_clk_n] +#set_property IOSTANDARD DIFF_SSTL15 [get_ports ddram_clk_n] +# ## ddram:0.cke +#set_property LOC N5 [get_ports ddram_cke] +#set_property SLEW FAST [get_ports ddram_cke] +#set_property IOSTANDARD SSTL15 [get_ports ddram_cke] +# ## ddram:0.odt +#set_property LOC R5 [get_ports ddram_odt] +#set_property SLEW FAST [get_ports ddram_odt] +#set_property IOSTANDARD SSTL15 [get_ports ddram_odt] +# ## ddram:0.reset_n +#set_property LOC K6 [get_ports ddram_reset_n] +#set_property SLEW FAST [get_ports ddram_reset_n] +#set_property IOSTANDARD SSTL15 [get_ports ddram_reset_n] +# ## eth_clocks:0.tx +#set_property LOC H16 [get_ports eth_clocks_tx] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_clocks_tx] +# ## eth_clocks:0.rx +#set_property LOC F15 [get_ports eth_clocks_rx] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_clocks_rx] +# ## eth:0.rst_n +#set_property LOC C16 [get_ports eth_rst_n] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_rst_n] +# ## eth:0.mdio +#set_property LOC K13 [get_ports eth_mdio] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_mdio] +# ## eth:0.mdc +#set_property LOC F16 [get_ports eth_mdc] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_mdc] +# ## eth:0.rx_dv +#set_property LOC G16 [get_ports eth_rx_dv] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_rx_dv] +# ## eth:0.rx_er +#set_property LOC C17 [get_ports eth_rx_er] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_rx_er] +# ## eth:0.rx_data +#set_property LOC D18 [get_ports eth_rx_data[0]] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_rx_data[0]] +# ## eth:0.rx_data +#set_property LOC E17 [get_ports eth_rx_data[1]] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_rx_data[1]] +# ## eth:0.rx_data +#set_property LOC E18 [get_ports eth_rx_data[2]] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_rx_data[2]] +# ## eth:0.rx_data +#set_property LOC G17 [get_ports eth_rx_data[3]] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_rx_data[3]] +# ## eth:0.tx_en +#set_property LOC H15 [get_ports eth_tx_en] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_tx_en] +# ## eth:0.tx_data +#set_property LOC H14 [get_ports eth_tx_data[0]] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_tx_data[0]] +# ## eth:0.tx_data +#set_property LOC J14 [get_ports eth_tx_data[1]] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_tx_data[1]] +# ## eth:0.tx_data +#set_property LOC J13 [get_ports eth_tx_data[2]] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_tx_data[2]] +# ## eth:0.tx_data +#set_property LOC H17 [get_ports eth_tx_data[3]] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_tx_data[3]] +# ## eth:0.col +#set_property LOC D17 [get_ports eth_col] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_col] +# ## eth:0.crs +#set_property LOC G14 [get_ports eth_crs] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_crs] + +set_property INTERNAL_VREF 0.750 [get_iobanks 34] + +create_clock -name sys_clk -period 10.0 [get_nets sys_clk] + +create_clock -name clk100 -period 10.0 [get_nets clk100] + +#create_clock -name eth_rx_clk -period 40.0 [get_nets eth_rx_clk] + +#create_clock -name eth_tx_clk -period 40.0 [get_nets eth_tx_clk] + +#set_clock_groups -group [get_clocks -include_generated_clocks -of [get_nets sys_clk]] -group [get_clocks -include_generated_clocks -of [get_nets eth_rx_clk]] -asynchronous + +#set_clock_groups -group [get_clocks -include_generated_clocks -of [get_nets sys_clk]] -group [get_clocks -include_generated_clocks -of [get_nets eth_tx_clk]] -asynchronous + +#set_clock_groups -group [get_clocks -include_generated_clocks -of [get_nets eth_rx_clk]] -group [get_clocks -include_generated_clocks -of [get_nets eth_tx_clk]] -asynchronous + +set_false_path -quiet -to [get_nets -quiet -filter {mr_ff == TRUE}] + +set_false_path -quiet -to [get_pins -quiet -filter {REF_PIN_NAME == PRE} -of [get_cells -quiet -filter {ars_ff1 == TRUE || ars_ff2 == TRUE}]] + +set_max_delay 2 -quiet -from [get_pins -quiet -filter {REF_PIN_NAME == Q} -of [get_cells -quiet -filter {ars_ff1 == TRUE}]] -to [get_pins -quiet -filter {REF_PIN_NAME == D} -of [get_cells -quiet -filter {ars_ff2 == TRUE}]] diff --git a/scripts/Murax/arty_a7/make_mcs_file b/scripts/Murax/arty_a7/make_mcs_file new file mode 100755 index 00000000..40bcc5ac --- /dev/null +++ b/scripts/Murax/arty_a7/make_mcs_file @@ -0,0 +1,6 @@ +#!/bin/sh +#Create mcs file for QSPI flash + +cd ./build + +vivado -mode batch -source ../make_mcs_file.tcl -notrace diff --git a/scripts/Murax/arty_a7/make_mmi_files b/scripts/Murax/arty_a7/make_mmi_files new file mode 100755 index 00000000..3919e16a --- /dev/null +++ b/scripts/Murax/arty_a7/make_mmi_files @@ -0,0 +1,4 @@ +#!/bin/sh + +cd ./build +vivado -mode batch -source ../make_mmi_files.tcl -notrace diff --git a/scripts/Murax/arty_a7/make_vivado_project b/scripts/Murax/arty_a7/make_vivado_project new file mode 100755 index 00000000..4a925107 --- /dev/null +++ b/scripts/Murax/arty_a7/make_vivado_project @@ -0,0 +1,9 @@ +#!/bin/sh + +#cannot rm build because it erase software images that the make file copy there +#rm -rf ./build + +mkdir ./build + +cd ./build +vivado -mode batch -source ../make_vivado_project.tcl -notrace diff --git a/scripts/Murax/arty_a7/makefile b/scripts/Murax/arty_a7/makefile new file mode 100644 index 00000000..b6726523 --- /dev/null +++ b/scripts/Murax/arty_a7/makefile @@ -0,0 +1,62 @@ +ROOT=../../.. +SWBASE=$(ROOT)/src/main/c/murax +SOCSW=hello_world +SOCMEMSRC=$(SWBASE)/$(SOCSW)/build/$(SOCSW).v +SOCMEM=build/soc.mem + +TOP=Murax + +all : build/latest.bit + +../../../$(TOP).v : toplevel.v + (cd ../../..; sbt "runMain vexriscv.demo.Murax_arty") + +.PHONY: $(SOCMEMSRC) +$(SOCMEMSRC): + mkdir -p build + make -C $(SWBASE)/$(SOCSW) + +$(SOCMEM) : $(SOCMEMSRC) + cp -u $(SOCMEMSRC) $(SOCMEM) + +build/vivado_project/fpga.runs/impl_1/toplevel.bit : toplevel.v arty_a7.xdc ../../../$(TOP).v + mkdir -p build + ./make_vivado_project + cp build/vivado_project/fpga.runs/impl_1/toplevel.bit build/latest.bit + +build/soc.mmi: build/vivado_project/fpga.runs/impl_1/toplevel.bit + ./make_mmi_files + +build/latest_soc_sw.bit : $(SOCMEM) build/soc.mmi + rm -f updatemem.jou updatemem.log + updatemem -force --meminfo build/soc.mmi --data $(SOCMEM) --bit build/latest.bit --proc dummy --out build/latest_soc_sw.bit + cp build/latest_soc_sw.bit build/latest.bit + +build/latest.bit : build/latest_soc_sw.bit + +build/latest.mcs : build/latest.bit + ./make_mcs_file + +prog : build/latest.bit + ./write_fpga + +flash : build/latest.mcs + ./write_flash + +clean-soc-sw: + make -C $(SWBASE)/$(SOCSW) clean-all + +soc-sw: clean-soc-sw $(SOCMEM) + +.PHONY: clean +clean : + rm -rf build + mkdir build + rm -f updatemem.jou + rm -f updatemem.log + +clean-sw: clean-soc-sw + +clean-all : clean clean-sw + rm -f ../../../$(TOP).v + rm -f ../../../$(TOP).v_* diff --git a/scripts/Murax/arty_a7/open_vivado_project b/scripts/Murax/arty_a7/open_vivado_project new file mode 100755 index 00000000..24c54d12 --- /dev/null +++ b/scripts/Murax/arty_a7/open_vivado_project @@ -0,0 +1,4 @@ +#!/bin/sh + +cd ./build +vivado -mode batch -source ../open_vivado_project.tcl -notrace diff --git a/scripts/Murax/arty_a7/picocom_arty b/scripts/Murax/arty_a7/picocom_arty new file mode 100644 index 00000000..ff15a172 --- /dev/null +++ b/scripts/Murax/arty_a7/picocom_arty @@ -0,0 +1 @@ +picocom --baud 115200 --imap lfcrlf /dev/ttyUSB1 diff --git a/scripts/Murax/arty_a7/toplevel.v b/scripts/Murax/arty_a7/toplevel.v new file mode 100644 index 00000000..e127da69 --- /dev/null +++ b/scripts/Murax/arty_a7/toplevel.v @@ -0,0 +1,66 @@ +`timescale 1ns / 1ps + +module toplevel( + input wire clk100, + input wire cpu_reset,//active low + + input wire tck, + input wire tms, + input wire tdi, + input wire trst,//ignored + output reg tdo, + + input wire serial_rx, + output wire serial_tx, + + input wire user_sw0, + input wire user_sw1, + input wire user_sw2, + input wire user_sw3, + + input wire user_btn0, + input wire user_btn1, + input wire user_btn2, + input wire user_btn3, + + output wire user_led0, + output wire user_led1, + output wire user_led2, + output wire user_led3 + ); + + wire [31:0] io_gpioA_read; + wire [31:0] io_gpioA_write; + wire [31:0] io_gpioA_writeEnable; + + wire io_asyncReset = ~cpu_reset; + + assign {user_led3,user_led2,user_led1,user_led0} = io_gpioA_write[3 : 0]; + assign io_gpioA_read[3:0] = {user_sw3,user_sw2,user_sw1,user_sw0}; + assign io_gpioA_read[7:4] = {user_btn3,user_btn2,user_btn1,user_btn0}; + assign io_gpioA_read[11:8] = {tck,tms,tdi,trst}; + + reg tesic_tck,tesic_tms,tesic_tdi; + wire tesic_tdo; + reg soc_tck,soc_tms,soc_tdi; + wire soc_tdo; + + always @(*) begin + {soc_tck, soc_tms, soc_tdi } = {tck,tms,tdi}; + tdo = soc_tdo; + end + + Murax core ( + .io_asyncReset(io_asyncReset), + .io_mainClk (clk100 ), + .io_jtag_tck(soc_tck), + .io_jtag_tdi(soc_tdi), + .io_jtag_tdo(soc_tdo), + .io_jtag_tms(soc_tms), + .io_gpioA_read (io_gpioA_read), + .io_gpioA_write (io_gpioA_write), + .io_gpioA_writeEnable(io_gpioA_writeEnable), + .io_uart_txd(serial_tx), + .io_uart_rxd(serial_rx) + ); +endmodule diff --git a/scripts/Murax/arty_a7/write_flash b/scripts/Murax/arty_a7/write_flash new file mode 100755 index 00000000..05414c4a --- /dev/null +++ b/scripts/Murax/arty_a7/write_flash @@ -0,0 +1,3 @@ +#!/bin/sh +cd ./build +vivado -mode batch -source ../write_flash.tcl -notrace diff --git a/scripts/Murax/arty_a7/write_fpga b/scripts/Murax/arty_a7/write_fpga new file mode 100755 index 00000000..63a344e0 --- /dev/null +++ b/scripts/Murax/arty_a7/write_fpga @@ -0,0 +1,3 @@ +#!/bin/sh +cd ./build +vivado -mode batch -source ../write_fpga.tcl -notrace diff --git a/src/main/c/murax/hello_world/makefile b/src/main/c/murax/hello_world/makefile new file mode 100644 index 00000000..dc560c0a --- /dev/null +++ b/src/main/c/murax/hello_world/makefile @@ -0,0 +1,134 @@ +PROJ_NAME=hello_world +DEBUG=no +BENCH=no +MULDIV=no + +SRCS = $(wildcard src/*.c) \ + $(wildcard src/*.cpp) \ + $(wildcard src/*.S) + +OBJDIR = build + +INC = +LIBS = +LIBSINC = -L$(OBJDIR) +LDSCRIPT = ./src/linker.ld + +#include ../../../resources/gcc.mk +# Set it to yes if you are using the sifive precompiled GCC pack +SIFIVE_GCC_PACK ?= yes + +ifeq ($(SIFIVE_GCC_PACK),yes) + RISCV_NAME ?= riscv64-unknown-elf + RISCV_PATH ?= /opt/riscv/ +else + RISCV_NAME ?= riscv32-unknown-elf + ifeq ($(MULDIV),yes) + RISCV_PATH ?= /opt/riscv32im/ + else + RISCV_PATH ?= /opt/riscv32i/ + endif +endif + +MABI=ilp32 +MARCH := rv32i +ifeq ($(MULDIV),yes) + MARCH := $(MARCH)m +endif +ifeq ($(COMPRESSED),yes) + MARCH := $(MARCH)ac +endif + +CFLAGS += -march=$(MARCH) -mabi=$(MABI) -DNDEBUG +LDFLAGS += -march=$(MARCH) -mabi=$(MABI) + + + +#include ../../../resources/subproject.mk + + +ifeq ($(DEBUG),yes) + CFLAGS += -g3 -O0 +endif + +ifeq ($(DEBUG),no) + CFLAGS += -g -Os +endif + +ifeq ($(BENCH),yes) + CFLAGS += -fno-inline +endif + +ifeq ($(SIFIVE_GCC_PACK),yes) + RISCV_CLIB=$(RISCV_PATH)/$(RISCV_NAME)/lib/$(MARCH)/$(MABI)/ +else + RISCV_CLIB=$(RISCV_PATH)/$(RISCV_NAME)/lib/ +endif + + + + + +RISCV_OBJCOPY = $(RISCV_PATH)/bin/$(RISCV_NAME)-objcopy +RISCV_OBJDUMP = $(RISCV_PATH)/bin/$(RISCV_NAME)-objdump +RISCV_CC=$(RISCV_PATH)/bin/$(RISCV_NAME)-gcc + +CFLAGS += -MD -fstrict-volatile-bitfields -fno-strict-aliasing +LDFLAGS += -nostdlib -lgcc -mcmodel=medany -nostartfiles -ffreestanding -Wl,-Bstatic,-T,$(LDSCRIPT),-Map,$(OBJDIR)/$(PROJ_NAME).map,--print-memory-usage +#LDFLAGS += -lgcc -lc -lg -nostdlib -lgcc -msave-restore --strip-debug, + +OBJS := $(SRCS) +OBJS := $(OBJS:.c=.o) +OBJS := $(OBJS:.cpp=.o) +OBJS := $(OBJS:.S=.o) +OBJS := $(OBJS:..=miaou) +OBJS := $(addprefix $(OBJDIR)/,$(OBJS)) + + +all: $(OBJDIR)/$(PROJ_NAME).elf $(OBJDIR)/$(PROJ_NAME).hex $(OBJDIR)/$(PROJ_NAME).asm $(OBJDIR)/$(PROJ_NAME).v + +$(OBJDIR)/%.elf: $(OBJS) | $(OBJDIR) + $(RISCV_CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) $(LIBSINC) $(LIBS) + +%.hex: %.elf + $(RISCV_OBJCOPY) -O ihex $^ $@ + +%.bin: %.elf + $(RISCV_OBJCOPY) -O binary $^ $@ + +%.v: %.elf + $(RISCV_OBJCOPY) -O verilog $^ $@ + +%.asm: %.elf + $(RISCV_OBJDUMP) -S -d $^ > $@ + +$(OBJDIR)/%.o: %.c + mkdir -p $(dir $@) + $(RISCV_CC) -c $(CFLAGS) $(INC) -o $@ $^ + $(RISCV_CC) -S $(CFLAGS) $(INC) -o $@.disasm $^ + +$(OBJDIR)/%.o: %.cpp + mkdir -p $(dir $@) + $(RISCV_CC) -c $(CFLAGS) $(INC) -o $@ $^ + +$(OBJDIR)/%.o: %.S + mkdir -p $(dir $@) + $(RISCV_CC) -c $(CFLAGS) -o $@ $^ -D__ASSEMBLY__=1 + +$(OBJDIR): + mkdir -p $@ + +.PHONY: clean +clean: + rm -rf $(OBJDIR)/src + rm -f $(OBJDIR)/$(PROJ_NAME).elf + rm -f $(OBJDIR)/$(PROJ_NAME).hex + rm -f $(OBJDIR)/$(PROJ_NAME).map + rm -f $(OBJDIR)/$(PROJ_NAME).v + rm -f $(OBJDIR)/$(PROJ_NAME).asm + find $(OBJDIR) -type f -name '*.o' -print0 | xargs -0 -r rm + find $(OBJDIR) -type f -name '*.d' -print0 | xargs -0 -r rm + +clean-all : clean + +.SECONDARY: $(OBJS) diff --git a/src/main/c/murax/hello_world/src/crt.S b/src/main/c/murax/hello_world/src/crt.S new file mode 100644 index 00000000..62d67b9e --- /dev/null +++ b/src/main/c/murax/hello_world/src/crt.S @@ -0,0 +1,98 @@ +.global crtStart +.global main +.global irqCallback + + .section .start_jump,"ax",@progbits +crtStart: + //long jump to allow crtInit to be anywhere + //do it always in 12 bytes + lui x2, %hi(crtInit) + addi x2, x2, %lo(crtInit) + jalr x1,x2 + nop + +.section .text + +.global trap_entry +.align 5 +trap_entry: + sw x1, - 1*4(sp) + sw x5, - 2*4(sp) + sw x6, - 3*4(sp) + sw x7, - 4*4(sp) + sw x10, - 5*4(sp) + sw x11, - 6*4(sp) + sw x12, - 7*4(sp) + sw x13, - 8*4(sp) + sw x14, - 9*4(sp) + sw x15, -10*4(sp) + sw x16, -11*4(sp) + sw x17, -12*4(sp) + sw x28, -13*4(sp) + sw x29, -14*4(sp) + sw x30, -15*4(sp) + sw x31, -16*4(sp) + addi sp,sp,-16*4 + call irqCallback + lw x1 , 15*4(sp) + lw x5, 14*4(sp) + lw x6, 13*4(sp) + lw x7, 12*4(sp) + lw x10, 11*4(sp) + lw x11, 10*4(sp) + lw x12, 9*4(sp) + lw x13, 8*4(sp) + lw x14, 7*4(sp) + lw x15, 6*4(sp) + lw x16, 5*4(sp) + lw x17, 4*4(sp) + lw x28, 3*4(sp) + lw x29, 2*4(sp) + lw x30, 1*4(sp) + lw x31, 0*4(sp) + addi sp,sp,16*4 + mret + .text + + +crtInit: + .option push + .option norelax + la gp, __global_pointer$ + .option pop + la sp, _stack_start + +bss_init: + la a0, _bss_start + la a1, _bss_end +bss_loop: + beq a0,a1,bss_done + sw zero,0(a0) + add a0,a0,4 + j bss_loop +bss_done: + +ctors_init: + la a0, _ctors_start + addi sp,sp,-4 +ctors_loop: + la a1, _ctors_end + beq a0,a1,ctors_done + lw a3,0(a0) + add a0,a0,4 + sw a0,0(sp) + jalr a3 + lw a0,0(sp) + j ctors_loop +ctors_done: + addi sp,sp,4 + + + li a0, 0x880 //880 enable timer + external interrupts + csrw mie,a0 + li a0, 0x1808 //1808 enable interrupts + csrw mstatus,a0 + + call main +infinitLoop: + j infinitLoop diff --git a/src/main/c/murax/hello_world/src/gpio.h b/src/main/c/murax/hello_world/src/gpio.h new file mode 100644 index 00000000..34348fec --- /dev/null +++ b/src/main/c/murax/hello_world/src/gpio.h @@ -0,0 +1,15 @@ +#ifndef GPIO_H_ +#define GPIO_H_ + + +typedef struct +{ + volatile uint32_t INPUT; + volatile uint32_t OUTPUT; + volatile uint32_t OUTPUT_ENABLE; +} Gpio_Reg; + + +#endif /* GPIO_H_ */ + + diff --git a/src/main/c/murax/hello_world/src/interrupt.h b/src/main/c/murax/hello_world/src/interrupt.h new file mode 100644 index 00000000..23b7d277 --- /dev/null +++ b/src/main/c/murax/hello_world/src/interrupt.h @@ -0,0 +1,17 @@ +#ifndef INTERRUPTCTRL_H_ +#define INTERRUPTCTRL_H_ + +#include + +typedef struct +{ + volatile uint32_t PENDINGS; + volatile uint32_t MASKS; +} InterruptCtrl_Reg; + +static void interruptCtrl_init(InterruptCtrl_Reg* reg){ + reg->MASKS = 0; + reg->PENDINGS = 0xFFFFFFFF; +} + +#endif /* INTERRUPTCTRL_H_ */ diff --git a/src/main/c/murax/hello_world/src/linker.ld b/src/main/c/murax/hello_world/src/linker.ld new file mode 100644 index 00000000..57bc2f7b --- /dev/null +++ b/src/main/c/murax/hello_world/src/linker.ld @@ -0,0 +1,110 @@ +/* +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. +*/ +OUTPUT_FORMAT("elf32-littleriscv", "elf32-littleriscv", "elf32-littleriscv") +OUTPUT_ARCH(riscv) +ENTRY(crtStart) + +MEMORY { + RAM (rwx): ORIGIN = 0x80000000, LENGTH = 2k +} + +_stack_size = DEFINED(_stack_size) ? _stack_size : 256; +_heap_size = DEFINED(_heap_size) ? _heap_size : 0; + +SECTIONS { + + ._vector ORIGIN(RAM): { + *crt.o(.start_jump); + *crt.o(.text); + } > RAM + + ._user_heap (NOLOAD): + { + . = ALIGN(8); + PROVIDE ( end = . ); + PROVIDE ( _end = . ); + PROVIDE ( _heap_start = .); + . = . + _heap_size; + . = ALIGN(8); + PROVIDE ( _heap_end = .); + } > RAM + +._stack (NOLOAD): + { + . = ALIGN(16); + PROVIDE (_stack_end = .); + . = . + _stack_size; + . = ALIGN(16); + PROVIDE (_stack_start = .); + } > RAM + + .data : + { + *(.rdata) + *(.rodata .rodata.*) + *(.gnu.linkonce.r.*) + *(.data .data.*) + *(.gnu.linkonce.d.*) + . = ALIGN(8); + PROVIDE( __global_pointer$ = . + 0x800 ); + *(.sdata .sdata.*) + *(.gnu.linkonce.s.*) + . = ALIGN(8); + *(.srodata.cst16) + *(.srodata.cst8) + *(.srodata.cst4) + *(.srodata.cst2) + *(.srodata .srodata.*) + } > RAM + + .bss (NOLOAD) : { + . = ALIGN(4); + /* This is used by the startup in order to initialize the .bss secion */ + _bss_start = .; + *(.sbss*) + *(.gnu.linkonce.sb.*) + *(.bss .bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(4); + _bss_end = .; + } > RAM + + + .rodata : + { + *(.rdata) + *(.rodata .rodata.*) + *(.gnu.linkonce.r.*) + } > RAM + + .noinit (NOLOAD) : { + . = ALIGN(4); + *(.noinit .noinit.*) + . = ALIGN(4); + } > RAM + + .memory : { + *(.text); + end = .; + } > RAM + + .ctors : + { + . = ALIGN(4); + _ctors_start = .; + KEEP(*(.init_array*)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + . = ALIGN(4); + _ctors_end = .; + PROVIDE ( END_OF_SW_IMAGE = . ); + } > RAM + +} diff --git a/src/main/c/murax/hello_world/src/main.c b/src/main/c/murax/hello_world/src/main.c new file mode 100644 index 00000000..05f32273 --- /dev/null +++ b/src/main/c/murax/hello_world/src/main.c @@ -0,0 +1,42 @@ +//#include "stddefs.h" +#include + +#include "murax.h" + +void print(const char*str){ + while(*str){ + uart_write(UART,*str); + str++; + } +} +void println(const char*str){ + print(str); + uart_write(UART,'\n'); +} + +void delay(uint32_t loops){ + for(int i=0;iOUTPUT; + } +} + +void main() { + GPIO_A->OUTPUT_ENABLE = 0x0000000F; + GPIO_A->OUTPUT = 0x00000001; + println("hello world arty a7 v1"); + const int nleds = 4; + const int nloops = 2000000; + while(1){ + for(unsigned int i=0;iOUTPUT = 1<OUTPUT = (1<<(nleds-1))>>i; + delay(nloops); + } + } +} + +void irqCallback(){ +} diff --git a/src/main/c/murax/hello_world/src/murax.h b/src/main/c/murax/hello_world/src/murax.h new file mode 100644 index 00000000..fbfdf3e7 --- /dev/null +++ b/src/main/c/murax/hello_world/src/murax.h @@ -0,0 +1,17 @@ +#ifndef __MURAX_H__ +#define __MURAX_H__ + +#include "timer.h" +#include "prescaler.h" +#include "interrupt.h" +#include "gpio.h" +#include "uart.h" + +#define GPIO_A ((Gpio_Reg*)(0xF0000000)) +#define TIMER_PRESCALER ((Prescaler_Reg*)0xF0020000) +#define TIMER_INTERRUPT ((InterruptCtrl_Reg*)0xF0020010) +#define TIMER_A ((Timer_Reg*)0xF0020040) +#define TIMER_B ((Timer_Reg*)0xF0020050) +#define UART ((Uart_Reg*)(0xF0010000)) + +#endif /* __MURAX_H__ */ diff --git a/src/main/c/murax/hello_world/src/prescaler.h b/src/main/c/murax/hello_world/src/prescaler.h new file mode 100644 index 00000000..6bd9694a --- /dev/null +++ b/src/main/c/murax/hello_world/src/prescaler.h @@ -0,0 +1,16 @@ +#ifndef PRESCALERCTRL_H_ +#define PRESCALERCTRL_H_ + +#include + + +typedef struct +{ + volatile uint32_t LIMIT; +} Prescaler_Reg; + +static void prescaler_init(Prescaler_Reg* reg){ + +} + +#endif /* PRESCALERCTRL_H_ */ diff --git a/src/main/c/murax/hello_world/src/timer.h b/src/main/c/murax/hello_world/src/timer.h new file mode 100644 index 00000000..1577535c --- /dev/null +++ b/src/main/c/murax/hello_world/src/timer.h @@ -0,0 +1,20 @@ +#ifndef TIMERCTRL_H_ +#define TIMERCTRL_H_ + +#include + + +typedef struct +{ + volatile uint32_t CLEARS_TICKS; + volatile uint32_t LIMIT; + volatile uint32_t VALUE; +} Timer_Reg; + +static void timer_init(Timer_Reg *reg){ + reg->CLEARS_TICKS = 0; + reg->VALUE = 0; +} + + +#endif /* TIMERCTRL_H_ */ diff --git a/src/main/c/murax/hello_world/src/uart.h b/src/main/c/murax/hello_world/src/uart.h new file mode 100644 index 00000000..c3a30a56 --- /dev/null +++ b/src/main/c/murax/hello_world/src/uart.h @@ -0,0 +1,42 @@ +#ifndef UART_H_ +#define UART_H_ + + +typedef struct +{ + volatile uint32_t DATA; + volatile uint32_t STATUS; + volatile uint32_t CLOCK_DIVIDER; + volatile uint32_t FRAME_CONFIG; +} Uart_Reg; + +enum UartParity {NONE = 0,EVEN = 1,ODD = 2}; +enum UartStop {ONE = 0,TWO = 1}; + +typedef struct { + uint32_t dataLength; + enum UartParity parity; + enum UartStop stop; + uint32_t clockDivider; +} Uart_Config; + +static uint32_t uart_writeAvailability(Uart_Reg *reg){ + return (reg->STATUS >> 16) & 0xFF; +} +static uint32_t uart_readOccupancy(Uart_Reg *reg){ + return reg->STATUS >> 24; +} + +static void uart_write(Uart_Reg *reg, uint32_t data){ + while(uart_writeAvailability(reg) == 0); + reg->DATA = data; +} + +static void uart_applyConfig(Uart_Reg *reg, Uart_Config *config){ + reg->CLOCK_DIVIDER = config->clockDivider; + reg->FRAME_CONFIG = ((config->dataLength-1) << 0) | (config->parity << 8) | (config->stop << 16); +} + +#endif /* UART_H_ */ + + diff --git a/src/main/scala/vexriscv/demo/Murax.scala b/src/main/scala/vexriscv/demo/Murax.scala index 389b91f4..dc2bc6f7 100644 --- a/src/main/scala/vexriscv/demo/Murax.scala +++ b/src/main/scala/vexriscv/demo/Murax.scala @@ -477,3 +477,10 @@ object MuraxWithRamInit{ SpinalVerilog(Murax(MuraxConfig.default.copy(onChipRamSize = 4 kB, onChipRamHexFile = "src/main/ressource/hex/muraxDemo.hex"))) } } + +object Murax_arty{ + def main(args: Array[String]) { + val hex = "src/main/c/murax/hello_world/build/hello_world.hex" + SpinalVerilog(Murax(MuraxConfig.default(false).copy(coreFrequency = 100 MHz,onChipRamSize = 32 kB, onChipRamHexFile = hex))) + } +} From 2bcddd333d8150f948d61aa748bf3239d3600311 Mon Sep 17 00:00:00 2001 From: sebastien-riou Date: Fri, 17 Jan 2020 00:33:02 +0100 Subject: [PATCH 289/951] forced the commit of missing TCL files --- scripts/Murax/arty_a7/make_bit_file.tcl | 50 ++++++ scripts/Murax/arty_a7/make_mcs_file.tcl | 31 ++++ scripts/Murax/arty_a7/make_mmi_files.tcl | 6 + scripts/Murax/arty_a7/make_vivado_project.tcl | 46 ++++++ scripts/Murax/arty_a7/open_vivado_project.tcl | 4 + scripts/Murax/arty_a7/soc_mmi.tcl | 151 ++++++++++++++++++ scripts/Murax/arty_a7/vivado_params.tcl | 5 + scripts/Murax/arty_a7/write_flash.tcl | 26 +++ scripts/Murax/arty_a7/write_fpga.tcl | 10 ++ 9 files changed, 329 insertions(+) create mode 100644 scripts/Murax/arty_a7/make_bit_file.tcl create mode 100644 scripts/Murax/arty_a7/make_mcs_file.tcl create mode 100644 scripts/Murax/arty_a7/make_mmi_files.tcl create mode 100644 scripts/Murax/arty_a7/make_vivado_project.tcl create mode 100644 scripts/Murax/arty_a7/open_vivado_project.tcl create mode 100644 scripts/Murax/arty_a7/soc_mmi.tcl create mode 100644 scripts/Murax/arty_a7/vivado_params.tcl create mode 100644 scripts/Murax/arty_a7/write_flash.tcl create mode 100644 scripts/Murax/arty_a7/write_fpga.tcl diff --git a/scripts/Murax/arty_a7/make_bit_file.tcl b/scripts/Murax/arty_a7/make_bit_file.tcl new file mode 100644 index 00000000..a97b399f --- /dev/null +++ b/scripts/Murax/arty_a7/make_bit_file.tcl @@ -0,0 +1,50 @@ + +# Input files +set mmi_file "./soc.mmi" +set elf_file "./soc.elf" +set source_bit_file "./soc.bit" + +# Output files +set output_bit_file "./soc_latest_sw.bit" + +# Enable to turn on debug +set updatemem_debug 0 + +# Assemble bit file that can be downloaded to device directly +# Combine the original bit file, mmi file, and software elf to create the full bitstream + +# Delete target file +file delete -force $output_bit_file + +# Determine if the user has built the project and has the target source file +# If not, then use the reference bit file shipped with the project +if { ![file exists $source_bit_file] } { + puts "\n********************************************" + puts "INFO - File $source_bit_file doesn't exist as project has not been built" + puts " Using $reference_bit_file instead\n" + puts "********************************************/n" + set source_bit_file $reference_bit_file +} + +# Banner message to console as there is no output for a few seconds +puts " Running updatemem ..." + +if { $updatemem_debug } { + set error [catch {exec updatemem --debug --force --meminfo $mmi_file --data $elf_file --bit $source_bit_file --proc dummy --out $output_bit_file} result] +} else { + set error [catch {exec updatemem --force --meminfo $mmi_file --data $elf_file --bit $source_bit_file --proc dummy --out $output_bit_file} result] +} + +# Print the stdout from updatemem +puts $result + +# Updatemem returns 0 even when there is an error, so cannot trap on error. Having deleted output file to start, then +# detect if it now exists, else exit. +if { ![file exists $output_bit_file] } { + puts "ERROR - $output_bit_file not made" + return -1 +} else { + puts "\n********************************************" + puts " $output_bit_file correctly generated" + puts "********************************************\n" +} diff --git a/scripts/Murax/arty_a7/make_mcs_file.tcl b/scripts/Murax/arty_a7/make_mcs_file.tcl new file mode 100644 index 00000000..9863a2ca --- /dev/null +++ b/scripts/Murax/arty_a7/make_mcs_file.tcl @@ -0,0 +1,31 @@ + +# Input file +set source_bit_file "./latest.bit" + +# Output file +set output_mcs_file "./latest.mcs" + +# Delete target file +file delete -force $output_mcs_file + +# Determine if the user has built the project and has the target source file +# If not, then use the reference bit file shipped with the project +if { ![file exists $source_bit_file] } { + puts "\n********************************************" + puts "INFO - File $source_bit_file doesn't exist as project has not been built\n" + puts "********************************************/n" + error +} + +# Create MCS file for base board QSPI flash memory +write_cfgmem -force -format MCS -size 16 -interface SPIx4 -loadbit " up 0 $source_bit_file" $output_mcs_file + +# Check MCS was correctly made +if { ![file exists $output_mcs_file] } { + puts "ERROR - $output_bit_file not made" + return -1 +} else { + puts "\n********************************************" + puts " $output_mcs_file correctly generated" + puts "********************************************\n" +} diff --git a/scripts/Murax/arty_a7/make_mmi_files.tcl b/scripts/Murax/arty_a7/make_mmi_files.tcl new file mode 100644 index 00000000..d9ecd484 --- /dev/null +++ b/scripts/Murax/arty_a7/make_mmi_files.tcl @@ -0,0 +1,6 @@ +source [file join [file dirname [file normalize [info script]]] vivado_params.tcl] + +open_project -read_only $outputdir/$projectName +open_run impl_1 +source $base/soc_mmi.tcl +puts "mmi files generated" diff --git a/scripts/Murax/arty_a7/make_vivado_project.tcl b/scripts/Murax/arty_a7/make_vivado_project.tcl new file mode 100644 index 00000000..b206ddbb --- /dev/null +++ b/scripts/Murax/arty_a7/make_vivado_project.tcl @@ -0,0 +1,46 @@ +#Create output directory and clear contents +source [file join [file dirname [file normalize [info script]]] vivado_params.tcl] + +file mkdir $outputdir +set files [glob -nocomplain "$outputdir/*"] +if {[llength $files] != 0} { + puts "deleting contents of $outputdir" + file delete -force {*}[glob -directory $outputdir *]; # clear folder contents +} else { + puts "$outputdir is empty" +} + +#Create project +create_project -part $part $projectName $outputdir + +#add source files to Vivado project +#add_files -fileset sim_1 ./path/to/testbench.vhd +#add_files [glob ./path/to/sources/*.vhd] +#add_files -fileset constrs_1 ./path/to/constraint/constraint.xdc +#add_files [glob ./path/to/library/sources/*.vhd] +#set_property -library userDefined [glob ./path/to/library/sources/*.vhd] +add_files [glob $base/*.v] +add_files [glob $topv] +add_files -fileset constrs_1 $base/arty_a7.xdc + +#set top level module and update compile order +set_property top toplevel [current_fileset] +update_compile_order -fileset sources_1 +#update_compile_order -fileset sim_1 + +#launch synthesis +launch_runs synth_1 +wait_on_run synth_1 + +#Run implementation and generate bitstream +set_property STEPS.PHYS_OPT_DESIGN.IS_ENABLED true [get_runs impl_1] +launch_runs impl_1 -to_step write_bitstream +wait_on_run impl_1 +puts "Implementation done!" + +#reports generated by default +#open_run impl_1 +#report_timing_summary -check_timing_verbose -report_unconstrained -file report_timing_summary.rpt +#report_utilization -hierarchical -file report_utilization.rpt + +#TODO: add checks about timing, DRC, CDC such that the script give clear indication if design is OK or not diff --git a/scripts/Murax/arty_a7/open_vivado_project.tcl b/scripts/Murax/arty_a7/open_vivado_project.tcl new file mode 100644 index 00000000..41200198 --- /dev/null +++ b/scripts/Murax/arty_a7/open_vivado_project.tcl @@ -0,0 +1,4 @@ +source [file join [file dirname [file normalize [info script]]] vivado_params.tcl] + +open_project -read_only $outputdir/$projectName +start_gui diff --git a/scripts/Murax/arty_a7/soc_mmi.tcl b/scripts/Murax/arty_a7/soc_mmi.tcl new file mode 100644 index 00000000..33ea6866 --- /dev/null +++ b/scripts/Murax/arty_a7/soc_mmi.tcl @@ -0,0 +1,151 @@ +#script to update the init values of RAM without re-synthesis + +if {![info exists mmi_file]} { + # Set MMI output file name + set mmi_file "soc.mmi" +} +if {![info exists part]} { + set part "xc7a35ticsg324-1L" +} + +# Function to swap bits +proc swap_bits { bit } { + + if { $bit > 23 } {return [expr {24 + (31 - $bit)}]} + if { $bit > 15 } {return [expr {16 + (23 - $bit)}]} + if { $bit > 7 } {return [expr {8 + (15 - $bit)}]} + return [expr {7 - $bit}] +} + +# If run from batch file, will need to open project, then open the run +# open_run impl_1 + +# Find all the RAMs, place in a list +set rams [get_cells -hier -regexp {.*core/system_ram/.*} -filter {REF_NAME =~ RAMB36E1}] + +puts "[llength $rams] RAMs in total" +foreach m $rams {puts $m} + +set mems [dict create] +foreach m $rams { + set numbers [regexp -all -inline -- {[0-9]+} $m] + dict set mems $numbers $m +} +set keys [dict keys $mems] +#set keys [lsort -integer $keys] +set rams [] +foreach key $keys { + set m [dict get $mems $key] + puts "$key -> $m" + lappend rams $m +} + +puts "after sort:" +foreach m $rams {puts $m} +puts $rams + +if { [llength $rams] == 0 } { + puts "Error - no memories found" + return -1 +} + +if { [expr {[llength $rams] % 4}] != 0 } { + puts "Error - Number of memories not divisible by 4" + return -1 +} + +set size_bytes [expr {4096*[llength $rams]}] +puts "Instruction memory size $size_bytes" + +# Currently only support memory sizes between 16kB, (one byte per mem), and 128kB, (one bit per mem) +if { ($size_bytes < (4*4096)) || ($size_bytes > (32*4096)) } { + puts "Error - Memory size of $size_bytes out of range" + puts " Script only supports memory sizes between 16kB and 128kB" + return -1 +} + +# Create and open target mmi file +set fp [open $mmi_file {WRONLY CREAT TRUNC}] +if { $fp == 0 } { + puts "Error - Unable to open $mmi_file for writing" + return -1 +} + +# Write the file header +puts $fp "" +puts $fp "" +puts $fp " " +puts $fp " " +puts $fp " " + +# Calculate the expected number of bits per memory +set mem_bits [expr {32/[llength $rams]}] + +puts "mem_bits = $mem_bits" + +set mem_info [dict create] + +set i 0 +foreach ram $rams { + # Get the RAM location + set loc_val [get_property LOC [get_cells $ram]] + regexp -- {(RAMB36_)([0-9XY]+)} $loc_val full ram_name loc_xy + + set memi [dict create ram $ram loc $loc_xy] + + set numbers [regexp -all -inline -- {[0-9]+} $ram] + if { [llength $numbers] == 2 } { + dict lappend mem_info [lindex $numbers 0] $memi + } else { + dict lappend mem_info [expr $i/4] $memi + } + incr i +} + +set sorted_mem_info [dict create] +foreach {idx mems} $mem_info { + foreach mem [lreverse $mems] { + dict lappend sorted_mem_info $idx $mem + } +} +foreach mems $sorted_mem_info { + foreach mem $mems { + puts $mem + } +} + +set lsb 0 +set memlen [ expr 4096*8 / $mem_bits ] +foreach {idx mems} $sorted_mem_info { + puts "idx=$idx" + foreach mem $mems { + puts "mem=$mem" + set ram [dict get $mem ram] + set loc [dict get $mem loc] + set msb [expr $lsb+$mem_bits-1] + set addr_start 0 + set addr_end [expr $memlen-1] + puts "ram=$ram loc=$loc lsb=$lsb msb=$msb addr_start=$addr_start addr_end=$addr_end" + puts $fp " " + puts $fp " " + puts $fp " " + puts $fp " " + puts $fp " " + puts $fp " " + + set lsb [expr ($msb+1)%32] + } +} + +puts $fp " " +puts $fp " " +puts $fp " " +puts $fp " " +puts $fp " " +puts $fp " " +puts $fp " " +puts $fp " " +puts $fp "" + +close $fp diff --git a/scripts/Murax/arty_a7/vivado_params.tcl b/scripts/Murax/arty_a7/vivado_params.tcl new file mode 100644 index 00000000..343058dd --- /dev/null +++ b/scripts/Murax/arty_a7/vivado_params.tcl @@ -0,0 +1,5 @@ +set outputdir ./vivado_project +set part "xc7a35ticsg324-1L" +set base ".." +set projectName "fpga" +set topv "$base/../../../Murax.v" diff --git a/scripts/Murax/arty_a7/write_flash.tcl b/scripts/Murax/arty_a7/write_flash.tcl new file mode 100644 index 00000000..845bff74 --- /dev/null +++ b/scripts/Murax/arty_a7/write_flash.tcl @@ -0,0 +1,26 @@ + +open_hw +connect_hw_server +open_hw_target +current_hw_device [get_hw_devices xc7a35t_0] +refresh_hw_device -update_hw_probes false [lindex [get_hw_devices xc7a35t_0] 0] + +create_hw_cfgmem -hw_device [lindex [get_hw_devices] 0] -mem_dev [lindex [get_cfgmem_parts {s25fl128sxxxxxx0-spi-x1_x2_x4}] 0] +set_property PROBES.FILE {} [get_hw_devices xc7a35t_0] +set_property FULL_PROBES.FILE {} [get_hw_devices xc7a35t_0] +refresh_hw_device [lindex [get_hw_devices xc7a35t_0] 0] +set_property PROGRAM.ADDRESS_RANGE {use_file} [ get_property PROGRAM.HW_CFGMEM [lindex [get_hw_devices xc7a35t_0] 0]] +set_property PROGRAM.FILES [list "latest.mcs" ] [ get_property PROGRAM.HW_CFGMEM [lindex [get_hw_devices xc7a35t_0] 0]] +set_property PROGRAM.PRM_FILE {} [ get_property PROGRAM.HW_CFGMEM [lindex [get_hw_devices xc7a35t_0] 0]] +set_property PROGRAM.UNUSED_PIN_TERMINATION {pull-none} [ get_property PROGRAM.HW_CFGMEM [lindex [get_hw_devices xc7a35t_0] 0]] +set_property PROGRAM.BLANK_CHECK 0 [ get_property PROGRAM.HW_CFGMEM [lindex [get_hw_devices xc7a35t_0] 0]] +set_property PROGRAM.ERASE 1 [ get_property PROGRAM.HW_CFGMEM [lindex [get_hw_devices xc7a35t_0] 0]] +set_property PROGRAM.CFG_PROGRAM 1 [ get_property PROGRAM.HW_CFGMEM [lindex [get_hw_devices xc7a35t_0] 0]] +set_property PROGRAM.VERIFY 1 [ get_property PROGRAM.HW_CFGMEM [lindex [get_hw_devices xc7a35t_0] 0]] +set_property PROGRAM.CHECKSUM 0 [ get_property PROGRAM.HW_CFGMEM [lindex [get_hw_devices xc7a35t_0] 0]] + +if {![string equal [get_property PROGRAM.HW_CFGMEM_TYPE [lindex [get_hw_devices xc7a35t_0] 0]] [get_property MEM_TYPE [get_property CFGMEM_PART [ get_property PROGRAM.HW_CFGMEM [lindex [get_hw_devices xc7a35t_0] 0]]]]] } { create_hw_bitstream -hw_device [lindex [get_hw_devices xc7a35t_0] 0] [get_property PROGRAM.HW_CFGMEM_BITFILE [ lindex [get_hw_devices xc7a35t_0] 0]]; program_hw_devices [lindex [get_hw_devices xc7a35t_0] 0]; }; +program_hw_cfgmem -hw_cfgmem [ get_property PROGRAM.HW_CFGMEM [lindex [get_hw_devices xc7a35t_0] 0]] + +close_hw_target +close_hw diff --git a/scripts/Murax/arty_a7/write_fpga.tcl b/scripts/Murax/arty_a7/write_fpga.tcl new file mode 100644 index 00000000..e3214f88 --- /dev/null +++ b/scripts/Murax/arty_a7/write_fpga.tcl @@ -0,0 +1,10 @@ +open_hw +connect_hw_server +open_hw_target +current_hw_device [get_hw_devices xc7a35t_0] +refresh_hw_device -update_hw_probes false [lindex [get_hw_devices xc7a35t_0] 0] +set_property PROBES.FILE {} [get_hw_devices xc7a35t_0] +set_property FULL_PROBES.FILE {} [get_hw_devices xc7a35t_0] +set_property PROGRAM.FILE {latest.bit} [get_hw_devices xc7a35t_0] +program_hw_devices [get_hw_devices xc7a35t_0] +disconnect_hw_server From 1fb1e358bbc90ea03d821e7f3c3b5ac397c9e6fa Mon Sep 17 00:00:00 2001 From: sebastien-riou Date: Fri, 17 Jan 2020 00:49:35 +0100 Subject: [PATCH 290/951] fix makefile clean target --- src/main/c/murax/xipBootloader/makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/c/murax/xipBootloader/makefile b/src/main/c/murax/xipBootloader/makefile index 44211313..e08c17b2 100644 --- a/src/main/c/murax/xipBootloader/makefile +++ b/src/main/c/murax/xipBootloader/makefile @@ -33,5 +33,5 @@ clean-for-commit: rm -f *.d rm demo_rom.bin demo.bin crt_ram.bin -clean: clean-tmp +clean: clean-for-commit rm -f *.bin From c01c2567578b18e4fec4466d6db3ce644b8eeede Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Wed, 29 Jan 2020 15:20:13 +0100 Subject: [PATCH 291/951] Revert "Merge branch 'master' into dev" This reverts commit b5374433a53f5ffa47ca63f9b532ee59695e1e59, reversing changes made to f01da9c73b42897c3bd49b92401063b84edb84ef. --- README.md | 4 +- scripts/Murax/arty_a7/README.md | 129 ------ scripts/Murax/arty_a7/arty_a7.xdc | 366 ------------------ scripts/Murax/arty_a7/arty_a7_org.xdc | 350 ----------------- scripts/Murax/arty_a7/make_bit_file.tcl | 50 --- scripts/Murax/arty_a7/make_mcs_file | 6 - scripts/Murax/arty_a7/make_mcs_file.tcl | 31 -- scripts/Murax/arty_a7/make_mmi_files | 4 - scripts/Murax/arty_a7/make_mmi_files.tcl | 6 - scripts/Murax/arty_a7/make_vivado_project | 9 - scripts/Murax/arty_a7/make_vivado_project.tcl | 46 --- scripts/Murax/arty_a7/makefile | 62 --- scripts/Murax/arty_a7/open_vivado_project | 4 - scripts/Murax/arty_a7/open_vivado_project.tcl | 4 - scripts/Murax/arty_a7/picocom_arty | 1 - scripts/Murax/arty_a7/soc_mmi.tcl | 151 -------- scripts/Murax/arty_a7/toplevel.v | 66 ---- scripts/Murax/arty_a7/vivado_params.tcl | 5 - scripts/Murax/arty_a7/write_flash | 3 - scripts/Murax/arty_a7/write_flash.tcl | 26 -- scripts/Murax/arty_a7/write_fpga | 3 - scripts/Murax/arty_a7/write_fpga.tcl | 10 - .../iCE40-hx8k_breakout_board_xip/Makefile | 22 +- .../Murax_iCE40_hx8k_breakout_board_xip.pcf | 22 +- .../iCE40-hx8k_breakout_board_xip/README.md | 137 +------ src/main/c/murax/hello_world/makefile | 134 ------- src/main/c/murax/hello_world/src/crt.S | 98 ----- src/main/c/murax/hello_world/src/gpio.h | 15 - src/main/c/murax/hello_world/src/interrupt.h | 17 - src/main/c/murax/hello_world/src/linker.ld | 110 ------ src/main/c/murax/hello_world/src/main.c | 42 -- src/main/c/murax/hello_world/src/murax.h | 17 - src/main/c/murax/hello_world/src/prescaler.h | 16 - src/main/c/murax/hello_world/src/timer.h | 20 - src/main/c/murax/hello_world/src/uart.h | 42 -- src/main/c/murax/xipBootloader/crt.S | 22 +- src/main/c/murax/xipBootloader/crt.bin | Bin 192 -> 120 bytes src/main/c/murax/xipBootloader/demo.S | 11 +- src/main/c/murax/xipBootloader/demo.bin | Bin 0 -> 48 bytes src/main/c/murax/xipBootloader/makefile | 22 +- src/main/c/murax/xipBootloader/mapping_rom.ld | 96 ----- src/main/c/murax/xipBootloader/mapping_xip.ld | 96 ----- src/main/scala/vexriscv/demo/Murax.scala | 92 +++-- src/main/scala/vexriscv/ip/DataCache.scala | 19 +- .../vexriscv/plugin/DBusCachedPlugin.scala | 33 +- .../vexriscv/plugin/HazardSimplePlugin.scala | 2 +- .../scala/vexriscv/plugin/Mul16Plugin.scala | 119 ------ .../plugin/MulDivIterativePlugin.scala | 26 +- .../vexriscv/plugin/MulSimplePlugin.scala | 14 +- .../vexriscv/TestIndividualFeatures.scala | 49 +-- 50 files changed, 146 insertions(+), 2483 deletions(-) delete mode 100644 scripts/Murax/arty_a7/README.md delete mode 100644 scripts/Murax/arty_a7/arty_a7.xdc delete mode 100644 scripts/Murax/arty_a7/arty_a7_org.xdc delete mode 100644 scripts/Murax/arty_a7/make_bit_file.tcl delete mode 100755 scripts/Murax/arty_a7/make_mcs_file delete mode 100644 scripts/Murax/arty_a7/make_mcs_file.tcl delete mode 100755 scripts/Murax/arty_a7/make_mmi_files delete mode 100644 scripts/Murax/arty_a7/make_mmi_files.tcl delete mode 100755 scripts/Murax/arty_a7/make_vivado_project delete mode 100644 scripts/Murax/arty_a7/make_vivado_project.tcl delete mode 100644 scripts/Murax/arty_a7/makefile delete mode 100755 scripts/Murax/arty_a7/open_vivado_project delete mode 100644 scripts/Murax/arty_a7/open_vivado_project.tcl delete mode 100644 scripts/Murax/arty_a7/picocom_arty delete mode 100644 scripts/Murax/arty_a7/soc_mmi.tcl delete mode 100644 scripts/Murax/arty_a7/toplevel.v delete mode 100644 scripts/Murax/arty_a7/vivado_params.tcl delete mode 100755 scripts/Murax/arty_a7/write_flash delete mode 100644 scripts/Murax/arty_a7/write_flash.tcl delete mode 100755 scripts/Murax/arty_a7/write_fpga delete mode 100644 scripts/Murax/arty_a7/write_fpga.tcl delete mode 100644 src/main/c/murax/hello_world/makefile delete mode 100644 src/main/c/murax/hello_world/src/crt.S delete mode 100644 src/main/c/murax/hello_world/src/gpio.h delete mode 100644 src/main/c/murax/hello_world/src/interrupt.h delete mode 100644 src/main/c/murax/hello_world/src/linker.ld delete mode 100644 src/main/c/murax/hello_world/src/main.c delete mode 100644 src/main/c/murax/hello_world/src/murax.h delete mode 100644 src/main/c/murax/hello_world/src/prescaler.h delete mode 100644 src/main/c/murax/hello_world/src/timer.h delete mode 100644 src/main/c/murax/hello_world/src/uart.h create mode 100755 src/main/c/murax/xipBootloader/demo.bin delete mode 100644 src/main/c/murax/xipBootloader/mapping_rom.ld delete mode 100644 src/main/c/murax/xipBootloader/mapping_xip.ld delete mode 100644 src/main/scala/vexriscv/plugin/Mul16Plugin.scala diff --git a/README.md b/README.md index d0deb166..2af47aa5 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,8 @@ - [Regression tests](#regression-tests) - [Interactive debug of the simulated CPU via GDB OpenOCD and Verilator](#interactive-debug-of-the-simulated-cpu-via-gdb-openocd-and-verilator) - [Using Eclipse to run the software and debug it](#using-Eclipse-to-run-the-software-and-debug-it) - * [By using gnu-mcu-eclipse](#by-using-gnu-mcu-eclipse) - * [By using Zylin plugin (old)](#by-using-zylin-plugin-old) + * [By using Zylin plugin](#by-using-zylin-plugin) + * [By using FreedomStudio](#by-using-freedomstudio) - [Briey SoC](#briey-soc) - [Murax SoC](#murax-soc) - [Running Linux](#running-linux) diff --git a/scripts/Murax/arty_a7/README.md b/scripts/Murax/arty_a7/README.md deleted file mode 100644 index ad781f3f..00000000 --- a/scripts/Murax/arty_a7/README.md +++ /dev/null @@ -1,129 +0,0 @@ -This example is for the Digilent ARTY A7 35T board. - -# Using the example - -## Before Starting - -You should make sure you have the following tools installed: - * vivado 2018.1 or later - * riscv toolchain (riscv64-unknown-elf) - * sbt - -## Board setup -Make sure you have a rev E board. If you have a later version check that the -flash part is S25FL128SAGMF100. - -Jumper settings for board rev E: - * Disconnect anything from the connectors (Pmod, Arduino) - * Jumpers: JP1 and JP2 on, others off. - -## Building - -You should be able to just type `make` and get output similar to this; -``` -... -Memory region Used Size Region Size %age Used - RAM: 896 B 2 KB 43.75% -... ---------------------------------------------------------------------------------- -Finished RTL Elaboration : Time (s): cpu = 00:00:08 ; elapsed = 00:00:09 . Memory (MB): peak = 1457.785 ; gain = 243.430 ; free physical = 17940 ; free virtual = 57159 ---------------------------------------------------------------------------------- -... ---------------------------------------------------------------------------------- -Finished Technology Mapping : Time (s): cpu = 00:02:42 ; elapsed = 00:02:58 . Memory (MB): peak = 1986.879 ; gain = 772.523 ; free physical = 17454 ; free virtual = 56670 ---------------------------------------------------------------------------------- -... ---------------------------------------------------------------------------------- -Finished Writing Synthesis Report : Time (s): cpu = 00:02:45 ; elapsed = 00:03:01 . Memory (MB): peak = 1986.879 ; gain = 772.523 ; free physical = 17457 ; free virtual = 56673 ---------------------------------------------------------------------------------- -... -Writing bitstream ./toplevel.bit... -... -mmi files generated -... -******************************************** - ./soc_latest_sw.bit correctly generated -******************************************** -... -******************************************** - ./soc_latest_sw.mcs correctly generated -******************************************** - -INFO: [Common 17-206] Exiting Vivado at Thu Nov 28 04:00:50 2019... -``` - -The process should take around 8 minutes on a reasonably fast computer. - -## Programming - -### Direct FPGA RAM programming - -Run `make prog` to program the bit file directly to FPGA RAM. - -You should get output like the following; -``` -... -****** Xilinx hw_server v2018.1 - **** Build date : Apr 4 2018-18:56:09 - ** Copyright 1986-2018 Xilinx, Inc. All Rights Reserved. - -INFO: [Labtoolstcl 44-466] Opening hw_target localhost:3121/xilinx_tcf/Digilent/210319AB569AA -INFO: [Labtools 27-1434] Device xc7a35t (JTAG device index = 0) is programmed with a design that has no supported debug core(s) in it. -WARNING: [Labtools 27-3361] The debug hub core was not detected. -Resolution: -1. Make sure the clock connected to the debug hub (dbg_hub) core is a free running clock and is active. -2. Make sure the BSCAN_SWITCH_USER_MASK device property in Vivado Hardware Manager reflects the user scan chain setting in the design and refresh the device. To determine the user scan chain setting in the design, open the implemented design and use 'get_property C_USER_SCAN_CHAIN [get_debug_cores dbg_hub]'. -For more details on setting the scan chain property, consult the Vivado Debug and Programming User Guide (UG908). -INFO: [Labtools 27-3164] End of startup status: HIGH -INFO: [Common 17-206] Exiting Vivado at Thu Nov 28 04:01:36 2019... -``` - -After programming the LED4~LED7 shall show some activity. - -### QSPI flash programming - -Run `make flash` to program the bit file to the QSPI flash. - -You should get output like the following; -``` -... -****** Xilinx hw_server v2018.1 - **** Build date : Apr 4 2018-18:56:09 - ** Copyright 1986-2018 Xilinx, Inc. All Rights Reserved. - - -INFO: [Labtoolstcl 44-466] Opening hw_target localhost:3121/xilinx_tcf/Digilent/210319AB569AA -INFO: [Labtools 27-1434] Device xc7a35t (JTAG device index = 0) is programmed with a design that has no supported debug core(s) in it. -... -INFO: [Labtools 27-3164] End of startup status: HIGH -Mfg ID : 1 Memory Type : 20 Memory Capacity : 18 Device ID 1 : 0 Device ID 2 : 0 -Performing Erase Operation... -Erase Operation successful. -Performing Program and Verify Operations... -Program/Verify Operation successful. -INFO: [Labtoolstcl 44-377] Flash programming completed successfully -program_hw_cfgmem: Time (s): cpu = 00:00:00.11 ; elapsed = 00:00:52 . Memory (MB): peak = 1792.711 ; gain = 8.000 ; free physical = 17712 ; free virtual = 56943 -INFO: [Labtoolstcl 44-464] Closing hw_target localhost:3121/xilinx_tcf/Digilent/210319AB569AA -... -INFO: [Common 17-206] Exiting Vivado at Thu Nov 28 04:06:28 2019... -``` - -After programming the flash you need to press the "PROG" button on the board. Then after a second or so the "DONE" LED shall be ON and LED4~LED7 shall show some activity. - - -## Connect - -After programming you should be able to connect to the serial port and have some output. - -On Linux you can do this using a command like `screen /dev/ttyUSB1`. Other good alternatives: - -* moserial (GUI) -* picocom (can be launched via the file "picocom_arty") - -Parameters: -* port is : /dev/ttyUSB1 -* flowcontrol : none -* baudrate is : 115200 -* parity is : none -* databits are : 8 -* stopbits are : 1 diff --git a/scripts/Murax/arty_a7/arty_a7.xdc b/scripts/Murax/arty_a7/arty_a7.xdc deleted file mode 100644 index 5ddd8fe1..00000000 --- a/scripts/Murax/arty_a7/arty_a7.xdc +++ /dev/null @@ -1,366 +0,0 @@ -set_property PACKAGE_PIN F4 [get_ports tck] -set_property IOSTANDARD LVCMOS33 [get_ports tck] - -set_property PACKAGE_PIN D2 [get_ports tms] -set_property IOSTANDARD LVCMOS33 [get_ports tms] - -set_property PACKAGE_PIN D4 [get_ports tdo] -set_property IOSTANDARD LVCMOS33 [get_ports tdo] -set_property PULLUP true [get_ports tdo] - -set_property PACKAGE_PIN E2 [get_ports tdi] -set_property IOSTANDARD LVCMOS33 [get_ports tdi] - -set_property PACKAGE_PIN D3 [get_ports trst] -set_property IOSTANDARD LVCMOS33 [get_ports trst] -set_property PULLUP true [get_ports trst] - - -## serial:0.tx -set_property PACKAGE_PIN D10 [get_ports serial_tx] -set_property IOSTANDARD LVCMOS33 [get_ports serial_tx] -## serial:0.rx -set_property PACKAGE_PIN A9 [get_ports serial_rx] -set_property IOSTANDARD LVCMOS33 [get_ports serial_rx] -## clk100:0 -set_property PACKAGE_PIN E3 [get_ports clk100] -set_property IOSTANDARD LVCMOS33 [get_ports clk100] -## cpu_reset:0 -set_property PACKAGE_PIN C2 [get_ports cpu_reset] -set_property IOSTANDARD LVCMOS33 [get_ports cpu_reset] -## eth_ref_clk:0 -#set_property LOC G18 [get_ports eth_ref_clk] -#set_property IOSTANDARD LVCMOS33 [get_ports eth_ref_clk] -## user_led:0 -set_property PACKAGE_PIN H5 [get_ports user_led0] -set_property IOSTANDARD LVCMOS33 [get_ports user_led0] -## user_led:1 -set_property PACKAGE_PIN J5 [get_ports user_led1] -set_property IOSTANDARD LVCMOS33 [get_ports user_led1] -## user_led:2 -set_property PACKAGE_PIN T9 [get_ports user_led2] -set_property IOSTANDARD LVCMOS33 [get_ports user_led2] -## user_led:3 -set_property PACKAGE_PIN T10 [get_ports user_led3] -set_property IOSTANDARD LVCMOS33 [get_ports user_led3] -## user_sw:0 -set_property PACKAGE_PIN A8 [get_ports user_sw0] -set_property IOSTANDARD LVCMOS33 [get_ports user_sw0] -## user_sw:1 -set_property PACKAGE_PIN C11 [get_ports user_sw1] -set_property IOSTANDARD LVCMOS33 [get_ports user_sw1] -## user_sw:2 -set_property PACKAGE_PIN C10 [get_ports user_sw2] -set_property IOSTANDARD LVCMOS33 [get_ports user_sw2] -## user_sw:3 -set_property PACKAGE_PIN A10 [get_ports user_sw3] -set_property IOSTANDARD LVCMOS33 [get_ports user_sw3] -## user_btn:0 -set_property PACKAGE_PIN D9 [get_ports user_btn0] -set_property IOSTANDARD LVCMOS33 [get_ports user_btn0] -## user_btn:1 -set_property PACKAGE_PIN C9 [get_ports user_btn1] -set_property IOSTANDARD LVCMOS33 [get_ports user_btn1] -## user_btn:2 -set_property PACKAGE_PIN B9 [get_ports user_btn2] -set_property IOSTANDARD LVCMOS33 [get_ports user_btn2] -## user_btn:3 -set_property PACKAGE_PIN B8 [get_ports user_btn3] -set_property IOSTANDARD LVCMOS33 [get_ports user_btn3] -## spiflash_1x:0.cs_n -#set_property LOC L13 [get_ports spiflash_1x_cs_n] -#set_property IOSTANDARD LVCMOS33 [get_ports spiflash_1x_cs_n] -# ## spiflash_1x:0.mosi -#set_property LOC K17 [get_ports spiflash_1x_mosi] -#set_property IOSTANDARD LVCMOS33 [get_ports spiflash_1x_mosi] -# ## spiflash_1x:0.miso -#set_property LOC K18 [get_ports spiflash_1x_miso] -#set_property IOSTANDARD LVCMOS33 [get_ports spiflash_1x_miso] -# ## spiflash_1x:0.wp -#set_property LOC L14 [get_ports spiflash_1x_wp] -#set_property IOSTANDARD LVCMOS33 [get_ports spiflash_1x_wp] -# ## spiflash_1x:0.hold -#set_property LOC M14 [get_ports spiflash_1x_hold] -#set_property IOSTANDARD LVCMOS33 [get_ports spiflash_1x_hold] -# ## ddram:0.a -#set_property LOC R2 [get_ports ddram_a[0]] -#set_property SLEW FAST [get_ports ddram_a[0]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_a[0]] -# ## ddram:0.a -#set_property LOC M6 [get_ports ddram_a[1]] -#set_property SLEW FAST [get_ports ddram_a[1]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_a[1]] -# ## ddram:0.a -#set_property LOC N4 [get_ports ddram_a[2]] -#set_property SLEW FAST [get_ports ddram_a[2]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_a[2]] -# ## ddram:0.a -#set_property LOC T1 [get_ports ddram_a[3]] -#set_property SLEW FAST [get_ports ddram_a[3]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_a[3]] -# ## ddram:0.a -#set_property LOC N6 [get_ports ddram_a[4]] -#set_property SLEW FAST [get_ports ddram_a[4]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_a[4]] -# ## ddram:0.a -#set_property LOC R7 [get_ports ddram_a[5]] -#set_property SLEW FAST [get_ports ddram_a[5]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_a[5]] -# ## ddram:0.a -#set_property LOC V6 [get_ports ddram_a[6]] -#set_property SLEW FAST [get_ports ddram_a[6]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_a[6]] -# ## ddram:0.a -#set_property LOC U7 [get_ports ddram_a[7]] -#set_property SLEW FAST [get_ports ddram_a[7]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_a[7]] -# ## ddram:0.a -#set_property LOC R8 [get_ports ddram_a[8]] -#set_property SLEW FAST [get_ports ddram_a[8]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_a[8]] -# ## ddram:0.a -#set_property LOC V7 [get_ports ddram_a[9]] -#set_property SLEW FAST [get_ports ddram_a[9]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_a[9]] -# ## ddram:0.a -#set_property LOC R6 [get_ports ddram_a[10]] -#set_property SLEW FAST [get_ports ddram_a[10]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_a[10]] -# ## ddram:0.a -#set_property LOC U6 [get_ports ddram_a[11]] -#set_property SLEW FAST [get_ports ddram_a[11]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_a[11]] -# ## ddram:0.a -#set_property LOC T6 [get_ports ddram_a[12]] -#set_property SLEW FAST [get_ports ddram_a[12]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_a[12]] -# ## ddram:0.a -#set_property LOC T8 [get_ports ddram_a[13]] -#set_property SLEW FAST [get_ports ddram_a[13]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_a[13]] -# ## ddram:0.ba -#set_property LOC R1 [get_ports ddram_ba[0]] -#set_property SLEW FAST [get_ports ddram_ba[0]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_ba[0]] -# ## ddram:0.ba -#set_property LOC P4 [get_ports ddram_ba[1]] -#set_property SLEW FAST [get_ports ddram_ba[1]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_ba[1]] -# ## ddram:0.ba -#set_property LOC P2 [get_ports ddram_ba[2]] -#set_property SLEW FAST [get_ports ddram_ba[2]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_ba[2]] -# ## ddram:0.ras_n -#set_property LOC P3 [get_ports ddram_ras_n] -#set_property SLEW FAST [get_ports ddram_ras_n] -#set_property IOSTANDARD SSTL15 [get_ports ddram_ras_n] -# ## ddram:0.cas_n -#set_property LOC M4 [get_ports ddram_cas_n] -#set_property SLEW FAST [get_ports ddram_cas_n] -#set_property IOSTANDARD SSTL15 [get_ports ddram_cas_n] -# ## ddram:0.we_n -#set_property LOC P5 [get_ports ddram_we_n] -#set_property SLEW FAST [get_ports ddram_we_n] -#set_property IOSTANDARD SSTL15 [get_ports ddram_we_n] -# ## ddram:0.cs_n -#set_property LOC U8 [get_ports ddram_cs_n] -#set_property SLEW FAST [get_ports ddram_cs_n] -#set_property IOSTANDARD SSTL15 [get_ports ddram_cs_n] -# ## ddram:0.dm -#set_property LOC L1 [get_ports ddram_dm[0]] -#set_property SLEW FAST [get_ports ddram_dm[0]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_dm[0]] -# ## ddram:0.dm -#set_property LOC U1 [get_ports ddram_dm[1]] -#set_property SLEW FAST [get_ports ddram_dm[1]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_dm[1]] -# ## ddram:0.dq -#set_property LOC K5 [get_ports ddram_dq[0]] -#set_property SLEW FAST [get_ports ddram_dq[0]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[0]] -#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[0]] -# ## ddram:0.dq -#set_property LOC L3 [get_ports ddram_dq[1]] -#set_property SLEW FAST [get_ports ddram_dq[1]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[1]] -#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[1]] -# ## ddram:0.dq -#set_property LOC K3 [get_ports ddram_dq[2]] -#set_property SLEW FAST [get_ports ddram_dq[2]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[2]] -#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[2]] -# ## ddram:0.dq -#set_property LOC L6 [get_ports ddram_dq[3]] -#set_property SLEW FAST [get_ports ddram_dq[3]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[3]] -#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[3]] -# ## ddram:0.dq -#set_property LOC M3 [get_ports ddram_dq[4]] -#set_property SLEW FAST [get_ports ddram_dq[4]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[4]] -#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[4]] -# ## ddram:0.dq -#set_property LOC M1 [get_ports ddram_dq[5]] -#set_property SLEW FAST [get_ports ddram_dq[5]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[5]] -#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[5]] -# ## ddram:0.dq -#set_property LOC L4 [get_ports ddram_dq[6]] -#set_property SLEW FAST [get_ports ddram_dq[6]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[6]] -#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[6]] -# ## ddram:0.dq -#set_property LOC M2 [get_ports ddram_dq[7]] -#set_property SLEW FAST [get_ports ddram_dq[7]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[7]] -#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[7]] -# ## ddram:0.dq -#set_property LOC V4 [get_ports ddram_dq[8]] -#set_property SLEW FAST [get_ports ddram_dq[8]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[8]] -#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[8]] -# ## ddram:0.dq -#set_property LOC T5 [get_ports ddram_dq[9]] -#set_property SLEW FAST [get_ports ddram_dq[9]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[9]] -#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[9]] -# ## ddram:0.dq -#set_property LOC U4 [get_ports ddram_dq[10]] -#set_property SLEW FAST [get_ports ddram_dq[10]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[10]] -#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[10]] -# ## ddram:0.dq -#set_property LOC V5 [get_ports ddram_dq[11]] -#set_property SLEW FAST [get_ports ddram_dq[11]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[11]] -#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[11]] -# ## ddram:0.dq -#set_property LOC V1 [get_ports ddram_dq[12]] -#set_property SLEW FAST [get_ports ddram_dq[12]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[12]] -#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[12]] -# ## ddram:0.dq -#set_property LOC T3 [get_ports ddram_dq[13]] -#set_property SLEW FAST [get_ports ddram_dq[13]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[13]] -#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[13]] -# ## ddram:0.dq -#set_property LOC U3 [get_ports ddram_dq[14]] -#set_property SLEW FAST [get_ports ddram_dq[14]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[14]] -#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[14]] -# ## ddram:0.dq -#set_property LOC R3 [get_ports ddram_dq[15]] -#set_property SLEW FAST [get_ports ddram_dq[15]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[15]] -#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[15]] -# ## ddram:0.dqs_p -#set_property LOC N2 [get_ports ddram_dqs_p[0]] -#set_property SLEW FAST [get_ports ddram_dqs_p[0]] -#set_property IOSTANDARD DIFF_SSTL15 [get_ports ddram_dqs_p[0]] -# ## ddram:0.dqs_p -#set_property LOC U2 [get_ports ddram_dqs_p[1]] -#set_property SLEW FAST [get_ports ddram_dqs_p[1]] -#set_property IOSTANDARD DIFF_SSTL15 [get_ports ddram_dqs_p[1]] -# ## ddram:0.dqs_n -#set_property LOC N1 [get_ports ddram_dqs_n[0]] -#set_property SLEW FAST [get_ports ddram_dqs_n[0]] -#set_property IOSTANDARD DIFF_SSTL15 [get_ports ddram_dqs_n[0]] -# ## ddram:0.dqs_n -#set_property LOC V2 [get_ports ddram_dqs_n[1]] -#set_property SLEW FAST [get_ports ddram_dqs_n[1]] -#set_property IOSTANDARD DIFF_SSTL15 [get_ports ddram_dqs_n[1]] -# ## ddram:0.clk_p -#set_property LOC U9 [get_ports ddram_clk_p] -#set_property SLEW FAST [get_ports ddram_clk_p] -#set_property IOSTANDARD DIFF_SSTL15 [get_ports ddram_clk_p] -# ## ddram:0.clk_n -#set_property LOC V9 [get_ports ddram_clk_n] -#set_property SLEW FAST [get_ports ddram_clk_n] -#set_property IOSTANDARD DIFF_SSTL15 [get_ports ddram_clk_n] -# ## ddram:0.cke -#set_property LOC N5 [get_ports ddram_cke] -#set_property SLEW FAST [get_ports ddram_cke] -#set_property IOSTANDARD SSTL15 [get_ports ddram_cke] -# ## ddram:0.odt -#set_property LOC R5 [get_ports ddram_odt] -#set_property SLEW FAST [get_ports ddram_odt] -#set_property IOSTANDARD SSTL15 [get_ports ddram_odt] -# ## ddram:0.reset_n -#set_property LOC K6 [get_ports ddram_reset_n] -#set_property SLEW FAST [get_ports ddram_reset_n] -#set_property IOSTANDARD SSTL15 [get_ports ddram_reset_n] -# ## eth_clocks:0.tx -#set_property LOC H16 [get_ports eth_clocks_tx] -#set_property IOSTANDARD LVCMOS33 [get_ports eth_clocks_tx] -# ## eth_clocks:0.rx -#set_property LOC F15 [get_ports eth_clocks_rx] -#set_property IOSTANDARD LVCMOS33 [get_ports eth_clocks_rx] -# ## eth:0.rst_n -#set_property LOC C16 [get_ports eth_rst_n] -#set_property IOSTANDARD LVCMOS33 [get_ports eth_rst_n] -# ## eth:0.mdio -#set_property LOC K13 [get_ports eth_mdio] -#set_property IOSTANDARD LVCMOS33 [get_ports eth_mdio] -# ## eth:0.mdc -#set_property LOC F16 [get_ports eth_mdc] -#set_property IOSTANDARD LVCMOS33 [get_ports eth_mdc] -# ## eth:0.rx_dv -#set_property LOC G16 [get_ports eth_rx_dv] -#set_property IOSTANDARD LVCMOS33 [get_ports eth_rx_dv] -# ## eth:0.rx_er -#set_property LOC C17 [get_ports eth_rx_er] -#set_property IOSTANDARD LVCMOS33 [get_ports eth_rx_er] -# ## eth:0.rx_data -#set_property LOC D18 [get_ports eth_rx_data[0]] -#set_property IOSTANDARD LVCMOS33 [get_ports eth_rx_data[0]] -# ## eth:0.rx_data -#set_property LOC E17 [get_ports eth_rx_data[1]] -#set_property IOSTANDARD LVCMOS33 [get_ports eth_rx_data[1]] -# ## eth:0.rx_data -#set_property LOC E18 [get_ports eth_rx_data[2]] -#set_property IOSTANDARD LVCMOS33 [get_ports eth_rx_data[2]] -# ## eth:0.rx_data -#set_property LOC G17 [get_ports eth_rx_data[3]] -#set_property IOSTANDARD LVCMOS33 [get_ports eth_rx_data[3]] -# ## eth:0.tx_en -#set_property LOC H15 [get_ports eth_tx_en] -#set_property IOSTANDARD LVCMOS33 [get_ports eth_tx_en] -# ## eth:0.tx_data -#set_property LOC H14 [get_ports eth_tx_data[0]] -#set_property IOSTANDARD LVCMOS33 [get_ports eth_tx_data[0]] -# ## eth:0.tx_data -#set_property LOC J14 [get_ports eth_tx_data[1]] -#set_property IOSTANDARD LVCMOS33 [get_ports eth_tx_data[1]] -# ## eth:0.tx_data -#set_property LOC J13 [get_ports eth_tx_data[2]] -#set_property IOSTANDARD LVCMOS33 [get_ports eth_tx_data[2]] -# ## eth:0.tx_data -#set_property LOC H17 [get_ports eth_tx_data[3]] -#set_property IOSTANDARD LVCMOS33 [get_ports eth_tx_data[3]] -# ## eth:0.col -#set_property LOC D17 [get_ports eth_col] -#set_property IOSTANDARD LVCMOS33 [get_ports eth_col] -# ## eth:0.crs -#set_property LOC G14 [get_ports eth_crs] -#set_property IOSTANDARD LVCMOS33 [get_ports eth_crs] - -set_property INTERNAL_VREF 0.75 [get_iobanks 34] - - -create_clock -period 10.000 -name clk100 [get_nets clk100] - -#create_clock -name eth_rx_clk -period 40.0 [get_nets eth_rx_clk] - -#create_clock -name eth_tx_clk -period 40.0 [get_nets eth_tx_clk] - -#set_clock_groups -group [get_clocks -include_generated_clocks -of [get_nets sys_clk]] -group [get_clocks -include_generated_clocks -of [get_nets eth_rx_clk]] -asynchronous - -#set_clock_groups -group [get_clocks -include_generated_clocks -of [get_nets sys_clk]] -group [get_clocks -include_generated_clocks -of [get_nets eth_tx_clk]] -asynchronous - -#set_clock_groups -group [get_clocks -include_generated_clocks -of [get_nets eth_rx_clk]] -group [get_clocks -include_generated_clocks -of [get_nets eth_tx_clk]] -asynchronous - - - - -set_property BITSTREAM.CONFIG.SPI_BUSWIDTH 4 [current_design] diff --git a/scripts/Murax/arty_a7/arty_a7_org.xdc b/scripts/Murax/arty_a7/arty_a7_org.xdc deleted file mode 100644 index 75c81b14..00000000 --- a/scripts/Murax/arty_a7/arty_a7_org.xdc +++ /dev/null @@ -1,350 +0,0 @@ - ## serial:0.tx -set_property LOC D10 [get_ports serial_tx] -set_property IOSTANDARD LVCMOS33 [get_ports serial_tx] - ## serial:0.rx -set_property LOC A9 [get_ports serial_rx] -set_property IOSTANDARD LVCMOS33 [get_ports serial_rx] - ## clk100:0 -set_property LOC E3 [get_ports clk100] -set_property IOSTANDARD LVCMOS33 [get_ports clk100] - ## cpu_reset:0 -set_property LOC C2 [get_ports cpu_reset] -set_property IOSTANDARD LVCMOS33 [get_ports cpu_reset] - ## eth_ref_clk:0 -#set_property LOC G18 [get_ports eth_ref_clk] -#set_property IOSTANDARD LVCMOS33 [get_ports eth_ref_clk] - ## user_led:0 -set_property LOC H5 [get_ports user_led0] -set_property IOSTANDARD LVCMOS33 [get_ports user_led0] - ## user_led:1 -set_property LOC J5 [get_ports user_led1] -set_property IOSTANDARD LVCMOS33 [get_ports user_led1] - ## user_led:2 -set_property LOC T9 [get_ports user_led2] -set_property IOSTANDARD LVCMOS33 [get_ports user_led2] - ## user_led:3 -set_property LOC T10 [get_ports user_led3] -set_property IOSTANDARD LVCMOS33 [get_ports user_led3] - ## user_sw:0 -set_property LOC A8 [get_ports user_sw0] -set_property IOSTANDARD LVCMOS33 [get_ports user_sw0] - ## user_sw:1 -set_property LOC C11 [get_ports user_sw1] -set_property IOSTANDARD LVCMOS33 [get_ports user_sw1] - ## user_sw:2 -set_property LOC C10 [get_ports user_sw2] -set_property IOSTANDARD LVCMOS33 [get_ports user_sw2] - ## user_sw:3 -set_property LOC A10 [get_ports user_sw3] -set_property IOSTANDARD LVCMOS33 [get_ports user_sw3] - ## user_btn:0 -set_property LOC D9 [get_ports user_btn0] -set_property IOSTANDARD LVCMOS33 [get_ports user_btn0] - ## user_btn:1 -set_property LOC C9 [get_ports user_btn1] -set_property IOSTANDARD LVCMOS33 [get_ports user_btn1] - ## user_btn:2 -set_property LOC B9 [get_ports user_btn2] -set_property IOSTANDARD LVCMOS33 [get_ports user_btn2] - ## user_btn:3 -set_property LOC B8 [get_ports user_btn3] -set_property IOSTANDARD LVCMOS33 [get_ports user_btn3] - ## spiflash_1x:0.cs_n -#set_property LOC L13 [get_ports spiflash_1x_cs_n] -#set_property IOSTANDARD LVCMOS33 [get_ports spiflash_1x_cs_n] -# ## spiflash_1x:0.mosi -#set_property LOC K17 [get_ports spiflash_1x_mosi] -#set_property IOSTANDARD LVCMOS33 [get_ports spiflash_1x_mosi] -# ## spiflash_1x:0.miso -#set_property LOC K18 [get_ports spiflash_1x_miso] -#set_property IOSTANDARD LVCMOS33 [get_ports spiflash_1x_miso] -# ## spiflash_1x:0.wp -#set_property LOC L14 [get_ports spiflash_1x_wp] -#set_property IOSTANDARD LVCMOS33 [get_ports spiflash_1x_wp] -# ## spiflash_1x:0.hold -#set_property LOC M14 [get_ports spiflash_1x_hold] -#set_property IOSTANDARD LVCMOS33 [get_ports spiflash_1x_hold] -# ## ddram:0.a -#set_property LOC R2 [get_ports ddram_a[0]] -#set_property SLEW FAST [get_ports ddram_a[0]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_a[0]] -# ## ddram:0.a -#set_property LOC M6 [get_ports ddram_a[1]] -#set_property SLEW FAST [get_ports ddram_a[1]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_a[1]] -# ## ddram:0.a -#set_property LOC N4 [get_ports ddram_a[2]] -#set_property SLEW FAST [get_ports ddram_a[2]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_a[2]] -# ## ddram:0.a -#set_property LOC T1 [get_ports ddram_a[3]] -#set_property SLEW FAST [get_ports ddram_a[3]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_a[3]] -# ## ddram:0.a -#set_property LOC N6 [get_ports ddram_a[4]] -#set_property SLEW FAST [get_ports ddram_a[4]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_a[4]] -# ## ddram:0.a -#set_property LOC R7 [get_ports ddram_a[5]] -#set_property SLEW FAST [get_ports ddram_a[5]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_a[5]] -# ## ddram:0.a -#set_property LOC V6 [get_ports ddram_a[6]] -#set_property SLEW FAST [get_ports ddram_a[6]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_a[6]] -# ## ddram:0.a -#set_property LOC U7 [get_ports ddram_a[7]] -#set_property SLEW FAST [get_ports ddram_a[7]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_a[7]] -# ## ddram:0.a -#set_property LOC R8 [get_ports ddram_a[8]] -#set_property SLEW FAST [get_ports ddram_a[8]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_a[8]] -# ## ddram:0.a -#set_property LOC V7 [get_ports ddram_a[9]] -#set_property SLEW FAST [get_ports ddram_a[9]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_a[9]] -# ## ddram:0.a -#set_property LOC R6 [get_ports ddram_a[10]] -#set_property SLEW FAST [get_ports ddram_a[10]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_a[10]] -# ## ddram:0.a -#set_property LOC U6 [get_ports ddram_a[11]] -#set_property SLEW FAST [get_ports ddram_a[11]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_a[11]] -# ## ddram:0.a -#set_property LOC T6 [get_ports ddram_a[12]] -#set_property SLEW FAST [get_ports ddram_a[12]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_a[12]] -# ## ddram:0.a -#set_property LOC T8 [get_ports ddram_a[13]] -#set_property SLEW FAST [get_ports ddram_a[13]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_a[13]] -# ## ddram:0.ba -#set_property LOC R1 [get_ports ddram_ba[0]] -#set_property SLEW FAST [get_ports ddram_ba[0]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_ba[0]] -# ## ddram:0.ba -#set_property LOC P4 [get_ports ddram_ba[1]] -#set_property SLEW FAST [get_ports ddram_ba[1]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_ba[1]] -# ## ddram:0.ba -#set_property LOC P2 [get_ports ddram_ba[2]] -#set_property SLEW FAST [get_ports ddram_ba[2]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_ba[2]] -# ## ddram:0.ras_n -#set_property LOC P3 [get_ports ddram_ras_n] -#set_property SLEW FAST [get_ports ddram_ras_n] -#set_property IOSTANDARD SSTL15 [get_ports ddram_ras_n] -# ## ddram:0.cas_n -#set_property LOC M4 [get_ports ddram_cas_n] -#set_property SLEW FAST [get_ports ddram_cas_n] -#set_property IOSTANDARD SSTL15 [get_ports ddram_cas_n] -# ## ddram:0.we_n -#set_property LOC P5 [get_ports ddram_we_n] -#set_property SLEW FAST [get_ports ddram_we_n] -#set_property IOSTANDARD SSTL15 [get_ports ddram_we_n] -# ## ddram:0.cs_n -#set_property LOC U8 [get_ports ddram_cs_n] -#set_property SLEW FAST [get_ports ddram_cs_n] -#set_property IOSTANDARD SSTL15 [get_ports ddram_cs_n] -# ## ddram:0.dm -#set_property LOC L1 [get_ports ddram_dm[0]] -#set_property SLEW FAST [get_ports ddram_dm[0]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_dm[0]] -# ## ddram:0.dm -#set_property LOC U1 [get_ports ddram_dm[1]] -#set_property SLEW FAST [get_ports ddram_dm[1]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_dm[1]] -# ## ddram:0.dq -#set_property LOC K5 [get_ports ddram_dq[0]] -#set_property SLEW FAST [get_ports ddram_dq[0]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[0]] -#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[0]] -# ## ddram:0.dq -#set_property LOC L3 [get_ports ddram_dq[1]] -#set_property SLEW FAST [get_ports ddram_dq[1]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[1]] -#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[1]] -# ## ddram:0.dq -#set_property LOC K3 [get_ports ddram_dq[2]] -#set_property SLEW FAST [get_ports ddram_dq[2]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[2]] -#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[2]] -# ## ddram:0.dq -#set_property LOC L6 [get_ports ddram_dq[3]] -#set_property SLEW FAST [get_ports ddram_dq[3]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[3]] -#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[3]] -# ## ddram:0.dq -#set_property LOC M3 [get_ports ddram_dq[4]] -#set_property SLEW FAST [get_ports ddram_dq[4]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[4]] -#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[4]] -# ## ddram:0.dq -#set_property LOC M1 [get_ports ddram_dq[5]] -#set_property SLEW FAST [get_ports ddram_dq[5]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[5]] -#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[5]] -# ## ddram:0.dq -#set_property LOC L4 [get_ports ddram_dq[6]] -#set_property SLEW FAST [get_ports ddram_dq[6]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[6]] -#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[6]] -# ## ddram:0.dq -#set_property LOC M2 [get_ports ddram_dq[7]] -#set_property SLEW FAST [get_ports ddram_dq[7]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[7]] -#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[7]] -# ## ddram:0.dq -#set_property LOC V4 [get_ports ddram_dq[8]] -#set_property SLEW FAST [get_ports ddram_dq[8]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[8]] -#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[8]] -# ## ddram:0.dq -#set_property LOC T5 [get_ports ddram_dq[9]] -#set_property SLEW FAST [get_ports ddram_dq[9]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[9]] -#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[9]] -# ## ddram:0.dq -#set_property LOC U4 [get_ports ddram_dq[10]] -#set_property SLEW FAST [get_ports ddram_dq[10]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[10]] -#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[10]] -# ## ddram:0.dq -#set_property LOC V5 [get_ports ddram_dq[11]] -#set_property SLEW FAST [get_ports ddram_dq[11]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[11]] -#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[11]] -# ## ddram:0.dq -#set_property LOC V1 [get_ports ddram_dq[12]] -#set_property SLEW FAST [get_ports ddram_dq[12]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[12]] -#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[12]] -# ## ddram:0.dq -#set_property LOC T3 [get_ports ddram_dq[13]] -#set_property SLEW FAST [get_ports ddram_dq[13]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[13]] -#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[13]] -# ## ddram:0.dq -#set_property LOC U3 [get_ports ddram_dq[14]] -#set_property SLEW FAST [get_ports ddram_dq[14]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[14]] -#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[14]] -# ## ddram:0.dq -#set_property LOC R3 [get_ports ddram_dq[15]] -#set_property SLEW FAST [get_ports ddram_dq[15]] -#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[15]] -#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[15]] -# ## ddram:0.dqs_p -#set_property LOC N2 [get_ports ddram_dqs_p[0]] -#set_property SLEW FAST [get_ports ddram_dqs_p[0]] -#set_property IOSTANDARD DIFF_SSTL15 [get_ports ddram_dqs_p[0]] -# ## ddram:0.dqs_p -#set_property LOC U2 [get_ports ddram_dqs_p[1]] -#set_property SLEW FAST [get_ports ddram_dqs_p[1]] -#set_property IOSTANDARD DIFF_SSTL15 [get_ports ddram_dqs_p[1]] -# ## ddram:0.dqs_n -#set_property LOC N1 [get_ports ddram_dqs_n[0]] -#set_property SLEW FAST [get_ports ddram_dqs_n[0]] -#set_property IOSTANDARD DIFF_SSTL15 [get_ports ddram_dqs_n[0]] -# ## ddram:0.dqs_n -#set_property LOC V2 [get_ports ddram_dqs_n[1]] -#set_property SLEW FAST [get_ports ddram_dqs_n[1]] -#set_property IOSTANDARD DIFF_SSTL15 [get_ports ddram_dqs_n[1]] -# ## ddram:0.clk_p -#set_property LOC U9 [get_ports ddram_clk_p] -#set_property SLEW FAST [get_ports ddram_clk_p] -#set_property IOSTANDARD DIFF_SSTL15 [get_ports ddram_clk_p] -# ## ddram:0.clk_n -#set_property LOC V9 [get_ports ddram_clk_n] -#set_property SLEW FAST [get_ports ddram_clk_n] -#set_property IOSTANDARD DIFF_SSTL15 [get_ports ddram_clk_n] -# ## ddram:0.cke -#set_property LOC N5 [get_ports ddram_cke] -#set_property SLEW FAST [get_ports ddram_cke] -#set_property IOSTANDARD SSTL15 [get_ports ddram_cke] -# ## ddram:0.odt -#set_property LOC R5 [get_ports ddram_odt] -#set_property SLEW FAST [get_ports ddram_odt] -#set_property IOSTANDARD SSTL15 [get_ports ddram_odt] -# ## ddram:0.reset_n -#set_property LOC K6 [get_ports ddram_reset_n] -#set_property SLEW FAST [get_ports ddram_reset_n] -#set_property IOSTANDARD SSTL15 [get_ports ddram_reset_n] -# ## eth_clocks:0.tx -#set_property LOC H16 [get_ports eth_clocks_tx] -#set_property IOSTANDARD LVCMOS33 [get_ports eth_clocks_tx] -# ## eth_clocks:0.rx -#set_property LOC F15 [get_ports eth_clocks_rx] -#set_property IOSTANDARD LVCMOS33 [get_ports eth_clocks_rx] -# ## eth:0.rst_n -#set_property LOC C16 [get_ports eth_rst_n] -#set_property IOSTANDARD LVCMOS33 [get_ports eth_rst_n] -# ## eth:0.mdio -#set_property LOC K13 [get_ports eth_mdio] -#set_property IOSTANDARD LVCMOS33 [get_ports eth_mdio] -# ## eth:0.mdc -#set_property LOC F16 [get_ports eth_mdc] -#set_property IOSTANDARD LVCMOS33 [get_ports eth_mdc] -# ## eth:0.rx_dv -#set_property LOC G16 [get_ports eth_rx_dv] -#set_property IOSTANDARD LVCMOS33 [get_ports eth_rx_dv] -# ## eth:0.rx_er -#set_property LOC C17 [get_ports eth_rx_er] -#set_property IOSTANDARD LVCMOS33 [get_ports eth_rx_er] -# ## eth:0.rx_data -#set_property LOC D18 [get_ports eth_rx_data[0]] -#set_property IOSTANDARD LVCMOS33 [get_ports eth_rx_data[0]] -# ## eth:0.rx_data -#set_property LOC E17 [get_ports eth_rx_data[1]] -#set_property IOSTANDARD LVCMOS33 [get_ports eth_rx_data[1]] -# ## eth:0.rx_data -#set_property LOC E18 [get_ports eth_rx_data[2]] -#set_property IOSTANDARD LVCMOS33 [get_ports eth_rx_data[2]] -# ## eth:0.rx_data -#set_property LOC G17 [get_ports eth_rx_data[3]] -#set_property IOSTANDARD LVCMOS33 [get_ports eth_rx_data[3]] -# ## eth:0.tx_en -#set_property LOC H15 [get_ports eth_tx_en] -#set_property IOSTANDARD LVCMOS33 [get_ports eth_tx_en] -# ## eth:0.tx_data -#set_property LOC H14 [get_ports eth_tx_data[0]] -#set_property IOSTANDARD LVCMOS33 [get_ports eth_tx_data[0]] -# ## eth:0.tx_data -#set_property LOC J14 [get_ports eth_tx_data[1]] -#set_property IOSTANDARD LVCMOS33 [get_ports eth_tx_data[1]] -# ## eth:0.tx_data -#set_property LOC J13 [get_ports eth_tx_data[2]] -#set_property IOSTANDARD LVCMOS33 [get_ports eth_tx_data[2]] -# ## eth:0.tx_data -#set_property LOC H17 [get_ports eth_tx_data[3]] -#set_property IOSTANDARD LVCMOS33 [get_ports eth_tx_data[3]] -# ## eth:0.col -#set_property LOC D17 [get_ports eth_col] -#set_property IOSTANDARD LVCMOS33 [get_ports eth_col] -# ## eth:0.crs -#set_property LOC G14 [get_ports eth_crs] -#set_property IOSTANDARD LVCMOS33 [get_ports eth_crs] - -set_property INTERNAL_VREF 0.750 [get_iobanks 34] - -create_clock -name sys_clk -period 10.0 [get_nets sys_clk] - -create_clock -name clk100 -period 10.0 [get_nets clk100] - -#create_clock -name eth_rx_clk -period 40.0 [get_nets eth_rx_clk] - -#create_clock -name eth_tx_clk -period 40.0 [get_nets eth_tx_clk] - -#set_clock_groups -group [get_clocks -include_generated_clocks -of [get_nets sys_clk]] -group [get_clocks -include_generated_clocks -of [get_nets eth_rx_clk]] -asynchronous - -#set_clock_groups -group [get_clocks -include_generated_clocks -of [get_nets sys_clk]] -group [get_clocks -include_generated_clocks -of [get_nets eth_tx_clk]] -asynchronous - -#set_clock_groups -group [get_clocks -include_generated_clocks -of [get_nets eth_rx_clk]] -group [get_clocks -include_generated_clocks -of [get_nets eth_tx_clk]] -asynchronous - -set_false_path -quiet -to [get_nets -quiet -filter {mr_ff == TRUE}] - -set_false_path -quiet -to [get_pins -quiet -filter {REF_PIN_NAME == PRE} -of [get_cells -quiet -filter {ars_ff1 == TRUE || ars_ff2 == TRUE}]] - -set_max_delay 2 -quiet -from [get_pins -quiet -filter {REF_PIN_NAME == Q} -of [get_cells -quiet -filter {ars_ff1 == TRUE}]] -to [get_pins -quiet -filter {REF_PIN_NAME == D} -of [get_cells -quiet -filter {ars_ff2 == TRUE}]] diff --git a/scripts/Murax/arty_a7/make_bit_file.tcl b/scripts/Murax/arty_a7/make_bit_file.tcl deleted file mode 100644 index a97b399f..00000000 --- a/scripts/Murax/arty_a7/make_bit_file.tcl +++ /dev/null @@ -1,50 +0,0 @@ - -# Input files -set mmi_file "./soc.mmi" -set elf_file "./soc.elf" -set source_bit_file "./soc.bit" - -# Output files -set output_bit_file "./soc_latest_sw.bit" - -# Enable to turn on debug -set updatemem_debug 0 - -# Assemble bit file that can be downloaded to device directly -# Combine the original bit file, mmi file, and software elf to create the full bitstream - -# Delete target file -file delete -force $output_bit_file - -# Determine if the user has built the project and has the target source file -# If not, then use the reference bit file shipped with the project -if { ![file exists $source_bit_file] } { - puts "\n********************************************" - puts "INFO - File $source_bit_file doesn't exist as project has not been built" - puts " Using $reference_bit_file instead\n" - puts "********************************************/n" - set source_bit_file $reference_bit_file -} - -# Banner message to console as there is no output for a few seconds -puts " Running updatemem ..." - -if { $updatemem_debug } { - set error [catch {exec updatemem --debug --force --meminfo $mmi_file --data $elf_file --bit $source_bit_file --proc dummy --out $output_bit_file} result] -} else { - set error [catch {exec updatemem --force --meminfo $mmi_file --data $elf_file --bit $source_bit_file --proc dummy --out $output_bit_file} result] -} - -# Print the stdout from updatemem -puts $result - -# Updatemem returns 0 even when there is an error, so cannot trap on error. Having deleted output file to start, then -# detect if it now exists, else exit. -if { ![file exists $output_bit_file] } { - puts "ERROR - $output_bit_file not made" - return -1 -} else { - puts "\n********************************************" - puts " $output_bit_file correctly generated" - puts "********************************************\n" -} diff --git a/scripts/Murax/arty_a7/make_mcs_file b/scripts/Murax/arty_a7/make_mcs_file deleted file mode 100755 index 40bcc5ac..00000000 --- a/scripts/Murax/arty_a7/make_mcs_file +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/sh -#Create mcs file for QSPI flash - -cd ./build - -vivado -mode batch -source ../make_mcs_file.tcl -notrace diff --git a/scripts/Murax/arty_a7/make_mcs_file.tcl b/scripts/Murax/arty_a7/make_mcs_file.tcl deleted file mode 100644 index 9863a2ca..00000000 --- a/scripts/Murax/arty_a7/make_mcs_file.tcl +++ /dev/null @@ -1,31 +0,0 @@ - -# Input file -set source_bit_file "./latest.bit" - -# Output file -set output_mcs_file "./latest.mcs" - -# Delete target file -file delete -force $output_mcs_file - -# Determine if the user has built the project and has the target source file -# If not, then use the reference bit file shipped with the project -if { ![file exists $source_bit_file] } { - puts "\n********************************************" - puts "INFO - File $source_bit_file doesn't exist as project has not been built\n" - puts "********************************************/n" - error -} - -# Create MCS file for base board QSPI flash memory -write_cfgmem -force -format MCS -size 16 -interface SPIx4 -loadbit " up 0 $source_bit_file" $output_mcs_file - -# Check MCS was correctly made -if { ![file exists $output_mcs_file] } { - puts "ERROR - $output_bit_file not made" - return -1 -} else { - puts "\n********************************************" - puts " $output_mcs_file correctly generated" - puts "********************************************\n" -} diff --git a/scripts/Murax/arty_a7/make_mmi_files b/scripts/Murax/arty_a7/make_mmi_files deleted file mode 100755 index 3919e16a..00000000 --- a/scripts/Murax/arty_a7/make_mmi_files +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh - -cd ./build -vivado -mode batch -source ../make_mmi_files.tcl -notrace diff --git a/scripts/Murax/arty_a7/make_mmi_files.tcl b/scripts/Murax/arty_a7/make_mmi_files.tcl deleted file mode 100644 index d9ecd484..00000000 --- a/scripts/Murax/arty_a7/make_mmi_files.tcl +++ /dev/null @@ -1,6 +0,0 @@ -source [file join [file dirname [file normalize [info script]]] vivado_params.tcl] - -open_project -read_only $outputdir/$projectName -open_run impl_1 -source $base/soc_mmi.tcl -puts "mmi files generated" diff --git a/scripts/Murax/arty_a7/make_vivado_project b/scripts/Murax/arty_a7/make_vivado_project deleted file mode 100755 index 4a925107..00000000 --- a/scripts/Murax/arty_a7/make_vivado_project +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/sh - -#cannot rm build because it erase software images that the make file copy there -#rm -rf ./build - -mkdir ./build - -cd ./build -vivado -mode batch -source ../make_vivado_project.tcl -notrace diff --git a/scripts/Murax/arty_a7/make_vivado_project.tcl b/scripts/Murax/arty_a7/make_vivado_project.tcl deleted file mode 100644 index b206ddbb..00000000 --- a/scripts/Murax/arty_a7/make_vivado_project.tcl +++ /dev/null @@ -1,46 +0,0 @@ -#Create output directory and clear contents -source [file join [file dirname [file normalize [info script]]] vivado_params.tcl] - -file mkdir $outputdir -set files [glob -nocomplain "$outputdir/*"] -if {[llength $files] != 0} { - puts "deleting contents of $outputdir" - file delete -force {*}[glob -directory $outputdir *]; # clear folder contents -} else { - puts "$outputdir is empty" -} - -#Create project -create_project -part $part $projectName $outputdir - -#add source files to Vivado project -#add_files -fileset sim_1 ./path/to/testbench.vhd -#add_files [glob ./path/to/sources/*.vhd] -#add_files -fileset constrs_1 ./path/to/constraint/constraint.xdc -#add_files [glob ./path/to/library/sources/*.vhd] -#set_property -library userDefined [glob ./path/to/library/sources/*.vhd] -add_files [glob $base/*.v] -add_files [glob $topv] -add_files -fileset constrs_1 $base/arty_a7.xdc - -#set top level module and update compile order -set_property top toplevel [current_fileset] -update_compile_order -fileset sources_1 -#update_compile_order -fileset sim_1 - -#launch synthesis -launch_runs synth_1 -wait_on_run synth_1 - -#Run implementation and generate bitstream -set_property STEPS.PHYS_OPT_DESIGN.IS_ENABLED true [get_runs impl_1] -launch_runs impl_1 -to_step write_bitstream -wait_on_run impl_1 -puts "Implementation done!" - -#reports generated by default -#open_run impl_1 -#report_timing_summary -check_timing_verbose -report_unconstrained -file report_timing_summary.rpt -#report_utilization -hierarchical -file report_utilization.rpt - -#TODO: add checks about timing, DRC, CDC such that the script give clear indication if design is OK or not diff --git a/scripts/Murax/arty_a7/makefile b/scripts/Murax/arty_a7/makefile deleted file mode 100644 index b6726523..00000000 --- a/scripts/Murax/arty_a7/makefile +++ /dev/null @@ -1,62 +0,0 @@ -ROOT=../../.. -SWBASE=$(ROOT)/src/main/c/murax -SOCSW=hello_world -SOCMEMSRC=$(SWBASE)/$(SOCSW)/build/$(SOCSW).v -SOCMEM=build/soc.mem - -TOP=Murax - -all : build/latest.bit - -../../../$(TOP).v : toplevel.v - (cd ../../..; sbt "runMain vexriscv.demo.Murax_arty") - -.PHONY: $(SOCMEMSRC) -$(SOCMEMSRC): - mkdir -p build - make -C $(SWBASE)/$(SOCSW) - -$(SOCMEM) : $(SOCMEMSRC) - cp -u $(SOCMEMSRC) $(SOCMEM) - -build/vivado_project/fpga.runs/impl_1/toplevel.bit : toplevel.v arty_a7.xdc ../../../$(TOP).v - mkdir -p build - ./make_vivado_project - cp build/vivado_project/fpga.runs/impl_1/toplevel.bit build/latest.bit - -build/soc.mmi: build/vivado_project/fpga.runs/impl_1/toplevel.bit - ./make_mmi_files - -build/latest_soc_sw.bit : $(SOCMEM) build/soc.mmi - rm -f updatemem.jou updatemem.log - updatemem -force --meminfo build/soc.mmi --data $(SOCMEM) --bit build/latest.bit --proc dummy --out build/latest_soc_sw.bit - cp build/latest_soc_sw.bit build/latest.bit - -build/latest.bit : build/latest_soc_sw.bit - -build/latest.mcs : build/latest.bit - ./make_mcs_file - -prog : build/latest.bit - ./write_fpga - -flash : build/latest.mcs - ./write_flash - -clean-soc-sw: - make -C $(SWBASE)/$(SOCSW) clean-all - -soc-sw: clean-soc-sw $(SOCMEM) - -.PHONY: clean -clean : - rm -rf build - mkdir build - rm -f updatemem.jou - rm -f updatemem.log - -clean-sw: clean-soc-sw - -clean-all : clean clean-sw - rm -f ../../../$(TOP).v - rm -f ../../../$(TOP).v_* diff --git a/scripts/Murax/arty_a7/open_vivado_project b/scripts/Murax/arty_a7/open_vivado_project deleted file mode 100755 index 24c54d12..00000000 --- a/scripts/Murax/arty_a7/open_vivado_project +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh - -cd ./build -vivado -mode batch -source ../open_vivado_project.tcl -notrace diff --git a/scripts/Murax/arty_a7/open_vivado_project.tcl b/scripts/Murax/arty_a7/open_vivado_project.tcl deleted file mode 100644 index 41200198..00000000 --- a/scripts/Murax/arty_a7/open_vivado_project.tcl +++ /dev/null @@ -1,4 +0,0 @@ -source [file join [file dirname [file normalize [info script]]] vivado_params.tcl] - -open_project -read_only $outputdir/$projectName -start_gui diff --git a/scripts/Murax/arty_a7/picocom_arty b/scripts/Murax/arty_a7/picocom_arty deleted file mode 100644 index ff15a172..00000000 --- a/scripts/Murax/arty_a7/picocom_arty +++ /dev/null @@ -1 +0,0 @@ -picocom --baud 115200 --imap lfcrlf /dev/ttyUSB1 diff --git a/scripts/Murax/arty_a7/soc_mmi.tcl b/scripts/Murax/arty_a7/soc_mmi.tcl deleted file mode 100644 index 33ea6866..00000000 --- a/scripts/Murax/arty_a7/soc_mmi.tcl +++ /dev/null @@ -1,151 +0,0 @@ -#script to update the init values of RAM without re-synthesis - -if {![info exists mmi_file]} { - # Set MMI output file name - set mmi_file "soc.mmi" -} -if {![info exists part]} { - set part "xc7a35ticsg324-1L" -} - -# Function to swap bits -proc swap_bits { bit } { - - if { $bit > 23 } {return [expr {24 + (31 - $bit)}]} - if { $bit > 15 } {return [expr {16 + (23 - $bit)}]} - if { $bit > 7 } {return [expr {8 + (15 - $bit)}]} - return [expr {7 - $bit}] -} - -# If run from batch file, will need to open project, then open the run -# open_run impl_1 - -# Find all the RAMs, place in a list -set rams [get_cells -hier -regexp {.*core/system_ram/.*} -filter {REF_NAME =~ RAMB36E1}] - -puts "[llength $rams] RAMs in total" -foreach m $rams {puts $m} - -set mems [dict create] -foreach m $rams { - set numbers [regexp -all -inline -- {[0-9]+} $m] - dict set mems $numbers $m -} -set keys [dict keys $mems] -#set keys [lsort -integer $keys] -set rams [] -foreach key $keys { - set m [dict get $mems $key] - puts "$key -> $m" - lappend rams $m -} - -puts "after sort:" -foreach m $rams {puts $m} -puts $rams - -if { [llength $rams] == 0 } { - puts "Error - no memories found" - return -1 -} - -if { [expr {[llength $rams] % 4}] != 0 } { - puts "Error - Number of memories not divisible by 4" - return -1 -} - -set size_bytes [expr {4096*[llength $rams]}] -puts "Instruction memory size $size_bytes" - -# Currently only support memory sizes between 16kB, (one byte per mem), and 128kB, (one bit per mem) -if { ($size_bytes < (4*4096)) || ($size_bytes > (32*4096)) } { - puts "Error - Memory size of $size_bytes out of range" - puts " Script only supports memory sizes between 16kB and 128kB" - return -1 -} - -# Create and open target mmi file -set fp [open $mmi_file {WRONLY CREAT TRUNC}] -if { $fp == 0 } { - puts "Error - Unable to open $mmi_file for writing" - return -1 -} - -# Write the file header -puts $fp "" -puts $fp "" -puts $fp " " -puts $fp " " -puts $fp " " - -# Calculate the expected number of bits per memory -set mem_bits [expr {32/[llength $rams]}] - -puts "mem_bits = $mem_bits" - -set mem_info [dict create] - -set i 0 -foreach ram $rams { - # Get the RAM location - set loc_val [get_property LOC [get_cells $ram]] - regexp -- {(RAMB36_)([0-9XY]+)} $loc_val full ram_name loc_xy - - set memi [dict create ram $ram loc $loc_xy] - - set numbers [regexp -all -inline -- {[0-9]+} $ram] - if { [llength $numbers] == 2 } { - dict lappend mem_info [lindex $numbers 0] $memi - } else { - dict lappend mem_info [expr $i/4] $memi - } - incr i -} - -set sorted_mem_info [dict create] -foreach {idx mems} $mem_info { - foreach mem [lreverse $mems] { - dict lappend sorted_mem_info $idx $mem - } -} -foreach mems $sorted_mem_info { - foreach mem $mems { - puts $mem - } -} - -set lsb 0 -set memlen [ expr 4096*8 / $mem_bits ] -foreach {idx mems} $sorted_mem_info { - puts "idx=$idx" - foreach mem $mems { - puts "mem=$mem" - set ram [dict get $mem ram] - set loc [dict get $mem loc] - set msb [expr $lsb+$mem_bits-1] - set addr_start 0 - set addr_end [expr $memlen-1] - puts "ram=$ram loc=$loc lsb=$lsb msb=$msb addr_start=$addr_start addr_end=$addr_end" - puts $fp " " - puts $fp " " - puts $fp " " - puts $fp " " - puts $fp " " - puts $fp " " - - set lsb [expr ($msb+1)%32] - } -} - -puts $fp " " -puts $fp " " -puts $fp " " -puts $fp " " -puts $fp " " -puts $fp " " -puts $fp " " -puts $fp " " -puts $fp "" - -close $fp diff --git a/scripts/Murax/arty_a7/toplevel.v b/scripts/Murax/arty_a7/toplevel.v deleted file mode 100644 index e127da69..00000000 --- a/scripts/Murax/arty_a7/toplevel.v +++ /dev/null @@ -1,66 +0,0 @@ -`timescale 1ns / 1ps - -module toplevel( - input wire clk100, - input wire cpu_reset,//active low - - input wire tck, - input wire tms, - input wire tdi, - input wire trst,//ignored - output reg tdo, - - input wire serial_rx, - output wire serial_tx, - - input wire user_sw0, - input wire user_sw1, - input wire user_sw2, - input wire user_sw3, - - input wire user_btn0, - input wire user_btn1, - input wire user_btn2, - input wire user_btn3, - - output wire user_led0, - output wire user_led1, - output wire user_led2, - output wire user_led3 - ); - - wire [31:0] io_gpioA_read; - wire [31:0] io_gpioA_write; - wire [31:0] io_gpioA_writeEnable; - - wire io_asyncReset = ~cpu_reset; - - assign {user_led3,user_led2,user_led1,user_led0} = io_gpioA_write[3 : 0]; - assign io_gpioA_read[3:0] = {user_sw3,user_sw2,user_sw1,user_sw0}; - assign io_gpioA_read[7:4] = {user_btn3,user_btn2,user_btn1,user_btn0}; - assign io_gpioA_read[11:8] = {tck,tms,tdi,trst}; - - reg tesic_tck,tesic_tms,tesic_tdi; - wire tesic_tdo; - reg soc_tck,soc_tms,soc_tdi; - wire soc_tdo; - - always @(*) begin - {soc_tck, soc_tms, soc_tdi } = {tck,tms,tdi}; - tdo = soc_tdo; - end - - Murax core ( - .io_asyncReset(io_asyncReset), - .io_mainClk (clk100 ), - .io_jtag_tck(soc_tck), - .io_jtag_tdi(soc_tdi), - .io_jtag_tdo(soc_tdo), - .io_jtag_tms(soc_tms), - .io_gpioA_read (io_gpioA_read), - .io_gpioA_write (io_gpioA_write), - .io_gpioA_writeEnable(io_gpioA_writeEnable), - .io_uart_txd(serial_tx), - .io_uart_rxd(serial_rx) - ); -endmodule diff --git a/scripts/Murax/arty_a7/vivado_params.tcl b/scripts/Murax/arty_a7/vivado_params.tcl deleted file mode 100644 index 343058dd..00000000 --- a/scripts/Murax/arty_a7/vivado_params.tcl +++ /dev/null @@ -1,5 +0,0 @@ -set outputdir ./vivado_project -set part "xc7a35ticsg324-1L" -set base ".." -set projectName "fpga" -set topv "$base/../../../Murax.v" diff --git a/scripts/Murax/arty_a7/write_flash b/scripts/Murax/arty_a7/write_flash deleted file mode 100755 index 05414c4a..00000000 --- a/scripts/Murax/arty_a7/write_flash +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -cd ./build -vivado -mode batch -source ../write_flash.tcl -notrace diff --git a/scripts/Murax/arty_a7/write_flash.tcl b/scripts/Murax/arty_a7/write_flash.tcl deleted file mode 100644 index 845bff74..00000000 --- a/scripts/Murax/arty_a7/write_flash.tcl +++ /dev/null @@ -1,26 +0,0 @@ - -open_hw -connect_hw_server -open_hw_target -current_hw_device [get_hw_devices xc7a35t_0] -refresh_hw_device -update_hw_probes false [lindex [get_hw_devices xc7a35t_0] 0] - -create_hw_cfgmem -hw_device [lindex [get_hw_devices] 0] -mem_dev [lindex [get_cfgmem_parts {s25fl128sxxxxxx0-spi-x1_x2_x4}] 0] -set_property PROBES.FILE {} [get_hw_devices xc7a35t_0] -set_property FULL_PROBES.FILE {} [get_hw_devices xc7a35t_0] -refresh_hw_device [lindex [get_hw_devices xc7a35t_0] 0] -set_property PROGRAM.ADDRESS_RANGE {use_file} [ get_property PROGRAM.HW_CFGMEM [lindex [get_hw_devices xc7a35t_0] 0]] -set_property PROGRAM.FILES [list "latest.mcs" ] [ get_property PROGRAM.HW_CFGMEM [lindex [get_hw_devices xc7a35t_0] 0]] -set_property PROGRAM.PRM_FILE {} [ get_property PROGRAM.HW_CFGMEM [lindex [get_hw_devices xc7a35t_0] 0]] -set_property PROGRAM.UNUSED_PIN_TERMINATION {pull-none} [ get_property PROGRAM.HW_CFGMEM [lindex [get_hw_devices xc7a35t_0] 0]] -set_property PROGRAM.BLANK_CHECK 0 [ get_property PROGRAM.HW_CFGMEM [lindex [get_hw_devices xc7a35t_0] 0]] -set_property PROGRAM.ERASE 1 [ get_property PROGRAM.HW_CFGMEM [lindex [get_hw_devices xc7a35t_0] 0]] -set_property PROGRAM.CFG_PROGRAM 1 [ get_property PROGRAM.HW_CFGMEM [lindex [get_hw_devices xc7a35t_0] 0]] -set_property PROGRAM.VERIFY 1 [ get_property PROGRAM.HW_CFGMEM [lindex [get_hw_devices xc7a35t_0] 0]] -set_property PROGRAM.CHECKSUM 0 [ get_property PROGRAM.HW_CFGMEM [lindex [get_hw_devices xc7a35t_0] 0]] - -if {![string equal [get_property PROGRAM.HW_CFGMEM_TYPE [lindex [get_hw_devices xc7a35t_0] 0]] [get_property MEM_TYPE [get_property CFGMEM_PART [ get_property PROGRAM.HW_CFGMEM [lindex [get_hw_devices xc7a35t_0] 0]]]]] } { create_hw_bitstream -hw_device [lindex [get_hw_devices xc7a35t_0] 0] [get_property PROGRAM.HW_CFGMEM_BITFILE [ lindex [get_hw_devices xc7a35t_0] 0]]; program_hw_devices [lindex [get_hw_devices xc7a35t_0] 0]; }; -program_hw_cfgmem -hw_cfgmem [ get_property PROGRAM.HW_CFGMEM [lindex [get_hw_devices xc7a35t_0] 0]] - -close_hw_target -close_hw diff --git a/scripts/Murax/arty_a7/write_fpga b/scripts/Murax/arty_a7/write_fpga deleted file mode 100755 index 63a344e0..00000000 --- a/scripts/Murax/arty_a7/write_fpga +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -cd ./build -vivado -mode batch -source ../write_fpga.tcl -notrace diff --git a/scripts/Murax/arty_a7/write_fpga.tcl b/scripts/Murax/arty_a7/write_fpga.tcl deleted file mode 100644 index e3214f88..00000000 --- a/scripts/Murax/arty_a7/write_fpga.tcl +++ /dev/null @@ -1,10 +0,0 @@ -open_hw -connect_hw_server -open_hw_target -current_hw_device [get_hw_devices xc7a35t_0] -refresh_hw_device -update_hw_probes false [lindex [get_hw_devices xc7a35t_0] 0] -set_property PROBES.FILE {} [get_hw_devices xc7a35t_0] -set_property FULL_PROBES.FILE {} [get_hw_devices xc7a35t_0] -set_property PROGRAM.FILE {latest.bit} [get_hw_devices xc7a35t_0] -program_hw_devices [get_hw_devices xc7a35t_0] -disconnect_hw_server diff --git a/scripts/Murax/iCE40-hx8k_breakout_board_xip/Makefile b/scripts/Murax/iCE40-hx8k_breakout_board_xip/Makefile index 8feef205..88aa1a2f 100644 --- a/scripts/Murax/iCE40-hx8k_breakout_board_xip/Makefile +++ b/scripts/Murax/iCE40-hx8k_breakout_board_xip/Makefile @@ -1,21 +1,19 @@ -VBASE = ../../.. -VNAME = Murax_iCE40_hx8k_breakout_board_xip -VERILOG = ${VBASE}/${VNAME}.v -all: prog +VERILOG = ../../../Murax_iCE40_hx8k_breakout_board_xip.v -${VERILOG} : - (cd ${VBASE}; sbt "runMain vexriscv.demo.${VNAME}") +generate : + #(cd ../../..; sbt "runMain vexriscv.demo.Murax_iCE40_hx8k_breakout_board_xip") -generate : ${VERILOG} +../../../Murax_iCE40_hx8k_breakout_board_xip.v : + #(cd ../../..; sbt "runMain vexriscv.demo.Murax_iCE40_hx8k_breakout_board_xip") -${VERILOG}*.bin: +../../../Murax_iCE40_hx8k_breakout_board_xip.v*.bin: -bin/Murax_iCE40_hx8k_breakout_board_xip.blif : ${VERILOG} ${VERILOG}*.bin +bin/Murax_iCE40_hx8k_breakout_board_xip.blif : ${VERILOG} ../../../Murax_iCE40_hx8k_breakout_board_xip.v*.bin mkdir -p bin rm -f Murax_iCE40_hx8k_breakout_board_xip.v*.bin - cp ${VERILOG}*.bin . | true + cp ../../../Murax_iCE40_hx8k_breakout_board_xip.v*.bin . | true yosys -v3 -p "synth_ice40 -top Murax_iCE40_hx8k_breakout_board_xip -blif bin/Murax_iCE40_hx8k_breakout_board_xip.blif" ${VERILOG} bin/Murax_iCE40_hx8k_breakout_board_xip.asc : Murax_iCE40_hx8k_breakout_board_xip.pcf bin/Murax_iCE40_hx8k_breakout_board_xip.blif @@ -30,15 +28,11 @@ time: bin/Murax_iCE40_hx8k_breakout_board_xip.bin icetime -tmd hx8k bin/Murax_iCE40_hx8k_breakout_board_xip.asc prog : bin/Murax_iCE40_hx8k_breakout_board_xip.bin - lsusb -d 0403:6010 iceprog -S bin/Murax_iCE40_hx8k_breakout_board_xip.bin sudo-prog : bin/Murax_iCE40_hx8k_breakout_board_xip.bin - sudo lsusb -d 0403:6010 sudo iceprog -S bin/Murax_iCE40_hx8k_breakout_board_xip.bin clean : rm -rf bin rm -f Murax_iCE40_hx8k_breakout_board_xip.v*.bin - rm -f ${VERILOG}*.bin - rm -f ${VERILOG} diff --git a/scripts/Murax/iCE40-hx8k_breakout_board_xip/Murax_iCE40_hx8k_breakout_board_xip.pcf b/scripts/Murax/iCE40-hx8k_breakout_board_xip/Murax_iCE40_hx8k_breakout_board_xip.pcf index 510acf71..4962e25b 100644 --- a/scripts/Murax/iCE40-hx8k_breakout_board_xip/Murax_iCE40_hx8k_breakout_board_xip.pcf +++ b/scripts/Murax/iCE40-hx8k_breakout_board_xip/Murax_iCE40_hx8k_breakout_board_xip.pcf @@ -1,12 +1,12 @@ ## iCE40-hx8k breakout board -set_io io_mainClk J3 -set_io io_jtag_tck H16 -set_io io_jtag_tdi G15 -set_io io_jtag_tdo G16 -set_io io_jtag_tms F15 -set_io io_uart_txd B12 -set_io io_uart_rxd B10 +set_io io_J3 J3 +set_io io_H16 H16 +set_io io_G15 G15 +set_io io_G16 G16 +set_io io_F15 F15 +set_io io_B12 B12 +set_io io_B10 B10 set_io io_led[0] B5 set_io io_led[1] B4 set_io io_led[2] A2 @@ -17,7 +17,7 @@ set_io io_led[6] B3 set_io io_led[7] C3 #XIP -set_io io_miso P12 -set_io io_mosi P11 -set_io io_sclk R11 -set_io io_spis R12 +set_io io_P12 P12 +set_io io_P11 P11 +set_io io_R11 R11 +set_io io_R12 R12 \ No newline at end of file diff --git a/scripts/Murax/iCE40-hx8k_breakout_board_xip/README.md b/scripts/Murax/iCE40-hx8k_breakout_board_xip/README.md index 3ed77c5e..1e50a02f 100644 --- a/scripts/Murax/iCE40-hx8k_breakout_board_xip/README.md +++ b/scripts/Murax/iCE40-hx8k_breakout_board_xip/README.md @@ -9,10 +9,6 @@ This board can be purchased for ~$USD 49 directly from Lattice and is supported by the IceStorm [`iceprog`](https://github.com/cliffordwolf/icestorm/tree/master/iceprog) tool. -# Bootloader operations - -A bootloader is implemented in a ROM within the FPGA bitfile. It configure the SPI and attempt to read the first word in 'XIP' area of the flash (0xE0040000 in CPU address space, 0x40000 in flash). If this first word is not 0xFFFFFFFF and the same value is read 3 times, -then the bootloader jump at 0xE0040000. # Using the example @@ -63,29 +59,12 @@ The process should take around 30 seconds on a reasonable fast computer. ## Programming -Make sure the FPGA board is the only USB peripheral with ID 0403:6010 - -For example, this is bad: -``` -user@lafite:~$ lsusb -d 0403:6010 -Bus 001 Device 088: ID 0403:6010 Future Technology Devices International, Ltd FT2232C Dual USB-UART/FIFO IC -Bus 001 Device 090: ID 0403:6010 Future Technology Devices International, Ltd FT2232C Dual USB-UART/FIFO IC -``` -This is good: -``` -user@lafite:~$ lsusb -d 0403:6010 -Bus 001 Device 088: ID 0403:6010 Future Technology Devices International, Ltd FT2232C Dual USB-UART/FIFO IC -``` - - After building you should be able to run `make prog`. You may need to run `make sudo-prog` if root is needed to access your USB devices. You should get output like the following; ``` -lsusb -d 0403:6010 -Bus 001 Device 088: ID 0403:6010 Future Technology Devices International, Ltd FT2232C Dual USB-UART/FIFO IC -iceprog -S bin/Murax_iCE40_hx8k_breakout_board_xip.bin +iceprog -S bin/toplevel.bin init.. cdone: high reset.. @@ -95,113 +74,13 @@ cdone: high Bye. ``` -WARNING: having this output does NOT guarantee you actually programmed anything in the FPGA! +After programming the LEDs at the top of the board should start flashing in an +interesting pattern. -After programming nothing visual will happen, except the LEDs being off. -The bootloader is waiting for a valid content in the flash (see Bootloader operations). +## Connect -## Programming flash image +After programming you should be able to connect to the serial port and have the +output echoed back to you. -### Connect JTAG - -We will use vexrisc JTAG to program the flash, so you need openocd and a -suitable JTAG dongle. - -Pin-out: -``` -TCK: H16 aka J2.25 -TDO: G16 aka J2.26 -TDI: G15 aka J2.27 -TMS: F15 aka J2.28 -``` -In addition you need to connect the ground and VTarget aka VIO: J2.2 on the -board. - -### Start GDB server / OpenOCD -Make sure to use https://github.com/SpinalHDL/openocd_riscv -Make sure to select the configuration file which match your JTAG dongle. - -An example with the dongle "ft2232h_breakout": -``` -src/openocd -f tcl/interface/ftdi/ft2232h_breakout.cfg -c "set MURAX_CPU0_YAML ../VexRiscv/cpu0.yaml" -f tcl/target/murax_xip.cfg -``` - -You should get an output like below: -``` -Open On-Chip Debugger 0.10.0+dev-01214-g0ace94f (2019-10-02-18:23) -Licensed under GNU GPL v2 -For bug reports, read - http://openocd.org/doc/doxygen/bugs.html -../VexRiscv/cpu0.yaml -adapter speed: 100 kHz -adapter_nsrst_delay: 260 -Info : auto-selecting first available session transport "jtag". To override use 'transport select '. -jtag_ntrst_delay: 250 -Info : set servers polling period to 50ms -Error: libusb_get_string_descriptor_ascii() failed with LIBUSB_ERROR_INVALID_PARAM -Info : clock speed 100 kHz -Info : JTAG tap: fpga_spinal.bridge tap/device found: 0x10001fff (mfg: 0x7ff (), part: 0x0001, ver: 0x1) -Info : Listening on port 3333 for gdb connections -requesting target halt and executing a soft reset -Info : Listening on port 6666 for tcl connections -Info : Listening on port 4444 for telnet connections -``` - -### Loading the flash with telnet - -First we connect and stop execution on the device: -``` -user@lafite:~/Downloads/vexrisc_full/VexRiscv/src/main/c/murax/xipBootloader$ telnet 127.0.0.1 4444 -Trying 127.0.0.1... -Connected to 127.0.0.1. -Escape character is '^]'. -Open On-Chip Debugger -> reset -JTAG tap: fpga_spinal.bridge tap/device found: 0x10001fff (mfg: 0x7ff (), part: 0x0001, ver: 0x1) -> -``` - -Now we can safely connect the J7 jumper on the board to be able to access the flash. -After that, we can load the program in flash: -``` -> flash erase_sector 0 4 4 -erased sectors 4 through 4 on flash bank 0 in 0.872235s -> flash write_bank 0 /home/user/dev/vexrisc_fork/VexRiscv/src/main/c/murax/xipBootloader/demo_xip.bin 0x40000 -wrote 48 bytes from file /home/user/dev/vexrisc_fork/VexRiscv/src/main/c/murax/xipBootloader/demo_xip.bin to flash bank 0 at offset 0x00040000 in 0.285539s (0.164 KiB/s) -> flash verify_bank 0 /home/user/dev/vexrisc_fork/VexRiscv/src/main/c/murax/xipBootloader/demo_xip.bin 0x40000 -read 48 bytes from file /home/user/dev/vexrisc_fork/VexRiscv/src/main/c/murax/xipBootloader/demo_xip.bin and flash bank 0 at offset 0x00040000 in 0.192036s (0.244 KiB/s) -contents match -> reset -JTAG tap: fpga_spinal.bridge tap/device found: 0x10001fff (mfg: 0x7ff (), part: 0x0001, ver: 0x1) -> resume -> exit -Connection closed by foreign host. -``` - -From now the device runs the code from flash, LEDs shall display a dot moving from D9 to D2. - -### Loading flash using GDB / eclipse -``` -src/openocd -f tcl/interface/ftdi/ft2232h_breakout.cfg -c "set MURAX_CPU0_YAML ../VexRiscv/cpu0.yaml" -f tcl/target/murax_xip.cfg -``` -- Make sure J7 is connected. -- Connect to GDB / eclipse as usual. - -From there code loading, step, break points works as usual (including software break points in flash). - -## Update hardware/bootloader - -- Stop any OpenOCD connection -- Remove J7, then: -``` -make clean prog -``` -- Remember to check a single FTDI device is listed in the output. If not: - - Disconnect the other devices - ``` - make prog - ``` -- Connect J7, flash software shall start executing. - -## Flash software -Refer to "Loading the flash with telnet" or "Loading flash using GDB / eclipse". +On Linux you can do this using a command like `screen /dev/ttyUSB1`. Then as +you type you should get back the same characters. diff --git a/src/main/c/murax/hello_world/makefile b/src/main/c/murax/hello_world/makefile deleted file mode 100644 index dc560c0a..00000000 --- a/src/main/c/murax/hello_world/makefile +++ /dev/null @@ -1,134 +0,0 @@ -PROJ_NAME=hello_world -DEBUG=no -BENCH=no -MULDIV=no - -SRCS = $(wildcard src/*.c) \ - $(wildcard src/*.cpp) \ - $(wildcard src/*.S) - -OBJDIR = build - -INC = -LIBS = -LIBSINC = -L$(OBJDIR) -LDSCRIPT = ./src/linker.ld - -#include ../../../resources/gcc.mk -# Set it to yes if you are using the sifive precompiled GCC pack -SIFIVE_GCC_PACK ?= yes - -ifeq ($(SIFIVE_GCC_PACK),yes) - RISCV_NAME ?= riscv64-unknown-elf - RISCV_PATH ?= /opt/riscv/ -else - RISCV_NAME ?= riscv32-unknown-elf - ifeq ($(MULDIV),yes) - RISCV_PATH ?= /opt/riscv32im/ - else - RISCV_PATH ?= /opt/riscv32i/ - endif -endif - -MABI=ilp32 -MARCH := rv32i -ifeq ($(MULDIV),yes) - MARCH := $(MARCH)m -endif -ifeq ($(COMPRESSED),yes) - MARCH := $(MARCH)ac -endif - -CFLAGS += -march=$(MARCH) -mabi=$(MABI) -DNDEBUG -LDFLAGS += -march=$(MARCH) -mabi=$(MABI) - - - -#include ../../../resources/subproject.mk - - -ifeq ($(DEBUG),yes) - CFLAGS += -g3 -O0 -endif - -ifeq ($(DEBUG),no) - CFLAGS += -g -Os -endif - -ifeq ($(BENCH),yes) - CFLAGS += -fno-inline -endif - -ifeq ($(SIFIVE_GCC_PACK),yes) - RISCV_CLIB=$(RISCV_PATH)/$(RISCV_NAME)/lib/$(MARCH)/$(MABI)/ -else - RISCV_CLIB=$(RISCV_PATH)/$(RISCV_NAME)/lib/ -endif - - - - - -RISCV_OBJCOPY = $(RISCV_PATH)/bin/$(RISCV_NAME)-objcopy -RISCV_OBJDUMP = $(RISCV_PATH)/bin/$(RISCV_NAME)-objdump -RISCV_CC=$(RISCV_PATH)/bin/$(RISCV_NAME)-gcc - -CFLAGS += -MD -fstrict-volatile-bitfields -fno-strict-aliasing -LDFLAGS += -nostdlib -lgcc -mcmodel=medany -nostartfiles -ffreestanding -Wl,-Bstatic,-T,$(LDSCRIPT),-Map,$(OBJDIR)/$(PROJ_NAME).map,--print-memory-usage -#LDFLAGS += -lgcc -lc -lg -nostdlib -lgcc -msave-restore --strip-debug, - -OBJS := $(SRCS) -OBJS := $(OBJS:.c=.o) -OBJS := $(OBJS:.cpp=.o) -OBJS := $(OBJS:.S=.o) -OBJS := $(OBJS:..=miaou) -OBJS := $(addprefix $(OBJDIR)/,$(OBJS)) - - -all: $(OBJDIR)/$(PROJ_NAME).elf $(OBJDIR)/$(PROJ_NAME).hex $(OBJDIR)/$(PROJ_NAME).asm $(OBJDIR)/$(PROJ_NAME).v - -$(OBJDIR)/%.elf: $(OBJS) | $(OBJDIR) - $(RISCV_CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) $(LIBSINC) $(LIBS) - -%.hex: %.elf - $(RISCV_OBJCOPY) -O ihex $^ $@ - -%.bin: %.elf - $(RISCV_OBJCOPY) -O binary $^ $@ - -%.v: %.elf - $(RISCV_OBJCOPY) -O verilog $^ $@ - -%.asm: %.elf - $(RISCV_OBJDUMP) -S -d $^ > $@ - -$(OBJDIR)/%.o: %.c - mkdir -p $(dir $@) - $(RISCV_CC) -c $(CFLAGS) $(INC) -o $@ $^ - $(RISCV_CC) -S $(CFLAGS) $(INC) -o $@.disasm $^ - -$(OBJDIR)/%.o: %.cpp - mkdir -p $(dir $@) - $(RISCV_CC) -c $(CFLAGS) $(INC) -o $@ $^ - -$(OBJDIR)/%.o: %.S - mkdir -p $(dir $@) - $(RISCV_CC) -c $(CFLAGS) -o $@ $^ -D__ASSEMBLY__=1 - -$(OBJDIR): - mkdir -p $@ - -.PHONY: clean -clean: - rm -rf $(OBJDIR)/src - rm -f $(OBJDIR)/$(PROJ_NAME).elf - rm -f $(OBJDIR)/$(PROJ_NAME).hex - rm -f $(OBJDIR)/$(PROJ_NAME).map - rm -f $(OBJDIR)/$(PROJ_NAME).v - rm -f $(OBJDIR)/$(PROJ_NAME).asm - find $(OBJDIR) -type f -name '*.o' -print0 | xargs -0 -r rm - find $(OBJDIR) -type f -name '*.d' -print0 | xargs -0 -r rm - -clean-all : clean - -.SECONDARY: $(OBJS) diff --git a/src/main/c/murax/hello_world/src/crt.S b/src/main/c/murax/hello_world/src/crt.S deleted file mode 100644 index 62d67b9e..00000000 --- a/src/main/c/murax/hello_world/src/crt.S +++ /dev/null @@ -1,98 +0,0 @@ -.global crtStart -.global main -.global irqCallback - - .section .start_jump,"ax",@progbits -crtStart: - //long jump to allow crtInit to be anywhere - //do it always in 12 bytes - lui x2, %hi(crtInit) - addi x2, x2, %lo(crtInit) - jalr x1,x2 - nop - -.section .text - -.global trap_entry -.align 5 -trap_entry: - sw x1, - 1*4(sp) - sw x5, - 2*4(sp) - sw x6, - 3*4(sp) - sw x7, - 4*4(sp) - sw x10, - 5*4(sp) - sw x11, - 6*4(sp) - sw x12, - 7*4(sp) - sw x13, - 8*4(sp) - sw x14, - 9*4(sp) - sw x15, -10*4(sp) - sw x16, -11*4(sp) - sw x17, -12*4(sp) - sw x28, -13*4(sp) - sw x29, -14*4(sp) - sw x30, -15*4(sp) - sw x31, -16*4(sp) - addi sp,sp,-16*4 - call irqCallback - lw x1 , 15*4(sp) - lw x5, 14*4(sp) - lw x6, 13*4(sp) - lw x7, 12*4(sp) - lw x10, 11*4(sp) - lw x11, 10*4(sp) - lw x12, 9*4(sp) - lw x13, 8*4(sp) - lw x14, 7*4(sp) - lw x15, 6*4(sp) - lw x16, 5*4(sp) - lw x17, 4*4(sp) - lw x28, 3*4(sp) - lw x29, 2*4(sp) - lw x30, 1*4(sp) - lw x31, 0*4(sp) - addi sp,sp,16*4 - mret - .text - - -crtInit: - .option push - .option norelax - la gp, __global_pointer$ - .option pop - la sp, _stack_start - -bss_init: - la a0, _bss_start - la a1, _bss_end -bss_loop: - beq a0,a1,bss_done - sw zero,0(a0) - add a0,a0,4 - j bss_loop -bss_done: - -ctors_init: - la a0, _ctors_start - addi sp,sp,-4 -ctors_loop: - la a1, _ctors_end - beq a0,a1,ctors_done - lw a3,0(a0) - add a0,a0,4 - sw a0,0(sp) - jalr a3 - lw a0,0(sp) - j ctors_loop -ctors_done: - addi sp,sp,4 - - - li a0, 0x880 //880 enable timer + external interrupts - csrw mie,a0 - li a0, 0x1808 //1808 enable interrupts - csrw mstatus,a0 - - call main -infinitLoop: - j infinitLoop diff --git a/src/main/c/murax/hello_world/src/gpio.h b/src/main/c/murax/hello_world/src/gpio.h deleted file mode 100644 index 34348fec..00000000 --- a/src/main/c/murax/hello_world/src/gpio.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef GPIO_H_ -#define GPIO_H_ - - -typedef struct -{ - volatile uint32_t INPUT; - volatile uint32_t OUTPUT; - volatile uint32_t OUTPUT_ENABLE; -} Gpio_Reg; - - -#endif /* GPIO_H_ */ - - diff --git a/src/main/c/murax/hello_world/src/interrupt.h b/src/main/c/murax/hello_world/src/interrupt.h deleted file mode 100644 index 23b7d277..00000000 --- a/src/main/c/murax/hello_world/src/interrupt.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef INTERRUPTCTRL_H_ -#define INTERRUPTCTRL_H_ - -#include - -typedef struct -{ - volatile uint32_t PENDINGS; - volatile uint32_t MASKS; -} InterruptCtrl_Reg; - -static void interruptCtrl_init(InterruptCtrl_Reg* reg){ - reg->MASKS = 0; - reg->PENDINGS = 0xFFFFFFFF; -} - -#endif /* INTERRUPTCTRL_H_ */ diff --git a/src/main/c/murax/hello_world/src/linker.ld b/src/main/c/murax/hello_world/src/linker.ld deleted file mode 100644 index 57bc2f7b..00000000 --- a/src/main/c/murax/hello_world/src/linker.ld +++ /dev/null @@ -1,110 +0,0 @@ -/* -This is free and unencumbered software released into the public domain. - -Anyone is free to copy, modify, publish, use, compile, sell, or -distribute this software, either in source code form or as a compiled -binary, for any purpose, commercial or non-commercial, and by any -means. -*/ -OUTPUT_FORMAT("elf32-littleriscv", "elf32-littleriscv", "elf32-littleriscv") -OUTPUT_ARCH(riscv) -ENTRY(crtStart) - -MEMORY { - RAM (rwx): ORIGIN = 0x80000000, LENGTH = 2k -} - -_stack_size = DEFINED(_stack_size) ? _stack_size : 256; -_heap_size = DEFINED(_heap_size) ? _heap_size : 0; - -SECTIONS { - - ._vector ORIGIN(RAM): { - *crt.o(.start_jump); - *crt.o(.text); - } > RAM - - ._user_heap (NOLOAD): - { - . = ALIGN(8); - PROVIDE ( end = . ); - PROVIDE ( _end = . ); - PROVIDE ( _heap_start = .); - . = . + _heap_size; - . = ALIGN(8); - PROVIDE ( _heap_end = .); - } > RAM - -._stack (NOLOAD): - { - . = ALIGN(16); - PROVIDE (_stack_end = .); - . = . + _stack_size; - . = ALIGN(16); - PROVIDE (_stack_start = .); - } > RAM - - .data : - { - *(.rdata) - *(.rodata .rodata.*) - *(.gnu.linkonce.r.*) - *(.data .data.*) - *(.gnu.linkonce.d.*) - . = ALIGN(8); - PROVIDE( __global_pointer$ = . + 0x800 ); - *(.sdata .sdata.*) - *(.gnu.linkonce.s.*) - . = ALIGN(8); - *(.srodata.cst16) - *(.srodata.cst8) - *(.srodata.cst4) - *(.srodata.cst2) - *(.srodata .srodata.*) - } > RAM - - .bss (NOLOAD) : { - . = ALIGN(4); - /* This is used by the startup in order to initialize the .bss secion */ - _bss_start = .; - *(.sbss*) - *(.gnu.linkonce.sb.*) - *(.bss .bss.*) - *(.gnu.linkonce.b.*) - *(COMMON) - . = ALIGN(4); - _bss_end = .; - } > RAM - - - .rodata : - { - *(.rdata) - *(.rodata .rodata.*) - *(.gnu.linkonce.r.*) - } > RAM - - .noinit (NOLOAD) : { - . = ALIGN(4); - *(.noinit .noinit.*) - . = ALIGN(4); - } > RAM - - .memory : { - *(.text); - end = .; - } > RAM - - .ctors : - { - . = ALIGN(4); - _ctors_start = .; - KEEP(*(.init_array*)) - KEEP (*(SORT(.ctors.*))) - KEEP (*(.ctors)) - . = ALIGN(4); - _ctors_end = .; - PROVIDE ( END_OF_SW_IMAGE = . ); - } > RAM - -} diff --git a/src/main/c/murax/hello_world/src/main.c b/src/main/c/murax/hello_world/src/main.c deleted file mode 100644 index 05f32273..00000000 --- a/src/main/c/murax/hello_world/src/main.c +++ /dev/null @@ -1,42 +0,0 @@ -//#include "stddefs.h" -#include - -#include "murax.h" - -void print(const char*str){ - while(*str){ - uart_write(UART,*str); - str++; - } -} -void println(const char*str){ - print(str); - uart_write(UART,'\n'); -} - -void delay(uint32_t loops){ - for(int i=0;iOUTPUT; - } -} - -void main() { - GPIO_A->OUTPUT_ENABLE = 0x0000000F; - GPIO_A->OUTPUT = 0x00000001; - println("hello world arty a7 v1"); - const int nleds = 4; - const int nloops = 2000000; - while(1){ - for(unsigned int i=0;iOUTPUT = 1<OUTPUT = (1<<(nleds-1))>>i; - delay(nloops); - } - } -} - -void irqCallback(){ -} diff --git a/src/main/c/murax/hello_world/src/murax.h b/src/main/c/murax/hello_world/src/murax.h deleted file mode 100644 index fbfdf3e7..00000000 --- a/src/main/c/murax/hello_world/src/murax.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef __MURAX_H__ -#define __MURAX_H__ - -#include "timer.h" -#include "prescaler.h" -#include "interrupt.h" -#include "gpio.h" -#include "uart.h" - -#define GPIO_A ((Gpio_Reg*)(0xF0000000)) -#define TIMER_PRESCALER ((Prescaler_Reg*)0xF0020000) -#define TIMER_INTERRUPT ((InterruptCtrl_Reg*)0xF0020010) -#define TIMER_A ((Timer_Reg*)0xF0020040) -#define TIMER_B ((Timer_Reg*)0xF0020050) -#define UART ((Uart_Reg*)(0xF0010000)) - -#endif /* __MURAX_H__ */ diff --git a/src/main/c/murax/hello_world/src/prescaler.h b/src/main/c/murax/hello_world/src/prescaler.h deleted file mode 100644 index 6bd9694a..00000000 --- a/src/main/c/murax/hello_world/src/prescaler.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef PRESCALERCTRL_H_ -#define PRESCALERCTRL_H_ - -#include - - -typedef struct -{ - volatile uint32_t LIMIT; -} Prescaler_Reg; - -static void prescaler_init(Prescaler_Reg* reg){ - -} - -#endif /* PRESCALERCTRL_H_ */ diff --git a/src/main/c/murax/hello_world/src/timer.h b/src/main/c/murax/hello_world/src/timer.h deleted file mode 100644 index 1577535c..00000000 --- a/src/main/c/murax/hello_world/src/timer.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef TIMERCTRL_H_ -#define TIMERCTRL_H_ - -#include - - -typedef struct -{ - volatile uint32_t CLEARS_TICKS; - volatile uint32_t LIMIT; - volatile uint32_t VALUE; -} Timer_Reg; - -static void timer_init(Timer_Reg *reg){ - reg->CLEARS_TICKS = 0; - reg->VALUE = 0; -} - - -#endif /* TIMERCTRL_H_ */ diff --git a/src/main/c/murax/hello_world/src/uart.h b/src/main/c/murax/hello_world/src/uart.h deleted file mode 100644 index c3a30a56..00000000 --- a/src/main/c/murax/hello_world/src/uart.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef UART_H_ -#define UART_H_ - - -typedef struct -{ - volatile uint32_t DATA; - volatile uint32_t STATUS; - volatile uint32_t CLOCK_DIVIDER; - volatile uint32_t FRAME_CONFIG; -} Uart_Reg; - -enum UartParity {NONE = 0,EVEN = 1,ODD = 2}; -enum UartStop {ONE = 0,TWO = 1}; - -typedef struct { - uint32_t dataLength; - enum UartParity parity; - enum UartStop stop; - uint32_t clockDivider; -} Uart_Config; - -static uint32_t uart_writeAvailability(Uart_Reg *reg){ - return (reg->STATUS >> 16) & 0xFF; -} -static uint32_t uart_readOccupancy(Uart_Reg *reg){ - return reg->STATUS >> 24; -} - -static void uart_write(Uart_Reg *reg, uint32_t data){ - while(uart_writeAvailability(reg) == 0); - reg->DATA = data; -} - -static void uart_applyConfig(Uart_Reg *reg, Uart_Config *config){ - reg->CLOCK_DIVIDER = config->clockDivider; - reg->FRAME_CONFIG = ((config->dataLength-1) << 0) | (config->parity << 8) | (config->stop << 16); -} - -#endif /* UART_H_ */ - - diff --git a/src/main/c/murax/xipBootloader/crt.S b/src/main/c/murax/xipBootloader/crt.S index 52687677..178f7884 100644 --- a/src/main/c/murax/xipBootloader/crt.S +++ b/src/main/c/murax/xipBootloader/crt.S @@ -42,33 +42,13 @@ crtStart: li t0, 0x1 sw t0, CTRL_XIP_CONFIG(CTRL) li t0, XIP_BASE - lw t1, (t0) - li t2, 0xFFFFFFFF - xor t3,t1,t2 - beqz t3,retry - //if we are here we have read a value from flash which is not all ones - lw t2, (t0) - xor t3,t1,t2 - bnez t3,retry - lw t2, (t0) - xor t3,t1,t2 - bnez t3,retry - //if we are here we have read the same value 3 times, so flash seems good, lets's jump jr t0 -retry: - li a0, 0x800 - call spiWrite - li t1,100000 -loop: - addi t1,t1,-1 - bnez t1, loop - j crtStart spiWrite: sw a0,CTRL_DATA(CTRL) spiWrite_wait: lw t0,CTRL_STATUS(CTRL) - slli t0,t0,0x10 + srli t0,t0,0x10 beqz t0,spiWrite_wait ret diff --git a/src/main/c/murax/xipBootloader/crt.bin b/src/main/c/murax/xipBootloader/crt.bin index 3584ff4b9d823a2b06f626f59e6ea53c5f120f29..d64a1cb00efe30e57fa9ae8eb357f1590f780573 100755 GIT binary patch delta 84 zcmX@WSTRA%?*OwftANCN1_vN*0HhBvnTs+o2(z*_yk}rw+RpT!VRF+Z0p&&UER&f8 l7?c;pvutN#d63?~1Z1ygXkO&cF!>S_6Tn*@{>#j{Li z5@1kX5YMumiRA(FVkU;k%pd+6`xP@JGw?Ar1NmUK6dwbeEyBl;-oV6wWFDh=Gb4jA qGjoE<%Gcy-XZW030pZ`CWWB!-_Vg5e`AOHYn Cd=EPS literal 0 HcmV?d00001 diff --git a/src/main/c/murax/xipBootloader/makefile b/src/main/c/murax/xipBootloader/makefile index e08c17b2..56b8ab84 100644 --- a/src/main/c/murax/xipBootloader/makefile +++ b/src/main/c/murax/xipBootloader/makefile @@ -4,34 +4,20 @@ LFLAGS= -nostdlib -mcmodel=medany -nostartfiles -ffreestanding -fPIC -fPIE all: crt.S demo.S riscv64-unknown-elf-gcc -c $(CFLAGS) -o crt.o crt.S - riscv64-unknown-elf-gcc $(CFLAGS) -o crt.elf crt.o $(LFLAGS) -Wl,-Bstatic,-T,mapping_rom.ld,-Map,crt.map,--print-memory-usage + riscv64-unknown-elf-gcc $(CFLAGS) -o crt.elf crt.o $(LFLAGS) -Wl,-Bstatic,-T,mapping.ld,-Map,crt.map,--print-memory-usage riscv64-unknown-elf-objdump -S -d crt.elf > crt.asm riscv64-unknown-elf-objcopy -O binary crt.elf crt.bin - riscv64-unknown-elf-gcc $(CFLAGS) -o crt_ram.elf crt.o $(LFLAGS) -Wl,-Bstatic,-T,mapping.ld,-Map,crt_ram.map,--print-memory-usage - riscv64-unknown-elf-objdump -S -d crt_ram.elf > crt_ram.asm - riscv64-unknown-elf-objcopy -O binary crt_ram.elf crt_ram.bin - riscv64-unknown-elf-gcc -c $(CFLAGS) -o demo.o demo.S riscv64-unknown-elf-gcc $(CFLAGS) -o demo.elf demo.o $(LFLAGS) -Wl,-Bstatic,-T,mapping.ld,-Map,demo.map,--print-memory-usage riscv64-unknown-elf-objdump -S -d demo.elf > demo.asm riscv64-unknown-elf-objcopy -O binary demo.elf demo.bin - riscv64-unknown-elf-gcc $(CFLAGS) -o demo_rom.elf demo.o $(LFLAGS) -Wl,-Bstatic,-T,mapping_rom.ld,-Map,demo_rom.map,--print-memory-usage - riscv64-unknown-elf-objdump -S -d demo_rom.elf > demo_rom.asm - riscv64-unknown-elf-objcopy -O binary demo_rom.elf demo_rom.bin - riscv64-unknown-elf-gcc $(CFLAGS) -o demo_xip.elf demo.o $(LFLAGS) -Wl,-Bstatic,-T,mapping_xip.ld,-Map,demo_xip.map,--print-memory-usage - riscv64-unknown-elf-objdump -S -d demo_xip.elf > demo_xip.asm - riscv64-unknown-elf-objcopy -O binary demo_xip.elf demo_xip.bin -clean-for-commit: +clean: rm -f *.o + rm -f *.bin rm -f *.elf rm -f *.asm - rm -f *.map - rm -f *.d - rm demo_rom.bin demo.bin crt_ram.bin - -clean: clean-for-commit - rm -f *.bin + rm -f *.map \ No newline at end of file diff --git a/src/main/c/murax/xipBootloader/mapping_rom.ld b/src/main/c/murax/xipBootloader/mapping_rom.ld deleted file mode 100644 index aaa0c3ca..00000000 --- a/src/main/c/murax/xipBootloader/mapping_rom.ld +++ /dev/null @@ -1,96 +0,0 @@ -/* -This is free and unencumbered software released into the public domain. - -Anyone is free to copy, modify, publish, use, compile, sell, or -distribute this software, either in source code form or as a compiled -binary, for any purpose, commercial or non-commercial, and by any -means. -*/ -OUTPUT_FORMAT("elf32-littleriscv", "elf32-littleriscv", "elf32-littleriscv") -OUTPUT_ARCH(riscv) -ENTRY(crtStart) - -MEMORY { - mem : ORIGIN = 0x80000000, LENGTH = 0x00000400 - rom : ORIGIN = 0xF001E000, LENGTH = 0x00000400 -} - -_stack_size = DEFINED(_stack_size) ? _stack_size : 0; - -SECTIONS { - - .vector : { - *crt.o(.text); - } > rom - - .memory : { - *(.text); - end = .; - } > rom - - .rodata : - { - *(.rdata) - *(.rodata .rodata.*) - *(.gnu.linkonce.r.*) - } > rom - - .ctors : - { - . = ALIGN(4); - _ctors_start = .; - KEEP(*(.init_array*)) - KEEP (*(SORT(.ctors.*))) - KEEP (*(.ctors)) - . = ALIGN(4); - _ctors_end = .; - } > rom - - .data : - { - *(.rdata) - *(.rodata .rodata.*) - *(.gnu.linkonce.r.*) - *(.data .data.*) - *(.gnu.linkonce.d.*) - . = ALIGN(8); - PROVIDE( __global_pointer$ = . + 0x800 ); - *(.sdata .sdata.*) - *(.gnu.linkonce.s.*) - . = ALIGN(8); - *(.srodata.cst16) - *(.srodata.cst8) - *(.srodata.cst4) - *(.srodata.cst2) - *(.srodata .srodata.*) - } > rom - - .bss (NOLOAD) : { - . = ALIGN(4); - /* This is used by the startup in order to initialize the .bss secion */ - _bss_start = .; - *(.sbss*) - *(.gnu.linkonce.sb.*) - *(.bss .bss.*) - *(.gnu.linkonce.b.*) - *(COMMON) - . = ALIGN(4); - _bss_end = .; - } > mem - - .noinit (NOLOAD) : { - . = ALIGN(4); - *(.noinit .noinit.*) - . = ALIGN(4); - } > mem - - ._stack (NOLOAD): - { - . = ALIGN(16); - PROVIDE (_stack_end = .); - . = . + _stack_size; - . = ALIGN(16); - PROVIDE (_stack_start = .); - } > mem - -} diff --git a/src/main/c/murax/xipBootloader/mapping_xip.ld b/src/main/c/murax/xipBootloader/mapping_xip.ld deleted file mode 100644 index ed564007..00000000 --- a/src/main/c/murax/xipBootloader/mapping_xip.ld +++ /dev/null @@ -1,96 +0,0 @@ -/* -This is free and unencumbered software released into the public domain. - -Anyone is free to copy, modify, publish, use, compile, sell, or -distribute this software, either in source code form or as a compiled -binary, for any purpose, commercial or non-commercial, and by any -means. -*/ -OUTPUT_FORMAT("elf32-littleriscv", "elf32-littleriscv", "elf32-littleriscv") -OUTPUT_ARCH(riscv) -ENTRY(crtStart) - -MEMORY { - mem : ORIGIN = 0x80000000, LENGTH = 0x00000400 - xip : ORIGIN = 0xE0040000, LENGTH = 0x00000400 -} - -_stack_size = DEFINED(_stack_size) ? _stack_size : 0; - -SECTIONS { - - .vector : { - *crt.o(.text); - } > xip - - .memory : { - *(.text); - end = .; - } > xip - - .rodata : - { - *(.rdata) - *(.rodata .rodata.*) - *(.gnu.linkonce.r.*) - } > xip - - .ctors : - { - . = ALIGN(4); - _ctors_start = .; - KEEP(*(.init_array*)) - KEEP (*(SORT(.ctors.*))) - KEEP (*(.ctors)) - . = ALIGN(4); - _ctors_end = .; - } > xip - - .data : - { - *(.rdata) - *(.rodata .rodata.*) - *(.gnu.linkonce.r.*) - *(.data .data.*) - *(.gnu.linkonce.d.*) - . = ALIGN(8); - PROVIDE( __global_pointer$ = . + 0x800 ); - *(.sdata .sdata.*) - *(.gnu.linkonce.s.*) - . = ALIGN(8); - *(.srodata.cst16) - *(.srodata.cst8) - *(.srodata.cst4) - *(.srodata.cst2) - *(.srodata .srodata.*) - } > xip - - .bss (NOLOAD) : { - . = ALIGN(4); - /* This is used by the startup in order to initialize the .bss secion */ - _bss_start = .; - *(.sbss*) - *(.gnu.linkonce.sb.*) - *(.bss .bss.*) - *(.gnu.linkonce.b.*) - *(COMMON) - . = ALIGN(4); - _bss_end = .; - } > mem - - .noinit (NOLOAD) : { - . = ALIGN(4); - *(.noinit .noinit.*) - . = ALIGN(4); - } > mem - - ._stack (NOLOAD): - { - . = ALIGN(16); - PROVIDE (_stack_end = .); - . = . + _stack_size; - . = ALIGN(16); - PROVIDE (_stack_start = .); - } > mem - -} diff --git a/src/main/scala/vexriscv/demo/Murax.scala b/src/main/scala/vexriscv/demo/Murax.scala index 6d98907b..42a3d7ef 100644 --- a/src/main/scala/vexriscv/demo/Murax.scala +++ b/src/main/scala/vexriscv/demo/Murax.scala @@ -362,55 +362,57 @@ object Murax_iCE40_hx8k_breakout_board_xip{ case class Murax_iCE40_hx8k_breakout_board_xip() extends Component{ val io = new Bundle { - val mainClk = in Bool() - val jtag_tck = in Bool() - val jtag_tdi = in Bool() - val jtag_tdo = out Bool() - val jtag_tms = in Bool() - val uart_txd = out Bool() - val uart_rxd = in Bool() + val J3 = in Bool() + val H16 = in Bool() + val G15 = in Bool() + val G16 = out Bool() + val F15 = in Bool() + val B12 = out Bool() + val B10 = in Bool() - val mosi = inout(Analog(Bool)) - val miso = inout(Analog(Bool)) - val sclk = out Bool() - val spis = out Bool() + + //p12 as mosi mean flash config + val P12 = inout(Analog(Bool)) + val P11 = inout(Analog(Bool)) + val R11 = out Bool() + val R12 = out Bool() val led = out Bits(8 bits) } - val murax = Murax(MuraxConfig.default(withXip = true).copy(onChipRamSize = 8 kB)) + val murax = Murax(MuraxConfig.default(withXip = true)) murax.io.asyncReset := False val mainClkBuffer = SB_GB() - mainClkBuffer.USER_SIGNAL_TO_GLOBAL_BUFFER <> io.mainClk + mainClkBuffer.USER_SIGNAL_TO_GLOBAL_BUFFER <> io.J3 mainClkBuffer.GLOBAL_BUFFER_OUTPUT <> murax.io.mainClk val jtagClkBuffer = SB_GB() - jtagClkBuffer.USER_SIGNAL_TO_GLOBAL_BUFFER <> io.jtag_tck + jtagClkBuffer.USER_SIGNAL_TO_GLOBAL_BUFFER <> io.H16 jtagClkBuffer.GLOBAL_BUFFER_OUTPUT <> murax.io.jtag.tck io.led <> murax.io.gpioA.write(7 downto 0) - murax.io.jtag.tdi <> io.jtag_tdi - murax.io.jtag.tdo <> io.jtag_tdo - murax.io.jtag.tms <> io.jtag_tms + murax.io.jtag.tdi <> io.G15 + murax.io.jtag.tdo <> io.G16 + murax.io.jtag.tms <> io.F15 murax.io.gpioA.read <> 0 - murax.io.uart.txd <> io.uart_txd - murax.io.uart.rxd <> io.uart_rxd + murax.io.uart.txd <> io.B12 + murax.io.uart.rxd <> io.B10 val xip = new ClockingArea(murax.systemClockDomain) { - RegNext(murax.io.xip.ss.asBool) <> io.spis + RegNext(murax.io.xip.ss.asBool) <> io.R12 val sclkIo = SB_IO_SCLK() - sclkIo.PACKAGE_PIN <> io.sclk + sclkIo.PACKAGE_PIN <> io.R11 sclkIo.CLOCK_ENABLE := True sclkIo.OUTPUT_CLK := ClockDomain.current.readClockWire sclkIo.D_OUT_0 <> murax.io.xip.sclk.write(0) sclkIo.D_OUT_1 <> RegNext(murax.io.xip.sclk.write(1)) - val datas = for ((data, pin) <- (murax.io.xip.data, List(io.mosi, io.miso)).zipped) yield new Area { + val datas = for ((data, pin) <- (murax.io.xip.data, List(io.P12, io.P11).reverse).zipped) yield new Area { val dataIo = SB_IO_DATA() dataIo.PACKAGE_PIN := pin dataIo.CLOCK_ENABLE := True @@ -430,6 +432,45 @@ object Murax_iCE40_hx8k_breakout_board_xip{ def main(args: Array[String]) { SpinalVerilog(Murax_iCE40_hx8k_breakout_board_xip()) + /*SpinalVerilog{ + val c = Murax(MuraxConfig.default(withXip = true)) + + + + + c.rework { + c.resetCtrlClockDomain { + c.io.xip.setAsDirectionLess.allowDirectionLessIo.flattenForeach(_.unsetName()) + + out(RegNext(c.io.xip.ss)).setName("io_xip_ss") + + val sclk = SB_IO_SCLK() + sclk.PACKAGE_PIN := inout(Analog(Bool)).setName("io_xip_sclk") + sclk.CLOCK_ENABLE := True + + sclk.OUTPUT_CLK := ClockDomain.current.readClockWire + sclk.D_OUT_0 <> c.io.xip.sclk.write(0) + sclk.D_OUT_1 <> RegNext(c.io.xip.sclk.write(1)) + + for (i <- 0 until c.io.xip.p.dataWidth) { + val data = c.io.xip.data(i) + val bb = SB_IO_DATA() + bb.PACKAGE_PIN := inout(Analog(Bool)).setName(s"io_xip_data_$i" ) + bb.CLOCK_ENABLE := True + + bb.OUTPUT_CLK := ClockDomain.current.readClockWire + bb.OUTPUT_ENABLE <> data.writeEnable + bb.D_OUT_0 <> data.write(0) + bb.D_OUT_1 <> RegNext(data.write(1)) + + bb.INPUT_CLK := ClockDomain.current.readClockWire + data.read(0) := bb.D_IN_0 + data.read(1) := RegNext(bb.D_IN_1) + } + } + } + c + }*/ } } @@ -471,10 +512,3 @@ object MuraxWithRamInit{ SpinalVerilog(Murax(MuraxConfig.default.copy(onChipRamSize = 4 kB, onChipRamHexFile = "src/main/ressource/hex/muraxDemo.hex"))) } } - -object Murax_arty{ - def main(args: Array[String]) { - val hex = "src/main/c/murax/hello_world/build/hello_world.hex" - SpinalVerilog(Murax(MuraxConfig.default(false).copy(coreFrequency = 100 MHz,onChipRamSize = 32 kB, onChipRamHexFile = hex))) - } -} diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index 838489d2..591e36e2 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -24,9 +24,8 @@ case class DataCacheConfig(cacheSize : Int, earlyDataMux : Boolean = false, tagSizeShift : Int = 0, //Used to force infering ram withLrSc : Boolean = false, - withAmo : Boolean = false, - mergeExecuteMemory : Boolean = false){ - assert(!(mergeExecuteMemory && (earlyDataMux || earlyWaysHits))) + withAmo : Boolean = false){ + assert(!(earlyDataMux && !earlyWaysHits)) def burstSize = bytePerLine*8/memDataWidth val burstLength = bytePerLine/(memDataWidth/8) @@ -448,7 +447,7 @@ class DataCache(p : DataCacheConfig) extends Component{ } val stageA = new Area{ - def stagePipe[T <: Data](that : T) = if(mergeExecuteMemory) CombInit(that) else RegNextWhen(that, !io.cpu.memory.isStuck) + def stagePipe[T <: Data](that : T) = RegNextWhen(that, !io.cpu.memory.isStuck) val request = stagePipe(io.cpu.execute.args) val mask = stagePipe(stage0.mask) io.cpu.memory.mmuBus.cmd.isValid := io.cpu.memory.isValid @@ -459,22 +458,16 @@ class DataCache(p : DataCacheConfig) extends Component{ val wayHits = earlyWaysHits generate ways.map(way => (io.cpu.memory.mmuBus.rsp.physicalAddress(tagRange) === way.tagsReadRsp.address && way.tagsReadRsp.valid)) val dataMux = earlyDataMux generate MuxOH(wayHits, ways.map(_.dataReadRsp)) - val colisions = if(mergeExecuteMemory){ - stagePipe(stage0.colisions) - } else { - //Assume the writeback stage will never be unstall memory acces while memory stage is stalled - stagePipe(stage0.colisions) | collisionProcess(io.cpu.memory.address(lineRange.high downto wordRange.low), mask) - } + val colisions = stagePipe(stage0.colisions) | collisionProcess(io.cpu.memory.address(lineRange.high downto wordRange.low), mask) //Assume the writeback stage will never be unstall memory acces while memory stage is stalled } val stageB = new Area { def stagePipe[T <: Data](that : T) = RegNextWhen(that, !io.cpu.writeBack.isStuck) - def ramPipe[T <: Data](that : T) = if(mergeExecuteMemory) CombInit(that) else RegNextWhen(that, !io.cpu.writeBack.isStuck) val request = RegNextWhen(stageA.request, !io.cpu.writeBack.isStuck) val mmuRspFreeze = False val mmuRsp = RegNextWhen(io.cpu.memory.mmuBus.rsp, !io.cpu.writeBack.isStuck && !mmuRspFreeze) - val tagsReadRsp = ways.map(w => ramPipe(w.tagsReadRsp)) - val dataReadRsp = !earlyDataMux generate ways.map(w => ramPipe(w.dataReadRsp)) + val tagsReadRsp = ways.map(w => stagePipe(w.tagsReadRsp)) + val dataReadRsp = !earlyDataMux generate ways.map(w => stagePipe(w.dataReadRsp)) val waysHits = if(earlyWaysHits) stagePipe(B(stageA.wayHits)) else B(tagsReadRsp.map(tag => mmuRsp.physicalAddress(tagRange) === tag.address && tag.valid).asBits()) val waysHit = waysHits.orR val dataMux = if(earlyDataMux) stagePipe(stageA.dataMux) else MuxOH(waysHits, dataReadRsp) diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index 9c633de2..978dd5db 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -148,7 +148,7 @@ class DBusCachedPlugin(val config : DataCacheConfig, redoBranch = pipeline.service(classOf[JumpService]).createJumpInterface(if(pipeline.writeBack != null) pipeline.writeBack else pipeline.execute) if(catchSomething) - exceptionBus = pipeline.service(classOf[ExceptionService]).newExceptionPort(if(pipeline.writeBack == null) pipeline.memory else pipeline.writeBack) + exceptionBus = pipeline.service(classOf[ExceptionService]).newExceptionPort(pipeline.writeBack) if(pipeline.serviceExist(classOf[PrivilegeService])) privilegeService = pipeline.service(classOf[PrivilegeService]) @@ -162,9 +162,7 @@ class DBusCachedPlugin(val config : DataCacheConfig, dBus = master(DataCacheMemBus(this.config)).setName("dBus") - val cache = new DataCache(this.config.copy( - mergeExecuteMemory = writeBack == null - )) + val cache = new DataCache(this.config) //Interconnect the plugin dBus with the cache dBus with some optional pipelining def optionPipe[T](cond : Boolean, on : T)(f : T => T) : T = if(cond) f(on) else on @@ -231,22 +229,19 @@ class DBusCachedPlugin(val config : DataCacheConfig, } } - val mmuAndBufferStage = if(writeBack != null) memory else execute - mmuAndBufferStage plug new Area { - import mmuAndBufferStage._ - + memory plug new Area{ + import memory._ cache.io.cpu.memory.isValid := arbitration.isValid && input(MEMORY_ENABLE) cache.io.cpu.memory.isStuck := arbitration.isStuck cache.io.cpu.memory.isRemoved := arbitration.removeIt - cache.io.cpu.memory.address := (if(relaxedMemoryTranslationRegister) input(MEMORY_VIRTUAL_ADDRESS) else if(mmuAndBufferStage == execute) cache.io.cpu.execute.address else U(input(REGFILE_WRITE_DATA))) + cache.io.cpu.memory.address := (if(relaxedMemoryTranslationRegister) input(MEMORY_VIRTUAL_ADDRESS) else U(input(REGFILE_WRITE_DATA))) cache.io.cpu.memory.mmuBus <> mmuBus cache.io.cpu.memory.mmuBus.rsp.isIoAccess setWhen(pipeline(DEBUG_BYPASS_CACHE) && !cache.io.cpu.memory.isWrite) } - val managementStage = stages.last - managementStage plug new Area{ - import managementStage._ + writeBack plug new Area{ + import writeBack._ 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() else False) @@ -331,10 +326,10 @@ class DBusCachedPlugin(val config : DataCacheConfig, execute.insert(IS_DBUS_SHARING) := dBusAccess.cmd.fire - mmuBus.cmd.bypassTranslation setWhen(mmuAndBufferStage.input(IS_DBUS_SHARING)) - if(mmuAndBufferStage != execute) (cache.io.cpu.memory.isValid setWhen(mmuAndBufferStage.input(IS_DBUS_SHARING))) - cache.io.cpu.writeBack.isValid setWhen(managementStage.input(IS_DBUS_SHARING)) - dBusAccess.rsp.valid := managementStage.input(IS_DBUS_SHARING) && !cache.io.cpu.writeBack.isWrite && (cache.io.cpu.redo || !cache.io.cpu.writeBack.haltIt) + mmuBus.cmd.bypassTranslation setWhen(memory.input(IS_DBUS_SHARING)) + cache.io.cpu.memory.isValid setWhen(memory.input(IS_DBUS_SHARING)) + cache.io.cpu.writeBack.isValid setWhen(writeBack.input(IS_DBUS_SHARING)) + dBusAccess.rsp.valid := writeBack.input(IS_DBUS_SHARING) && !cache.io.cpu.writeBack.isWrite && (cache.io.cpu.redo || !cache.io.cpu.writeBack.haltIt) dBusAccess.rsp.data := cache.io.cpu.writeBack.data dBusAccess.rsp.error := cache.io.cpu.writeBack.unalignedAccess || cache.io.cpu.writeBack.accessError dBusAccess.rsp.redo := cache.io.cpu.redo @@ -342,10 +337,10 @@ class DBusCachedPlugin(val config : DataCacheConfig, when(forceDatapath){ execute.output(REGFILE_WRITE_DATA) := dBusAccess.cmd.address.asBits } - if(mmuAndBufferStage != execute) mmuAndBufferStage.input(IS_DBUS_SHARING) init(False) - managementStage.input(IS_DBUS_SHARING) init(False) + memory.input(IS_DBUS_SHARING) init(False) + writeBack.input(IS_DBUS_SHARING) init(False) when(dBusAccess.rsp.valid){ - managementStage.input(IS_DBUS_SHARING).getDrivingReg := False + writeBack.input(IS_DBUS_SHARING).getDrivingReg := False } } } diff --git a/src/main/scala/vexriscv/plugin/HazardSimplePlugin.scala b/src/main/scala/vexriscv/plugin/HazardSimplePlugin.scala index 1ed1d83e..f674ae87 100644 --- a/src/main/scala/vexriscv/plugin/HazardSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/HazardSimplePlugin.scala @@ -95,7 +95,7 @@ class HazardSimplePlugin(bypassExecute : Boolean = false, } if(withWriteBackStage) trackHazardWithStage(writeBack,bypassWriteBack,null) - if(withMemoryStage) trackHazardWithStage(memory ,bypassMemory, if(stages.last == memory) null else BYPASSABLE_MEMORY_STAGE) + if(withMemoryStage) trackHazardWithStage(memory ,bypassMemory ,BYPASSABLE_MEMORY_STAGE) if(readStage != execute) trackHazardWithStage(execute ,bypassExecute , if(stages.last == execute) null else BYPASSABLE_EXECUTE_STAGE) diff --git a/src/main/scala/vexriscv/plugin/Mul16Plugin.scala b/src/main/scala/vexriscv/plugin/Mul16Plugin.scala deleted file mode 100644 index f2a63c31..00000000 --- a/src/main/scala/vexriscv/plugin/Mul16Plugin.scala +++ /dev/null @@ -1,119 +0,0 @@ -package vexriscv.plugin - -import vexriscv._ -import vexriscv.plugin._ -import spinal.core._ - -/** - * A multiplication plugin using only 16-bit multiplications - */ -class Mul16Plugin extends Plugin[VexRiscv]{ - - object MUL_LL extends Stageable(UInt(32 bits)) - object MUL_LH extends Stageable(UInt(32 bits)) - object MUL_HL extends Stageable(UInt(32 bits)) - object MUL_HH extends Stageable(UInt(32 bits)) - - object MUL extends Stageable(Bits(64 bits)) - - object IS_MUL extends Stageable(Bool) - - override def setup(pipeline: VexRiscv): Unit = { - import Riscv._ - import pipeline.config._ - - - val actions = List[(Stageable[_ <: BaseType],Any)]( - SRC1_CTRL -> Src1CtrlEnum.RS, - SRC2_CTRL -> Src2CtrlEnum.RS, - REGFILE_WRITE_VALID -> True, - BYPASSABLE_EXECUTE_STAGE -> False, - BYPASSABLE_MEMORY_STAGE -> False, - RS1_USE -> True, - RS2_USE -> True, - IS_MUL -> True - ) - - val decoderService = pipeline.service(classOf[DecoderService]) - decoderService.addDefault(IS_MUL, False) - decoderService.add(List( - MULX -> actions - )) - - } - - override def build(pipeline: VexRiscv): Unit = { - import pipeline._ - import pipeline.config._ - - // Prepare signed inputs for the multiplier in the next stage. - // This will map them best to an FPGA DSP. - execute plug new Area { - import execute._ - val a,b = Bits(32 bit) - - a := input(SRC1) - b := input(SRC2) - - val aLow = a(15 downto 0).asUInt - val bLow = b(15 downto 0).asUInt - val aHigh = a(31 downto 16).asUInt - val bHigh = b(31 downto 16).asUInt - - insert(MUL_LL) := aLow * bLow - insert(MUL_LH) := aLow * bHigh - insert(MUL_HL) := aHigh * bLow - insert(MUL_HH) := aHigh * bHigh - } - - memory plug new Area { - import memory._ - - val ll = UInt(32 bits) - val lh = UInt(33 bits) - val hl = UInt(32 bits) - val hh = UInt(32 bits) - - ll := input(MUL_LL) - lh := input(MUL_LH).resized - hl := input(MUL_HL) - hh := input(MUL_HH) - - val hllh = lh + hl - insert(MUL) := ((hh ## ll(31 downto 16)).asUInt + hllh) ## ll(15 downto 0) - } - - writeBack plug new Area { - import writeBack._ - val aSigned,bSigned = Bool - switch(input(INSTRUCTION)(13 downto 12)) { - is(B"01") { - aSigned := True - bSigned := True - } - is(B"10") { - aSigned := True - bSigned := False - } - default { - aSigned := False - bSigned := False - } - } - - val a = (aSigned && input(SRC1).msb) ? input(SRC2).asUInt | U(0) - val b = (bSigned && input(SRC2).msb) ? input(SRC1).asUInt | U(0) - - when(arbitration.isValid && input(IS_MUL)){ - switch(input(INSTRUCTION)(13 downto 12)){ - is(B"00"){ - output(REGFILE_WRITE_DATA) := input(MUL)(31 downto 0) - } - is(B"01",B"10",B"11"){ - output(REGFILE_WRITE_DATA) := (((input(MUL)(63 downto 32)).asUInt + ~a) + (~b + 2)).asBits - } - } - } - } - } -} diff --git a/src/main/scala/vexriscv/plugin/MulDivIterativePlugin.scala b/src/main/scala/vexriscv/plugin/MulDivIterativePlugin.scala index 6820f8ec..f366854c 100644 --- a/src/main/scala/vexriscv/plugin/MulDivIterativePlugin.scala +++ b/src/main/scala/vexriscv/plugin/MulDivIterativePlugin.scala @@ -31,7 +31,7 @@ class MulDivIterativePlugin(genMul : Boolean = true, SRC1_CTRL -> Src1CtrlEnum.RS, SRC2_CTRL -> Src2CtrlEnum.RS, REGFILE_WRITE_VALID -> True, - BYPASSABLE_EXECUTE_STAGE -> Bool(pipeline.stages.last == pipeline.execute), + BYPASSABLE_EXECUTE_STAGE -> False, BYPASSABLE_MEMORY_STAGE -> True, RS1_USE -> True, RS2_USE -> True @@ -69,28 +69,21 @@ class MulDivIterativePlugin(genMul : Boolean = true, import pipeline.config._ if(!genMul && !genDiv) return - val flushStage = if(memory != null) memory else execute - flushStage plug new Area { - import flushStage._ + memory plug new Area { + import memory._ //Shared ressources val rs1 = Reg(UInt(33 bits)) val rs2 = Reg(UInt(32 bits)) val accumulator = Reg(UInt(65 bits)) - //FrontendOK is only used for CPU configs without memory/writeback stages, were it is required to wait one extra cycle - // to let's the frontend process rs1 rs2 registers - val frontendOk = if(flushStage != execute) True else RegInit(False) setWhen(arbitration.isValid && !pipeline.service(classOf[HazardService]).hazardOnExecuteRS && ((if(genDiv) input(IS_DIV) else False) || (if(genMul) input(IS_MUL) else False))) clearWhen(arbitration.isMoving) val mul = ifGen(genMul) (if(customMul != null) customMul(rs1,rs2,memory,pipeline) else new Area{ assert(isPow2(mulUnrollFactor)) val counter = Counter(32 / mulUnrollFactor + 1) val done = counter.willOverflowIfInc when(arbitration.isValid && input(IS_MUL)){ - when(!frontendOk || !done){ - arbitration.haltItself := True - } - when(frontendOk && !done){ + when(!done){ arbitration.haltItself := True counter.increment() rs2 := rs2 |>> mulUnrollFactor @@ -119,10 +112,8 @@ class MulDivIterativePlugin(genMul : Boolean = true, val done = Reg(Bool) setWhen(counter === counter.end-1) clearWhen(!arbitration.isStuck) val result = Reg(Bits(32 bits)) when(arbitration.isValid && input(IS_DIV)){ - when(!frontendOk || !done){ + when(!done){ arbitration.haltItself := True - } - when(frontendOk && !done){ counter.increment() def stages(inNumerator: UInt, inRemainder: UInt, stage: Int): Unit = stage match { @@ -148,11 +139,16 @@ class MulDivIterativePlugin(genMul : Boolean = true, } output(REGFILE_WRITE_DATA) := result +// when(input(INSTRUCTION)(13 downto 12) === "00" && counter === 0 && rs2 =/= 0 && rs1 < 16 && rs2 < 16 && !input(RS1).msb && !input(RS2).msb) { +// output(REGFILE_WRITE_DATA) := B(rs1(3 downto 0) / rs2(3 downto 0)).resized +// counter.willIncrement := False +// arbitration.haltItself := False +// } } }) //Execute stage logic to drive memory stage's input regs - when(if(flushStage != execute) !arbitration.isStuck else !frontendOk){ + when(!arbitration.isStuck){ accumulator := 0 def twoComplement(that : Bits, enable: Bool): UInt = (Mux(enable, ~that, that).asUInt + enable.asUInt) val rs2NeedRevert = execute.input(RS2).msb && execute.input(IS_RS2_SIGNED) diff --git a/src/main/scala/vexriscv/plugin/MulSimplePlugin.scala b/src/main/scala/vexriscv/plugin/MulSimplePlugin.scala index 3b407e1d..41ed3916 100644 --- a/src/main/scala/vexriscv/plugin/MulSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/MulSimplePlugin.scala @@ -19,8 +19,8 @@ class MulSimplePlugin extends Plugin[VexRiscv]{ SRC1_CTRL -> Src1CtrlEnum.RS, SRC2_CTRL -> Src2CtrlEnum.RS, REGFILE_WRITE_VALID -> True, - BYPASSABLE_EXECUTE_STAGE -> Bool(pipeline.stages.last == pipeline.execute), - BYPASSABLE_MEMORY_STAGE -> Bool(pipeline.stages.last == pipeline.memory), + BYPASSABLE_EXECUTE_STAGE -> False, + BYPASSABLE_MEMORY_STAGE -> False, RS1_USE -> True, RS2_USE -> True, IS_MUL -> True @@ -66,16 +66,14 @@ class MulSimplePlugin extends Plugin[VexRiscv]{ insert(MUL_OPB) := ((bSigned ? b.msb | False) ## b).asSInt } - val injectionStage = if(pipeline.memory != null) pipeline.memory else pipeline.execute - injectionStage plug new Area { - import injectionStage._ + memory plug new Area { + import memory._ insert(MUL) := (input(MUL_OPA) * input(MUL_OPB))(63 downto 0).asBits } - val memStage = stages.last - memStage plug new Area { - import memStage._ + writeBack plug new Area { + import writeBack._ when(arbitration.isValid && input(IS_MUL)){ switch(input(INSTRUCTION)(13 downto 12)){ diff --git a/src/test/scala/vexriscv/TestIndividualFeatures.scala b/src/test/scala/vexriscv/TestIndividualFeatures.scala index 005f3359..33e4aa6e 100644 --- a/src/test/scala/vexriscv/TestIndividualFeatures.scala +++ b/src/test/scala/vexriscv/TestIndividualFeatures.scala @@ -99,35 +99,6 @@ class MulDivDimension extends VexRiscvDimension("MulDiv") { val noWriteBack = universes.contains(VexRiscvUniverse.NO_WRITEBACK) var l = List[VexRiscvPosition]() - - - - l = new VexRiscvPosition("MulDivFpgaSimple") { - override def testParam = "MUL=yes DIV=yes" - override def applyOn(config: VexRiscvConfig): Unit = { - config.plugins += new MulSimplePlugin - config.plugins += new MulDivIterativePlugin( - genMul = false, - genDiv = true, - mulUnrollFactor = 32, - divUnrollFactor = 1 - ) - } - } :: l - - if(!noMemory && !noWriteBack) l = new VexRiscvPosition("MulDivFpga16BitsDsp") { - override def testParam = "MUL=yes DIV=yes" - override def applyOn(config: VexRiscvConfig): Unit = { - config.plugins += new Mul16Plugin - config.plugins += new MulDivIterativePlugin( - genMul = false, - genDiv = true, - mulUnrollFactor = 32, - divUnrollFactor = 1 - ) - } - } :: l - if(!noMemory) { l = new VexRiscvPosition("MulDivAsic") { override def testParam = "MUL=yes DIV=yes" @@ -405,7 +376,7 @@ class DBusDimension extends VexRiscvDimension("DBus") { - if(r.nextDouble() < 0.4 || noMemory){ + if(r.nextDouble() < 0.4 || noMemory || noWriteBack){ val withLrSc = catchAll val earlyInjection = r.nextBoolean() && !universes.contains(VexRiscvUniverse.NO_WRITEBACK) new VexRiscvPosition("Simple" + (if(earlyInjection) "Early" else "Late")) { @@ -425,8 +396,7 @@ class DBusDimension extends VexRiscvDimension("DBus") { var wayCount = 0 val withLrSc = catchAll val withAmo = catchAll && r.nextBoolean() - val dBusRspSlavePipe, relaxedMemoryTranslationRegister = r.nextBoolean() - val earlyWaysHits = r.nextBoolean() && !noWriteBack + val dBusRspSlavePipe, relaxedMemoryTranslationRegister, earlyWaysHits = r.nextBoolean() val dBusCmdMasterPipe, dBusCmdSlavePipe = false //As it create test bench issues do{ @@ -630,11 +600,11 @@ class TestIndividualFeatures extends FunSuite { val testId : Option[mutable.HashSet[Int]] = None val seed = sys.env.getOrElse("VEXRISCV_REGRESSION_SEED", Random.nextLong().toString).toLong -// + // val testId = Some(mutable.HashSet(3,4,9,11,13,16,18,19,20,21)) -// val testId = Some(mutable.HashSet(11)) -// val testId = Some(mutable.HashSet(4, 11)) -// val seed = 6592877339343561798l +// val testId = Some(mutable.HashSet(24, 43, 49)) +// val testId = Some(mutable.HashSet(11)) +// val seed = -8309068850561113754l val rand = new Random(seed) @@ -652,16 +622,11 @@ class TestIndividualFeatures extends FunSuite { universe += VexRiscvUniverse.MMU universe += VexRiscvUniverse.FORCE_MULDIV universe += VexRiscvUniverse.SUPERVISOR - if(sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_DEMW_RATE", "0.6").toDouble < rand.nextDouble()){ - universe += VexRiscvUniverse.NO_WRITEBACK - } } else { if(sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_MACHINE_OS_RATE", "0.5").toDouble > rand.nextDouble()) { universe += VexRiscvUniverse.CATCH_ALL - if(sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_DEMW_RATE", "0.6").toDouble < rand.nextDouble()){ - universe += VexRiscvUniverse.NO_WRITEBACK - } } + var tmp = rand.nextDouble() if(sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_DEMW_RATE", "0.6").toDouble > rand.nextDouble()){ }else if(sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_DEM_RATE", "0.5").toDouble > rand.nextDouble()){ universe += VexRiscvUniverse.NO_WRITEBACK From 5b8febb977c1e7318109937b4b777ef9c0b8cc6b Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Wed, 29 Jan 2020 22:37:09 +0100 Subject: [PATCH 292/951] Revert "Revert "Merge branch 'master' into dev"" This reverts commit c01c2567578b18e4fec4466d6db3ce644b8eeede. Fix dBusCachedPlugin relaxedMemoryTranslationRegister when mmu translation is done in the execute stage --- README.md | 4 +- scripts/Murax/arty_a7/README.md | 129 ++++++ scripts/Murax/arty_a7/arty_a7.xdc | 366 ++++++++++++++++++ scripts/Murax/arty_a7/arty_a7_org.xdc | 350 +++++++++++++++++ scripts/Murax/arty_a7/make_bit_file.tcl | 50 +++ scripts/Murax/arty_a7/make_mcs_file | 6 + scripts/Murax/arty_a7/make_mcs_file.tcl | 31 ++ scripts/Murax/arty_a7/make_mmi_files | 4 + scripts/Murax/arty_a7/make_mmi_files.tcl | 6 + scripts/Murax/arty_a7/make_vivado_project | 9 + scripts/Murax/arty_a7/make_vivado_project.tcl | 46 +++ scripts/Murax/arty_a7/makefile | 62 +++ scripts/Murax/arty_a7/open_vivado_project | 4 + scripts/Murax/arty_a7/open_vivado_project.tcl | 4 + scripts/Murax/arty_a7/picocom_arty | 1 + scripts/Murax/arty_a7/soc_mmi.tcl | 151 ++++++++ scripts/Murax/arty_a7/toplevel.v | 66 ++++ scripts/Murax/arty_a7/vivado_params.tcl | 5 + scripts/Murax/arty_a7/write_flash | 3 + scripts/Murax/arty_a7/write_flash.tcl | 26 ++ scripts/Murax/arty_a7/write_fpga | 3 + scripts/Murax/arty_a7/write_fpga.tcl | 10 + .../iCE40-hx8k_breakout_board_xip/Makefile | 22 +- .../Murax_iCE40_hx8k_breakout_board_xip.pcf | 22 +- .../iCE40-hx8k_breakout_board_xip/README.md | 137 ++++++- src/main/c/murax/hello_world/makefile | 134 +++++++ src/main/c/murax/hello_world/src/crt.S | 98 +++++ src/main/c/murax/hello_world/src/gpio.h | 15 + src/main/c/murax/hello_world/src/interrupt.h | 17 + src/main/c/murax/hello_world/src/linker.ld | 110 ++++++ src/main/c/murax/hello_world/src/main.c | 42 ++ src/main/c/murax/hello_world/src/murax.h | 17 + src/main/c/murax/hello_world/src/prescaler.h | 16 + src/main/c/murax/hello_world/src/timer.h | 20 + src/main/c/murax/hello_world/src/uart.h | 42 ++ src/main/c/murax/xipBootloader/crt.S | 22 +- src/main/c/murax/xipBootloader/crt.bin | Bin 120 -> 192 bytes src/main/c/murax/xipBootloader/demo.S | 11 +- src/main/c/murax/xipBootloader/demo.bin | Bin 48 -> 0 bytes src/main/c/murax/xipBootloader/makefile | 22 +- src/main/c/murax/xipBootloader/mapping_rom.ld | 96 +++++ src/main/c/murax/xipBootloader/mapping_xip.ld | 96 +++++ src/main/scala/vexriscv/demo/Murax.scala | 92 ++--- src/main/scala/vexriscv/ip/DataCache.scala | 19 +- .../vexriscv/plugin/DBusCachedPlugin.scala | 38 +- .../vexriscv/plugin/HazardSimplePlugin.scala | 2 +- .../scala/vexriscv/plugin/Mul16Plugin.scala | 119 ++++++ .../plugin/MulDivIterativePlugin.scala | 26 +- .../vexriscv/plugin/MulSimplePlugin.scala | 14 +- .../vexriscv/TestIndividualFeatures.scala | 49 ++- 50 files changed, 2487 insertions(+), 147 deletions(-) create mode 100644 scripts/Murax/arty_a7/README.md create mode 100644 scripts/Murax/arty_a7/arty_a7.xdc create mode 100644 scripts/Murax/arty_a7/arty_a7_org.xdc create mode 100644 scripts/Murax/arty_a7/make_bit_file.tcl create mode 100755 scripts/Murax/arty_a7/make_mcs_file create mode 100644 scripts/Murax/arty_a7/make_mcs_file.tcl create mode 100755 scripts/Murax/arty_a7/make_mmi_files create mode 100644 scripts/Murax/arty_a7/make_mmi_files.tcl create mode 100755 scripts/Murax/arty_a7/make_vivado_project create mode 100644 scripts/Murax/arty_a7/make_vivado_project.tcl create mode 100644 scripts/Murax/arty_a7/makefile create mode 100755 scripts/Murax/arty_a7/open_vivado_project create mode 100644 scripts/Murax/arty_a7/open_vivado_project.tcl create mode 100644 scripts/Murax/arty_a7/picocom_arty create mode 100644 scripts/Murax/arty_a7/soc_mmi.tcl create mode 100644 scripts/Murax/arty_a7/toplevel.v create mode 100644 scripts/Murax/arty_a7/vivado_params.tcl create mode 100755 scripts/Murax/arty_a7/write_flash create mode 100644 scripts/Murax/arty_a7/write_flash.tcl create mode 100755 scripts/Murax/arty_a7/write_fpga create mode 100644 scripts/Murax/arty_a7/write_fpga.tcl create mode 100644 src/main/c/murax/hello_world/makefile create mode 100644 src/main/c/murax/hello_world/src/crt.S create mode 100644 src/main/c/murax/hello_world/src/gpio.h create mode 100644 src/main/c/murax/hello_world/src/interrupt.h create mode 100644 src/main/c/murax/hello_world/src/linker.ld create mode 100644 src/main/c/murax/hello_world/src/main.c create mode 100644 src/main/c/murax/hello_world/src/murax.h create mode 100644 src/main/c/murax/hello_world/src/prescaler.h create mode 100644 src/main/c/murax/hello_world/src/timer.h create mode 100644 src/main/c/murax/hello_world/src/uart.h delete mode 100755 src/main/c/murax/xipBootloader/demo.bin create mode 100644 src/main/c/murax/xipBootloader/mapping_rom.ld create mode 100644 src/main/c/murax/xipBootloader/mapping_xip.ld create mode 100644 src/main/scala/vexriscv/plugin/Mul16Plugin.scala diff --git a/README.md b/README.md index 2af47aa5..d0deb166 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,8 @@ - [Regression tests](#regression-tests) - [Interactive debug of the simulated CPU via GDB OpenOCD and Verilator](#interactive-debug-of-the-simulated-cpu-via-gdb-openocd-and-verilator) - [Using Eclipse to run the software and debug it](#using-Eclipse-to-run-the-software-and-debug-it) - * [By using Zylin plugin](#by-using-zylin-plugin) - * [By using FreedomStudio](#by-using-freedomstudio) + * [By using gnu-mcu-eclipse](#by-using-gnu-mcu-eclipse) + * [By using Zylin plugin (old)](#by-using-zylin-plugin-old) - [Briey SoC](#briey-soc) - [Murax SoC](#murax-soc) - [Running Linux](#running-linux) diff --git a/scripts/Murax/arty_a7/README.md b/scripts/Murax/arty_a7/README.md new file mode 100644 index 00000000..ad781f3f --- /dev/null +++ b/scripts/Murax/arty_a7/README.md @@ -0,0 +1,129 @@ +This example is for the Digilent ARTY A7 35T board. + +# Using the example + +## Before Starting + +You should make sure you have the following tools installed: + * vivado 2018.1 or later + * riscv toolchain (riscv64-unknown-elf) + * sbt + +## Board setup +Make sure you have a rev E board. If you have a later version check that the +flash part is S25FL128SAGMF100. + +Jumper settings for board rev E: + * Disconnect anything from the connectors (Pmod, Arduino) + * Jumpers: JP1 and JP2 on, others off. + +## Building + +You should be able to just type `make` and get output similar to this; +``` +... +Memory region Used Size Region Size %age Used + RAM: 896 B 2 KB 43.75% +... +--------------------------------------------------------------------------------- +Finished RTL Elaboration : Time (s): cpu = 00:00:08 ; elapsed = 00:00:09 . Memory (MB): peak = 1457.785 ; gain = 243.430 ; free physical = 17940 ; free virtual = 57159 +--------------------------------------------------------------------------------- +... +--------------------------------------------------------------------------------- +Finished Technology Mapping : Time (s): cpu = 00:02:42 ; elapsed = 00:02:58 . Memory (MB): peak = 1986.879 ; gain = 772.523 ; free physical = 17454 ; free virtual = 56670 +--------------------------------------------------------------------------------- +... +--------------------------------------------------------------------------------- +Finished Writing Synthesis Report : Time (s): cpu = 00:02:45 ; elapsed = 00:03:01 . Memory (MB): peak = 1986.879 ; gain = 772.523 ; free physical = 17457 ; free virtual = 56673 +--------------------------------------------------------------------------------- +... +Writing bitstream ./toplevel.bit... +... +mmi files generated +... +******************************************** + ./soc_latest_sw.bit correctly generated +******************************************** +... +******************************************** + ./soc_latest_sw.mcs correctly generated +******************************************** + +INFO: [Common 17-206] Exiting Vivado at Thu Nov 28 04:00:50 2019... +``` + +The process should take around 8 minutes on a reasonably fast computer. + +## Programming + +### Direct FPGA RAM programming + +Run `make prog` to program the bit file directly to FPGA RAM. + +You should get output like the following; +``` +... +****** Xilinx hw_server v2018.1 + **** Build date : Apr 4 2018-18:56:09 + ** Copyright 1986-2018 Xilinx, Inc. All Rights Reserved. + +INFO: [Labtoolstcl 44-466] Opening hw_target localhost:3121/xilinx_tcf/Digilent/210319AB569AA +INFO: [Labtools 27-1434] Device xc7a35t (JTAG device index = 0) is programmed with a design that has no supported debug core(s) in it. +WARNING: [Labtools 27-3361] The debug hub core was not detected. +Resolution: +1. Make sure the clock connected to the debug hub (dbg_hub) core is a free running clock and is active. +2. Make sure the BSCAN_SWITCH_USER_MASK device property in Vivado Hardware Manager reflects the user scan chain setting in the design and refresh the device. To determine the user scan chain setting in the design, open the implemented design and use 'get_property C_USER_SCAN_CHAIN [get_debug_cores dbg_hub]'. +For more details on setting the scan chain property, consult the Vivado Debug and Programming User Guide (UG908). +INFO: [Labtools 27-3164] End of startup status: HIGH +INFO: [Common 17-206] Exiting Vivado at Thu Nov 28 04:01:36 2019... +``` + +After programming the LED4~LED7 shall show some activity. + +### QSPI flash programming + +Run `make flash` to program the bit file to the QSPI flash. + +You should get output like the following; +``` +... +****** Xilinx hw_server v2018.1 + **** Build date : Apr 4 2018-18:56:09 + ** Copyright 1986-2018 Xilinx, Inc. All Rights Reserved. + + +INFO: [Labtoolstcl 44-466] Opening hw_target localhost:3121/xilinx_tcf/Digilent/210319AB569AA +INFO: [Labtools 27-1434] Device xc7a35t (JTAG device index = 0) is programmed with a design that has no supported debug core(s) in it. +... +INFO: [Labtools 27-3164] End of startup status: HIGH +Mfg ID : 1 Memory Type : 20 Memory Capacity : 18 Device ID 1 : 0 Device ID 2 : 0 +Performing Erase Operation... +Erase Operation successful. +Performing Program and Verify Operations... +Program/Verify Operation successful. +INFO: [Labtoolstcl 44-377] Flash programming completed successfully +program_hw_cfgmem: Time (s): cpu = 00:00:00.11 ; elapsed = 00:00:52 . Memory (MB): peak = 1792.711 ; gain = 8.000 ; free physical = 17712 ; free virtual = 56943 +INFO: [Labtoolstcl 44-464] Closing hw_target localhost:3121/xilinx_tcf/Digilent/210319AB569AA +... +INFO: [Common 17-206] Exiting Vivado at Thu Nov 28 04:06:28 2019... +``` + +After programming the flash you need to press the "PROG" button on the board. Then after a second or so the "DONE" LED shall be ON and LED4~LED7 shall show some activity. + + +## Connect + +After programming you should be able to connect to the serial port and have some output. + +On Linux you can do this using a command like `screen /dev/ttyUSB1`. Other good alternatives: + +* moserial (GUI) +* picocom (can be launched via the file "picocom_arty") + +Parameters: +* port is : /dev/ttyUSB1 +* flowcontrol : none +* baudrate is : 115200 +* parity is : none +* databits are : 8 +* stopbits are : 1 diff --git a/scripts/Murax/arty_a7/arty_a7.xdc b/scripts/Murax/arty_a7/arty_a7.xdc new file mode 100644 index 00000000..5ddd8fe1 --- /dev/null +++ b/scripts/Murax/arty_a7/arty_a7.xdc @@ -0,0 +1,366 @@ +set_property PACKAGE_PIN F4 [get_ports tck] +set_property IOSTANDARD LVCMOS33 [get_ports tck] + +set_property PACKAGE_PIN D2 [get_ports tms] +set_property IOSTANDARD LVCMOS33 [get_ports tms] + +set_property PACKAGE_PIN D4 [get_ports tdo] +set_property IOSTANDARD LVCMOS33 [get_ports tdo] +set_property PULLUP true [get_ports tdo] + +set_property PACKAGE_PIN E2 [get_ports tdi] +set_property IOSTANDARD LVCMOS33 [get_ports tdi] + +set_property PACKAGE_PIN D3 [get_ports trst] +set_property IOSTANDARD LVCMOS33 [get_ports trst] +set_property PULLUP true [get_ports trst] + + +## serial:0.tx +set_property PACKAGE_PIN D10 [get_ports serial_tx] +set_property IOSTANDARD LVCMOS33 [get_ports serial_tx] +## serial:0.rx +set_property PACKAGE_PIN A9 [get_ports serial_rx] +set_property IOSTANDARD LVCMOS33 [get_ports serial_rx] +## clk100:0 +set_property PACKAGE_PIN E3 [get_ports clk100] +set_property IOSTANDARD LVCMOS33 [get_ports clk100] +## cpu_reset:0 +set_property PACKAGE_PIN C2 [get_ports cpu_reset] +set_property IOSTANDARD LVCMOS33 [get_ports cpu_reset] +## eth_ref_clk:0 +#set_property LOC G18 [get_ports eth_ref_clk] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_ref_clk] +## user_led:0 +set_property PACKAGE_PIN H5 [get_ports user_led0] +set_property IOSTANDARD LVCMOS33 [get_ports user_led0] +## user_led:1 +set_property PACKAGE_PIN J5 [get_ports user_led1] +set_property IOSTANDARD LVCMOS33 [get_ports user_led1] +## user_led:2 +set_property PACKAGE_PIN T9 [get_ports user_led2] +set_property IOSTANDARD LVCMOS33 [get_ports user_led2] +## user_led:3 +set_property PACKAGE_PIN T10 [get_ports user_led3] +set_property IOSTANDARD LVCMOS33 [get_ports user_led3] +## user_sw:0 +set_property PACKAGE_PIN A8 [get_ports user_sw0] +set_property IOSTANDARD LVCMOS33 [get_ports user_sw0] +## user_sw:1 +set_property PACKAGE_PIN C11 [get_ports user_sw1] +set_property IOSTANDARD LVCMOS33 [get_ports user_sw1] +## user_sw:2 +set_property PACKAGE_PIN C10 [get_ports user_sw2] +set_property IOSTANDARD LVCMOS33 [get_ports user_sw2] +## user_sw:3 +set_property PACKAGE_PIN A10 [get_ports user_sw3] +set_property IOSTANDARD LVCMOS33 [get_ports user_sw3] +## user_btn:0 +set_property PACKAGE_PIN D9 [get_ports user_btn0] +set_property IOSTANDARD LVCMOS33 [get_ports user_btn0] +## user_btn:1 +set_property PACKAGE_PIN C9 [get_ports user_btn1] +set_property IOSTANDARD LVCMOS33 [get_ports user_btn1] +## user_btn:2 +set_property PACKAGE_PIN B9 [get_ports user_btn2] +set_property IOSTANDARD LVCMOS33 [get_ports user_btn2] +## user_btn:3 +set_property PACKAGE_PIN B8 [get_ports user_btn3] +set_property IOSTANDARD LVCMOS33 [get_ports user_btn3] +## spiflash_1x:0.cs_n +#set_property LOC L13 [get_ports spiflash_1x_cs_n] +#set_property IOSTANDARD LVCMOS33 [get_ports spiflash_1x_cs_n] +# ## spiflash_1x:0.mosi +#set_property LOC K17 [get_ports spiflash_1x_mosi] +#set_property IOSTANDARD LVCMOS33 [get_ports spiflash_1x_mosi] +# ## spiflash_1x:0.miso +#set_property LOC K18 [get_ports spiflash_1x_miso] +#set_property IOSTANDARD LVCMOS33 [get_ports spiflash_1x_miso] +# ## spiflash_1x:0.wp +#set_property LOC L14 [get_ports spiflash_1x_wp] +#set_property IOSTANDARD LVCMOS33 [get_ports spiflash_1x_wp] +# ## spiflash_1x:0.hold +#set_property LOC M14 [get_ports spiflash_1x_hold] +#set_property IOSTANDARD LVCMOS33 [get_ports spiflash_1x_hold] +# ## ddram:0.a +#set_property LOC R2 [get_ports ddram_a[0]] +#set_property SLEW FAST [get_ports ddram_a[0]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_a[0]] +# ## ddram:0.a +#set_property LOC M6 [get_ports ddram_a[1]] +#set_property SLEW FAST [get_ports ddram_a[1]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_a[1]] +# ## ddram:0.a +#set_property LOC N4 [get_ports ddram_a[2]] +#set_property SLEW FAST [get_ports ddram_a[2]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_a[2]] +# ## ddram:0.a +#set_property LOC T1 [get_ports ddram_a[3]] +#set_property SLEW FAST [get_ports ddram_a[3]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_a[3]] +# ## ddram:0.a +#set_property LOC N6 [get_ports ddram_a[4]] +#set_property SLEW FAST [get_ports ddram_a[4]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_a[4]] +# ## ddram:0.a +#set_property LOC R7 [get_ports ddram_a[5]] +#set_property SLEW FAST [get_ports ddram_a[5]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_a[5]] +# ## ddram:0.a +#set_property LOC V6 [get_ports ddram_a[6]] +#set_property SLEW FAST [get_ports ddram_a[6]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_a[6]] +# ## ddram:0.a +#set_property LOC U7 [get_ports ddram_a[7]] +#set_property SLEW FAST [get_ports ddram_a[7]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_a[7]] +# ## ddram:0.a +#set_property LOC R8 [get_ports ddram_a[8]] +#set_property SLEW FAST [get_ports ddram_a[8]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_a[8]] +# ## ddram:0.a +#set_property LOC V7 [get_ports ddram_a[9]] +#set_property SLEW FAST [get_ports ddram_a[9]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_a[9]] +# ## ddram:0.a +#set_property LOC R6 [get_ports ddram_a[10]] +#set_property SLEW FAST [get_ports ddram_a[10]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_a[10]] +# ## ddram:0.a +#set_property LOC U6 [get_ports ddram_a[11]] +#set_property SLEW FAST [get_ports ddram_a[11]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_a[11]] +# ## ddram:0.a +#set_property LOC T6 [get_ports ddram_a[12]] +#set_property SLEW FAST [get_ports ddram_a[12]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_a[12]] +# ## ddram:0.a +#set_property LOC T8 [get_ports ddram_a[13]] +#set_property SLEW FAST [get_ports ddram_a[13]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_a[13]] +# ## ddram:0.ba +#set_property LOC R1 [get_ports ddram_ba[0]] +#set_property SLEW FAST [get_ports ddram_ba[0]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_ba[0]] +# ## ddram:0.ba +#set_property LOC P4 [get_ports ddram_ba[1]] +#set_property SLEW FAST [get_ports ddram_ba[1]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_ba[1]] +# ## ddram:0.ba +#set_property LOC P2 [get_ports ddram_ba[2]] +#set_property SLEW FAST [get_ports ddram_ba[2]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_ba[2]] +# ## ddram:0.ras_n +#set_property LOC P3 [get_ports ddram_ras_n] +#set_property SLEW FAST [get_ports ddram_ras_n] +#set_property IOSTANDARD SSTL15 [get_ports ddram_ras_n] +# ## ddram:0.cas_n +#set_property LOC M4 [get_ports ddram_cas_n] +#set_property SLEW FAST [get_ports ddram_cas_n] +#set_property IOSTANDARD SSTL15 [get_ports ddram_cas_n] +# ## ddram:0.we_n +#set_property LOC P5 [get_ports ddram_we_n] +#set_property SLEW FAST [get_ports ddram_we_n] +#set_property IOSTANDARD SSTL15 [get_ports ddram_we_n] +# ## ddram:0.cs_n +#set_property LOC U8 [get_ports ddram_cs_n] +#set_property SLEW FAST [get_ports ddram_cs_n] +#set_property IOSTANDARD SSTL15 [get_ports ddram_cs_n] +# ## ddram:0.dm +#set_property LOC L1 [get_ports ddram_dm[0]] +#set_property SLEW FAST [get_ports ddram_dm[0]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dm[0]] +# ## ddram:0.dm +#set_property LOC U1 [get_ports ddram_dm[1]] +#set_property SLEW FAST [get_ports ddram_dm[1]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dm[1]] +# ## ddram:0.dq +#set_property LOC K5 [get_ports ddram_dq[0]] +#set_property SLEW FAST [get_ports ddram_dq[0]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[0]] +#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[0]] +# ## ddram:0.dq +#set_property LOC L3 [get_ports ddram_dq[1]] +#set_property SLEW FAST [get_ports ddram_dq[1]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[1]] +#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[1]] +# ## ddram:0.dq +#set_property LOC K3 [get_ports ddram_dq[2]] +#set_property SLEW FAST [get_ports ddram_dq[2]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[2]] +#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[2]] +# ## ddram:0.dq +#set_property LOC L6 [get_ports ddram_dq[3]] +#set_property SLEW FAST [get_ports ddram_dq[3]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[3]] +#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[3]] +# ## ddram:0.dq +#set_property LOC M3 [get_ports ddram_dq[4]] +#set_property SLEW FAST [get_ports ddram_dq[4]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[4]] +#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[4]] +# ## ddram:0.dq +#set_property LOC M1 [get_ports ddram_dq[5]] +#set_property SLEW FAST [get_ports ddram_dq[5]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[5]] +#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[5]] +# ## ddram:0.dq +#set_property LOC L4 [get_ports ddram_dq[6]] +#set_property SLEW FAST [get_ports ddram_dq[6]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[6]] +#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[6]] +# ## ddram:0.dq +#set_property LOC M2 [get_ports ddram_dq[7]] +#set_property SLEW FAST [get_ports ddram_dq[7]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[7]] +#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[7]] +# ## ddram:0.dq +#set_property LOC V4 [get_ports ddram_dq[8]] +#set_property SLEW FAST [get_ports ddram_dq[8]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[8]] +#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[8]] +# ## ddram:0.dq +#set_property LOC T5 [get_ports ddram_dq[9]] +#set_property SLEW FAST [get_ports ddram_dq[9]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[9]] +#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[9]] +# ## ddram:0.dq +#set_property LOC U4 [get_ports ddram_dq[10]] +#set_property SLEW FAST [get_ports ddram_dq[10]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[10]] +#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[10]] +# ## ddram:0.dq +#set_property LOC V5 [get_ports ddram_dq[11]] +#set_property SLEW FAST [get_ports ddram_dq[11]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[11]] +#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[11]] +# ## ddram:0.dq +#set_property LOC V1 [get_ports ddram_dq[12]] +#set_property SLEW FAST [get_ports ddram_dq[12]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[12]] +#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[12]] +# ## ddram:0.dq +#set_property LOC T3 [get_ports ddram_dq[13]] +#set_property SLEW FAST [get_ports ddram_dq[13]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[13]] +#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[13]] +# ## ddram:0.dq +#set_property LOC U3 [get_ports ddram_dq[14]] +#set_property SLEW FAST [get_ports ddram_dq[14]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[14]] +#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[14]] +# ## ddram:0.dq +#set_property LOC R3 [get_ports ddram_dq[15]] +#set_property SLEW FAST [get_ports ddram_dq[15]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[15]] +#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[15]] +# ## ddram:0.dqs_p +#set_property LOC N2 [get_ports ddram_dqs_p[0]] +#set_property SLEW FAST [get_ports ddram_dqs_p[0]] +#set_property IOSTANDARD DIFF_SSTL15 [get_ports ddram_dqs_p[0]] +# ## ddram:0.dqs_p +#set_property LOC U2 [get_ports ddram_dqs_p[1]] +#set_property SLEW FAST [get_ports ddram_dqs_p[1]] +#set_property IOSTANDARD DIFF_SSTL15 [get_ports ddram_dqs_p[1]] +# ## ddram:0.dqs_n +#set_property LOC N1 [get_ports ddram_dqs_n[0]] +#set_property SLEW FAST [get_ports ddram_dqs_n[0]] +#set_property IOSTANDARD DIFF_SSTL15 [get_ports ddram_dqs_n[0]] +# ## ddram:0.dqs_n +#set_property LOC V2 [get_ports ddram_dqs_n[1]] +#set_property SLEW FAST [get_ports ddram_dqs_n[1]] +#set_property IOSTANDARD DIFF_SSTL15 [get_ports ddram_dqs_n[1]] +# ## ddram:0.clk_p +#set_property LOC U9 [get_ports ddram_clk_p] +#set_property SLEW FAST [get_ports ddram_clk_p] +#set_property IOSTANDARD DIFF_SSTL15 [get_ports ddram_clk_p] +# ## ddram:0.clk_n +#set_property LOC V9 [get_ports ddram_clk_n] +#set_property SLEW FAST [get_ports ddram_clk_n] +#set_property IOSTANDARD DIFF_SSTL15 [get_ports ddram_clk_n] +# ## ddram:0.cke +#set_property LOC N5 [get_ports ddram_cke] +#set_property SLEW FAST [get_ports ddram_cke] +#set_property IOSTANDARD SSTL15 [get_ports ddram_cke] +# ## ddram:0.odt +#set_property LOC R5 [get_ports ddram_odt] +#set_property SLEW FAST [get_ports ddram_odt] +#set_property IOSTANDARD SSTL15 [get_ports ddram_odt] +# ## ddram:0.reset_n +#set_property LOC K6 [get_ports ddram_reset_n] +#set_property SLEW FAST [get_ports ddram_reset_n] +#set_property IOSTANDARD SSTL15 [get_ports ddram_reset_n] +# ## eth_clocks:0.tx +#set_property LOC H16 [get_ports eth_clocks_tx] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_clocks_tx] +# ## eth_clocks:0.rx +#set_property LOC F15 [get_ports eth_clocks_rx] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_clocks_rx] +# ## eth:0.rst_n +#set_property LOC C16 [get_ports eth_rst_n] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_rst_n] +# ## eth:0.mdio +#set_property LOC K13 [get_ports eth_mdio] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_mdio] +# ## eth:0.mdc +#set_property LOC F16 [get_ports eth_mdc] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_mdc] +# ## eth:0.rx_dv +#set_property LOC G16 [get_ports eth_rx_dv] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_rx_dv] +# ## eth:0.rx_er +#set_property LOC C17 [get_ports eth_rx_er] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_rx_er] +# ## eth:0.rx_data +#set_property LOC D18 [get_ports eth_rx_data[0]] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_rx_data[0]] +# ## eth:0.rx_data +#set_property LOC E17 [get_ports eth_rx_data[1]] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_rx_data[1]] +# ## eth:0.rx_data +#set_property LOC E18 [get_ports eth_rx_data[2]] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_rx_data[2]] +# ## eth:0.rx_data +#set_property LOC G17 [get_ports eth_rx_data[3]] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_rx_data[3]] +# ## eth:0.tx_en +#set_property LOC H15 [get_ports eth_tx_en] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_tx_en] +# ## eth:0.tx_data +#set_property LOC H14 [get_ports eth_tx_data[0]] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_tx_data[0]] +# ## eth:0.tx_data +#set_property LOC J14 [get_ports eth_tx_data[1]] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_tx_data[1]] +# ## eth:0.tx_data +#set_property LOC J13 [get_ports eth_tx_data[2]] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_tx_data[2]] +# ## eth:0.tx_data +#set_property LOC H17 [get_ports eth_tx_data[3]] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_tx_data[3]] +# ## eth:0.col +#set_property LOC D17 [get_ports eth_col] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_col] +# ## eth:0.crs +#set_property LOC G14 [get_ports eth_crs] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_crs] + +set_property INTERNAL_VREF 0.75 [get_iobanks 34] + + +create_clock -period 10.000 -name clk100 [get_nets clk100] + +#create_clock -name eth_rx_clk -period 40.0 [get_nets eth_rx_clk] + +#create_clock -name eth_tx_clk -period 40.0 [get_nets eth_tx_clk] + +#set_clock_groups -group [get_clocks -include_generated_clocks -of [get_nets sys_clk]] -group [get_clocks -include_generated_clocks -of [get_nets eth_rx_clk]] -asynchronous + +#set_clock_groups -group [get_clocks -include_generated_clocks -of [get_nets sys_clk]] -group [get_clocks -include_generated_clocks -of [get_nets eth_tx_clk]] -asynchronous + +#set_clock_groups -group [get_clocks -include_generated_clocks -of [get_nets eth_rx_clk]] -group [get_clocks -include_generated_clocks -of [get_nets eth_tx_clk]] -asynchronous + + + + +set_property BITSTREAM.CONFIG.SPI_BUSWIDTH 4 [current_design] diff --git a/scripts/Murax/arty_a7/arty_a7_org.xdc b/scripts/Murax/arty_a7/arty_a7_org.xdc new file mode 100644 index 00000000..75c81b14 --- /dev/null +++ b/scripts/Murax/arty_a7/arty_a7_org.xdc @@ -0,0 +1,350 @@ + ## serial:0.tx +set_property LOC D10 [get_ports serial_tx] +set_property IOSTANDARD LVCMOS33 [get_ports serial_tx] + ## serial:0.rx +set_property LOC A9 [get_ports serial_rx] +set_property IOSTANDARD LVCMOS33 [get_ports serial_rx] + ## clk100:0 +set_property LOC E3 [get_ports clk100] +set_property IOSTANDARD LVCMOS33 [get_ports clk100] + ## cpu_reset:0 +set_property LOC C2 [get_ports cpu_reset] +set_property IOSTANDARD LVCMOS33 [get_ports cpu_reset] + ## eth_ref_clk:0 +#set_property LOC G18 [get_ports eth_ref_clk] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_ref_clk] + ## user_led:0 +set_property LOC H5 [get_ports user_led0] +set_property IOSTANDARD LVCMOS33 [get_ports user_led0] + ## user_led:1 +set_property LOC J5 [get_ports user_led1] +set_property IOSTANDARD LVCMOS33 [get_ports user_led1] + ## user_led:2 +set_property LOC T9 [get_ports user_led2] +set_property IOSTANDARD LVCMOS33 [get_ports user_led2] + ## user_led:3 +set_property LOC T10 [get_ports user_led3] +set_property IOSTANDARD LVCMOS33 [get_ports user_led3] + ## user_sw:0 +set_property LOC A8 [get_ports user_sw0] +set_property IOSTANDARD LVCMOS33 [get_ports user_sw0] + ## user_sw:1 +set_property LOC C11 [get_ports user_sw1] +set_property IOSTANDARD LVCMOS33 [get_ports user_sw1] + ## user_sw:2 +set_property LOC C10 [get_ports user_sw2] +set_property IOSTANDARD LVCMOS33 [get_ports user_sw2] + ## user_sw:3 +set_property LOC A10 [get_ports user_sw3] +set_property IOSTANDARD LVCMOS33 [get_ports user_sw3] + ## user_btn:0 +set_property LOC D9 [get_ports user_btn0] +set_property IOSTANDARD LVCMOS33 [get_ports user_btn0] + ## user_btn:1 +set_property LOC C9 [get_ports user_btn1] +set_property IOSTANDARD LVCMOS33 [get_ports user_btn1] + ## user_btn:2 +set_property LOC B9 [get_ports user_btn2] +set_property IOSTANDARD LVCMOS33 [get_ports user_btn2] + ## user_btn:3 +set_property LOC B8 [get_ports user_btn3] +set_property IOSTANDARD LVCMOS33 [get_ports user_btn3] + ## spiflash_1x:0.cs_n +#set_property LOC L13 [get_ports spiflash_1x_cs_n] +#set_property IOSTANDARD LVCMOS33 [get_ports spiflash_1x_cs_n] +# ## spiflash_1x:0.mosi +#set_property LOC K17 [get_ports spiflash_1x_mosi] +#set_property IOSTANDARD LVCMOS33 [get_ports spiflash_1x_mosi] +# ## spiflash_1x:0.miso +#set_property LOC K18 [get_ports spiflash_1x_miso] +#set_property IOSTANDARD LVCMOS33 [get_ports spiflash_1x_miso] +# ## spiflash_1x:0.wp +#set_property LOC L14 [get_ports spiflash_1x_wp] +#set_property IOSTANDARD LVCMOS33 [get_ports spiflash_1x_wp] +# ## spiflash_1x:0.hold +#set_property LOC M14 [get_ports spiflash_1x_hold] +#set_property IOSTANDARD LVCMOS33 [get_ports spiflash_1x_hold] +# ## ddram:0.a +#set_property LOC R2 [get_ports ddram_a[0]] +#set_property SLEW FAST [get_ports ddram_a[0]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_a[0]] +# ## ddram:0.a +#set_property LOC M6 [get_ports ddram_a[1]] +#set_property SLEW FAST [get_ports ddram_a[1]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_a[1]] +# ## ddram:0.a +#set_property LOC N4 [get_ports ddram_a[2]] +#set_property SLEW FAST [get_ports ddram_a[2]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_a[2]] +# ## ddram:0.a +#set_property LOC T1 [get_ports ddram_a[3]] +#set_property SLEW FAST [get_ports ddram_a[3]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_a[3]] +# ## ddram:0.a +#set_property LOC N6 [get_ports ddram_a[4]] +#set_property SLEW FAST [get_ports ddram_a[4]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_a[4]] +# ## ddram:0.a +#set_property LOC R7 [get_ports ddram_a[5]] +#set_property SLEW FAST [get_ports ddram_a[5]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_a[5]] +# ## ddram:0.a +#set_property LOC V6 [get_ports ddram_a[6]] +#set_property SLEW FAST [get_ports ddram_a[6]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_a[6]] +# ## ddram:0.a +#set_property LOC U7 [get_ports ddram_a[7]] +#set_property SLEW FAST [get_ports ddram_a[7]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_a[7]] +# ## ddram:0.a +#set_property LOC R8 [get_ports ddram_a[8]] +#set_property SLEW FAST [get_ports ddram_a[8]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_a[8]] +# ## ddram:0.a +#set_property LOC V7 [get_ports ddram_a[9]] +#set_property SLEW FAST [get_ports ddram_a[9]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_a[9]] +# ## ddram:0.a +#set_property LOC R6 [get_ports ddram_a[10]] +#set_property SLEW FAST [get_ports ddram_a[10]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_a[10]] +# ## ddram:0.a +#set_property LOC U6 [get_ports ddram_a[11]] +#set_property SLEW FAST [get_ports ddram_a[11]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_a[11]] +# ## ddram:0.a +#set_property LOC T6 [get_ports ddram_a[12]] +#set_property SLEW FAST [get_ports ddram_a[12]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_a[12]] +# ## ddram:0.a +#set_property LOC T8 [get_ports ddram_a[13]] +#set_property SLEW FAST [get_ports ddram_a[13]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_a[13]] +# ## ddram:0.ba +#set_property LOC R1 [get_ports ddram_ba[0]] +#set_property SLEW FAST [get_ports ddram_ba[0]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_ba[0]] +# ## ddram:0.ba +#set_property LOC P4 [get_ports ddram_ba[1]] +#set_property SLEW FAST [get_ports ddram_ba[1]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_ba[1]] +# ## ddram:0.ba +#set_property LOC P2 [get_ports ddram_ba[2]] +#set_property SLEW FAST [get_ports ddram_ba[2]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_ba[2]] +# ## ddram:0.ras_n +#set_property LOC P3 [get_ports ddram_ras_n] +#set_property SLEW FAST [get_ports ddram_ras_n] +#set_property IOSTANDARD SSTL15 [get_ports ddram_ras_n] +# ## ddram:0.cas_n +#set_property LOC M4 [get_ports ddram_cas_n] +#set_property SLEW FAST [get_ports ddram_cas_n] +#set_property IOSTANDARD SSTL15 [get_ports ddram_cas_n] +# ## ddram:0.we_n +#set_property LOC P5 [get_ports ddram_we_n] +#set_property SLEW FAST [get_ports ddram_we_n] +#set_property IOSTANDARD SSTL15 [get_ports ddram_we_n] +# ## ddram:0.cs_n +#set_property LOC U8 [get_ports ddram_cs_n] +#set_property SLEW FAST [get_ports ddram_cs_n] +#set_property IOSTANDARD SSTL15 [get_ports ddram_cs_n] +# ## ddram:0.dm +#set_property LOC L1 [get_ports ddram_dm[0]] +#set_property SLEW FAST [get_ports ddram_dm[0]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dm[0]] +# ## ddram:0.dm +#set_property LOC U1 [get_ports ddram_dm[1]] +#set_property SLEW FAST [get_ports ddram_dm[1]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dm[1]] +# ## ddram:0.dq +#set_property LOC K5 [get_ports ddram_dq[0]] +#set_property SLEW FAST [get_ports ddram_dq[0]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[0]] +#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[0]] +# ## ddram:0.dq +#set_property LOC L3 [get_ports ddram_dq[1]] +#set_property SLEW FAST [get_ports ddram_dq[1]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[1]] +#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[1]] +# ## ddram:0.dq +#set_property LOC K3 [get_ports ddram_dq[2]] +#set_property SLEW FAST [get_ports ddram_dq[2]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[2]] +#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[2]] +# ## ddram:0.dq +#set_property LOC L6 [get_ports ddram_dq[3]] +#set_property SLEW FAST [get_ports ddram_dq[3]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[3]] +#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[3]] +# ## ddram:0.dq +#set_property LOC M3 [get_ports ddram_dq[4]] +#set_property SLEW FAST [get_ports ddram_dq[4]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[4]] +#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[4]] +# ## ddram:0.dq +#set_property LOC M1 [get_ports ddram_dq[5]] +#set_property SLEW FAST [get_ports ddram_dq[5]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[5]] +#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[5]] +# ## ddram:0.dq +#set_property LOC L4 [get_ports ddram_dq[6]] +#set_property SLEW FAST [get_ports ddram_dq[6]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[6]] +#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[6]] +# ## ddram:0.dq +#set_property LOC M2 [get_ports ddram_dq[7]] +#set_property SLEW FAST [get_ports ddram_dq[7]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[7]] +#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[7]] +# ## ddram:0.dq +#set_property LOC V4 [get_ports ddram_dq[8]] +#set_property SLEW FAST [get_ports ddram_dq[8]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[8]] +#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[8]] +# ## ddram:0.dq +#set_property LOC T5 [get_ports ddram_dq[9]] +#set_property SLEW FAST [get_ports ddram_dq[9]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[9]] +#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[9]] +# ## ddram:0.dq +#set_property LOC U4 [get_ports ddram_dq[10]] +#set_property SLEW FAST [get_ports ddram_dq[10]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[10]] +#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[10]] +# ## ddram:0.dq +#set_property LOC V5 [get_ports ddram_dq[11]] +#set_property SLEW FAST [get_ports ddram_dq[11]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[11]] +#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[11]] +# ## ddram:0.dq +#set_property LOC V1 [get_ports ddram_dq[12]] +#set_property SLEW FAST [get_ports ddram_dq[12]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[12]] +#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[12]] +# ## ddram:0.dq +#set_property LOC T3 [get_ports ddram_dq[13]] +#set_property SLEW FAST [get_ports ddram_dq[13]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[13]] +#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[13]] +# ## ddram:0.dq +#set_property LOC U3 [get_ports ddram_dq[14]] +#set_property SLEW FAST [get_ports ddram_dq[14]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[14]] +#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[14]] +# ## ddram:0.dq +#set_property LOC R3 [get_ports ddram_dq[15]] +#set_property SLEW FAST [get_ports ddram_dq[15]] +#set_property IOSTANDARD SSTL15 [get_ports ddram_dq[15]] +#set_property IN_TERM UNTUNED_SPLIT_40 [get_ports ddram_dq[15]] +# ## ddram:0.dqs_p +#set_property LOC N2 [get_ports ddram_dqs_p[0]] +#set_property SLEW FAST [get_ports ddram_dqs_p[0]] +#set_property IOSTANDARD DIFF_SSTL15 [get_ports ddram_dqs_p[0]] +# ## ddram:0.dqs_p +#set_property LOC U2 [get_ports ddram_dqs_p[1]] +#set_property SLEW FAST [get_ports ddram_dqs_p[1]] +#set_property IOSTANDARD DIFF_SSTL15 [get_ports ddram_dqs_p[1]] +# ## ddram:0.dqs_n +#set_property LOC N1 [get_ports ddram_dqs_n[0]] +#set_property SLEW FAST [get_ports ddram_dqs_n[0]] +#set_property IOSTANDARD DIFF_SSTL15 [get_ports ddram_dqs_n[0]] +# ## ddram:0.dqs_n +#set_property LOC V2 [get_ports ddram_dqs_n[1]] +#set_property SLEW FAST [get_ports ddram_dqs_n[1]] +#set_property IOSTANDARD DIFF_SSTL15 [get_ports ddram_dqs_n[1]] +# ## ddram:0.clk_p +#set_property LOC U9 [get_ports ddram_clk_p] +#set_property SLEW FAST [get_ports ddram_clk_p] +#set_property IOSTANDARD DIFF_SSTL15 [get_ports ddram_clk_p] +# ## ddram:0.clk_n +#set_property LOC V9 [get_ports ddram_clk_n] +#set_property SLEW FAST [get_ports ddram_clk_n] +#set_property IOSTANDARD DIFF_SSTL15 [get_ports ddram_clk_n] +# ## ddram:0.cke +#set_property LOC N5 [get_ports ddram_cke] +#set_property SLEW FAST [get_ports ddram_cke] +#set_property IOSTANDARD SSTL15 [get_ports ddram_cke] +# ## ddram:0.odt +#set_property LOC R5 [get_ports ddram_odt] +#set_property SLEW FAST [get_ports ddram_odt] +#set_property IOSTANDARD SSTL15 [get_ports ddram_odt] +# ## ddram:0.reset_n +#set_property LOC K6 [get_ports ddram_reset_n] +#set_property SLEW FAST [get_ports ddram_reset_n] +#set_property IOSTANDARD SSTL15 [get_ports ddram_reset_n] +# ## eth_clocks:0.tx +#set_property LOC H16 [get_ports eth_clocks_tx] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_clocks_tx] +# ## eth_clocks:0.rx +#set_property LOC F15 [get_ports eth_clocks_rx] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_clocks_rx] +# ## eth:0.rst_n +#set_property LOC C16 [get_ports eth_rst_n] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_rst_n] +# ## eth:0.mdio +#set_property LOC K13 [get_ports eth_mdio] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_mdio] +# ## eth:0.mdc +#set_property LOC F16 [get_ports eth_mdc] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_mdc] +# ## eth:0.rx_dv +#set_property LOC G16 [get_ports eth_rx_dv] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_rx_dv] +# ## eth:0.rx_er +#set_property LOC C17 [get_ports eth_rx_er] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_rx_er] +# ## eth:0.rx_data +#set_property LOC D18 [get_ports eth_rx_data[0]] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_rx_data[0]] +# ## eth:0.rx_data +#set_property LOC E17 [get_ports eth_rx_data[1]] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_rx_data[1]] +# ## eth:0.rx_data +#set_property LOC E18 [get_ports eth_rx_data[2]] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_rx_data[2]] +# ## eth:0.rx_data +#set_property LOC G17 [get_ports eth_rx_data[3]] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_rx_data[3]] +# ## eth:0.tx_en +#set_property LOC H15 [get_ports eth_tx_en] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_tx_en] +# ## eth:0.tx_data +#set_property LOC H14 [get_ports eth_tx_data[0]] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_tx_data[0]] +# ## eth:0.tx_data +#set_property LOC J14 [get_ports eth_tx_data[1]] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_tx_data[1]] +# ## eth:0.tx_data +#set_property LOC J13 [get_ports eth_tx_data[2]] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_tx_data[2]] +# ## eth:0.tx_data +#set_property LOC H17 [get_ports eth_tx_data[3]] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_tx_data[3]] +# ## eth:0.col +#set_property LOC D17 [get_ports eth_col] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_col] +# ## eth:0.crs +#set_property LOC G14 [get_ports eth_crs] +#set_property IOSTANDARD LVCMOS33 [get_ports eth_crs] + +set_property INTERNAL_VREF 0.750 [get_iobanks 34] + +create_clock -name sys_clk -period 10.0 [get_nets sys_clk] + +create_clock -name clk100 -period 10.0 [get_nets clk100] + +#create_clock -name eth_rx_clk -period 40.0 [get_nets eth_rx_clk] + +#create_clock -name eth_tx_clk -period 40.0 [get_nets eth_tx_clk] + +#set_clock_groups -group [get_clocks -include_generated_clocks -of [get_nets sys_clk]] -group [get_clocks -include_generated_clocks -of [get_nets eth_rx_clk]] -asynchronous + +#set_clock_groups -group [get_clocks -include_generated_clocks -of [get_nets sys_clk]] -group [get_clocks -include_generated_clocks -of [get_nets eth_tx_clk]] -asynchronous + +#set_clock_groups -group [get_clocks -include_generated_clocks -of [get_nets eth_rx_clk]] -group [get_clocks -include_generated_clocks -of [get_nets eth_tx_clk]] -asynchronous + +set_false_path -quiet -to [get_nets -quiet -filter {mr_ff == TRUE}] + +set_false_path -quiet -to [get_pins -quiet -filter {REF_PIN_NAME == PRE} -of [get_cells -quiet -filter {ars_ff1 == TRUE || ars_ff2 == TRUE}]] + +set_max_delay 2 -quiet -from [get_pins -quiet -filter {REF_PIN_NAME == Q} -of [get_cells -quiet -filter {ars_ff1 == TRUE}]] -to [get_pins -quiet -filter {REF_PIN_NAME == D} -of [get_cells -quiet -filter {ars_ff2 == TRUE}]] diff --git a/scripts/Murax/arty_a7/make_bit_file.tcl b/scripts/Murax/arty_a7/make_bit_file.tcl new file mode 100644 index 00000000..a97b399f --- /dev/null +++ b/scripts/Murax/arty_a7/make_bit_file.tcl @@ -0,0 +1,50 @@ + +# Input files +set mmi_file "./soc.mmi" +set elf_file "./soc.elf" +set source_bit_file "./soc.bit" + +# Output files +set output_bit_file "./soc_latest_sw.bit" + +# Enable to turn on debug +set updatemem_debug 0 + +# Assemble bit file that can be downloaded to device directly +# Combine the original bit file, mmi file, and software elf to create the full bitstream + +# Delete target file +file delete -force $output_bit_file + +# Determine if the user has built the project and has the target source file +# If not, then use the reference bit file shipped with the project +if { ![file exists $source_bit_file] } { + puts "\n********************************************" + puts "INFO - File $source_bit_file doesn't exist as project has not been built" + puts " Using $reference_bit_file instead\n" + puts "********************************************/n" + set source_bit_file $reference_bit_file +} + +# Banner message to console as there is no output for a few seconds +puts " Running updatemem ..." + +if { $updatemem_debug } { + set error [catch {exec updatemem --debug --force --meminfo $mmi_file --data $elf_file --bit $source_bit_file --proc dummy --out $output_bit_file} result] +} else { + set error [catch {exec updatemem --force --meminfo $mmi_file --data $elf_file --bit $source_bit_file --proc dummy --out $output_bit_file} result] +} + +# Print the stdout from updatemem +puts $result + +# Updatemem returns 0 even when there is an error, so cannot trap on error. Having deleted output file to start, then +# detect if it now exists, else exit. +if { ![file exists $output_bit_file] } { + puts "ERROR - $output_bit_file not made" + return -1 +} else { + puts "\n********************************************" + puts " $output_bit_file correctly generated" + puts "********************************************\n" +} diff --git a/scripts/Murax/arty_a7/make_mcs_file b/scripts/Murax/arty_a7/make_mcs_file new file mode 100755 index 00000000..40bcc5ac --- /dev/null +++ b/scripts/Murax/arty_a7/make_mcs_file @@ -0,0 +1,6 @@ +#!/bin/sh +#Create mcs file for QSPI flash + +cd ./build + +vivado -mode batch -source ../make_mcs_file.tcl -notrace diff --git a/scripts/Murax/arty_a7/make_mcs_file.tcl b/scripts/Murax/arty_a7/make_mcs_file.tcl new file mode 100644 index 00000000..9863a2ca --- /dev/null +++ b/scripts/Murax/arty_a7/make_mcs_file.tcl @@ -0,0 +1,31 @@ + +# Input file +set source_bit_file "./latest.bit" + +# Output file +set output_mcs_file "./latest.mcs" + +# Delete target file +file delete -force $output_mcs_file + +# Determine if the user has built the project and has the target source file +# If not, then use the reference bit file shipped with the project +if { ![file exists $source_bit_file] } { + puts "\n********************************************" + puts "INFO - File $source_bit_file doesn't exist as project has not been built\n" + puts "********************************************/n" + error +} + +# Create MCS file for base board QSPI flash memory +write_cfgmem -force -format MCS -size 16 -interface SPIx4 -loadbit " up 0 $source_bit_file" $output_mcs_file + +# Check MCS was correctly made +if { ![file exists $output_mcs_file] } { + puts "ERROR - $output_bit_file not made" + return -1 +} else { + puts "\n********************************************" + puts " $output_mcs_file correctly generated" + puts "********************************************\n" +} diff --git a/scripts/Murax/arty_a7/make_mmi_files b/scripts/Murax/arty_a7/make_mmi_files new file mode 100755 index 00000000..3919e16a --- /dev/null +++ b/scripts/Murax/arty_a7/make_mmi_files @@ -0,0 +1,4 @@ +#!/bin/sh + +cd ./build +vivado -mode batch -source ../make_mmi_files.tcl -notrace diff --git a/scripts/Murax/arty_a7/make_mmi_files.tcl b/scripts/Murax/arty_a7/make_mmi_files.tcl new file mode 100644 index 00000000..d9ecd484 --- /dev/null +++ b/scripts/Murax/arty_a7/make_mmi_files.tcl @@ -0,0 +1,6 @@ +source [file join [file dirname [file normalize [info script]]] vivado_params.tcl] + +open_project -read_only $outputdir/$projectName +open_run impl_1 +source $base/soc_mmi.tcl +puts "mmi files generated" diff --git a/scripts/Murax/arty_a7/make_vivado_project b/scripts/Murax/arty_a7/make_vivado_project new file mode 100755 index 00000000..4a925107 --- /dev/null +++ b/scripts/Murax/arty_a7/make_vivado_project @@ -0,0 +1,9 @@ +#!/bin/sh + +#cannot rm build because it erase software images that the make file copy there +#rm -rf ./build + +mkdir ./build + +cd ./build +vivado -mode batch -source ../make_vivado_project.tcl -notrace diff --git a/scripts/Murax/arty_a7/make_vivado_project.tcl b/scripts/Murax/arty_a7/make_vivado_project.tcl new file mode 100644 index 00000000..b206ddbb --- /dev/null +++ b/scripts/Murax/arty_a7/make_vivado_project.tcl @@ -0,0 +1,46 @@ +#Create output directory and clear contents +source [file join [file dirname [file normalize [info script]]] vivado_params.tcl] + +file mkdir $outputdir +set files [glob -nocomplain "$outputdir/*"] +if {[llength $files] != 0} { + puts "deleting contents of $outputdir" + file delete -force {*}[glob -directory $outputdir *]; # clear folder contents +} else { + puts "$outputdir is empty" +} + +#Create project +create_project -part $part $projectName $outputdir + +#add source files to Vivado project +#add_files -fileset sim_1 ./path/to/testbench.vhd +#add_files [glob ./path/to/sources/*.vhd] +#add_files -fileset constrs_1 ./path/to/constraint/constraint.xdc +#add_files [glob ./path/to/library/sources/*.vhd] +#set_property -library userDefined [glob ./path/to/library/sources/*.vhd] +add_files [glob $base/*.v] +add_files [glob $topv] +add_files -fileset constrs_1 $base/arty_a7.xdc + +#set top level module and update compile order +set_property top toplevel [current_fileset] +update_compile_order -fileset sources_1 +#update_compile_order -fileset sim_1 + +#launch synthesis +launch_runs synth_1 +wait_on_run synth_1 + +#Run implementation and generate bitstream +set_property STEPS.PHYS_OPT_DESIGN.IS_ENABLED true [get_runs impl_1] +launch_runs impl_1 -to_step write_bitstream +wait_on_run impl_1 +puts "Implementation done!" + +#reports generated by default +#open_run impl_1 +#report_timing_summary -check_timing_verbose -report_unconstrained -file report_timing_summary.rpt +#report_utilization -hierarchical -file report_utilization.rpt + +#TODO: add checks about timing, DRC, CDC such that the script give clear indication if design is OK or not diff --git a/scripts/Murax/arty_a7/makefile b/scripts/Murax/arty_a7/makefile new file mode 100644 index 00000000..b6726523 --- /dev/null +++ b/scripts/Murax/arty_a7/makefile @@ -0,0 +1,62 @@ +ROOT=../../.. +SWBASE=$(ROOT)/src/main/c/murax +SOCSW=hello_world +SOCMEMSRC=$(SWBASE)/$(SOCSW)/build/$(SOCSW).v +SOCMEM=build/soc.mem + +TOP=Murax + +all : build/latest.bit + +../../../$(TOP).v : toplevel.v + (cd ../../..; sbt "runMain vexriscv.demo.Murax_arty") + +.PHONY: $(SOCMEMSRC) +$(SOCMEMSRC): + mkdir -p build + make -C $(SWBASE)/$(SOCSW) + +$(SOCMEM) : $(SOCMEMSRC) + cp -u $(SOCMEMSRC) $(SOCMEM) + +build/vivado_project/fpga.runs/impl_1/toplevel.bit : toplevel.v arty_a7.xdc ../../../$(TOP).v + mkdir -p build + ./make_vivado_project + cp build/vivado_project/fpga.runs/impl_1/toplevel.bit build/latest.bit + +build/soc.mmi: build/vivado_project/fpga.runs/impl_1/toplevel.bit + ./make_mmi_files + +build/latest_soc_sw.bit : $(SOCMEM) build/soc.mmi + rm -f updatemem.jou updatemem.log + updatemem -force --meminfo build/soc.mmi --data $(SOCMEM) --bit build/latest.bit --proc dummy --out build/latest_soc_sw.bit + cp build/latest_soc_sw.bit build/latest.bit + +build/latest.bit : build/latest_soc_sw.bit + +build/latest.mcs : build/latest.bit + ./make_mcs_file + +prog : build/latest.bit + ./write_fpga + +flash : build/latest.mcs + ./write_flash + +clean-soc-sw: + make -C $(SWBASE)/$(SOCSW) clean-all + +soc-sw: clean-soc-sw $(SOCMEM) + +.PHONY: clean +clean : + rm -rf build + mkdir build + rm -f updatemem.jou + rm -f updatemem.log + +clean-sw: clean-soc-sw + +clean-all : clean clean-sw + rm -f ../../../$(TOP).v + rm -f ../../../$(TOP).v_* diff --git a/scripts/Murax/arty_a7/open_vivado_project b/scripts/Murax/arty_a7/open_vivado_project new file mode 100755 index 00000000..24c54d12 --- /dev/null +++ b/scripts/Murax/arty_a7/open_vivado_project @@ -0,0 +1,4 @@ +#!/bin/sh + +cd ./build +vivado -mode batch -source ../open_vivado_project.tcl -notrace diff --git a/scripts/Murax/arty_a7/open_vivado_project.tcl b/scripts/Murax/arty_a7/open_vivado_project.tcl new file mode 100644 index 00000000..41200198 --- /dev/null +++ b/scripts/Murax/arty_a7/open_vivado_project.tcl @@ -0,0 +1,4 @@ +source [file join [file dirname [file normalize [info script]]] vivado_params.tcl] + +open_project -read_only $outputdir/$projectName +start_gui diff --git a/scripts/Murax/arty_a7/picocom_arty b/scripts/Murax/arty_a7/picocom_arty new file mode 100644 index 00000000..ff15a172 --- /dev/null +++ b/scripts/Murax/arty_a7/picocom_arty @@ -0,0 +1 @@ +picocom --baud 115200 --imap lfcrlf /dev/ttyUSB1 diff --git a/scripts/Murax/arty_a7/soc_mmi.tcl b/scripts/Murax/arty_a7/soc_mmi.tcl new file mode 100644 index 00000000..33ea6866 --- /dev/null +++ b/scripts/Murax/arty_a7/soc_mmi.tcl @@ -0,0 +1,151 @@ +#script to update the init values of RAM without re-synthesis + +if {![info exists mmi_file]} { + # Set MMI output file name + set mmi_file "soc.mmi" +} +if {![info exists part]} { + set part "xc7a35ticsg324-1L" +} + +# Function to swap bits +proc swap_bits { bit } { + + if { $bit > 23 } {return [expr {24 + (31 - $bit)}]} + if { $bit > 15 } {return [expr {16 + (23 - $bit)}]} + if { $bit > 7 } {return [expr {8 + (15 - $bit)}]} + return [expr {7 - $bit}] +} + +# If run from batch file, will need to open project, then open the run +# open_run impl_1 + +# Find all the RAMs, place in a list +set rams [get_cells -hier -regexp {.*core/system_ram/.*} -filter {REF_NAME =~ RAMB36E1}] + +puts "[llength $rams] RAMs in total" +foreach m $rams {puts $m} + +set mems [dict create] +foreach m $rams { + set numbers [regexp -all -inline -- {[0-9]+} $m] + dict set mems $numbers $m +} +set keys [dict keys $mems] +#set keys [lsort -integer $keys] +set rams [] +foreach key $keys { + set m [dict get $mems $key] + puts "$key -> $m" + lappend rams $m +} + +puts "after sort:" +foreach m $rams {puts $m} +puts $rams + +if { [llength $rams] == 0 } { + puts "Error - no memories found" + return -1 +} + +if { [expr {[llength $rams] % 4}] != 0 } { + puts "Error - Number of memories not divisible by 4" + return -1 +} + +set size_bytes [expr {4096*[llength $rams]}] +puts "Instruction memory size $size_bytes" + +# Currently only support memory sizes between 16kB, (one byte per mem), and 128kB, (one bit per mem) +if { ($size_bytes < (4*4096)) || ($size_bytes > (32*4096)) } { + puts "Error - Memory size of $size_bytes out of range" + puts " Script only supports memory sizes between 16kB and 128kB" + return -1 +} + +# Create and open target mmi file +set fp [open $mmi_file {WRONLY CREAT TRUNC}] +if { $fp == 0 } { + puts "Error - Unable to open $mmi_file for writing" + return -1 +} + +# Write the file header +puts $fp "" +puts $fp "" +puts $fp " " +puts $fp " " +puts $fp " " + +# Calculate the expected number of bits per memory +set mem_bits [expr {32/[llength $rams]}] + +puts "mem_bits = $mem_bits" + +set mem_info [dict create] + +set i 0 +foreach ram $rams { + # Get the RAM location + set loc_val [get_property LOC [get_cells $ram]] + regexp -- {(RAMB36_)([0-9XY]+)} $loc_val full ram_name loc_xy + + set memi [dict create ram $ram loc $loc_xy] + + set numbers [regexp -all -inline -- {[0-9]+} $ram] + if { [llength $numbers] == 2 } { + dict lappend mem_info [lindex $numbers 0] $memi + } else { + dict lappend mem_info [expr $i/4] $memi + } + incr i +} + +set sorted_mem_info [dict create] +foreach {idx mems} $mem_info { + foreach mem [lreverse $mems] { + dict lappend sorted_mem_info $idx $mem + } +} +foreach mems $sorted_mem_info { + foreach mem $mems { + puts $mem + } +} + +set lsb 0 +set memlen [ expr 4096*8 / $mem_bits ] +foreach {idx mems} $sorted_mem_info { + puts "idx=$idx" + foreach mem $mems { + puts "mem=$mem" + set ram [dict get $mem ram] + set loc [dict get $mem loc] + set msb [expr $lsb+$mem_bits-1] + set addr_start 0 + set addr_end [expr $memlen-1] + puts "ram=$ram loc=$loc lsb=$lsb msb=$msb addr_start=$addr_start addr_end=$addr_end" + puts $fp " " + puts $fp " " + puts $fp " " + puts $fp " " + puts $fp " " + puts $fp " " + + set lsb [expr ($msb+1)%32] + } +} + +puts $fp " " +puts $fp " " +puts $fp " " +puts $fp " " +puts $fp " " +puts $fp " " +puts $fp " " +puts $fp " " +puts $fp "" + +close $fp diff --git a/scripts/Murax/arty_a7/toplevel.v b/scripts/Murax/arty_a7/toplevel.v new file mode 100644 index 00000000..e127da69 --- /dev/null +++ b/scripts/Murax/arty_a7/toplevel.v @@ -0,0 +1,66 @@ +`timescale 1ns / 1ps + +module toplevel( + input wire clk100, + input wire cpu_reset,//active low + + input wire tck, + input wire tms, + input wire tdi, + input wire trst,//ignored + output reg tdo, + + input wire serial_rx, + output wire serial_tx, + + input wire user_sw0, + input wire user_sw1, + input wire user_sw2, + input wire user_sw3, + + input wire user_btn0, + input wire user_btn1, + input wire user_btn2, + input wire user_btn3, + + output wire user_led0, + output wire user_led1, + output wire user_led2, + output wire user_led3 + ); + + wire [31:0] io_gpioA_read; + wire [31:0] io_gpioA_write; + wire [31:0] io_gpioA_writeEnable; + + wire io_asyncReset = ~cpu_reset; + + assign {user_led3,user_led2,user_led1,user_led0} = io_gpioA_write[3 : 0]; + assign io_gpioA_read[3:0] = {user_sw3,user_sw2,user_sw1,user_sw0}; + assign io_gpioA_read[7:4] = {user_btn3,user_btn2,user_btn1,user_btn0}; + assign io_gpioA_read[11:8] = {tck,tms,tdi,trst}; + + reg tesic_tck,tesic_tms,tesic_tdi; + wire tesic_tdo; + reg soc_tck,soc_tms,soc_tdi; + wire soc_tdo; + + always @(*) begin + {soc_tck, soc_tms, soc_tdi } = {tck,tms,tdi}; + tdo = soc_tdo; + end + + Murax core ( + .io_asyncReset(io_asyncReset), + .io_mainClk (clk100 ), + .io_jtag_tck(soc_tck), + .io_jtag_tdi(soc_tdi), + .io_jtag_tdo(soc_tdo), + .io_jtag_tms(soc_tms), + .io_gpioA_read (io_gpioA_read), + .io_gpioA_write (io_gpioA_write), + .io_gpioA_writeEnable(io_gpioA_writeEnable), + .io_uart_txd(serial_tx), + .io_uart_rxd(serial_rx) + ); +endmodule diff --git a/scripts/Murax/arty_a7/vivado_params.tcl b/scripts/Murax/arty_a7/vivado_params.tcl new file mode 100644 index 00000000..343058dd --- /dev/null +++ b/scripts/Murax/arty_a7/vivado_params.tcl @@ -0,0 +1,5 @@ +set outputdir ./vivado_project +set part "xc7a35ticsg324-1L" +set base ".." +set projectName "fpga" +set topv "$base/../../../Murax.v" diff --git a/scripts/Murax/arty_a7/write_flash b/scripts/Murax/arty_a7/write_flash new file mode 100755 index 00000000..05414c4a --- /dev/null +++ b/scripts/Murax/arty_a7/write_flash @@ -0,0 +1,3 @@ +#!/bin/sh +cd ./build +vivado -mode batch -source ../write_flash.tcl -notrace diff --git a/scripts/Murax/arty_a7/write_flash.tcl b/scripts/Murax/arty_a7/write_flash.tcl new file mode 100644 index 00000000..845bff74 --- /dev/null +++ b/scripts/Murax/arty_a7/write_flash.tcl @@ -0,0 +1,26 @@ + +open_hw +connect_hw_server +open_hw_target +current_hw_device [get_hw_devices xc7a35t_0] +refresh_hw_device -update_hw_probes false [lindex [get_hw_devices xc7a35t_0] 0] + +create_hw_cfgmem -hw_device [lindex [get_hw_devices] 0] -mem_dev [lindex [get_cfgmem_parts {s25fl128sxxxxxx0-spi-x1_x2_x4}] 0] +set_property PROBES.FILE {} [get_hw_devices xc7a35t_0] +set_property FULL_PROBES.FILE {} [get_hw_devices xc7a35t_0] +refresh_hw_device [lindex [get_hw_devices xc7a35t_0] 0] +set_property PROGRAM.ADDRESS_RANGE {use_file} [ get_property PROGRAM.HW_CFGMEM [lindex [get_hw_devices xc7a35t_0] 0]] +set_property PROGRAM.FILES [list "latest.mcs" ] [ get_property PROGRAM.HW_CFGMEM [lindex [get_hw_devices xc7a35t_0] 0]] +set_property PROGRAM.PRM_FILE {} [ get_property PROGRAM.HW_CFGMEM [lindex [get_hw_devices xc7a35t_0] 0]] +set_property PROGRAM.UNUSED_PIN_TERMINATION {pull-none} [ get_property PROGRAM.HW_CFGMEM [lindex [get_hw_devices xc7a35t_0] 0]] +set_property PROGRAM.BLANK_CHECK 0 [ get_property PROGRAM.HW_CFGMEM [lindex [get_hw_devices xc7a35t_0] 0]] +set_property PROGRAM.ERASE 1 [ get_property PROGRAM.HW_CFGMEM [lindex [get_hw_devices xc7a35t_0] 0]] +set_property PROGRAM.CFG_PROGRAM 1 [ get_property PROGRAM.HW_CFGMEM [lindex [get_hw_devices xc7a35t_0] 0]] +set_property PROGRAM.VERIFY 1 [ get_property PROGRAM.HW_CFGMEM [lindex [get_hw_devices xc7a35t_0] 0]] +set_property PROGRAM.CHECKSUM 0 [ get_property PROGRAM.HW_CFGMEM [lindex [get_hw_devices xc7a35t_0] 0]] + +if {![string equal [get_property PROGRAM.HW_CFGMEM_TYPE [lindex [get_hw_devices xc7a35t_0] 0]] [get_property MEM_TYPE [get_property CFGMEM_PART [ get_property PROGRAM.HW_CFGMEM [lindex [get_hw_devices xc7a35t_0] 0]]]]] } { create_hw_bitstream -hw_device [lindex [get_hw_devices xc7a35t_0] 0] [get_property PROGRAM.HW_CFGMEM_BITFILE [ lindex [get_hw_devices xc7a35t_0] 0]]; program_hw_devices [lindex [get_hw_devices xc7a35t_0] 0]; }; +program_hw_cfgmem -hw_cfgmem [ get_property PROGRAM.HW_CFGMEM [lindex [get_hw_devices xc7a35t_0] 0]] + +close_hw_target +close_hw diff --git a/scripts/Murax/arty_a7/write_fpga b/scripts/Murax/arty_a7/write_fpga new file mode 100755 index 00000000..63a344e0 --- /dev/null +++ b/scripts/Murax/arty_a7/write_fpga @@ -0,0 +1,3 @@ +#!/bin/sh +cd ./build +vivado -mode batch -source ../write_fpga.tcl -notrace diff --git a/scripts/Murax/arty_a7/write_fpga.tcl b/scripts/Murax/arty_a7/write_fpga.tcl new file mode 100644 index 00000000..e3214f88 --- /dev/null +++ b/scripts/Murax/arty_a7/write_fpga.tcl @@ -0,0 +1,10 @@ +open_hw +connect_hw_server +open_hw_target +current_hw_device [get_hw_devices xc7a35t_0] +refresh_hw_device -update_hw_probes false [lindex [get_hw_devices xc7a35t_0] 0] +set_property PROBES.FILE {} [get_hw_devices xc7a35t_0] +set_property FULL_PROBES.FILE {} [get_hw_devices xc7a35t_0] +set_property PROGRAM.FILE {latest.bit} [get_hw_devices xc7a35t_0] +program_hw_devices [get_hw_devices xc7a35t_0] +disconnect_hw_server diff --git a/scripts/Murax/iCE40-hx8k_breakout_board_xip/Makefile b/scripts/Murax/iCE40-hx8k_breakout_board_xip/Makefile index 88aa1a2f..8feef205 100644 --- a/scripts/Murax/iCE40-hx8k_breakout_board_xip/Makefile +++ b/scripts/Murax/iCE40-hx8k_breakout_board_xip/Makefile @@ -1,19 +1,21 @@ +VBASE = ../../.. +VNAME = Murax_iCE40_hx8k_breakout_board_xip +VERILOG = ${VBASE}/${VNAME}.v -VERILOG = ../../../Murax_iCE40_hx8k_breakout_board_xip.v +all: prog -generate : - #(cd ../../..; sbt "runMain vexriscv.demo.Murax_iCE40_hx8k_breakout_board_xip") +${VERILOG} : + (cd ${VBASE}; sbt "runMain vexriscv.demo.${VNAME}") -../../../Murax_iCE40_hx8k_breakout_board_xip.v : - #(cd ../../..; sbt "runMain vexriscv.demo.Murax_iCE40_hx8k_breakout_board_xip") +generate : ${VERILOG} -../../../Murax_iCE40_hx8k_breakout_board_xip.v*.bin: +${VERILOG}*.bin: -bin/Murax_iCE40_hx8k_breakout_board_xip.blif : ${VERILOG} ../../../Murax_iCE40_hx8k_breakout_board_xip.v*.bin +bin/Murax_iCE40_hx8k_breakout_board_xip.blif : ${VERILOG} ${VERILOG}*.bin mkdir -p bin rm -f Murax_iCE40_hx8k_breakout_board_xip.v*.bin - cp ../../../Murax_iCE40_hx8k_breakout_board_xip.v*.bin . | true + cp ${VERILOG}*.bin . | true yosys -v3 -p "synth_ice40 -top Murax_iCE40_hx8k_breakout_board_xip -blif bin/Murax_iCE40_hx8k_breakout_board_xip.blif" ${VERILOG} bin/Murax_iCE40_hx8k_breakout_board_xip.asc : Murax_iCE40_hx8k_breakout_board_xip.pcf bin/Murax_iCE40_hx8k_breakout_board_xip.blif @@ -28,11 +30,15 @@ time: bin/Murax_iCE40_hx8k_breakout_board_xip.bin icetime -tmd hx8k bin/Murax_iCE40_hx8k_breakout_board_xip.asc prog : bin/Murax_iCE40_hx8k_breakout_board_xip.bin + lsusb -d 0403:6010 iceprog -S bin/Murax_iCE40_hx8k_breakout_board_xip.bin sudo-prog : bin/Murax_iCE40_hx8k_breakout_board_xip.bin + sudo lsusb -d 0403:6010 sudo iceprog -S bin/Murax_iCE40_hx8k_breakout_board_xip.bin clean : rm -rf bin rm -f Murax_iCE40_hx8k_breakout_board_xip.v*.bin + rm -f ${VERILOG}*.bin + rm -f ${VERILOG} diff --git a/scripts/Murax/iCE40-hx8k_breakout_board_xip/Murax_iCE40_hx8k_breakout_board_xip.pcf b/scripts/Murax/iCE40-hx8k_breakout_board_xip/Murax_iCE40_hx8k_breakout_board_xip.pcf index 4962e25b..510acf71 100644 --- a/scripts/Murax/iCE40-hx8k_breakout_board_xip/Murax_iCE40_hx8k_breakout_board_xip.pcf +++ b/scripts/Murax/iCE40-hx8k_breakout_board_xip/Murax_iCE40_hx8k_breakout_board_xip.pcf @@ -1,12 +1,12 @@ ## iCE40-hx8k breakout board -set_io io_J3 J3 -set_io io_H16 H16 -set_io io_G15 G15 -set_io io_G16 G16 -set_io io_F15 F15 -set_io io_B12 B12 -set_io io_B10 B10 +set_io io_mainClk J3 +set_io io_jtag_tck H16 +set_io io_jtag_tdi G15 +set_io io_jtag_tdo G16 +set_io io_jtag_tms F15 +set_io io_uart_txd B12 +set_io io_uart_rxd B10 set_io io_led[0] B5 set_io io_led[1] B4 set_io io_led[2] A2 @@ -17,7 +17,7 @@ set_io io_led[6] B3 set_io io_led[7] C3 #XIP -set_io io_P12 P12 -set_io io_P11 P11 -set_io io_R11 R11 -set_io io_R12 R12 \ No newline at end of file +set_io io_miso P12 +set_io io_mosi P11 +set_io io_sclk R11 +set_io io_spis R12 diff --git a/scripts/Murax/iCE40-hx8k_breakout_board_xip/README.md b/scripts/Murax/iCE40-hx8k_breakout_board_xip/README.md index 1e50a02f..3ed77c5e 100644 --- a/scripts/Murax/iCE40-hx8k_breakout_board_xip/README.md +++ b/scripts/Murax/iCE40-hx8k_breakout_board_xip/README.md @@ -9,6 +9,10 @@ This board can be purchased for ~$USD 49 directly from Lattice and is supported by the IceStorm [`iceprog`](https://github.com/cliffordwolf/icestorm/tree/master/iceprog) tool. +# Bootloader operations + +A bootloader is implemented in a ROM within the FPGA bitfile. It configure the SPI and attempt to read the first word in 'XIP' area of the flash (0xE0040000 in CPU address space, 0x40000 in flash). If this first word is not 0xFFFFFFFF and the same value is read 3 times, +then the bootloader jump at 0xE0040000. # Using the example @@ -59,12 +63,29 @@ The process should take around 30 seconds on a reasonable fast computer. ## Programming +Make sure the FPGA board is the only USB peripheral with ID 0403:6010 + +For example, this is bad: +``` +user@lafite:~$ lsusb -d 0403:6010 +Bus 001 Device 088: ID 0403:6010 Future Technology Devices International, Ltd FT2232C Dual USB-UART/FIFO IC +Bus 001 Device 090: ID 0403:6010 Future Technology Devices International, Ltd FT2232C Dual USB-UART/FIFO IC +``` +This is good: +``` +user@lafite:~$ lsusb -d 0403:6010 +Bus 001 Device 088: ID 0403:6010 Future Technology Devices International, Ltd FT2232C Dual USB-UART/FIFO IC +``` + + After building you should be able to run `make prog`. You may need to run `make sudo-prog` if root is needed to access your USB devices. You should get output like the following; ``` -iceprog -S bin/toplevel.bin +lsusb -d 0403:6010 +Bus 001 Device 088: ID 0403:6010 Future Technology Devices International, Ltd FT2232C Dual USB-UART/FIFO IC +iceprog -S bin/Murax_iCE40_hx8k_breakout_board_xip.bin init.. cdone: high reset.. @@ -74,13 +95,113 @@ cdone: high Bye. ``` -After programming the LEDs at the top of the board should start flashing in an -interesting pattern. +WARNING: having this output does NOT guarantee you actually programmed anything in the FPGA! -## Connect +After programming nothing visual will happen, except the LEDs being off. +The bootloader is waiting for a valid content in the flash (see Bootloader operations). -After programming you should be able to connect to the serial port and have the -output echoed back to you. +## Programming flash image -On Linux you can do this using a command like `screen /dev/ttyUSB1`. Then as -you type you should get back the same characters. +### Connect JTAG + +We will use vexrisc JTAG to program the flash, so you need openocd and a +suitable JTAG dongle. + +Pin-out: +``` +TCK: H16 aka J2.25 +TDO: G16 aka J2.26 +TDI: G15 aka J2.27 +TMS: F15 aka J2.28 +``` +In addition you need to connect the ground and VTarget aka VIO: J2.2 on the +board. + +### Start GDB server / OpenOCD +Make sure to use https://github.com/SpinalHDL/openocd_riscv +Make sure to select the configuration file which match your JTAG dongle. + +An example with the dongle "ft2232h_breakout": +``` +src/openocd -f tcl/interface/ftdi/ft2232h_breakout.cfg -c "set MURAX_CPU0_YAML ../VexRiscv/cpu0.yaml" -f tcl/target/murax_xip.cfg +``` + +You should get an output like below: +``` +Open On-Chip Debugger 0.10.0+dev-01214-g0ace94f (2019-10-02-18:23) +Licensed under GNU GPL v2 +For bug reports, read + http://openocd.org/doc/doxygen/bugs.html +../VexRiscv/cpu0.yaml +adapter speed: 100 kHz +adapter_nsrst_delay: 260 +Info : auto-selecting first available session transport "jtag". To override use 'transport select '. +jtag_ntrst_delay: 250 +Info : set servers polling period to 50ms +Error: libusb_get_string_descriptor_ascii() failed with LIBUSB_ERROR_INVALID_PARAM +Info : clock speed 100 kHz +Info : JTAG tap: fpga_spinal.bridge tap/device found: 0x10001fff (mfg: 0x7ff (), part: 0x0001, ver: 0x1) +Info : Listening on port 3333 for gdb connections +requesting target halt and executing a soft reset +Info : Listening on port 6666 for tcl connections +Info : Listening on port 4444 for telnet connections +``` + +### Loading the flash with telnet + +First we connect and stop execution on the device: +``` +user@lafite:~/Downloads/vexrisc_full/VexRiscv/src/main/c/murax/xipBootloader$ telnet 127.0.0.1 4444 +Trying 127.0.0.1... +Connected to 127.0.0.1. +Escape character is '^]'. +Open On-Chip Debugger +> reset +JTAG tap: fpga_spinal.bridge tap/device found: 0x10001fff (mfg: 0x7ff (), part: 0x0001, ver: 0x1) +> +``` + +Now we can safely connect the J7 jumper on the board to be able to access the flash. +After that, we can load the program in flash: +``` +> flash erase_sector 0 4 4 +erased sectors 4 through 4 on flash bank 0 in 0.872235s +> flash write_bank 0 /home/user/dev/vexrisc_fork/VexRiscv/src/main/c/murax/xipBootloader/demo_xip.bin 0x40000 +wrote 48 bytes from file /home/user/dev/vexrisc_fork/VexRiscv/src/main/c/murax/xipBootloader/demo_xip.bin to flash bank 0 at offset 0x00040000 in 0.285539s (0.164 KiB/s) +> flash verify_bank 0 /home/user/dev/vexrisc_fork/VexRiscv/src/main/c/murax/xipBootloader/demo_xip.bin 0x40000 +read 48 bytes from file /home/user/dev/vexrisc_fork/VexRiscv/src/main/c/murax/xipBootloader/demo_xip.bin and flash bank 0 at offset 0x00040000 in 0.192036s (0.244 KiB/s) +contents match +> reset +JTAG tap: fpga_spinal.bridge tap/device found: 0x10001fff (mfg: 0x7ff (), part: 0x0001, ver: 0x1) +> resume +> exit +Connection closed by foreign host. +``` + +From now the device runs the code from flash, LEDs shall display a dot moving from D9 to D2. + +### Loading flash using GDB / eclipse +``` +src/openocd -f tcl/interface/ftdi/ft2232h_breakout.cfg -c "set MURAX_CPU0_YAML ../VexRiscv/cpu0.yaml" -f tcl/target/murax_xip.cfg +``` +- Make sure J7 is connected. +- Connect to GDB / eclipse as usual. + +From there code loading, step, break points works as usual (including software break points in flash). + +## Update hardware/bootloader + +- Stop any OpenOCD connection +- Remove J7, then: +``` +make clean prog +``` +- Remember to check a single FTDI device is listed in the output. If not: + - Disconnect the other devices + ``` + make prog + ``` +- Connect J7, flash software shall start executing. + +## Flash software +Refer to "Loading the flash with telnet" or "Loading flash using GDB / eclipse". diff --git a/src/main/c/murax/hello_world/makefile b/src/main/c/murax/hello_world/makefile new file mode 100644 index 00000000..dc560c0a --- /dev/null +++ b/src/main/c/murax/hello_world/makefile @@ -0,0 +1,134 @@ +PROJ_NAME=hello_world +DEBUG=no +BENCH=no +MULDIV=no + +SRCS = $(wildcard src/*.c) \ + $(wildcard src/*.cpp) \ + $(wildcard src/*.S) + +OBJDIR = build + +INC = +LIBS = +LIBSINC = -L$(OBJDIR) +LDSCRIPT = ./src/linker.ld + +#include ../../../resources/gcc.mk +# Set it to yes if you are using the sifive precompiled GCC pack +SIFIVE_GCC_PACK ?= yes + +ifeq ($(SIFIVE_GCC_PACK),yes) + RISCV_NAME ?= riscv64-unknown-elf + RISCV_PATH ?= /opt/riscv/ +else + RISCV_NAME ?= riscv32-unknown-elf + ifeq ($(MULDIV),yes) + RISCV_PATH ?= /opt/riscv32im/ + else + RISCV_PATH ?= /opt/riscv32i/ + endif +endif + +MABI=ilp32 +MARCH := rv32i +ifeq ($(MULDIV),yes) + MARCH := $(MARCH)m +endif +ifeq ($(COMPRESSED),yes) + MARCH := $(MARCH)ac +endif + +CFLAGS += -march=$(MARCH) -mabi=$(MABI) -DNDEBUG +LDFLAGS += -march=$(MARCH) -mabi=$(MABI) + + + +#include ../../../resources/subproject.mk + + +ifeq ($(DEBUG),yes) + CFLAGS += -g3 -O0 +endif + +ifeq ($(DEBUG),no) + CFLAGS += -g -Os +endif + +ifeq ($(BENCH),yes) + CFLAGS += -fno-inline +endif + +ifeq ($(SIFIVE_GCC_PACK),yes) + RISCV_CLIB=$(RISCV_PATH)/$(RISCV_NAME)/lib/$(MARCH)/$(MABI)/ +else + RISCV_CLIB=$(RISCV_PATH)/$(RISCV_NAME)/lib/ +endif + + + + + +RISCV_OBJCOPY = $(RISCV_PATH)/bin/$(RISCV_NAME)-objcopy +RISCV_OBJDUMP = $(RISCV_PATH)/bin/$(RISCV_NAME)-objdump +RISCV_CC=$(RISCV_PATH)/bin/$(RISCV_NAME)-gcc + +CFLAGS += -MD -fstrict-volatile-bitfields -fno-strict-aliasing +LDFLAGS += -nostdlib -lgcc -mcmodel=medany -nostartfiles -ffreestanding -Wl,-Bstatic,-T,$(LDSCRIPT),-Map,$(OBJDIR)/$(PROJ_NAME).map,--print-memory-usage +#LDFLAGS += -lgcc -lc -lg -nostdlib -lgcc -msave-restore --strip-debug, + +OBJS := $(SRCS) +OBJS := $(OBJS:.c=.o) +OBJS := $(OBJS:.cpp=.o) +OBJS := $(OBJS:.S=.o) +OBJS := $(OBJS:..=miaou) +OBJS := $(addprefix $(OBJDIR)/,$(OBJS)) + + +all: $(OBJDIR)/$(PROJ_NAME).elf $(OBJDIR)/$(PROJ_NAME).hex $(OBJDIR)/$(PROJ_NAME).asm $(OBJDIR)/$(PROJ_NAME).v + +$(OBJDIR)/%.elf: $(OBJS) | $(OBJDIR) + $(RISCV_CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) $(LIBSINC) $(LIBS) + +%.hex: %.elf + $(RISCV_OBJCOPY) -O ihex $^ $@ + +%.bin: %.elf + $(RISCV_OBJCOPY) -O binary $^ $@ + +%.v: %.elf + $(RISCV_OBJCOPY) -O verilog $^ $@ + +%.asm: %.elf + $(RISCV_OBJDUMP) -S -d $^ > $@ + +$(OBJDIR)/%.o: %.c + mkdir -p $(dir $@) + $(RISCV_CC) -c $(CFLAGS) $(INC) -o $@ $^ + $(RISCV_CC) -S $(CFLAGS) $(INC) -o $@.disasm $^ + +$(OBJDIR)/%.o: %.cpp + mkdir -p $(dir $@) + $(RISCV_CC) -c $(CFLAGS) $(INC) -o $@ $^ + +$(OBJDIR)/%.o: %.S + mkdir -p $(dir $@) + $(RISCV_CC) -c $(CFLAGS) -o $@ $^ -D__ASSEMBLY__=1 + +$(OBJDIR): + mkdir -p $@ + +.PHONY: clean +clean: + rm -rf $(OBJDIR)/src + rm -f $(OBJDIR)/$(PROJ_NAME).elf + rm -f $(OBJDIR)/$(PROJ_NAME).hex + rm -f $(OBJDIR)/$(PROJ_NAME).map + rm -f $(OBJDIR)/$(PROJ_NAME).v + rm -f $(OBJDIR)/$(PROJ_NAME).asm + find $(OBJDIR) -type f -name '*.o' -print0 | xargs -0 -r rm + find $(OBJDIR) -type f -name '*.d' -print0 | xargs -0 -r rm + +clean-all : clean + +.SECONDARY: $(OBJS) diff --git a/src/main/c/murax/hello_world/src/crt.S b/src/main/c/murax/hello_world/src/crt.S new file mode 100644 index 00000000..62d67b9e --- /dev/null +++ b/src/main/c/murax/hello_world/src/crt.S @@ -0,0 +1,98 @@ +.global crtStart +.global main +.global irqCallback + + .section .start_jump,"ax",@progbits +crtStart: + //long jump to allow crtInit to be anywhere + //do it always in 12 bytes + lui x2, %hi(crtInit) + addi x2, x2, %lo(crtInit) + jalr x1,x2 + nop + +.section .text + +.global trap_entry +.align 5 +trap_entry: + sw x1, - 1*4(sp) + sw x5, - 2*4(sp) + sw x6, - 3*4(sp) + sw x7, - 4*4(sp) + sw x10, - 5*4(sp) + sw x11, - 6*4(sp) + sw x12, - 7*4(sp) + sw x13, - 8*4(sp) + sw x14, - 9*4(sp) + sw x15, -10*4(sp) + sw x16, -11*4(sp) + sw x17, -12*4(sp) + sw x28, -13*4(sp) + sw x29, -14*4(sp) + sw x30, -15*4(sp) + sw x31, -16*4(sp) + addi sp,sp,-16*4 + call irqCallback + lw x1 , 15*4(sp) + lw x5, 14*4(sp) + lw x6, 13*4(sp) + lw x7, 12*4(sp) + lw x10, 11*4(sp) + lw x11, 10*4(sp) + lw x12, 9*4(sp) + lw x13, 8*4(sp) + lw x14, 7*4(sp) + lw x15, 6*4(sp) + lw x16, 5*4(sp) + lw x17, 4*4(sp) + lw x28, 3*4(sp) + lw x29, 2*4(sp) + lw x30, 1*4(sp) + lw x31, 0*4(sp) + addi sp,sp,16*4 + mret + .text + + +crtInit: + .option push + .option norelax + la gp, __global_pointer$ + .option pop + la sp, _stack_start + +bss_init: + la a0, _bss_start + la a1, _bss_end +bss_loop: + beq a0,a1,bss_done + sw zero,0(a0) + add a0,a0,4 + j bss_loop +bss_done: + +ctors_init: + la a0, _ctors_start + addi sp,sp,-4 +ctors_loop: + la a1, _ctors_end + beq a0,a1,ctors_done + lw a3,0(a0) + add a0,a0,4 + sw a0,0(sp) + jalr a3 + lw a0,0(sp) + j ctors_loop +ctors_done: + addi sp,sp,4 + + + li a0, 0x880 //880 enable timer + external interrupts + csrw mie,a0 + li a0, 0x1808 //1808 enable interrupts + csrw mstatus,a0 + + call main +infinitLoop: + j infinitLoop diff --git a/src/main/c/murax/hello_world/src/gpio.h b/src/main/c/murax/hello_world/src/gpio.h new file mode 100644 index 00000000..34348fec --- /dev/null +++ b/src/main/c/murax/hello_world/src/gpio.h @@ -0,0 +1,15 @@ +#ifndef GPIO_H_ +#define GPIO_H_ + + +typedef struct +{ + volatile uint32_t INPUT; + volatile uint32_t OUTPUT; + volatile uint32_t OUTPUT_ENABLE; +} Gpio_Reg; + + +#endif /* GPIO_H_ */ + + diff --git a/src/main/c/murax/hello_world/src/interrupt.h b/src/main/c/murax/hello_world/src/interrupt.h new file mode 100644 index 00000000..23b7d277 --- /dev/null +++ b/src/main/c/murax/hello_world/src/interrupt.h @@ -0,0 +1,17 @@ +#ifndef INTERRUPTCTRL_H_ +#define INTERRUPTCTRL_H_ + +#include + +typedef struct +{ + volatile uint32_t PENDINGS; + volatile uint32_t MASKS; +} InterruptCtrl_Reg; + +static void interruptCtrl_init(InterruptCtrl_Reg* reg){ + reg->MASKS = 0; + reg->PENDINGS = 0xFFFFFFFF; +} + +#endif /* INTERRUPTCTRL_H_ */ diff --git a/src/main/c/murax/hello_world/src/linker.ld b/src/main/c/murax/hello_world/src/linker.ld new file mode 100644 index 00000000..57bc2f7b --- /dev/null +++ b/src/main/c/murax/hello_world/src/linker.ld @@ -0,0 +1,110 @@ +/* +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. +*/ +OUTPUT_FORMAT("elf32-littleriscv", "elf32-littleriscv", "elf32-littleriscv") +OUTPUT_ARCH(riscv) +ENTRY(crtStart) + +MEMORY { + RAM (rwx): ORIGIN = 0x80000000, LENGTH = 2k +} + +_stack_size = DEFINED(_stack_size) ? _stack_size : 256; +_heap_size = DEFINED(_heap_size) ? _heap_size : 0; + +SECTIONS { + + ._vector ORIGIN(RAM): { + *crt.o(.start_jump); + *crt.o(.text); + } > RAM + + ._user_heap (NOLOAD): + { + . = ALIGN(8); + PROVIDE ( end = . ); + PROVIDE ( _end = . ); + PROVIDE ( _heap_start = .); + . = . + _heap_size; + . = ALIGN(8); + PROVIDE ( _heap_end = .); + } > RAM + +._stack (NOLOAD): + { + . = ALIGN(16); + PROVIDE (_stack_end = .); + . = . + _stack_size; + . = ALIGN(16); + PROVIDE (_stack_start = .); + } > RAM + + .data : + { + *(.rdata) + *(.rodata .rodata.*) + *(.gnu.linkonce.r.*) + *(.data .data.*) + *(.gnu.linkonce.d.*) + . = ALIGN(8); + PROVIDE( __global_pointer$ = . + 0x800 ); + *(.sdata .sdata.*) + *(.gnu.linkonce.s.*) + . = ALIGN(8); + *(.srodata.cst16) + *(.srodata.cst8) + *(.srodata.cst4) + *(.srodata.cst2) + *(.srodata .srodata.*) + } > RAM + + .bss (NOLOAD) : { + . = ALIGN(4); + /* This is used by the startup in order to initialize the .bss secion */ + _bss_start = .; + *(.sbss*) + *(.gnu.linkonce.sb.*) + *(.bss .bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(4); + _bss_end = .; + } > RAM + + + .rodata : + { + *(.rdata) + *(.rodata .rodata.*) + *(.gnu.linkonce.r.*) + } > RAM + + .noinit (NOLOAD) : { + . = ALIGN(4); + *(.noinit .noinit.*) + . = ALIGN(4); + } > RAM + + .memory : { + *(.text); + end = .; + } > RAM + + .ctors : + { + . = ALIGN(4); + _ctors_start = .; + KEEP(*(.init_array*)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + . = ALIGN(4); + _ctors_end = .; + PROVIDE ( END_OF_SW_IMAGE = . ); + } > RAM + +} diff --git a/src/main/c/murax/hello_world/src/main.c b/src/main/c/murax/hello_world/src/main.c new file mode 100644 index 00000000..05f32273 --- /dev/null +++ b/src/main/c/murax/hello_world/src/main.c @@ -0,0 +1,42 @@ +//#include "stddefs.h" +#include + +#include "murax.h" + +void print(const char*str){ + while(*str){ + uart_write(UART,*str); + str++; + } +} +void println(const char*str){ + print(str); + uart_write(UART,'\n'); +} + +void delay(uint32_t loops){ + for(int i=0;iOUTPUT; + } +} + +void main() { + GPIO_A->OUTPUT_ENABLE = 0x0000000F; + GPIO_A->OUTPUT = 0x00000001; + println("hello world arty a7 v1"); + const int nleds = 4; + const int nloops = 2000000; + while(1){ + for(unsigned int i=0;iOUTPUT = 1<OUTPUT = (1<<(nleds-1))>>i; + delay(nloops); + } + } +} + +void irqCallback(){ +} diff --git a/src/main/c/murax/hello_world/src/murax.h b/src/main/c/murax/hello_world/src/murax.h new file mode 100644 index 00000000..fbfdf3e7 --- /dev/null +++ b/src/main/c/murax/hello_world/src/murax.h @@ -0,0 +1,17 @@ +#ifndef __MURAX_H__ +#define __MURAX_H__ + +#include "timer.h" +#include "prescaler.h" +#include "interrupt.h" +#include "gpio.h" +#include "uart.h" + +#define GPIO_A ((Gpio_Reg*)(0xF0000000)) +#define TIMER_PRESCALER ((Prescaler_Reg*)0xF0020000) +#define TIMER_INTERRUPT ((InterruptCtrl_Reg*)0xF0020010) +#define TIMER_A ((Timer_Reg*)0xF0020040) +#define TIMER_B ((Timer_Reg*)0xF0020050) +#define UART ((Uart_Reg*)(0xF0010000)) + +#endif /* __MURAX_H__ */ diff --git a/src/main/c/murax/hello_world/src/prescaler.h b/src/main/c/murax/hello_world/src/prescaler.h new file mode 100644 index 00000000..6bd9694a --- /dev/null +++ b/src/main/c/murax/hello_world/src/prescaler.h @@ -0,0 +1,16 @@ +#ifndef PRESCALERCTRL_H_ +#define PRESCALERCTRL_H_ + +#include + + +typedef struct +{ + volatile uint32_t LIMIT; +} Prescaler_Reg; + +static void prescaler_init(Prescaler_Reg* reg){ + +} + +#endif /* PRESCALERCTRL_H_ */ diff --git a/src/main/c/murax/hello_world/src/timer.h b/src/main/c/murax/hello_world/src/timer.h new file mode 100644 index 00000000..1577535c --- /dev/null +++ b/src/main/c/murax/hello_world/src/timer.h @@ -0,0 +1,20 @@ +#ifndef TIMERCTRL_H_ +#define TIMERCTRL_H_ + +#include + + +typedef struct +{ + volatile uint32_t CLEARS_TICKS; + volatile uint32_t LIMIT; + volatile uint32_t VALUE; +} Timer_Reg; + +static void timer_init(Timer_Reg *reg){ + reg->CLEARS_TICKS = 0; + reg->VALUE = 0; +} + + +#endif /* TIMERCTRL_H_ */ diff --git a/src/main/c/murax/hello_world/src/uart.h b/src/main/c/murax/hello_world/src/uart.h new file mode 100644 index 00000000..c3a30a56 --- /dev/null +++ b/src/main/c/murax/hello_world/src/uart.h @@ -0,0 +1,42 @@ +#ifndef UART_H_ +#define UART_H_ + + +typedef struct +{ + volatile uint32_t DATA; + volatile uint32_t STATUS; + volatile uint32_t CLOCK_DIVIDER; + volatile uint32_t FRAME_CONFIG; +} Uart_Reg; + +enum UartParity {NONE = 0,EVEN = 1,ODD = 2}; +enum UartStop {ONE = 0,TWO = 1}; + +typedef struct { + uint32_t dataLength; + enum UartParity parity; + enum UartStop stop; + uint32_t clockDivider; +} Uart_Config; + +static uint32_t uart_writeAvailability(Uart_Reg *reg){ + return (reg->STATUS >> 16) & 0xFF; +} +static uint32_t uart_readOccupancy(Uart_Reg *reg){ + return reg->STATUS >> 24; +} + +static void uart_write(Uart_Reg *reg, uint32_t data){ + while(uart_writeAvailability(reg) == 0); + reg->DATA = data; +} + +static void uart_applyConfig(Uart_Reg *reg, Uart_Config *config){ + reg->CLOCK_DIVIDER = config->clockDivider; + reg->FRAME_CONFIG = ((config->dataLength-1) << 0) | (config->parity << 8) | (config->stop << 16); +} + +#endif /* UART_H_ */ + + diff --git a/src/main/c/murax/xipBootloader/crt.S b/src/main/c/murax/xipBootloader/crt.S index 178f7884..52687677 100644 --- a/src/main/c/murax/xipBootloader/crt.S +++ b/src/main/c/murax/xipBootloader/crt.S @@ -42,13 +42,33 @@ crtStart: li t0, 0x1 sw t0, CTRL_XIP_CONFIG(CTRL) li t0, XIP_BASE + lw t1, (t0) + li t2, 0xFFFFFFFF + xor t3,t1,t2 + beqz t3,retry + //if we are here we have read a value from flash which is not all ones + lw t2, (t0) + xor t3,t1,t2 + bnez t3,retry + lw t2, (t0) + xor t3,t1,t2 + bnez t3,retry + //if we are here we have read the same value 3 times, so flash seems good, lets's jump jr t0 +retry: + li a0, 0x800 + call spiWrite + li t1,100000 +loop: + addi t1,t1,-1 + bnez t1, loop + j crtStart spiWrite: sw a0,CTRL_DATA(CTRL) spiWrite_wait: lw t0,CTRL_STATUS(CTRL) - srli t0,t0,0x10 + slli t0,t0,0x10 beqz t0,spiWrite_wait ret diff --git a/src/main/c/murax/xipBootloader/crt.bin b/src/main/c/murax/xipBootloader/crt.bin index d64a1cb00efe30e57fa9ae8eb357f1590f780573..3584ff4b9d823a2b06f626f59e6ea53c5f120f29 100755 GIT binary patch delta 157 zcmb<8z&Jsx-ho4yRY2lB!vS_-Rs$gIz-}(ez#z=Z+VGyCfo(g}e}>6Tn*@{>#j{Li z5@1kX5YMumiRA(FVkU;k%pd+6`xP@JGw?Ar1NmUK6dwbeEyBl;-oV6wWFDh=Gb4jA qGjoS_E<%Gcy-XZW030pZ`CWWB!-_Vg5e`AOHYn Cd=EPS diff --git a/src/main/c/murax/xipBootloader/makefile b/src/main/c/murax/xipBootloader/makefile index 56b8ab84..e08c17b2 100644 --- a/src/main/c/murax/xipBootloader/makefile +++ b/src/main/c/murax/xipBootloader/makefile @@ -4,20 +4,34 @@ LFLAGS= -nostdlib -mcmodel=medany -nostartfiles -ffreestanding -fPIC -fPIE all: crt.S demo.S riscv64-unknown-elf-gcc -c $(CFLAGS) -o crt.o crt.S - riscv64-unknown-elf-gcc $(CFLAGS) -o crt.elf crt.o $(LFLAGS) -Wl,-Bstatic,-T,mapping.ld,-Map,crt.map,--print-memory-usage + riscv64-unknown-elf-gcc $(CFLAGS) -o crt.elf crt.o $(LFLAGS) -Wl,-Bstatic,-T,mapping_rom.ld,-Map,crt.map,--print-memory-usage riscv64-unknown-elf-objdump -S -d crt.elf > crt.asm riscv64-unknown-elf-objcopy -O binary crt.elf crt.bin + riscv64-unknown-elf-gcc $(CFLAGS) -o crt_ram.elf crt.o $(LFLAGS) -Wl,-Bstatic,-T,mapping.ld,-Map,crt_ram.map,--print-memory-usage + riscv64-unknown-elf-objdump -S -d crt_ram.elf > crt_ram.asm + riscv64-unknown-elf-objcopy -O binary crt_ram.elf crt_ram.bin + riscv64-unknown-elf-gcc -c $(CFLAGS) -o demo.o demo.S riscv64-unknown-elf-gcc $(CFLAGS) -o demo.elf demo.o $(LFLAGS) -Wl,-Bstatic,-T,mapping.ld,-Map,demo.map,--print-memory-usage riscv64-unknown-elf-objdump -S -d demo.elf > demo.asm riscv64-unknown-elf-objcopy -O binary demo.elf demo.bin + riscv64-unknown-elf-gcc $(CFLAGS) -o demo_rom.elf demo.o $(LFLAGS) -Wl,-Bstatic,-T,mapping_rom.ld,-Map,demo_rom.map,--print-memory-usage + riscv64-unknown-elf-objdump -S -d demo_rom.elf > demo_rom.asm + riscv64-unknown-elf-objcopy -O binary demo_rom.elf demo_rom.bin + riscv64-unknown-elf-gcc $(CFLAGS) -o demo_xip.elf demo.o $(LFLAGS) -Wl,-Bstatic,-T,mapping_xip.ld,-Map,demo_xip.map,--print-memory-usage + riscv64-unknown-elf-objdump -S -d demo_xip.elf > demo_xip.asm + riscv64-unknown-elf-objcopy -O binary demo_xip.elf demo_xip.bin -clean: +clean-for-commit: rm -f *.o - rm -f *.bin rm -f *.elf rm -f *.asm - rm -f *.map \ No newline at end of file + rm -f *.map + rm -f *.d + rm demo_rom.bin demo.bin crt_ram.bin + +clean: clean-for-commit + rm -f *.bin diff --git a/src/main/c/murax/xipBootloader/mapping_rom.ld b/src/main/c/murax/xipBootloader/mapping_rom.ld new file mode 100644 index 00000000..aaa0c3ca --- /dev/null +++ b/src/main/c/murax/xipBootloader/mapping_rom.ld @@ -0,0 +1,96 @@ +/* +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. +*/ +OUTPUT_FORMAT("elf32-littleriscv", "elf32-littleriscv", "elf32-littleriscv") +OUTPUT_ARCH(riscv) +ENTRY(crtStart) + +MEMORY { + mem : ORIGIN = 0x80000000, LENGTH = 0x00000400 + rom : ORIGIN = 0xF001E000, LENGTH = 0x00000400 +} + +_stack_size = DEFINED(_stack_size) ? _stack_size : 0; + +SECTIONS { + + .vector : { + *crt.o(.text); + } > rom + + .memory : { + *(.text); + end = .; + } > rom + + .rodata : + { + *(.rdata) + *(.rodata .rodata.*) + *(.gnu.linkonce.r.*) + } > rom + + .ctors : + { + . = ALIGN(4); + _ctors_start = .; + KEEP(*(.init_array*)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + . = ALIGN(4); + _ctors_end = .; + } > rom + + .data : + { + *(.rdata) + *(.rodata .rodata.*) + *(.gnu.linkonce.r.*) + *(.data .data.*) + *(.gnu.linkonce.d.*) + . = ALIGN(8); + PROVIDE( __global_pointer$ = . + 0x800 ); + *(.sdata .sdata.*) + *(.gnu.linkonce.s.*) + . = ALIGN(8); + *(.srodata.cst16) + *(.srodata.cst8) + *(.srodata.cst4) + *(.srodata.cst2) + *(.srodata .srodata.*) + } > rom + + .bss (NOLOAD) : { + . = ALIGN(4); + /* This is used by the startup in order to initialize the .bss secion */ + _bss_start = .; + *(.sbss*) + *(.gnu.linkonce.sb.*) + *(.bss .bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(4); + _bss_end = .; + } > mem + + .noinit (NOLOAD) : { + . = ALIGN(4); + *(.noinit .noinit.*) + . = ALIGN(4); + } > mem + + ._stack (NOLOAD): + { + . = ALIGN(16); + PROVIDE (_stack_end = .); + . = . + _stack_size; + . = ALIGN(16); + PROVIDE (_stack_start = .); + } > mem + +} diff --git a/src/main/c/murax/xipBootloader/mapping_xip.ld b/src/main/c/murax/xipBootloader/mapping_xip.ld new file mode 100644 index 00000000..ed564007 --- /dev/null +++ b/src/main/c/murax/xipBootloader/mapping_xip.ld @@ -0,0 +1,96 @@ +/* +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. +*/ +OUTPUT_FORMAT("elf32-littleriscv", "elf32-littleriscv", "elf32-littleriscv") +OUTPUT_ARCH(riscv) +ENTRY(crtStart) + +MEMORY { + mem : ORIGIN = 0x80000000, LENGTH = 0x00000400 + xip : ORIGIN = 0xE0040000, LENGTH = 0x00000400 +} + +_stack_size = DEFINED(_stack_size) ? _stack_size : 0; + +SECTIONS { + + .vector : { + *crt.o(.text); + } > xip + + .memory : { + *(.text); + end = .; + } > xip + + .rodata : + { + *(.rdata) + *(.rodata .rodata.*) + *(.gnu.linkonce.r.*) + } > xip + + .ctors : + { + . = ALIGN(4); + _ctors_start = .; + KEEP(*(.init_array*)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + . = ALIGN(4); + _ctors_end = .; + } > xip + + .data : + { + *(.rdata) + *(.rodata .rodata.*) + *(.gnu.linkonce.r.*) + *(.data .data.*) + *(.gnu.linkonce.d.*) + . = ALIGN(8); + PROVIDE( __global_pointer$ = . + 0x800 ); + *(.sdata .sdata.*) + *(.gnu.linkonce.s.*) + . = ALIGN(8); + *(.srodata.cst16) + *(.srodata.cst8) + *(.srodata.cst4) + *(.srodata.cst2) + *(.srodata .srodata.*) + } > xip + + .bss (NOLOAD) : { + . = ALIGN(4); + /* This is used by the startup in order to initialize the .bss secion */ + _bss_start = .; + *(.sbss*) + *(.gnu.linkonce.sb.*) + *(.bss .bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(4); + _bss_end = .; + } > mem + + .noinit (NOLOAD) : { + . = ALIGN(4); + *(.noinit .noinit.*) + . = ALIGN(4); + } > mem + + ._stack (NOLOAD): + { + . = ALIGN(16); + PROVIDE (_stack_end = .); + . = . + _stack_size; + . = ALIGN(16); + PROVIDE (_stack_start = .); + } > mem + +} diff --git a/src/main/scala/vexriscv/demo/Murax.scala b/src/main/scala/vexriscv/demo/Murax.scala index 42a3d7ef..6d98907b 100644 --- a/src/main/scala/vexriscv/demo/Murax.scala +++ b/src/main/scala/vexriscv/demo/Murax.scala @@ -362,57 +362,55 @@ object Murax_iCE40_hx8k_breakout_board_xip{ case class Murax_iCE40_hx8k_breakout_board_xip() extends Component{ val io = new Bundle { - val J3 = in Bool() - val H16 = in Bool() - val G15 = in Bool() - val G16 = out Bool() - val F15 = in Bool() - val B12 = out Bool() - val B10 = in Bool() + val mainClk = in Bool() + val jtag_tck = in Bool() + val jtag_tdi = in Bool() + val jtag_tdo = out Bool() + val jtag_tms = in Bool() + val uart_txd = out Bool() + val uart_rxd = in Bool() - - //p12 as mosi mean flash config - val P12 = inout(Analog(Bool)) - val P11 = inout(Analog(Bool)) - val R11 = out Bool() - val R12 = out Bool() + val mosi = inout(Analog(Bool)) + val miso = inout(Analog(Bool)) + val sclk = out Bool() + val spis = out Bool() val led = out Bits(8 bits) } - val murax = Murax(MuraxConfig.default(withXip = true)) + val murax = Murax(MuraxConfig.default(withXip = true).copy(onChipRamSize = 8 kB)) murax.io.asyncReset := False val mainClkBuffer = SB_GB() - mainClkBuffer.USER_SIGNAL_TO_GLOBAL_BUFFER <> io.J3 + mainClkBuffer.USER_SIGNAL_TO_GLOBAL_BUFFER <> io.mainClk mainClkBuffer.GLOBAL_BUFFER_OUTPUT <> murax.io.mainClk val jtagClkBuffer = SB_GB() - jtagClkBuffer.USER_SIGNAL_TO_GLOBAL_BUFFER <> io.H16 + jtagClkBuffer.USER_SIGNAL_TO_GLOBAL_BUFFER <> io.jtag_tck jtagClkBuffer.GLOBAL_BUFFER_OUTPUT <> murax.io.jtag.tck io.led <> murax.io.gpioA.write(7 downto 0) - murax.io.jtag.tdi <> io.G15 - murax.io.jtag.tdo <> io.G16 - murax.io.jtag.tms <> io.F15 + murax.io.jtag.tdi <> io.jtag_tdi + murax.io.jtag.tdo <> io.jtag_tdo + murax.io.jtag.tms <> io.jtag_tms murax.io.gpioA.read <> 0 - murax.io.uart.txd <> io.B12 - murax.io.uart.rxd <> io.B10 + murax.io.uart.txd <> io.uart_txd + murax.io.uart.rxd <> io.uart_rxd val xip = new ClockingArea(murax.systemClockDomain) { - RegNext(murax.io.xip.ss.asBool) <> io.R12 + RegNext(murax.io.xip.ss.asBool) <> io.spis val sclkIo = SB_IO_SCLK() - sclkIo.PACKAGE_PIN <> io.R11 + sclkIo.PACKAGE_PIN <> io.sclk sclkIo.CLOCK_ENABLE := True sclkIo.OUTPUT_CLK := ClockDomain.current.readClockWire sclkIo.D_OUT_0 <> murax.io.xip.sclk.write(0) sclkIo.D_OUT_1 <> RegNext(murax.io.xip.sclk.write(1)) - val datas = for ((data, pin) <- (murax.io.xip.data, List(io.P12, io.P11).reverse).zipped) yield new Area { + val datas = for ((data, pin) <- (murax.io.xip.data, List(io.mosi, io.miso)).zipped) yield new Area { val dataIo = SB_IO_DATA() dataIo.PACKAGE_PIN := pin dataIo.CLOCK_ENABLE := True @@ -432,45 +430,6 @@ object Murax_iCE40_hx8k_breakout_board_xip{ def main(args: Array[String]) { SpinalVerilog(Murax_iCE40_hx8k_breakout_board_xip()) - /*SpinalVerilog{ - val c = Murax(MuraxConfig.default(withXip = true)) - - - - - c.rework { - c.resetCtrlClockDomain { - c.io.xip.setAsDirectionLess.allowDirectionLessIo.flattenForeach(_.unsetName()) - - out(RegNext(c.io.xip.ss)).setName("io_xip_ss") - - val sclk = SB_IO_SCLK() - sclk.PACKAGE_PIN := inout(Analog(Bool)).setName("io_xip_sclk") - sclk.CLOCK_ENABLE := True - - sclk.OUTPUT_CLK := ClockDomain.current.readClockWire - sclk.D_OUT_0 <> c.io.xip.sclk.write(0) - sclk.D_OUT_1 <> RegNext(c.io.xip.sclk.write(1)) - - for (i <- 0 until c.io.xip.p.dataWidth) { - val data = c.io.xip.data(i) - val bb = SB_IO_DATA() - bb.PACKAGE_PIN := inout(Analog(Bool)).setName(s"io_xip_data_$i" ) - bb.CLOCK_ENABLE := True - - bb.OUTPUT_CLK := ClockDomain.current.readClockWire - bb.OUTPUT_ENABLE <> data.writeEnable - bb.D_OUT_0 <> data.write(0) - bb.D_OUT_1 <> RegNext(data.write(1)) - - bb.INPUT_CLK := ClockDomain.current.readClockWire - data.read(0) := bb.D_IN_0 - data.read(1) := RegNext(bb.D_IN_1) - } - } - } - c - }*/ } } @@ -512,3 +471,10 @@ object MuraxWithRamInit{ SpinalVerilog(Murax(MuraxConfig.default.copy(onChipRamSize = 4 kB, onChipRamHexFile = "src/main/ressource/hex/muraxDemo.hex"))) } } + +object Murax_arty{ + def main(args: Array[String]) { + val hex = "src/main/c/murax/hello_world/build/hello_world.hex" + SpinalVerilog(Murax(MuraxConfig.default(false).copy(coreFrequency = 100 MHz,onChipRamSize = 32 kB, onChipRamHexFile = hex))) + } +} diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index 591e36e2..838489d2 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -24,8 +24,9 @@ case class DataCacheConfig(cacheSize : Int, earlyDataMux : Boolean = false, tagSizeShift : Int = 0, //Used to force infering ram withLrSc : Boolean = false, - withAmo : Boolean = false){ - + withAmo : Boolean = false, + mergeExecuteMemory : Boolean = false){ + assert(!(mergeExecuteMemory && (earlyDataMux || earlyWaysHits))) assert(!(earlyDataMux && !earlyWaysHits)) def burstSize = bytePerLine*8/memDataWidth val burstLength = bytePerLine/(memDataWidth/8) @@ -447,7 +448,7 @@ class DataCache(p : DataCacheConfig) extends Component{ } val stageA = new Area{ - def stagePipe[T <: Data](that : T) = RegNextWhen(that, !io.cpu.memory.isStuck) + def stagePipe[T <: Data](that : T) = if(mergeExecuteMemory) CombInit(that) else RegNextWhen(that, !io.cpu.memory.isStuck) val request = stagePipe(io.cpu.execute.args) val mask = stagePipe(stage0.mask) io.cpu.memory.mmuBus.cmd.isValid := io.cpu.memory.isValid @@ -458,16 +459,22 @@ class DataCache(p : DataCacheConfig) extends Component{ val wayHits = earlyWaysHits generate ways.map(way => (io.cpu.memory.mmuBus.rsp.physicalAddress(tagRange) === way.tagsReadRsp.address && way.tagsReadRsp.valid)) val dataMux = earlyDataMux generate MuxOH(wayHits, ways.map(_.dataReadRsp)) - val colisions = stagePipe(stage0.colisions) | collisionProcess(io.cpu.memory.address(lineRange.high downto wordRange.low), mask) //Assume the writeback stage will never be unstall memory acces while memory stage is stalled + val colisions = if(mergeExecuteMemory){ + stagePipe(stage0.colisions) + } else { + //Assume the writeback stage will never be unstall memory acces while memory stage is stalled + stagePipe(stage0.colisions) | collisionProcess(io.cpu.memory.address(lineRange.high downto wordRange.low), mask) + } } val stageB = new Area { def stagePipe[T <: Data](that : T) = RegNextWhen(that, !io.cpu.writeBack.isStuck) + def ramPipe[T <: Data](that : T) = if(mergeExecuteMemory) CombInit(that) else RegNextWhen(that, !io.cpu.writeBack.isStuck) val request = RegNextWhen(stageA.request, !io.cpu.writeBack.isStuck) val mmuRspFreeze = False val mmuRsp = RegNextWhen(io.cpu.memory.mmuBus.rsp, !io.cpu.writeBack.isStuck && !mmuRspFreeze) - val tagsReadRsp = ways.map(w => stagePipe(w.tagsReadRsp)) - val dataReadRsp = !earlyDataMux generate ways.map(w => stagePipe(w.dataReadRsp)) + val tagsReadRsp = ways.map(w => ramPipe(w.tagsReadRsp)) + val dataReadRsp = !earlyDataMux generate ways.map(w => ramPipe(w.dataReadRsp)) val waysHits = if(earlyWaysHits) stagePipe(B(stageA.wayHits)) else B(tagsReadRsp.map(tag => mmuRsp.physicalAddress(tagRange) === tag.address && tag.valid).asBits()) val waysHit = waysHits.orR val dataMux = if(earlyDataMux) stagePipe(stageA.dataMux) else MuxOH(waysHits, dataReadRsp) diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index 978dd5db..f0eaa81a 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -148,7 +148,7 @@ class DBusCachedPlugin(val config : DataCacheConfig, redoBranch = pipeline.service(classOf[JumpService]).createJumpInterface(if(pipeline.writeBack != null) pipeline.writeBack else pipeline.execute) if(catchSomething) - exceptionBus = pipeline.service(classOf[ExceptionService]).newExceptionPort(pipeline.writeBack) + exceptionBus = pipeline.service(classOf[ExceptionService]).newExceptionPort(if(pipeline.writeBack == null) pipeline.memory else pipeline.writeBack) if(pipeline.serviceExist(classOf[PrivilegeService])) privilegeService = pipeline.service(classOf[PrivilegeService]) @@ -162,7 +162,9 @@ class DBusCachedPlugin(val config : DataCacheConfig, dBus = master(DataCacheMemBus(this.config)).setName("dBus") - val cache = new DataCache(this.config) + val cache = new DataCache(this.config.copy( + mergeExecuteMemory = writeBack == null + )) //Interconnect the plugin dBus with the cache dBus with some optional pipelining def optionPipe[T](cond : Boolean, on : T)(f : T => T) : T = if(cond) f(on) else on @@ -225,23 +227,29 @@ class DBusCachedPlugin(val config : DataCacheConfig, if(relaxedMemoryTranslationRegister) { insert(MEMORY_VIRTUAL_ADDRESS) := cache.io.cpu.execute.address - addPrePopTask( () => KeepAttribute(memory.input(MEMORY_VIRTUAL_ADDRESS).getDrivingReg)) + memory.input(MEMORY_VIRTUAL_ADDRESS) + if(writeBack != null) addPrePopTask( () => + KeepAttribute(memory.input(MEMORY_VIRTUAL_ADDRESS).getDrivingReg) + ) } } - memory plug new Area{ - import memory._ + val mmuAndBufferStage = if(writeBack != null) memory else execute + mmuAndBufferStage plug new Area { + import mmuAndBufferStage._ + cache.io.cpu.memory.isValid := arbitration.isValid && input(MEMORY_ENABLE) cache.io.cpu.memory.isStuck := arbitration.isStuck cache.io.cpu.memory.isRemoved := arbitration.removeIt - cache.io.cpu.memory.address := (if(relaxedMemoryTranslationRegister) input(MEMORY_VIRTUAL_ADDRESS) else U(input(REGFILE_WRITE_DATA))) + cache.io.cpu.memory.address := (if(relaxedMemoryTranslationRegister) input(MEMORY_VIRTUAL_ADDRESS) else if(mmuAndBufferStage == execute) cache.io.cpu.execute.address else U(input(REGFILE_WRITE_DATA))) cache.io.cpu.memory.mmuBus <> mmuBus cache.io.cpu.memory.mmuBus.rsp.isIoAccess setWhen(pipeline(DEBUG_BYPASS_CACHE) && !cache.io.cpu.memory.isWrite) } - writeBack plug new Area{ - import writeBack._ + val managementStage = stages.last + managementStage plug new Area{ + import managementStage._ 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() else False) @@ -326,10 +334,10 @@ class DBusCachedPlugin(val config : DataCacheConfig, execute.insert(IS_DBUS_SHARING) := dBusAccess.cmd.fire - mmuBus.cmd.bypassTranslation setWhen(memory.input(IS_DBUS_SHARING)) - cache.io.cpu.memory.isValid setWhen(memory.input(IS_DBUS_SHARING)) - cache.io.cpu.writeBack.isValid setWhen(writeBack.input(IS_DBUS_SHARING)) - dBusAccess.rsp.valid := writeBack.input(IS_DBUS_SHARING) && !cache.io.cpu.writeBack.isWrite && (cache.io.cpu.redo || !cache.io.cpu.writeBack.haltIt) + mmuBus.cmd.bypassTranslation setWhen(mmuAndBufferStage.input(IS_DBUS_SHARING)) + if(mmuAndBufferStage != execute) (cache.io.cpu.memory.isValid setWhen(mmuAndBufferStage.input(IS_DBUS_SHARING))) + cache.io.cpu.writeBack.isValid setWhen(managementStage.input(IS_DBUS_SHARING)) + dBusAccess.rsp.valid := managementStage.input(IS_DBUS_SHARING) && !cache.io.cpu.writeBack.isWrite && (cache.io.cpu.redo || !cache.io.cpu.writeBack.haltIt) dBusAccess.rsp.data := cache.io.cpu.writeBack.data dBusAccess.rsp.error := cache.io.cpu.writeBack.unalignedAccess || cache.io.cpu.writeBack.accessError dBusAccess.rsp.redo := cache.io.cpu.redo @@ -337,10 +345,10 @@ class DBusCachedPlugin(val config : DataCacheConfig, when(forceDatapath){ execute.output(REGFILE_WRITE_DATA) := dBusAccess.cmd.address.asBits } - memory.input(IS_DBUS_SHARING) init(False) - writeBack.input(IS_DBUS_SHARING) init(False) + if(mmuAndBufferStage != execute) mmuAndBufferStage.input(IS_DBUS_SHARING) init(False) + managementStage.input(IS_DBUS_SHARING) init(False) when(dBusAccess.rsp.valid){ - writeBack.input(IS_DBUS_SHARING).getDrivingReg := False + managementStage.input(IS_DBUS_SHARING).getDrivingReg := False } } } diff --git a/src/main/scala/vexriscv/plugin/HazardSimplePlugin.scala b/src/main/scala/vexriscv/plugin/HazardSimplePlugin.scala index f674ae87..1ed1d83e 100644 --- a/src/main/scala/vexriscv/plugin/HazardSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/HazardSimplePlugin.scala @@ -95,7 +95,7 @@ class HazardSimplePlugin(bypassExecute : Boolean = false, } if(withWriteBackStage) trackHazardWithStage(writeBack,bypassWriteBack,null) - if(withMemoryStage) trackHazardWithStage(memory ,bypassMemory ,BYPASSABLE_MEMORY_STAGE) + if(withMemoryStage) trackHazardWithStage(memory ,bypassMemory, if(stages.last == memory) null else BYPASSABLE_MEMORY_STAGE) if(readStage != execute) trackHazardWithStage(execute ,bypassExecute , if(stages.last == execute) null else BYPASSABLE_EXECUTE_STAGE) diff --git a/src/main/scala/vexriscv/plugin/Mul16Plugin.scala b/src/main/scala/vexriscv/plugin/Mul16Plugin.scala new file mode 100644 index 00000000..f2a63c31 --- /dev/null +++ b/src/main/scala/vexriscv/plugin/Mul16Plugin.scala @@ -0,0 +1,119 @@ +package vexriscv.plugin + +import vexriscv._ +import vexriscv.plugin._ +import spinal.core._ + +/** + * A multiplication plugin using only 16-bit multiplications + */ +class Mul16Plugin extends Plugin[VexRiscv]{ + + object MUL_LL extends Stageable(UInt(32 bits)) + object MUL_LH extends Stageable(UInt(32 bits)) + object MUL_HL extends Stageable(UInt(32 bits)) + object MUL_HH extends Stageable(UInt(32 bits)) + + object MUL extends Stageable(Bits(64 bits)) + + object IS_MUL extends Stageable(Bool) + + override def setup(pipeline: VexRiscv): Unit = { + import Riscv._ + import pipeline.config._ + + + val actions = List[(Stageable[_ <: BaseType],Any)]( + SRC1_CTRL -> Src1CtrlEnum.RS, + SRC2_CTRL -> Src2CtrlEnum.RS, + REGFILE_WRITE_VALID -> True, + BYPASSABLE_EXECUTE_STAGE -> False, + BYPASSABLE_MEMORY_STAGE -> False, + RS1_USE -> True, + RS2_USE -> True, + IS_MUL -> True + ) + + val decoderService = pipeline.service(classOf[DecoderService]) + decoderService.addDefault(IS_MUL, False) + decoderService.add(List( + MULX -> actions + )) + + } + + override def build(pipeline: VexRiscv): Unit = { + import pipeline._ + import pipeline.config._ + + // Prepare signed inputs for the multiplier in the next stage. + // This will map them best to an FPGA DSP. + execute plug new Area { + import execute._ + val a,b = Bits(32 bit) + + a := input(SRC1) + b := input(SRC2) + + val aLow = a(15 downto 0).asUInt + val bLow = b(15 downto 0).asUInt + val aHigh = a(31 downto 16).asUInt + val bHigh = b(31 downto 16).asUInt + + insert(MUL_LL) := aLow * bLow + insert(MUL_LH) := aLow * bHigh + insert(MUL_HL) := aHigh * bLow + insert(MUL_HH) := aHigh * bHigh + } + + memory plug new Area { + import memory._ + + val ll = UInt(32 bits) + val lh = UInt(33 bits) + val hl = UInt(32 bits) + val hh = UInt(32 bits) + + ll := input(MUL_LL) + lh := input(MUL_LH).resized + hl := input(MUL_HL) + hh := input(MUL_HH) + + val hllh = lh + hl + insert(MUL) := ((hh ## ll(31 downto 16)).asUInt + hllh) ## ll(15 downto 0) + } + + writeBack plug new Area { + import writeBack._ + val aSigned,bSigned = Bool + switch(input(INSTRUCTION)(13 downto 12)) { + is(B"01") { + aSigned := True + bSigned := True + } + is(B"10") { + aSigned := True + bSigned := False + } + default { + aSigned := False + bSigned := False + } + } + + val a = (aSigned && input(SRC1).msb) ? input(SRC2).asUInt | U(0) + val b = (bSigned && input(SRC2).msb) ? input(SRC1).asUInt | U(0) + + when(arbitration.isValid && input(IS_MUL)){ + switch(input(INSTRUCTION)(13 downto 12)){ + is(B"00"){ + output(REGFILE_WRITE_DATA) := input(MUL)(31 downto 0) + } + is(B"01",B"10",B"11"){ + output(REGFILE_WRITE_DATA) := (((input(MUL)(63 downto 32)).asUInt + ~a) + (~b + 2)).asBits + } + } + } + } + } +} diff --git a/src/main/scala/vexriscv/plugin/MulDivIterativePlugin.scala b/src/main/scala/vexriscv/plugin/MulDivIterativePlugin.scala index f366854c..6820f8ec 100644 --- a/src/main/scala/vexriscv/plugin/MulDivIterativePlugin.scala +++ b/src/main/scala/vexriscv/plugin/MulDivIterativePlugin.scala @@ -31,7 +31,7 @@ class MulDivIterativePlugin(genMul : Boolean = true, SRC1_CTRL -> Src1CtrlEnum.RS, SRC2_CTRL -> Src2CtrlEnum.RS, REGFILE_WRITE_VALID -> True, - BYPASSABLE_EXECUTE_STAGE -> False, + BYPASSABLE_EXECUTE_STAGE -> Bool(pipeline.stages.last == pipeline.execute), BYPASSABLE_MEMORY_STAGE -> True, RS1_USE -> True, RS2_USE -> True @@ -69,21 +69,28 @@ class MulDivIterativePlugin(genMul : Boolean = true, import pipeline.config._ if(!genMul && !genDiv) return - memory plug new Area { - import memory._ + val flushStage = if(memory != null) memory else execute + flushStage plug new Area { + import flushStage._ //Shared ressources val rs1 = Reg(UInt(33 bits)) val rs2 = Reg(UInt(32 bits)) val accumulator = Reg(UInt(65 bits)) + //FrontendOK is only used for CPU configs without memory/writeback stages, were it is required to wait one extra cycle + // to let's the frontend process rs1 rs2 registers + val frontendOk = if(flushStage != execute) True else RegInit(False) setWhen(arbitration.isValid && !pipeline.service(classOf[HazardService]).hazardOnExecuteRS && ((if(genDiv) input(IS_DIV) else False) || (if(genMul) input(IS_MUL) else False))) clearWhen(arbitration.isMoving) val mul = ifGen(genMul) (if(customMul != null) customMul(rs1,rs2,memory,pipeline) else new Area{ assert(isPow2(mulUnrollFactor)) val counter = Counter(32 / mulUnrollFactor + 1) val done = counter.willOverflowIfInc when(arbitration.isValid && input(IS_MUL)){ - when(!done){ + when(!frontendOk || !done){ + arbitration.haltItself := True + } + when(frontendOk && !done){ arbitration.haltItself := True counter.increment() rs2 := rs2 |>> mulUnrollFactor @@ -112,8 +119,10 @@ class MulDivIterativePlugin(genMul : Boolean = true, val done = Reg(Bool) setWhen(counter === counter.end-1) clearWhen(!arbitration.isStuck) val result = Reg(Bits(32 bits)) when(arbitration.isValid && input(IS_DIV)){ - when(!done){ + when(!frontendOk || !done){ arbitration.haltItself := True + } + when(frontendOk && !done){ counter.increment() def stages(inNumerator: UInt, inRemainder: UInt, stage: Int): Unit = stage match { @@ -139,16 +148,11 @@ class MulDivIterativePlugin(genMul : Boolean = true, } output(REGFILE_WRITE_DATA) := result -// when(input(INSTRUCTION)(13 downto 12) === "00" && counter === 0 && rs2 =/= 0 && rs1 < 16 && rs2 < 16 && !input(RS1).msb && !input(RS2).msb) { -// output(REGFILE_WRITE_DATA) := B(rs1(3 downto 0) / rs2(3 downto 0)).resized -// counter.willIncrement := False -// arbitration.haltItself := False -// } } }) //Execute stage logic to drive memory stage's input regs - when(!arbitration.isStuck){ + when(if(flushStage != execute) !arbitration.isStuck else !frontendOk){ accumulator := 0 def twoComplement(that : Bits, enable: Bool): UInt = (Mux(enable, ~that, that).asUInt + enable.asUInt) val rs2NeedRevert = execute.input(RS2).msb && execute.input(IS_RS2_SIGNED) diff --git a/src/main/scala/vexriscv/plugin/MulSimplePlugin.scala b/src/main/scala/vexriscv/plugin/MulSimplePlugin.scala index 41ed3916..3b407e1d 100644 --- a/src/main/scala/vexriscv/plugin/MulSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/MulSimplePlugin.scala @@ -19,8 +19,8 @@ class MulSimplePlugin extends Plugin[VexRiscv]{ SRC1_CTRL -> Src1CtrlEnum.RS, SRC2_CTRL -> Src2CtrlEnum.RS, REGFILE_WRITE_VALID -> True, - BYPASSABLE_EXECUTE_STAGE -> False, - BYPASSABLE_MEMORY_STAGE -> False, + BYPASSABLE_EXECUTE_STAGE -> Bool(pipeline.stages.last == pipeline.execute), + BYPASSABLE_MEMORY_STAGE -> Bool(pipeline.stages.last == pipeline.memory), RS1_USE -> True, RS2_USE -> True, IS_MUL -> True @@ -66,14 +66,16 @@ class MulSimplePlugin extends Plugin[VexRiscv]{ insert(MUL_OPB) := ((bSigned ? b.msb | False) ## b).asSInt } - memory plug new Area { - import memory._ + val injectionStage = if(pipeline.memory != null) pipeline.memory else pipeline.execute + injectionStage plug new Area { + import injectionStage._ insert(MUL) := (input(MUL_OPA) * input(MUL_OPB))(63 downto 0).asBits } - writeBack plug new Area { - import writeBack._ + val memStage = stages.last + memStage plug new Area { + import memStage._ when(arbitration.isValid && input(IS_MUL)){ switch(input(INSTRUCTION)(13 downto 12)){ diff --git a/src/test/scala/vexriscv/TestIndividualFeatures.scala b/src/test/scala/vexriscv/TestIndividualFeatures.scala index 33e4aa6e..005f3359 100644 --- a/src/test/scala/vexriscv/TestIndividualFeatures.scala +++ b/src/test/scala/vexriscv/TestIndividualFeatures.scala @@ -99,6 +99,35 @@ class MulDivDimension extends VexRiscvDimension("MulDiv") { val noWriteBack = universes.contains(VexRiscvUniverse.NO_WRITEBACK) var l = List[VexRiscvPosition]() + + + + l = new VexRiscvPosition("MulDivFpgaSimple") { + override def testParam = "MUL=yes DIV=yes" + override def applyOn(config: VexRiscvConfig): Unit = { + config.plugins += new MulSimplePlugin + config.plugins += new MulDivIterativePlugin( + genMul = false, + genDiv = true, + mulUnrollFactor = 32, + divUnrollFactor = 1 + ) + } + } :: l + + if(!noMemory && !noWriteBack) l = new VexRiscvPosition("MulDivFpga16BitsDsp") { + override def testParam = "MUL=yes DIV=yes" + override def applyOn(config: VexRiscvConfig): Unit = { + config.plugins += new Mul16Plugin + config.plugins += new MulDivIterativePlugin( + genMul = false, + genDiv = true, + mulUnrollFactor = 32, + divUnrollFactor = 1 + ) + } + } :: l + if(!noMemory) { l = new VexRiscvPosition("MulDivAsic") { override def testParam = "MUL=yes DIV=yes" @@ -376,7 +405,7 @@ class DBusDimension extends VexRiscvDimension("DBus") { - if(r.nextDouble() < 0.4 || noMemory || noWriteBack){ + if(r.nextDouble() < 0.4 || noMemory){ val withLrSc = catchAll val earlyInjection = r.nextBoolean() && !universes.contains(VexRiscvUniverse.NO_WRITEBACK) new VexRiscvPosition("Simple" + (if(earlyInjection) "Early" else "Late")) { @@ -396,7 +425,8 @@ class DBusDimension extends VexRiscvDimension("DBus") { var wayCount = 0 val withLrSc = catchAll val withAmo = catchAll && r.nextBoolean() - val dBusRspSlavePipe, relaxedMemoryTranslationRegister, earlyWaysHits = r.nextBoolean() + val dBusRspSlavePipe, relaxedMemoryTranslationRegister = r.nextBoolean() + val earlyWaysHits = r.nextBoolean() && !noWriteBack val dBusCmdMasterPipe, dBusCmdSlavePipe = false //As it create test bench issues do{ @@ -600,11 +630,11 @@ class TestIndividualFeatures extends FunSuite { val testId : Option[mutable.HashSet[Int]] = None val seed = sys.env.getOrElse("VEXRISCV_REGRESSION_SEED", Random.nextLong().toString).toLong - +// // val testId = Some(mutable.HashSet(3,4,9,11,13,16,18,19,20,21)) -// val testId = Some(mutable.HashSet(24, 43, 49)) -// val testId = Some(mutable.HashSet(11)) -// val seed = -8309068850561113754l +// val testId = Some(mutable.HashSet(11)) +// val testId = Some(mutable.HashSet(4, 11)) +// val seed = 6592877339343561798l val rand = new Random(seed) @@ -622,11 +652,16 @@ class TestIndividualFeatures extends FunSuite { universe += VexRiscvUniverse.MMU universe += VexRiscvUniverse.FORCE_MULDIV universe += VexRiscvUniverse.SUPERVISOR + if(sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_DEMW_RATE", "0.6").toDouble < rand.nextDouble()){ + universe += VexRiscvUniverse.NO_WRITEBACK + } } else { if(sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_MACHINE_OS_RATE", "0.5").toDouble > rand.nextDouble()) { universe += VexRiscvUniverse.CATCH_ALL + if(sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_DEMW_RATE", "0.6").toDouble < rand.nextDouble()){ + universe += VexRiscvUniverse.NO_WRITEBACK + } } - var tmp = rand.nextDouble() if(sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_DEMW_RATE", "0.6").toDouble > rand.nextDouble()){ }else if(sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_DEM_RATE", "0.5").toDouble > rand.nextDouble()){ universe += VexRiscvUniverse.NO_WRITEBACK From 390645e581c802b4e1321068d0cfe3769109eef6 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Wed, 29 Jan 2020 23:20:35 +0100 Subject: [PATCH 293/951] SpinalHDL 1.3.8 --- build.sbt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/build.sbt b/build.sbt index ccb19f17..a938f345 100644 --- a/build.sbt +++ b/build.sbt @@ -7,16 +7,16 @@ lazy val root = (project in file(".")). version := "2.0.0" )), libraryDependencies ++= Seq( -// "com.github.spinalhdl" % "spinalhdl-core_2.11" % "1.3.6", -// "com.github.spinalhdl" % "spinalhdl-lib_2.11" % "1.3.6", + "com.github.spinalhdl" % "spinalhdl-core_2.11" % "1.3.8", + "com.github.spinalhdl" % "spinalhdl-lib_2.11" % "1.3.8", "org.scalatest" % "scalatest_2.11" % "2.2.1", "org.yaml" % "snakeyaml" % "1.8" ), name := "VexRiscv" - ).dependsOn(spinalHdlSim,spinalHdlCore,spinalHdlLib) -lazy val spinalHdlSim = ProjectRef(file("../SpinalHDL"), "sim") -lazy val spinalHdlCore = ProjectRef(file("../SpinalHDL"), "core") -lazy val spinalHdlLib = ProjectRef(file("../SpinalHDL"), "lib") + )//.dependsOn(spinalHdlSim,spinalHdlCore,spinalHdlLib) +//lazy val spinalHdlSim = ProjectRef(file("../SpinalHDL"), "sim") +//lazy val spinalHdlCore = ProjectRef(file("../SpinalHDL"), "core") +//lazy val spinalHdlLib = ProjectRef(file("../SpinalHDL"), "lib") fork := true \ No newline at end of file From 38a573a48c6b17c6f41294ec811cc711f550f3bb Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Mon, 3 Feb 2020 13:35:55 +0100 Subject: [PATCH 294/951] Update build.sbt --- build.sbt | 1 + 1 file changed, 1 insertion(+) diff --git a/build.sbt b/build.sbt index ccb19f17..27bcb19b 100644 --- a/build.sbt +++ b/build.sbt @@ -6,6 +6,7 @@ lazy val root = (project in file(".")). scalaVersion := "2.11.12", version := "2.0.0" )), + scalacOptions += s"-Xplugin:${new File("../SpinalHDL/idslplugin/target/scala-2.11/spinalhdl-idsl-plugin_2.11-1.3.9.jar").getAbsolutePath}", libraryDependencies ++= Seq( // "com.github.spinalhdl" % "spinalhdl-core_2.11" % "1.3.6", // "com.github.spinalhdl" % "spinalhdl-lib_2.11" % "1.3.6", From 10da093422368de055b08dd3433e27b906c1521d Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Thu, 6 Feb 2020 21:07:40 +0100 Subject: [PATCH 295/951] Fix sbt --- build.sbt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/build.sbt b/build.sbt index 27bcb19b..ac8feba7 100644 --- a/build.sbt +++ b/build.sbt @@ -1,4 +1,3 @@ - lazy val root = (project in file(".")). settings( inThisBuild(List( @@ -6,7 +5,8 @@ lazy val root = (project in file(".")). scalaVersion := "2.11.12", version := "2.0.0" )), - scalacOptions += s"-Xplugin:${new File("../SpinalHDL/idslplugin/target/scala-2.11/spinalhdl-idsl-plugin_2.11-1.3.9.jar").getAbsolutePath}", + scalacOptions += s"-Xplugin:${new File(baseDirectory.value + "/../SpinalHDL/idslplugin/target/scala-2.11/spinalhdl-idsl-plugin_2.11-1.3.9.jar")}", + scalacOptions += s"-Xplugin-require:idsl-plugin", libraryDependencies ++= Seq( // "com.github.spinalhdl" % "spinalhdl-core_2.11" % "1.3.6", // "com.github.spinalhdl" % "spinalhdl-lib_2.11" % "1.3.6", @@ -14,10 +14,10 @@ lazy val root = (project in file(".")). "org.yaml" % "snakeyaml" % "1.8" ), name := "VexRiscv" - ).dependsOn(spinalHdlSim,spinalHdlCore,spinalHdlLib) + ).dependsOn(spinalHdlIdslPlugin, spinalHdlSim,spinalHdlCore,spinalHdlLib) +lazy val spinalHdlIdslPlugin = ProjectRef(file("../SpinalHDL"), "idslplugin") lazy val spinalHdlSim = ProjectRef(file("../SpinalHDL"), "sim") lazy val spinalHdlCore = ProjectRef(file("../SpinalHDL"), "core") lazy val spinalHdlLib = ProjectRef(file("../SpinalHDL"), "lib") - fork := true \ No newline at end of file From fd961dccb5753e9872c427d37be9b231eea5e0f9 Mon Sep 17 00:00:00 2001 From: japm48 Date: Tue, 11 Feb 2020 18:18:39 +0100 Subject: [PATCH 296/951] Readme: fix spelling and made some clarifications --- README.md | 184 +++++++++++++++++++++++++++--------------------------- 1 file changed, 91 insertions(+), 93 deletions(-) diff --git a/README.md b/README.md index d0deb166..29d3ad22 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ - [CPU generation](#cpu-generation) - [Regression tests](#regression-tests) - [Interactive debug of the simulated CPU via GDB OpenOCD and Verilator](#interactive-debug-of-the-simulated-cpu-via-gdb-openocd-and-verilator) -- [Using Eclipse to run the software and debug it](#using-Eclipse-to-run-the-software-and-debug-it) +- [Using Eclipse to run and debug the software](#using-Eclipse-to-run-and-debug-the-software) * [By using gnu-mcu-eclipse](#by-using-gnu-mcu-eclipse) * [By using Zylin plugin (old)](#by-using-zylin-plugin-old) - [Briey SoC](#briey-soc) @@ -30,14 +30,14 @@ This repository hosts a RISC-V implementation written in SpinalHDL. Here are som - RV32I[M][C][A] instruction set (Atomic only inside a single core) - Pipelined from 2 to 5+ stages ([Fetch*X], Decode, Execute, [Memory], [WriteBack]) - 1.44 DMIPS/Mhz --no-inline when nearly all features are enabled (1.57 DMIPS/Mhz when the divider lookup table is enabled) -- Optimized for FPGA, do not use any vendor specific IP block / primitive +- Optimized for FPGA, does not use any vendor specific IP block / primitive - AXI4, Avalon, wishbone ready - Optional MUL/DIV extensions - Optional instruction and data caches - Optional hardware refilled MMU - Optional debug extension allowing Eclipse debugging via a GDB >> openOCD >> JTAG connection - Optional interrupts and exception handling with Machine, [Supervisor] and [User] modes as defined in the [RISC-V Privileged ISA Specification v1.10](https://riscv.org/specifications/privileged-isa/). -- Two implementations of shift instructions: Single cycle and shiftNumber cycles +- Two implementations of shift instructions: single cycle (full barrel shifter) and shiftNumber cycles - Each stage can have optional bypass or interlock hazard logic - Linux compatible (SoC : https://github.com/enjoy-digital/linux-on-litex-vexriscv) - Zephyr compatible @@ -60,7 +60,7 @@ For commercial support, please contact spinalhdl@gmail.com. The following numbers were obtained by synthesizing the CPU as toplevel without any specific synthesis options to save area or to get better maximal frequency (neutral).
The clock constraint is set to an unattainable value, which tends to increase the design area.
The dhrystone benchmark was compiled with the `-O3 -fno-inline` option.
-All the cached configurations have some cache trashing during the dhrystone benchmark except the `VexRiscv full max perf` one. This of course reduces the performance. It is possible to produce +All the cached configurations have some cache trashing during the dhrystone benchmark except the `VexRiscv full max perf` one. This, of course, reduces the performance. It is possible to produce dhrystone binaries which fit inside a 4KB I$ and 4KB D$ (I already had this case once) but currently it isn't the case.
The CPU configurations used below can be found in the `src/scala/vexriscv/demo` directory. @@ -118,7 +118,7 @@ VexRiscv linux balanced (RV32IMA, 1.21 DMIPS/Mhz 2.27 Coremark/Mhz, with cache t The following configuration results in 1.44 DMIPS/MHz: -- 5 stage : F -> D -> E -> M -> WB +- 5 stage: F -> D -> E -> M -> WB - single cycle ADD/SUB/Bitwise/Shift ALU - branch/jump done in the E stage - memory load values are bypassed in the WB stage (late result) @@ -126,11 +126,11 @@ The following configuration results in 1.44 DMIPS/MHz: - single cycle multiplication with bypassing in the WB stage (late result) - dynamic branch prediction done in the F stage with a direct mapped target buffer cache (no penalties on correct predictions) -Note that recently, the capability to remove the Fetch/Memory/WriteBack stage was added to reduce the area of the CPU, which end up with a smaller CPU and a better DMIPS/Mhz for the small configurations. +Note that, recently, the capability to remove the Fetch/Memory/WriteBack stage was added to reduce the area of the CPU, which ends up with a smaller CPU and a better DMIPS/Mhz for the small configurations. ## Dependencies -On Ubuntu 14 : +On Ubuntu 14: ```sh # JAVA JDK 8 @@ -146,7 +146,7 @@ sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 2EE0EA64E40A89 sudo apt-get update sudo apt-get install sbt -# Verilator (for sim only, realy need 3.9+, in general apt-get will give you 3.8) +# Verilator (for sim only, really needs 3.9+, in general apt-get will give you 3.8) sudo apt-get install git make autoconf g++ flex bison git clone http://git.veripool.org/git/verilator # Only first time unsetenv VERILATOR_ROOT # For csh; ignore error if on bash @@ -162,10 +162,10 @@ sudo make install ## CPU generation You can find two example CPU instances in: -- src/main/scala/vexriscv/demo/GenFull.scala -- src/main/scala/vexriscv/demo/GenSmallest.scala +- `src/main/scala/vexriscv/demo/GenFull.scala` +- `src/main/scala/vexriscv/demo/GenSmallest.scala` -To generate the corresponding RTL as a VexRiscv.v file, run the following commands in the root directory of this repository: +To generate the corresponding RTL as a `VexRiscv.v` file, run the following commands in the root directory of this repository: ```sh sbt "runMain vexriscv.demo.GenFull" @@ -186,11 +186,11 @@ NOTES: [![Build Status](https://travis-ci.org/SpinalHDL/VexRiscv.svg?branch=master)](https://travis-ci.org/SpinalHDL/VexRiscv) -To run tests (need the verilator simulator), go in the src/test/cpp/regression folder and run : +To run tests (Verilator simulator is required), go in the `src/test/cpp/regression` folder and run: ```sh # To test the GenFull CPU -# (Don't worry about the CSR test not passing, basicaly the GenFull isn't the truly full version of the CPU, some CSR features are disable in it) +# (Don't worry about the CSR test not passing, basically the GenFull isn't the truly full version of the CPU, some CSR features are disabled in it) make clean run # To test the GenSmallest CPU @@ -203,16 +203,16 @@ The self-test includes: - 24 FreeRTOS tests - Some handwritten tests to check the CSR, debug module and MMU plugins -You can enable FreeRTOS tests by adding `FREERTOS=yes` to the command line, but it will take time to run. Also, it uses THREAD_COUNT host CPU threads to run multiple regression in parallel. +You can enable FreeRTOS tests by adding `FREERTOS=yes` to the command line, but it will take time to run. Also, it uses `THREAD_COUNT` host CPU threads to run multiple regression tests in parallel. ## Interactive debug of the simulated CPU via GDB OpenOCD and Verilator -It's as described to run tests, but you just have to add `DEBUG_PLUGIN_EXTERNAL=yes` in the make arguments. -Work for the GenFull, but not for the GenSmallest as this configuration has no debug module. +To use this, you just need to use the same command as with running tests, but adding `DEBUG_PLUGIN_EXTERNAL=yes` in the make arguments. +This works for the `GenFull` configuration, but not for `GenSmallest`, as this configuration has no debug module. -Then you can use the https://github.com/SpinalHDL/openocd_riscv tool to create a GDB server connected to the target (the simulated CPU) +Then, you can use the [OpenOCD RISC-V](https://github.com/SpinalHDL/openocd_riscv) tool to create a GDB server connected to the target (the simulated CPU), as follows: ```sh -#in the VexRiscv repository, to run the simulation on which one OpenOCD can connect itself => +#In the VexRiscv repository, to run the simulation on which one OpenOCD can connect itself => sbt "runMain vexriscv.demo.GenFull" cd src/test/cpp/regression make run DEBUG_PLUGIN_EXTERNAL=yes @@ -230,17 +230,17 @@ continue # Now it should print messages in the Verilator simulation of the CPU ``` -## Using Eclipse to run the software and debug it +## Using Eclipse to run and debug the software ### By using gnu-mcu-eclipse -You can download releases of the IDE here : https://github.com/gnu-mcu-eclipse/org.eclipse.epp.packages/releases +You can download releases of the IDE here: -In the IDE, you can import a makefile project by : +In the IDE, you can import a makefile project by: - file -> import -> C/C++ -> existing Code as Makefile Project -- Select the folder which contain the makefile, select "Cross GCC" (not "RISC-V Cross GCC") +- Select the folder which contains the makefile, then select "Cross GCC" (not "RISC-V Cross GCC") -To create a new debug configuration : +To create a new debug configuration: - run -> Debug Configurations -> GDB OpenOCD Debugging double click - Look at https://drive.google.com/open?id=1c46tyEV0xLwOsk76b0y2qqs8CYy7Zq3f for a configuration example @@ -257,13 +257,13 @@ cd eclipse See https://drive.google.com/drive/folders/1NseNHH05B6lmIXqQFVwK8xRjWE4ydeG-?usp=sharing to import a makefile project and create a debug configuration. -Note that sometime this Eclipse need to be restarted in order to be able to place new breakpoints. +Note that sometimes Eclipse needs to be restarted in order to be able to place new breakpoints. ## Briey SoC -As a demonstrator, a SoC named Briey is implemented in `src/main/scala/vexriscv/demo/Briey.scala`. This SoC is very similar to -the [Pinsec SOC](https://spinalhdl.github.io/SpinalDoc/spinal/lib/pinsec/hardware/): +As a demonstration, a SoC named Briey is implemented in `src/main/scala/vexriscv/demo/Briey.scala`. This SoC is very similar to +the [Pinsec SoC](https://spinalhdl.github.io/SpinalDoc/spinal/lib/pinsec/hardware/): -![Alt text](assets/brieySoc.png?raw=true "") +![Briey SoC](assets/brieySoc.png?raw=true "") To generate the Briey SoC Hardware: @@ -271,7 +271,7 @@ To generate the Briey SoC Hardware: sbt "runMain vexriscv.demo.Briey" ``` -To run the verilator simulation of the Briey SoC which can then be connected to OpenOCD/GDB, first get those dependencies: +To run the verilator simulation of the Briey SoC, which can then be connected to OpenOCD/GDB, first get these dependencies: ```sh sudo apt-get install build-essential xorg-dev libudev-dev libts-dev libgl1-mesa-dev libglu1-mesa-dev libasound2-dev libpulse-dev libopenal-dev libogg-dev libvorbis-dev libaudiofile-dev libpng12-dev libfreetype6-dev libusb-dev libdbus-1-dev zlib1g-dev libdirectfb-dev libsdl2-dev @@ -289,11 +289,11 @@ To connect OpenOCD (https://github.com/SpinalHDL/openocd_riscv) to the simulatio src/openocd -f tcl/interface/jtag_tcp.cfg -c "set BRIEY_CPU0_YAML /home/spinalvm/Spinal/VexRiscv/cpu0.yaml" -f tcl/target/briey.cfg ``` -You can find multiple software examples and demos here: https://github.com/SpinalHDL/VexRiscvSocSoftware/tree/master/projects/briey +You can find multiple software examples and demos here: You can find some FPGA projects which instantiate the Briey SoC here (DE1-SoC, DE0-Nano): https://drive.google.com/drive/folders/0B-CqLXDTaMbKZGdJZlZ5THAxRTQ?usp=sharing -Here are some measurements of Briey SoC timings and area : +Here are some measurements of Briey SoC timings and area: ``` Artix 7 -> 186 Mhz 3138 LUT 3328 FF @@ -313,13 +313,13 @@ Murax is a very light SoC (it fits in an ICE40 FPGA) which can work without any - one 16 bits prescaler, two 16 bits timers - one UART with tx/rx fifo -Depending the CPU configuration, on the ICE40-hx8k FPGA with icestorm for synthesis, the full SoC has the following area/performance : +Depending on the CPU configuration, on the ICE40-hx8k FPGA with icestorm for synthesis, the full SoC has the following area/performance: - RV32I interlocked stages => 51 Mhz, 2387 LC 0.45 DMIPS/Mhz - RV32I bypassed stages => 45 Mhz, 2718 LC 0.65 DMIPS/Mhz Its implementation can be found here: `src/main/scala/vexriscv/demo/Murax.scala`. -To generate the Murax SoC Hardware : +To generate the Murax SoC Hardware: ```sh # To generate the SoC without any content in the ram @@ -333,13 +333,13 @@ The demo program included by default with `MuraxWithRamInit` will blink the LEDs and echo characters received on the UART back to the user. To see this when running the Verilator sim, type some text and press enter. -Then go in src/test/cpp/murax and run the simulation with : +Then go in `src/test/cpp/murax` and run the simulation with: ```sh make clean run ``` -To connect OpenOCD (https://github.com/SpinalHDL/openocd_riscv) to the simulation : +To connect OpenOCD (https://github.com/SpinalHDL/openocd_riscv) to the simulation: ```sh src/openocd -f tcl/interface/jtag_tcp.cfg -c "set MURAX_CPU0_YAML /home/spinalvm/Spinal/VexRiscv/cpu0.yaml" -f tcl/target/murax.cfg @@ -365,7 +365,7 @@ MuraxFast bypassed stages (0.65 DMIPS/Mhz, 8 bits GPIO) -> Some scripts to generate the SoC and call the icestorm toolchain can be found here: `scripts/Murax/` -A toplevel simulation testbench with the same features + a GUI are implemented with SpinalSim. You can find it in `src/test/scala/vexriscv/MuraxSim.scala`. +A top level simulation testbench with the same features + a GUI are implemented with SpinalSim. You can find it in `src/test/scala/vexriscv/MuraxSim.scala`. To run it : @@ -376,13 +376,13 @@ sbt "test:runMain vexriscv.MuraxSim" ## Running Linux -A default configuration is located in src/main/scala/vexriscv/demo/Linux.scala +A default configuration is located in `src/main/scala/vexriscv/demo/Linux.scala`. This file also contains - The commands to compile the buildroot image - How to run the Verilator simulation in interative mode -There is currently no SoC to run it on hardware, it is WIP. But the CPU simulation can already boot linux and run user space application (even python). +There is currently no SoC to run it on hardware, it is WIP. But the CPU simulation can already boot linux and run user space applications (even python). Note that VexRiscv can run Linux on both cache full and cache less design. @@ -494,7 +494,7 @@ import spinal.core._ import vexriscv.plugin.Plugin import vexriscv.{Stageable, DecoderService, VexRiscv} -//This plugin example will add a new instruction named SIMD_ADD which do the following : +//This plugin example will add a new instruction named SIMD_ADD which does the following: // //RD : Regfile Destination, RS : Regfile Source //RD( 7 downto 0) = RS1( 7 downto 0) + RS2( 7 downto 0) @@ -509,7 +509,7 @@ import vexriscv.{Stageable, DecoderService, VexRiscv} //Note : RS1, RS2, RD positions follow the RISC-V spec and are common for all instruction of the ISA class SimdAddPlugin extends Plugin[VexRiscv]{ - //Define the concept of IS_SIMD_ADD signals, which specify if the current instruction is destined for ths plugin + //Define the concept of IS_SIMD_ADD signals, which specify if the current instruction is destined for this plugin object IS_SIMD_ADD extends Stageable(Bool) //Callback to setup the plugin and ask for different services @@ -519,10 +519,10 @@ class SimdAddPlugin extends Plugin[VexRiscv]{ //Retrieve the DecoderService instance val decoderService = pipeline.service(classOf[DecoderService]) - //Specify the IS_SIMD_ADD default value when instruction are decoded + //Specify the IS_SIMD_ADD default value when instructions are decoded decoderService.addDefault(IS_SIMD_ADD, False) - //Specify the instruction decoding which should be applied when the instruction match the 'key' parttern + //Specify the instruction decoding which should be applied when the instruction matches the 'key' parttern decoderService.add( //Bit pattern of the new SIMD_ADD instruction key = M"0000011----------000-----0110011", @@ -533,8 +533,8 @@ class SimdAddPlugin extends Plugin[VexRiscv]{ REGFILE_WRITE_VALID -> True, //Enable the register file write BYPASSABLE_EXECUTE_STAGE -> True, //Notify the hazard management unit that the instruction result is already accessible in the EXECUTE stage (Bypass ready) BYPASSABLE_MEMORY_STAGE -> True, //Same as above but for the memory stage - RS1_USE -> True, //Notify the hazard management unit that this instruction use the RS1 value - RS2_USE -> True //Same than above but for RS2. + RS1_USE -> True, //Notify the hazard management unit that this instruction uses the RS1 value + RS2_USE -> True //Same as above but for RS2. ) ) } @@ -545,19 +545,19 @@ class SimdAddPlugin extends Plugin[VexRiscv]{ //Add a new scope on the execute stage (used to give a name to signals) execute plug new Area { - //Define some signals used internally to the plugin + //Define some signals used internally by the plugin val rs1 = execute.input(RS1).asUInt //32 bits UInt value of the regfile[RS1] val rs2 = execute.input(RS2).asUInt val rd = UInt(32 bits) - //Do some computation + //Do some computations rd(7 downto 0) := rs1(7 downto 0) + rs2(7 downto 0) rd(16 downto 8) := rs1(16 downto 8) + rs2(16 downto 8) rd(23 downto 16) := rs1(23 downto 16) + rs2(23 downto 16) rd(31 downto 24) := rs1(31 downto 24) + rs2(31 downto 24) - //When the instruction is a SIMD_ADD one, then write the result into the register file data path. + //When the instruction is a SIMD_ADD, write the result into the register file data path. when(execute.input(IS_SIMD_ADD)) { execute.output(REGFILE_WRITE_DATA) := rd.asBits } @@ -572,15 +572,15 @@ This example is a very simple one, but each plugin can really have access to the - Halt a given stage of the CPU - Unschedule instructions - Emit an exception -- Introduce new instruction decoding specification +- Introduce a new instruction decoding specification - Ask to jump the PC somewhere - Read signals published by other plugins -- override published signals values +- Override published signals values - Provide an alternative implementation - ... -As a demonstrator, this SimdAddPlugin was integrated in the `src/main/scala/vexriscv/demo/GenCustomSimdAdd.scala` CPU configuration -and is self-tested by the `src/test/cpp/custom/simd_add` application by running the following commands : +As a demonstration, this SimdAddPlugin was integrated in the `src/main/scala/vexriscv/demo/GenCustomSimdAdd.scala` CPU configuration +and is self-tested by the `src/test/cpp/custom/simd_add` application by running the following commands: ```sh # Generate the CPU @@ -589,7 +589,7 @@ sbt "runMain vexriscv.demo.GenCustomSimdAdd" cd src/test/cpp/regression/ # Optionally add TRACE=yes if you want to get the VCD waveform from the simulation. -# Also you have to know that by default, the testbench introduce instruction/data bus stall. +# Also you have to know that, by default, the testbench introduce instruction/data bus stall. # Note the CUSTOM_SIMD_ADD flag is set to yes. make clean run IBUS=SIMPLE DBUS=SIMPLE CSR=no MMU=no DEBUG_PLUGIN=no MUL=no DIV=no DHRYSTONE=no REDO=2 CUSTOM_SIMD_ADD=yes ``` @@ -607,14 +607,14 @@ The second one (`CustomCsrDemoGpioPlugin`) creates a GPIO peripheral directly ma ## CPU clock and resets -Without the debug plugin, the CPU will have a standard `clk` input and a `reset` input. But with the debug plugin the situation is the following : +Without the debug plugin, the CPU will have a standard `clk` input and a `reset` input. But with the debug plugin the situation is the following: -- clk : As before, the clock which drive the whole CPU design, including the debug logic -- reset : Reset all the CPU states excepted the debug logics -- debugReset : Reset the debug logic of the CPU -- debug_resetOut : a CPU output signal which allows the JTAG to reset the CPU + the memory interconnect + the peripherals +- `clk`: as before, the clock which drives the whole CPU design, including the debug logic +- `reset`: reset all the CPU states except the debug logic +- `debugReset`: reset the debug logic of the CPU +- `debug_resetOut`: a CPU output signal which allows the JTAG to reset the CPU + the memory interconnect + the peripherals -So here is the reset interconnect in case you use the debug plugin : +So here is the reset interconnect, in case you use the debug plugin: ``` VexRiscv @@ -635,20 +635,20 @@ toplevelReset >----+--------> debugReset | ## VexRiscv Architecture VexRiscv is implemented via a 5 stage in-order pipeline on which many optional and complementary plugins add functionalities to provide a functional RISC-V CPU. -This approach is completely unconventional and only possible through meta hardware description languages (SpinalHDL in the current case) but has proven its advantages +This approach is completely unconventional and only possible through meta hardware description languages (SpinalHDL, in the current case) but has proven its advantages via the VexRiscv implementation: - You can swap/turn on/turn off parts of the CPU directly via the plugin system -- You can add new functionalities/instruction without having to modify any sources code of the CPU -- It allows the CPU configuration to cover a very large spectrum of implementation without cooking spaghetti code -- It allows your code base to truly produce a parametrized CPU design +- You can add new functionalities/instructions without having to modify any of the sources of the CPU +- It allows the CPU configuration to cover a very large spectrum of implementations without cooking spaghetti code +- It allows your codebase to truly produce a parametrized CPU design If you generate the CPU without any plugin, it will only contain the definition of the 5 pipeline stages and their basic arbitration, but nothing else, -as everything else, including the program counter is added into the CPU via plugins. +and everything else, including the program counter is added into the CPU via plugins. ### Plugins -This chapter describes plugins currently implemented. +This chapter describes the currently implemented plugins. - [IBusSimplePlugin](#ibussimpleplugin) - [IBusCachedPlugin](#ibuscachedplugin) @@ -674,7 +674,7 @@ This chapter describes plugins currently implemented. #### IBusSimplePlugin -This plugin implement the CPU frontend (instruction fetch) via a very simple and neutral memory interface going outside the CPU. +This plugin implements the CPU frontend (instruction fetch) via a very simple and neutral memory interface going outside the CPU. | Parameters | type | description | | ------ | ----------- | ------ | @@ -715,7 +715,7 @@ case class IBusSimpleBus(interfaceKeepData : Boolean) extends Bundle with IMaste } ``` -**Important** : Checkout the cmdForkPersistence parameter, because if it's not set, it can break the iBus compatibility with your memory system (unless you externaly add some buffers) +**Important** : check out the cmdForkPersistence parameter, because if it is not set, it can break the iBus compatibility with your memory system (unless you externaly add some buffers). Setting cmdForkPersistence and cmdForkOnSecondStage improves iBus cmd timings. @@ -759,19 +759,19 @@ Note: If you enable the twoCycleRam option and if wayCount is bigger than one, t #### DecoderSimplePlugin -This plugin provides instruction decoding capabilities to others plugins. +This plugin provides instruction decoding capabilities to other plugins. For instance, for a given instruction, the pipeline hazard plugin needs to know if it uses the register file source 1/2 in order to stall the pipeline until the hazard is gone. -To provide this kind of information, each plugin which implements an instruction documents this kind of information to the DecoderSimplePlugin plugin. +Each plugin that implements an instruction provides this kind of information to the DecoderSimplePlugin plugin. | Parameters | type | description | | ------ | ----------- | ------ | | catchIllegalInstruction | Boolean | When true, instructions that don't match a decoding specification will generate a trap exception | -Here is a usage example : +Here is a usage example: ```scala - //Specify the instruction decoding which should be applied when the instruction match the 'key' pattern + //Specify the instruction decoding which should be applied when the instruction matches the 'key' pattern decoderService.add( //Bit pattern of the new instruction key = M"0000011----------000-----0110011", @@ -797,15 +797,15 @@ This plugin implements the register file. | Parameters | type | description | | ------ | ----------- | ------ | -| regFileReadyKind | RegFileReadKind | Can bet set to ASYNC or SYNC. Specifies the kind of memory read used to implement the register file. ASYNC means zero cycle latency memory read, while SYNC means one cycle latency memory read which can be mapped into standard FPGA memory blocks | -| zeroBoot | Boolean | Load all registers with zeroes at the beginning of simulations to keep everything deterministic in logs/traces| +| regFileReadyKind | RegFileReadKind | Can be set to ASYNC or SYNC. Specifies the kind of memory read used to implement the register file. ASYNC means zero cycle latency memory read, while SYNC means one cycle latency memory read which can be mapped into standard FPGA memory blocks | +| zeroBoot | Boolean | Load all registers with zeroes at the beginning of the simulation to keep everything deterministic in logs/traces| This register file use a `don't care` read-during-write policy, so the bypassing/hazard plugin should take care of this. #### HazardSimplePlugin This plugin checks the pipeline instruction dependencies and, if necessary or possible, will stop the instruction in the decoding stage or bypass the instruction results -from the later stages to the decode stage. +from the later stages of the decode stage. Since the register file is implemented with a `don't care` read-during-write policy, this plugin also manages these kind of hazards. @@ -829,7 +829,7 @@ Except for SRC1/SRC2, this plugin does everything at the begining of Execute sta #### IntAluPlugin -This plugin implements all ADD/SUB/SLT/SLTU/XOR/OR/AND/LUI/AUIPC instructions in the execute stage by using the SrcPlugin outputs. It is a realy simple plugin. +This plugin implements all ADD/SUB/SLT/SLTU/XOR/OR/AND/LUI/AUIPC instructions in the execute stage by using the SrcPlugin outputs. It is a really simple plugin. The result is injected into the pipeline directly at the end of the execute stage. @@ -841,7 +841,7 @@ The result is injected into the pipeline directly at the end of the execute stag #### FullBarrelShifterPlugin -Implements SLL/SRL/SRA instructions by using a full barrel shifter, so it execute all shifts in a single cycle. +Implements SLL/SRL/SRA instructions by using a full barrel shifter, so it executes all shifts in a single cycle. | Parameters | type | description | | ------ | ----------- | ------ | @@ -849,7 +849,7 @@ Implements SLL/SRL/SRA instructions by using a full barrel shifter, so it execut #### BranchPlugin -This plugin implement all branch/jump instructions (JAL/JALR/BEQ/BNE/BLT/BGE/BLTU/BGEU) with primitives used by the cpu frontend plugins to implement branch prediction. The prediction implementation is set in the frontend plugins (IBusX) +This plugin implements all branch/jump instructions (JAL/JALR/BEQ/BNE/BLT/BGE/BLTU/BGEU) with primitives used by the cpu frontend plugins to implement branch prediction. The prediction implementation is set in the frontend plugins (IBusX). | Parameters | type | description | | ------ | ----------- | ------ | @@ -869,13 +869,13 @@ otherwise the standard penalty is applied. ##### Prediction DYNAMIC -Same as the STATIC prediction, except that to do the prediction, it use a direct mapped 2 bit history cache (BHT) which remembers if the branch is more likely to be taken or not. +Same as the STATIC prediction, except that to do the prediction, it uses a direct mapped 2 bit history cache (BHT) which remembers if the branch is more likely to be taken or not. ##### Prediction DYNAMIC_TARGET -This predictor uses a direct mapped branch target buffer (BTB) in the Fetch stage which store the PC of the instruction, the target PC of the instruction and a 2 bit history to remember -if the branch is more likely to be taken or not. This is the most efficient branch predictor actualy implemented on VexRiscv as when the branch prediction is right, it produce no branch penalty. -The down side is that this predictor has a long combinatorial path coming from the prediction cache read port to the programm counter by passing through the jump interface. +This predictor uses a direct mapped branch target buffer (BTB) in the Fetch stage which stores the PC of the instruction, the target PC of the instruction and a 2 bit history to remember +if the branch is more likely to be taken or not. This is actually the most efficient branch predictor implemented on VexRiscv, because when the branch prediction is right, it produces no branch penalty. +The downside is that this predictor has a long combinatorial path coming from the prediction cache read port to the programm counter, passing through the jump interface. #### DBusSimplePlugin @@ -919,7 +919,7 @@ case class DBusSimpleBus() extends Bundle with IMasterSlave{ } ``` -Note that bridges are available to convert this interface into AXI4 and Avalon +Note that there are bridges available that can convert this interface into AXI4 and Avalon. There is at least one cycle latency between a cmd and the corresponding rsp. The rsp.ready flag should be false after a read cmd until the rsp is present. @@ -937,7 +937,7 @@ The processing is fully pipelined between the Execute/Memory/Writeback stage. Th Implements the division/modulo instruction from the RISC-V M extension. It is done in a simple iterative way which always takes 34 cycles. The result is inserted into the Memory stage. -This plugin is now based on the MulDivIterativePlugin one. +This plugin is now based on MulDivIterativePlugin. #### MulDivIterativePlugin @@ -955,14 +955,14 @@ This plugin is able to unroll the iterative calculation process to reduce the nu The number of cycles used to execute a multiplication is '32/mulUnrollFactor' The number of cycles used to execute a division is '32/divUnrollFactor + 1' -Both mul/div are processed into the memory stage (late result). +Both mul/div are processed in the memory stage (late result). #### CsrPlugin -Implements most of the Machine mode and a few of the User mode registers as specified in the RISC-V priviledged spec. -The access mode of most of the CSR is parameterizable (NONE/READ_ONLY/WRITE_ONLY/READ_WRITE) to reduce the area usage of unneeded features. +Implements most of the Machine mode and a few of the User mode registers, as specified in the RISC-V priviledged spec. +The access mode of most of the CSR is parameterizable to reduce the area usage of unneeded features. -(CsrAccess can be NONE/READ_ONLY/WRITE_ONLY/READ_WRITE) +(CsrAccess can be `NONE/READ_ONLY/WRITE_ONLY/READ_WRITE`) | Parameters | type | description | | ------ | ----------- | ------ | @@ -992,11 +992,11 @@ stage before jumping to mtvec. #### StaticMemoryTranslatorPlugin -Static memory translator plugin which allows one to specify which range of the memory addresses is IO mapped and shouldn't be cached. +Static memory translator plugin which allows to specify which range of the memory addresses is I/O mapped and shouldn't be cached. #### MmuPlugin -Hardware refilled MMU implementation. Allows others plugins such as DBusCachedPlugin/IBusCachedPlugin to instanciate memory address translation ports. Each port has a small dedicated +Hardware refilled MMU implementation. Allows other plugins such as DBusCachedPlugin/IBusCachedPlugin to instanciate memory address translation ports. Each port has a small dedicated fully associative TLB cache which is refilled automaticaly via a dbus access sharing. #### DebugPlugin @@ -1010,7 +1010,7 @@ The JTAG interface is provided by another bridge, which makes it possible to eff The internals of the debug plugin are done in a manner which reduces the area usage and the FMax impact of this plugin. -Here is the simple bus to access it, the rsp come one cycle after the request : +Here is the simple bus to access it, the rsp comes one cycle after the request: ```scala case class DebugExtensionCmd() extends Bundle{ @@ -1034,7 +1034,7 @@ case class DebugExtensionBus() extends Bundle with IMasterSlave{ ``` -Here is the register mapping : +Here is the register mapping: ``` Read address 0x00 -> @@ -1056,12 +1056,10 @@ Write Address 0x04 -> bits (31 downto 0) : Instruction that should be pushed into the CPU pipeline for debug purposes ``` -The OpenOCD port is there : -https://github.com/SpinalHDL/openocd_riscv +The OpenOCD port is here: #### YamlPlugin -This plugin offers a service to others plugins to generate a usefull Yaml file about the CPU configuration. It contains, for instance, the sequence of instruction required +This plugin offers a service to other plugins to generate a useful Yaml file describing the CPU configuration. It contains, for instance, the sequence of instructions required to flush the data cache (information used by openocd). - From 163611bd114ba177ab8abec2e91f4da2ce5df845 Mon Sep 17 00:00:00 2001 From: japm48 Date: Tue, 11 Feb 2020 18:49:56 +0100 Subject: [PATCH 297/951] Murax on arty_a7: fix RAMB type on soc_mmi.tcl --- scripts/Murax/arty_a7/soc_mmi.tcl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/Murax/arty_a7/soc_mmi.tcl b/scripts/Murax/arty_a7/soc_mmi.tcl index 33ea6866..2689dadf 100644 --- a/scripts/Murax/arty_a7/soc_mmi.tcl +++ b/scripts/Murax/arty_a7/soc_mmi.tcl @@ -21,7 +21,7 @@ proc swap_bits { bit } { # open_run impl_1 # Find all the RAMs, place in a list -set rams [get_cells -hier -regexp {.*core/system_ram/.*} -filter {REF_NAME =~ RAMB36E1}] +set rams [get_cells -hier -regexp {.*core/system_ram/.*} -filter {REF_NAME == RAMB36E1 || REF_NAME == RAMB18E1}] puts "[llength $rams] RAMs in total" foreach m $rams {puts $m} @@ -89,7 +89,7 @@ set i 0 foreach ram $rams { # Get the RAM location set loc_val [get_property LOC [get_cells $ram]] - regexp -- {(RAMB36_)([0-9XY]+)} $loc_val full ram_name loc_xy + regexp {(RAMB.+_)([0-9XY]+)} $loc_val full ram_name loc_xy set memi [dict create ram $ram loc $loc_xy] From 6547eefffdd884a3218f9030c63a2c79dde3b7a5 Mon Sep 17 00:00:00 2001 From: japm48 Date: Tue, 11 Feb 2020 18:58:43 +0100 Subject: [PATCH 298/951] Murax on arty_a7: fix mkdir error --- scripts/Murax/arty_a7/make_vivado_project | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/Murax/arty_a7/make_vivado_project b/scripts/Murax/arty_a7/make_vivado_project index 4a925107..eb0f5a9a 100755 --- a/scripts/Murax/arty_a7/make_vivado_project +++ b/scripts/Murax/arty_a7/make_vivado_project @@ -3,7 +3,7 @@ #cannot rm build because it erase software images that the make file copy there #rm -rf ./build -mkdir ./build +mkdir -p ./build cd ./build vivado -mode batch -source ../make_vivado_project.tcl -notrace From 6edab1eb34eeed9943b586f5a203dbf1756b908b Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Sat, 15 Feb 2020 00:24:33 +0100 Subject: [PATCH 299/951] Add SMP spec draft --- doc/smp/smp.md | 155 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 doc/smp/smp.md diff --git a/doc/smp/smp.md b/doc/smp/smp.md new file mode 100644 index 00000000..596b6a39 --- /dev/null +++ b/doc/smp/smp.md @@ -0,0 +1,155 @@ +# Coherent interface specification + +Features : +- 3 buses (write, read, probe) composed of 7 streams +- Two data paths (read + write), but allow dirty/clean sharing by reusing the write data path +- Allow multi level coherent interconnect +- No ordering, but provide barrier + + +## Memory copy flags + +| Name | Description | +|---------------|-------------| +| Valid/Invalid | Line loaded or not | +| Shared/Unique | shared => multiple copy of the cache line in different caches, unique => no other caches has a copy of the line | +| Owner/Lodger | invited => copy of the line, but no other responsibility, invited => the given cache is responsible to write back dirty data and answer probes with the data | +| Clean/Dirty | clean => match main memory, dirty => main memory need updates | + +All combination of those cache flag are valid. But if a cache line is invalid, the other flags have no meaning. + +Later in the spec, memory copy state can be described as : + +- VSOC for (Valid, Shared, Owner, Clean) +- V-OC for (Valid, Shared or Unique, Owner, Clean) +- !V-OC for NOT (Valid, Shared or Unique, Owner, Clean) + +## buses + +One full interface is composed of 3 buses +- write (M -> S) +- read (M -> S) +- probe (M <- S) + +### Read bus + +Composed of 3 stream : + +| Name | Direction | Description | +|---------|-----------|----------| +| readCmd | M -> S | Emit memory read and cache management commands | +| readRsp | M <- S | Return some data and/or a status from readCmd | +| readAck | M -> S | Return ACK from readRsp | + +### Write bus + +Composed of 2 stream : + +| Name | Direction | Description | +|---------|-----------|----------| +| writeCmd | M -> S | Emit memory writes and cache management commands | +| writeRsp | M <- S | Return a status from writeCmd | + +### Probe bus + +| Name | Direction | Description | +|----------|-----------|----------| +| probeCmd | M <- S | Used for cache management | +| probeRsp | M -> S | Acknowledgment | + +## Transactions + +This chapter define transactions moving over the 3 previously defined buses. + +### Read commands + +Emitted on the readCmd channel (master -> slave) + +| Command | Initial state | Description | Usage example | +|-------------|---------------|----------|------| +| readShared | I--- | Get a memory copy as V--- | Want to read a uncached address | +| readUnique | I--- | Get a memory copy as VUO- | Want to write a uncached address | +| readOnce | I--- | Get a memory copy without coherency tracking | Instruction cache read | +| makeInvalid | VS-- | Make other memory copy as I--- and make yourself VUO- | Want to write into a shared line | +| readBarrier | N/A | Ensure that the visibility of the memory operations of this channel do not cross the barrier | ISA fence | + +makeInvalid should be designed with care. There is a few corner cases : +- While a master has a inflight makeInvalid, a probe can change its state. +- Multi level coherent interconnect should be careful to properly move the ownership and not lose dirty data + +I'm not sure yet if we should add some barrier transactions to enforce + +### Read responses + +Emitted on the readRsp channel (master <- slave) + +success, abort, error, data shared/unique clean/dirty owner/notOwner + +| Responses | From command | Description | +|-----------|---------------|----------| +| success | makeInvalid, readBarrier | - | +| abort | makeInvalid | A concurrent makeInvalid toke over | +| error | readShared, readUnique, readOnce | Bad address | +| readData | readShared, readUnique, readOnce | Data + coherency flags (V???) | + +### Read ack + +Emitted on the readAck channel (master -> slave), it carry no information, just a notification that the master received the read response + +| Name | From command | Description | +|--------------|---------------|----------| +| readSuccess | * | - | + +### Write commands + +Write commands can be emitted on the writeCmd channel (master -> slave) + +| Name | Initial state | Description | Usage example | +|--------------|---------------|----------|----------| +| writeInvalid | V-O- | Write the memory copy and update it status to I--- | Need to free the dirty cache line | +| writeShare | V-O- | Write the memory copy but keep it as VSO- | A probe makeShared asked it | +| evict | V---, !V-OD | Notify the interconnect that the cache line is now I--- | Need to free a clean cache line | +| writeBarrier | N/A | Ensure that the visibility of the memory operations of this channel do not cross the barrier | ISA fence | + +### Write responses + +Emitted on the writeRsp channel (master <- slave), it carry no information, just a notification that the corresponding command is done. + +| Name | From command | Description | +|--------------|---------------|----------| +| writeSuccess | * | - | + +### Probe commands + +Probe commands can be emitted on the probeCmd channel (slave -> master) + +| Name | Description | Usage example | +|-------------|-------------|---------------| +| makeInvalid | Make the memory copy I--- | Another cache want to make his shared copy unique to write it | +| makeShared | Make the memory copy VS-- | Another cache want to read a memory block, so unique copy need to be shared | + +Both makeInvalid and makeShared could result into one of the following probeSuccess, writeInvalid, writeShare. + +To help the slave matching the writeInvalid and writeShare generated from a probe, those request are tagged with a matching ID. + +### Probe responses + +Emitted on the probeRsp channel (master -> slave), it carry no information, just a notification that the corresponding command is done. + +| Name | From command | Description | +|--------------|---------------|----------| +| probeSuccess | * | - | + + +## Channel interlocking + +There is the streams priority (top => high priority, bottom => low priority ) +- writeCmd, writeRsp, readRsp, readAck, probeRsp. Nothing should realy block them excepted bandwidth +- probeCmd. Can be blocked by inflight/generated writes +- readCmd. Can be blocked by inflight/generated probes + +In other words : + +Masters can wait the completion of inflight writes before answering probes. +Slaves can emit probes and wait their completion before answering reads. +Slaves can wait on readAck incomming from generated readRsp before at all times From f1959ff830d3d9f711fb079dc3fea157d7bde58a Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Sat, 15 Feb 2020 00:26:11 +0100 Subject: [PATCH 300/951] smp spec typo --- doc/smp/smp.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/smp/smp.md b/doc/smp/smp.md index 596b6a39..c335f1fa 100644 --- a/doc/smp/smp.md +++ b/doc/smp/smp.md @@ -13,7 +13,7 @@ Features : |---------------|-------------| | Valid/Invalid | Line loaded or not | | Shared/Unique | shared => multiple copy of the cache line in different caches, unique => no other caches has a copy of the line | -| Owner/Lodger | invited => copy of the line, but no other responsibility, invited => the given cache is responsible to write back dirty data and answer probes with the data | +| Owner/Lodger | lodger => copy of the line, but no other responsibility, owner => the given cache is responsible to write back dirty data and answer probes with the data | | Clean/Dirty | clean => match main memory, dirty => main memory need updates | All combination of those cache flag are valid. But if a cache line is invalid, the other flags have no meaning. From d241f3562501bed750f958b116a40cf453be7021 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Sat, 15 Feb 2020 10:10:04 +0100 Subject: [PATCH 301/951] Remove usages of implicit string to B/U/S --- src/main/scala/vexriscv/ip/DataCache.scala | 6 +++--- src/main/scala/vexriscv/plugin/BranchPlugin.scala | 6 +++--- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 10 +++++----- src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala | 2 +- src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala | 6 +++--- src/main/scala/vexriscv/plugin/Misc.scala | 4 ++-- .../scala/vexriscv/plugin/MulDivIterativePlugin.scala | 2 +- 7 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index 838489d2..eaed1d08 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -259,7 +259,7 @@ case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave val cmdBridge = Stream (DataCacheMemCmd(p)) val isBurst = cmdBridge.length =/= 0 cmdBridge.valid := cmd.valid - cmdBridge.address := (isBurst ? (cmd.address(31 downto widthOf(counter) + 2) @@ counter @@ "00") | (cmd.address(31 downto 2) @@ "00")) + cmdBridge.address := (isBurst ? (cmd.address(31 downto widthOf(counter) + 2) @@ counter @@ U"00") | (cmd.address(31 downto 2) @@ U"00")) cmdBridge.wr := cmd.wr cmdBridge.mask := cmd.mask cmdBridge.data := cmd.data @@ -278,8 +278,8 @@ case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave bus.ADR := cmdBridge.address >> 2 bus.CTI := Mux(isBurst, cmdBridge.last ? B"111" | B"010", B"000") - bus.BTE := "00" - bus.SEL := cmdBridge.wr ? cmdBridge.mask | "1111" + bus.BTE := B"00" + bus.SEL := cmdBridge.wr ? cmdBridge.mask | B"1111" bus.WE := cmdBridge.wr bus.DAT_MOSI := cmdBridge.data diff --git a/src/main/scala/vexriscv/plugin/BranchPlugin.scala b/src/main/scala/vexriscv/plugin/BranchPlugin.scala index 77f72b8e..e90a1fce 100644 --- a/src/main/scala/vexriscv/plugin/BranchPlugin.scala +++ b/src/main/scala/vexriscv/plugin/BranchPlugin.scala @@ -197,7 +197,7 @@ class BranchPlugin(earlyBranch : Boolean, ).asUInt val branchAdder = branch_src1 + branch_src2 - insert(BRANCH_CALC) := branchAdder(31 downto 1) @@ "0" + insert(BRANCH_CALC) := branchAdder(31 downto 1) @@ U"0" } //Apply branchs (JAL,JALR, Bxx) @@ -274,7 +274,7 @@ class BranchPlugin(earlyBranch : Boolean, } } val branchAdder = branch_src1 + branch_src2 - insert(BRANCH_CALC) := branchAdder(31 downto 1) @@ "0" + insert(BRANCH_CALC) := branchAdder(31 downto 1) @@ U"0" } @@ -341,7 +341,7 @@ class BranchPlugin(earlyBranch : Boolean, ).asUInt val branchAdder = branch_src1 + input(BRANCH_SRC2) - insert(BRANCH_CALC) := branchAdder(31 downto 1) @@ "0" + insert(BRANCH_CALC) := branchAdder(31 downto 1) @@ U"0" insert(NEXT_PC) := input(PC) + (if(pipeline(RVC_GEN)) ((input(IS_RVC)) ? U(2) | U(4)) else 4) insert(TARGET_MISSMATCH) := decode.input(PC) =/= input(BRANCH_CALC) } diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 8759df56..98dfbaa8 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -775,8 +775,8 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep var privilegs = if (supervisorGen) List(1, 3) else List(3) val targetPrivilege = if(pipelinedInterrupt) Reg(UInt(2 bits)) else UInt(2 bits).assignDontCare() val privilegeAllowInterrupts = mutable.HashMap[Int, Bool]() - if (supervisorGen) privilegeAllowInterrupts += 1 -> ((sstatus.SIE && privilege === "01") || privilege < "01") - privilegeAllowInterrupts += 3 -> (mstatus.MIE || privilege < "11") + if (supervisorGen) privilegeAllowInterrupts += 1 -> ((sstatus.SIE && privilege === U"01") || privilege < U"01") + privilegeAllowInterrupts += 3 -> (mstatus.MIE || privilege < U"11") while (privilegs.nonEmpty) { val p = privilegs.head when(privilegeAllowInterrupts(p)) { @@ -844,7 +844,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep fetcher.haltIt() //Avoid having the fetch confused by the incomming privilege switch jumpInterface.valid := True - jumpInterface.payload := (if(!xtvecModeGen) xtvec.base @@ "00" else (xtvec.mode === 0 || hadException) ? (xtvec.base @@ "00") | ((xtvec.base + trapCause) @@ "00") ) + jumpInterface.payload := (if(!xtvecModeGen) xtvec.base @@ U"00" else (xtvec.mode === 0 || hadException) ? (xtvec.base @@ U"00") | ((xtvec.base + trapCause) @@ U"00") ) lastStage.arbitration.flushNext := True if(privilegeGen) privilegeReg := targetPrivilege @@ -917,8 +917,8 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep val imm = IMM(input(INSTRUCTION)) insert(CSR_WRITE_OPCODE) := ! ( - (input(INSTRUCTION)(14 downto 13) === "01" && input(INSTRUCTION)(rs1Range) === 0) - || (input(INSTRUCTION)(14 downto 13) === "11" && imm.z === 0) + (input(INSTRUCTION)(14 downto 13) === B"01" && input(INSTRUCTION)(rs1Range) === 0) + || (input(INSTRUCTION)(14 downto 13) === B"11" && imm.z === 0) ) insert(CSR_READ_OPCODE) := input(INSTRUCTION)(13 downto 7) =/= B"0100000" } diff --git a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala index a7b21940..8ef10b25 100644 --- a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala @@ -211,7 +211,7 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l, if (catchSomething) { decodeExceptionPort.valid := False decodeExceptionPort.code.assignDontCare() - decodeExceptionPort.badAddr := cacheRsp.pc(31 downto 2) @@ "00" + decodeExceptionPort.badAddr := cacheRsp.pc(31 downto 2) @@ U"00" } when(cacheRsp.isValid && cacheRsp.mmuRefilling && !issueDetected) { diff --git a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala index fa74f6c8..7936f178 100644 --- a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala @@ -316,7 +316,7 @@ class IBusSimplePlugin( resetVector : BigInt, mmuBus.cmd.bypassTranslation := False mmuBus.end := cmdForkStage.output.fire || fetcherflushIt - cmd.pc := mmuBus.rsp.physicalAddress(31 downto 2) @@ "00" + cmd.pc := mmuBus.rsp.physicalAddress(31 downto 2) @@ U"00" //do not emit memory request if MMU miss when(mmuBus.rsp.exception || mmuBus.rsp.refilling){ @@ -333,7 +333,7 @@ class IBusSimplePlugin( resetVector : BigInt, } val mmuLess = (mmuBus == null) generate new Area{ - cmd.pc := cmdForkStage.input.payload(31 downto 2) @@ "00" + cmd.pc := cmdForkStage.input.payload(31 downto 2) @@ U"00" } val rspJoin = new Area { @@ -389,7 +389,7 @@ class IBusSimplePlugin( resetVector : BigInt, if(catchSomething){ decodeExceptionPort.code.assignDontCare() - decodeExceptionPort.badAddr := join.pc(31 downto 2) @@ "00" + decodeExceptionPort.badAddr := join.pc(31 downto 2) @@ U"00" if(catchAccessFault) when(join.valid && join.rsp.error){ decodeExceptionPort.code := 1 diff --git a/src/main/scala/vexriscv/plugin/Misc.scala b/src/main/scala/vexriscv/plugin/Misc.scala index b8ddd8ea..8f68e4eb 100644 --- a/src/main/scala/vexriscv/plugin/Misc.scala +++ b/src/main/scala/vexriscv/plugin/Misc.scala @@ -50,7 +50,7 @@ object RvcDecompressor{ ret := (i(11 downto 7) === 2) ? addi16sp | lui } is(12){ - val isImmediate = i(11 downto 10) =/= "11" + val isImmediate = i(11 downto 10) =/= B"11" val isShift = !i(11) val func3 = i(11 downto 10).mux( 0 -> B"101", @@ -64,7 +64,7 @@ object RvcDecompressor{ ) ) val msbs = Mux( - sel = i(11 downto 10) === "10", + sel = i(11 downto 10) === B"10", whenTrue = B((6 downto 0) -> i(12)), //andi whenFalse = B"0" ## (i(11 downto 10) === B"01" || (i(11 downto 10) === B"11" && i(6 downto 5) === B"00")) ## B"00000" ) diff --git a/src/main/scala/vexriscv/plugin/MulDivIterativePlugin.scala b/src/main/scala/vexriscv/plugin/MulDivIterativePlugin.scala index 6820f8ec..eafa4daa 100644 --- a/src/main/scala/vexriscv/plugin/MulDivIterativePlugin.scala +++ b/src/main/scala/vexriscv/plugin/MulDivIterativePlugin.scala @@ -167,7 +167,7 @@ class MulDivIterativePlugin(genMul : Boolean = true, } if(dhrystoneOpt) { - execute.insert(FAST_DIV_VALID) := execute.input(IS_DIV) && execute.input(INSTRUCTION)(13 downto 12) === "00" && !execute.input(RS1).msb && !execute.input(RS2).msb && execute.input(RS1).asUInt < 16 && execute.input(RS2).asUInt < 16 && execute.input(RS2) =/= 0 + execute.insert(FAST_DIV_VALID) := execute.input(IS_DIV) && execute.input(INSTRUCTION)(13 downto 12) === B"00" && !execute.input(RS1).msb && !execute.input(RS2).msb && execute.input(RS1).asUInt < 16 && execute.input(RS2).asUInt < 16 && execute.input(RS2) =/= 0 execute.insert(FAST_DIV_VALUE) := (0 to 15).flatMap(n => (0 to 15).map(d => U(if (d == 0) 0 else n / d, 4 bits))).read(U(execute.input(RS1)(3 downto 0)) @@ U(execute.input(RS2)(3 downto 0))) //(U(execute.input(RS1)(3 downto 0)) / U(execute.input(RS2)(3 downto 0)) when(execute.input(FAST_DIV_VALID)) { execute.output(IS_DIV) := False From 3d34d754a9b5adc2e173eb12e79da9cb11c74abd Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Sat, 15 Feb 2020 10:10:04 +0100 Subject: [PATCH 302/951] Remove usages of implicit string to B/U/S --- src/main/scala/vexriscv/ip/DataCache.scala | 6 +++--- src/main/scala/vexriscv/plugin/BranchPlugin.scala | 6 +++--- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 10 +++++----- src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala | 2 +- src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala | 6 +++--- src/main/scala/vexriscv/plugin/Misc.scala | 4 ++-- .../scala/vexriscv/plugin/MulDivIterativePlugin.scala | 2 +- 7 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index 838489d2..eaed1d08 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -259,7 +259,7 @@ case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave val cmdBridge = Stream (DataCacheMemCmd(p)) val isBurst = cmdBridge.length =/= 0 cmdBridge.valid := cmd.valid - cmdBridge.address := (isBurst ? (cmd.address(31 downto widthOf(counter) + 2) @@ counter @@ "00") | (cmd.address(31 downto 2) @@ "00")) + cmdBridge.address := (isBurst ? (cmd.address(31 downto widthOf(counter) + 2) @@ counter @@ U"00") | (cmd.address(31 downto 2) @@ U"00")) cmdBridge.wr := cmd.wr cmdBridge.mask := cmd.mask cmdBridge.data := cmd.data @@ -278,8 +278,8 @@ case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave bus.ADR := cmdBridge.address >> 2 bus.CTI := Mux(isBurst, cmdBridge.last ? B"111" | B"010", B"000") - bus.BTE := "00" - bus.SEL := cmdBridge.wr ? cmdBridge.mask | "1111" + bus.BTE := B"00" + bus.SEL := cmdBridge.wr ? cmdBridge.mask | B"1111" bus.WE := cmdBridge.wr bus.DAT_MOSI := cmdBridge.data diff --git a/src/main/scala/vexriscv/plugin/BranchPlugin.scala b/src/main/scala/vexriscv/plugin/BranchPlugin.scala index 77f72b8e..e90a1fce 100644 --- a/src/main/scala/vexriscv/plugin/BranchPlugin.scala +++ b/src/main/scala/vexriscv/plugin/BranchPlugin.scala @@ -197,7 +197,7 @@ class BranchPlugin(earlyBranch : Boolean, ).asUInt val branchAdder = branch_src1 + branch_src2 - insert(BRANCH_CALC) := branchAdder(31 downto 1) @@ "0" + insert(BRANCH_CALC) := branchAdder(31 downto 1) @@ U"0" } //Apply branchs (JAL,JALR, Bxx) @@ -274,7 +274,7 @@ class BranchPlugin(earlyBranch : Boolean, } } val branchAdder = branch_src1 + branch_src2 - insert(BRANCH_CALC) := branchAdder(31 downto 1) @@ "0" + insert(BRANCH_CALC) := branchAdder(31 downto 1) @@ U"0" } @@ -341,7 +341,7 @@ class BranchPlugin(earlyBranch : Boolean, ).asUInt val branchAdder = branch_src1 + input(BRANCH_SRC2) - insert(BRANCH_CALC) := branchAdder(31 downto 1) @@ "0" + insert(BRANCH_CALC) := branchAdder(31 downto 1) @@ U"0" insert(NEXT_PC) := input(PC) + (if(pipeline(RVC_GEN)) ((input(IS_RVC)) ? U(2) | U(4)) else 4) insert(TARGET_MISSMATCH) := decode.input(PC) =/= input(BRANCH_CALC) } diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 8759df56..98dfbaa8 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -775,8 +775,8 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep var privilegs = if (supervisorGen) List(1, 3) else List(3) val targetPrivilege = if(pipelinedInterrupt) Reg(UInt(2 bits)) else UInt(2 bits).assignDontCare() val privilegeAllowInterrupts = mutable.HashMap[Int, Bool]() - if (supervisorGen) privilegeAllowInterrupts += 1 -> ((sstatus.SIE && privilege === "01") || privilege < "01") - privilegeAllowInterrupts += 3 -> (mstatus.MIE || privilege < "11") + if (supervisorGen) privilegeAllowInterrupts += 1 -> ((sstatus.SIE && privilege === U"01") || privilege < U"01") + privilegeAllowInterrupts += 3 -> (mstatus.MIE || privilege < U"11") while (privilegs.nonEmpty) { val p = privilegs.head when(privilegeAllowInterrupts(p)) { @@ -844,7 +844,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep fetcher.haltIt() //Avoid having the fetch confused by the incomming privilege switch jumpInterface.valid := True - jumpInterface.payload := (if(!xtvecModeGen) xtvec.base @@ "00" else (xtvec.mode === 0 || hadException) ? (xtvec.base @@ "00") | ((xtvec.base + trapCause) @@ "00") ) + jumpInterface.payload := (if(!xtvecModeGen) xtvec.base @@ U"00" else (xtvec.mode === 0 || hadException) ? (xtvec.base @@ U"00") | ((xtvec.base + trapCause) @@ U"00") ) lastStage.arbitration.flushNext := True if(privilegeGen) privilegeReg := targetPrivilege @@ -917,8 +917,8 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep val imm = IMM(input(INSTRUCTION)) insert(CSR_WRITE_OPCODE) := ! ( - (input(INSTRUCTION)(14 downto 13) === "01" && input(INSTRUCTION)(rs1Range) === 0) - || (input(INSTRUCTION)(14 downto 13) === "11" && imm.z === 0) + (input(INSTRUCTION)(14 downto 13) === B"01" && input(INSTRUCTION)(rs1Range) === 0) + || (input(INSTRUCTION)(14 downto 13) === B"11" && imm.z === 0) ) insert(CSR_READ_OPCODE) := input(INSTRUCTION)(13 downto 7) =/= B"0100000" } diff --git a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala index a7b21940..8ef10b25 100644 --- a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala @@ -211,7 +211,7 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l, if (catchSomething) { decodeExceptionPort.valid := False decodeExceptionPort.code.assignDontCare() - decodeExceptionPort.badAddr := cacheRsp.pc(31 downto 2) @@ "00" + decodeExceptionPort.badAddr := cacheRsp.pc(31 downto 2) @@ U"00" } when(cacheRsp.isValid && cacheRsp.mmuRefilling && !issueDetected) { diff --git a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala index fa74f6c8..7936f178 100644 --- a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala @@ -316,7 +316,7 @@ class IBusSimplePlugin( resetVector : BigInt, mmuBus.cmd.bypassTranslation := False mmuBus.end := cmdForkStage.output.fire || fetcherflushIt - cmd.pc := mmuBus.rsp.physicalAddress(31 downto 2) @@ "00" + cmd.pc := mmuBus.rsp.physicalAddress(31 downto 2) @@ U"00" //do not emit memory request if MMU miss when(mmuBus.rsp.exception || mmuBus.rsp.refilling){ @@ -333,7 +333,7 @@ class IBusSimplePlugin( resetVector : BigInt, } val mmuLess = (mmuBus == null) generate new Area{ - cmd.pc := cmdForkStage.input.payload(31 downto 2) @@ "00" + cmd.pc := cmdForkStage.input.payload(31 downto 2) @@ U"00" } val rspJoin = new Area { @@ -389,7 +389,7 @@ class IBusSimplePlugin( resetVector : BigInt, if(catchSomething){ decodeExceptionPort.code.assignDontCare() - decodeExceptionPort.badAddr := join.pc(31 downto 2) @@ "00" + decodeExceptionPort.badAddr := join.pc(31 downto 2) @@ U"00" if(catchAccessFault) when(join.valid && join.rsp.error){ decodeExceptionPort.code := 1 diff --git a/src/main/scala/vexriscv/plugin/Misc.scala b/src/main/scala/vexriscv/plugin/Misc.scala index b8ddd8ea..8f68e4eb 100644 --- a/src/main/scala/vexriscv/plugin/Misc.scala +++ b/src/main/scala/vexriscv/plugin/Misc.scala @@ -50,7 +50,7 @@ object RvcDecompressor{ ret := (i(11 downto 7) === 2) ? addi16sp | lui } is(12){ - val isImmediate = i(11 downto 10) =/= "11" + val isImmediate = i(11 downto 10) =/= B"11" val isShift = !i(11) val func3 = i(11 downto 10).mux( 0 -> B"101", @@ -64,7 +64,7 @@ object RvcDecompressor{ ) ) val msbs = Mux( - sel = i(11 downto 10) === "10", + sel = i(11 downto 10) === B"10", whenTrue = B((6 downto 0) -> i(12)), //andi whenFalse = B"0" ## (i(11 downto 10) === B"01" || (i(11 downto 10) === B"11" && i(6 downto 5) === B"00")) ## B"00000" ) diff --git a/src/main/scala/vexriscv/plugin/MulDivIterativePlugin.scala b/src/main/scala/vexriscv/plugin/MulDivIterativePlugin.scala index 6820f8ec..eafa4daa 100644 --- a/src/main/scala/vexriscv/plugin/MulDivIterativePlugin.scala +++ b/src/main/scala/vexriscv/plugin/MulDivIterativePlugin.scala @@ -167,7 +167,7 @@ class MulDivIterativePlugin(genMul : Boolean = true, } if(dhrystoneOpt) { - execute.insert(FAST_DIV_VALID) := execute.input(IS_DIV) && execute.input(INSTRUCTION)(13 downto 12) === "00" && !execute.input(RS1).msb && !execute.input(RS2).msb && execute.input(RS1).asUInt < 16 && execute.input(RS2).asUInt < 16 && execute.input(RS2) =/= 0 + execute.insert(FAST_DIV_VALID) := execute.input(IS_DIV) && execute.input(INSTRUCTION)(13 downto 12) === B"00" && !execute.input(RS1).msb && !execute.input(RS2).msb && execute.input(RS1).asUInt < 16 && execute.input(RS2).asUInt < 16 && execute.input(RS2) =/= 0 execute.insert(FAST_DIV_VALUE) := (0 to 15).flatMap(n => (0 to 15).map(d => U(if (d == 0) 0 else n / d, 4 bits))).read(U(execute.input(RS1)(3 downto 0)) @@ U(execute.input(RS2)(3 downto 0))) //(U(execute.input(RS1)(3 downto 0)) / U(execute.input(RS2)(3 downto 0)) when(execute.input(FAST_DIV_VALID)) { execute.output(IS_DIV) := False From 29f85a7ae2d50b349ae527acecd7439b8afc0ba5 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Sun, 16 Feb 2020 18:44:10 +0100 Subject: [PATCH 303/951] Remove INSTRUCTION_READY Add proper Fetcher.ibusRsp.flush prediction are disabled yet much is broken for sure, WIP --- src/main/scala/vexriscv/VexRiscv.scala | 1 - .../vexriscv/plugin/DecoderSimplePlugin.scala | 2 +- src/main/scala/vexriscv/plugin/Fetcher.scala | 478 +++++++++--------- .../vexriscv/plugin/IBusCachedPlugin.scala | 11 +- .../vexriscv/plugin/IBusSimplePlugin.scala | 1 + 5 files changed, 237 insertions(+), 256 deletions(-) diff --git a/src/main/scala/vexriscv/VexRiscv.scala b/src/main/scala/vexriscv/VexRiscv.scala index 1e387915..3350dc9e 100644 --- a/src/main/scala/vexriscv/VexRiscv.scala +++ b/src/main/scala/vexriscv/VexRiscv.scala @@ -36,7 +36,6 @@ case class VexRiscvConfig(){ object PC extends Stageable(UInt(32 bits)) object PC_CALC_WITHOUT_JUMP extends Stageable(UInt(32 bits)) object INSTRUCTION extends Stageable(Bits(32 bits)) - object INSTRUCTION_READY extends Stageable(Bool) object INSTRUCTION_ANTICIPATED extends Stageable(Bits(32 bits)) object LEGAL_INSTRUCTION extends Stageable(Bool) object REGFILE_WRITE_VALID extends Stageable(Bool) diff --git a/src/main/scala/vexriscv/plugin/DecoderSimplePlugin.scala b/src/main/scala/vexriscv/plugin/DecoderSimplePlugin.scala index a1076e76..e88a98c9 100644 --- a/src/main/scala/vexriscv/plugin/DecoderSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/DecoderSimplePlugin.scala @@ -172,7 +172,7 @@ class DecoderSimplePlugin(catchIllegalInstruction : Boolean = false, } if(catchIllegalInstruction){ - decodeExceptionPort.valid := arbitration.isValid && input(INSTRUCTION_READY) && !input(LEGAL_INSTRUCTION) // ?? HalitIt to alow decoder stage to wait valid data from 2 stages cache cache ?? + decodeExceptionPort.valid := arbitration.isValid && !input(LEGAL_INSTRUCTION) // ?? HalitIt to alow decoder stage to wait valid data from 2 stages cache cache ?? decodeExceptionPort.code := 2 decodeExceptionPort.badAddr := input(INSTRUCTION).asUInt } diff --git a/src/main/scala/vexriscv/plugin/Fetcher.scala b/src/main/scala/vexriscv/plugin/Fetcher.scala index 8aa351e9..1fefe1a7 100644 --- a/src/main/scala/vexriscv/plugin/Fetcher.scala +++ b/src/main/scala/vexriscv/plugin/Fetcher.scala @@ -67,29 +67,42 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, pipeline(RVC_GEN) = compressedGen - prediction match { - case NONE => - case STATIC | DYNAMIC => { - predictionJumpInterface = createJumpInterface(pipeline.decode) - decodePrediction = pipeline.service(classOf[PredictionInterface]).askDecodePrediction() - } - case DYNAMIC_TARGET => { - fetchPrediction = pipeline.service(classOf[PredictionInterface]).askFetchPrediction() - if(compressedGen && cmdToRspStageCount > 1){ - dynamicTargetFailureCorrection = createJumpInterface(pipeline.decode) - } - } - } +// prediction match { +// case NONE => +// case STATIC | DYNAMIC => { +// predictionJumpInterface = createJumpInterface(pipeline.decode) +// decodePrediction = pipeline.service(classOf[PredictionInterface]).askDecodePrediction() +// } +// case DYNAMIC_TARGET => { +// fetchPrediction = pipeline.service(classOf[PredictionInterface]).askFetchPrediction() +// if(compressedGen && cmdToRspStageCount > 1){ +// dynamicTargetFailureCorrection = createJumpInterface(pipeline.decode) +// } +// } +// } pcValids = Vec(Bool, pipeline.stages.size) } + object IBUS_RSP + object DECOMPRESSOR + object INJECTOR_M2S + + def isDrivingDecode(s : Any): Boolean = { + if(injectorStage) return s == INJECTOR_M2S + if(compressedGen) return s == DECOMPRESSOR + s == IBUS_RSP + } + + def getFlushAt(s : Any, lastCond : Boolean = true): Bool = { + if(isDrivingDecode(s) && lastCond) pipeline.decode.arbitration.isRemoved else fetcherflushIt + } class FetchArea(pipeline : VexRiscv) extends Area { import pipeline._ import pipeline.config._ - //JumpService hardware implementation + //Arbitrate jump requests into pcLoad val jump = new Area { val sortedByStage = jumpInfos.sortWith((a, b) => { (pipeline.indexOf(a.stage) > pipeline.indexOf(b.stage)) || @@ -117,25 +130,25 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, val booted = RegNext(True) init (False) val inc = RegInit(False) clearWhen(corrected || pcRegPropagate) setWhen(output.fire) clearWhen(!output.valid && output.ready) val pc = pcReg + (inc ## B"00").asUInt - val predictionPcLoad = ifGen(prediction == DYNAMIC_TARGET) (Flow(UInt(32 bits))) +// val predictionPcLoad = ifGen(prediction == DYNAMIC_TARGET) (Flow(UInt(32 bits))) if(compressedGen) when(inc) { pc(1) := False } - if(predictionPcLoad != null) { - when(predictionPcLoad.valid) { - corrected := True - pc := predictionPcLoad.payload - } - } +// if(predictionPcLoad != null) { +// when(predictionPcLoad.valid) { +// corrected := True +// pc := predictionPcLoad.payload +// } +// } when(jump.pcLoad.valid) { corrected := True pc := jump.pcLoad.payload } - when(booted && (output.ready || fetcherflushIt || pcRegPropagate)){ + when(booted && (output.ready || corrected || pcRegPropagate)){ pcReg := pc } @@ -160,12 +173,12 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, pcReg := pcPlus } - val predictionPcLoad = ifGen(prediction == DYNAMIC_TARGET) (Flow(UInt(32 bits))) - if(prediction == DYNAMIC_TARGET) { - when(predictionPcLoad.valid) { - pcReg := predictionPcLoad.payload - } - } +// val predictionPcLoad = ifGen(prediction == DYNAMIC_TARGET) (Flow(UInt(32 bits))) +// if(prediction == DYNAMIC_TARGET) { +// when(predictionPcLoad.valid) { +// pcReg := predictionPcLoad.payload +// } +// } //application of the selected jump request when(jump.pcLoad.valid && (!decode.arbitration.isStuck || decode.arbitration.isRemoved)) { @@ -177,27 +190,18 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, case class FetchRsp() extends Bundle { val pc = UInt(32 bits) val rsp = IBusSimpleRsp() - val isRvc = Bool + val isRvc = Bool() } val iBusRsp = new Area { -// val input = Stream(UInt(32 bits)) -// val inputPipeline = Vec(Stream(UInt(32 bits)), cmdToRspStageCount) -// val inputPipelineHalt = Vec(False, cmdToRspStageCount-1) -// for(i <- 0 until cmdToRspStageCount) { -// inputPipeline(i) << {i match { -// case 0 => input.m2sPipeWithFlush(flush, false, collapsBubble = false) -// case _ => inputPipeline(i-1).haltWhen(inputPipelineHalt(i-1)).m2sPipeWithFlush(flush,collapsBubble = false) -// }} -// } - -// val stages = Array.fill(cmdToRspStageCount)(Stream(UInt(32 bits))) + val fetchFlush = False val stages = Array.fill(cmdToRspStageCount + 1)(new Bundle { val input = Stream(UInt(32 bits)) val output = Stream(UInt(32 bits)) - val halt = Bool - val inputSample = Bool + val halt = Bool() + val inputSample = Bool() + val flush = Bool() }) stages(0).input << fetchPc.output @@ -207,29 +211,18 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, s.output << s.input.haltWhen(s.halt) } + stages.head.flush := getFlushAt(IBUS_RSP, stages.head == stages.last) || fetchFlush for((s,sNext) <- (stages, stages.tail).zipped) { + sNext.flush := getFlushAt(IBUS_RSP, sNext == stages.last) || fetchFlush if(s == stages.head && pcRegReusedForSecondStage) { - sNext.input.arbitrationFrom(s.output.toEvent().m2sPipeWithFlush(fetcherflushIt, s != stages.head, collapsBubble = false)) + sNext.input.arbitrationFrom(s.output.toEvent().m2sPipeWithFlush(sNext.flush, s != stages.head, collapsBubble = false)) sNext.input.payload := fetchPc.pcReg fetchPc.pcRegPropagate setWhen(sNext.input.ready) } else { - sNext.input << s.output.m2sPipeWithFlush(fetcherflushIt, s != stages.head, collapsBubble = false) + sNext.input << s.output.m2sPipeWithFlush(sNext.flush, s != stages.head, collapsBubble = false) } } -// -// val pipeline = Vec(Stream(UInt(32 bits)), cmdToRspStageCount + 1) -// val halts = Vec(False, cmdToRspStageCount) -// for(i <- 0 until cmdToRspStageCount + 1) { -// pipeline(i) << {i match { -// case 0 => pipeline(0) << fetchPc.output.haltWhen(halts(i)) -// case 1 => pipeline(1).m2sPipeWithFlush(flush, false, collapsBubble = false) -// case _ => inputPipeline(i-1).haltWhen(inputPipelineHalt(i-1)).m2sPipeWithFlush(flush,collapsBubble = false) -// }} -// } - - // ... - val readyForError = True val output = Stream(FetchRsp()) incomingInstruction setWhen(stages.tail.map(_.input.valid).reduce(_ || _)) @@ -253,7 +246,6 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, output.pc := input.pc output.isRvc := isRvc output.rsp.inst := isRvc ? decompressed | raw -// input.ready := (bufferValid ? (!isRvc && output.ready) | (input.pc(1) || output.ready)) input.ready := !output.valid || !(!output.ready || (isRvc && !input.pc(1) && input.rsp.inst(16, 2 bits) =/= 3) || (!isRvc && bufferValid && input.rsp.inst(16, 2 bits) =/= 3)) addPrePopTask(() => { when(!input.ready && output.fire && !fetcherflushIt /* && ((isRvc && !bufferValid && !input.pc(1)) || (!isRvc && bufferValid && input.rsp.inst(16, 2 bits) =/= 3))*/) { @@ -286,7 +278,8 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, incomingInstruction setWhen (inputBeforeStage.valid) } val decodeInput = (if (injectorStage) { - val decodeInput = inputBeforeStage.m2sPipeWithFlush(fetcherflushIt, collapsBubble = false) + val flushStage = getFlushAt(INJECTOR_M2S) + val decodeInput = inputBeforeStage.m2sPipeWithFlush(flushStage, collapsBubble = false) decode.insert(INSTRUCTION_ANTICIPATED) := Mux(decode.arbitration.isStuck, decode.input(INSTRUCTION), inputBeforeStage.rsp.inst) iBusRsp.readyForError.clearWhen(decodeInput.valid) //Can't emit error when there is a instruction pending in the injector stage buffer incomingInstruction setWhen (decodeInput.valid) @@ -323,13 +316,10 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, pcValids := Vec(valids.takeRight(stages.size)) } - val decodeRemoved = RegInit(False) setWhen(decode.arbitration.isRemoved) clearWhen(fetcherflushIt) //!decode.arbitration.isStuck || decode.arbitration.isFlushed - decodeInput.ready := !decode.arbitration.isStuck - decode.arbitration.isValid := decodeInput.valid && !decodeRemoved + decode.arbitration.isValid := decodeInput.valid decode.insert(PC) := (if (decodePcGen) decodePc.pcReg else decodeInput.pc) decode.insert(INSTRUCTION) := decodeInput.rsp.inst - decode.insert(INSTRUCTION_READY) := True if (compressedGen) decode.insert(IS_RVC) := decodeInput.isRvc if (injectionPort != null) { @@ -401,11 +391,11 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, else decode.input(PC) + 4) - if(decodePc != null && decodePc.predictionPcLoad != null){ - when(decodePc.predictionPcLoad.valid){ - decode.insert(FORMAL_PC_NEXT) := decodePc.predictionPcLoad.payload - } - } +// if(decodePc != null && decodePc.predictionPcLoad != null){ +// when(decodePc.predictionPcLoad.valid){ +// decode.insert(FORMAL_PC_NEXT) := decodePc.predictionPcLoad.payload +// } +// } jumpInfos.foreach(info => { when(info.interface.valid) { @@ -429,182 +419,182 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, (ifGen(compressedGen)(decompressorContext), injectorContextWire) } - val predictor = prediction match { - case NONE => - case STATIC | DYNAMIC => { - def historyWidth = 2 - val dynamic = ifGen(prediction == DYNAMIC) (new Area { - case class BranchPredictorLine() extends Bundle{ - val history = SInt(historyWidth bits) - } - - val historyCache = Mem(BranchPredictorLine(), 1 << historyRamSizeLog2) - val historyWrite = historyCache.writePort - val historyWriteLast = RegNextWhen(historyWrite, iBusRsp.stages(0).output.ready) - val hazard = historyWriteLast.valid && historyWriteLast.address === (iBusRsp.stages(0).input.payload >> 2).resized - - case class DynamicContext() extends Bundle{ - val hazard = Bool - val line = BranchPredictorLine() - } - val fetchContext = DynamicContext() - fetchContext.hazard := hazard - fetchContext.line := historyCache.readSync((fetchPc.output.payload >> 2).resized, iBusRsp.stages(0).output.ready || fetcherflushIt) - - object PREDICTION_CONTEXT extends Stageable(DynamicContext()) - decode.insert(PREDICTION_CONTEXT) := stage1ToInjectorPipe(fetchContext)._2 - val decodeContextPrediction = decode.input(PREDICTION_CONTEXT).line.history.msb - - val branchStage = decodePrediction.stage - val branchContext = branchStage.input(PREDICTION_CONTEXT) - val moreJump = decodePrediction.rsp.wasWrong ^ branchContext.line.history.msb - - historyWrite.address := branchStage.input(PC)(2, historyRamSizeLog2 bits) + (if(pipeline(RVC_GEN)) - ((!branchStage.input(IS_RVC) && branchStage.input(PC)(1)) ? U(1) | U(0)) - else - U(0)) - - historyWrite.data.history := branchContext.line.history + (moreJump ? S(-1) | S(1)) - val sat = (branchContext.line.history === (moreJump ? S(branchContext.line.history.minValue) | S(branchContext.line.history.maxValue))) - historyWrite.valid := !branchContext.hazard && branchStage.arbitration.isFiring && branchStage.input(BRANCH_CTRL) === BranchCtrlEnum.B && !sat - }) - - - val imm = IMM(decode.input(INSTRUCTION)) - - val conditionalBranchPrediction = prediction match { - case STATIC => imm.b_sext.msb - case DYNAMIC => dynamic.decodeContextPrediction - } - - decodePrediction.cmd.hadBranch := decode.input(BRANCH_CTRL) === BranchCtrlEnum.JAL || (decode.input(BRANCH_CTRL) === BranchCtrlEnum.B && conditionalBranchPrediction) - - val noPredictionOnMissaligned = (!pipeline(RVC_GEN)) generate new Area{ - val missaligned = decode.input(BRANCH_CTRL).mux( - BranchCtrlEnum.JAL -> imm.j_sext(1), - default -> imm.b_sext(1) - ) - decodePrediction.cmd.hadBranch clearWhen(missaligned) - } - - //TODO no more fireing depedancies - predictionJumpInterface.valid := decode.arbitration.isValid && decodePrediction.cmd.hadBranch //TODO OH Doublon de priorité - predictionJumpInterface.payload := decode.input(PC) + ((decode.input(BRANCH_CTRL) === BranchCtrlEnum.JAL) ? imm.j_sext | imm.b_sext).asUInt - if(relaxPredictorAddress) KeepAttribute(predictionJumpInterface.payload) - - when(predictionJumpInterface.valid && decode.arbitration.isFiring){ - flushIt() - } - } - case DYNAMIC_TARGET => new Area{ -// assert(!compressedGen || cmdToRspStageCount == 1, "Can't combine DYNAMIC_TARGET and RVC as it could stop the instruction fetch mid-air") - - case class BranchPredictorLine() extends Bundle{ - val source = Bits(30 - historyRamSizeLog2 bits) - val branchWish = UInt(2 bits) - val target = UInt(32 bits) - val unaligned = ifGen(compressedGen)(Bool) - } - - val history = Mem(BranchPredictorLine(), 1 << historyRamSizeLog2) - val historyWrite = history.writePort - - val line = history.readSync((iBusRsp.stages(0).input.payload >> 2).resized, iBusRsp.stages(0).output.ready || fetcherflushIt) - val hit = line.source === (iBusRsp.stages(1).input.payload.asBits >> 2 + historyRamSizeLog2) && (if(compressedGen)(!(!line.unaligned && iBusRsp.stages(1).input.payload(1))) else True) - - //Avoid stoping instruction fetch in the middle patch - if(compressedGen && cmdToRspStageCount == 1){ - hit clearWhen(!decompressor.output.valid) - } - - //Avoid write to read hazard - val historyWriteLast = RegNextWhen(historyWrite, iBusRsp.stages(0).output.ready) - val hazard = historyWriteLast.valid && historyWriteLast.address === (iBusRsp.stages(1).input.payload >> 2).resized - //TODO improve predictionPcLoad way of doing things - fetchPc.predictionPcLoad.valid := line.branchWish.msb && hit && !hazard && iBusRsp.stages(1).output.valid //XXX && !(!line.unaligned && iBusRsp.inputPipeline(0).payload(1)) - fetchPc.predictionPcLoad.payload := line.target - - case class PredictionResult() extends Bundle{ - val hazard = Bool - val hit = Bool - val line = BranchPredictorLine() - } - - val fetchContext = PredictionResult() - fetchContext.hazard := hazard - fetchContext.hit := hit - fetchContext.line := line - - val (decompressorContext, injectorContext) = stage1ToInjectorPipe(fetchContext) - if(compressedGen) { - //prediction hit on the right instruction into words - decompressorContext.hit clearWhen(decompressorContext.line.unaligned && (decompressor.bufferValid || (decompressor.isRvc && !decompressor.input.pc(1)))) - - // if(compressedGen) injectorContext.hit clearWhen(decodePc.pcReg(1) =/= injectorContext.line.unaligned) - - decodePc.predictionPcLoad.valid := injectorContext.line.branchWish.msb && injectorContext.hit && !injectorContext.hazard && injector.decodeInput.fire - decodePc.predictionPcLoad.payload := injectorContext.line.target - - - when(decompressorContext.line.branchWish.msb && decompressorContext.hit && !decompressorContext.hazard && decompressor.output.fire){ - decompressor.bufferValid := False - decompressor.input.ready := True - } - } - - object PREDICTION_CONTEXT extends Stageable(PredictionResult()) - pipeline.decode.insert(PREDICTION_CONTEXT) := injectorContext - val branchStage = fetchPrediction.stage - val branchContext = branchStage.input(PREDICTION_CONTEXT) - - fetchPrediction.cmd.hadBranch := branchContext.hit && !branchContext.hazard && branchContext.line.branchWish.msb - fetchPrediction.cmd.targetPc := branchContext.line.target - - - historyWrite.valid := False - historyWrite.address := fetchPrediction.rsp.sourceLastWord(2, historyRamSizeLog2 bits) - historyWrite.data.source := fetchPrediction.rsp.sourceLastWord.asBits >> 2 + historyRamSizeLog2 - historyWrite.data.target := fetchPrediction.rsp.finalPc - if(compressedGen) historyWrite.data.unaligned := !fetchPrediction.stage.input(PC)(1) ^ fetchPrediction.stage.input(IS_RVC) - - when(fetchPrediction.rsp.wasRight) { - historyWrite.valid := branchContext.hit - historyWrite.data.branchWish := branchContext.line.branchWish + (branchContext.line.branchWish === 2).asUInt - (branchContext.line.branchWish === 1).asUInt - } otherwise { - when(branchContext.hit) { - historyWrite.valid := True - historyWrite.data.branchWish := branchContext.line.branchWish - (branchContext.line.branchWish.msb).asUInt + (!branchContext.line.branchWish.msb).asUInt - } otherwise { - historyWrite.valid := True - historyWrite.data.branchWish := "10" - } - } - - historyWrite.valid clearWhen(branchContext.hazard || !branchStage.arbitration.isFiring) - - - - val predictionFailure = ifGen(compressedGen && cmdToRspStageCount > 1)(new Area{ - val predictionBranch = decompressorContext.hit && !decompressorContext.hazard && decompressorContext.line.branchWish(1) - val unalignedWordIssue = decompressor.bufferFill && decompressor.input.rsp.inst(17 downto 16) === 3 && predictionBranch - val decompressorFailure = RegInit(False) setWhen(unalignedWordIssue) clearWhen(fetcherflushIt) - val injectorFailure = Delay(decompressorFailure, cycleCount=if(injectorStage) 1 else 0, when=injector.decodeInput.ready) - val bypassFailure = if(!injectorStage) False else decompressorFailure && !injector.decodeInput.valid - - dynamicTargetFailureCorrection.valid := False - dynamicTargetFailureCorrection.payload := decode.input(PC) - when(injectorFailure || bypassFailure){ - historyWrite.valid := True - historyWrite.address := (decode.input(PC) >> 2).resized - historyWrite.data.branchWish := 0 - - decode.arbitration.isValid := False - decode.arbitration.flushNext := True - dynamicTargetFailureCorrection.valid := True - } - }) - } - } +// val predictor = prediction match { +// case NONE => +// case STATIC | DYNAMIC => { +// def historyWidth = 2 +// val dynamic = ifGen(prediction == DYNAMIC) (new Area { +// case class BranchPredictorLine() extends Bundle{ +// val history = SInt(historyWidth bits) +// } +// +// val historyCache = Mem(BranchPredictorLine(), 1 << historyRamSizeLog2) +// val historyWrite = historyCache.writePort +// val historyWriteLast = RegNextWhen(historyWrite, iBusRsp.stages(0).output.ready) +// val hazard = historyWriteLast.valid && historyWriteLast.address === (iBusRsp.stages(0).input.payload >> 2).resized +// +// case class DynamicContext() extends Bundle{ +// val hazard = Bool +// val line = BranchPredictorLine() +// } +// val fetchContext = DynamicContext() +// fetchContext.hazard := hazard +// fetchContext.line := historyCache.readSync((fetchPc.output.payload >> 2).resized, iBusRsp.stages(0).output.ready || fetcherflushIt) +// +// object PREDICTION_CONTEXT extends Stageable(DynamicContext()) +// decode.insert(PREDICTION_CONTEXT) := stage1ToInjectorPipe(fetchContext)._2 +// val decodeContextPrediction = decode.input(PREDICTION_CONTEXT).line.history.msb +// +// val branchStage = decodePrediction.stage +// val branchContext = branchStage.input(PREDICTION_CONTEXT) +// val moreJump = decodePrediction.rsp.wasWrong ^ branchContext.line.history.msb +// +// historyWrite.address := branchStage.input(PC)(2, historyRamSizeLog2 bits) + (if(pipeline(RVC_GEN)) +// ((!branchStage.input(IS_RVC) && branchStage.input(PC)(1)) ? U(1) | U(0)) +// else +// U(0)) +// +// historyWrite.data.history := branchContext.line.history + (moreJump ? S(-1) | S(1)) +// val sat = (branchContext.line.history === (moreJump ? S(branchContext.line.history.minValue) | S(branchContext.line.history.maxValue))) +// historyWrite.valid := !branchContext.hazard && branchStage.arbitration.isFiring && branchStage.input(BRANCH_CTRL) === BranchCtrlEnum.B && !sat +// }) +// +// +// val imm = IMM(decode.input(INSTRUCTION)) +// +// val conditionalBranchPrediction = prediction match { +// case STATIC => imm.b_sext.msb +// case DYNAMIC => dynamic.decodeContextPrediction +// } +// +// decodePrediction.cmd.hadBranch := decode.input(BRANCH_CTRL) === BranchCtrlEnum.JAL || (decode.input(BRANCH_CTRL) === BranchCtrlEnum.B && conditionalBranchPrediction) +// +// val noPredictionOnMissaligned = (!pipeline(RVC_GEN)) generate new Area{ +// val missaligned = decode.input(BRANCH_CTRL).mux( +// BranchCtrlEnum.JAL -> imm.j_sext(1), +// default -> imm.b_sext(1) +// ) +// decodePrediction.cmd.hadBranch clearWhen(missaligned) +// } +// +// //TODO no more fireing depedancies +// predictionJumpInterface.valid := decode.arbitration.isValid && decodePrediction.cmd.hadBranch //TODO OH Doublon de priorité +// predictionJumpInterface.payload := decode.input(PC) + ((decode.input(BRANCH_CTRL) === BranchCtrlEnum.JAL) ? imm.j_sext | imm.b_sext).asUInt +// if(relaxPredictorAddress) KeepAttribute(predictionJumpInterface.payload) +// +// when(predictionJumpInterface.valid && decode.arbitration.isFiring){ +// flushIt() +// } +// } +// case DYNAMIC_TARGET => new Area{ +//// assert(!compressedGen || cmdToRspStageCount == 1, "Can't combine DYNAMIC_TARGET and RVC as it could stop the instruction fetch mid-air") +// +// case class BranchPredictorLine() extends Bundle{ +// val source = Bits(30 - historyRamSizeLog2 bits) +// val branchWish = UInt(2 bits) +// val target = UInt(32 bits) +// val unaligned = ifGen(compressedGen)(Bool) +// } +// +// val history = Mem(BranchPredictorLine(), 1 << historyRamSizeLog2) +// val historyWrite = history.writePort +// +// val line = history.readSync((iBusRsp.stages(0).input.payload >> 2).resized, iBusRsp.stages(0).output.ready || fetcherflushIt) +// val hit = line.source === (iBusRsp.stages(1).input.payload.asBits >> 2 + historyRamSizeLog2) && (if(compressedGen)(!(!line.unaligned && iBusRsp.stages(1).input.payload(1))) else True) +// +// //Avoid stoping instruction fetch in the middle patch +// if(compressedGen && cmdToRspStageCount == 1){ +// hit clearWhen(!decompressor.output.valid) +// } +// +// //Avoid write to read hazard +// val historyWriteLast = RegNextWhen(historyWrite, iBusRsp.stages(0).output.ready) +// val hazard = historyWriteLast.valid && historyWriteLast.address === (iBusRsp.stages(1).input.payload >> 2).resized +// //TODO improve predictionPcLoad way of doing things +// fetchPc.predictionPcLoad.valid := line.branchWish.msb && hit && !hazard && iBusRsp.stages(1).output.valid //XXX && !(!line.unaligned && iBusRsp.inputPipeline(0).payload(1)) +// fetchPc.predictionPcLoad.payload := line.target +// +// case class PredictionResult() extends Bundle{ +// val hazard = Bool +// val hit = Bool +// val line = BranchPredictorLine() +// } +// +// val fetchContext = PredictionResult() +// fetchContext.hazard := hazard +// fetchContext.hit := hit +// fetchContext.line := line +// +// val (decompressorContext, injectorContext) = stage1ToInjectorPipe(fetchContext) +// if(compressedGen) { +// //prediction hit on the right instruction into words +// decompressorContext.hit clearWhen(decompressorContext.line.unaligned && (decompressor.bufferValid || (decompressor.isRvc && !decompressor.input.pc(1)))) +// +// // if(compressedGen) injectorContext.hit clearWhen(decodePc.pcReg(1) =/= injectorContext.line.unaligned) +// +// decodePc.predictionPcLoad.valid := injectorContext.line.branchWish.msb && injectorContext.hit && !injectorContext.hazard && injector.decodeInput.fire +// decodePc.predictionPcLoad.payload := injectorContext.line.target +// +// +// when(decompressorContext.line.branchWish.msb && decompressorContext.hit && !decompressorContext.hazard && decompressor.output.fire){ +// decompressor.bufferValid := False +// decompressor.input.ready := True +// } +// } +// +// object PREDICTION_CONTEXT extends Stageable(PredictionResult()) +// pipeline.decode.insert(PREDICTION_CONTEXT) := injectorContext +// val branchStage = fetchPrediction.stage +// val branchContext = branchStage.input(PREDICTION_CONTEXT) +// +// fetchPrediction.cmd.hadBranch := branchContext.hit && !branchContext.hazard && branchContext.line.branchWish.msb +// fetchPrediction.cmd.targetPc := branchContext.line.target +// +// +// historyWrite.valid := False +// historyWrite.address := fetchPrediction.rsp.sourceLastWord(2, historyRamSizeLog2 bits) +// historyWrite.data.source := fetchPrediction.rsp.sourceLastWord.asBits >> 2 + historyRamSizeLog2 +// historyWrite.data.target := fetchPrediction.rsp.finalPc +// if(compressedGen) historyWrite.data.unaligned := !fetchPrediction.stage.input(PC)(1) ^ fetchPrediction.stage.input(IS_RVC) +// +// when(fetchPrediction.rsp.wasRight) { +// historyWrite.valid := branchContext.hit +// historyWrite.data.branchWish := branchContext.line.branchWish + (branchContext.line.branchWish === 2).asUInt - (branchContext.line.branchWish === 1).asUInt +// } otherwise { +// when(branchContext.hit) { +// historyWrite.valid := True +// historyWrite.data.branchWish := branchContext.line.branchWish - (branchContext.line.branchWish.msb).asUInt + (!branchContext.line.branchWish.msb).asUInt +// } otherwise { +// historyWrite.valid := True +// historyWrite.data.branchWish := "10" +// } +// } +// +// historyWrite.valid clearWhen(branchContext.hazard || !branchStage.arbitration.isFiring) +// +// +// +// val predictionFailure = ifGen(compressedGen && cmdToRspStageCount > 1)(new Area{ +// val predictionBranch = decompressorContext.hit && !decompressorContext.hazard && decompressorContext.line.branchWish(1) +// val unalignedWordIssue = decompressor.bufferFill && decompressor.input.rsp.inst(17 downto 16) === 3 && predictionBranch +// val decompressorFailure = RegInit(False) setWhen(unalignedWordIssue) clearWhen(fetcherflushIt) +// val injectorFailure = Delay(decompressorFailure, cycleCount=if(injectorStage) 1 else 0, when=injector.decodeInput.ready) +// val bypassFailure = if(!injectorStage) False else decompressorFailure && !injector.decodeInput.valid +// +// dynamicTargetFailureCorrection.valid := False +// dynamicTargetFailureCorrection.payload := decode.input(PC) +// when(injectorFailure || bypassFailure){ +// historyWrite.valid := True +// historyWrite.address := (decode.input(PC) >> 2).resized +// historyWrite.data.branchWish := 0 +// +// decode.arbitration.isValid := False +// decode.arbitration.flushNext := True +// dynamicTargetFailureCorrection.valid := True +// } +// }) +// } +// } def stageXToIBusRsp[T <: Data](stage : Any, input : T): (T) ={ iBusRsp.stages.dropWhile(_ != stage).tail.foldLeft(input)((data,stage) => RegNextWhen(data, stage.output.ready)) diff --git a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala index a7b21940..953ef241 100644 --- a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala @@ -237,19 +237,10 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l, decodeExceptionPort.code := 1 } - when(!iBusRsp.readyForError){ - redoFetch := False - cache.io.cpu.fill.valid := False - } -// when(pipeline.stages.map(_.arbitration.flushIt).orR){ -// cache.io.cpu.fill.valid := False -// } - - redoBranch.valid := redoFetch redoBranch.payload := (if (decodePcGen) decode.input(PC) else cacheRsp.pc) - decode.arbitration.flushNext setWhen(redoBranch.valid) + iBusRsp.fetchFlush setWhen(redoBranch.valid) cacheRspArbitration.halt setWhen (issueDetected || iBusRspOutputHalt) diff --git a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala index fa74f6c8..c866a4a0 100644 --- a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala @@ -384,6 +384,7 @@ class IBusSimplePlugin( resetVector : BigInt, decode.arbitration.flushIt setWhen(redoBranch.valid) decode.arbitration.flushNext setWhen(redoBranch.valid) + ??? } From 8be50b8e3d3c7f3f049ba3d3e10ce1021c5713a4 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Mon, 17 Feb 2020 12:50:12 +0100 Subject: [PATCH 304/951] IBusFetcher now support proper iBusRsp.redo/flush --- src/main/scala/vexriscv/demo/Linux.scala | 4 ++-- src/main/scala/vexriscv/plugin/Fetcher.scala | 14 ++++++++++---- .../scala/vexriscv/plugin/IBusCachedPlugin.scala | 12 +++++------- .../scala/vexriscv/plugin/IBusSimplePlugin.scala | 14 +++++--------- src/test/scala/vexriscv/DhrystoneBench.scala | 4 ++-- 5 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/main/scala/vexriscv/demo/Linux.scala b/src/main/scala/vexriscv/demo/Linux.scala index 906b5b22..c13ef12e 100644 --- a/src/main/scala/vexriscv/demo/Linux.scala +++ b/src/main/scala/vexriscv/demo/Linux.scala @@ -272,7 +272,7 @@ object LinuxGen { // wfiGenAsNop = true, // ucycleAccess = CsrAccess.NONE // )), -// new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))), + new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))), new BranchPlugin( earlyBranch = false, catchAddressMisaligned = true, @@ -310,7 +310,7 @@ object LinuxGen { // } // } - SpinalConfig(mergeAsyncProcess = true, anonymSignalPrefix = "_zz").generateVerilog { + SpinalConfig(mergeAsyncProcess = false, anonymSignalPrefix = "_zz").generateVerilog { val toplevel = new VexRiscv(configFull( diff --git a/src/main/scala/vexriscv/plugin/Fetcher.scala b/src/main/scala/vexriscv/plugin/Fetcher.scala index 1fefe1a7..79b8b078 100644 --- a/src/main/scala/vexriscv/plugin/Fetcher.scala +++ b/src/main/scala/vexriscv/plugin/Fetcher.scala @@ -21,7 +21,8 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, val prediction : BranchPrediction, val historyRamSizeLog2 : Int, val injectorStage : Boolean, - val relaxPredictorAddress : Boolean) extends Plugin[VexRiscv] with JumpService with IBusFetcher{ + val relaxPredictorAddress : Boolean, + val fetchRedoGen : Boolean) extends Plugin[VexRiscv] with JumpService with IBusFetcher{ var prefetchExceptionPort : Flow[ExceptionCause] = null var decodePrediction : DecodePredictionBus = null var fetchPrediction : FetchPredictionBus = null @@ -131,11 +132,16 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, val inc = RegInit(False) clearWhen(corrected || pcRegPropagate) setWhen(output.fire) clearWhen(!output.valid && output.ready) val pc = pcReg + (inc ## B"00").asUInt // val predictionPcLoad = ifGen(prediction == DYNAMIC_TARGET) (Flow(UInt(32 bits))) + val redo = fetchRedoGen generate Flow(UInt(32 bits)) if(compressedGen) when(inc) { pc(1) := False } + if(fetchRedoGen) when(redo.valid){ + corrected := True + pc := redo.payload + } // if(predictionPcLoad != null) { // when(predictionPcLoad.valid) { // corrected := True @@ -147,7 +153,6 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, pc := jump.pcLoad.payload } - when(booted && (output.ready || corrected || pcRegPropagate)){ pcReg := pc } @@ -231,6 +236,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, val decompressor = ifGen(decodePcGen)(new Area{ def input = iBusRsp.output val output = Stream(FetchRsp()) + val flush = getFlushAt(DECOMPRESSOR) val bufferValid = RegInit(False) val bufferData = Reg(Bits(16 bits)) @@ -248,7 +254,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, output.rsp.inst := isRvc ? decompressed | raw input.ready := !output.valid || !(!output.ready || (isRvc && !input.pc(1) && input.rsp.inst(16, 2 bits) =/= 3) || (!isRvc && bufferValid && input.rsp.inst(16, 2 bits) =/= 3)) addPrePopTask(() => { - when(!input.ready && output.fire && !fetcherflushIt /* && ((isRvc && !bufferValid && !input.pc(1)) || (!isRvc && bufferValid && input.rsp.inst(16, 2 bits) =/= 3))*/) { + when(!input.ready && output.fire && !flush /* && ((isRvc && !bufferValid && !input.pc(1)) || (!isRvc && bufferValid && input.rsp.inst(16, 2 bits) =/= 3))*/) { input.pc.getDrivingReg(1) := True } }) @@ -264,7 +270,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, } bufferData := input.rsp.inst(31 downto 16) } - bufferValid.clearWhen(fetcherflushIt) + bufferValid.clearWhen(flush) iBusRsp.readyForError.clearWhen(bufferValid && isRvc) //Can't emit error, as there is a earlier instruction pending incomingInstruction setWhen(bufferValid && bufferData(1 downto 0) =/= 3) }) diff --git a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala index 06ffa0a2..537cb0f8 100644 --- a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala @@ -46,7 +46,8 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l, prediction = prediction, historyRamSizeLog2 = historyRamSizeLog2, injectorStage = (!config.twoCycleCache && !withoutInjectorStage) || injectorStage, - relaxPredictorAddress = relaxPredictorAddress){ + relaxPredictorAddress = relaxPredictorAddress, + fetchRedoGen = true){ import config._ assert(isPow2(cacheSize)) @@ -86,9 +87,6 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l, FLUSH_ALL -> True )) - - redoBranch = pipeline.service(classOf[JumpService]).createJumpInterface(pipeline.decode, priority = 1) //Priority 1 will win against branch predictor - if(catchSomething) { val exceptionService = pipeline.service(classOf[ExceptionService]) decodeExceptionPort = exceptionService.newExceptionPort(pipeline.decode,1) @@ -238,9 +236,9 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l, } - redoBranch.valid := redoFetch - redoBranch.payload := (if (decodePcGen) decode.input(PC) else cacheRsp.pc) - iBusRsp.fetchFlush setWhen(redoBranch.valid) + fetchPc.redo.valid := redoFetch + fetchPc.redo.payload := iBusRsp.stages.last.input.payload + iBusRsp.fetchFlush setWhen(redoFetch) cacheRspArbitration.halt setWhen (issueDetected || iBusRspOutputHalt) diff --git a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala index 0be42753..aa4fcb6d 100644 --- a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala @@ -245,13 +245,13 @@ class IBusSimplePlugin( resetVector : BigInt, prediction = prediction, historyRamSizeLog2 = historyRamSizeLog2, injectorStage = injectorStage, - relaxPredictorAddress = relaxPredictorAddress){ + relaxPredictorAddress = relaxPredictorAddress, + fetchRedoGen = memoryTranslatorPortConfig != null){ var iBus : IBusSimpleBus = null var decodeExceptionPort : Flow[ExceptionCause] = null val catchSomething = memoryTranslatorPortConfig != null || catchAccessFault var mmuBus : MemoryTranslatorBus = null - var redoBranch : Flow[UInt] = null if(rspHoldValue) assert(busLatencyMin <= 1) @@ -268,7 +268,6 @@ class IBusSimplePlugin( resetVector : BigInt, if(memoryTranslatorPortConfig != null) { mmuBus = pipeline.service(classOf[MemoryTranslator]).newTranslationPort(MemoryTranslatorPort.PRIORITY_INSTRUCTION, memoryTranslatorPortConfig) - redoBranch = pipeline.service(classOf[JumpService]).createJumpInterface(pipeline.decode, priority = 1) //Priority 1 will win against branch predictor } } @@ -379,12 +378,9 @@ class IBusSimplePlugin( resetVector : BigInt, if(memoryTranslatorPortConfig != null){ redoRequired setWhen( stages.last.input.valid && mmu.joinCtx.refilling) - redoBranch.valid := redoRequired && iBusRsp.readyForError - redoBranch.payload := decode.input(PC) - - decode.arbitration.flushIt setWhen(redoBranch.valid) - decode.arbitration.flushNext setWhen(redoBranch.valid) - ??? + fetchPc.redo.valid := redoRequired && iBusRsp.readyForError + fetchPc.redo.payload := decode.input(PC) + iBusRsp.fetchFlush setWhen(fetchPc.redo.valid) } diff --git a/src/test/scala/vexriscv/DhrystoneBench.scala b/src/test/scala/vexriscv/DhrystoneBench.scala index 1034aed0..d23c4e1d 100644 --- a/src/test/scala/vexriscv/DhrystoneBench.scala +++ b/src/test/scala/vexriscv/DhrystoneBench.scala @@ -102,9 +102,9 @@ class DhrystoneBench extends FunSuite{ getDmips( name = "GenLinuxBalenced", gen = LinuxGen.main(Array.fill[String](0)("")), - testCmd = "make clean run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD DHRYSTONE=yes SUPERVISOR=yes MMU=no CSR=yes CSR_SKIP_TEST=yes DEBUG_PLUGIN=no COMPRESSED=no MUL=yes DIV=yes LRSC=yes AMO=yes REDO=10 TRACE=no COREMARK=yes LINUX_REGRESSION=no" + testCmd = "make clean run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD DHRYSTONE=yes SUPERVISOR=yes MMU=no CSR=yes CSR_SKIP_TEST=yes COMPRESSED=no MUL=yes DIV=yes LRSC=yes AMO=yes REDO=10 TRACE=no COREMARK=yes LINUX_REGRESSION=no" ) - + //make run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD DHRYSTONE=yess SUPERVISOR=yes CSR=yes COMPRESSED=no MUL=yes DIV=yes LRSC=yes AMO=yes REDO=1 TRACE=no LINUX_REGRESSION=yes SEED=42 test("final_report") { From 9e75e2cb58967f9142fe812dcef3968b55296e38 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Mon, 17 Feb 2020 14:36:08 +0100 Subject: [PATCH 305/951] IBusFetcher disable pcRegReusedForSecondStage when using fetch prediction. Fix some fetch flush DYNAMIC_PREDICTION start to work again --- src/main/scala/vexriscv/plugin/Fetcher.scala | 424 +++++++++--------- .../vexriscv/plugin/IBusCachedPlugin.scala | 2 +- .../vexriscv/plugin/IBusSimplePlugin.scala | 2 +- src/main/scala/vexriscv/plugin/Misc.scala | 7 +- 4 files changed, 218 insertions(+), 217 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/Fetcher.scala b/src/main/scala/vexriscv/plugin/Fetcher.scala index 79b8b078..eae54615 100644 --- a/src/main/scala/vexriscv/plugin/Fetcher.scala +++ b/src/main/scala/vexriscv/plugin/Fetcher.scala @@ -16,7 +16,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, val decodePcGen : Boolean, val compressedGen : Boolean, val cmdToRspStageCount : Int, - val pcRegReusedForSecondStage : Boolean, + val allowPcRegReusedForSecondStage : Boolean, val injectorReadyCutGen : Boolean, val prediction : BranchPrediction, val historyRamSizeLog2 : Int, @@ -43,7 +43,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, injectionPort = Stream(Bits(32 bits)) injectionPort } - + def pcRegReusedForSecondStage = allowPcRegReusedForSecondStage && prediction != DYNAMIC_TARGET var predictionJumpInterface : Flow[UInt] = null override def haltIt(): Unit = fetcherHalt := True @@ -68,19 +68,19 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, pipeline(RVC_GEN) = compressedGen -// prediction match { -// case NONE => -// case STATIC | DYNAMIC => { -// predictionJumpInterface = createJumpInterface(pipeline.decode) -// decodePrediction = pipeline.service(classOf[PredictionInterface]).askDecodePrediction() -// } -// case DYNAMIC_TARGET => { -// fetchPrediction = pipeline.service(classOf[PredictionInterface]).askFetchPrediction() -// if(compressedGen && cmdToRspStageCount > 1){ -// dynamicTargetFailureCorrection = createJumpInterface(pipeline.decode) -// } -// } -// } + prediction match { + case NONE => + case STATIC | DYNAMIC => { + predictionJumpInterface = createJumpInterface(pipeline.decode) + decodePrediction = pipeline.service(classOf[PredictionInterface]).askDecodePrediction() + } + case DYNAMIC_TARGET => { + fetchPrediction = pipeline.service(classOf[PredictionInterface]).askFetchPrediction() + if(compressedGen && cmdToRspStageCount > 1){ + dynamicTargetFailureCorrection = createJumpInterface(pipeline.decode) + } + } + } pcValids = Vec(Bool, pipeline.stages.size) } @@ -131,7 +131,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, val booted = RegNext(True) init (False) val inc = RegInit(False) clearWhen(corrected || pcRegPropagate) setWhen(output.fire) clearWhen(!output.valid && output.ready) val pc = pcReg + (inc ## B"00").asUInt -// val predictionPcLoad = ifGen(prediction == DYNAMIC_TARGET) (Flow(UInt(32 bits))) + val predictionPcLoad = ifGen(prediction == DYNAMIC_TARGET) (Flow(UInt(32 bits))) val redo = fetchRedoGen generate Flow(UInt(32 bits)) if(compressedGen) when(inc) { @@ -142,12 +142,12 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, corrected := True pc := redo.payload } -// if(predictionPcLoad != null) { -// when(predictionPcLoad.valid) { -// corrected := True -// pc := predictionPcLoad.payload -// } -// } + if(predictionPcLoad != null) { + when(predictionPcLoad.valid) { + corrected := True + pc := predictionPcLoad.payload + } + } when(jump.pcLoad.valid) { corrected := True pc := jump.pcLoad.payload @@ -178,12 +178,12 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, pcReg := pcPlus } -// val predictionPcLoad = ifGen(prediction == DYNAMIC_TARGET) (Flow(UInt(32 bits))) -// if(prediction == DYNAMIC_TARGET) { -// when(predictionPcLoad.valid) { -// pcReg := predictionPcLoad.payload -// } -// } + val predictionPcLoad = ifGen(prediction == DYNAMIC_TARGET) (Flow(UInt(32 bits))) + if(prediction == DYNAMIC_TARGET) { + when(predictionPcLoad.valid) { + pcReg := predictionPcLoad.payload + } + } //application of the selected jump request when(jump.pcLoad.valid && (!decode.arbitration.isStuck || decode.arbitration.isRemoved)) { @@ -205,26 +205,25 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, val input = Stream(UInt(32 bits)) val output = Stream(UInt(32 bits)) val halt = Bool() - val inputSample = Bool() val flush = Bool() }) stages(0).input << fetchPc.output - stages(0).inputSample := True for(s <- stages) { s.halt := False s.output << s.input.haltWhen(s.halt) } - stages.head.flush := getFlushAt(IBUS_RSP, stages.head == stages.last) || fetchFlush + stages.head.flush := False //getFlushAt(IBUS_RSP, stages.head == stages.last) || fetchFlush for((s,sNext) <- (stages, stages.tail).zipped) { + val discardInputOnFlush = s != stages.head sNext.flush := getFlushAt(IBUS_RSP, sNext == stages.last) || fetchFlush if(s == stages.head && pcRegReusedForSecondStage) { - sNext.input.arbitrationFrom(s.output.toEvent().m2sPipeWithFlush(sNext.flush, s != stages.head, collapsBubble = false)) + sNext.input.arbitrationFrom(s.output.toEvent().m2sPipeWithFlush(sNext.flush, false, collapsBubble = false, flushInput = s.flush)) sNext.input.payload := fetchPc.pcReg fetchPc.pcRegPropagate setWhen(sNext.input.ready) } else { - sNext.input << s.output.m2sPipeWithFlush(sNext.flush, s != stages.head, collapsBubble = false) + sNext.input << s.output.m2sPipeWithFlush(sNext.flush, false, collapsBubble = false, flushInput = s.flush) } } @@ -234,7 +233,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, } val decompressor = ifGen(decodePcGen)(new Area{ - def input = iBusRsp.output + val input = iBusRsp.output.clearValidWhen(iBusRsp.stages.last.flush) val output = Stream(FetchRsp()) val flush = getFlushAt(DECOMPRESSOR) @@ -285,7 +284,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, } val decodeInput = (if (injectorStage) { val flushStage = getFlushAt(INJECTOR_M2S) - val decodeInput = inputBeforeStage.m2sPipeWithFlush(flushStage, collapsBubble = false) + val decodeInput = inputBeforeStage.m2sPipeWithFlush(flushStage, false, collapsBubble = false, flushInput = fetcherflushIt) decode.insert(INSTRUCTION_ANTICIPATED) := Mux(decode.arbitration.isStuck, decode.input(INSTRUCTION), inputBeforeStage.rsp.inst) iBusRsp.readyForError.clearWhen(decodeInput.valid) //Can't emit error when there is a instruction pending in the injector stage buffer incomingInstruction setWhen (decodeInput.valid) @@ -397,11 +396,11 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, else decode.input(PC) + 4) -// if(decodePc != null && decodePc.predictionPcLoad != null){ -// when(decodePc.predictionPcLoad.valid){ -// decode.insert(FORMAL_PC_NEXT) := decodePc.predictionPcLoad.payload -// } -// } + if(decodePc != null && decodePc.predictionPcLoad != null){ + when(decodePc.predictionPcLoad.valid){ + decode.insert(FORMAL_PC_NEXT) := decodePc.predictionPcLoad.payload + } + } jumpInfos.foreach(info => { when(info.interface.valid) { @@ -425,182 +424,181 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, (ifGen(compressedGen)(decompressorContext), injectorContextWire) } -// val predictor = prediction match { -// case NONE => -// case STATIC | DYNAMIC => { -// def historyWidth = 2 -// val dynamic = ifGen(prediction == DYNAMIC) (new Area { -// case class BranchPredictorLine() extends Bundle{ -// val history = SInt(historyWidth bits) -// } -// -// val historyCache = Mem(BranchPredictorLine(), 1 << historyRamSizeLog2) -// val historyWrite = historyCache.writePort -// val historyWriteLast = RegNextWhen(historyWrite, iBusRsp.stages(0).output.ready) -// val hazard = historyWriteLast.valid && historyWriteLast.address === (iBusRsp.stages(0).input.payload >> 2).resized -// -// case class DynamicContext() extends Bundle{ -// val hazard = Bool -// val line = BranchPredictorLine() -// } -// val fetchContext = DynamicContext() -// fetchContext.hazard := hazard -// fetchContext.line := historyCache.readSync((fetchPc.output.payload >> 2).resized, iBusRsp.stages(0).output.ready || fetcherflushIt) -// -// object PREDICTION_CONTEXT extends Stageable(DynamicContext()) -// decode.insert(PREDICTION_CONTEXT) := stage1ToInjectorPipe(fetchContext)._2 -// val decodeContextPrediction = decode.input(PREDICTION_CONTEXT).line.history.msb -// -// val branchStage = decodePrediction.stage -// val branchContext = branchStage.input(PREDICTION_CONTEXT) -// val moreJump = decodePrediction.rsp.wasWrong ^ branchContext.line.history.msb -// -// historyWrite.address := branchStage.input(PC)(2, historyRamSizeLog2 bits) + (if(pipeline(RVC_GEN)) -// ((!branchStage.input(IS_RVC) && branchStage.input(PC)(1)) ? U(1) | U(0)) -// else -// U(0)) -// -// historyWrite.data.history := branchContext.line.history + (moreJump ? S(-1) | S(1)) -// val sat = (branchContext.line.history === (moreJump ? S(branchContext.line.history.minValue) | S(branchContext.line.history.maxValue))) -// historyWrite.valid := !branchContext.hazard && branchStage.arbitration.isFiring && branchStage.input(BRANCH_CTRL) === BranchCtrlEnum.B && !sat -// }) -// -// -// val imm = IMM(decode.input(INSTRUCTION)) -// -// val conditionalBranchPrediction = prediction match { -// case STATIC => imm.b_sext.msb -// case DYNAMIC => dynamic.decodeContextPrediction -// } -// -// decodePrediction.cmd.hadBranch := decode.input(BRANCH_CTRL) === BranchCtrlEnum.JAL || (decode.input(BRANCH_CTRL) === BranchCtrlEnum.B && conditionalBranchPrediction) -// -// val noPredictionOnMissaligned = (!pipeline(RVC_GEN)) generate new Area{ -// val missaligned = decode.input(BRANCH_CTRL).mux( -// BranchCtrlEnum.JAL -> imm.j_sext(1), -// default -> imm.b_sext(1) -// ) -// decodePrediction.cmd.hadBranch clearWhen(missaligned) -// } -// -// //TODO no more fireing depedancies -// predictionJumpInterface.valid := decode.arbitration.isValid && decodePrediction.cmd.hadBranch //TODO OH Doublon de priorité -// predictionJumpInterface.payload := decode.input(PC) + ((decode.input(BRANCH_CTRL) === BranchCtrlEnum.JAL) ? imm.j_sext | imm.b_sext).asUInt -// if(relaxPredictorAddress) KeepAttribute(predictionJumpInterface.payload) -// -// when(predictionJumpInterface.valid && decode.arbitration.isFiring){ -// flushIt() -// } -// } -// case DYNAMIC_TARGET => new Area{ -//// assert(!compressedGen || cmdToRspStageCount == 1, "Can't combine DYNAMIC_TARGET and RVC as it could stop the instruction fetch mid-air") -// -// case class BranchPredictorLine() extends Bundle{ -// val source = Bits(30 - historyRamSizeLog2 bits) -// val branchWish = UInt(2 bits) -// val target = UInt(32 bits) -// val unaligned = ifGen(compressedGen)(Bool) -// } -// -// val history = Mem(BranchPredictorLine(), 1 << historyRamSizeLog2) -// val historyWrite = history.writePort -// -// val line = history.readSync((iBusRsp.stages(0).input.payload >> 2).resized, iBusRsp.stages(0).output.ready || fetcherflushIt) -// val hit = line.source === (iBusRsp.stages(1).input.payload.asBits >> 2 + historyRamSizeLog2) && (if(compressedGen)(!(!line.unaligned && iBusRsp.stages(1).input.payload(1))) else True) -// -// //Avoid stoping instruction fetch in the middle patch + val predictor = prediction match { + case NONE => + case STATIC | DYNAMIC => { + def historyWidth = 2 + val dynamic = ifGen(prediction == DYNAMIC) (new Area { + case class BranchPredictorLine() extends Bundle{ + val history = SInt(historyWidth bits) + } + + val historyCache = Mem(BranchPredictorLine(), 1 << historyRamSizeLog2) + val historyWrite = historyCache.writePort + val historyWriteLast = RegNextWhen(historyWrite, iBusRsp.stages(0).output.ready) + val hazard = historyWriteLast.valid && historyWriteLast.address === (iBusRsp.stages(0).input.payload >> 2).resized + + case class DynamicContext() extends Bundle{ + val hazard = Bool + val line = BranchPredictorLine() + } + val fetchContext = DynamicContext() + fetchContext.hazard := hazard + fetchContext.line := historyCache.readSync((fetchPc.output.payload >> 2).resized, iBusRsp.stages(0).output.ready || fetcherflushIt) + + object PREDICTION_CONTEXT extends Stageable(DynamicContext()) + decode.insert(PREDICTION_CONTEXT) := stage1ToInjectorPipe(fetchContext)._2 + val decodeContextPrediction = decode.input(PREDICTION_CONTEXT).line.history.msb + + val branchStage = decodePrediction.stage + val branchContext = branchStage.input(PREDICTION_CONTEXT) + val moreJump = decodePrediction.rsp.wasWrong ^ branchContext.line.history.msb + + historyWrite.address := branchStage.input(PC)(2, historyRamSizeLog2 bits) + (if(pipeline(RVC_GEN)) + ((!branchStage.input(IS_RVC) && branchStage.input(PC)(1)) ? U(1) | U(0)) + else + U(0)) + + historyWrite.data.history := branchContext.line.history + (moreJump ? S(-1) | S(1)) + val sat = (branchContext.line.history === (moreJump ? S(branchContext.line.history.minValue) | S(branchContext.line.history.maxValue))) + historyWrite.valid := !branchContext.hazard && branchStage.arbitration.isFiring && branchStage.input(BRANCH_CTRL) === BranchCtrlEnum.B && !sat + }) + + + val imm = IMM(decode.input(INSTRUCTION)) + + val conditionalBranchPrediction = prediction match { + case STATIC => imm.b_sext.msb + case DYNAMIC => dynamic.decodeContextPrediction + } + + decodePrediction.cmd.hadBranch := decode.input(BRANCH_CTRL) === BranchCtrlEnum.JAL || (decode.input(BRANCH_CTRL) === BranchCtrlEnum.B && conditionalBranchPrediction) + + val noPredictionOnMissaligned = (!pipeline(RVC_GEN)) generate new Area{ + val missaligned = decode.input(BRANCH_CTRL).mux( + BranchCtrlEnum.JAL -> imm.j_sext(1), + default -> imm.b_sext(1) + ) + decodePrediction.cmd.hadBranch clearWhen(missaligned) + } + + //TODO no more fireing depedancies + predictionJumpInterface.valid := decode.arbitration.isValid && decodePrediction.cmd.hadBranch //TODO OH Doublon de priorité + predictionJumpInterface.payload := decode.input(PC) + ((decode.input(BRANCH_CTRL) === BranchCtrlEnum.JAL) ? imm.j_sext | imm.b_sext).asUInt + if(relaxPredictorAddress) KeepAttribute(predictionJumpInterface.payload) + + when(predictionJumpInterface.valid && decode.arbitration.isFiring){ + flushIt() + } + } + case DYNAMIC_TARGET => new Area{ +// assert(!compressedGen || cmdToRspStageCount == 1, "Can't combine DYNAMIC_TARGET and RVC as it could stop the instruction fetch mid-air") + + case class BranchPredictorLine() extends Bundle{ + val source = Bits(30 - historyRamSizeLog2 bits) + val branchWish = UInt(2 bits) + val target = UInt(32 bits) + val unaligned = ifGen(compressedGen)(Bool) + } + + val history = Mem(BranchPredictorLine(), 1 << historyRamSizeLog2) + val historyWrite = history.writePort + + //Avoid write to read hazard + val historyWriteLast = RegNextWhen(historyWrite, iBusRsp.stages(0).output.ready) + val hazard = historyWriteLast.valid && historyWriteLast.address === (iBusRsp.stages(1).input.payload >> 2).resized + val line = history.readSync((iBusRsp.stages(0).input.payload >> 2).resized, iBusRsp.stages(0).output.ready) + val hit = line.source === (iBusRsp.stages(1).input.payload.asBits >> 2 + historyRamSizeLog2) && (if(compressedGen)(!(!line.unaligned && iBusRsp.stages(1).input.payload(1))) else True) + + //Avoid stoping instruction fetch in the middle patch // if(compressedGen && cmdToRspStageCount == 1){ // hit clearWhen(!decompressor.output.valid) // } -// -// //Avoid write to read hazard -// val historyWriteLast = RegNextWhen(historyWrite, iBusRsp.stages(0).output.ready) -// val hazard = historyWriteLast.valid && historyWriteLast.address === (iBusRsp.stages(1).input.payload >> 2).resized -// //TODO improve predictionPcLoad way of doing things -// fetchPc.predictionPcLoad.valid := line.branchWish.msb && hit && !hazard && iBusRsp.stages(1).output.valid //XXX && !(!line.unaligned && iBusRsp.inputPipeline(0).payload(1)) -// fetchPc.predictionPcLoad.payload := line.target -// -// case class PredictionResult() extends Bundle{ -// val hazard = Bool -// val hit = Bool -// val line = BranchPredictorLine() -// } -// -// val fetchContext = PredictionResult() -// fetchContext.hazard := hazard -// fetchContext.hit := hit -// fetchContext.line := line -// -// val (decompressorContext, injectorContext) = stage1ToInjectorPipe(fetchContext) -// if(compressedGen) { -// //prediction hit on the right instruction into words -// decompressorContext.hit clearWhen(decompressorContext.line.unaligned && (decompressor.bufferValid || (decompressor.isRvc && !decompressor.input.pc(1)))) -// -// // if(compressedGen) injectorContext.hit clearWhen(decodePc.pcReg(1) =/= injectorContext.line.unaligned) -// -// decodePc.predictionPcLoad.valid := injectorContext.line.branchWish.msb && injectorContext.hit && !injectorContext.hazard && injector.decodeInput.fire -// decodePc.predictionPcLoad.payload := injectorContext.line.target -// -// -// when(decompressorContext.line.branchWish.msb && decompressorContext.hit && !decompressorContext.hazard && decompressor.output.fire){ -// decompressor.bufferValid := False -// decompressor.input.ready := True -// } -// } -// -// object PREDICTION_CONTEXT extends Stageable(PredictionResult()) -// pipeline.decode.insert(PREDICTION_CONTEXT) := injectorContext -// val branchStage = fetchPrediction.stage -// val branchContext = branchStage.input(PREDICTION_CONTEXT) -// -// fetchPrediction.cmd.hadBranch := branchContext.hit && !branchContext.hazard && branchContext.line.branchWish.msb -// fetchPrediction.cmd.targetPc := branchContext.line.target -// -// -// historyWrite.valid := False -// historyWrite.address := fetchPrediction.rsp.sourceLastWord(2, historyRamSizeLog2 bits) -// historyWrite.data.source := fetchPrediction.rsp.sourceLastWord.asBits >> 2 + historyRamSizeLog2 -// historyWrite.data.target := fetchPrediction.rsp.finalPc -// if(compressedGen) historyWrite.data.unaligned := !fetchPrediction.stage.input(PC)(1) ^ fetchPrediction.stage.input(IS_RVC) -// -// when(fetchPrediction.rsp.wasRight) { -// historyWrite.valid := branchContext.hit -// historyWrite.data.branchWish := branchContext.line.branchWish + (branchContext.line.branchWish === 2).asUInt - (branchContext.line.branchWish === 1).asUInt -// } otherwise { -// when(branchContext.hit) { -// historyWrite.valid := True -// historyWrite.data.branchWish := branchContext.line.branchWish - (branchContext.line.branchWish.msb).asUInt + (!branchContext.line.branchWish.msb).asUInt -// } otherwise { -// historyWrite.valid := True -// historyWrite.data.branchWish := "10" -// } -// } -// -// historyWrite.valid clearWhen(branchContext.hazard || !branchStage.arbitration.isFiring) -// -// -// -// val predictionFailure = ifGen(compressedGen && cmdToRspStageCount > 1)(new Area{ -// val predictionBranch = decompressorContext.hit && !decompressorContext.hazard && decompressorContext.line.branchWish(1) -// val unalignedWordIssue = decompressor.bufferFill && decompressor.input.rsp.inst(17 downto 16) === 3 && predictionBranch -// val decompressorFailure = RegInit(False) setWhen(unalignedWordIssue) clearWhen(fetcherflushIt) -// val injectorFailure = Delay(decompressorFailure, cycleCount=if(injectorStage) 1 else 0, when=injector.decodeInput.ready) -// val bypassFailure = if(!injectorStage) False else decompressorFailure && !injector.decodeInput.valid -// -// dynamicTargetFailureCorrection.valid := False -// dynamicTargetFailureCorrection.payload := decode.input(PC) -// when(injectorFailure || bypassFailure){ -// historyWrite.valid := True -// historyWrite.address := (decode.input(PC) >> 2).resized -// historyWrite.data.branchWish := 0 -// -// decode.arbitration.isValid := False -// decode.arbitration.flushNext := True -// dynamicTargetFailureCorrection.valid := True -// } -// }) -// } -// } + + fetchPc.predictionPcLoad.valid := line.branchWish.msb && hit && !hazard && iBusRsp.stages(1).input.valid + fetchPc.predictionPcLoad.payload := line.target + + case class PredictionResult() extends Bundle{ + val hazard = Bool + val hit = Bool + val line = BranchPredictorLine() + } + + val fetchContext = PredictionResult() + fetchContext.hazard := hazard + fetchContext.hit := hit + fetchContext.line := line + + val (decompressorContext, injectorContext) = stage1ToInjectorPipe(fetchContext) + if(compressedGen) { + //prediction hit on the right instruction into words + decompressorContext.hit clearWhen(decompressorContext.line.unaligned && (decompressor.bufferValid || (decompressor.isRvc && !decompressor.input.pc(1)))) + + // if(compressedGen) injectorContext.hit clearWhen(decodePc.pcReg(1) =/= injectorContext.line.unaligned) + + decodePc.predictionPcLoad.valid := injectorContext.line.branchWish.msb && injectorContext.hit && !injectorContext.hazard && injector.decodeInput.fire + decodePc.predictionPcLoad.payload := injectorContext.line.target + + + when(decompressorContext.line.branchWish.msb && decompressorContext.hit && !decompressorContext.hazard && decompressor.output.fire){ + decompressor.bufferValid := False + decompressor.input.ready := True + } + } + + object PREDICTION_CONTEXT extends Stageable(PredictionResult()) + pipeline.decode.insert(PREDICTION_CONTEXT) := injectorContext + val branchStage = fetchPrediction.stage + val branchContext = branchStage.input(PREDICTION_CONTEXT) + + fetchPrediction.cmd.hadBranch := branchContext.hit && !branchContext.hazard && branchContext.line.branchWish.msb + fetchPrediction.cmd.targetPc := branchContext.line.target + + + historyWrite.valid := False + historyWrite.address := fetchPrediction.rsp.sourceLastWord(2, historyRamSizeLog2 bits) + historyWrite.data.source := fetchPrediction.rsp.sourceLastWord.asBits >> 2 + historyRamSizeLog2 + historyWrite.data.target := fetchPrediction.rsp.finalPc + if(compressedGen) historyWrite.data.unaligned := !fetchPrediction.stage.input(PC)(1) ^ fetchPrediction.stage.input(IS_RVC) + + when(fetchPrediction.rsp.wasRight) { + historyWrite.valid := branchContext.hit + historyWrite.data.branchWish := branchContext.line.branchWish + (branchContext.line.branchWish === 2).asUInt - (branchContext.line.branchWish === 1).asUInt + } otherwise { + when(branchContext.hit) { + historyWrite.valid := True + historyWrite.data.branchWish := branchContext.line.branchWish - (branchContext.line.branchWish.msb).asUInt + (!branchContext.line.branchWish.msb).asUInt + } otherwise { + historyWrite.valid := True + historyWrite.data.branchWish := "10" + } + } + + historyWrite.valid clearWhen(branchContext.hazard || !branchStage.arbitration.isFiring) + + + + val predictionFailure = ifGen(compressedGen && cmdToRspStageCount > 1)(new Area{ + val predictionBranch = decompressorContext.hit && !decompressorContext.hazard && decompressorContext.line.branchWish(1) + val unalignedWordIssue = decompressor.bufferFill && decompressor.input.rsp.inst(17 downto 16) === 3 && predictionBranch + val decompressorFailure = RegInit(False) setWhen(unalignedWordIssue) clearWhen(fetcherflushIt) + val injectorFailure = Delay(decompressorFailure, cycleCount=if(injectorStage) 1 else 0, when=injector.decodeInput.ready) + val bypassFailure = if(!injectorStage) False else decompressorFailure && !injector.decodeInput.valid + + dynamicTargetFailureCorrection.valid := False + dynamicTargetFailureCorrection.payload := decode.input(PC) + when(injectorFailure || bypassFailure){ + historyWrite.valid := True + historyWrite.address := (decode.input(PC) >> 2).resized + historyWrite.data.branchWish := 0 + + decode.arbitration.isValid := False + decode.arbitration.flushNext := True + dynamicTargetFailureCorrection.valid := True + } + }) + } + } def stageXToIBusRsp[T <: Data](stage : Any, input : T): (T) ={ iBusRsp.stages.dropWhile(_ != stage).tail.foldLeft(input)((data,stage) => RegNextWhen(data, stage.output.ready)) diff --git a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala index 537cb0f8..4a633643 100644 --- a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala @@ -41,7 +41,7 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l, decodePcGen = compressedGen, compressedGen = compressedGen, cmdToRspStageCount = (if(config.twoCycleCache) 2 else 1) + (if(relaxedPcCalculation) 1 else 0), - pcRegReusedForSecondStage = true, + allowPcRegReusedForSecondStage = true, injectorReadyCutGen = false, prediction = prediction, historyRamSizeLog2 = historyRamSizeLog2, diff --git a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala index aa4fcb6d..c14ac30f 100644 --- a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala @@ -240,7 +240,7 @@ class IBusSimplePlugin( resetVector : BigInt, decodePcGen = compressedGen, compressedGen = compressedGen, cmdToRspStageCount = busLatencyMin + (if(cmdForkOnSecondStage) 1 else 0), - pcRegReusedForSecondStage = !(cmdForkOnSecondStage && cmdForkPersistence), + allowPcRegReusedForSecondStage = !(cmdForkOnSecondStage && cmdForkPersistence), injectorReadyCutGen = false, prediction = prediction, historyRamSizeLog2 = historyRamSizeLog2, diff --git a/src/main/scala/vexriscv/plugin/Misc.scala b/src/main/scala/vexriscv/plugin/Misc.scala index 8f68e4eb..60c16822 100644 --- a/src/main/scala/vexriscv/plugin/Misc.scala +++ b/src/main/scala/vexriscv/plugin/Misc.scala @@ -122,7 +122,7 @@ object StreamForkVex{ object StreamVexPimper{ implicit class StreamFlushPimper[T <: Data](pimped : Stream[T]){ - def m2sPipeWithFlush(flush : Bool, discardInput : Boolean = true, collapsBubble : Boolean = true): Stream[T] = { + def m2sPipeWithFlush(flush : Bool, discardInput : Boolean = true, collapsBubble : Boolean = true, flushInput : Bool = null): Stream[T] = { val ret = cloneOf(pimped) val rValid = RegInit(False) @@ -132,7 +132,10 @@ object StreamVexPimper{ pimped.ready := (Bool(collapsBubble) && !ret.valid) || ret.ready when(pimped.ready) { - rValid := pimped.valid + if(flushInput == null) + rValid := pimped.valid + else + rValid := pimped.valid && !flushInput rData := pimped.payload } From e23295f06e00ba7296748b5213bbe6cb7d2ee2e0 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Mon, 17 Feb 2020 19:29:41 +0100 Subject: [PATCH 306/951] Fix Fetcher pcValid pipeline --- src/main/scala/vexriscv/plugin/Fetcher.scala | 35 +++++++++----------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/Fetcher.scala b/src/main/scala/vexriscv/plugin/Fetcher.scala index eae54615..0ba19e03 100644 --- a/src/main/scala/vexriscv/plugin/Fetcher.scala +++ b/src/main/scala/vexriscv/plugin/Fetcher.scala @@ -133,24 +133,27 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, val pc = pcReg + (inc ## B"00").asUInt val predictionPcLoad = ifGen(prediction == DYNAMIC_TARGET) (Flow(UInt(32 bits))) val redo = fetchRedoGen generate Flow(UInt(32 bits)) + val flushed = False if(compressedGen) when(inc) { pc(1) := False } - if(fetchRedoGen) when(redo.valid){ - corrected := True - pc := redo.payload - } if(predictionPcLoad != null) { when(predictionPcLoad.valid) { corrected := True pc := predictionPcLoad.payload } } + if(fetchRedoGen) when(redo.valid){ + corrected := True + pc := redo.payload + flushed := True + } when(jump.pcLoad.valid) { corrected := True pc := jump.pcLoad.payload + flushed := True } when(booted && (output.ready || corrected || pcRegPropagate)){ @@ -166,6 +169,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, val decodePc = ifGen(decodePcGen)(new Area { //PC calculation without Jump + val flushed = False val pcReg = Reg(UInt(32 bits)) init(if(resetVector != null) resetVector else externalResetVector) addAttribute(Verilator.public) val pcPlus = if(compressedGen) pcReg + ((decode.input(IS_RVC)) ? U(2) | U(4)) @@ -188,6 +192,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, //application of the selected jump request when(jump.pcLoad.valid && (!decode.arbitration.isStuck || decode.arbitration.isRemoved)) { pcReg := jump.pcLoad.payload + flushed := True } }) @@ -296,16 +301,16 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, if(!decodePcGen) iBusRsp.readyForError.clearWhen(!pcValid(decode)) //Need to wait a valid PC on the decode stage, as it is use to fill CSR xEPC - def pcUpdatedGen(input : Bool, stucks : Seq[Bool], relaxedInput : Boolean) : Seq[Bool] = { + def pcUpdatedGen(input : Bool, stucks : Seq[Bool], relaxedInput : Boolean, flush : Bool) : Seq[Bool] = { stucks.scanLeft(input)((i, stuck) => { val reg = RegInit(False) - if(!relaxedInput) when(fetcherflushIt) { + if(!relaxedInput) when(flush) { reg := False } when(!stuck) { reg := i } - if(relaxedInput || i != input) when(fetcherflushIt) { + if(relaxedInput || i != input) when(flush) { reg := False } reg @@ -314,10 +319,10 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, val stagesFromExecute = stages.dropWhile(_ != execute).toList val nextPcCalc = if (decodePcGen) new Area{ - val valids = pcUpdatedGen(True, False :: stagesFromExecute.map(_.arbitration.isStuck), true) + val valids = pcUpdatedGen(True, False :: stagesFromExecute.map(_.arbitration.isStuck), true, decodePc.flushed) pcValids := Vec(valids.takeRight(stages.size)) } else new Area{ - val valids = pcUpdatedGen(True, iBusRsp.stages.tail.map(!_.input.ready) ++ (if (injectorStage) List(!decodeInput.ready) else Nil) ++ stagesFromExecute.map(_.arbitration.isStuck), false) + val valids = pcUpdatedGen(True, iBusRsp.stages.tail.map(!_.input.ready) ++ (if (injectorStage) List(!decodeInput.ready) else Nil) ++ stagesFromExecute.map(_.arbitration.isStuck), false, fetchPc.flushed) pcValids := Vec(valids.takeRight(stages.size)) } @@ -508,12 +513,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, val historyWriteLast = RegNextWhen(historyWrite, iBusRsp.stages(0).output.ready) val hazard = historyWriteLast.valid && historyWriteLast.address === (iBusRsp.stages(1).input.payload >> 2).resized val line = history.readSync((iBusRsp.stages(0).input.payload >> 2).resized, iBusRsp.stages(0).output.ready) - val hit = line.source === (iBusRsp.stages(1).input.payload.asBits >> 2 + historyRamSizeLog2) && (if(compressedGen)(!(!line.unaligned && iBusRsp.stages(1).input.payload(1))) else True) - - //Avoid stoping instruction fetch in the middle patch -// if(compressedGen && cmdToRspStageCount == 1){ -// hit clearWhen(!decompressor.output.valid) -// } + val hit = line.source === (iBusRsp.stages(1).input.payload.asBits >> 2 + historyRamSizeLog2) fetchPc.predictionPcLoad.valid := line.branchWish.msb && hit && !hazard && iBusRsp.stages(1).input.valid fetchPc.predictionPcLoad.payload := line.target @@ -534,12 +534,9 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, //prediction hit on the right instruction into words decompressorContext.hit clearWhen(decompressorContext.line.unaligned && (decompressor.bufferValid || (decompressor.isRvc && !decompressor.input.pc(1)))) - // if(compressedGen) injectorContext.hit clearWhen(decodePc.pcReg(1) =/= injectorContext.line.unaligned) - decodePc.predictionPcLoad.valid := injectorContext.line.branchWish.msb && injectorContext.hit && !injectorContext.hazard && injector.decodeInput.fire decodePc.predictionPcLoad.payload := injectorContext.line.target - when(decompressorContext.line.branchWish.msb && decompressorContext.hit && !decompressorContext.hazard && decompressor.output.fire){ decompressor.bufferValid := False decompressor.input.ready := True @@ -584,7 +581,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, val decompressorFailure = RegInit(False) setWhen(unalignedWordIssue) clearWhen(fetcherflushIt) val injectorFailure = Delay(decompressorFailure, cycleCount=if(injectorStage) 1 else 0, when=injector.decodeInput.ready) val bypassFailure = if(!injectorStage) False else decompressorFailure && !injector.decodeInput.valid - + ??? dynamicTargetFailureCorrection.valid := False dynamicTargetFailureCorrection.payload := decode.input(PC) when(injectorFailure || bypassFailure){ From 0e0a568743a9fa9b1023a4387e183d4237e1c72d Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Mon, 17 Feb 2020 21:43:02 +0100 Subject: [PATCH 307/951] Apply DYNAMIC_TARGET correction all the time --- src/main/scala/vexriscv/plugin/Fetcher.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/Fetcher.scala b/src/main/scala/vexriscv/plugin/Fetcher.scala index 0ba19e03..255efc2e 100644 --- a/src/main/scala/vexriscv/plugin/Fetcher.scala +++ b/src/main/scala/vexriscv/plugin/Fetcher.scala @@ -76,7 +76,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, } case DYNAMIC_TARGET => { fetchPrediction = pipeline.service(classOf[PredictionInterface]).askFetchPrediction() - if(compressedGen && cmdToRspStageCount > 1){ + if(compressedGen){ dynamicTargetFailureCorrection = createJumpInterface(pipeline.decode) } } @@ -575,13 +575,13 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, - val predictionFailure = ifGen(compressedGen && cmdToRspStageCount > 1)(new Area{ + val predictionFailure = ifGen(compressedGen)(new Area{ val predictionBranch = decompressorContext.hit && !decompressorContext.hazard && decompressorContext.line.branchWish(1) val unalignedWordIssue = decompressor.bufferFill && decompressor.input.rsp.inst(17 downto 16) === 3 && predictionBranch val decompressorFailure = RegInit(False) setWhen(unalignedWordIssue) clearWhen(fetcherflushIt) val injectorFailure = Delay(decompressorFailure, cycleCount=if(injectorStage) 1 else 0, when=injector.decodeInput.ready) val bypassFailure = if(!injectorStage) False else decompressorFailure && !injector.decodeInput.valid - ??? + dynamicTargetFailureCorrection.valid := False dynamicTargetFailureCorrection.payload := decode.input(PC) when(injectorFailure || bypassFailure){ From e0cd9a6e067e6e42f385a87af9f439f8314290f0 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Mon, 17 Feb 2020 22:45:34 +0100 Subject: [PATCH 308/951] clean iBusRsp redo --- src/main/scala/vexriscv/plugin/Fetcher.scala | 16 ++++++---------- .../scala/vexriscv/plugin/IBusCachedPlugin.scala | 8 +++----- .../scala/vexriscv/plugin/IBusSimplePlugin.scala | 10 ++++------ 3 files changed, 13 insertions(+), 21 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/Fetcher.scala b/src/main/scala/vexriscv/plugin/Fetcher.scala index 255efc2e..f933ab92 100644 --- a/src/main/scala/vexriscv/plugin/Fetcher.scala +++ b/src/main/scala/vexriscv/plugin/Fetcher.scala @@ -76,9 +76,6 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, } case DYNAMIC_TARGET => { fetchPrediction = pipeline.service(classOf[PredictionInterface]).askFetchPrediction() - if(compressedGen){ - dynamicTargetFailureCorrection = createJumpInterface(pipeline.decode) - } } } @@ -205,7 +202,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, val iBusRsp = new Area { - val fetchFlush = False + val redoFetch = False val stages = Array.fill(cmdToRspStageCount + 1)(new Bundle { val input = Stream(UInt(32 bits)) val output = Stream(UInt(32 bits)) @@ -219,10 +216,13 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, s.output << s.input.haltWhen(s.halt) } + fetchPc.redo.valid := redoFetch + fetchPc.redo.payload := stages.last.input.payload + stages.head.flush := False //getFlushAt(IBUS_RSP, stages.head == stages.last) || fetchFlush for((s,sNext) <- (stages, stages.tail).zipped) { val discardInputOnFlush = s != stages.head - sNext.flush := getFlushAt(IBUS_RSP, sNext == stages.last) || fetchFlush + sNext.flush := getFlushAt(IBUS_RSP, sNext == stages.last) || redoFetch if(s == stages.head && pcRegReusedForSecondStage) { sNext.input.arbitrationFrom(s.output.toEvent().m2sPipeWithFlush(sNext.flush, false, collapsBubble = false, flushInput = s.flush)) sNext.input.payload := fetchPc.pcReg @@ -582,16 +582,12 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, val injectorFailure = Delay(decompressorFailure, cycleCount=if(injectorStage) 1 else 0, when=injector.decodeInput.ready) val bypassFailure = if(!injectorStage) False else decompressorFailure && !injector.decodeInput.valid - dynamicTargetFailureCorrection.valid := False - dynamicTargetFailureCorrection.payload := decode.input(PC) when(injectorFailure || bypassFailure){ historyWrite.valid := True historyWrite.address := (decode.input(PC) >> 2).resized historyWrite.data.branchWish := 0 - decode.arbitration.isValid := False - decode.arbitration.flushNext := True - dynamicTargetFailureCorrection.valid := True + iBusRsp.redoFetch := True } }) } diff --git a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala index 4a633643..f018bb3b 100644 --- a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala @@ -59,7 +59,6 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l, var iBus : InstructionCacheMemBus = null var mmuBus : MemoryTranslatorBus = null var privilegeService : PrivilegeService = null - var redoBranch : Flow[UInt] = null var decodeExceptionPort : Flow[ExceptionCause] = null val tightlyCoupledPorts = ArrayBuffer[TightlyCoupledPort]() def tightlyGen = tightlyCoupledPorts.nonEmpty @@ -235,10 +234,9 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l, decodeExceptionPort.code := 1 } - - fetchPc.redo.valid := redoFetch - fetchPc.redo.payload := iBusRsp.stages.last.input.payload - iBusRsp.fetchFlush setWhen(redoFetch) + when(redoFetch) { + iBusRsp.redoFetch := True + } cacheRspArbitration.halt setWhen (issueDetected || iBusRspOutputHalt) diff --git a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala index c14ac30f..319634d3 100644 --- a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala @@ -369,18 +369,16 @@ class IBusSimplePlugin( resetVector : BigInt, val join = Stream(FetchRsp()) val exceptionDetected = False - val redoRequired = False join.valid := stages.last.output.valid && rspBufferOutput.valid join.payload := fetchRsp stages.last.output.ready := stages.last.output.valid ? join.fire | join.ready rspBufferOutput.ready := join.fire - output << join.haltWhen(exceptionDetected || redoRequired) + output << join.haltWhen(exceptionDetected) if(memoryTranslatorPortConfig != null){ - redoRequired setWhen( stages.last.input.valid && mmu.joinCtx.refilling) - fetchPc.redo.valid := redoRequired && iBusRsp.readyForError - fetchPc.redo.payload := decode.input(PC) - iBusRsp.fetchFlush setWhen(fetchPc.redo.valid) + when(stages.last.input.valid && mmu.joinCtx.refilling) { + iBusRsp.redoFetch := True + } } From 53a29e35e9a05a3f08247367c3cba96cf73615a9 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Mon, 17 Feb 2020 23:27:17 +0100 Subject: [PATCH 309/951] fix deleg external interrupt propagation time failure --- src/test/cpp/raw/deleg/build/deleg.asm | 1198 ++++++++++++++---------- src/test/cpp/raw/deleg/build/deleg.hex | 290 +++--- src/test/cpp/raw/deleg/src/crt.S | 17 + 3 files changed, 891 insertions(+), 614 deletions(-) diff --git a/src/test/cpp/raw/deleg/build/deleg.asm b/src/test/cpp/raw/deleg/build/deleg.asm index 9e3098f2..e64c3748 100644 --- a/src/test/cpp/raw/deleg/build/deleg.asm +++ b/src/test/cpp/raw/deleg/build/deleg.asm @@ -6,536 +6,744 @@ Disassembly of section .crt_section: 80000000 <_start>: 80000000: 00100e93 li t4,1 -80000004: 00000097 auipc ra,0x0 -80000008: 6fc08093 addi ra,ra,1788 # 80000700 +80000004: 00001097 auipc ra,0x1 +80000008: a3c08093 addi ra,ra,-1476 # 80000a40 8000000c: 30509073 csrw mtvec,ra -80000010: 00000097 auipc ra,0x0 -80000014: 72808093 addi ra,ra,1832 # 80000738 +80000010: 00001097 auipc ra,0x1 +80000014: a6808093 addi ra,ra,-1432 # 80000a78 80000018: 10509073 csrw stvec,ra 8000001c: f00110b7 lui ra,0xf0011 80000020: 00000113 li sp,0 -80000024: 0020a023 sw sp,0(ra) # f0011000 +80000024: 0020a023 sw sp,0(ra) # f0011000 +80000028: 00000013 nop +8000002c: 00000013 nop +80000030: 00000013 nop +80000034: 00000013 nop +80000038: 00000013 nop +8000003c: 00000013 nop +80000040: 00000013 nop +80000044: 00000013 nop -80000028 : -80000028: 00100e13 li t3,1 -8000002c: 00000f17 auipc t5,0x0 -80000030: 00cf0f13 addi t5,t5,12 # 80000038 -80000034: 00000073 ecall +80000048 : +80000048: 00100e13 li t3,1 +8000004c: 00000f17 auipc t5,0x0 +80000050: 00cf0f13 addi t5,t5,12 # 80000058 +80000054: 00000073 ecall -80000038 : -80000038: 00200e13 li t3,2 -8000003c: 000020b7 lui ra,0x2 -80000040: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800> -80000044: 00000113 li sp,0 -80000048: 3000b073 csrc mstatus,ra -8000004c: 30012073 csrs mstatus,sp -80000050: 00000097 auipc ra,0x0 -80000054: 01408093 addi ra,ra,20 # 80000064 -80000058: 34109073 csrw mepc,ra -8000005c: 30200073 mret -80000060: 6880006f j 800006e8 -80000064: 00000f17 auipc t5,0x0 -80000068: 024f0f13 addi t5,t5,36 # 80000088 -8000006c: 00000073 ecall -80000070: 6780006f j 800006e8 +80000058 : +80000058: 00200e13 li t3,2 +8000005c: 000020b7 lui ra,0x2 +80000060: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800> +80000064: 00000113 li sp,0 +80000068: 3000b073 csrc mstatus,ra +8000006c: 30012073 csrs mstatus,sp +80000070: 00000097 auipc ra,0x0 +80000074: 01408093 addi ra,ra,20 # 80000084 +80000078: 34109073 csrw mepc,ra +8000007c: 30200073 mret +80000080: 1a90006f j 80000a28 +80000084: 00000f17 auipc t5,0x0 +80000088: 024f0f13 addi t5,t5,36 # 800000a8 +8000008c: 00000073 ecall +80000090: 1990006f j 80000a28 -80000074 : -80000074: 00300e13 li t3,3 -80000078: 00000f17 auipc t5,0x0 -8000007c: 010f0f13 addi t5,t5,16 # 80000088 -80000080: 00102083 lw ra,1(zero) # 1 <_start-0x7fffffff> -80000084: 6640006f j 800006e8 +80000094 : +80000094: 00300e13 li t3,3 +80000098: 00000f17 auipc t5,0x0 +8000009c: 010f0f13 addi t5,t5,16 # 800000a8 +800000a0: 00102083 lw ra,1(zero) # 1 <_start-0x7fffffff> +800000a4: 1850006f j 80000a28 -80000088 : -80000088: 00400e13 li t3,4 -8000008c: 000020b7 lui ra,0x2 -80000090: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800> -80000094: 00001137 lui sp,0x1 -80000098: 80010113 addi sp,sp,-2048 # 800 <_start-0x7ffff800> -8000009c: 3000b073 csrc mstatus,ra -800000a0: 30012073 csrs mstatus,sp -800000a4: 00000097 auipc ra,0x0 -800000a8: 01408093 addi ra,ra,20 # 800000b8 -800000ac: 34109073 csrw mepc,ra -800000b0: 30200073 mret -800000b4: 6340006f j 800006e8 -800000b8: 00000f17 auipc t5,0x0 -800000bc: 010f0f13 addi t5,t5,16 # 800000c8 -800000c0: 00102083 lw ra,1(zero) # 1 <_start-0x7fffffff> -800000c4: 6240006f j 800006e8 +800000a8 : +800000a8: 00400e13 li t3,4 +800000ac: 000020b7 lui ra,0x2 +800000b0: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800> +800000b4: 00001137 lui sp,0x1 +800000b8: 80010113 addi sp,sp,-2048 # 800 <_start-0x7ffff800> +800000bc: 3000b073 csrc mstatus,ra +800000c0: 30012073 csrs mstatus,sp +800000c4: 00000097 auipc ra,0x0 +800000c8: 01408093 addi ra,ra,20 # 800000d8 +800000cc: 34109073 csrw mepc,ra +800000d0: 30200073 mret +800000d4: 1550006f j 80000a28 +800000d8: 00000f17 auipc t5,0x0 +800000dc: 010f0f13 addi t5,t5,16 # 800000e8 +800000e0: 00102083 lw ra,1(zero) # 1 <_start-0x7fffffff> +800000e4: 1450006f j 80000a28 -800000c8 : -800000c8: 00500e13 li t3,5 -800000cc: 000020b7 lui ra,0x2 -800000d0: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800> -800000d4: 00000113 li sp,0 -800000d8: 3000b073 csrc mstatus,ra -800000dc: 30012073 csrs mstatus,sp -800000e0: 00000097 auipc ra,0x0 -800000e4: 01408093 addi ra,ra,20 # 800000f4 -800000e8: 34109073 csrw mepc,ra -800000ec: 30200073 mret -800000f0: 5f80006f j 800006e8 -800000f4: 00000f17 auipc t5,0x0 -800000f8: 010f0f13 addi t5,t5,16 # 80000104 -800000fc: 00102083 lw ra,1(zero) # 1 <_start-0x7fffffff> -80000100: 5e80006f j 800006e8 - -80000104 : -80000104: 00600e13 li t3,6 -80000108: 01000093 li ra,16 -8000010c: 30209073 csrw medeleg,ra - -80000110 : -80000110: 00700e13 li t3,7 +800000e8 : +800000e8: 00500e13 li t3,5 +800000ec: 000020b7 lui ra,0x2 +800000f0: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800> +800000f4: 00000113 li sp,0 +800000f8: 3000b073 csrc mstatus,ra +800000fc: 30012073 csrs mstatus,sp +80000100: 00000097 auipc ra,0x0 +80000104: 01408093 addi ra,ra,20 # 80000114 +80000108: 34109073 csrw mepc,ra +8000010c: 30200073 mret +80000110: 1190006f j 80000a28 80000114: 00000f17 auipc t5,0x0 -80000118: 010f0f13 addi t5,t5,16 # 80000124 +80000118: 010f0f13 addi t5,t5,16 # 80000124 8000011c: 00102083 lw ra,1(zero) # 1 <_start-0x7fffffff> -80000120: 5c80006f j 800006e8 +80000120: 1090006f j 80000a28 -80000124 : -80000124: 00800e13 li t3,8 -80000128: 00000f17 auipc t5,0x0 -8000012c: 03cf0f13 addi t5,t5,60 # 80000164 -80000130: 000020b7 lui ra,0x2 -80000134: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800> -80000138: 00001137 lui sp,0x1 -8000013c: 80010113 addi sp,sp,-2048 # 800 <_start-0x7ffff800> -80000140: 3000b073 csrc mstatus,ra -80000144: 30012073 csrs mstatus,sp -80000148: 00000097 auipc ra,0x0 -8000014c: 01408093 addi ra,ra,20 # 8000015c -80000150: 34109073 csrw mepc,ra -80000154: 30200073 mret -80000158: 5900006f j 800006e8 -8000015c: 00102083 lw ra,1(zero) # 1 <_start-0x7fffffff> -80000160: 5880006f j 800006e8 +80000124 : +80000124: 00600e13 li t3,6 +80000128: 01000093 li ra,16 +8000012c: 30209073 csrw medeleg,ra -80000164 : -80000164: 00900e13 li t3,9 -80000168: 00000f17 auipc t5,0x0 -8000016c: 038f0f13 addi t5,t5,56 # 800001a0 -80000170: 000020b7 lui ra,0x2 -80000174: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800> -80000178: 00000113 li sp,0 -8000017c: 3000b073 csrc mstatus,ra -80000180: 30012073 csrs mstatus,sp -80000184: 00000097 auipc ra,0x0 -80000188: 01408093 addi ra,ra,20 # 80000198 -8000018c: 34109073 csrw mepc,ra -80000190: 30200073 mret -80000194: 5540006f j 800006e8 -80000198: 00102083 lw ra,1(zero) # 1 <_start-0x7fffffff> -8000019c: 54c0006f j 800006e8 +80000130 : +80000130: 00700e13 li t3,7 +80000134: 00000f17 auipc t5,0x0 +80000138: 010f0f13 addi t5,t5,16 # 80000144 +8000013c: 00102083 lw ra,1(zero) # 1 <_start-0x7fffffff> +80000140: 0e90006f j 80000a28 -800001a0 : -800001a0: 00a00e13 li t3,10 -800001a4: 00000f17 auipc t5,0x0 -800001a8: 03cf0f13 addi t5,t5,60 # 800001e0 -800001ac: f00110b7 lui ra,0xf0011 -800001b0: 00000113 li sp,0 -800001b4: 0020a023 sw sp,0(ra) # f0011000 -800001b8: 00800093 li ra,8 -800001bc: 30009073 csrw mstatus,ra -800001c0: 000010b7 lui ra,0x1 -800001c4: 80008093 addi ra,ra,-2048 # 800 <_start-0x7ffff800> -800001c8: 30409073 csrw mie,ra +80000144 : +80000144: 00800e13 li t3,8 +80000148: 00000f17 auipc t5,0x0 +8000014c: 03cf0f13 addi t5,t5,60 # 80000184 +80000150: 000020b7 lui ra,0x2 +80000154: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800> +80000158: 00001137 lui sp,0x1 +8000015c: 80010113 addi sp,sp,-2048 # 800 <_start-0x7ffff800> +80000160: 3000b073 csrc mstatus,ra +80000164: 30012073 csrs mstatus,sp +80000168: 00000097 auipc ra,0x0 +8000016c: 01408093 addi ra,ra,20 # 8000017c +80000170: 34109073 csrw mepc,ra +80000174: 30200073 mret +80000178: 0b10006f j 80000a28 +8000017c: 00102083 lw ra,1(zero) # 1 <_start-0x7fffffff> +80000180: 0a90006f j 80000a28 + +80000184 : +80000184: 00900e13 li t3,9 +80000188: 00000f17 auipc t5,0x0 +8000018c: 038f0f13 addi t5,t5,56 # 800001c0 +80000190: 000020b7 lui ra,0x2 +80000194: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800> +80000198: 00000113 li sp,0 +8000019c: 3000b073 csrc mstatus,ra +800001a0: 30012073 csrs mstatus,sp +800001a4: 00000097 auipc ra,0x0 +800001a8: 01408093 addi ra,ra,20 # 800001b8 +800001ac: 34109073 csrw mepc,ra +800001b0: 30200073 mret +800001b4: 0750006f j 80000a28 +800001b8: 00102083 lw ra,1(zero) # 1 <_start-0x7fffffff> +800001bc: 06d0006f j 80000a28 + +800001c0 : +800001c0: 00a00e13 li t3,10 +800001c4: 00000f17 auipc t5,0x0 +800001c8: 07cf0f13 addi t5,t5,124 # 80000240 800001cc: f00110b7 lui ra,0xf0011 -800001d0: 00100113 li sp,1 -800001d4: 0020a023 sw sp,0(ra) # f0011000 -800001d8: 10500073 wfi -800001dc: 50c0006f j 800006e8 - -800001e0 : -800001e0: 00b00e13 li t3,11 -800001e4: 00000f17 auipc t5,0x0 -800001e8: 068f0f13 addi t5,t5,104 # 8000024c -800001ec: f00110b7 lui ra,0xf0011 -800001f0: 00000113 li sp,0 -800001f4: 0020a023 sw sp,0(ra) # f0011000 +800001d0: 00000113 li sp,0 +800001d4: 0020a023 sw sp,0(ra) # f0011000 +800001d8: 00000013 nop +800001dc: 00000013 nop +800001e0: 00000013 nop +800001e4: 00000013 nop +800001e8: 00000013 nop +800001ec: 00000013 nop +800001f0: 00000013 nop +800001f4: 00000013 nop 800001f8: 00800093 li ra,8 800001fc: 30009073 csrw mstatus,ra 80000200: 000010b7 lui ra,0x1 80000204: 80008093 addi ra,ra,-2048 # 800 <_start-0x7ffff800> 80000208: 30409073 csrw mie,ra -8000020c: 000020b7 lui ra,0x2 -80000210: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800> -80000214: 00001137 lui sp,0x1 -80000218: 80010113 addi sp,sp,-2048 # 800 <_start-0x7ffff800> -8000021c: 3000b073 csrc mstatus,ra -80000220: 30012073 csrs mstatus,sp -80000224: 00000097 auipc ra,0x0 -80000228: 01408093 addi ra,ra,20 # 80000238 -8000022c: 34109073 csrw mepc,ra -80000230: 30200073 mret -80000234: 4b40006f j 800006e8 -80000238: f00110b7 lui ra,0xf0011 -8000023c: 00100113 li sp,1 -80000240: 0020a023 sw sp,0(ra) # f0011000 -80000244: 10500073 wfi -80000248: 4a00006f j 800006e8 +8000020c: f00110b7 lui ra,0xf0011 +80000210: 00100113 li sp,1 +80000214: 0020a023 sw sp,0(ra) # f0011000 +80000218: 00000013 nop +8000021c: 00000013 nop +80000220: 00000013 nop +80000224: 00000013 nop +80000228: 00000013 nop +8000022c: 00000013 nop +80000230: 00000013 nop +80000234: 00000013 nop +80000238: 10500073 wfi +8000023c: 7ec0006f j 80000a28 -8000024c : -8000024c: 00c00e13 li t3,12 -80000250: 00000f17 auipc t5,0x0 -80000254: 064f0f13 addi t5,t5,100 # 800002b4 -80000258: f00110b7 lui ra,0xf0011 -8000025c: 00000113 li sp,0 -80000260: 0020a023 sw sp,0(ra) # f0011000 -80000264: 00800093 li ra,8 -80000268: 30009073 csrw mstatus,ra -8000026c: 000010b7 lui ra,0x1 -80000270: 80008093 addi ra,ra,-2048 # 800 <_start-0x7ffff800> -80000274: 30409073 csrw mie,ra -80000278: 000020b7 lui ra,0x2 -8000027c: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800> -80000280: 00000113 li sp,0 -80000284: 3000b073 csrc mstatus,ra -80000288: 30012073 csrs mstatus,sp -8000028c: 00000097 auipc ra,0x0 -80000290: 01408093 addi ra,ra,20 # 800002a0 -80000294: 34109073 csrw mepc,ra -80000298: 30200073 mret -8000029c: 44c0006f j 800006e8 -800002a0: f00110b7 lui ra,0xf0011 -800002a4: 00100113 li sp,1 -800002a8: 0020a023 sw sp,0(ra) # f0011000 -800002ac: 10500073 wfi -800002b0: 4380006f j 800006e8 +80000240 : +80000240: 00b00e13 li t3,11 +80000244: 00000f17 auipc t5,0x0 +80000248: 0a8f0f13 addi t5,t5,168 # 800002ec +8000024c: f00110b7 lui ra,0xf0011 +80000250: 00000113 li sp,0 +80000254: 0020a023 sw sp,0(ra) # f0011000 +80000258: 00000013 nop +8000025c: 00000013 nop +80000260: 00000013 nop +80000264: 00000013 nop +80000268: 00000013 nop +8000026c: 00000013 nop +80000270: 00000013 nop +80000274: 00000013 nop +80000278: 00800093 li ra,8 +8000027c: 30009073 csrw mstatus,ra +80000280: 000010b7 lui ra,0x1 +80000284: 80008093 addi ra,ra,-2048 # 800 <_start-0x7ffff800> +80000288: 30409073 csrw mie,ra +8000028c: 000020b7 lui ra,0x2 +80000290: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800> +80000294: 00001137 lui sp,0x1 +80000298: 80010113 addi sp,sp,-2048 # 800 <_start-0x7ffff800> +8000029c: 3000b073 csrc mstatus,ra +800002a0: 30012073 csrs mstatus,sp +800002a4: 00000097 auipc ra,0x0 +800002a8: 01408093 addi ra,ra,20 # 800002b8 +800002ac: 34109073 csrw mepc,ra +800002b0: 30200073 mret +800002b4: 7740006f j 80000a28 +800002b8: f00110b7 lui ra,0xf0011 +800002bc: 00100113 li sp,1 +800002c0: 0020a023 sw sp,0(ra) # f0011000 +800002c4: 00000013 nop +800002c8: 00000013 nop +800002cc: 00000013 nop +800002d0: 00000013 nop +800002d4: 00000013 nop +800002d8: 00000013 nop +800002dc: 00000013 nop +800002e0: 00000013 nop +800002e4: 10500073 wfi +800002e8: 7400006f j 80000a28 -800002b4 : -800002b4: 00200093 li ra,2 -800002b8: 10009073 csrw sstatus,ra -800002bc: 00e00e13 li t3,14 -800002c0: 00000f17 auipc t5,0x0 -800002c4: 040f0f13 addi t5,t5,64 # 80000300 -800002c8: f00120b7 lui ra,0xf0012 -800002cc: 00000113 li sp,0 -800002d0: 0020a023 sw sp,0(ra) # f0012000 -800002d4: 00200093 li ra,2 -800002d8: 30009073 csrw mstatus,ra -800002dc: 20000093 li ra,512 -800002e0: 30409073 csrw mie,ra -800002e4: 00000e93 li t4,0 -800002e8: f00120b7 lui ra,0xf0012 -800002ec: 00100113 li sp,1 -800002f0: 0020a023 sw sp,0(ra) # f0012000 -800002f4: 06400093 li ra,100 -800002f8: fff08093 addi ra,ra,-1 -800002fc: fe104ee3 bgtz ra,800002f8 +800002ec : +800002ec: 00c00e13 li t3,12 +800002f0: 00000f17 auipc t5,0x0 +800002f4: 0a4f0f13 addi t5,t5,164 # 80000394 +800002f8: f00110b7 lui ra,0xf0011 +800002fc: 00000113 li sp,0 +80000300: 0020a023 sw sp,0(ra) # f0011000 +80000304: 00000013 nop +80000308: 00000013 nop +8000030c: 00000013 nop +80000310: 00000013 nop +80000314: 00000013 nop +80000318: 00000013 nop +8000031c: 00000013 nop +80000320: 00000013 nop +80000324: 00800093 li ra,8 +80000328: 30009073 csrw mstatus,ra +8000032c: 000010b7 lui ra,0x1 +80000330: 80008093 addi ra,ra,-2048 # 800 <_start-0x7ffff800> +80000334: 30409073 csrw mie,ra +80000338: 000020b7 lui ra,0x2 +8000033c: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800> +80000340: 00000113 li sp,0 +80000344: 3000b073 csrc mstatus,ra +80000348: 30012073 csrs mstatus,sp +8000034c: 00000097 auipc ra,0x0 +80000350: 01408093 addi ra,ra,20 # 80000360 +80000354: 34109073 csrw mepc,ra +80000358: 30200073 mret +8000035c: 6cc0006f j 80000a28 +80000360: f00110b7 lui ra,0xf0011 +80000364: 00100113 li sp,1 +80000368: 0020a023 sw sp,0(ra) # f0011000 +8000036c: 00000013 nop +80000370: 00000013 nop +80000374: 00000013 nop +80000378: 00000013 nop +8000037c: 00000013 nop +80000380: 00000013 nop +80000384: 00000013 nop +80000388: 00000013 nop +8000038c: 10500073 wfi +80000390: 6980006f j 80000a28 -80000300 : -80000300: 00f00e13 li t3,15 -80000304: 00000f17 auipc t5,0x0 -80000308: 068f0f13 addi t5,t5,104 # 8000036c -8000030c: f00120b7 lui ra,0xf0012 -80000310: 00000113 li sp,0 -80000314: 0020a023 sw sp,0(ra) # f0012000 -80000318: 00200093 li ra,2 -8000031c: 30009073 csrw mstatus,ra -80000320: 20000093 li ra,512 -80000324: 30409073 csrw mie,ra -80000328: 000020b7 lui ra,0x2 -8000032c: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800> -80000330: 00001137 lui sp,0x1 -80000334: 80010113 addi sp,sp,-2048 # 800 <_start-0x7ffff800> -80000338: 3000b073 csrc mstatus,ra -8000033c: 30012073 csrs mstatus,sp -80000340: 00000097 auipc ra,0x0 -80000344: 01408093 addi ra,ra,20 # 80000354 -80000348: 34109073 csrw mepc,ra -8000034c: 30200073 mret -80000350: 3980006f j 800006e8 -80000354: 00100e93 li t4,1 -80000358: f00120b7 lui ra,0xf0012 -8000035c: 00100113 li sp,1 -80000360: 0020a023 sw sp,0(ra) # f0012000 -80000364: 10500073 wfi -80000368: 3800006f j 800006e8 +80000394 : +80000394: 00200093 li ra,2 +80000398: 10009073 csrw sstatus,ra +8000039c: 00e00e13 li t3,14 +800003a0: 00000f17 auipc t5,0x0 +800003a4: 080f0f13 addi t5,t5,128 # 80000420 +800003a8: f00120b7 lui ra,0xf0012 +800003ac: 00000113 li sp,0 +800003b0: 0020a023 sw sp,0(ra) # f0012000 +800003b4: 00000013 nop +800003b8: 00000013 nop +800003bc: 00000013 nop +800003c0: 00000013 nop +800003c4: 00000013 nop +800003c8: 00000013 nop +800003cc: 00000013 nop +800003d0: 00000013 nop +800003d4: 00200093 li ra,2 +800003d8: 30009073 csrw mstatus,ra +800003dc: 20000093 li ra,512 +800003e0: 30409073 csrw mie,ra +800003e4: 00000e93 li t4,0 +800003e8: f00120b7 lui ra,0xf0012 +800003ec: 00100113 li sp,1 +800003f0: 0020a023 sw sp,0(ra) # f0012000 +800003f4: 00000013 nop +800003f8: 00000013 nop +800003fc: 00000013 nop +80000400: 00000013 nop +80000404: 00000013 nop +80000408: 00000013 nop +8000040c: 00000013 nop +80000410: 00000013 nop +80000414: 06400093 li ra,100 +80000418: fff08093 addi ra,ra,-1 +8000041c: fe104ee3 bgtz ra,80000418 -8000036c : -8000036c: 01000e13 li t3,16 -80000370: 00000f17 auipc t5,0x0 -80000374: 060f0f13 addi t5,t5,96 # 800003d0 -80000378: f00120b7 lui ra,0xf0012 -8000037c: 00000113 li sp,0 -80000380: 0020a023 sw sp,0(ra) # f0012000 -80000384: 00200093 li ra,2 -80000388: 30009073 csrw mstatus,ra -8000038c: 20000093 li ra,512 -80000390: 30409073 csrw mie,ra -80000394: 000020b7 lui ra,0x2 -80000398: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800> -8000039c: 00000113 li sp,0 -800003a0: 3000b073 csrc mstatus,ra -800003a4: 30012073 csrs mstatus,sp -800003a8: 00000097 auipc ra,0x0 -800003ac: 01408093 addi ra,ra,20 # 800003bc -800003b0: 34109073 csrw mepc,ra -800003b4: 30200073 mret -800003b8: 3300006f j 800006e8 -800003bc: f00120b7 lui ra,0xf0012 -800003c0: 00100113 li sp,1 -800003c4: 0020a023 sw sp,0(ra) # f0012000 -800003c8: 10500073 wfi -800003cc: 31c0006f j 800006e8 +80000420 : +80000420: 00f00e13 li t3,15 +80000424: 00000f17 auipc t5,0x0 +80000428: 0a8f0f13 addi t5,t5,168 # 800004cc +8000042c: f00120b7 lui ra,0xf0012 +80000430: 00000113 li sp,0 +80000434: 0020a023 sw sp,0(ra) # f0012000 +80000438: 00000013 nop +8000043c: 00000013 nop +80000440: 00000013 nop +80000444: 00000013 nop +80000448: 00000013 nop +8000044c: 00000013 nop +80000450: 00000013 nop +80000454: 00000013 nop +80000458: 00200093 li ra,2 +8000045c: 30009073 csrw mstatus,ra +80000460: 20000093 li ra,512 +80000464: 30409073 csrw mie,ra +80000468: 000020b7 lui ra,0x2 +8000046c: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800> +80000470: 00001137 lui sp,0x1 +80000474: 80010113 addi sp,sp,-2048 # 800 <_start-0x7ffff800> +80000478: 3000b073 csrc mstatus,ra +8000047c: 30012073 csrs mstatus,sp +80000480: 00000097 auipc ra,0x0 +80000484: 01408093 addi ra,ra,20 # 80000494 +80000488: 34109073 csrw mepc,ra +8000048c: 30200073 mret +80000490: 5980006f j 80000a28 +80000494: 00100e93 li t4,1 +80000498: f00120b7 lui ra,0xf0012 +8000049c: 00100113 li sp,1 +800004a0: 0020a023 sw sp,0(ra) # f0012000 +800004a4: 00000013 nop +800004a8: 00000013 nop +800004ac: 00000013 nop +800004b0: 00000013 nop +800004b4: 00000013 nop +800004b8: 00000013 nop +800004bc: 00000013 nop +800004c0: 00000013 nop +800004c4: 10500073 wfi +800004c8: 5600006f j 80000a28 -800003d0 : -800003d0: 01100e13 li t3,17 -800003d4: 20000093 li ra,512 -800003d8: 30309073 csrw mideleg,ra -800003dc: 00000f17 auipc t5,0x0 -800003e0: 040f0f13 addi t5,t5,64 # 8000041c -800003e4: f00120b7 lui ra,0xf0012 -800003e8: 00000113 li sp,0 -800003ec: 0020a023 sw sp,0(ra) # f0012000 -800003f0: 00200093 li ra,2 -800003f4: 30009073 csrw mstatus,ra -800003f8: 20000093 li ra,512 -800003fc: 30409073 csrw mie,ra -80000400: 00000e93 li t4,0 -80000404: f00120b7 lui ra,0xf0012 -80000408: 00100113 li sp,1 -8000040c: 0020a023 sw sp,0(ra) # f0012000 -80000410: 06400093 li ra,100 -80000414: fff08093 addi ra,ra,-1 -80000418: fe104ee3 bgtz ra,80000414 - -8000041c : -8000041c: 01200e13 li t3,18 -80000420: 00000f17 auipc t5,0x0 -80000424: 068f0f13 addi t5,t5,104 # 80000488 -80000428: f00120b7 lui ra,0xf0012 -8000042c: 00000113 li sp,0 -80000430: 0020a023 sw sp,0(ra) # f0012000 -80000434: 00200093 li ra,2 -80000438: 30009073 csrw mstatus,ra -8000043c: 20000093 li ra,512 -80000440: 30409073 csrw mie,ra -80000444: 000020b7 lui ra,0x2 -80000448: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800> -8000044c: 00001137 lui sp,0x1 -80000450: 80010113 addi sp,sp,-2048 # 800 <_start-0x7ffff800> -80000454: 3000b073 csrc mstatus,ra -80000458: 30012073 csrs mstatus,sp -8000045c: 00000097 auipc ra,0x0 -80000460: 01408093 addi ra,ra,20 # 80000470 -80000464: 34109073 csrw mepc,ra -80000468: 30200073 mret -8000046c: 27c0006f j 800006e8 -80000470: 00100e93 li t4,1 -80000474: f00120b7 lui ra,0xf0012 -80000478: 00100113 li sp,1 -8000047c: 0020a023 sw sp,0(ra) # f0012000 -80000480: 10500073 wfi -80000484: 2640006f j 800006e8 - -80000488 : -80000488: 01300e13 li t3,19 -8000048c: 00000f17 auipc t5,0x0 -80000490: 060f0f13 addi t5,t5,96 # 800004ec -80000494: f00120b7 lui ra,0xf0012 -80000498: 00000113 li sp,0 -8000049c: 0020a023 sw sp,0(ra) # f0012000 -800004a0: 00200093 li ra,2 -800004a4: 30009073 csrw mstatus,ra -800004a8: 20000093 li ra,512 -800004ac: 30409073 csrw mie,ra -800004b0: 000020b7 lui ra,0x2 -800004b4: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800> -800004b8: 00000113 li sp,0 -800004bc: 3000b073 csrc mstatus,ra -800004c0: 30012073 csrs mstatus,sp -800004c4: 00000097 auipc ra,0x0 -800004c8: 01408093 addi ra,ra,20 # 800004d8 -800004cc: 34109073 csrw mepc,ra -800004d0: 30200073 mret -800004d4: 2140006f j 800006e8 +800004cc : +800004cc: 01000e13 li t3,16 +800004d0: 00000f17 auipc t5,0x0 +800004d4: 0a0f0f13 addi t5,t5,160 # 80000570 800004d8: f00120b7 lui ra,0xf0012 -800004dc: 00100113 li sp,1 -800004e0: 0020a023 sw sp,0(ra) # f0012000 -800004e4: 10500073 wfi -800004e8: 2000006f j 800006e8 - -800004ec : -800004ec: f00120b7 lui ra,0xf0012 -800004f0: 00000113 li sp,0 -800004f4: 0020a023 sw sp,0(ra) # f0012000 -800004f8: 01400e13 li t3,20 -800004fc: 00000f17 auipc t5,0x0 -80000500: 030f0f13 addi t5,t5,48 # 8000052c +800004dc: 00000113 li sp,0 +800004e0: 0020a023 sw sp,0(ra) # f0012000 +800004e4: 00000013 nop +800004e8: 00000013 nop +800004ec: 00000013 nop +800004f0: 00000013 nop +800004f4: 00000013 nop +800004f8: 00000013 nop +800004fc: 00000013 nop +80000500: 00000013 nop 80000504: 00200093 li ra,2 80000508: 30009073 csrw mstatus,ra 8000050c: 20000093 li ra,512 80000510: 30409073 csrw mie,ra -80000514: 00000e93 li t4,0 -80000518: 20000093 li ra,512 -8000051c: 1440a073 csrs sip,ra -80000520: 06400093 li ra,100 -80000524: fff08093 addi ra,ra,-1 -80000528: fe104ee3 bgtz ra,80000524 +80000514: 000020b7 lui ra,0x2 +80000518: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800> +8000051c: 00000113 li sp,0 +80000520: 3000b073 csrc mstatus,ra +80000524: 30012073 csrs mstatus,sp +80000528: 00000097 auipc ra,0x0 +8000052c: 01408093 addi ra,ra,20 # 8000053c +80000530: 34109073 csrw mepc,ra +80000534: 30200073 mret +80000538: 4f00006f j 80000a28 +8000053c: f00120b7 lui ra,0xf0012 +80000540: 00100113 li sp,1 +80000544: 0020a023 sw sp,0(ra) # f0012000 +80000548: 00000013 nop +8000054c: 00000013 nop +80000550: 00000013 nop +80000554: 00000013 nop +80000558: 00000013 nop +8000055c: 00000013 nop +80000560: 00000013 nop +80000564: 00000013 nop +80000568: 10500073 wfi +8000056c: 4bc0006f j 80000a28 -8000052c : -8000052c: 01500e13 li t3,21 -80000530: 00000f17 auipc t5,0x0 -80000534: 060f0f13 addi t5,t5,96 # 80000590 -80000538: 20000093 li ra,512 -8000053c: 1440b073 csrc sip,ra -80000540: 00200093 li ra,2 -80000544: 30009073 csrw mstatus,ra -80000548: 20000093 li ra,512 -8000054c: 30409073 csrw mie,ra -80000550: 000020b7 lui ra,0x2 -80000554: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800> -80000558: 00001137 lui sp,0x1 -8000055c: 80010113 addi sp,sp,-2048 # 800 <_start-0x7ffff800> -80000560: 3000b073 csrc mstatus,ra -80000564: 30012073 csrs mstatus,sp -80000568: 00000097 auipc ra,0x0 -8000056c: 01408093 addi ra,ra,20 # 8000057c -80000570: 34109073 csrw mepc,ra -80000574: 30200073 mret -80000578: 1700006f j 800006e8 -8000057c: 00100e93 li t4,1 -80000580: 20000093 li ra,512 -80000584: 1440a073 csrs sip,ra -80000588: 10500073 wfi -8000058c: 15c0006f j 800006e8 +80000570 : +80000570: 01100e13 li t3,17 +80000574: 20000093 li ra,512 +80000578: 30309073 csrw mideleg,ra +8000057c: 00000f17 auipc t5,0x0 +80000580: 080f0f13 addi t5,t5,128 # 800005fc +80000584: f00120b7 lui ra,0xf0012 +80000588: 00000113 li sp,0 +8000058c: 0020a023 sw sp,0(ra) # f0012000 +80000590: 00000013 nop +80000594: 00000013 nop +80000598: 00000013 nop +8000059c: 00000013 nop +800005a0: 00000013 nop +800005a4: 00000013 nop +800005a8: 00000013 nop +800005ac: 00000013 nop +800005b0: 00200093 li ra,2 +800005b4: 30009073 csrw mstatus,ra +800005b8: 20000093 li ra,512 +800005bc: 30409073 csrw mie,ra +800005c0: 00000e93 li t4,0 +800005c4: f00120b7 lui ra,0xf0012 +800005c8: 00100113 li sp,1 +800005cc: 0020a023 sw sp,0(ra) # f0012000 +800005d0: 00000013 nop +800005d4: 00000013 nop +800005d8: 00000013 nop +800005dc: 00000013 nop +800005e0: 00000013 nop +800005e4: 00000013 nop +800005e8: 00000013 nop +800005ec: 00000013 nop +800005f0: 06400093 li ra,100 +800005f4: fff08093 addi ra,ra,-1 +800005f8: fe104ee3 bgtz ra,800005f4 -80000590 : -80000590: 01600e13 li t3,22 -80000594: 00000f17 auipc t5,0x0 -80000598: 058f0f13 addi t5,t5,88 # 800005ec -8000059c: 20000093 li ra,512 -800005a0: 1440b073 csrc sip,ra -800005a4: 00200093 li ra,2 -800005a8: 30009073 csrw mstatus,ra -800005ac: 20000093 li ra,512 -800005b0: 30409073 csrw mie,ra -800005b4: 20000093 li ra,512 -800005b8: 1440a073 csrs sip,ra -800005bc: 000020b7 lui ra,0x2 -800005c0: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800> -800005c4: 00000113 li sp,0 -800005c8: 3000b073 csrc mstatus,ra -800005cc: 30012073 csrs mstatus,sp -800005d0: 00000097 auipc ra,0x0 -800005d4: 01408093 addi ra,ra,20 # 800005e4 -800005d8: 34109073 csrw mepc,ra -800005dc: 30200073 mret -800005e0: 1080006f j 800006e8 -800005e4: 10500073 wfi -800005e8: 1000006f j 800006e8 +800005fc : +800005fc: 01200e13 li t3,18 +80000600: 00000f17 auipc t5,0x0 +80000604: 0a8f0f13 addi t5,t5,168 # 800006a8 +80000608: f00120b7 lui ra,0xf0012 +8000060c: 00000113 li sp,0 +80000610: 0020a023 sw sp,0(ra) # f0012000 +80000614: 00000013 nop +80000618: 00000013 nop +8000061c: 00000013 nop +80000620: 00000013 nop +80000624: 00000013 nop +80000628: 00000013 nop +8000062c: 00000013 nop +80000630: 00000013 nop +80000634: 00200093 li ra,2 +80000638: 30009073 csrw mstatus,ra +8000063c: 20000093 li ra,512 +80000640: 30409073 csrw mie,ra +80000644: 000020b7 lui ra,0x2 +80000648: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800> +8000064c: 00001137 lui sp,0x1 +80000650: 80010113 addi sp,sp,-2048 # 800 <_start-0x7ffff800> +80000654: 3000b073 csrc mstatus,ra +80000658: 30012073 csrs mstatus,sp +8000065c: 00000097 auipc ra,0x0 +80000660: 01408093 addi ra,ra,20 # 80000670 +80000664: 34109073 csrw mepc,ra +80000668: 30200073 mret +8000066c: 3bc0006f j 80000a28 +80000670: 00100e93 li t4,1 +80000674: f00120b7 lui ra,0xf0012 +80000678: 00100113 li sp,1 +8000067c: 0020a023 sw sp,0(ra) # f0012000 +80000680: 00000013 nop +80000684: 00000013 nop +80000688: 00000013 nop +8000068c: 00000013 nop +80000690: 00000013 nop +80000694: 00000013 nop +80000698: 00000013 nop +8000069c: 00000013 nop +800006a0: 10500073 wfi +800006a4: 3840006f j 80000a28 -800005ec : -800005ec: 01700e13 li t3,23 -800005f0: 00000e93 li t4,0 -800005f4: f00120b7 lui ra,0xf0012 -800005f8: 00000113 li sp,0 -800005fc: 0020a023 sw sp,0(ra) # f0012000 -80000600: 20000093 li ra,512 -80000604: 1440b073 csrc sip,ra -80000608: 344021f3 csrr gp,mip -8000060c: f00120b7 lui ra,0xf0012 -80000610: 00100113 li sp,1 -80000614: 0020a023 sw sp,0(ra) # f0012000 -80000618: 20000093 li ra,512 -8000061c: 1440b073 csrc sip,ra -80000620: 344021f3 csrr gp,mip -80000624: f00120b7 lui ra,0xf0012 -80000628: 00000113 li sp,0 -8000062c: 0020a023 sw sp,0(ra) # f0012000 -80000630: 20000093 li ra,512 -80000634: 1440b073 csrc sip,ra -80000638: 344021f3 csrr gp,mip -8000063c: f00120b7 lui ra,0xf0012 -80000640: 00000113 li sp,0 -80000644: 0020a023 sw sp,0(ra) # f0012000 -80000648: 20000093 li ra,512 -8000064c: 1440a073 csrs sip,ra -80000650: 344021f3 csrr gp,mip -80000654: f00120b7 lui ra,0xf0012 -80000658: 00100113 li sp,1 -8000065c: 0020a023 sw sp,0(ra) # f0012000 -80000660: 20000093 li ra,512 -80000664: 1440a073 csrs sip,ra -80000668: 344021f3 csrr gp,mip -8000066c: f00120b7 lui ra,0xf0012 -80000670: 00000113 li sp,0 -80000674: 0020a023 sw sp,0(ra) # f0012000 +800006a8 : +800006a8: 01300e13 li t3,19 +800006ac: 00000f17 auipc t5,0x0 +800006b0: 0a0f0f13 addi t5,t5,160 # 8000074c +800006b4: f00120b7 lui ra,0xf0012 +800006b8: 00000113 li sp,0 +800006bc: 0020a023 sw sp,0(ra) # f0012000 +800006c0: 00000013 nop +800006c4: 00000013 nop +800006c8: 00000013 nop +800006cc: 00000013 nop +800006d0: 00000013 nop +800006d4: 00000013 nop +800006d8: 00000013 nop +800006dc: 00000013 nop +800006e0: 00200093 li ra,2 +800006e4: 30009073 csrw mstatus,ra +800006e8: 20000093 li ra,512 +800006ec: 30409073 csrw mie,ra +800006f0: 000020b7 lui ra,0x2 +800006f4: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800> +800006f8: 00000113 li sp,0 +800006fc: 3000b073 csrc mstatus,ra +80000700: 30012073 csrs mstatus,sp +80000704: 00000097 auipc ra,0x0 +80000708: 01408093 addi ra,ra,20 # 80000718 +8000070c: 34109073 csrw mepc,ra +80000710: 30200073 mret +80000714: 3140006f j 80000a28 +80000718: f00120b7 lui ra,0xf0012 +8000071c: 00100113 li sp,1 +80000720: 0020a023 sw sp,0(ra) # f0012000 +80000724: 00000013 nop +80000728: 00000013 nop +8000072c: 00000013 nop +80000730: 00000013 nop +80000734: 00000013 nop +80000738: 00000013 nop +8000073c: 00000013 nop +80000740: 00000013 nop +80000744: 10500073 wfi +80000748: 2e00006f j 80000a28 -80000678 : -80000678: 01800e13 li t3,24 -8000067c: 00200093 li ra,2 -80000680: 3040a073 csrs mie,ra -80000684: 3440a073 csrs mip,ra -80000688: 3000a073 csrs mstatus,ra -8000068c: 00100e93 li t4,1 -80000690: 00000f17 auipc t5,0x0 -80000694: 03cf0f13 addi t5,t5,60 # 800006cc -80000698: 000020b7 lui ra,0x2 -8000069c: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800> -800006a0: 00001137 lui sp,0x1 -800006a4: 80010113 addi sp,sp,-2048 # 800 <_start-0x7ffff800> -800006a8: 3000b073 csrc mstatus,ra -800006ac: 30012073 csrs mstatus,sp -800006b0: 00000097 auipc ra,0x0 -800006b4: 01408093 addi ra,ra,20 # 800006c4 -800006b8: 34109073 csrw mepc,ra -800006bc: 30200073 mret -800006c0: 0280006f j 800006e8 - -800006c4 : -800006c4: 10500073 wfi -800006c8: 0200006f j 800006e8 - -800006cc : -800006cc: 01900e13 li t3,25 -800006d0: 00000f17 auipc t5,0x0 -800006d4: 014f0f13 addi t5,t5,20 # 800006e4 -800006d8: 30046073 csrsi mstatus,8 -800006dc: 10500073 wfi -800006e0: 0080006f j 800006e8 - -800006e4 : -800006e4: 0100006f j 800006f4 - -800006e8 : -800006e8: f0100137 lui sp,0xf0100 -800006ec: f2410113 addi sp,sp,-220 # f00fff24 -800006f0: 01c12023 sw t3,0(sp) - -800006f4 : -800006f4: f0100137 lui sp,0xf0100 -800006f8: f2010113 addi sp,sp,-224 # f00fff20 -800006fc: 00012023 sw zero,0(sp) - -80000700 : -80000700: fe0e84e3 beqz t4,800006e8 -80000704: 342020f3 csrr ra,mcause -80000708: 341020f3 csrr ra,mepc -8000070c: 300020f3 csrr ra,mstatus -80000710: 343020f3 csrr ra,mtval -80000714: 08000093 li ra,128 -80000718: 3000b073 csrc mstatus,ra -8000071c: 00200093 li ra,2 -80000720: fc1e8ae3 beq t4,ra,800006f4 -80000724: 000020b7 lui ra,0x2 -80000728: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800> -8000072c: 3000a073 csrs mstatus,ra -80000730: 341f1073 csrw mepc,t5 -80000734: 30200073 mret - -80000738 : -80000738: fa0e88e3 beqz t4,800006e8 -8000073c: 142020f3 csrr ra,scause -80000740: 141020f3 csrr ra,sepc -80000744: 100020f3 csrr ra,sstatus -80000748: 143020f3 csrr ra,stval -8000074c: 00000073 ecall -80000750: 00000013 nop -80000754: 00000013 nop +8000074c : +8000074c: f00120b7 lui ra,0xf0012 +80000750: 00000113 li sp,0 +80000754: 0020a023 sw sp,0(ra) # f0012000 80000758: 00000013 nop 8000075c: 00000013 nop 80000760: 00000013 nop 80000764: 00000013 nop +80000768: 00000013 nop +8000076c: 00000013 nop +80000770: 00000013 nop +80000774: 00000013 nop +80000778: 01400e13 li t3,20 +8000077c: 00000f17 auipc t5,0x0 +80000780: 030f0f13 addi t5,t5,48 # 800007ac +80000784: 00200093 li ra,2 +80000788: 30009073 csrw mstatus,ra +8000078c: 20000093 li ra,512 +80000790: 30409073 csrw mie,ra +80000794: 00000e93 li t4,0 +80000798: 20000093 li ra,512 +8000079c: 1440a073 csrs sip,ra +800007a0: 06400093 li ra,100 +800007a4: fff08093 addi ra,ra,-1 +800007a8: fe104ee3 bgtz ra,800007a4 + +800007ac : +800007ac: 01500e13 li t3,21 +800007b0: 00000f17 auipc t5,0x0 +800007b4: 060f0f13 addi t5,t5,96 # 80000810 +800007b8: 20000093 li ra,512 +800007bc: 1440b073 csrc sip,ra +800007c0: 00200093 li ra,2 +800007c4: 30009073 csrw mstatus,ra +800007c8: 20000093 li ra,512 +800007cc: 30409073 csrw mie,ra +800007d0: 000020b7 lui ra,0x2 +800007d4: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800> +800007d8: 00001137 lui sp,0x1 +800007dc: 80010113 addi sp,sp,-2048 # 800 <_start-0x7ffff800> +800007e0: 3000b073 csrc mstatus,ra +800007e4: 30012073 csrs mstatus,sp +800007e8: 00000097 auipc ra,0x0 +800007ec: 01408093 addi ra,ra,20 # 800007fc +800007f0: 34109073 csrw mepc,ra +800007f4: 30200073 mret +800007f8: 2300006f j 80000a28 +800007fc: 00100e93 li t4,1 +80000800: 20000093 li ra,512 +80000804: 1440a073 csrs sip,ra +80000808: 10500073 wfi +8000080c: 21c0006f j 80000a28 + +80000810 : +80000810: 01600e13 li t3,22 +80000814: 00000f17 auipc t5,0x0 +80000818: 058f0f13 addi t5,t5,88 # 8000086c +8000081c: 20000093 li ra,512 +80000820: 1440b073 csrc sip,ra +80000824: 00200093 li ra,2 +80000828: 30009073 csrw mstatus,ra +8000082c: 20000093 li ra,512 +80000830: 30409073 csrw mie,ra +80000834: 20000093 li ra,512 +80000838: 1440a073 csrs sip,ra +8000083c: 000020b7 lui ra,0x2 +80000840: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800> +80000844: 00000113 li sp,0 +80000848: 3000b073 csrc mstatus,ra +8000084c: 30012073 csrs mstatus,sp +80000850: 00000097 auipc ra,0x0 +80000854: 01408093 addi ra,ra,20 # 80000864 +80000858: 34109073 csrw mepc,ra +8000085c: 30200073 mret +80000860: 1c80006f j 80000a28 +80000864: 10500073 wfi +80000868: 1c00006f j 80000a28 + +8000086c : +8000086c: 01700e13 li t3,23 +80000870: 00000e93 li t4,0 +80000874: f00120b7 lui ra,0xf0012 +80000878: 00000113 li sp,0 +8000087c: 0020a023 sw sp,0(ra) # f0012000 +80000880: 00000013 nop +80000884: 00000013 nop +80000888: 00000013 nop +8000088c: 00000013 nop +80000890: 00000013 nop +80000894: 00000013 nop +80000898: 00000013 nop +8000089c: 00000013 nop +800008a0: 20000093 li ra,512 +800008a4: 1440b073 csrc sip,ra +800008a8: 344021f3 csrr gp,mip +800008ac: f00120b7 lui ra,0xf0012 +800008b0: 00100113 li sp,1 +800008b4: 0020a023 sw sp,0(ra) # f0012000 +800008b8: 00000013 nop +800008bc: 00000013 nop +800008c0: 00000013 nop +800008c4: 00000013 nop +800008c8: 00000013 nop +800008cc: 00000013 nop +800008d0: 00000013 nop +800008d4: 00000013 nop +800008d8: 20000093 li ra,512 +800008dc: 1440b073 csrc sip,ra +800008e0: 344021f3 csrr gp,mip +800008e4: f00120b7 lui ra,0xf0012 +800008e8: 00000113 li sp,0 +800008ec: 0020a023 sw sp,0(ra) # f0012000 +800008f0: 00000013 nop +800008f4: 00000013 nop +800008f8: 00000013 nop +800008fc: 00000013 nop +80000900: 00000013 nop +80000904: 00000013 nop +80000908: 00000013 nop +8000090c: 00000013 nop +80000910: 20000093 li ra,512 +80000914: 1440b073 csrc sip,ra +80000918: 344021f3 csrr gp,mip +8000091c: f00120b7 lui ra,0xf0012 +80000920: 00000113 li sp,0 +80000924: 0020a023 sw sp,0(ra) # f0012000 +80000928: 00000013 nop +8000092c: 00000013 nop +80000930: 00000013 nop +80000934: 00000013 nop +80000938: 00000013 nop +8000093c: 00000013 nop +80000940: 00000013 nop +80000944: 00000013 nop +80000948: 20000093 li ra,512 +8000094c: 1440a073 csrs sip,ra +80000950: 344021f3 csrr gp,mip +80000954: f00120b7 lui ra,0xf0012 +80000958: 00100113 li sp,1 +8000095c: 0020a023 sw sp,0(ra) # f0012000 +80000960: 00000013 nop +80000964: 00000013 nop +80000968: 00000013 nop +8000096c: 00000013 nop +80000970: 00000013 nop +80000974: 00000013 nop +80000978: 00000013 nop +8000097c: 00000013 nop +80000980: 20000093 li ra,512 +80000984: 1440a073 csrs sip,ra +80000988: 344021f3 csrr gp,mip +8000098c: f00120b7 lui ra,0xf0012 +80000990: 00000113 li sp,0 +80000994: 0020a023 sw sp,0(ra) # f0012000 +80000998: 00000013 nop +8000099c: 00000013 nop +800009a0: 00000013 nop +800009a4: 00000013 nop +800009a8: 00000013 nop +800009ac: 00000013 nop +800009b0: 00000013 nop +800009b4: 00000013 nop + +800009b8 : +800009b8: 01800e13 li t3,24 +800009bc: 00200093 li ra,2 +800009c0: 3040a073 csrs mie,ra +800009c4: 3440a073 csrs mip,ra +800009c8: 3000a073 csrs mstatus,ra +800009cc: 00100e93 li t4,1 +800009d0: 00000f17 auipc t5,0x0 +800009d4: 03cf0f13 addi t5,t5,60 # 80000a0c +800009d8: 000020b7 lui ra,0x2 +800009dc: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800> +800009e0: 00001137 lui sp,0x1 +800009e4: 80010113 addi sp,sp,-2048 # 800 <_start-0x7ffff800> +800009e8: 3000b073 csrc mstatus,ra +800009ec: 30012073 csrs mstatus,sp +800009f0: 00000097 auipc ra,0x0 +800009f4: 01408093 addi ra,ra,20 # 80000a04 +800009f8: 34109073 csrw mepc,ra +800009fc: 30200073 mret +80000a00: 0280006f j 80000a28 + +80000a04 : +80000a04: 10500073 wfi +80000a08: 0200006f j 80000a28 + +80000a0c : +80000a0c: 01900e13 li t3,25 +80000a10: 00000f17 auipc t5,0x0 +80000a14: 014f0f13 addi t5,t5,20 # 80000a24 +80000a18: 30046073 csrsi mstatus,8 +80000a1c: 10500073 wfi +80000a20: 0080006f j 80000a28 + +80000a24 : +80000a24: 0100006f j 80000a34 + +80000a28 : +80000a28: f0100137 lui sp,0xf0100 +80000a2c: f2410113 addi sp,sp,-220 # f00fff24 +80000a30: 01c12023 sw t3,0(sp) + +80000a34 : +80000a34: f0100137 lui sp,0xf0100 +80000a38: f2010113 addi sp,sp,-224 # f00fff20 +80000a3c: 00012023 sw zero,0(sp) + +80000a40 : +80000a40: fe0e84e3 beqz t4,80000a28 +80000a44: 342020f3 csrr ra,mcause +80000a48: 341020f3 csrr ra,mepc +80000a4c: 300020f3 csrr ra,mstatus +80000a50: 343020f3 csrr ra,mbadaddr +80000a54: 08000093 li ra,128 +80000a58: 3000b073 csrc mstatus,ra +80000a5c: 00200093 li ra,2 +80000a60: fc1e8ae3 beq t4,ra,80000a34 +80000a64: 000020b7 lui ra,0x2 +80000a68: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800> +80000a6c: 3000a073 csrs mstatus,ra +80000a70: 341f1073 csrw mepc,t5 +80000a74: 30200073 mret + +80000a78 : +80000a78: fa0e88e3 beqz t4,80000a28 +80000a7c: 142020f3 csrr ra,scause +80000a80: 141020f3 csrr ra,sepc +80000a84: 100020f3 csrr ra,sstatus +80000a88: 143020f3 csrr ra,sbadaddr +80000a8c: 00000073 ecall +80000a90: 00000013 nop +80000a94: 00000013 nop +80000a98: 00000013 nop +80000a9c: 00000013 nop +80000aa0: 00000013 nop +80000aa4: 00000013 nop diff --git a/src/test/cpp/raw/deleg/build/deleg.hex b/src/test/cpp/raw/deleg/build/deleg.hex index ba5fc068..9290e851 100644 --- a/src/test/cpp/raw/deleg/build/deleg.hex +++ b/src/test/cpp/raw/deleg/build/deleg.hex @@ -1,122 +1,174 @@ :0200000480007A -:10000000930E1000970000009380C06F73905030E3 -:10001000970000009380807273905010B71001F029 -:100020001301000023A02000130E1000170F000082 -:10003000130FCF0073000000130E2000B720000044 -:10004000938000801301000073B0003073200130F2 -:1000500097000000938040017390103473002030AB -:100060006F008068170F0000130F4F02730000002D -:100070006F008067130E3000170F0000130F0F0181 -:10008000832010006F004066130E4000B720000070 -:1000900093800080371100001301018073B000309D -:1000A000732001309700000093804001739010345A -:1000B000730020306F004063170F0000130F0F0113 -:1000C000832010006F004062130E5000B720000024 -:1000D000938000801301000073B000307320013062 -:1000E000970000009380400173901034730020301B -:1000F0006F00805F170F0000130F0F0183201000A7 -:100100006F00805E130E600093000001739020303A -:10011000130E7000170F0000130F0F018320100043 -:100120006F00805C130E8000170F0000130FCF03C9 -:10013000B720000093800080371100001301018078 -:1001400073B00030732001309700000093804001AD -:1001500073901034730020306F000059832010001A -:100160006F008058130E9000170F0000130F8F03BD -:10017000B7200000938000801301000073B00030AE -:100180007320013097000000938040017390103479 -:10019000730020306F004055832010006F00C05462 -:1001A000130EA000170F0000130FCF03B71001F0BC -:1001B0001301000023A02000930080007390003002 -:1001C000B71000009380008073904030B71001F0AA -:1001D0001301100023A02000730050106F00C050C6 -:1001E000130EB000170F0000130F8F06B71001F0A9 -:1001F0001301000023A020009300800073900030C2 -:10020000B71000009380008073904030B72000004A -:1002100093800080371100001301018073B000301B -:1002200073200130970000009380400173901034D8 -:10023000730020306F00404BB71001F01301100025 -:1002400023A02000730050106F00004A130EC0005E -:10025000170F0000130F4F06B71001F01301000035 -:1002600023A020009300800073900030B71000009E -:100270009380008073904030B7200000938000800E -:100280001301000073B000307320013097000000AC -:100290009380400173901034730020306F00C0448D -:1002A000B71001F01301100023A0200073005010BC -:1002B0006F0080439300200073900010130EE00045 -:1002C000170F0000130F0F04B72001F013010000F7 -:1002D00023A02000930020007390003093000020A2 -:1002E00073904030930E0000B72001F0130110000E -:1002F00023A02000930040069380F0FFE34E10FE01 -:10030000130EF000170F0000130F8F06B72001F037 -:100310001301000023A02000930020007390003000 -:100320009300002073904030B7200000938000803D -:10033000371100001301018073B0003073200130C9 -:1003400097000000938040017390103473002030B8 -:100350006F008039930E1000B72001F013011000D8 -:1003600023A02000730050106F000038130E00010E -:10037000170F0000130F0F06B72001F01301000044 -:1003800023A02000930020007390003093000020F1 -:1003900073904030B720000093800080130100006C -:1003A00073B000307320013097000000938040014B -:1003B00073901034730020306F000033B72001F0C9 -:1003C0001301100023A02000730050106F00C031F3 -:1003D000130E10019300002073903030170F0000AF -:1003E000130F0F04B72001F01301000023A0200019 -:1003F00093002000739000309300002073904030F1 -:10040000930E0000B72001F01301100023A020007C -:10041000930040069380F0FFE34E10FE130E200180 -:10042000170F0000130F8F06B72001F01301000013 -:1004300023A0200093002000739000309300002040 -:1004400073904030B7200000938000803711000087 -:100450001301018073B00030732001309700000059 -:100460009380400173901034730020306F00C027D8 -:10047000930E1000B72001F01301100023A02000FC -:10048000730050106F004026130E3001170F00004C -:10049000130F0F06B72001F01301000023A0200066 -:1004A0009300200073900030930000207390403040 -:1004B000B7200000938000801301000073B000306B -:1004C0007320013097000000938040017390103436 -:1004D000730020306F004021B72001F0130110009D -:1004E00023A02000730050106F000020B72001F0FF -:1004F0001301000023A02000130E4001170F00007D -:10050000130F0F039300200073900030930000201E -:1005100073904030930E00009300002073A04014AD -:10052000930040069380F0FFE34E10FE130E50013F -:10053000170F0000130F0F069300002073B0401434 -:10054000930020007390003093000020739040309F -:10055000B720000093800080371100001301018054 -:1005600073B0003073200130970000009380400189 -:1005700073901034730020306F000017930E10003A -:100580009300002073A04014730050106F00C0153A -:10059000130E6001170F0000130F8F05930000204A -:1005A00073B040149300200073900030930000203B -:1005B000739040309300002073A04014B7200000D7 -:1005C000938000801301000073B00030732001306D -:1005D0009700000093804001739010347300203026 -:1005E0006F008010730050106F000010130E700128 -:1005F000930E0000B72001F01301000023A020009B -:100600009300002073B04014F3214034B72001F070 -:100610001301100023A020009300002073B04014A9 -:10062000F3214034B72001F01301000023A0200083 -:100630009300002073B04014F3214034B72001F040 -:100640001301000023A020009300002073A0401499 -:10065000F3214034B72001F01301100023A0200043 -:100660009300002073A04014F3214034B72001F020 -:100670001301000023A02000130E8001930020002E -:1006800073A0403073A0403473A00030930E10006C -:10069000170F0000130FCF03B720000093800080D6 -:1006A000371100001301018073B000307320013056 -:1006B0009700000093804001739010347300203045 -:1006C0006F008002730050106F000002130E900143 -:1006D000170F0000130F4F017360043073005010A8 -:1006E0006F0080006F000001370110F0130141F22C -:1006F0002320C101370110F0130101F22320010072 -:10070000E3840EFEF3202034F3201034F320003075 -:10071000F32030349300000873B0003093002000C1 -:10072000E38A1EFCB72000009380008073A0003095 -:1007300073101F3473002030E3880EFAF320201466 -:10074000F3201014F3200010F32030147300000085 -:10075000130000001300000013000000130000004D -:0807600013000000130000006B +:10000000930E1000971000009380C0A3739050309F +:1000100097100000938080A673905010B71001F0E5 +:100020001301000023A020001300000013000000B3 +:100030001300000013000000130000001300000074 +:100040001300000013000000130E1000170F000033 +:10005000130FCF0073000000130E2000B720000024 +:10006000938000801301000073B0003073200130D2 +:10007000970000009380400173901034730020308B +:100080006F00901A170F0000130F4F02730000004B +:100090006F009019130E3000170F0000130F0F019F +:1000A000832010006F005018130E4000B72000008E +:1000B00093800080371100001301018073B000307D +:1000C000732001309700000093804001739010343A +:1000D000730020306F005015170F0000130F0F0131 +:1000E000832010006F005014130E5000B720000042 +:1000F000938000801301000073B000307320013042 +:1001000097000000938040017390103473002030FA +:100110006F009011170F0000130F0F0183201000C4 +:100120006F009010130E6000930000017390203058 +:10013000130E7000170F0000130F0F018320100023 +:100140006F00900E130E8000170F0000130FCF03E7 +:10015000B720000093800080371100001301018058 +:1001600073B000307320013097000000938040018D +:1001700073901034730020306F00100B8320100038 +:100180006F00900A130E9000170F0000130F8F03DB +:10019000B7200000938000801301000073B000308E +:1001A0007320013097000000938040017390103459 +:1001B000730020306F005007832010006F00D006BE +:1001C000130EA000170F0000130FCF07B71001F098 +:1001D0001301000023A02000130000001300000002 +:1001E00013000000130000001300000013000000C3 +:1001F0001300000013000000930080007390003093 +:10020000B71000009380008073904030B71001F069 +:100210001301100023A020001300000013000000B1 +:100220001300000013000000130000001300000082 +:100230001300000013000000730050106F00C07E18 +:10024000130EB000170F0000130F8F0AB71001F044 +:100250001301000023A02000130000001300000081 +:100260001300000013000000130000001300000042 +:100270001300000013000000930080007390003012 +:10028000B71000009380008073904030B7200000CA +:1002900093800080371100001301018073B000309B +:1002A0007320013097000000938040017390103458 +:1002B000730020306F004077B71001F01301100079 +:1002C00023A0200013000000130000001300000012 +:1002D00013000000130000001300000013000000D2 +:1002E00013000000730050106F000074130EC00064 +:1002F000170F0000130F4F0AB71001F01301000091 +:1003000023A02000130000001300000013000000D1 +:100310001300000013000000130000001300000091 +:10032000130000009300800073900030B7100000AD +:100330009380008073904030B7200000938000804D +:100340001301000073B000307320013097000000EB +:100350009380400173901034730020306F00C06CA4 +:10036000B71001F01301100023A0200013000000BB +:100370001300000013000000130000001300000031 +:100380001300000013000000130000007300501061 +:100390006F0080699300200073900010130EE0003E +:1003A000170F0000130F0F08B72001F01301000012 +:1003B00023A0200013000000130000001300000021 +:1003C00013000000130000001300000013000000E1 +:1003D0001300000093002000739000309300002071 +:1003E00073904030930E0000B72001F0130110000D +:1003F00023A02000130000001300000013000000E1 +:1004000013000000130000001300000013000000A0 +:1004100013000000930040069380F0FFE34E10FEAF +:10042000130EF000170F0000130F8F0AB72001F012 +:100430001301000023A0200013000000130000009F +:100440001300000013000000130000001300000060 +:100450001300000013000000930020007390003090 +:100460009300002073904030B720000093800080FC +:10047000371100001301018073B000307320013088 +:100480009700000093804001739010347300203077 +:100490006F008059930E1000B72001F01301100077 +:1004A00023A0200013000000130000001300000030 +:1004B00013000000130000001300000013000000F0 +:1004C00013000000730050106F000056130E00015F +:1004D000170F0000130F0F0AB72001F013010000DF +:1004E00023A02000130000001300000013000000F0 +:1004F00013000000130000001300000013000000B0 +:10050000130000009300200073900030930000203F +:1005100073904030B72000009380008013010000EA +:1005200073B00030732001309700000093804001C9 +:1005300073901034730020306F00004FB72001F02B +:100540001301100023A0200013000000130000007E +:10055000130000001300000013000000130000004F +:100560001300000013000000730050106F00C04B18 +:10057000130E10019300002073903030170F00000D +:10058000130F0F08B72001F01301000023A0200073 +:10059000130000001300000013000000130000000F +:1005A00013000000130000001300000013000000FF +:1005B000930020007390003093000020739040302F +:1005C000930E0000B72001F01301100023A02000BB +:1005D00013000000130000001300000013000000CF +:1005E00013000000130000001300000013000000BF +:1005F000930040069380F0FFE34E10FE130E20019F +:10060000170F0000130F8F0AB72001F0130100002D +:1006100023A02000130000001300000013000000BE +:10062000130000001300000013000000130000007E +:10063000130000009300200073900030930000200E +:1006400073904030B7200000938000803711000085 +:100650001301018073B00030732001309700000057 +:100660009380400173901034730020306F00C03BC2 +:10067000930E1000B72001F01301100023A02000FA +:10068000130000001300000013000000130000001E +:10069000130000001300000013000000130000000E +:1006A000730050106F004038130E3001170F000018 +:1006B000130F0F0AB72001F01301000023A0200040 +:1006C00013000000130000001300000013000000DE +:1006D00013000000130000001300000013000000CE +:1006E00093002000739000309300002073904030FE +:1006F000B7200000938000801301000073B0003029 +:1007000073200130970000009380400173901034F3 +:10071000730020306F004031B72001F0130110004A +:1007200023A02000130000001300000013000000AD +:10073000130000001300000013000000130000006D +:1007400013000000730050106F00002EB72001F05E +:100750001301000023A0200013000000130000007C +:10076000130000001300000013000000130000003D +:100770001300000013000000130E4001170F0000CB +:10078000130F0F039300200073900030930000209C +:1007900073904030930E00009300002073A040142B +:1007A000930040069380F0FFE34E10FE130E5001BD +:1007B000170F0000130F0F069300002073B04014B2 +:1007C000930020007390003093000020739040301D +:1007D000B7200000938000803711000013010180D2 +:1007E00073B0003073200130970000009380400107 +:1007F00073901034730020306F000023930E1000AC +:100800009300002073A04014730050106F00C021AB +:10081000130E6001170F0000130F8F0593000020C7 +:1008200073B04014930020007390003093000020B8 +:10083000739040309300002073A04014B720000054 +:10084000938000801301000073B0003073200130EA +:1008500097000000938040017390103473002030A3 +:100860006F00801C730050106F00001C130E70018D +:10087000930E0000B72001F01301000023A0200018 +:10088000130000001300000013000000130000001C +:10089000130000001300000013000000130000000C +:1008A0009300002073B04014F3214034B72001F0CE +:1008B0001301100023A0200013000000130000000B +:1008C00013000000130000001300000013000000DC +:1008D00013000000130000009300002073B04014C8 +:1008E000F3214034B72001F01301000023A02000C1 +:1008F00013000000130000001300000013000000AC +:10090000130000001300000013000000130000009B +:100910009300002073B04014F3214034B72001F05D +:100920001301000023A020001300000013000000AA +:10093000130000001300000013000000130000006B +:1009400013000000130000009300002073A0401467 +:10095000F3214034B72001F01301100023A0200040 +:10096000130000001300000013000000130000003B +:10097000130000001300000013000000130000002B +:100980009300002073A04014F3214034B72001F0FD +:100990001301000023A0200013000000130000003A +:1009A00013000000130000001300000013000000FB +:1009B0001300000013000000130E800193002000BC +:1009C00073A0403073A0403473A00030930E100029 +:1009D000170F0000130FCF03B72000009380008093 +:1009E000371100001301018073B000307320013013 +:1009F0009700000093804001739010347300203002 +:100A00006F008002730050106F000002130E9001FF +:100A1000170F0000130F4F01736004307300501064 +:100A20006F0080006F000001370110F0130141F2E8 +:100A30002320C101370110F0130101F2232001002E +:100A4000E3840EFEF3202034F3201034F320003032 +:100A5000F32030349300000873B00030930020007E +:100A6000E38A1EFCB72000009380008073A0003052 +:100A700073101F3473002030E3880EFAF320201423 +:100A8000F3201014F3200010F32030147300000042 +:100A9000130000001300000013000000130000000A +:080AA000130000001300000028 :040000058000000077 :00000001FF diff --git a/src/test/cpp/raw/deleg/src/crt.S b/src/test/cpp/raw/deleg/src/crt.S index 86dd58f8..f88d13f8 100644 --- a/src/test/cpp/raw/deleg/src/crt.S +++ b/src/test/cpp/raw/deleg/src/crt.S @@ -10,11 +10,28 @@ li x1, 0xF0011000; \ li x2, value; \ sw x2, 0(x1); \ + nop; \ + nop; \ + nop; \ + nop; \ + nop; \ + nop; \ + nop; \ + nop; \ + #define externalInterruptS(value) \ li x1, 0xF0012000; \ li x2, value; \ sw x2, 0(x1); \ + nop; \ + nop; \ + nop; \ + nop; \ + nop; \ + nop; \ + nop; \ + nop; \ From f63c4db469926ee4b8ba84f13749893052c5d237 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Tue, 18 Feb 2020 00:59:39 +0100 Subject: [PATCH 310/951] Fix CsrPlugin pipeline liberator --- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 98dfbaa8..7d98bb9b 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -808,17 +808,29 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep //Used to make the pipeline empty softly (for interrupts) val pipelineLiberator = new Area{ - when(interrupt.valid && allowInterrupts){ - decode.arbitration.haltByOther := decode.arbitration.isValid + val pcValids = Vec(RegInit(False), stagesFromExecute.length) + val active = interrupt.valid && allowInterrupts && decode.arbitration.isValid + when(active){ + decode.arbitration.haltByOther := True + for((stage, reg, previous) <- (stagesFromExecute, pcValids, True :: pcValids.toList).zipped){ + when(!stage.arbitration.isStuck){ + reg := previous + } + } + } + when(!active || decode.arbitration.isRemoved) { + pcValids.foreach(_ := False) } - val done = !stagesFromExecute.map(_.arbitration.isValid).orR && fetcher.pcValid(mepcCaptureStage) +// val pcValids = for(stage <- stagesFromExecute) yield RegInit(False) clearWhen(!started) setWhen(!stage.arbitration.isValid) + val done = CombInit(pcValids.last) if(exceptionPortCtrl != null) done.clearWhen(exceptionPortCtrl.exceptionValidsRegs.tail.orR) } //Interrupt/Exception entry logic val interruptJump = Bool.addTag(Verilator.public) interruptJump := interrupt.valid && pipelineLiberator.done && allowInterrupts + if(pipelinedInterrupt) interrupt.valid clearWhen(interruptJump) //avoid double fireing val hadException = RegNext(exception) init(False) pipelineLiberator.done.clearWhen(hadException) From a7440426fd6fd8c1b80b816a0c63a70ed4412e9d Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Tue, 18 Feb 2020 01:00:11 +0100 Subject: [PATCH 311/951] Fix FetchPlugin redo gen condition Fix injectorFailure reset --- src/main/scala/vexriscv/plugin/Fetcher.scala | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/Fetcher.scala b/src/main/scala/vexriscv/plugin/Fetcher.scala index f933ab92..065f01ff 100644 --- a/src/main/scala/vexriscv/plugin/Fetcher.scala +++ b/src/main/scala/vexriscv/plugin/Fetcher.scala @@ -129,7 +129,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, val inc = RegInit(False) clearWhen(corrected || pcRegPropagate) setWhen(output.fire) clearWhen(!output.valid && output.ready) val pc = pcReg + (inc ## B"00").asUInt val predictionPcLoad = ifGen(prediction == DYNAMIC_TARGET) (Flow(UInt(32 bits))) - val redo = fetchRedoGen generate Flow(UInt(32 bits)) + val redo = (fetchRedoGen || prediction == DYNAMIC_TARGET) generate Flow(UInt(32 bits)) val flushed = False if(compressedGen) when(inc) { @@ -142,7 +142,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, pc := predictionPcLoad.payload } } - if(fetchRedoGen) when(redo.valid){ + if(redo != null) when(redo.valid){ corrected := True pc := redo.payload flushed := True @@ -216,8 +216,10 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, s.output << s.input.haltWhen(s.halt) } - fetchPc.redo.valid := redoFetch - fetchPc.redo.payload := stages.last.input.payload + if(fetchPc.redo != null) { + fetchPc.redo.valid := redoFetch + fetchPc.redo.payload := stages.last.input.payload + } stages.head.flush := False //getFlushAt(IBUS_RSP, stages.head == stages.last) || fetchFlush for((s,sNext) <- (stages, stages.tail).zipped) { @@ -579,7 +581,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, val predictionBranch = decompressorContext.hit && !decompressorContext.hazard && decompressorContext.line.branchWish(1) val unalignedWordIssue = decompressor.bufferFill && decompressor.input.rsp.inst(17 downto 16) === 3 && predictionBranch val decompressorFailure = RegInit(False) setWhen(unalignedWordIssue) clearWhen(fetcherflushIt) - val injectorFailure = Delay(decompressorFailure, cycleCount=if(injectorStage) 1 else 0, when=injector.decodeInput.ready) + val injectorFailure = Delay(decompressorFailure, cycleCount=if(injectorStage) 1 else 0, when=injector.decodeInput.ready, init=False) val bypassFailure = if(!injectorStage) False else decompressorFailure && !injector.decodeInput.valid when(injectorFailure || bypassFailure){ From a684d5e4d172e649a388e9d33b4e4e03c4754883 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Wed, 19 Feb 2020 01:20:52 +0100 Subject: [PATCH 312/951] Rework/clean decompressor logic --- src/main/scala/vexriscv/plugin/Fetcher.scala | 37 ++++++++++---------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/Fetcher.scala b/src/main/scala/vexriscv/plugin/Fetcher.scala index 065f01ff..5c2c5dd7 100644 --- a/src/main/scala/vexriscv/plugin/Fetcher.scala +++ b/src/main/scala/vexriscv/plugin/Fetcher.scala @@ -43,7 +43,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, injectionPort = Stream(Bits(32 bits)) injectionPort } - def pcRegReusedForSecondStage = allowPcRegReusedForSecondStage && prediction != DYNAMIC_TARGET + def pcRegReusedForSecondStage = allowPcRegReusedForSecondStage && prediction != DYNAMIC_TARGET //TODO might not be required for DYNAMIC_TARGET var predictionJumpInterface : Flow[UInt] = null override def haltIt(): Unit = fetcherHalt := True @@ -253,32 +253,31 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, whenFalse = input.rsp.inst(31 downto 16) ## (input.pc(1) ? input.rsp.inst(31 downto 16) | input.rsp.inst(15 downto 0)) ) val isRvc = raw(1 downto 0) =/= 3 + val isBufferRvc = bufferData(1 downto 0) =/= 3 val decompressed = RvcDecompressor(raw(15 downto 0)) - output.valid := (isRvc ? (bufferValid || input.valid) | (input.valid && (bufferValid || !input.pc(1)))) + output.valid := bufferValid ? (isBufferRvc || input.valid) | (input.valid && (!input.pc(1) || input.rsp.inst(17 downto 16) =/= 3)) output.pc := input.pc output.isRvc := isRvc output.rsp.inst := isRvc ? decompressed | raw - input.ready := !output.valid || !(!output.ready || (isRvc && !input.pc(1) && input.rsp.inst(16, 2 bits) =/= 3) || (!isRvc && bufferValid && input.rsp.inst(16, 2 bits) =/= 3)) - addPrePopTask(() => { - when(!input.ready && output.fire && !flush /* && ((isRvc && !bufferValid && !input.pc(1)) || (!isRvc && bufferValid && input.rsp.inst(16, 2 bits) =/= 3))*/) { - input.pc.getDrivingReg(1) := True - } - }) + input.ready := output.ready && !(bufferValid && isBufferRvc) - bufferValid clearWhen(output.fire) val bufferFill = False - when(input.fire){ - when(!(!isRvc && !input.pc(1) && !bufferValid) && !(isRvc && input.pc(1) && output.ready)) { - bufferValid := True - bufferFill := True - } otherwise { - bufferValid := False - } - bufferData := input.rsp.inst(31 downto 16) + when(output.ready && (isBufferRvc || input.valid)){ + bufferValid := False } + when(output.ready && input.valid){ + bufferData := input.rsp.inst(31 downto 16) + when((!bufferValid && !input.pc(1) && input.rsp.inst(1 downto 0) =/= 3) || (bufferValid && !isBufferRvc) || (input.pc(1) && input.rsp.inst(17 downto 16) === 3)){ + bufferFill := True + bufferValid := True + } + } + bufferValid.clearWhen(flush) - iBusRsp.readyForError.clearWhen(bufferValid && isRvc) //Can't emit error, as there is a earlier instruction pending - incomingInstruction setWhen(bufferValid && bufferData(1 downto 0) =/= 3) + when(bufferValid && isBufferRvc){ + iBusRsp.readyForError := False + incomingInstruction := True + } }) From 59508d5b5736848eae2eed229d01b7566dbcf8d1 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Thu, 20 Feb 2020 02:27:57 +0100 Subject: [PATCH 313/951] Fix target branch prediction for RVC, all default configs pass dhrystone --- src/main/scala/vexriscv/plugin/Fetcher.scala | 56 +++++++++++--------- 1 file changed, 30 insertions(+), 26 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/Fetcher.scala b/src/main/scala/vexriscv/plugin/Fetcher.scala index 5c2c5dd7..3106e993 100644 --- a/src/main/scala/vexriscv/plugin/Fetcher.scala +++ b/src/main/scala/vexriscv/plugin/Fetcher.scala @@ -247,36 +247,42 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, val bufferValid = RegInit(False) val bufferData = Reg(Bits(16 bits)) + + val isInputLowRvc = input.rsp.inst(1 downto 0) =/= 3 + val isInputHighRvc = input.rsp.inst(17 downto 16) =/= 3 + val doubleRvc = iBusRsp.stages.last.input.valid && !bufferValid && isInputLowRvc && isInputHighRvc && !input.pc(1) + val throw2BytesReg = RegInit(False) + val throw2Bytes = throw2BytesReg || input.pc(1) + val unaligned = throw2Bytes || bufferValid + def aligned = !unaligned val raw = Mux( sel = bufferValid, whenTrue = input.rsp.inst(15 downto 0) ## bufferData, - whenFalse = input.rsp.inst(31 downto 16) ## (input.pc(1) ? input.rsp.inst(31 downto 16) | input.rsp.inst(15 downto 0)) + whenFalse = input.rsp.inst(31 downto 16) ## (throw2Bytes ? input.rsp.inst(31 downto 16) | input.rsp.inst(15 downto 0)) ) val isRvc = raw(1 downto 0) =/= 3 - val isBufferRvc = bufferData(1 downto 0) =/= 3 val decompressed = RvcDecompressor(raw(15 downto 0)) - output.valid := bufferValid ? (isBufferRvc || input.valid) | (input.valid && (!input.pc(1) || input.rsp.inst(17 downto 16) =/= 3)) + output.valid := input.valid && !(throw2Bytes && !bufferValid && !isInputHighRvc) output.pc := input.pc output.isRvc := isRvc output.rsp.inst := isRvc ? decompressed | raw - input.ready := output.ready && !(bufferValid && isBufferRvc) + input.ready := output.ready && (!iBusRsp.stages.last.input.valid || (!(bufferValid && isInputHighRvc) && !(aligned && isInputLowRvc && isInputHighRvc))) - val bufferFill = False - when(output.ready && (isBufferRvc || input.valid)){ + when(output.fire){ + throw2BytesReg := (aligned && isInputLowRvc && isInputHighRvc) || (bufferValid && isInputHighRvc) + } + val bufferFill = (aligned && isInputLowRvc && !isInputHighRvc) || (bufferValid && !isInputHighRvc) || (throw2Bytes && !isRvc && !isInputHighRvc) + when(output.ready && input.valid){ bufferValid := False } when(output.ready && input.valid){ bufferData := input.rsp.inst(31 downto 16) - when((!bufferValid && !input.pc(1) && input.rsp.inst(1 downto 0) =/= 3) || (bufferValid && !isBufferRvc) || (input.pc(1) && input.rsp.inst(17 downto 16) === 3)){ - bufferFill := True - bufferValid := True - } + bufferValid setWhen(bufferFill) } - bufferValid.clearWhen(flush) - when(bufferValid && isBufferRvc){ - iBusRsp.readyForError := False - incomingInstruction := True + when(flush){ + throw2BytesReg := False + bufferValid := False } }) @@ -504,7 +510,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, val source = Bits(30 - historyRamSizeLog2 bits) val branchWish = UInt(2 bits) val target = UInt(32 bits) - val unaligned = ifGen(compressedGen)(Bool) + val last2Bytes = ifGen(compressedGen)(Bool) } val history = Mem(BranchPredictorLine(), 1 << historyRamSizeLog2) @@ -515,6 +521,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, val hazard = historyWriteLast.valid && historyWriteLast.address === (iBusRsp.stages(1).input.payload >> 2).resized val line = history.readSync((iBusRsp.stages(0).input.payload >> 2).resized, iBusRsp.stages(0).output.ready) val hit = line.source === (iBusRsp.stages(1).input.payload.asBits >> 2 + historyRamSizeLog2) + if(compressedGen) hit clearWhen(!line.last2Bytes && iBusRsp.stages(1).input.payload(1)) fetchPc.predictionPcLoad.valid := line.branchWish.msb && hit && !hazard && iBusRsp.stages(1).input.valid fetchPc.predictionPcLoad.payload := line.target @@ -533,14 +540,16 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, val (decompressorContext, injectorContext) = stage1ToInjectorPipe(fetchContext) if(compressedGen) { //prediction hit on the right instruction into words - decompressorContext.hit clearWhen(decompressorContext.line.unaligned && (decompressor.bufferValid || (decompressor.isRvc && !decompressor.input.pc(1)))) + decompressorContext.hit clearWhen(decompressorContext.line.last2Bytes && (decompressor.bufferValid || (decompressor.isRvc && !decompressor.throw2Bytes))) decodePc.predictionPcLoad.valid := injectorContext.line.branchWish.msb && injectorContext.hit && !injectorContext.hazard && injector.decodeInput.fire decodePc.predictionPcLoad.payload := injectorContext.line.target + //Clean the RVC buffer when a prediction was made when(decompressorContext.line.branchWish.msb && decompressorContext.hit && !decompressorContext.hazard && decompressor.output.fire){ decompressor.bufferValid := False - decompressor.input.ready := True + decompressor.throw2BytesReg := False + decompressor.input.ready := True //Drop the remaining byte if any } } @@ -557,7 +566,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, historyWrite.address := fetchPrediction.rsp.sourceLastWord(2, historyRamSizeLog2 bits) historyWrite.data.source := fetchPrediction.rsp.sourceLastWord.asBits >> 2 + historyRamSizeLog2 historyWrite.data.target := fetchPrediction.rsp.finalPc - if(compressedGen) historyWrite.data.unaligned := !fetchPrediction.stage.input(PC)(1) ^ fetchPrediction.stage.input(IS_RVC) + if(compressedGen) historyWrite.data.last2Bytes := fetchPrediction.stage.input(PC)(1) && fetchPrediction.stage.input(IS_RVC) when(fetchPrediction.rsp.wasRight) { historyWrite.valid := branchContext.hit @@ -574,18 +583,13 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, historyWrite.valid clearWhen(branchContext.hazard || !branchStage.arbitration.isFiring) - - val predictionFailure = ifGen(compressedGen)(new Area{ val predictionBranch = decompressorContext.hit && !decompressorContext.hazard && decompressorContext.line.branchWish(1) - val unalignedWordIssue = decompressor.bufferFill && decompressor.input.rsp.inst(17 downto 16) === 3 && predictionBranch - val decompressorFailure = RegInit(False) setWhen(unalignedWordIssue) clearWhen(fetcherflushIt) - val injectorFailure = Delay(decompressorFailure, cycleCount=if(injectorStage) 1 else 0, when=injector.decodeInput.ready, init=False) - val bypassFailure = if(!injectorStage) False else decompressorFailure && !injector.decodeInput.valid + val unalignedWordIssue = iBusRsp.output.valid && predictionBranch && decompressor.throw2Bytes && !decompressor.isInputHighRvc - when(injectorFailure || bypassFailure){ + when(unalignedWordIssue){ historyWrite.valid := True - historyWrite.address := (decode.input(PC) >> 2).resized + historyWrite.address := (iBusRsp.stages(1).input.payload >> 2).resized historyWrite.data.branchWish := 0 iBusRsp.redoFetch := True From 32fade50e54609d8406f32222d92cafdf44b6211 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Fri, 21 Feb 2020 02:03:29 +0100 Subject: [PATCH 314/951] Fix fetcher decompressor when driving decode stage --- src/main/scala/vexriscv/plugin/Fetcher.scala | 20 +++++++++---------- .../vexriscv/plugin/IBusSimplePlugin.scala | 3 ++- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/Fetcher.scala b/src/main/scala/vexriscv/plugin/Fetcher.scala index 3106e993..0c61fa17 100644 --- a/src/main/scala/vexriscv/plugin/Fetcher.scala +++ b/src/main/scala/vexriscv/plugin/Fetcher.scala @@ -88,8 +88,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, def isDrivingDecode(s : Any): Boolean = { if(injectorStage) return s == INJECTOR_M2S - if(compressedGen) return s == DECOMPRESSOR - s == IBUS_RSP + s == IBUS_RSP || s == DECOMPRESSOR } def getFlushAt(s : Any, lastCond : Boolean = true): Bool = { @@ -240,9 +239,11 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, } val decompressor = ifGen(decodePcGen)(new Area{ - val input = iBusRsp.output.clearValidWhen(iBusRsp.stages.last.flush) + val input = iBusRsp.output.clearValidWhen(iBusRsp.redoFetch) val output = Stream(FetchRsp()) val flush = getFlushAt(DECOMPRESSOR) + val flushNext = if(isDrivingDecode(DECOMPRESSOR)) decode.arbitration.flushNext else False + val consumeCurrent = if(isDrivingDecode(DECOMPRESSOR)) flushNext && output.ready else False val bufferValid = RegInit(False) val bufferData = Reg(Bits(16 bits)) @@ -250,7 +251,6 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, val isInputLowRvc = input.rsp.inst(1 downto 0) =/= 3 val isInputHighRvc = input.rsp.inst(17 downto 16) =/= 3 - val doubleRvc = iBusRsp.stages.last.input.valid && !bufferValid && isInputLowRvc && isInputHighRvc && !input.pc(1) val throw2BytesReg = RegInit(False) val throw2Bytes = throw2BytesReg || input.pc(1) val unaligned = throw2Bytes || bufferValid @@ -266,7 +266,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, output.pc := input.pc output.isRvc := isRvc output.rsp.inst := isRvc ? decompressed | raw - input.ready := output.ready && (!iBusRsp.stages.last.input.valid || (!(bufferValid && isInputHighRvc) && !(aligned && isInputLowRvc && isInputHighRvc))) + input.ready := output.ready && (!iBusRsp.stages.last.input.valid || flushNext || (!(bufferValid && isInputHighRvc) && !(aligned && isInputLowRvc && isInputHighRvc))) when(output.fire){ throw2BytesReg := (aligned && isInputLowRvc && isInputHighRvc) || (bufferValid && isInputHighRvc) @@ -280,7 +280,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, bufferValid setWhen(bufferFill) } - when(flush){ + when(flush || consumeCurrent){ throw2BytesReg := False bufferValid := False } @@ -495,13 +495,11 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, } //TODO no more fireing depedancies - predictionJumpInterface.valid := decode.arbitration.isValid && decodePrediction.cmd.hadBranch //TODO OH Doublon de priorité + predictionJumpInterface.valid := decode.arbitration.isValid && decodePrediction.cmd.hadBranch predictionJumpInterface.payload := decode.input(PC) + ((decode.input(BRANCH_CTRL) === BranchCtrlEnum.JAL) ? imm.j_sext | imm.b_sext).asUInt - if(relaxPredictorAddress) KeepAttribute(predictionJumpInterface.payload) + decode.arbitration.flushNext setWhen(predictionJumpInterface.valid) - when(predictionJumpInterface.valid && decode.arbitration.isFiring){ - flushIt() - } + if(relaxPredictorAddress) KeepAttribute(predictionJumpInterface.payload) } case DYNAMIC_TARGET => new Area{ // assert(!compressedGen || cmdToRspStageCount == 1, "Can't combine DYNAMIC_TARGET and RVC as it could stop the instruction fetch mid-air") diff --git a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala index 319634d3..8681b9cf 100644 --- a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala @@ -352,7 +352,8 @@ class IBusSimplePlugin( resetVector : BigInt, val rspBuffer = if(!rspHoldValue) new Area{ val c = StreamFifoLowLatency(IBusSimpleRsp(), busLatencyMin + (if(cmdForkOnSecondStage && cmdForkPersistence) 1 else 0)) c.io.push << iBus.rsp.throwWhen(discardCounter =/= 0).toStream - c.io.flush := fetcherflushIt + c.io.flush := iBusRsp.stages.last.flush + if(compressedGen) c.io.flush setWhen(decompressor.consumeCurrent) rspBufferOutput << c.io.pop } else new Area{ val rspStream = iBus.rsp.throwWhen(discardCounter =/= 0).toStream From befc54a444b7ddbe61c4d456c8a2981fd40d221f Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Fri, 21 Feb 2020 13:28:29 +0100 Subject: [PATCH 315/951] No more Fetcher flush() API as it can now be done via the decoder.flushNext --- src/main/scala/vexriscv/Services.scala | 1 - src/main/scala/vexriscv/ip/InstructionCache.scala | 2 +- src/main/scala/vexriscv/plugin/DebugPlugin.scala | 1 - src/main/scala/vexriscv/plugin/Fetcher.scala | 15 +++++++-------- 4 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/main/scala/vexriscv/Services.scala b/src/main/scala/vexriscv/Services.scala index 09cd0982..4b0aeca5 100644 --- a/src/main/scala/vexriscv/Services.scala +++ b/src/main/scala/vexriscv/Services.scala @@ -13,7 +13,6 @@ trait JumpService{ trait IBusFetcher{ def haltIt() : Unit - def flushIt() : Unit def incoming() : Bool def pcValid(stage : Stage) : Bool def getInjectionPort() : Stream[Bits] diff --git a/src/main/scala/vexriscv/ip/InstructionCache.scala b/src/main/scala/vexriscv/ip/InstructionCache.scala index 0a809c62..4df0f79d 100644 --- a/src/main/scala/vexriscv/ip/InstructionCache.scala +++ b/src/main/scala/vexriscv/ip/InstructionCache.scala @@ -114,7 +114,7 @@ case class InstructionCacheCpuFetch(p : InstructionCacheConfig) extends Bundle w val mmuBus = MemoryTranslatorBus() val physicalAddress = UInt(p.addressWidth bits) val cacheMiss, error, mmuRefilling, mmuException, isUser = ifGen(!p.twoCycleCache)(Bool) - val haltIt = Bool + val haltIt = Bool() //Used to wait on the MMU rsp busy override def asMaster(): Unit = { out(isValid, isStuck, isRemoved, pc) diff --git a/src/main/scala/vexriscv/plugin/DebugPlugin.scala b/src/main/scala/vexriscv/plugin/DebugPlugin.scala index 1b0084be..a1051d72 100644 --- a/src/main/scala/vexriscv/plugin/DebugPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DebugPlugin.scala @@ -201,7 +201,6 @@ class DebugPlugin(val debugClockDomain : ClockDomain, hardwareBreakpointCount : execute.arbitration.haltByOther := True busReadDataReg := execute.input(PC).asBits when(stagesFromExecute.tail.map(_.arbitration.isValid).orR === False){ - iBusFetcher.flushIt() iBusFetcher.haltIt() execute.arbitration.flushIt := True execute.arbitration.flushNext := True diff --git a/src/main/scala/vexriscv/plugin/Fetcher.scala b/src/main/scala/vexriscv/plugin/Fetcher.scala index 0c61fa17..ec407738 100644 --- a/src/main/scala/vexriscv/plugin/Fetcher.scala +++ b/src/main/scala/vexriscv/plugin/Fetcher.scala @@ -32,7 +32,6 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, // assert(!(cmdToRspStageCount == 1 && !injectorStage)) assert(!(compressedGen && !decodePcGen)) var fetcherHalt : Bool = null - var fetcherflushIt : Bool = null var pcValids : Vec[Bool] = null def pcValid(stage : Stage) = pcValids(pipeline.indexOf(stage)) var incomingInstruction : Bool = null @@ -47,8 +46,6 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, var predictionJumpInterface : Flow[UInt] = null override def haltIt(): Unit = fetcherHalt := True - override def flushIt(): Unit = fetcherflushIt := True - case class JumpInfo(interface : Flow[UInt], stage: Stage, priority : Int) val jumpInfos = ArrayBuffer[JumpInfo]() override def createJumpInterface(stage: Stage, priority : Int = 0): Flow[UInt] = { @@ -62,7 +59,6 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, // var decodeExceptionPort : Flow[ExceptionCause] = null override def setup(pipeline: VexRiscv): Unit = { fetcherHalt = False - fetcherflushIt = False incomingInstruction = False if(resetVector == null) externalResetVector = in(UInt(32 bits).setName("externalResetVector")) @@ -91,13 +87,16 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, s == IBUS_RSP || s == DECOMPRESSOR } - def getFlushAt(s : Any, lastCond : Boolean = true): Bool = { - if(isDrivingDecode(s) && lastCond) pipeline.decode.arbitration.isRemoved else fetcherflushIt - } + class FetchArea(pipeline : VexRiscv) extends Area { import pipeline._ import pipeline.config._ + val fetcherflushIt = stages.map(_.arbitration.flushNext).orR + + def getFlushAt(s : Any, lastCond : Boolean = true): Bool = { + if(isDrivingDecode(s) && lastCond) pipeline.decode.arbitration.isRemoved else fetcherflushIt + } //Arbitrate jump requests into pcLoad val jump = new Area { @@ -113,7 +112,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, pcLoad.payload := MuxOH(OHMasking.first(valids.asBits), pcs) } - fetcherflushIt setWhen(stages.map(_.arbitration.flushNext).orR) + //The fetchPC pcReg can also be use for the second stage of the fetch //When the fetcherHalt is set and the pipeline isn't stalled,, the pc is propagated to to the pcReg, which allow From 4ad1215873c993db456dbc817c7f1dd6bd9ff0a9 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Fri, 21 Feb 2020 13:28:42 +0100 Subject: [PATCH 316/951] Fix iBusSimplePlugin MMU integration --- .../vexriscv/plugin/IBusSimplePlugin.scala | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala index 8681b9cf..b2f1083a 100644 --- a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala @@ -317,15 +317,16 @@ class IBusSimplePlugin( resetVector : BigInt, cmd.pc := mmuBus.rsp.physicalAddress(31 downto 2) @@ U"00" - //do not emit memory request if MMU miss - when(mmuBus.rsp.exception || mmuBus.rsp.refilling){ - cmdForkStage.halt := False - cmd.valid := False - } - - when(mmuBus.busy){ - cmdForkStage.input.valid := False - cmdForkStage.input.ready := False + //do not emit memory request if MMU had issues + when(cmdForkStage.input.valid) { + when(mmuBus.rsp.refilling) { + cmdForkStage.halt := True + cmd.valid := False + } + when(mmuBus.rsp.exception) { + cmdForkStage.halt := False + cmd.valid := False + } } val joinCtx = stageXToIBusRsp(cmdForkStage, mmuBus.rsp) @@ -354,6 +355,7 @@ class IBusSimplePlugin( resetVector : BigInt, c.io.push << iBus.rsp.throwWhen(discardCounter =/= 0).toStream c.io.flush := iBusRsp.stages.last.flush if(compressedGen) c.io.flush setWhen(decompressor.consumeCurrent) + if(!compressedGen && isDrivingDecode(IBUS_RSP)) c.io.flush setWhen(decode.arbitration.flushNext && iBusRsp.output.ready) rspBufferOutput << c.io.pop } else new Area{ val rspStream = iBus.rsp.throwWhen(discardCounter =/= 0).toStream From 41008551c16afaa3c1781db3f4623d01df5079d0 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Fri, 21 Feb 2020 20:01:35 +0100 Subject: [PATCH 317/951] CsrPlugin redo interface do not need next pc calculation --- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 7d98bb9b..8366b553 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -447,9 +447,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep if(supervisorGen) { - redoInterface = pcManagerService.createJumpInterface(pipeline.execute) - redoInterface.valid := False - redoInterface.payload.assignDontCare() + redoInterface = pcManagerService.createJumpInterface(pipeline.execute, -1) } exceptionPendings = Vec(Bool, pipeline.stages.length) @@ -643,10 +641,13 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep satpAccess(CSR.SATP, 31 -> satp.MODE, 22 -> satp.ASID, 0 -> satp.PPN) - if(supervisorGen) onWrite(CSR.SATP){ - execute.arbitration.flushNext := True - redoInterface.valid := True - redoInterface.payload := execute.input(PC) + 4 + if(supervisorGen) { + redoInterface.valid := False + redoInterface.payload := decode.input(PC) + onWrite(CSR.SATP){ + execute.arbitration.flushNext := True + redoInterface.valid := True + } } } } From 5ea0b57d1b277ee9ff20c2ed8490e72477e605fa Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Sat, 22 Feb 2020 11:53:47 +0100 Subject: [PATCH 318/951] Fix BRANCH_TARGET with RVC patch --- src/main/scala/vexriscv/plugin/Fetcher.scala | 50 +++++++++---------- .../vexriscv/TestIndividualFeatures.scala | 6 +-- 2 files changed, 26 insertions(+), 30 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/Fetcher.scala b/src/main/scala/vexriscv/plugin/Fetcher.scala index ec407738..4b763364 100644 --- a/src/main/scala/vexriscv/plugin/Fetcher.scala +++ b/src/main/scala/vexriscv/plugin/Fetcher.scala @@ -421,18 +421,15 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, } } - def stage1ToInjectorPipe[T <: Data](input : T): (T,T) ={ + def stage1ToInjectorPipe[T <: Data](input : T): (T, T, T) ={ val iBusRspContext = iBusRsp.stages.drop(1).dropRight(1).foldLeft(input)((data,stage) => RegNextWhen(data, stage.output.ready)) -// val decompressorContext = ifGen(compressedGen)(new Area{ -// val lastContext = RegNextWhen(iBusRspContext, decompressor.input.fire) -// val output = decompressor.bufferValid ? lastContext | iBusRspContext -// }) - val decompressorContext = cloneOf(input) - decompressorContext := iBusRspContext - val injectorContext = Delay(if(compressedGen) decompressorContext else iBusRspContext, cycleCount=if(injectorStage) 1 else 0, when=injector.decodeInput.ready) + + val iBusRspContextOutput = cloneOf(input) + iBusRspContextOutput := iBusRspContext + val injectorContext = Delay(iBusRspContextOutput, cycleCount=if(injectorStage) 1 else 0, when=injector.decodeInput.ready) val injectorContextWire = cloneOf(input) //Allow combinatorial override injectorContextWire := injectorContext - (ifGen(compressedGen)(decompressorContext), injectorContextWire) + (iBusRspContext, iBusRspContextOutput, injectorContextWire) } val predictor = prediction match { @@ -458,7 +455,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, fetchContext.line := historyCache.readSync((fetchPc.output.payload >> 2).resized, iBusRsp.stages(0).output.ready || fetcherflushIt) object PREDICTION_CONTEXT extends Stageable(DynamicContext()) - decode.insert(PREDICTION_CONTEXT) := stage1ToInjectorPipe(fetchContext)._2 + decode.insert(PREDICTION_CONTEXT) := stage1ToInjectorPipe(fetchContext)._3 val decodeContextPrediction = decode.input(PREDICTION_CONTEXT).line.history.msb val branchStage = decodePrediction.stage @@ -534,21 +531,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, fetchContext.hit := hit fetchContext.line := line - val (decompressorContext, injectorContext) = stage1ToInjectorPipe(fetchContext) - if(compressedGen) { - //prediction hit on the right instruction into words - decompressorContext.hit clearWhen(decompressorContext.line.last2Bytes && (decompressor.bufferValid || (decompressor.isRvc && !decompressor.throw2Bytes))) - - decodePc.predictionPcLoad.valid := injectorContext.line.branchWish.msb && injectorContext.hit && !injectorContext.hazard && injector.decodeInput.fire - decodePc.predictionPcLoad.payload := injectorContext.line.target - - //Clean the RVC buffer when a prediction was made - when(decompressorContext.line.branchWish.msb && decompressorContext.hit && !decompressorContext.hazard && decompressor.output.fire){ - decompressor.bufferValid := False - decompressor.throw2BytesReg := False - decompressor.input.ready := True //Drop the remaining byte if any - } - } + val (decompressorContext, decompressorContextOutput, injectorContext) = stage1ToInjectorPipe(fetchContext) object PREDICTION_CONTEXT extends Stageable(PredictionResult()) pipeline.decode.insert(PREDICTION_CONTEXT) := injectorContext @@ -580,7 +563,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, historyWrite.valid clearWhen(branchContext.hazard || !branchStage.arbitration.isFiring) - val predictionFailure = ifGen(compressedGen)(new Area{ + val compressor = compressedGen generate new Area{ val predictionBranch = decompressorContext.hit && !decompressorContext.hazard && decompressorContext.line.branchWish(1) val unalignedWordIssue = iBusRsp.output.valid && predictionBranch && decompressor.throw2Bytes && !decompressor.isInputHighRvc @@ -591,7 +574,20 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, iBusRsp.redoFetch := True } - }) + + //Do not trigger prediction hit when it is one for the upper RVC word and we aren't there yet + decompressorContextOutput.hit clearWhen(decompressorContext.line.last2Bytes && !decompressor.throw2Bytes) + + decodePc.predictionPcLoad.valid := injectorContext.line.branchWish.msb && injectorContext.hit && !injectorContext.hazard && injector.decodeInput.fire + decodePc.predictionPcLoad.payload := injectorContext.line.target + + //Clean the RVC buffer when a prediction was made + when(decompressorContext.line.branchWish.msb && decompressorContextOutput.hit && !decompressorContext.hazard && decompressor.output.fire){ + decompressor.bufferValid := False + decompressor.throw2BytesReg := False + decompressor.input.ready := True //Drop the remaining byte if any + } + } } } diff --git a/src/test/scala/vexriscv/TestIndividualFeatures.scala b/src/test/scala/vexriscv/TestIndividualFeatures.scala index 005f3359..7f00d1f6 100644 --- a/src/test/scala/vexriscv/TestIndividualFeatures.scala +++ b/src/test/scala/vexriscv/TestIndividualFeatures.scala @@ -620,7 +620,7 @@ class TestIndividualFeatures extends FunSuite { test(prefix + name + "_test") { println("START TEST " + prefix + name) val debug = true - val stdCmd = (s"make clean run WITH_USER_IO=no REDO=10 TRACE=${if(debug) "yes" else "no"} TRACE_START=9999924910246l STOP_ON_ERROR=no FLOW_INFO=no STOP_ON_ERROR=no DHRYSTONE=yes COREMARK=${sys.env.getOrElse("VEXRISCV_REGRESSION_COREMARK", "yes")} THREAD_COUNT=${sys.env.getOrElse("VEXRISCV_REGRESSION_THREAD_COUNT", 1)} ") + s" SEED=${testSeed} " + val stdCmd = (s"make clean run WITH_USER_IO=no REDO=10 TRACE=${if(debug) "yes" else "no"} TRACE_START=9999924910246l FLOW_INFO=no STOP_ON_ERROR=no DHRYSTONE=yes COREMARK=${sys.env.getOrElse("VEXRISCV_REGRESSION_COREMARK", "yes")} THREAD_COUNT=${sys.env.getOrElse("VEXRISCV_REGRESSION_THREAD_COUNT", 1)} ") + s" SEED=${testSeed} " val testCmd = stdCmd + (positionsToApply).map(_.testParam).mkString(" ") println(testCmd) val str = doCmd(testCmd) @@ -633,8 +633,8 @@ class TestIndividualFeatures extends FunSuite { // // val testId = Some(mutable.HashSet(3,4,9,11,13,16,18,19,20,21)) // val testId = Some(mutable.HashSet(11)) -// val testId = Some(mutable.HashSet(4, 11)) -// val seed = 6592877339343561798l +// val testId = Some(mutable.HashSet(6)) +// val seed = 9095713085965080531l val rand = new Random(seed) From 01e5112680cd437cca7151bd13bf220fc85e1ec9 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Sun, 23 Feb 2020 10:44:44 +0100 Subject: [PATCH 319/951] Fetcher RVC ensure redo keep PC(1) Fix BranchTarget RVC inibition --- src/main/scala/vexriscv/plugin/Fetcher.scala | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/Fetcher.scala b/src/main/scala/vexriscv/plugin/Fetcher.scala index 4b763364..4200982c 100644 --- a/src/main/scala/vexriscv/plugin/Fetcher.scala +++ b/src/main/scala/vexriscv/plugin/Fetcher.scala @@ -247,7 +247,6 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, val bufferValid = RegInit(False) val bufferData = Reg(Bits(16 bits)) - val isInputLowRvc = input.rsp.inst(1 downto 0) =/= 3 val isInputHighRvc = input.rsp.inst(17 downto 16) =/= 3 val throw2BytesReg = RegInit(False) @@ -283,6 +282,10 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, throw2BytesReg := False bufferValid := False } + + if(fetchPc.redo != null) { + fetchPc.redo.payload(1) setWhen(throw2BytesReg) + } }) @@ -576,7 +579,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, } //Do not trigger prediction hit when it is one for the upper RVC word and we aren't there yet - decompressorContextOutput.hit clearWhen(decompressorContext.line.last2Bytes && !decompressor.throw2Bytes) + decompressorContextOutput.hit clearWhen(decompressorContext.line.last2Bytes && (decompressor.bufferValid || (!decompressor.throw2Bytes && decompressor.isInputLowRvc))) decodePc.predictionPcLoad.valid := injectorContext.line.branchWish.msb && injectorContext.hit && !injectorContext.hazard && injector.decodeInput.fire decodePc.predictionPcLoad.payload := injectorContext.line.target From c8016e90a4987a30b6fde5e435626760ddf4b322 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Sun, 23 Feb 2020 20:25:31 +0100 Subject: [PATCH 320/951] MulPlugin now add KEEP attribute on RS1 and RS2 to force Vivado to not retime it with the DSP --- src/main/scala/vexriscv/plugin/MulPlugin.scala | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/scala/vexriscv/plugin/MulPlugin.scala b/src/main/scala/vexriscv/plugin/MulPlugin.scala index 96db3e94..efe3ba09 100644 --- a/src/main/scala/vexriscv/plugin/MulPlugin.scala +++ b/src/main/scala/vexriscv/plugin/MulPlugin.scala @@ -2,6 +2,7 @@ package vexriscv.plugin import vexriscv._ import vexriscv.VexRiscv import spinal.core._ +import spinal.lib.KeepAttribute //Input buffer generaly avoid the FPGA synthesis to duplicate reg inside the DSP cell, which could stress timings quite much. class MulPlugin(inputBuffer : Boolean = false) extends Plugin[VexRiscv]{ @@ -94,6 +95,12 @@ class MulPlugin(inputBuffer : Boolean = false) extends Plugin[VexRiscv]{ insert(MUL_LH) := aSLow * bHigh insert(MUL_HL) := aHigh * bSLow insert(MUL_HH) := aHigh * bHigh + + Component.current.afterElaboration{ + //Avoid synthesis tools to retime RS1 RS2 from execute stage to decode stage leading to bad timings (ex : Vivado, even if retiming is disabled) + KeepAttribute(input(RS1).getDrivingReg) + KeepAttribute(input(RS2).getDrivingReg) + } } //First aggregation of partial multiplication From 67d2071a32c88b822c0d601757d2e1c3aade3d9a Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Sun, 23 Feb 2020 23:17:02 +0100 Subject: [PATCH 321/951] typo --- src/main/scala/vexriscv/demo/SynthesisBench.scala | 2 +- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/scala/vexriscv/demo/SynthesisBench.scala b/src/main/scala/vexriscv/demo/SynthesisBench.scala index 08a7d729..503ef376 100644 --- a/src/main/scala/vexriscv/demo/SynthesisBench.scala +++ b/src/main/scala/vexriscv/demo/SynthesisBench.scala @@ -121,7 +121,7 @@ object VexRiscvSynthesisBench { ) ++ IcestormStdTargets().take(1) // val targets = IcestormStdTargets() - Bench(rtls, targets, "/media/miaou/HD/linux/tmp") + Bench(rtls, targets, "/media/miaou/HD/linux/tmp/") } } diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 8366b553..6e0c41b4 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -686,7 +686,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep //Aggregate all exception port and remove required instructions - val exceptionPortCtrl = if(exceptionPortsInfos.nonEmpty) new Area{ + val exceptionPortCtrl = exceptionPortsInfos.nonEmpty generate new Area{ val firstStageIndexWithExceptionPort = exceptionPortsInfos.map(i => indexOf(i.stage)).min val exceptionValids = Vec(stages.map(s => Bool().setPartialName(s.getName()))) val exceptionValidsRegs = Vec(stages.map(s => Reg(Bool).init(False).setPartialName(s.getName()))).allowUnsetRegToAvoidLatch @@ -763,7 +763,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep //Avoid the PC register of the last stage to change durring an exception handleing (Used to fill Xepc) stages.last.dontSample.getOrElseUpdate(PC, ArrayBuffer[Bool]()) += exceptionValids.last exceptionPendings := exceptionValidsRegs - } else null + } From fad09e805f3470abc14f57cffa380860cc89a4c7 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Sun, 23 Feb 2020 23:18:27 +0100 Subject: [PATCH 322/951] Add Fetcher.predictionBuffer option to pipeline BRANCH_TARGET, higher FMax, about 1 ns critical path gain on Arty7 => 5 ns --- src/main/scala/vexriscv/plugin/Fetcher.scala | 54 +++++++++++++------ .../vexriscv/plugin/IBusCachedPlugin.scala | 6 ++- .../vexriscv/plugin/IBusSimplePlugin.scala | 6 ++- 3 files changed, 46 insertions(+), 20 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/Fetcher.scala b/src/main/scala/vexriscv/plugin/Fetcher.scala index 4200982c..cac87891 100644 --- a/src/main/scala/vexriscv/plugin/Fetcher.scala +++ b/src/main/scala/vexriscv/plugin/Fetcher.scala @@ -22,7 +22,8 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, val historyRamSizeLog2 : Int, val injectorStage : Boolean, val relaxPredictorAddress : Boolean, - val fetchRedoGen : Boolean) extends Plugin[VexRiscv] with JumpService with IBusFetcher{ + val fetchRedoGen : Boolean, + val predictionBuffer : Boolean = true) extends Plugin[VexRiscv] with JumpService with IBusFetcher{ var prefetchExceptionPort : Flow[ExceptionCause] = null var decodePrediction : DecodePredictionBus = null var fetchPrediction : FetchPredictionBus = null @@ -121,10 +122,12 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, //PC calculation without Jump val output = Stream(UInt(32 bits)) val pcReg = Reg(UInt(32 bits)) init(if(resetVector != null) resetVector else externalResetVector) addAttribute(Verilator.public) - val corrected = False + val correction = False + val correctionReg = RegInit(False) setWhen(correction) clearWhen(output.fire) + val corrected = correction || correctionReg val pcRegPropagate = False val booted = RegNext(True) init (False) - val inc = RegInit(False) clearWhen(corrected || pcRegPropagate) setWhen(output.fire) clearWhen(!output.valid && output.ready) + val inc = RegInit(False) clearWhen(correction || pcRegPropagate) setWhen(output.fire) clearWhen(!output.valid && output.ready) val pc = pcReg + (inc ## B"00").asUInt val predictionPcLoad = ifGen(prediction == DYNAMIC_TARGET) (Flow(UInt(32 bits))) val redo = (fetchRedoGen || prediction == DYNAMIC_TARGET) generate Flow(UInt(32 bits)) @@ -136,22 +139,22 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, if(predictionPcLoad != null) { when(predictionPcLoad.valid) { - corrected := True + correction := True pc := predictionPcLoad.payload } } if(redo != null) when(redo.valid){ - corrected := True + correction := True pc := redo.payload flushed := True } when(jump.pcLoad.valid) { - corrected := True + correction := True pc := jump.pcLoad.payload flushed := True } - when(booted && (output.ready || corrected || pcRegPropagate)){ + when(booted && (output.ready || correction || pcRegPropagate)){ pcReg := pc } @@ -506,17 +509,36 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, case class BranchPredictorLine() extends Bundle{ val source = Bits(30 - historyRamSizeLog2 bits) val branchWish = UInt(2 bits) - val target = UInt(32 bits) val last2Bytes = ifGen(compressedGen)(Bool) + val target = UInt(32 bits) } val history = Mem(BranchPredictorLine(), 1 << historyRamSizeLog2) - val historyWrite = history.writePort + val historyWriteDelayPatched = history.writePort + val historyWrite = cloneOf(historyWriteDelayPatched) + historyWriteDelayPatched.valid := historyWrite.valid + historyWriteDelayPatched.address := (if(predictionBuffer) historyWrite.address - 1 else historyWrite.address) + historyWriteDelayPatched.data := historyWrite.data + + + val writeLast = RegNextWhen(historyWriteDelayPatched, iBusRsp.stages(0).output.ready) //Avoid write to read hazard - val historyWriteLast = RegNextWhen(historyWrite, iBusRsp.stages(0).output.ready) - val hazard = historyWriteLast.valid && historyWriteLast.address === (iBusRsp.stages(1).input.payload >> 2).resized - val line = history.readSync((iBusRsp.stages(0).input.payload >> 2).resized, iBusRsp.stages(0).output.ready) + val buffer = predictionBuffer generate new Area{ + val line = history.readSync((iBusRsp.stages(0).input.payload >> 2).resized, iBusRsp.stages(0).output.ready) + val pcCorrected = RegNextWhen(fetchPc.corrected, iBusRsp.stages(0).input.ready) + val hazard = (writeLast.valid && writeLast.address === (iBusRsp.stages(1).input.payload >> 2).resized) + } + + val (line, hazard) = predictionBuffer match { + case true => + (RegNextWhen(buffer.line, iBusRsp.stages(0).output.ready), + RegNextWhen(buffer.hazard, iBusRsp.stages(0).output.ready) || buffer.pcCorrected) + case false => + (history.readSync((iBusRsp.stages(0).input.payload >> 2).resized, + iBusRsp.stages(0).output.ready), writeLast.valid && writeLast.address === (iBusRsp.stages(1).input.payload >> 2).resized) + } + val hit = line.source === (iBusRsp.stages(1).input.payload.asBits >> 2 + historyRamSizeLog2) if(compressedGen) hit clearWhen(!line.last2Bytes && iBusRsp.stages(1).input.payload(1)) @@ -534,7 +556,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, fetchContext.hit := hit fetchContext.line := line - val (decompressorContext, decompressorContextOutput, injectorContext) = stage1ToInjectorPipe(fetchContext) + val (iBusRspContext, iBusRspContextOutput, injectorContext) = stage1ToInjectorPipe(fetchContext) object PREDICTION_CONTEXT extends Stageable(PredictionResult()) pipeline.decode.insert(PREDICTION_CONTEXT) := injectorContext @@ -567,7 +589,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, historyWrite.valid clearWhen(branchContext.hazard || !branchStage.arbitration.isFiring) val compressor = compressedGen generate new Area{ - val predictionBranch = decompressorContext.hit && !decompressorContext.hazard && decompressorContext.line.branchWish(1) + val predictionBranch = iBusRspContext.hit && !iBusRspContext.hazard && iBusRspContext.line.branchWish(1) val unalignedWordIssue = iBusRsp.output.valid && predictionBranch && decompressor.throw2Bytes && !decompressor.isInputHighRvc when(unalignedWordIssue){ @@ -579,13 +601,13 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, } //Do not trigger prediction hit when it is one for the upper RVC word and we aren't there yet - decompressorContextOutput.hit clearWhen(decompressorContext.line.last2Bytes && (decompressor.bufferValid || (!decompressor.throw2Bytes && decompressor.isInputLowRvc))) + iBusRspContextOutput.hit clearWhen(iBusRspContext.line.last2Bytes && (decompressor.bufferValid || (!decompressor.throw2Bytes && decompressor.isInputLowRvc))) decodePc.predictionPcLoad.valid := injectorContext.line.branchWish.msb && injectorContext.hit && !injectorContext.hazard && injector.decodeInput.fire decodePc.predictionPcLoad.payload := injectorContext.line.target //Clean the RVC buffer when a prediction was made - when(decompressorContext.line.branchWish.msb && decompressorContextOutput.hit && !decompressorContext.hazard && decompressor.output.fire){ + when(iBusRspContext.line.branchWish.msb && iBusRspContextOutput.hit && !iBusRspContext.hazard && decompressor.output.fire){ decompressor.bufferValid := False decompressor.throw2BytesReg := False decompressor.input.ready := True //Drop the remaining byte if any diff --git a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala index f018bb3b..1f59a33a 100644 --- a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala @@ -35,7 +35,8 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l, memoryTranslatorPortConfig : Any = null, injectorStage : Boolean = false, withoutInjectorStage : Boolean = false, - relaxPredictorAddress : Boolean = true) extends IBusFetcherImpl( + relaxPredictorAddress : Boolean = true, + predictionBuffer : Boolean = true) extends IBusFetcherImpl( resetVector = resetVector, keepPcPlus4 = keepPcPlus4, decodePcGen = compressedGen, @@ -47,7 +48,8 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l, historyRamSizeLog2 = historyRamSizeLog2, injectorStage = (!config.twoCycleCache && !withoutInjectorStage) || injectorStage, relaxPredictorAddress = relaxPredictorAddress, - fetchRedoGen = true){ + fetchRedoGen = true, + predictionBuffer = predictionBuffer){ import config._ assert(isPow2(cacheSize)) diff --git a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala index b2f1083a..56ad76f7 100644 --- a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala @@ -233,7 +233,8 @@ class IBusSimplePlugin( resetVector : BigInt, val rspHoldValue : Boolean = false, val singleInstructionPipeline : Boolean = false, val memoryTranslatorPortConfig : Any = null, - relaxPredictorAddress : Boolean = true + relaxPredictorAddress : Boolean = true, + predictionBuffer : Boolean = true ) extends IBusFetcherImpl( resetVector = resetVector, keepPcPlus4 = keepPcPlus4, @@ -246,7 +247,8 @@ class IBusSimplePlugin( resetVector : BigInt, historyRamSizeLog2 = historyRamSizeLog2, injectorStage = injectorStage, relaxPredictorAddress = relaxPredictorAddress, - fetchRedoGen = memoryTranslatorPortConfig != null){ + fetchRedoGen = memoryTranslatorPortConfig != null, + predictionBuffer = predictionBuffer){ var iBus : IBusSimpleBus = null var decodeExceptionPort : Flow[ExceptionCause] = null From 485b4a5838e1c9b0b5bd1c76b900dc85731012c8 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Sun, 23 Feb 2020 23:52:43 +0100 Subject: [PATCH 323/951] Improve maxPerf configs --- src/main/scala/vexriscv/demo/GenFullNoMmuMaxPerf.scala | 8 ++++---- src/main/scala/vexriscv/demo/GenNoCacheNoMmuMaxPerf.scala | 2 +- src/main/scala/vexriscv/demo/SynthesisBench.scala | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/scala/vexriscv/demo/GenFullNoMmuMaxPerf.scala b/src/main/scala/vexriscv/demo/GenFullNoMmuMaxPerf.scala index 28843d8c..6c892f04 100644 --- a/src/main/scala/vexriscv/demo/GenFullNoMmuMaxPerf.scala +++ b/src/main/scala/vexriscv/demo/GenFullNoMmuMaxPerf.scala @@ -20,7 +20,7 @@ object GenFullNoMmuMaxPerf extends App{ prediction = DYNAMIC_TARGET, historyRamSizeLog2 = 8, config = InstructionCacheConfig( - cacheSize = 4096*4, + cacheSize = 4096*2, bytePerLine =32, wayCount = 1, addressWidth = 32, @@ -29,13 +29,13 @@ object GenFullNoMmuMaxPerf extends App{ catchIllegalAccess = true, catchAccessFault = true, asyncTagMemory = false, - twoCycleRam = true, + twoCycleRam = false, twoCycleCache = true ) ), new DBusCachedPlugin( config = new DataCacheConfig( - cacheSize = 4096*4, + cacheSize = 4096*2, bytePerLine = 32, wayCount = 1, addressWidth = 32, @@ -76,7 +76,7 @@ object GenFullNoMmuMaxPerf extends App{ new CsrPlugin(CsrPluginConfig.small), new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))), new BranchPlugin( - earlyBranch = true, + earlyBranch = false, catchAddressMisaligned = true ), new YamlPlugin("cpu0.yaml") diff --git a/src/main/scala/vexriscv/demo/GenNoCacheNoMmuMaxPerf.scala b/src/main/scala/vexriscv/demo/GenNoCacheNoMmuMaxPerf.scala index 89dffe0b..9bca107e 100644 --- a/src/main/scala/vexriscv/demo/GenNoCacheNoMmuMaxPerf.scala +++ b/src/main/scala/vexriscv/demo/GenNoCacheNoMmuMaxPerf.scala @@ -56,7 +56,7 @@ object GenNoCacheNoMmuMaxPerf extends App{ new CsrPlugin(CsrPluginConfig.small), new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))), new BranchPlugin( - earlyBranch = true, + earlyBranch = false, catchAddressMisaligned = true ), new YamlPlugin("cpu0.yaml") diff --git a/src/main/scala/vexriscv/demo/SynthesisBench.scala b/src/main/scala/vexriscv/demo/SynthesisBench.scala index 503ef376..4df6f5e5 100644 --- a/src/main/scala/vexriscv/demo/SynthesisBench.scala +++ b/src/main/scala/vexriscv/demo/SynthesisBench.scala @@ -96,7 +96,7 @@ object VexRiscvSynthesisBench { } val full = new Rtl { - override def getName(): String = "VexRiscv full" + override def getName(): String = "VexRiscv full with MMU" override def getRtlPath(): String = "VexRiscvFull.v" SpinalVerilog(wrap(GenFull.cpu()).setDefinitionName(getRtlPath().split("\\.").head)) } From 999a868c1412796c0a230bc2802449055ece990a Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Mon, 24 Feb 2020 00:07:14 +0100 Subject: [PATCH 324/951] Update readme VexRiscv perf numbers --- README.md | 59 +++++++++++++++++++++++++++---------------------------- 1 file changed, 29 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index d0deb166..f60369bf 100644 --- a/README.md +++ b/README.md @@ -65,55 +65,54 @@ dhrystone binaries which fit inside a 4KB I$ and 4KB D$ (I already had this case The CPU configurations used below can be found in the `src/scala/vexriscv/demo` directory. ``` -VexRiscv smallest (RV32I, 0.52 DMIPS/Mhz, no datapath bypass, no interrupt) -> - Artix 7 -> 233 Mhz 494 LUT 505 FF - Cyclone V -> 193 Mhz 347 ALMs - Cyclone IV -> 179 Mhz 730 LUT 494 FF +VexRiscv small (RV32I, 0.52 DMIPS/Mhz, no datapath bypass, no interrupt) -> + Artix 7 -> 239 Mhz 494 LUT 505 FF + Cyclone V -> 189 Mhz 345 ALMs + Cyclone IV -> 179 Mhz 730 LUT 494 FF iCE40 -> 92 Mhz 1130 LC -VexRiscv smallest (RV32I, 0.52 DMIPS/Mhz, no datapath bypass) -> - Artix 7 -> 232 Mhz 538 LUT 562 FF - Cyclone V -> 189 Mhz 387 ALMs - Cyclone IV -> 175 Mhz 829 LUT 550 FF +VexRiscv small (RV32I, 0.52 DMIPS/Mhz, no datapath bypass) -> + Artix 7 -> 238 Mhz 552 LUT 562 FF + Cyclone V -> 192 Mhz 390 ALMs + Cyclone IV -> 172 Mhz 832 LUT 551 FF iCE40 -> 85 Mhz 1292 LC VexRiscv small and productive (RV32I, 0.82 DMIPS/Mhz) -> - Artix 7 -> 226 Mhz 689 LUT 531 FF - Cyclone V -> 145 Mhz 499 ALMs - Cyclone IV -> 150 Mhz 1,111 LUT 525 FF + Artix 7 -> 225 Mhz 699 LUT 532 FF + Cyclone V -> 144 Mhz 493 ALMs + Cyclone IV -> 148 Mhz 1,111 LUT 526 FF iCE40 -> 63 Mhz 1596 LC VexRiscv small and productive with I$ (RV32I, 0.70 DMIPS/Mhz, 4KB-I$) -> - Artix 7 -> 230 Mhz 734 LUT 564 FF + Artix 7 -> 225 Mhz 719 LUT 566 FF Cyclone V -> 145 Mhz 511 ALMs - Cyclone IV -> 144 Mhz 1,145 LUT 531 FF + Cyclone IV -> 150 Mhz 1,138 LUT 532 FF iCE40 -> 66 Mhz 1680 LC VexRiscv full no cache (RV32IM, 1.21 DMIPS/Mhz 2.30 Coremark/Mhz, single cycle barrel shifter, debug module, catch exceptions, static branch) -> - Artix 7 -> 219 Mhz 1537 LUT 977 FF - Cyclone V -> 139 Mhz 958 ALMs - Cyclone IV -> 135 Mhz 2,011 LUT 968 FF + Artix 7 -> 219 Mhz 1486 LUT 975 FF + Cyclone V -> 149 Mhz 943 ALMs + Cyclone IV -> 138 Mhz 2,013 LUT 966 FF VexRiscv full (RV32IM, 1.21 DMIPS/Mhz 2.30 Coremark/Mhz with cache trashing, 4KB-I$,4KB-D$, single cycle barrel shifter, debug module, catch exceptions, static branch) -> - Artix 7 -> 193 Mhz 1706 LUT 1172 FF - Cyclone V -> 144 Mhz 1,128 ALMs - Cyclone IV -> 133 Mhz 2,298 LUT 1,096 FF + Artix 7 -> 204 Mhz 1661 LUT 1172 FF + Cyclone V -> 143 Mhz 1,118 ALMs + Cyclone IV -> 133 Mhz 2,278 LUT 1,061 FF -VexRiscv full max dmips/mhz -> (RV32IM, 1.44 DMIPS/Mhz 2.70 Coremark/Mhz,, 16KB-I$,16KB-D$, single cycle barrel shifter, debug module, catch exceptions, dynamic branch prediction in the fetch stage, branch and shift operations done in the Execute stage) -> - Artix 7 -> 140 Mhz 1767 LUT 1128 FF - Cyclone V -> 90 Mhz 1,089 ALMs - Cyclone IV -> 79 Mhz 2,336 LUT 1,048 FF +VexRiscv full max perf (HZ*IPC) -> (RV32IM, 1.38 DMIPS/Mhz 2.57 Coremark/Mhz, 8KB-I$,8KB-D$, single cycle barrel shifter, debug module, catch exceptions, dynamic branch prediction in the fetch stage, branch and shift operations done in the Execute stage) -> + Artix 7 -> 199 Mhz 1739 LUT 1229 FF + Cyclone V -> 132 Mhz 1,129 ALMs + Cyclone IV -> 126 Mhz 2,345 LUT 1,114 FF VexRiscv full with MMU (RV32IM, 1.24 DMIPS/Mhz 2.35 Coremark/Mhz, with cache trashing, 4KB-I$, 4KB-D$, single cycle barrel shifter, debug module, catch exceptions, dynamic branch, MMU) -> - Artix 7 -> 161 Mhz 1985 LUT 1585 FF - Cyclone V -> 124 Mhz 1,319 ALMs - Cyclone IV -> 122 Mhz 2,710 LUT 1,501 FF + Artix 7 -> 167 Mhz 1927 LUT 1553 FF + Cyclone V -> 128 Mhz 1,302 ALMs + Cyclone IV -> 125 Mhz 2,685 LUT 1,466 FF VexRiscv linux balanced (RV32IMA, 1.21 DMIPS/Mhz 2.27 Coremark/Mhz, with cache trashing, 4KB-I$, 4KB-D$, single cycle barrel shifter, catch exceptions, static branch, MMU, Supervisor, Compatible with mainstream linux) -> - Artix 7 -> 170 Mhz 2530 LUT 2013 FF - Cyclone V -> 125 Mhz 1,618 ALMs - Cyclone IV -> 116 Mhz 3,314 LUT 2,016 FF - + Artix 7 -> 179 Mhz 2685 LUT 2177 FF + Cyclone V -> 136 Mhz 1,666 ALMs + Cyclone IV -> 123 Mhz 3,350 LUT 2,059 FF ``` The following configuration results in 1.44 DMIPS/MHz: From f88b259ebacb84624f2df3cfd14db56a5dd2ca4f Mon Sep 17 00:00:00 2001 From: Mateusz Holenko Date: Mon, 24 Feb 2020 12:43:35 +0100 Subject: [PATCH 325/951] emulator: Use external hw/common.h from LiteX Remove code copied from `hw/common.h` and use the header from the LiteX repository provided using `LITEX_BASE` environment variable. Content of `common.h` is now evolving (new functions are added, some are removed) and syncing it between repos would be cumbersome. --- src/main/c/emulator/makefile | 7 ++++--- src/main/c/emulator/src/hal.c | 32 -------------------------------- 2 files changed, 4 insertions(+), 35 deletions(-) diff --git a/src/main/c/emulator/makefile b/src/main/c/emulator/makefile index 7534d083..6f3c8fce 100755 --- a/src/main/c/emulator/makefile +++ b/src/main/c/emulator/makefile @@ -18,10 +18,11 @@ sim: all qemu: CFLAGS += -DQEMU qemu: all -litex: CFLAGS += -DLITEX -I${LITEX_BASE}/software/include -litex: | check_litex_base all -check_litex_base: +litex: CFLAGS += -DLITEX -I${LITEX_GENERATED} -I${LITEX_BASE}/litex/soc/software/include +litex: | check_litex all +check_litex: @[ "${LITEX_BASE}" ] || ( echo ">> LITEX_BASE is not set"; exit 1 ) + @[ "${LITEX_GENERATED}" ] || ( echo ">> LITEX_GENERATED is not set"; exit 1 ) include ${STANDALONE}/common/riscv64-unknown-elf.mk include ${STANDALONE}/common/standalone.mk diff --git a/src/main/c/emulator/src/hal.c b/src/main/c/emulator/src/hal.c index 5a151bb2..aa6745b9 100644 --- a/src/main/c/emulator/src/hal.c +++ b/src/main/c/emulator/src/hal.c @@ -146,38 +146,6 @@ void halInit(){ #ifdef LITEX -// this is copied from LiteX -#define CSR_ACCESSORS_DEFINED -static inline void csr_writeb(uint8_t value, unsigned long addr) -{ - *((volatile uint8_t *)addr) = value; -} - -static inline uint8_t csr_readb(unsigned long addr) -{ - return *(volatile uint8_t *)addr; -} - -static inline void csr_writew(uint16_t value, unsigned long addr) -{ - *((volatile uint16_t *)addr) = value; -} - -static inline uint16_t csr_readw(unsigned long addr) -{ - return *(volatile uint16_t *)addr; -} - -static inline void csr_writel(uint32_t value, unsigned long addr) -{ - *((volatile uint32_t *)addr) = value; -} - -static inline uint32_t csr_readl(unsigned long addr) -{ - return *(volatile uint32_t *)addr; -} - // this is a file generated by LiteX #include From 76d063f20ab94d6be2463b88861aef737cd79f1e Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Mon, 24 Feb 2020 22:43:08 +0100 Subject: [PATCH 326/951] Fix MulPlugin keep attribute --- src/main/scala/vexriscv/plugin/MulPlugin.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/MulPlugin.scala b/src/main/scala/vexriscv/plugin/MulPlugin.scala index efe3ba09..31714e82 100644 --- a/src/main/scala/vexriscv/plugin/MulPlugin.scala +++ b/src/main/scala/vexriscv/plugin/MulPlugin.scala @@ -98,8 +98,8 @@ class MulPlugin(inputBuffer : Boolean = false) extends Plugin[VexRiscv]{ Component.current.afterElaboration{ //Avoid synthesis tools to retime RS1 RS2 from execute stage to decode stage leading to bad timings (ex : Vivado, even if retiming is disabled) - KeepAttribute(input(RS1).getDrivingReg) - KeepAttribute(input(RS2).getDrivingReg) + KeepAttribute(input(RS1)) + KeepAttribute(input(RS2)) } } From 492310e6fa66e9d8a47a48ea6dc406fde961dcf8 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Fri, 28 Feb 2020 17:21:59 +0100 Subject: [PATCH 327/951] DBusCachedPlugin fix noWriteBack redo priority --- .../scala/vexriscv/plugin/DBusCachedPlugin.scala | 2 +- src/main/scala/vexriscv/plugin/Fetcher.scala | 4 ++-- .../scala/vexriscv/plugin/IBusSimplePlugin.scala | 2 +- .../scala/vexriscv/TestIndividualFeatures.scala | 14 ++++++++------ 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index f0eaa81a..fd45dd80 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -145,7 +145,7 @@ class DBusCachedPlugin(val config : DataCacheConfig, decoderService.add(FENCE, Nil) mmuBus = pipeline.service(classOf[MemoryTranslator]).newTranslationPort(MemoryTranslatorPort.PRIORITY_DATA ,memoryTranslatorPortConfig) - redoBranch = pipeline.service(classOf[JumpService]).createJumpInterface(if(pipeline.writeBack != null) pipeline.writeBack else pipeline.execute) + redoBranch = pipeline.service(classOf[JumpService]).createJumpInterface(if(pipeline.writeBack != null) pipeline.writeBack else pipeline.memory) if(catchSomething) exceptionBus = pipeline.service(classOf[ExceptionService]).newExceptionPort(if(pipeline.writeBack == null) pipeline.memory else pipeline.writeBack) diff --git a/src/main/scala/vexriscv/plugin/Fetcher.scala b/src/main/scala/vexriscv/plugin/Fetcher.scala index cac87891..8463238d 100644 --- a/src/main/scala/vexriscv/plugin/Fetcher.scala +++ b/src/main/scala/vexriscv/plugin/Fetcher.scala @@ -159,7 +159,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, } pc(0) := False - if(!pipeline(RVC_GEN)) pc(1) := False + if(!compressedGen) pc(1) := False output.valid := !fetcherHalt && booted output.payload := pc @@ -590,7 +590,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, val compressor = compressedGen generate new Area{ val predictionBranch = iBusRspContext.hit && !iBusRspContext.hazard && iBusRspContext.line.branchWish(1) - val unalignedWordIssue = iBusRsp.output.valid && predictionBranch && decompressor.throw2Bytes && !decompressor.isInputHighRvc + val unalignedWordIssue = iBusRsp.output.valid && predictionBranch && iBusRspContext.line.last2Bytes && Mux(decompressor.unaligned, !decompressor.isInputHighRvc, decompressor.isInputLowRvc && !decompressor.isInputHighRvc) when(unalignedWordIssue){ historyWrite.valid := True diff --git a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala index 56ad76f7..ed5cbb4d 100644 --- a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala @@ -343,7 +343,7 @@ class IBusSimplePlugin( resetVector : BigInt, //Manage flush for iBus transactions in flight val discardCounter = Reg(UInt(log2Up(pendingMax + 1) bits)) init (0) discardCounter := discardCounter - (iBus.rsp.fire && discardCounter =/= 0).asUInt - when(fetcherflushIt) { + when(iBusRsp.stages.last.flush) { if(secondStagePersistence) discardCounter := pendingCmd + cmd.valid.asUInt - iBus.rsp.fire.asUInt else diff --git a/src/test/scala/vexriscv/TestIndividualFeatures.scala b/src/test/scala/vexriscv/TestIndividualFeatures.scala index 7f00d1f6..3ed94a02 100644 --- a/src/test/scala/vexriscv/TestIndividualFeatures.scala +++ b/src/test/scala/vexriscv/TestIndividualFeatures.scala @@ -628,13 +628,15 @@ class TestIndividualFeatures extends FunSuite { } } - val testId : Option[mutable.HashSet[Int]] = None - val seed = sys.env.getOrElse("VEXRISCV_REGRESSION_SEED", Random.nextLong().toString).toLong -// + var testId : Option[mutable.HashSet[Int]] = None + var seed = sys.env.getOrElse("VEXRISCV_REGRESSION_SEED", Random.nextInt(1000000000).toString).toLong + // val testId = Some(mutable.HashSet(3,4,9,11,13,16,18,19,20,21)) -// val testId = Some(mutable.HashSet(11)) -// val testId = Some(mutable.HashSet(6)) -// val seed = 9095713085965080531l +// val testId = Some(mutable.HashSet(15)) +// seed = -7374992264756372315l +// testId = Some(mutable.HashSet(1,2,6,14,15,16,19)) +// testId = Some(mutable.HashSet(1,2,6,14)) +// testId = Some(mutable.HashSet(1)) val rand = new Random(seed) From c94d8f1c6c1896fd35e1e5779f69566a9f09bb28 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Fri, 28 Feb 2020 17:23:44 +0100 Subject: [PATCH 328/951] Fetcher and IBusSimplePlugin flush reworked --- src/main/scala/vexriscv/plugin/Fetcher.scala | 21 +++-- .../vexriscv/plugin/IBusCachedPlugin.scala | 2 +- .../vexriscv/plugin/IBusSimplePlugin.scala | 88 +++++++++---------- 3 files changed, 55 insertions(+), 56 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/Fetcher.scala b/src/main/scala/vexriscv/plugin/Fetcher.scala index 8463238d..1de5021a 100644 --- a/src/main/scala/vexriscv/plugin/Fetcher.scala +++ b/src/main/scala/vexriscv/plugin/Fetcher.scala @@ -93,10 +93,10 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, class FetchArea(pipeline : VexRiscv) extends Area { import pipeline._ import pipeline.config._ - val fetcherflushIt = stages.map(_.arbitration.flushNext).orR + val externalFlush = stages.map(_.arbitration.flushNext).orR def getFlushAt(s : Any, lastCond : Boolean = true): Bool = { - if(isDrivingDecode(s) && lastCond) pipeline.decode.arbitration.isRemoved else fetcherflushIt + if(isDrivingDecode(s) && lastCond) pipeline.decode.arbitration.isRemoved else externalFlush } //Arbitrate jump requests into pcLoad @@ -208,7 +208,6 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, val input = Stream(UInt(32 bits)) val output = Stream(UInt(32 bits)) val halt = Bool() - val flush = Bool() }) stages(0).input << fetchPc.output @@ -222,16 +221,16 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, fetchPc.redo.payload := stages.last.input.payload } - stages.head.flush := False //getFlushAt(IBUS_RSP, stages.head == stages.last) || fetchFlush + val flush = (if(isDrivingDecode(IBUS_RSP)) pipeline.decode.arbitration.isRemoved || decode.arbitration.flushNext && !decode.arbitration.isStuck else externalFlush) || redoFetch for((s,sNext) <- (stages, stages.tail).zipped) { - val discardInputOnFlush = s != stages.head - sNext.flush := getFlushAt(IBUS_RSP, sNext == stages.last) || redoFetch + val sFlushed = if(s != stages.head) flush else False + val sNextFlushed = flush if(s == stages.head && pcRegReusedForSecondStage) { - sNext.input.arbitrationFrom(s.output.toEvent().m2sPipeWithFlush(sNext.flush, false, collapsBubble = false, flushInput = s.flush)) + sNext.input.arbitrationFrom(s.output.toEvent().m2sPipeWithFlush(sNextFlushed, false, collapsBubble = false, flushInput = sFlushed)) sNext.input.payload := fetchPc.pcReg fetchPc.pcRegPropagate setWhen(sNext.input.ready) } else { - sNext.input << s.output.m2sPipeWithFlush(sNext.flush, false, collapsBubble = false, flushInput = s.flush) + sNext.input << s.output.m2sPipeWithFlush(sNextFlushed, false, collapsBubble = false, flushInput = sFlushed) } } @@ -294,14 +293,14 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, def condApply[T](that : T, cond : Boolean)(func : (T) => T) = if(cond)func(that) else that val injector = new Area { - val inputBeforeStage = condApply(if (decodePcGen) decompressor.output else iBusRsp.output, injectorReadyCutGen)(_.s2mPipe(fetcherflushIt)) + val inputBeforeStage = condApply(if (decodePcGen) decompressor.output else iBusRsp.output, injectorReadyCutGen)(_.s2mPipe(externalFlush)) if (injectorReadyCutGen) { iBusRsp.readyForError.clearWhen(inputBeforeStage.valid) //Can't emit error if there is a instruction pending in the s2mPipe incomingInstruction setWhen (inputBeforeStage.valid) } val decodeInput = (if (injectorStage) { val flushStage = getFlushAt(INJECTOR_M2S) - val decodeInput = inputBeforeStage.m2sPipeWithFlush(flushStage, false, collapsBubble = false, flushInput = fetcherflushIt) + val decodeInput = inputBeforeStage.m2sPipeWithFlush(flushStage, false, collapsBubble = false, flushInput = externalFlush) decode.insert(INSTRUCTION_ANTICIPATED) := Mux(decode.arbitration.isStuck, decode.input(INSTRUCTION), inputBeforeStage.rsp.inst) iBusRsp.readyForError.clearWhen(decodeInput.valid) //Can't emit error when there is a instruction pending in the injector stage buffer incomingInstruction setWhen (decodeInput.valid) @@ -458,7 +457,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, } val fetchContext = DynamicContext() fetchContext.hazard := hazard - fetchContext.line := historyCache.readSync((fetchPc.output.payload >> 2).resized, iBusRsp.stages(0).output.ready || fetcherflushIt) + fetchContext.line := historyCache.readSync((fetchPc.output.payload >> 2).resized, iBusRsp.stages(0).output.ready || externalFlush) object PREDICTION_CONTEXT extends Stageable(DynamicContext()) decode.insert(PREDICTION_CONTEXT) := stage1ToInjectorPipe(fetchContext)._3 diff --git a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala index 1f59a33a..642fcbb5 100644 --- a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala @@ -156,7 +156,7 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l, stages(0).halt setWhen (cache.io.cpu.prefetch.haltIt) - cache.io.cpu.fetch.isRemoved := fetcherflushIt + cache.io.cpu.fetch.isRemoved := externalFlush } diff --git a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala index ed5cbb4d..b8bc9782 100644 --- a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala @@ -255,7 +255,9 @@ class IBusSimplePlugin( resetVector : BigInt, val catchSomething = memoryTranslatorPortConfig != null || catchAccessFault var mmuBus : MemoryTranslatorBus = null - if(rspHoldValue) assert(busLatencyMin <= 1) +// if(rspHoldValue) assert(busLatencyMin <= 1) + assert(!rspHoldValue, "rspHoldValue not supported yet") + assert(!singleInstructionPipeline) override def setup(pipeline: VexRiscv): Unit = { super.setup(pipeline) @@ -283,9 +285,12 @@ class IBusSimplePlugin( resetVector : BigInt, iBus.cmd << (if(cmdWithS2mPipe) cmd.s2mPipe() else cmd) //Avoid sending to many iBus cmd - val pendingCmd = Reg(UInt(log2Up(pendingMax + 1) bits)) init (0) - val pendingCmdNext = pendingCmd + cmd.fire.asUInt - iBus.rsp.fire.asUInt - pendingCmd := pendingCmdNext + val pending = new Area{ + val inc, dec = Bool() + val value = Reg(UInt(log2Up(pendingMax + 1) bits)) init (0) + val next = value + U(inc) - U(dec) + value := next + } val secondStagePersistence = cmdForkPersistence && cmdForkOnSecondStage && !cmdWithS2mPipe def cmdForkStage = if(!secondStagePersistence) iBusRsp.stages(if(cmdForkOnSecondStage) 1 else 0) else iBusRsp.stages(1) @@ -293,29 +298,30 @@ class IBusSimplePlugin( resetVector : BigInt, val cmdFork = if(!secondStagePersistence) new Area { //This implementation keep the cmd on the bus until it's executed or the the pipeline is flushed def stage = cmdForkStage - stage.halt setWhen(stage.input.valid && (!cmd.valid || !cmd.ready)) - if(singleInstructionPipeline) { - cmd.valid := stage.input.valid && pendingCmd =/= pendingMax && !stages.map(_.arbitration.isValid).orR - assert(injectorStage == false) - assert(iBusRsp.stages.dropWhile(_ != stage).length <= 2) - }else { - cmd.valid := stage.input.valid && stage.output.ready && pendingCmd =/= pendingMax - } + val canEmit = stage.output.ready && pending.value =/= pendingMax + stage.halt setWhen(stage.input.valid && (!canEmit || !cmd.ready)) + cmd.valid := stage.input.valid && canEmit + pending.inc := cmd.fire } else new Area{ //This implementation keep the cmd on the bus until it's executed, even if the pipeline is flushed def stage = cmdForkStage - val pendingFull = pendingCmd === pendingMax - val cmdKeep = RegInit(False) setWhen(cmd.valid) clearWhen(cmd.ready) + val pendingFull = pending.value === pendingMax + val enterTheMarket = Bool() + val cmdKeep = RegInit(False) setWhen(enterTheMarket) clearWhen(cmd.ready) val cmdFired = RegInit(False) setWhen(cmd.fire) clearWhen(stage.input.ready) - stage.halt setWhen(cmd.isStall || (pendingFull && !cmdFired)) - cmd.valid := (stage.input.valid || cmdKeep) && !pendingFull && !cmdFired + enterTheMarket := stage.input.valid && !pendingFull && !cmdFired && !cmdKeep +// stage.halt setWhen(cmd.isStall || (pendingFull && !cmdFired)) //(cmd.isStall) + stage.halt setWhen(pendingFull && !cmdFired && !cmdKeep) + stage.halt setWhen(!cmd.ready && !cmdFired) + cmd.valid := enterTheMarket || cmdKeep + pending.inc := enterTheMarket } val mmu = (mmuBus != null) generate new Area { mmuBus.cmd.isValid := cmdForkStage.input.valid mmuBus.cmd.virtualAddress := cmdForkStage.input.payload mmuBus.cmd.bypassTranslation := False - mmuBus.end := cmdForkStage.output.fire || fetcherflushIt + mmuBus.end := cmdForkStage.output.fire || externalFlush cmd.pc := mmuBus.rsp.physicalAddress(31 downto 2) @@ U"00" @@ -341,43 +347,37 @@ class IBusSimplePlugin( resetVector : BigInt, val rspJoin = new Area { import iBusRsp._ //Manage flush for iBus transactions in flight - val discardCounter = Reg(UInt(log2Up(pendingMax + 1) bits)) init (0) - discardCounter := discardCounter - (iBus.rsp.fire && discardCounter =/= 0).asUInt - when(iBusRsp.stages.last.flush) { - if(secondStagePersistence) - discardCounter := pendingCmd + cmd.valid.asUInt - iBus.rsp.fire.asUInt - else - discardCounter := (if(cmdForkOnSecondStage) pendingCmdNext else pendingCmd - iBus.rsp.fire.asUInt) - } - - val rspBufferOutput = Stream(IBusSimpleRsp()) - - val rspBuffer = if(!rspHoldValue) new Area{ + val rspBuffer = new Area { + val output = Stream(IBusSimpleRsp()) val c = StreamFifoLowLatency(IBusSimpleRsp(), busLatencyMin + (if(cmdForkOnSecondStage && cmdForkPersistence) 1 else 0)) - c.io.push << iBus.rsp.throwWhen(discardCounter =/= 0).toStream - c.io.flush := iBusRsp.stages.last.flush - if(compressedGen) c.io.flush setWhen(decompressor.consumeCurrent) - if(!compressedGen && isDrivingDecode(IBUS_RSP)) c.io.flush setWhen(decode.arbitration.flushNext && iBusRsp.output.ready) - rspBufferOutput << c.io.pop - } else new Area{ - val rspStream = iBus.rsp.throwWhen(discardCounter =/= 0).toStream - val validReg = RegInit(False) setWhen(rspStream.valid) clearWhen(rspBufferOutput.ready) - rspBufferOutput << rspStream - rspBufferOutput.valid setWhen(validReg) + val discardCounter = Reg(UInt(log2Up(pendingMax + 1) bits)) init (0) + discardCounter := discardCounter - (c.io.pop.valid && discardCounter =/= 0).asUInt + when(iBusRsp.flush) { + discardCounter := (if(cmdForkOnSecondStage) pending.next else pending.value - U(pending.dec)) + } + + c.io.push << iBus.rsp.toStream +// if(compressedGen) c.io.flush setWhen(decompressor.consumeCurrent) +// if(!compressedGen && isDrivingDecode(IBUS_RSP)) c.io.flush setWhen(decode.arbitration.flushNext && iBusRsp.output.ready) + val flush = discardCounter =/= 0 || iBusRsp.flush + output.valid := c.io.pop.valid && discardCounter === 0 + output.payload := c.io.pop.payload + c.io.pop.ready := output.ready || flush + + pending.dec := c.io.pop.fire // iBus.rsp.valid && flush || c.io.pop.valid && output.ready instead to avoid unecessary dependancies ? } val fetchRsp = FetchRsp() fetchRsp.pc := stages.last.output.payload - fetchRsp.rsp := rspBufferOutput.payload - fetchRsp.rsp.error.clearWhen(!rspBufferOutput.valid) //Avoid interference with instruction injection from the debug plugin - + fetchRsp.rsp := rspBuffer.output.payload + fetchRsp.rsp.error.clearWhen(!rspBuffer.output.valid) //Avoid interference with instruction injection from the debug plugin val join = Stream(FetchRsp()) val exceptionDetected = False - join.valid := stages.last.output.valid && rspBufferOutput.valid + join.valid := stages.last.output.valid && rspBuffer.output.valid join.payload := fetchRsp stages.last.output.ready := stages.last.output.valid ? join.fire | join.ready - rspBufferOutput.ready := join.fire + rspBuffer.output.ready := join.fire output << join.haltWhen(exceptionDetected) if(memoryTranslatorPortConfig != null){ From 25d880f6c7f30fea5e6f3393eba9b2360ab71fa1 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Fri, 28 Feb 2020 18:20:08 +0100 Subject: [PATCH 329/951] Fix synthesis bench --- src/main/scala/vexriscv/demo/SynthesisBench.scala | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/scala/vexriscv/demo/SynthesisBench.scala b/src/main/scala/vexriscv/demo/SynthesisBench.scala index 4df6f5e5..91c1e5fb 100644 --- a/src/main/scala/vexriscv/demo/SynthesisBench.scala +++ b/src/main/scala/vexriscv/demo/SynthesisBench.scala @@ -4,8 +4,9 @@ import spinal.core._ import spinal.lib._ import spinal.lib.eda.bench._ import spinal.lib.eda.icestorm.IcestormStdTargets +import spinal.lib.io.InOutWrapper import vexriscv.VexRiscv -import vexriscv.plugin.{DecoderSimplePlugin} +import vexriscv.plugin.DecoderSimplePlugin import scala.collection.mutable.ArrayBuffer import scala.util.Random @@ -132,7 +133,7 @@ object BrieySynthesisBench { override def getName(): String = "Briey" override def getRtlPath(): String = "Briey.v" SpinalVerilog({ - val briey = new Briey(BrieyConfig.default).setDefinitionName(getRtlPath().split("\\.").head) + val briey = InOutWrapper(new Briey(BrieyConfig.default).setDefinitionName(getRtlPath().split("\\.").head)) briey.io.axiClk.setName("clk") briey }) @@ -161,7 +162,7 @@ object MuraxSynthesisBench { override def getName(): String = "Murax" override def getRtlPath(): String = "Murax.v" SpinalVerilog({ - val murax = new Murax(MuraxConfig.default.copy(gpioWidth = 8)).setDefinitionName(getRtlPath().split("\\.").head) + val murax = InOutWrapper(new Murax(MuraxConfig.default.copy(gpioWidth = 8)).setDefinitionName(getRtlPath().split("\\.").head)) murax.io.mainClk.setName("clk") murax }) @@ -172,7 +173,7 @@ object MuraxSynthesisBench { override def getName(): String = "MuraxFast" override def getRtlPath(): String = "MuraxFast.v" SpinalVerilog({ - val murax = new Murax(MuraxConfig.fast.copy(gpioWidth = 8)).setDefinitionName(getRtlPath().split("\\.").head) + val murax = InOutWrapper(new Murax(MuraxConfig.fast.copy(gpioWidth = 8)).setDefinitionName(getRtlPath().split("\\.").head)) murax.io.mainClk.setName("clk") murax }) From 0c7556ad7fc874e296805cad856434d00b536005 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sat, 29 Feb 2020 23:46:21 +0100 Subject: [PATCH 330/951] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 29d3ad22..830bd59d 100644 --- a/README.md +++ b/README.md @@ -153,7 +153,7 @@ unsetenv VERILATOR_ROOT # For csh; ignore error if on bash unset VERILATOR_ROOT # For bash cd verilator git pull # Make sure we're up-to-date -git checkout verilator_3_918 +git checkout v3.916 autoconf # Create ./configure script ./configure make From 559260020b4dda3c5532fc281ae302936ed6baa3 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sun, 1 Mar 2020 13:02:08 +0100 Subject: [PATCH 331/951] Improve testing infrastructure with more options and better readme https://github.com/litex-hub/linux-on-litex-vexriscv/issues/112 --- README.md | 45 ++++++++--- .../vexriscv/TestIndividualFeatures.scala | 76 +++++++++++-------- 2 files changed, 80 insertions(+), 41 deletions(-) diff --git a/README.md b/README.md index d0deb166..d76a040a 100644 --- a/README.md +++ b/README.md @@ -186,24 +186,47 @@ NOTES: [![Build Status](https://travis-ci.org/SpinalHDL/VexRiscv.svg?branch=master)](https://travis-ci.org/SpinalHDL/VexRiscv) -To run tests (need the verilator simulator), go in the src/test/cpp/regression folder and run : +To run tests (need the java, scala, verilator), just do : ```sh -# To test the GenFull CPU -# (Don't worry about the CSR test not passing, basicaly the GenFull isn't the truly full version of the CPU, some CSR features are disable in it) -make clean run - -# To test the GenSmallest CPU -make clean run IBUS=SIMPLE DBUS=SIMPLE CSR=no MMU=no DEBUG_PLUGIN=no MUL=no DIV=no +export VEXRISCV_REGRESSION_SEED=42 +export VEXRISCV_REGRESSION_TEST_ID= +sbt "testOnly vexriscv.TestIndividualFeatures" ``` -The self-test includes: -- ISA tests from https://github.com/riscv/riscv-tests/tree/master/isa +This will generate random VexRiscv configuration and test them with: +- ISA tests from https://github.com/riscv/riscv-tests/tree/master/isa and https://github.com/riscv/riscv-compliance - Dhrystone benchmark -- 24 FreeRTOS tests +- Coremark benchmark +- Zephyr os +- Buildroot/Linux os - Some handwritten tests to check the CSR, debug module and MMU plugins -You can enable FreeRTOS tests by adding `FREERTOS=yes` to the command line, but it will take time to run. Also, it uses THREAD_COUNT host CPU threads to run multiple regression in parallel. +You can rerun some specific test by setting VEXRISCV_REGRESSION_TEST_ID by their id. For instance, if you want to rerun : +- test_id_5_test_IBus_CachedS1024W1BPL32Relaxvexriscv.plugin.DYNAMIC_DBus_CachedS8192W2BPL16_MulDiv_MulDivFpga_Shift_FullLate_Branch_Late_Hazard_BypassAll_RegFile_SyncDR_Src__Csr_AllNoException_Decoder__Debug_None_DBus_NoMmu +- test_id_9_test_IBus_Simple1S2InjStagevexriscv.plugin.STATIC_DBus_SimpleLate_MulDiv_MulDivFpgaSimple_Shift_FullEarly_Branch_Late_Hazard_Interlock_RegFile_AsyncER_Src_AddSubExecute_Csr_None_Decoder__Debug_None_DBus_NoMmu + +then : + +``` +export VEXRISCV_REGRESSION_TEST_ID=5,9 +``` + +Also there is a few environnement variable that you can use to modulate the random generation : + +| Parameters | range | description | +| ------------------------------------------- | ------------------ | ----------- | +| VEXRISCV_REGRESSION_SEED | Int | Seed used to generate the random configurations | +| VEXRISCV_REGRESSION_TEST_ID | \[Int\[,\Int\]\*\] | Random configuration that should be keeped and tested | +| VEXRISCV_REGRESSION_CONFIG_COUNT | Int | Number of random configurations | +| VEXRISCV_REGRESSION_CONFIG_RVC_RATE | 0.0-1.0 | Chance to generate a RVC config | +| VEXRISCV_REGRESSION_CONFIG_LINUX_RATE | 0.0-1.0 | Chance to generate a linux ready config | +| VEXRISCV_REGRESSION_CONFIG_MACHINE_OS_RATE | 0.0-1.0 | Chance to generate a machine mode OS ready config | +| VEXRISCV_REGRESSION_LINUX_REGRESSION | yes/no | Enable the linux test | +| VEXRISCV_REGRESSION_COREMARK | yes/no | Enable the Coremark test | +| VEXRISCV_REGRESSION_ZEPHYR_COUNT | Int | Number of zephyr tests to run on capable configs | +| VEXRISCV_REGRESSION_CONFIG_DEMW_RATE | 0.0-1.0 | Chance to generate a config with writeback stage | +| VEXRISCV_REGRESSION_CONFIG_DEM_RATE | 0.0-1.0 | Chance to generate a config with memory stage | ## Interactive debug of the simulated CPU via GDB OpenOCD and Verilator It's as described to run tests, but you just have to add `DEBUG_PLUGIN_EXTERNAL=yes` in the make arguments. diff --git a/src/test/scala/vexriscv/TestIndividualFeatures.scala b/src/test/scala/vexriscv/TestIndividualFeatures.scala index 005f3359..6605cb54 100644 --- a/src/test/scala/vexriscv/TestIndividualFeatures.scala +++ b/src/test/scala/vexriscv/TestIndividualFeatures.scala @@ -3,7 +3,7 @@ package vexriscv import java.io.File import org.apache.commons.io.FileUtils -import org.scalatest.FunSuite +import org.scalatest.{BeforeAndAfterAll, FunSuite, ParallelTestExecution} import spinal.core._ import vexriscv.demo._ import vexriscv.ip.{DataCacheConfig, InstructionCacheConfig} @@ -313,7 +313,7 @@ class SrcDimension extends VexRiscvDimension("Src") { } -class IBusDimension extends VexRiscvDimension("IBus") { +class IBusDimension(rvcRate : Double) extends VexRiscvDimension("IBus") { override def randomPositionImpl(universes: Seq[ConfigUniverse], r: Random) = { @@ -322,7 +322,7 @@ class IBusDimension extends VexRiscvDimension("IBus") { if(r.nextDouble() < 0.5){ val latency = r.nextInt(5) + 1 - val compressed = r.nextBoolean() + val compressed = r.nextDouble() < rvcRate val injectorStage = r.nextBoolean() || latency == 1 val prediction = random(r, List(NONE, STATIC, DYNAMIC, DYNAMIC_TARGET)) val catchAll = universes.contains(VexRiscvUniverse.CATCH_ALL) @@ -345,7 +345,7 @@ class IBusDimension extends VexRiscvDimension("IBus") { } } else { val catchAll = universes.contains(VexRiscvUniverse.CATCH_ALL) - val compressed = r.nextBoolean() + val compressed = r.nextDouble() < rvcRate val tighlyCoupled = r.nextBoolean() && !catchAll // val tighlyCoupled = false val prediction = random(r, List(NONE, STATIC, DYNAMIC, DYNAMIC_TARGET)) @@ -497,14 +497,14 @@ class MmuDimension extends VexRiscvDimension("DBus") { trait CatchAllPosition -class CsrDimension(freertos : String, zephyr : String) extends VexRiscvDimension("Csr") { +class CsrDimension(freertos : String, zephyr : String, linux : String) extends VexRiscvDimension("Csr") { override def randomPositionImpl(universes: Seq[ConfigUniverse], r: Random) = { val catchAll = universes.contains(VexRiscvUniverse.CATCH_ALL) val supervisor = universes.contains(VexRiscvUniverse.SUPERVISOR) if(supervisor){ new VexRiscvPosition("Supervisor") with CatchAllPosition{ override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new CsrPlugin(CsrPluginConfig.linuxFull(0x80000020l)) - override def testParam = s"FREERTOS=$freertos ZEPHYR=$zephyr LINUX_REGRESSION=${sys.env.getOrElse("VEXRISCV_REGRESSION_LINUX_REGRESSION", "yes")} SUPERVISOR=yes" + override def testParam = s"FREERTOS=$freertos ZEPHYR=$zephyr LINUX_REGRESSION=$linux SUPERVISOR=yes" } } else if(catchAll){ new VexRiscvPosition("MachineOs") with CatchAllPosition{ @@ -554,10 +554,35 @@ class DecoderDimension extends VexRiscvDimension("Decoder") { } - +//class TesterPlay extends FunSuite with ParallelTestExecution { +// def createTest(name : String): Unit ={ +// test(name){ +// for(i <- 0 to 4) { +// println(s"$name $i") +// Thread.sleep(2000) +// } +// } +// } +// List("a", "b","c").foreach(createTest) +//} class TestIndividualFeatures extends FunSuite { + val testCount = sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_COUNT", "100").toInt + val seed = sys.env.getOrElse("VEXRISCV_REGRESSION_SEED", Random.nextLong().toString).toLong + val testId : Set[Int] = sys.env.get("VEXRISCV_REGRESSION_TEST_ID") match { + case Some(x) if x != "" => x.split(',').map(_.toInt).toSet + case _ => (0 until testCount).toSet + } + val rvcRate = sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_RVC_RATE", "0.5").toDouble + val linuxRate = sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_LINUX_RATE", "0.3").toDouble + val machineOsRate = sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_MACHINE_OS_RATE", "0.5").toDouble + val linuxRegression = sys.env.getOrElse("VEXRISCV_REGRESSION_LINUX_REGRESSION", "yes") + val coremarkRegression = sys.env.getOrElse("VEXRISCV_REGRESSION_COREMARK", "yes") + val zephyrCount = sys.env.getOrElse("VEXRISCV_REGRESSION_ZEPHYR_COUNT", "4") + val demwRate = sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_DEMW_RATE", "0.6").toDouble + val demRate = sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_DEM_RATE", "0.5").toDouble + def doCmd(cmd: String): String = { val stdOut = new StringBuilder() class Logger extends ProcessLogger { @@ -578,7 +603,7 @@ class TestIndividualFeatures extends FunSuite { val dimensions = List( - new IBusDimension, + new IBusDimension(rvcRate), new DBusDimension, new MulDivDimension, new ShiftDimension, @@ -586,7 +611,7 @@ class TestIndividualFeatures extends FunSuite { new HazardDimension, new RegFileDimension, new SrcDimension, - new CsrDimension(/*sys.env.getOrElse("VEXRISCV_REGRESSION_FREERTOS_COUNT", "1")*/ "0", sys.env.getOrElse("VEXRISCV_REGRESSION_ZEPHYR_COUNT", "4")), //Freertos old port software is broken + new CsrDimension(/*sys.env.getOrElse("VEXRISCV_REGRESSION_FREERTOS_COUNT", "1")*/ "0", zephyrCount, linuxRegression), //Freertos old port software is broken new DecoderDimension, new DebugDimension, new MmuDimension @@ -612,15 +637,15 @@ class TestIndividualFeatures extends FunSuite { } val name = (if(noMemory) "noMemoryStage_" else "") + (if(noWriteback) "noWritebackStage_" else "") + positionsToApply.map(d => d.dimension.name + "_" + d.name).mkString("_") - test(prefix + name + "_gen") { + test(prefix + "gen_" + name) { gen } - test(prefix + name + "_test") { + test(prefix + "test_" + name) { println("START TEST " + prefix + name) val debug = true - val stdCmd = (s"make clean run WITH_USER_IO=no REDO=10 TRACE=${if(debug) "yes" else "no"} TRACE_START=9999924910246l STOP_ON_ERROR=no FLOW_INFO=no STOP_ON_ERROR=no DHRYSTONE=yes COREMARK=${sys.env.getOrElse("VEXRISCV_REGRESSION_COREMARK", "yes")} THREAD_COUNT=${sys.env.getOrElse("VEXRISCV_REGRESSION_THREAD_COUNT", 1)} ") + s" SEED=${testSeed} " + val stdCmd = (s"make clean run WITH_USER_IO=no REDO=10 TRACE=${if(debug) "yes" else "no"} TRACE_START=1000000000000l STOP_ON_ERROR=no FLOW_INFO=no STOP_ON_ERROR=no DHRYSTONE=yes COREMARK=${coremarkRegression} THREAD_COUNT=1 ") + s" SEED=${testSeed} " val testCmd = stdCmd + (positionsToApply).map(_.testParam).mkString(" ") println(testCmd) val str = doCmd(testCmd) @@ -628,42 +653,33 @@ class TestIndividualFeatures extends FunSuite { } } - val testId : Option[mutable.HashSet[Int]] = None - val seed = sys.env.getOrElse("VEXRISCV_REGRESSION_SEED", Random.nextLong().toString).toLong -// -// val testId = Some(mutable.HashSet(3,4,9,11,13,16,18,19,20,21)) -// val testId = Some(mutable.HashSet(11)) -// val testId = Some(mutable.HashSet(4, 11)) -// val seed = 6592877339343561798l - - val rand = new Random(seed) test("Info"){ println(s"MAIN_SEED=$seed") } println(s"Seed=$seed") - for(i <- 0 until sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_COUNT", "100").toInt){ + for(i <- 0 until testCount){ var positions : List[VexRiscvPosition] = null var universe = mutable.HashSet[VexRiscvUniverse]() if(rand.nextDouble() < 0.5) universe += VexRiscvUniverse.EXECUTE_RF - if(sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_LINUX_RATE", "0.3").toDouble > rand.nextDouble()) { + if(linuxRate > rand.nextDouble()) { universe += VexRiscvUniverse.CATCH_ALL universe += VexRiscvUniverse.MMU universe += VexRiscvUniverse.FORCE_MULDIV universe += VexRiscvUniverse.SUPERVISOR - if(sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_DEMW_RATE", "0.6").toDouble < rand.nextDouble()){ + if(demwRate < rand.nextDouble()){ universe += VexRiscvUniverse.NO_WRITEBACK } } else { - if(sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_MACHINE_OS_RATE", "0.5").toDouble > rand.nextDouble()) { + if(machineOsRate > rand.nextDouble()) { universe += VexRiscvUniverse.CATCH_ALL - if(sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_DEMW_RATE", "0.6").toDouble < rand.nextDouble()){ + if(demwRate < rand.nextDouble()){ universe += VexRiscvUniverse.NO_WRITEBACK } } - if(sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_DEMW_RATE", "0.6").toDouble > rand.nextDouble()){ - }else if(sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_DEM_RATE", "0.5").toDouble > rand.nextDouble()){ + if(demwRate > rand.nextDouble()){ + }else if(demRate > rand.nextDouble()){ universe += VexRiscvUniverse.NO_WRITEBACK } else { universe += VexRiscvUniverse.NO_WRITEBACK @@ -676,8 +692,8 @@ class TestIndividualFeatures extends FunSuite { }while(!positions.forall(_.isCompatibleWith(positions))) val testSeed = rand.nextInt() - if(testId.isEmpty || testId.get.contains(i)) - doTest(positions," random_" + i + "_", testSeed, universe) + if(testId.contains(i)) + doTest(positions," test_id_" + i + "_", testSeed, universe) Hack.dCounter += 1 } } \ No newline at end of file From 02545b9beae0e1420d38f7b8001dde98f4585445 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sun, 1 Mar 2020 13:03:40 +0100 Subject: [PATCH 332/951] typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d76a040a..76f511b0 100644 --- a/README.md +++ b/README.md @@ -186,7 +186,7 @@ NOTES: [![Build Status](https://travis-ci.org/SpinalHDL/VexRiscv.svg?branch=master)](https://travis-ci.org/SpinalHDL/VexRiscv) -To run tests (need the java, scala, verilator), just do : +To run tests (need java, scala, verilator), just do : ```sh export VEXRISCV_REGRESSION_SEED=42 From ea5464ea26c4151b6218ac53ed6fc5bba4c96e77 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sun, 1 Mar 2020 21:40:53 +0100 Subject: [PATCH 333/951] TestIndividualFeatures is now multithreaded --- src/test/cpp/regression/main.cpp | 58 +++--- src/test/cpp/regression/makefile | 15 +- .../vexriscv/TestIndividualFeatures.scala | 166 +++++++++++++----- 3 files changed, 160 insertions(+), 79 deletions(-) diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 75f06bd9..d983e8e6 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -2805,7 +2805,7 @@ public: uint32_t regFileWriteRefIndex = 0; TestA() : WorkspaceRegression("testA") { - loadHex("../../resources/hex/testA.hex"); + loadHex(string(REGRESSION_PATH) + "../../resources/hex/testA.hex"); } virtual void checks(){ @@ -2831,7 +2831,7 @@ public: TestX28(string name, uint32_t *ref, uint32_t refSize) : WorkspaceRegression(name) { this->ref = ref; this->refSize = refSize; - loadHex("../../resources/hex/" + name + ".hex"); + loadHex(string(REGRESSION_PATH) + "../../resources/hex/" + name + ".hex"); } virtual void checks(){ @@ -2851,7 +2851,7 @@ public: class RiscvTest : public WorkspaceRegression{ public: RiscvTest(string name) : WorkspaceRegression(name) { - loadHex("../../resources/hex/" + name + ".hex"); + loadHex(string(REGRESSION_PATH) + "../../resources/hex/" + name + ".hex"); bootAt(0x800000bcu); } @@ -2899,7 +2899,7 @@ public: setIStall(iStall); setDStall(dStall); withRiscvRef(); - loadHex("../../resources/hex/" + hexName + ".hex"); + loadHex(string(REGRESSION_PATH) + "../../resources/hex/" + hexName + ".hex"); this->hexName = hexName; } @@ -2942,7 +2942,7 @@ public: int out32Counter = 0; Compliance(string name) : WorkspaceRegression(name) { withRiscvRef(); - loadHex("../../resources/hex/" + name + ".elf.hex"); + loadHex(string(REGRESSION_PATH) + "../../resources/hex/" + name + ".elf.hex"); out32.open (name + ".out32"); this->name = name; } @@ -2963,7 +2963,7 @@ public: virtual void pass(){ - FILE *refFile = fopen((string("../../resources/ref/") + name + ".reference_output").c_str(), "r"); + FILE *refFile = fopen((string(REGRESSION_PATH) + string("../../resources/ref/") + name + ".reference_output").c_str(), "r"); fseek(refFile, 0, SEEK_END); uint32_t refSize = ftell(refFile); fseek(refFile, 0, SEEK_SET); @@ -3152,7 +3152,7 @@ public: DebugPluginTest() : WorkspaceRegression("DebugPluginTest") { - loadHex("../../resources/hex/debugPlugin.hex"); + loadHex(string(REGRESSION_PATH) + "../../resources/hex/debugPlugin.hex"); pthread_create(&clientThreadId, NULL, &clientThreadWrapper, this); } @@ -3837,17 +3837,17 @@ int main(int argc, char **argv, char **env) { // #endif #ifdef IBUS_CACHED - redo(REDO,WorkspaceRegression("icache").withRiscvRef()->loadHex("../raw/icache/build/icache.hex")->bootAt(0x80000000u)->run(50e3);); + redo(REDO,WorkspaceRegression("icache").withRiscvRef()->loadHex(string(REGRESSION_PATH) + "../raw/icache/build/icache.hex")->bootAt(0x80000000u)->run(50e3);); #endif #ifdef DBUS_CACHED - redo(REDO,WorkspaceRegression("dcache").loadHex("../raw/dcache/build/dcache.hex")->bootAt(0x80000000u)->run(2500e3);); + redo(REDO,WorkspaceRegression("dcache").loadHex(string(REGRESSION_PATH) + "../raw/dcache/build/dcache.hex")->bootAt(0x80000000u)->run(2500e3);); #endif #ifdef MMU - redo(REDO,WorkspaceRegression("mmu").withRiscvRef()->loadHex("../raw/mmu/build/mmu.hex")->bootAt(0x80000000u)->run(50e3);); + redo(REDO,WorkspaceRegression("mmu").withRiscvRef()->loadHex(string(REGRESSION_PATH) + "../raw/mmu/build/mmu.hex")->bootAt(0x80000000u)->run(50e3);); #endif #ifdef SUPERVISOR - redo(REDO,WorkspaceRegression("deleg").withRiscvRef()->loadHex("../raw/deleg/build/deleg.hex")->bootAt(0x80000000u)->run(50e3);); + redo(REDO,WorkspaceRegression("deleg").withRiscvRef()->loadHex(string(REGRESSION_PATH) + "../raw/deleg/build/deleg.hex")->bootAt(0x80000000u)->run(50e3);); #endif #ifdef DEBUG_PLUGIN @@ -3858,20 +3858,20 @@ int main(int argc, char **argv, char **env) { #endif #ifdef CUSTOM_SIMD_ADD - redo(REDO,WorkspaceRegression("custom_simd_add").loadHex("../custom/simd_add/build/custom_simd_add.hex")->bootAt(0x00000000u)->run(50e3);); + redo(REDO,WorkspaceRegression("custom_simd_add").loadHex(string(REGRESSION_PATH) + "../custom/simd_add/build/custom_simd_add.hex")->bootAt(0x00000000u)->run(50e3);); #endif #ifdef CUSTOM_CSR - redo(REDO,WorkspaceRegression("custom_csr").loadHex("../custom/custom_csr/build/custom_csr.hex")->bootAt(0x00000000u)->run(50e3);); + redo(REDO,WorkspaceRegression("custom_csr").loadHex(string(REGRESSION_PATH) + "../custom/custom_csr/build/custom_csr.hex")->bootAt(0x00000000u)->run(50e3);); #endif #ifdef LRSC - redo(REDO,WorkspaceRegression("lrsc").withRiscvRef()->loadHex("../raw/lrsc/build/lrsc.hex")->bootAt(0x00000000u)->run(10e3);); + redo(REDO,WorkspaceRegression("lrsc").withRiscvRef()->loadHex(string(REGRESSION_PATH) + "../raw/lrsc/build/lrsc.hex")->bootAt(0x00000000u)->run(10e3);); #endif #ifdef AMO - redo(REDO,WorkspaceRegression("amo").withRiscvRef()->loadHex("../raw/amo/build/amo.hex")->bootAt(0x00000000u)->run(10e3);); + redo(REDO,WorkspaceRegression("amo").withRiscvRef()->loadHex(string(REGRESSION_PATH) + "../raw/amo/build/amo.hex")->bootAt(0x00000000u)->run(10e3);); #endif #ifdef DHRYSTONE @@ -3910,7 +3910,7 @@ int main(int argc, char **argv, char **env) { if(withStall == -1) break; #endif WorkspaceRegression("coremark_" + rv + (withStall > 0 ? "_stall" : "_nostall")).withRiscvRef() - ->loadBin("../../resources/bin/coremark_" + rv + ".bin", 0x80000000) + ->loadBin(string(REGRESSION_PATH) + "../../resources/bin/coremark_" + rv + ".bin", 0x80000000) ->bootAt(0x80000000) ->setIStall(withStall > 0) ->setDStall(withStall > 0) @@ -3930,17 +3930,17 @@ int main(int argc, char **argv, char **env) { /*for(int redo = 0;redo < 4;redo++)*/{ for(const string &name : freeRtosTests){ - tasks.push_back([=]() { WorkspaceRegression(name + "_rv32i_O0").withRiscvRef()->loadHex("../../resources/freertos/" + name + "_rv32i_O0.hex")->bootAt(0x80000000u)->run(4e6*15);}); - tasks.push_back([=]() { WorkspaceRegression(name + "_rv32i_O3").withRiscvRef()->loadHex("../../resources/freertos/" + name + "_rv32i_O3.hex")->bootAt(0x80000000u)->run(4e6*15);}); + tasks.push_back([=]() { WorkspaceRegression(name + "_rv32i_O0").withRiscvRef()->loadHex(string(REGRESSION_PATH) + "../../resources/freertos/" + name + "_rv32i_O0.hex")->bootAt(0x80000000u)->run(4e6*15);}); + tasks.push_back([=]() { WorkspaceRegression(name + "_rv32i_O3").withRiscvRef()->loadHex(string(REGRESSION_PATH) + "../../resources/freertos/" + name + "_rv32i_O3.hex")->bootAt(0x80000000u)->run(4e6*15);}); #ifdef COMPRESSED -// tasks.push_back([=]() { WorkspaceRegression(name + "_rv32ic_O0").withRiscvRef()->loadHex("../../resources/freertos/" + name + "_rv32ic_O0.hex")->bootAt(0x80000000u)->run(5e6*15);}); - tasks.push_back([=]() { WorkspaceRegression(name + "_rv32ic_O3").withRiscvRef()->loadHex("../../resources/freertos/" + name + "_rv32ic_O3.hex")->bootAt(0x80000000u)->run(4e6*15);}); +// tasks.push_back([=]() { WorkspaceRegression(name + "_rv32ic_O0").withRiscvRef()->loadHex(string(REGRESSION_PATH) + "../../resources/freertos/" + name + "_rv32ic_O0.hex")->bootAt(0x80000000u)->run(5e6*15);}); + tasks.push_back([=]() { WorkspaceRegression(name + "_rv32ic_O3").withRiscvRef()->loadHex(string(REGRESSION_PATH) + "../../resources/freertos/" + name + "_rv32ic_O3.hex")->bootAt(0x80000000u)->run(4e6*15);}); #endif #if defined(MUL) && defined(DIV) // #ifdef COMPRESSED -// tasks.push_back([=]() { WorkspaceRegression(name + "_rv32imac_O3").withRiscvRef()->loadHex("../../resources/freertos/" + name + "_rv32imac_O3.hex")->bootAt(0x80000000u)->run(4e6*15);}); +// tasks.push_back([=]() { WorkspaceRegression(name + "_rv32imac_O3").withRiscvRef()->loadHex(string(REGRESSION_PATH) + "../../resources/freertos/" + name + "_rv32imac_O3.hex")->bootAt(0x80000000u)->run(4e6*15);}); // #else - tasks.push_back([=]() { WorkspaceRegression(name + "_rv32im_O3").withRiscvRef()->loadHex("../../resources/freertos/" + name + "_rv32im_O3.hex")->bootAt(0x80000000u)->run(4e6*15);}); + tasks.push_back([=]() { WorkspaceRegression(name + "_rv32im_O3").withRiscvRef()->loadHex(string(REGRESSION_PATH) + "../../resources/freertos/" + name + "_rv32im_O3.hex")->bootAt(0x80000000u)->run(4e6*15);}); // #endif #endif } @@ -3967,12 +3967,12 @@ int main(int argc, char **argv, char **env) { /*for(int redo = 0;redo < 4;redo++)*/{ for(const string &name : zephyrTests){ #ifdef COMPRESSED - tasks.push_back([=]() { ZephyrRegression(name + "_rv32ic").withRiscvRef()->loadHex("../../resources/VexRiscvRegressionData/sim/zephyr/" + name + "_rv32ic.hex")->bootAt(0x80000000u)->run(180e6);}); + tasks.push_back([=]() { ZephyrRegression(name + "_rv32ic").withRiscvRef()->loadHex(string(REGRESSION_PATH) + "../../resources/VexRiscvRegressionData/sim/zephyr/" + name + "_rv32ic.hex")->bootAt(0x80000000u)->run(180e6);}); #else - tasks.push_back([=]() { ZephyrRegression(name + "_rv32i").withRiscvRef()->loadHex("../../resources/VexRiscvRegressionData/sim/zephyr/" + name + "_rv32i.hex")->bootAt(0x80000000u)->run(180e6);}); + tasks.push_back([=]() { ZephyrRegression(name + "_rv32i").withRiscvRef()->loadHex(string(REGRESSION_PATH) + "../../resources/VexRiscvRegressionData/sim/zephyr/" + name + "_rv32i.hex")->bootAt(0x80000000u)->run(180e6);}); #endif #if defined(MUL) && defined(DIV) - tasks.push_back([=]() { ZephyrRegression(name + "_rv32im").withRiscvRef()->loadHex("../../resources/VexRiscvRegressionData/sim/zephyr/" + name + "_rv32im.hex")->bootAt(0x80000000u)->run(180e6);}); + tasks.push_back([=]() { ZephyrRegression(name + "_rv32im").withRiscvRef()->loadHex(string(REGRESSION_PATH) + "../../resources/VexRiscvRegressionData/sim/zephyr/" + name + "_rv32im.hex")->bootAt(0x80000000u)->run(180e6);}); #endif } } @@ -3993,10 +3993,10 @@ int main(int argc, char **argv, char **env) { LinuxRegression soc("linux"); #ifndef DEBUG_PLUGIN_EXTERNAL soc.withRiscvRef(); - soc.loadBin(EMULATOR, 0x80000000); - soc.loadBin(VMLINUX, 0xC0000000); - soc.loadBin(DTB, 0xC3000000); - soc.loadBin(RAMDISK, 0xC2000000); + soc.loadBin(string(REGRESSION_PATH) + EMULATOR, 0x80000000); + soc.loadBin(string(REGRESSION_PATH) + VMLINUX, 0xC0000000); + soc.loadBin(string(REGRESSION_PATH) + DTB, 0xC3000000); + soc.loadBin(string(REGRESSION_PATH) + RAMDISK, 0xC2000000); #endif //soc.setIStall(true); //soc.setDStall(true); diff --git a/src/test/cpp/regression/makefile b/src/test/cpp/regression/makefile index ad057079..61fe9d17 100644 --- a/src/test/cpp/regression/makefile +++ b/src/test/cpp/regression/makefile @@ -1,5 +1,6 @@ DEBUG?=no - +REGRESSION_PATH?=./ +VEXRISCV_FILE?=../../../../VexRiscv.v IBUS?=CACHED IBUS_TC?=no DBUS?=CACHED @@ -38,6 +39,7 @@ STOP_ON_ERROR?=no COREMARK=no WITH_USER_IO?=no +ADDCFLAGS += -CFLAGS -DREGRESSION_PATH='\"$(REGRESSION_PATH)/\"' ADDCFLAGS += -CFLAGS -DIBUS_${IBUS} ADDCFLAGS += -CFLAGS -DDBUS_${DBUS} ADDCFLAGS += -CFLAGS -DREDO=${REDO} @@ -107,11 +109,11 @@ endif -ifneq ($(shell grep timerInterrupt ../../../../VexRiscv.v -w),) +ifneq ($(shell grep timerInterrupt ${VEXRISCV_FILE} -w),) ADDCFLAGS += -CFLAGS -DTIMER_INTERRUPT endif -ifneq ($(shell grep externalInterrupt ../../../../VexRiscv.v -w),) +ifneq ($(shell grep externalInterrupt ${VEXRISCV_FILE} -w),) ifneq ($(EXTERNAL_INTERRUPT),no) ADDCFLAGS += -CFLAGS -DEXTERNAL_INTERRUPT endif @@ -267,10 +269,9 @@ all: clean run run: compile ./obj_dir/VVexRiscv -verilate: ../../../../VexRiscv.v - rm -f VexRiscv.v*.bin - cp ../../../../VexRiscv.v*.bin . | true - verilator -cc ../../../../VexRiscv.v -O3 -CFLAGS -std=c++11 -LDFLAGS -pthread ${ADDCFLAGS} --gdbbt ${VERILATOR_ARGS} -Wno-UNOPTFLAT -Wno-WIDTH --x-assign unique --exe main.cpp +verilate: ${VEXRISCV_FILE} + cp ${VEXRISCV_FILE}*.bin . | true + verilator -cc ${VEXRISCV_FILE} -O3 -CFLAGS -std=c++11 -LDFLAGS -pthread ${ADDCFLAGS} --gdbbt ${VERILATOR_ARGS} -Wno-UNOPTFLAT -Wno-WIDTH --x-assign unique --exe main.cpp compile: verilate make -j${THREAD_COUNT} -C obj_dir/ -f VVexRiscv.mk VVexRiscv diff --git a/src/test/scala/vexriscv/TestIndividualFeatures.scala b/src/test/scala/vexriscv/TestIndividualFeatures.scala index 6605cb54..047c719b 100644 --- a/src/test/scala/vexriscv/TestIndividualFeatures.scala +++ b/src/test/scala/vexriscv/TestIndividualFeatures.scala @@ -1,9 +1,10 @@ package vexriscv -import java.io.File +import java.io.{File, OutputStream} +import java.util.concurrent.TimeUnit import org.apache.commons.io.FileUtils -import org.scalatest.{BeforeAndAfterAll, FunSuite, ParallelTestExecution} +import org.scalatest.{BeforeAndAfterAll, FunSuite, ParallelTestExecution, Tag, Transformer} import spinal.core._ import vexriscv.demo._ import vexriscv.ip.{DataCacheConfig, InstructionCacheConfig} @@ -11,6 +12,8 @@ import vexriscv.plugin._ import scala.collection.mutable import scala.collection.mutable.ArrayBuffer +import scala.concurrent.duration.Duration +import scala.concurrent.{Await, ExecutionContext, Future} import scala.sys.process._ import scala.util.Random @@ -534,6 +537,7 @@ class DebugDimension extends VexRiscvDimension("Debug") { }, new VexRiscvPosition("Enable") { override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))) + override def testParam = "CONCURRENT_OS_EXECUTIONS=yes" } )) } @@ -553,21 +557,80 @@ class DecoderDimension extends VexRiscvDimension("Decoder") { } } +object PlayFuture extends App{ + implicit val ec = ExecutionContext.global + val x = for(i <- 0 until 160) yield Future { + print(s"$i ") + Thread.sleep(1000) + } -//class TesterPlay extends FunSuite with ParallelTestExecution { -// def createTest(name : String): Unit ={ -// test(name){ -// for(i <- 0 to 4) { -// println(s"$name $i") -// Thread.sleep(2000) -// } -// } -// } -// List("a", "b","c").foreach(createTest) -//} + Thread.sleep(8000) +} + +class MultithreadedFunSuite extends FunSuite { + implicit val ec = ExecutionContext.global + class Job(body : => Unit){ + val originalOutput = Console.out + val buffer = mutable.Queue[Char]() + var bufferEnabled = true + def redirector() = new OutputStream{ + override def write(i: Int): Unit = synchronized { + if(bufferEnabled) buffer += i.toChar + else originalOutput.print(i.toChar) + } + } + val future = Future{ + Console.withOut(redirector()){ + Console.withErr(redirector())(body) + } + } + + def join(): Unit = { + Thread.sleep(50) + synchronized{ + bufferEnabled = false + buffer.foreach(originalOutput.print) + } + Await.result(future, Duration.Inf) + } + } + + override protected def test(testName: String, testTags: Tag*)(testFun: => Unit) { + val job = new Job(testFun) + super.test(testName, testTags :_*)(job.join()) + } + protected def testSingleThread(testName: String, testTags: Tag*)(testFun: => Unit) { + super.test(testName, testTags :_*)(testFun) + } +} -class TestIndividualFeatures extends FunSuite { +class FunTestPara extends MultithreadedFunSuite{ + def createTest(name : String): Unit ={ + test(name){ + for(i <- 0 to 4) { + println(s"$name $i") + Thread.sleep(500) + } + } + } + (0 to 80).map(_.toString).foreach(createTest) +} + +class FunTestPlay extends FunSuite { + def createTest(name : String): Unit ={ + test(name){ + Thread.sleep(500) + for(i <- 0 to 4) { + println(s"$name $i") + Thread.sleep(500) + } + } + } + (0 to 80).map(_.toString).foreach(createTest) +} + +class TestIndividualFeatures extends MultithreadedFunSuite { val testCount = sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_COUNT", "100").toInt val seed = sys.env.getOrElse("VEXRISCV_REGRESSION_SEED", Random.nextLong().toString).toLong val testId : Set[Int] = sys.env.get("VEXRISCV_REGRESSION_TEST_ID") match { @@ -582,24 +645,8 @@ class TestIndividualFeatures extends FunSuite { val zephyrCount = sys.env.getOrElse("VEXRISCV_REGRESSION_ZEPHYR_COUNT", "4") val demwRate = sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_DEMW_RATE", "0.6").toDouble val demRate = sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_DEM_RATE", "0.5").toDouble + val lock = new{} - def doCmd(cmd: String): String = { - val stdOut = new StringBuilder() - class Logger extends ProcessLogger { - override def err(s: => String): Unit = { - if (!s.startsWith("ar: creating ")) println(s) - } - - override def out(s: => String): Unit = { - println(s) - stdOut ++= s - } - - override def buffer[T](f: => T) = f - } - Process(cmd, new File("src/test/cpp/regression")).!(new Logger) - stdOut.toString() - } val dimensions = List( @@ -617,12 +664,40 @@ class TestIndividualFeatures extends FunSuite { new MmuDimension ) + var clockCounter = 0l + var startAt = System.currentTimeMillis() def doTest(positionsToApply : List[VexRiscvPosition], prefix : String = "", testSeed : Int, universes : mutable.HashSet[VexRiscvUniverse]): Unit ={ val noMemory = universes.contains(VexRiscvUniverse.NO_MEMORY) val noWriteback = universes.contains(VexRiscvUniverse.NO_WRITEBACK) - def gen = { + val name = (if(noMemory) "noMemoryStage_" else "") + (if(noWriteback) "noWritebackStage_" else "") + positionsToApply.map(d => d.dimension.name + "_" + d.name).mkString("_") + val workspace = "simWorkspace" + val project = s"$workspace/$prefix" + def doCmd(cmd: String): String = { + val stdOut = new StringBuilder() + class Logger extends ProcessLogger { + override def err(s: => String): Unit = { + if (!s.startsWith("ar: creating ")) println(s) + } + override def out(s: => String): Unit = { + println(s) + stdOut ++= s + } + override def buffer[T](f: => T) = f + } + Process(cmd, new File(project)).!(new Logger) + stdOut.toString() + } + + test(prefix + name) { + println("START TEST " + prefix + name) + + //Cleanup + FileUtils.deleteDirectory(new File(project)) + FileUtils.forceMkdir(new File(project)) + + //Generate RTL FileUtils.deleteQuietly(new File("VexRiscv.v")) - SpinalVerilog{ + SpinalConfig(targetDirectory = project).generateVerilog{ val config = VexRiscvConfig( withMemoryStage = !noMemory, withWriteBackStage = !noWriteback, @@ -634,22 +709,22 @@ class TestIndividualFeatures extends FunSuite { for (positionToApply <- positionsToApply) positionToApply.applyOn(config) new VexRiscv(config) } - } - val name = (if(noMemory) "noMemoryStage_" else "") + (if(noWriteback) "noWritebackStage_" else "") + positionsToApply.map(d => d.dimension.name + "_" + d.name).mkString("_") - test(prefix + "gen_" + name) { - gen - } + //Setup test + val files = List("main.cpp", "encoding.h" ,"makefile", "dhrystoneO3.logRef", "dhrystoneO3C.logRef","dhrystoneO3MC.logRef","dhrystoneO3M.logRef") + files.foreach(f => FileUtils.copyFileToDirectory(new File(s"src/test/cpp/regression/$f"), new File(project))) - - test(prefix + "test_" + name) { - println("START TEST " + prefix + name) + //Test RTL val debug = true - val stdCmd = (s"make clean run WITH_USER_IO=no REDO=10 TRACE=${if(debug) "yes" else "no"} TRACE_START=1000000000000l STOP_ON_ERROR=no FLOW_INFO=no STOP_ON_ERROR=no DHRYSTONE=yes COREMARK=${coremarkRegression} THREAD_COUNT=1 ") + s" SEED=${testSeed} " + val stdCmd = (s"make run REGRESSION_PATH=../../src/test/cpp/regression VEXRISCV_FILE=VexRiscv.v WITH_USER_IO=no REDO=10 TRACE=${if(debug) "yes" else "no"} TRACE_START=1000000000000l STOP_ON_ERROR=no FLOW_INFO=no STOP_ON_ERROR=no DHRYSTONE=yes COREMARK=${coremarkRegression} THREAD_COUNT=1 ") + s" SEED=${testSeed} " val testCmd = stdCmd + (positionsToApply).map(_.testParam).mkString(" ") println(testCmd) val str = doCmd(testCmd) assert(str.contains("REGRESSION SUCCESS") && !str.contains("Broken pipe")) + val pattern = "Had simulate ([0-9]+)".r + val hit = pattern.findFirstMatchIn(str) + + lock.synchronized(clockCounter += hit.get.group(1).toLong) } } @@ -693,7 +768,12 @@ class TestIndividualFeatures extends FunSuite { val testSeed = rand.nextInt() if(testId.contains(i)) - doTest(positions," test_id_" + i + "_", testSeed, universe) + doTest(positions,"test_id_" + i + "_", testSeed, universe) Hack.dCounter += 1 } + testSingleThread("report"){ + val time = (System.currentTimeMillis() - startAt)*1e-3 + val clockPerSecond = (clockCounter/time*1e-3).toLong + println(s"Duration=${(time/60).toInt}mn clocks=${(clockCounter*1e-6).toLong}M clockPerSecond=${clockPerSecond}K") + } } \ No newline at end of file From 54581f6d9e38d1d0d809588dfd752e69d06c8256 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 2 Mar 2020 14:23:26 +0100 Subject: [PATCH 334/951] Fix #117 DataCache mem blackboxing --- src/main/scala/vexriscv/ip/DataCache.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index eaed1d08..8e62bc7d 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -402,7 +402,7 @@ class DataCache(p : DataCacheConfig) extends Component{ //Writes when(tagsWriteCmd.valid && tagsWriteCmd.way(i)){ - tags(tagsWriteCmd.address) := tagsWriteCmd.data + tags.write(tagsWriteCmd.address, tagsWriteCmd.data) } when(dataWriteCmd.valid && dataWriteCmd.way(i)){ data.write( From ef5398ce2107a029f1ea1a51ac37a5119c2d7596 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 2 Mar 2020 14:23:26 +0100 Subject: [PATCH 335/951] Fix #117 DataCache mem blackboxing --- src/main/scala/vexriscv/ip/DataCache.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index eaed1d08..8e62bc7d 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -402,7 +402,7 @@ class DataCache(p : DataCacheConfig) extends Component{ //Writes when(tagsWriteCmd.valid && tagsWriteCmd.way(i)){ - tags(tagsWriteCmd.address) := tagsWriteCmd.data + tags.write(tagsWriteCmd.address, tagsWriteCmd.data) } when(dataWriteCmd.valid && dataWriteCmd.way(i)){ data.write( From fd37962a58c88cb3314e366a5d4b693df94418f6 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Tue, 3 Mar 2020 10:55:59 +0100 Subject: [PATCH 336/951] typo --- doc/smp/smp.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/smp/smp.md b/doc/smp/smp.md index c335f1fa..6fa67c63 100644 --- a/doc/smp/smp.md +++ b/doc/smp/smp.md @@ -52,6 +52,8 @@ Composed of 2 stream : ### Probe bus +Composed of 2 stream : + | Name | Direction | Description | |----------|-----------|----------| | probeCmd | M <- S | Used for cache management | @@ -98,7 +100,7 @@ Emitted on the readAck channel (master -> slave), it carry no information, just | Name | From command | Description | |--------------|---------------|----------| -| readSuccess | * | - | +| readSuccess | * | - | ### Write commands From 12463e40a46079167d226b56ed1969b3b43e117a Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 3 Mar 2020 15:59:30 +0100 Subject: [PATCH 337/951] improve debugPlugin step logic --- src/main/scala/vexriscv/plugin/DebugPlugin.scala | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/DebugPlugin.scala b/src/main/scala/vexriscv/plugin/DebugPlugin.scala index a1051d72..8c990f9b 100644 --- a/src/main/scala/vexriscv/plugin/DebugPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DebugPlugin.scala @@ -213,11 +213,14 @@ class DebugPlugin(val debugClockDomain : ClockDomain, hardwareBreakpointCount : iBusFetcher.haltIt() } - when(stepIt && iBusFetcher.incoming()) { - iBusFetcher.haltIt() + when(stepIt) { + //Assume nothing will stop the CPU in the decode stage when(decode.arbitration.isValid) { haltIt := True } + when(execute.arbitration.isValid) { + decode.arbitration.flushNext := True + } } //Avoid having two C instruction executed in a single step From ff5cfc0ddee98fe89bc1f4f23ac9b4cb748961ce Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 3 Mar 2020 18:27:53 +0100 Subject: [PATCH 338/951] Fix DebugPlugin step --- src/main/scala/vexriscv/plugin/DebugPlugin.scala | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/DebugPlugin.scala b/src/main/scala/vexriscv/plugin/DebugPlugin.scala index 8c990f9b..93e65e34 100644 --- a/src/main/scala/vexriscv/plugin/DebugPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DebugPlugin.scala @@ -217,8 +217,6 @@ class DebugPlugin(val debugClockDomain : ClockDomain, hardwareBreakpointCount : //Assume nothing will stop the CPU in the decode stage when(decode.arbitration.isValid) { haltIt := True - } - when(execute.arbitration.isValid) { decode.arbitration.flushNext := True } } From 0a212c91fdaa2509c07fe321576bfd1cf80c4de3 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 4 Mar 2020 18:13:56 +0100 Subject: [PATCH 339/951] update synthesisBench paths --- .../scala/vexriscv/demo/SynthesisBench.scala | 21 +++---------------- 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/src/main/scala/vexriscv/demo/SynthesisBench.scala b/src/main/scala/vexriscv/demo/SynthesisBench.scala index 91c1e5fb..ca925bf7 100644 --- a/src/main/scala/vexriscv/demo/SynthesisBench.scala +++ b/src/main/scala/vexriscv/demo/SynthesisBench.scala @@ -114,12 +114,7 @@ object VexRiscvSynthesisBench { // val rtls = List(smallAndProductive, smallAndProductiveWithICache, fullNoMmuMaxPerf, fullNoMmu, full) // val rtls = List(smallAndProductive) - val targets = XilinxStdTargets( - vivadoArtix7Path = "/media/miaou/HD/linux/Xilinx/Vivado/2018.3/bin" - ) ++ AlteraStdTargets( - quartusCycloneIVPath = "/media/miaou/HD/linux/intelFPGA_lite/18.1/quartus/bin", - quartusCycloneVPath = "/media/miaou/HD/linux/intelFPGA_lite/18.1/quartus/bin" - ) ++ IcestormStdTargets().take(1) + val targets = XilinxStdTargets() ++ AlteraStdTargets() ++ IcestormStdTargets().take(1) // val targets = IcestormStdTargets() Bench(rtls, targets, "/media/miaou/HD/linux/tmp/") @@ -142,12 +137,7 @@ object BrieySynthesisBench { val rtls = List(briey) - val targets = XilinxStdTargets( - vivadoArtix7Path = "/media/miaou/HD/linux/Xilinx/Vivado/2018.3/bin" - ) ++ AlteraStdTargets( - quartusCycloneIVPath = "/media/miaou/HD/linux/intelFPGA_lite/18.1/quartus/bin", - quartusCycloneVPath = "/media/miaou/HD/linux/intelFPGA_lite/18.1/quartus/bin" - ) + val targets = XilinxStdTargets() ++ AlteraStdTargets() ++ IcestormStdTargets().take(1) Bench(rtls, targets, "/media/miaou/HD/linux/tmp") } @@ -181,12 +171,7 @@ object MuraxSynthesisBench { val rtls = List(murax, muraxFast) - val targets = IcestormStdTargets().take(1) ++ XilinxStdTargets( - vivadoArtix7Path = "/media/miaou/HD/linux/Xilinx/Vivado/2018.3/bin" - ) ++ AlteraStdTargets( - quartusCycloneIVPath = "/media/miaou/HD/linux/intelFPGA_lite/18.1/quartus/bin", - quartusCycloneVPath = "/media/miaou/HD/linux/intelFPGA_lite/18.1/quartus/bin" - ) + val targets = XilinxStdTargets() ++ AlteraStdTargets() ++ IcestormStdTargets().take(1) Bench(rtls, targets, "/media/miaou/HD/linux/tmp") } From 505d0b700a3897ddbb4a6d3c60d449d796d80730 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Wed, 4 Mar 2020 19:58:50 +0100 Subject: [PATCH 340/951] MulDivPlugin now give names to div stages --- src/main/scala/vexriscv/plugin/MulDivIterativePlugin.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/MulDivIterativePlugin.scala b/src/main/scala/vexriscv/plugin/MulDivIterativePlugin.scala index eafa4daa..da3738d7 100644 --- a/src/main/scala/vexriscv/plugin/MulDivIterativePlugin.scala +++ b/src/main/scala/vexriscv/plugin/MulDivIterativePlugin.scala @@ -108,7 +108,7 @@ class MulDivIterativePlugin(genMul : Boolean = true, val div = ifGen(genDiv) (new Area{ assert(isPow2(divUnrollFactor)) - + def area = this //register allocation def numerator = rs1(31 downto 0) def denominator = rs2 @@ -130,13 +130,13 @@ class MulDivIterativePlugin(genMul : Boolean = true, numerator := inNumerator remainder := inRemainder } - case _ => { + case _ => new Area { val remainderShifted = (inRemainder ## inNumerator.msb).asUInt val remainderMinusDenominator = remainderShifted - denominator val outRemainder = !remainderMinusDenominator.msb ? remainderMinusDenominator.resize(32 bits) | remainderShifted.resize(32 bits) val outNumerator = (inNumerator ## !remainderMinusDenominator.msb).asUInt.resize(32 bits) stages(outNumerator, outRemainder, stage - 1) - } + }.setCompositeName(area, "stage_" + (divUnrollFactor-stage)) } stages(numerator, remainder, divUnrollFactor) From 50ec0a1917293a5de2b0a3f2469f80583fb136f8 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Thu, 5 Mar 2020 00:12:46 +0100 Subject: [PATCH 341/951] update readme perf --- README.md | 54 +++++++++++++++++++++++++++--------------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index a8f8cc97..dd90af3d 100644 --- a/README.md +++ b/README.md @@ -66,53 +66,53 @@ The CPU configurations used below can be found in the `src/scala/vexriscv/demo` ``` VexRiscv small (RV32I, 0.52 DMIPS/Mhz, no datapath bypass, no interrupt) -> - Artix 7 -> 239 Mhz 494 LUT 505 FF - Cyclone V -> 189 Mhz 345 ALMs - Cyclone IV -> 179 Mhz 730 LUT 494 FF + Artix 7 -> 253 Mhz 498 LUT 505 FF + Cyclone V -> 205 Mhz 350 ALMs + Cyclone IV -> 172 Mhz 731 LUT 494 FF iCE40 -> 92 Mhz 1130 LC VexRiscv small (RV32I, 0.52 DMIPS/Mhz, no datapath bypass) -> - Artix 7 -> 238 Mhz 552 LUT 562 FF - Cyclone V -> 192 Mhz 390 ALMs - Cyclone IV -> 172 Mhz 832 LUT 551 FF + Artix 7 -> 225 Mhz 549 LUT 563 FF + Cyclone V -> 194 Mhz 392 ALMs + Cyclone IV -> 172 Mhz 830 LUT 551 FF iCE40 -> 85 Mhz 1292 LC VexRiscv small and productive (RV32I, 0.82 DMIPS/Mhz) -> - Artix 7 -> 225 Mhz 699 LUT 532 FF - Cyclone V -> 144 Mhz 493 ALMs - Cyclone IV -> 148 Mhz 1,111 LUT 526 FF + Artix 7 -> 213 Mhz 787 LUT 531 FF + Cyclone V -> 150 Mhz 487 ALMs + Cyclone IV -> 151 Mhz 1,115 LUT 526 FF iCE40 -> 63 Mhz 1596 LC VexRiscv small and productive with I$ (RV32I, 0.70 DMIPS/Mhz, 4KB-I$) -> - Artix 7 -> 225 Mhz 719 LUT 566 FF - Cyclone V -> 145 Mhz 511 ALMs - Cyclone IV -> 150 Mhz 1,138 LUT 532 FF + Artix 7 -> 220 Mhz 719 LUT 570 FF + Cyclone V -> 147 Mhz 516 ALMs + Cyclone IV -> 144 Mhz 1,139 LUT 532 FF iCE40 -> 66 Mhz 1680 LC VexRiscv full no cache (RV32IM, 1.21 DMIPS/Mhz 2.30 Coremark/Mhz, single cycle barrel shifter, debug module, catch exceptions, static branch) -> - Artix 7 -> 219 Mhz 1486 LUT 975 FF - Cyclone V -> 149 Mhz 943 ALMs - Cyclone IV -> 138 Mhz 2,013 LUT 966 FF + Artix 7 -> 210 Mhz 1410 LUT 975 FF + Cyclone V -> 144 Mhz 927 ALMs + Cyclone IV -> 141 Mhz 2,074 LUT 966 FF VexRiscv full (RV32IM, 1.21 DMIPS/Mhz 2.30 Coremark/Mhz with cache trashing, 4KB-I$,4KB-D$, single cycle barrel shifter, debug module, catch exceptions, static branch) -> - Artix 7 -> 204 Mhz 1661 LUT 1172 FF - Cyclone V -> 143 Mhz 1,118 ALMs - Cyclone IV -> 133 Mhz 2,278 LUT 1,061 FF + Artix 7 -> 199 Mhz 1736 LUT 1120 FF + Cyclone V -> 137 Mhz 1,177 ALMs + Cyclone IV -> 142 Mhz 2,409 LUT 1,061 FF VexRiscv full max perf (HZ*IPC) -> (RV32IM, 1.38 DMIPS/Mhz 2.57 Coremark/Mhz, 8KB-I$,8KB-D$, single cycle barrel shifter, debug module, catch exceptions, dynamic branch prediction in the fetch stage, branch and shift operations done in the Execute stage) -> - Artix 7 -> 199 Mhz 1739 LUT 1229 FF - Cyclone V -> 132 Mhz 1,129 ALMs - Cyclone IV -> 126 Mhz 2,345 LUT 1,114 FF + Artix 7 -> 197 Mhz 1788 LUT 1210 FF + Cyclone V -> 130 Mhz 1,173 ALMs + Cyclone IV -> 124 Mhz 2,483 LUT 1,114 FF VexRiscv full with MMU (RV32IM, 1.24 DMIPS/Mhz 2.35 Coremark/Mhz, with cache trashing, 4KB-I$, 4KB-D$, single cycle barrel shifter, debug module, catch exceptions, dynamic branch, MMU) -> - Artix 7 -> 167 Mhz 1927 LUT 1553 FF - Cyclone V -> 128 Mhz 1,302 ALMs - Cyclone IV -> 125 Mhz 2,685 LUT 1,466 FF + Artix 7 -> 164 Mhz 2000 LUT 1501 FF + Cyclone V -> 125 Mhz 1,375 ALMs + Cyclone IV -> 121 Mhz 2,821 LUT 1,444 FF VexRiscv linux balanced (RV32IMA, 1.21 DMIPS/Mhz 2.27 Coremark/Mhz, with cache trashing, 4KB-I$, 4KB-D$, single cycle barrel shifter, catch exceptions, static branch, MMU, Supervisor, Compatible with mainstream linux) -> - Artix 7 -> 179 Mhz 2685 LUT 2177 FF - Cyclone V -> 136 Mhz 1,666 ALMs - Cyclone IV -> 123 Mhz 3,350 LUT 2,059 FF + Artix 7 -> 176 Mhz 2678 LUT 2087 FF + Cyclone V -> 137 Mhz 1,797 ALMs + Cyclone IV -> 120 Mhz 3,544 LUT 2,059 FF ``` The following configuration results in 1.44 DMIPS/MHz: From 58af94269e0c634a9f4232abc3e73122b38a2901 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Thu, 5 Mar 2020 00:13:04 +0100 Subject: [PATCH 342/951] add CsrPlugin.csrOhDecoder --- .../scala/vexriscv/plugin/CsrPlugin.scala | 117 ++++++++++++------ 1 file changed, 76 insertions(+), 41 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 6e0c41b4..0cdc8968 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -69,6 +69,7 @@ case class CsrPluginConfig( midelegAccess : CsrAccess = CsrAccess.NONE, pipelineCsrRead : Boolean = false, pipelinedInterrupt : Boolean = true, + csrOhDecoder : Boolean = true, deterministicInteruptionEntry : Boolean = false, //Only used for simulatation purposes wfiOutput : Boolean = false ){ @@ -263,7 +264,7 @@ case class CsrReadToWriteOverride(that : Data, bitOffset : Int) //Used for speci case class CsrOnWrite(doThat :() => Unit) case class CsrOnRead(doThat : () => Unit) case class CsrMapping() extends CsrInterface{ - val mapping = mutable.HashMap[Int,ArrayBuffer[Any]]() + val mapping = mutable.LinkedHashMap[Int,ArrayBuffer[Any]]() def addMappingAt(address : Int,that : Any) = mapping.getOrElseUpdate(address,new ArrayBuffer[Any]) += that override def r(csrAddress : Int, bitOffset : Int, that : Data): Unit = addMappingAt(csrAddress, CsrRead(that,bitOffset)) override def w(csrAddress : Int, bitOffset : Int, that : Data): Unit = addMappingAt(csrAddress, CsrWrite(that,bitOffset)) @@ -997,7 +998,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep val imm = IMM(input(INSTRUCTION)) def writeSrc = input(SRC1) // val readDataValid = True - val readData = B(0, 32 bits) + val readData = Bits(32 bits) val writeInstruction = arbitration.isValid && input(IS_CSR) && input(CSR_WRITE_OPCODE) val readInstruction = arbitration.isValid && input(IS_CSR) && input(CSR_READ_OPCODE) val writeEnable = writeInstruction && ! blockedBySideEffects && !arbitration.isStuckByOthers// && readDataRegValid @@ -1043,50 +1044,84 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep //Translation of the csrMapping into real logic val csrAddress = input(INSTRUCTION)(csrRange) - Component.current.addPrePopTask(() => { - switch(csrAddress) { - for ((address, jobs) <- csrMapping.mapping) { - is(address) { - val withWrite = jobs.exists(j => j.isInstanceOf[CsrWrite] || j.isInstanceOf[CsrOnWrite]) - val withRead = jobs.exists(j => j.isInstanceOf[CsrRead] || j.isInstanceOf[CsrOnRead]) - if(withRead && withWrite) { - illegalAccess := False - } else { - if (withWrite) illegalAccess.clearWhen(input(CSR_WRITE_OPCODE)) - if (withRead) illegalAccess.clearWhen(input(CSR_READ_OPCODE)) - } + Component.current.afterElaboration{ + def doJobs(jobs : ArrayBuffer[Any]): Unit ={ + val withWrite = jobs.exists(j => j.isInstanceOf[CsrWrite] || j.isInstanceOf[CsrOnWrite]) + val withRead = jobs.exists(j => j.isInstanceOf[CsrRead] || j.isInstanceOf[CsrOnRead]) + if(withRead && withWrite) { + illegalAccess := False + } else { + if (withWrite) illegalAccess.clearWhen(input(CSR_WRITE_OPCODE)) + if (withRead) illegalAccess.clearWhen(input(CSR_READ_OPCODE)) + } - when(writeEnable) { - for (element <- jobs) element match { - case element: CsrWrite => element.that.assignFromBits(writeData(element.bitOffset, element.that.getBitsWidth bits)) - case element: CsrOnWrite => - element.doThat() - case _ => - } - } + when(writeEnable) { + for (element <- jobs) element match { + case element: CsrWrite => element.that.assignFromBits(writeData(element.bitOffset, element.that.getBitsWidth bits)) + case element: CsrOnWrite => + element.doThat() + case _ => + } + } - for (element <- jobs) element match { - case element: CsrRead if element.that.getBitsWidth != 0 => readData(element.bitOffset, element.that.getBitsWidth bits) := element.that.asBits - case _ => - } - - when(readEnable) { - for (element <- jobs) element match { - case element: CsrOnRead => - element.doThat() - case _ => - } - } + when(readEnable) { + for (element <- jobs) element match { + case element: CsrOnRead => + element.doThat() + case _ => } } } - switch(csrAddress) { - for ((address, jobs) <- csrMapping.mapping if jobs.exists(_.isInstanceOf[CsrReadToWriteOverride])) { - is(address) { - for (element <- jobs) element match { - case element: CsrReadToWriteOverride if element.that.getBitsWidth != 0 => readToWriteData(element.bitOffset, element.that.getBitsWidth bits) := element.that.asBits - case _ => + def doJobsOverride(jobs : ArrayBuffer[Any]): Unit ={ + for (element <- jobs) element match { + case element: CsrReadToWriteOverride if element.that.getBitsWidth != 0 => readToWriteData(element.bitOffset, element.that.getBitsWidth bits) := element.that.asBits + case _ => + } + } + + csrOhDecoder match { + case false => { + readData := 0 + switch(csrAddress) { + for ((address, jobs) <- csrMapping.mapping) { + is(address) { + doJobs(jobs) + for (element <- jobs) element match { + case element: CsrRead if element.that.getBitsWidth != 0 => readData(element.bitOffset, element.that.getBitsWidth bits) := element.that.asBits + case _ => + } + } + } + } + switch(csrAddress) { + for ((address, jobs) <- csrMapping.mapping if jobs.exists(_.isInstanceOf[CsrReadToWriteOverride])) { + is(address) { + doJobsOverride(jobs) + } + } + } + } + case true => { + val oh = csrMapping.mapping.keys.toList.distinct.map(address => address -> RegNextWhen(decode.input(INSTRUCTION)(csrRange) === address, !execute.arbitration.isStuck).setCompositeName(this, "csr_" + address)).toMap + val readDatas = ArrayBuffer[Bits]() + for ((address, jobs) <- csrMapping.mapping) { + when(oh(address)){ + doJobs(jobs) + } + if(jobs.exists(_.isInstanceOf[CsrRead])) { + val masked = B(0, 32 bits) + when(oh(address)) (for (element <- jobs) element match { + case element: CsrRead if element.that.getBitsWidth != 0 => masked(element.bitOffset, element.that.getBitsWidth bits) := element.that.asBits + case _ => + }) + readDatas += masked + } + } + readData := readDatas.reduceBalancedTree(_ | _) + for ((address, jobs) <- csrMapping.mapping) { + when(oh(address)){ + doJobsOverride(jobs) } } } @@ -1094,7 +1129,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep illegalAccess setWhen(privilege < csrAddress(9 downto 8).asUInt) illegalAccess clearWhen(!arbitration.isValid || !input(IS_CSR)) - }) + } } } } From b7ae902bbc4a89761209b8c8290db200d104859b Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Thu, 5 Mar 2020 00:14:11 +0100 Subject: [PATCH 343/951] smp spec improvements, no more read abort --- doc/smp/smp.md | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/doc/smp/smp.md b/doc/smp/smp.md index c335f1fa..cc06b16a 100644 --- a/doc/smp/smp.md +++ b/doc/smp/smp.md @@ -5,9 +5,11 @@ Features : - Two data paths (read + write), but allow dirty/clean sharing by reusing the write data path - Allow multi level coherent interconnect - No ordering, but provide barrier +- Allow cache-full and cache-less agents +## Memory copy status -## Memory copy flags +Memory copy, in other words, cache line, have more states than non coherent systems : | Name | Description | |---------------|-------------| @@ -16,13 +18,14 @@ Features : | Owner/Lodger | lodger => copy of the line, but no other responsibility, owner => the given cache is responsible to write back dirty data and answer probes with the data | | Clean/Dirty | clean => match main memory, dirty => main memory need updates | -All combination of those cache flag are valid. But if a cache line is invalid, the other flags have no meaning. +All combination of those cache flag are valid. But if a cache line is invalid, the other status have no meaning. -Later in the spec, memory copy state can be described as : +Later in the spec, memory copy state can be described for example as : - VSOC for (Valid, Shared, Owner, Clean) - V-OC for (Valid, Shared or Unique, Owner, Clean) - !V-OC for NOT (Valid, Shared or Unique, Owner, Clean) +- ... ## buses @@ -70,11 +73,11 @@ Emitted on the readCmd channel (master -> slave) | readShared | I--- | Get a memory copy as V--- | Want to read a uncached address | | readUnique | I--- | Get a memory copy as VUO- | Want to write a uncached address | | readOnce | I--- | Get a memory copy without coherency tracking | Instruction cache read | -| makeInvalid | VS-- | Make other memory copy as I--- and make yourself VUO- | Want to write into a shared line | +| makeUnique | VS-- | Make other memory copy as I--- and make yourself VUO- | Want to write into a shared line | | readBarrier | N/A | Ensure that the visibility of the memory operations of this channel do not cross the barrier | ISA fence | -makeInvalid should be designed with care. There is a few corner cases : -- While a master has a inflight makeInvalid, a probe can change its state. +makeUnique should be designed with care. There is a few corner cases : +- While a master has a inflight makeUnique, a probe can change its state, in such case, the makeUnique become weak and invalidation is canceled. This is usefull for multi level coherent interconnects. - Multi level coherent interconnect should be careful to properly move the ownership and not lose dirty data I'm not sure yet if we should add some barrier transactions to enforce @@ -83,14 +86,13 @@ I'm not sure yet if we should add some barrier transactions to enforce Emitted on the readRsp channel (master <- slave) -success, abort, error, data shared/unique clean/dirty owner/notOwner +readSuccess, readError, data shared/unique clean/dirty owner/notOwner -| Responses | From command | Description | -|-----------|---------------|----------| -| success | makeInvalid, readBarrier | - | -| abort | makeInvalid | A concurrent makeInvalid toke over | -| error | readShared, readUnique, readOnce | Bad address | -| readData | readShared, readUnique, readOnce | Data + coherency flags (V???) | +| Responses | From command | Description | +|-------------|---------------|----------| +| readSuccess | makeUnique, readBarrier | - | +| readError | readShared, readUnique, readOnce | Bad address | +| readData | readShared, readUnique, readOnce | Data + coherency status (V???) | ### Read ack @@ -108,6 +110,7 @@ Write commands can be emitted on the writeCmd channel (master -> slave) |--------------|---------------|----------|----------| | writeInvalid | V-O- | Write the memory copy and update it status to I--- | Need to free the dirty cache line | | writeShare | V-O- | Write the memory copy but keep it as VSO- | A probe makeShared asked it | +| writeUnique | VUO- | Write the memory copy but keep it as VUO- | A probe probeOnce need to read the data | | evict | V---, !V-OD | Notify the interconnect that the cache line is now I--- | Need to free a clean cache line | | writeBarrier | N/A | Ensure that the visibility of the memory operations of this channel do not cross the barrier | ISA fence | @@ -127,8 +130,11 @@ Probe commands can be emitted on the probeCmd channel (slave -> master) |-------------|-------------|---------------| | makeInvalid | Make the memory copy I--- | Another cache want to make his shared copy unique to write it | | makeShared | Make the memory copy VS-- | Another cache want to read a memory block, so unique copy need to be shared | +| probeOnce | Read the V-O- memory copy | A non coherent agent did a readOnce | -Both makeInvalid and makeShared could result into one of the following probeSuccess, writeInvalid, writeShare. +makeInvalid and makeShared could result into one of the following probeSuccess, writeInvalid, writeShare + +probeOnce can result into one of the following probeSuccess, writeShare, writeUnique To help the slave matching the writeInvalid and writeShare generated from a probe, those request are tagged with a matching ID. From 2c6076ba972ea89082a2f87940034834dfdc16b2 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Sat, 7 Mar 2020 13:35:21 +0100 Subject: [PATCH 344/951] improve smp spec --- doc/smp/smp.md | 63 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 47 insertions(+), 16 deletions(-) diff --git a/doc/smp/smp.md b/doc/smp/smp.md index cc06b16a..200ebee0 100644 --- a/doc/smp/smp.md +++ b/doc/smp/smp.md @@ -1,12 +1,35 @@ # Coherent interface specification Features : -- 3 buses (write, read, probe) composed of 7 streams +- 3 interface (write, read, probe) composed of 7 streams - Two data paths (read + write), but allow dirty/clean sharing by reusing the write data path - Allow multi level coherent interconnect - No ordering, but provide barrier - Allow cache-full and cache-less agents +## A few hint to help reading the spec + +In order to make the spec more readable, there is some definitions : + +### Stream + +A stream is a primitive interface which carry transactions using a valid/ready handshake. + +### Memory copy + +To talk in a non abstract way, in a system with multiple caches, a given memory address can potentialy be loaded in multiple caches at the same time. So let's define that : + +- The DDR memory is named `main memory` +- Each cache line can be loaded with a part of the main memory, let's name that a `memory copy` + +### Master / Interconnect / Slave + +A master could be for instance a CPU cache, the side of the interconnect toward the main memory or toward a more general interconnect. + +A slave could be main memory, the side of the interconnect toward a CPU cache or toward a less general interconnect. + +The spec will try to stay abstract and define the coherent interface as something which can be used between two agents (cpu, interconnect, main memory) + ## Memory copy status Memory copy, in other words, cache line, have more states than non coherent systems : @@ -27,14 +50,16 @@ Later in the spec, memory copy state can be described for example as : - !V-OC for NOT (Valid, Shared or Unique, Owner, Clean) - ... -## buses +## Coherent interface -One full interface is composed of 3 buses -- write (M -> S) -- read (M -> S) -- probe (M <- S) +One full coherent interface is composed of 3 inner interfaces, them-self composed of 7 stream described bellow as `interfaceName (Side -> StreamName -> Side -> StreamName -> ...)` +- write (M -> writeCmd -> S -> writeRsp -> M) +- read (M -> readCmd- > S -> readRsp -> M -> readAck -> S) +- probe (S -> probeCmd -> M -> probeRsp -> S) -### Read bus +### Read interface + +Used by masters to obtain new memory copies and make copies unique (used to write them). Composed of 3 stream : @@ -42,9 +67,11 @@ Composed of 3 stream : |---------|-----------|----------| | readCmd | M -> S | Emit memory read and cache management commands | | readRsp | M <- S | Return some data and/or a status from readCmd | -| readAck | M -> S | Return ACK from readRsp | +| readAck | M -> S | Return ACK from readRsp to syncronize the interconnect status | -### Write bus +### Write interface + +Used by masters to write data back to the memory and notify the interconnect of memory copies eviction (used to keep potential directories updated). Composed of 2 stream : @@ -53,7 +80,9 @@ Composed of 2 stream : | writeCmd | M -> S | Emit memory writes and cache management commands | | writeRsp | M <- S | Return a status from writeCmd | -### Probe bus +### Probe interface + +Used by the interconnect to order master to change their memory copies status and get memory copies owners data. | Name | Direction | Description | |----------|-----------|----------| @@ -62,7 +91,7 @@ Composed of 2 stream : ## Transactions -This chapter define transactions moving over the 3 previously defined buses. +This chapter define transactions moving over the 3 previously defined interface (read/write/probe). ### Read commands @@ -92,7 +121,7 @@ readSuccess, readError, data shared/unique clean/dirty owner/notOwner |-------------|---------------|----------| | readSuccess | makeUnique, readBarrier | - | | readError | readShared, readUnique, readOnce | Bad address | -| readData | readShared, readUnique, readOnce | Data + coherency status (V???) | +| readData | readShared, readUnique, readOnce | Data + coherency status (V---) | ### Read ack @@ -149,13 +178,15 @@ Emitted on the probeRsp channel (master -> slave), it carry no information, just ## Channel interlocking -There is the streams priority (top => high priority, bottom => low priority ) +This is a delicate subject as if everything was permited, it would be easy to end up with deadlocks. + +There is the streams priority (top => high priority, bottom => low priority) A lower priority stream should not block a higher priority stream in order to avoid deadlocks. - writeCmd, writeRsp, readRsp, readAck, probeRsp. Nothing should realy block them excepted bandwidth - probeCmd. Can be blocked by inflight/generated writes - readCmd. Can be blocked by inflight/generated probes In other words : -Masters can wait the completion of inflight writes before answering probes. -Slaves can emit probes and wait their completion before answering reads. -Slaves can wait on readAck incomming from generated readRsp before at all times +Masters can emit writeCmd and wait their writeRsp completion before answering probes commands. +Slaves can emit probeCmd and wait their proveRsp completion before answering reads. +Slaves can emit readRsp and wait on their readAck completion before doing anything else From 44005ebf31099a4f03670d4f8e8dc2aea3c42204 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sat, 7 Mar 2020 18:22:01 +0100 Subject: [PATCH 345/951] update Synthesis results --- README.md | 76 +++++++++---------- .../scala/vexriscv/demo/SynthesisBench.scala | 8 +- 2 files changed, 42 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index dd90af3d..d192005b 100644 --- a/README.md +++ b/README.md @@ -66,53 +66,53 @@ The CPU configurations used below can be found in the `src/scala/vexriscv/demo` ``` VexRiscv small (RV32I, 0.52 DMIPS/Mhz, no datapath bypass, no interrupt) -> - Artix 7 -> 253 Mhz 498 LUT 505 FF - Cyclone V -> 205 Mhz 350 ALMs - Cyclone IV -> 172 Mhz 731 LUT 494 FF + Artix 7 -> 243 Mhz 504 LUT 505 FF + Cyclone V -> 174 Mhz 352 ALMs + Cyclone IV -> 179 Mhz 731 LUT 494 FF iCE40 -> 92 Mhz 1130 LC VexRiscv small (RV32I, 0.52 DMIPS/Mhz, no datapath bypass) -> - Artix 7 -> 225 Mhz 549 LUT 563 FF - Cyclone V -> 194 Mhz 392 ALMs - Cyclone IV -> 172 Mhz 830 LUT 551 FF + Artix 7 -> 240 Mhz 556 LUT 566 FF + Cyclone V -> 194 Mhz 394 ALMs + Cyclone IV -> 174 Mhz 831 LUT 555 FF iCE40 -> 85 Mhz 1292 LC VexRiscv small and productive (RV32I, 0.82 DMIPS/Mhz) -> - Artix 7 -> 213 Mhz 787 LUT 531 FF - Cyclone V -> 150 Mhz 487 ALMs - Cyclone IV -> 151 Mhz 1,115 LUT 526 FF + Artix 7 -> 232 Mhz 816 LUT 534 FF + Cyclone V -> 155 Mhz 492 ALMs + Cyclone IV -> 155 Mhz 1,111 LUT 530 FF iCE40 -> 63 Mhz 1596 LC VexRiscv small and productive with I$ (RV32I, 0.70 DMIPS/Mhz, 4KB-I$) -> - Artix 7 -> 220 Mhz 719 LUT 570 FF - Cyclone V -> 147 Mhz 516 ALMs - Cyclone IV -> 144 Mhz 1,139 LUT 532 FF + Artix 7 -> 220 Mhz 730 LUT 570 FF + Cyclone V -> 142 Mhz 501 ALMs + Cyclone IV -> 150 Mhz 1,139 LUT 536 FF iCE40 -> 66 Mhz 1680 LC VexRiscv full no cache (RV32IM, 1.21 DMIPS/Mhz 2.30 Coremark/Mhz, single cycle barrel shifter, debug module, catch exceptions, static branch) -> - Artix 7 -> 210 Mhz 1410 LUT 975 FF - Cyclone V -> 144 Mhz 927 ALMs - Cyclone IV -> 141 Mhz 2,074 LUT 966 FF + Artix 7 -> 216 Mhz 1418 LUT 949 FF + Cyclone V -> 133 Mhz 933 ALMs + Cyclone IV -> 143 Mhz 2,076 LUT 972 FF VexRiscv full (RV32IM, 1.21 DMIPS/Mhz 2.30 Coremark/Mhz with cache trashing, 4KB-I$,4KB-D$, single cycle barrel shifter, debug module, catch exceptions, static branch) -> - Artix 7 -> 199 Mhz 1736 LUT 1120 FF - Cyclone V -> 137 Mhz 1,177 ALMs - Cyclone IV -> 142 Mhz 2,409 LUT 1,061 FF + Artix 7 -> 199 Mhz 1840 LUT 1158 FF + Cyclone V -> 141 Mhz 1,166 ALMs + Cyclone IV -> 131 Mhz 2,407 LUT 1,067 FF VexRiscv full max perf (HZ*IPC) -> (RV32IM, 1.38 DMIPS/Mhz 2.57 Coremark/Mhz, 8KB-I$,8KB-D$, single cycle barrel shifter, debug module, catch exceptions, dynamic branch prediction in the fetch stage, branch and shift operations done in the Execute stage) -> - Artix 7 -> 197 Mhz 1788 LUT 1210 FF - Cyclone V -> 130 Mhz 1,173 ALMs - Cyclone IV -> 124 Mhz 2,483 LUT 1,114 FF + Artix 7 -> 200 Mhz 1935 LUT 1216 FF + Cyclone V -> 130 Mhz 1,166 ALMs + Cyclone IV -> 126 Mhz 2,484 LUT 1,120 FF VexRiscv full with MMU (RV32IM, 1.24 DMIPS/Mhz 2.35 Coremark/Mhz, with cache trashing, 4KB-I$, 4KB-D$, single cycle barrel shifter, debug module, catch exceptions, dynamic branch, MMU) -> - Artix 7 -> 164 Mhz 2000 LUT 1501 FF - Cyclone V -> 125 Mhz 1,375 ALMs - Cyclone IV -> 121 Mhz 2,821 LUT 1,444 FF + Artix 7 -> 151 Mhz 2021 LUT 1541 FF + Cyclone V -> 124 Mhz 1,368 ALMs + Cyclone IV -> 128 Mhz 2,826 LUT 1,474 FF VexRiscv linux balanced (RV32IMA, 1.21 DMIPS/Mhz 2.27 Coremark/Mhz, with cache trashing, 4KB-I$, 4KB-D$, single cycle barrel shifter, catch exceptions, static branch, MMU, Supervisor, Compatible with mainstream linux) -> - Artix 7 -> 176 Mhz 2678 LUT 2087 FF - Cyclone V -> 137 Mhz 1,797 ALMs - Cyclone IV -> 120 Mhz 3,544 LUT 2,059 FF + Artix 7 -> 180 Mhz 2883 LUT 2130 FF + Cyclone V -> 131 Mhz 1,764 ALMs + Cyclone IV -> 121 Mhz 3,608 LUT 2,082 FF ``` The following configuration results in 1.44 DMIPS/MHz: @@ -318,9 +318,9 @@ You can find some FPGA projects which instantiate the Briey SoC here (DE1-SoC, D Here are some measurements of Briey SoC timings and area : ``` - Artix 7 -> 186 Mhz 3138 LUT 3328 FF - Cyclone V -> 139 Mhz 2,175 ALMs - Cyclone IV -> 129 Mhz 4,337 LUT 3,170 FF +Artix 7 -> 181 Mhz 3220 LUT 3181 FF +Cyclone V -> 142 Mhz 2,222 ALMs +Cyclone IV -> 130 Mhz 4,538 LUT 3,211 FF ``` ## Murax SoC @@ -373,16 +373,16 @@ Here are some timing and area measurements of the Murax SoC: ``` Murax interlocked stages (0.45 DMIPS/Mhz, 8 bits GPIO) -> - Artix 7 -> 215 Mhz 1044 LUT 1202 FF - Cyclone V -> 173 Mhz 737 ALMs - Cyclone IV -> 144 Mhz 1,484 LUT 1,206 FF - iCE40 -> 64 Mhz 2422 LC (nextpnr) + Artix 7 -> 216 Mhz 1109 LUT 1201 FF + Cyclone V -> 182 Mhz 725 ALMs + Cyclone IV -> 147 Mhz 1,551 LUT 1,223 FF + iCE40 -> 64 Mhz 2422 LC (nextpnr) MuraxFast bypassed stages (0.65 DMIPS/Mhz, 8 bits GPIO) -> - Artix 7 -> 229 Mhz 1269 LUT 1302 FF - Cyclone V -> 159 Mhz 864 ALMs - Cyclone IV -> 137 Mhz 1,688 LUT 1,241 FF - iCE40 -> 66 Mhz 2799 LC (nextpnr) + Artix 7 -> 224 Mhz 1278 LUT 1300 FF + Cyclone V -> 173 Mhz 867 ALMs + Cyclone IV -> 143 Mhz 1,755 LUT 1,258 FF + iCE40 -> 66 Mhz 2799 LC (nextpnr) ``` Some scripts to generate the SoC and call the icestorm toolchain can be found here: `scripts/Murax/` diff --git a/src/main/scala/vexriscv/demo/SynthesisBench.scala b/src/main/scala/vexriscv/demo/SynthesisBench.scala index ca925bf7..a9961a96 100644 --- a/src/main/scala/vexriscv/demo/SynthesisBench.scala +++ b/src/main/scala/vexriscv/demo/SynthesisBench.scala @@ -117,7 +117,7 @@ object VexRiscvSynthesisBench { val targets = XilinxStdTargets() ++ AlteraStdTargets() ++ IcestormStdTargets().take(1) // val targets = IcestormStdTargets() - Bench(rtls, targets, "/media/miaou/HD/linux/tmp/") + Bench(rtls, targets) } } @@ -137,9 +137,9 @@ object BrieySynthesisBench { val rtls = List(briey) - val targets = XilinxStdTargets() ++ AlteraStdTargets() ++ IcestormStdTargets().take(1) + val targets = XilinxStdTargets() ++ AlteraStdTargets() ++ IcestormStdTargets().take(1) - Bench(rtls, targets, "/media/miaou/HD/linux/tmp") + Bench(rtls, targets) } } @@ -173,7 +173,7 @@ object MuraxSynthesisBench { val targets = XilinxStdTargets() ++ AlteraStdTargets() ++ IcestormStdTargets().take(1) - Bench(rtls, targets, "/media/miaou/HD/linux/tmp") + Bench(rtls, targets) } } From 7a5afb86a57f6848437c6cd8bd23d48be13896eb Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sat, 7 Mar 2020 19:09:33 +0100 Subject: [PATCH 346/951] Fix build.sbt --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index ac8feba7..cd635f87 100644 --- a/build.sbt +++ b/build.sbt @@ -5,7 +5,7 @@ lazy val root = (project in file(".")). scalaVersion := "2.11.12", version := "2.0.0" )), - scalacOptions += s"-Xplugin:${new File(baseDirectory.value + "/../SpinalHDL/idslplugin/target/scala-2.11/spinalhdl-idsl-plugin_2.11-1.3.9.jar")}", + scalacOptions += s"-Xplugin:${new File(baseDirectory.value + "/../SpinalHDL/idslplugin/target/scala-2.11").listFiles().filter(_.getName.endsWith(".jar")).head}", scalacOptions += s"-Xplugin-require:idsl-plugin", libraryDependencies ++= Seq( // "com.github.spinalhdl" % "spinalhdl-core_2.11" % "1.3.6", From 04bf1a4cedb6f72f049f1aaab3f052c0a2f1804e Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sun, 8 Mar 2020 00:23:19 +0100 Subject: [PATCH 347/951] Fix build.sbt --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index cd635f87..11c11f9b 100644 --- a/build.sbt +++ b/build.sbt @@ -5,7 +5,7 @@ lazy val root = (project in file(".")). scalaVersion := "2.11.12", version := "2.0.0" )), - scalacOptions += s"-Xplugin:${new File(baseDirectory.value + "/../SpinalHDL/idslplugin/target/scala-2.11").listFiles().filter(_.getName.endsWith(".jar")).head}", + scalacOptions += s"-Xplugin:${new File(baseDirectory.value + "/../SpinalHDL/idslplugin/target/scala-2.11/spinalhdl-idsl-plugin_2.11-1.4.0.jar")}", scalacOptions += s"-Xplugin-require:idsl-plugin", libraryDependencies ++= Seq( // "com.github.spinalhdl" % "spinalhdl-core_2.11" % "1.3.6", From defe3c55589b7450ede2c4dae3b61bce3c62c848 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sun, 8 Mar 2020 12:35:24 +0100 Subject: [PATCH 348/951] DataCache relax flush timings --- src/main/scala/vexriscv/ip/DataCache.scala | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index 8e62bc7d..7cbe4ba7 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -490,8 +490,7 @@ class DataCache(p : DataCacheConfig) extends Component{ //Evict the cache after reset logics val flusher = new Area { - val valid = RegInit(True) - mmuRsp.physicalAddress init (0) + val valid = RegInit(False) when(valid) { tagsWriteCmd.valid := valid tagsWriteCmd.address := mmuRsp.physicalAddress(lineRange) @@ -506,7 +505,10 @@ class DataCache(p : DataCacheConfig) extends Component{ } io.cpu.flush.ready := False - when(io.cpu.flush.valid && !io.cpu.execute.isValid && !io.cpu.memory.isValid && !io.cpu.writeBack.isValid && !io.cpu.redo){ + val start = RegInit(True) //Used to relax timings + start := !start && io.cpu.flush.valid && !io.cpu.execute.isValid && !io.cpu.memory.isValid && !io.cpu.writeBack.isValid && !io.cpu.redo + + when(start){ io.cpu.flush.ready := True mmuRsp.physicalAddress.getDrivingReg(lineRange) := 0 valid := True From 5f90702b2ffaddff5fa22b8b04a19be7b745faee Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 9 Mar 2020 13:14:16 +0100 Subject: [PATCH 349/951] SpinalHDL update --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index 11c11f9b..c1510b23 100644 --- a/build.sbt +++ b/build.sbt @@ -5,7 +5,7 @@ lazy val root = (project in file(".")). scalaVersion := "2.11.12", version := "2.0.0" )), - scalacOptions += s"-Xplugin:${new File(baseDirectory.value + "/../SpinalHDL/idslplugin/target/scala-2.11/spinalhdl-idsl-plugin_2.11-1.4.0.jar")}", + scalacOptions += s"-Xplugin:${new File(baseDirectory.value + "/../SpinalHDL/idslplugin/target/scala-2.11/spinalhdl-idsl-plugin_2.11-1.4.1.jar")}", scalacOptions += s"-Xplugin-require:idsl-plugin", libraryDependencies ++= Seq( // "com.github.spinalhdl" % "spinalhdl-core_2.11" % "1.3.6", From c122365a52df707662afd1636736b25bf2baf63c Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 11 Mar 2020 14:20:13 +0100 Subject: [PATCH 350/951] Smp spec update, add Interface subsets (writeOnly, readOnly) --- doc/smp/smp.md | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/doc/smp/smp.md b/doc/smp/smp.md index 5e22e4d1..f8b39c2a 100644 --- a/doc/smp/smp.md +++ b/doc/smp/smp.md @@ -57,6 +57,11 @@ One full coherent interface is composed of 3 inner interfaces, them-self compose - read (M -> readCmd- > S -> readRsp -> M -> readAck -> S) - probe (S -> probeCmd -> M -> probeRsp -> S) +The following streams could physically be merges in order to reduce the number of arbitration : + +- writeCmd, probeRsp, readAck +- writeRsp, readRsp + ### Read interface Used by masters to obtain new memory copies and make copies unique (used to write them). @@ -67,7 +72,7 @@ Composed of 3 stream : |---------|-----------|----------| | readCmd | M -> S | Emit memory read and cache management commands | | readRsp | M <- S | Return some data and/or a status from readCmd | -| readAck | M -> S | Return ACK from readRsp to syncronize the interconnect status | +| readAck | M -> S | Return ACK from readRsp to synchronize the interconnect status | ### Write interface @@ -192,3 +197,20 @@ In other words : Masters can emit writeCmd and wait their writeRsp completion before answering probes commands. Slaves can emit probeCmd and wait their proveRsp completion before answering reads. Slaves can emit readRsp and wait on their readAck completion before doing anything else + +## Interface subsets + +There is a few cases where you could need a specific subset of the coherent interface : +- Instruction caches do not necessarily need to maintain the coherency with the memory system. +- DMA need to read and write the memory system, but are cache-less (no probe) + +### ReadOnly interface without maintained coherency + +Such interface is only composed of the read bus on which the readCmd stream can only use readOnce requests + + +### WriteOnly interface + +In such interface, there is no read/probe buses, but only a writeCmd and a writeRsp stream. The writeCmd will invalidate other memory copies, then write into the memory while the writeRsp will return a writeSuccess/writeError status. + + From 31667b18d8fb1acee198c141900f5dd874f1c8e3 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 20 Mar 2020 11:26:38 +0100 Subject: [PATCH 351/951] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 22bfba82..84b811e2 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ For commercial support, please contact spinalhdl@gmail.com. ## Area usage and maximal frequency -The following numbers were obtained by synthesizing the CPU as toplevel without any specific synthesis options to save area or to get better maximal frequency (neutral).
+The following numbers were obtained by synthesizing the CPU as toplevel on the fastest speed grade without any specific synthesis options to save area or to get better maximal frequency (neutral).
The clock constraint is set to an unattainable value, which tends to increase the design area.
The dhrystone benchmark was compiled with the `-O3 -fno-inline` option.
All the cached configurations have some cache trashing during the dhrystone benchmark except the `VexRiscv full max perf` one. This, of course, reduces the performance. It is possible to produce From b3215e8beba80b807831286fd90de9509a3cb361 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 24 Mar 2020 13:11:07 +0100 Subject: [PATCH 352/951] Make things generated in a deterministic order --- src/main/scala/vexriscv/Pipeline.scala | 4 ++-- src/main/scala/vexriscv/Stage.scala | 14 +++++++------- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 4 ++-- .../vexriscv/plugin/DecoderSimplePlugin.scala | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/main/scala/vexriscv/Pipeline.scala b/src/main/scala/vexriscv/Pipeline.scala index 2a04ef2b..e9d93c24 100644 --- a/src/main/scala/vexriscv/Pipeline.scala +++ b/src/main/scala/vexriscv/Pipeline.scala @@ -14,7 +14,7 @@ trait Pipeline { val plugins = ArrayBuffer[Plugin[T]]() var stages = ArrayBuffer[Stage]() var unremovableStages = mutable.Set[Stage]() - val things = mutable.HashMap[PipelineThing[_], Any]() + val things = mutable.LinkedHashMap[PipelineThing[_], Any]() // val services = ArrayBuffer[Any]() def stageBefore(stage : Stage) = stages(indexOf(stage)-1) @@ -78,7 +78,7 @@ trait Pipeline { def setInsertStageId(stageId : Int) = insertStageId = stageId } - val inputOutputKeys = mutable.HashMap[Stageable[Data],KeyInfo]() + val inputOutputKeys = mutable.LinkedHashMap[Stageable[Data],KeyInfo]() val insertedStageable = mutable.Set[Stageable[Data]]() for(stageIndex <- 0 until stages.length; stage = stages(stageIndex)){ stage.inserts.keysIterator.foreach(signal => inputOutputKeys.getOrElseUpdate(signal,new KeyInfo).setInsertStageId(stageIndex)) diff --git a/src/main/scala/vexriscv/Stage.scala b/src/main/scala/vexriscv/Stage.scala index d86c2567..5f3365ac 100644 --- a/src/main/scala/vexriscv/Stage.scala +++ b/src/main/scala/vexriscv/Stage.scala @@ -61,15 +61,15 @@ class Stage() extends Area{ } - val inputs = mutable.HashMap[Stageable[Data],Data]() - val outputs = mutable.HashMap[Stageable[Data],Data]() - val signals = mutable.HashMap[Stageable[Data],Data]() - val inserts = mutable.HashMap[Stageable[Data],Data]() + val inputs = mutable.LinkedHashMap[Stageable[Data],Data]() + val outputs = mutable.LinkedHashMap[Stageable[Data],Data]() + val signals = mutable.LinkedHashMap[Stageable[Data],Data]() + val inserts = mutable.LinkedHashMap[Stageable[Data],Data]() - val inputsDefault = mutable.HashMap[Stageable[Data],Data]() - val outputsDefault = mutable.HashMap[Stageable[Data],Data]() + val inputsDefault = mutable.LinkedHashMap[Stageable[Data],Data]() + val outputsDefault = mutable.LinkedHashMap[Stageable[Data],Data]() - val dontSample = mutable.HashMap[Stageable[_], ArrayBuffer[Bool]]() + val dontSample = mutable.LinkedHashMap[Stageable[_], ArrayBuffer[Bool]]() def dontSampleStageable(s : Stageable[_], cond : Bool): Unit ={ dontSample.getOrElseUpdate(s, ArrayBuffer[Bool]()) += cond diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 0cdc8968..fce4c153 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -550,7 +550,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep val medeleg = supervisorGen generate new Area { val IAM, IAF, II, LAM, LAF, SAM, SAF, EU, ES, IPF, LPF, SPF = RegInit(False) - val mapping = mutable.HashMap(0 -> IAM, 1 -> IAF, 2 -> II, 4 -> LAM, 5 -> LAF, 6 -> SAM, 7 -> SAF, 8 -> EU, 9 -> ES, 12 -> IPF, 13 -> LPF, 15 -> SPF) + val mapping = mutable.LinkedHashMap(0 -> IAM, 1 -> IAF, 2 -> II, 4 -> LAM, 5 -> LAF, 6 -> SAM, 7 -> SAF, 8 -> EU, 9 -> ES, 12 -> IPF, 13 -> LPF, 15 -> SPF) } val mideleg = supervisorGen generate new Area { val ST, SE, SS = RegInit(False) @@ -776,7 +776,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep val code = if(pipelinedInterrupt) Reg(UInt(trapCodeWidth bits)) else UInt(trapCodeWidth bits).assignDontCare() var privilegs = if (supervisorGen) List(1, 3) else List(3) val targetPrivilege = if(pipelinedInterrupt) Reg(UInt(2 bits)) else UInt(2 bits).assignDontCare() - val privilegeAllowInterrupts = mutable.HashMap[Int, Bool]() + val privilegeAllowInterrupts = mutable.LinkedHashMap[Int, Bool]() if (supervisorGen) privilegeAllowInterrupts += 1 -> ((sstatus.SIE && privilege === U"01") || privilege < U"01") privilegeAllowInterrupts += 3 -> (mstatus.MIE || privilege < U"11") while (privilegs.nonEmpty) { diff --git a/src/main/scala/vexriscv/plugin/DecoderSimplePlugin.scala b/src/main/scala/vexriscv/plugin/DecoderSimplePlugin.scala index e88a98c9..e2ab1117 100644 --- a/src/main/scala/vexriscv/plugin/DecoderSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/DecoderSimplePlugin.scala @@ -89,7 +89,7 @@ class DecoderSimplePlugin(catchIllegalInstruction : Boolean = false, import pipeline.config._ import pipeline.decode._ - val stageables = (encodings.flatMap(_._2.map(_._1)) ++ defaults.map(_._1)).toSet.toList + val stageables = (encodings.flatMap(_._2.map(_._1)) ++ defaults.map(_._1)).toList.distinct val stupidDecoder = false if(stupidDecoder){ From 2dac7dae32e065e2ac1304bc7249cfa85535d017 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sat, 28 Mar 2020 14:36:02 +0100 Subject: [PATCH 353/951] Fix BranchPlugin.jumpInterface priority to avoid conflicts with other instructions on DYNAMIC_TARGET missprediction --- src/main/scala/vexriscv/plugin/BranchPlugin.scala | 5 ++++- src/test/scala/vexriscv/TestIndividualFeatures.scala | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/BranchPlugin.scala b/src/main/scala/vexriscv/plugin/BranchPlugin.scala index e90a1fce..9c36cf7d 100644 --- a/src/main/scala/vexriscv/plugin/BranchPlugin.scala +++ b/src/main/scala/vexriscv/plugin/BranchPlugin.scala @@ -139,7 +139,10 @@ class BranchPlugin(earlyBranch : Boolean, } val pcManagerService = pipeline.service(classOf[JumpService]) - jumpInterface = pcManagerService.createJumpInterface(branchStage) + + //Priority -1, as DYNAMIC_TARGET misspredicted on non branch instruction should lose against other instructions + //legitim branches, as MRET for instance + jumpInterface = pcManagerService.createJumpInterface(branchStage, priority = -10) if (catchAddressMisalignedForReal) { diff --git a/src/test/scala/vexriscv/TestIndividualFeatures.scala b/src/test/scala/vexriscv/TestIndividualFeatures.scala index 047c719b..bbf84a4e 100644 --- a/src/test/scala/vexriscv/TestIndividualFeatures.scala +++ b/src/test/scala/vexriscv/TestIndividualFeatures.scala @@ -716,7 +716,7 @@ class TestIndividualFeatures extends MultithreadedFunSuite { //Test RTL val debug = true - val stdCmd = (s"make run REGRESSION_PATH=../../src/test/cpp/regression VEXRISCV_FILE=VexRiscv.v WITH_USER_IO=no REDO=10 TRACE=${if(debug) "yes" else "no"} TRACE_START=1000000000000l STOP_ON_ERROR=no FLOW_INFO=no STOP_ON_ERROR=no DHRYSTONE=yes COREMARK=${coremarkRegression} THREAD_COUNT=1 ") + s" SEED=${testSeed} " + val stdCmd = (s"make run REGRESSION_PATH=../../src/test/cpp/regression VEXRISCV_FILE=VexRiscv.v WITH_USER_IO=no REDO=10 TRACE=${if(debug) "yes" else "no"} TRACE_START=1000000000000l FLOW_INFO=no STOP_ON_ERROR=no DHRYSTONE=yes COREMARK=${coremarkRegression} THREAD_COUNT=1 ") + s" SEED=${testSeed} " val testCmd = stdCmd + (positionsToApply).map(_.testParam).mkString(" ") println(testCmd) val str = doCmd(testCmd) From 31d2aaa05bd3b353e8d2e4dba2448f17cca2f52b Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sat, 28 Mar 2020 15:38:32 +0100 Subject: [PATCH 354/951] Update README.md --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 84b811e2..bb37f034 100644 --- a/README.md +++ b/README.md @@ -824,6 +824,12 @@ This plugin implements the register file. This register file use a `don't care` read-during-write policy, so the bypassing/hazard plugin should take care of this. +If you get a `Missing inserts : INSTRUCTION_ANTICIPATE` error, that's because the RegFilePlugin is configured to use SYNC memory read ports to access the register file, but the IBus plugin configuration can't provide the instruction's register file read address one cycle before the decode stage. To workaround that you can : + +- Configure the RegFilePlugin to implement the register file read in a asyncronus manner (ASYNC), if your target device support such things +- If you use the IBusSimplePlugin, you need to enable the injectorStage configuration +- If you use the IBusCachedPlugin, you can either enable the injectorStage, or set twoCycleCache + twoCycleRam to false. + #### HazardSimplePlugin This plugin checks the pipeline instruction dependencies and, if necessary or possible, will stop the instruction in the decoding stage or bypass the instruction results From c9bbf0d12a7654b939bd764bd0c621006e12f7ab Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sat, 4 Apr 2020 21:21:35 +0200 Subject: [PATCH 355/951] update LrSc reservation logic to match the spec --- src/main/scala/vexriscv/ip/DataCache.scala | 37 ++-- .../vexriscv/plugin/DBusCachedPlugin.scala | 1 - .../vexriscv/plugin/DBusSimplePlugin.scala | 8 +- src/test/cpp/raw/lrsc/build/lrsc.asm | 194 ++++++------------ src/test/cpp/raw/lrsc/build/lrsc.hex | 61 ++---- src/test/cpp/raw/lrsc/src/crt.S | 94 +-------- src/test/cpp/regression/main.cpp | 4 +- src/test/cpp/regression/makefile | 1 - .../vexriscv/TestIndividualFeatures.scala | 2 +- 9 files changed, 113 insertions(+), 289 deletions(-) diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index 7cbe4ba7..0dfe74e0 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -25,13 +25,16 @@ case class DataCacheConfig(cacheSize : Int, tagSizeShift : Int = 0, //Used to force infering ram withLrSc : Boolean = false, withAmo : Boolean = false, + withSmp : Boolean = false, mergeExecuteMemory : Boolean = false){ assert(!(mergeExecuteMemory && (earlyDataMux || earlyWaysHits))) assert(!(earlyDataMux && !earlyWaysHits)) def burstSize = bytePerLine*8/memDataWidth val burstLength = bytePerLine/(memDataWidth/8) def catchSomething = catchUnaligned || catchIllegal || catchAccessError - + def withInternalAmo = withAmo && !withSmp + def withInternalLrSc = withLrSc && !withSmp + def withExternalLrSc = withLrSc && withSmp def getAxi4SharedConfig() = Axi4Config( addressWidth = addressWidth, dataWidth = memDataWidth, @@ -133,15 +136,13 @@ case class DataCacheCpuWriteBack(p : DataCacheConfig) extends Bundle with IMaste val isWrite = Bool val data = Bits(p.cpuDataWidth bit) val address = UInt(p.addressWidth bit) - val mmuException, unalignedAccess , accessError = Bool - val clearLrsc = ifGen(p.withLrSc) {Bool} + val mmuException, unalignedAccess, accessError = Bool // val exceptionBus = if(p.catchSomething) Flow(ExceptionCause()) else null override def asMaster(): Unit = { out(isValid,isStuck,isUser, address) in(haltIt, data, mmuException, unalignedAccess, accessError, isWrite) - outWithNull(clearLrsc) } } @@ -169,11 +170,13 @@ case class DataCacheMemCmd(p : DataCacheConfig) extends Bundle{ val data = Bits(p.memDataWidth bits) val mask = Bits(p.memDataWidth/8 bits) val length = UInt(log2Up(p.burstLength) bits) + val exclusive = p.withSmp generate Bool() val last = Bool } case class DataCacheMemRsp(p : DataCacheConfig) extends Bundle{ val data = Bits(p.memDataWidth bit) val error = Bool + val exclusive = p.withSmp generate Bool() } case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave{ @@ -516,19 +519,17 @@ class DataCache(p : DataCacheConfig) extends Component{ } - val lrsc = withLrSc generate new Area{ + val lrSc = withLrSc generate new Area{ val reserved = RegInit(False) - when(io.cpu.writeBack.isValid && !io.cpu.writeBack.isStuck && !io.cpu.redo && request.isLrsc && !request.wr){ - reserved := True - } - when(io.cpu.writeBack.clearLrsc){ - reserved := False + when(io.cpu.writeBack.isValid && !io.cpu.writeBack.isStuck && request.isLrsc + && !io.cpu.redo && !io.cpu.writeBack.mmuException && !io.cpu.writeBack.unalignedAccess && !io.cpu.writeBack.accessError){ + reserved := !request.wr } } val requestDataBypass = CombInit(request.data) val isAmo = if(withAmo) request.isAmo else False - val amo = withAmo generate new Area{ + val internalAmo = withInternalAmo generate new Area{ def rf = request.data def mem = dataMux @@ -550,6 +551,7 @@ class DataCache(p : DataCacheConfig) extends Component{ } + val memCmdSent = RegInit(False) setWhen (io.mem.cmd.ready) clearWhen (!io.cpu.writeBack.isStuck) io.cpu.redo := False io.cpu.writeBack.accessError := False @@ -564,9 +566,10 @@ class DataCache(p : DataCacheConfig) extends Component{ io.mem.cmd.wr := request.wr io.mem.cmd.mask := mask io.mem.cmd.data := requestDataBypass + if(withExternalLrSc) io.mem.cmd.exclusive := request.isLrsc || request.isAmo when(io.cpu.writeBack.isValid) { - when(mmuRsp.isIoAccess) { + when(mmuRsp.isIoAccess || (if(withExternalLrSc) request.isLrsc else False)) { io.cpu.writeBack.haltIt.clearWhen(request.wr ? io.mem.cmd.ready | io.mem.rsp.valid) io.mem.cmd.valid := !memCmdSent @@ -574,7 +577,7 @@ class DataCache(p : DataCacheConfig) extends Component{ io.mem.cmd.length := 0 io.mem.cmd.last := True - if(withLrSc) when(request.isLrsc && !lrsc.reserved){ + if(withInternalLrSc) when(request.isLrsc && !lrSc.reserved){ io.mem.cmd.valid := False io.cpu.writeBack.haltIt := False } @@ -595,7 +598,7 @@ class DataCache(p : DataCacheConfig) extends Component{ io.cpu.writeBack.haltIt clearWhen(!request.wr || io.mem.cmd.ready) if(withAmo) when(isAmo){ - when(!amo.resultRegValid) { + when(!internalAmo.resultRegValid) { io.mem.cmd.valid := False dataWriteCmd.valid := False io.cpu.writeBack.haltIt := True @@ -608,7 +611,7 @@ class DataCache(p : DataCacheConfig) extends Component{ if(withAmo) io.mem.cmd.valid := False } - if(withLrSc) when(request.isLrsc && !lrsc.reserved){ + if(withInternalLrSc) when(request.isLrsc && !lrSc.reserved){ io.mem.cmd.valid := False dataWriteCmd.valid := False io.cpu.writeBack.haltIt := False @@ -648,12 +651,12 @@ class DataCache(p : DataCacheConfig) extends Component{ if(withLrSc){ when(request.isLrsc && request.wr){ - io.cpu.writeBack.data := (!lrsc.reserved).asBits.resized + io.cpu.writeBack.data := (!lrSc.reserved).asBits.resized } } if(withAmo){ when(request.isAmo){ - requestDataBypass := amo.resultReg + requestDataBypass := internalAmo.resultReg } } } diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index fd45dd80..73b0fb05 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -254,7 +254,6 @@ class DBusCachedPlugin(val config : DataCacheConfig, cache.io.cpu.writeBack.isStuck := arbitration.isStuck cache.io.cpu.writeBack.isUser := (if(privilegeService != null) privilegeService.isUser() else False) cache.io.cpu.writeBack.address := U(input(REGFILE_WRITE_DATA)) - if(withLrSc) cache.io.cpu.writeBack.clearLrsc := service(classOf[IContextSwitching]).isContextSwitching redoBranch.valid := False redoBranch.payload := input(PC) diff --git a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala index e08b6402..0b02da2d 100644 --- a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala @@ -469,13 +469,9 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, val atomic = withLrSc generate new Area{ val reserved = RegInit(False) insert(ATOMIC_HIT) := reserved - when(arbitration.isFiring && input(MEMORY_ENABLE) && input(MEMORY_ATOMIC) && !input(MEMORY_STORE)){ - reserved := True + when(arbitration.isFiring && input(MEMORY_ENABLE) && input(MEMORY_ATOMIC) && !input(MMU_FAULT) && !skipCmd){ + reserved := !input(MEMORY_STORE) } - when(service(classOf[IContextSwitching]).isContextSwitching){ - reserved := False - } - when(input(MEMORY_STORE) && input(MEMORY_ATOMIC) && !input(ATOMIC_HIT)){ skipCmd := True } diff --git a/src/test/cpp/raw/lrsc/build/lrsc.asm b/src/test/cpp/raw/lrsc/build/lrsc.asm index 95b4751d..4ff24b47 100644 --- a/src/test/cpp/raw/lrsc/build/lrsc.asm +++ b/src/test/cpp/raw/lrsc/build/lrsc.asm @@ -38,9 +38,9 @@ Disassembly of section .crt_section: 80000060: 00d52023 sw a3,0(a0) # 10000000 80000064: 18b5262f sc.w a2,a1,(a0) 80000068: 00100713 li a4,1 -8000006c: 26e61e63 bne a2,a4,800002e8 +8000006c: 14e61a63 bne a2,a4,800001c0 80000070: 00052703 lw a4,0(a0) -80000074: 26e69a63 bne a3,a4,800002e8 +80000074: 14e69663 bne a3,a4,800001c0 80000078: 00200e13 li t3,2 8000007c: 10000537 lui a0,0x10000 80000080: 00450513 addi a0,a0,4 # 10000004 @@ -50,9 +50,9 @@ Disassembly of section .crt_section: 80000090: 00d52023 sw a3,0(a0) 80000094: 18b5262f sc.w a2,a1,(a0) 80000098: 00100713 li a4,1 -8000009c: 24e61663 bne a2,a4,800002e8 +8000009c: 12e61263 bne a2,a4,800001c0 800000a0: 00052703 lw a4,0(a0) -800000a4: 24e69263 bne a3,a4,800002e8 +800000a4: 10e69e63 bne a3,a4,800001c0 800000a8: 00300e13 li t3,3 800000ac: 10000537 lui a0,0x10000 800000b0: 00450513 addi a0,a0,4 # 10000004 @@ -61,9 +61,9 @@ Disassembly of section .crt_section: 800000bc: 06900693 li a3,105 800000c0: 18b5262f sc.w a2,a1,(a0) 800000c4: 00100713 li a4,1 -800000c8: 22e61063 bne a2,a4,800002e8 +800000c8: 0ee61c63 bne a2,a4,800001c0 800000cc: 00052703 lw a4,0(a0) -800000d0: 20e69c63 bne a3,a4,800002e8 +800000d0: 0ee69863 bne a3,a4,800001c0 800000d4: 00400e13 li t3,4 800000d8: 10000537 lui a0,0x10000 800000dc: 00850513 addi a0,a0,8 # 10000008 @@ -73,10 +73,10 @@ Disassembly of section .crt_section: 800000ec: 00d52023 sw a3,0(a0) 800000f0: 100527af lr.w a5,(a0) 800000f4: 18b5262f sc.w a2,a1,(a0) -800000f8: 1ed79863 bne a5,a3,800002e8 -800000fc: 1e061663 bnez a2,800002e8 +800000f8: 0cd79463 bne a5,a3,800001c0 +800000fc: 0c061263 bnez a2,800001c0 80000100: 00052703 lw a4,0(a0) -80000104: 1ee59263 bne a1,a4,800002e8 +80000104: 0ae59e63 bne a1,a4,800001c0 80000108: 00500e13 li t3,5 8000010c: 10000537 lui a0,0x10000 80000110: 00850513 addi a0,a0,8 # 10000008 @@ -85,133 +85,59 @@ Disassembly of section .crt_section: 8000011c: 06f00693 li a3,111 80000120: 00d52023 sw a3,0(a0) 80000124: 18b5262f sc.w a2,a1,(a0) -80000128: 1c061063 bnez a2,800002e8 +80000128: 08060c63 beqz a2,800001c0 8000012c: 00052703 lw a4,0(a0) -80000130: 1ae59c63 bne a1,a4,800002e8 -80000134: 00600e13 li t3,6 +80000130: 08e69863 bne a3,a4,800001c0 +80000134: 00700e13 li t3,7 80000138: 10000537 lui a0,0x10000 -8000013c: 00c50513 addi a0,a0,12 # 1000000c -80000140: 07000593 li a1,112 -80000144: 07100613 li a2,113 -80000148: 07200693 li a3,114 -8000014c: 10000437 lui s0,0x10000 -80000150: 01040413 addi s0,s0,16 # 10000010 -80000154: 07300493 li s1,115 -80000158: 07400913 li s2,116 -8000015c: 07500993 li s3,117 -80000160: 00d52023 sw a3,0(a0) -80000164: 01342023 sw s3,0(s0) -80000168: 100527af lr.w a5,(a0) -8000016c: 10042aaf lr.w s5,(s0) -80000170: 18b5262f sc.w a2,a1,(a0) -80000174: 1894292f sc.w s2,s1,(s0) -80000178: 16d79863 bne a5,a3,800002e8 -8000017c: 16061663 bnez a2,800002e8 -80000180: 00052703 lw a4,0(a0) -80000184: 16e59263 bne a1,a4,800002e8 -80000188: 173a9063 bne s5,s3,800002e8 -8000018c: 14091e63 bnez s2,800002e8 -80000190: 00042a03 lw s4,0(s0) -80000194: 15449a63 bne s1,s4,800002e8 -80000198: 00700e13 li t3,7 -8000019c: 10000537 lui a0,0x10000 -800001a0: 01450513 addi a0,a0,20 # 10000014 -800001a4: 07800593 li a1,120 -800001a8: 07900613 li a2,121 -800001ac: 07a00693 li a3,122 -800001b0: 01000e93 li t4,16 +8000013c: 01450513 addi a0,a0,20 # 10000014 +80000140: 07800593 li a1,120 +80000144: 07900613 li a2,121 +80000148: 07a00693 li a3,122 +8000014c: 01000e93 li t4,16 -800001b4 : -800001b4: 00d52023 sw a3,0(a0) -800001b8: 100527af lr.w a5,(a0) -800001bc: 18b5262f sc.w a2,a1,(a0) -800001c0: 12d79463 bne a5,a3,800002e8 -800001c4: 12061263 bnez a2,800002e8 -800001c8: 00052703 lw a4,0(a0) -800001cc: 10e59e63 bne a1,a4,800002e8 -800001d0: fffe8e93 addi t4,t4,-1 -800001d4: 00450513 addi a0,a0,4 -800001d8: 00358593 addi a1,a1,3 -800001dc: 00360613 addi a2,a2,3 -800001e0: 00368693 addi a3,a3,3 -800001e4: fc0e98e3 bnez t4,800001b4 -800001e8: 00900e13 li t3,9 -800001ec: 10000537 lui a0,0x10000 -800001f0: 10050513 addi a0,a0,256 # 10000100 -800001f4: 07b00593 li a1,123 -800001f8: 07c00613 li a2,124 -800001fc: 07d00693 li a3,125 -80000200: 00d52023 sw a3,0(a0) -80000204: 100527af lr.w a5,(a0) -80000208: 00000073 ecall -8000020c: 18b5262f sc.w a2,a1,(a0) -80000210: 00100713 li a4,1 -80000214: 0ce61a63 bne a2,a4,800002e8 -80000218: 00052703 lw a4,0(a0) -8000021c: 0ce69663 bne a3,a4,800002e8 -80000220: 00b00e13 li t3,11 -80000224: 10000537 lui a0,0x10000 -80000228: 30050513 addi a0,a0,768 # 10000300 -8000022c: 08200593 li a1,130 -80000230: 08300613 li a2,131 -80000234: 08400693 li a3,132 -80000238: 00d52023 sw a3,0(a0) -8000023c: 00001eb7 lui t4,0x1 -80000240: 800e8e93 addi t4,t4,-2048 # 800 -80000244: 304e9073 csrw mie,t4 -80000248: 00800e93 li t4,8 -8000024c: 100527af lr.w a5,(a0) -80000250: 300e9073 csrw mstatus,t4 -80000254: 00000013 nop -80000258: 00000013 nop -8000025c: 00000013 nop -80000260: 00000013 nop -80000264: 00000013 nop -80000268: 00000013 nop -8000026c: 18b5262f sc.w a2,a1,(a0) -80000270: 00100713 li a4,1 -80000274: 06e61a63 bne a2,a4,800002e8 -80000278: 00052703 lw a4,0(a0) -8000027c: 06e69663 bne a3,a4,800002e8 -80000280: 00c00e13 li t3,12 -80000284: 10000537 lui a0,0x10000 -80000288: 40050513 addi a0,a0,1024 # 10000400 -8000028c: 08c00593 li a1,140 -80000290: 08d00613 li a2,141 -80000294: 08e00693 li a3,142 -80000298: 00d52023 sw a3,0(a0) -8000029c: 00001eb7 lui t4,0x1 -800002a0: 800e8e93 addi t4,t4,-2048 # 800 -800002a4: 304e9073 csrw mie,t4 -800002a8: 00002eb7 lui t4,0x2 -800002ac: 808e8e93 addi t4,t4,-2040 # 1808 -800002b0: 100527af lr.w a5,(a0) -800002b4: 300e9073 csrw mstatus,t4 -800002b8: 00000013 nop -800002bc: 00000013 nop -800002c0: 00000013 nop -800002c4: 00000013 nop -800002c8: 00000013 nop -800002cc: 00000013 nop -800002d0: 18b5262f sc.w a2,a1,(a0) -800002d4: 00100713 li a4,1 -800002d8: 00e61863 bne a2,a4,800002e8 -800002dc: 00052703 lw a4,0(a0) -800002e0: 00e69463 bne a3,a4,800002e8 -800002e4: 0100006f j 800002f4 +80000150 : +80000150: 00d52023 sw a3,0(a0) +80000154: 100527af lr.w a5,(a0) +80000158: 18b5262f sc.w a2,a1,(a0) +8000015c: 06d79263 bne a5,a3,800001c0 +80000160: 06061063 bnez a2,800001c0 +80000164: 00052703 lw a4,0(a0) +80000168: 04e59c63 bne a1,a4,800001c0 +8000016c: fffe8e93 addi t4,t4,-1 +80000170: 00450513 addi a0,a0,4 +80000174: 00358593 addi a1,a1,3 +80000178: 00360613 addi a2,a2,3 +8000017c: 00368693 addi a3,a3,3 +80000180: fc0e98e3 bnez t4,80000150 +80000184: 00900e13 li t3,9 +80000188: 10000537 lui a0,0x10000 +8000018c: 10050513 addi a0,a0,256 # 10000100 +80000190: 07b00593 li a1,123 +80000194: 07c00613 li a2,124 +80000198: 07d00693 li a3,125 +8000019c: 00d52023 sw a3,0(a0) +800001a0: 100527af lr.w a5,(a0) +800001a4: 00000073 ecall +800001a8: 18b527af sc.w a5,a1,(a0) +800001ac: 00000713 li a4,0 +800001b0: 00e79863 bne a5,a4,800001c0 +800001b4: 00052703 lw a4,0(a0) +800001b8: 00e59463 bne a1,a4,800001c0 +800001bc: 0100006f j 800001cc -800002e8 : -800002e8: f0100137 lui sp,0xf0100 -800002ec: f2410113 addi sp,sp,-220 # f00fff24 -800002f0: 01c12023 sw t3,0(sp) +800001c0 : +800001c0: f0100137 lui sp,0xf0100 +800001c4: f2410113 addi sp,sp,-220 # f00fff24 +800001c8: 01c12023 sw t3,0(sp) -800002f4 : -800002f4: f0100137 lui sp,0xf0100 -800002f8: f2010113 addi sp,sp,-224 # f00fff20 -800002fc: 00012023 sw zero,0(sp) -80000300: 00000013 nop -80000304: 00000013 nop -80000308: 00000013 nop -8000030c: 00000013 nop -80000310: 00000013 nop -80000314: 00000013 nop +800001cc : +800001cc: f0100137 lui sp,0xf0100 +800001d0: f2010113 addi sp,sp,-224 # f00fff20 +800001d4: 00012023 sw zero,0(sp) +800001d8: 00000013 nop +800001dc: 00000013 nop +800001e0: 00000013 nop +800001e4: 00000013 nop +800001e8: 00000013 nop +800001ec: 00000013 nop diff --git a/src/test/cpp/raw/lrsc/build/lrsc.hex b/src/test/cpp/raw/lrsc/build/lrsc.hex index 7b96205d..1c1cd4c2 100644 --- a/src/test/cpp/raw/lrsc/build/lrsc.hex +++ b/src/test/cpp/raw/lrsc/build/lrsc.hex @@ -5,49 +5,30 @@ :10003000938E0E8073900E3073002030F32E1034A8 :10004000938E4E0073901E3473002030130E1000F8 :100050003705001093054006130650069306600608 -:100060002320D5002F26B51813071000631EE6269F -:1000700003270500639AE626130E200037050010BB +:100060002320D5002F26B51813071000631AE614B5 +:10007000032705006396E614130E200037050010D1 :100080001305450093057006130680069306900637 -:100090002320D5002F26B518130710006316E62479 -:1000A000032705006392E624130E30003705001085 +:100090002320D5002F26B518130710006312E6128F +:1000A00003270500639EE610130E3000370500108D :1000B0001305450093057006130680069306900607 -:1000C0002F26B518130710006310E622032705003A -:1000D000639CE620130E40003705001013058500D1 +:1000C0002F26B51813071000631CE60E0327050042 +:1000D0006398E60E130E40003705001013058500E7 :1000E0009305A0061306B0069306C0062320D5008C -:1000F000AF2705102F26B5186398D71E6316061E66 -:10010000032705006392E51E130E5000370500100B +:1000F000AF2705102F26B5186394D70C6312060C92 +:1001000003270500639EE50A130E50003705001013 :10011000130585009305D0061306E0069306F00646 -:100120002320D5002F26B5186310061C03270500D1 -:10013000639CE51A130E6000370500101305C50017 -:1001400093050007130610079306200737040010D5 -:10015000130404019304300713094007930950075F -:100160002320D50023203401AF270510AF2A041027 -:100170002F26B5182F2994186398D71663160616DC -:10018000032705006392E51663903A17631E09146E -:10019000032A0400639A4415130E700037050010FB -:1001A0001305450193058007130690079306A007E2 -:1001B000930E00012320D500AF2705102F26B51878 -:1001C0006394D7126312061203270500639EE5109D -:1001D000938EFEFF13054500938535001306360008 -:1001E00093863600E3980EFC130E9000370500103E -:1001F000130505109305B0071306C0079306D00733 -:100200002320D500AF270510730000002F26B51856 -:1002100013071000631AE60C032705006396E60C2B -:10022000130EB000370500101305053093052008A4 -:1002300013063008930640082320D500B71E00009F -:10024000938E0E8073904E30930E8000AF27051072 -:1002500073900E3013000000130000001300000024 -:100260001300000013000000130000002F26B51833 -:1002700013071000631AE606032705006396E606D7 -:10028000130EC00037050010130505409305C00884 -:100290001306D0089306E0082320D500B71E0000FF -:1002A000938E0E8073904E30B72E0000938E8E800A -:1002B000AF27051073900E301300000013000000EC -:1002C00013000000130000001300000013000000E2 -:1002D0002F26B518130710006318E6000327050042 -:1002E0006394E6006F000001370110F0130141F242 -:1002F0002320C101370110F0130101F22320010076 -:1003000013000000130000001300000013000000A1 -:080310001300000013000000BF +:100120002320D5002F26B518630C060803270500E9 +:100130006398E608130E700037050010130545019B +:1001400093058007130690079306A007930E0001FE +:100150002320D500AF2705102F26B5186392D706A8 +:100160006310060603270500639CE504938EFEFFDB +:100170001305450093853500130636009386360037 +:10018000E3980EFC130E90003705001013050510C0 +:100190009305B0071306C0079306D0072320D500A8 +:1001A000AF27051073000000AF27B5181307000034 +:1001B0006398E700032705006394E5006F000001E2 +:1001C000370110F0130141F22320C101370110F073 +:1001D000130101F2232001001300000013000000AE +:1001E00013000000130000001300000013000000C3 :040000058000004C2B :00000001FF diff --git a/src/test/cpp/raw/lrsc/src/crt.S b/src/test/cpp/raw/lrsc/src/crt.S index 7fef5e35..0cddcd37 100644 --- a/src/test/cpp/raw/lrsc/src/crt.S +++ b/src/test/cpp/raw/lrsc/src/crt.S @@ -81,7 +81,7 @@ _start: bne a1, a4, fail -//Test 5 redo SC on reserved area should pass and should be written write memory +//Test 5 redo SC on reserved area should fail li x28, 5 li a0, 0x10000008 li a1, 109 @@ -89,36 +89,10 @@ _start: li a3, 111 sw a3, 0(a0) sc.w a2, a1, (a0) - bne a2, x0, fail + beq a2, x0, fail lw a4, 0(a0) - bne a1, a4, fail + bne a3, a4, fail -//Test 6 Allow two entries at the same time - li x28, 6 - li a0, 0x1000000C - li a1, 112 - li a2, 113 - li a3, 114 - li s0, 0x10000010 - li s1, 115 - li s2, 116 - li s3, 117 - - sw a3, 0(a0) - sw s3, 0(s0) - lr.w a5, (a0) - lr.w s5, (s0) - sc.w a2, a1, (a0) - sc.w s2, s1, (s0) - bne a5, a3, fail - bne a2, x0, fail - lw a4, 0(a0) - bne a1, a4, fail - - bne s5, s3, fail - bne s2, x0, fail - lw s4, 0(s0) - bne s1, s4, fail //Test 7 do a lot of allocation to clear the entries li x28, 7 @@ -157,7 +131,7 @@ test7: bne a5, a4, fail*/ -//Test 9 SC should fail after a context switching +//Test 9 SC should pass after a context switching li x28, 9 li a0, 0x10000100 li a1, 123 @@ -166,11 +140,11 @@ test7: sw a3, 0(a0) lr.w a5, (a0) scall - sc.w a2, a1, (a0) - li a4, 1 - bne a2, a4, fail + sc.w a5, a1, (a0) + li a4, 0 + bne a5, a4, fail lw a4, 0(a0) - bne a3, a4, fail + bne a1, a4, fail @@ -192,58 +166,6 @@ test7: bne a7, a4, fail*/ - -//Test 11 SC should fail after a external interrupt context switching - li x28, 11 - li a0, 0x10000300 - li a1, 130 - li a2, 131 - li a3, 132 - sw a3, 0(a0) - li x29, 0x800 //800 external interrupts - csrw mie,x29 - li x29, 0x008 //008 enable interrupts - lr.w a5, (a0) - csrw mstatus,x29 //Enable external interrupt (will jump instantly due to testbench setup) - nop - nop - nop - nop - nop - nop - sc.w a2, a1, (a0) - li a4, 1 - bne a2, a4, fail - lw a4, 0(a0) - bne a3, a4, fail - - -//Test 12 SC should fail after a external interrupt context switching (callback on lr) - li x28, 12 - li a0, 0x10000400 - li a1, 140 - li a2, 141 - li a3, 142 - sw a3, 0(a0) - li x29, 0x800 //800 external interrupts - csrw mie,x29 - li x29, 0x1808 //008 enable interrupts - lr.w a5, (a0) - csrw mstatus,x29 //Enable external interrupt (will jump instantly due to testbench setup) - nop - nop - nop - nop - nop - nop - sc.w a2, a1, (a0) - li a4, 1 - bne a2, a4, fail - lw a4, 0(a0) - bne a3, a4, fail - - - j pass diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index d983e8e6..9394144c 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -464,7 +464,6 @@ public: cout << hex << " a7=0x" << regs[17] << " a0=0x" << regs[10] << " a1=0x" << regs[11] << " a2=0x" << regs[12] << dec << endl; } #endif - lrscReserved = false; //Check leguality of the interrupt if(interrupt) { bool hit = false; @@ -835,7 +834,6 @@ public: status.mpie = 1; status.mpp = 0; pcWrite(mepc); - lrscReserved = false; }break; case 0x10200073:{ //SRET if(privilege < 1){ ilegalInstruction(); return;} @@ -844,7 +842,6 @@ public: status.spie = 1; status.spp = 0; pcWrite(sepc); - lrscReserved = false; }break; case 0x00000073:{ //ECALL trap(0, 8+privilege, 0x00000073); //To follow the VexRiscv area saving implementation @@ -909,6 +906,7 @@ public: if(hit){ dWrite(pAddr, 4, i32_rs2); } + lrscReserved = false; rfWrite(rd32, !hit); pcWrite(pc + 4); } diff --git a/src/test/cpp/regression/makefile b/src/test/cpp/regression/makefile index 61fe9d17..2278d064 100644 --- a/src/test/cpp/regression/makefile +++ b/src/test/cpp/regression/makefile @@ -278,5 +278,4 @@ compile: verilate clean: rm -rf obj_dir - rm -f VexRiscv.v*.bin diff --git a/src/test/scala/vexriscv/TestIndividualFeatures.scala b/src/test/scala/vexriscv/TestIndividualFeatures.scala index bbf84a4e..9d147bc9 100644 --- a/src/test/scala/vexriscv/TestIndividualFeatures.scala +++ b/src/test/scala/vexriscv/TestIndividualFeatures.scala @@ -436,7 +436,7 @@ class DBusDimension extends VexRiscvDimension("DBus") { cacheSize = 512 << r.nextInt(5) wayCount = 1 << r.nextInt(3) }while(cacheSize/wayCount < 512 || (catchAll && cacheSize/wayCount > 4096)) - new VexRiscvPosition("Cached" + "S" + cacheSize + "W" + wayCount + "BPL" + bytePerLine + (if(dBusCmdMasterPipe) "Cmp " else "") + (if(dBusCmdSlavePipe) "Csp " else "") + (if(dBusRspSlavePipe) "Rsp " else "") + (if(relaxedMemoryTranslationRegister) "Rmtr " else "") + (if(earlyWaysHits) "Ewh " else "")) { + new VexRiscvPosition("Cached" + "S" + cacheSize + "W" + wayCount + "BPL" + bytePerLine + (if(dBusCmdMasterPipe) "Cmp " else "") + (if(dBusCmdSlavePipe) "Csp " else "") + (if(dBusRspSlavePipe) "Rsp " else "") + (if(relaxedMemoryTranslationRegister) "Rmtr " else "") + (if(earlyWaysHits) "Ewh " else "") + (if(withAmo) "Amo " else "")) { override def testParam = "DBUS=CACHED " + (if(withLrSc) "LRSC=yes " else "") + (if(withAmo) "AMO=yes " else "") override def applyOn(config: VexRiscvConfig): Unit = { From ff074459ade53eaa99bb35b6451d5d6b9c9801e3 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sat, 4 Apr 2020 22:54:35 +0200 Subject: [PATCH 356/951] Fix LrSc for configs without mmu --- src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala index 0b02da2d..41306911 100644 --- a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala @@ -469,7 +469,7 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, val atomic = withLrSc generate new Area{ val reserved = RegInit(False) insert(ATOMIC_HIT) := reserved - when(arbitration.isFiring && input(MEMORY_ENABLE) && input(MEMORY_ATOMIC) && !input(MMU_FAULT) && !skipCmd){ + when(arbitration.isFiring && input(MEMORY_ENABLE) && input(MEMORY_ATOMIC) && (if(mmuBus != null) !input(MMU_FAULT) else True) && !skipCmd){ reserved := !input(MEMORY_STORE) } when(input(MEMORY_STORE) && input(MEMORY_ATOMIC) && !input(ATOMIC_HIT)){ From f2ef8e95ab18b65149bec06c4a6bafe269d413d9 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sun, 5 Apr 2020 11:38:57 +0200 Subject: [PATCH 357/951] Implement external LrSc --- src/main/scala/vexriscv/ip/DataCache.scala | 48 +++++++++++++------ .../vexriscv/plugin/DBusCachedPlugin.scala | 2 +- 2 files changed, 34 insertions(+), 16 deletions(-) diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index 0dfe74e0..af6f15c5 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -26,6 +26,7 @@ case class DataCacheConfig(cacheSize : Int, withLrSc : Boolean = false, withAmo : Boolean = false, withSmp : Boolean = false, + pendingMax : Int = 64, mergeExecuteMemory : Boolean = false){ assert(!(mergeExecuteMemory && (earlyDataMux || earlyWaysHits))) assert(!(earlyDataMux && !earlyWaysHits)) @@ -91,12 +92,12 @@ object DataCacheCpuExecute{ case class DataCacheCpuExecute(p : DataCacheConfig) extends Bundle with IMasterSlave{ val isValid = Bool val address = UInt(p.addressWidth bit) - // val haltIt = Bool + val haltIt = Bool val args = DataCacheCpuExecuteArgs(p) override def asMaster(): Unit = { out(isValid, args, address) - // in(haltIt) + in(haltIt) } } @@ -441,6 +442,22 @@ class DataCache(p : DataCacheConfig) extends Component{ ret } + + io.cpu.execute.haltIt := False + + val rspSync = True + val pending = withSmp generate new Area{ + val counter = Reg(UInt(log2Up(pendingMax) + 1 bits)) init(0) + counter := counter + U(io.mem.cmd.fire && io.mem.cmd.last) - U(io.mem.rsp.valid) + + val full = RegNext(counter.msb) + val last = counter === 1 + + io.cpu.execute.haltIt setWhen(full) + rspSync clearWhen(!last) + } + + val stage0 = new Area{ val mask = io.cpu.execute.size.mux ( U(0) -> B"0001", @@ -566,11 +583,14 @@ class DataCache(p : DataCacheConfig) extends Component{ io.mem.cmd.wr := request.wr io.mem.cmd.mask := mask io.mem.cmd.data := requestDataBypass - if(withExternalLrSc) io.mem.cmd.exclusive := request.isLrsc || request.isAmo + if(withExternalLrSc) io.mem.cmd.exclusive := request.isLrsc || (if(withAmo) request.isAmo else False) when(io.cpu.writeBack.isValid) { when(mmuRsp.isIoAccess || (if(withExternalLrSc) request.isLrsc else False)) { - io.cpu.writeBack.haltIt.clearWhen(request.wr ? io.mem.cmd.ready | io.mem.rsp.valid) + val waitResponse = !request.wr + if(withExternalLrSc) waitResponse setWhen(request.isLrsc) + + io.cpu.writeBack.haltIt.clearWhen(waitResponse ? (io.mem.rsp.valid && rspSync) | io.mem.cmd.ready) io.mem.cmd.valid := !memCmdSent io.mem.cmd.address := mmuRsp.physicalAddress(tagRange.high downto wordRange.low) @@ U(0, wordRange.low bit) @@ -636,6 +656,12 @@ class DataCache(p : DataCacheConfig) extends Component{ io.cpu.writeBack.data := dataMux if(catchAccessError) io.cpu.writeBack.accessError := (waysHits & B(tagsReadRsp.map(_.error))) =/= 0 } + if(withLrSc) when(request.isLrsc && request.wr){ + io.cpu.writeBack.data := B(!lrSc.reserved || !io.mem.rsp.exclusive).resized + } + if(withAmo) when(request.isAmo){ + requestDataBypass := internalAmo.resultReg + } //remove side effects on exceptions when(mmuRsp.refilling || io.cpu.writeBack.accessError || io.cpu.writeBack.mmuException || io.cpu.writeBack.unalignedAccess){ @@ -649,16 +675,8 @@ 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") - if(withLrSc){ - when(request.isLrsc && request.wr){ - io.cpu.writeBack.data := (!lrSc.reserved).asBits.resized - } - } - if(withAmo){ - when(request.isAmo){ - requestDataBypass := internalAmo.resultReg - } - } + + } val loader = new Area{ @@ -669,7 +687,7 @@ class DataCache(p : DataCacheConfig) extends Component{ val waysAllocator = Reg(Bits(wayCount bits)) init(1) val error = RegInit(False) - when(valid && io.mem.rsp.valid){ + when(valid && io.mem.rsp.valid && rspSync){ dataWriteCmd.valid := True dataWriteCmd.address := baseAddress(lineRange) @@ counter dataWriteCmd.data := io.mem.rsp.data diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index 73b0fb05..958d1a8e 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -204,7 +204,7 @@ class DBusCachedPlugin(val config : DataCacheConfig, cache.io.cpu.flush.valid := arbitration.isValid && input(MEMORY_MANAGMENT) - arbitration.haltItself setWhen(cache.io.cpu.flush.isStall) + arbitration.haltItself setWhen(cache.io.cpu.flush.isStall || cache.io.cpu.execute.haltIt) if(withLrSc) { cache.io.cpu.execute.args.isLrsc := False From 2eec18de655af449bcec2642e6a855bc8554b43d Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sun, 5 Apr 2020 16:28:46 +0200 Subject: [PATCH 358/951] LrSc SMP, linux crash in userspace --- src/main/scala/vexriscv/TestsWorkspace.scala | 94 ++++--- src/main/scala/vexriscv/ip/DataCache.scala | 47 ++-- src/test/cpp/raw/lrsc/build/lrsc.asm | 249 +++++++++++-------- src/test/cpp/raw/lrsc/build/lrsc.hex | 64 ++--- src/test/cpp/raw/lrsc/src/crt.S | 38 ++- src/test/cpp/regression/main.cpp | 89 ++++--- src/test/cpp/regression/makefile | 5 + 7 files changed, 362 insertions(+), 224 deletions(-) diff --git a/src/main/scala/vexriscv/TestsWorkspace.scala b/src/main/scala/vexriscv/TestsWorkspace.scala index 8db43167..9c223a72 100644 --- a/src/main/scala/vexriscv/TestsWorkspace.scala +++ b/src/main/scala/vexriscv/TestsWorkspace.scala @@ -26,29 +26,40 @@ import vexriscv.ip._ import spinal.lib.bus.avalon.AvalonMM import spinal.lib.eda.altera.{InterruptReceiverTag, ResetEmitterTag} + +//make clean all SEED=42 MMU=no STOP_ON_ERROR=yes SMP=yes SUPERVISOR=yes REDO=10 DHRYSTONE=no LRSC=yes LINUX_REGRESSION=yes TRACE=yes TRACE_START=1000000000000l FLOW_INFO=no object TestsWorkspace { def main(args: Array[String]) { def configFull = { val config = VexRiscvConfig( plugins = List( - // new IBusSimplePlugin( - // resetVector = 0x80000000l, - // cmdForkOnSecondStage = false, - // cmdForkPersistence = false, - // prediction = NONE, - // historyRamSizeLog2 = 10, - // catchAccessFault = false, - // compressedGen = false, - // busLatencyMin = 1, - // injectorStage = true - // ), + new MmuPlugin( + ioRange = x => x(31 downto 28) === 0xF + ), + //Uncomment the whole IBusSimplePlugin and comment IBusCachedPlugin if you want uncached iBus config + // new IBusSimplePlugin( + // resetVector = 0x80000000l, + // cmdForkOnSecondStage = false, + // cmdForkPersistence = false, + // prediction = DYNAMIC_TARGET, + // historyRamSizeLog2 = 10, + // catchAccessFault = true, + // compressedGen = true, + // busLatencyMin = 1, + // injectorStage = true, + // memoryTranslatorPortConfig = withMmu generate MmuPortConfig( + // portTlbSize = 4 + // ) + // ), + + //Uncomment the whole IBusCachedPlugin and comment IBusSimplePlugin if you want cached iBus config new IBusCachedPlugin( resetVector = 0x80000000l, compressedGen = false, - prediction = NONE, - injectorStage = true, + prediction = STATIC, + injectorStage = false, config = InstructionCacheConfig( - cacheSize = 4096, + cacheSize = 4096*1, bytePerLine = 32, wayCount = 1, addressWidth = 32, @@ -59,20 +70,28 @@ object TestsWorkspace { asyncTagMemory = false, twoCycleRam = false, twoCycleCache = true + // ) ), - memoryTranslatorPortConfig = MemoryTranslatorPortConfig( + memoryTranslatorPortConfig = MmuPortConfig( portTlbSize = 4 ) ), -// ).newTightlyCoupledPort(TightlyCoupledPortParameter("iBusTc", a => a(30 downto 28) === 0x0 && a(5))), - // new DBusSimplePlugin( - // catchAddressMisaligned = true, - // catchAccessFault = false, - // earlyInjection = false - // ), + // ).newTightlyCoupledPort(TightlyCoupledPortParameter("iBusTc", a => a(30 downto 28) === 0x0 && a(5))), + // new DBusSimplePlugin( + // catchAddressMisaligned = true, + // catchAccessFault = true, + // earlyInjection = false, + // withLrSc = true, + // memoryTranslatorPortConfig = withMmu generate MmuPortConfig( + // portTlbSize = 4 + // ) + // ), new DBusCachedPlugin( + dBusCmdMasterPipe = true, + dBusCmdSlavePipe = true, + dBusRspSlavePipe = true, config = new DataCacheConfig( - cacheSize = 4096, + cacheSize = 4096*1, bytePerLine = 32, wayCount = 1, addressWidth = 32, @@ -81,33 +100,34 @@ object TestsWorkspace { catchAccessError = true, catchIllegal = true, catchUnaligned = true, - withLrSc = true + withLrSc = true, + withAmo = false, + withSmp = true + // ) ), - // memoryTranslatorPortConfig = null - memoryTranslatorPortConfig = MemoryTranslatorPortConfig( - portTlbSize = 6 + memoryTranslatorPortConfig = MmuPortConfig( + portTlbSize = 4 ) ), - // new StaticMemoryTranslatorPlugin( + + // new MemoryTranslatorPlugin( + // tlbSize = 32, + // virtualRange = _(31 downto 28) === 0xC, // ioRange = _(31 downto 28) === 0xF // ), - new MemoryTranslatorPlugin( - tlbSize = 32, - virtualRange = _(31 downto 28) === 0xC, - ioRange = _(31 downto 28) === 0xF - ), + new DecoderSimplePlugin( catchIllegalInstruction = true ), new RegFilePlugin( - regFileReadyKind = plugin.ASYNC, + regFileReadyKind = plugin.SYNC, zeroBoot = true ), new IntAluPlugin, new SrcPlugin( separatedAddSub = false ), - new FullBarrelShifterPlugin(earlyInjection = true), + new FullBarrelShifterPlugin(earlyInjection = false), // new LightShifterPlugin, new HazardSimplePlugin( bypassExecute = true, @@ -128,7 +148,7 @@ object TestsWorkspace { divUnrollFactor = 1 ), // new DivPlugin, - new CsrPlugin(CsrPluginConfig.all(0x80000020l)), + new CsrPlugin(CsrPluginConfig.all2(0x80000020l).copy(ebreakGen = false)), // new CsrPlugin(//CsrPluginConfig.all2(0x80000020l).copy(ebreakGen = true)/* // CsrPluginConfig( // catchIllegalAccess = false, @@ -154,9 +174,9 @@ object TestsWorkspace { // )), new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))), new BranchPlugin( - earlyBranch = true, + earlyBranch = false, catchAddressMisaligned = true, - fenceiGenAsAJump = true + fenceiGenAsAJump = false ), new YamlPlugin("cpu0.yaml") ) diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index af6f15c5..758186ab 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -175,6 +175,7 @@ case class DataCacheMemCmd(p : DataCacheConfig) extends Bundle{ val last = Bool } case class DataCacheMemRsp(p : DataCacheConfig) extends Bundle{ + val last = Bool() val data = Bits(p.memDataWidth bit) val error = Bool val exclusive = p.withSmp generate Bool() @@ -446,15 +447,18 @@ class DataCache(p : DataCacheConfig) extends Component{ io.cpu.execute.haltIt := False val rspSync = True + val rspLast = True + val memCmdSent = RegInit(False) setWhen (io.mem.cmd.ready) clearWhen (!io.cpu.writeBack.isStuck) val pending = withSmp generate new Area{ val counter = Reg(UInt(log2Up(pendingMax) + 1 bits)) init(0) - counter := counter + U(io.mem.cmd.fire && io.mem.cmd.last) - U(io.mem.rsp.valid) + counter := counter + U(io.mem.cmd.fire && io.mem.cmd.last) - U(io.mem.rsp.valid && io.mem.rsp.last) val full = RegNext(counter.msb) val last = counter === 1 io.cpu.execute.haltIt setWhen(full) - rspSync clearWhen(!last) + rspSync clearWhen(!last || !memCmdSent) + rspLast clearWhen(!last) } @@ -568,8 +572,15 @@ class DataCache(p : DataCacheConfig) extends Component{ } + val cpuWriteToCache = False + when(cpuWriteToCache){ + dataWriteCmd.valid setWhen(request.wr && waysHit) + dataWriteCmd.address := mmuRsp.physicalAddress(lineRange.high downto wordRange.low) + dataWriteCmd.data := requestDataBypass + dataWriteCmd.mask := mask + dataWriteCmd.way := waysHits + } - val memCmdSent = RegInit(False) setWhen (io.mem.cmd.ready) clearWhen (!io.cpu.writeBack.isStuck) io.cpu.redo := False io.cpu.writeBack.accessError := False io.cpu.writeBack.mmuException := io.cpu.writeBack.isValid && (if(catchIllegal) mmuRsp.exception || (!mmuRsp.allowWrite && request.wr) || (!mmuRsp.allowRead && (!request.wr || isAmo)) else False) @@ -579,14 +590,16 @@ class DataCache(p : DataCacheConfig) extends Component{ io.mem.cmd.valid := False io.mem.cmd.address.assignDontCare() io.mem.cmd.length.assignDontCare() - io.mem.cmd.last.assignDontCare() + io.mem.cmd.last := True io.mem.cmd.wr := request.wr io.mem.cmd.mask := mask io.mem.cmd.data := requestDataBypass if(withExternalLrSc) io.mem.cmd.exclusive := request.isLrsc || (if(withAmo) request.isAmo else False) + val bypassCache = mmuRsp.isIoAccess || (if(withExternalLrSc) request.isLrsc else False) + when(io.cpu.writeBack.isValid) { - when(mmuRsp.isIoAccess || (if(withExternalLrSc) request.isLrsc else False)) { + when(bypassCache) { val waitResponse = !request.wr if(withExternalLrSc) waitResponse setWhen(request.isLrsc) @@ -595,7 +608,6 @@ class DataCache(p : DataCacheConfig) extends Component{ io.mem.cmd.valid := !memCmdSent io.mem.cmd.address := mmuRsp.physicalAddress(tagRange.high downto wordRange.low) @@ U(0, wordRange.low bit) io.mem.cmd.length := 0 - io.mem.cmd.last := True if(withInternalLrSc) when(request.isLrsc && !lrSc.reserved){ io.mem.cmd.valid := False @@ -603,18 +615,12 @@ class DataCache(p : DataCacheConfig) extends Component{ } } otherwise { when(waysHit || request.wr && !isAmo) { //Do not require a cache refill ? - //Data cache update - dataWriteCmd.valid setWhen(request.wr && waysHit) - dataWriteCmd.address := mmuRsp.physicalAddress(lineRange.high downto wordRange.low) - dataWriteCmd.data := requestDataBypass - dataWriteCmd.mask := mask - dataWriteCmd.way := waysHits + cpuWriteToCache := True //Write through io.mem.cmd.valid setWhen(request.wr) io.mem.cmd.address := mmuRsp.physicalAddress(tagRange.high downto wordRange.low) @@ U(0, wordRange.low bit) io.mem.cmd.length := 0 - io.mem.cmd.last := True io.cpu.writeBack.haltIt clearWhen(!request.wr || io.mem.cmd.ready) if(withAmo) when(isAmo){ @@ -642,22 +648,29 @@ class DataCache(p : DataCacheConfig) extends Component{ io.mem.cmd.wr := False io.mem.cmd.address := mmuRsp.physicalAddress(tagRange.high downto lineRange.low) @@ U(0,lineRange.low bit) io.mem.cmd.length := p.burstLength-1 - io.mem.cmd.last := True loaderValid setWhen(io.mem.cmd.ready) } } } - when(mmuRsp.isIoAccess){ + when(bypassCache){ io.cpu.writeBack.data := io.mem.rsp.data if(catchAccessError) io.cpu.writeBack.accessError := io.mem.rsp.valid && io.mem.rsp.error } otherwise { io.cpu.writeBack.data := dataMux if(catchAccessError) io.cpu.writeBack.accessError := (waysHits & B(tagsReadRsp.map(_.error))) =/= 0 } + if(withLrSc) when(request.isLrsc && request.wr){ - io.cpu.writeBack.data := B(!lrSc.reserved || !io.mem.rsp.exclusive).resized + val success = CombInit(lrSc.reserved) + if(withExternalLrSc) success clearWhen(!io.mem.rsp.exclusive) + + io.cpu.writeBack.data := B(!success).resized + + if(withExternalLrSc) when(io.cpu.writeBack.isValid && io.mem.rsp.valid && rspSync && success && waysHit){ + cpuWriteToCache := True + } } if(withAmo) when(request.isAmo){ requestDataBypass := internalAmo.resultReg @@ -687,7 +700,7 @@ class DataCache(p : DataCacheConfig) extends Component{ val waysAllocator = Reg(Bits(wayCount bits)) init(1) val error = RegInit(False) - when(valid && io.mem.rsp.valid && rspSync){ + when(valid && io.mem.rsp.valid && rspLast){ dataWriteCmd.valid := True dataWriteCmd.address := baseAddress(lineRange) @@ counter dataWriteCmd.data := io.mem.rsp.data diff --git a/src/test/cpp/raw/lrsc/build/lrsc.asm b/src/test/cpp/raw/lrsc/build/lrsc.asm index 4ff24b47..a2ba4c70 100644 --- a/src/test/cpp/raw/lrsc/build/lrsc.asm +++ b/src/test/cpp/raw/lrsc/build/lrsc.asm @@ -5,7 +5,7 @@ build/lrsc.elf: file format elf32-littleriscv Disassembly of section .crt_section: 80000000 : -80000000: 04c0006f j 8000004c <_start> +80000000: 06c0006f j 8000006c <_start> 80000004: 00000013 nop 80000008: 00000013 nop 8000000c: 00000013 nop @@ -29,115 +29,152 @@ Disassembly of section .crt_section: 80000044: 341e9073 csrw mepc,t4 80000048: 30200073 mret -8000004c <_start>: -8000004c: 00100e13 li t3,1 -80000050: 10000537 lui a0,0x10000 -80000054: 06400593 li a1,100 -80000058: 06500613 li a2,101 -8000005c: 06600693 li a3,102 -80000060: 00d52023 sw a3,0(a0) # 10000000 -80000064: 18b5262f sc.w a2,a1,(a0) -80000068: 00100713 li a4,1 -8000006c: 14e61a63 bne a2,a4,800001c0 -80000070: 00052703 lw a4,0(a0) -80000074: 14e69663 bne a3,a4,800001c0 -80000078: 00200e13 li t3,2 -8000007c: 10000537 lui a0,0x10000 -80000080: 00450513 addi a0,a0,4 # 10000004 -80000084: 06700593 li a1,103 -80000088: 06800613 li a2,104 -8000008c: 06900693 li a3,105 -80000090: 00d52023 sw a3,0(a0) -80000094: 18b5262f sc.w a2,a1,(a0) -80000098: 00100713 li a4,1 -8000009c: 12e61263 bne a2,a4,800001c0 -800000a0: 00052703 lw a4,0(a0) -800000a4: 10e69e63 bne a3,a4,800001c0 -800000a8: 00300e13 li t3,3 -800000ac: 10000537 lui a0,0x10000 -800000b0: 00450513 addi a0,a0,4 # 10000004 -800000b4: 06700593 li a1,103 -800000b8: 06800613 li a2,104 -800000bc: 06900693 li a3,105 -800000c0: 18b5262f sc.w a2,a1,(a0) -800000c4: 00100713 li a4,1 -800000c8: 0ee61c63 bne a2,a4,800001c0 +8000004c : +8000004c: 200002b7 lui t0,0x20000 +80000050: 00001337 lui t1,0x1 +80000054: 02000393 li t2,32 + +80000058 : +80000058: 0002ae03 lw t3,0(t0) # 20000000 +8000005c: 006282b3 add t0,t0,t1 +80000060: fff38393 addi t2,t2,-1 +80000064: fe039ae3 bnez t2,80000058 +80000068: 00008067 ret + +8000006c <_start>: +8000006c: 00100e13 li t3,1 +80000070: 10000537 lui a0,0x10000 +80000074: 06400593 li a1,100 +80000078: 06500613 li a2,101 +8000007c: 06600693 li a3,102 +80000080: 00d52023 sw a3,0(a0) # 10000000 +80000084: 18b5262f sc.w a2,a1,(a0) +80000088: 00100713 li a4,1 +8000008c: 18e61863 bne a2,a4,8000021c +80000090: 00052703 lw a4,0(a0) +80000094: 18e69463 bne a3,a4,8000021c + +80000098 : +80000098: 00200e13 li t3,2 +8000009c: 10000537 lui a0,0x10000 +800000a0: 00450513 addi a0,a0,4 # 10000004 +800000a4: 06700593 li a1,103 +800000a8: 06800613 li a2,104 +800000ac: 06900693 li a3,105 +800000b0: 00d52023 sw a3,0(a0) +800000b4: 18b5262f sc.w a2,a1,(a0) +800000b8: 00100713 li a4,1 +800000bc: 16e61063 bne a2,a4,8000021c +800000c0: 00052703 lw a4,0(a0) +800000c4: 14e69c63 bne a3,a4,8000021c +800000c8: f85ff0ef jal ra,8000004c 800000cc: 00052703 lw a4,0(a0) -800000d0: 0ee69863 bne a3,a4,800001c0 -800000d4: 00400e13 li t3,4 +800000d0: 14e69663 bne a3,a4,8000021c + +800000d4 : +800000d4: 00300e13 li t3,3 800000d8: 10000537 lui a0,0x10000 -800000dc: 00850513 addi a0,a0,8 # 10000008 -800000e0: 06a00593 li a1,106 -800000e4: 06b00613 li a2,107 -800000e8: 06c00693 li a3,108 -800000ec: 00d52023 sw a3,0(a0) -800000f0: 100527af lr.w a5,(a0) -800000f4: 18b5262f sc.w a2,a1,(a0) -800000f8: 0cd79463 bne a5,a3,800001c0 -800000fc: 0c061263 bnez a2,800001c0 -80000100: 00052703 lw a4,0(a0) -80000104: 0ae59e63 bne a1,a4,800001c0 -80000108: 00500e13 li t3,5 -8000010c: 10000537 lui a0,0x10000 -80000110: 00850513 addi a0,a0,8 # 10000008 -80000114: 06d00593 li a1,109 -80000118: 06e00613 li a2,110 -8000011c: 06f00693 li a3,111 -80000120: 00d52023 sw a3,0(a0) -80000124: 18b5262f sc.w a2,a1,(a0) -80000128: 08060c63 beqz a2,800001c0 -8000012c: 00052703 lw a4,0(a0) -80000130: 08e69863 bne a3,a4,800001c0 -80000134: 00700e13 li t3,7 -80000138: 10000537 lui a0,0x10000 -8000013c: 01450513 addi a0,a0,20 # 10000014 -80000140: 07800593 li a1,120 -80000144: 07900613 li a2,121 -80000148: 07a00693 li a3,122 -8000014c: 01000e93 li t4,16 +800000dc: 00450513 addi a0,a0,4 # 10000004 +800000e0: 06700593 li a1,103 +800000e4: 06800613 li a2,104 +800000e8: 06900693 li a3,105 +800000ec: 18b5262f sc.w a2,a1,(a0) +800000f0: 00100713 li a4,1 +800000f4: 12e61463 bne a2,a4,8000021c +800000f8: 00052703 lw a4,0(a0) +800000fc: 12e69063 bne a3,a4,8000021c +80000100: f4dff0ef jal ra,8000004c +80000104: 00052703 lw a4,0(a0) +80000108: 10e69a63 bne a3,a4,8000021c -80000150 : -80000150: 00d52023 sw a3,0(a0) -80000154: 100527af lr.w a5,(a0) -80000158: 18b5262f sc.w a2,a1,(a0) -8000015c: 06d79263 bne a5,a3,800001c0 -80000160: 06061063 bnez a2,800001c0 -80000164: 00052703 lw a4,0(a0) -80000168: 04e59c63 bne a1,a4,800001c0 -8000016c: fffe8e93 addi t4,t4,-1 -80000170: 00450513 addi a0,a0,4 -80000174: 00358593 addi a1,a1,3 -80000178: 00360613 addi a2,a2,3 -8000017c: 00368693 addi a3,a3,3 -80000180: fc0e98e3 bnez t4,80000150 -80000184: 00900e13 li t3,9 +8000010c : +8000010c: 00400e13 li t3,4 +80000110: 10000537 lui a0,0x10000 +80000114: 00850513 addi a0,a0,8 # 10000008 +80000118: 06a00593 li a1,106 +8000011c: 06b00613 li a2,107 +80000120: 06c00693 li a3,108 +80000124: 00d52023 sw a3,0(a0) +80000128: 100527af lr.w a5,(a0) +8000012c: 18b5262f sc.w a2,a1,(a0) +80000130: 0ed79663 bne a5,a3,8000021c +80000134: 0e061463 bnez a2,8000021c +80000138: 00052703 lw a4,0(a0) +8000013c: 0ee59063 bne a1,a4,8000021c +80000140: f0dff0ef jal ra,8000004c +80000144: 00052703 lw a4,0(a0) +80000148: 0ce59a63 bne a1,a4,8000021c + +8000014c : +8000014c: 00500e13 li t3,5 +80000150: 10000537 lui a0,0x10000 +80000154: 00850513 addi a0,a0,8 # 10000008 +80000158: 06d00593 li a1,109 +8000015c: 06e00613 li a2,110 +80000160: 06f00693 li a3,111 +80000164: 00d52023 sw a3,0(a0) +80000168: 18b5262f sc.w a2,a1,(a0) +8000016c: 0a060863 beqz a2,8000021c +80000170: 00052703 lw a4,0(a0) +80000174: 0ae69463 bne a3,a4,8000021c +80000178: ed5ff0ef jal ra,8000004c +8000017c: 00052703 lw a4,0(a0) +80000180: 08e69e63 bne a3,a4,8000021c +80000184: 00700e13 li t3,7 80000188: 10000537 lui a0,0x10000 -8000018c: 10050513 addi a0,a0,256 # 10000100 -80000190: 07b00593 li a1,123 -80000194: 07c00613 li a2,124 -80000198: 07d00693 li a3,125 -8000019c: 00d52023 sw a3,0(a0) -800001a0: 100527af lr.w a5,(a0) -800001a4: 00000073 ecall -800001a8: 18b527af sc.w a5,a1,(a0) -800001ac: 00000713 li a4,0 -800001b0: 00e79863 bne a5,a4,800001c0 +8000018c: 01450513 addi a0,a0,20 # 10000014 +80000190: 07800593 li a1,120 +80000194: 07900613 li a2,121 +80000198: 07a00693 li a3,122 +8000019c: 01000e93 li t4,16 + +800001a0 : +800001a0: 00d52023 sw a3,0(a0) +800001a4: 100527af lr.w a5,(a0) +800001a8: 18b5262f sc.w a2,a1,(a0) +800001ac: 06d79863 bne a5,a3,8000021c +800001b0: 06061663 bnez a2,8000021c 800001b4: 00052703 lw a4,0(a0) -800001b8: 00e59463 bne a1,a4,800001c0 -800001bc: 0100006f j 800001cc +800001b8: 06e59263 bne a1,a4,8000021c +800001bc: fffe8e93 addi t4,t4,-1 +800001c0: 00450513 addi a0,a0,4 +800001c4: 00358593 addi a1,a1,3 +800001c8: 00360613 addi a2,a2,3 +800001cc: 00368693 addi a3,a3,3 +800001d0: fc0e98e3 bnez t4,800001a0 -800001c0 : -800001c0: f0100137 lui sp,0xf0100 -800001c4: f2410113 addi sp,sp,-220 # f00fff24 -800001c8: 01c12023 sw t3,0(sp) +800001d4 : +800001d4: 00900e13 li t3,9 +800001d8: 10000537 lui a0,0x10000 +800001dc: 10050513 addi a0,a0,256 # 10000100 +800001e0: 07b00593 li a1,123 +800001e4: 07c00613 li a2,124 +800001e8: 07d00693 li a3,125 +800001ec: 00d52023 sw a3,0(a0) +800001f0: 100527af lr.w a5,(a0) +800001f4: 00000073 ecall +800001f8: 18b527af sc.w a5,a1,(a0) +800001fc: 00000713 li a4,0 +80000200: 00e79e63 bne a5,a4,8000021c +80000204: 00052703 lw a4,0(a0) +80000208: 00e59a63 bne a1,a4,8000021c +8000020c: e41ff0ef jal ra,8000004c +80000210: 00052703 lw a4,0(a0) +80000214: 00e59463 bne a1,a4,8000021c +80000218: 0100006f j 80000228 -800001cc : -800001cc: f0100137 lui sp,0xf0100 -800001d0: f2010113 addi sp,sp,-224 # f00fff20 -800001d4: 00012023 sw zero,0(sp) -800001d8: 00000013 nop -800001dc: 00000013 nop -800001e0: 00000013 nop -800001e4: 00000013 nop -800001e8: 00000013 nop -800001ec: 00000013 nop +8000021c : +8000021c: f0100137 lui sp,0xf0100 +80000220: f2410113 addi sp,sp,-220 # f00fff24 +80000224: 01c12023 sw t3,0(sp) + +80000228 : +80000228: f0100137 lui sp,0xf0100 +8000022c: f2010113 addi sp,sp,-224 # f00fff20 +80000230: 00012023 sw zero,0(sp) +80000234: 00000013 nop +80000238: 00000013 nop +8000023c: 00000013 nop +80000240: 00000013 nop +80000244: 00000013 nop +80000248: 00000013 nop diff --git a/src/test/cpp/raw/lrsc/build/lrsc.hex b/src/test/cpp/raw/lrsc/build/lrsc.hex index 1c1cd4c2..b0ee2734 100644 --- a/src/test/cpp/raw/lrsc/build/lrsc.hex +++ b/src/test/cpp/raw/lrsc/build/lrsc.hex @@ -1,34 +1,40 @@ :0200000480007A -:100000006F00C00413000000130000001300000084 +:100000006F00C00613000000130000001300000082 :100010001300000013000000130000001300000094 :10002000F32E003093FE0E08638A0E00B72E0000F8 :10003000938E0E8073900E3073002030F32E1034A8 -:10004000938E4E0073901E3473002030130E1000F8 -:100050003705001093054006130650069306600608 -:100060002320D5002F26B51813071000631AE614B5 -:10007000032705006396E614130E200037050010D1 -:100080001305450093057006130680069306900637 -:100090002320D5002F26B518130710006312E6128F -:1000A00003270500639EE610130E3000370500108D -:1000B0001305450093057006130680069306900607 -:1000C0002F26B51813071000631CE60E0327050042 -:1000D0006398E60E130E40003705001013058500E7 -:1000E0009305A0061306B0069306C0062320D5008C -:1000F000AF2705102F26B5186394D70C6312060C92 -:1001000003270500639EE50A130E50003705001013 -:10011000130585009305D0061306E0069306F00646 -:100120002320D5002F26B518630C060803270500E9 -:100130006398E608130E700037050010130545019B -:1001400093058007130690079306A007930E0001FE -:100150002320D500AF2705102F26B5186392D706A8 -:100160006310060603270500639CE504938EFEFFDB -:100170001305450093853500130636009386360037 -:10018000E3980EFC130E90003705001013050510C0 -:100190009305B0071306C0079306D0072320D500A8 -:1001A000AF27051073000000AF27B5181307000034 -:1001B0006398E700032705006394E5006F000001E2 -:1001C000370110F0130141F22320C101370110F073 -:1001D000130101F2232001001300000013000000AE -:1001E00013000000130000001300000013000000C3 -:040000058000004C2B +:10004000938E4E0073901E3473002030B702002050 +:10005000371300009303000203AE0200B382620074 +:100060009383F3FFE39A03FE67800000130E1000F2 +:1000700037050010930540061306500693066006E8 +:100080002320D5002F26B518130710006318E61893 +:10009000032705006394E618130E200037050010AF +:1000A0001305450093057006130680069306900617 +:1000B0002320D5002F26B518130710006310E6166D +:1000C00003270500639CE614EFF05FF803270500A3 +:1000D0006396E614130E3000370500101305450033 +:1000E0009305700613068006930690062F26B51812 +:1000F000130710006314E612032705006390E6124D +:10010000EFF0DFF403270500639AE610130E4000BA +:1001100037050010130585009305A0061306B006E9 +:100120009306C0062320D500AF2705102F26B5184B +:100130006396D70E6314060E032705006390E50E41 +:10014000EFF0DFF003270500639AE50C130E500073 +:1001500037050010130585009305D0061306E00649 +:100160009306F0062320D5002F26B5186308060A4B +:10017000032705006394E60AEFF05FED032705000F +:10018000639EE608130E7000370500101305450145 +:1001900093058007130690079306A007930E0001AE +:1001A0002320D500AF2705102F26B5186398D70652 +:1001B00063160606032705006392E506938EFEFF8D +:1001C00013054500938535001306360093863600E7 +:1001D000E3980EFC130E9000370500101305051070 +:1001E0009305B0071306C0079306D0072320D50058 +:1001F000AF27051073000000AF27B51813070000E4 +:10020000639EE70003270500639AE500EFF01FE413 +:10021000032705006394E5006F000001370110F02B +:10022000130141F22320C101370110F0130101F243 +:100230002320010013000000130000001300000041 +:0C02400013000000130000001300000079 +:040000058000006C0B :00000001FF diff --git a/src/test/cpp/raw/lrsc/src/crt.S b/src/test/cpp/raw/lrsc/src/crt.S index 0cddcd37..a19663fd 100644 --- a/src/test/cpp/raw/lrsc/src/crt.S +++ b/src/test/cpp/raw/lrsc/src/crt.S @@ -25,8 +25,19 @@ notExternalInterrupt: csrw mepc, x29 mret +flush: + li t0, 0x20000000 + li t1, 0x1000 + li t2, 32 +flushLoop: + lw t3, 0(t0) + add t0, t0, t1 + addi t2,t2,-1 + bnez t2, flushLoop + ret + _start: -//Test 1 SC on unreserved area should fail and not write memory +test1: //Test 1 SC on unreserved area should fail and not write memory li x28, 1 li a0, 0x10000000 li a1, 100 @@ -39,7 +50,7 @@ _start: lw a4, 0(a0) bne a3, a4, fail -//Test 2 SC on another unreserved area should fail and not write memory +test2: //Test 2 SC on another unreserved area should fail and not write memory li x28, 2 li a0, 0x10000004 li a1, 103 @@ -51,9 +62,12 @@ _start: bne a2, a4, fail lw a4, 0(a0) bne a3, a4, fail + call flush + lw a4, 0(a0) + bne a3, a4, fail -//Test 3 retrying SC on unreserved area should fail and not write memory +test3: //Test 3 retrying SC on unreserved area should fail and not write memory li x28, 3 li a0, 0x10000004 li a1, 103 @@ -64,9 +78,12 @@ _start: bne a2, a4, fail lw a4, 0(a0) bne a3, a4, fail + call flush + lw a4, 0(a0) + bne a3, a4, fail -//Test 4 SC on reserved area should pass and should be written write memory +test4: //Test 4 SC on reserved area should pass and should be written write memory li x28, 4 li a0, 0x10000008 li a1, 106 @@ -79,9 +96,12 @@ _start: bne a2, x0, fail lw a4, 0(a0) bne a1, a4, fail + call flush + lw a4, 0(a0) + bne a1, a4, fail -//Test 5 redo SC on reserved area should fail +test5: //Test 5 redo SC on reserved area should fail li x28, 5 li a0, 0x10000008 li a1, 109 @@ -92,6 +112,9 @@ _start: beq a2, x0, fail lw a4, 0(a0) bne a3, a4, fail + call flush + lw a4, 0(a0) + bne a3, a4, fail //Test 7 do a lot of allocation to clear the entries @@ -131,7 +154,7 @@ test7: bne a5, a4, fail*/ -//Test 9 SC should pass after a context switching +test9: //Test 9 SC should pass after a context switching li x28, 9 li a0, 0x10000100 li a1, 123 @@ -145,6 +168,9 @@ test7: bne a5, a4, fail lw a4, 0(a0) bne a1, a4, fail + call flush + lw a4, 0(a0) + bne a1, a4, fail diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 9394144c..8b959e24 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -1409,7 +1409,7 @@ public: virtual void fillSimELements(); void dump(int i){ #ifdef TRACE - if(i == TRACE_START && i != 0) cout << "START TRACE" << endl; + if(i == TRACE_START && i != 0) cout << "**" << endl << "**" << endl << "**" << endl << "**" << endl << "**" << endl << "START TRACE" << endl; if(i >= TRACE_START) tfp->dump(i); #endif } @@ -1518,7 +1518,7 @@ public: currentTime = i; #ifdef FLOW_INFO - if(i % 2000000 == 0) cout << "PROGRESS TRACE_START=" << i << endl; + if(i % 2000000 == 0) cout << "**" << endl << "**" << endl << "**" << endl << "**" << endl << "**" << endl << "PROGRESS TRACE_START=" << i << endl; #endif @@ -2314,16 +2314,25 @@ public: #ifdef DBUS_CACHED //#include "VVexRiscv_DataCache.h" +#include + +struct DBusCachedTask{ + uint32_t data; + bool error; + bool last; + bool exclusive; +}; class DBusCached : public SimElement{ public: - uint32_t address; - bool error_next = false; - uint32_t pendingCount = 0; - bool wr; + queue rsps; + + bool reservationValid = false; + uint32_t reservationAddress; Workspace *ws; VVexRiscv* top; + DBusCached(Workspace* ws){ this->ws = ws; this->top = ws->top; @@ -2345,41 +2354,63 @@ public: VL_IN8(io_cpu_execute_args_invalidate,0,0); VL_IN8(io_cpu_execute_args_way,0,0); -// if(top->VexRiscv->dataCache_1->io_cpu_execute_isValid && !top->VexRiscv->dataCache_1->io_cpu_execute_isStuck -// && top->VexRiscv->dataCache_1->io_cpu_execute_args_wr){ -// if(top->VexRiscv->dataCache_1->io_cpu_execute_args_address == 0x80025978) -// cout << "WR 0x80025978 = " << hex << setw(8) << top->VexRiscv->dataCache_1->io_cpu_execute_args_data << endl; -// if(top->VexRiscv->dataCache_1->io_cpu_execute_args_address == 0x8002596c) -// cout << "WR 0x8002596c = " << hex << setw(8) << top->VexRiscv->dataCache_1->io_cpu_execute_args_data << endl; -// } if (top->dBus_cmd_valid && top->dBus_cmd_ready) { - if(pendingCount == 0){ - pendingCount = top->dBus_cmd_payload_length+1; - address = top->dBus_cmd_payload_address; - wr = top->dBus_cmd_payload_wr; - } - if(top->dBus_cmd_payload_wr){ - ws->dBusAccess(address,top->dBus_cmd_payload_wr,2,top->dBus_cmd_payload_mask,&top->dBus_cmd_payload_data,&error_next); - address += 4; - pendingCount--; - } + if(top->dBus_cmd_payload_wr){ + #ifndef SMP + bool error; + ws->dBusAccess(top->dBus_cmd_payload_address,1,2,top->dBus_cmd_payload_mask,&top->dBus_cmd_payload_data,&error); + #else + bool cancel = false; + DBusCachedTask rsp; + if(top->dBus_cmd_payload_exclusive){ + bool hit = reservationValid && reservationAddress == top->dBus_cmd_payload_address; + rsp.exclusive = hit; + cancel = !hit; + reservationValid = false; + } + if(!cancel) ws->dBusAccess(top->dBus_cmd_payload_address,1,2,top->dBus_cmd_payload_mask,&top->dBus_cmd_payload_data,&rsp.error); + rsp.last = true; + rsps.push(rsp); + #endif + } else { + for(int beat = 0;beat <= top->dBus_cmd_payload_length;beat++){ + DBusCachedTask rsp; + ws->dBusAccess(top->dBus_cmd_payload_address + beat * 4,0,2,0,&rsp.data,&rsp.error); + rsp.last = beat == top->dBus_cmd_payload_length; + #ifdef SMP + rsp.exclusive = true; + reservationValid = true; + reservationAddress = top->dBus_cmd_payload_address; + #endif + rsps.push(rsp); + } + } } } virtual void postCycle(){ - if(pendingCount != 0 && !wr && (!ws->dStall || VL_RANDOM_I(7) < 100)){ - ws->dBusAccess(address,0,2,0,&top->dBus_rsp_payload_data,&error_next); - top->dBus_rsp_payload_error = error_next; + + if(!rsps.empty() && (!ws->dStall || VL_RANDOM_I(7) < 100)){ + DBusCachedTask rsp = rsps.front(); + rsps.pop(); top->dBus_rsp_valid = 1; - address += 4; - pendingCount--; + top->dBus_rsp_payload_error = rsp.error; + top->dBus_rsp_payload_data = rsp.data; + top->dBus_rsp_payload_last = rsp.last; + #ifdef SMP + top->dBus_rsp_payload_exclusive = rsp.exclusive; + #endif } else{ top->dBus_rsp_valid = 0; top->dBus_rsp_payload_data = VL_RANDOM_I(32); top->dBus_rsp_payload_error = VL_RANDOM_I(1); + top->dBus_rsp_payload_last = VL_RANDOM_I(1); + #ifdef SMP + top->dBus_rsp_payload_exclusive = VL_RANDOM_I(1); + #endif } - top->dBus_cmd_ready = (ws->dStall ? VL_RANDOM_I(7) < 100 : 1) && (pendingCount == 0 || wr); + top->dBus_cmd_ready = (ws->dStall ? VL_RANDOM_I(7) < 100 : 1); } }; #endif diff --git a/src/test/cpp/regression/makefile b/src/test/cpp/regression/makefile index 2278d064..fba824e0 100644 --- a/src/test/cpp/regression/makefile +++ b/src/test/cpp/regression/makefile @@ -15,6 +15,7 @@ CSR_SKIP_TEST?=no EBREAK?=no FENCEI?=no MMU?=yes +SMP?=no SEED?=no LRSC?=no AMO?=no @@ -217,6 +218,10 @@ ifeq ($(MMU),yes) ADDCFLAGS += -CFLAGS -DMMU endif +ifeq ($(SMP),yes) + ADDCFLAGS += -CFLAGS -DSMP +endif + ifeq ($(MUL),yes) ADDCFLAGS += -CFLAGS -DMUL endif From ca72a421bec72d7cdf4fbc2e3c8b50c12e65031e Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sun, 5 Apr 2020 21:45:45 +0200 Subject: [PATCH 359/951] LrSc align software model to the hardware. Linux OK --- src/test/cpp/regression/main.cpp | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 8b959e24..62c58f29 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -376,6 +376,7 @@ public: bool lrscReserved; + uint32_t lrscReservedAddress; RiscvGolden() { pc = 0x80000000; @@ -891,6 +892,7 @@ public: trap(0, 5, address); } else { lrscReserved = true; + lrscReservedAddress = pAddr; rfWrite(rd32, data); pcWrite(pc + 4); } @@ -902,7 +904,7 @@ public: trap(0, 6, address); } else { if(v2p(address, &pAddr, WRITE)){ trap(0, 15, address); return; } - bool hit = lrscReserved; + bool hit = lrscReserved && lrscReservedAddress == pAddr; if(hit){ dWrite(pAddr, 4, i32_rs2); } @@ -1407,7 +1409,7 @@ public: virtual void pass(){ throw success();} virtual void fail(){ throw std::exception();} virtual void fillSimELements(); - void dump(int i){ + void dump(uint64_t i){ #ifdef TRACE if(i == TRACE_START && i != 0) cout << "**" << endl << "**" << endl << "**" << endl << "**" << endl << "**" << endl << "START TRACE" << endl; if(i >= TRACE_START) tfp->dump(i); @@ -2344,16 +2346,6 @@ public: } virtual void preCycle(){ - VL_IN8(io_cpu_execute_isValid,0,0); - VL_IN8(io_cpu_execute_isStuck,0,0); - VL_IN8(io_cpu_execute_args_kind,0,0); - VL_IN8(io_cpu_execute_args_wr,0,0); - VL_IN8(io_cpu_execute_args_size,1,0); - VL_IN8(io_cpu_execute_args_forceUncachedAccess,0,0); - VL_IN8(io_cpu_execute_args_clean,0,0); - VL_IN8(io_cpu_execute_args_invalidate,0,0); - VL_IN8(io_cpu_execute_args_way,0,0); - if (top->dBus_cmd_valid && top->dBus_cmd_ready) { if(top->dBus_cmd_payload_wr){ #ifndef SMP @@ -2378,9 +2370,11 @@ public: ws->dBusAccess(top->dBus_cmd_payload_address + beat * 4,0,2,0,&rsp.data,&rsp.error); rsp.last = beat == top->dBus_cmd_payload_length; #ifdef SMP - rsp.exclusive = true; - reservationValid = true; - reservationAddress = top->dBus_cmd_payload_address; + if(top->dBus_cmd_payload_exclusive){ + rsp.exclusive = true; + reservationValid = true; + reservationAddress = top->dBus_cmd_payload_address; + } #endif rsps.push(rsp); } From a107e45116af7404b2bd94949dee4acc2a57c1a8 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 6 Apr 2020 06:43:28 +0200 Subject: [PATCH 360/951] fix non smp regression --- src/test/cpp/regression/main.cpp | 6 +++++- src/test/scala/vexriscv/TestIndividualFeatures.scala | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 62c58f29..ac03373e 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -904,7 +904,11 @@ public: trap(0, 6, address); } else { if(v2p(address, &pAddr, WRITE)){ trap(0, 15, address); return; } - bool hit = lrscReserved && lrscReservedAddress == pAddr; + #ifdef SMP + bool hit = lrscReserved && lrscReservedAddress == pAddr; + #else + bool hit = lrscReserved; + #endif if(hit){ dWrite(pAddr, 4, i32_rs2); } diff --git a/src/test/scala/vexriscv/TestIndividualFeatures.scala b/src/test/scala/vexriscv/TestIndividualFeatures.scala index 9d147bc9..81112586 100644 --- a/src/test/scala/vexriscv/TestIndividualFeatures.scala +++ b/src/test/scala/vexriscv/TestIndividualFeatures.scala @@ -716,7 +716,7 @@ class TestIndividualFeatures extends MultithreadedFunSuite { //Test RTL val debug = true - val stdCmd = (s"make run REGRESSION_PATH=../../src/test/cpp/regression VEXRISCV_FILE=VexRiscv.v WITH_USER_IO=no REDO=10 TRACE=${if(debug) "yes" else "no"} TRACE_START=1000000000000l FLOW_INFO=no STOP_ON_ERROR=no DHRYSTONE=yes COREMARK=${coremarkRegression} THREAD_COUNT=1 ") + s" SEED=${testSeed} " + val stdCmd = (s"make run REGRESSION_PATH=../../src/test/cpp/regression VEXRISCV_FILE=VexRiscv.v WITH_USER_IO=no REDO=10 TRACE=${if(debug) "yes" else "no"} TRACE_START=1000000000ll FLOW_INFO=no STOP_ON_ERROR=no DHRYSTONE=yes COREMARK=${coremarkRegression} THREAD_COUNT=1 ") + s" SEED=${testSeed} " val testCmd = stdCmd + (positionsToApply).map(_.testParam).mkString(" ") println(testCmd) val str = doCmd(testCmd) From a52b833727456d8811c0f2f6c57fd84b58e940d9 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 6 Apr 2020 21:42:44 +0200 Subject: [PATCH 361/951] fix weird regression testbench memory bug --- src/test/cpp/regression/main.cpp | 4 ++-- src/test/scala/vexriscv/TestIndividualFeatures.scala | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index ac03373e..28d22eeb 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -1782,7 +1782,7 @@ public: virtual void dutPutChar(char c){ if(*hit == c) hit++; else hit = target; - if(*hit == NULL) { + if(*hit == 0) { cout << endl << "T=" << i <ws = ws; @@ -2370,7 +2371,6 @@ public: #endif } else { for(int beat = 0;beat <= top->dBus_cmd_payload_length;beat++){ - DBusCachedTask rsp; ws->dBusAccess(top->dBus_cmd_payload_address + beat * 4,0,2,0,&rsp.data,&rsp.error); rsp.last = beat == top->dBus_cmd_payload_length; #ifdef SMP diff --git a/src/test/scala/vexriscv/TestIndividualFeatures.scala b/src/test/scala/vexriscv/TestIndividualFeatures.scala index 81112586..d2922030 100644 --- a/src/test/scala/vexriscv/TestIndividualFeatures.scala +++ b/src/test/scala/vexriscv/TestIndividualFeatures.scala @@ -716,7 +716,7 @@ class TestIndividualFeatures extends MultithreadedFunSuite { //Test RTL val debug = true - val stdCmd = (s"make run REGRESSION_PATH=../../src/test/cpp/regression VEXRISCV_FILE=VexRiscv.v WITH_USER_IO=no REDO=10 TRACE=${if(debug) "yes" else "no"} TRACE_START=1000000000ll FLOW_INFO=no STOP_ON_ERROR=no DHRYSTONE=yes COREMARK=${coremarkRegression} THREAD_COUNT=1 ") + s" SEED=${testSeed} " + val stdCmd = (s"make run REGRESSION_PATH=../../src/test/cpp/regression VEXRISCV_FILE=VexRiscv.v WITH_USER_IO=no REDO=10 TRACE=${if(debug) "yes" else "no"} TRACE_START=100000000000ll FLOW_INFO=no STOP_ON_ERROR=no DHRYSTONE=yes COREMARK=${coremarkRegression} THREAD_COUNT=1 ") + s" SEED=${testSeed} " val testCmd = stdCmd + (positionsToApply).map(_.testParam).mkString(" ") println(testCmd) val str = doCmd(testCmd) From 5aa0b86d9697b6ab617966cbf6b0fbdb752d4418 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 7 Apr 2020 12:13:40 +0200 Subject: [PATCH 362/951] Fix DebugPlugin step by step --- src/main/scala/vexriscv/plugin/DebugPlugin.scala | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/DebugPlugin.scala b/src/main/scala/vexriscv/plugin/DebugPlugin.scala index 93e65e34..c04d167b 100644 --- a/src/main/scala/vexriscv/plugin/DebugPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DebugPlugin.scala @@ -213,18 +213,17 @@ class DebugPlugin(val debugClockDomain : ClockDomain, hardwareBreakpointCount : iBusFetcher.haltIt() } - when(stepIt) { - //Assume nothing will stop the CPU in the decode stage + when(stepIt && iBusFetcher.incoming()) { + iBusFetcher.haltIt() when(decode.arbitration.isValid) { haltIt := True - decode.arbitration.flushNext := True } } //Avoid having two C instruction executed in a single step if(pipeline(RVC_GEN)){ val cleanStep = RegNext(stepIt && decode.arbitration.isFiring) init(False) - decode.arbitration.removeIt setWhen(cleanStep) + execute.arbitration.flushNext setWhen(cleanStep) } io.resetOut := RegNext(resetIt) From ddc59bc40417fd8cf23bdcee482330430ab172a2 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 7 Apr 2020 12:13:40 +0200 Subject: [PATCH 363/951] Fix DebugPlugin step by step --- src/main/scala/vexriscv/plugin/DebugPlugin.scala | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/DebugPlugin.scala b/src/main/scala/vexriscv/plugin/DebugPlugin.scala index 93e65e34..c04d167b 100644 --- a/src/main/scala/vexriscv/plugin/DebugPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DebugPlugin.scala @@ -213,18 +213,17 @@ class DebugPlugin(val debugClockDomain : ClockDomain, hardwareBreakpointCount : iBusFetcher.haltIt() } - when(stepIt) { - //Assume nothing will stop the CPU in the decode stage + when(stepIt && iBusFetcher.incoming()) { + iBusFetcher.haltIt() when(decode.arbitration.isValid) { haltIt := True - decode.arbitration.flushNext := True } } //Avoid having two C instruction executed in a single step if(pipeline(RVC_GEN)){ val cleanStep = RegNext(stepIt && decode.arbitration.isFiring) init(False) - decode.arbitration.removeIt setWhen(cleanStep) + execute.arbitration.flushNext setWhen(cleanStep) } io.resetOut := RegNext(resetIt) From f20eb4d5413efc663c6882ad5ea7877b140b5dd1 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 18 Mar 2020 12:02:27 +0100 Subject: [PATCH 364/951] Merge pull request #115 from antmicro/fix_emulator emulator: Use external hw/common.h from LiteX --- src/main/c/emulator/makefile | 7 ++++--- src/main/c/emulator/src/hal.c | 32 -------------------------------- 2 files changed, 4 insertions(+), 35 deletions(-) diff --git a/src/main/c/emulator/makefile b/src/main/c/emulator/makefile index 7534d083..6f3c8fce 100755 --- a/src/main/c/emulator/makefile +++ b/src/main/c/emulator/makefile @@ -18,10 +18,11 @@ sim: all qemu: CFLAGS += -DQEMU qemu: all -litex: CFLAGS += -DLITEX -I${LITEX_BASE}/software/include -litex: | check_litex_base all -check_litex_base: +litex: CFLAGS += -DLITEX -I${LITEX_GENERATED} -I${LITEX_BASE}/litex/soc/software/include +litex: | check_litex all +check_litex: @[ "${LITEX_BASE}" ] || ( echo ">> LITEX_BASE is not set"; exit 1 ) + @[ "${LITEX_GENERATED}" ] || ( echo ">> LITEX_GENERATED is not set"; exit 1 ) include ${STANDALONE}/common/riscv64-unknown-elf.mk include ${STANDALONE}/common/standalone.mk diff --git a/src/main/c/emulator/src/hal.c b/src/main/c/emulator/src/hal.c index 5a151bb2..aa6745b9 100644 --- a/src/main/c/emulator/src/hal.c +++ b/src/main/c/emulator/src/hal.c @@ -146,38 +146,6 @@ void halInit(){ #ifdef LITEX -// this is copied from LiteX -#define CSR_ACCESSORS_DEFINED -static inline void csr_writeb(uint8_t value, unsigned long addr) -{ - *((volatile uint8_t *)addr) = value; -} - -static inline uint8_t csr_readb(unsigned long addr) -{ - return *(volatile uint8_t *)addr; -} - -static inline void csr_writew(uint16_t value, unsigned long addr) -{ - *((volatile uint16_t *)addr) = value; -} - -static inline uint16_t csr_readw(unsigned long addr) -{ - return *(volatile uint16_t *)addr; -} - -static inline void csr_writel(uint32_t value, unsigned long addr) -{ - *((volatile uint32_t *)addr) = value; -} - -static inline uint32_t csr_readl(unsigned long addr) -{ - return *(volatile uint32_t *)addr; -} - // this is a file generated by LiteX #include From 6e239fb2808743134108b159559584dbb36e169c Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 20 Mar 2020 11:26:38 +0100 Subject: [PATCH 365/951] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 22bfba82..84b811e2 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ For commercial support, please contact spinalhdl@gmail.com. ## Area usage and maximal frequency -The following numbers were obtained by synthesizing the CPU as toplevel without any specific synthesis options to save area or to get better maximal frequency (neutral).
+The following numbers were obtained by synthesizing the CPU as toplevel on the fastest speed grade without any specific synthesis options to save area or to get better maximal frequency (neutral).
The clock constraint is set to an unattainable value, which tends to increase the design area.
The dhrystone benchmark was compiled with the `-O3 -fno-inline` option.
All the cached configurations have some cache trashing during the dhrystone benchmark except the `VexRiscv full max perf` one. This, of course, reduces the performance. It is possible to produce From 5eaa5ba4db17b967549c669afcc20a74aebc47e8 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sat, 28 Mar 2020 15:38:32 +0100 Subject: [PATCH 366/951] Update README.md --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 84b811e2..bb37f034 100644 --- a/README.md +++ b/README.md @@ -824,6 +824,12 @@ This plugin implements the register file. This register file use a `don't care` read-during-write policy, so the bypassing/hazard plugin should take care of this. +If you get a `Missing inserts : INSTRUCTION_ANTICIPATE` error, that's because the RegFilePlugin is configured to use SYNC memory read ports to access the register file, but the IBus plugin configuration can't provide the instruction's register file read address one cycle before the decode stage. To workaround that you can : + +- Configure the RegFilePlugin to implement the register file read in a asyncronus manner (ASYNC), if your target device support such things +- If you use the IBusSimplePlugin, you need to enable the injectorStage configuration +- If you use the IBusCachedPlugin, you can either enable the injectorStage, or set twoCycleCache + twoCycleRam to false. + #### HazardSimplePlugin This plugin checks the pipeline instruction dependencies and, if necessary or possible, will stop the instruction in the decoding stage or bypass the instruction results From 0c8ea4a3681b3f800e01aadb20907b403c6e9dc6 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 7 Apr 2020 19:18:20 +0200 Subject: [PATCH 367/951] DataCache add invalidation feature --- src/main/scala/vexriscv/TestsWorkspace.scala | 5 +- src/main/scala/vexriscv/ip/DataCache.scala | 110 +++++++++++++++--- .../vexriscv/plugin/DBusCachedPlugin.scala | 3 + src/test/cpp/regression/main.cpp | 10 +- src/test/cpp/regression/makefile | 6 +- 5 files changed, 108 insertions(+), 26 deletions(-) diff --git a/src/main/scala/vexriscv/TestsWorkspace.scala b/src/main/scala/vexriscv/TestsWorkspace.scala index 9c223a72..51776313 100644 --- a/src/main/scala/vexriscv/TestsWorkspace.scala +++ b/src/main/scala/vexriscv/TestsWorkspace.scala @@ -27,7 +27,7 @@ import spinal.lib.bus.avalon.AvalonMM import spinal.lib.eda.altera.{InterruptReceiverTag, ResetEmitterTag} -//make clean all SEED=42 MMU=no STOP_ON_ERROR=yes SMP=yes SUPERVISOR=yes REDO=10 DHRYSTONE=no LRSC=yes LINUX_REGRESSION=yes TRACE=yes TRACE_START=1000000000000l FLOW_INFO=no +//make clean all SEED=42 MMU=no STOP_ON_ERROR=yes DBUS_EXCLUSIVE=yes SUPERVISOR=yes REDO=10 DHRYSTONE=no LRSC=yes LINUX_REGRESSION=yes TRACE=yes TRACE_START=1000000000000l FLOW_INFO=no object TestsWorkspace { def main(args: Array[String]) { def configFull = { @@ -102,7 +102,8 @@ object TestsWorkspace { catchUnaligned = true, withLrSc = true, withAmo = false, - withSmp = true + withExclusive = true, + withInvalidate = true // ) ), memoryTranslatorPortConfig = MmuPortConfig( diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index 758186ab..a69f8973 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -25,7 +25,8 @@ case class DataCacheConfig(cacheSize : Int, tagSizeShift : Int = 0, //Used to force infering ram withLrSc : Boolean = false, withAmo : Boolean = false, - withSmp : Boolean = false, + withExclusive : Boolean = false, + withInvalidate : Boolean = false, pendingMax : Int = 64, mergeExecuteMemory : Boolean = false){ assert(!(mergeExecuteMemory && (earlyDataMux || earlyWaysHits))) @@ -33,9 +34,9 @@ case class DataCacheConfig(cacheSize : Int, def burstSize = bytePerLine*8/memDataWidth val burstLength = bytePerLine/(memDataWidth/8) def catchSomething = catchUnaligned || catchIllegal || catchAccessError - def withInternalAmo = withAmo && !withSmp - def withInternalLrSc = withLrSc && !withSmp - def withExternalLrSc = withLrSc && withSmp + def withInternalAmo = withAmo && !withExclusive + def withInternalLrSc = withLrSc && !withExclusive + def withExternalLrSc = withLrSc && withExclusive def getAxi4SharedConfig() = Axi4Config( addressWidth = addressWidth, dataWidth = memDataWidth, @@ -171,14 +172,30 @@ case class DataCacheMemCmd(p : DataCacheConfig) extends Bundle{ val data = Bits(p.memDataWidth bits) val mask = Bits(p.memDataWidth/8 bits) val length = UInt(log2Up(p.burstLength) bits) - val exclusive = p.withSmp generate Bool() + val exclusive = p.withExclusive generate Bool() val last = Bool } case class DataCacheMemRsp(p : DataCacheConfig) extends Bundle{ val last = Bool() val data = Bits(p.memDataWidth bit) val error = Bool - val exclusive = p.withSmp generate Bool() + val exclusive = p.withExclusive generate Bool() +} +case class DataCacheInvalidateCmd(p : DataCacheConfig) extends Bundle{ + val address = UInt(p.addressWidth bit) +} +case class DataCacheInvalidateRsp(p : DataCacheConfig) extends Bundle{ + val hit = Bool() +} + +case class DataCacheInvalidateBus(p : DataCacheConfig) extends Bundle with IMasterSlave { + val cmd = Stream(DataCacheInvalidateCmd(p)) + val rsp = Stream(DataCacheInvalidateRsp(p)) + + override def asMaster(): Unit = { + master(cmd) + slave(rsp) + } } case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave{ @@ -353,7 +370,7 @@ class DataCache(p : DataCacheConfig) extends Component{ val io = new Bundle{ val cpu = slave(DataCacheCpuBus(p)) val mem = master(DataCacheMemBus(p)) - // val flushDone = out Bool //It pulse at the same time than the manager.request.fire + val inv = withInvalidate generate slave(DataCacheInvalidateBus(p)) } val haltCpu = False @@ -371,6 +388,7 @@ class DataCache(p : DataCacheConfig) 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 hitRange = tagRange.high downto lineRange.low class LineInfo() extends Bundle{ @@ -379,6 +397,7 @@ class DataCache(p : DataCacheConfig) extends Component{ } val tagsReadCmd = Flow(UInt(log2Up(wayLineCount) bits)) + val tagsInvReadCmd = withInvalidate generate Flow(UInt(log2Up(wayLineCount) bits)) val tagsWriteCmd = Flow(new Bundle{ val way = Bits(wayCount bits) val address = UInt(log2Up(wayLineCount) bits) @@ -403,6 +422,7 @@ class DataCache(p : DataCacheConfig) extends Component{ //Reads val tagsReadRsp = tags.readSync(tagsReadCmd.payload, tagsReadCmd.valid && !io.cpu.memory.isStuck) + val tagsInvReadRsp = withInvalidate generate tags.readSync(tagsInvReadCmd.payload, tagsReadCmd.valid && !io.cpu.memory.isStuck) val dataReadRsp = data.readSync(dataReadCmd.payload, dataReadCmd.valid && !io.cpu.memory.isStuck) //Writes @@ -449,7 +469,7 @@ class DataCache(p : DataCacheConfig) extends Component{ val rspSync = True val rspLast = True val memCmdSent = RegInit(False) setWhen (io.mem.cmd.ready) clearWhen (!io.cpu.writeBack.isStuck) - val pending = withSmp generate new Area{ + val pending = withExclusive generate new Area{ val counter = Reg(UInt(log2Up(pendingMax) + 1 bits)) init(0) counter := counter + U(io.mem.cmd.fire && io.mem.cmd.last) - U(io.mem.rsp.valid && io.mem.rsp.last) @@ -468,7 +488,8 @@ class DataCache(p : DataCacheConfig) extends Component{ U(1) -> B"0011", default -> B"1111" ) |<< io.cpu.execute.address(1 downto 0) - val colisions = collisionProcess(io.cpu.execute.address(lineRange.high downto wordRange.low), mask) + val dataColisions = collisionProcess(io.cpu.execute.address(lineRange.high downto wordRange.low), mask) + val wayInvalidate = B(0, wayCount bits) //Used if invalidate enabled } val stageA = new Area{ @@ -483,11 +504,12 @@ class DataCache(p : DataCacheConfig) extends Component{ val wayHits = earlyWaysHits generate ways.map(way => (io.cpu.memory.mmuBus.rsp.physicalAddress(tagRange) === way.tagsReadRsp.address && way.tagsReadRsp.valid)) val dataMux = earlyDataMux generate MuxOH(wayHits, ways.map(_.dataReadRsp)) - val colisions = if(mergeExecuteMemory){ - stagePipe(stage0.colisions) + val wayInvalidate = stagePipe(stage0. wayInvalidate) + val dataColisions = if(mergeExecuteMemory){ + stagePipe(stage0.dataColisions) } else { //Assume the writeback stage will never be unstall memory acces while memory stage is stalled - stagePipe(stage0.colisions) | collisionProcess(io.cpu.memory.address(lineRange.high downto wordRange.low), mask) + stagePipe(stage0.dataColisions) | collisionProcess(io.cpu.memory.address(lineRange.high downto wordRange.low), mask) } } @@ -499,11 +521,13 @@ class DataCache(p : DataCacheConfig) extends Component{ val mmuRsp = RegNextWhen(io.cpu.memory.mmuBus.rsp, !io.cpu.writeBack.isStuck && !mmuRspFreeze) val tagsReadRsp = ways.map(w => ramPipe(w.tagsReadRsp)) val dataReadRsp = !earlyDataMux generate ways.map(w => ramPipe(w.dataReadRsp)) - val waysHits = if(earlyWaysHits) stagePipe(B(stageA.wayHits)) else B(tagsReadRsp.map(tag => mmuRsp.physicalAddress(tagRange) === tag.address && tag.valid).asBits()) + val wayInvalidate = stagePipe(stageA. wayInvalidate) + val dataColisions = stagePipe(stageA.dataColisions) + val waysHitsBeforeInvalidate = if(earlyWaysHits) stagePipe(B(stageA.wayHits)) else B(tagsReadRsp.map(tag => mmuRsp.physicalAddress(tagRange) === tag.address && tag.valid).asBits()) + val waysHits = waysHitsBeforeInvalidate & ~wayInvalidate val waysHit = waysHits.orR val dataMux = if(earlyDataMux) stagePipe(stageA.dataMux) else MuxOH(waysHits, dataReadRsp) val mask = stagePipe(stageA.mask) - val colisions = stagePipe(stageA.colisions) //Loader interface val loaderValid = False @@ -631,8 +655,8 @@ class DataCache(p : DataCacheConfig) extends Component{ } } - //On write to read colisions - when((!request.wr || isAmo) && (colisions & waysHits) =/= 0){ + //On write to read dataColisions + when((!request.wr || isAmo) && (dataColisions & waysHits) =/= 0){ io.cpu.redo := True if(withAmo) io.mem.cmd.valid := False } @@ -699,6 +723,7 @@ class DataCache(p : DataCacheConfig) extends Component{ val counter = Counter(memTransactionPerLine) val waysAllocator = Reg(Bits(wayCount bits)) init(1) val error = RegInit(False) + val kill = False when(valid && io.mem.rsp.valid && rspLast){ dataWriteCmd.valid := True @@ -731,5 +756,58 @@ class DataCache(p : DataCacheConfig) extends Component{ io.cpu.redo setWhen(valid) stageB.mmuRspFreeze setWhen(stageB.loaderValid || valid) + + when(kill){ + valid := False + error := False + tagsWriteCmd.valid := False + counter.clear() + } + } + + val invalidate = withInvalidate generate new Area{ + val loaderReadToWriteConflict = False + val s0 = new Area{ + val input = io.inv.cmd.haltWhen(loaderReadToWriteConflict) + tagsInvReadCmd.valid := input.fire + tagsInvReadCmd.payload := input.address(lineRange) + + val loaderHit = loader.valid && input.address(hitRange) === loader.baseAddress(hitRange) + when(loaderHit){ + loader.kill := True + } + } + val s1 = new Area{ + val input = s0.input.stage() + val loaderValid = RegNextWhen(loader.valid, s0.input.ready) + val loaderWay = RegNextWhen(loader.waysAllocator, s0.input.ready) + val loaderHit = RegNextWhen(s0.loaderHit, s0.input.ready) + + var wayHits = B(ways.map(way => (input.address(tagRange) === way.tagsInvReadRsp.address && way.tagsInvReadRsp.valid))) + + //Handle invalider read during loader write hazard + when(loaderValid && !loaderHit){ + wayHits \= wayHits & ~loaderWay + } + } + val s2 = new Area{ + val input = s1.input.stage() + val wayHits = RegNextWhen(s1.wayHits, s1.input.ready) + val wayHit = wayHits.orR + + when(input.valid) { + stage0.wayInvalidate := wayHits + + when(wayHit) { + tagsWriteCmd.valid := True + tagsWriteCmd.address := input.address(lineRange) + tagsWriteCmd.data.valid := False + tagsWriteCmd.way := wayHits + loaderReadToWriteConflict := input.address(lineRange) === s0.input.address(lineRange) + } + } + io.inv.rsp.arbitrationFrom(input) + io.inv.rsp.hit := wayHit + } } } \ No newline at end of file diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index 958d1a8e..2764637f 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -31,6 +31,7 @@ class DBusCachedPlugin(val config : DataCacheConfig, assert(!(memoryTranslatorPortConfig != null && config.cacheSize/config.wayCount > 4096), "When the D$ is used with MMU, each way can't be bigger than a page (4096 bytes)") var dBus : DataCacheMemBus = null + var inv : DataCacheInvalidateBus = null var mmuBus : MemoryTranslatorBus = null var exceptionBus : Flow[ExceptionCause] = null var privilegeService : PrivilegeService = null @@ -161,6 +162,7 @@ class DBusCachedPlugin(val config : DataCacheConfig, import pipeline.config._ dBus = master(DataCacheMemBus(this.config)).setName("dBus") + inv = withInvalidate generate slave(DataCacheInvalidateBus(this.config)) val cache = new DataCache(this.config.copy( mergeExecuteMemory = writeBack == null @@ -171,6 +173,7 @@ class DBusCachedPlugin(val config : DataCacheConfig, def cmdBuf = optionPipe(dBusCmdSlavePipe, cache.io.mem.cmd)(_.s2mPipe()) dBus.cmd << optionPipe(dBusCmdMasterPipe, cmdBuf)(_.m2sPipe()) cache.io.mem.rsp << optionPipe(dBusRspSlavePipe,dBus.rsp)(_.m2sPipe()) + cache.io.inv <> inv pipeline plug new Area{ //Memory bandwidth counter diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 28d22eeb..47a822b6 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -904,7 +904,7 @@ public: trap(0, 6, address); } else { if(v2p(address, &pAddr, WRITE)){ trap(0, 15, address); return; } - #ifdef SMP + #ifdef DBUS_EXCLUSIVE bool hit = lrscReserved && lrscReservedAddress == pAddr; #else bool hit = lrscReserved; @@ -2353,7 +2353,7 @@ public: virtual void preCycle(){ if (top->dBus_cmd_valid && top->dBus_cmd_ready) { if(top->dBus_cmd_payload_wr){ - #ifndef SMP + #ifndef DBUS_EXCLUSIVE bool error; ws->dBusAccess(top->dBus_cmd_payload_address,1,2,top->dBus_cmd_payload_mask,&top->dBus_cmd_payload_data,&error); #else @@ -2373,7 +2373,7 @@ public: for(int beat = 0;beat <= top->dBus_cmd_payload_length;beat++){ ws->dBusAccess(top->dBus_cmd_payload_address + beat * 4,0,2,0,&rsp.data,&rsp.error); rsp.last = beat == top->dBus_cmd_payload_length; - #ifdef SMP + #ifdef DBUS_EXCLUSIVE if(top->dBus_cmd_payload_exclusive){ rsp.exclusive = true; reservationValid = true; @@ -2395,7 +2395,7 @@ public: top->dBus_rsp_payload_error = rsp.error; top->dBus_rsp_payload_data = rsp.data; top->dBus_rsp_payload_last = rsp.last; - #ifdef SMP + #ifdef DBUS_EXCLUSIVE top->dBus_rsp_payload_exclusive = rsp.exclusive; #endif } else{ @@ -2403,7 +2403,7 @@ public: top->dBus_rsp_payload_data = VL_RANDOM_I(32); top->dBus_rsp_payload_error = VL_RANDOM_I(1); top->dBus_rsp_payload_last = VL_RANDOM_I(1); - #ifdef SMP + #ifdef DBUS_EXCLUSIVE top->dBus_rsp_payload_exclusive = VL_RANDOM_I(1); #endif } diff --git a/src/test/cpp/regression/makefile b/src/test/cpp/regression/makefile index fba824e0..48e55515 100644 --- a/src/test/cpp/regression/makefile +++ b/src/test/cpp/regression/makefile @@ -15,7 +15,7 @@ CSR_SKIP_TEST?=no EBREAK?=no FENCEI?=no MMU?=yes -SMP?=no +DBUS_EXCLUSIVE?=no SEED?=no LRSC?=no AMO?=no @@ -218,8 +218,8 @@ ifeq ($(MMU),yes) ADDCFLAGS += -CFLAGS -DMMU endif -ifeq ($(SMP),yes) - ADDCFLAGS += -CFLAGS -DSMP +ifeq ($(DBUS_EXCLUSIVE),yes) + ADDCFLAGS += -CFLAGS -DDBUS_EXCLUSIVE endif ifeq ($(MUL),yes) From 9e1817a28034bab4a07782b1320bffe345335e76 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 7 Apr 2020 20:05:24 +0200 Subject: [PATCH 368/951] fix DataCache for config without invalidation --- src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index 2764637f..7df58ce5 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -173,7 +173,7 @@ class DBusCachedPlugin(val config : DataCacheConfig, def cmdBuf = optionPipe(dBusCmdSlavePipe, cache.io.mem.cmd)(_.s2mPipe()) dBus.cmd << optionPipe(dBusCmdMasterPipe, cmdBuf)(_.m2sPipe()) cache.io.mem.rsp << optionPipe(dBusRspSlavePipe,dBus.rsp)(_.m2sPipe()) - cache.io.inv <> inv + if(withInvalidate) cache.io.inv <> inv pipeline plug new Area{ //Memory bandwidth counter From 6922f80a87c140ce1cf7f878eff276d29dc6e6a9 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 8 Apr 2020 18:12:13 +0200 Subject: [PATCH 369/951] DataCache now implement fence operations --- src/main/scala/vexriscv/ip/DataCache.scala | 10 +++++- .../vexriscv/plugin/DBusCachedPlugin.scala | 35 ++++++++++++++++++- 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index a69f8973..85d7d0c8 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -31,6 +31,7 @@ case class DataCacheConfig(cacheSize : Int, mergeExecuteMemory : Boolean = false){ assert(!(mergeExecuteMemory && (earlyDataMux || earlyWaysHits))) assert(!(earlyDataMux && !earlyWaysHits)) + def withWriteResponse = withExclusive def burstSize = bytePerLine*8/memDataWidth val burstLength = bytePerLine/(memDataWidth/8) def catchSomething = catchUnaligned || catchIllegal || catchAccessError @@ -95,9 +96,10 @@ case class DataCacheCpuExecute(p : DataCacheConfig) extends Bundle with IMasterS val address = UInt(p.addressWidth bit) val haltIt = Bool val args = DataCacheCpuExecuteArgs(p) + val fence = Bool() override def asMaster(): Unit = { - out(isValid, args, address) + out(isValid, args, address, fence) in(haltIt) } } @@ -490,6 +492,12 @@ class DataCache(p : DataCacheConfig) extends Component{ ) |<< io.cpu.execute.address(1 downto 0) val dataColisions = collisionProcess(io.cpu.execute.address(lineRange.high downto wordRange.low), mask) val wayInvalidate = B(0, wayCount bits) //Used if invalidate enabled + + if(withWriteResponse) when(io.cpu.execute.fence){ + when(pending.counter =/= 0 || io.cpu.memory.isValid || io.cpu.writeBack.isValid){ + io.cpu.execute.haltIt := True + } + } } val stageA = new Area{ diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index 7df58ce5..0d7c930d 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -50,6 +50,8 @@ class DBusCachedPlugin(val config : DataCacheConfig, object MEMORY_ADDRESS_LOW extends Stageable(UInt(2 bits)) object MEMORY_LRSC extends Stageable(Bool) object MEMORY_AMO extends Stageable(Bool) + object MEMORY_FENCE extends Stageable(Bool) + object MEMORY_FENCE_DECODED extends Stageable(Bool) object IS_DBUS_SHARING extends Stageable(Bool()) object MEMORY_VIRTUAL_ADDRESS extends Stageable(UInt(32 bits)) @@ -143,7 +145,13 @@ class DBusCachedPlugin(val config : DataCacheConfig, MEMORY_MANAGMENT -> True )) - decoderService.add(FENCE, Nil) + withWriteResponse match { + case false => decoderService.add(FENCE, Nil) + case true => { + decoderService.addDefault(MEMORY_FENCE, False) + decoderService.add(FENCE, List(MEMORY_FENCE -> True)) + } + } mmuBus = pipeline.service(classOf[MemoryTranslator]).newTranslationPort(MemoryTranslatorPort.PRIORITY_DATA ,memoryTranslatorPortConfig) redoBranch = pipeline.service(classOf[JumpService]).createJumpInterface(if(pipeline.writeBack != null) pipeline.writeBack else pipeline.memory) @@ -189,6 +197,30 @@ class DBusCachedPlugin(val config : DataCacheConfig, when(mmuBus.busy && arbitration.isValid && input(MEMORY_ENABLE)) { arbitration.haltItself := True } + + case class FenceFlags() extends Bundle { + val SW,SR,SO,SI,PW,PR,PO,PI = Bool() + val FM = Bits(4 bits) + + def SL = SR || SI + def SS = SW || SO + def PL = PR || PI + def PS = PW || PO + } + + val fence = new Area{ + val hazard = False + val ff = input(INSTRUCTION)(31 downto 20).as(FenceFlags()) + if(withWriteResponse){ + hazard setWhen(input(MEMORY_FENCE) && (ff.PS && ff.SL)) //Manage write to read hit ordering (ensure invalidation timings) +// Not required as LR SC AMO naturaly enforce ordering +// when(input(INSTRUCTION)(26 downto 25) =/= 0){ +// if(withLrSc) hazard setWhen(input(MEMORY_LRSC)) +// if(withAmo) hazard setWhen(input(MEMORY_AMO)) +// } + } + insert(MEMORY_FENCE_DECODED) := hazard + } } execute plug new Area { @@ -207,6 +239,7 @@ class DBusCachedPlugin(val config : DataCacheConfig, cache.io.cpu.flush.valid := arbitration.isValid && input(MEMORY_MANAGMENT) + cache.io.cpu.execute.fence := arbitration.isValid && input(MEMORY_FENCE_DECODED) arbitration.haltItself setWhen(cache.io.cpu.flush.isStall || cache.io.cpu.execute.haltIt) if(withLrSc) { From 861df664cf0f6a29196b6642445461fe95dc4283 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 8 Apr 2020 18:48:01 +0200 Subject: [PATCH 370/951] clean some AMO stuff --- src/main/scala/vexriscv/ip/DataCache.scala | 7 ++++--- src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index 85d7d0c8..d0a536b1 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -629,6 +629,7 @@ class DataCache(p : DataCacheConfig) extends Component{ if(withExternalLrSc) io.mem.cmd.exclusive := request.isLrsc || (if(withAmo) request.isAmo else False) val bypassCache = mmuRsp.isIoAccess || (if(withExternalLrSc) request.isLrsc else False) + val isAmoCached = if(withInternalAmo) isAmo else False when(io.cpu.writeBack.isValid) { when(bypassCache) { @@ -646,7 +647,7 @@ class DataCache(p : DataCacheConfig) extends Component{ io.cpu.writeBack.haltIt := False } } otherwise { - when(waysHit || request.wr && !isAmo) { //Do not require a cache refill ? + when(waysHit || request.wr && !isAmoCached) { //Do not require a cache refill ? cpuWriteToCache := True //Write through @@ -655,7 +656,7 @@ class DataCache(p : DataCacheConfig) extends Component{ io.mem.cmd.length := 0 io.cpu.writeBack.haltIt clearWhen(!request.wr || io.mem.cmd.ready) - if(withAmo) when(isAmo){ + if(withInternalAmo) when(isAmo){ when(!internalAmo.resultRegValid) { io.mem.cmd.valid := False dataWriteCmd.valid := False @@ -664,7 +665,7 @@ class DataCache(p : DataCacheConfig) extends Component{ } //On write to read dataColisions - when((!request.wr || isAmo) && (dataColisions & waysHits) =/= 0){ + when((!request.wr || isAmoCached) && (dataColisions & waysHits) =/= 0){ io.cpu.redo := True if(withAmo) io.mem.cmd.valid := False } diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index 0d7c930d..3a13a7ca 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -213,7 +213,7 @@ class DBusCachedPlugin(val config : DataCacheConfig, val ff = input(INSTRUCTION)(31 downto 20).as(FenceFlags()) if(withWriteResponse){ hazard setWhen(input(MEMORY_FENCE) && (ff.PS && ff.SL)) //Manage write to read hit ordering (ensure invalidation timings) -// Not required as LR SC AMO naturaly enforce ordering +// Not required as LR SC AMO emited on the memory bus enforce the ordering, + it bypass the cache // when(input(INSTRUCTION)(26 downto 25) =/= 0){ // if(withLrSc) hazard setWhen(input(MEMORY_LRSC)) // if(withAmo) hazard setWhen(input(MEMORY_AMO)) From 1d0e180e1d9eb611645b00f614639c9dbdef576b Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 9 Apr 2020 20:11:56 +0200 Subject: [PATCH 371/951] Add GenTwoStage config and UltraScale synthesis --- .../scala/vexriscv/demo/GenTwoStage.scala | 71 ++++++++++++ .../scala/vexriscv/demo/SynthesisBench.scala | 101 ++++++++++++++++-- src/test/scala/vexriscv/DhrystoneBench.scala | 42 +++++++- 3 files changed, 205 insertions(+), 9 deletions(-) create mode 100644 src/main/scala/vexriscv/demo/GenTwoStage.scala diff --git a/src/main/scala/vexriscv/demo/GenTwoStage.scala b/src/main/scala/vexriscv/demo/GenTwoStage.scala new file mode 100644 index 00000000..b3d08047 --- /dev/null +++ b/src/main/scala/vexriscv/demo/GenTwoStage.scala @@ -0,0 +1,71 @@ +package vexriscv.demo + +import spinal.core.SpinalVerilog +import vexriscv.{VexRiscv, VexRiscvConfig, plugin} +import vexriscv.plugin.{BranchPlugin, CsrPlugin, CsrPluginConfig, DBusSimplePlugin, DecoderSimplePlugin, DivPlugin, FullBarrelShifterPlugin, HazardSimplePlugin, IBusSimplePlugin, IntAluPlugin, LightShifterPlugin, MulPlugin, MulSimplePlugin, NONE, RegFilePlugin, SrcPlugin, YamlPlugin} + +object GenTwoStage extends App{ + def cpu(withMulDiv : Boolean, + bypass : Boolean, + barrielShifter : Boolean) = new VexRiscv( + config = VexRiscvConfig( + withMemoryStage = false, + withWriteBackStage = false, + plugins = List( + new IBusSimplePlugin( + resetVector = 0x80000000l, + cmdForkOnSecondStage = false, + cmdForkPersistence = false, + prediction = NONE, + catchAccessFault = false, + compressedGen = false, + injectorStage = false + ), + new DBusSimplePlugin( + catchAddressMisaligned = false, + catchAccessFault = false + ), + new CsrPlugin(CsrPluginConfig.smallest), + new DecoderSimplePlugin( + catchIllegalInstruction = false + ), + new RegFilePlugin( + regFileReadyKind = plugin.SYNC, + readInExecute = true, + zeroBoot = true, + x0Init = false + ), + new IntAluPlugin, + new SrcPlugin( + separatedAddSub = false, + executeInsertion = true + ), + new HazardSimplePlugin( + bypassExecute = bypass, + bypassMemory = false, + bypassWriteBack = false, + bypassWriteBackBuffer = bypass, + pessimisticUseSrc = false, + pessimisticWriteRegFile = false, + pessimisticAddressMatch = false + ), + new BranchPlugin( + earlyBranch = true, + catchAddressMisaligned = false + ), + new YamlPlugin("cpu0.yaml") + ) ++ (if(!withMulDiv) Nil else List( + new MulSimplePlugin, + new DivPlugin + )) ++ List(if(!barrielShifter) + new LightShifterPlugin + else + new FullBarrelShifterPlugin( + earlyInjection = true + ) + ) + ) + ) + + SpinalVerilog(cpu(false,false,false)) +} diff --git a/src/main/scala/vexriscv/demo/SynthesisBench.scala b/src/main/scala/vexriscv/demo/SynthesisBench.scala index a9961a96..3d9dbf9e 100644 --- a/src/main/scala/vexriscv/demo/SynthesisBench.scala +++ b/src/main/scala/vexriscv/demo/SynthesisBench.scala @@ -4,6 +4,7 @@ import spinal.core._ import spinal.lib._ import spinal.lib.eda.bench._ import spinal.lib.eda.icestorm.IcestormStdTargets +import spinal.lib.eda.xilinx.VivadoFlow import spinal.lib.io.InOutWrapper import vexriscv.VexRiscv import vexriscv.plugin.DecoderSimplePlugin @@ -49,6 +50,42 @@ object VexRiscvSynthesisBench { // top // } + val twoStage = new Rtl { + override def getName(): String = "VexRiscv two stages" + override def getRtlPath(): String = "VexRiscvTwoStages.v" + SpinalVerilog(wrap(GenTwoStage.cpu( + withMulDiv = false, + bypass = false, + barrielShifter = false + )).setDefinitionName(getRtlPath().split("\\.").head)) + } + val twoStageBarell = new Rtl { + override def getName(): String = "VexRiscv two stages with barriel" + override def getRtlPath(): String = "VexRiscvTwoStagesBar.v" + SpinalVerilog(wrap(GenTwoStage.cpu( + withMulDiv = false, + bypass = true, + barrielShifter = true + )).setDefinitionName(getRtlPath().split("\\.").head)) + } + val twoStageMulDiv = new Rtl { + override def getName(): String = "VexRiscv two stages with Mul Div" + override def getRtlPath(): String = "VexRiscvTwoStagesMD.v" + SpinalVerilog(wrap(GenTwoStage.cpu( + withMulDiv = true, + bypass = false, + barrielShifter = false + )).setDefinitionName(getRtlPath().split("\\.").head)) + } + val twoStageAll = new Rtl { + override def getName(): String = "VexRiscv two stages with Mul Div fast" + override def getRtlPath(): String = "VexRiscvTwoStagesMDfast.v" + SpinalVerilog(wrap(GenTwoStage.cpu( + withMulDiv = true, + bypass = true, + barrielShifter = true + )).setDefinitionName(getRtlPath().split("\\.").head)) + } val smallestNoCsr = new Rtl { override def getName(): String = "VexRiscv smallest no CSR" override def getRtlPath(): String = "VexRiscvSmallestNoCsr.v" @@ -109,13 +146,63 @@ object VexRiscvSynthesisBench { SpinalConfig(inlineRom = true).generateVerilog(wrap(new VexRiscv(LinuxGen.configFull(false, true))).setDefinitionName(getRtlPath().split("\\.").head)) } - val rtls = List(smallestNoCsr, smallest, smallAndProductive, smallAndProductiveWithICache, fullNoMmuNoCache, noCacheNoMmuMaxPerf, fullNoMmuMaxPerf, fullNoMmu, full, linuxBalanced) -// val rtls = List(smallestNoCsr, smallest, smallAndProductive, smallAndProductiveWithICache) - // val rtls = List(smallAndProductive, smallAndProductiveWithICache, fullNoMmuMaxPerf, fullNoMmu, full) -// val rtls = List(smallAndProductive) - - val targets = XilinxStdTargets() ++ AlteraStdTargets() ++ IcestormStdTargets().take(1) - + val rtls = List(twoStage, twoStageBarell, twoStageMulDiv, twoStageAll, smallestNoCsr, smallest, smallAndProductive, smallAndProductiveWithICache, fullNoMmuNoCache, noCacheNoMmuMaxPerf, fullNoMmuMaxPerf, fullNoMmu, full, linuxBalanced) +// val rtls = List(twoStage, twoStageBarell, twoStageMulDiv, twoStageAll) +// val rtls = List(smallest) + val targets = XilinxStdTargets() ++ AlteraStdTargets() ++ IcestormStdTargets().take(1) ++ List( + new Target { + override def getFamilyName(): String = "Kintex UltraScale" + override def synthesise(rtl: Rtl, workspace: String): Report = { + VivadoFlow( + frequencyTarget = 50 MHz, + vivadoPath=sys.env.getOrElse("VIVADO_ARTIX_7_BIN", null), + workspacePath=workspace + "_area", + toplevelPath=rtl.getRtlPath(), + family=getFamilyName(), + device="xcku035-fbva900-3-e" + ) + } + }, + new Target { + override def getFamilyName(): String = "Kintex UltraScale" + override def synthesise(rtl: Rtl, workspace: String): Report = { + VivadoFlow( + frequencyTarget = 800 MHz, + vivadoPath=sys.env.getOrElse("VIVADO_ARTIX_7_BIN", null), + workspacePath=workspace + "_fmax", + toplevelPath=rtl.getRtlPath(), + family=getFamilyName(), + device="xcku035-fbva900-3-e" + ) + } + }, + new Target { + override def getFamilyName(): String = "Kintex UltraScale+" + override def synthesise(rtl: Rtl, workspace: String): Report = { + VivadoFlow( + frequencyTarget = 50 MHz, + vivadoPath=sys.env.getOrElse("VIVADO_ARTIX_7_BIN", null), + workspacePath=workspace + "_area", + toplevelPath=rtl.getRtlPath(), + family=getFamilyName(), + device="xcku3p-ffvd900-3-e" + ) + } + }, + new Target { + override def getFamilyName(): String = "Kintex UltraScale+" + override def synthesise(rtl: Rtl, workspace: String): Report = { + VivadoFlow( + frequencyTarget = 800 MHz, + vivadoPath=sys.env.getOrElse("VIVADO_ARTIX_7_BIN", null), + workspacePath=workspace + "_fmax", + toplevelPath=rtl.getRtlPath(), + family=getFamilyName(), + device="xcku3p-ffvd900-3-e" + ) + } + } + ) // val targets = IcestormStdTargets() Bench(rtls, targets) } diff --git a/src/test/scala/vexriscv/DhrystoneBench.scala b/src/test/scala/vexriscv/DhrystoneBench.scala index d23c4e1d..39c434a0 100644 --- a/src/test/scala/vexriscv/DhrystoneBench.scala +++ b/src/test/scala/vexriscv/DhrystoneBench.scala @@ -2,7 +2,8 @@ package vexriscv import java.io.File -import org.scalatest.{FunSuite} +import org.scalatest.FunSuite +import spinal.core.SpinalVerilog import vexriscv.demo._ import scala.sys.process._ @@ -42,6 +43,43 @@ class DhrystoneBench extends FunSuite{ } + getDmips( + name = "GenTwoStageArty", + gen = SpinalVerilog(GenTwoStage.cpu( + withMulDiv = false, + bypass = false, + barrielShifter = false + )), + testCmd = "make clean run REDO=10 IBUS=SIMPLE DBUS=SIMPLE CSR=no MMU=no DEBUG_PLUGIN=no MUL=no DIV=no COREMARK=yes" + ) + getDmips( + name = "GenTwoStageBarrielArty", + gen = SpinalVerilog(GenTwoStage.cpu( + withMulDiv = false, + bypass = true, + barrielShifter = true + )), + testCmd = "make clean run REDO=10 IBUS=SIMPLE DBUS=SIMPLE CSR=no MMU=no DEBUG_PLUGIN=no MUL=no DIV=no COREMARK=yes" + ) + getDmips( + name = "GenTwoStageMDArty", + gen = SpinalVerilog(GenTwoStage.cpu( + withMulDiv = true, + bypass = false, + barrielShifter = false + )), + testCmd = "make clean run REDO=10 IBUS=SIMPLE DBUS=SIMPLE CSR=no MMU=no DEBUG_PLUGIN=no MUL=yes DIV=yes COREMARK=yes" + ) + getDmips( + name = "GenTwoStageMDBarrielArty", + gen = SpinalVerilog(GenTwoStage.cpu( + withMulDiv = true, + bypass = true, + barrielShifter = true + )), + testCmd = "make clean run REDO=10 IBUS=SIMPLE DBUS=SIMPLE CSR=no MMU=no DEBUG_PLUGIN=no MUL=yes DIV=yes COREMARK=yes" + ) + getDmips( name = "GenSmallestNoCsr", gen = GenSmallestNoCsr.main(null), @@ -104,7 +142,7 @@ class DhrystoneBench extends FunSuite{ gen = LinuxGen.main(Array.fill[String](0)("")), testCmd = "make clean run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD DHRYSTONE=yes SUPERVISOR=yes MMU=no CSR=yes CSR_SKIP_TEST=yes COMPRESSED=no MUL=yes DIV=yes LRSC=yes AMO=yes REDO=10 TRACE=no COREMARK=yes LINUX_REGRESSION=no" ) - //make run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD DHRYSTONE=yess SUPERVISOR=yes CSR=yes COMPRESSED=no MUL=yes DIV=yes LRSC=yes AMO=yes REDO=1 TRACE=no LINUX_REGRESSION=yes SEED=42 +// //make run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD DHRYSTONE=yess SUPERVISOR=yes CSR=yes COMPRESSED=no MUL=yes DIV=yes LRSC=yes AMO=yes REDO=1 TRACE=no LINUX_REGRESSION=yes SEED=42 test("final_report") { From 296cb44bc446c6f23e1898a927999cede629c260 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 9 Apr 2020 20:12:37 +0200 Subject: [PATCH 372/951] Add hardware AMO support using LR/SC exclusive --- src/main/scala/vexriscv/TestsWorkspace.scala | 2 +- src/main/scala/vexriscv/ip/DataCache.scala | 109 +++++++++++++----- .../vexriscv/plugin/DBusCachedPlugin.scala | 17 ++- src/test/cpp/regression/main.cpp | 5 +- 4 files changed, 97 insertions(+), 36 deletions(-) diff --git a/src/main/scala/vexriscv/TestsWorkspace.scala b/src/main/scala/vexriscv/TestsWorkspace.scala index 51776313..2daf2f0d 100644 --- a/src/main/scala/vexriscv/TestsWorkspace.scala +++ b/src/main/scala/vexriscv/TestsWorkspace.scala @@ -101,7 +101,7 @@ object TestsWorkspace { catchIllegal = true, catchUnaligned = true, withLrSc = true, - withAmo = false, + withAmo = true, withExclusive = true, withInvalidate = true // ) diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index d0a536b1..9f9ad267 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -38,6 +38,7 @@ case class DataCacheConfig(cacheSize : Int, def withInternalAmo = withAmo && !withExclusive def withInternalLrSc = withLrSc && !withExclusive def withExternalLrSc = withLrSc && withExclusive + def withExternalAmo = withAmo && withExclusive def getAxi4SharedConfig() = Axi4Config( addressWidth = addressWidth, dataWidth = memDataWidth, @@ -133,20 +134,21 @@ case class DataCacheCpuMemory(p : DataCacheConfig) extends Bundle with IMasterSl case class DataCacheCpuWriteBack(p : DataCacheConfig) extends Bundle with IMasterSlave{ - val isValid = Bool - val isStuck = Bool - val isUser = Bool - val haltIt = Bool - val isWrite = Bool + val isValid = Bool() + val isStuck = Bool() + val isUser = Bool() + val haltIt = Bool() + val isWrite = Bool() val data = Bits(p.cpuDataWidth bit) val address = UInt(p.addressWidth bit) - val mmuException, unalignedAccess, accessError = Bool + val mmuException, unalignedAccess, accessError = Bool() + val keepMemRspData = Bool() //Used by external AMO to avoid having an internal buffer // val exceptionBus = if(p.catchSomething) Flow(ExceptionCause()) else null override def asMaster(): Unit = { out(isValid,isStuck,isUser, address) - in(haltIt, data, mmuException, unalignedAccess, accessError, isWrite) + in(haltIt, data, mmuException, unalignedAccess, accessError, isWrite, keepMemRspData) } } @@ -364,8 +366,12 @@ case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave } +object DataCacheExternalAmoStates extends SpinalEnum{ + val LR_CMD, LR_RSP, SC_CMD, SC_RSP = newElement(); +} -class DataCache(p : DataCacheConfig) extends Component{ +//If external amo, mem rsp should stay +class DataCache(val p : DataCacheConfig) extends Component{ import p._ assert(cpuDataWidth == memDataWidth) @@ -572,7 +578,7 @@ class DataCache(p : DataCacheConfig) extends Component{ } - val lrSc = withLrSc generate new Area{ + val lrSc = withInternalLrSc generate new Area{ val reserved = RegInit(False) when(io.cpu.writeBack.isValid && !io.cpu.writeBack.isStuck && request.isLrsc && !io.cpu.redo && !io.cpu.writeBack.mmuException && !io.cpu.writeBack.unalignedAccess && !io.cpu.writeBack.accessError){ @@ -580,12 +586,16 @@ class DataCache(p : DataCacheConfig) extends Component{ } } - val requestDataBypass = CombInit(request.data) val isAmo = if(withAmo) request.isAmo else False - val internalAmo = withInternalAmo generate new Area{ - def rf = request.data - def mem = dataMux + val isAmoCached = if(withInternalAmo) isAmo else False + val isExternalLsrc = if(withExternalLrSc) request.isLrsc else False + val isExternalAmo = if(withExternalAmo) request.isAmo else False + val requestDataBypass = CombInit(request.data) + import DataCacheExternalAmoStates._ + val amo = withAmo generate new Area{ + def rf = request.data + def mem = if(withInternalAmo) dataMux else io.mem.rsp.data val compare = request.amoCtrl.alu.msb val unsigned = request.amoCtrl.alu(2 downto 1) === B"11" val addSub = (rf.asSInt + Mux(compare, ~mem, mem).asSInt + Mux(compare, S(1), S(0))).asBits @@ -599,8 +609,17 @@ class DataCache(p : DataCacheConfig) extends Component{ B"011" -> (rf & mem), default -> (selectRf ? rf | mem) ) - val resultRegValid = RegNext(True) clearWhen(!io.cpu.writeBack.isStuck) - val resultReg = RegNext(result) +// val resultRegValid = RegNext(True) clearWhen(!io.cpu.writeBack.isStuck) +// val resultReg = RegNext(result) + val resultReg = Reg(Bits(32 bits)) + + val internal = withInternalAmo generate new Area{ + val resultRegValid = RegNext(io.cpu.writeBack.isStuck) + resultReg := result + } + val external = !withInternalAmo generate new Area{ + val state = RegInit(LR_CMD) + } } @@ -620,27 +639,58 @@ class DataCache(p : DataCacheConfig) extends Component{ io.cpu.writeBack.isWrite := request.wr io.mem.cmd.valid := False - io.mem.cmd.address.assignDontCare() - io.mem.cmd.length.assignDontCare() + io.mem.cmd.address := mmuRsp.physicalAddress(tagRange.high downto wordRange.low) @@ U(0, wordRange.low bit) + io.mem.cmd.length := 0 io.mem.cmd.last := True io.mem.cmd.wr := request.wr io.mem.cmd.mask := mask io.mem.cmd.data := requestDataBypass - if(withExternalLrSc) io.mem.cmd.exclusive := request.isLrsc || (if(withAmo) request.isAmo else False) + if(withExternalLrSc) io.mem.cmd.exclusive := request.isLrsc || isAmo - val bypassCache = mmuRsp.isIoAccess || (if(withExternalLrSc) request.isLrsc else False) - val isAmoCached = if(withInternalAmo) isAmo else False + val bypassCache = mmuRsp.isIoAccess || isExternalLsrc || isExternalAmo + + io.cpu.writeBack.keepMemRspData := False when(io.cpu.writeBack.isValid) { - when(bypassCache) { + when(isExternalAmo){ + if(withExternalAmo) switch(amo.external.state){ + is(LR_CMD){ + io.mem.cmd.valid := True + io.mem.cmd.wr := False + when(io.mem.cmd.ready) { + amo.external.state := LR_RSP + } + } + is(LR_RSP){ + when(io.mem.rsp.valid && pending.last) { + amo.external.state := SC_CMD + amo.resultReg := amo.result + } + } + is(SC_CMD){ + io.mem.cmd.valid := True + when(io.mem.cmd.ready) { + amo.external.state := SC_RSP + } + } + is(SC_RSP){ + io.cpu.writeBack.keepMemRspData := True + when(io.mem.rsp.valid) { + amo.external.state := LR_CMD + when(io.mem.rsp.exclusive){ //Success + cpuWriteToCache := True + io.cpu.writeBack.haltIt := False + } + } + } + } + } elsewhen(mmuRsp.isIoAccess || isExternalLsrc) { val waitResponse = !request.wr if(withExternalLrSc) waitResponse setWhen(request.isLrsc) io.cpu.writeBack.haltIt.clearWhen(waitResponse ? (io.mem.rsp.valid && rspSync) | io.mem.cmd.ready) io.mem.cmd.valid := !memCmdSent - io.mem.cmd.address := mmuRsp.physicalAddress(tagRange.high downto wordRange.low) @@ U(0, wordRange.low bit) - io.mem.cmd.length := 0 if(withInternalLrSc) when(request.isLrsc && !lrSc.reserved){ io.mem.cmd.valid := False @@ -657,7 +707,7 @@ class DataCache(p : DataCacheConfig) extends Component{ io.cpu.writeBack.haltIt clearWhen(!request.wr || io.mem.cmd.ready) if(withInternalAmo) when(isAmo){ - when(!internalAmo.resultRegValid) { + when(!amo.internal.resultRegValid) { io.mem.cmd.valid := False dataWriteCmd.valid := False io.cpu.writeBack.haltIt := True @@ -696,17 +746,14 @@ class DataCache(p : DataCacheConfig) extends Component{ } if(withLrSc) when(request.isLrsc && request.wr){ - val success = CombInit(lrSc.reserved) - if(withExternalLrSc) success clearWhen(!io.mem.rsp.exclusive) - + val success = if(withInternalLrSc)lrSc.reserved else io.mem.rsp.exclusive io.cpu.writeBack.data := B(!success).resized - if(withExternalLrSc) when(io.cpu.writeBack.isValid && io.mem.rsp.valid && rspSync && success && waysHit){ cpuWriteToCache := True } } if(withAmo) when(request.isAmo){ - requestDataBypass := internalAmo.resultReg + requestDataBypass := amo.resultReg } //remove side effects on exceptions @@ -716,13 +763,11 @@ class DataCache(p : DataCacheConfig) extends Component{ dataWriteCmd.valid := False loaderValid := False io.cpu.writeBack.haltIt := False + if(withExternalAmo) amo.external.state := LR_CMD } io.cpu.redo setWhen(io.cpu.writeBack.isValid && mmuRsp.refilling) assert(!(io.cpu.writeBack.isValid && !io.cpu.writeBack.haltIt && io.cpu.writeBack.isStuck), "writeBack stuck by another plugin is not allowed") - - - } val loader = new Area{ diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index 3a13a7ca..a128b8b9 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -26,7 +26,7 @@ class DBusCachedPlugin(val config : DataCacheConfig, relaxedMemoryTranslationRegister : Boolean = false, csrInfo : Boolean = false) extends Plugin[VexRiscv] with DBusAccessService { import config._ - + assert(!(config.withExternalAmo && !dBusRspSlavePipe)) assert(isPow2(cacheSize)) assert(!(memoryTranslatorPortConfig != null && config.cacheSize/config.wayCount > 4096), "When the D$ is used with MMU, each way can't be bigger than a page (4096 bytes)") @@ -180,7 +180,20 @@ class DBusCachedPlugin(val config : DataCacheConfig, def optionPipe[T](cond : Boolean, on : T)(f : T => T) : T = if(cond) f(on) else on def cmdBuf = optionPipe(dBusCmdSlavePipe, cache.io.mem.cmd)(_.s2mPipe()) dBus.cmd << optionPipe(dBusCmdMasterPipe, cmdBuf)(_.m2sPipe()) - cache.io.mem.rsp << optionPipe(dBusRspSlavePipe,dBus.rsp)(_.m2sPipe()) + cache.io.mem.rsp << (dBusRspSlavePipe match { + case false => dBus.rsp + case true if !withExternalAmo => dBus.rsp.m2sPipe() + case true if withExternalAmo => { + val rsp = Flow (DataCacheMemRsp(cache.p)) + rsp.valid := RegNext(dBus.rsp.valid) + rsp.exclusive := RegNext(dBus.rsp.exclusive) + rsp.error := RegNext(dBus.rsp.error) + rsp.last := RegNext(dBus.rsp.last) + rsp.data := RegNextWhen(dBus.rsp.data, dBus.rsp.valid && !cache.io.cpu.writeBack.keepMemRspData) + rsp + } + }) + if(withInvalidate) cache.io.inv <> inv pipeline plug new Area{ diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 47a822b6..c4120c95 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -926,6 +926,10 @@ public: int32_t src = i32_rs2; int32_t readValue; + #ifdef DBUS_EXCLUSIVE + lrscReserved = false; + #endif + uint32_t pAddr; if(v2p(addr, &pAddr, READ_WRITE)){ trap(0, 15, addr); return; } if(dRead(pAddr, 4, (uint32_t*)&readValue)){ @@ -2358,7 +2362,6 @@ public: ws->dBusAccess(top->dBus_cmd_payload_address,1,2,top->dBus_cmd_payload_mask,&top->dBus_cmd_payload_data,&error); #else bool cancel = false; - DBusCachedTask rsp; if(top->dBus_cmd_payload_exclusive){ bool hit = reservationValid && reservationAddress == top->dBus_cmd_payload_address; rsp.exclusive = hit; From f71f360e325719dff08b304fb9f4a4808a642bc8 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 10 Apr 2020 14:27:39 +0200 Subject: [PATCH 373/951] Add SMP synthesis --- src/main/scala/vexriscv/demo/Linux.scala | 4 +++- src/main/scala/vexriscv/demo/SynthesisBench.scala | 11 +++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/main/scala/vexriscv/demo/Linux.scala b/src/main/scala/vexriscv/demo/Linux.scala index c13ef12e..0010fa3a 100644 --- a/src/main/scala/vexriscv/demo/Linux.scala +++ b/src/main/scala/vexriscv/demo/Linux.scala @@ -134,7 +134,7 @@ make clean run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD DHRYSTONE=yes SUPERVISO object LinuxGen { - def configFull(litex : Boolean, withMmu : Boolean) = { + def configFull(litex : Boolean, withMmu : Boolean, withSmp : Boolean = false) = { val config = VexRiscvConfig( plugins = List( //Uncomment the whole IBusSimplePlugin and comment IBusCachedPlugin if you want uncached iBus config @@ -201,6 +201,8 @@ object LinuxGen { catchAccessError = true, catchIllegal = true, catchUnaligned = true, + withExclusive = withSmp, + withInvalidate = withSmp, withLrSc = true, withAmo = true // ) diff --git a/src/main/scala/vexriscv/demo/SynthesisBench.scala b/src/main/scala/vexriscv/demo/SynthesisBench.scala index 3d9dbf9e..94d00551 100644 --- a/src/main/scala/vexriscv/demo/SynthesisBench.scala +++ b/src/main/scala/vexriscv/demo/SynthesisBench.scala @@ -146,8 +146,15 @@ object VexRiscvSynthesisBench { SpinalConfig(inlineRom = true).generateVerilog(wrap(new VexRiscv(LinuxGen.configFull(false, true))).setDefinitionName(getRtlPath().split("\\.").head)) } - val rtls = List(twoStage, twoStageBarell, twoStageMulDiv, twoStageAll, smallestNoCsr, smallest, smallAndProductive, smallAndProductiveWithICache, fullNoMmuNoCache, noCacheNoMmuMaxPerf, fullNoMmuMaxPerf, fullNoMmu, full, linuxBalanced) -// val rtls = List(twoStage, twoStageBarell, twoStageMulDiv, twoStageAll) + val linuxBalancedSmp = new Rtl { + override def getName(): String = "VexRiscv linux balanced SMP" + override def getRtlPath(): String = "VexRiscvLinuxBalancedSmp.v" + SpinalConfig(inlineRom = true).generateVerilog(wrap(new VexRiscv(LinuxGen.configFull(false, true, withSmp = true))).setDefinitionName(getRtlPath().split("\\.").head)) + } + + +// val rtls = List(twoStage, twoStageBarell, twoStageMulDiv, twoStageAll, smallestNoCsr, smallest, smallAndProductive, smallAndProductiveWithICache, fullNoMmuNoCache, noCacheNoMmuMaxPerf, fullNoMmuMaxPerf, fullNoMmu, full, linuxBalanced, linuxBalancedSmp) + val rtls = List(linuxBalanced, linuxBalancedSmp) // val rtls = List(smallest) val targets = XilinxStdTargets() ++ AlteraStdTargets() ++ IcestormStdTargets().take(1) ++ List( new Target { From 0ad0f5ed3f12b0919183b6b9f0d23647803044a3 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 10 Apr 2020 14:28:16 +0200 Subject: [PATCH 374/951] Add d$ invalidation tests fix d$ invalidation, linux OK --- src/main/scala/vexriscv/TestsWorkspace.scala | 2 +- src/main/scala/vexriscv/ip/DataCache.scala | 46 ++++++++++--------- .../vexriscv/plugin/DBusCachedPlugin.scala | 5 +- src/test/cpp/regression/main.cpp | 39 +++++++++++++++- src/test/cpp/regression/makefile | 7 +++ 5 files changed, 73 insertions(+), 26 deletions(-) diff --git a/src/main/scala/vexriscv/TestsWorkspace.scala b/src/main/scala/vexriscv/TestsWorkspace.scala index 2daf2f0d..3cd633bc 100644 --- a/src/main/scala/vexriscv/TestsWorkspace.scala +++ b/src/main/scala/vexriscv/TestsWorkspace.scala @@ -27,7 +27,7 @@ import spinal.lib.bus.avalon.AvalonMM import spinal.lib.eda.altera.{InterruptReceiverTag, ResetEmitterTag} -//make clean all SEED=42 MMU=no STOP_ON_ERROR=yes DBUS_EXCLUSIVE=yes SUPERVISOR=yes REDO=10 DHRYSTONE=no LRSC=yes LINUX_REGRESSION=yes TRACE=yes TRACE_START=1000000000000l FLOW_INFO=no +//make clean all SEED=42 MMU=no STOP_ON_ERROR=yes DBUS_EXCLUSIVE=yes DBUS_INVALIDATE=yes SUPERVISOR=yes REDO=0 DHRYSTONE=no LRSC=yes AMO=yes LINUX_REGRESSION=yes TRACE=yes TRACE_START=9546629800l FLOW_INFO=ye object TestsWorkspace { def main(args: Array[String]) { def configFull = { diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index 9f9ad267..5a7326c3 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -581,7 +581,7 @@ class DataCache(val p : DataCacheConfig) extends Component{ val lrSc = withInternalLrSc generate new Area{ val reserved = RegInit(False) when(io.cpu.writeBack.isValid && !io.cpu.writeBack.isStuck && request.isLrsc - && !io.cpu.redo && !io.cpu.writeBack.mmuException && !io.cpu.writeBack.unalignedAccess && !io.cpu.writeBack.accessError){ + && !io.cpu.redo && !io.cpu.writeBack.mmuException && !io.cpu.writeBack.unalignedAccess && !io.cpu.writeBack.accessError){ reserved := !request.wr } } @@ -609,8 +609,8 @@ class DataCache(val p : DataCacheConfig) extends Component{ B"011" -> (rf & mem), default -> (selectRf ? rf | mem) ) -// val resultRegValid = RegNext(True) clearWhen(!io.cpu.writeBack.isStuck) -// val resultReg = RegNext(result) + // val resultRegValid = RegNext(True) clearWhen(!io.cpu.writeBack.isStuck) + // val resultReg = RegNext(result) val resultReg = Reg(Bits(32 bits)) val internal = withInternalAmo generate new Area{ @@ -778,6 +778,7 @@ class DataCache(val p : DataCacheConfig) extends Component{ val waysAllocator = Reg(Bits(wayCount bits)) init(1) val error = RegInit(False) val kill = False + val killReg = RegInit(False) setWhen(kill) when(valid && io.mem.rsp.valid && rspLast){ dataWriteCmd.valid := True @@ -789,19 +790,22 @@ class DataCache(val p : DataCacheConfig) extends Component{ counter.increment() } + val done = CombInit(counter.willOverflow) + if(withInvalidate) done setWhen(valid && pending.counter === 0) //Used to solve invalidate write request at the same time - when(counter.willOverflow){ + when(done){ valid := False //Update tags tagsWriteCmd.valid := True tagsWriteCmd.address := baseAddress(lineRange) - tagsWriteCmd.data.valid := True + tagsWriteCmd.data.valid := !(kill || killReg) tagsWriteCmd.data.address := baseAddress(tagRange) - tagsWriteCmd.data.error := error || io.mem.rsp.error + tagsWriteCmd.data.error := error || (io.mem.rsp.valid && io.mem.rsp.error) tagsWriteCmd.way := waysAllocator error := False + killReg := False } when(!valid){ @@ -810,24 +814,18 @@ class DataCache(val p : DataCacheConfig) extends Component{ io.cpu.redo setWhen(valid) stageB.mmuRspFreeze setWhen(stageB.loaderValid || valid) - - when(kill){ - valid := False - error := False - tagsWriteCmd.valid := False - counter.clear() - } } val invalidate = withInvalidate generate new Area{ - val loaderReadToWriteConflict = False + val readToWriteConflict = False val s0 = new Area{ - val input = io.inv.cmd.haltWhen(loaderReadToWriteConflict) + val input = io.inv.cmd.haltWhen(readToWriteConflict) tagsInvReadCmd.valid := input.fire tagsInvReadCmd.payload := input.address(lineRange) - val loaderHit = loader.valid && input.address(hitRange) === loader.baseAddress(hitRange) - when(loaderHit){ + val loaderTagHit = input.address(tagRange) === loader.baseAddress(tagRange) + val loaderLineHit = input.address(lineRange) === loader.baseAddress(lineRange) + when(input.valid && loader.valid && loaderLineHit && loaderTagHit){ loader.kill := True } } @@ -835,12 +833,13 @@ class DataCache(val p : DataCacheConfig) extends Component{ val input = s0.input.stage() val loaderValid = RegNextWhen(loader.valid, s0.input.ready) val loaderWay = RegNextWhen(loader.waysAllocator, s0.input.ready) - val loaderHit = RegNextWhen(s0.loaderHit, s0.input.ready) + val loaderTagHit = RegNextWhen(s0.loaderTagHit, s0.input.ready) + val loaderLineHit = RegNextWhen(s0.loaderLineHit, s0.input.ready) var wayHits = B(ways.map(way => (input.address(tagRange) === way.tagsInvReadRsp.address && way.tagsInvReadRsp.valid))) //Handle invalider read during loader write hazard - when(loaderValid && !loaderHit){ + when(loaderValid && loaderLineHit && !loaderTagHit){ wayHits \= wayHits & ~loaderWay } } @@ -850,14 +849,19 @@ class DataCache(val p : DataCacheConfig) extends Component{ val wayHit = wayHits.orR when(input.valid) { - stage0.wayInvalidate := wayHits + //Manage invalidate write during cpu read hazard + when(input.address(lineRange) === io.cpu.execute.address(lineRange)) { + stage0.wayInvalidate := wayHits + } + //Invalidate cache tag when(wayHit) { tagsWriteCmd.valid := True tagsWriteCmd.address := input.address(lineRange) tagsWriteCmd.data.valid := False tagsWriteCmd.way := wayHits - loaderReadToWriteConflict := input.address(lineRange) === s0.input.address(lineRange) + readToWriteConflict := input.address(lineRange) === s0.input.address(lineRange) + loader.done := False //Hold loader tags write } } io.inv.rsp.arbitrationFrom(input) diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index a128b8b9..ce3f81c0 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -59,6 +59,9 @@ class DBusCachedPlugin(val config : DataCacheConfig, import Riscv._ import pipeline.config._ + dBus = master(DataCacheMemBus(this.config)).setName("dBus") + inv = withInvalidate generate slave(DataCacheInvalidateBus(this.config)).setName("dBus_inv") + val decoderService = pipeline.service(classOf[DecoderService]) val stdActions = List[(Stageable[_ <: BaseType],Any)]( @@ -169,8 +172,6 @@ class DBusCachedPlugin(val config : DataCacheConfig, import pipeline._ import pipeline.config._ - dBus = master(DataCacheMemBus(this.config)).setName("dBus") - inv = withInvalidate generate slave(DataCacheInvalidateBus(this.config)) val cache = new DataCache(this.config.copy( mergeExecuteMemory = writeBack == null diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index c4120c95..03077781 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -1106,6 +1106,7 @@ public: #ifdef TRACE VerilatedVcdC* tfp; #endif + bool allowInvalidate = true; uint32_t seed; @@ -1305,6 +1306,14 @@ public: return this; } + Workspace* withInvalidation(){ + allowInvalidate = true; + return this; + } + Workspace* withoutInvalidation(){ + allowInvalidate = false; + return this; + } virtual bool isPerifRegion(uint32_t addr) { return false; } virtual bool isMmuRegion(uint32_t addr) { return true;} virtual void iBusAccess(uint32_t addr, uint32_t *data, bool *error) { @@ -1777,7 +1786,8 @@ public: uint32_t regFileWriteRefIndex = 0; - char *target = "PROJECT EXECUTION SUCCESSFUL", *hit = target; + const char *target = "PROJECT EXECUTION SUCCESSFUL"; + const char *hit = target; ZephyrRegression(string name) : WorkspaceRegression(name) { cout << endl << endl; @@ -2336,6 +2346,7 @@ struct DBusCachedTask{ class DBusCached : public SimElement{ public: queue rsps; + queue invalidationHint; bool reservationValid = false; uint32_t reservationAddress; @@ -2385,6 +2396,14 @@ public: #endif rsps.push(rsp); } + + #ifdef DBUS_INVALIDATE + if(ws->allowInvalidate){ + if(VL_RANDOM_I(7) < 100){ + invalidationHint.push(top->dBus_cmd_payload_address + VL_RANDOM_I(5)); + } + } + #endif } } } @@ -2410,8 +2429,24 @@ public: top->dBus_rsp_payload_exclusive = VL_RANDOM_I(1); #endif } - top->dBus_cmd_ready = (ws->dStall ? VL_RANDOM_I(7) < 100 : 1); + + #ifdef DBUS_INVALIDATE + if(ws->allowInvalidate){ + if(top->dBus_inv_cmd_ready) top->dBus_inv_cmd_valid = 0; + if(top->dBus_inv_cmd_valid == 0 && VL_RANDOM_I(7) < 10){ + top->dBus_inv_cmd_valid = invalidationHint.empty() == 0; + if(!invalidationHint.empty()){ + top->dBus_inv_cmd_payload_address = invalidationHint.front(); + invalidationHint.pop(); + } else { + top->dBus_inv_cmd_payload_address = VL_RANDOM_I(32); + } + } + } + top->dBus_inv_rsp_ready = (ws->dStall ? VL_RANDOM_I(7) < 100 : 1); + #endif + } }; #endif diff --git a/src/test/cpp/regression/makefile b/src/test/cpp/regression/makefile index 48e55515..160707a0 100644 --- a/src/test/cpp/regression/makefile +++ b/src/test/cpp/regression/makefile @@ -16,6 +16,7 @@ EBREAK?=no FENCEI?=no MMU?=yes DBUS_EXCLUSIVE?=no +DBUS_INVALIDATE?=no SEED?=no LRSC?=no AMO?=no @@ -45,6 +46,9 @@ ADDCFLAGS += -CFLAGS -DIBUS_${IBUS} ADDCFLAGS += -CFLAGS -DDBUS_${DBUS} ADDCFLAGS += -CFLAGS -DREDO=${REDO} ADDCFLAGS += -CFLAGS -pthread +ADDCFLAGS += -CFLAGS -Wno-unused-result + + ADDCFLAGS += -CFLAGS -DTHREAD_COUNT=${THREAD_COUNT} @@ -221,6 +225,9 @@ endif ifeq ($(DBUS_EXCLUSIVE),yes) ADDCFLAGS += -CFLAGS -DDBUS_EXCLUSIVE endif +ifeq ($(DBUS_INVALIDATE),yes) + ADDCFLAGS += -CFLAGS -DDBUS_INVALIDATE +endif ifeq ($(MUL),yes) ADDCFLAGS += -CFLAGS -DMUL From 4a9b8c1f724a359167e35c92d5978a46622434ca Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 10 Apr 2020 14:44:28 +0200 Subject: [PATCH 375/951] improve invalidation read during write hazard logic --- src/main/scala/vexriscv/ip/DataCache.scala | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index 5a7326c3..9a4dfc85 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -817,9 +817,8 @@ class DataCache(val p : DataCacheConfig) extends Component{ } val invalidate = withInvalidate generate new Area{ - val readToWriteConflict = False val s0 = new Area{ - val input = io.inv.cmd.haltWhen(readToWriteConflict) + val input = io.inv.cmd tagsInvReadCmd.valid := input.fire tagsInvReadCmd.payload := input.address(lineRange) @@ -835,8 +834,9 @@ class DataCache(val p : DataCacheConfig) extends Component{ val loaderWay = RegNextWhen(loader.waysAllocator, s0.input.ready) val loaderTagHit = RegNextWhen(s0.loaderTagHit, s0.input.ready) val loaderLineHit = RegNextWhen(s0.loaderLineHit, s0.input.ready) + val invalidations = Bits(wayCount bits) - var wayHits = B(ways.map(way => (input.address(tagRange) === way.tagsInvReadRsp.address && way.tagsInvReadRsp.valid))) + var wayHits = B(ways.map(way => (input.address(tagRange) === way.tagsInvReadRsp.address && way.tagsInvReadRsp.valid))) & ~invalidations //Handle invalider read during loader write hazard when(loaderValid && loaderLineHit && !loaderTagHit){ @@ -860,12 +860,14 @@ class DataCache(val p : DataCacheConfig) extends Component{ tagsWriteCmd.address := input.address(lineRange) tagsWriteCmd.data.valid := False tagsWriteCmd.way := wayHits - readToWriteConflict := input.address(lineRange) === s0.input.address(lineRange) loader.done := False //Hold loader tags write } } io.inv.rsp.arbitrationFrom(input) io.inv.rsp.hit := wayHit + + //Manage invalidation read during write hazard + s1.invalidations := RegNext(input.valid ? wayHits | 0) } } } \ No newline at end of file From abbfaf6bcf6afeb355d915881c20c386eeae23df Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 10 Apr 2020 18:58:03 +0200 Subject: [PATCH 376/951] regression : restore normal invalidation setup --- src/test/cpp/regression/main.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 03077781..3b5122b8 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -2399,7 +2399,7 @@ public: #ifdef DBUS_INVALIDATE if(ws->allowInvalidate){ - if(VL_RANDOM_I(7) < 100){ + if(VL_RANDOM_I(7) < 10){ invalidationHint.push(top->dBus_cmd_payload_address + VL_RANDOM_I(5)); } } @@ -2434,8 +2434,8 @@ public: #ifdef DBUS_INVALIDATE if(ws->allowInvalidate){ if(top->dBus_inv_cmd_ready) top->dBus_inv_cmd_valid = 0; - if(top->dBus_inv_cmd_valid == 0 && VL_RANDOM_I(7) < 10){ - top->dBus_inv_cmd_valid = invalidationHint.empty() == 0; + if(top->dBus_inv_cmd_valid == 0 && VL_RANDOM_I(7) < 5){ + top->dBus_inv_cmd_valid = 1; if(!invalidationHint.empty()){ top->dBus_inv_cmd_payload_address = invalidationHint.front(); invalidationHint.pop(); From 467a2bc488a248fd818960a282dd9e3336be5bc3 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sat, 11 Apr 2020 19:06:22 +0200 Subject: [PATCH 377/951] refactor DBus invalidation, and add invalidation enable --- src/main/scala/vexriscv/ip/DataCache.scala | 48 +++++++++++-------- .../vexriscv/plugin/DBusCachedPlugin.scala | 7 +-- src/test/cpp/regression/main.cpp | 13 ++--- 3 files changed, 40 insertions(+), 28 deletions(-) diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index 9a4dfc85..ec6ad57c 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -185,30 +185,29 @@ case class DataCacheMemRsp(p : DataCacheConfig) extends Bundle{ val error = Bool val exclusive = p.withExclusive generate Bool() } -case class DataCacheInvalidateCmd(p : DataCacheConfig) extends Bundle{ +case class DataCacheInv(p : DataCacheConfig) extends Bundle{ + val enable = Bool() val address = UInt(p.addressWidth bit) } -case class DataCacheInvalidateRsp(p : DataCacheConfig) extends Bundle{ +case class DataCacheAck(p : DataCacheConfig) extends Bundle{ val hit = Bool() } -case class DataCacheInvalidateBus(p : DataCacheConfig) extends Bundle with IMasterSlave { - val cmd = Stream(DataCacheInvalidateCmd(p)) - val rsp = Stream(DataCacheInvalidateRsp(p)) - - override def asMaster(): Unit = { - master(cmd) - slave(rsp) - } -} - case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave{ val cmd = Stream (DataCacheMemCmd(p)) val rsp = Flow (DataCacheMemRsp(p)) + val inv = p.withInvalidate generate Stream(DataCacheInv(p)) + val ack = p.withInvalidate generate Stream(DataCacheAck(p)) + override def asMaster(): Unit = { master(cmd) slave(rsp) + + if(p.withInvalidate) { + slave(inv) + master(ack) + } } def toAxi4Shared(stageCmd : Boolean = false, pendingWritesMax : Int = 7): Axi4Shared = { @@ -353,14 +352,26 @@ case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave bus.cmd.data := cmd.data bus.cmd.length := (cmd.length << 2) | 3 //TODO better sub word access bus.cmd.mask := cmd.mask + if(p.withExclusive) bus.cmd.exclusive := cmd.exclusive cmd.ready := bus.cmd.ready rsp.valid := bus.rsp.valid && !bus.rsp.context(0) rsp.data := bus.rsp.data rsp.error := bus.rsp.isError + if(p.withExclusive) rsp.exclusive := bus.rsp.exclusive bus.rsp.ready := True + if(p.withInvalidate){ + bus.ack.arbitrationFrom(ack) + //TODO manage lenght ? + inv.address := bus.inv.address +// inv.opcode := bus.inv.opcode + ??? + + bus.ack.arbitrationFrom(ack) + } + bus } @@ -378,7 +389,6 @@ class DataCache(val p : DataCacheConfig) extends Component{ val io = new Bundle{ val cpu = slave(DataCacheCpuBus(p)) val mem = master(DataCacheMemBus(p)) - val inv = withInvalidate generate slave(DataCacheInvalidateBus(p)) } val haltCpu = False @@ -818,13 +828,13 @@ class DataCache(val p : DataCacheConfig) extends Component{ val invalidate = withInvalidate generate new Area{ val s0 = new Area{ - val input = io.inv.cmd + val input = io.mem.inv tagsInvReadCmd.valid := input.fire tagsInvReadCmd.payload := input.address(lineRange) val loaderTagHit = input.address(tagRange) === loader.baseAddress(tagRange) val loaderLineHit = input.address(lineRange) === loader.baseAddress(lineRange) - when(input.valid && loader.valid && loaderLineHit && loaderTagHit){ + when(input.valid && input.enable && loader.valid && loaderLineHit && loaderTagHit){ loader.kill := True } } @@ -848,7 +858,7 @@ class DataCache(val p : DataCacheConfig) extends Component{ val wayHits = RegNextWhen(s1.wayHits, s1.input.ready) val wayHit = wayHits.orR - when(input.valid) { + when(input.valid && input.enable) { //Manage invalidate write during cpu read hazard when(input.address(lineRange) === io.cpu.execute.address(lineRange)) { stage0.wayInvalidate := wayHits @@ -863,11 +873,11 @@ class DataCache(val p : DataCacheConfig) extends Component{ loader.done := False //Hold loader tags write } } - io.inv.rsp.arbitrationFrom(input) - io.inv.rsp.hit := wayHit + io.mem.ack.arbitrationFrom(input) + io.mem.ack.hit := wayHit //Manage invalidation read during write hazard - s1.invalidations := RegNext(input.valid ? wayHits | 0) + s1.invalidations := RegNext((input.valid && input.enable) ? wayHits | 0) } } } \ No newline at end of file diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index ce3f81c0..c27cae77 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -31,7 +31,6 @@ class DBusCachedPlugin(val config : DataCacheConfig, assert(!(memoryTranslatorPortConfig != null && config.cacheSize/config.wayCount > 4096), "When the D$ is used with MMU, each way can't be bigger than a page (4096 bytes)") var dBus : DataCacheMemBus = null - var inv : DataCacheInvalidateBus = null var mmuBus : MemoryTranslatorBus = null var exceptionBus : Flow[ExceptionCause] = null var privilegeService : PrivilegeService = null @@ -60,7 +59,6 @@ class DBusCachedPlugin(val config : DataCacheConfig, import pipeline.config._ dBus = master(DataCacheMemBus(this.config)).setName("dBus") - inv = withInvalidate generate slave(DataCacheInvalidateBus(this.config)).setName("dBus_inv") val decoderService = pipeline.service(classOf[DecoderService]) @@ -195,7 +193,10 @@ class DBusCachedPlugin(val config : DataCacheConfig, } }) - if(withInvalidate) cache.io.inv <> inv + if(withInvalidate) { + cache.io.mem.inv << dBus.inv + cache.io.mem.ack >> dBus.ack + } pipeline plug new Area{ //Memory bandwidth counter diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 3b5122b8..6070183d 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -2433,18 +2433,19 @@ public: #ifdef DBUS_INVALIDATE if(ws->allowInvalidate){ - if(top->dBus_inv_cmd_ready) top->dBus_inv_cmd_valid = 0; - if(top->dBus_inv_cmd_valid == 0 && VL_RANDOM_I(7) < 5){ - top->dBus_inv_cmd_valid = 1; + if(top->dBus_inv_ready) top->dBus_inv_valid = 0; + if(top->dBus_inv_valid == 0 && VL_RANDOM_I(7) < 5){ + top->dBus_inv_valid = 1; + top->dBus_inv_payload_enable = VL_RANDOM_I(7) < 100; if(!invalidationHint.empty()){ - top->dBus_inv_cmd_payload_address = invalidationHint.front(); + top->dBus_inv_payload_address = invalidationHint.front(); invalidationHint.pop(); } else { - top->dBus_inv_cmd_payload_address = VL_RANDOM_I(32); + top->dBus_inv_payload_address = VL_RANDOM_I(32); } } } - top->dBus_inv_rsp_ready = (ws->dStall ? VL_RANDOM_I(7) < 100 : 1); + top->dBus_ack_ready = (ws->dStall ? VL_RANDOM_I(7) < 100 : 1); #endif } From a00605b10cccace3ebace022b7f1e4c1dc97eccb Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 13 Apr 2020 13:01:12 +0200 Subject: [PATCH 378/951] fix Briey verilator --- src/test/cpp/briey/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/cpp/briey/main.cpp b/src/test/cpp/briey/main.cpp index 2243dced..0ee7c456 100644 --- a/src/test/cpp/briey/main.cpp +++ b/src/test/cpp/briey/main.cpp @@ -401,7 +401,7 @@ public: sdramIo->ADDR = &top->io_sdram_ADDR ; sdramIo->DQ_read = (CData*)&top->io_sdram_DQ_read ; sdramIo->DQ_write = (CData*)&top->io_sdram_DQ_write ; - sdramIo->DQ_writeEnable = &top->io_sdram_DQ_writeEnable; + sdramIo->DQ_writeEnable = (CData*)&top->io_sdram_DQ_writeEnable; Sdram *sdram = new Sdram(sdramConfig, sdramIo); axiClk->add(sdram); From 46207abbc42ddce91a49bc04288e0cc700220a60 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 16 Apr 2020 01:28:38 +0200 Subject: [PATCH 379/951] dataCache now implement invalidation sync --- src/main/scala/vexriscv/ip/DataCache.scala | 81 ++++++++++++++----- .../vexriscv/plugin/DBusCachedPlugin.scala | 7 +- 2 files changed, 66 insertions(+), 22 deletions(-) diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index ec6ad57c..80054407 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -80,11 +80,16 @@ case class DataCacheConfig(cacheSize : Int, dataWidth = 32, lengthWidth = log2Up(this.bytePerLine), sourceWidth = 0, - contextWidth = 1, + contextWidth = if(!withWriteResponse) 1 else 0, canRead = true, canWrite = true, alignment = BmbParameter.BurstAlignement.LENGTH, - maximumPendingTransactionPerId = Int.MaxValue + maximumPendingTransactionPerId = Int.MaxValue, + canInvalidate = withInvalidate, + canSync = withInvalidate, + canExclusive = withExclusive, + invalidateLength = log2Up(this.bytePerLine), + invalidateAlignment = BmbParameter.BurstAlignement.LENGTH ) } @@ -193,12 +198,17 @@ case class DataCacheAck(p : DataCacheConfig) extends Bundle{ val hit = Bool() } +case class DataCacheSync(p : DataCacheConfig) extends Bundle{ + +} + case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave{ val cmd = Stream (DataCacheMemCmd(p)) val rsp = Flow (DataCacheMemRsp(p)) val inv = p.withInvalidate generate Stream(DataCacheInv(p)) val ack = p.withInvalidate generate Stream(DataCacheAck(p)) + val sync = p.withInvalidate generate Stream(DataCacheSync(p)) override def asMaster(): Unit = { master(cmd) @@ -207,6 +217,7 @@ case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave if(p.withInvalidate) { slave(inv) master(ack) + slave(sync) } } @@ -342,11 +353,11 @@ case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave def toBmb() : Bmb = { val pipelinedMemoryBusConfig = p.getBmbParameter() - val bus = Bmb(pipelinedMemoryBusConfig) + val bus = Bmb(pipelinedMemoryBusConfig).setCompositeName(this,"toBmb", true) bus.cmd.valid := cmd.valid bus.cmd.last := cmd.last - bus.cmd.context(0) := cmd.wr + if(!p.withWriteResponse) bus.cmd.context(0) := cmd.wr bus.cmd.opcode := (cmd.wr ? B(Bmb.Cmd.Opcode.WRITE) | B(Bmb.Cmd.Opcode.READ)) bus.cmd.address := cmd.address.resized bus.cmd.data := cmd.data @@ -356,22 +367,33 @@ case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave cmd.ready := bus.cmd.ready - rsp.valid := bus.rsp.valid && !bus.rsp.context(0) + rsp.valid := bus.rsp.valid + if(!p.withWriteResponse) rsp.valid clearWhen(bus.rsp.context(0)) rsp.data := bus.rsp.data rsp.error := bus.rsp.isError + rsp.last := bus.rsp.last if(p.withExclusive) rsp.exclusive := bus.rsp.exclusive bus.rsp.ready := True if(p.withInvalidate){ - bus.ack.arbitrationFrom(ack) - //TODO manage lenght ? + inv.arbitrationFrom(bus.inv) inv.address := bus.inv.address -// inv.opcode := bus.inv.opcode - ??? + inv.enable := bus.inv.all bus.ack.arbitrationFrom(ack) + + sync.arbitrationFrom(bus.sync) + +// bus.ack.arbitrationFrom(ack) +// //TODO manage lenght ? +// inv.address := bus.inv.address +//// inv.opcode := bus.inv.opcode +// ??? +// +// bus.ack.arbitrationFrom(ack) } + bus } @@ -440,9 +462,10 @@ class DataCache(val p : DataCacheConfig) extends Component{ //Reads val tagsReadRsp = tags.readSync(tagsReadCmd.payload, tagsReadCmd.valid && !io.cpu.memory.isStuck) - val tagsInvReadRsp = withInvalidate generate tags.readSync(tagsInvReadCmd.payload, tagsReadCmd.valid && !io.cpu.memory.isStuck) val dataReadRsp = data.readSync(dataReadCmd.payload, dataReadCmd.valid && !io.cpu.memory.isStuck) + val tagsInvReadRsp = withInvalidate generate tags.readSync(tagsInvReadCmd.payload, tagsInvReadCmd.valid) + //Writes when(tagsWriteCmd.valid && tagsWriteCmd.way(i)){ tags.write(tagsWriteCmd.address, tagsWriteCmd.data) @@ -494,9 +517,22 @@ class DataCache(val p : DataCacheConfig) extends Component{ val full = RegNext(counter.msb) val last = counter === 1 + if(!withInvalidate) { + io.cpu.execute.haltIt setWhen(full) + } + + rspSync clearWhen (!last || !memCmdSent) + rspLast clearWhen (!last) + } + + val sync = withInvalidate generate new Area{ + io.mem.sync.ready := True + + val counter = Reg(UInt(log2Up(pendingMax) + 1 bits)) init(0) + counter := counter + U(io.mem.cmd.fire && io.mem.cmd.wr) - U(io.mem.sync.fire) + + val full = RegNext(counter.msb) io.cpu.execute.haltIt setWhen(full) - rspSync clearWhen(!last || !memCmdSent) - rspLast clearWhen(!last) } @@ -509,9 +545,12 @@ class DataCache(val p : DataCacheConfig) extends Component{ val dataColisions = collisionProcess(io.cpu.execute.address(lineRange.high downto wordRange.low), mask) val wayInvalidate = B(0, wayCount bits) //Used if invalidate enabled - if(withWriteResponse) when(io.cpu.execute.fence){ - when(pending.counter =/= 0 || io.cpu.memory.isValid || io.cpu.writeBack.isValid){ - io.cpu.execute.haltIt := True + when(io.cpu.execute.fence){ + val counter = if(withInvalidate) sync.counter else if(withWriteResponse) pending.counter else null + if(counter != null){ + when(counter =/= 0 || io.cpu.memory.isValid || io.cpu.writeBack.isValid){ + io.cpu.execute.haltIt := True + } } } } @@ -563,16 +602,19 @@ class DataCache(val p : DataCacheConfig) extends Component{ //Evict the cache after reset logics val flusher = new Area { val valid = RegInit(False) + val hold = False when(valid) { tagsWriteCmd.valid := valid tagsWriteCmd.address := mmuRsp.physicalAddress(lineRange) tagsWriteCmd.way.setAll() tagsWriteCmd.data.valid := False io.cpu.writeBack.haltIt := True - when(mmuRsp.physicalAddress(lineRange) =/= wayLineCount - 1) { - mmuRsp.physicalAddress.getDrivingReg(lineRange) := mmuRsp.physicalAddress(lineRange) + 1 - } otherwise { - valid := False + when(!hold) { + when(mmuRsp.physicalAddress(lineRange) =/= wayLineCount - 1) { + mmuRsp.physicalAddress.getDrivingReg(lineRange) := mmuRsp.physicalAddress(lineRange) + 1 + } otherwise { + valid := False + } } } @@ -867,6 +909,7 @@ class DataCache(val p : DataCacheConfig) extends Component{ //Invalidate cache tag when(wayHit) { tagsWriteCmd.valid := True + stageB.flusher.hold := True tagsWriteCmd.address := input.address(lineRange) tagsWriteCmd.data.valid := False tagsWriteCmd.way := wayHits diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index c27cae77..abd6d523 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -184,7 +184,7 @@ class DBusCachedPlugin(val config : DataCacheConfig, case true if !withExternalAmo => dBus.rsp.m2sPipe() case true if withExternalAmo => { val rsp = Flow (DataCacheMemRsp(cache.p)) - rsp.valid := RegNext(dBus.rsp.valid) + rsp.valid := RegNext(dBus.rsp.valid) init(False) rsp.exclusive := RegNext(dBus.rsp.exclusive) rsp.error := RegNext(dBus.rsp.error) rsp.last := RegNext(dBus.rsp.last) @@ -194,8 +194,9 @@ class DBusCachedPlugin(val config : DataCacheConfig, }) if(withInvalidate) { - cache.io.mem.inv << dBus.inv - cache.io.mem.ack >> dBus.ack + cache.io.mem.inv << dBus.inv + cache.io.mem.ack >> dBus.ack + cache.io.mem.sync << dBus.sync } pipeline plug new Area{ From b9ceabf128492bbddae09fc1ccf1492ffd48fa9b Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 16 Apr 2020 01:29:13 +0200 Subject: [PATCH 380/951] few fixes --- .../scala/vexriscv/ip/InstructionCache.scala | 2 +- src/main/scala/vexriscv/plugin/DebugPlugin.scala | 2 +- src/test/cpp/raw/common/asm.mk | 2 +- src/test/cpp/regression/main.cpp | 16 ++++++++++++++++ 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/main/scala/vexriscv/ip/InstructionCache.scala b/src/main/scala/vexriscv/ip/InstructionCache.scala index 4df0f79d..09b1a8ac 100644 --- a/src/main/scala/vexriscv/ip/InstructionCache.scala +++ b/src/main/scala/vexriscv/ip/InstructionCache.scala @@ -251,7 +251,7 @@ case class InstructionCacheMemBus(p : InstructionCacheConfig) extends Bundle wit def toBmb() : Bmb = { val busParameter = p.getBmbParameter - val bus = Bmb(busParameter) + val bus = Bmb(busParameter).setCompositeName(this,"toBmb", true) bus.cmd.arbitrationFrom(cmd) bus.cmd.opcode := Bmb.Cmd.Opcode.READ bus.cmd.address := cmd.address.resized diff --git a/src/main/scala/vexriscv/plugin/DebugPlugin.scala b/src/main/scala/vexriscv/plugin/DebugPlugin.scala index c04d167b..34a878a9 100644 --- a/src/main/scala/vexriscv/plugin/DebugPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DebugPlugin.scala @@ -96,7 +96,7 @@ case class DebugExtensionIo() extends Bundle with IMasterSlave{ -class DebugPlugin(val debugClockDomain : ClockDomain, hardwareBreakpointCount : Int = 0) extends Plugin[VexRiscv] { +class DebugPlugin(var debugClockDomain : ClockDomain, hardwareBreakpointCount : Int = 0) extends Plugin[VexRiscv] { var io : DebugExtensionIo = null val injectionAsks = ArrayBuffer[(Stage, Bool)]() diff --git a/src/test/cpp/raw/common/asm.mk b/src/test/cpp/raw/common/asm.mk index 3d4b2050..b63c80a6 100644 --- a/src/test/cpp/raw/common/asm.mk +++ b/src/test/cpp/raw/common/asm.mk @@ -40,7 +40,7 @@ OBJS := $(addprefix $(OBJDIR)/,$(OBJS)) -all: $(OBJDIR)/$(PROJ_NAME).elf $(OBJDIR)/$(PROJ_NAME).hex $(OBJDIR)/$(PROJ_NAME).asm +all: $(OBJDIR)/$(PROJ_NAME).elf $(OBJDIR)/$(PROJ_NAME).hex $(OBJDIR)/$(PROJ_NAME).asm $(OBJDIR)/$(PROJ_NAME).bin @echo "done" $(OBJDIR)/%.elf: $(OBJS) | $(OBJDIR) diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 6070183d..67d7a0a6 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -2350,6 +2350,7 @@ public: bool reservationValid = false; uint32_t reservationAddress; + uint32_t pendingSync = 0; Workspace *ws; VVexRiscv* top; @@ -2363,11 +2364,17 @@ public: virtual void onReset(){ top->dBus_cmd_ready = 1; top->dBus_rsp_valid = 0; + top->dBus_inv_valid = 0; + top->dBus_ack_ready = 0; + top->dBus_sync_valid = 0; } virtual void preCycle(){ if (top->dBus_cmd_valid && top->dBus_cmd_ready) { if(top->dBus_cmd_payload_wr){ + #ifdef DBUS_INVALIDATE + pendingSync += 1; + #endif #ifndef DBUS_EXCLUSIVE bool error; ws->dBusAccess(top->dBus_cmd_payload_address,1,2,top->dBus_cmd_payload_mask,&top->dBus_cmd_payload_data,&error); @@ -2406,6 +2413,11 @@ public: #endif } } + #ifdef DBUS_INVALIDATE + if(top->dBus_sync_valid && top->dBus_sync_ready){ + pendingSync -= 1; + } + #endif } virtual void postCycle(){ @@ -2446,6 +2458,10 @@ public: } } top->dBus_ack_ready = (ws->dStall ? VL_RANDOM_I(7) < 100 : 1); + if(top->dBus_sync_ready) top->dBus_sync_valid = 0; + if(top->dBus_sync_valid == 0 && pendingSync != 0 && (ws->dStall ? VL_RANDOM_I(7) < 80 : 1) ){ + top->dBus_sync_valid = 1; + } #endif } From 73c21177e511aae1dc7dae800e2ad7fb8c1f8297 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 16 Apr 2020 01:30:03 +0200 Subject: [PATCH 381/951] Add VexRiscvSmpCluster, seem to work on simple case --- .../demo/smp/VexRiscvSmpCluster.scala | 302 ++++++++++++++++++ src/test/cpp/raw/smp/.gitignore | 5 + src/test/cpp/raw/smp/build/smp.asm | 108 +++++++ src/test/cpp/raw/smp/makefile | 5 + src/test/cpp/raw/smp/src/crt.S | 70 ++++ src/test/cpp/raw/smp/src/ld | 16 + 6 files changed, 506 insertions(+) create mode 100644 src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala create mode 100644 src/test/cpp/raw/smp/.gitignore create mode 100644 src/test/cpp/raw/smp/build/smp.asm create mode 100644 src/test/cpp/raw/smp/makefile create mode 100644 src/test/cpp/raw/smp/src/crt.S create mode 100644 src/test/cpp/raw/smp/src/ld diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala new file mode 100644 index 00000000..474357f5 --- /dev/null +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -0,0 +1,302 @@ +package vexriscv.demo.smp + +import spinal.core._ +import spinal.lib._ +import spinal.lib.bus.bmb.sim.BmbMemoryAgent +import spinal.lib.bus.bmb.{Bmb, BmbArbiter, BmbDecoder, BmbExclusiveMonitor, BmbInvalidateMonitor, BmbParameter} +import spinal.lib.com.jtag.Jtag +import spinal.lib.com.jtag.sim.JtagTcp +import vexriscv.ip.{DataCacheAck, DataCacheConfig, DataCacheMemBus, InstructionCacheConfig} +import vexriscv.plugin.{BranchPlugin, CsrPlugin, CsrPluginConfig, DBusCachedPlugin, DBusSimplePlugin, DebugPlugin, DecoderSimplePlugin, FullBarrelShifterPlugin, HazardSimplePlugin, IBusCachedPlugin, IBusSimplePlugin, IntAluPlugin, MmuPlugin, MmuPortConfig, MulDivIterativePlugin, MulPlugin, RegFilePlugin, STATIC, SrcPlugin, YamlPlugin} +import vexriscv.{VexRiscv, VexRiscvConfig, plugin} + + +case class VexRiscvSmpClusterParameter( cpuConfigs : Seq[VexRiscvConfig]) + +case class VexRiscvSmpCluster(p : VexRiscvSmpClusterParameter, + debugClockDomain : ClockDomain) extends Component{ + val dBusParameter = p.cpuConfigs.head.plugins.find(_.isInstanceOf[DBusCachedPlugin]).get.asInstanceOf[DBusCachedPlugin].config.getBmbParameter() + val dBusArbiterParameter = dBusParameter.copy(sourceWidth = log2Up(p.cpuConfigs.size)) + val exclusiveMonitorParameter = dBusArbiterParameter + val invalidateMonitorParameter = BmbExclusiveMonitor.outputParameter(exclusiveMonitorParameter) + val dMemParameter = BmbInvalidateMonitor.outputParameter(invalidateMonitorParameter) + + val iBusParameter = p.cpuConfigs.head.plugins.find(_.isInstanceOf[IBusCachedPlugin]).get.asInstanceOf[IBusCachedPlugin].config.getBmbParameter() + val iBusArbiterParameter = iBusParameter.copy(sourceWidth = log2Up(p.cpuConfigs.size)) + val iMemParameter = iBusArbiterParameter + + val io = new Bundle { + val dMem = master(Bmb(dMemParameter)) + val iMem = master(Bmb(iMemParameter)) + val timerInterrupts = in Bits(p.cpuConfigs.size bits) + val externalInterrupts = in Bits(p.cpuConfigs.size bits) + val externalSupervisorInterrupts = in Bits(p.cpuConfigs.size bits) + val jtag = slave(Jtag()) + val debugReset = out Bool() + } + + val cpus = for((cpuConfig, cpuId) <- p.cpuConfigs.zipWithIndex) yield new Area{ + var iBus : Bmb = null + var dBus : Bmb = null + cpuConfig.plugins.foreach { + case plugin: DebugPlugin => debugClockDomain{ + plugin.debugClockDomain = debugClockDomain + } + case _ => + } + val core = new VexRiscv(cpuConfig) + core.plugins.foreach { + case plugin: IBusCachedPlugin => iBus = plugin.iBus.toBmb() + case plugin: DBusCachedPlugin => dBus = plugin.dBus.toBmb() + case plugin: CsrPlugin => { + plugin.externalInterrupt := io.externalInterrupts(cpuId) + plugin.timerInterrupt := io.timerInterrupts(cpuId) + if (plugin.config.supervisorGen) plugin.externalInterruptS := io.externalSupervisorInterrupts(cpuId) + } + case plugin: DebugPlugin => debugClockDomain{ + io.debugReset := RegNext(plugin.io.resetOut) + io.jtag <> plugin.io.bus.fromJtag() + } + case _ => + } + } + + val dBusArbiter = BmbArbiter( + p = dBusArbiterParameter, + portCount = cpus.size, + pendingRspMax = 64, + lowerFirstPriority = false, + inputsWithInv = cpus.map(_ => true), + inputsWithSync = cpus.map(_ => true), + pendingInvMax = 16 + ) + + (dBusArbiter.io.inputs, cpus).zipped.foreach(_ << _.dBus) + + val exclusiveMonitor = BmbExclusiveMonitor( + inputParameter = exclusiveMonitorParameter, + pendingWriteMax = 64 + ) + exclusiveMonitor.io.input << dBusArbiter.io.output + + val invalidateMonitor = BmbInvalidateMonitor( + inputParameter = invalidateMonitorParameter, + pendingInvMax = 16 + ) + invalidateMonitor.io.input << exclusiveMonitor.io.output + + io.dMem << invalidateMonitor.io.output + + val iBusArbiter = BmbArbiter( + p = iBusArbiterParameter, + portCount = cpus.size, + pendingRspMax = 64, + lowerFirstPriority = false, + inputsWithInv = cpus.map(_ => true), + inputsWithSync = cpus.map(_ => true), + pendingInvMax = 16 + ) + + (iBusArbiter.io.inputs, cpus).zipped.foreach(_ << _.iBus) + io.iMem << iBusArbiter.io.output +} + + + +object VexRiscvSmpClusterGen { + def vexRiscvConfig(id : Int) = { + val config = VexRiscvConfig( + plugins = List( + new MmuPlugin( + ioRange = x => x(31 downto 28) === 0xF + ), + //Uncomment the whole IBusSimplePlugin and comment IBusCachedPlugin if you want uncached iBus config + // new IBusSimplePlugin( + // resetVector = 0x80000000l, + // cmdForkOnSecondStage = false, + // cmdForkPersistence = false, + // prediction = DYNAMIC_TARGET, + // historyRamSizeLog2 = 10, + // catchAccessFault = true, + // compressedGen = true, + // busLatencyMin = 1, + // injectorStage = true, + // memoryTranslatorPortConfig = withMmu generate MmuPortConfig( + // portTlbSize = 4 + // ) + // ), + + //Uncomment the whole IBusCachedPlugin and comment IBusSimplePlugin if you want cached iBus config + new IBusCachedPlugin( + resetVector = 0x80000000l, + compressedGen = false, + prediction = STATIC, + injectorStage = false, + config = InstructionCacheConfig( + cacheSize = 4096*1, + bytePerLine = 32, + wayCount = 1, + addressWidth = 32, + cpuDataWidth = 32, + memDataWidth = 32, + catchIllegalAccess = true, + catchAccessFault = true, + asyncTagMemory = false, + twoCycleRam = false, + twoCycleCache = true + // ) + ), + memoryTranslatorPortConfig = MmuPortConfig( + portTlbSize = 4 + ) + ), + // ).newTightlyCoupledPort(TightlyCoupledPortParameter("iBusTc", a => a(30 downto 28) === 0x0 && a(5))), + // new DBusSimplePlugin( + // catchAddressMisaligned = true, + // catchAccessFault = true, + // earlyInjection = false, + // withLrSc = true, + // memoryTranslatorPortConfig = withMmu generate MmuPortConfig( + // portTlbSize = 4 + // ) + // ), + new DBusCachedPlugin( + dBusCmdMasterPipe = true, + dBusCmdSlavePipe = true, + dBusRspSlavePipe = true, + config = new DataCacheConfig( + cacheSize = 4096*1, + bytePerLine = 32, + wayCount = 1, + addressWidth = 32, + cpuDataWidth = 32, + memDataWidth = 32, + catchAccessError = true, + catchIllegal = true, + catchUnaligned = true, + withLrSc = true, + withAmo = true, + withExclusive = true, + withInvalidate = true + // ) + ), + memoryTranslatorPortConfig = MmuPortConfig( + portTlbSize = 4 + ) + ), + + // new MemoryTranslatorPlugin( + // tlbSize = 32, + // virtualRange = _(31 downto 28) === 0xC, + // ioRange = _(31 downto 28) === 0xF + // ), + + new DecoderSimplePlugin( + catchIllegalInstruction = true + ), + new RegFilePlugin( + regFileReadyKind = plugin.SYNC, + zeroBoot = true + ), + new IntAluPlugin, + new SrcPlugin( + separatedAddSub = false + ), + new FullBarrelShifterPlugin(earlyInjection = false), + // new LightShifterPlugin, + new HazardSimplePlugin( + bypassExecute = true, + bypassMemory = true, + bypassWriteBack = true, + bypassWriteBackBuffer = true, + pessimisticUseSrc = false, + pessimisticWriteRegFile = false, + pessimisticAddressMatch = false + ), + // new HazardSimplePlugin(false, true, false, true), + // new HazardSimplePlugin(false, false, false, false), + new MulPlugin, + new MulDivIterativePlugin( + genMul = false, + genDiv = true, + mulUnrollFactor = 32, + divUnrollFactor = 1 + ), + // new DivPlugin, + new CsrPlugin(CsrPluginConfig.all2(0x80000020l).copy(ebreakGen = false, mhartid = id)), + // new CsrPlugin(//CsrPluginConfig.all2(0x80000020l).copy(ebreakGen = true)/* + // CsrPluginConfig( + // catchIllegalAccess = false, + // mvendorid = null, + // marchid = null, + // mimpid = null, + // mhartid = null, + // misaExtensionsInit = 0, + // misaAccess = CsrAccess.READ_ONLY, + // mtvecAccess = CsrAccess.WRITE_ONLY, + // mtvecInit = 0x80000020l, + // mepcAccess = CsrAccess.READ_WRITE, + // mscratchGen = true, + // mcauseAccess = CsrAccess.READ_ONLY, + // mbadaddrAccess = CsrAccess.READ_ONLY, + // mcycleAccess = CsrAccess.NONE, + // minstretAccess = CsrAccess.NONE, + // ecallGen = true, + // ebreakGen = true, + // wfiGenAsWait = false, + // wfiGenAsNop = true, + // ucycleAccess = CsrAccess.NONE + // )), + new BranchPlugin( + earlyBranch = false, + catchAddressMisaligned = true, + fenceiGenAsAJump = false + ), + new YamlPlugin(s"cpu$id.yaml") + ) + ) + if(id == 0) config.plugins += new DebugPlugin(null) + config + } + def vexRiscvCluster() = VexRiscvSmpCluster( + debugClockDomain = ClockDomain.current.copy(reset = Bool().setName("debugResetIn")), + p = VexRiscvSmpClusterParameter( + cpuConfigs = List.tabulate(4) { + vexRiscvConfig(_) + } + ) + ) + def main(args: Array[String]): Unit = { + SpinalVerilog { + vexRiscvCluster() + } + } +} + + +object VexRiscvSmpClusterTest extends App{ + import spinal.core.sim._ + + val simConfig = SimConfig + simConfig.withWave + simConfig.allOptimisation + simConfig.addSimulatorFlag("--threads 1") + + simConfig.compile(VexRiscvSmpClusterGen.vexRiscvCluster()).doSim(seed = 42){dut => + dut.clockDomain.forkSimSpeedPrinter(1.0) + dut.clockDomain.forkStimulus(10) + dut.debugClockDomain.forkStimulus(10) + + + JtagTcp(dut.io.jtag, 100) + + val ram = new BmbMemoryAgent(0x100000000l) + ram.addPort(dut.io.iMem,0,dut.clockDomain,true) + ram.addPort(dut.io.dMem,0,dut.clockDomain,true) + + ram.memory.loadBin(0x80000000l, "src/test/cpp/raw/smp/build/smp.bin") + + sleep(10000*10) + simSuccess() + } +} \ No newline at end of file diff --git a/src/test/cpp/raw/smp/.gitignore b/src/test/cpp/raw/smp/.gitignore new file mode 100644 index 00000000..16512ffc --- /dev/null +++ b/src/test/cpp/raw/smp/.gitignore @@ -0,0 +1,5 @@ +*.map +*.v +*.elf +*.o +*.hex \ No newline at end of file diff --git a/src/test/cpp/raw/smp/build/smp.asm b/src/test/cpp/raw/smp/build/smp.asm new file mode 100644 index 00000000..8173f8c2 --- /dev/null +++ b/src/test/cpp/raw/smp/build/smp.asm @@ -0,0 +1,108 @@ + +build/smp.elf: file format elf32-littleriscv + + +Disassembly of section .crt_section: + +80000000 <_start>: +80000000: f1402a73 csrr s4,mhartid +80000004: 00000517 auipc a0,0x0 +80000008: 07850513 addi a0,a0,120 # 8000007c +8000000c: 00000513 li a0,0 +80000010: 00a52023 sw a0,0(a0) + +80000014 : +80000014: 00100513 li a0,1 +80000018: 00000597 auipc a1,0x0 +8000001c: 05c58593 addi a1,a1,92 # 80000074 +80000020: 00a5a02f amoadd.w zero,a0,(a1) + +80000024 : +80000024: 00000417 auipc s0,0x0 +80000028: 05042403 lw s0,80(s0) # 80000074 +8000002c: 0c800513 li a0,200 +80000030: 038000ef jal ra,80000068 +80000034: 00000497 auipc s1,0x0 +80000038: 0404a483 lw s1,64(s1) # 80000074 +8000003c: fe8494e3 bne s1,s0,80000024 +80000040: 00000513 li a0,0 +80000044: 00952023 sw s1,0(a0) +80000048: 0040006f j 8000004c + +8000004c : +8000004c: 00800513 li a0,8 +80000050: 00052023 sw zero,0(a0) +80000054: 0100006f j 80000064 + +80000058 : +80000058: 00c00513 li a0,12 +8000005c: 00052023 sw zero,0(a0) +80000060: 0040006f j 80000064 + +80000064 : +80000064: 0000006f j 80000064 + +80000068 : +80000068: fff50513 addi a0,a0,-1 +8000006c: fe051ee3 bnez a0,80000068 +80000070: 00008067 ret + +80000074 : +80000074: 0000 unimp + ... + +80000078 : +80000078: 0000 unimp + ... + +8000007c : +8000007c: 0000000b 0xb + +80000080 : +80000080: 0016 c.slli zero,0x5 + ... + +80000084 : +80000084: 0049 c.nop 18 + ... + +80000088 : +80000088: 003a c.slli zero,0xe + ... + +8000008c : +8000008c: 0038 addi a4,sp,8 + ... + +80000090 : +80000090: 0000004b fnmsub.s ft0,ft0,ft0,ft0,rne + +80000094 : +80000094: 0038 addi a4,sp,8 + ... + +80000098 : +80000098: 00000053 fadd.s ft0,ft0,ft0,rne + +8000009c : +8000009c: 0021 c.nop 8 + ... + +800000a0 : +800000a0: ffffffbf 0xffffffbf + +800000a4 : +800000a4: ffa9 bnez a5,7ffffffe <_start-0x2> +800000a6: ffff 0xffff + +800000a8 : +800000a8: ffc9 bnez a5,80000042 +800000aa: ffff 0xffff + +800000ac : +800000ac: 0004 0x4 +800000ae: ffff 0xffff + +800000b0 : +800000b0: 0005 c.nop 1 +800000b2: ffff 0xffff diff --git a/src/test/cpp/raw/smp/makefile b/src/test/cpp/raw/smp/makefile new file mode 100644 index 00000000..0886c1b6 --- /dev/null +++ b/src/test/cpp/raw/smp/makefile @@ -0,0 +1,5 @@ +PROJ_NAME=smp + +ATOMIC=yes + +include ../common/asm.mk \ No newline at end of file diff --git a/src/test/cpp/raw/smp/src/crt.S b/src/test/cpp/raw/smp/src/crt.S new file mode 100644 index 00000000..be1e59d8 --- /dev/null +++ b/src/test/cpp/raw/smp/src/crt.S @@ -0,0 +1,70 @@ +#define REPORT_OFFSET 0xF0000000 +#define REPORT_THREAD_ID 0 +#define REPORT_THREAD_COUNT 1 +#define REPORT_SUCCESS 2 +#define REPORT_FAILURE 3 + +#define report(reg, id) \ + li a0, id*4; \ + sw reg, 0(a0); \ + +_start: + + #define HART_ID x20 + csrr HART_ID, mhartid + la a0, test1_data + report(a0, REPORT_THREAD_ID) + + +count_thread_start: + //Count up threads + li a0, 1 + la a1, thread_count + amoadd.w x0, a0, (a1) + +count_thread_wait: + //Wait everybody + lw s0, thread_count + li a0, 200 + call sleep + lw s1, thread_count + bne s1, s0, count_thread_wait + report(s1, REPORT_THREAD_ID) + + j success + +success: + report(x0, REPORT_SUCCESS) + j end + +failure: + report(x0, REPORT_FAILURE) + j end + +end: + j end + + +sleep: + addi a0, a0, -1 + bnez a0, sleep + ret + + +thread_count: .word 0 +shared_memory_1: .word 0 + +test1_data: .word 11 +test2_data: .word 22 +test3_data: .word 73 +test4_data: .word 58 +test5_data: .word 56 +test6_data: .word 75 +test7_data: .word 56 +test8_data: .word 83 +test9_data: .word 33 +test10_data: .word -65 +test11_data: .word -87 +test12_data: .word -55 +test13_data: .word 0xFFFF0004 +test14_data: .word 0xFFFF0005 \ No newline at end of file diff --git a/src/test/cpp/raw/smp/src/ld b/src/test/cpp/raw/smp/src/ld new file mode 100644 index 00000000..93d8de8e --- /dev/null +++ b/src/test/cpp/raw/smp/src/ld @@ -0,0 +1,16 @@ +OUTPUT_ARCH( "riscv" ) + +MEMORY { + onChipRam (W!RX)/*(RX)*/ : ORIGIN = 0x80000000, LENGTH = 128K +} + +SECTIONS +{ + + .crt_section : + { + . = ALIGN(4); + *crt.o(.text) + } > onChipRam + +} From fd52f9ba5090951de44d5d3c6972542bfa6edb27 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 16 Apr 2020 02:22:18 +0200 Subject: [PATCH 382/951] Add smp.bin --- src/test/cpp/raw/smp/.gitignore | 3 ++- src/test/cpp/raw/smp/build/smp.bin | Bin 0 -> 180 bytes 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100755 src/test/cpp/raw/smp/build/smp.bin diff --git a/src/test/cpp/raw/smp/.gitignore b/src/test/cpp/raw/smp/.gitignore index 16512ffc..a7caa3b4 100644 --- a/src/test/cpp/raw/smp/.gitignore +++ b/src/test/cpp/raw/smp/.gitignore @@ -2,4 +2,5 @@ *.v *.elf *.o -*.hex \ No newline at end of file +*.hex +!*.bin \ No newline at end of file diff --git a/src/test/cpp/raw/smp/build/smp.bin b/src/test/cpp/raw/smp/build/smp.bin new file mode 100755 index 0000000000000000000000000000000000000000..05ebfb983b57501c52c46d03b1f0fe27ab61ea39 GIT binary patch literal 180 zcmXTca`-6D%D^DZ+R82rq?Hwx0@(r#(}C>Ctw&k)7c6BEXJKGqR$*ZkW^Lek&(Od; z9msE9!ou=+O3Ocpo~aD^3=Tkj4M6>@KsE!TFzW#*+X2J}%68Vd m42V5}*b0a(fY=*K2LowEAm0D~|NoUhd=iLR82 Date: Thu, 16 Apr 2020 15:23:25 +0200 Subject: [PATCH 383/951] More SMP tests (barrier via AMO and LRSC) --- .../demo/smp/VexRiscvSmpCluster.scala | 88 +++++-- src/test/cpp/raw/smp/build/smp.asm | 241 +++++++++++------- src/test/cpp/raw/smp/build/smp.bin | Bin 180 -> 496 bytes src/test/cpp/raw/smp/src/crt.S | 120 ++++++--- 4 files changed, 312 insertions(+), 137 deletions(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index 474357f5..519a010f 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -10,6 +10,8 @@ import vexriscv.ip.{DataCacheAck, DataCacheConfig, DataCacheMemBus, InstructionC import vexriscv.plugin.{BranchPlugin, CsrPlugin, CsrPluginConfig, DBusCachedPlugin, DBusSimplePlugin, DebugPlugin, DecoderSimplePlugin, FullBarrelShifterPlugin, HazardSimplePlugin, IBusCachedPlugin, IBusSimplePlugin, IntAluPlugin, MmuPlugin, MmuPortConfig, MulDivIterativePlugin, MulPlugin, RegFilePlugin, STATIC, SrcPlugin, YamlPlugin} import vexriscv.{VexRiscv, VexRiscvConfig, plugin} +import scala.collection.mutable + case class VexRiscvSmpClusterParameter( cpuConfigs : Seq[VexRiscvConfig]) @@ -27,7 +29,8 @@ case class VexRiscvSmpCluster(p : VexRiscvSmpClusterParameter, val io = new Bundle { val dMem = master(Bmb(dMemParameter)) - val iMem = master(Bmb(iMemParameter)) +// val iMem = master(Bmb(iMemParameter)) + val iMems = Vec(master(Bmb(iMemParameter)), p.cpuConfigs.size) val timerInterrupts = in Bits(p.cpuConfigs.size bits) val externalInterrupts = in Bits(p.cpuConfigs.size bits) val externalSupervisorInterrupts = in Bits(p.cpuConfigs.size bits) @@ -87,18 +90,19 @@ case class VexRiscvSmpCluster(p : VexRiscvSmpClusterParameter, io.dMem << invalidateMonitor.io.output - val iBusArbiter = BmbArbiter( - p = iBusArbiterParameter, - portCount = cpus.size, - pendingRspMax = 64, - lowerFirstPriority = false, - inputsWithInv = cpus.map(_ => true), - inputsWithSync = cpus.map(_ => true), - pendingInvMax = 16 - ) - - (iBusArbiter.io.inputs, cpus).zipped.foreach(_ << _.iBus) - io.iMem << iBusArbiter.io.output +// val iBusArbiter = BmbArbiter( +// p = iBusArbiterParameter, +// portCount = cpus.size, +// pendingRspMax = 64, +// lowerFirstPriority = false, +// inputsWithInv = cpus.map(_ => true), +// inputsWithSync = cpus.map(_ => true), +// pendingInvMax = 16 +// ) +// +// (iBusArbiter.io.inputs, cpus).zipped.foreach(_ << _.iBus) +// io.iMem << iBusArbiter.io.output + (io.iMems, cpus).zipped.foreach(_ << _.iBus) } @@ -274,6 +278,14 @@ object VexRiscvSmpClusterGen { } +object SmpTest{ + val REPORT_OFFSET = 0xF8000000 + val REPORT_THREAD_ID = 0x00 + val REPORT_THREAD_COUNT = 0x04 + val REPORT_END = 0x08 + val REPORT_BARRIER_START = 0x0C + val REPORT_BARRIER_END = 0x10 +} object VexRiscvSmpClusterTest extends App{ import spinal.core.sim._ @@ -282,21 +294,57 @@ object VexRiscvSmpClusterTest extends App{ simConfig.allOptimisation simConfig.addSimulatorFlag("--threads 1") - simConfig.compile(VexRiscvSmpClusterGen.vexRiscvCluster()).doSim(seed = 42){dut => + simConfig.compile(VexRiscvSmpClusterGen.vexRiscvCluster()).doSimUntilVoid(seed = 42){dut => + SimTimeout(10000*10) dut.clockDomain.forkSimSpeedPrinter(1.0) dut.clockDomain.forkStimulus(10) dut.debugClockDomain.forkStimulus(10) + val hartCount = dut.cpus.size JtagTcp(dut.io.jtag, 100) - val ram = new BmbMemoryAgent(0x100000000l) - ram.addPort(dut.io.iMem,0,dut.clockDomain,true) - ram.addPort(dut.io.dMem,0,dut.clockDomain,true) + val withStall = false + val cpuEnd = Array.fill(dut.p.cpuConfigs.size)(false) + val barriers = mutable.HashMap[Int, Int]() + val ram = new BmbMemoryAgent(0x100000000l){ + var writeData = 0 + override def setByte(address: Long, value: Byte): Unit = { + if((address & 0xF0000000l) != 0xF0000000l) return super.setByte(address, value) + val byteId = address & 3 + val mask = 0xFF << (byteId*8) + writeData = (writeData & ~mask) | ((value.toInt << (byteId*8)) & mask) + if(byteId != 3) return + val offset = (address & ~0xF0000000l)-3 + println(s"W[0x${offset.toHexString}] = $writeData") + offset match { + case _ if offset >= 0x8000000 && offset < 0x9000000 => { + val hart = ((offset & 0xFF0000) >> 16).toInt + val code = (offset & 0x00FFFF).toInt + val data = writeData + import SmpTest._ + code match { + case REPORT_THREAD_ID => assert(data == hart) + case REPORT_THREAD_COUNT => assert(data == hartCount) + case REPORT_END => assert(data == 0); assert(cpuEnd(hart) == false); cpuEnd(hart) = true; if(!cpuEnd.exists(_ == false)) simSuccess() + case REPORT_BARRIER_START => { + val counter = barriers.getOrElse(data, 0) + assert(counter < hartCount) + barriers(data) = counter + 1 + } + case REPORT_BARRIER_END => { + val counter = barriers.getOrElse(data, 0) + assert(counter == hartCount) + } + } + } + } + } + } + dut.io.iMems.foreach(ram.addPort(_,0,dut.clockDomain,true, withStall)) //Moarr powaaaaa +// ram.addPort(dut.io.iMem,0,dut.clockDomain,true, withStall) + ram.addPort(dut.io.dMem,0,dut.clockDomain,true, withStall) ram.memory.loadBin(0x80000000l, "src/test/cpp/raw/smp/build/smp.bin") - - sleep(10000*10) - simSuccess() } } \ No newline at end of file diff --git a/src/test/cpp/raw/smp/build/smp.asm b/src/test/cpp/raw/smp/build/smp.asm index 8173f8c2..7820bb4d 100644 --- a/src/test/cpp/raw/smp/build/smp.asm +++ b/src/test/cpp/raw/smp/build/smp.asm @@ -5,104 +5,171 @@ build/smp.elf: file format elf32-littleriscv Disassembly of section .crt_section: 80000000 <_start>: -80000000: f1402a73 csrr s4,mhartid -80000004: 00000517 auipc a0,0x0 -80000008: 07850513 addi a0,a0,120 # 8000007c -8000000c: 00000513 li a0,0 -80000010: 00a52023 sw a0,0(a0) +80000000: f1402473 csrr s0,mhartid +80000004: f80002b7 lui t0,0xf8000 +80000008: f1402373 csrr t1,mhartid +8000000c: 01031313 slli t1,t1,0x10 +80000010: 006282b3 add t0,t0,t1 +80000014: 0082a023 sw s0,0(t0) # f8000000 -80000014 : -80000014: 00100513 li a0,1 -80000018: 00000597 auipc a1,0x0 -8000001c: 05c58593 addi a1,a1,92 # 80000074 -80000020: 00a5a02f amoadd.w zero,a0,(a1) +80000018 : +80000018: 00100513 li a0,1 +8000001c: 00000597 auipc a1,0x0 +80000020: 1c458593 addi a1,a1,452 # 800001e0 +80000024: 00a5a02f amoadd.w zero,a0,(a1) -80000024 : -80000024: 00000417 auipc s0,0x0 -80000028: 05042403 lw s0,80(s0) # 80000074 -8000002c: 0c800513 li a0,200 -80000030: 038000ef jal ra,80000068 -80000034: 00000497 auipc s1,0x0 -80000038: 0404a483 lw s1,64(s1) # 80000074 -8000003c: fe8494e3 bne s1,s0,80000024 -80000040: 00000513 li a0,0 -80000044: 00952023 sw s1,0(a0) -80000048: 0040006f j 8000004c +80000028 : +80000028: 00000417 auipc s0,0x0 +8000002c: 1b842403 lw s0,440(s0) # 800001e0 +80000030: 0c800513 li a0,200 +80000034: 1a0000ef jal ra,800001d4 +80000038: 00000497 auipc s1,0x0 +8000003c: 1a84a483 lw s1,424(s1) # 800001e0 +80000040: fe8494e3 bne s1,s0,80000028 +80000044: f80002b7 lui t0,0xf8000 +80000048: 00428293 addi t0,t0,4 # f8000004 +8000004c: f1402373 csrr t1,mhartid +80000050: 01031313 slli t1,t1,0x10 +80000054: 006282b3 add t0,t0,t1 +80000058: 0092a023 sw s1,0(t0) -8000004c : -8000004c: 00800513 li a0,8 -80000050: 00052023 sw zero,0(a0) -80000054: 0100006f j 80000064 +8000005c : +8000005c: 00100513 li a0,1 +80000060: 040000ef jal ra,800000a0 +80000064: 00200513 li a0,2 +80000068: 038000ef jal ra,800000a0 +8000006c: 00300513 li a0,3 +80000070: 030000ef jal ra,800000a0 +80000074: 00400513 li a0,4 +80000078: 09c000ef jal ra,80000114 +8000007c: 00500513 li a0,5 +80000080: 094000ef jal ra,80000114 +80000084: 00600513 li a0,6 +80000088: 08c000ef jal ra,80000114 +8000008c: 00700513 li a0,7 +80000090: 010000ef jal ra,800000a0 +80000094: 00800513 li a0,8 +80000098: 07c000ef jal ra,80000114 +8000009c: 0f40006f j 80000190 -80000058 : -80000058: 00c00513 li a0,12 -8000005c: 00052023 sw zero,0(a0) -80000060: 0040006f j 80000064 +800000a0 : +800000a0: f80002b7 lui t0,0xf8000 +800000a4: 00c28293 addi t0,t0,12 # f800000c +800000a8: f1402373 csrr t1,mhartid +800000ac: 01031313 slli t1,t1,0x10 +800000b0: 006282b3 add t0,t0,t1 +800000b4: 00a2a023 sw a0,0(t0) +800000b8: 00000297 auipc t0,0x0 +800000bc: 13028293 addi t0,t0,304 # 800001e8 +800000c0: 00100313 li t1,1 +800000c4: 0062a02f amoadd.w zero,t1,(t0) +800000c8: 00000317 auipc t1,0x0 +800000cc: 11832303 lw t1,280(t1) # 800001e0 -80000064 : -80000064: 0000006f j 80000064 +800000d0 : +800000d0: 0002a383 lw t2,0(t0) +800000d4: fe639ee3 bne t2,t1,800000d0 +800000d8: f80002b7 lui t0,0xf8000 +800000dc: 01028293 addi t0,t0,16 # f8000010 +800000e0: f1402373 csrr t1,mhartid +800000e4: 01031313 slli t1,t1,0x10 +800000e8: 006282b3 add t0,t0,t1 +800000ec: 00a2a023 sw a0,0(t0) -80000068 : -80000068: fff50513 addi a0,a0,-1 -8000006c: fe051ee3 bnez a0,80000068 -80000070: 00008067 ret +800000f0 : +800000f0: f14022f3 csrr t0,mhartid +800000f4: 00029863 bnez t0,80000104 +800000f8: 00000297 auipc t0,0x0 +800000fc: 0e02a823 sw zero,240(t0) # 800001e8 +80000100: 00008067 ret -80000074 : -80000074: 0000 unimp +80000104 : +80000104: 00000297 auipc t0,0x0 +80000108: 0e42a283 lw t0,228(t0) # 800001e8 +8000010c: fe029ce3 bnez t0,80000104 +80000110: 00008067 ret + +80000114 : +80000114: f80002b7 lui t0,0xf8000 +80000118: 00c28293 addi t0,t0,12 # f800000c +8000011c: f1402373 csrr t1,mhartid +80000120: 01031313 slli t1,t1,0x10 +80000124: 006282b3 add t0,t0,t1 +80000128: 00a2a023 sw a0,0(t0) +8000012c: 00000297 auipc t0,0x0 +80000130: 0c028293 addi t0,t0,192 # 800001ec + +80000134 : +80000134: 1002a32f lr.w t1,(t0) +80000138: 00130313 addi t1,t1,1 +8000013c: 1862a32f sc.w t1,t1,(t0) +80000140: fe031ae3 bnez t1,80000134 +80000144: 00000317 auipc t1,0x0 +80000148: 09c32303 lw t1,156(t1) # 800001e0 + +8000014c : +8000014c: 0002a383 lw t2,0(t0) +80000150: fe639ee3 bne t2,t1,8000014c +80000154: f80002b7 lui t0,0xf8000 +80000158: 01028293 addi t0,t0,16 # f8000010 +8000015c: f1402373 csrr t1,mhartid +80000160: 01031313 slli t1,t1,0x10 +80000164: 006282b3 add t0,t0,t1 +80000168: 00a2a023 sw a0,0(t0) + +8000016c : +8000016c: f14022f3 csrr t0,mhartid +80000170: 00029863 bnez t0,80000180 +80000174: 00000297 auipc t0,0x0 +80000178: 0602ac23 sw zero,120(t0) # 800001ec +8000017c: 00008067 ret + +80000180 : +80000180: 00000297 auipc t0,0x0 +80000184: 06c2a283 lw t0,108(t0) # 800001ec +80000188: fe029ce3 bnez t0,80000180 +8000018c: 00008067 ret + +80000190 : +80000190: 00000413 li s0,0 +80000194: f80002b7 lui t0,0xf8000 +80000198: 00828293 addi t0,t0,8 # f8000008 +8000019c: f1402373 csrr t1,mhartid +800001a0: 01031313 slli t1,t1,0x10 +800001a4: 006282b3 add t0,t0,t1 +800001a8: 0082a023 sw s0,0(t0) +800001ac: 0240006f j 800001d0 + +800001b0 : +800001b0: 00100413 li s0,1 +800001b4: f80002b7 lui t0,0xf8000 +800001b8: 00828293 addi t0,t0,8 # f8000008 +800001bc: f1402373 csrr t1,mhartid +800001c0: 01031313 slli t1,t1,0x10 +800001c4: 006282b3 add t0,t0,t1 +800001c8: 0082a023 sw s0,0(t0) +800001cc: 0040006f j 800001d0 + +800001d0 : +800001d0: 0000006f j 800001d0 + +800001d4 : +800001d4: fff50513 addi a0,a0,-1 +800001d8: fe051ee3 bnez a0,800001d4 +800001dc: 00008067 ret + +800001e0 : +800001e0: 0000 unimp ... -80000078 : -80000078: 0000 unimp +800001e4 : +800001e4: 0000 unimp ... -8000007c : -8000007c: 0000000b 0xb - -80000080 : -80000080: 0016 c.slli zero,0x5 +800001e8 : +800001e8: 0000 unimp ... -80000084 : -80000084: 0049 c.nop 18 +800001ec : +800001ec: 0000 unimp ... - -80000088 : -80000088: 003a c.slli zero,0xe - ... - -8000008c : -8000008c: 0038 addi a4,sp,8 - ... - -80000090 : -80000090: 0000004b fnmsub.s ft0,ft0,ft0,ft0,rne - -80000094 : -80000094: 0038 addi a4,sp,8 - ... - -80000098 : -80000098: 00000053 fadd.s ft0,ft0,ft0,rne - -8000009c : -8000009c: 0021 c.nop 8 - ... - -800000a0 : -800000a0: ffffffbf 0xffffffbf - -800000a4 : -800000a4: ffa9 bnez a5,7ffffffe <_start-0x2> -800000a6: ffff 0xffff - -800000a8 : -800000a8: ffc9 bnez a5,80000042 -800000aa: ffff 0xffff - -800000ac : -800000ac: 0004 0x4 -800000ae: ffff 0xffff - -800000b0 : -800000b0: 0005 c.nop 1 -800000b2: ffff 0xffff diff --git a/src/test/cpp/raw/smp/build/smp.bin b/src/test/cpp/raw/smp/build/smp.bin index 05ebfb983b57501c52c46d03b1f0fe27ab61ea39..85f5095b37a3b0e5edf4e19cc9b07e93bfd0ea2b 100755 GIT binary patch literal 496 zcmb7Au}Z{15PjLro*o=$WQvn0BIf$|3Cn@KpCGxyQsI6eY~l}iLM%i=qF`ZXVJqjS zm^qD3U7_w|V=RnfKnzY^=*Cf%loGOCo7KngCvEK*~X)fcg31j-TFPWCL;> zZ<7iKOTbN-N4K$CT*g&BKQ|L}H7*(r?zKtnVTn+ZI$#8&W_<3GI%3p}$2DIkbyn9c z_Ne*VDfC9Gy;#xCkO=~pIUbu(pn-Ph&xN;LD{y%?T^ zX#P<)85Y-~s`($D13woINrImTTZJpD*88RZFYgD@`|)1%zP*X>+WMQ7oelUNf^6rv SI`@F@{`OJqs%96ao%ac}0*hk+ literal 180 zcmXTca`-6D%D^DZ+R82rq?Hwx0@(r#(}C>Ctw&k)7c6BEXJKGqR$*ZkW^Lek&(Od; z9msE9!ou=+O3Ocpo~aD^3=Tkj4M6>@KsE!TFzW#*+X2J}%68Vd m42V5}*b0a(fY=*K2LowEAm0D~|NoUhd=iLR82 Date: Thu, 16 Apr 2020 17:27:27 +0200 Subject: [PATCH 384/951] fix smp test barrier --- .../demo/smp/VexRiscvSmpCluster.scala | 55 +++-- src/test/cpp/raw/smp/build/smp.asm | 219 +++++++++--------- src/test/cpp/raw/smp/build/smp.bin | Bin 496 -> 504 bytes src/test/cpp/raw/smp/src/crt.S | 66 +++--- 4 files changed, 177 insertions(+), 163 deletions(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index 519a010f..fff9b033 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -11,6 +11,7 @@ import vexriscv.plugin.{BranchPlugin, CsrPlugin, CsrPluginConfig, DBusCachedPlug import vexriscv.{VexRiscv, VexRiscvConfig, plugin} import scala.collection.mutable +import scala.collection.mutable.ArrayBuffer case class VexRiscvSmpClusterParameter( cpuConfigs : Seq[VexRiscvConfig]) @@ -262,17 +263,17 @@ object VexRiscvSmpClusterGen { if(id == 0) config.plugins += new DebugPlugin(null) config } - def vexRiscvCluster() = VexRiscvSmpCluster( + def vexRiscvCluster(cpuCount : Int) = VexRiscvSmpCluster( debugClockDomain = ClockDomain.current.copy(reset = Bool().setName("debugResetIn")), p = VexRiscvSmpClusterParameter( - cpuConfigs = List.tabulate(4) { + cpuConfigs = List.tabulate(cpuCount) { vexRiscvConfig(_) } ) ) def main(args: Array[String]): Unit = { SpinalVerilog { - vexRiscvCluster() + vexRiscvCluster(4) } } } @@ -294,19 +295,41 @@ object VexRiscvSmpClusterTest extends App{ simConfig.allOptimisation simConfig.addSimulatorFlag("--threads 1") - simConfig.compile(VexRiscvSmpClusterGen.vexRiscvCluster()).doSimUntilVoid(seed = 42){dut => - SimTimeout(10000*10) + val cpuCount = 4 + simConfig.compile(VexRiscvSmpClusterGen.vexRiscvCluster(cpuCount)).doSimUntilVoid(seed = 42){dut => + SimTimeout(10000*10*cpuCount) dut.clockDomain.forkSimSpeedPrinter(1.0) dut.clockDomain.forkStimulus(10) dut.debugClockDomain.forkStimulus(10) - val hartCount = dut.cpus.size JtagTcp(dut.io.jtag, 100) val withStall = false val cpuEnd = Array.fill(dut.p.cpuConfigs.size)(false) val barriers = mutable.HashMap[Int, Int]() + + var reportWatchdog = 0 + periodicaly(10000*10){ + assert(reportWatchdog != 0) + reportWatchdog = 0 + } + + case class Report(hart : Int, code : Int, data : Int){ + override def toString: String = { + f"CPU:$hart%2d h${code}%3x -> $data%3d" + } + } + val reports = ArrayBuffer.fill(cpuCount)(ArrayBuffer[Report]()) + onSimEnd{ + for((list, hart) <- reports.zipWithIndex){ + println(f"\n\n**** CPU $hart%2d ****") + for((report, reportId) <- list.zipWithIndex){ + println(f" $reportId%3d : h${report.code}%3x -> ${report.data}%3d") + } + } + } + val ram = new BmbMemoryAgent(0x100000000l){ var writeData = 0 override def setByte(address: Long, value: Byte): Unit = { @@ -316,25 +339,31 @@ object VexRiscvSmpClusterTest extends App{ writeData = (writeData & ~mask) | ((value.toInt << (byteId*8)) & mask) if(byteId != 3) return val offset = (address & ~0xF0000000l)-3 - println(s"W[0x${offset.toHexString}] = $writeData") +// println(s"W[0x${offset.toHexString}] = $writeData @${simTime()}") offset match { case _ if offset >= 0x8000000 && offset < 0x9000000 => { - val hart = ((offset & 0xFF0000) >> 16).toInt - val code = (offset & 0x00FFFF).toInt - val data = writeData + val report = Report( + hart = ((offset & 0xFF0000) >> 16).toInt, + code = (offset & 0x00FFFF).toInt, + data = writeData + ) + println(report) + reports(report.hart) += report + reportWatchdog += 1 + import report._ import SmpTest._ code match { case REPORT_THREAD_ID => assert(data == hart) - case REPORT_THREAD_COUNT => assert(data == hartCount) + case REPORT_THREAD_COUNT => assert(data == cpuCount) case REPORT_END => assert(data == 0); assert(cpuEnd(hart) == false); cpuEnd(hart) = true; if(!cpuEnd.exists(_ == false)) simSuccess() case REPORT_BARRIER_START => { val counter = barriers.getOrElse(data, 0) - assert(counter < hartCount) + assert(counter < cpuCount) barriers(data) = counter + 1 } case REPORT_BARRIER_END => { val counter = barriers.getOrElse(data, 0) - assert(counter == hartCount) + assert(counter == cpuCount) } } } diff --git a/src/test/cpp/raw/smp/build/smp.asm b/src/test/cpp/raw/smp/build/smp.asm index 7820bb4d..db25d17d 100644 --- a/src/test/cpp/raw/smp/build/smp.asm +++ b/src/test/cpp/raw/smp/build/smp.asm @@ -10,24 +10,24 @@ Disassembly of section .crt_section: 80000008: f1402373 csrr t1,mhartid 8000000c: 01031313 slli t1,t1,0x10 80000010: 006282b3 add t0,t0,t1 -80000014: 0082a023 sw s0,0(t0) # f8000000 +80000014: 0082a023 sw s0,0(t0) # f8000000 80000018 : 80000018: 00100513 li a0,1 8000001c: 00000597 auipc a1,0x0 -80000020: 1c458593 addi a1,a1,452 # 800001e0 +80000020: 1d058593 addi a1,a1,464 # 800001ec 80000024: 00a5a02f amoadd.w zero,a0,(a1) 80000028 : 80000028: 00000417 auipc s0,0x0 -8000002c: 1b842403 lw s0,440(s0) # 800001e0 +8000002c: 1c442403 lw s0,452(s0) # 800001ec 80000030: 0c800513 li a0,200 -80000034: 1a0000ef jal ra,800001d4 +80000034: 1ac000ef jal ra,800001e0 80000038: 00000497 auipc s1,0x0 -8000003c: 1a84a483 lw s1,424(s1) # 800001e0 +8000003c: 1b44a483 lw s1,436(s1) # 800001ec 80000040: fe8494e3 bne s1,s0,80000028 80000044: f80002b7 lui t0,0xf8000 -80000048: 00428293 addi t0,t0,4 # f8000004 +80000048: 00428293 addi t0,t0,4 # f8000004 8000004c: f1402373 csrr t1,mhartid 80000050: 01031313 slli t1,t1,0x10 80000054: 006282b3 add t0,t0,t1 @@ -41,135 +41,126 @@ Disassembly of section .crt_section: 8000006c: 00300513 li a0,3 80000070: 030000ef jal ra,800000a0 80000074: 00400513 li a0,4 -80000078: 09c000ef jal ra,80000114 +80000078: 0a4000ef jal ra,8000011c 8000007c: 00500513 li a0,5 -80000080: 094000ef jal ra,80000114 +80000080: 09c000ef jal ra,8000011c 80000084: 00600513 li a0,6 -80000088: 08c000ef jal ra,80000114 +80000088: 094000ef jal ra,8000011c 8000008c: 00700513 li a0,7 80000090: 010000ef jal ra,800000a0 80000094: 00800513 li a0,8 -80000098: 07c000ef jal ra,80000114 -8000009c: 0f40006f j 80000190 +80000098: 084000ef jal ra,8000011c +8000009c: 1000006f j 8000019c 800000a0 : 800000a0: f80002b7 lui t0,0xf8000 -800000a4: 00c28293 addi t0,t0,12 # f800000c +800000a4: 00c28293 addi t0,t0,12 # f800000c 800000a8: f1402373 csrr t1,mhartid 800000ac: 01031313 slli t1,t1,0x10 800000b0: 006282b3 add t0,t0,t1 800000b4: 00a2a023 sw a0,0(t0) -800000b8: 00000297 auipc t0,0x0 -800000bc: 13028293 addi t0,t0,304 # 800001e8 -800000c0: 00100313 li t1,1 -800000c4: 0062a02f amoadd.w zero,t1,(t0) -800000c8: 00000317 auipc t1,0x0 -800000cc: 11832303 lw t1,280(t1) # 800001e0 +800000b8: 00000e97 auipc t4,0x0 +800000bc: 13ceae83 lw t4,316(t4) # 800001f4 +800000c0: 00000297 auipc t0,0x0 +800000c4: 13028293 addi t0,t0,304 # 800001f0 +800000c8: 00100313 li t1,1 +800000cc: 0062a2af amoadd.w t0,t1,(t0) +800000d0: 00128293 addi t0,t0,1 +800000d4: 00000317 auipc t1,0x0 +800000d8: 11832303 lw t1,280(t1) # 800001ec +800000dc: 00629c63 bne t0,t1,800000f4 +800000e0: 001e8293 addi t0,t4,1 +800000e4: 00000317 auipc t1,0x0 +800000e8: 10032623 sw zero,268(t1) # 800001f0 +800000ec: 00000317 auipc t1,0x0 +800000f0: 10532423 sw t0,264(t1) # 800001f4 -800000d0 : -800000d0: 0002a383 lw t2,0(t0) -800000d4: fe639ee3 bne t2,t1,800000d0 -800000d8: f80002b7 lui t0,0xf8000 -800000dc: 01028293 addi t0,t0,16 # f8000010 -800000e0: f1402373 csrr t1,mhartid -800000e4: 01031313 slli t1,t1,0x10 -800000e8: 006282b3 add t0,t0,t1 -800000ec: 00a2a023 sw a0,0(t0) +800000f4 : +800000f4: 00000297 auipc t0,0x0 +800000f8: 1002a283 lw t0,256(t0) # 800001f4 +800000fc: ffd28ce3 beq t0,t4,800000f4 +80000100: f80002b7 lui t0,0xf8000 +80000104: 01028293 addi t0,t0,16 # f8000010 +80000108: f1402373 csrr t1,mhartid +8000010c: 01031313 slli t1,t1,0x10 +80000110: 006282b3 add t0,t0,t1 +80000114: 00a2a023 sw a0,0(t0) +80000118: 00008067 ret -800000f0 : -800000f0: f14022f3 csrr t0,mhartid -800000f4: 00029863 bnez t0,80000104 -800000f8: 00000297 auipc t0,0x0 -800000fc: 0e02a823 sw zero,240(t0) # 800001e8 -80000100: 00008067 ret +8000011c : +8000011c: f80002b7 lui t0,0xf8000 +80000120: 00c28293 addi t0,t0,12 # f800000c +80000124: f1402373 csrr t1,mhartid +80000128: 01031313 slli t1,t1,0x10 +8000012c: 006282b3 add t0,t0,t1 +80000130: 00a2a023 sw a0,0(t0) +80000134: 00000e97 auipc t4,0x0 +80000138: 0c0eae83 lw t4,192(t4) # 800001f4 +8000013c: 00000297 auipc t0,0x0 +80000140: 0b428293 addi t0,t0,180 # 800001f0 -80000104 : -80000104: 00000297 auipc t0,0x0 -80000108: 0e42a283 lw t0,228(t0) # 800001e8 -8000010c: fe029ce3 bnez t0,80000104 -80000110: 00008067 ret +80000144 : +80000144: 1002a32f lr.w t1,(t0) +80000148: 00130313 addi t1,t1,1 +8000014c: 1862a3af sc.w t2,t1,(t0) +80000150: fe039ae3 bnez t2,80000144 +80000154: 00000297 auipc t0,0x0 +80000158: 0982a283 lw t0,152(t0) # 800001ec +8000015c: 00629c63 bne t0,t1,80000174 +80000160: 001e8293 addi t0,t4,1 +80000164: 00000317 auipc t1,0x0 +80000168: 08032623 sw zero,140(t1) # 800001f0 +8000016c: 00000317 auipc t1,0x0 +80000170: 08532423 sw t0,136(t1) # 800001f4 -80000114 : -80000114: f80002b7 lui t0,0xf8000 -80000118: 00c28293 addi t0,t0,12 # f800000c -8000011c: f1402373 csrr t1,mhartid -80000120: 01031313 slli t1,t1,0x10 -80000124: 006282b3 add t0,t0,t1 -80000128: 00a2a023 sw a0,0(t0) -8000012c: 00000297 auipc t0,0x0 -80000130: 0c028293 addi t0,t0,192 # 800001ec - -80000134 : -80000134: 1002a32f lr.w t1,(t0) -80000138: 00130313 addi t1,t1,1 -8000013c: 1862a32f sc.w t1,t1,(t0) -80000140: fe031ae3 bnez t1,80000134 -80000144: 00000317 auipc t1,0x0 -80000148: 09c32303 lw t1,156(t1) # 800001e0 - -8000014c : -8000014c: 0002a383 lw t2,0(t0) -80000150: fe639ee3 bne t2,t1,8000014c -80000154: f80002b7 lui t0,0xf8000 -80000158: 01028293 addi t0,t0,16 # f8000010 -8000015c: f1402373 csrr t1,mhartid -80000160: 01031313 slli t1,t1,0x10 -80000164: 006282b3 add t0,t0,t1 -80000168: 00a2a023 sw a0,0(t0) - -8000016c : -8000016c: f14022f3 csrr t0,mhartid -80000170: 00029863 bnez t0,80000180 +80000174 : 80000174: 00000297 auipc t0,0x0 -80000178: 0602ac23 sw zero,120(t0) # 800001ec -8000017c: 00008067 ret +80000178: 0802a283 lw t0,128(t0) # 800001f4 +8000017c: ffd28ce3 beq t0,t4,80000174 +80000180: f80002b7 lui t0,0xf8000 +80000184: 01028293 addi t0,t0,16 # f8000010 +80000188: f1402373 csrr t1,mhartid +8000018c: 01031313 slli t1,t1,0x10 +80000190: 006282b3 add t0,t0,t1 +80000194: 00a2a023 sw a0,0(t0) +80000198: 00008067 ret -80000180 : -80000180: 00000297 auipc t0,0x0 -80000184: 06c2a283 lw t0,108(t0) # 800001ec -80000188: fe029ce3 bnez t0,80000180 -8000018c: 00008067 ret +8000019c : +8000019c: 00000413 li s0,0 +800001a0: f80002b7 lui t0,0xf8000 +800001a4: 00828293 addi t0,t0,8 # f8000008 +800001a8: f1402373 csrr t1,mhartid +800001ac: 01031313 slli t1,t1,0x10 +800001b0: 006282b3 add t0,t0,t1 +800001b4: 0082a023 sw s0,0(t0) +800001b8: 0240006f j 800001dc -80000190 : -80000190: 00000413 li s0,0 -80000194: f80002b7 lui t0,0xf8000 -80000198: 00828293 addi t0,t0,8 # f8000008 -8000019c: f1402373 csrr t1,mhartid -800001a0: 01031313 slli t1,t1,0x10 -800001a4: 006282b3 add t0,t0,t1 -800001a8: 0082a023 sw s0,0(t0) -800001ac: 0240006f j 800001d0 +800001bc : +800001bc: 00100413 li s0,1 +800001c0: f80002b7 lui t0,0xf8000 +800001c4: 00828293 addi t0,t0,8 # f8000008 +800001c8: f1402373 csrr t1,mhartid +800001cc: 01031313 slli t1,t1,0x10 +800001d0: 006282b3 add t0,t0,t1 +800001d4: 0082a023 sw s0,0(t0) +800001d8: 0040006f j 800001dc -800001b0 : -800001b0: 00100413 li s0,1 -800001b4: f80002b7 lui t0,0xf8000 -800001b8: 00828293 addi t0,t0,8 # f8000008 -800001bc: f1402373 csrr t1,mhartid -800001c0: 01031313 slli t1,t1,0x10 -800001c4: 006282b3 add t0,t0,t1 -800001c8: 0082a023 sw s0,0(t0) -800001cc: 0040006f j 800001d0 +800001dc : +800001dc: 0000006f j 800001dc -800001d0 : -800001d0: 0000006f j 800001d0 +800001e0 : +800001e0: fff50513 addi a0,a0,-1 +800001e4: fe051ee3 bnez a0,800001e0 +800001e8: 00008067 ret -800001d4 : -800001d4: fff50513 addi a0,a0,-1 -800001d8: fe051ee3 bnez a0,800001d4 -800001dc: 00008067 ret - -800001e0 : -800001e0: 0000 unimp - ... - -800001e4 : -800001e4: 0000 unimp - ... - -800001e8 : -800001e8: 0000 unimp - ... - -800001ec : +800001ec : 800001ec: 0000 unimp ... + +800001f0 : +800001f0: 0000 unimp + ... + +800001f4 : +800001f4: 0000 unimp + ... diff --git a/src/test/cpp/raw/smp/build/smp.bin b/src/test/cpp/raw/smp/build/smp.bin index 85f5095b37a3b0e5edf4e19cc9b07e93bfd0ea2b..9eaea4019f4f0b20fe25f3cedf802e0ed45ec5d7 100755 GIT binary patch literal 504 zcmah`J5Iwu6ddn*B?qEt;T1uAA|zY1;Rsfg10Zn$WD3e42~k82w4|V* zjdB1AuHXY$DUhff-o_NfMc8I`_U)UQw>u2N#k;`w&<__x(s?rx{ILNkjZ^`nTXobO zzo6{`GUy+Yikk&y`ziC}xqpy9+?2L|WO`WFxL;`$fJ^Ea1!76+lo5;}W4J}?jB(Z= zbzwQ}RrUUuSOIoBRI#{V4;1p&JV0h2q z0HhOu^Z^cG)&d~Szz9?g;%p@Sp rEX<(4I7#BM6!Slbk%u{vj8s4|at#w3!pK8xAR{NwU`zmdhk*eA_L4z& diff --git a/src/test/cpp/raw/smp/src/crt.S b/src/test/cpp/raw/smp/src/crt.S index 27b0717d..eb197d6c 100644 --- a/src/test/cpp/raw/smp/src/crt.S +++ b/src/test/cpp/raw/smp/src/crt.S @@ -58,49 +58,44 @@ barrier_amo_test: - +#define ENTRY_PHASE t4 barrier_amo: report(a0, REPORT_BARRIER_START) - la t0, barrier_amo_value + lw ENTRY_PHASE, barrier_phase + la t0, barrier_value li t1, 1 - amoadd.w x0, t1, (t0) + amoadd.w t0, t1, (t0) + addi t0, t0, 1 lw t1, thread_count + bne t0, t1, barrier_amo_wait + addi t0,ENTRY_PHASE,1 + sw x0, barrier_value, t1 + sw t0, barrier_phase, t1 barrier_amo_wait: - lw t2, (t0) - bne t2, t1, barrier_amo_wait + lw t0, barrier_phase + beq t0, ENTRY_PHASE, barrier_amo_wait report(a0, REPORT_BARRIER_END) -barrier_amo_reset: - csrr t0, mhartid - bnez t0, barrier_amo_reset_wait - sw x0, barrier_amo_value, t0 ret -barrier_amo_reset_wait: - lw t0, barrier_amo_value - bnez t0, barrier_amo_reset_wait - ret - + barrier_lrsc: - report(a0, REPORT_BARRIER_START) - la t0, barrier_lrsc_value + report(a0, REPORT_BARRIER_START) + lw ENTRY_PHASE, barrier_phase + la t0, barrier_value barrier_lrsc_try: - lr.w t1, (t0) - addi t1, t1, 1 - sc.w t1, t1, (t0) - bnez t1, barrier_lrsc_try - lw t1, thread_count + lr.w t1, (t0) + addi t1, t1, 1 + sc.w t2, t1, (t0) + bnez t2, barrier_lrsc_try + lw t0, thread_count + bne t0, t1, barrier_lrsc_wait + addi t0,ENTRY_PHASE,1 + sw x0, barrier_value, t1 + sw t0, barrier_phase, t1 barrier_lrsc_wait: - lw t2, (t0) - bne t2, t1, barrier_lrsc_wait - report(a0, REPORT_BARRIER_END) -barrier_lrsc_reset: - csrr t0, mhartid - bnez t0, barrier_lrsc_reset_wait - sw x0, barrier_lrsc_value, t0 - ret -barrier_lrsc_reset_wait: - lw t0, barrier_lrsc_value - bnez t0, barrier_lrsc_reset_wait - ret + lw t0, barrier_phase + beq t0, ENTRY_PHASE, barrier_lrsc_wait + report(a0, REPORT_BARRIER_END) + ret @@ -125,6 +120,5 @@ sleep: thread_count: .word 0 -shared_memory_1: .word 0 -barrier_amo_value: .word 0 -barrier_lrsc_value: .word 0 +barrier_value: .word 0 +barrier_phase: .word 0 From ebe070f9ddb4943b8cbb13f3a4e746e4ed586e96 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 17 Apr 2020 19:58:54 +0200 Subject: [PATCH 385/951] Update README.md --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index bb37f034..87130251 100644 --- a/README.md +++ b/README.md @@ -417,10 +417,10 @@ A prebuild GCC toolsuite can be found here: The VexRiscvSocSoftware makefiles are expecting to find this prebuild version in /opt/riscv/__contentOfThisPreBuild__ ```sh -wget https://static.dev.sifive.com/dev-tools/riscv64-unknown-elf-gcc-20171231-x86_64-linux-centos6.tar.gz -tar -xzvf riscv64-unknown-elf-gcc-20171231-x86_64-linux-centos6.tar.gz -sudo mv riscv64-unknown-elf-gcc-20171231-x86_64-linux-centos6 /opt/riscv64-unknown-elf-gcc-20171231-x86_64-linux-centos6 -sudo mv /opt/riscv64-unknown-elf-gcc-20171231-x86_64-linux-centos6 /opt/riscv +version=riscv64-unknown-elf-gcc-8.3.0-2019.08.0-x86_64-linux-ubuntu14 +wget -O riscv64-unknown-elf-gcc.tar.gz riscv https://static.dev.sifive.com/dev-tools/$version.tar.gz +tar -xzvf riscv64-unknown-elf-gcc.tar.gz +sudo mv $version /opt/riscv echo 'export PATH=/opt/riscv/bin:$PATH' >> ~/.bashrc ``` From 8c0e534c6b20efdd01645d493380545b9d7497eb Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sat, 18 Apr 2020 00:51:47 +0200 Subject: [PATCH 386/951] Add openSBI test, seem to work fine --- src/main/scala/vexriscv/Riscv.scala | 2 + .../demo/smp/VexRiscvSmpCluster.scala | 189 +++++++++++++----- src/test/cpp/raw/smp/build/smp.asm | 2 +- src/test/cpp/raw/smp/build/smp.bin | Bin 504 -> 504 bytes src/test/cpp/raw/smp/src/crt.S | 2 +- 5 files changed, 144 insertions(+), 51 deletions(-) diff --git a/src/main/scala/vexriscv/Riscv.scala b/src/main/scala/vexriscv/Riscv.scala index 91cf876b..90a40c5c 100644 --- a/src/main/scala/vexriscv/Riscv.scala +++ b/src/main/scala/vexriscv/Riscv.scala @@ -4,6 +4,8 @@ import spinal.core._ object Riscv{ + def misaToInt(values : String) = values.toLowerCase.map(e => 1 << (e-'a')).reduce(_ | _) + def funct7Range = 31 downto 25 def rdRange = 11 downto 7 def funct3Range = 14 downto 12 diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index fff9b033..f92321c8 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -1,14 +1,17 @@ package vexriscv.demo.smp +import spinal.core import spinal.core._ +import spinal.core.sim.{onSimEnd, simSuccess} import spinal.lib._ import spinal.lib.bus.bmb.sim.BmbMemoryAgent import spinal.lib.bus.bmb.{Bmb, BmbArbiter, BmbDecoder, BmbExclusiveMonitor, BmbInvalidateMonitor, BmbParameter} import spinal.lib.com.jtag.Jtag import spinal.lib.com.jtag.sim.JtagTcp +import vexriscv.demo.smp.VexRiscvSmpClusterTest.{cpuCount, withStall} import vexriscv.ip.{DataCacheAck, DataCacheConfig, DataCacheMemBus, InstructionCacheConfig} import vexriscv.plugin.{BranchPlugin, CsrPlugin, CsrPluginConfig, DBusCachedPlugin, DBusSimplePlugin, DebugPlugin, DecoderSimplePlugin, FullBarrelShifterPlugin, HazardSimplePlugin, IBusCachedPlugin, IBusSimplePlugin, IntAluPlugin, MmuPlugin, MmuPortConfig, MulDivIterativePlugin, MulPlugin, RegFilePlugin, STATIC, SrcPlugin, YamlPlugin} -import vexriscv.{VexRiscv, VexRiscvConfig, plugin} +import vexriscv.{Riscv, VexRiscv, VexRiscvConfig, plugin} import scala.collection.mutable import scala.collection.mutable.ArrayBuffer @@ -34,6 +37,7 @@ case class VexRiscvSmpCluster(p : VexRiscvSmpClusterParameter, val iMems = Vec(master(Bmb(iMemParameter)), p.cpuConfigs.size) val timerInterrupts = in Bits(p.cpuConfigs.size bits) val externalInterrupts = in Bits(p.cpuConfigs.size bits) + val softwareInterrupts = in Bits(p.cpuConfigs.size bits) val externalSupervisorInterrupts = in Bits(p.cpuConfigs.size bits) val jtag = slave(Jtag()) val debugReset = out Bool() @@ -53,6 +57,7 @@ case class VexRiscvSmpCluster(p : VexRiscvSmpClusterParameter, case plugin: IBusCachedPlugin => iBus = plugin.iBus.toBmb() case plugin: DBusCachedPlugin => dBus = plugin.dBus.toBmb() case plugin: CsrPlugin => { + plugin.softwareInterrupt := io.softwareInterrupts(cpuId) plugin.externalInterrupt := io.externalInterrupts(cpuId) plugin.timerInterrupt := io.timerInterrupts(cpuId) if (plugin.config.supervisorGen) plugin.externalInterruptS := io.externalSupervisorInterrupts(cpuId) @@ -228,7 +233,7 @@ object VexRiscvSmpClusterGen { divUnrollFactor = 1 ), // new DivPlugin, - new CsrPlugin(CsrPluginConfig.all2(0x80000020l).copy(ebreakGen = false, mhartid = id)), + new CsrPlugin(CsrPluginConfig.all2(0x80000020l).copy(ebreakGen = false, mhartid = id, misaExtensionsInit = Riscv.misaToInt("imas"))), // new CsrPlugin(//CsrPluginConfig.all2(0x80000020l).copy(ebreakGen = true)/* // CsrPluginConfig( // catchIllegalAccess = false, @@ -279,59 +284,51 @@ object VexRiscvSmpClusterGen { } -object SmpTest{ + +object VexRiscvSmpClusterTestInfrastructure{ val REPORT_OFFSET = 0xF8000000 val REPORT_THREAD_ID = 0x00 val REPORT_THREAD_COUNT = 0x04 val REPORT_END = 0x08 val REPORT_BARRIER_START = 0x0C val REPORT_BARRIER_END = 0x10 -} -object VexRiscvSmpClusterTest extends App{ - import spinal.core.sim._ - val simConfig = SimConfig - simConfig.withWave - simConfig.allOptimisation - simConfig.addSimulatorFlag("--threads 1") + val PUTC = 0x00 + val GETC = 0x04 + val CLINT_ADDR = 0x10000 + val CLINT_IPI_ADDR = CLINT_ADDR+0x0000 + val CLINT_CMP_ADDR = CLINT_ADDR+0x4000 + val CLINT_TIME_ADDR = CLINT_ADDR+0xBFF8 - val cpuCount = 4 - simConfig.compile(VexRiscvSmpClusterGen.vexRiscvCluster(cpuCount)).doSimUntilVoid(seed = 42){dut => - SimTimeout(10000*10*cpuCount) - dut.clockDomain.forkSimSpeedPrinter(1.0) - dut.clockDomain.forkStimulus(10) - dut.debugClockDomain.forkStimulus(10) - - - JtagTcp(dut.io.jtag, 100) - - val withStall = false - val cpuEnd = Array.fill(dut.p.cpuConfigs.size)(false) - val barriers = mutable.HashMap[Int, Int]() - - var reportWatchdog = 0 - periodicaly(10000*10){ - assert(reportWatchdog != 0) - reportWatchdog = 0 - } - - case class Report(hart : Int, code : Int, data : Int){ - override def toString: String = { - f"CPU:$hart%2d h${code}%3x -> $data%3d" - } - } - val reports = ArrayBuffer.fill(cpuCount)(ArrayBuffer[Report]()) - onSimEnd{ - for((list, hart) <- reports.zipWithIndex){ - println(f"\n\n**** CPU $hart%2d ****") - for((report, reportId) <- list.zipWithIndex){ - println(f" $reportId%3d : h${report.code}%3x -> ${report.data}%3d") + def ram(dut : VexRiscvSmpCluster) = { + import spinal.core.sim._ + val cpuCount = dut.cpus.size + val ram = new BmbMemoryAgent(0x100000000l){ + case class Report(hart : Int, code : Int, data : Int){ + override def toString: String = { + f"CPU:$hart%2d ${code}%3x -> $data%3d" + } + } + val reports = ArrayBuffer.fill(cpuCount)(ArrayBuffer[Report]()) + onSimEnd{ + for((list, hart) <- reports.zipWithIndex){ + println(f"\n\n**** CPU $hart%2d ****") + for((report, reportId) <- list.zipWithIndex){ + println(f" $reportId%3d : ${report.code}%3x -> ${report.data}%3d") + } } } - } - val ram = new BmbMemoryAgent(0x100000000l){ + val writeTable = mutable.HashMap[Int, Int => Unit]() + val readTable = mutable.HashMap[Int, () => Int]() + def onWrite(address : Int)(body : Int => Unit) = writeTable(address) = body + def onRead(address : Int)(body : => Int) = readTable(address) = () => body + var writeData = 0 + var readData = 0 + var reportWatchdog = 0 + val cpuEnd = Array.fill(cpuCount)(false) + val barriers = mutable.HashMap[Int, Int]() override def setByte(address: Long, value: Byte): Unit = { if((address & 0xF0000000l) != 0xF0000000l) return super.setByte(address, value) val byteId = address & 3 @@ -339,7 +336,7 @@ object VexRiscvSmpClusterTest extends App{ writeData = (writeData & ~mask) | ((value.toInt << (byteId*8)) & mask) if(byteId != 3) return val offset = (address & ~0xF0000000l)-3 -// println(s"W[0x${offset.toHexString}] = $writeData @${simTime()}") + // println(s"W[0x${offset.toHexString}] = $writeData @${simTime()}") offset match { case _ if offset >= 0x8000000 && offset < 0x9000000 => { val report = Report( @@ -351,7 +348,6 @@ object VexRiscvSmpClusterTest extends App{ reports(report.hart) += report reportWatchdog += 1 import report._ - import SmpTest._ code match { case REPORT_THREAD_ID => assert(data == hart) case REPORT_THREAD_COUNT => assert(data == cpuCount) @@ -367,13 +363,108 @@ object VexRiscvSmpClusterTest extends App{ } } } + case _ => writeTable.get(offset.toInt) match { + case Some(x) => x(writeData) + case _ => simFailure(f"\n\nWrite at ${address-3}%8x with $writeData%8x") + } } } - } - dut.io.iMems.foreach(ram.addPort(_,0,dut.clockDomain,true, withStall)) //Moarr powaaaaa -// ram.addPort(dut.io.iMem,0,dut.clockDomain,true, withStall) - ram.addPort(dut.io.dMem,0,dut.clockDomain,true, withStall) + override def getByte(address: Long): Byte = { + if((address & 0xF0000000l) != 0xF0000000l) return super.getByte(address) + val byteId = address & 3 + val offset = (address & ~0xF0000000l) + if(byteId == 0) readData = readTable.get(offset.toInt) match { + case Some(x) => x() + case _ => simFailure(f"\n\nRead at $address%8x") + } + (readData >> (byteId*8)).toByte + } + + val clint = new { + val cmp = Array.fill(cpuCount)(0l) + } + + onWrite(PUTC)(data => print(data.toChar)) +// onWrite(GETC)(data => System.in.read().toInt) + + onRead(CLINT_TIME_ADDR)(simTime().toInt) + onRead(CLINT_TIME_ADDR+4)((simTime() >> 32).toInt) + for(hartId <- 0 until cpuCount){ + onWrite(CLINT_IPI_ADDR + hartId*4) {data => + val mask = 1l << hartId + val value = (dut.io.softwareInterrupts.toLong & ~mask) | (if(data == 1) mask else 0) + dut.io.softwareInterrupts #= value + } + onRead(CLINT_CMP_ADDR + hartId*8)(clint.cmp(hartId).toInt) + onRead(CLINT_CMP_ADDR + hartId*8+4)((clint.cmp(hartId) >> 32).toInt) + onWrite(CLINT_CMP_ADDR + hartId*8)(data => clint.cmp(hartId) = (clint.cmp(hartId) & 0xFFFFFFFF00000000l) | data) + onWrite(CLINT_CMP_ADDR + hartId*8+4)(data => (clint.cmp(hartId) & 0x00000000FFFFFFFFl) | (data << 32)) + } + + var time = 0l + periodicaly(100){ + time += 10 + var timerInterrupts = 0l + for(i <- 0 until cpuCount){ + if(clint.cmp(i) < time) timerInterrupts |= 1l << i + } + dut.io.timerInterrupts #= timerInterrupts + } + + } + dut.io.iMems.foreach(ram.addPort(_,0,dut.clockDomain,true, withStall)) + ram.addPort(dut.io.dMem,0,dut.clockDomain,true, withStall) + ram + } + def init(dut : VexRiscvSmpCluster): Unit ={ + import spinal.core.sim._ + dut.clockDomain.forkSimSpeedPrinter(1.0) + dut.clockDomain.forkStimulus(10) + dut.debugClockDomain.forkStimulus(10) + JtagTcp(dut.io.jtag, 100) + } +} + +object VexRiscvSmpClusterTest extends App{ + import spinal.core.sim._ + + val simConfig = SimConfig +// simConfig.withWave + simConfig.allOptimisation + simConfig.addSimulatorFlag("--threads 1") + + val cpuCount = 4 + val withStall = true + + simConfig.compile(VexRiscvSmpClusterGen.vexRiscvCluster(cpuCount)).doSimUntilVoid(seed = 42){dut => + SimTimeout(10000*10*cpuCount) + VexRiscvSmpClusterTestInfrastructure.init(dut) + val ram = VexRiscvSmpClusterTestInfrastructure.ram(dut) ram.memory.loadBin(0x80000000l, "src/test/cpp/raw/smp/build/smp.bin") + periodicaly(20000*10){ + assert(ram.reportWatchdog != 0) + ram.reportWatchdog = 0 + } + } +} + + +object VexRiscvSmpClusterOpenSbi extends App{ + import spinal.core.sim._ + + val simConfig = SimConfig + simConfig.withWave + simConfig.allOptimisation + simConfig.addSimulatorFlag("--threads 1") + + val cpuCount = 4 + val withStall = false + + simConfig.compile(VexRiscvSmpClusterGen.vexRiscvCluster(cpuCount)).doSimUntilVoid(seed = 42){dut => + VexRiscvSmpClusterTestInfrastructure.init(dut) + val ram = VexRiscvSmpClusterTestInfrastructure.ram(dut) + ram.memory.loadBin(0x80000000l, "../opensbi/build/platform/spinal/vexriscv/sim/smp/firmware/fw_payload.bin") +// ram.memory.loadBin(0x80000000l, "../opensbi/build/platform/spinal/vexriscv/sim/smp/firmware/fw_jump.bin") } } \ No newline at end of file diff --git a/src/test/cpp/raw/smp/build/smp.asm b/src/test/cpp/raw/smp/build/smp.asm index db25d17d..06f26160 100644 --- a/src/test/cpp/raw/smp/build/smp.asm +++ b/src/test/cpp/raw/smp/build/smp.asm @@ -21,7 +21,7 @@ Disassembly of section .crt_section: 80000028 : 80000028: 00000417 auipc s0,0x0 8000002c: 1c442403 lw s0,452(s0) # 800001ec -80000030: 0c800513 li a0,200 +80000030: 19000513 li a0,400 80000034: 1ac000ef jal ra,800001e0 80000038: 00000497 auipc s1,0x0 8000003c: 1b44a483 lw s1,436(s1) # 800001ec diff --git a/src/test/cpp/raw/smp/build/smp.bin b/src/test/cpp/raw/smp/build/smp.bin index 9eaea4019f4f0b20fe25f3cedf802e0ed45ec5d7..59a832fee66759269250ede3b78662b6fdd2d1d3 100755 GIT binary patch delta 13 Ucmeyt{DXOd5fg*tMw26q03)LWegFUf delta 13 Ucmeyt{DXOd5mN)tMw26q048Dt@c;k- diff --git a/src/test/cpp/raw/smp/src/crt.S b/src/test/cpp/raw/smp/src/crt.S index eb197d6c..72cc5b8f 100644 --- a/src/test/cpp/raw/smp/src/crt.S +++ b/src/test/cpp/raw/smp/src/crt.S @@ -26,7 +26,7 @@ count_thread_start: count_thread_wait: //Wait everybody lw s0, thread_count - li a0, 200 + li a0, 400 call sleep lw s1, thread_count bne s1, s0, count_thread_wait From befecc7ed6a02ded6c9c34981737db4dd3c9fd0d Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sat, 18 Apr 2020 00:51:57 +0200 Subject: [PATCH 387/951] cleaning --- src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index f92321c8..ad1d3c37 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -419,7 +419,7 @@ object VexRiscvSmpClusterTestInfrastructure{ } def init(dut : VexRiscvSmpCluster): Unit ={ import spinal.core.sim._ - dut.clockDomain.forkSimSpeedPrinter(1.0) +// dut.clockDomain.forkSimSpeedPrinter(1.0) dut.clockDomain.forkStimulus(10) dut.debugClockDomain.forkStimulus(10) JtagTcp(dut.io.jtag, 100) From 4a49e6d91fc575c125485496c24f61c1c830aef4 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sat, 18 Apr 2020 01:26:31 +0200 Subject: [PATCH 388/951] initialize the clint in sim --- src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index ad1d3c37..e691ea27 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -388,6 +388,10 @@ object VexRiscvSmpClusterTestInfrastructure{ onWrite(PUTC)(data => print(data.toChar)) // onWrite(GETC)(data => System.in.read().toInt) + dut.io.softwareInterrupts #= 0 + dut.io.timerInterrupts #= 0 + dut.io.externalInterrupts #= 0 + dut.io.externalSupervisorInterrupts #= 0 onRead(CLINT_TIME_ADDR)(simTime().toInt) onRead(CLINT_TIME_ADDR+4)((simTime() >> 32).toInt) for(hartId <- 0 until cpuCount){ @@ -458,7 +462,7 @@ object VexRiscvSmpClusterOpenSbi extends App{ simConfig.allOptimisation simConfig.addSimulatorFlag("--threads 1") - val cpuCount = 4 + val cpuCount = 16 val withStall = false simConfig.compile(VexRiscvSmpClusterGen.vexRiscvCluster(cpuCount)).doSimUntilVoid(seed = 42){dut => From af128ec9eb25d3f4ba6011a082064ca1879bb60c Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sat, 18 Apr 2020 01:27:35 +0200 Subject: [PATCH 389/951] revert to 4 cpu --- src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index e691ea27..92de7aa3 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -462,7 +462,7 @@ object VexRiscvSmpClusterOpenSbi extends App{ simConfig.allOptimisation simConfig.addSimulatorFlag("--threads 1") - val cpuCount = 16 + val cpuCount = 4 val withStall = false simConfig.compile(VexRiscvSmpClusterGen.vexRiscvCluster(cpuCount)).doSimUntilVoid(seed = 42){dut => From ad2d2e411a5533f1b57e60dd075cd287f6b3245c Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sun, 19 Apr 2020 17:56:26 +0200 Subject: [PATCH 390/951] Add tap less debug plugin bridges --- .../scala/vexriscv/plugin/DebugPlugin.scala | 38 ++++++++++++++----- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/DebugPlugin.scala b/src/main/scala/vexriscv/plugin/DebugPlugin.scala index c04d167b..f38e3bf9 100644 --- a/src/main/scala/vexriscv/plugin/DebugPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DebugPlugin.scala @@ -1,7 +1,7 @@ package vexriscv.plugin -import spinal.lib.com.jtag.Jtag -import spinal.lib.system.debugger.{JtagBridge, SystemDebugger, SystemDebuggerConfig} +import spinal.lib.com.jtag.{Jtag, JtagTapInstructionCtrl} +import spinal.lib.system.debugger.{JtagBridge, JtagBridgeNoTap, SystemDebugger, SystemDebuggerConfig, SystemDebuggerMemBus} import vexriscv.plugin.IntAluPlugin.{ALU_CTRL, AluCtrlEnum} import vexriscv._ import vexriscv.ip._ @@ -63,6 +63,18 @@ case class DebugExtensionBus() extends Bundle with IMasterSlave{ bus } + def from(c : SystemDebuggerConfig) : SystemDebuggerMemBus = { + val mem = SystemDebuggerMemBus(c) + cmd.valid := mem.cmd.valid + cmd.wr := mem.cmd.wr + cmd.data := mem.cmd.data + cmd.address := mem.cmd.address.resized + mem.cmd.ready := cmd.ready + mem.rsp.valid := RegNext(cmd.fire).init(False) + mem.rsp.payload := rsp.data + mem + } + def fromJtag(): Jtag ={ val jtagConfig = SystemDebuggerConfig( memAddressWidth = 32, @@ -72,16 +84,24 @@ case class DebugExtensionBus() extends Bundle with IMasterSlave{ val jtagBridge = new JtagBridge(jtagConfig) val debugger = new SystemDebugger(jtagConfig) debugger.io.remote <> jtagBridge.io.remote - debugger.io.mem.cmd.valid <> cmd.valid - debugger.io.mem.cmd.ready <> cmd.ready - debugger.io.mem.cmd.wr <> cmd.wr - cmd.address := debugger.io.mem.cmd.address.resized - debugger.io.mem.cmd.data <> cmd.data - debugger.io.mem.rsp.valid <> RegNext(cmd.fire).init(False) - debugger.io.mem.rsp.payload <> rsp.data + debugger.io.mem <> this.from(jtagConfig) jtagBridge.io.jtag } + + def fromJtagInstructionCtrl(jtagClockDomain : ClockDomain): JtagTapInstructionCtrl ={ + val jtagConfig = SystemDebuggerConfig( + memAddressWidth = 32, + memDataWidth = 32, + remoteCmdWidth = 1 + ) + val jtagBridge = new JtagBridgeNoTap(jtagConfig, jtagClockDomain) + val debugger = new SystemDebugger(jtagConfig) + debugger.io.remote <> jtagBridge.io.remote + debugger.io.mem <> this.from(jtagConfig) + + jtagBridge.io.ctrl + } } case class DebugExtensionIo() extends Bundle with IMasterSlave{ From a1b6353d6bafb24364e969339ae3b15b12bc180a Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sun, 19 Apr 2020 19:48:57 +0200 Subject: [PATCH 391/951] workaround AMO LR/SC consistancy issue, but that need a proper fix --- src/main/scala/vexriscv/ip/DataCache.scala | 9 ++++++--- src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala | 9 ++++----- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index 80054407..d685a343 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -514,6 +514,7 @@ class DataCache(val p : DataCacheConfig) extends Component{ val counter = Reg(UInt(log2Up(pendingMax) + 1 bits)) init(0) counter := counter + U(io.mem.cmd.fire && io.mem.cmd.last) - U(io.mem.rsp.valid && io.mem.rsp.last) + val consistent = counter === 0 val full = RegNext(counter.msb) val last = counter === 1 @@ -533,6 +534,8 @@ class DataCache(val p : DataCacheConfig) extends Component{ val full = RegNext(counter.msb) io.cpu.execute.haltIt setWhen(full) + + val consistent = counter === 0 } @@ -546,9 +549,9 @@ class DataCache(val p : DataCacheConfig) extends Component{ val wayInvalidate = B(0, wayCount bits) //Used if invalidate enabled when(io.cpu.execute.fence){ - val counter = if(withInvalidate) sync.counter else if(withWriteResponse) pending.counter else null - if(counter != null){ - when(counter =/= 0 || io.cpu.memory.isValid || io.cpu.writeBack.isValid){ + val consistent = if(withInvalidate) sync.consistent else if(withWriteResponse) pending.consistent else null + if(consistent != null){ + when(!consistent || io.cpu.memory.isValid && io.cpu.memory.isWrite || io.cpu.writeBack.isValid && io.cpu.memory.isWrite){ io.cpu.execute.haltIt := True } } diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index abd6d523..769ed070 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -229,11 +229,10 @@ class DBusCachedPlugin(val config : DataCacheConfig, val ff = input(INSTRUCTION)(31 downto 20).as(FenceFlags()) if(withWriteResponse){ hazard setWhen(input(MEMORY_FENCE) && (ff.PS && ff.SL)) //Manage write to read hit ordering (ensure invalidation timings) -// Not required as LR SC AMO emited on the memory bus enforce the ordering, + it bypass the cache -// when(input(INSTRUCTION)(26 downto 25) =/= 0){ -// if(withLrSc) hazard setWhen(input(MEMORY_LRSC)) -// if(withAmo) hazard setWhen(input(MEMORY_AMO)) -// } + when(input(INSTRUCTION)(26 downto 25) =/= 0){ + if(withLrSc) hazard setWhen(input(MEMORY_LRSC)) + if(withAmo) hazard setWhen(input(MEMORY_AMO)) + } } insert(MEMORY_FENCE_DECODED) := hazard } From 8e8b64feaaf0d3c93aab6c61d33be08260c4c60c Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sun, 19 Apr 2020 19:49:26 +0200 Subject: [PATCH 392/951] Got full linux / buildroot to boot in 4 cpu config --- .../demo/smp/VexRiscvSmpCluster.scala | 73 ++++++++++++++----- 1 file changed, 55 insertions(+), 18 deletions(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index 92de7aa3..b490654b 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -383,17 +383,32 @@ object VexRiscvSmpClusterTestInfrastructure{ val clint = new { val cmp = Array.fill(cpuCount)(0l) + var time = 0l + periodicaly(100){ + time += 10 + var timerInterrupts = 0l + for(i <- 0 until cpuCount){ + if(cmp(i) < time) timerInterrupts |= 1l << i + } + dut.io.timerInterrupts #= timerInterrupts + } + +// delayed(200*1000000){ +// dut.io.softwareInterrupts #= 0xE +// enableSimWave() +// println("force IPI") +// } } onWrite(PUTC)(data => print(data.toChar)) -// onWrite(GETC)(data => System.in.read().toInt) + onRead(GETC)( if(System.in.available() != 0) System.in.read() else -1) dut.io.softwareInterrupts #= 0 dut.io.timerInterrupts #= 0 dut.io.externalInterrupts #= 0 dut.io.externalSupervisorInterrupts #= 0 - onRead(CLINT_TIME_ADDR)(simTime().toInt) - onRead(CLINT_TIME_ADDR+4)((simTime() >> 32).toInt) + onRead(CLINT_TIME_ADDR)(clint.time.toInt) + onRead(CLINT_TIME_ADDR+4)((clint.time >> 32).toInt) for(hartId <- 0 until cpuCount){ onWrite(CLINT_IPI_ADDR + hartId*4) {data => val mask = 1l << hartId @@ -402,19 +417,11 @@ object VexRiscvSmpClusterTestInfrastructure{ } onRead(CLINT_CMP_ADDR + hartId*8)(clint.cmp(hartId).toInt) onRead(CLINT_CMP_ADDR + hartId*8+4)((clint.cmp(hartId) >> 32).toInt) - onWrite(CLINT_CMP_ADDR + hartId*8)(data => clint.cmp(hartId) = (clint.cmp(hartId) & 0xFFFFFFFF00000000l) | data) - onWrite(CLINT_CMP_ADDR + hartId*8+4)(data => (clint.cmp(hartId) & 0x00000000FFFFFFFFl) | (data << 32)) + onWrite(CLINT_CMP_ADDR + hartId*8){data => clint.cmp(hartId) = (clint.cmp(hartId) & 0xFFFFFFFF00000000l) | data} + onWrite(CLINT_CMP_ADDR + hartId*8+4){data => clint.cmp(hartId) = (clint.cmp(hartId) & 0x00000000FFFFFFFFl) | (data.toLong << 32)} } - var time = 0l - periodicaly(100){ - time += 10 - var timerInterrupts = 0l - for(i <- 0 until cpuCount){ - if(clint.cmp(i) < time) timerInterrupts |= 1l << i - } - dut.io.timerInterrupts #= timerInterrupts - } + } dut.io.iMems.foreach(ram.addPort(_,0,dut.clockDomain,true, withStall)) @@ -423,7 +430,6 @@ object VexRiscvSmpClusterTestInfrastructure{ } def init(dut : VexRiscvSmpCluster): Unit ={ import spinal.core.sim._ -// dut.clockDomain.forkSimSpeedPrinter(1.0) dut.clockDomain.forkStimulus(10) dut.debugClockDomain.forkStimulus(10) JtagTcp(dut.io.jtag, 100) @@ -465,10 +471,41 @@ object VexRiscvSmpClusterOpenSbi extends App{ val cpuCount = 4 val withStall = false - simConfig.compile(VexRiscvSmpClusterGen.vexRiscvCluster(cpuCount)).doSimUntilVoid(seed = 42){dut => + simConfig.workspaceName("rawr_4c").compile(VexRiscvSmpClusterGen.vexRiscvCluster(cpuCount)).doSimUntilVoid(seed = 42){dut => +// dut.clockDomain.forkSimSpeedPrinter(1.0) VexRiscvSmpClusterTestInfrastructure.init(dut) val ram = VexRiscvSmpClusterTestInfrastructure.ram(dut) - ram.memory.loadBin(0x80000000l, "../opensbi/build/platform/spinal/vexriscv/sim/smp/firmware/fw_payload.bin") -// ram.memory.loadBin(0x80000000l, "../opensbi/build/platform/spinal/vexriscv/sim/smp/firmware/fw_jump.bin") +// ram.memory.loadBin(0x80000000l, "../opensbi/build/platform/spinal/vexriscv/sim/smp/firmware/fw_payload.bin") + ram.memory.loadBin(0x80000000l, "../opensbi/build/platform/spinal/vexriscv/sim/smp/firmware/fw_jump.bin") + ram.memory.loadBin(0xC0000000l, "../buildroot/output/images/Image") + ram.memory.loadBin(0xC1000000l, "../buildroot/output/images/dtb") + ram.memory.loadBin(0xC2000000l, "../buildroot/output/images/rootfs.cpio") + +// fork{ +// disableSimWave() +// val atMs = 130 +// val durationMs = 15 +// sleep(atMs*1000000) +// enableSimWave() +// println("** enableSimWave **") +// sleep(durationMs*1000000) +// println("** disableSimWave **") +// while(true) { +// disableSimWave() +// sleep(100000 * 10) +// enableSimWave() +// sleep( 100 * 10) +// } +//// simSuccess() +// } + + fork{ + while(true) { + disableSimWave() + sleep(100000 * 10) + enableSimWave() + sleep( 100 * 10) + } + } } } \ No newline at end of file From b383b4b98b026b018129b1ec7238e3b1d001ff5d Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 20 Apr 2020 12:13:12 +0200 Subject: [PATCH 393/951] Add commented usage of fromXilinxBscane2 --- src/main/scala/vexriscv/demo/VexRiscvAhbLite3.scala | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/demo/VexRiscvAhbLite3.scala b/src/main/scala/vexriscv/demo/VexRiscvAhbLite3.scala index 593d399d..fc3c3c22 100644 --- a/src/main/scala/vexriscv/demo/VexRiscvAhbLite3.scala +++ b/src/main/scala/vexriscv/demo/VexRiscvAhbLite3.scala @@ -4,7 +4,7 @@ package vexriscv.demo import spinal.core._ import spinal.lib._ import spinal.lib.bus.avalon.AvalonMM -import spinal.lib.com.jtag.Jtag +import spinal.lib.com.jtag.{Jtag, JtagTapInstructionCtrl} import spinal.lib.eda.altera.{InterruptReceiverTag, QSysify, ResetEmitterTag} import vexriscv.ip.{DataCacheConfig, InstructionCacheConfig} import vexriscv.plugin._ @@ -163,6 +163,11 @@ object VexRiscvAhbLite3{ plugin.io.bus.setAsDirectionLess() val jtag = slave(new Jtag()).setName("jtag") jtag <> plugin.io.bus.fromJtag() + +// // On Artix FPGA jtag : +// val jtagCtrl = JtagTapInstructionCtrl() +// val tap = jtagCtrl.fromXilinxBscane2(userId = 1) +// jtagCtrl <> plugin.io.bus.fromJtagInstructionCtrl(ClockDomain(tap.TCK)) } case _ => } From 0e55caacab2f6a49fb186b695b4c6b903f4c64bc Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 21 Apr 2020 10:33:51 +0200 Subject: [PATCH 394/951] deduplicae VexRiscv wishbone --- .../spinal/lib/bus/wishbone/Wishbone.scala | 241 ------------------ 1 file changed, 241 deletions(-) delete mode 100644 src/main/scala/spinal/lib/bus/wishbone/Wishbone.scala diff --git a/src/main/scala/spinal/lib/bus/wishbone/Wishbone.scala b/src/main/scala/spinal/lib/bus/wishbone/Wishbone.scala deleted file mode 100644 index 1f41faae..00000000 --- a/src/main/scala/spinal/lib/bus/wishbone/Wishbone.scala +++ /dev/null @@ -1,241 +0,0 @@ -package spinal.lib.bus.wishbone - -import spinal.core._ -import spinal.lib._ - -/** This class is used for configuring the Wishbone class - * @param addressWidth size in bits of the address line - * @param dataWidth size in bits of the data line - * @param selWidth size in bits of the selection line, deafult to 0 (disabled) - * @param useSTALL activate the stall line, default to false (disabled) - * @param useLOCK activate the lock line, default to false (disabled) - * @param useERR activate the error line, default to false (disabled) - * @param useRTY activate the retry line, default to false (disabled) - * @param tgaWidth size in bits of the tag address linie, deafult to 0 (disabled) - * @param tgcWidth size in bits of the tag cycle line, deafult to 0 (disabled) - * @param tgdWidth size in bits of the tag data line, deafult to 0 (disabled) - * @param useBTE activate the BTE line, deafult to 0 (disabled) - * @param useCTI activate the CTI line, deafult to 0 (disabled) - * @example {{{ - * val wishboneBusConf = new WishboneConfig(32,8).withCycleTag(8).withDataTag(8) - * val wishboneBus = new Wishbone(wishboneBusConf) - * }}} - * @todo test example - */ -case class WishboneConfig( - val addressWidth : Int, - val dataWidth : Int, - val selWidth : Int = 0, - val useSTALL : Boolean = false, - val useLOCK : Boolean = false, - val useERR : Boolean = false, - val useRTY : Boolean = false, - val tgaWidth : Int = 0, - val tgcWidth : Int = 0, - val tgdWidth : Int = 0, - val useBTE : Boolean = false, - val useCTI : Boolean = false - ){ - def useTGA = tgaWidth > 0 - def useTGC = tgcWidth > 0 - def useTGD = tgdWidth > 0 - def useSEL = selWidth > 0 - def isPipelined = useSTALL - def pipelined : WishboneConfig = this.copy(useSTALL = true) - def withDataTag(size : Int) : WishboneConfig = this.copy(tgdWidth = size) - def withAddressTag(size : Int) : WishboneConfig = this.copy(tgaWidth = size) - def withCycleTag(size : Int) : WishboneConfig = this.copy(tgdWidth = size) -} - -/** This class rappresent a Wishbone bus - * @param config an istance of WishboneConfig, it will be used to configurate the Wishbone Bus - */ -case class Wishbone(config: WishboneConfig) extends Bundle with IMasterSlave { - ///////////////////// - // MINIMAL SIGNALS // - ///////////////////// - val CYC = Bool - val STB = Bool - val ACK = Bool - val WE = Bool - val ADR = UInt(config.addressWidth bits) - val DAT_MISO = Bits(config.dataWidth bits) - val DAT_MOSI = Bits(config.dataWidth bits) - - /////////////////////////// - // OPTIONAL FLOW CONTROS // - /////////////////////////// - val SEL = if(config.useSEL) Bits(config.selWidth bits) else null - val STALL = if(config.useSTALL) Bool else null - val LOCK = if(config.useLOCK) Bool else null - val ERR = if(config.useERR) Bool else null - val RTY = if(config.useRTY) Bool else null - - ////////// - // TAGS // - ////////// - val TGD_MISO = if(config.useTGD) Bits(config.tgdWidth bits) else null - val TGD_MOSI = if(config.useTGD) Bits(config.tgdWidth bits) else null - val TGA = if(config.useTGA) Bits(config.tgaWidth bits) else null - val TGC = if(config.useTGC) Bits(config.tgcWidth bits) else null - val BTE = if(config.useBTE) Bits(2 bits) else null - val CTI = if(config.useCTI) Bits(3 bits) else null - - override def asMaster(): Unit = { - outWithNull(DAT_MOSI, TGD_MOSI, ADR, CYC, LOCK, SEL, STB, TGA, TGC, WE, CTI, BTE) - inWithNull(DAT_MISO, TGD_MISO, ACK, STALL, ERR, RTY) - } - - // def isCycle : Bool = if(config.useERR) !ERR && CYC else CYC - // def isWrite : Bool = isCycle && WE - // def isRead : Bool = isCycle && !WE - // def isReadCycle : Bool = isRead && STB - // def isWriteCycle : Bool = isWrite && STB - // def isStalled : Bool = if(config.isPipelined) isCycle && STALL else False - // def isAcknoledge : Bool = isCycle && ACK - // def isStrobe : Bool = isCycle && STB - - // def doSlaveWrite : Bool = this.CYC && this.STB && this.WE - // def doSlaveRead : Bool = this.CYC && this.STB && !this.WE - // def doSlavePipelinedWrite : Bool = this.CYC && this.WE - // def doSlavePipelinedRead : Bool = this.CYC && !this.WE - - /** Connect the istance of this bus with another, allowing for resize of data - * @param that the wishbone instance that will be connected and resized - * @param allowDataResize allow to resize "that" data lines, default to false (disable) - * @param allowAddressResize allow to resize "that" address lines, default to false (disable) - * @param allowTagResize allow to resize "that" tag lines, default to false (disable) - */ - def connectTo(that : Wishbone, allowDataResize : Boolean = false, allowAddressResize : Boolean = false, allowTagResize : Boolean = false) : Unit = { - this.CYC <> that.CYC - this.STB <> that.STB - this.WE <> that.WE - this.ACK <> that.ACK - - if(allowDataResize){ - this.DAT_MISO.resized <> that.DAT_MISO - this.DAT_MOSI <> that.DAT_MOSI.resized - } else { - this.DAT_MOSI <> that.DAT_MOSI - this.DAT_MISO <> that.DAT_MISO - } - - if(allowAddressResize){ - this.ADR <> that.ADR.resized - } else { - this.ADR <> that.ADR - } - - /////////////////////////// - // OPTIONAL FLOW CONTROS // - /////////////////////////// - if(this.config.useSTALL && that.config.useSTALL) this.STALL <> that.STALL - if(this.config.useERR && that.config.useERR) this.ERR <> that.ERR - if(this.config.useRTY && that.config.useRTY) this.RTY <> that.RTY - if(this.config.useSEL && that.config.useSEL) this.SEL <> that.SEL - if(this.config.useCTI && that.config.useCTI) this.CTI <> that.CTI - - ////////// - // TAGS // - ////////// - if(this.config.useTGA && that.config.useTGA) - if(allowTagResize) this.TGA <> that.TGA.resized else this.TGA <> that.TGA - - if(this.config.useTGC && that.config.useTGC) - if(allowTagResize) this.TGC <> that.TGC.resized else this.TGC <> that.TGC - - if(this.config.useBTE && that.config.useBTE) - if(allowTagResize) this.BTE <> that.BTE.resized else this.BTE <> that.BTE - - if(this.config.useTGD && that.config.useTGD){ - if(allowTagResize){ - this.TGD_MISO <> that.TGD_MISO.resized - this.TGD_MOSI <> that.TGD_MOSI.resized - } else { - this.TGD_MISO <> that.TGD_MISO - this.TGD_MOSI <> that.TGD_MOSI - } - } - } - - /** Connect common Wishbone signals - * @example{{{wishbone1 <-> wishbone2}}} - */ - def <-> (sink : Wishbone) : Unit = { - ///////////////////// - // MINIMAL SIGNALS // - ///////////////////// - sink.CYC <> this.CYC - sink.ADR <> this.ADR - sink.DAT_MOSI <> this.DAT_MOSI - sink.DAT_MISO <> this.DAT_MISO - sink.STB <> this.STB - sink.WE <> this.WE - sink.ACK <> this.ACK - - /////////////////////////// - // OPTIONAL FLOW CONTROS // - /////////////////////////// - if(this.config.useSTALL && sink.config.useSTALL) sink.STALL <> this.STALL - if(this.config.useERR && sink.config.useERR) sink.ERR <> this.ERR - if(this.config.useRTY && sink.config.useRTY) sink.RTY <> this.RTY - if(this.config.useSEL && sink.config.useSEL) sink.SEL <> this.SEL - - ////////// - // TAGS // - ////////// - if(this.config.useTGA && sink.config.useTGA) sink.TGA <> this.TGA - if(this.config.useTGC && sink.config.useTGC) sink.TGC <> this.TGC - if(this.config.useCTI && sink.config.useCTI) sink.CTI <> this.CTI - if(this.config.useBTE && sink.config.useBTE) sink.BTE <> this.BTE - if(this.config.useTGD && sink.config.useTGD){ - sink.TGD_MISO <> this.TGD_MISO - sink.TGD_MOSI <> this.TGD_MOSI - } - } - - /** Clear all the relevant signals in the wishbone bus - * @example{{{ - * val wishbone1 = master(Wishbone(WishboneConfig(8,8))) - * val wishbone2 = slave(Wishbone(WishboneConfig(8,8))) - * val wishbone2 = slave(Wishbone(WishboneConfig(8,8).withDataTag(8))) - * - * // this will clear only the following signals: CYC,ADR,DAT_MOSI,STB,WE - * wishbone1.clearAll() - * // this will clear only the following signals: DAT_MISO,ACK - * wishbone2.clearAll() - * // this will clear only the following signals: DAT_MISO,ACK,TGD_MISO - * wishbone3.clearAll() - * }}} - */ - def clearAll() : Unit = { - ///////////////////// - // MINIMAl SIGLALS // - ///////////////////// - if( isMasterInterface) this.CYC.clear() - if( isMasterInterface) this.ADR.clearAll() - if( isMasterInterface) this.DAT_MOSI.clearAll() - if(!isMasterInterface) this.DAT_MISO.clearAll() - if( isMasterInterface) this.STB.clear() - if( isMasterInterface) this.WE.clear() - if(!isMasterInterface) this.ACK.clear() - - /////////////////////////// - // OPTIONAL FLOW CONTROS // - /////////////////////////// - if(this.config.useSTALL && !isMasterInterface) this.STALL.clear() - if(this.config.useERR && !isMasterInterface) this.ERR.clear() - if(this.config.useRTY && !isMasterInterface) this.RTY.clear() - if(this.config.useSEL && isMasterInterface) this.SEL.clearAll() - - ////////// - // TAGS // - ////////// - if(this.config.useTGA && isMasterInterface) this.TGA.clearAll() - if(this.config.useTGC && isMasterInterface) this.TGC.clearAll() - if(this.config.useCTI && isMasterInterface) this.CTI.clearAll() - if(this.config.useBTE && isMasterInterface) this.BTE.clearAll() - if(this.config.useTGD && !isMasterInterface) this.TGD_MISO.clearAll() - if(this.config.useTGD && isMasterInterface) this.TGD_MOSI.clearAll() - } -} From b389878d2323002d6619981a5a82cc4581cf2715 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 21 Apr 2020 12:18:10 +0200 Subject: [PATCH 395/951] Add smp consistency check, fix VexRiscv invalidation read during write hazard logic --- .../demo/smp/VexRiscvSmpCluster.scala | 51 ++- src/main/scala/vexriscv/ip/DataCache.scala | 46 +- .../vexriscv/plugin/DBusCachedPlugin.scala | 27 +- src/test/cpp/raw/smp/build/smp.asm | 409 +++++++++++++----- src/test/cpp/raw/smp/build/smp.bin | Bin 504 -> 1144 bytes src/test/cpp/raw/smp/src/crt.S | 145 ++++++- 6 files changed, 517 insertions(+), 161 deletions(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index b490654b..0371b29c 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -292,6 +292,7 @@ object VexRiscvSmpClusterTestInfrastructure{ val REPORT_END = 0x08 val REPORT_BARRIER_START = 0x0C val REPORT_BARRIER_END = 0x10 + val REPORT_CONSISTENCY_VALUES = 0x14 val PUTC = 0x00 val GETC = 0x04 @@ -310,14 +311,7 @@ object VexRiscvSmpClusterTestInfrastructure{ } } val reports = ArrayBuffer.fill(cpuCount)(ArrayBuffer[Report]()) - onSimEnd{ - for((list, hart) <- reports.zipWithIndex){ - println(f"\n\n**** CPU $hart%2d ****") - for((report, reportId) <- list.zipWithIndex){ - println(f" $reportId%3d : ${report.code}%3x -> ${report.data}%3d") - } - } - } + val writeTable = mutable.HashMap[Int, Int => Unit]() val readTable = mutable.HashMap[Int, () => Int]() @@ -329,6 +323,24 @@ object VexRiscvSmpClusterTestInfrastructure{ var reportWatchdog = 0 val cpuEnd = Array.fill(cpuCount)(false) val barriers = mutable.HashMap[Int, Int]() + var consistancyCounter = 0 + var consistancyLast = 0 + var consistancyA = 0 + var consistancyB = 0 + var consistancyAB = 0 + var consistancyNone = 0 + + onSimEnd{ + for((list, hart) <- reports.zipWithIndex){ + println(f"\n\n**** CPU $hart%2d ****") + for((report, reportId) <- list.zipWithIndex){ + println(f" $reportId%3d : ${report.code}%3x -> ${report.data}%3d") + } + } + + println(s"consistancy NONE:$consistancyNone A:$consistancyA B:$consistancyB AB:$consistancyAB") + } + override def setByte(address: Long, value: Byte): Unit = { if((address & 0xF0000000l) != 0xF0000000l) return super.setByte(address, value) val byteId = address & 3 @@ -344,7 +356,7 @@ object VexRiscvSmpClusterTestInfrastructure{ code = (offset & 0x00FFFF).toInt, data = writeData ) - println(report) +// println(report) reports(report.hart) += report reportWatchdog += 1 import report._ @@ -361,6 +373,21 @@ object VexRiscvSmpClusterTestInfrastructure{ val counter = barriers.getOrElse(data, 0) assert(counter == cpuCount) } + case REPORT_CONSISTENCY_VALUES => consistancyCounter match { + case 0 => { + consistancyCounter = 1 + consistancyLast = data + } + case 1 => { + consistancyCounter = 0 + (data, consistancyLast) match { + case (666, 0) => consistancyA += 1 + case (0, 666) => consistancyB += 1 + case (666, 666) => consistancyAB += 1 + case (0,0) => consistancyNone += 1; simFailure("Consistancy issue :(") + } + } + } } } case _ => writeTable.get(offset.toInt) match { @@ -440,7 +467,7 @@ object VexRiscvSmpClusterTest extends App{ import spinal.core.sim._ val simConfig = SimConfig -// simConfig.withWave + simConfig.withWave simConfig.allOptimisation simConfig.addSimulatorFlag("--threads 1") @@ -448,7 +475,9 @@ object VexRiscvSmpClusterTest extends App{ val withStall = true simConfig.compile(VexRiscvSmpClusterGen.vexRiscvCluster(cpuCount)).doSimUntilVoid(seed = 42){dut => - SimTimeout(10000*10*cpuCount) + disableSimWave() + SimTimeout(100000000l*10*cpuCount) + dut.clockDomain.forkSimSpeedPrinter(1.0) VexRiscvSmpClusterTestInfrastructure.init(dut) val ram = VexRiscvSmpClusterTestInfrastructure.ram(dut) ram.memory.loadBin(0x80000000l, "src/test/cpp/raw/smp/build/smp.bin") diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index d685a343..34641659 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -102,10 +102,10 @@ case class DataCacheCpuExecute(p : DataCacheConfig) extends Bundle with IMasterS val address = UInt(p.addressWidth bit) val haltIt = Bool val args = DataCacheCpuExecuteArgs(p) - val fence = Bool() + val totalyConsistent = Bool() override def asMaster(): Unit = { - out(isValid, args, address, fence) + out(isValid, args, address, totalyConsistent) in(haltIt) } } @@ -129,9 +129,10 @@ case class DataCacheCpuMemory(p : DataCacheConfig) extends Bundle with IMasterSl val isWrite = Bool val address = UInt(p.addressWidth bit) val mmuBus = MemoryTranslatorBus() + val fenceValid = Bool() override def asMaster(): Unit = { - out(isValid, isStuck, isRemoved, address) + out(isValid, isStuck, isRemoved, address, fenceValid) in(isWrite) slave(mmuBus) } @@ -148,11 +149,13 @@ case class DataCacheCpuWriteBack(p : DataCacheConfig) extends Bundle with IMaste val address = UInt(p.addressWidth bit) val mmuException, unalignedAccess, accessError = Bool() val keepMemRspData = Bool() //Used by external AMO to avoid having an internal buffer + val fenceValid = Bool() + val fenceFire = Bool() // val exceptionBus = if(p.catchSomething) Flow(ExceptionCause()) else null override def asMaster(): Unit = { - out(isValid,isStuck,isUser, address) + out(isValid,isStuck,isUser, address, fenceValid, fenceFire) in(haltIt, data, mmuException, unalignedAccess, accessError, isWrite, keepMemRspData) } } @@ -514,7 +517,7 @@ class DataCache(val p : DataCacheConfig) extends Component{ val counter = Reg(UInt(log2Up(pendingMax) + 1 bits)) init(0) counter := counter + U(io.mem.cmd.fire && io.mem.cmd.last) - U(io.mem.rsp.valid && io.mem.rsp.last) - val consistent = counter === 0 + val done = counter === 0 val full = RegNext(counter.msb) val last = counter === 1 @@ -529,16 +532,26 @@ class DataCache(val p : DataCacheConfig) extends Component{ val sync = withInvalidate generate new Area{ io.mem.sync.ready := True - val counter = Reg(UInt(log2Up(pendingMax) + 1 bits)) init(0) - counter := counter + U(io.mem.cmd.fire && io.mem.cmd.wr) - U(io.mem.sync.fire) + val pendingSync = Reg(UInt(log2Up(pendingMax) + 1 bits)) init(0) + val pendingSyncNext = pendingSync + U(io.mem.cmd.fire && io.mem.cmd.wr) - U(io.mem.sync.fire) + pendingSync := pendingSyncNext - val full = RegNext(counter.msb) + val full = RegNext(pendingSync.msb) io.cpu.execute.haltIt setWhen(full) - val consistent = counter === 0 + + val incoerentSync = Reg(UInt(log2Up(pendingMax) + 1 bits)) init(0) + incoerentSync := incoerentSync - U(io.mem.sync.fire && incoerentSync =/= 0) + when(io.cpu.writeBack.fenceValid){ incoerentSync := pendingSyncNext } + + + val totalyConsistent = pendingSync === 0 + val fenceConsistent = incoerentSync === 0 } + + val stage0 = new Area{ val mask = io.cpu.execute.size.mux ( U(0) -> B"0001", @@ -548,10 +561,14 @@ class DataCache(val p : DataCacheConfig) extends Component{ val dataColisions = collisionProcess(io.cpu.execute.address(lineRange.high downto wordRange.low), mask) val wayInvalidate = B(0, wayCount bits) //Used if invalidate enabled - when(io.cpu.execute.fence){ - val consistent = if(withInvalidate) sync.consistent else if(withWriteResponse) pending.consistent else null - if(consistent != null){ - when(!consistent || io.cpu.memory.isValid && io.cpu.memory.isWrite || io.cpu.writeBack.isValid && io.cpu.memory.isWrite){ + val isAmo = if(withAmo) io.cpu.execute.isAmo else False + + //Ensure write to read consistency + val consistancyCheck = (withInvalidate || withWriteResponse) generate new Area { + val fenceConsistent = (if(withInvalidate) sync.fenceConsistent else pending.done) && !io.cpu.writeBack.fenceValid && !io.cpu.memory.fenceValid //Pessimistic fence tracking + val totalyConsistent = (if(withInvalidate) sync.totalyConsistent else pending.done) && !(io.cpu.memory.isValid && io.cpu.memory.isWrite) && !(io.cpu.writeBack.isValid && io.cpu.memory.isWrite) + when(io.cpu.execute.isValid && (!io.cpu.execute.args.wr || isAmo)){ + when(!fenceConsistent || io.cpu.execute.totalyConsistent && !totalyConsistent){ io.cpu.execute.haltIt := True } } @@ -632,7 +649,6 @@ class DataCache(val p : DataCacheConfig) extends Component{ } } - val lrSc = withInternalLrSc generate new Area{ val reserved = RegInit(False) when(io.cpu.writeBack.isValid && !io.cpu.writeBack.isStuck && request.isLrsc @@ -923,7 +939,7 @@ class DataCache(val p : DataCacheConfig) extends Component{ io.mem.ack.hit := wayHit //Manage invalidation read during write hazard - s1.invalidations := RegNext((input.valid && input.enable) ? wayHits | 0) + s1.invalidations := RegNextWhen((input.valid && input.enable && input.address(lineRange) === s0.input.address(lineRange)) ? wayHits | 0, s0.input.ready) } } } \ No newline at end of file diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index 769ed070..82c7953d 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -50,7 +50,8 @@ class DBusCachedPlugin(val config : DataCacheConfig, object MEMORY_LRSC extends Stageable(Bool) object MEMORY_AMO extends Stageable(Bool) object MEMORY_FENCE extends Stageable(Bool) - object MEMORY_FENCE_DECODED extends Stageable(Bool) + object MEMORY_FENCE_FRONT extends Stageable(Bool) + object MEMORY_FENCE_BACK extends Stageable(Bool) object IS_DBUS_SHARING extends Stageable(Bool()) object MEMORY_VIRTUAL_ADDRESS extends Stageable(UInt(32 bits)) @@ -224,17 +225,22 @@ class DBusCachedPlugin(val config : DataCacheConfig, def PS = PW || PO } + //Manage write to read hit ordering (ensure invalidation timings) val fence = new Area{ - val hazard = False + insert(MEMORY_FENCE_FRONT) := False + insert(MEMORY_FENCE_BACK) := False val ff = input(INSTRUCTION)(31 downto 20).as(FenceFlags()) if(withWriteResponse){ - hazard setWhen(input(MEMORY_FENCE) && (ff.PS && ff.SL)) //Manage write to read hit ordering (ensure invalidation timings) - when(input(INSTRUCTION)(26 downto 25) =/= 0){ - if(withLrSc) hazard setWhen(input(MEMORY_LRSC)) - if(withAmo) hazard setWhen(input(MEMORY_AMO)) + insert(MEMORY_FENCE_BACK) setWhen(input(MEMORY_FENCE) && (ff.PS && ff.SL)) + when(input(INSTRUCTION)(26)) { //AQ + if(withLrSc) insert(MEMORY_FENCE_BACK) setWhen(input(MEMORY_LRSC)) + if(withAmo) insert(MEMORY_FENCE_BACK) setWhen(input(MEMORY_AMO)) + } + when(input(INSTRUCTION)(25)) { //RL but a bit pessimistic as could be MEMORY_FENCE_BACK when the memory op isn't a read + if(withLrSc) insert(MEMORY_FENCE_FRONT) setWhen(input(MEMORY_LRSC)) + if(withAmo) insert(MEMORY_FENCE_FRONT) setWhen(input(MEMORY_AMO)) } } - insert(MEMORY_FENCE_DECODED) := hazard } } @@ -254,7 +260,7 @@ class DBusCachedPlugin(val config : DataCacheConfig, cache.io.cpu.flush.valid := arbitration.isValid && input(MEMORY_MANAGMENT) - cache.io.cpu.execute.fence := arbitration.isValid && input(MEMORY_FENCE_DECODED) + cache.io.cpu.execute.totalyConsistent := arbitration.isValid && input(MEMORY_FENCE_FRONT) arbitration.haltItself setWhen(cache.io.cpu.flush.isStall || cache.io.cpu.execute.haltIt) if(withLrSc) { @@ -296,6 +302,8 @@ class DBusCachedPlugin(val config : DataCacheConfig, cache.io.cpu.memory.mmuBus <> mmuBus cache.io.cpu.memory.mmuBus.rsp.isIoAccess setWhen(pipeline(DEBUG_BYPASS_CACHE) && !cache.io.cpu.memory.isWrite) + + cache.io.cpu.memory.fenceValid := arbitration.isValid && input(MEMORY_FENCE_BACK) } val managementStage = stages.last @@ -306,6 +314,9 @@ class DBusCachedPlugin(val config : DataCacheConfig, cache.io.cpu.writeBack.isUser := (if(privilegeService != null) privilegeService.isUser() else False) cache.io.cpu.writeBack.address := U(input(REGFILE_WRITE_DATA)) + cache.io.cpu.writeBack.fenceValid := arbitration.isValid && input(MEMORY_FENCE_BACK) + cache.io.cpu.writeBack.fenceFire := arbitration.isFiring && input(MEMORY_FENCE_BACK) + redoBranch.valid := False redoBranch.payload := input(PC) arbitration.flushIt setWhen(redoBranch.valid) diff --git a/src/test/cpp/raw/smp/build/smp.asm b/src/test/cpp/raw/smp/build/smp.asm index 06f26160..19fc727d 100644 --- a/src/test/cpp/raw/smp/build/smp.asm +++ b/src/test/cpp/raw/smp/build/smp.asm @@ -10,24 +10,24 @@ Disassembly of section .crt_section: 80000008: f1402373 csrr t1,mhartid 8000000c: 01031313 slli t1,t1,0x10 80000010: 006282b3 add t0,t0,t1 -80000014: 0082a023 sw s0,0(t0) # f8000000 +80000014: 0082a023 sw s0,0(t0) # f8000000 80000018 : 80000018: 00100513 li a0,1 8000001c: 00000597 auipc a1,0x0 -80000020: 1d058593 addi a1,a1,464 # 800001ec +80000020: 36058593 addi a1,a1,864 # 8000037c 80000024: 00a5a02f amoadd.w zero,a0,(a1) 80000028 : 80000028: 00000417 auipc s0,0x0 -8000002c: 1c442403 lw s0,452(s0) # 800001ec +8000002c: 35442403 lw s0,852(s0) # 8000037c 80000030: 19000513 li a0,400 -80000034: 1ac000ef jal ra,800001e0 +80000034: 33c000ef jal ra,80000370 80000038: 00000497 auipc s1,0x0 -8000003c: 1b44a483 lw s1,436(s1) # 800001ec +8000003c: 3444a483 lw s1,836(s1) # 8000037c 80000040: fe8494e3 bne s1,s0,80000028 80000044: f80002b7 lui t0,0xf8000 -80000048: 00428293 addi t0,t0,4 # f8000004 +80000048: 00428293 addi t0,t0,4 # f8000004 8000004c: f1402373 csrr t1,mhartid 80000050: 01031313 slli t1,t1,0x10 80000054: 006282b3 add t0,t0,t1 @@ -35,132 +35,319 @@ Disassembly of section .crt_section: 8000005c : 8000005c: 00100513 li a0,1 -80000060: 040000ef jal ra,800000a0 +80000060: 1d0000ef jal ra,80000230 80000064: 00200513 li a0,2 -80000068: 038000ef jal ra,800000a0 +80000068: 1c8000ef jal ra,80000230 8000006c: 00300513 li a0,3 -80000070: 030000ef jal ra,800000a0 +80000070: 1c0000ef jal ra,80000230 80000074: 00400513 li a0,4 -80000078: 0a4000ef jal ra,8000011c +80000078: 234000ef jal ra,800002ac 8000007c: 00500513 li a0,5 -80000080: 09c000ef jal ra,8000011c +80000080: 22c000ef jal ra,800002ac 80000084: 00600513 li a0,6 -80000088: 094000ef jal ra,8000011c +80000088: 224000ef jal ra,800002ac 8000008c: 00700513 li a0,7 -80000090: 010000ef jal ra,800000a0 +80000090: 1a0000ef jal ra,80000230 80000094: 00800513 li a0,8 -80000098: 084000ef jal ra,8000011c -8000009c: 1000006f j 8000019c +80000098: 214000ef jal ra,800002ac +8000009c: 00000197 auipc gp,0x0 +800000a0: 2ec1a183 lw gp,748(gp) # 80000388 -800000a0 : -800000a0: f80002b7 lui t0,0xf8000 -800000a4: 00c28293 addi t0,t0,12 # f800000c -800000a8: f1402373 csrr t1,mhartid -800000ac: 01031313 slli t1,t1,0x10 -800000b0: 006282b3 add t0,t0,t1 -800000b4: 00a2a023 sw a0,0(t0) -800000b8: 00000e97 auipc t4,0x0 -800000bc: 13ceae83 lw t4,316(t4) # 800001f4 +800000a4 : +800000a4: 00018513 mv a0,gp +800000a8: 00118193 addi gp,gp,1 +800000ac: 200000ef jal ra,800002ac +800000b0: 00000297 auipc t0,0x0 +800000b4: 2e42a283 lw t0,740(t0) # 80000394 +800000b8: 00a00313 li t1,10 +800000bc: 1662d863 bge t0,t1,8000022c 800000c0: 00000297 auipc t0,0x0 -800000c4: 13028293 addi t0,t0,304 # 800001f0 -800000c8: 00100313 li t1,1 -800000cc: 0062a2af amoadd.w t0,t1,(t0) -800000d0: 00128293 addi t0,t0,1 -800000d4: 00000317 auipc t1,0x0 -800000d8: 11832303 lw t1,280(t1) # 800001ec -800000dc: 00629c63 bne t0,t1,800000f4 -800000e0: 001e8293 addi t0,t4,1 -800000e4: 00000317 auipc t1,0x0 -800000e8: 10032623 sw zero,268(t1) # 800001f0 -800000ec: 00000317 auipc t1,0x0 -800000f0: 10532423 sw t0,264(t1) # 800001f4 +800000c4: 2cc2a283 lw t0,716(t0) # 8000038c +800000c8: 00000317 auipc t1,0x0 +800000cc: 2c832303 lw t1,712(t1) # 80000390 +800000d0: 06628a63 beq t0,t1,80000144 +800000d4: f14022f3 csrr t0,mhartid +800000d8: 00000317 auipc t1,0x0 +800000dc: 2b432303 lw t1,692(t1) # 8000038c +800000e0: 00000417 auipc s0,0x0 +800000e4: 32040413 addi s0,s0,800 # 80000400 +800000e8: 00000497 auipc s1,0x0 +800000ec: 31c48493 addi s1,s1,796 # 80000404 +800000f0: 02628863 beq t0,t1,80000120 +800000f4: 00000317 auipc t1,0x0 +800000f8: 29c32303 lw t1,668(t1) # 80000390 +800000fc: 00000417 auipc s0,0x0 +80000100: 30840413 addi s0,s0,776 # 80000404 +80000104: 00000497 auipc s1,0x0 +80000108: 2fc48493 addi s1,s1,764 # 80000400 +8000010c: 00628a63 beq t0,t1,80000120 -800000f4 : -800000f4: 00000297 auipc t0,0x0 -800000f8: 1002a283 lw t0,256(t0) # 800001f4 -800000fc: ffd28ce3 beq t0,t4,800000f4 -80000100: f80002b7 lui t0,0xf8000 -80000104: 01028293 addi t0,t0,16 # f8000010 -80000108: f1402373 csrr t1,mhartid -8000010c: 01031313 slli t1,t1,0x10 -80000110: 006282b3 add t0,t0,t1 -80000114: 00a2a023 sw a0,0(t0) -80000118: 00008067 ret +80000110 : +80000110: 00018513 mv a0,gp +80000114: 00118193 addi gp,gp,1 +80000118: 194000ef jal ra,800002ac +8000011c: 0280006f j 80000144 -8000011c : -8000011c: f80002b7 lui t0,0xf8000 -80000120: 00c28293 addi t0,t0,12 # f800000c -80000124: f1402373 csrr t1,mhartid -80000128: 01031313 slli t1,t1,0x10 -8000012c: 006282b3 add t0,t0,t1 -80000130: 00a2a023 sw a0,0(t0) -80000134: 00000e97 auipc t4,0x0 -80000138: 0c0eae83 lw t4,192(t4) # 800001f4 -8000013c: 00000297 auipc t0,0x0 -80000140: 0b428293 addi t0,t0,180 # 800001f0 +80000120 : +80000120: 29a00913 li s2,666 +80000124: 00018513 mv a0,gp +80000128: 00118193 addi gp,gp,1 +8000012c: 0004a983 lw s3,0(s1) +80000130: 17c000ef jal ra,800002ac +80000134: 01242023 sw s2,0(s0) +80000138: 0120000f fence w,r +8000013c: 0004a983 lw s3,0(s1) +80000140: 05342023 sw s3,64(s0) -80000144 : -80000144: 1002a32f lr.w t1,(t0) -80000148: 00130313 addi t1,t1,1 -8000014c: 1862a3af sc.w t2,t1,(t0) -80000150: fe039ae3 bnez t2,80000144 -80000154: 00000297 auipc t0,0x0 -80000158: 0982a283 lw t0,152(t0) # 800001ec -8000015c: 00629c63 bne t0,t1,80000174 -80000160: 001e8293 addi t0,t4,1 +80000144 : +80000144: 0330000f fence rw,rw +80000148: 00018513 mv a0,gp +8000014c: 00118193 addi gp,gp,1 +80000150: 15c000ef jal ra,800002ac +80000154: f14022f3 csrr t0,mhartid +80000158: f40296e3 bnez t0,800000a4 + +8000015c : +8000015c: 00000297 auipc t0,0x0 +80000160: 2302a283 lw t0,560(t0) # 8000038c 80000164: 00000317 auipc t1,0x0 -80000168: 08032623 sw zero,140(t1) # 800001f0 -8000016c: 00000317 auipc t1,0x0 -80000170: 08532423 sw t0,136(t1) # 800001f4 +80000168: 22c32303 lw t1,556(t1) # 80000390 +8000016c: 04628263 beq t0,t1,800001b0 +80000170: 00000517 auipc a0,0x0 +80000174: 2d452503 lw a0,724(a0) # 80000444 +80000178: f80002b7 lui t0,0xf8000 +8000017c: 01428293 addi t0,t0,20 # f8000014 +80000180: f1402373 csrr t1,mhartid +80000184: 01031313 slli t1,t1,0x10 +80000188: 006282b3 add t0,t0,t1 +8000018c: 00a2a023 sw a0,0(t0) +80000190: 00000517 auipc a0,0x0 +80000194: 2b052503 lw a0,688(a0) # 80000440 +80000198: f80002b7 lui t0,0xf8000 +8000019c: 01428293 addi t0,t0,20 # f8000014 +800001a0: f1402373 csrr t1,mhartid +800001a4: 01031313 slli t1,t1,0x10 +800001a8: 006282b3 add t0,t0,t1 +800001ac: 00a2a023 sw a0,0(t0) -80000174 : -80000174: 00000297 auipc t0,0x0 -80000178: 0802a283 lw t0,128(t0) # 800001f4 -8000017c: ffd28ce3 beq t0,t4,80000174 -80000180: f80002b7 lui t0,0xf8000 -80000184: 01028293 addi t0,t0,16 # f8000010 -80000188: f1402373 csrr t1,mhartid -8000018c: 01031313 slli t1,t1,0x10 -80000190: 006282b3 add t0,t0,t1 -80000194: 00a2a023 sw a0,0(t0) -80000198: 00008067 ret +800001b0 : +800001b0: f14022f3 csrr t0,mhartid +800001b4: ee0298e3 bnez t0,800000a4 +800001b8: 00000297 auipc t0,0x0 +800001bc: 2402a423 sw zero,584(t0) # 80000400 +800001c0: 00000297 auipc t0,0x0 +800001c4: 2402a223 sw zero,580(t0) # 80000404 +800001c8: 00000417 auipc s0,0x0 +800001cc: 1b442403 lw s0,436(s0) # 8000037c +800001d0: 00000297 auipc t0,0x0 +800001d4: 1c02a283 lw t0,448(t0) # 80000390 +800001d8: 00128293 addi t0,t0,1 +800001dc: 00000317 auipc t1,0x0 +800001e0: 1a532a23 sw t0,436(t1) # 80000390 +800001e4: 04829063 bne t0,s0,80000224 +800001e8: 00000317 auipc t1,0x0 +800001ec: 1a032423 sw zero,424(t1) # 80000390 +800001f0: 00000297 auipc t0,0x0 +800001f4: 19c2a283 lw t0,412(t0) # 8000038c +800001f8: 00128293 addi t0,t0,1 +800001fc: 00000317 auipc t1,0x0 +80000200: 18532823 sw t0,400(t1) # 8000038c +80000204: 02829063 bne t0,s0,80000224 +80000208: 00000317 auipc t1,0x0 +8000020c: 18032223 sw zero,388(t1) # 8000038c +80000210: 00000297 auipc t0,0x0 +80000214: 1842a283 lw t0,388(t0) # 80000394 +80000218: 00128293 addi t0,t0,1 +8000021c: 00000317 auipc t1,0x0 +80000220: 16532c23 sw t0,376(t1) # 80000394 -8000019c : -8000019c: 00000413 li s0,0 -800001a0: f80002b7 lui t0,0xf8000 -800001a4: 00828293 addi t0,t0,8 # f8000008 -800001a8: f1402373 csrr t1,mhartid -800001ac: 01031313 slli t1,t1,0x10 -800001b0: 006282b3 add t0,t0,t1 -800001b4: 0082a023 sw s0,0(t0) -800001b8: 0240006f j 800001dc +80000224 : +80000224: 0130000f fence w,rw +80000228: e7dff06f j 800000a4 -800001bc : -800001bc: 00100413 li s0,1 -800001c0: f80002b7 lui t0,0xf8000 -800001c4: 00828293 addi t0,t0,8 # f8000008 -800001c8: f1402373 csrr t1,mhartid -800001cc: 01031313 slli t1,t1,0x10 -800001d0: 006282b3 add t0,t0,t1 -800001d4: 0082a023 sw s0,0(t0) -800001d8: 0040006f j 800001dc +8000022c : +8000022c: 1000006f j 8000032c -800001dc : -800001dc: 0000006f j 800001dc +80000230 : +80000230: f80002b7 lui t0,0xf8000 +80000234: 00c28293 addi t0,t0,12 # f800000c +80000238: f1402373 csrr t1,mhartid +8000023c: 01031313 slli t1,t1,0x10 +80000240: 006282b3 add t0,t0,t1 +80000244: 00a2a023 sw a0,0(t0) +80000248: 00000e97 auipc t4,0x0 +8000024c: 13ceae83 lw t4,316(t4) # 80000384 +80000250: 00000297 auipc t0,0x0 +80000254: 13028293 addi t0,t0,304 # 80000380 +80000258: 00100313 li t1,1 +8000025c: 0062a2af amoadd.w t0,t1,(t0) +80000260: 00128293 addi t0,t0,1 +80000264: 00000317 auipc t1,0x0 +80000268: 11832303 lw t1,280(t1) # 8000037c +8000026c: 00629c63 bne t0,t1,80000284 +80000270: 001e8293 addi t0,t4,1 +80000274: 00000317 auipc t1,0x0 +80000278: 10032623 sw zero,268(t1) # 80000380 +8000027c: 00000317 auipc t1,0x0 +80000280: 10532423 sw t0,264(t1) # 80000384 -800001e0 : -800001e0: fff50513 addi a0,a0,-1 -800001e4: fe051ee3 bnez a0,800001e0 -800001e8: 00008067 ret +80000284 : +80000284: 00000297 auipc t0,0x0 +80000288: 1002a283 lw t0,256(t0) # 80000384 +8000028c: ffd28ce3 beq t0,t4,80000284 +80000290: f80002b7 lui t0,0xf8000 +80000294: 01028293 addi t0,t0,16 # f8000010 +80000298: f1402373 csrr t1,mhartid +8000029c: 01031313 slli t1,t1,0x10 +800002a0: 006282b3 add t0,t0,t1 +800002a4: 00a2a023 sw a0,0(t0) +800002a8: 00008067 ret -800001ec : -800001ec: 0000 unimp +800002ac : +800002ac: f80002b7 lui t0,0xf8000 +800002b0: 00c28293 addi t0,t0,12 # f800000c +800002b4: f1402373 csrr t1,mhartid +800002b8: 01031313 slli t1,t1,0x10 +800002bc: 006282b3 add t0,t0,t1 +800002c0: 00a2a023 sw a0,0(t0) +800002c4: 00000e97 auipc t4,0x0 +800002c8: 0c0eae83 lw t4,192(t4) # 80000384 +800002cc: 00000297 auipc t0,0x0 +800002d0: 0b428293 addi t0,t0,180 # 80000380 + +800002d4 : +800002d4: 1002a32f lr.w t1,(t0) +800002d8: 00130313 addi t1,t1,1 +800002dc: 1862a3af sc.w t2,t1,(t0) +800002e0: fe039ae3 bnez t2,800002d4 +800002e4: 00000297 auipc t0,0x0 +800002e8: 0982a283 lw t0,152(t0) # 8000037c +800002ec: 00629c63 bne t0,t1,80000304 +800002f0: 001e8293 addi t0,t4,1 +800002f4: 00000317 auipc t1,0x0 +800002f8: 08032623 sw zero,140(t1) # 80000380 +800002fc: 00000317 auipc t1,0x0 +80000300: 08532423 sw t0,136(t1) # 80000384 + +80000304 : +80000304: 00000297 auipc t0,0x0 +80000308: 0802a283 lw t0,128(t0) # 80000384 +8000030c: ffd28ce3 beq t0,t4,80000304 +80000310: f80002b7 lui t0,0xf8000 +80000314: 01028293 addi t0,t0,16 # f8000010 +80000318: f1402373 csrr t1,mhartid +8000031c: 01031313 slli t1,t1,0x10 +80000320: 006282b3 add t0,t0,t1 +80000324: 00a2a023 sw a0,0(t0) +80000328: 00008067 ret + +8000032c : +8000032c: 00000413 li s0,0 +80000330: f80002b7 lui t0,0xf8000 +80000334: 00828293 addi t0,t0,8 # f8000008 +80000338: f1402373 csrr t1,mhartid +8000033c: 01031313 slli t1,t1,0x10 +80000340: 006282b3 add t0,t0,t1 +80000344: 0082a023 sw s0,0(t0) +80000348: 0240006f j 8000036c + +8000034c : +8000034c: 00100413 li s0,1 +80000350: f80002b7 lui t0,0xf8000 +80000354: 00828293 addi t0,t0,8 # f8000008 +80000358: f1402373 csrr t1,mhartid +8000035c: 01031313 slli t1,t1,0x10 +80000360: 006282b3 add t0,t0,t1 +80000364: 0082a023 sw s0,0(t0) +80000368: 0040006f j 8000036c + +8000036c : +8000036c: 0000006f j 8000036c + +80000370 : +80000370: fff50513 addi a0,a0,-1 +80000374: fe051ee3 bnez a0,80000370 +80000378: 00008067 ret + +8000037c : +8000037c: 0000 unimp ... -800001f0 : -800001f0: 0000 unimp +80000380 : +80000380: 0000 unimp ... -800001f4 : -800001f4: 0000 unimp +80000384 : +80000384: 0000 unimp + ... + +80000388 : +80000388: 1000 addi s0,sp,32 + ... + +8000038c : +8000038c: 0000 unimp + ... + +80000390 : +80000390: 0000 unimp + ... + +80000394 : +80000394: 0000 unimp +80000396: 0000 unimp +80000398: 00000013 nop +8000039c: 00000013 nop +800003a0: 00000013 nop +800003a4: 00000013 nop +800003a8: 00000013 nop +800003ac: 00000013 nop +800003b0: 00000013 nop +800003b4: 00000013 nop +800003b8: 00000013 nop +800003bc: 00000013 nop +800003c0: 00000013 nop +800003c4: 00000013 nop +800003c8: 00000013 nop +800003cc: 00000013 nop +800003d0: 00000013 nop +800003d4: 00000013 nop +800003d8: 00000013 nop +800003dc: 00000013 nop +800003e0: 00000013 nop +800003e4: 00000013 nop +800003e8: 00000013 nop +800003ec: 00000013 nop +800003f0: 00000013 nop +800003f4: 00000013 nop +800003f8: 00000013 nop +800003fc: 00000013 nop + +80000400 : +80000400: 0000 unimp + ... + +80000404 : +80000404: 0000 unimp +80000406: 0000 unimp +80000408: 00000013 nop +8000040c: 00000013 nop +80000410: 00000013 nop +80000414: 00000013 nop +80000418: 00000013 nop +8000041c: 00000013 nop +80000420: 00000013 nop +80000424: 00000013 nop +80000428: 00000013 nop +8000042c: 00000013 nop +80000430: 00000013 nop +80000434: 00000013 nop +80000438: 00000013 nop +8000043c: 00000013 nop + +80000440 : +80000440: 0000 unimp + ... + +80000444 : ... diff --git a/src/test/cpp/raw/smp/build/smp.bin b/src/test/cpp/raw/smp/build/smp.bin index 59a832fee66759269250ede3b78662b6fdd2d1d3..b391a14e6fda4e289fe59a0e77fca47434fcb461 100755 GIT binary patch literal 1144 zcmcgqJ#Q015S`n-MUFtpg%R-wAv(MVBE-Z70`xTqNq>=iateOqPRw}TSRePV~RI5UqI2&_+;B6ji;|xanpk6*1YE2Hlw|`x{AC5 z;rn30;9e=q$)9YN!aKpCFGYV~@Rb$q8*Tf7_8Ya{oDXjY%y6%l4cDrSxH9F!Pc1)R zhX%u$&hmJ#`P?QC-K=yyYYtpXW9hDmIjHdQ8RCy={p2D0YP>Ny(kq54u(LE%e(LJE z(afyLnZ;muvGO}Ut^J67(zWF_^U@eIPxnIib6n$Q%oZbc6tu29TPuY3l%1|UUNC$w zzt5kk<%mybB8xm{_-bySFVz;PKdb)v!^b*+vzy*^Z|bgNXwQ=Fi?^urBgN<`Ij|E4 zv^GBIZsx-$8ZQ}Nr@3Q1)f}VAoaFAiJyW0kGM5_-fP=MXj~MOh;qn%9kR$AD1-axg zADa4VW=cOZ($5&4W&Wg(G-KmIP4%y!4n9NMIf$n-^cKapy<|xYbw3lIGl2jJ{*QmG M`mb8!{J)Jq0A*P1s{jB1 delta 102 zcmeyt@q>ASvaGEBf~5@NEDQ|HDlRg@tPGOx84gHI2lAVjxJXZQP_|?dW>sK#&(Odu s%xVCn8Gy6{kapk_W(@$+2RMaU6F__*T>z426lQGz@i{i@FvTze0M}I)6#xJL diff --git a/src/test/cpp/raw/smp/src/crt.S b/src/test/cpp/raw/smp/src/crt.S index 72cc5b8f..4f984eb0 100644 --- a/src/test/cpp/raw/smp/src/crt.S +++ b/src/test/cpp/raw/smp/src/crt.S @@ -1,9 +1,13 @@ +#define CONSISTENCY_REDO_COUNT 10 + + #define REPORT_OFFSET 0xF8000000 #define REPORT_THREAD_ID 0x00 #define REPORT_THREAD_COUNT 0x04 #define REPORT_END 0x08 #define REPORT_BARRIER_START 0x0C #define REPORT_BARRIER_END 0x10 +#define REPORT_CONSISTENCY_VALUES 0x14 #define report(reg, id) \ li t0, REPORT_OFFSET+id; \ @@ -54,6 +58,92 @@ barrier_amo_test: call barrier_lrsc + lw gp, barrier_allocator +consistancy_loop: + //Sync + mv a0, gp + addi gp, gp, 1 + call barrier_lrsc + + //all passed ? + lw t0, consistancy_all_tested + li t1, CONSISTENCY_REDO_COUNT + bge t0, t1, consistancy_passed + + //identify who is A, who is B + lw t0, consistancy_a_hart + lw t1, consistancy_b_hart + beq t0, t1, consistancy_join + csrr t0, mhartid + lw t1, consistancy_a_hart + la s0, consistancy_a_value + la s1, consistancy_b_value + beq t0, t1, consistancy_do + lw t1, consistancy_b_hart + la s0, consistancy_b_value + la s1, consistancy_a_value + beq t0, t1, consistancy_do + +consistancy_hart_not_involved: + mv a0, gp + addi gp, gp, 1 + call barrier_lrsc + j consistancy_join + +consistancy_do: + li s2, 666 + mv a0, gp + addi gp, gp, 1 + lw s3, (s1) //Help getting the cache loaded for the consistancy check + call barrier_lrsc + + //Consistancy check : write to read ordering on two thread + sw s2, (s0) + fence w,r + lw s3, (s1) + sw s3, 64(s0) + +consistancy_join: + fence rw, rw //ensure updated values + mv a0, gp + addi gp, gp, 1 + call barrier_lrsc + csrr t0, mhartid + bnez t0, consistancy_loop + +consistancy_assert: + lw t0, consistancy_a_hart + lw t1, consistancy_b_hart + beq t0, t1, consistancy_increment + lw a0, consistancy_a_readed + report(a0, REPORT_CONSISTENCY_VALUES) + lw a0, consistancy_b_readed + report(a0, REPORT_CONSISTENCY_VALUES) + +consistancy_increment: + csrr t0, mhartid + bnez t0, consistancy_loop + sw x0, (consistancy_a_value), t0 + sw x0, (consistancy_b_value), t0 + lw s0,thread_count + lw t0,consistancy_b_hart + addi t0, t0, 1 + sw t0, consistancy_b_hart, t1 + bne t0, s0, consistancy_increment_fence + sw x0, consistancy_b_hart, t1 + lw t0,consistancy_a_hart + addi t0, t0, 1 + sw t0, consistancy_a_hart, t1 + bne t0, s0, consistancy_increment_fence + sw x0, consistancy_a_hart, t1 + lw t0, consistancy_all_tested + addi t0, t0, 1 + sw t0, consistancy_all_tested, t1 +consistancy_increment_fence: + fence w, rw + j consistancy_loop + +consistancy_passed: j success @@ -78,24 +168,25 @@ barrier_amo_wait: ret barrier_lrsc: - report(a0, REPORT_BARRIER_START) - lw ENTRY_PHASE, barrier_phase - la t0, barrier_value + report(a0, REPORT_BARRIER_START) + lw ENTRY_PHASE, barrier_phase + la t0, barrier_value barrier_lrsc_try: - lr.w t1, (t0) - addi t1, t1, 1 - sc.w t2, t1, (t0) - bnez t2, barrier_lrsc_try - lw t0, thread_count - bne t0, t1, barrier_lrsc_wait - addi t0,ENTRY_PHASE,1 - sw x0, barrier_value, t1 - sw t0, barrier_phase, t1 + lr.w t1, (t0) + addi t1, t1, 1 + sc.w t2, t1, (t0) + bnez t2, barrier_lrsc_try + lw t0, thread_count + bne t0, t1, barrier_lrsc_wait + addi t0,ENTRY_PHASE,1 + sw x0, barrier_value, t1 + sw t0, barrier_phase, t1 barrier_lrsc_wait: - lw t0, barrier_phase - beq t0, ENTRY_PHASE, barrier_lrsc_wait - report(a0, REPORT_BARRIER_END) - ret + lw t0, barrier_phase + beq t0, ENTRY_PHASE, barrier_lrsc_wait + report(a0, REPORT_BARRIER_END) + ret + @@ -120,5 +211,27 @@ sleep: thread_count: .word 0 + +.align 6 //Same cache line barrier_value: .word 0 barrier_phase: .word 0 +barrier_allocator: .word 0x1000 + +consistancy_a_hart: .word 0 +consistancy_b_hart: .word 0 +consistancy_all_tested: .word 0 + + +nop;nop;nop;nop;nop;nop;nop;nop; +nop;nop;nop;nop;nop;nop;nop;nop; +.align 6 //Same cache line +consistancy_a_value: .word 0 +consistancy_b_value: .word 0 + +.align 6 //Same cache line +consistancy_b_readed: .word 0 +consistancy_a_readed: .word 0 + +.align 6 //Same cache line +consistancy_init_call: .word 0 +consistancy_do_call: .word 0 \ No newline at end of file From 056bf638663f69da7142fc2f8fd9d23729eb3387 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 21 Apr 2020 16:03:03 +0200 Subject: [PATCH 396/951] Add more consistancy tests --- .../demo/smp/VexRiscvSmpCluster.scala | 4 +- .../vexriscv/plugin/DBusCachedPlugin.scala | 2 +- src/test/cpp/raw/smp/build/smp.asm | 660 ++++++++++-------- src/test/cpp/raw/smp/build/smp.bin | Bin 1144 -> 1388 bytes src/test/cpp/raw/smp/src/crt.S | 68 +- 5 files changed, 437 insertions(+), 297 deletions(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index 0371b29c..f823f4f1 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -488,7 +488,9 @@ object VexRiscvSmpClusterTest extends App{ } } - +// echo "echo 10000 | dhrystone >> log" > test +// time sh test & +// top -b -n 1 object VexRiscvSmpClusterOpenSbi extends App{ import spinal.core.sim._ diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index 82c7953d..8308bc0f 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -236,7 +236,7 @@ class DBusCachedPlugin(val config : DataCacheConfig, if(withLrSc) insert(MEMORY_FENCE_BACK) setWhen(input(MEMORY_LRSC)) if(withAmo) insert(MEMORY_FENCE_BACK) setWhen(input(MEMORY_AMO)) } - when(input(INSTRUCTION)(25)) { //RL but a bit pessimistic as could be MEMORY_FENCE_BACK when the memory op isn't a read + when(input(INSTRUCTION)(25)) { //RL but a bit pessimistic as it could be MEMORY_FENCE_BACK when the memory op isn't a read if(withLrSc) insert(MEMORY_FENCE_FRONT) setWhen(input(MEMORY_LRSC)) if(withAmo) insert(MEMORY_FENCE_FRONT) setWhen(input(MEMORY_AMO)) } diff --git a/src/test/cpp/raw/smp/build/smp.asm b/src/test/cpp/raw/smp/build/smp.asm index 19fc727d..b0492f90 100644 --- a/src/test/cpp/raw/smp/build/smp.asm +++ b/src/test/cpp/raw/smp/build/smp.asm @@ -10,24 +10,24 @@ Disassembly of section .crt_section: 80000008: f1402373 csrr t1,mhartid 8000000c: 01031313 slli t1,t1,0x10 80000010: 006282b3 add t0,t0,t1 -80000014: 0082a023 sw s0,0(t0) # f8000000 +80000014: 0082a023 sw s0,0(t0) # f8000000 80000018 : 80000018: 00100513 li a0,1 8000001c: 00000597 auipc a1,0x0 -80000020: 36058593 addi a1,a1,864 # 8000037c +80000020: 42058593 addi a1,a1,1056 # 8000043c 80000024: 00a5a02f amoadd.w zero,a0,(a1) 80000028 : 80000028: 00000417 auipc s0,0x0 -8000002c: 35442403 lw s0,852(s0) # 8000037c +8000002c: 41442403 lw s0,1044(s0) # 8000043c 80000030: 19000513 li a0,400 -80000034: 33c000ef jal ra,80000370 +80000034: 3fc000ef jal ra,80000430 80000038: 00000497 auipc s1,0x0 -8000003c: 3444a483 lw s1,836(s1) # 8000037c +8000003c: 4044a483 lw s1,1028(s1) # 8000043c 80000040: fe8494e3 bne s1,s0,80000028 80000044: f80002b7 lui t0,0xf8000 -80000048: 00428293 addi t0,t0,4 # f8000004 +80000048: 00428293 addi t0,t0,4 # f8000004 8000004c: f1402373 csrr t1,mhartid 80000050: 01031313 slli t1,t1,0x10 80000054: 006282b3 add t0,t0,t1 @@ -35,319 +35,407 @@ Disassembly of section .crt_section: 8000005c : 8000005c: 00100513 li a0,1 -80000060: 1d0000ef jal ra,80000230 +80000060: 290000ef jal ra,800002f0 80000064: 00200513 li a0,2 -80000068: 1c8000ef jal ra,80000230 +80000068: 288000ef jal ra,800002f0 8000006c: 00300513 li a0,3 -80000070: 1c0000ef jal ra,80000230 +80000070: 280000ef jal ra,800002f0 80000074: 00400513 li a0,4 -80000078: 234000ef jal ra,800002ac +80000078: 2f4000ef jal ra,8000036c 8000007c: 00500513 li a0,5 -80000080: 22c000ef jal ra,800002ac +80000080: 2ec000ef jal ra,8000036c 80000084: 00600513 li a0,6 -80000088: 224000ef jal ra,800002ac +80000088: 2e4000ef jal ra,8000036c 8000008c: 00700513 li a0,7 -80000090: 1a0000ef jal ra,80000230 +80000090: 260000ef jal ra,800002f0 80000094: 00800513 li a0,8 -80000098: 214000ef jal ra,800002ac +80000098: 2d4000ef jal ra,8000036c 8000009c: 00000197 auipc gp,0x0 -800000a0: 2ec1a183 lw gp,748(gp) # 80000388 +800000a0: 3ac1a183 lw gp,940(gp) # 80000448 -800000a4 : -800000a4: 00018513 mv a0,gp -800000a8: 00118193 addi gp,gp,1 -800000ac: 200000ef jal ra,800002ac -800000b0: 00000297 auipc t0,0x0 -800000b4: 2e42a283 lw t0,740(t0) # 80000394 -800000b8: 00a00313 li t1,10 -800000bc: 1662d863 bge t0,t1,8000022c -800000c0: 00000297 auipc t0,0x0 -800000c4: 2cc2a283 lw t0,716(t0) # 8000038c -800000c8: 00000317 auipc t1,0x0 -800000cc: 2c832303 lw t1,712(t1) # 80000390 -800000d0: 06628a63 beq t0,t1,80000144 -800000d4: f14022f3 csrr t0,mhartid -800000d8: 00000317 auipc t1,0x0 -800000dc: 2b432303 lw t1,692(t1) # 8000038c -800000e0: 00000417 auipc s0,0x0 -800000e4: 32040413 addi s0,s0,800 # 80000400 -800000e8: 00000497 auipc s1,0x0 -800000ec: 31c48493 addi s1,s1,796 # 80000404 -800000f0: 02628863 beq t0,t1,80000120 -800000f4: 00000317 auipc t1,0x0 -800000f8: 29c32303 lw t1,668(t1) # 80000390 -800000fc: 00000417 auipc s0,0x0 -80000100: 30840413 addi s0,s0,776 # 80000404 -80000104: 00000497 auipc s1,0x0 -80000108: 2fc48493 addi s1,s1,764 # 80000400 -8000010c: 00628a63 beq t0,t1,80000120 +800000a4 : +800000a4: 00000297 auipc t0,0x0 +800000a8: 06828293 addi t0,t0,104 # 8000010c +800000ac: 00000317 auipc t1,0x0 +800000b0: 48532a23 sw t0,1172(t1) # 80000540 +800000b4: 00000297 auipc t0,0x0 +800000b8: 06028293 addi t0,t0,96 # 80000114 +800000bc: 00000317 auipc t1,0x0 +800000c0: 48532423 sw t0,1160(t1) # 80000544 +800000c4: 00000297 auipc t0,0x0 +800000c8: 01428293 addi t0,t0,20 # 800000d8 +800000cc: 00000317 auipc t1,0x0 +800000d0: 46532e23 sw t0,1148(t1) # 80000548 +800000d4: 0640006f j 80000138 -80000110 : -80000110: 00018513 mv a0,gp -80000114: 00118193 addi gp,gp,1 -80000118: 194000ef jal ra,800002ac -8000011c: 0280006f j 80000144 +800000d8 : +800000d8: 00000297 auipc t0,0x0 +800000dc: 03428293 addi t0,t0,52 # 8000010c +800000e0: 00000317 auipc t1,0x0 +800000e4: 46532023 sw t0,1120(t1) # 80000540 +800000e8: 00000297 auipc t0,0x0 +800000ec: 04028293 addi t0,t0,64 # 80000128 +800000f0: 00000317 auipc t1,0x0 +800000f4: 44532a23 sw t0,1108(t1) # 80000544 +800000f8: 00000297 auipc t0,0x0 +800000fc: 2f428293 addi t0,t0,756 # 800003ec +80000100: 00000317 auipc t1,0x0 +80000104: 44532423 sw t0,1096(t1) # 80000548 +80000108: 0300006f j 80000138 -80000120 : -80000120: 29a00913 li s2,666 -80000124: 00018513 mv a0,gp -80000128: 00118193 addi gp,gp,1 -8000012c: 0004a983 lw s3,0(s1) -80000130: 17c000ef jal ra,800002ac -80000134: 01242023 sw s2,0(s0) -80000138: 0120000f fence w,r -8000013c: 0004a983 lw s3,0(s1) -80000140: 05342023 sw s3,64(s0) +8000010c : +8000010c: 0004a983 lw s3,0(s1) +80000110: 0c40006f j 800001d4 -80000144 : -80000144: 0330000f fence rw,rw -80000148: 00018513 mv a0,gp -8000014c: 00118193 addi gp,gp,1 -80000150: 15c000ef jal ra,800002ac -80000154: f14022f3 csrr t0,mhartid -80000158: f40296e3 bnez t0,800000a4 +80000114 : +80000114: 01242023 sw s2,0(s0) +80000118: 0120000f fence w,r +8000011c: 0004a983 lw s3,0(s1) +80000120: 05342023 sw s3,64(s0) +80000124: 0cc0006f j 800001f0 -8000015c : -8000015c: 00000297 auipc t0,0x0 -80000160: 2302a283 lw t0,560(t0) # 8000038c -80000164: 00000317 auipc t1,0x0 -80000168: 22c32303 lw t1,556(t1) # 80000390 -8000016c: 04628263 beq t0,t1,800001b0 -80000170: 00000517 auipc a0,0x0 -80000174: 2d452503 lw a0,724(a0) # 80000444 -80000178: f80002b7 lui t0,0xf8000 -8000017c: 01428293 addi t0,t0,20 # f8000014 -80000180: f1402373 csrr t1,mhartid -80000184: 01031313 slli t1,t1,0x10 -80000188: 006282b3 add t0,t0,t1 -8000018c: 00a2a023 sw a0,0(t0) -80000190: 00000517 auipc a0,0x0 -80000194: 2b052503 lw a0,688(a0) # 80000440 -80000198: f80002b7 lui t0,0xf8000 -8000019c: 01428293 addi t0,t0,20 # f8000014 -800001a0: f1402373 csrr t1,mhartid -800001a4: 01031313 slli t1,t1,0x10 -800001a8: 006282b3 add t0,t0,t1 -800001ac: 00a2a023 sw a0,0(t0) +80000128 : +80000128: 01242023 sw s2,0(s0) +8000012c: 1204a9af lr.w.rl s3,(s1) +80000130: 05342023 sw s3,64(s0) +80000134: 0bc0006f j 800001f0 -800001b0 : -800001b0: f14022f3 csrr t0,mhartid -800001b4: ee0298e3 bnez t0,800000a4 -800001b8: 00000297 auipc t0,0x0 -800001bc: 2402a423 sw zero,584(t0) # 80000400 -800001c0: 00000297 auipc t0,0x0 -800001c4: 2402a223 sw zero,580(t0) # 80000404 -800001c8: 00000417 auipc s0,0x0 -800001cc: 1b442403 lw s0,436(s0) # 8000037c -800001d0: 00000297 auipc t0,0x0 -800001d4: 1c02a283 lw t0,448(t0) # 80000390 -800001d8: 00128293 addi t0,t0,1 -800001dc: 00000317 auipc t1,0x0 -800001e0: 1a532a23 sw t0,436(t1) # 80000390 -800001e4: 04829063 bne t0,s0,80000224 -800001e8: 00000317 auipc t1,0x0 -800001ec: 1a032423 sw zero,424(t1) # 80000390 -800001f0: 00000297 auipc t0,0x0 -800001f4: 19c2a283 lw t0,412(t0) # 8000038c -800001f8: 00128293 addi t0,t0,1 -800001fc: 00000317 auipc t1,0x0 -80000200: 18532823 sw t0,400(t1) # 8000038c -80000204: 02829063 bne t0,s0,80000224 -80000208: 00000317 auipc t1,0x0 -8000020c: 18032223 sw zero,388(t1) # 8000038c -80000210: 00000297 auipc t0,0x0 -80000214: 1842a283 lw t0,388(t0) # 80000394 -80000218: 00128293 addi t0,t0,1 -8000021c: 00000317 auipc t1,0x0 -80000220: 16532c23 sw t0,376(t1) # 80000394 +80000138 : +80000138: 00018513 mv a0,gp +8000013c: 00118193 addi gp,gp,1 +80000140: 22c000ef jal ra,8000036c +80000144: 00000297 auipc t0,0x0 +80000148: 3002a823 sw zero,784(t0) # 80000454 -80000224 : -80000224: 0130000f fence w,rw -80000228: e7dff06f j 800000a4 +8000014c : +8000014c: 00018513 mv a0,gp +80000150: 00118193 addi gp,gp,1 +80000154: 218000ef jal ra,8000036c +80000158: 00000297 auipc t0,0x0 +8000015c: 2fc2a283 lw t0,764(t0) # 80000454 +80000160: 03200313 li t1,50 +80000164: 1662da63 bge t0,t1,800002d8 +80000168: 00000297 auipc t0,0x0 +8000016c: 2e42a283 lw t0,740(t0) # 8000044c +80000170: 00000317 auipc t1,0x0 +80000174: 2e032303 lw t1,736(t1) # 80000450 +80000178: 06628c63 beq t0,t1,800001f0 +8000017c: f14022f3 csrr t0,mhartid +80000180: 00000317 auipc t1,0x0 +80000184: 2cc32303 lw t1,716(t1) # 8000044c +80000188: 00000417 auipc s0,0x0 +8000018c: 33840413 addi s0,s0,824 # 800004c0 +80000190: 00000497 auipc s1,0x0 +80000194: 33448493 addi s1,s1,820 # 800004c4 +80000198: 02628863 beq t0,t1,800001c8 +8000019c: 00000317 auipc t1,0x0 +800001a0: 2b432303 lw t1,692(t1) # 80000450 +800001a4: 00000417 auipc s0,0x0 +800001a8: 32040413 addi s0,s0,800 # 800004c4 +800001ac: 00000497 auipc s1,0x0 +800001b0: 31448493 addi s1,s1,788 # 800004c0 +800001b4: 00628a63 beq t0,t1,800001c8 -8000022c : -8000022c: 1000006f j 8000032c +800001b8 : +800001b8: 00018513 mv a0,gp +800001bc: 00118193 addi gp,gp,1 +800001c0: 1ac000ef jal ra,8000036c +800001c4: 02c0006f j 800001f0 -80000230 : -80000230: f80002b7 lui t0,0xf8000 -80000234: 00c28293 addi t0,t0,12 # f800000c -80000238: f1402373 csrr t1,mhartid -8000023c: 01031313 slli t1,t1,0x10 -80000240: 006282b3 add t0,t0,t1 -80000244: 00a2a023 sw a0,0(t0) -80000248: 00000e97 auipc t4,0x0 -8000024c: 13ceae83 lw t4,316(t4) # 80000384 -80000250: 00000297 auipc t0,0x0 -80000254: 13028293 addi t0,t0,304 # 80000380 -80000258: 00100313 li t1,1 -8000025c: 0062a2af amoadd.w t0,t1,(t0) -80000260: 00128293 addi t0,t0,1 -80000264: 00000317 auipc t1,0x0 -80000268: 11832303 lw t1,280(t1) # 8000037c -8000026c: 00629c63 bne t0,t1,80000284 -80000270: 001e8293 addi t0,t4,1 -80000274: 00000317 auipc t1,0x0 -80000278: 10032623 sw zero,268(t1) # 80000380 -8000027c: 00000317 auipc t1,0x0 -80000280: 10532423 sw t0,264(t1) # 80000384 +800001c8 : +800001c8: 00000297 auipc t0,0x0 +800001cc: 3782a283 lw t0,888(t0) # 80000540 +800001d0: 000280e7 jalr t0 -80000284 : -80000284: 00000297 auipc t0,0x0 -80000288: 1002a283 lw t0,256(t0) # 80000384 -8000028c: ffd28ce3 beq t0,t4,80000284 -80000290: f80002b7 lui t0,0xf8000 -80000294: 01028293 addi t0,t0,16 # f8000010 -80000298: f1402373 csrr t1,mhartid -8000029c: 01031313 slli t1,t1,0x10 -800002a0: 006282b3 add t0,t0,t1 -800002a4: 00a2a023 sw a0,0(t0) -800002a8: 00008067 ret +800001d4 : +800001d4: 29a00913 li s2,666 +800001d8: 00018513 mv a0,gp +800001dc: 00118193 addi gp,gp,1 +800001e0: 18c000ef jal ra,8000036c +800001e4: 00000297 auipc t0,0x0 +800001e8: 3602a283 lw t0,864(t0) # 80000544 +800001ec: 000280e7 jalr t0 -800002ac : -800002ac: f80002b7 lui t0,0xf8000 -800002b0: 00c28293 addi t0,t0,12 # f800000c -800002b4: f1402373 csrr t1,mhartid -800002b8: 01031313 slli t1,t1,0x10 -800002bc: 006282b3 add t0,t0,t1 -800002c0: 00a2a023 sw a0,0(t0) -800002c4: 00000e97 auipc t4,0x0 -800002c8: 0c0eae83 lw t4,192(t4) # 80000384 -800002cc: 00000297 auipc t0,0x0 -800002d0: 0b428293 addi t0,t0,180 # 80000380 +800001f0 : +800001f0: 0330000f fence rw,rw +800001f4: 00018513 mv a0,gp +800001f8: 00118193 addi gp,gp,1 +800001fc: 170000ef jal ra,8000036c +80000200: f14022f3 csrr t0,mhartid +80000204: f40294e3 bnez t0,8000014c -800002d4 : -800002d4: 1002a32f lr.w t1,(t0) -800002d8: 00130313 addi t1,t1,1 -800002dc: 1862a3af sc.w t2,t1,(t0) -800002e0: fe039ae3 bnez t2,800002d4 -800002e4: 00000297 auipc t0,0x0 -800002e8: 0982a283 lw t0,152(t0) # 8000037c -800002ec: 00629c63 bne t0,t1,80000304 -800002f0: 001e8293 addi t0,t4,1 -800002f4: 00000317 auipc t1,0x0 -800002f8: 08032623 sw zero,140(t1) # 80000380 -800002fc: 00000317 auipc t1,0x0 -80000300: 08532423 sw t0,136(t1) # 80000384 +80000208 : +80000208: 00000297 auipc t0,0x0 +8000020c: 2442a283 lw t0,580(t0) # 8000044c +80000210: 00000317 auipc t1,0x0 +80000214: 24032303 lw t1,576(t1) # 80000450 +80000218: 04628263 beq t0,t1,8000025c +8000021c: 00000517 auipc a0,0x0 +80000220: 2e852503 lw a0,744(a0) # 80000504 +80000224: f80002b7 lui t0,0xf8000 +80000228: 01428293 addi t0,t0,20 # f8000014 +8000022c: f1402373 csrr t1,mhartid +80000230: 01031313 slli t1,t1,0x10 +80000234: 006282b3 add t0,t0,t1 +80000238: 00a2a023 sw a0,0(t0) +8000023c: 00000517 auipc a0,0x0 +80000240: 2c452503 lw a0,708(a0) # 80000500 +80000244: f80002b7 lui t0,0xf8000 +80000248: 01428293 addi t0,t0,20 # f8000014 +8000024c: f1402373 csrr t1,mhartid +80000250: 01031313 slli t1,t1,0x10 +80000254: 006282b3 add t0,t0,t1 +80000258: 00a2a023 sw a0,0(t0) -80000304 : -80000304: 00000297 auipc t0,0x0 -80000308: 0802a283 lw t0,128(t0) # 80000384 -8000030c: ffd28ce3 beq t0,t4,80000304 -80000310: f80002b7 lui t0,0xf8000 -80000314: 01028293 addi t0,t0,16 # f8000010 -80000318: f1402373 csrr t1,mhartid -8000031c: 01031313 slli t1,t1,0x10 -80000320: 006282b3 add t0,t0,t1 -80000324: 00a2a023 sw a0,0(t0) -80000328: 00008067 ret +8000025c : +8000025c: f14022f3 csrr t0,mhartid +80000260: ee0296e3 bnez t0,8000014c +80000264: 00000297 auipc t0,0x0 +80000268: 2402ae23 sw zero,604(t0) # 800004c0 +8000026c: 00000297 auipc t0,0x0 +80000270: 2402ac23 sw zero,600(t0) # 800004c4 +80000274: 00000417 auipc s0,0x0 +80000278: 1c842403 lw s0,456(s0) # 8000043c +8000027c: 00000297 auipc t0,0x0 +80000280: 1d42a283 lw t0,468(t0) # 80000450 +80000284: 00128293 addi t0,t0,1 +80000288: 00000317 auipc t1,0x0 +8000028c: 1c532423 sw t0,456(t1) # 80000450 +80000290: 04829063 bne t0,s0,800002d0 +80000294: 00000317 auipc t1,0x0 +80000298: 1a032e23 sw zero,444(t1) # 80000450 +8000029c: 00000297 auipc t0,0x0 +800002a0: 1b02a283 lw t0,432(t0) # 8000044c +800002a4: 00128293 addi t0,t0,1 +800002a8: 00000317 auipc t1,0x0 +800002ac: 1a532223 sw t0,420(t1) # 8000044c +800002b0: 02829063 bne t0,s0,800002d0 +800002b4: 00000317 auipc t1,0x0 +800002b8: 18032c23 sw zero,408(t1) # 8000044c +800002bc: 00000297 auipc t0,0x0 +800002c0: 1982a283 lw t0,408(t0) # 80000454 +800002c4: 00128293 addi t0,t0,1 +800002c8: 00000317 auipc t1,0x0 +800002cc: 18532623 sw t0,396(t1) # 80000454 -8000032c : -8000032c: 00000413 li s0,0 -80000330: f80002b7 lui t0,0xf8000 -80000334: 00828293 addi t0,t0,8 # f8000008 -80000338: f1402373 csrr t1,mhartid -8000033c: 01031313 slli t1,t1,0x10 -80000340: 006282b3 add t0,t0,t1 -80000344: 0082a023 sw s0,0(t0) -80000348: 0240006f j 8000036c +800002d0 : +800002d0: 0130000f fence w,rw +800002d4: e79ff06f j 8000014c -8000034c : -8000034c: 00100413 li s0,1 +800002d8 : +800002d8: 00000417 auipc s0,0x0 +800002dc: 27042403 lw s0,624(s0) # 80000548 +800002e0: 00018513 mv a0,gp +800002e4: 00118193 addi gp,gp,1 +800002e8: 084000ef jal ra,8000036c +800002ec: 000400e7 jalr s0 + +800002f0 : +800002f0: f80002b7 lui t0,0xf8000 +800002f4: 00c28293 addi t0,t0,12 # f800000c +800002f8: f1402373 csrr t1,mhartid +800002fc: 01031313 slli t1,t1,0x10 +80000300: 006282b3 add t0,t0,t1 +80000304: 00a2a023 sw a0,0(t0) +80000308: 00000e97 auipc t4,0x0 +8000030c: 13ceae83 lw t4,316(t4) # 80000444 +80000310: 00000297 auipc t0,0x0 +80000314: 13028293 addi t0,t0,304 # 80000440 +80000318: 00100313 li t1,1 +8000031c: 0062a2af amoadd.w t0,t1,(t0) +80000320: 00128293 addi t0,t0,1 +80000324: 00000317 auipc t1,0x0 +80000328: 11832303 lw t1,280(t1) # 8000043c +8000032c: 00629c63 bne t0,t1,80000344 +80000330: 001e8293 addi t0,t4,1 +80000334: 00000317 auipc t1,0x0 +80000338: 10032623 sw zero,268(t1) # 80000440 +8000033c: 00000317 auipc t1,0x0 +80000340: 10532423 sw t0,264(t1) # 80000444 + +80000344 : +80000344: 00000297 auipc t0,0x0 +80000348: 1002a283 lw t0,256(t0) # 80000444 +8000034c: ffd28ce3 beq t0,t4,80000344 80000350: f80002b7 lui t0,0xf8000 -80000354: 00828293 addi t0,t0,8 # f8000008 +80000354: 01028293 addi t0,t0,16 # f8000010 80000358: f1402373 csrr t1,mhartid 8000035c: 01031313 slli t1,t1,0x10 80000360: 006282b3 add t0,t0,t1 -80000364: 0082a023 sw s0,0(t0) -80000368: 0040006f j 8000036c +80000364: 00a2a023 sw a0,0(t0) +80000368: 00008067 ret -8000036c : -8000036c: 0000006f j 8000036c +8000036c : +8000036c: f80002b7 lui t0,0xf8000 +80000370: 00c28293 addi t0,t0,12 # f800000c +80000374: f1402373 csrr t1,mhartid +80000378: 01031313 slli t1,t1,0x10 +8000037c: 006282b3 add t0,t0,t1 +80000380: 00a2a023 sw a0,0(t0) +80000384: 00000e97 auipc t4,0x0 +80000388: 0c0eae83 lw t4,192(t4) # 80000444 +8000038c: 00000297 auipc t0,0x0 +80000390: 0b428293 addi t0,t0,180 # 80000440 -80000370 : -80000370: fff50513 addi a0,a0,-1 -80000374: fe051ee3 bnez a0,80000370 -80000378: 00008067 ret +80000394 : +80000394: 1002a32f lr.w t1,(t0) +80000398: 00130313 addi t1,t1,1 +8000039c: 1862a3af sc.w t2,t1,(t0) +800003a0: fe039ae3 bnez t2,80000394 +800003a4: 00000297 auipc t0,0x0 +800003a8: 0982a283 lw t0,152(t0) # 8000043c +800003ac: 00629c63 bne t0,t1,800003c4 +800003b0: 001e8293 addi t0,t4,1 +800003b4: 00000317 auipc t1,0x0 +800003b8: 08032623 sw zero,140(t1) # 80000440 +800003bc: 00000317 auipc t1,0x0 +800003c0: 08532423 sw t0,136(t1) # 80000444 -8000037c : -8000037c: 0000 unimp +800003c4 : +800003c4: 00000297 auipc t0,0x0 +800003c8: 0802a283 lw t0,128(t0) # 80000444 +800003cc: ffd28ce3 beq t0,t4,800003c4 +800003d0: f80002b7 lui t0,0xf8000 +800003d4: 01028293 addi t0,t0,16 # f8000010 +800003d8: f1402373 csrr t1,mhartid +800003dc: 01031313 slli t1,t1,0x10 +800003e0: 006282b3 add t0,t0,t1 +800003e4: 00a2a023 sw a0,0(t0) +800003e8: 00008067 ret + +800003ec : +800003ec: 00000413 li s0,0 +800003f0: f80002b7 lui t0,0xf8000 +800003f4: 00828293 addi t0,t0,8 # f8000008 +800003f8: f1402373 csrr t1,mhartid +800003fc: 01031313 slli t1,t1,0x10 +80000400: 006282b3 add t0,t0,t1 +80000404: 0082a023 sw s0,0(t0) +80000408: 0240006f j 8000042c + +8000040c : +8000040c: 00100413 li s0,1 +80000410: f80002b7 lui t0,0xf8000 +80000414: 00828293 addi t0,t0,8 # f8000008 +80000418: f1402373 csrr t1,mhartid +8000041c: 01031313 slli t1,t1,0x10 +80000420: 006282b3 add t0,t0,t1 +80000424: 0082a023 sw s0,0(t0) +80000428: 0040006f j 8000042c + +8000042c : +8000042c: 0000006f j 8000042c + +80000430 : +80000430: fff50513 addi a0,a0,-1 +80000434: fe051ee3 bnez a0,80000430 +80000438: 00008067 ret + +8000043c : +8000043c: 0000 unimp ... -80000380 : -80000380: 0000 unimp - ... - -80000384 : -80000384: 0000 unimp - ... - -80000388 : -80000388: 1000 addi s0,sp,32 - ... - -8000038c : -8000038c: 0000 unimp - ... - -80000390 : -80000390: 0000 unimp - ... - -80000394 : -80000394: 0000 unimp -80000396: 0000 unimp -80000398: 00000013 nop -8000039c: 00000013 nop -800003a0: 00000013 nop -800003a4: 00000013 nop -800003a8: 00000013 nop -800003ac: 00000013 nop -800003b0: 00000013 nop -800003b4: 00000013 nop -800003b8: 00000013 nop -800003bc: 00000013 nop -800003c0: 00000013 nop -800003c4: 00000013 nop -800003c8: 00000013 nop -800003cc: 00000013 nop -800003d0: 00000013 nop -800003d4: 00000013 nop -800003d8: 00000013 nop -800003dc: 00000013 nop -800003e0: 00000013 nop -800003e4: 00000013 nop -800003e8: 00000013 nop -800003ec: 00000013 nop -800003f0: 00000013 nop -800003f4: 00000013 nop -800003f8: 00000013 nop -800003fc: 00000013 nop - -80000400 : -80000400: 0000 unimp - ... - -80000404 : -80000404: 0000 unimp -80000406: 0000 unimp -80000408: 00000013 nop -8000040c: 00000013 nop -80000410: 00000013 nop -80000414: 00000013 nop -80000418: 00000013 nop -8000041c: 00000013 nop -80000420: 00000013 nop -80000424: 00000013 nop -80000428: 00000013 nop -8000042c: 00000013 nop -80000430: 00000013 nop -80000434: 00000013 nop -80000438: 00000013 nop -8000043c: 00000013 nop - -80000440 : +80000440 : 80000440: 0000 unimp ... -80000444 : +80000444 : +80000444: 0000 unimp + ... + +80000448 : +80000448: 1000 addi s0,sp,32 + ... + +8000044c : +8000044c: 0000 unimp + ... + +80000450 : +80000450: 0000 unimp + ... + +80000454 : +80000454: 0000 unimp +80000456: 0000 unimp +80000458: 00000013 nop +8000045c: 00000013 nop +80000460: 00000013 nop +80000464: 00000013 nop +80000468: 00000013 nop +8000046c: 00000013 nop +80000470: 00000013 nop +80000474: 00000013 nop +80000478: 00000013 nop +8000047c: 00000013 nop +80000480: 00000013 nop +80000484: 00000013 nop +80000488: 00000013 nop +8000048c: 00000013 nop +80000490: 00000013 nop +80000494: 00000013 nop +80000498: 00000013 nop +8000049c: 00000013 nop +800004a0: 00000013 nop +800004a4: 00000013 nop +800004a8: 00000013 nop +800004ac: 00000013 nop +800004b0: 00000013 nop +800004b4: 00000013 nop +800004b8: 00000013 nop +800004bc: 00000013 nop + +800004c0 : +800004c0: 0000 unimp + ... + +800004c4 : +800004c4: 0000 unimp +800004c6: 0000 unimp +800004c8: 00000013 nop +800004cc: 00000013 nop +800004d0: 00000013 nop +800004d4: 00000013 nop +800004d8: 00000013 nop +800004dc: 00000013 nop +800004e0: 00000013 nop +800004e4: 00000013 nop +800004e8: 00000013 nop +800004ec: 00000013 nop +800004f0: 00000013 nop +800004f4: 00000013 nop +800004f8: 00000013 nop +800004fc: 00000013 nop + +80000500 : +80000500: 0000 unimp + ... + +80000504 : +80000504: 0000 unimp +80000506: 0000 unimp +80000508: 00000013 nop +8000050c: 00000013 nop +80000510: 00000013 nop +80000514: 00000013 nop +80000518: 00000013 nop +8000051c: 00000013 nop +80000520: 00000013 nop +80000524: 00000013 nop +80000528: 00000013 nop +8000052c: 00000013 nop +80000530: 00000013 nop +80000534: 00000013 nop +80000538: 00000013 nop +8000053c: 00000013 nop + +80000540 : +80000540: 0000 unimp + ... + +80000544 : +80000544: 0000 unimp + ... + +80000548 : ... diff --git a/src/test/cpp/raw/smp/build/smp.bin b/src/test/cpp/raw/smp/build/smp.bin index b391a14e6fda4e289fe59a0e77fca47434fcb461..5ce691833aa5418f5dbaaa0a6dafe4f821e092e2 100755 GIT binary patch literal 1388 zcmcgrL2DC182xr;C#1Br+YXpC*0N^TXf-C$ih>u{H5QM;{sGxNc#P0L5GM(U^dN3A zAc8SfuprIBL$0yjJ$Uq*LvF^Pf~VA(ooQntwjkod^5xCjdGCGSOxA5@&_?iM-Esz$ zV(l&S!D=v|#DF>h2y4X6H(o(P2f%jmIwi2!ht9P+$CZ~wr@L7liv1yTVO-;Jq|pah zp~Qqfl+RF7;1zgvcy;oW+~&2DqvVdjyxtRhhLWVGPN7(j?CEi|TTL->(#xiYf4opp8%e+KN z(23Ss+xmjS)3l~Rcz>Sf?4*U3^%@mMYvq$-t%7%AN!hi z1`@x|iuqE#x+>-xR*S2_10PB5#yQF97ZrCQc<95(tCQmSkkn^adSwK3sA z2HBz?Y*&{At~A{fAzJ|9YuVmX@QBGX%Hfpc(eVR5?WH&$&Be-M)fZbl;4@y5_otP< zJnu;l{q(3;C*A`c+EFjN6L+-<^;w=}=K~dR(H#Ag!k->^meE7Tgaf8LTk%UcAw&*)Mrx@{&D3WSN`#%{3)Ni x%*Q7BXX4%?svC##{2P8p$@jhPG8u|~#vWq~0p;+2y!)-Dep@9P{^e*$`^7D)gA delta 517 zcmZ{hF;Buk6vtn$cSc=6FVcdLRIVl>2&m}XAZ`vMd;!yb08IPxtkAN}9s2btK;8_AyV-C2-G{1k*Z* zpZVoHl|8Ut%vk6LIYs6Hn3J2Jbit&y}dO$F7?Xq;rj4`FM)U!=so(~}>+5dRZ{04oB=B$hKKz*c(W%w7Y3h($R z>DtR6=2qEeEn&57EDY1-L|8D0&kEQ^P31gz6_%FOkeAh8o~y<9hEjd>`d$Z!_C`oW L?h(=4DvAC8dYFFt diff --git a/src/test/cpp/raw/smp/src/crt.S b/src/test/cpp/raw/smp/src/crt.S index 4f984eb0..9a72bd7e 100644 --- a/src/test/cpp/raw/smp/src/crt.S +++ b/src/test/cpp/raw/smp/src/crt.S @@ -1,4 +1,4 @@ -#define CONSISTENCY_REDO_COUNT 10 +#define CONSISTENCY_REDO_COUNT 50 #define REPORT_OFFSET 0xF8000000 @@ -59,6 +59,51 @@ barrier_amo_test: lw gp, barrier_allocator + +consistancy_test1: + la t0, consistancy_init_load + sw t0, consistancy_init_call, t1 + la t0, consistancy_do_simple_fence + sw t0, consistancy_do_call, t1 + la t0, consistancy_test2 + sw t0, consistancy_done_call, t1 + j consistancy_start + +consistancy_test2: + la t0, consistancy_init_load + sw t0, consistancy_init_call, t1 + la t0, consistancy_do_rl_fence + sw t0, consistancy_do_call, t1 + la t0, success + sw t0, consistancy_done_call, t1 + j consistancy_start + + +consistancy_init_load: + lw s3, (s1) //Help getting the cache loaded for the consistancy check + j consistancy_do_init_done + +consistancy_do_simple_fence: + //Consistancy check : write to read ordering on two thread + sw s2, (s0) + fence w,r + lw s3, (s1) + sw s3, 64(s0) + j consistancy_join + +consistancy_do_rl_fence: + //Consistancy check : write to read ordering on two thread + sw s2, (s0) + lr.w.rl s3, (s1) + sw s3, 64(s0) + j consistancy_join + + +consistancy_start: + mv a0, gp + addi gp, gp, 1 + call barrier_lrsc + sw x0, consistancy_all_tested, t0 consistancy_loop: //Sync mv a0, gp @@ -91,17 +136,17 @@ consistancy_hart_not_involved: j consistancy_join consistancy_do: + lw t0, consistancy_init_call + jalr t0 +consistancy_do_init_done: li s2, 666 mv a0, gp addi gp, gp, 1 - lw s3, (s1) //Help getting the cache loaded for the consistancy check call barrier_lrsc - //Consistancy check : write to read ordering on two thread - sw s2, (s0) - fence w,r - lw s3, (s1) - sw s3, 64(s0) + + lw t0, consistancy_do_call + jalr t0 consistancy_join: fence rw, rw //ensure updated values @@ -144,7 +189,11 @@ consistancy_increment_fence: j consistancy_loop consistancy_passed: - j success + lw s0, consistancy_done_call + mv a0, gp + addi gp, gp, 1 + call barrier_lrsc + jalr s0 @@ -234,4 +283,5 @@ consistancy_a_readed: .word 0 .align 6 //Same cache line consistancy_init_call: .word 0 -consistancy_do_call: .word 0 \ No newline at end of file +consistancy_do_call: .word 0 +consistancy_done_call: .word 0 \ No newline at end of file From 4016b1fc5274b799ca1a5f7be88b7809744396e7 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 21 Apr 2020 17:18:08 +0200 Subject: [PATCH 397/951] Add sbt assembly --- project/plugins.sbt | 1 + 1 file changed, 1 insertion(+) diff --git a/project/plugins.sbt b/project/plugins.sbt index e5c42332..60a54de4 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,2 +1,3 @@ addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "5.2.4") +addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.10") From 3fb123a64a77abec5ca8136a31ba562f40a078a3 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 21 Apr 2020 21:20:54 +0200 Subject: [PATCH 398/951] fix withStall --- src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index f823f4f1..286d503e 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -8,7 +8,6 @@ import spinal.lib.bus.bmb.sim.BmbMemoryAgent import spinal.lib.bus.bmb.{Bmb, BmbArbiter, BmbDecoder, BmbExclusiveMonitor, BmbInvalidateMonitor, BmbParameter} import spinal.lib.com.jtag.Jtag import spinal.lib.com.jtag.sim.JtagTcp -import vexriscv.demo.smp.VexRiscvSmpClusterTest.{cpuCount, withStall} import vexriscv.ip.{DataCacheAck, DataCacheConfig, DataCacheMemBus, InstructionCacheConfig} import vexriscv.plugin.{BranchPlugin, CsrPlugin, CsrPluginConfig, DBusCachedPlugin, DBusSimplePlugin, DebugPlugin, DecoderSimplePlugin, FullBarrelShifterPlugin, HazardSimplePlugin, IBusCachedPlugin, IBusSimplePlugin, IntAluPlugin, MmuPlugin, MmuPortConfig, MulDivIterativePlugin, MulPlugin, RegFilePlugin, STATIC, SrcPlugin, YamlPlugin} import vexriscv.{Riscv, VexRiscv, VexRiscvConfig, plugin} @@ -301,7 +300,7 @@ object VexRiscvSmpClusterTestInfrastructure{ val CLINT_CMP_ADDR = CLINT_ADDR+0x4000 val CLINT_TIME_ADDR = CLINT_ADDR+0xBFF8 - def ram(dut : VexRiscvSmpCluster) = { + def ram(dut : VexRiscvSmpCluster, withStall : Boolean) = { import spinal.core.sim._ val cpuCount = dut.cpus.size val ram = new BmbMemoryAgent(0x100000000l){ @@ -479,7 +478,7 @@ object VexRiscvSmpClusterTest extends App{ SimTimeout(100000000l*10*cpuCount) dut.clockDomain.forkSimSpeedPrinter(1.0) VexRiscvSmpClusterTestInfrastructure.init(dut) - val ram = VexRiscvSmpClusterTestInfrastructure.ram(dut) + val ram = VexRiscvSmpClusterTestInfrastructure.ram(dut, withStall) ram.memory.loadBin(0x80000000l, "src/test/cpp/raw/smp/build/smp.bin") periodicaly(20000*10){ assert(ram.reportWatchdog != 0) @@ -505,7 +504,7 @@ object VexRiscvSmpClusterOpenSbi extends App{ simConfig.workspaceName("rawr_4c").compile(VexRiscvSmpClusterGen.vexRiscvCluster(cpuCount)).doSimUntilVoid(seed = 42){dut => // dut.clockDomain.forkSimSpeedPrinter(1.0) VexRiscvSmpClusterTestInfrastructure.init(dut) - val ram = VexRiscvSmpClusterTestInfrastructure.ram(dut) + val ram = VexRiscvSmpClusterTestInfrastructure.ram(dut, withStall) // ram.memory.loadBin(0x80000000l, "../opensbi/build/platform/spinal/vexriscv/sim/smp/firmware/fw_payload.bin") ram.memory.loadBin(0x80000000l, "../opensbi/build/platform/spinal/vexriscv/sim/smp/firmware/fw_jump.bin") ram.memory.loadBin(0xC0000000l, "../buildroot/output/images/Image") From 0c59dd9ed3b967cd3b0f38cdae4ffc083d991dcf Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 27 Apr 2020 17:37:15 +0200 Subject: [PATCH 399/951] SMP fence now ensure ordering for all kinds of memory transfers --- src/main/scala/vexriscv/ip/DataCache.scala | 2 +- src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index 34641659..4d2b2a20 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -567,7 +567,7 @@ class DataCache(val p : DataCacheConfig) extends Component{ val consistancyCheck = (withInvalidate || withWriteResponse) generate new Area { val fenceConsistent = (if(withInvalidate) sync.fenceConsistent else pending.done) && !io.cpu.writeBack.fenceValid && !io.cpu.memory.fenceValid //Pessimistic fence tracking val totalyConsistent = (if(withInvalidate) sync.totalyConsistent else pending.done) && !(io.cpu.memory.isValid && io.cpu.memory.isWrite) && !(io.cpu.writeBack.isValid && io.cpu.memory.isWrite) - when(io.cpu.execute.isValid && (!io.cpu.execute.args.wr || isAmo)){ + when(io.cpu.execute.isValid /*&& (!io.cpu.execute.args.wr || isAmo)*/){ when(!fenceConsistent || io.cpu.execute.totalyConsistent && !totalyConsistent){ io.cpu.execute.haltIt := True } diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index 8308bc0f..12f38f3e 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -236,7 +236,7 @@ class DBusCachedPlugin(val config : DataCacheConfig, if(withLrSc) insert(MEMORY_FENCE_BACK) setWhen(input(MEMORY_LRSC)) if(withAmo) insert(MEMORY_FENCE_BACK) setWhen(input(MEMORY_AMO)) } - when(input(INSTRUCTION)(25)) { //RL but a bit pessimistic as it could be MEMORY_FENCE_BACK when the memory op isn't a read + when(input(INSTRUCTION)(25)) { //RL if(withLrSc) insert(MEMORY_FENCE_FRONT) setWhen(input(MEMORY_LRSC)) if(withAmo) insert(MEMORY_FENCE_FRONT) setWhen(input(MEMORY_AMO)) } From 5fd0b220cdd8ed15a6bf0d66b7b77ea41f0685aa Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 27 Apr 2020 17:37:30 +0200 Subject: [PATCH 400/951] CsrPlugin add openSbi config --- .../scala/vexriscv/plugin/CsrPlugin.scala | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index fce4c153..bb56c3e7 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -83,6 +83,46 @@ object CsrPluginConfig{ def all : CsrPluginConfig = all(0x00000020l) def small : CsrPluginConfig = small(0x00000020l) def smallest : CsrPluginConfig = smallest(0x00000020l) + + def openSbi(hartId : Int, misa : Int) = CsrPluginConfig( + catchIllegalAccess = true, + mvendorid = 0, + marchid = 0, + mimpid = 0, + mhartid = hartId, + misaExtensionsInit = misa, + misaAccess = CsrAccess.READ_ONLY, + mtvecAccess = CsrAccess.READ_WRITE, //Could have been WRITE_ONLY :( + mtvecInit = null, + mepcAccess = CsrAccess.READ_WRITE, + mscratchGen = true, + mcauseAccess = CsrAccess.READ_ONLY, + mbadaddrAccess = CsrAccess.READ_ONLY, + mcycleAccess = CsrAccess.NONE, + minstretAccess = CsrAccess.NONE, + ucycleAccess = CsrAccess.NONE, + wfiGenAsWait = true, + ecallGen = true, + xtvecModeGen = false, + noCsrAlu = false, + wfiGenAsNop = false, + ebreakGen = false, //TODO + userGen = true, + supervisorGen = true, + sscratchGen = true, + stvecAccess = CsrAccess.READ_WRITE, + sepcAccess = CsrAccess.READ_WRITE, + scauseAccess = CsrAccess.READ_WRITE, + sbadaddrAccess = CsrAccess.READ_WRITE, + scycleAccess = CsrAccess.NONE, + sinstretAccess = CsrAccess.NONE, + satpAccess = CsrAccess.NONE, + medelegAccess = CsrAccess.READ_WRITE, //Could have been WRITE_ONLY :( + midelegAccess = CsrAccess.READ_WRITE, //Could have been WRITE_ONLY :( + pipelineCsrRead = false, + deterministicInteruptionEntry = false + ) + def linuxMinimal(mtVecInit : BigInt) = CsrPluginConfig( catchIllegalAccess = true, mvendorid = 1, From 3ba509931c43902bc823e1cd59b30a028cb54f47 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 27 Apr 2020 17:38:06 +0200 Subject: [PATCH 401/951] Add VexRiscvSmpLitexCluster with the required pipelining to get proper FMax --- .../demo/smp/VexRiscvSmpCluster.scala | 65 +++-- .../demo/smp/VexRiscvSmpLitexCluster.scala | 228 ++++++++++++++++++ 2 files changed, 255 insertions(+), 38 deletions(-) create mode 100644 src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index 286d503e..3c857310 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -27,7 +27,7 @@ case class VexRiscvSmpCluster(p : VexRiscvSmpClusterParameter, val dMemParameter = BmbInvalidateMonitor.outputParameter(invalidateMonitorParameter) val iBusParameter = p.cpuConfigs.head.plugins.find(_.isInstanceOf[IBusCachedPlugin]).get.asInstanceOf[IBusCachedPlugin].config.getBmbParameter() - val iBusArbiterParameter = iBusParameter.copy(sourceWidth = log2Up(p.cpuConfigs.size)) + val iBusArbiterParameter = iBusParameter//.copy(sourceWidth = log2Up(p.cpuConfigs.size)) val iMemParameter = iBusArbiterParameter val io = new Bundle { @@ -72,20 +72,19 @@ case class VexRiscvSmpCluster(p : VexRiscvSmpClusterParameter, val dBusArbiter = BmbArbiter( p = dBusArbiterParameter, portCount = cpus.size, - pendingRspMax = 64, lowerFirstPriority = false, inputsWithInv = cpus.map(_ => true), inputsWithSync = cpus.map(_ => true), pendingInvMax = 16 ) - (dBusArbiter.io.inputs, cpus).zipped.foreach(_ << _.dBus) + (dBusArbiter.io.inputs, cpus).zipped.foreach(_ << _.dBus.pipelined(invValid = true, ackValid = true, syncValid = true)) val exclusiveMonitor = BmbExclusiveMonitor( inputParameter = exclusiveMonitorParameter, pendingWriteMax = 64 ) - exclusiveMonitor.io.input << dBusArbiter.io.output + exclusiveMonitor.io.input << dBusArbiter.io.output.pipelined(cmdValid = true, cmdReady = true, rspValid = true) val invalidateMonitor = BmbInvalidateMonitor( inputParameter = invalidateMonitorParameter, @@ -113,11 +112,13 @@ case class VexRiscvSmpCluster(p : VexRiscvSmpClusterParameter, object VexRiscvSmpClusterGen { - def vexRiscvConfig(id : Int) = { + def vexRiscvConfig(hartId : Int, + ioRange : UInt => Bool = (x => x(31 downto 28) === 0xF), + resetVector : Long = 0x80000000l) = { val config = VexRiscvConfig( plugins = List( new MmuPlugin( - ioRange = x => x(31 downto 28) === 0xF + ioRange = ioRange ), //Uncomment the whole IBusSimplePlugin and comment IBusCachedPlugin if you want uncached iBus config // new IBusSimplePlugin( @@ -137,10 +138,11 @@ object VexRiscvSmpClusterGen { //Uncomment the whole IBusCachedPlugin and comment IBusSimplePlugin if you want cached iBus config new IBusCachedPlugin( - resetVector = 0x80000000l, + resetVector = resetVector, compressedGen = false, prediction = STATIC, injectorStage = false, + relaxedPcCalculation = true, config = InstructionCacheConfig( cacheSize = 4096*1, bytePerLine = 32, @@ -151,7 +153,7 @@ object VexRiscvSmpClusterGen { catchIllegalAccess = true, catchAccessFault = true, asyncTagMemory = false, - twoCycleRam = false, + twoCycleRam = true, twoCycleCache = true // ) ), @@ -173,6 +175,7 @@ object VexRiscvSmpClusterGen { dBusCmdMasterPipe = true, dBusCmdSlavePipe = true, dBusRspSlavePipe = true, + relaxedMemoryTranslationRegister = true, config = new DataCacheConfig( cacheSize = 4096*1, bytePerLine = 32, @@ -204,8 +207,9 @@ object VexRiscvSmpClusterGen { catchIllegalInstruction = true ), new RegFilePlugin( - regFileReadyKind = plugin.SYNC, - zeroBoot = true + regFileReadyKind = plugin.ASYNC, + zeroBoot = true, + x0Init = false ), new IntAluPlugin, new SrcPlugin( @@ -232,39 +236,17 @@ object VexRiscvSmpClusterGen { divUnrollFactor = 1 ), // new DivPlugin, - new CsrPlugin(CsrPluginConfig.all2(0x80000020l).copy(ebreakGen = false, mhartid = id, misaExtensionsInit = Riscv.misaToInt("imas"))), - // new CsrPlugin(//CsrPluginConfig.all2(0x80000020l).copy(ebreakGen = true)/* - // CsrPluginConfig( - // catchIllegalAccess = false, - // mvendorid = null, - // marchid = null, - // mimpid = null, - // mhartid = null, - // misaExtensionsInit = 0, - // misaAccess = CsrAccess.READ_ONLY, - // mtvecAccess = CsrAccess.WRITE_ONLY, - // mtvecInit = 0x80000020l, - // mepcAccess = CsrAccess.READ_WRITE, - // mscratchGen = true, - // mcauseAccess = CsrAccess.READ_ONLY, - // mbadaddrAccess = CsrAccess.READ_ONLY, - // mcycleAccess = CsrAccess.NONE, - // minstretAccess = CsrAccess.NONE, - // ecallGen = true, - // ebreakGen = true, - // wfiGenAsWait = false, - // wfiGenAsNop = true, - // ucycleAccess = CsrAccess.NONE - // )), + new CsrPlugin(CsrPluginConfig.openSbi(hartId = hartId, misa = Riscv.misaToInt("imas"))), + new BranchPlugin( earlyBranch = false, catchAddressMisaligned = true, fenceiGenAsAJump = false ), - new YamlPlugin(s"cpu$id.yaml") + new YamlPlugin(s"cpu$hartId.yaml") ) ) - if(id == 0) config.plugins += new DebugPlugin(null) + if(hartId == 0) config.plugins += new DebugPlugin(null) config } def vexRiscvCluster(cpuCount : Int) = VexRiscvSmpCluster( @@ -441,8 +423,8 @@ object VexRiscvSmpClusterTestInfrastructure{ val value = (dut.io.softwareInterrupts.toLong & ~mask) | (if(data == 1) mask else 0) dut.io.softwareInterrupts #= value } - onRead(CLINT_CMP_ADDR + hartId*8)(clint.cmp(hartId).toInt) - onRead(CLINT_CMP_ADDR + hartId*8+4)((clint.cmp(hartId) >> 32).toInt) +// onRead(CLINT_CMP_ADDR + hartId*8)(clint.cmp(hartId).toInt) +// onRead(CLINT_CMP_ADDR + hartId*8+4)((clint.cmp(hartId) >> 32).toInt) onWrite(CLINT_CMP_ADDR + hartId*8){data => clint.cmp(hartId) = (clint.cmp(hartId) & 0xFFFFFFFF00000000l) | data} onWrite(CLINT_CMP_ADDR + hartId*8+4){data => clint.cmp(hartId) = (clint.cmp(hartId) & 0x00000000FFFFFFFFl) | (data.toLong << 32)} } @@ -490,6 +472,13 @@ object VexRiscvSmpClusterTest extends App{ // echo "echo 10000 | dhrystone >> log" > test // time sh test & // top -b -n 1 + +// TODO +// litex cluster should use out of order decoder +// MultiChannelFifo.toStream arbitration +// BmbDecoderOutOfOrder arbitration +// DataCache to bmb invalidation that are more than single line +// update fence w to w object VexRiscvSmpClusterOpenSbi extends App{ import spinal.core.sim._ diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala new file mode 100644 index 00000000..244c3a90 --- /dev/null +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala @@ -0,0 +1,228 @@ +package vexriscv.demo.smp + +import spinal.core._ +import spinal.lib.bus.bmb._ +import spinal.lib.bus.wishbone.{Wishbone, WishboneConfig, WishboneSlaveFactory} +import spinal.lib.com.jtag.Jtag +import spinal.lib._ +import spinal.lib.bus.misc.{AddressMapping, DefaultMapping, SizeMapping} +import spinal.lib.misc.Clint +import vexriscv.demo.smp.VexRiscvSmpClusterGen.vexRiscvConfig +import vexriscv.{VexRiscv, VexRiscvConfig} +import vexriscv.plugin.{CsrPlugin, DBusCachedPlugin, DebugPlugin, IBusCachedPlugin} + +case class LiteDramNativeParameter(addressWidth : Int, dataWidth : Int) + +case class LiteDramNativeCmd(p : LiteDramNativeParameter) extends Bundle{ + val we = Bool() + val addr = UInt(p.addressWidth bits) +} + +case class LiteDramNativeWData(p : LiteDramNativeParameter) extends Bundle{ + val data = Bits(p.dataWidth bits) + val we = Bits(p.dataWidth/8 bits) +} + +case class LiteDramNativeRData(p : LiteDramNativeParameter) extends Bundle{ + val data = Bits(p.dataWidth bits) +} + + +case class LiteDramNative(p : LiteDramNativeParameter) extends Bundle with IMasterSlave { + val cmd = Stream(LiteDramNativeCmd(p)) + val wdata = Stream(LiteDramNativeWData(p)) + val rdata = Stream(LiteDramNativeRData(p)) + override def asMaster(): Unit = { + master(cmd, wdata) + slave(rdata) + } + + def fromBmb(bmb : Bmb): Unit = new Area{ + val resized = bmb.resize(p.dataWidth) + val unburstified = resized.unburstify() + case class Context() extends Bundle { + val context = Bits(unburstified.p.contextWidth bits) + val source = UInt(unburstified.p.sourceWidth bits) + val isWrite = Bool() + } + val (queueFork, cmdFork, dataFork) = StreamFork3(unburstified.cmd) + cmd.arbitrationFrom(cmdFork) + cmd.addr := (cmdFork.address >> log2Up(bmb.p.byteCount)).resized + cmd.we := cmdFork.isWrite + + if(bmb.p.canWrite) { + wdata.arbitrationFrom(dataFork.throwWhen(dataFork.isRead)) + wdata.data := cmdFork.data + wdata.we := cmdFork.mask + } else { + dataFork.ready := True + wdata.valid := False + wdata.data.assignDontCare() + wdata.we.assignDontCare() + } + + val cmdContext = Stream(Context()) + cmdContext.arbitrationFrom(queueFork) + cmdContext.context := unburstified.cmd.context + cmdContext.source := unburstified.cmd.source + cmdContext.isWrite := unburstified.cmd.isWrite + + val rspContext = cmdContext.queue(64) + + rdata.ready := unburstified.rsp.fire && !rspContext.isWrite + rspContext.ready := unburstified.rsp.fire + unburstified.rsp.valid := rspContext.valid && (rspContext.isWrite || rdata.valid) + unburstified.rsp.setSuccess() + unburstified.rsp.last := True + unburstified.rsp.source := rspContext.source + unburstified.rsp.context := rspContext.context + unburstified.rsp.data := rdata.data + } +} + +case class VexRiscvLitexSmpClusterParameter( cluster : VexRiscvSmpClusterParameter, + liteDram : LiteDramNativeParameter, + liteDramMapping : AddressMapping) + +case class VexRiscvLitexSmpCluster(p : VexRiscvLitexSmpClusterParameter, + debugClockDomain : ClockDomain) extends Component{ + + val peripheralWishboneConfig = WishboneConfig( + addressWidth = 30, + dataWidth = 32, + selWidth = 4, + useERR = true, + useBTE = true, + useCTI = true + ) + + val io = new Bundle { + val dMem = master(LiteDramNative(p.liteDram)) + val iMem = master(LiteDramNative(p.liteDram)) + val peripheral = master(Wishbone(peripheralWishboneConfig)) + val clint = slave(Wishbone(Clint.getWisboneConfig())) + val externalInterrupts = in Bits(p.cluster.cpuConfigs.size bits) + val externalSupervisorInterrupts = in Bits(p.cluster.cpuConfigs.size bits) + val jtag = slave(Jtag()) + val debugReset = out Bool() + } + val cpuCount = p.cluster.cpuConfigs.size + val clint = Clint(cpuCount) + clint.driveFrom(WishboneSlaveFactory(io.clint)) + + val cluster = VexRiscvSmpCluster(p.cluster, debugClockDomain) + cluster.io.externalInterrupts <> io.externalInterrupts + cluster.io.externalSupervisorInterrupts <> io.externalSupervisorInterrupts + cluster.io.jtag <> io.jtag + cluster.io.debugReset <> io.debugReset + cluster.io.timerInterrupts <> B(clint.harts.map(_.timerInterrupt)) + cluster.io.softwareInterrupts <> B(clint.harts.map(_.softwareInterrupt)) + + + val dBusDecoder = BmbDecoderOutOfOrder( + p = cluster.io.dMem.p, + mappings = Seq(DefaultMapping, p.liteDramMapping), + capabilities = Seq(cluster.io.dMem.p, cluster.io.dMem.p), + pendingRspTransactionMax = 32 + ) + dBusDecoder.io.input << cluster.io.dMem.pipelined(cmdValid = true, cmdReady = true, rspValid = true) + io.dMem.fromBmb(dBusDecoder.io.outputs(1)) + + val iBusArbiterParameter = cluster.iBusParameter.copy(sourceWidth = log2Up(cpuCount)) + val iBusArbiter = BmbArbiter( + p = iBusArbiterParameter, + portCount = cpuCount, + lowerFirstPriority = false + ) + + (iBusArbiter.io.inputs, cluster.io.iMems).zipped.foreach(_ << _.pipelined(cmdHalfRate = true, rspValid = true)) + + val iBusDecoder = BmbDecoder( + p = iBusArbiter.io.output.p, + mappings = Seq(DefaultMapping, p.liteDramMapping), + capabilities = Seq(iBusArbiterParameter, iBusArbiterParameter), + pendingMax = 15 + ) + iBusDecoder.io.input << iBusArbiter.io.output + io.iMem.fromBmb(iBusDecoder.io.outputs(1)) + + val peripheralArbiter = BmbArbiter( + p = dBusDecoder.io.outputs(0).p.copy(sourceWidth = dBusDecoder.io.outputs(0).p.sourceWidth + 1), + portCount = 2, + lowerFirstPriority = true + ) + peripheralArbiter.io.inputs(0) << iBusDecoder.io.outputs(0).resize(dataWidth = 32).pipelined(cmdHalfRate = true, rspValid = true) + peripheralArbiter.io.inputs(1) << dBusDecoder.io.outputs(0).resize(dataWidth = 32).pipelined(cmdHalfRate = true, rspValid = true) + + val peripheralWishbone = peripheralArbiter.io.output.toWishbone() + io.peripheral << peripheralWishbone +} + + +object VexRiscvLitexSmpClusterOpenSbi extends App{ + import spinal.core.sim._ + + val simConfig = SimConfig + simConfig.withWave + simConfig.allOptimisation + simConfig.addSimulatorFlag("--threads 1") + + val cpuCount = 4 + val withStall = false + + def parameter = VexRiscvLitexSmpClusterParameter( + cluster = VexRiscvSmpClusterParameter( + cpuConfigs = List.tabulate(cpuCount) { hartId => + vexRiscvConfig( + hartId = hartId, + ioRange = address => address.msb, + resetVector = 0 + ) + } + ), + liteDram = LiteDramNativeParameter(addressWidth = 32, dataWidth = 32), + liteDramMapping = SizeMapping(0x40000000l, 0x40000000l) + ) + + def dutGen = VexRiscvLitexSmpCluster( + p = parameter, + debugClockDomain = ClockDomain.current.copy(reset = Bool().setName("debugResetIn")) + ) + simConfig.compile(dutGen).doSimUntilVoid(seed = 42){dut => + // dut.clockDomain.forkSimSpeedPrinter(1.0) +// VexRiscvSmpClusterTestInfrastructure.init(dut) +// val ram = VexRiscvSmpClusterTestInfrastructure.ram(dut, withStall) + // ram.memory.loadBin(0x80000000l, "../opensbi/build/platform/spinal/vexriscv/sim/smp/firmware/fw_payload.bin") +// ram.memory.loadBin(0x80000000l, "../opensbi/build/platform/spinal/vexriscv/sim/smp/firmware/fw_jump.bin") +// ram.memory.loadBin(0xC0000000l, "../buildroot/output/images/Image") +// ram.memory.loadBin(0xC1000000l, "../buildroot/output/images/dtb") +// ram.memory.loadBin(0xC2000000l, "../buildroot/output/images/rootfs.cpio") + + // fork{ + // disableSimWave() + // val atMs = 130 + // val durationMs = 15 + // sleep(atMs*1000000) + // enableSimWave() + // println("** enableSimWave **") + // sleep(durationMs*1000000) + // println("** disableSimWave **") + // while(true) { + // disableSimWave() + // sleep(100000 * 10) + // enableSimWave() + // sleep( 100 * 10) + // } + //// simSuccess() + // } + + fork{ + while(true) { + disableSimWave() + sleep(100000 * 10) + enableSimWave() + sleep( 100 * 10) + } + } + } + } \ No newline at end of file From 4a49b2363655d54d69b8f88baec8b80d3792a689 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 28 Apr 2020 14:38:27 +0200 Subject: [PATCH 402/951] Fix regression --- src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala | 1 + src/test/cpp/regression/main.cpp | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index 3c857310..f4aa237a 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -479,6 +479,7 @@ object VexRiscvSmpClusterTest extends App{ // BmbDecoderOutOfOrder arbitration // DataCache to bmb invalidation that are more than single line // update fence w to w +// DBusCachedPlugin dBusAccess execute.isValid := True is induce a longe combinatorial path to check conditions, D$ execute valid => execute haltIt object VexRiscvSmpClusterOpenSbi extends App{ import spinal.core.sim._ diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 67d7a0a6..82e0671f 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -2364,9 +2364,11 @@ public: virtual void onReset(){ top->dBus_cmd_ready = 1; top->dBus_rsp_valid = 0; + #ifdef DBUS_INVALIDATE top->dBus_inv_valid = 0; top->dBus_ack_ready = 0; top->dBus_sync_valid = 0; + #endif } virtual void preCycle(){ From 03a044577527007910a829d7ab7ea9114bdac1b5 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 28 Apr 2020 15:50:20 +0200 Subject: [PATCH 403/951] Fix SMP for configuration without writeback stage. Include SMP core into the single core tests regressions --- src/main/scala/vexriscv/ip/DataCache.scala | 4 ++-- .../scala/vexriscv/TestIndividualFeatures.scala | 14 +++++++++----- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index 4d2b2a20..de29f49c 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -565,8 +565,8 @@ class DataCache(val p : DataCacheConfig) extends Component{ //Ensure write to read consistency val consistancyCheck = (withInvalidate || withWriteResponse) generate new Area { - val fenceConsistent = (if(withInvalidate) sync.fenceConsistent else pending.done) && !io.cpu.writeBack.fenceValid && !io.cpu.memory.fenceValid //Pessimistic fence tracking - val totalyConsistent = (if(withInvalidate) sync.totalyConsistent else pending.done) && !(io.cpu.memory.isValid && io.cpu.memory.isWrite) && !(io.cpu.writeBack.isValid && io.cpu.memory.isWrite) + val fenceConsistent = (if(withInvalidate) sync.fenceConsistent else pending.done) && !io.cpu.writeBack.fenceValid && (if(mergeExecuteMemory) True else !io.cpu.memory.fenceValid) //Pessimistic fence tracking + val totalyConsistent = (if(withInvalidate) sync.totalyConsistent else pending.done) && (if(mergeExecuteMemory) True else !(io.cpu.memory.isValid && io.cpu.memory.isWrite)) && !(io.cpu.writeBack.isValid && io.cpu.memory.isWrite) when(io.cpu.execute.isValid /*&& (!io.cpu.execute.args.wr || isAmo)*/){ when(!fenceConsistent || io.cpu.execute.totalyConsistent && !totalyConsistent){ io.cpu.execute.haltIt := True diff --git a/src/test/scala/vexriscv/TestIndividualFeatures.scala b/src/test/scala/vexriscv/TestIndividualFeatures.scala index d2922030..f23299a2 100644 --- a/src/test/scala/vexriscv/TestIndividualFeatures.scala +++ b/src/test/scala/vexriscv/TestIndividualFeatures.scala @@ -427,8 +427,10 @@ class DBusDimension extends VexRiscvDimension("DBus") { var cacheSize = 0 var wayCount = 0 val withLrSc = catchAll - val withAmo = catchAll && r.nextBoolean() - val dBusRspSlavePipe, relaxedMemoryTranslationRegister = r.nextBoolean() + val withSmp = withLrSc && r.nextBoolean() + val withAmo = catchAll && r.nextBoolean() || withSmp + val dBusRspSlavePipe = r.nextBoolean() || withSmp + val relaxedMemoryTranslationRegister = r.nextBoolean() val earlyWaysHits = r.nextBoolean() && !noWriteBack val dBusCmdMasterPipe, dBusCmdSlavePipe = false //As it create test bench issues @@ -436,8 +438,8 @@ class DBusDimension extends VexRiscvDimension("DBus") { cacheSize = 512 << r.nextInt(5) wayCount = 1 << r.nextInt(3) }while(cacheSize/wayCount < 512 || (catchAll && cacheSize/wayCount > 4096)) - new VexRiscvPosition("Cached" + "S" + cacheSize + "W" + wayCount + "BPL" + bytePerLine + (if(dBusCmdMasterPipe) "Cmp " else "") + (if(dBusCmdSlavePipe) "Csp " else "") + (if(dBusRspSlavePipe) "Rsp " else "") + (if(relaxedMemoryTranslationRegister) "Rmtr " else "") + (if(earlyWaysHits) "Ewh " else "") + (if(withAmo) "Amo " else "")) { - override def testParam = "DBUS=CACHED " + (if(withLrSc) "LRSC=yes " else "") + (if(withAmo) "AMO=yes " else "") + new VexRiscvPosition("Cached" + "S" + cacheSize + "W" + wayCount + "BPL" + bytePerLine + (if(dBusCmdMasterPipe) "Cmp " else "") + (if(dBusCmdSlavePipe) "Csp " else "") + (if(dBusRspSlavePipe) "Rsp " else "") + (if(relaxedMemoryTranslationRegister) "Rmtr " else "") + (if(earlyWaysHits) "Ewh " else "") + (if(withAmo) "Amo " else "") + (if(withSmp) "Smp " else "")) { + override def testParam = "DBUS=CACHED " + (if(withLrSc) "LRSC=yes " else "") + (if(withAmo) "AMO=yes " else "") + (if(withSmp) "DBUS_EXCLUSIVE=yes DBUS_INVALIDATE=yes " else "") override def applyOn(config: VexRiscvConfig): Unit = { config.plugins += new DBusCachedPlugin( @@ -453,7 +455,9 @@ class DBusDimension extends VexRiscvDimension("DBus") { catchUnaligned = catchAll, withLrSc = withLrSc, withAmo = withAmo, - earlyWaysHits = earlyWaysHits + earlyWaysHits = earlyWaysHits, + withExclusive = withSmp, + withInvalidate = withSmp ), dBusCmdMasterPipe = dBusCmdMasterPipe, dBusCmdSlavePipe = dBusCmdSlavePipe, From 23b8c40cab6b41bb3f9c3d2c0a6ca88f185443b1 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 28 Apr 2020 16:19:00 +0200 Subject: [PATCH 404/951] update travis verilator --- scripts/regression/verilator.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/regression/verilator.mk b/scripts/regression/verilator.mk index b13ca4c8..9472858e 100644 --- a/scripts/regression/verilator.mk +++ b/scripts/regression/verilator.mk @@ -3,7 +3,7 @@ verilator/configure: rm -rf verilator* - wget https://www.veripool.org/ftp/verilator-4.012.tgz + wget https://www.veripool.org/ftp/verilator-4.032.tgz tar xvzf verilator*.t*gz mv verilator-4.012 verilator From eee9927baf875fd5ab270542a7188442fd559ade Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 28 Apr 2020 22:10:56 +0200 Subject: [PATCH 405/951] IBusCachedPlugin now support memory data width multiple of 32 --- src/main/scala/vexriscv/ip/InstructionCache.scala | 9 ++++----- src/test/cpp/regression/main.cpp | 11 ++++++++--- src/test/cpp/regression/makefile | 4 ++++ src/test/scala/vexriscv/TestIndividualFeatures.scala | 9 +++++---- 4 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/main/scala/vexriscv/ip/InstructionCache.scala b/src/main/scala/vexriscv/ip/InstructionCache.scala index 09b1a8ac..469377c4 100644 --- a/src/main/scala/vexriscv/ip/InstructionCache.scala +++ b/src/main/scala/vexriscv/ip/InstructionCache.scala @@ -70,7 +70,7 @@ case class InstructionCacheConfig( cacheSize : Int, def getBmbParameter() = BmbParameter( addressWidth = 32, - dataWidth = 32, + dataWidth = memDataWidth, lengthWidth = log2Up(this.bytePerLine), sourceWidth = 0, contextWidth = 0, @@ -278,7 +278,6 @@ case class InstructionCacheFlushBus() extends Bundle with IMasterSlave{ class InstructionCache(p : InstructionCacheConfig) extends Component{ import p._ - assert(cpuDataWidth == memDataWidth, "Need testing") val io = new Bundle{ val flush = in Bool() val cpu = slave(InstructionCacheCpuBus(p)) @@ -287,7 +286,7 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{ val lineWidth = bytePerLine*8 val lineCount = cacheSize/bytePerLine - val wordWidth = Math.max(memDataWidth,32) + val wordWidth = cpuDataWidth val wordWidthLog2 = log2Up(wordWidth) val wordPerLine = lineWidth/wordWidth val memWordPerLine = lineWidth/memDataWidth @@ -295,7 +294,7 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{ val bytePerMemWord = memDataWidth/8 val wayLineCount = lineCount/wayCount val wayLineLog2 = log2Up(wayLineCount) - val wayWordCount = wayLineCount * wordPerLine + val wayMemWordCount = wayLineCount * memWordPerLine val tagRange = addressWidth-1 downto log2Up(wayLineCount*bytePerLine) val lineRange = tagRange.low-1 downto log2Up(bytePerLine) @@ -314,7 +313,7 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{ val ways = Seq.fill(wayCount)(new Area{ val tags = Mem(LineTag(),wayLineCount) - val datas = Mem(Bits(memDataWidth bits),wayWordCount) + val datas = Mem(Bits(memDataWidth bits),wayMemWordCount) if(preResetFlush){ tags.initBigInt(List.fill(wayLineCount)(BigInt(0))) diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 82e0671f..5fa9635a 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -2026,10 +2026,15 @@ public: ws->fail(); } #endif - ws->iBusAccess(address,&top->iBus_rsp_payload_data,&error); + error = false; + for(int idx = 0;idx < IBUS_DATA_WIDTH/32;idx++){ + bool localError; + ws->iBusAccess(address+idx*4,((uint32_t*)&top->iBus_rsp_payload_data)+idx,&localError); + error |= localError; + } top->iBus_rsp_payload_error = error; - pendingCount--; - address = address + 4; + pendingCount-=IBUS_DATA_WIDTH/32; + address = address + IBUS_DATA_WIDTH/8; top->iBus_rsp_valid = 1; } if(ws->iStall) top->iBus_cmd_ready = VL_RANDOM_I(7) < 100 && pendingCount == 0; diff --git a/src/test/cpp/regression/makefile b/src/test/cpp/regression/makefile index 160707a0..98363266 100644 --- a/src/test/cpp/regression/makefile +++ b/src/test/cpp/regression/makefile @@ -3,6 +3,7 @@ REGRESSION_PATH?=./ VEXRISCV_FILE?=../../../../VexRiscv.v IBUS?=CACHED IBUS_TC?=no +IBUS_DATA_WIDTH?=32 DBUS?=CACHED TRACE?=no TRACE_ACCESS?=no @@ -41,8 +42,11 @@ STOP_ON_ERROR?=no COREMARK=no WITH_USER_IO?=no + ADDCFLAGS += -CFLAGS -DREGRESSION_PATH='\"$(REGRESSION_PATH)/\"' ADDCFLAGS += -CFLAGS -DIBUS_${IBUS} +ADDCFLAGS += -CFLAGS -DIBUS_DATA_WIDTH=${IBUS_DATA_WIDTH} + ADDCFLAGS += -CFLAGS -DDBUS_${DBUS} ADDCFLAGS += -CFLAGS -DREDO=${REDO} ADDCFLAGS += -CFLAGS -pthread diff --git a/src/test/scala/vexriscv/TestIndividualFeatures.scala b/src/test/scala/vexriscv/TestIndividualFeatures.scala index f23299a2..98da2297 100644 --- a/src/test/scala/vexriscv/TestIndividualFeatures.scala +++ b/src/test/scala/vexriscv/TestIndividualFeatures.scala @@ -354,7 +354,8 @@ class IBusDimension(rvcRate : Double) extends VexRiscvDimension("IBus") { val prediction = random(r, List(NONE, STATIC, DYNAMIC, DYNAMIC_TARGET)) val relaxedPcCalculation, twoCycleCache, injectorStage = r.nextBoolean() val twoCycleRam = r.nextBoolean() && twoCycleCache - val bytePerLine = List(8,16,32,64)(r.nextInt(4)) + val memDataWidth = List(32,64,128)(r.nextInt(3)) + val bytePerLine = Math.max(memDataWidth/8, List(8,16,32,64)(r.nextInt(4))) var cacheSize = 0 var wayCount = 0 do{ @@ -362,8 +363,8 @@ class IBusDimension(rvcRate : Double) extends VexRiscvDimension("IBus") { wayCount = 1 << r.nextInt(3) }while(cacheSize/wayCount < 512 || (catchAll && cacheSize/wayCount > 4096)) - new VexRiscvPosition("Cached" + (if(twoCycleCache) "2cc" else "") + (if(injectorStage) "Injstage" else "") + (if(twoCycleRam) "2cr" else "") + "S" + cacheSize + "W" + wayCount + "BPL" + bytePerLine + (if(relaxedPcCalculation) "Relax" else "") + (if(compressed) "Rvc" else "") + prediction.getClass.getTypeName().replace("$","")+ (if(tighlyCoupled)"Tc" else "")) with InstructionAnticipatedPosition{ - override def testParam = "IBUS=CACHED" + (if(compressed) " COMPRESSED=yes" else "") + (if(tighlyCoupled)" IBUS_TC=yes" else "") + new VexRiscvPosition(s"Cached${memDataWidth}d" + (if(twoCycleCache) "2cc" else "") + (if(injectorStage) "Injstage" else "") + (if(twoCycleRam) "2cr" else "") + "S" + cacheSize + "W" + wayCount + "BPL" + bytePerLine + (if(relaxedPcCalculation) "Relax" else "") + (if(compressed) "Rvc" else "") + prediction.getClass.getTypeName().replace("$","")+ (if(tighlyCoupled)"Tc" else "")) with InstructionAnticipatedPosition{ + override def testParam = s"IBUS=CACHED IBUS_DATA_WIDTH=$memDataWidth" + (if(compressed) " COMPRESSED=yes" else "") + (if(tighlyCoupled)" IBUS_TC=yes" else "") override def applyOn(config: VexRiscvConfig): Unit = { val p = new IBusCachedPlugin( resetVector = 0x80000000l, @@ -378,7 +379,7 @@ class IBusDimension(rvcRate : Double) extends VexRiscvDimension("IBus") { wayCount = wayCount, addressWidth = 32, cpuDataWidth = 32, - memDataWidth = 32, + memDataWidth = memDataWidth, catchIllegalAccess = catchAll, catchAccessFault = catchAll, asyncTagMemory = false, From 7b80e1fc307727d3a9a5c8023d9ba12b123b52b1 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 28 Apr 2020 22:11:41 +0200 Subject: [PATCH 406/951] Set SMP workspace to use i$ memDataWidth of 128 bits --- src/main/scala/vexriscv/TestsWorkspace.scala | 2 +- .../demo/smp/VexRiscvSmpCluster.scala | 2 +- .../demo/smp/VexRiscvSmpLitexCluster.scala | 30 ++++++++++++++++++- 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/src/main/scala/vexriscv/TestsWorkspace.scala b/src/main/scala/vexriscv/TestsWorkspace.scala index 3cd633bc..4d9575ea 100644 --- a/src/main/scala/vexriscv/TestsWorkspace.scala +++ b/src/main/scala/vexriscv/TestsWorkspace.scala @@ -64,7 +64,7 @@ object TestsWorkspace { wayCount = 1, addressWidth = 32, cpuDataWidth = 32, - memDataWidth = 32, + memDataWidth = 128, catchIllegalAccess = true, catchAccessFault = true, asyncTagMemory = false, diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index f4aa237a..3a726033 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -149,7 +149,7 @@ object VexRiscvSmpClusterGen { wayCount = 1, addressWidth = 32, cpuDataWidth = 32, - memDataWidth = 32, + memDataWidth = 128, catchIllegalAccess = true, catchAccessFault = true, asyncTagMemory = false, diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala index 244c3a90..60add57a 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala @@ -6,7 +6,9 @@ import spinal.lib.bus.wishbone.{Wishbone, WishboneConfig, WishboneSlaveFactory} import spinal.lib.com.jtag.Jtag import spinal.lib._ import spinal.lib.bus.misc.{AddressMapping, DefaultMapping, SizeMapping} +import spinal.lib.eda.bench.Bench import spinal.lib.misc.Clint +import vexriscv.demo.smp.VexRiscvLitexSmpClusterOpenSbi.{cpuCount, parameter} import vexriscv.demo.smp.VexRiscvSmpClusterGen.vexRiscvConfig import vexriscv.{VexRiscv, VexRiscvConfig} import vexriscv.plugin.{CsrPlugin, DBusCachedPlugin, DebugPlugin, IBusCachedPlugin} @@ -157,6 +159,32 @@ case class VexRiscvLitexSmpCluster(p : VexRiscvLitexSmpClusterParameter, val peripheralWishbone = peripheralArbiter.io.output.toWishbone() io.peripheral << peripheralWishbone } +object VexRiscvLitexSmpClusterGen extends App { + val cpuCount = 4 + val withStall = false + + def parameter = VexRiscvLitexSmpClusterParameter( + cluster = VexRiscvSmpClusterParameter( + cpuConfigs = List.tabulate(cpuCount) { hartId => + vexRiscvConfig( + hartId = hartId, + ioRange = address => address.msb, + resetVector = 0 + ) + } + ), + liteDram = LiteDramNativeParameter(addressWidth = 32, dataWidth = 128), + liteDramMapping = SizeMapping(0x40000000l, 0x40000000l) + ) + + def dutGen = VexRiscvLitexSmpCluster( + p = parameter, + debugClockDomain = ClockDomain.current.copy(reset = Bool().setName("debugResetIn")) + ) + + SpinalVerilog(Bench.compressIo(dutGen)) + +} object VexRiscvLitexSmpClusterOpenSbi extends App{ @@ -180,7 +208,7 @@ object VexRiscvLitexSmpClusterOpenSbi extends App{ ) } ), - liteDram = LiteDramNativeParameter(addressWidth = 32, dataWidth = 32), + liteDram = LiteDramNativeParameter(addressWidth = 32, dataWidth = 128), liteDramMapping = SizeMapping(0x40000000l, 0x40000000l) ) From 86e0cbc1f3683be610a0c1ce9796daa82c44541c Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 29 Apr 2020 13:59:43 +0200 Subject: [PATCH 407/951] I$ with memDataWidth > cpuDataWidth now mux memWords into cpuWords before the decode stage by default. Add twoCycleRamInnerMux option to move that to the decode stage --- src/main/scala/vexriscv/ip/InstructionCache.scala | 10 ++++++---- src/test/scala/vexriscv/TestIndividualFeatures.scala | 4 +++- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/main/scala/vexriscv/ip/InstructionCache.scala b/src/main/scala/vexriscv/ip/InstructionCache.scala index 469377c4..75601143 100644 --- a/src/main/scala/vexriscv/ip/InstructionCache.scala +++ b/src/main/scala/vexriscv/ip/InstructionCache.scala @@ -22,6 +22,7 @@ case class InstructionCacheConfig( cacheSize : Int, asyncTagMemory : Boolean, twoCycleCache : Boolean = true, twoCycleRam : Boolean = false, + twoCycleRamInnerMux : Boolean = false, preResetFlush : Boolean = false, bypassGen : Boolean = false ){ @@ -404,7 +405,8 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{ }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 dataMem = way.datas.readSync(io.cpu.prefetch.pc(lineRange.high downto memWordRange.low), !io.cpu.fetch.isStuck) + val data = if(!twoCycleRamInnerMux) dataMem.subdivideIn(cpuDataWidth bits).read(io.cpu.fetch.pc(memWordToCpuWordRange)) else dataMem } } @@ -415,7 +417,7 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{ val id = OHToUInt(hits) val error = read.waysValues.map(_.tag.error).read(id) val data = read.waysValues.map(_.data).read(id) - val word = if(cpuDataWidth == memDataWidth) CombInit(data) else data.subdivideIn(cpuDataWidth bits).read(io.cpu.fetch.pc(memWordToCpuWordRange)) + val word = if(cpuDataWidth == memDataWidth || !twoCycleRamInnerMux) CombInit(data) else data.subdivideIn(cpuDataWidth bits).read(io.cpu.fetch.pc(memWordToCpuWordRange)) io.cpu.fetch.data := (if(p.bypassGen) (io.cpu.fetch.dataBypassValid ? io.cpu.fetch.dataBypass | word) else word) if(twoCycleCache){ io.cpu.decode.data := RegNextWhen(io.cpu.fetch.data,!io.cpu.decode.isStuck) @@ -423,7 +425,7 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{ } if(twoCycleRam && wayCount == 1){ - val cacheData = if(cpuDataWidth == memDataWidth) CombInit(read.waysValues.head.data) else read.waysValues.head.data.subdivideIn(cpuDataWidth bits).read(io.cpu.fetch.pc(memWordToCpuWordRange)) + val cacheData = if(cpuDataWidth == memDataWidth || !twoCycleRamInnerMux) CombInit(read.waysValues.head.data) else read.waysValues.head.data.subdivideIn(cpuDataWidth bits).read(io.cpu.fetch.pc(memWordToCpuWordRange)) io.cpu.fetch.data := (if(p.bypassGen) (io.cpu.fetch.dataBypassValid ? io.cpu.fetch.dataBypass | cacheData) else cacheData) } @@ -459,7 +461,7 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{ val id = OHToUInt(hits) val error = tags(id).error val data = fetchStage.read.waysValues.map(way => stage(way.data)).read(id) - val word = if(cpuDataWidth == memDataWidth) data else data.subdivideIn(cpuDataWidth bits).read(io.cpu.decode.pc(memWordToCpuWordRange)) + val word = if(cpuDataWidth == memDataWidth || !twoCycleRamInnerMux) data else data.subdivideIn(cpuDataWidth bits).read(io.cpu.decode.pc(memWordToCpuWordRange)) if(p.bypassGen) when(stage(io.cpu.fetch.dataBypassValid)){ word := stage(io.cpu.fetch.dataBypass) } diff --git a/src/test/scala/vexriscv/TestIndividualFeatures.scala b/src/test/scala/vexriscv/TestIndividualFeatures.scala index 98da2297..72651b44 100644 --- a/src/test/scala/vexriscv/TestIndividualFeatures.scala +++ b/src/test/scala/vexriscv/TestIndividualFeatures.scala @@ -354,6 +354,7 @@ class IBusDimension(rvcRate : Double) extends VexRiscvDimension("IBus") { val prediction = random(r, List(NONE, STATIC, DYNAMIC, DYNAMIC_TARGET)) val relaxedPcCalculation, twoCycleCache, injectorStage = r.nextBoolean() val twoCycleRam = r.nextBoolean() && twoCycleCache + val twoCycleRamInnerMux = r.nextBoolean() && twoCycleRam val memDataWidth = List(32,64,128)(r.nextInt(3)) val bytePerLine = Math.max(memDataWidth/8, List(8,16,32,64)(r.nextInt(4))) var cacheSize = 0 @@ -384,7 +385,8 @@ class IBusDimension(rvcRate : Double) extends VexRiscvDimension("IBus") { catchAccessFault = catchAll, asyncTagMemory = false, twoCycleRam = twoCycleRam, - twoCycleCache = twoCycleCache + twoCycleCache = twoCycleCache, + twoCycleRamInnerMux = twoCycleRamInnerMux ) ) if(tighlyCoupled) p.newTightlyCoupledPort(TightlyCoupledPortParameter("iBusTc", a => a(30 downto 28) === 0x0)) From 9e9d28bfa697038adbe9a3babf579908fb402446 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 29 Apr 2020 14:02:41 +0200 Subject: [PATCH 408/951] d$ now implement consistancy hazard by using writeback redo --- src/main/scala/vexriscv/ip/DataCache.scala | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index de29f49c..f99acffc 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -564,12 +564,13 @@ class DataCache(val p : DataCacheConfig) extends Component{ val isAmo = if(withAmo) io.cpu.execute.isAmo else False //Ensure write to read consistency + val consistancyIssue = False val consistancyCheck = (withInvalidate || withWriteResponse) generate new Area { val fenceConsistent = (if(withInvalidate) sync.fenceConsistent else pending.done) && !io.cpu.writeBack.fenceValid && (if(mergeExecuteMemory) True else !io.cpu.memory.fenceValid) //Pessimistic fence tracking val totalyConsistent = (if(withInvalidate) sync.totalyConsistent else pending.done) && (if(mergeExecuteMemory) True else !(io.cpu.memory.isValid && io.cpu.memory.isWrite)) && !(io.cpu.writeBack.isValid && io.cpu.memory.isWrite) when(io.cpu.execute.isValid /*&& (!io.cpu.execute.args.wr || isAmo)*/){ when(!fenceConsistent || io.cpu.execute.totalyConsistent && !totalyConsistent){ - io.cpu.execute.haltIt := True + consistancyIssue := True } } } @@ -588,6 +589,7 @@ class DataCache(val p : DataCacheConfig) extends Component{ val wayHits = earlyWaysHits generate ways.map(way => (io.cpu.memory.mmuBus.rsp.physicalAddress(tagRange) === way.tagsReadRsp.address && way.tagsReadRsp.valid)) val dataMux = earlyDataMux generate MuxOH(wayHits, ways.map(_.dataReadRsp)) val wayInvalidate = stagePipe(stage0. wayInvalidate) + val consistancyIssue = stagePipe(stage0.consistancyIssue) val dataColisions = if(mergeExecuteMemory){ stagePipe(stage0.dataColisions) } else { @@ -605,6 +607,7 @@ class DataCache(val p : DataCacheConfig) extends Component{ val tagsReadRsp = ways.map(w => ramPipe(w.tagsReadRsp)) val dataReadRsp = !earlyDataMux generate ways.map(w => ramPipe(w.dataReadRsp)) val wayInvalidate = stagePipe(stageA. wayInvalidate) + val consistancyIssue = stagePipe(stageA.consistancyIssue) val dataColisions = stagePipe(stageA.dataColisions) val waysHitsBeforeInvalidate = if(earlyWaysHits) stagePipe(B(stageA.wayHits)) else B(tagsReadRsp.map(tag => mmuRsp.physicalAddress(tagRange) === tag.address && tag.valid).asBits()) val waysHits = waysHitsBeforeInvalidate & ~wayInvalidate @@ -651,8 +654,7 @@ class DataCache(val p : DataCacheConfig) extends Component{ val lrSc = withInternalLrSc generate new Area{ val reserved = RegInit(False) - when(io.cpu.writeBack.isValid && !io.cpu.writeBack.isStuck && request.isLrsc - && !io.cpu.redo && !io.cpu.writeBack.mmuException && !io.cpu.writeBack.unalignedAccess && !io.cpu.writeBack.accessError){ + when(io.cpu.writeBack.isValid && !io.cpu.writeBack.isStuck && request.isLrsc){ reserved := !request.wr } } @@ -828,15 +830,16 @@ class DataCache(val p : DataCacheConfig) extends Component{ } //remove side effects on exceptions - when(mmuRsp.refilling || io.cpu.writeBack.accessError || io.cpu.writeBack.mmuException || io.cpu.writeBack.unalignedAccess){ + when(consistancyIssue || mmuRsp.refilling || io.cpu.writeBack.accessError || io.cpu.writeBack.mmuException || io.cpu.writeBack.unalignedAccess){ io.mem.cmd.valid := False tagsWriteCmd.valid := False dataWriteCmd.valid := False loaderValid := False io.cpu.writeBack.haltIt := False + if(withInternalLrSc) lrSc.reserved := lrSc.reserved if(withExternalAmo) amo.external.state := LR_CMD } - io.cpu.redo setWhen(io.cpu.writeBack.isValid && mmuRsp.refilling) + io.cpu.redo setWhen(io.cpu.writeBack.isValid && (mmuRsp.refilling || consistancyIssue)) assert(!(io.cpu.writeBack.isValid && !io.cpu.writeBack.haltIt && io.cpu.writeBack.isStuck), "writeBack stuck by another plugin is not allowed") } From 7c50fa6d5541a0e2118e67a13250d1b826c81f9f Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 29 Apr 2020 14:03:00 +0200 Subject: [PATCH 409/951] SmpCluster now use i$ line of 64 bytes --- src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala | 2 +- src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index 3a726033..98ab7886 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -145,7 +145,7 @@ object VexRiscvSmpClusterGen { relaxedPcCalculation = true, config = InstructionCacheConfig( cacheSize = 4096*1, - bytePerLine = 32, + bytePerLine = 64, wayCount = 1, addressWidth = 32, cpuDataWidth = 32, diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala index 60add57a..e911e446 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala @@ -148,8 +148,9 @@ case class VexRiscvLitexSmpCluster(p : VexRiscvLitexSmpClusterParameter, iBusDecoder.io.input << iBusArbiter.io.output io.iMem.fromBmb(iBusDecoder.io.outputs(1)) + val peripheralAccessLength = Math.max(iBusDecoder.io.outputs(0).p.lengthWidth, dBusDecoder.io.outputs(0).p.lengthWidth) val peripheralArbiter = BmbArbiter( - p = dBusDecoder.io.outputs(0).p.copy(sourceWidth = dBusDecoder.io.outputs(0).p.sourceWidth + 1), + p = dBusDecoder.io.outputs(0).p.copy(sourceWidth = dBusDecoder.io.outputs(0).p.sourceWidth + 1, lengthWidth = peripheralAccessLength), portCount = 2, lowerFirstPriority = true ) From dc0da9662a4187439afcba079f143e1e624f310e Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 1 May 2020 11:14:11 +0200 Subject: [PATCH 410/951] Update SMP fence (final) --- src/main/scala/vexriscv/TestsWorkspace.scala | 3 +- src/main/scala/vexriscv/ip/DataCache.scala | 122 ++++++++++++------ .../vexriscv/plugin/DBusCachedPlugin.scala | 61 ++++----- 3 files changed, 119 insertions(+), 67 deletions(-) diff --git a/src/main/scala/vexriscv/TestsWorkspace.scala b/src/main/scala/vexriscv/TestsWorkspace.scala index 4d9575ea..04ceda38 100644 --- a/src/main/scala/vexriscv/TestsWorkspace.scala +++ b/src/main/scala/vexriscv/TestsWorkspace.scala @@ -103,7 +103,8 @@ object TestsWorkspace { withLrSc = true, withAmo = true, withExclusive = true, - withInvalidate = true + withInvalidate = true, + pendingMax = 32 // ) ), memoryTranslatorPortConfig = MmuPortConfig( diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index f99acffc..2e33999a 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -27,10 +27,11 @@ case class DataCacheConfig(cacheSize : Int, withAmo : Boolean = false, withExclusive : Boolean = false, withInvalidate : Boolean = false, - pendingMax : Int = 64, + pendingMax : Int = 32, mergeExecuteMemory : Boolean = false){ assert(!(mergeExecuteMemory && (earlyDataMux || earlyWaysHits))) assert(!(earlyDataMux && !earlyWaysHits)) + assert(isPow2(pendingMax)) def withWriteResponse = withExclusive def burstSize = bytePerLine*8/memDataWidth val burstLength = bytePerLine/(memDataWidth/8) @@ -102,10 +103,9 @@ case class DataCacheCpuExecute(p : DataCacheConfig) extends Bundle with IMasterS val address = UInt(p.addressWidth bit) val haltIt = Bool val args = DataCacheCpuExecuteArgs(p) - val totalyConsistent = Bool() override def asMaster(): Unit = { - out(isValid, args, address, totalyConsistent) + out(isValid, args, address) in(haltIt) } } @@ -120,6 +120,8 @@ case class DataCacheCpuExecuteArgs(p : DataCacheConfig) extends Bundle{ val swap = Bool() val alu = Bits(3 bits) } + + val totalyConsistent = Bool() //Only for AMO/LRSC } case class DataCacheCpuMemory(p : DataCacheConfig) extends Bundle with IMasterSlave{ @@ -129,16 +131,31 @@ case class DataCacheCpuMemory(p : DataCacheConfig) extends Bundle with IMasterSl val isWrite = Bool val address = UInt(p.addressWidth bit) val mmuBus = MemoryTranslatorBus() - val fenceValid = Bool() override def asMaster(): Unit = { - out(isValid, isStuck, isRemoved, address, fenceValid) + out(isValid, isStuck, isRemoved, address) in(isWrite) slave(mmuBus) } } +case class FenceFlags() extends Bundle { + val SW,SR,SO,SI,PW,PR,PO,PI = Bool() + val FM = Bits(4 bits) + + def SL = SR || SI + def SS = SW || SO + def PL = PR || PI + def PS = PW || PO + def forceAll(): Unit ={ + List(SW,SR,SO,SI,PW,PR,PO,PI).foreach(_ := True) + } + def clearAll(): Unit ={ + List(SW,SR,SO,SI,PW,PR,PO,PI).foreach(_ := False) + } +} + case class DataCacheCpuWriteBack(p : DataCacheConfig) extends Bundle with IMasterSlave{ val isValid = Bool() val isStuck = Bool() @@ -149,13 +166,10 @@ case class DataCacheCpuWriteBack(p : DataCacheConfig) extends Bundle with IMaste val address = UInt(p.addressWidth bit) val mmuException, unalignedAccess, accessError = Bool() val keepMemRspData = Bool() //Used by external AMO to avoid having an internal buffer - val fenceValid = Bool() - val fenceFire = Bool() - - // val exceptionBus = if(p.catchSomething) Flow(ExceptionCause()) else null + val fence = FenceFlags() override def asMaster(): Unit = { - out(isValid,isStuck,isUser, address, fenceValid, fenceFire) + out(isValid,isStuck,isUser, address, fence) in(haltIt, data, mmuException, unalignedAccess, accessError, isWrite, keepMemRspData) } } @@ -180,6 +194,7 @@ case class DataCacheCpuBus(p : DataCacheConfig) extends Bundle with IMasterSlave case class DataCacheMemCmd(p : DataCacheConfig) extends Bundle{ val wr = Bool + val uncached = Bool val address = UInt(p.addressWidth bit) val data = Bits(p.memDataWidth bits) val mask = Bits(p.memDataWidth/8 bits) @@ -532,21 +547,48 @@ class DataCache(val p : DataCacheConfig) extends Component{ val sync = withInvalidate generate new Area{ io.mem.sync.ready := True - val pendingSync = Reg(UInt(log2Up(pendingMax) + 1 bits)) init(0) - val pendingSyncNext = pendingSync + U(io.mem.cmd.fire && io.mem.cmd.wr) - U(io.mem.sync.fire) - pendingSync := pendingSyncNext + val syncContext = new Area{ + val history = Mem(Bool, pendingMax) + val wPtr, rPtr = Reg(UInt(log2Up(pendingMax)+1 bits)) init(0) + when(io.mem.cmd.fire && io.mem.cmd.wr){ + history.write(wPtr.resized, io.mem.cmd.uncached) + wPtr := wPtr + 1 + } - val full = RegNext(pendingSync.msb) - io.cpu.execute.haltIt setWhen(full) + when(io.mem.sync.fire){ + rPtr := rPtr + 1 + } + val uncached = history.readAsync(rPtr.resized) + val full = RegNext(wPtr - rPtr >= pendingMax-1) + io.cpu.execute.haltIt setWhen(full) + } + def pending(inc : Bool, dec : Bool) = new Area { + val pendingSync = Reg(UInt(log2Up(pendingMax) + 1 bits)) init(0) + val pendingSyncNext = pendingSync + U(io.mem.cmd.fire && io.mem.cmd.wr && inc) - U(io.mem.sync.fire && dec) + pendingSync := pendingSyncNext + } - val incoerentSync = Reg(UInt(log2Up(pendingMax) + 1 bits)) init(0) - incoerentSync := incoerentSync - U(io.mem.sync.fire && incoerentSync =/= 0) - when(io.cpu.writeBack.fenceValid){ incoerentSync := pendingSyncNext } + val writeCached = pending(inc = !io.mem.cmd.uncached, dec = !syncContext.uncached) + val writeUncached = pending(inc = io.mem.cmd.uncached, dec = syncContext.uncached) + def track(load : Bool, uncached : Boolean) = new Area { + val counter = Reg(UInt(log2Up(pendingMax) + 1 bits)) init(0) + counter := counter - U(io.mem.sync.fire && counter =/= 0 && (if(uncached) syncContext.uncached else !syncContext.uncached)) + when(load){ counter := (if(uncached) writeUncached.pendingSyncNext else writeCached.pendingSyncNext) } - val totalyConsistent = pendingSync === 0 - val fenceConsistent = incoerentSync === 0 + val busy = counter =/= 0 + } + + val w2w = track(load = io.cpu.writeBack.fence.PW && io.cpu.writeBack.fence.SW, uncached = false) + val w2r = track(load = io.cpu.writeBack.fence.PW && io.cpu.writeBack.fence.SR, uncached = false) + val w2i = track(load = io.cpu.writeBack.fence.PW && io.cpu.writeBack.fence.SI, uncached = false) + val w2o = track(load = io.cpu.writeBack.fence.PW && io.cpu.writeBack.fence.SO, uncached = false) + val o2w = track(load = io.cpu.writeBack.fence.PO && io.cpu.writeBack.fence.SW, uncached = true) + val o2r = track(load = io.cpu.writeBack.fence.PO && io.cpu.writeBack.fence.SR, uncached = true) + //Assume o2i and o2o are ordered by the interconnect + + val notTotalyConsistent = w2w.busy || w2r.busy || w2i.busy || w2o.busy || o2w.busy || o2r.busy } @@ -562,18 +604,6 @@ class DataCache(val p : DataCacheConfig) extends Component{ val wayInvalidate = B(0, wayCount bits) //Used if invalidate enabled val isAmo = if(withAmo) io.cpu.execute.isAmo else False - - //Ensure write to read consistency - val consistancyIssue = False - val consistancyCheck = (withInvalidate || withWriteResponse) generate new Area { - val fenceConsistent = (if(withInvalidate) sync.fenceConsistent else pending.done) && !io.cpu.writeBack.fenceValid && (if(mergeExecuteMemory) True else !io.cpu.memory.fenceValid) //Pessimistic fence tracking - val totalyConsistent = (if(withInvalidate) sync.totalyConsistent else pending.done) && (if(mergeExecuteMemory) True else !(io.cpu.memory.isValid && io.cpu.memory.isWrite)) && !(io.cpu.writeBack.isValid && io.cpu.memory.isWrite) - when(io.cpu.execute.isValid /*&& (!io.cpu.execute.args.wr || isAmo)*/){ - when(!fenceConsistent || io.cpu.execute.totalyConsistent && !totalyConsistent){ - consistancyIssue := True - } - } - } } val stageA = new Area{ @@ -586,10 +616,29 @@ class DataCache(val p : DataCacheConfig) extends Component{ io.cpu.memory.mmuBus.end := !io.cpu.memory.isStuck || io.cpu.memory.isRemoved io.cpu.memory.isWrite := request.wr + val isAmo = if(withAmo) request.isAmo else False + val isLrsc = if(withAmo) request.isLrsc else False + val consistancyCheck = (withInvalidate || withWriteResponse) generate new Area { + val hazard = False + val w = sync.w2w.busy || sync.o2w.busy + val r = stagePipe(sync.w2r.busy || sync.o2r.busy) || sync.w2r.busy || sync.o2r.busy // As it use the cache, need to check against the execute stage status too + val o = CombInit(sync.w2o.busy) + val i = CombInit(sync.w2i.busy) + + val s = io.cpu.memory.mmuBus.rsp.isIoAccess ? o | w + val l = io.cpu.memory.mmuBus.rsp.isIoAccess ? i | r + + when(isAmo? (s || l) | (request.wr ? s | l)){ + hazard := True + } + when(request.totalyConsistent && (sync.notTotalyConsistent || io.cpu.writeBack.isValid && io.cpu.writeBack.isWrite)){ + hazard := True + } + } + val wayHits = earlyWaysHits generate ways.map(way => (io.cpu.memory.mmuBus.rsp.physicalAddress(tagRange) === way.tagsReadRsp.address && way.tagsReadRsp.valid)) val dataMux = earlyDataMux generate MuxOH(wayHits, ways.map(_.dataReadRsp)) val wayInvalidate = stagePipe(stage0. wayInvalidate) - val consistancyIssue = stagePipe(stage0.consistancyIssue) val dataColisions = if(mergeExecuteMemory){ stagePipe(stage0.dataColisions) } else { @@ -607,7 +656,7 @@ class DataCache(val p : DataCacheConfig) extends Component{ val tagsReadRsp = ways.map(w => ramPipe(w.tagsReadRsp)) val dataReadRsp = !earlyDataMux generate ways.map(w => ramPipe(w.dataReadRsp)) val wayInvalidate = stagePipe(stageA. wayInvalidate) - val consistancyIssue = stagePipe(stageA.consistancyIssue) + val consistancyHazard = if(stageA.consistancyCheck != null) stagePipe(stageA.consistancyCheck.hazard) else False val dataColisions = stagePipe(stageA.dataColisions) val waysHitsBeforeInvalidate = if(earlyWaysHits) stagePipe(B(stageA.wayHits)) else B(tagsReadRsp.map(tag => mmuRsp.physicalAddress(tagRange) === tag.address && tag.valid).asBits()) val waysHits = waysHitsBeforeInvalidate & ~wayInvalidate @@ -718,6 +767,7 @@ class DataCache(val p : DataCacheConfig) extends Component{ io.mem.cmd.wr := request.wr io.mem.cmd.mask := mask io.mem.cmd.data := requestDataBypass + io.mem.cmd.uncached := mmuRsp.isIoAccess if(withExternalLrSc) io.mem.cmd.exclusive := request.isLrsc || isAmo @@ -830,7 +880,7 @@ class DataCache(val p : DataCacheConfig) extends Component{ } //remove side effects on exceptions - when(consistancyIssue || mmuRsp.refilling || io.cpu.writeBack.accessError || io.cpu.writeBack.mmuException || io.cpu.writeBack.unalignedAccess){ + when(consistancyHazard || mmuRsp.refilling || io.cpu.writeBack.accessError || io.cpu.writeBack.mmuException || io.cpu.writeBack.unalignedAccess){ io.mem.cmd.valid := False tagsWriteCmd.valid := False dataWriteCmd.valid := False @@ -839,7 +889,7 @@ class DataCache(val p : DataCacheConfig) extends Component{ if(withInternalLrSc) lrSc.reserved := lrSc.reserved if(withExternalAmo) amo.external.state := LR_CMD } - io.cpu.redo setWhen(io.cpu.writeBack.isValid && (mmuRsp.refilling || consistancyIssue)) + io.cpu.redo setWhen(io.cpu.writeBack.isValid && (mmuRsp.refilling || consistancyHazard)) assert(!(io.cpu.writeBack.isValid && !io.cpu.writeBack.haltIt && io.cpu.writeBack.isStuck), "writeBack stuck by another plugin is not allowed") } diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index 12f38f3e..1d5adbb1 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -50,8 +50,7 @@ class DBusCachedPlugin(val config : DataCacheConfig, object MEMORY_LRSC extends Stageable(Bool) object MEMORY_AMO extends Stageable(Bool) object MEMORY_FENCE extends Stageable(Bool) - object MEMORY_FENCE_FRONT extends Stageable(Bool) - object MEMORY_FENCE_BACK extends Stageable(Bool) + object MEMORY_FORCE_CONSTISTENCY extends Stageable(Bool) object IS_DBUS_SHARING extends Stageable(Bool()) object MEMORY_VIRTUAL_ADDRESS extends Stageable(UInt(32 bits)) @@ -215,31 +214,13 @@ class DBusCachedPlugin(val config : DataCacheConfig, arbitration.haltItself := True } - case class FenceFlags() extends Bundle { - val SW,SR,SO,SI,PW,PR,PO,PI = Bool() - val FM = Bits(4 bits) - - def SL = SR || SI - def SS = SW || SO - def PL = PR || PI - def PS = PW || PO - } //Manage write to read hit ordering (ensure invalidation timings) - val fence = new Area{ - insert(MEMORY_FENCE_FRONT) := False - insert(MEMORY_FENCE_BACK) := False - val ff = input(INSTRUCTION)(31 downto 20).as(FenceFlags()) - if(withWriteResponse){ - insert(MEMORY_FENCE_BACK) setWhen(input(MEMORY_FENCE) && (ff.PS && ff.SL)) - when(input(INSTRUCTION)(26)) { //AQ - if(withLrSc) insert(MEMORY_FENCE_BACK) setWhen(input(MEMORY_LRSC)) - if(withAmo) insert(MEMORY_FENCE_BACK) setWhen(input(MEMORY_AMO)) - } - when(input(INSTRUCTION)(25)) { //RL - if(withLrSc) insert(MEMORY_FENCE_FRONT) setWhen(input(MEMORY_LRSC)) - if(withAmo) insert(MEMORY_FENCE_FRONT) setWhen(input(MEMORY_AMO)) - } + val fence = new Area { + insert(MEMORY_FORCE_CONSTISTENCY) := False + when(input(INSTRUCTION)(25)) { //RL + if (withLrSc) insert(MEMORY_FORCE_CONSTISTENCY) setWhen (input(MEMORY_LRSC)) + if (withAmo) insert(MEMORY_FORCE_CONSTISTENCY) setWhen (input(MEMORY_AMO)) } } } @@ -260,7 +241,7 @@ class DBusCachedPlugin(val config : DataCacheConfig, cache.io.cpu.flush.valid := arbitration.isValid && input(MEMORY_MANAGMENT) - cache.io.cpu.execute.totalyConsistent := arbitration.isValid && input(MEMORY_FENCE_FRONT) + cache.io.cpu.execute.args.totalyConsistent := input(MEMORY_FORCE_CONSTISTENCY) arbitration.haltItself setWhen(cache.io.cpu.flush.isStall || cache.io.cpu.execute.haltIt) if(withLrSc) { @@ -302,8 +283,6 @@ class DBusCachedPlugin(val config : DataCacheConfig, cache.io.cpu.memory.mmuBus <> mmuBus cache.io.cpu.memory.mmuBus.rsp.isIoAccess setWhen(pipeline(DEBUG_BYPASS_CACHE) && !cache.io.cpu.memory.isWrite) - - cache.io.cpu.memory.fenceValid := arbitration.isValid && input(MEMORY_FENCE_BACK) } val managementStage = stages.last @@ -314,8 +293,30 @@ class DBusCachedPlugin(val config : DataCacheConfig, cache.io.cpu.writeBack.isUser := (if(privilegeService != null) privilegeService.isUser() else False) cache.io.cpu.writeBack.address := U(input(REGFILE_WRITE_DATA)) - cache.io.cpu.writeBack.fenceValid := arbitration.isValid && input(MEMORY_FENCE_BACK) - cache.io.cpu.writeBack.fenceFire := arbitration.isFiring && input(MEMORY_FENCE_BACK) + val fence = if(withInvalidate) { + cache.io.cpu.writeBack.fence := input(INSTRUCTION)(31 downto 20).as(FenceFlags()) + val aquire = False + if(withWriteResponse) when(input(INSTRUCTION)(26)) { //AQ + if(withLrSc) when(input(MEMORY_LRSC)){ + aquire := True + } + if(withAmo) when(input(MEMORY_AMO)){ + aquire := True + } + } + + when(aquire){ + cache.io.cpu.writeBack.fence.forceAll() + } + + when(!input(MEMORY_FENCE) || !arbitration.isFiring){ + cache.io.cpu.writeBack.fence.clearAll() + } + + when(arbitration.isValid && (input(MEMORY_FENCE) || aquire)){ + memory.arbitration.haltByOther := True //Ensure that the fence affect the memory stage instruction by stoping it + } + } redoBranch.valid := False redoBranch.payload := input(PC) From f5f30615ba2f37bb8cf0f6f3653783c92446fead Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 1 May 2020 11:14:52 +0200 Subject: [PATCH 411/951] Got litex SMP cluster to work on FPGA --- .../demo/smp/VexRiscvSmpCluster.scala | 17 +- .../demo/smp/VexRiscvSmpLitexCluster.scala | 353 ++++++++++++++---- 2 files changed, 292 insertions(+), 78 deletions(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index 98ab7886..d5c0bcf4 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -249,11 +249,11 @@ object VexRiscvSmpClusterGen { if(hartId == 0) config.plugins += new DebugPlugin(null) config } - def vexRiscvCluster(cpuCount : Int) = VexRiscvSmpCluster( + def vexRiscvCluster(cpuCount : Int, resetVector : Long = 0x80000000l) = VexRiscvSmpCluster( debugClockDomain = ClockDomain.current.copy(reset = Bool().setName("debugResetIn")), p = VexRiscvSmpClusterParameter( cpuConfigs = List.tabulate(cpuCount) { - vexRiscvConfig(_) + vexRiscvConfig(_, resetVector = resetVector) } ) ) @@ -440,7 +440,10 @@ object VexRiscvSmpClusterTestInfrastructure{ import spinal.core.sim._ dut.clockDomain.forkStimulus(10) dut.debugClockDomain.forkStimulus(10) - JtagTcp(dut.io.jtag, 100) +// JtagTcp(dut.io.jtag, 100) + dut.io.jtag.tck #= false + dut.io.jtag.tdi #= false + dut.io.jtag.tms #= false } } @@ -491,11 +494,17 @@ object VexRiscvSmpClusterOpenSbi extends App{ val cpuCount = 4 val withStall = false - simConfig.workspaceName("rawr_4c").compile(VexRiscvSmpClusterGen.vexRiscvCluster(cpuCount)).doSimUntilVoid(seed = 42){dut => + simConfig.workspaceName("rawr_4c").compile(VexRiscvSmpClusterGen.vexRiscvCluster(cpuCount, resetVector = 0x80000000l)).doSimUntilVoid(seed = 42){dut => // dut.clockDomain.forkSimSpeedPrinter(1.0) VexRiscvSmpClusterTestInfrastructure.init(dut) val ram = VexRiscvSmpClusterTestInfrastructure.ram(dut, withStall) // ram.memory.loadBin(0x80000000l, "../opensbi/build/platform/spinal/vexriscv/sim/smp/firmware/fw_payload.bin") + +// ram.memory.loadBin(0x40F00000l, "/media/data/open/litex_smp/litex_vexriscv_smp/images/fw_jump.bin") +// ram.memory.loadBin(0x40000000l, "/media/data/open/litex_smp/litex_vexriscv_smp/images/Image") +// ram.memory.loadBin(0x40EF0000l, "/media/data/open/litex_smp/litex_vexriscv_smp/images/dtb") +// ram.memory.loadBin(0x41000000l, "/media/data/open/litex_smp/litex_vexriscv_smp/images/rootfs.cpio") + ram.memory.loadBin(0x80000000l, "../opensbi/build/platform/spinal/vexriscv/sim/smp/firmware/fw_jump.bin") ram.memory.loadBin(0xC0000000l, "../buildroot/output/images/Image") ram.memory.loadBin(0xC1000000l, "../buildroot/output/images/dtb") diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala index e911e446..170b584d 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala @@ -5,14 +5,19 @@ import spinal.lib.bus.bmb._ import spinal.lib.bus.wishbone.{Wishbone, WishboneConfig, WishboneSlaveFactory} import spinal.lib.com.jtag.Jtag import spinal.lib._ +import spinal.lib.bus.bmb.sim.{BmbMemoryMultiPort, BmbMemoryTester} import spinal.lib.bus.misc.{AddressMapping, DefaultMapping, SizeMapping} import spinal.lib.eda.bench.Bench import spinal.lib.misc.Clint +import spinal.lib.sim.{SimData, SparseMemory, StreamDriver, StreamMonitor, StreamReadyRandomizer} import vexriscv.demo.smp.VexRiscvLitexSmpClusterOpenSbi.{cpuCount, parameter} import vexriscv.demo.smp.VexRiscvSmpClusterGen.vexRiscvConfig import vexriscv.{VexRiscv, VexRiscvConfig} import vexriscv.plugin.{CsrPlugin, DBusCachedPlugin, DebugPlugin, IBusCachedPlugin} +import scala.collection.mutable +import scala.util.Random + case class LiteDramNativeParameter(addressWidth : Int, dataWidth : Int) case class LiteDramNativeCmd(p : LiteDramNativeParameter) extends Bundle{ @@ -39,46 +44,195 @@ case class LiteDramNative(p : LiteDramNativeParameter) extends Bundle with IMast slave(rdata) } - def fromBmb(bmb : Bmb): Unit = new Area{ - val resized = bmb.resize(p.dataWidth) - val unburstified = resized.unburstify() - case class Context() extends Bundle { - val context = Bits(unburstified.p.contextWidth bits) - val source = UInt(unburstified.p.sourceWidth bits) - val isWrite = Bool() - } - val (queueFork, cmdFork, dataFork) = StreamFork3(unburstified.cmd) - cmd.arbitrationFrom(cmdFork) - cmd.addr := (cmdFork.address >> log2Up(bmb.p.byteCount)).resized - cmd.we := cmdFork.isWrite + def fromBmb(bmb : Bmb, wdataFifoSize : Int, rdataFifoSize : Int) = { + val bridge = BmbToLiteDram( + bmbParameter = bmb.p, + liteDramParameter = this.p, + wdataFifoSize = wdataFifoSize, + rdataFifoSize = rdataFifoSize + ) + bridge.io.input << bmb + bridge.io.output <> this + bridge + } - if(bmb.p.canWrite) { - wdata.arbitrationFrom(dataFork.throwWhen(dataFork.isRead)) - wdata.data := cmdFork.data - wdata.we := cmdFork.mask - } else { - dataFork.ready := True - wdata.valid := False - wdata.data.assignDontCare() - wdata.we.assignDontCare() + def simSlave(ram : SparseMemory,cd : ClockDomain, bmb : Bmb = null): Unit ={ + import spinal.core.sim._ + def bus = this + case class Cmd(address : Long, we : Boolean) + case class WData(data : BigInt, we : Long) + val cmdQueue = mutable.Queue[Cmd]() + val wdataQueue = mutable.Queue[WData]() + val rdataQueue = mutable.Queue[BigInt]() + + + case class Ref(address : Long, data : BigInt, we : Long, time : Long) + val ref = mutable.Queue[Ref]() + if(bmb != null) StreamMonitor(bmb.cmd, cd){p => + if(bmb.cmd.opcode.toInt == 1) ref.enqueue(Ref(p.fragment.address.toLong, p.fragment.data.toBigInt, p.fragment.mask.toLong, simTime())) } - val cmdContext = Stream(Context()) - cmdContext.arbitrationFrom(queueFork) - cmdContext.context := unburstified.cmd.context - cmdContext.source := unburstified.cmd.source - cmdContext.isWrite := unburstified.cmd.isWrite + var writeCmdCounter, writeDataCounter = 0 + StreamReadyRandomizer(bus.cmd, cd) + StreamMonitor(bus.cmd, cd) { t => + cmdQueue.enqueue(Cmd(t.addr.toLong * (p.dataWidth/8) , t.we.toBoolean)) + if(t.we.toBoolean) writeCmdCounter += 1 + } - val rspContext = cmdContext.queue(64) + StreamReadyRandomizer(bus.wdata, cd) + StreamMonitor(bus.wdata, cd) { p => + writeDataCounter += 1 +// if(p.data.toBigInt == BigInt("00000002000000020000000200000002",16)){ +// println("ASD") +// } + wdataQueue.enqueue(WData(p.data.toBigInt, p.we.toLong)) + } - rdata.ready := unburstified.rsp.fire && !rspContext.isWrite - rspContext.ready := unburstified.rsp.fire - unburstified.rsp.valid := rspContext.valid && (rspContext.isWrite || rdata.valid) - unburstified.rsp.setSuccess() - unburstified.rsp.last := True - unburstified.rsp.source := rspContext.source - unburstified.rsp.context := rspContext.context - unburstified.rsp.data := rdata.data +// new SimStreamAssert(cmd,cd) +// new SimStreamAssert(wdata,cd) +// new SimStreamAssert(rdata,cd) + + cd.onSamplings{ + if(writeDataCounter-writeCmdCounter > 2){ + println("miaou") + } + if(cmdQueue.nonEmpty && Random.nextFloat() < 0.5){ + val cmd = cmdQueue.head + if(cmd.we){ + if(wdataQueue.nonEmpty){ +// if(cmd.address == 0xc02ae850l) { +// println(s"! $writeCmdCounter $writeDataCounter") +// } + cmdQueue.dequeue() + val wdata = wdataQueue.dequeue() + val raw = wdata.data.toByteArray + val left = wdata.data.toByteArray.size-1 + if(bmb != null){ + assert(ref.nonEmpty) + assert((ref.head.address & 0xFFFFFFF0l) == cmd.address) + assert(ref.head.data == wdata.data) + assert(ref.head.we == wdata.we) + ref.dequeue() + } +// if(cmd.address == 0xc02ae850l) { +// println(s"$cmd $wdata ${simTime()}") +// } + for(i <- 0 until p.dataWidth/8){ + + + if(((wdata.we >> i) & 1) != 0) { +// if(cmd.address == 0xc02ae850l) { +// println(s"W $i ${ if (left - i >= 0) raw(left - i) else 0}") +// } + ram.write(cmd.address + i, if (left - i >= 0) raw(left - i) else 0) + } + } + } + } else { + cmdQueue.dequeue() + val value = new Array[Byte](p.dataWidth/8+1) + val left = value.size-1 + for(i <- 0 until p.dataWidth/8) { + value(left-i) = ram.read(cmd.address+i) + } + rdataQueue.enqueue(BigInt(value)) + } + } + } + + StreamDriver(bus.rdata, cd){ p => + if(rdataQueue.isEmpty){ + false + } else { + p.data #= rdataQueue.dequeue() + true + } + } + } +} + + + +case class BmbToLiteDram(bmbParameter : BmbParameter, + liteDramParameter : LiteDramNativeParameter, + wdataFifoSize : Int, + rdataFifoSize : Int) extends Component{ + val io = new Bundle { + val input = slave(Bmb(bmbParameter)) + val output = master(LiteDramNative(liteDramParameter)) + } + + val resized = io.input.resize(liteDramParameter.dataWidth) + val unburstified = resized.unburstify() + case class Context() extends Bundle { + val context = Bits(unburstified.p.contextWidth bits) + val source = UInt(unburstified.p.sourceWidth bits) + val isWrite = Bool() + } + + assert(isPow2(rdataFifoSize)) + val pendingRead = Reg(UInt(log2Up(rdataFifoSize) + 1 bits)) init(0) + + val halt = Bool() + val (cmdFork, dataFork) = StreamFork2(unburstified.cmd.haltWhen(halt)) + io.output.cmd.arbitrationFrom(cmdFork.haltWhen(pendingRead.msb)) + io.output.cmd.addr := (cmdFork.address >> log2Up(liteDramParameter.dataWidth/8)).resized + io.output.cmd.we := cmdFork.isWrite + + if(bmbParameter.canWrite) { + val fifo = dataFork.throwWhen(dataFork.isRead).queue(wdataFifoSize) + io.output.wdata.arbitrationFrom(fifo) + io.output.wdata.data := fifo.data + io.output.wdata.we := fifo.mask + } else { + dataFork.ready := True + io.output.wdata.valid := False + io.output.wdata.data.assignDontCare() + io.output.wdata.we.assignDontCare() + } + + val cmdContext = Stream(Context()) + cmdContext.valid := unburstified.cmd.fire + cmdContext.context := unburstified.cmd.context + cmdContext.source := unburstified.cmd.source + cmdContext.isWrite := unburstified.cmd.isWrite + halt := !cmdContext.ready + + val rspContext = cmdContext.queue(rdataFifoSize) + val rdataFifo = io.output.rdata.queueLowLatency(rdataFifoSize, latency = 1) + + rdataFifo.ready := unburstified.rsp.fire && !rspContext.isWrite + rspContext.ready := unburstified.rsp.fire + unburstified.rsp.valid := rspContext.valid && (rspContext.isWrite || rdataFifo.valid) + unburstified.rsp.setSuccess() + unburstified.rsp.last := True + unburstified.rsp.source := rspContext.source + unburstified.rsp.context := rspContext.context + unburstified.rsp.data := rdataFifo.data + + + pendingRead := pendingRead + U(io.output.cmd.fire && !io.output.cmd.we) - U(rdataFifo.fire) +} + +object BmbToLiteDramTester extends App{ + import spinal.core.sim._ + SimConfig.withWave.compile(BmbToLiteDram( + bmbParameter = BmbParameter( + addressWidth = 20, + dataWidth = 32, + lengthWidth = 6, + sourceWidth = 4, + contextWidth = 16 + ), + liteDramParameter = LiteDramNativeParameter( + addressWidth = 20, + dataWidth = 128 + ), + wdataFifoSize = 16, + rdataFifoSize = 16 + )).doSimUntilVoid(seed = 42){dut => + val tester = new BmbMemoryTester(dut.io.input, dut.clockDomain, rspCounterTarget = 3000) + dut.io.output.simSlave(tester.memory.memory, dut.clockDomain) } } @@ -120,15 +274,21 @@ case class VexRiscvLitexSmpCluster(p : VexRiscvLitexSmpClusterParameter, cluster.io.timerInterrupts <> B(clint.harts.map(_.timerInterrupt)) cluster.io.softwareInterrupts <> B(clint.harts.map(_.softwareInterrupt)) - - val dBusDecoder = BmbDecoderOutOfOrder( + //TODO +// val dBusDecoder = BmbDecoderOutOfOrder( +// p = cluster.io.dMem.p, +// mappings = Seq(DefaultMapping, p.liteDramMapping), +// capabilities = Seq(cluster.io.dMem.p, cluster.io.dMem.p), +// pendingRspTransactionMax = 32 +// ) + val dBusDecoder = BmbDecoder( p = cluster.io.dMem.p, mappings = Seq(DefaultMapping, p.liteDramMapping), capabilities = Seq(cluster.io.dMem.p, cluster.io.dMem.p), - pendingRspTransactionMax = 32 + pendingMax = 31 ) dBusDecoder.io.input << cluster.io.dMem.pipelined(cmdValid = true, cmdReady = true, rspValid = true) - io.dMem.fromBmb(dBusDecoder.io.outputs(1)) + val dMemBridge = io.dMem.fromBmb(dBusDecoder.io.outputs(1), wdataFifoSize = 32, rdataFifoSize = 32) val iBusArbiterParameter = cluster.iBusParameter.copy(sourceWidth = log2Up(cpuCount)) val iBusArbiter = BmbArbiter( @@ -146,7 +306,7 @@ case class VexRiscvLitexSmpCluster(p : VexRiscvLitexSmpClusterParameter, pendingMax = 15 ) iBusDecoder.io.input << iBusArbiter.io.output - io.iMem.fromBmb(iBusDecoder.io.outputs(1)) + val iMemBridge = io.iMem.fromBmb(iBusDecoder.io.outputs(1), wdataFifoSize = 0, rdataFifoSize = 32) val peripheralAccessLength = Math.max(iBusDecoder.io.outputs(0).p.lengthWidth, dBusDecoder.io.outputs(0).p.lengthWidth) val peripheralArbiter = BmbArbiter( @@ -160,6 +320,7 @@ case class VexRiscvLitexSmpCluster(p : VexRiscvLitexSmpClusterParameter, val peripheralWishbone = peripheralArbiter.io.output.toWishbone() io.peripheral << peripheralWishbone } + object VexRiscvLitexSmpClusterGen extends App { val cpuCount = 4 val withStall = false @@ -183,7 +344,8 @@ object VexRiscvLitexSmpClusterGen extends App { debugClockDomain = ClockDomain.current.copy(reset = Bool().setName("debugResetIn")) ) - SpinalVerilog(Bench.compressIo(dutGen)) +// SpinalVerilog(Bench.compressIo(dutGen)) + SpinalVerilog(dutGen) } @@ -194,7 +356,6 @@ object VexRiscvLitexSmpClusterOpenSbi extends App{ val simConfig = SimConfig simConfig.withWave simConfig.allOptimisation - simConfig.addSimulatorFlag("--threads 1") val cpuCount = 4 val withStall = false @@ -204,46 +365,90 @@ object VexRiscvLitexSmpClusterOpenSbi extends App{ cpuConfigs = List.tabulate(cpuCount) { hartId => vexRiscvConfig( hartId = hartId, - ioRange = address => address.msb, - resetVector = 0 + ioRange = address => address(31 downto 28) === 0xF, + resetVector = 0x80000000l ) } ), liteDram = LiteDramNativeParameter(addressWidth = 32, dataWidth = 128), - liteDramMapping = SizeMapping(0x40000000l, 0x40000000l) + liteDramMapping = SizeMapping(0x80000000l, 0x70000000l) ) - def dutGen = VexRiscvLitexSmpCluster( - p = parameter, - debugClockDomain = ClockDomain.current.copy(reset = Bool().setName("debugResetIn")) - ) + def dutGen = { + val top = VexRiscvLitexSmpCluster( + p = parameter, + debugClockDomain = ClockDomain.current.copy(reset = Bool().setName("debugResetIn")) + ) + top.rework{ + top.io.clint.setAsDirectionLess.allowDirectionLessIo + top.io.peripheral.setAsDirectionLess.allowDirectionLessIo.simPublic() + + val hit = (top.io.peripheral.ADR <<2 >= 0xF0010000l && top.io.peripheral.ADR<<2 < 0xF0020000l) + top.io.clint.CYC := top.io.peripheral.CYC && hit + top.io.clint.STB := top.io.peripheral.STB + top.io.clint.WE := top.io.peripheral.WE + top.io.clint.ADR := top.io.peripheral.ADR.resized + top.io.clint.DAT_MOSI := top.io.peripheral.DAT_MOSI + top.io.peripheral.DAT_MISO := top.io.clint.DAT_MISO + top.io.peripheral.ACK := top.io.peripheral.CYC && (!hit || top.io.clint.ACK) + top.io.peripheral.ERR := False + + top.dMemBridge.unburstified.cmd.simPublic() + } + top + } simConfig.compile(dutGen).doSimUntilVoid(seed = 42){dut => - // dut.clockDomain.forkSimSpeedPrinter(1.0) -// VexRiscvSmpClusterTestInfrastructure.init(dut) -// val ram = VexRiscvSmpClusterTestInfrastructure.ram(dut, withStall) - // ram.memory.loadBin(0x80000000l, "../opensbi/build/platform/spinal/vexriscv/sim/smp/firmware/fw_payload.bin") -// ram.memory.loadBin(0x80000000l, "../opensbi/build/platform/spinal/vexriscv/sim/smp/firmware/fw_jump.bin") -// ram.memory.loadBin(0xC0000000l, "../buildroot/output/images/Image") -// ram.memory.loadBin(0xC1000000l, "../buildroot/output/images/dtb") -// ram.memory.loadBin(0xC2000000l, "../buildroot/output/images/rootfs.cpio") + dut.clockDomain.forkStimulus(10) + fork { + dut.debugClockDomain.resetSim #= false + sleep (0) + dut.debugClockDomain.resetSim #= true + sleep (10) + dut.debugClockDomain.resetSim #= false + } - // fork{ - // disableSimWave() - // val atMs = 130 - // val durationMs = 15 - // sleep(atMs*1000000) - // enableSimWave() - // println("** enableSimWave **") - // sleep(durationMs*1000000) - // println("** disableSimWave **") - // while(true) { - // disableSimWave() - // sleep(100000 * 10) - // enableSimWave() - // sleep( 100 * 10) - // } - //// simSuccess() - // } + + val ram = SparseMemory() + ram.loadBin(0x80000000l, "../opensbi/build/platform/spinal/vexriscv/sim/smp/firmware/fw_jump.bin") + ram.loadBin(0xC0000000l, "../buildroot/output/images/Image") + ram.loadBin(0xC1000000l, "../buildroot/output/images/dtb") + ram.loadBin(0xC2000000l, "../buildroot/output/images/rootfs.cpio") + + + dut.io.iMem.simSlave(ram, dut.clockDomain) + dut.io.dMem.simSlave(ram, dut.clockDomain, dut.dMemBridge.unburstified) + + dut.io.externalInterrupts #= 0 + dut.io.externalSupervisorInterrupts #= 0 + + dut.clockDomain.onSamplings{ + if(dut.io.peripheral.CYC.toBoolean){ + (dut.io.peripheral.ADR.toLong << 2) match { + case 0xF0000000l => print(dut.io.peripheral.DAT_MOSI.toLong.toChar) + case 0xF0000004l => dut.io.peripheral.DAT_MISO #= (if(System.in.available() != 0) System.in.read() else 0xFFFFFFFFl) + case _ => + } +// println(f"${dut.io.peripheral.ADR.toLong}%x") + } + } + +// fork{ +// disableSimWave() +// val atMs = 8 +// val durationMs = 3 +// sleep(atMs*1000000) +// enableSimWave() +// println("** enableSimWave **") +// sleep(durationMs*1000000) +// println("** disableSimWave **") +// while(true) { +// disableSimWave() +// sleep(100000 * 10) +// enableSimWave() +// sleep( 100 * 10) +// } +// // simSuccess() +// } fork{ while(true) { From 09ac23b78f708c752017ab4ca59e001234c513e2 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 1 May 2020 12:45:16 +0200 Subject: [PATCH 412/951] Fix SMP fence lock when 4 stages CPU --- src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index 1d5adbb1..17c429c0 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -314,7 +314,7 @@ class DBusCachedPlugin(val config : DataCacheConfig, } when(arbitration.isValid && (input(MEMORY_FENCE) || aquire)){ - memory.arbitration.haltByOther := True //Ensure that the fence affect the memory stage instruction by stoping it + mmuAndBufferStage.arbitration.haltByOther := True //Ensure that the fence affect the memory stage instruction by stoping it } } From f0745eb0d9b3c1854227a6b58a130f77e7644761 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sat, 2 May 2020 23:44:27 +0200 Subject: [PATCH 413/951] update SMP line size to 64 bytes --- src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index d5c0bcf4..92e3976c 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -178,7 +178,7 @@ object VexRiscvSmpClusterGen { relaxedMemoryTranslationRegister = true, config = new DataCacheConfig( cacheSize = 4096*1, - bytePerLine = 32, + bytePerLine = 64, wayCount = 1, addressWidth = 32, cpuDataWidth = 32, From 93b386e16ee6b31b4247979ead63e5a0dc82cbc1 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sat, 2 May 2020 23:44:58 +0200 Subject: [PATCH 414/951] litex smp cluster now use OO decoder --- .../demo/smp/VexRiscvSmpLitexCluster.scala | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala index 170b584d..c2c287ad 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala @@ -274,19 +274,18 @@ case class VexRiscvLitexSmpCluster(p : VexRiscvLitexSmpClusterParameter, cluster.io.timerInterrupts <> B(clint.harts.map(_.timerInterrupt)) cluster.io.softwareInterrupts <> B(clint.harts.map(_.softwareInterrupt)) - //TODO -// val dBusDecoder = BmbDecoderOutOfOrder( -// p = cluster.io.dMem.p, -// mappings = Seq(DefaultMapping, p.liteDramMapping), -// capabilities = Seq(cluster.io.dMem.p, cluster.io.dMem.p), -// pendingRspTransactionMax = 32 -// ) - val dBusDecoder = BmbDecoder( + val dBusDecoder = BmbDecoderOutOfOrder( p = cluster.io.dMem.p, mappings = Seq(DefaultMapping, p.liteDramMapping), capabilities = Seq(cluster.io.dMem.p, cluster.io.dMem.p), - pendingMax = 31 + pendingRspTransactionMax = 32 ) +// val dBusDecoder = BmbDecoderOut( +// p = cluster.io.dMem.p, +// mappings = Seq(DefaultMapping, p.liteDramMapping), +// capabilities = Seq(cluster.io.dMem.p, cluster.io.dMem.p), +// pendingMax = 31 +// ) dBusDecoder.io.input << cluster.io.dMem.pipelined(cmdValid = true, cmdReady = true, rspValid = true) val dMemBridge = io.dMem.fromBmb(dBusDecoder.io.outputs(1), wdataFifoSize = 32, rdataFifoSize = 32) From b0f7f37ac8b3ca9221e1d176b8d1d893b3cbd9f3 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 4 May 2020 12:54:16 +0200 Subject: [PATCH 415/951] D$ now support memDataWidth > 32 --- src/main/scala/vexriscv/TestsWorkspace.scala | 8 +-- src/main/scala/vexriscv/ip/DataCache.scala | 60 +++++++++++-------- src/test/cpp/regression/main.cpp | 45 +++++++++++--- src/test/cpp/regression/makefile | 2 + .../vexriscv/TestIndividualFeatures.scala | 49 ++++++++------- 5 files changed, 104 insertions(+), 60 deletions(-) diff --git a/src/main/scala/vexriscv/TestsWorkspace.scala b/src/main/scala/vexriscv/TestsWorkspace.scala index 04ceda38..40f8b33c 100644 --- a/src/main/scala/vexriscv/TestsWorkspace.scala +++ b/src/main/scala/vexriscv/TestsWorkspace.scala @@ -27,7 +27,7 @@ import spinal.lib.bus.avalon.AvalonMM import spinal.lib.eda.altera.{InterruptReceiverTag, ResetEmitterTag} -//make clean all SEED=42 MMU=no STOP_ON_ERROR=yes DBUS_EXCLUSIVE=yes DBUS_INVALIDATE=yes SUPERVISOR=yes REDO=0 DHRYSTONE=no LRSC=yes AMO=yes LINUX_REGRESSION=yes TRACE=yes TRACE_START=9546629800l FLOW_INFO=ye +// make clean all SEED=42 MMU=no STOP_ON_ERROR=yes DBUS_EXCLUSIVE=yes DBUS_INVALIDATE=yes SUPERVISOR=yes REDO=1 DHRYSTONE=yes LRSC=yes AMO=yes LINUX_REGRESSION=yes TRACE=yes TRACE_START=1000000000 FLOW_INFO=ye IBUS_DATA_WIDTH=128 DBUS_DATA_WIDTH=128 object TestsWorkspace { def main(args: Array[String]) { def configFull = { @@ -60,7 +60,7 @@ object TestsWorkspace { injectorStage = false, config = InstructionCacheConfig( cacheSize = 4096*1, - bytePerLine = 32, + bytePerLine = 64, wayCount = 1, addressWidth = 32, cpuDataWidth = 32, @@ -92,11 +92,11 @@ object TestsWorkspace { dBusRspSlavePipe = true, config = new DataCacheConfig( cacheSize = 4096*1, - bytePerLine = 32, + bytePerLine = 64, wayCount = 1, addressWidth = 32, cpuDataWidth = 32, - memDataWidth = 32, + memDataWidth = 128, catchAccessError = true, catchIllegal = true, catchUnaligned = true, diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index 2e33999a..9de6f090 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -34,7 +34,7 @@ case class DataCacheConfig(cacheSize : Int, assert(isPow2(pendingMax)) def withWriteResponse = withExclusive def burstSize = bytePerLine*8/memDataWidth - val burstLength = bytePerLine/(memDataWidth/8) + val burstLength = bytePerLine/(cpuDataWidth/8) def catchSomething = catchUnaligned || catchIllegal || catchAccessError def withInternalAmo = withAmo && !withExclusive def withInternalLrSc = withLrSc && !withExclusive @@ -196,8 +196,8 @@ case class DataCacheMemCmd(p : DataCacheConfig) extends Bundle{ val wr = Bool val uncached = Bool val address = UInt(p.addressWidth bit) - val data = Bits(p.memDataWidth bits) - val mask = Bits(p.memDataWidth/8 bits) + val data = Bits(p.cpuDataWidth bits) + val mask = Bits(p.cpuDataWidth/8 bits) val length = UInt(log2Up(p.burstLength) bits) val exclusive = p.withExclusive generate Bool() val last = Bool @@ -424,7 +424,6 @@ object DataCacheExternalAmoStates extends SpinalEnum{ //If external amo, mem rsp should stay class DataCache(val p : DataCacheConfig) extends Component{ import p._ - assert(cpuDataWidth == memDataWidth) val io = new Bundle{ val cpu = slave(DataCacheCpuBus(p)) @@ -434,19 +433,24 @@ class DataCache(val p : DataCacheConfig) extends Component{ val haltCpu = False val lineWidth = bytePerLine*8 val lineCount = cacheSize/bytePerLine - val wordWidth = Math.max(memDataWidth,cpuDataWidth) + val wordWidth = cpuDataWidth val wordWidthLog2 = log2Up(wordWidth) val wordPerLine = lineWidth/wordWidth val bytePerWord = wordWidth/8 val wayLineCount = lineCount/wayCount val wayLineLog2 = log2Up(wayLineCount) val wayWordCount = wayLineCount * wordPerLine + val memWordPerLine = lineWidth/memDataWidth val memTransactionPerLine = p.bytePerLine / (p.memDataWidth/8) + val bytePerMemWord = memDataWidth/8 + val wayMemWordCount = wayLineCount * memWordPerLine 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 cpuWordRange = log2Up(bytePerLine)-1 downto log2Up(bytePerWord) + val memWordRange = log2Up(bytePerLine)-1 downto log2Up(bytePerMemWord) val hitRange = tagRange.high downto lineRange.low + val memWordToCpuWordRange = log2Up(bytePerMemWord)-1 downto log2Up(bytePerWord) class LineInfo() extends Bundle{ @@ -464,23 +468,24 @@ class DataCache(val p : DataCacheConfig) extends Component{ val tagsWriteLastCmd = RegNext(tagsWriteCmd) - val dataReadCmd = Flow(UInt(log2Up(wayWordCount) bits)) + val dataReadCmd = Flow(UInt(log2Up(wayMemWordCount) bits)) val dataWriteCmd = Flow(new Bundle{ val way = Bits(wayCount bits) - val address = UInt(log2Up(wayWordCount) bits) - val data = Bits(wordWidth bits) - val mask = Bits(wordWidth/8 bits) + val address = UInt(log2Up(wayMemWordCount) bits) + val data = Bits(memDataWidth bits) + val mask = Bits(memDataWidth/8 bits) }) - val ways = for(i <- 0 until wayCount) yield new Area{ val tags = Mem(new LineInfo(), wayLineCount) - val data = Mem(Bits(wordWidth bit), wayWordCount) + val data = Mem(Bits(memDataWidth bit), wayMemWordCount) //Reads val tagsReadRsp = tags.readSync(tagsReadCmd.payload, tagsReadCmd.valid && !io.cpu.memory.isStuck) - val dataReadRsp = data.readSync(dataReadCmd.payload, dataReadCmd.valid && !io.cpu.memory.isStuck) + val dataReadRspMem = data.readSync(dataReadCmd.payload, dataReadCmd.valid && !io.cpu.memory.isStuck) + val dataReadRspSel = if(mergeExecuteMemory) io.cpu.writeBack.address else io.cpu.memory.address + val dataReadRsp = dataReadRspMem.subdivideIn(cpuDataWidth bits).read(dataReadRspSel(memWordToCpuWordRange)) val tagsInvReadRsp = withInvalidate generate tags.readSync(tagsInvReadCmd.payload, tagsInvReadCmd.valid) @@ -511,13 +516,15 @@ class DataCache(val p : DataCacheConfig) extends Component{ tagsReadCmd.valid := True dataReadCmd.valid := True tagsReadCmd.payload := io.cpu.execute.address(lineRange) - dataReadCmd.payload := io.cpu.execute.address(lineRange.high downto wordRange.low) + dataReadCmd.payload := io.cpu.execute.address(lineRange.high downto memWordRange.low) } def collisionProcess(readAddress : UInt, readMask : Bits): Bits ={ val ret = Bits(wayCount bits) + val readAddressAligned = (readAddress >> log2Up(memDataWidth/cpuDataWidth)) + val dataWriteMaskAligned = dataWriteCmd.mask.subdivideIn(memDataWidth/cpuDataWidth slices).read(readAddress(log2Up(memDataWidth/cpuDataWidth)-1 downto 0)) for(i <- 0 until wayCount){ - ret(i) := dataWriteCmd.valid && dataWriteCmd.way(i) && dataWriteCmd.address === readAddress && (readMask & dataWriteCmd.mask) =/= 0 + ret(i) := dataWriteCmd.valid && dataWriteCmd.way(i) && dataWriteCmd.address === readAddressAligned && (readMask & dataWriteMaskAligned) =/= 0 } ret } @@ -600,7 +607,7 @@ class DataCache(val p : DataCacheConfig) extends Component{ U(1) -> B"0011", default -> B"1111" ) |<< io.cpu.execute.address(1 downto 0) - val dataColisions = collisionProcess(io.cpu.execute.address(lineRange.high downto wordRange.low), mask) + val dataColisions = collisionProcess(io.cpu.execute.address(lineRange.high downto cpuWordRange.low), mask) val wayInvalidate = B(0, wayCount bits) //Used if invalidate enabled val isAmo = if(withAmo) io.cpu.execute.isAmo else False @@ -643,7 +650,7 @@ class DataCache(val p : DataCacheConfig) extends Component{ stagePipe(stage0.dataColisions) } else { //Assume the writeback stage will never be unstall memory acces while memory stage is stalled - stagePipe(stage0.dataColisions) | collisionProcess(io.cpu.memory.address(lineRange.high downto wordRange.low), mask) + stagePipe(stage0.dataColisions) | collisionProcess(io.cpu.memory.address(lineRange.high downto cpuWordRange.low), mask) } } @@ -667,7 +674,7 @@ class DataCache(val p : DataCacheConfig) extends Component{ //Loader interface val loaderValid = False - + val ioMemRspMuxed = io.mem.rsp.data.subdivideIn(cpuDataWidth bits).read(io.cpu.writeBack.address(memWordToCpuWordRange)) io.cpu.writeBack.haltIt := io.cpu.writeBack.isValid @@ -717,7 +724,7 @@ class DataCache(val p : DataCacheConfig) extends Component{ import DataCacheExternalAmoStates._ val amo = withAmo generate new Area{ def rf = request.data - def mem = if(withInternalAmo) dataMux else io.mem.rsp.data + def mem = if(withInternalAmo) dataMux else ioMemRspMuxed val compare = request.amoCtrl.alu.msb val unsigned = request.amoCtrl.alu(2 downto 1) === B"11" val addSub = (rf.asSInt + Mux(compare, ~mem, mem).asSInt + Mux(compare, S(1), S(0))).asBits @@ -748,9 +755,10 @@ class DataCache(val p : DataCacheConfig) extends Component{ val cpuWriteToCache = False when(cpuWriteToCache){ dataWriteCmd.valid setWhen(request.wr && waysHit) - dataWriteCmd.address := mmuRsp.physicalAddress(lineRange.high downto wordRange.low) - dataWriteCmd.data := requestDataBypass - dataWriteCmd.mask := mask + dataWriteCmd.address := mmuRsp.physicalAddress(lineRange.high downto memWordRange.low) + dataWriteCmd.data.subdivideIn(cpuDataWidth bits).foreach(_ := requestDataBypass) + dataWriteCmd.mask := 0 + dataWriteCmd.mask.subdivideIn(cpuDataWidth/8 bits).write(io.cpu.writeBack.address(memWordToCpuWordRange), mask) dataWriteCmd.way := waysHits } @@ -761,7 +769,7 @@ class DataCache(val p : DataCacheConfig) extends Component{ io.cpu.writeBack.isWrite := request.wr io.mem.cmd.valid := False - io.mem.cmd.address := mmuRsp.physicalAddress(tagRange.high downto wordRange.low) @@ U(0, wordRange.low bit) + io.mem.cmd.address := mmuRsp.physicalAddress(tagRange.high downto cpuWordRange.low) @@ U(0, cpuWordRange.low bits) io.mem.cmd.length := 0 io.mem.cmd.last := True io.mem.cmd.wr := request.wr @@ -825,7 +833,7 @@ class DataCache(val p : DataCacheConfig) extends Component{ //Write through io.mem.cmd.valid setWhen(request.wr) - io.mem.cmd.address := mmuRsp.physicalAddress(tagRange.high downto wordRange.low) @@ U(0, wordRange.low bit) + io.mem.cmd.address := mmuRsp.physicalAddress(tagRange.high downto cpuWordRange.low) @@ U(0, cpuWordRange.low bits) io.mem.cmd.length := 0 io.cpu.writeBack.haltIt clearWhen(!request.wr || io.mem.cmd.ready) @@ -861,10 +869,10 @@ class DataCache(val p : DataCacheConfig) extends Component{ } when(bypassCache){ - io.cpu.writeBack.data := io.mem.rsp.data + io.cpu.writeBack.data := ioMemRspMuxed if(catchAccessError) io.cpu.writeBack.accessError := io.mem.rsp.valid && io.mem.rsp.error } otherwise { - io.cpu.writeBack.data := dataMux + io.cpu.writeBack.data := dataMux if(catchAccessError) io.cpu.writeBack.accessError := (waysHits & B(tagsReadRsp.map(_.error))) =/= 0 } diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 5fa9635a..e0f50aba 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -2028,7 +2028,7 @@ public: #endif error = false; for(int idx = 0;idx < IBUS_DATA_WIDTH/32;idx++){ - bool localError; + bool localError = false; ws->iBusAccess(address+idx*4,((uint32_t*)&top->iBus_rsp_payload_data)+idx,&localError); error |= localError; } @@ -2342,7 +2342,7 @@ public: #include struct DBusCachedTask{ - uint32_t data; + char data[DBUS_DATA_WIDTH/8]; bool error; bool last; bool exclusive; @@ -2386,21 +2386,43 @@ public: bool error; ws->dBusAccess(top->dBus_cmd_payload_address,1,2,top->dBus_cmd_payload_mask,&top->dBus_cmd_payload_data,&error); #else - bool cancel = false; + bool cancel = false, error = false; if(top->dBus_cmd_payload_exclusive){ bool hit = reservationValid && reservationAddress == top->dBus_cmd_payload_address; rsp.exclusive = hit; cancel = !hit; reservationValid = false; } - if(!cancel) ws->dBusAccess(top->dBus_cmd_payload_address,1,2,top->dBus_cmd_payload_mask,&top->dBus_cmd_payload_data,&rsp.error); + if(!cancel) { + for(int idx = 0;idx < 1;idx++){ + bool localError = false; + ws->dBusAccess(top->dBus_cmd_payload_address+idx*4,1,2,top->dBus_cmd_payload_mask >> idx*4,((uint32_t*)&top->dBus_cmd_payload_data)+idx, &localError); + error |= localError; + + //printf("%d ", (int)localError); + } + } + + // printf("%x %d\n", top->dBus_cmd_payload_address, (int)error); rsp.last = true; + rsp.error = error; rsps.push(rsp); #endif } else { - for(int beat = 0;beat <= top->dBus_cmd_payload_length;beat++){ - ws->dBusAccess(top->dBus_cmd_payload_address + beat * 4,0,2,0,&rsp.data,&rsp.error); - rsp.last = beat == top->dBus_cmd_payload_length; + bool error = false; + uint32_t beatCount = top->dBus_cmd_payload_length*32/DBUS_DATA_WIDTH; + for(int beat = 0;beat <= beatCount;beat++){ + if(top->dBus_cmd_payload_length == 0){ + uint32_t sel = (top->dBus_cmd_payload_address >> 2) & (DBUS_DATA_WIDTH/32-1); + ws->dBusAccess(top->dBus_cmd_payload_address,0,2,0,((uint32_t*)rsp.data) + sel,&error); + } else { + for(int idx = 0;idx < DBUS_DATA_WIDTH/32;idx++){ + bool localError = false; + ws->dBusAccess(top->dBus_cmd_payload_address + beat * DBUS_DATA_WIDTH/8 + idx*4,0,2,0,((uint32_t*)rsp.data)+idx, &localError); + error |= localError; + } + } + rsp.last = beat == beatCount; #ifdef DBUS_EXCLUSIVE if(top->dBus_cmd_payload_exclusive){ rsp.exclusive = true; @@ -2408,6 +2430,7 @@ public: reservationAddress = top->dBus_cmd_payload_address; } #endif + rsp.error = error; rsps.push(rsp); } @@ -2434,14 +2457,18 @@ public: rsps.pop(); top->dBus_rsp_valid = 1; top->dBus_rsp_payload_error = rsp.error; - top->dBus_rsp_payload_data = rsp.data; + for(int idx = 0;idx < DBUS_DATA_WIDTH/32;idx++){ + ((uint32_t*)&top->dBus_rsp_payload_data)[idx] = ((uint32_t*)rsp.data)[idx]; + } top->dBus_rsp_payload_last = rsp.last; #ifdef DBUS_EXCLUSIVE top->dBus_rsp_payload_exclusive = rsp.exclusive; #endif } else{ top->dBus_rsp_valid = 0; - top->dBus_rsp_payload_data = VL_RANDOM_I(32); + for(int idx = 0;idx < DBUS_DATA_WIDTH/32;idx++){ + ((uint32_t*)&top->dBus_rsp_payload_data)[idx] = VL_RANDOM_I(32); + } top->dBus_rsp_payload_error = VL_RANDOM_I(1); top->dBus_rsp_payload_last = VL_RANDOM_I(1); #ifdef DBUS_EXCLUSIVE diff --git a/src/test/cpp/regression/makefile b/src/test/cpp/regression/makefile index 98363266..da525c59 100644 --- a/src/test/cpp/regression/makefile +++ b/src/test/cpp/regression/makefile @@ -5,6 +5,7 @@ IBUS?=CACHED IBUS_TC?=no IBUS_DATA_WIDTH?=32 DBUS?=CACHED +DBUS_DATA_WIDTH?=32 TRACE?=no TRACE_ACCESS?=no TRACE_START=0 @@ -46,6 +47,7 @@ WITH_USER_IO?=no ADDCFLAGS += -CFLAGS -DREGRESSION_PATH='\"$(REGRESSION_PATH)/\"' ADDCFLAGS += -CFLAGS -DIBUS_${IBUS} ADDCFLAGS += -CFLAGS -DIBUS_DATA_WIDTH=${IBUS_DATA_WIDTH} +ADDCFLAGS += -CFLAGS -DDBUS_DATA_WIDTH=${DBUS_DATA_WIDTH} ADDCFLAGS += -CFLAGS -DDBUS_${DBUS} ADDCFLAGS += -CFLAGS -DREDO=${REDO} diff --git a/src/test/scala/vexriscv/TestIndividualFeatures.scala b/src/test/scala/vexriscv/TestIndividualFeatures.scala index 72651b44..8a7ace11 100644 --- a/src/test/scala/vexriscv/TestIndividualFeatures.scala +++ b/src/test/scala/vexriscv/TestIndividualFeatures.scala @@ -1,7 +1,7 @@ package vexriscv import java.io.{File, OutputStream} -import java.util.concurrent.TimeUnit +import java.util.concurrent.{ForkJoinPool, TimeUnit} import org.apache.commons.io.FileUtils import org.scalatest.{BeforeAndAfterAll, FunSuite, ParallelTestExecution, Tag, Transformer} @@ -426,7 +426,8 @@ class DBusDimension extends VexRiscvDimension("DBus") { // override def isCompatibleWith(positions: Seq[ConfigPosition[VexRiscvConfig]]) = catchAll == positions.exists(_.isInstanceOf[CatchAllPosition]) } } else { - val bytePerLine = List(8,16,32,64)(r.nextInt(4)) + val memDataWidth = List(32,64,128)(r.nextInt(3)) + val bytePerLine = Math.max(memDataWidth/8, List(8,16,32,64)(r.nextInt(4))) var cacheSize = 0 var wayCount = 0 val withLrSc = catchAll @@ -441,8 +442,8 @@ class DBusDimension extends VexRiscvDimension("DBus") { cacheSize = 512 << r.nextInt(5) wayCount = 1 << r.nextInt(3) }while(cacheSize/wayCount < 512 || (catchAll && cacheSize/wayCount > 4096)) - new VexRiscvPosition("Cached" + "S" + cacheSize + "W" + wayCount + "BPL" + bytePerLine + (if(dBusCmdMasterPipe) "Cmp " else "") + (if(dBusCmdSlavePipe) "Csp " else "") + (if(dBusRspSlavePipe) "Rsp " else "") + (if(relaxedMemoryTranslationRegister) "Rmtr " else "") + (if(earlyWaysHits) "Ewh " else "") + (if(withAmo) "Amo " else "") + (if(withSmp) "Smp " else "")) { - override def testParam = "DBUS=CACHED " + (if(withLrSc) "LRSC=yes " else "") + (if(withAmo) "AMO=yes " else "") + (if(withSmp) "DBUS_EXCLUSIVE=yes DBUS_INVALIDATE=yes " else "") + new VexRiscvPosition(s"Cached${memDataWidth}d" + "S" + cacheSize + "W" + wayCount + "BPL" + bytePerLine + (if(dBusCmdMasterPipe) "Cmp " else "") + (if(dBusCmdSlavePipe) "Csp " else "") + (if(dBusRspSlavePipe) "Rsp " else "") + (if(relaxedMemoryTranslationRegister) "Rmtr " else "") + (if(earlyWaysHits) "Ewh " else "") + (if(withAmo) "Amo " else "") + (if(withSmp) "Smp " else "")) { + override def testParam = s"DBUS=CACHED DBUS_DATA_WIDTH=$memDataWidth " + (if(withLrSc) "LRSC=yes " else "") + (if(withAmo) "AMO=yes " else "") + (if(withSmp) "DBUS_EXCLUSIVE=yes DBUS_INVALIDATE=yes " else "") override def applyOn(config: VexRiscvConfig): Unit = { config.plugins += new DBusCachedPlugin( @@ -452,7 +453,7 @@ class DBusDimension extends VexRiscvDimension("DBus") { wayCount = wayCount, addressWidth = 32, cpuDataWidth = 32, - memDataWidth = 32, + memDataWidth = memDataWidth, catchAccessError = catchAll, catchIllegal = catchAll, catchUnaligned = catchAll, @@ -574,8 +575,14 @@ object PlayFuture extends App{ Thread.sleep(8000) } -class MultithreadedFunSuite extends FunSuite { - implicit val ec = ExecutionContext.global +class MultithreadedFunSuite(threadCount : Int) extends FunSuite { + val finalThreadCount = if(threadCount > 0) threadCount else { + val systemInfo = new oshi.SystemInfo + systemInfo.getHardware.getProcessor.getLogicalProcessorCount + } + implicit val ec = ExecutionContext.fromExecutorService( + new ForkJoinPool(finalThreadCount, ForkJoinPool.defaultForkJoinWorkerThreadFactory, null, true) + ) class Job(body : => Unit){ val originalOutput = Console.out val buffer = mutable.Queue[Char]() @@ -612,7 +619,7 @@ class MultithreadedFunSuite extends FunSuite { } -class FunTestPara extends MultithreadedFunSuite{ +class FunTestPara extends MultithreadedFunSuite(3){ def createTest(name : String): Unit ={ test(name){ for(i <- 0 to 4) { @@ -624,20 +631,20 @@ class FunTestPara extends MultithreadedFunSuite{ (0 to 80).map(_.toString).foreach(createTest) } -class FunTestPlay extends FunSuite { - def createTest(name : String): Unit ={ - test(name){ - Thread.sleep(500) - for(i <- 0 to 4) { - println(s"$name $i") - Thread.sleep(500) - } - } - } - (0 to 80).map(_.toString).foreach(createTest) -} +//class FunTestPlay extends FunSuite { +// def createTest(name : String): Unit ={ +// test(name){ +// Thread.sleep(500) +// for(i <- 0 to 4) { +// println(s"$name $i") +// Thread.sleep(500) +// } +// } +// } +// (0 to 80).map(_.toString).foreach(createTest) +//} -class TestIndividualFeatures extends MultithreadedFunSuite { +class TestIndividualFeatures extends MultithreadedFunSuite(sys.env.getOrElse("VEXRISCV_REGRESSION_THREAD_COUNT", "0").toInt) { val testCount = sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_COUNT", "100").toInt val seed = sys.env.getOrElse("VEXRISCV_REGRESSION_SEED", Random.nextLong().toString).toLong val testId : Set[Int] = sys.env.get("VEXRISCV_REGRESSION_TEST_ID") match { From c16f2ed7879877c4fe75a6ac658ab0ed6bf2771d Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 4 May 2020 12:54:28 +0200 Subject: [PATCH 416/951] Add probes in SmpCluster sim --- .../demo/smp/VexRiscvSmpCluster.scala | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index 92e3976c..7f165f21 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -510,6 +510,39 @@ object VexRiscvSmpClusterOpenSbi extends App{ ram.memory.loadBin(0xC1000000l, "../buildroot/output/images/dtb") ram.memory.loadBin(0xC2000000l, "../buildroot/output/images/rootfs.cpio") + import spinal.core.sim._ + var iMemReadBytes, dMemReadBytes, dMemWriteBytes = 0l + var reportTimer = 0 + var reportCycle = 0 + + import java.io._ + val csv = new PrintWriter(new File("bench.csv" )) + csv.write(s"reportCycle,iMemReadBytes,dMemReadBytes,dMemWriteBytes\n") + dut.clockDomain.onSamplings{ + dut.io.iMems.foreach{ iMem => + if(iMem.cmd.valid.toBoolean && iMem.cmd.ready.toBoolean){ + iMemReadBytes += iMem.cmd.length.toInt+1 + } + } + if(dut.io.dMem.cmd.valid.toBoolean && dut.io.dMem.cmd.ready.toBoolean){ + if(dut.io.dMem.cmd.opcode.toInt == Bmb.Cmd.Opcode.WRITE){ + dMemWriteBytes += dut.io.dMem.cmd.length.toInt+1 + }else { + dMemReadBytes += dut.io.dMem.cmd.length.toInt+1 + } + } + reportTimer = reportTimer + 1 + reportCycle = reportCycle + 1 + if(reportTimer == 100000){ + reportTimer = 0 +// println(f"\n** c=${reportCycle} ir=${iMemReadBytes*1e-6}%5.2f dr=${dMemReadBytes*1e-6}%5.2f dw=${dMemWriteBytes*1e-6}%5.2f **\n") + + csv.write(s"$reportCycle,$iMemReadBytes,$dMemReadBytes,$dMemWriteBytes\n") + csv.flush() + } + } + + // fork{ // disableSimWave() // val atMs = 130 From 09724e907ba984660b1d3a1cedb8ac5ef05498ee Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 5 May 2020 00:32:59 +0200 Subject: [PATCH 417/951] play around with CSR synthesis impact on design size --- .../scala/vexriscv/demo/SynthesisBench.scala | 102 +++++++++++++++++- .../vexriscv/TestIndividualFeatures.scala | 3 +- 2 files changed, 101 insertions(+), 4 deletions(-) diff --git a/src/main/scala/vexriscv/demo/SynthesisBench.scala b/src/main/scala/vexriscv/demo/SynthesisBench.scala index 94d00551..b6e9f2fd 100644 --- a/src/main/scala/vexriscv/demo/SynthesisBench.scala +++ b/src/main/scala/vexriscv/demo/SynthesisBench.scala @@ -6,8 +6,9 @@ import spinal.lib.eda.bench._ import spinal.lib.eda.icestorm.IcestormStdTargets import spinal.lib.eda.xilinx.VivadoFlow import spinal.lib.io.InOutWrapper -import vexriscv.VexRiscv -import vexriscv.plugin.DecoderSimplePlugin +import vexriscv.plugin.CsrAccess.{READ_ONLY, READ_WRITE, WRITE_ONLY} +import vexriscv.{VexRiscv, VexRiscvConfig, plugin} +import vexriscv.plugin.{BranchPlugin, CsrPlugin, CsrPluginConfig, DBusSimplePlugin, DecoderSimplePlugin, FullBarrelShifterPlugin, HazardSimplePlugin, IBusSimplePlugin, IntAluPlugin, LightShifterPlugin, NONE, RegFilePlugin, SrcPlugin, YamlPlugin} import scala.collection.mutable.ArrayBuffer import scala.util.Random @@ -153,6 +154,7 @@ object VexRiscvSynthesisBench { } + // val rtls = List(twoStage, twoStageBarell, twoStageMulDiv, twoStageAll, smallestNoCsr, smallest, smallAndProductive, smallAndProductiveWithICache, fullNoMmuNoCache, noCacheNoMmuMaxPerf, fullNoMmuMaxPerf, fullNoMmu, full, linuxBalanced, linuxBalancedSmp) val rtls = List(linuxBalanced, linuxBalancedSmp) // val rtls = List(smallest) @@ -278,4 +280,100 @@ object AllSynthesisBench { MuraxSynthesisBench.main(args) } +} + + + +object VexRiscvCustomSynthesisBench { + def main(args: Array[String]) { + + + def gen(csr : CsrPlugin) = new VexRiscv( + config = VexRiscvConfig( + plugins = List( + new IBusSimplePlugin( + resetVector = 0x80000000l, + cmdForkOnSecondStage = false, + cmdForkPersistence = false, + prediction = NONE, + catchAccessFault = false, + compressedGen = false + ), + new DBusSimplePlugin( + catchAddressMisaligned = false, + catchAccessFault = false + ), + new DecoderSimplePlugin( + catchIllegalInstruction = false + ), + new RegFilePlugin( + regFileReadyKind = plugin.SYNC, + zeroBoot = false + ), + new IntAluPlugin, + new SrcPlugin( + separatedAddSub = false, + executeInsertion = true + ), + csr, + new FullBarrelShifterPlugin(), + new HazardSimplePlugin( + bypassExecute = true, + bypassMemory = true, + bypassWriteBack = true, + bypassWriteBackBuffer = true, + pessimisticUseSrc = false, + pessimisticWriteRegFile = false, + pessimisticAddressMatch = false + ), + new BranchPlugin( + earlyBranch = false, + catchAddressMisaligned = false + ), + new YamlPlugin("cpu0.yaml") + ) + ) + ) + + + val fixedMtvec = new Rtl { + override def getName(): String = "Fixed MTVEC" + override def getRtlPath(): String = "fixedMtvec.v" + SpinalVerilog(gen(new CsrPlugin(CsrPluginConfig.smallest(0x80000000l))).setDefinitionName(getRtlPath().split("\\.").head)) + } + + val writeOnlyMtvec = new Rtl { + override def getName(): String = "write only MTVEC" + override def getRtlPath(): String = "woMtvec.v" + SpinalVerilog(gen(new CsrPlugin(CsrPluginConfig.smallest(null).copy(mtvecAccess = WRITE_ONLY))).setDefinitionName(getRtlPath().split("\\.").head)) + } + + val readWriteMtvec = new Rtl { + override def getName(): String = "read write MTVEC" + override def getRtlPath(): String = "wrMtvec.v" + SpinalVerilog(gen(new CsrPlugin(CsrPluginConfig.smallest(null).copy(mtvecAccess = READ_WRITE))).setDefinitionName(getRtlPath().split("\\.").head)) + } + + val fixedMtvecRoCounter = new Rtl { + override def getName(): String = "Fixed MTVEC, read only mcycle/minstret" + override def getRtlPath(): String = "fixedMtvecRoCounter.v" + SpinalVerilog(gen(new CsrPlugin(CsrPluginConfig.smallest(0x80000000l).copy(mcycleAccess = READ_ONLY, minstretAccess = READ_ONLY))).setDefinitionName(getRtlPath().split("\\.").head)) + } + + + val rwMtvecRoCounter = new Rtl { + override def getName(): String = "read write MTVEC, read only mcycle/minstret" + override def getRtlPath(): String = "readWriteMtvecRoCounter.v" + SpinalVerilog(gen(new CsrPlugin(CsrPluginConfig.smallest(null).copy(mtvecAccess = READ_WRITE, mcycleAccess = READ_ONLY, minstretAccess = READ_ONLY))).setDefinitionName(getRtlPath().split("\\.").head)) + } + + + // val rtls = List(twoStage, twoStageBarell, twoStageMulDiv, twoStageAll, smallestNoCsr, smallest, smallAndProductive, smallAndProductiveWithICache, fullNoMmuNoCache, noCacheNoMmuMaxPerf, fullNoMmuMaxPerf, fullNoMmu, full, linuxBalanced, linuxBalancedSmp) + val rtls = List(fixedMtvec, writeOnlyMtvec, readWriteMtvec,fixedMtvecRoCounter, rwMtvecRoCounter) + // val rtls = List(smallest) + val targets = XilinxStdTargets() ++ AlteraStdTargets() ++ IcestormStdTargets().take(1) + + // val targets = IcestormStdTargets() + Bench(rtls, targets) + } } \ No newline at end of file diff --git a/src/test/scala/vexriscv/TestIndividualFeatures.scala b/src/test/scala/vexriscv/TestIndividualFeatures.scala index 8a7ace11..eafd1d9f 100644 --- a/src/test/scala/vexriscv/TestIndividualFeatures.scala +++ b/src/test/scala/vexriscv/TestIndividualFeatures.scala @@ -577,8 +577,7 @@ object PlayFuture extends App{ class MultithreadedFunSuite(threadCount : Int) extends FunSuite { val finalThreadCount = if(threadCount > 0) threadCount else { - val systemInfo = new oshi.SystemInfo - systemInfo.getHardware.getProcessor.getLogicalProcessorCount + new oshi.SystemInfo().getHardware.getProcessor.getLogicalProcessorCount } implicit val ec = ExecutionContext.fromExecutorService( new ForkJoinPool(finalThreadCount, ForkJoinPool.defaultForkJoinWorkerThreadFactory, null, true) From 8043feebd504a37b110060b5944cbf9bd7921608 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 6 May 2020 17:06:17 +0200 Subject: [PATCH 418/951] More VexRiscv smp cluster probes --- .../demo/smp/VexRiscvSmpCluster.scala | 59 +++++++++++++++---- 1 file changed, 49 insertions(+), 10 deletions(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index 7f165f21..2f694cc2 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -8,7 +8,7 @@ import spinal.lib.bus.bmb.sim.BmbMemoryAgent import spinal.lib.bus.bmb.{Bmb, BmbArbiter, BmbDecoder, BmbExclusiveMonitor, BmbInvalidateMonitor, BmbParameter} import spinal.lib.com.jtag.Jtag import spinal.lib.com.jtag.sim.JtagTcp -import vexriscv.ip.{DataCacheAck, DataCacheConfig, DataCacheMemBus, InstructionCacheConfig} +import vexriscv.ip.{DataCacheAck, DataCacheConfig, DataCacheMemBus, InstructionCache, InstructionCacheConfig} import vexriscv.plugin.{BranchPlugin, CsrPlugin, CsrPluginConfig, DBusCachedPlugin, DBusSimplePlugin, DebugPlugin, DecoderSimplePlugin, FullBarrelShifterPlugin, HazardSimplePlugin, IBusCachedPlugin, IBusSimplePlugin, IntAluPlugin, MmuPlugin, MmuPortConfig, MulDivIterativePlugin, MulPlugin, RegFilePlugin, STATIC, SrcPlugin, YamlPlugin} import vexriscv.{Riscv, VexRiscv, VexRiscvConfig, plugin} @@ -491,10 +491,21 @@ object VexRiscvSmpClusterOpenSbi extends App{ simConfig.allOptimisation simConfig.addSimulatorFlag("--threads 1") - val cpuCount = 4 + val cpuCount = 1 val withStall = false - simConfig.workspaceName("rawr_4c").compile(VexRiscvSmpClusterGen.vexRiscvCluster(cpuCount, resetVector = 0x80000000l)).doSimUntilVoid(seed = 42){dut => + def gen = { + val dut = VexRiscvSmpClusterGen.vexRiscvCluster(cpuCount, resetVector = 0x80000000l) + dut.cpus.foreach{cpu => + cpu.core.children.foreach{ + case cache : InstructionCache => cache.io.cpu.decode.simPublic() + case _ => + } + } + dut + } + + simConfig.workspaceName("rawr_4c").compile(gen).doSimUntilVoid(seed = 42){dut => // dut.clockDomain.forkSimSpeedPrinter(1.0) VexRiscvSmpClusterTestInfrastructure.init(dut) val ram = VexRiscvSmpClusterTestInfrastructure.ram(dut, withStall) @@ -511,17 +522,39 @@ object VexRiscvSmpClusterOpenSbi extends App{ ram.memory.loadBin(0xC2000000l, "../buildroot/output/images/rootfs.cpio") import spinal.core.sim._ - var iMemReadBytes, dMemReadBytes, dMemWriteBytes = 0l + var iMemReadBytes, dMemReadBytes, dMemWriteBytes, iMemSequencial,iMemRequests = 0l var reportTimer = 0 var reportCycle = 0 import java.io._ val csv = new PrintWriter(new File("bench.csv" )) - csv.write(s"reportCycle,iMemReadBytes,dMemReadBytes,dMemWriteBytes\n") + val iMemCtx = Array.tabulate(cpuCount)(i => new { + var sequencialPrediction = 0l + val cache = dut.cpus(i).core.children.find(_.isInstanceOf[InstructionCache]).head.asInstanceOf[InstructionCache].io.cpu.decode + }) + csv.write(s"reportCycle,iMemReadBytes,dMemReadBytes,dMemWriteBytes,miaou,asd\n") dut.clockDomain.onSamplings{ - dut.io.iMems.foreach{ iMem => - if(iMem.cmd.valid.toBoolean && iMem.cmd.ready.toBoolean){ - iMemReadBytes += iMem.cmd.length.toInt+1 + for(i <- 0 until cpuCount; iMem = dut.io.iMems(i); ctx = iMemCtx(i)){ +// if(iMem.cmd.valid.toBoolean && iMem.cmd.ready.toBoolean){ +// val length = iMem.cmd.length.toInt + 1 +// val address = iMem.cmd.address.toLong +// iMemReadBytes += length +// iMemRequests += 1 +// } + if(ctx.cache.isValid.toBoolean && !ctx.cache.mmuRefilling.toBoolean && !ctx.cache.mmuException.toBoolean){ + val address = ctx.cache.physicalAddress.toLong + val length = ctx.cache.p.bytePerLine.toLong + val mask = ~(length-1) + if(ctx.cache.cacheMiss.toBoolean) { + iMemReadBytes += length + iMemRequests += 1 + if ((address & mask) == (ctx.sequencialPrediction & mask)) { + iMemSequencial += 1 + } + } + if(!ctx.cache.isStuck.toBoolean) { + ctx.sequencialPrediction = address + length + } } } if(dut.io.dMem.cmd.valid.toBoolean && dut.io.dMem.cmd.ready.toBoolean){ @@ -533,12 +566,18 @@ object VexRiscvSmpClusterOpenSbi extends App{ } reportTimer = reportTimer + 1 reportCycle = reportCycle + 1 - if(reportTimer == 100000){ + if(reportTimer == 400000){ reportTimer = 0 // println(f"\n** c=${reportCycle} ir=${iMemReadBytes*1e-6}%5.2f dr=${dMemReadBytes*1e-6}%5.2f dw=${dMemWriteBytes*1e-6}%5.2f **\n") - csv.write(s"$reportCycle,$iMemReadBytes,$dMemReadBytes,$dMemWriteBytes\n") + csv.write(s"$reportCycle,$iMemReadBytes,$dMemReadBytes,$dMemWriteBytes,$iMemRequests,$iMemSequencial\n") csv.flush() + reportCycle = 0 + iMemReadBytes = 0 + dMemReadBytes = 0 + dMemWriteBytes = 0 + iMemRequests = 0 + iMemSequencial = 0 } } From ed4a89e4af4a9e70a72db3c4284218d120f2a46c Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 6 May 2020 17:06:45 +0200 Subject: [PATCH 419/951] more pipelineing in Litex SMP cluster interconnect --- .../demo/smp/VexRiscvSmpLitexCluster.scala | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala index c2c287ad..bb02e602 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala @@ -180,10 +180,11 @@ case class BmbToLiteDram(bmbParameter : BmbParameter, io.output.cmd.we := cmdFork.isWrite if(bmbParameter.canWrite) { - val fifo = dataFork.throwWhen(dataFork.isRead).queue(wdataFifoSize) - io.output.wdata.arbitrationFrom(fifo) - io.output.wdata.data := fifo.data - io.output.wdata.we := fifo.mask + val wData = Stream(LiteDramNativeWData(liteDramParameter)) + wData.arbitrationFrom(dataFork.throwWhen(dataFork.isRead)) + wData.data := dataFork.data + wData.we := dataFork.mask + io.output.wdata << wData.queue(wdataFifoSize) } else { dataFork.ready := True io.output.wdata.valid := False @@ -305,7 +306,13 @@ case class VexRiscvLitexSmpCluster(p : VexRiscvLitexSmpClusterParameter, pendingMax = 15 ) iBusDecoder.io.input << iBusArbiter.io.output - val iMemBridge = io.iMem.fromBmb(iBusDecoder.io.outputs(1), wdataFifoSize = 0, rdataFifoSize = 32) + + val iMem = LiteDramNative(p.liteDram) + val iMemBridge = iMem.fromBmb(iBusDecoder.io.outputs(1), wdataFifoSize = 0, rdataFifoSize = 32) + iMem.cmd >-> io.iMem.cmd + iMem.wdata >> io.iMem.wdata + iMem.rdata << io.iMem.rdata + val peripheralAccessLength = Math.max(iBusDecoder.io.outputs(0).p.lengthWidth, dBusDecoder.io.outputs(0).p.lengthWidth) val peripheralArbiter = BmbArbiter( @@ -316,7 +323,7 @@ case class VexRiscvLitexSmpCluster(p : VexRiscvLitexSmpClusterParameter, peripheralArbiter.io.inputs(0) << iBusDecoder.io.outputs(0).resize(dataWidth = 32).pipelined(cmdHalfRate = true, rspValid = true) peripheralArbiter.io.inputs(1) << dBusDecoder.io.outputs(0).resize(dataWidth = 32).pipelined(cmdHalfRate = true, rspValid = true) - val peripheralWishbone = peripheralArbiter.io.output.toWishbone() + val peripheralWishbone = peripheralArbiter.io.output.pipelined(cmdValid = true).toWishbone() io.peripheral << peripheralWishbone } @@ -343,8 +350,8 @@ object VexRiscvLitexSmpClusterGen extends App { debugClockDomain = ClockDomain.current.copy(reset = Bool().setName("debugResetIn")) ) -// SpinalVerilog(Bench.compressIo(dutGen)) - SpinalVerilog(dutGen) + SpinalVerilog(Bench.compressIo(dutGen)) +// SpinalVerilog(dutGen) } From 6323caf265a69d1f183a93a7166861bed8b16c04 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 6 May 2020 17:09:46 +0200 Subject: [PATCH 420/951] MMU now allow $ to match tag against tlb pyhsical values directly D$ retiming D$ directTlbHit feature added for better timings --- src/main/scala/vexriscv/Services.scala | 13 +++- src/main/scala/vexriscv/ip/DataCache.scala | 36 +++++++---- .../scala/vexriscv/ip/InstructionCache.scala | 12 ++-- .../vexriscv/plugin/DBusCachedPlugin.scala | 9 ++- .../vexriscv/plugin/DBusSimplePlugin.scala | 3 +- .../vexriscv/plugin/IBusCachedPlugin.scala | 2 +- .../plugin/MemoryTranslatorPlugin.scala | 4 +- .../scala/vexriscv/plugin/MmuPlugin.scala | 62 ++++++++++++------- .../plugin/StaticMemoryTranslatorPlugin.scala | 3 +- .../vexriscv/TestIndividualFeatures.scala | 6 +- 10 files changed, 97 insertions(+), 53 deletions(-) diff --git a/src/main/scala/vexriscv/Services.scala b/src/main/scala/vexriscv/Services.scala index 4b0aeca5..1c9a2aee 100644 --- a/src/main/scala/vexriscv/Services.scala +++ b/src/main/scala/vexriscv/Services.scala @@ -68,17 +68,24 @@ case class MemoryTranslatorCmd() extends Bundle{ val virtualAddress = UInt(32 bits) val bypassTranslation = Bool } -case class MemoryTranslatorRsp() extends Bundle{ +case class MemoryTranslatorRsp(wayCount : Int) extends Bundle{ val physicalAddress = UInt(32 bits) val isIoAccess = Bool val allowRead, allowWrite, allowExecute = Bool val exception = Bool val refilling = Bool + val bypassTranslation = Bool + val ways = Vec(MemoryTranslatorRspWay(), wayCount) +} +case class MemoryTranslatorRspWay() extends Bundle{ + val sel = Bool() + val physical = UInt(32 bits) } -case class MemoryTranslatorBus() extends Bundle with IMasterSlave{ + +case class MemoryTranslatorBus(wayCount : Int) extends Bundle with IMasterSlave{ val cmd = MemoryTranslatorCmd() - val rsp = MemoryTranslatorRsp() + val rsp = MemoryTranslatorRsp(wayCount) val end = Bool val busy = Bool diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index 9de6f090..657b8c06 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -28,6 +28,7 @@ case class DataCacheConfig(cacheSize : Int, withExclusive : Boolean = false, withInvalidate : Boolean = false, pendingMax : Int = 32, + directTlbHit : Boolean = false, mergeExecuteMemory : Boolean = false){ assert(!(mergeExecuteMemory && (earlyDataMux || earlyWaysHits))) assert(!(earlyDataMux && !earlyWaysHits)) @@ -124,13 +125,13 @@ case class DataCacheCpuExecuteArgs(p : DataCacheConfig) extends Bundle{ val totalyConsistent = Bool() //Only for AMO/LRSC } -case class DataCacheCpuMemory(p : DataCacheConfig) extends Bundle with IMasterSlave{ +case class DataCacheCpuMemory(p : DataCacheConfig, tlbWayCount : Int) extends Bundle with IMasterSlave{ val isValid = Bool val isStuck = Bool val isRemoved = Bool val isWrite = Bool val address = UInt(p.addressWidth bit) - val mmuBus = MemoryTranslatorBus() + val mmuBus = MemoryTranslatorBus(tlbWayCount) override def asMaster(): Unit = { out(isValid, isStuck, isRemoved, address) @@ -174,9 +175,9 @@ case class DataCacheCpuWriteBack(p : DataCacheConfig) extends Bundle with IMaste } } -case class DataCacheCpuBus(p : DataCacheConfig) extends Bundle with IMasterSlave{ +case class DataCacheCpuBus(p : DataCacheConfig, tlbWayCount : Int) extends Bundle with IMasterSlave{ val execute = DataCacheCpuExecute(p) - val memory = DataCacheCpuMemory(p) + val memory = DataCacheCpuMemory(p, tlbWayCount) val writeBack = DataCacheCpuWriteBack(p) val redo = Bool() @@ -422,11 +423,11 @@ object DataCacheExternalAmoStates extends SpinalEnum{ } //If external amo, mem rsp should stay -class DataCache(val p : DataCacheConfig) extends Component{ +class DataCache(val p : DataCacheConfig, tlbWayCount : Int) extends Component{ import p._ val io = new Bundle{ - val cpu = slave(DataCacheCpuBus(p)) + val cpu = slave(DataCacheCpuBus(p, tlbWayCount)) val mem = master(DataCacheMemBus(p)) } @@ -537,11 +538,12 @@ class DataCache(val p : DataCacheConfig) extends Component{ val memCmdSent = RegInit(False) setWhen (io.mem.cmd.ready) clearWhen (!io.cpu.writeBack.isStuck) val pending = withExclusive generate new Area{ val counter = Reg(UInt(log2Up(pendingMax) + 1 bits)) init(0) - counter := counter + U(io.mem.cmd.fire && io.mem.cmd.last) - U(io.mem.rsp.valid && io.mem.rsp.last) + val counterNext = counter + U(io.mem.cmd.fire && io.mem.cmd.last) - U(io.mem.rsp.valid && io.mem.rsp.last) + counter := counterNext - val done = counter === 0 - val full = RegNext(counter.msb) - val last = counter === 1 + val done = RegNext(counterNext === 0) + val full = RegNext(counter.msb) //Has margin + val last = RegNext(counterNext === 1) //Equivalent to counter === 1 but pipelined if(!withInvalidate) { io.cpu.execute.haltIt setWhen(full) @@ -643,7 +645,19 @@ class DataCache(val p : DataCacheConfig) extends Component{ } } - val wayHits = earlyWaysHits generate ways.map(way => (io.cpu.memory.mmuBus.rsp.physicalAddress(tagRange) === way.tagsReadRsp.address && way.tagsReadRsp.valid)) + val wayHits = earlyWaysHits generate Bits(wayCount bits) + val indirectTlbHitGen = (earlyWaysHits && !directTlbHit) generate new Area { + wayHits := B(ways.map(way => (io.cpu.memory.mmuBus.rsp.physicalAddress(tagRange) === way.tagsReadRsp.address && way.tagsReadRsp.valid))) + } + val directTlbHitGen = (earlyWaysHits && directTlbHit) generate new Area { + val wayTlbHits = for (way <- ways) yield for (tlb <- io.cpu.memory.mmuBus.rsp.ways) yield { + way.tagsReadRsp.address === tlb.physical(tagRange) && tlb.sel + } + val translatedHits = B(wayTlbHits.map(_.orR)) + val bypassHits = B(ways.map(_.tagsReadRsp.address === io.cpu.memory.address(tagRange))) + wayHits := (io.cpu.memory.mmuBus.rsp.bypassTranslation ? bypassHits | translatedHits) & B(ways.map(_.tagsReadRsp.valid)) + } + val dataMux = earlyDataMux generate MuxOH(wayHits, ways.map(_.dataReadRsp)) val wayInvalidate = stagePipe(stage0. wayInvalidate) val dataColisions = if(mergeExecuteMemory){ diff --git a/src/main/scala/vexriscv/ip/InstructionCache.scala b/src/main/scala/vexriscv/ip/InstructionCache.scala index 75601143..d6842989 100644 --- a/src/main/scala/vexriscv/ip/InstructionCache.scala +++ b/src/main/scala/vexriscv/ip/InstructionCache.scala @@ -104,7 +104,7 @@ trait InstructionCacheCommons{ val cacheMiss, error, mmuRefilling, mmuException, isUser : Bool } -case class InstructionCacheCpuFetch(p : InstructionCacheConfig) extends Bundle with IMasterSlave with InstructionCacheCommons { +case class InstructionCacheCpuFetch(p : InstructionCacheConfig, tlbWayCount : Int) extends Bundle with IMasterSlave with InstructionCacheCommons { val isValid = Bool() val isStuck = Bool() val isRemoved = Bool() @@ -112,7 +112,7 @@ case class InstructionCacheCpuFetch(p : InstructionCacheConfig) extends Bundle w val data = Bits(p.cpuDataWidth bits) val dataBypassValid = p.bypassGen generate Bool() val dataBypass = p.bypassGen generate Bits(p.cpuDataWidth bits) - val mmuBus = MemoryTranslatorBus() + val mmuBus = MemoryTranslatorBus(tlbWayCount) val physicalAddress = UInt(p.addressWidth bits) val cacheMiss, error, mmuRefilling, mmuException, isUser = ifGen(!p.twoCycleCache)(Bool) val haltIt = Bool() //Used to wait on the MMU rsp busy @@ -141,9 +141,9 @@ case class InstructionCacheCpuDecode(p : InstructionCacheConfig) extends Bundle } } -case class InstructionCacheCpuBus(p : InstructionCacheConfig) extends Bundle with IMasterSlave{ +case class InstructionCacheCpuBus(p : InstructionCacheConfig, tlbWayCount : Int) extends Bundle with IMasterSlave{ val prefetch = InstructionCacheCpuPrefetch(p) - val fetch = InstructionCacheCpuFetch(p) + val fetch = InstructionCacheCpuFetch(p, tlbWayCount) val decode = InstructionCacheCpuDecode(p) val fill = Flow(UInt(p.addressWidth bits)) @@ -277,11 +277,11 @@ case class InstructionCacheFlushBus() extends Bundle with IMasterSlave{ } } -class InstructionCache(p : InstructionCacheConfig) extends Component{ +class InstructionCache(p : InstructionCacheConfig, tlbWayCount : Int) extends Component{ import p._ val io = new Bundle{ val flush = in Bool() - val cpu = slave(InstructionCacheCpuBus(p)) + val cpu = slave(InstructionCacheCpuBus(p, tlbWayCount)) val mem = master(InstructionCacheMemBus(p)) } diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index 17c429c0..3855c116 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -171,9 +171,12 @@ class DBusCachedPlugin(val config : DataCacheConfig, import pipeline.config._ - val cache = new DataCache(this.config.copy( - mergeExecuteMemory = writeBack == null - )) + val cache = new DataCache( + this.config.copy( + mergeExecuteMemory = writeBack == null + ), + tlbWayCount = mmuBus.rsp.wayCount + ) //Interconnect the plugin dBus with the cache dBus with some optional pipelining def optionPipe[T](cond : Boolean, on : T)(f : T => T) : T = if(cond) f(on) else on diff --git a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala index 41306911..5b750525 100644 --- a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala @@ -298,7 +298,6 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, object MEMORY_ADDRESS_LOW extends Stageable(UInt(2 bits)) object ALIGNEMENT_FAULT extends Stageable(Bool) object MMU_FAULT extends Stageable(Bool) - object MMU_RSP extends Stageable(MemoryTranslatorRsp()) object MEMORY_ATOMIC extends Stageable(Bool) object ATOMIC_HIT extends Stageable(Bool) object MEMORY_STORE extends Stageable(Bool) @@ -393,6 +392,8 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, import pipeline._ import pipeline.config._ + object MMU_RSP extends Stageable(MemoryTranslatorRsp(mmuBus.rsp.wayCount)) + dBus = master(DBusSimpleBus()).setName("dBus") diff --git a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala index 642fcbb5..ede324c5 100644 --- a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala @@ -124,7 +124,7 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l, import pipeline.config._ pipeline plug new FetchArea(pipeline) { - val cache = new InstructionCache(IBusCachedPlugin.this.config.copy(bypassGen = tightlyGen)) + val cache = new InstructionCache(IBusCachedPlugin.this.config.copy(bypassGen = tightlyGen), mmuBus.rsp.wayCount) iBus = master(new InstructionCacheMemBus(IBusCachedPlugin.this.config)).setName("iBus") iBus <> cache.io.mem iBus.cmd.address.allowOverride := cache.io.mem.cmd.address diff --git a/src/main/scala/vexriscv/plugin/MemoryTranslatorPlugin.scala b/src/main/scala/vexriscv/plugin/MemoryTranslatorPlugin.scala index 623d872e..903d93cc 100644 --- a/src/main/scala/vexriscv/plugin/MemoryTranslatorPlugin.scala +++ b/src/main/scala/vexriscv/plugin/MemoryTranslatorPlugin.scala @@ -22,8 +22,8 @@ class MemoryTranslatorPlugin(tlbSize : Int, val portsInfo = ArrayBuffer[MemoryTranslatorPort]() override def newTranslationPort(priority : Int,args : Any): MemoryTranslatorBus = { -// val exceptionBus = pipeline.service(classOf[ExceptionService]).newExceptionPort(stage) - val port = MemoryTranslatorPort(MemoryTranslatorBus(),priority,args.asInstanceOf[MemoryTranslatorPortConfig]/*,exceptionBus*/) + val config = args.asInstanceOf[MemoryTranslatorPortConfig] + val port = MemoryTranslatorPort(MemoryTranslatorBus(0),priority, config/*,exceptionBus*/) portsInfo += port port.bus } diff --git a/src/main/scala/vexriscv/plugin/MmuPlugin.scala b/src/main/scala/vexriscv/plugin/MmuPlugin.scala index 9dedde5d..4c5083f4 100644 --- a/src/main/scala/vexriscv/plugin/MmuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/MmuPlugin.scala @@ -47,7 +47,8 @@ class MmuPlugin(ioRange : UInt => Bool, val portsInfo = ArrayBuffer[MmuPort]() override def newTranslationPort(priority : Int,args : Any): MemoryTranslatorBus = { - val port = MmuPort(MemoryTranslatorBus(),priority,args.asInstanceOf[MmuPortConfig], portsInfo.length) + val config = args.asInstanceOf[MmuPortConfig] + val port = MmuPort(MemoryTranslatorBus(config.portTlbSize),priority, config, portsInfo.length) portsInfo += port port.bus } @@ -71,7 +72,7 @@ class MmuPlugin(ioRange : UInt => Bool, val csrService = pipeline.service(classOf[CsrInterface]) //Sorted by priority - val sortedPortsInfo = portsInfo.sortWith((a,b) => a.priority > b.priority) + val sortedPortsInfo = portsInfo.sortBy(_.priority) case class CacheLine() extends Bundle { val valid, exception, superPage = Bool @@ -137,6 +138,12 @@ class MmuPlugin(ioRange : UInt => Bool, } port.bus.rsp.isIoAccess := ioRange(port.bus.rsp.physicalAddress) + port.bus.rsp.bypassTranslation := !requireMmuLockup + for(wayId <- 0 until port.args.portTlbSize){ + port.bus.rsp.ways(wayId).sel := cacheHits(wayId) + port.bus.rsp.ways(wayId).physical := cache(wayId).physicalAddress(1) @@ (cache(wayId).superPage ? port.bus.cmd.virtualAddress(21 downto 12) | cache(wayId).physicalAddress(0)) @@ port.bus.cmd.virtualAddress(11 downto 0) + } + // Avoid keeping any invalid line in the cache after an exception. // https://github.com/riscv/riscv-linux/blob/8fe28cb58bcb235034b64cbbb7550a8a43fd88be/arch/riscv/include/asm/pgtable.h#L276 when(service(classOf[IContextSwitching]).isContextSwitching) { @@ -154,21 +161,23 @@ class MmuPlugin(ioRange : UInt => Bool, } val state = RegInit(State.IDLE) val vpn = Reg(Vec(UInt(10 bits), UInt(10 bits))) - val portId = Reg(UInt(log2Up(portsInfo.length) bits)) + val portSortedOh = Reg(Bits(portsInfo.length bits)) case class PTE() extends Bundle { val V, R, W ,X, U, G, A, D = Bool() val RSW = Bits(2 bits) val PPN0 = UInt(10 bits) val PPN1 = UInt(12 bits) } + + val dBusRspStaged = dBusAccess.rsp.stage() val dBusRsp = new Area{ val pte = PTE() - pte.assignFromBits(dBusAccess.rsp.data) - val exception = !pte.V || (!pte.R && pte.W) || dBusAccess.rsp.error + pte.assignFromBits(dBusRspStaged.data) + val exception = !pte.V || (!pte.R && pte.W) || dBusRspStaged.error val leaf = pte.R || pte.X } - val pteBuffer = RegNextWhen(dBusRsp.pte, dBusAccess.rsp.valid && !dBusAccess.rsp.redo) + val pteBuffer = RegNextWhen(dBusRsp.pte, dBusRspStaged.valid && !dBusRspStaged.redo) dBusAccess.cmd.valid := False dBusAccess.cmd.write := False @@ -176,16 +185,25 @@ class MmuPlugin(ioRange : UInt => Bool, dBusAccess.cmd.address.assignDontCare() dBusAccess.cmd.data.assignDontCare() dBusAccess.cmd.writeMask.assignDontCare() + + val refills = OHMasking.last(B(sortedPortsInfo.map(port => port.bus.cmd.isValid && port.bus.rsp.refilling))) switch(state){ is(State.IDLE){ - for(port <- portsInfo.sortBy(_.priority)){ - when(port.bus.cmd.isValid && port.bus.rsp.refilling){ - vpn(1) := port.bus.cmd.virtualAddress(31 downto 22) - vpn(0) := port.bus.cmd.virtualAddress(21 downto 12) - portId := port.id - state := State.L1_CMD - } + when(refills.orR){ + portSortedOh := refills + state := State.L1_CMD + val address = MuxOH(refills, sortedPortsInfo.map(_.bus.cmd.virtualAddress)) + vpn(1) := address(31 downto 22) + vpn(0) := address(21 downto 12) } +// for(port <- portsInfo.sortBy(_.priority)){ +// when(port.bus.cmd.isValid && port.bus.rsp.refilling){ +// vpn(1) := port.bus.cmd.virtualAddress(31 downto 22) +// vpn(0) := port.bus.cmd.virtualAddress(21 downto 12) +// portId := port.id +// state := State.L1_CMD +// } +// } } is(State.L1_CMD){ dBusAccess.cmd.valid := True @@ -195,12 +213,12 @@ class MmuPlugin(ioRange : UInt => Bool, } } is(State.L1_RSP){ - when(dBusAccess.rsp.valid){ + when(dBusRspStaged.valid){ state := State.L0_CMD when(dBusRsp.leaf || dBusRsp.exception){ state := State.IDLE } - when(dBusAccess.rsp.redo){ + when(dBusRspStaged.redo){ state := State.L1_CMD } } @@ -213,22 +231,22 @@ class MmuPlugin(ioRange : UInt => Bool, } } is(State.L0_RSP){ - when(dBusAccess.rsp.valid) { + when(dBusRspStaged.valid) { state := State.IDLE - when(dBusAccess.rsp.redo){ + when(dBusRspStaged.redo){ state := State.L0_CMD } } } } - for(port <- ports) { - port.handle.bus.busy := state =/= State.IDLE && portId === port.id + for((port, id) <- sortedPortsInfo.zipWithIndex) { + port.bus.busy := state =/= State.IDLE && portSortedOh(id) } - when(dBusAccess.rsp.valid && !dBusAccess.rsp.redo && (dBusRsp.leaf || dBusRsp.exception)){ - for(port <- ports){ - when(portId === port.id) { + when(dBusRspStaged.valid && !dBusRspStaged.redo && (dBusRsp.leaf || dBusRsp.exception)){ + for((port, id) <- ports.zipWithIndex) { + when(portSortedOh(id)) { port.entryToReplace.increment() for ((line, lineId) <- port.cache.zipWithIndex) { when(port.entryToReplace === lineId){ diff --git a/src/main/scala/vexriscv/plugin/StaticMemoryTranslatorPlugin.scala b/src/main/scala/vexriscv/plugin/StaticMemoryTranslatorPlugin.scala index 351ebc55..6f626e7b 100644 --- a/src/main/scala/vexriscv/plugin/StaticMemoryTranslatorPlugin.scala +++ b/src/main/scala/vexriscv/plugin/StaticMemoryTranslatorPlugin.scala @@ -11,8 +11,7 @@ class StaticMemoryTranslatorPlugin(ioRange : UInt => Bool) extends Plugin[VexRis val portsInfo = ArrayBuffer[StaticMemoryTranslatorPort]() override def newTranslationPort(priority : Int,args : Any): MemoryTranslatorBus = { -// val exceptionBus = pipeline.service(classOf[ExceptionService]).newExceptionPort(stage) - val port = StaticMemoryTranslatorPort(MemoryTranslatorBus(),priority) + val port = StaticMemoryTranslatorPort(MemoryTranslatorBus(0),priority) portsInfo += port port.bus } diff --git a/src/test/scala/vexriscv/TestIndividualFeatures.scala b/src/test/scala/vexriscv/TestIndividualFeatures.scala index eafd1d9f..c31a30a6 100644 --- a/src/test/scala/vexriscv/TestIndividualFeatures.scala +++ b/src/test/scala/vexriscv/TestIndividualFeatures.scala @@ -436,13 +436,14 @@ class DBusDimension extends VexRiscvDimension("DBus") { val dBusRspSlavePipe = r.nextBoolean() || withSmp val relaxedMemoryTranslationRegister = r.nextBoolean() val earlyWaysHits = r.nextBoolean() && !noWriteBack + val directTlbHit = r.nextBoolean() && mmuConfig.isInstanceOf[MmuPortConfig] val dBusCmdMasterPipe, dBusCmdSlavePipe = false //As it create test bench issues do{ cacheSize = 512 << r.nextInt(5) wayCount = 1 << r.nextInt(3) }while(cacheSize/wayCount < 512 || (catchAll && cacheSize/wayCount > 4096)) - new VexRiscvPosition(s"Cached${memDataWidth}d" + "S" + cacheSize + "W" + wayCount + "BPL" + bytePerLine + (if(dBusCmdMasterPipe) "Cmp " else "") + (if(dBusCmdSlavePipe) "Csp " else "") + (if(dBusRspSlavePipe) "Rsp " else "") + (if(relaxedMemoryTranslationRegister) "Rmtr " else "") + (if(earlyWaysHits) "Ewh " else "") + (if(withAmo) "Amo " else "") + (if(withSmp) "Smp " else "")) { + new VexRiscvPosition(s"Cached${memDataWidth}d" + "S" + cacheSize + "W" + wayCount + "BPL" + bytePerLine + (if(dBusCmdMasterPipe) "Cmp " else "") + (if(dBusCmdSlavePipe) "Csp " else "") + (if(dBusRspSlavePipe) "Rsp " else "") + (if(relaxedMemoryTranslationRegister) "Rmtr " else "") + (if(earlyWaysHits) "Ewh " else "") + (if(withAmo) "Amo " else "") + (if(withSmp) "Smp " else "") + (if(directTlbHit) "Dtlb " else "")) { override def testParam = s"DBUS=CACHED DBUS_DATA_WIDTH=$memDataWidth " + (if(withLrSc) "LRSC=yes " else "") + (if(withAmo) "AMO=yes " else "") + (if(withSmp) "DBUS_EXCLUSIVE=yes DBUS_INVALIDATE=yes " else "") override def applyOn(config: VexRiscvConfig): Unit = { @@ -461,7 +462,8 @@ class DBusDimension extends VexRiscvDimension("DBus") { withAmo = withAmo, earlyWaysHits = earlyWaysHits, withExclusive = withSmp, - withInvalidate = withSmp + withInvalidate = withSmp, + directTlbHit = directTlbHit ), dBusCmdMasterPipe = dBusCmdMasterPipe, dBusCmdSlavePipe = dBusCmdSlavePipe, From fc0f3a2020a4cbc49ca51b50d942cdc924cef330 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 6 May 2020 18:05:20 +0200 Subject: [PATCH 421/951] cleanup mmu interface --- src/main/scala/vexriscv/Services.scala | 10 +++++----- src/main/scala/vexriscv/ip/DataCache.scala | 12 ++++++------ src/main/scala/vexriscv/ip/InstructionCache.scala | 12 ++++++------ .../scala/vexriscv/plugin/DBusCachedPlugin.scala | 2 +- .../scala/vexriscv/plugin/DBusSimplePlugin.scala | 2 +- .../scala/vexriscv/plugin/IBusCachedPlugin.scala | 2 +- .../vexriscv/plugin/MemoryTranslatorPlugin.scala | 2 +- src/main/scala/vexriscv/plugin/MmuPlugin.scala | 2 +- .../plugin/StaticMemoryTranslatorPlugin.scala | 2 +- 9 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/main/scala/vexriscv/Services.scala b/src/main/scala/vexriscv/Services.scala index 1c9a2aee..5bf763e4 100644 --- a/src/main/scala/vexriscv/Services.scala +++ b/src/main/scala/vexriscv/Services.scala @@ -68,24 +68,24 @@ case class MemoryTranslatorCmd() extends Bundle{ val virtualAddress = UInt(32 bits) val bypassTranslation = Bool } -case class MemoryTranslatorRsp(wayCount : Int) extends Bundle{ +case class MemoryTranslatorRsp(p : MemoryTranslatorBusParameter) extends Bundle{ val physicalAddress = UInt(32 bits) val isIoAccess = Bool val allowRead, allowWrite, allowExecute = Bool val exception = Bool val refilling = Bool val bypassTranslation = Bool - val ways = Vec(MemoryTranslatorRspWay(), wayCount) + val ways = Vec(MemoryTranslatorRspWay(), p.wayCount) } case class MemoryTranslatorRspWay() extends Bundle{ val sel = Bool() val physical = UInt(32 bits) } - -case class MemoryTranslatorBus(wayCount : Int) extends Bundle with IMasterSlave{ +case class MemoryTranslatorBusParameter(wayCount : Int) +case class MemoryTranslatorBus(p : MemoryTranslatorBusParameter) extends Bundle with IMasterSlave{ val cmd = MemoryTranslatorCmd() - val rsp = MemoryTranslatorRsp(wayCount) + val rsp = MemoryTranslatorRsp(p) val end = Bool val busy = Bool diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index 657b8c06..a99a9292 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -125,13 +125,13 @@ case class DataCacheCpuExecuteArgs(p : DataCacheConfig) extends Bundle{ val totalyConsistent = Bool() //Only for AMO/LRSC } -case class DataCacheCpuMemory(p : DataCacheConfig, tlbWayCount : Int) extends Bundle with IMasterSlave{ +case class DataCacheCpuMemory(p : DataCacheConfig, mmu : MemoryTranslatorBusParameter) extends Bundle with IMasterSlave{ val isValid = Bool val isStuck = Bool val isRemoved = Bool val isWrite = Bool val address = UInt(p.addressWidth bit) - val mmuBus = MemoryTranslatorBus(tlbWayCount) + val mmuBus = MemoryTranslatorBus(mmu) override def asMaster(): Unit = { out(isValid, isStuck, isRemoved, address) @@ -175,9 +175,9 @@ case class DataCacheCpuWriteBack(p : DataCacheConfig) extends Bundle with IMaste } } -case class DataCacheCpuBus(p : DataCacheConfig, tlbWayCount : Int) extends Bundle with IMasterSlave{ +case class DataCacheCpuBus(p : DataCacheConfig, mmu : MemoryTranslatorBusParameter) extends Bundle with IMasterSlave{ val execute = DataCacheCpuExecute(p) - val memory = DataCacheCpuMemory(p, tlbWayCount) + val memory = DataCacheCpuMemory(p, mmu) val writeBack = DataCacheCpuWriteBack(p) val redo = Bool() @@ -423,11 +423,11 @@ object DataCacheExternalAmoStates extends SpinalEnum{ } //If external amo, mem rsp should stay -class DataCache(val p : DataCacheConfig, tlbWayCount : Int) extends Component{ +class DataCache(val p : DataCacheConfig, mmuParameter : MemoryTranslatorBusParameter) extends Component{ import p._ val io = new Bundle{ - val cpu = slave(DataCacheCpuBus(p, tlbWayCount)) + val cpu = slave(DataCacheCpuBus(p, mmuParameter)) val mem = master(DataCacheMemBus(p)) } diff --git a/src/main/scala/vexriscv/ip/InstructionCache.scala b/src/main/scala/vexriscv/ip/InstructionCache.scala index d6842989..aedd6af2 100644 --- a/src/main/scala/vexriscv/ip/InstructionCache.scala +++ b/src/main/scala/vexriscv/ip/InstructionCache.scala @@ -104,7 +104,7 @@ trait InstructionCacheCommons{ val cacheMiss, error, mmuRefilling, mmuException, isUser : Bool } -case class InstructionCacheCpuFetch(p : InstructionCacheConfig, tlbWayCount : Int) extends Bundle with IMasterSlave with InstructionCacheCommons { +case class InstructionCacheCpuFetch(p : InstructionCacheConfig, mmuParameter : MemoryTranslatorBusParameter) extends Bundle with IMasterSlave with InstructionCacheCommons { val isValid = Bool() val isStuck = Bool() val isRemoved = Bool() @@ -112,7 +112,7 @@ case class InstructionCacheCpuFetch(p : InstructionCacheConfig, tlbWayCount : In val data = Bits(p.cpuDataWidth bits) val dataBypassValid = p.bypassGen generate Bool() val dataBypass = p.bypassGen generate Bits(p.cpuDataWidth bits) - val mmuBus = MemoryTranslatorBus(tlbWayCount) + val mmuBus = MemoryTranslatorBus(mmuParameter) val physicalAddress = UInt(p.addressWidth bits) val cacheMiss, error, mmuRefilling, mmuException, isUser = ifGen(!p.twoCycleCache)(Bool) val haltIt = Bool() //Used to wait on the MMU rsp busy @@ -141,9 +141,9 @@ case class InstructionCacheCpuDecode(p : InstructionCacheConfig) extends Bundle } } -case class InstructionCacheCpuBus(p : InstructionCacheConfig, tlbWayCount : Int) extends Bundle with IMasterSlave{ +case class InstructionCacheCpuBus(p : InstructionCacheConfig, mmuParameter : MemoryTranslatorBusParameter) extends Bundle with IMasterSlave{ val prefetch = InstructionCacheCpuPrefetch(p) - val fetch = InstructionCacheCpuFetch(p, tlbWayCount) + val fetch = InstructionCacheCpuFetch(p, mmuParameter) val decode = InstructionCacheCpuDecode(p) val fill = Flow(UInt(p.addressWidth bits)) @@ -277,11 +277,11 @@ case class InstructionCacheFlushBus() extends Bundle with IMasterSlave{ } } -class InstructionCache(p : InstructionCacheConfig, tlbWayCount : Int) extends Component{ +class InstructionCache(p : InstructionCacheConfig, mmuParameter : MemoryTranslatorBusParameter) extends Component{ import p._ val io = new Bundle{ val flush = in Bool() - val cpu = slave(InstructionCacheCpuBus(p, tlbWayCount)) + val cpu = slave(InstructionCacheCpuBus(p, mmuParameter)) val mem = master(InstructionCacheMemBus(p)) } diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index 3855c116..96e1b1bd 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -175,7 +175,7 @@ class DBusCachedPlugin(val config : DataCacheConfig, this.config.copy( mergeExecuteMemory = writeBack == null ), - tlbWayCount = mmuBus.rsp.wayCount + mmuParameter = mmuBus.p ) //Interconnect the plugin dBus with the cache dBus with some optional pipelining diff --git a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala index 5b750525..819fc8f9 100644 --- a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala @@ -392,7 +392,7 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, import pipeline._ import pipeline.config._ - object MMU_RSP extends Stageable(MemoryTranslatorRsp(mmuBus.rsp.wayCount)) + object MMU_RSP extends Stageable(MemoryTranslatorRsp(mmuBus.p)) dBus = master(DBusSimpleBus()).setName("dBus") diff --git a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala index ede324c5..be08cdad 100644 --- a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala @@ -124,7 +124,7 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l, import pipeline.config._ pipeline plug new FetchArea(pipeline) { - val cache = new InstructionCache(IBusCachedPlugin.this.config.copy(bypassGen = tightlyGen), mmuBus.rsp.wayCount) + val cache = new InstructionCache(IBusCachedPlugin.this.config.copy(bypassGen = tightlyGen), mmuBus.p) iBus = master(new InstructionCacheMemBus(IBusCachedPlugin.this.config)).setName("iBus") iBus <> cache.io.mem iBus.cmd.address.allowOverride := cache.io.mem.cmd.address diff --git a/src/main/scala/vexriscv/plugin/MemoryTranslatorPlugin.scala b/src/main/scala/vexriscv/plugin/MemoryTranslatorPlugin.scala index 903d93cc..c8c00ecf 100644 --- a/src/main/scala/vexriscv/plugin/MemoryTranslatorPlugin.scala +++ b/src/main/scala/vexriscv/plugin/MemoryTranslatorPlugin.scala @@ -23,7 +23,7 @@ class MemoryTranslatorPlugin(tlbSize : Int, override def newTranslationPort(priority : Int,args : Any): MemoryTranslatorBus = { val config = args.asInstanceOf[MemoryTranslatorPortConfig] - val port = MemoryTranslatorPort(MemoryTranslatorBus(0),priority, config/*,exceptionBus*/) + val port = MemoryTranslatorPort(MemoryTranslatorBus(MemoryTranslatorBusParameter(wayCount = 0)),priority, config/*,exceptionBus*/) portsInfo += port port.bus } diff --git a/src/main/scala/vexriscv/plugin/MmuPlugin.scala b/src/main/scala/vexriscv/plugin/MmuPlugin.scala index 4c5083f4..884a2d55 100644 --- a/src/main/scala/vexriscv/plugin/MmuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/MmuPlugin.scala @@ -48,7 +48,7 @@ class MmuPlugin(ioRange : UInt => Bool, override def newTranslationPort(priority : Int,args : Any): MemoryTranslatorBus = { val config = args.asInstanceOf[MmuPortConfig] - val port = MmuPort(MemoryTranslatorBus(config.portTlbSize),priority, config, portsInfo.length) + val port = MmuPort(MemoryTranslatorBus(MemoryTranslatorBusParameter(wayCount = config.portTlbSize)),priority, config, portsInfo.length) portsInfo += port port.bus } diff --git a/src/main/scala/vexriscv/plugin/StaticMemoryTranslatorPlugin.scala b/src/main/scala/vexriscv/plugin/StaticMemoryTranslatorPlugin.scala index 6f626e7b..cbe55f9b 100644 --- a/src/main/scala/vexriscv/plugin/StaticMemoryTranslatorPlugin.scala +++ b/src/main/scala/vexriscv/plugin/StaticMemoryTranslatorPlugin.scala @@ -11,7 +11,7 @@ class StaticMemoryTranslatorPlugin(ioRange : UInt => Bool) extends Plugin[VexRis val portsInfo = ArrayBuffer[StaticMemoryTranslatorPort]() override def newTranslationPort(priority : Int,args : Any): MemoryTranslatorBus = { - val port = StaticMemoryTranslatorPort(MemoryTranslatorBus(0),priority) + val port = StaticMemoryTranslatorPort(MemoryTranslatorBus(MemoryTranslatorBusParameter(wayCount = 0)),priority) portsInfo += port port.bus } From 8e025aeeaa85c5919ab84f1c75bba4112a7a2296 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 7 May 2020 13:18:11 +0200 Subject: [PATCH 422/951] more litex smp cluster pipelining --- .../scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala index bb02e602..9bfca0bf 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala @@ -305,7 +305,7 @@ case class VexRiscvLitexSmpCluster(p : VexRiscvLitexSmpClusterParameter, capabilities = Seq(iBusArbiterParameter, iBusArbiterParameter), pendingMax = 15 ) - iBusDecoder.io.input << iBusArbiter.io.output + iBusDecoder.io.input << iBusArbiter.io.output.pipelined(cmdValid = true) val iMem = LiteDramNative(p.liteDram) val iMemBridge = iMem.fromBmb(iBusDecoder.io.outputs(1), wdataFifoSize = 0, rdataFifoSize = 32) @@ -350,8 +350,8 @@ object VexRiscvLitexSmpClusterGen extends App { debugClockDomain = ClockDomain.current.copy(reset = Bool().setName("debugResetIn")) ) - SpinalVerilog(Bench.compressIo(dutGen)) -// SpinalVerilog(dutGen) +// SpinalVerilog(Bench.compressIo(dutGen)) + SpinalVerilog(dutGen) } From 41ee8fd2265e533784b33c50ef1572ec776cc9ed Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 7 May 2020 13:37:53 +0200 Subject: [PATCH 423/951] MmuPlugin now support multiple stages, D$ can now take advantage of that --- src/main/scala/vexriscv/Services.scala | 5 +- src/main/scala/vexriscv/TestsWorkspace.scala | 6 ++- .../demo/smp/VexRiscvSmpCluster.scala | 5 +- src/main/scala/vexriscv/ip/DataCache.scala | 23 ++++---- .../scala/vexriscv/ip/InstructionCache.scala | 6 +-- .../vexriscv/plugin/DBusCachedPlugin.scala | 24 +++++++-- .../vexriscv/plugin/DBusSimplePlugin.scala | 7 +-- .../vexriscv/plugin/IBusCachedPlugin.scala | 4 +- .../vexriscv/plugin/IBusSimplePlugin.scala | 6 +-- .../plugin/MemoryTranslatorPlugin.scala | 12 ++--- .../scala/vexriscv/plugin/MmuPlugin.scala | 52 +++++++++++++------ .../plugin/StaticMemoryTranslatorPlugin.scala | 2 +- .../vexriscv/TestIndividualFeatures.scala | 7 +-- 13 files changed, 97 insertions(+), 62 deletions(-) diff --git a/src/main/scala/vexriscv/Services.scala b/src/main/scala/vexriscv/Services.scala index 5bf763e4..51dbe6b8 100644 --- a/src/main/scala/vexriscv/Services.scala +++ b/src/main/scala/vexriscv/Services.scala @@ -65,6 +65,7 @@ trait RegFileService{ case class MemoryTranslatorCmd() extends Bundle{ val isValid = Bool + val isStuck = Bool val virtualAddress = UInt(32 bits) val bypassTranslation = Bool } @@ -82,9 +83,9 @@ case class MemoryTranslatorRspWay() extends Bundle{ val physical = UInt(32 bits) } -case class MemoryTranslatorBusParameter(wayCount : Int) +case class MemoryTranslatorBusParameter(wayCount : Int = 0, latency : Int = 0) case class MemoryTranslatorBus(p : MemoryTranslatorBusParameter) extends Bundle with IMasterSlave{ - val cmd = MemoryTranslatorCmd() + val cmd = Vec(MemoryTranslatorCmd(), p.latency + 1) val rsp = MemoryTranslatorRsp(p) val end = Bool val busy = Bool diff --git a/src/main/scala/vexriscv/TestsWorkspace.scala b/src/main/scala/vexriscv/TestsWorkspace.scala index 40f8b33c..b97936d7 100644 --- a/src/main/scala/vexriscv/TestsWorkspace.scala +++ b/src/main/scala/vexriscv/TestsWorkspace.scala @@ -73,7 +73,8 @@ object TestsWorkspace { // ) ), memoryTranslatorPortConfig = MmuPortConfig( - portTlbSize = 4 + portTlbSize = 4, + latency = 0 ) ), // ).newTightlyCoupledPort(TightlyCoupledPortParameter("iBusTc", a => a(30 downto 28) === 0x0 && a(5))), @@ -108,7 +109,8 @@ object TestsWorkspace { // ) ), memoryTranslatorPortConfig = MmuPortConfig( - portTlbSize = 4 + portTlbSize = 4, + latency = 1 ) ), diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index 2f694cc2..3f23a238 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -193,7 +193,10 @@ object VexRiscvSmpClusterGen { // ) ), memoryTranslatorPortConfig = MmuPortConfig( - portTlbSize = 4 + portTlbSize = 4, + latency = 1, + earlyRequireMmuLockup = true, + earlyCacheHits = true ) ), diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index a99a9292..2f2e8c2f 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -128,15 +128,14 @@ case class DataCacheCpuExecuteArgs(p : DataCacheConfig) extends Bundle{ case class DataCacheCpuMemory(p : DataCacheConfig, mmu : MemoryTranslatorBusParameter) extends Bundle with IMasterSlave{ val isValid = Bool val isStuck = Bool - val isRemoved = Bool val isWrite = Bool val address = UInt(p.addressWidth bit) - val mmuBus = MemoryTranslatorBus(mmu) + val mmuRsp = MemoryTranslatorRsp(mmu) override def asMaster(): Unit = { - out(isValid, isStuck, isRemoved, address) + out(isValid, isStuck, address) in(isWrite) - slave(mmuBus) + out(mmuRsp) } } @@ -619,10 +618,6 @@ class DataCache(val p : DataCacheConfig, mmuParameter : MemoryTranslatorBusParam def stagePipe[T <: Data](that : T) = if(mergeExecuteMemory) CombInit(that) else RegNextWhen(that, !io.cpu.memory.isStuck) val request = stagePipe(io.cpu.execute.args) val mask = stagePipe(stage0.mask) - io.cpu.memory.mmuBus.cmd.isValid := io.cpu.memory.isValid - io.cpu.memory.mmuBus.cmd.virtualAddress := io.cpu.memory.address - io.cpu.memory.mmuBus.cmd.bypassTranslation := False - io.cpu.memory.mmuBus.end := !io.cpu.memory.isStuck || io.cpu.memory.isRemoved io.cpu.memory.isWrite := request.wr val isAmo = if(withAmo) request.isAmo else False @@ -634,8 +629,8 @@ class DataCache(val p : DataCacheConfig, mmuParameter : MemoryTranslatorBusParam val o = CombInit(sync.w2o.busy) val i = CombInit(sync.w2i.busy) - val s = io.cpu.memory.mmuBus.rsp.isIoAccess ? o | w - val l = io.cpu.memory.mmuBus.rsp.isIoAccess ? i | r + val s = io.cpu.memory.mmuRsp.isIoAccess ? o | w + val l = io.cpu.memory.mmuRsp.isIoAccess ? i | r when(isAmo? (s || l) | (request.wr ? s | l)){ hazard := True @@ -647,15 +642,15 @@ class DataCache(val p : DataCacheConfig, mmuParameter : MemoryTranslatorBusParam val wayHits = earlyWaysHits generate Bits(wayCount bits) val indirectTlbHitGen = (earlyWaysHits && !directTlbHit) generate new Area { - wayHits := B(ways.map(way => (io.cpu.memory.mmuBus.rsp.physicalAddress(tagRange) === way.tagsReadRsp.address && way.tagsReadRsp.valid))) + wayHits := B(ways.map(way => (io.cpu.memory.mmuRsp.physicalAddress(tagRange) === way.tagsReadRsp.address && way.tagsReadRsp.valid))) } val directTlbHitGen = (earlyWaysHits && directTlbHit) generate new Area { - val wayTlbHits = for (way <- ways) yield for (tlb <- io.cpu.memory.mmuBus.rsp.ways) yield { + val wayTlbHits = for (way <- ways) yield for (tlb <- io.cpu.memory.mmuRsp.ways) yield { way.tagsReadRsp.address === tlb.physical(tagRange) && tlb.sel } val translatedHits = B(wayTlbHits.map(_.orR)) val bypassHits = B(ways.map(_.tagsReadRsp.address === io.cpu.memory.address(tagRange))) - wayHits := (io.cpu.memory.mmuBus.rsp.bypassTranslation ? bypassHits | translatedHits) & B(ways.map(_.tagsReadRsp.valid)) + wayHits := (io.cpu.memory.mmuRsp.bypassTranslation ? bypassHits | translatedHits) & B(ways.map(_.tagsReadRsp.valid)) } val dataMux = earlyDataMux generate MuxOH(wayHits, ways.map(_.dataReadRsp)) @@ -673,7 +668,7 @@ class DataCache(val p : DataCacheConfig, mmuParameter : MemoryTranslatorBusParam def ramPipe[T <: Data](that : T) = if(mergeExecuteMemory) CombInit(that) else RegNextWhen(that, !io.cpu.writeBack.isStuck) val request = RegNextWhen(stageA.request, !io.cpu.writeBack.isStuck) val mmuRspFreeze = False - val mmuRsp = RegNextWhen(io.cpu.memory.mmuBus.rsp, !io.cpu.writeBack.isStuck && !mmuRspFreeze) + val mmuRsp = RegNextWhen(io.cpu.memory.mmuRsp, !io.cpu.writeBack.isStuck && !mmuRspFreeze) val tagsReadRsp = ways.map(w => ramPipe(w.tagsReadRsp)) val dataReadRsp = !earlyDataMux generate ways.map(w => ramPipe(w.dataReadRsp)) val wayInvalidate = stagePipe(stageA. wayInvalidate) diff --git a/src/main/scala/vexriscv/ip/InstructionCache.scala b/src/main/scala/vexriscv/ip/InstructionCache.scala index aedd6af2..6053c0f1 100644 --- a/src/main/scala/vexriscv/ip/InstructionCache.scala +++ b/src/main/scala/vexriscv/ip/InstructionCache.scala @@ -429,9 +429,9 @@ class InstructionCache(p : InstructionCacheConfig, mmuParameter : MemoryTranslat io.cpu.fetch.data := (if(p.bypassGen) (io.cpu.fetch.dataBypassValid ? io.cpu.fetch.dataBypass | cacheData) else cacheData) } - io.cpu.fetch.mmuBus.cmd.isValid := io.cpu.fetch.isValid - io.cpu.fetch.mmuBus.cmd.virtualAddress := io.cpu.fetch.pc - io.cpu.fetch.mmuBus.cmd.bypassTranslation := False + io.cpu.fetch.mmuBus.cmd.last.isValid := io.cpu.fetch.isValid + io.cpu.fetch.mmuBus.cmd.last.virtualAddress := io.cpu.fetch.pc + io.cpu.fetch.mmuBus.cmd.last.bypassTranslation := False io.cpu.fetch.mmuBus.end := !io.cpu.fetch.isStuck || io.cpu.fetch.isRemoved io.cpu.fetch.physicalAddress := io.cpu.fetch.mmuBus.rsp.physicalAddress diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index 96e1b1bd..f1336160 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -170,6 +170,10 @@ class DBusCachedPlugin(val config : DataCacheConfig, import pipeline._ import pipeline.config._ + val twoStageMmu = mmuBus.p.latency match { + case 0 => false + case 1 => true + } val cache = new DataCache( this.config.copy( @@ -242,6 +246,12 @@ class DBusCachedPlugin(val config : DataCacheConfig, ) cache.io.cpu.execute.args.size := size + if(twoStageMmu) { + mmuBus.cmd(0).isValid := cache.io.cpu.execute.isValid + mmuBus.cmd(0).isStuck := arbitration.isStuck + mmuBus.cmd(0).virtualAddress := cache.io.cpu.execute.address + mmuBus.cmd(0).bypassTranslation := False + } cache.io.cpu.flush.valid := arbitration.isValid && input(MEMORY_MANAGMENT) cache.io.cpu.execute.args.totalyConsistent := input(MEMORY_FORCE_CONSTISTENCY) @@ -281,11 +291,15 @@ class DBusCachedPlugin(val config : DataCacheConfig, cache.io.cpu.memory.isValid := arbitration.isValid && input(MEMORY_ENABLE) cache.io.cpu.memory.isStuck := arbitration.isStuck - cache.io.cpu.memory.isRemoved := arbitration.removeIt cache.io.cpu.memory.address := (if(relaxedMemoryTranslationRegister) input(MEMORY_VIRTUAL_ADDRESS) else if(mmuAndBufferStage == execute) cache.io.cpu.execute.address else U(input(REGFILE_WRITE_DATA))) - cache.io.cpu.memory.mmuBus <> mmuBus - cache.io.cpu.memory.mmuBus.rsp.isIoAccess setWhen(pipeline(DEBUG_BYPASS_CACHE) && !cache.io.cpu.memory.isWrite) + mmuBus.cmd.last.isValid := cache.io.cpu.memory.isValid + mmuBus.cmd.last.isStuck := cache.io.cpu.memory.isStuck + mmuBus.cmd.last.virtualAddress := cache.io.cpu.memory.address + mmuBus.cmd.last.bypassTranslation := False + 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) } val managementStage = stages.last @@ -397,9 +411,9 @@ class DBusCachedPlugin(val config : DataCacheConfig, } } execute.insert(IS_DBUS_SHARING) := dBusAccess.cmd.fire + mmuBus.cmd.last.bypassTranslation setWhen(mmuAndBufferStage.input(IS_DBUS_SHARING)) + if(twoStageMmu) mmuBus.cmd(0).bypassTranslation setWhen(execute.input(IS_DBUS_SHARING)) - - mmuBus.cmd.bypassTranslation setWhen(mmuAndBufferStage.input(IS_DBUS_SHARING)) if(mmuAndBufferStage != execute) (cache.io.cpu.memory.isValid setWhen(mmuAndBufferStage.input(IS_DBUS_SHARING))) cache.io.cpu.writeBack.isValid setWhen(managementStage.input(IS_DBUS_SHARING)) dBusAccess.rsp.valid := managementStage.input(IS_DBUS_SHARING) && !cache.io.cpu.writeBack.isWrite && (cache.io.cpu.redo || !cache.io.cpu.writeBack.haltIt) diff --git a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala index 819fc8f9..ba896fae 100644 --- a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala @@ -449,9 +449,10 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, insert(FORMAL_MEM_WDATA) := dBus.cmd.payload.data val mmu = (mmuBus != null) generate new Area { - mmuBus.cmd.isValid := arbitration.isValid && input(MEMORY_ENABLE) - mmuBus.cmd.virtualAddress := input(SRC_ADD).asUInt - mmuBus.cmd.bypassTranslation := False + mmuBus.cmd.last.isValid := arbitration.isValid && input(MEMORY_ENABLE) + mmuBus.cmd.last.isStuck := arbitration.isStuck + mmuBus.cmd.last.virtualAddress := input(SRC_ADD).asUInt + mmuBus.cmd.last.bypassTranslation := False mmuBus.end := !arbitration.isStuck || arbitration.isRemoved dBus.cmd.address := mmuBus.rsp.physicalAddress diff --git a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala index be08cdad..4d417908 100644 --- a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala @@ -124,7 +124,7 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l, import pipeline.config._ pipeline plug new FetchArea(pipeline) { - val cache = new InstructionCache(IBusCachedPlugin.this.config.copy(bypassGen = tightlyGen), mmuBus.p) + val cache = new InstructionCache(IBusCachedPlugin.this.config.copy(bypassGen = tightlyGen), if(mmuBus != null) mmuBus.p else MemoryTranslatorBusParameter(0,0)) iBus = master(new InstructionCacheMemBus(IBusCachedPlugin.this.config)).setName("iBus") iBus <> cache.io.mem iBus.cmd.address.allowOverride := cache.io.mem.cmd.address @@ -251,7 +251,7 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l, 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.physicalAddress := cache.io.cpu.fetch.mmuBus.cmd.last.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 diff --git a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala index b8bc9782..19145f54 100644 --- a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala @@ -318,9 +318,9 @@ class IBusSimplePlugin( resetVector : BigInt, } val mmu = (mmuBus != null) generate new Area { - mmuBus.cmd.isValid := cmdForkStage.input.valid - mmuBus.cmd.virtualAddress := cmdForkStage.input.payload - mmuBus.cmd.bypassTranslation := False + mmuBus.cmd.last.isValid := cmdForkStage.input.valid + mmuBus.cmd.last.virtualAddress := cmdForkStage.input.payload + mmuBus.cmd.last.bypassTranslation := False mmuBus.end := cmdForkStage.output.fire || externalFlush cmd.pc := mmuBus.rsp.physicalAddress(31 downto 2) @@ U"00" diff --git a/src/main/scala/vexriscv/plugin/MemoryTranslatorPlugin.scala b/src/main/scala/vexriscv/plugin/MemoryTranslatorPlugin.scala index c8c00ecf..081b11d2 100644 --- a/src/main/scala/vexriscv/plugin/MemoryTranslatorPlugin.scala +++ b/src/main/scala/vexriscv/plugin/MemoryTranslatorPlugin.scala @@ -70,17 +70,17 @@ class MemoryTranslatorPlugin(tlbSize : Int, val ports = for ((port, portId) <- sortedPortsInfo.zipWithIndex) yield new Area { val cache = Vec(Reg(CacheLine()) init, port.args.portTlbSize) - val cacheHits = cache.map(line => line.valid && line.virtualAddress === port.bus.cmd.virtualAddress(31 downto 12)) + val cacheHits = cache.map(line => line.valid && line.virtualAddress === port.bus.cmd.last.virtualAddress(31 downto 12)) val cacheHit = cacheHits.asBits.orR val cacheLine = MuxOH(cacheHits, cache) - val isInMmuRange = virtualRange(port.bus.cmd.virtualAddress) && !port.bus.cmd.bypassTranslation + val isInMmuRange = virtualRange(port.bus.cmd.last.virtualAddress) && !port.bus.cmd.last.bypassTranslation val sharedMiss = RegInit(False) val sharedIterator = Reg(UInt(log2Up(tlbSize + 1) bits)) val sharedAccessed = RegInit(B"00") val entryToReplace = Counter(port.args.portTlbSize) - val sharedAccessAsked = RegNext(port.bus.cmd.isValid && !cacheHit && sharedIterator < tlbSize && isInMmuRange) + val sharedAccessAsked = RegNext(port.bus.cmd.last.isValid && !cacheHit && sharedIterator < tlbSize && isInMmuRange) val sharedAccessGranted = sharedAccessAsked && shared.free when(sharedAccessGranted) { shared.readAddr := sharedIterator.resized @@ -92,7 +92,7 @@ class MemoryTranslatorPlugin(tlbSize : Int, } when(sharedAccessed.msb){ - when(shared.readData.virtualAddress === port.bus.cmd.virtualAddress(31 downto 12)){ + when(shared.readData.virtualAddress === port.bus.cmd.last.virtualAddress(31 downto 12)){ cache(entryToReplace) := shared.readData entryToReplace.increment() } @@ -108,7 +108,7 @@ class MemoryTranslatorPlugin(tlbSize : Int, when(isInMmuRange) { - port.bus.rsp.physicalAddress := cacheLine.physicalAddress @@ port.bus.cmd.virtualAddress(11 downto 0) + port.bus.rsp.physicalAddress := cacheLine.physicalAddress @@ port.bus.cmd.last.virtualAddress(11 downto 0) port.bus.rsp.allowRead := cacheLine.allowRead port.bus.rsp.allowWrite := cacheLine.allowWrite port.bus.rsp.allowExecute := cacheLine.allowExecute @@ -116,7 +116,7 @@ class MemoryTranslatorPlugin(tlbSize : Int, // port.bus.rsp.hit := cacheHit // port.stage.arbitration.haltItself setWhen (port.bus.cmd.isValid && !cacheHit && !sharedMiss) } otherwise { - port.bus.rsp.physicalAddress := port.bus.cmd.virtualAddress + port.bus.rsp.physicalAddress := port.bus.cmd.last.virtualAddress port.bus.rsp.allowRead := True port.bus.rsp.allowWrite := True port.bus.rsp.allowExecute := True diff --git a/src/main/scala/vexriscv/plugin/MmuPlugin.scala b/src/main/scala/vexriscv/plugin/MmuPlugin.scala index 884a2d55..e797bcfa 100644 --- a/src/main/scala/vexriscv/plugin/MmuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/MmuPlugin.scala @@ -34,9 +34,9 @@ object MmuPort{ val PRIORITY_DATA = 1 val PRIORITY_INSTRUCTION = 0 } -case class MmuPort(bus : MemoryTranslatorBus, priority : Int, args : MmuPortConfig, id : Int/*, exceptionBus: Flow[ExceptionCause]*/) +case class MmuPort(bus : MemoryTranslatorBus, priority : Int, args : MmuPortConfig, id : Int) -case class MmuPortConfig(portTlbSize : Int) +case class MmuPortConfig(portTlbSize : Int, latency : Int = 0, earlyRequireMmuLockup : Boolean = false, earlyCacheHits : Boolean = false) class MmuPlugin(ioRange : UInt => Bool, virtualRange : UInt => Bool = address => True, @@ -48,7 +48,7 @@ class MmuPlugin(ioRange : UInt => Bool, override def newTranslationPort(priority : Int,args : Any): MemoryTranslatorBus = { val config = args.asInstanceOf[MmuPortConfig] - val port = MmuPort(MemoryTranslatorBus(MemoryTranslatorBusParameter(wayCount = config.portTlbSize)),priority, config, portsInfo.length) + val port = MmuPort(MemoryTranslatorBus(MemoryTranslatorBusParameter(wayCount = config.portTlbSize, latency = config.latency)),priority, config, portsInfo.length) portsInfo += port port.bus } @@ -103,33 +103,51 @@ class MmuPlugin(ioRange : UInt => Bool, val ports = for (port <- sortedPortsInfo) yield new Area { val handle = port val id = port.id - val cache = Vec(Reg(CacheLine()) init, port.args.portTlbSize) - val cacheHits = cache.map(line => line.valid && line.virtualAddress(1) === port.bus.cmd.virtualAddress(31 downto 22) && (line.superPage || line.virtualAddress(0) === port.bus.cmd.virtualAddress(21 downto 12))) - val cacheHit = cacheHits.asBits.orR - val cacheLine = MuxOH(cacheHits, cache) val privilegeService = pipeline.serviceElse(classOf[PrivilegeService], PrivilegeServiceDefault()) - val entryToReplace = Counter(port.args.portTlbSize) - val requireMmuLockup = virtualRange(port.bus.cmd.virtualAddress) && !port.bus.cmd.bypassTranslation && csr.satp.mode + val cache = Vec(Reg(CacheLine()) init, port.args.portTlbSize) + + def toRsp[T <: Data](data : T, from : MemoryTranslatorCmd) : T = from match { + case _ if from == port.bus.cmd.last => data + case _ => { + val next = port.bus.cmd.dropWhile(_ != from)(1) + toRsp(RegNextWhen(data, !next.isStuck), next) + } + } + val requireMmuLockupCmd = port.bus.cmd.takeRight(if(port.args.earlyRequireMmuLockup) 2 else 1).head + + val requireMmuLockupCalc = virtualRange(requireMmuLockupCmd.virtualAddress) && !requireMmuLockupCmd.bypassTranslation && csr.satp.mode if(!enableMmuInMachineMode) { - requireMmuLockup clearWhen(!csr.status.mprv && privilegeService.isMachine()) + requireMmuLockupCalc clearWhen(!csr.status.mprv && privilegeService.isMachine()) when(privilegeService.isMachine()) { if (port.priority == MmuPort.PRIORITY_DATA) { - requireMmuLockup clearWhen (!csr.status.mprv || pipeline(MPP) === 3) + requireMmuLockupCalc clearWhen (!csr.status.mprv || pipeline(MPP) === 3) } else { - requireMmuLockup := False + requireMmuLockupCalc := False } } } + val cacheHitsCmd = port.bus.cmd.takeRight(if(port.args.earlyCacheHits) 2 else 1).head + val cacheHitsCalc = B(cache.map(line => line.valid && line.virtualAddress(1) === cacheHitsCmd.virtualAddress(31 downto 22) && (line.superPage || line.virtualAddress(0) === cacheHitsCmd.virtualAddress(21 downto 12)))) + + + val requireMmuLockup = toRsp(requireMmuLockupCalc, requireMmuLockupCmd) + val cacheHits = toRsp(cacheHitsCalc, cacheHitsCmd) + + val cacheHit = cacheHits.asBits.orR + val cacheLine = MuxOH(cacheHits, cache) + val entryToReplace = Counter(port.args.portTlbSize) + + when(requireMmuLockup) { - port.bus.rsp.physicalAddress := cacheLine.physicalAddress(1) @@ (cacheLine.superPage ? port.bus.cmd.virtualAddress(21 downto 12) | cacheLine.physicalAddress(0)) @@ port.bus.cmd.virtualAddress(11 downto 0) + port.bus.rsp.physicalAddress := cacheLine.physicalAddress(1) @@ (cacheLine.superPage ? port.bus.cmd.last.virtualAddress(21 downto 12) | cacheLine.physicalAddress(0)) @@ port.bus.cmd.last.virtualAddress(11 downto 0) port.bus.rsp.allowRead := cacheLine.allowRead || csr.status.mxr && cacheLine.allowExecute port.bus.rsp.allowWrite := cacheLine.allowWrite port.bus.rsp.allowExecute := cacheLine.allowExecute port.bus.rsp.exception := cacheHit && (cacheLine.exception || cacheLine.allowUser && privilegeService.isSupervisor() && !csr.status.sum || !cacheLine.allowUser && privilegeService.isUser()) port.bus.rsp.refilling := !cacheHit } otherwise { - port.bus.rsp.physicalAddress := port.bus.cmd.virtualAddress + port.bus.rsp.physicalAddress := port.bus.cmd.last.virtualAddress port.bus.rsp.allowRead := True port.bus.rsp.allowWrite := True port.bus.rsp.allowExecute := True @@ -141,7 +159,7 @@ class MmuPlugin(ioRange : UInt => Bool, port.bus.rsp.bypassTranslation := !requireMmuLockup for(wayId <- 0 until port.args.portTlbSize){ port.bus.rsp.ways(wayId).sel := cacheHits(wayId) - port.bus.rsp.ways(wayId).physical := cache(wayId).physicalAddress(1) @@ (cache(wayId).superPage ? port.bus.cmd.virtualAddress(21 downto 12) | cache(wayId).physicalAddress(0)) @@ port.bus.cmd.virtualAddress(11 downto 0) + port.bus.rsp.ways(wayId).physical := cache(wayId).physicalAddress(1) @@ (cache(wayId).superPage ? port.bus.cmd.last.virtualAddress(21 downto 12) | cache(wayId).physicalAddress(0)) @@ port.bus.cmd.last.virtualAddress(11 downto 0) } // Avoid keeping any invalid line in the cache after an exception. @@ -186,13 +204,13 @@ class MmuPlugin(ioRange : UInt => Bool, dBusAccess.cmd.data.assignDontCare() dBusAccess.cmd.writeMask.assignDontCare() - val refills = OHMasking.last(B(sortedPortsInfo.map(port => port.bus.cmd.isValid && port.bus.rsp.refilling))) + val refills = OHMasking.last(B(sortedPortsInfo.map(port => port.bus.cmd.last.isValid && port.bus.rsp.refilling))) switch(state){ is(State.IDLE){ when(refills.orR){ portSortedOh := refills state := State.L1_CMD - val address = MuxOH(refills, sortedPortsInfo.map(_.bus.cmd.virtualAddress)) + val address = MuxOH(refills, sortedPortsInfo.map(_.bus.cmd.last.virtualAddress)) vpn(1) := address(31 downto 22) vpn(0) := address(21 downto 12) } diff --git a/src/main/scala/vexriscv/plugin/StaticMemoryTranslatorPlugin.scala b/src/main/scala/vexriscv/plugin/StaticMemoryTranslatorPlugin.scala index cbe55f9b..bc910c04 100644 --- a/src/main/scala/vexriscv/plugin/StaticMemoryTranslatorPlugin.scala +++ b/src/main/scala/vexriscv/plugin/StaticMemoryTranslatorPlugin.scala @@ -26,7 +26,7 @@ class StaticMemoryTranslatorPlugin(ioRange : UInt => Bool) extends Plugin[VexRis val core = pipeline plug new Area { val ports = for ((port, portId) <- portsInfo.zipWithIndex) yield new Area { - port.bus.rsp.physicalAddress := port.bus.cmd.virtualAddress + port.bus.rsp.physicalAddress := port.bus.cmd.last.virtualAddress port.bus.rsp.allowRead := True port.bus.rsp.allowWrite := True port.bus.rsp.allowExecute := True diff --git a/src/test/scala/vexriscv/TestIndividualFeatures.scala b/src/test/scala/vexriscv/TestIndividualFeatures.scala index c31a30a6..33a3857b 100644 --- a/src/test/scala/vexriscv/TestIndividualFeatures.scala +++ b/src/test/scala/vexriscv/TestIndividualFeatures.scala @@ -405,13 +405,12 @@ class DBusDimension extends VexRiscvDimension("DBus") { override def randomPositionImpl(universes: Seq[ConfigUniverse], r: Random) = { val catchAll = universes.contains(VexRiscvUniverse.CATCH_ALL) - val mmuConfig = if(universes.contains(VexRiscvUniverse.MMU)) MmuPortConfig( portTlbSize = 4) else null val noMemory = universes.contains(VexRiscvUniverse.NO_MEMORY) val noWriteBack = universes.contains(VexRiscvUniverse.NO_WRITEBACK) - if(r.nextDouble() < 0.4 || noMemory){ + val mmuConfig = if(universes.contains(VexRiscvUniverse.MMU)) MmuPortConfig( portTlbSize = 4, latency = 0) else null val withLrSc = catchAll val earlyInjection = r.nextBoolean() && !universes.contains(VexRiscvUniverse.NO_WRITEBACK) new VexRiscvPosition("Simple" + (if(earlyInjection) "Early" else "Late")) { @@ -426,6 +425,8 @@ class DBusDimension extends VexRiscvDimension("DBus") { // override def isCompatibleWith(positions: Seq[ConfigPosition[VexRiscvConfig]]) = catchAll == positions.exists(_.isInstanceOf[CatchAllPosition]) } } else { + val twoStageMmu = r.nextBoolean() && !noMemory && !noWriteBack + val mmuConfig = if(universes.contains(VexRiscvUniverse.MMU)) MmuPortConfig(portTlbSize = 4, latency = if(twoStageMmu) 1 else 0, earlyRequireMmuLockup = Random.nextBoolean() && twoStageMmu, earlyCacheHits = Random.nextBoolean() && twoStageMmu) else null val memDataWidth = List(32,64,128)(r.nextInt(3)) val bytePerLine = Math.max(memDataWidth/8, List(8,16,32,64)(r.nextInt(4))) var cacheSize = 0 @@ -443,7 +444,7 @@ class DBusDimension extends VexRiscvDimension("DBus") { cacheSize = 512 << r.nextInt(5) wayCount = 1 << r.nextInt(3) }while(cacheSize/wayCount < 512 || (catchAll && cacheSize/wayCount > 4096)) - new VexRiscvPosition(s"Cached${memDataWidth}d" + "S" + cacheSize + "W" + wayCount + "BPL" + bytePerLine + (if(dBusCmdMasterPipe) "Cmp " else "") + (if(dBusCmdSlavePipe) "Csp " else "") + (if(dBusRspSlavePipe) "Rsp " else "") + (if(relaxedMemoryTranslationRegister) "Rmtr " else "") + (if(earlyWaysHits) "Ewh " else "") + (if(withAmo) "Amo " else "") + (if(withSmp) "Smp " else "") + (if(directTlbHit) "Dtlb " else "")) { + new VexRiscvPosition(s"Cached${memDataWidth}d" + "S" + cacheSize + "W" + wayCount + "BPL" + bytePerLine + (if(dBusCmdMasterPipe) "Cmp " else "") + (if(dBusCmdSlavePipe) "Csp " else "") + (if(dBusRspSlavePipe) "Rsp " else "") + (if(relaxedMemoryTranslationRegister) "Rmtr " else "") + (if(earlyWaysHits) "Ewh " else "") + (if(withAmo) "Amo " else "") + (if(withSmp) "Smp " else "") + (if(directTlbHit) "Dtlb " else "") + (if(twoStageMmu) "Tsmmu " else "")) { override def testParam = s"DBUS=CACHED DBUS_DATA_WIDTH=$memDataWidth " + (if(withLrSc) "LRSC=yes " else "") + (if(withAmo) "AMO=yes " else "") + (if(withSmp) "DBUS_EXCLUSIVE=yes DBUS_INVALIDATE=yes " else "") override def applyOn(config: VexRiscvConfig): Unit = { From 0e76cf9ac8e385de06b53b98648d552e263e3440 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 7 May 2020 22:50:25 +0200 Subject: [PATCH 424/951] i$ now support multi cycle MMU --- .../scala/vexriscv/ip/InstructionCache.scala | 20 ++++------- .../vexriscv/plugin/IBusCachedPlugin.scala | 35 ++++++++++++------- .../vexriscv/TestIndividualFeatures.scala | 8 ++++- 3 files changed, 37 insertions(+), 26 deletions(-) diff --git a/src/main/scala/vexriscv/ip/InstructionCache.scala b/src/main/scala/vexriscv/ip/InstructionCache.scala index 6053c0f1..43f51300 100644 --- a/src/main/scala/vexriscv/ip/InstructionCache.scala +++ b/src/main/scala/vexriscv/ip/InstructionCache.scala @@ -112,16 +112,15 @@ case class InstructionCacheCpuFetch(p : InstructionCacheConfig, mmuParameter : M val data = Bits(p.cpuDataWidth bits) val dataBypassValid = p.bypassGen generate Bool() val dataBypass = p.bypassGen generate Bits(p.cpuDataWidth bits) - val mmuBus = MemoryTranslatorBus(mmuParameter) + val mmuRsp = MemoryTranslatorRsp(mmuParameter) val physicalAddress = UInt(p.addressWidth bits) val cacheMiss, error, mmuRefilling, mmuException, isUser = ifGen(!p.twoCycleCache)(Bool) - val haltIt = Bool() //Used to wait on the MMU rsp busy override def asMaster(): Unit = { out(isValid, isStuck, isRemoved, pc) - inWithNull(error,mmuRefilling,mmuException,data, cacheMiss,physicalAddress, haltIt) + inWithNull(error,mmuRefilling,mmuException,data, cacheMiss,physicalAddress) outWithNull(isUser, dataBypass, dataBypassValid) - slaveWithNull(mmuBus) + out(mmuRsp) } } @@ -321,7 +320,6 @@ class InstructionCache(p : InstructionCacheConfig, mmuParameter : MemoryTranslat } }) - io.cpu.fetch.haltIt := io.cpu.fetch.mmuBus.busy val lineLoader = new Area{ val fire = False @@ -412,7 +410,7 @@ class InstructionCache(p : InstructionCacheConfig, mmuParameter : MemoryTranslat val hit = (!twoCycleRam) generate new Area{ - val hits = read.waysValues.map(way => way.tag.valid && way.tag.address === io.cpu.fetch.mmuBus.rsp.physicalAddress(tagRange)) + val hits = read.waysValues.map(way => way.tag.valid && way.tag.address === io.cpu.fetch.mmuRsp.physicalAddress(tagRange)) val valid = Cat(hits).orR val id = OHToUInt(hits) val error = read.waysValues.map(_.tag.error).read(id) @@ -429,14 +427,10 @@ class InstructionCache(p : InstructionCacheConfig, mmuParameter : MemoryTranslat io.cpu.fetch.data := (if(p.bypassGen) (io.cpu.fetch.dataBypassValid ? io.cpu.fetch.dataBypass | cacheData) else cacheData) } - io.cpu.fetch.mmuBus.cmd.last.isValid := io.cpu.fetch.isValid - io.cpu.fetch.mmuBus.cmd.last.virtualAddress := io.cpu.fetch.pc - io.cpu.fetch.mmuBus.cmd.last.bypassTranslation := False - io.cpu.fetch.mmuBus.end := !io.cpu.fetch.isStuck || io.cpu.fetch.isRemoved - io.cpu.fetch.physicalAddress := io.cpu.fetch.mmuBus.rsp.physicalAddress + io.cpu.fetch.physicalAddress := io.cpu.fetch.mmuRsp.physicalAddress val resolution = ifGen(!twoCycleCache)( new Area{ - val mmuRsp = io.cpu.fetch.mmuBus.rsp + val mmuRsp = io.cpu.fetch.mmuRsp io.cpu.fetch.cacheMiss := !hit.valid io.cpu.fetch.error := hit.error @@ -449,7 +443,7 @@ class InstructionCache(p : InstructionCacheConfig, mmuParameter : MemoryTranslat val decodeStage = ifGen(twoCycleCache) (new Area{ def stage[T <: Data](that : T) = RegNextWhen(that,!io.cpu.decode.isStuck) - val mmuRsp = stage(io.cpu.fetch.mmuBus.rsp) + val mmuRsp = stage(io.cpu.fetch.mmuRsp) val hit = if(!twoCycleRam) new Area{ val valid = stage(fetchStage.hit.valid) diff --git a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala index 4d417908..e23cec7a 100644 --- a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala @@ -155,8 +155,13 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l, cache.io.cpu.prefetch.pc := stages(0).input.payload stages(0).halt setWhen (cache.io.cpu.prefetch.haltIt) - - cache.io.cpu.fetch.isRemoved := externalFlush + if(mmuBus != null && mmuBus.p.latency == 1) { + stages(0).halt setWhen(mmuBus.busy) + mmuBus.cmd(0).isValid := cache.io.cpu.prefetch.isValid + mmuBus.cmd(0).isStuck := !stages(0).input.ready + mmuBus.cmd(0).virtualAddress := cache.io.cpu.prefetch.pc + mmuBus.cmd(0).bypassTranslation := False + } } @@ -172,8 +177,15 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l, cache.io.cpu.fetch.isStuck := !stages(1).input.ready cache.io.cpu.fetch.pc := stages(1).input.payload + if(mmuBus != null) { + mmuBus.cmd.last.isValid := cache.io.cpu.fetch.isValid + mmuBus.cmd.last.isStuck := !stages(1).input.ready + mmuBus.cmd.last.virtualAddress := cache.io.cpu.fetch.pc + mmuBus.cmd.last.bypassTranslation := False + mmuBus.end := stages(1).input.ready || externalFlush + if (mmuBus.p.latency == 0) stages(1).halt setWhen (mmuBus.busy) + } - stages(1).halt setWhen(cache.io.cpu.fetch.haltIt) if (!twoCycleCache) { cache.io.cpu.fetch.isUser := privilegeService.isUser() @@ -249,16 +261,15 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l, } if (mmuBus != null) { - cache.io.cpu.fetch.mmuBus <> mmuBus + cache.io.cpu.fetch.mmuRsp <> mmuBus.rsp } else { - cache.io.cpu.fetch.mmuBus.rsp.physicalAddress := cache.io.cpu.fetch.mmuBus.cmd.last.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.isIoAccess := False - cache.io.cpu.fetch.mmuBus.rsp.exception := False - cache.io.cpu.fetch.mmuBus.rsp.refilling := False - cache.io.cpu.fetch.mmuBus.busy := False + cache.io.cpu.fetch.mmuRsp.physicalAddress := cache.io.cpu.fetch.pc + cache.io.cpu.fetch.mmuRsp.allowExecute := True + cache.io.cpu.fetch.mmuRsp.allowRead := True + cache.io.cpu.fetch.mmuRsp.allowWrite := True + cache.io.cpu.fetch.mmuRsp.isIoAccess := False + cache.io.cpu.fetch.mmuRsp.exception := False + cache.io.cpu.fetch.mmuRsp.refilling := False } val flushStage = decode diff --git a/src/test/scala/vexriscv/TestIndividualFeatures.scala b/src/test/scala/vexriscv/TestIndividualFeatures.scala index 33a3857b..66b308be 100644 --- a/src/test/scala/vexriscv/TestIndividualFeatures.scala +++ b/src/test/scala/vexriscv/TestIndividualFeatures.scala @@ -321,9 +321,12 @@ class IBusDimension(rvcRate : Double) extends VexRiscvDimension("IBus") { override def randomPositionImpl(universes: Seq[ConfigUniverse], r: Random) = { val catchAll = universes.contains(VexRiscvUniverse.CATCH_ALL) - val mmuConfig = if(universes.contains(VexRiscvUniverse.MMU)) MmuPortConfig( portTlbSize = 4) else null + val noMemory = universes.contains(VexRiscvUniverse.NO_MEMORY) + val noWriteBack = universes.contains(VexRiscvUniverse.NO_WRITEBACK) + if(r.nextDouble() < 0.5){ + val mmuConfig = if(universes.contains(VexRiscvUniverse.MMU)) MmuPortConfig( portTlbSize = 4) else null val latency = r.nextInt(5) + 1 val compressed = r.nextDouble() < rvcRate val injectorStage = r.nextBoolean() || latency == 1 @@ -347,6 +350,9 @@ class IBusDimension(rvcRate : Double) extends VexRiscvDimension("IBus") { override def instructionAnticipatedOk() = injectorStage } } else { + val twoStageMmu = r.nextBoolean() + val mmuConfig = if(universes.contains(VexRiscvUniverse.MMU)) MmuPortConfig(portTlbSize = 4, latency = if(twoStageMmu) 1 else 0, earlyRequireMmuLockup = Random.nextBoolean() && twoStageMmu, earlyCacheHits = Random.nextBoolean() && twoStageMmu) else null + val catchAll = universes.contains(VexRiscvUniverse.CATCH_ALL) val compressed = r.nextDouble() < rvcRate val tighlyCoupled = r.nextBoolean() && !catchAll From 0a159f06b23d59a567c3b28aaa3abc68cd87c26b Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 7 May 2020 22:50:36 +0200 Subject: [PATCH 425/951] update smp config --- src/main/scala/vexriscv/TestsWorkspace.scala | 10 +++++++--- .../scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala | 11 ++++++++--- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/main/scala/vexriscv/TestsWorkspace.scala b/src/main/scala/vexriscv/TestsWorkspace.scala index b97936d7..e25b2b79 100644 --- a/src/main/scala/vexriscv/TestsWorkspace.scala +++ b/src/main/scala/vexriscv/TestsWorkspace.scala @@ -68,13 +68,15 @@ object TestsWorkspace { catchIllegalAccess = true, catchAccessFault = true, asyncTagMemory = false, - twoCycleRam = false, + twoCycleRam = true, twoCycleCache = true // ) ), memoryTranslatorPortConfig = MmuPortConfig( portTlbSize = 4, - latency = 0 + latency = 1, + earlyRequireMmuLockup = true, + earlyCacheHits = true ) ), // ).newTightlyCoupledPort(TightlyCoupledPortParameter("iBusTc", a => a(30 downto 28) === 0x0 && a(5))), @@ -110,7 +112,9 @@ object TestsWorkspace { ), memoryTranslatorPortConfig = MmuPortConfig( portTlbSize = 4, - latency = 1 + latency = 1, + earlyRequireMmuLockup = true, + earlyCacheHits = true ) ), diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index 3f23a238..6efdf8fc 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -9,7 +9,7 @@ import spinal.lib.bus.bmb.{Bmb, BmbArbiter, BmbDecoder, BmbExclusiveMonitor, Bmb import spinal.lib.com.jtag.Jtag import spinal.lib.com.jtag.sim.JtagTcp import vexriscv.ip.{DataCacheAck, DataCacheConfig, DataCacheMemBus, InstructionCache, InstructionCacheConfig} -import vexriscv.plugin.{BranchPlugin, CsrPlugin, CsrPluginConfig, DBusCachedPlugin, DBusSimplePlugin, DebugPlugin, DecoderSimplePlugin, FullBarrelShifterPlugin, HazardSimplePlugin, IBusCachedPlugin, IBusSimplePlugin, IntAluPlugin, MmuPlugin, MmuPortConfig, MulDivIterativePlugin, MulPlugin, RegFilePlugin, STATIC, SrcPlugin, YamlPlugin} +import vexriscv.plugin.{BranchPlugin, CsrPlugin, CsrPluginConfig, DBusCachedPlugin, DBusSimplePlugin, DYNAMIC_TARGET, DebugPlugin, DecoderSimplePlugin, FullBarrelShifterPlugin, HazardSimplePlugin, IBusCachedPlugin, IBusSimplePlugin, IntAluPlugin, MmuPlugin, MmuPortConfig, MulDivIterativePlugin, MulPlugin, RegFilePlugin, STATIC, SrcPlugin, YamlPlugin} import vexriscv.{Riscv, VexRiscv, VexRiscvConfig, plugin} import scala.collection.mutable @@ -141,6 +141,8 @@ object VexRiscvSmpClusterGen { resetVector = resetVector, compressedGen = false, prediction = STATIC, + historyRamSizeLog2 = 9, + relaxPredictorAddress = true, injectorStage = false, relaxedPcCalculation = true, config = InstructionCacheConfig( @@ -153,12 +155,15 @@ object VexRiscvSmpClusterGen { catchIllegalAccess = true, catchAccessFault = true, asyncTagMemory = false, - twoCycleRam = true, + twoCycleRam = false, twoCycleCache = true // ) ), memoryTranslatorPortConfig = MmuPortConfig( - portTlbSize = 4 + portTlbSize = 4, + latency = 1, + earlyRequireMmuLockup = true, + earlyCacheHits = true ) ), // ).newTightlyCoupledPort(TightlyCoupledPortParameter("iBusTc", a => a(30 downto 28) === 0x0 && a(5))), From b592b0bff8d434dbcca4dc204d2b7bec2729adb4 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Sat, 9 May 2020 17:00:13 +0200 Subject: [PATCH 426/951] Add regression TRACE_SPORADIC, LINUX_SOC_SMP regression golden model now properly sync dut exceptions --- src/main/scala/vexriscv/TestsWorkspace.scala | 3 +- .../scala/vexriscv/plugin/CsrPlugin.scala | 3 +- src/test/cpp/regression/main.cpp | 124 +++++++++++++++++- src/test/cpp/regression/makefile | 16 +++ 4 files changed, 137 insertions(+), 9 deletions(-) diff --git a/src/main/scala/vexriscv/TestsWorkspace.scala b/src/main/scala/vexriscv/TestsWorkspace.scala index e25b2b79..8a785442 100644 --- a/src/main/scala/vexriscv/TestsWorkspace.scala +++ b/src/main/scala/vexriscv/TestsWorkspace.scala @@ -28,6 +28,7 @@ import spinal.lib.eda.altera.{InterruptReceiverTag, ResetEmitterTag} // make clean all SEED=42 MMU=no STOP_ON_ERROR=yes DBUS_EXCLUSIVE=yes DBUS_INVALIDATE=yes SUPERVISOR=yes REDO=1 DHRYSTONE=yes LRSC=yes AMO=yes LINUX_REGRESSION=yes TRACE=yes TRACE_START=1000000000 FLOW_INFO=ye IBUS_DATA_WIDTH=128 DBUS_DATA_WIDTH=128 +//make clean all SEED=42 MMU=no STOP_ON_ERROR=yes DBUS_EXCLUSIVE=yes DBUS_INVALIDATE=yes SUPERVISOR=yes REDO=1 DHRYSTONE=yes LRSC=yes AMO=yes TRACE=yes TRACE_START=1000000000 FLOW_INFO=ye IBUS_DATA_WIDTH=128 DBUS_DATA_WIDTH=128 LINUX_SOC_SMP=yes VMLINUX=../../../../../buildroot/output/images/Image RAMDISK=../../../../../buildroot/output/images/rootfs.cpio DTB=../../../../../buildroot/output/images/dtb EMULATOR=../../../../../opensbi/build/platform/spinal/vexriscv/sim/smp/firmware/fw_jump.bin object TestsWorkspace { def main(args: Array[String]) { def configFull = { @@ -156,7 +157,7 @@ object TestsWorkspace { divUnrollFactor = 1 ), // new DivPlugin, - new CsrPlugin(CsrPluginConfig.all2(0x80000020l).copy(ebreakGen = false)), + new CsrPlugin(CsrPluginConfig.all2(0x80000020l).copy(ebreakGen = false, misaExtensionsInit = Riscv.misaToInt("imas"))), // new CsrPlugin(//CsrPluginConfig.all2(0x80000020l).copy(ebreakGen = true)/* // CsrPluginConfig( // catchIllegalAccess = false, diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index bb56c3e7..43dbfaf0 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -8,6 +8,7 @@ import vexriscv.plugin.IntAluPlugin.{ALU_BITWISE_CTRL, ALU_CTRL, AluBitwiseCtrlE import scala.collection.mutable.ArrayBuffer import scala.collection.mutable +import spinal.core.sim._ /** * Created by spinalvm on 21.03.17. @@ -874,7 +875,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep interruptJump := interrupt.valid && pipelineLiberator.done && allowInterrupts if(pipelinedInterrupt) interrupt.valid clearWhen(interruptJump) //avoid double fireing - val hadException = RegNext(exception) init(False) + val hadException = RegNext(exception) init(False) addTag(Verilator.public) pipelineLiberator.done.clearWhen(hadException) diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index e0f50aba..717e5340 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -390,7 +390,7 @@ public: mcause.raw = 0; mbadaddr = 0; mepc = 0; - misa = 0; //TODO + misa = 0x40041101; //TODO status.raw = 0; status.mpp = 3; status.spp = 1; @@ -401,6 +401,7 @@ public: ipSoft = 0; ipInput = 0; stepCounter = 0; + sbadaddr = 42; lrscReserved = false; } @@ -513,7 +514,7 @@ public: pcWrite(xtvec.base << 2); if(interrupt) livenessInterrupt = 0; - if(!interrupt) step(); //As VexRiscv instruction which trap do not reach writeback stage fire +// if(!interrupt) step(); //As VexRiscv instruction which trap do not reach writeback stage fire } uint32_t currentInstruction; @@ -540,6 +541,7 @@ public: case MISA: *value = misa; break; case MEDELEG: *value = medeleg; break; case MIDELEG: *value = mideleg; break; + case MHARTID: *value = 0; break; case SSTATUS: *value = status.raw & 0xC0133; break; case SIP: *value = getIp().raw & 0x333; break; @@ -578,7 +580,7 @@ public: case MEPC: mepc = value; break; case MSCRATCH: mscratch = value; break; case MISA: misa = value; break; - case MEDELEG: medeleg = value; break; + case MEDELEG: medeleg = value & (~0x8); break; case MIDELEG: mideleg = value; break; case SSTATUS: maskedWrite(status.raw, value,0xC0133); break; @@ -1259,7 +1261,7 @@ public: top = new VVexRiscv; #ifdef TRACE_ACCESS regTraces.open (name + ".regTrace"); - memTraces.open (name + ".memTrace");hh + memTraces.open (name + ".memTrace"); #endif logTraces.open (name + ".logTrace"); debugLog.open (name + ".debugTrace"); @@ -1342,7 +1344,7 @@ public: #endif ) << #endif - " : WRITE mem" << (1 << size) << "[" << addr << "] = " << *data << endl; + " : WRITE mem" << hex << (1 << size) << "[" << addr << "] = " << *data << dec << endl; for(uint32_t b = 0;b < (1 << size);b++){ uint32_t offset = (addr+b)&0x3; if((mask >> offset) & 1 == 1) @@ -1356,6 +1358,7 @@ public: *data &= ~(0xFF << (offset*8)); *data |= mem[addr + b] << (offset*8); } + /* memTraces << #ifdef TRACE_WITH_TIME (currentTime @@ -1364,7 +1367,7 @@ public: #endif ) << #endif - " : READ mem" << (1 << size) << "[" << addr << "] = " << *data << endl; + " : READ mem" << (1 << size) << "[" << addr << "] = " << *data << endl;*/ } } @@ -1430,6 +1433,9 @@ public: #ifdef TRACE if(i == TRACE_START && i != 0) cout << "**" << endl << "**" << endl << "**" << endl << "**" << endl << "**" << endl << "START TRACE" << endl; if(i >= TRACE_START) tfp->dump(i); + #ifdef TRACE_SPORADIC + else if(i % 1000000 < 100) tfp->dump(i); + #endif #endif } @@ -1624,6 +1630,14 @@ public: } } + #ifdef CSR + if(top->VexRiscv->CsrPlugin_hadException){ + if(riscvRefEnable) { + riscvRef.step(); + } + } + #endif + for(SimElement* simElement : simElements) simElement->preCycle(); dump(i + 1); @@ -3451,7 +3465,6 @@ public: } }; - class LinuxRegression: public LinuxSoc{ public: string pendingLine = ""; @@ -3484,6 +3497,82 @@ public: #endif +#ifdef LINUX_SOC_SMP + +class LinuxSocSmp : public Workspace{ +public: + queue customCin; + void pushCin(string m){ + for(char& c : m) { + customCin.push(c); + } + } + + LinuxSocSmp(string name) : Workspace(name) { + #ifdef WITH_USER_IO + stdinNonBuffered(); + captureCtrlC(); + #endif + stdoutNonBuffered(); + } + + virtual ~LinuxSocSmp(){ + #ifdef WITH_USER_IO + stdinRestore(); + #endif + } + virtual bool isDBusCheckedRegion(uint32_t address){ return true;} + virtual bool isPerifRegion(uint32_t addr) { return (addr & 0xF0000000) == 0xF0000000;} + virtual bool isMmuRegion(uint32_t addr) { return true; } + + + + virtual void dBusAccess(uint32_t addr,bool wr, uint32_t size,uint32_t mask, uint32_t *data, bool *error) { + if(isPerifRegion(addr)) switch(addr){ + //TODO Emulate peripherals here + case 0xF0010000: if(wr && *data != 0) fail(); else *data = 0; break; + case 0xF001BFF8: if(wr) fail(); else *data = mTime; break; + case 0xF001BFFC: if(wr) fail(); else *data = mTime >> 32; break; + case 0xF0014000: if(wr) mTimeCmp = (mTimeCmp & 0xFFFFFFFF00000000) | *data; else fail(); break; + case 0xF0014004: if(wr) mTimeCmp = (mTimeCmp & 0x00000000FFFFFFFF) | (((uint64_t)*data) << 32); else fail(); break; + case 0xF0000000: + if(wr){ + char c = (char)*data; + cout << c; + logTraces << c; + logTraces.flush(); + onStdout(c); + } + case 0xF0000004: + if(!wr){ + #ifdef WITH_USER_IO + if(stdinNonEmpty()){ + char c; + read(0, &c, 1); + *data = c; + } else + #endif + if(!customCin.empty()){ + *data = customCin.front(); + customCin.pop(); + } else { + *data = -1; + } + } + break; + default: cout << "Unmapped peripheral access : addr=0x" << hex << addr << " wr=" << wr << " mask=0x" << mask << " data=0x" << data << dec << endl; fail(); break; + } + + Workspace::dBusAccess(addr,wr,size,mask,data,error); + } + + virtual void onStdout(char c){ + + } +}; + +#endif + string riscvTestMain[] = { //"rv32ui-p-simple", "rv32ui-p-lui", @@ -3840,6 +3929,27 @@ int main(int argc, char **argv, char **env) { #endif +#ifdef LINUX_SOC_SMP + { + + LinuxSocSmp soc("linuxSmp"); + #ifndef DEBUG_PLUGIN_EXTERNAL + soc.withRiscvRef(); + soc.loadBin(EMULATOR, 0x80000000); + soc.loadBin(VMLINUX, 0xC0000000); + soc.loadBin(DTB, 0xC4000000); + soc.loadBin(RAMDISK, 0xC2000000); + #endif + //soc.setIStall(true); + //soc.setDStall(true); + soc.bootAt(0x80000000); + soc.run(0); +// soc.run((496300000l + 2000000) / 2); +// soc.run(438700000l/2); + return -1; + } +#endif + diff --git a/src/test/cpp/regression/makefile b/src/test/cpp/regression/makefile index da525c59..c7dcf5f4 100644 --- a/src/test/cpp/regression/makefile +++ b/src/test/cpp/regression/makefile @@ -9,6 +9,7 @@ DBUS_DATA_WIDTH?=32 TRACE?=no TRACE_ACCESS?=no TRACE_START=0 +TRACE_SPORADIC?=no ISA_TEST?=yes MUL?=yes DIV?=yes @@ -84,6 +85,15 @@ ifeq ($(LINUX_SOC),yes) ADDCFLAGS += -CFLAGS -DEMULATOR='\"$(EMULATOR)\"' endif +ifeq ($(LINUX_SOC_SMP),yes) + ADDCFLAGS += -CFLAGS -DLINUX_SOC_SMP + ADDCFLAGS += -CFLAGS -DVMLINUX='\"$(VMLINUX)\"' + ADDCFLAGS += -CFLAGS -DDTB='\"$(DTB)\"' + ADDCFLAGS += -CFLAGS -DRAMDISK='\"$(RAMDISK)\"' + ADDCFLAGS += -CFLAGS -DEMULATOR='\"$(EMULATOR)\"' +endif + + ARCH_LINUX=rv32i ifeq ($(MUL),yes) ifeq ($(DIV),yes) @@ -187,6 +197,12 @@ ifeq ($(TRACE),yes) ADDCFLAGS += -CFLAGS -DTRACE endif +ifeq ($(TRACE_SPORADIC),yes) + ADDCFLAGS += -CFLAGS -DTRACE_SPORADIC +endif + + + ifeq ($(CSR),yes) ADDCFLAGS += -CFLAGS -DCSR endif From 63511b19a2fdc468aec5a11ec92cd2030b4b6cb0 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 11 May 2020 10:35:24 +0200 Subject: [PATCH 427/951] smp cluster add more profiling --- .../vexriscv/demo/smp/VexRiscvSmpCluster.scala | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index 6efdf8fc..1778687e 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -533,6 +533,9 @@ object VexRiscvSmpClusterOpenSbi extends App{ var iMemReadBytes, dMemReadBytes, dMemWriteBytes, iMemSequencial,iMemRequests = 0l var reportTimer = 0 var reportCycle = 0 + var dMemWrites, dMemWritesCached = 0l + var dMemWriteCacheAddress = 0l + val dMemWriteCacheMask = ~((1 << log2Up(128/8))-1) import java.io._ val csv = new PrintWriter(new File("bench.csv" )) @@ -540,7 +543,6 @@ object VexRiscvSmpClusterOpenSbi extends App{ var sequencialPrediction = 0l val cache = dut.cpus(i).core.children.find(_.isInstanceOf[InstructionCache]).head.asInstanceOf[InstructionCache].io.cpu.decode }) - csv.write(s"reportCycle,iMemReadBytes,dMemReadBytes,dMemWriteBytes,miaou,asd\n") dut.clockDomain.onSamplings{ for(i <- 0 until cpuCount; iMem = dut.io.iMems(i); ctx = iMemCtx(i)){ // if(iMem.cmd.valid.toBoolean && iMem.cmd.ready.toBoolean){ @@ -568,6 +570,13 @@ object VexRiscvSmpClusterOpenSbi extends App{ if(dut.io.dMem.cmd.valid.toBoolean && dut.io.dMem.cmd.ready.toBoolean){ if(dut.io.dMem.cmd.opcode.toInt == Bmb.Cmd.Opcode.WRITE){ dMemWriteBytes += dut.io.dMem.cmd.length.toInt+1 + val address = dut.io.dMem.cmd.address.toLong + dMemWrites += 1 + if((address & dMemWriteCacheMask) == (dMemWriteCacheAddress & dMemWriteCacheMask)){ + dMemWritesCached += 1 + } else { + dMemWriteCacheAddress = address + } }else { dMemReadBytes += dut.io.dMem.cmd.length.toInt+1 } @@ -578,7 +587,8 @@ object VexRiscvSmpClusterOpenSbi extends App{ reportTimer = 0 // println(f"\n** c=${reportCycle} ir=${iMemReadBytes*1e-6}%5.2f dr=${dMemReadBytes*1e-6}%5.2f dw=${dMemWriteBytes*1e-6}%5.2f **\n") - csv.write(s"$reportCycle,$iMemReadBytes,$dMemReadBytes,$dMemWriteBytes,$iMemRequests,$iMemSequencial\n") + + csv.write(s"$reportCycle,$iMemReadBytes,$dMemReadBytes,$dMemWriteBytes,$iMemRequests,$iMemSequencial,$dMemWrites,$dMemWritesCached\n") csv.flush() reportCycle = 0 iMemReadBytes = 0 @@ -586,6 +596,8 @@ object VexRiscvSmpClusterOpenSbi extends App{ dMemWriteBytes = 0 iMemRequests = 0 iMemSequencial = 0 + dMemWrites = 0 + dMemWritesCached = 0 } } From cb44a474fcb2e1ef99c39495e5481c947014de70 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 12 May 2020 13:25:55 +0200 Subject: [PATCH 428/951] more smp cluster profiling --- .../demo/smp/VexRiscvSmpCluster.scala | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index 1778687e..b9606435 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -534,8 +534,11 @@ object VexRiscvSmpClusterOpenSbi extends App{ var reportTimer = 0 var reportCycle = 0 var dMemWrites, dMemWritesCached = 0l - var dMemWriteCacheAddress = 0l - val dMemWriteCacheMask = ~((1 << log2Up(128/8))-1) + val dMemWriteCacheCtx = List(4,8,16,32,64).map(bytes => new { + var counter = 0l + var address = 0l + val mask = ~((1 << log2Up(bytes))-1) + }) import java.io._ val csv = new PrintWriter(new File("bench.csv" )) @@ -572,13 +575,16 @@ object VexRiscvSmpClusterOpenSbi extends App{ dMemWriteBytes += dut.io.dMem.cmd.length.toInt+1 val address = dut.io.dMem.cmd.address.toLong dMemWrites += 1 - if((address & dMemWriteCacheMask) == (dMemWriteCacheAddress & dMemWriteCacheMask)){ - dMemWritesCached += 1 - } else { - dMemWriteCacheAddress = address + for(ctx <- dMemWriteCacheCtx){ + if((address & ctx.mask) == (ctx.address & ctx.mask)){ + ctx.counter += 1 + } else { + ctx.address = address + } } }else { dMemReadBytes += dut.io.dMem.cmd.length.toInt+1 + for(ctx <- dMemWriteCacheCtx) ctx.address = -1 } } reportTimer = reportTimer + 1 @@ -588,7 +594,7 @@ object VexRiscvSmpClusterOpenSbi extends App{ // println(f"\n** c=${reportCycle} ir=${iMemReadBytes*1e-6}%5.2f dr=${dMemReadBytes*1e-6}%5.2f dw=${dMemWriteBytes*1e-6}%5.2f **\n") - csv.write(s"$reportCycle,$iMemReadBytes,$dMemReadBytes,$dMemWriteBytes,$iMemRequests,$iMemSequencial,$dMemWrites,$dMemWritesCached\n") + csv.write(s"$reportCycle,$iMemReadBytes,$dMemReadBytes,$dMemWriteBytes,$iMemRequests,$iMemSequencial,$dMemWrites,${dMemWriteCacheCtx.map(_.counter).mkString(",")}\n") csv.flush() reportCycle = 0 iMemReadBytes = 0 @@ -597,7 +603,7 @@ object VexRiscvSmpClusterOpenSbi extends App{ iMemRequests = 0 iMemSequencial = 0 dMemWrites = 0 - dMemWritesCached = 0 + for(ctx <- dMemWriteCacheCtx) ctx.counter = 0 } } From 0471c7ad7609f960a2220c2e184c129924643283 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 12 May 2020 23:55:47 +0200 Subject: [PATCH 429/951] Fix machineCsr test --- .../cpp/raw/machineCsr/build/machineCsr.asm | 88 ++++--- .../cpp/raw/machineCsr/build/machineCsr.hex | 20 +- .../machineCsr/build/machineCsrCompressed.asm | 240 ++++++++++-------- .../machineCsr/build/machineCsrCompressed.hex | 58 +++-- src/test/cpp/raw/machineCsr/src/crt.S | 14 + 5 files changed, 239 insertions(+), 181 deletions(-) diff --git a/src/test/cpp/raw/machineCsr/build/machineCsr.asm b/src/test/cpp/raw/machineCsr/build/machineCsr.asm index 4d80d753..679be705 100644 --- a/src/test/cpp/raw/machineCsr/build/machineCsr.asm +++ b/src/test/cpp/raw/machineCsr/build/machineCsr.asm @@ -29,26 +29,26 @@ Disassembly of section .crt_section: 80000044: 01de7f33 and t5,t3,t4 80000048: 000f1863 bnez t5,80000058 8000004c: 34102ef3 csrr t4,mepc -80000050: 004e8e93 addi t4,t4,4 # 80000004 +80000050: 004e8e93 addi t4,t4,4 # 80000004 80000054: 341e9073 csrw mepc,t4 80000058 : 80000058: 80000eb7 lui t4,0x80000 -8000005c: 003e8e93 addi t4,t4,3 # 80000003 +8000005c: 003e8e93 addi t4,t4,3 # 80000003 80000060: 01ce9863 bne t4,t3,80000070 80000064: f0013c37 lui s8,0xf0013 80000068: 00000c93 li s9,0 -8000006c: 019c2023 sw s9,0(s8) # f0013000 +8000006c: 019c2023 sw s9,0(s8) # f0013000 80000070 : 80000070: 80000eb7 lui t4,0x80000 -80000074: 007e8e93 addi t4,t4,7 # 80000007 +80000074: 007e8e93 addi t4,t4,7 # 80000007 80000078: 01ce9463 bne t4,t3,80000080 8000007c: 30405073 csrwi mie,0 80000080 : 80000080: 80000eb7 lui t4,0x80000 -80000084: 00be8e93 addi t4,t4,11 # 8000000b +80000084: 00be8e93 addi t4,t4,11 # 8000000b 80000088: 01ce9463 bne t4,t3,80000090 8000008c: 30405073 csrwi mie,0 @@ -65,7 +65,7 @@ Disassembly of section .crt_section: 800000ac: 30429073 csrw mie,t0 800000b0: f0013c37 lui s8,0xf0013 800000b4: 00100c93 li s9,1 -800000b8: 019c2023 sw s9,0(s8) # f0013000 +800000b8: 019c2023 sw s9,0(s8) # f0013000 800000bc: 00000013 nop 800000c0: 00000013 nop 800000c4: 00000013 nop @@ -101,41 +101,55 @@ Disassembly of section .crt_section: 8000013c: 00000013 nop 80000140: 00500e13 li t3,5 80000144: f01001b7 lui gp,0xf0100 -80000148: f4018193 addi gp,gp,-192 # f00fff40 +80000148: f4018193 addi gp,gp,-192 # f00fff40 8000014c: 0001a203 lw tp,0(gp) 80000150: 0041a283 lw t0,4(gp) 80000154: 3ff20213 addi tp,tp,1023 # 3ff 80000158: 0041a423 sw tp,8(gp) 8000015c: 0051a623 sw t0,12(gp) -80000160: 00600e13 li t3,6 -80000164: 08000213 li tp,128 -80000168: 30421073 csrw mie,tp -8000016c: 00700e13 li t3,7 -80000170: 10500073 wfi -80000174: 00800e13 li t3,8 -80000178: 00100193 li gp,1 -8000017c: 0041a023 sw tp,0(gp) -80000180: 00900e13 li t3,9 -80000184: 00419023 sh tp,0(gp) -80000188: 00a00e13 li t3,10 -8000018c: 0001a203 lw tp,0(gp) -80000190: 00b00e13 li t3,11 -80000194: 00019203 lh tp,0(gp) -80000198: 00c00e13 li t3,12 -8000019c: 00d00e13 li t3,13 -800001a0: 00002083 lw ra,0(zero) # 0 +80000160: 00000013 nop +80000164: 00000013 nop +80000168: 00000013 nop +8000016c: 00000013 nop +80000170: 00000013 nop +80000174: 00000013 nop +80000178: 00000013 nop +8000017c: 00000013 nop +80000180: 00000013 nop +80000184: 00000013 nop +80000188: 00000013 nop +8000018c: 00000013 nop +80000190: 00000013 nop +80000194: 00000013 nop +80000198: 00600e13 li t3,6 +8000019c: 08000213 li tp,128 +800001a0: 30421073 csrw mie,tp +800001a4: 00700e13 li t3,7 +800001a8: 10500073 wfi +800001ac: 00800e13 li t3,8 +800001b0: 00100193 li gp,1 +800001b4: 0041a023 sw tp,0(gp) +800001b8: 00900e13 li t3,9 +800001bc: 00419023 sh tp,0(gp) +800001c0: 00a00e13 li t3,10 +800001c4: 0001a203 lw tp,0(gp) +800001c8: 00b00e13 li t3,11 +800001cc: 00019203 lh tp,0(gp) +800001d0: 00c00e13 li t3,12 +800001d4: 00d00e13 li t3,13 +800001d8: 00002083 lw ra,0(zero) # 0 -800001a4 : -800001a4: 0020006f j 800001a6 -800001a8: 00002083 lw ra,0(zero) # 0 -800001ac: 00e00e13 li t3,14 -800001b0: 20200073 hret -800001b4: 00f00e13 li t3,15 -800001b8: f01000b7 lui ra,0xf0100 -800001bc: f6008093 addi ra,ra,-160 # f00fff60 -800001c0: 0000a103 lw sp,0(ra) -800001c4: 01000e13 li t3,16 -800001c8: 0020a023 sw sp,0(ra) -800001cc: 01100e13 li t3,17 -800001d0: 00008067 ret +800001dc : +800001dc: 0020006f j 800001de +800001e0: 00002083 lw ra,0(zero) # 0 +800001e4: 00e00e13 li t3,14 +800001e8: 20200073 hret +800001ec: 00f00e13 li t3,15 +800001f0: f01000b7 lui ra,0xf0100 +800001f4: f6008093 addi ra,ra,-160 # f00fff60 +800001f8: 0000a103 lw sp,0(ra) +800001fc: 01000e13 li t3,16 +80000200: 0020a023 sw sp,0(ra) +80000204: 01100e13 li t3,17 +80000208: 00008067 ret ... diff --git a/src/test/cpp/raw/machineCsr/build/machineCsr.hex b/src/test/cpp/raw/machineCsr/build/machineCsr.hex index d104c88d..d6c33e74 100644 --- a/src/test/cpp/raw/machineCsr/build/machineCsr.hex +++ b/src/test/cpp/raw/machineCsr/build/machineCsr.hex @@ -21,13 +21,17 @@ :100130001300000013000000130000001300000073 :10014000130E5000B70110F0938101F403A20100D7 :1001500083A241001302F23F23A4410023A65100D1 -:10016000130E60001302000873104230130E70006B -:1001700073005010130E80009301100023A0410063 -:10018000130E900023904100130EA00003A2010063 -:10019000130EB00003920100130EC000130ED00026 -:1001A000832000006F00200083200000130EE00079 -:1001B00073002020130EF000B70010F0938000F6BB -:1001C00003A10000130E000123A02000130E100154 -:1001D0006780000000000000000000000000000038 +:100160001300000013000000130000001300000043 +:100170001300000013000000130000001300000033 +:100180001300000013000000130000001300000023 +:100190001300000013000000130E6000130200089B +:1001A00073104230130E700073005010130E800055 +:1001B0009301100023A04100130E900023904100F2 +:1001C000130EA00003A20100130EB0000392010061 +:1001D000130EC000130ED000832000006F0020001B +:1001E00083200000130EE00073002020130EF000A7 +:1001F000B70010F0938000F603A10000130E000179 +:1002000023A02000130E10016780000000000000F2 +:1002100000000000000000000000000000000000DE :0400000580000094E3 :00000001FF diff --git a/src/test/cpp/raw/machineCsr/build/machineCsrCompressed.asm b/src/test/cpp/raw/machineCsr/build/machineCsrCompressed.asm index df9e96ff..097f4e31 100644 --- a/src/test/cpp/raw/machineCsr/build/machineCsrCompressed.asm +++ b/src/test/cpp/raw/machineCsr/build/machineCsrCompressed.asm @@ -5,8 +5,7 @@ build/machineCsrCompressed.elf: file format elf32-littleriscv Disassembly of section .crt_section: 80000000 : -80000000: a071 j 8000008c <_start> -80000002: 0001 nop +80000000: 0940006f j 80000094 <_start> 80000004: 00000013 nop 80000008: 00000013 nop 8000000c: 00000013 nop @@ -17,123 +16,140 @@ Disassembly of section .crt_section: 80000020 : 80000020: 34202e73 csrr t3,mcause -80000024: 000e1c63 bnez t3,8000003c +80000024: 000e1e63 bnez t3,80000040 80000028: ffc00f13 li t5,-4 8000002c: 34102ef3 csrr t4,mepc 80000030: 01eefeb3 and t4,t4,t5 -80000034: 0e91 addi t4,t4,4 -80000036: 341e9073 csrw mepc,t4 -8000003a: a821 j 80000052 +80000034: 004e8e93 addi t4,t4,4 +80000038: 341e9073 csrw mepc,t4 +8000003c: 01c0006f j 80000058 -8000003c : -8000003c: 80000eb7 lui t4,0x80000 -80000040: 01de7f33 and t5,t3,t4 -80000044: 000f1763 bnez t5,80000052 -80000048: 34102ef3 csrr t4,mepc -8000004c: 0e91 addi t4,t4,4 -8000004e: 341e9073 csrw mepc,t4 +80000040 : +80000040: 80000eb7 lui t4,0x80000 +80000044: 01de7f33 and t5,t3,t4 +80000048: 000f1863 bnez t5,80000058 +8000004c: 34102ef3 csrr t4,mepc +80000050: 004e8e93 addi t4,t4,4 # 80000004 +80000054: 341e9073 csrw mepc,t4 -80000052 : -80000052: 80000eb7 lui t4,0x80000 -80000056: 003e8e93 addi t4,t4,3 # 80000003 <_start+0xffffff77> -8000005a: 01ce9763 bne t4,t3,80000068 -8000005e: f0013c37 lui s8,0xf0013 -80000062: 4c81 li s9,0 -80000064: 019c2023 sw s9,0(s8) # f0013000 <_start+0x70012f74> +80000058 : +80000058: 80000eb7 lui t4,0x80000 +8000005c: 003e8e93 addi t4,t4,3 # 80000003 +80000060: 01ce9863 bne t4,t3,80000070 +80000064: f0013c37 lui s8,0xf0013 +80000068: 00000c93 li s9,0 +8000006c: 019c2023 sw s9,0(s8) # f0013000 -80000068 : -80000068: 80000eb7 lui t4,0x80000 -8000006c: 007e8e93 addi t4,t4,7 # 80000007 <_start+0xffffff7b> -80000070: 01ce9463 bne t4,t3,80000078 -80000074: 30405073 csrwi mie,0 +80000070 : +80000070: 80000eb7 lui t4,0x80000 +80000074: 007e8e93 addi t4,t4,7 # 80000007 +80000078: 01ce9463 bne t4,t3,80000080 +8000007c: 30405073 csrwi mie,0 -80000078 : -80000078: 80000eb7 lui t4,0x80000 -8000007c: 00be8e93 addi t4,t4,11 # 8000000b <_start+0xffffff7f> -80000080: 01ce9463 bne t4,t3,80000088 -80000084: 30405073 csrwi mie,0 +80000080 : +80000080: 80000eb7 lui t4,0x80000 +80000084: 00be8e93 addi t4,t4,11 # 8000000b +80000088: 01ce9463 bne t4,t3,80000090 +8000008c: 30405073 csrwi mie,0 -80000088 : -80000088: 30200073 mret +80000090 : +80000090: 30200073 mret -8000008c <_start>: -8000008c: 4e05 li t3,1 -8000008e: 00000073 ecall -80000092: 4e09 li t3,2 -80000094: 42a1 li t0,8 -80000096: 3002a073 csrs mstatus,t0 -8000009a: 42a1 li t0,8 -8000009c: 30429073 csrw mie,t0 -800000a0: f0013c37 lui s8,0xf0013 -800000a4: 4c85 li s9,1 -800000a6: 019c2023 sw s9,0(s8) # f0013000 <_start+0x70012f74> -800000aa: 0001 nop -800000ac: 0001 nop -800000ae: 0001 nop -800000b0: 0001 nop -800000b2: 0001 nop -800000b4: 0001 nop -800000b6: 0001 nop -800000b8: 0001 nop -800000ba: 0001 nop -800000bc: 0001 nop -800000be: 0001 nop -800000c0: 0001 nop -800000c2: 4e0d li t3,3 -800000c4: 08000293 li t0,128 -800000c8: 30429073 csrw mie,t0 -800000cc: 0001 nop -800000ce: 0001 nop -800000d0: 0001 nop -800000d2: 0001 nop -800000d4: 0001 nop -800000d6: 0001 nop -800000d8: 0001 nop -800000da: 4e11 li t3,4 -800000dc: 000012b7 lui t0,0x1 -800000e0: 80028293 addi t0,t0,-2048 # 800 -800000e4: 30429073 csrw mie,t0 -800000e8: 0001 nop -800000ea: 0001 nop -800000ec: 0001 nop -800000ee: 0001 nop -800000f0: 0001 nop -800000f2: 0001 nop -800000f4: 0001 nop -800000f6: 4e15 li t3,5 -800000f8: f01001b7 lui gp,0xf0100 -800000fc: f4018193 addi gp,gp,-192 # f00fff40 <_start+0x700ffeb4> -80000100: 0001a203 lw tp,0(gp) -80000104: 0041a283 lw t0,4(gp) -80000108: 3ff20213 addi tp,tp,1023 # 3ff -8000010c: 0041a423 sw tp,8(gp) -80000110: 0051a623 sw t0,12(gp) -80000114: 4e19 li t3,6 -80000116: 08000213 li tp,128 -8000011a: 30421073 csrw mie,tp -8000011e: 4e1d li t3,7 -80000120: 10500073 wfi -80000124: 4e21 li t3,8 -80000126: 4185 li gp,1 -80000128: 0041a023 sw tp,0(gp) -8000012c: 4e25 li t3,9 -8000012e: 00419023 sh tp,0(gp) -80000132: 4e29 li t3,10 -80000134: 0001a203 lw tp,0(gp) -80000138: 4e2d li t3,11 -8000013a: 00019203 lh tp,0(gp) -8000013e: 4e31 li t3,12 -80000140: 4e35 li t3,13 -80000142: 00002083 lw ra,0(zero) # 0 -80000146: 00002083 lw ra,0(zero) # 0 -8000014a: 4e39 li t3,14 -8000014c: 20200073 hret -80000150: 4e3d li t3,15 -80000152: f01000b7 lui ra,0xf0100 -80000156: f6008093 addi ra,ra,-160 # f00fff60 <_start+0x700ffed4> -8000015a: 0000a103 lw sp,0(ra) -8000015e: 4e41 li t3,16 -80000160: 0020a023 sw sp,0(ra) -80000164: 4e45 li t3,17 -80000166: 8082 ret +80000094 <_start>: +80000094: 00100e13 li t3,1 +80000098: 00000073 ecall +8000009c: 00200e13 li t3,2 +800000a0: 00800293 li t0,8 +800000a4: 3002a073 csrs mstatus,t0 +800000a8: 00800293 li t0,8 +800000ac: 30429073 csrw mie,t0 +800000b0: f0013c37 lui s8,0xf0013 +800000b4: 00100c93 li s9,1 +800000b8: 019c2023 sw s9,0(s8) # f0013000 +800000bc: 00000013 nop +800000c0: 00000013 nop +800000c4: 00000013 nop +800000c8: 00000013 nop +800000cc: 00000013 nop +800000d0: 00000013 nop +800000d4: 00000013 nop +800000d8: 00000013 nop +800000dc: 00000013 nop +800000e0: 00000013 nop +800000e4: 00000013 nop +800000e8: 00000013 nop +800000ec: 00300e13 li t3,3 +800000f0: 08000293 li t0,128 +800000f4: 30429073 csrw mie,t0 +800000f8: 00000013 nop +800000fc: 00000013 nop +80000100: 00000013 nop +80000104: 00000013 nop +80000108: 00000013 nop +8000010c: 00000013 nop +80000110: 00000013 nop +80000114: 00400e13 li t3,4 +80000118: 000012b7 lui t0,0x1 +8000011c: 80028293 addi t0,t0,-2048 # 800 +80000120: 30429073 csrw mie,t0 +80000124: 00000013 nop +80000128: 00000013 nop +8000012c: 00000013 nop +80000130: 00000013 nop +80000134: 00000013 nop +80000138: 00000013 nop +8000013c: 00000013 nop +80000140: 00500e13 li t3,5 +80000144: f01001b7 lui gp,0xf0100 +80000148: f4018193 addi gp,gp,-192 # f00fff40 +8000014c: 0001a203 lw tp,0(gp) +80000150: 0041a283 lw t0,4(gp) +80000154: 3ff20213 addi tp,tp,1023 # 3ff +80000158: 0041a423 sw tp,8(gp) +8000015c: 0051a623 sw t0,12(gp) +80000160: 00000013 nop +80000164: 00000013 nop +80000168: 00000013 nop +8000016c: 00000013 nop +80000170: 00000013 nop +80000174: 00000013 nop +80000178: 00000013 nop +8000017c: 00000013 nop +80000180: 00000013 nop +80000184: 00000013 nop +80000188: 00000013 nop +8000018c: 00000013 nop +80000190: 00000013 nop +80000194: 00000013 nop +80000198: 00600e13 li t3,6 +8000019c: 08000213 li tp,128 +800001a0: 30421073 csrw mie,tp +800001a4: 00700e13 li t3,7 +800001a8: 10500073 wfi +800001ac: 00800e13 li t3,8 +800001b0: 00100193 li gp,1 +800001b4: 0041a023 sw tp,0(gp) +800001b8: 00900e13 li t3,9 +800001bc: 00419023 sh tp,0(gp) +800001c0: 00a00e13 li t3,10 +800001c4: 0001a203 lw tp,0(gp) +800001c8: 00b00e13 li t3,11 +800001cc: 00019203 lh tp,0(gp) +800001d0: 00c00e13 li t3,12 +800001d4: 00d00e13 li t3,13 +800001d8: 00002083 lw ra,0(zero) # 0 + +800001dc : +800001dc: 0020006f j 800001de +800001e0: 00002083 lw ra,0(zero) # 0 +800001e4: 00e00e13 li t3,14 +800001e8: 20200073 hret +800001ec: 00f00e13 li t3,15 +800001f0: f01000b7 lui ra,0xf0100 +800001f4: f6008093 addi ra,ra,-160 # f00fff60 +800001f8: 0000a103 lw sp,0(ra) +800001fc: 01000e13 li t3,16 +80000200: 0020a023 sw sp,0(ra) +80000204: 01100e13 li t3,17 +80000208: 00008067 ret ... diff --git a/src/test/cpp/raw/machineCsr/build/machineCsrCompressed.hex b/src/test/cpp/raw/machineCsr/build/machineCsrCompressed.hex index 15466729..d6c33e74 100644 --- a/src/test/cpp/raw/machineCsr/build/machineCsrCompressed.hex +++ b/src/test/cpp/raw/machineCsr/build/machineCsrCompressed.hex @@ -1,27 +1,37 @@ :0200000480007A -:1000000071A00100130000001300000013000000A5 +:100000006F004009130000001300000013000000FF :100010001300000013000000130000001300000094 -:10002000732E2034631C0E00130FC0FFF32E103408 -:10003000B3FEEE01910E73901E3421A8B70E00801E -:10004000337FDE0163170F00F32E1034910E73908F -:100050001E34B70E0080938E3E006397CE01373C6E -:1000600001F0814C23209C01B70E0080938E7E000E -:100070006394CE0173504030B70E0080938EBE0063 -:100080006394CE017350403073002030054E7300EE -:100090000000094EA14273A00230A1427390423089 -:1000A000373C01F0854C23209C0101000100010038 -:1000B0000100010001000100010001000100010038 -:1000C00001000D4E930200087390423001000100C0 -:1000D00001000100010001000100114EB7120000F3 -:1000E0009382028073904230010001000100010000 -:1000F000010001000100154EB70110F0938101F4D9 -:1001000003A2010083A241001302F23F23A4410095 -:1001100023A65100194E13020008731042301D4EE1 -:1001200073005010214E854123A04100254E23909D -:100130004100294E03A201002D4E03920100314ED1 -:10014000354E8320000083200000394E73002020AC -:100150003D4EB70010F0938000F603A10000414E21 -:1001600023A02000454E8280000000000000000017 -:10017000000000000000000000000000000000007F -:040000058000008CEB +:10002000732E2034631E0E00130FC0FFF32E103406 +:10003000B3FEEE01938E4E0073901E346F00C0012C +:10004000B70E0080337FDE0163180F00F32E1034EB +:10005000938E4E0073901E34B70E0080938E3E0038 +:100060006398CE01373C01F0930C000023209C01E3 +:10007000B70E0080938E7E006394CE0173504030A3 +:10008000B70E0080938EBE006394CE017350403053 +:1000900073002030130E100073000000130E2000B8 +:1000A0009302800073A0023093028000739042306C +:1000B000373C01F0930C100023209C01130000003A +:1000C00013000000130000001300000013000000E4 +:1000D00013000000130000001300000013000000D4 +:1000E000130000001300000013000000130E300086 +:1000F00093020008739042301300000013000000C8 +:1001000013000000130000001300000013000000A3 +:1001100013000000130E4000B7120000938202800B +:100120007390423013000000130000001300000021 +:100130001300000013000000130000001300000073 +:10014000130E5000B70110F0938101F403A20100D7 +:1001500083A241001302F23F23A4410023A65100D1 +:100160001300000013000000130000001300000043 +:100170001300000013000000130000001300000033 +:100180001300000013000000130000001300000023 +:100190001300000013000000130E6000130200089B +:1001A00073104230130E700073005010130E800055 +:1001B0009301100023A04100130E900023904100F2 +:1001C000130EA00003A20100130EB0000392010061 +:1001D000130EC000130ED000832000006F0020001B +:1001E00083200000130EE00073002020130EF000A7 +:1001F000B70010F0938000F603A10000130E000179 +:1002000023A02000130E10016780000000000000F2 +:1002100000000000000000000000000000000000DE +:0400000580000094E3 :00000001FF diff --git a/src/test/cpp/raw/machineCsr/src/crt.S b/src/test/cpp/raw/machineCsr/src/crt.S index bbe966d5..91429dbc 100644 --- a/src/test/cpp/raw/machineCsr/src/crt.S +++ b/src/test/cpp/raw/machineCsr/src/crt.S @@ -102,6 +102,20 @@ _start: addi x4, x4, 1023 sw x4, 8(x3) sw x5, 12(x3) + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop li x28, 6 li x4, 0x080 csrw mie,x4 From 685c914227900f3142556391c9ce48d14ce56f2c Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 12 May 2020 23:58:28 +0200 Subject: [PATCH 430/951] Add i$ reduceBankWidth to take advantage of multi way by remaping the data location to reduce on chip ram data width --- .../scala/vexriscv/ip/InstructionCache.scala | 80 +++++++++++-------- .../vexriscv/TestIndividualFeatures.scala | 4 +- 2 files changed, 50 insertions(+), 34 deletions(-) diff --git a/src/main/scala/vexriscv/ip/InstructionCache.scala b/src/main/scala/vexriscv/ip/InstructionCache.scala index 43f51300..dc974442 100644 --- a/src/main/scala/vexriscv/ip/InstructionCache.scala +++ b/src/main/scala/vexriscv/ip/InstructionCache.scala @@ -24,7 +24,8 @@ case class InstructionCacheConfig( cacheSize : Int, twoCycleRam : Boolean = false, twoCycleRamInnerMux : Boolean = false, preResetFlush : Boolean = false, - bypassGen : Boolean = false ){ + bypassGen : Boolean = false, + reducedBankWidth : Boolean = false){ assert(!(twoCycleRam && !twoCycleCache)) @@ -286,23 +287,13 @@ class InstructionCache(p : InstructionCacheConfig, mmuParameter : MemoryTranslat val lineWidth = bytePerLine*8 val lineCount = cacheSize/bytePerLine - val wordWidth = cpuDataWidth - val wordWidthLog2 = log2Up(wordWidth) - val wordPerLine = lineWidth/wordWidth + val cpuWordWidth = cpuDataWidth val memWordPerLine = lineWidth/memDataWidth - val bytePerWord = wordWidth/8 - val bytePerMemWord = memDataWidth/8 + val bytePerCpuWord = cpuWordWidth/8 val wayLineCount = lineCount/wayCount - val wayLineLog2 = log2Up(wayLineCount) - val wayMemWordCount = wayLineCount * memWordPerLine 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 case class LineTag() extends Bundle{ val valid = Bool @@ -310,10 +301,17 @@ class InstructionCache(p : InstructionCacheConfig, mmuParameter : MemoryTranslat val address = UInt(tagRange.length bit) } + val bankCount = wayCount + val bankWidth = if(!reducedBankWidth) memDataWidth else Math.max(cpuDataWidth, memDataWidth/wayCount) + val bankByteSize = cacheSize/bankCount + val bankWordCount = bankByteSize*8/bankWidth + val bankWordToCpuWordRange = log2Up(bankWidth/8)-1 downto log2Up(bytePerCpuWord) + val memToBankRatio = bankWidth*bankCount / memDataWidth + + val banks = Seq.fill(bankCount)(Mem(Bits(bankWidth bits), bankWordCount)) val ways = Seq.fill(wayCount)(new Area{ val tags = Mem(LineTag(),wayLineCount) - val datas = Mem(Bits(memDataWidth bits),wayMemWordCount) if(preResetFlush){ tags.initBigInt(List.fill(wayLineCount)(BigInt(0))) @@ -367,7 +365,7 @@ class InstructionCache(p : InstructionCacheConfig, mmuParameter : MemoryTranslat val write = new Area{ val tag = ways.map(_.tags.writePort) - val data = ways.map(_.datas.writePort) + val data = banks.map(_.writePort) } for(wayId <- 0 until wayCount){ @@ -378,13 +376,24 @@ class InstructionCache(p : InstructionCacheConfig, mmuParameter : MemoryTranslat tag.data.valid := flushCounter.msb tag.data.error := hadError || io.mem.rsp.error tag.data.address := address(tagRange) - - val data = write.data(wayId) - data.valid := io.mem.rsp.valid && wayHit - data.address := address(lineRange) @@ wordIndex - data.data := io.mem.rsp.data } + for((writeBank, bankId) <- write.data.zipWithIndex){ + if(!reducedBankWidth) { + writeBank.valid := io.mem.rsp.valid && wayToAllocate === bankId + writeBank.address := address(lineRange) @@ wordIndex + writeBank.data := io.mem.rsp.data + } else { + val sel = U(bankId) - wayToAllocate.value + val groupSel = wayToAllocate(log2Up(bankCount)-1 downto log2Up(bankCount/memToBankRatio)) + val subSel = sel(log2Up(bankCount/memToBankRatio) -1 downto 0) + writeBank.valid := io.mem.rsp.valid && groupSel === (bankId >> log2Up(bankCount/memToBankRatio)) + writeBank.address := address(lineRange) @@ wordIndex @@ (subSel) + writeBank.data := io.mem.rsp.data.subdivideIn(bankCount/memToBankRatio slices)(subSel) + } + } + + when(io.mem.rsp.valid) { wordIndex := (wordIndex + 1).resized hadError.setWhen(io.mem.rsp.error) @@ -394,17 +403,20 @@ class InstructionCache(p : InstructionCacheConfig, mmuParameter : MemoryTranslat } } - val fetchStage = new Area{ val read = new Area{ - val waysValues = for(way <- ways) yield new Area{ + val banksValue = for(bank <- banks) yield new Area{ + val dataMem = bank.readSync(io.cpu.prefetch.pc(lineRange.high downto log2Up(bankWidth/8)), !io.cpu.fetch.isStuck) + val data = if(!twoCycleRamInnerMux) dataMem.subdivideIn(cpuDataWidth bits).read(io.cpu.fetch.pc(bankWordToCpuWordRange)) else dataMem + } + + val waysValues = for((way, wayId) <- ways.zipWithIndex) 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 dataMem = way.datas.readSync(io.cpu.prefetch.pc(lineRange.high downto memWordRange.low), !io.cpu.fetch.isStuck) - val data = if(!twoCycleRamInnerMux) dataMem.subdivideIn(cpuDataWidth bits).read(io.cpu.fetch.pc(memWordToCpuWordRange)) else dataMem +// val data = CombInit(banksValue(wayId).data) } } @@ -412,10 +424,11 @@ class InstructionCache(p : InstructionCacheConfig, mmuParameter : MemoryTranslat val hit = (!twoCycleRam) generate new Area{ val hits = read.waysValues.map(way => way.tag.valid && way.tag.address === io.cpu.fetch.mmuRsp.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 = if(cpuDataWidth == memDataWidth || !twoCycleRamInnerMux) CombInit(data) else data.subdivideIn(cpuDataWidth bits).read(io.cpu.fetch.pc(memWordToCpuWordRange)) + val wayId = OHToUInt(hits) + val bankId = if(!reducedBankWidth) wayId else (wayId >> log2Up(bankCount/memToBankRatio)) @@ ((wayId + (io.cpu.fetch.mmuRsp.physicalAddress(log2Up(bankWidth/8), log2Up(bankCount) bits))).resize(log2Up(bankCount/memToBankRatio))) + val error = read.waysValues.map(_.tag.error).read(wayId) + val data = read.banksValue.map(_.data).read(bankId) + val word = if(cpuDataWidth == memDataWidth || !twoCycleRamInnerMux) CombInit(data) else data.subdivideIn(cpuDataWidth bits).read(io.cpu.fetch.pc(bankWordToCpuWordRange)) io.cpu.fetch.data := (if(p.bypassGen) (io.cpu.fetch.dataBypassValid ? io.cpu.fetch.dataBypass | word) else word) if(twoCycleCache){ io.cpu.decode.data := RegNextWhen(io.cpu.fetch.data,!io.cpu.decode.isStuck) @@ -423,7 +436,7 @@ class InstructionCache(p : InstructionCacheConfig, mmuParameter : MemoryTranslat } if(twoCycleRam && wayCount == 1){ - val cacheData = if(cpuDataWidth == memDataWidth || !twoCycleRamInnerMux) CombInit(read.waysValues.head.data) else read.waysValues.head.data.subdivideIn(cpuDataWidth bits).read(io.cpu.fetch.pc(memWordToCpuWordRange)) + val cacheData = if(cpuDataWidth == memDataWidth || !twoCycleRamInnerMux) CombInit(read.banksValue.head.data) else read.banksValue.head.data.subdivideIn(cpuDataWidth bits).read(io.cpu.fetch.pc(bankWordToCpuWordRange)) io.cpu.fetch.data := (if(p.bypassGen) (io.cpu.fetch.dataBypassValid ? io.cpu.fetch.dataBypass | cacheData) else cacheData) } @@ -452,10 +465,11 @@ class InstructionCache(p : InstructionCacheConfig, mmuParameter : MemoryTranslat 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 - val data = fetchStage.read.waysValues.map(way => stage(way.data)).read(id) - val word = if(cpuDataWidth == memDataWidth || !twoCycleRamInnerMux) data else data.subdivideIn(cpuDataWidth bits).read(io.cpu.decode.pc(memWordToCpuWordRange)) + val wayId = OHToUInt(hits) + val bankId = if(!reducedBankWidth) wayId else (wayId >> log2Up(bankCount/memToBankRatio)) @@ ((wayId + (mmuRsp.physicalAddress(log2Up(bankWidth/8), log2Up(bankCount) bits))).resize(log2Up(bankCount/memToBankRatio))) + val error = tags(wayId).error + val data = fetchStage.read.banksValue.map(bank => stage(bank.data)).read(bankId) + val word = if(cpuDataWidth == memDataWidth || !twoCycleRamInnerMux) data else data.subdivideIn(cpuDataWidth bits).read(io.cpu.decode.pc(bankWordToCpuWordRange)) if(p.bypassGen) when(stage(io.cpu.fetch.dataBypassValid)){ word := stage(io.cpu.fetch.dataBypass) } diff --git a/src/test/scala/vexriscv/TestIndividualFeatures.scala b/src/test/scala/vexriscv/TestIndividualFeatures.scala index 66b308be..f3f5b28e 100644 --- a/src/test/scala/vexriscv/TestIndividualFeatures.scala +++ b/src/test/scala/vexriscv/TestIndividualFeatures.scala @@ -356,6 +356,7 @@ class IBusDimension(rvcRate : Double) extends VexRiscvDimension("IBus") { val catchAll = universes.contains(VexRiscvUniverse.CATCH_ALL) val compressed = r.nextDouble() < rvcRate val tighlyCoupled = r.nextBoolean() && !catchAll + val reducedBankWidth = r.nextBoolean() // val tighlyCoupled = false val prediction = random(r, List(NONE, STATIC, DYNAMIC, DYNAMIC_TARGET)) val relaxedPcCalculation, twoCycleCache, injectorStage = r.nextBoolean() @@ -392,7 +393,8 @@ class IBusDimension(rvcRate : Double) extends VexRiscvDimension("IBus") { asyncTagMemory = false, twoCycleRam = twoCycleRam, twoCycleCache = twoCycleCache, - twoCycleRamInnerMux = twoCycleRamInnerMux + twoCycleRamInnerMux = twoCycleRamInnerMux, + reducedBankWidth = reducedBankWidth ) ) if(tighlyCoupled) p.newTightlyCoupledPort(TightlyCoupledPortParameter("iBusTc", a => a(30 downto 28) === 0x0)) From 42fef8bbcdbb5a9058ee141ef80f5a8a46d4330e Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 12 May 2020 23:59:19 +0200 Subject: [PATCH 431/951] Smp cluster now use i$ reduceBankWidth --- src/main/scala/vexriscv/TestsWorkspace.scala | 9 ++-- .../demo/smp/VexRiscvSmpCluster.scala | 45 ++----------------- .../demo/smp/VexRiscvSmpLitexCluster.scala | 4 +- 3 files changed, 11 insertions(+), 47 deletions(-) diff --git a/src/main/scala/vexriscv/TestsWorkspace.scala b/src/main/scala/vexriscv/TestsWorkspace.scala index 8a785442..af1c77b5 100644 --- a/src/main/scala/vexriscv/TestsWorkspace.scala +++ b/src/main/scala/vexriscv/TestsWorkspace.scala @@ -60,9 +60,9 @@ object TestsWorkspace { prediction = STATIC, injectorStage = false, config = InstructionCacheConfig( - cacheSize = 4096*1, + cacheSize = 4096*2, bytePerLine = 64, - wayCount = 1, + wayCount = 2, addressWidth = 32, cpuDataWidth = 32, memDataWidth = 128, @@ -70,7 +70,8 @@ object TestsWorkspace { catchAccessFault = true, asyncTagMemory = false, twoCycleRam = true, - twoCycleCache = true + twoCycleCache = true, + reducedBankWidth = true // ) ), memoryTranslatorPortConfig = MmuPortConfig( @@ -129,7 +130,7 @@ object TestsWorkspace { catchIllegalInstruction = true ), new RegFilePlugin( - regFileReadyKind = plugin.SYNC, + regFileReadyKind = plugin.ASYNC, zeroBoot = true ), new IntAluPlugin, diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index b9606435..0a8c3ec6 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -120,22 +120,6 @@ object VexRiscvSmpClusterGen { new MmuPlugin( ioRange = ioRange ), - //Uncomment the whole IBusSimplePlugin and comment IBusCachedPlugin if you want uncached iBus config - // new IBusSimplePlugin( - // resetVector = 0x80000000l, - // cmdForkOnSecondStage = false, - // cmdForkPersistence = false, - // prediction = DYNAMIC_TARGET, - // historyRamSizeLog2 = 10, - // catchAccessFault = true, - // compressedGen = true, - // busLatencyMin = 1, - // injectorStage = true, - // memoryTranslatorPortConfig = withMmu generate MmuPortConfig( - // portTlbSize = 4 - // ) - // ), - //Uncomment the whole IBusCachedPlugin and comment IBusSimplePlugin if you want cached iBus config new IBusCachedPlugin( resetVector = resetVector, @@ -146,9 +130,9 @@ object VexRiscvSmpClusterGen { injectorStage = false, relaxedPcCalculation = true, config = InstructionCacheConfig( - cacheSize = 4096*1, + cacheSize = 4096*2, bytePerLine = 64, - wayCount = 1, + wayCount = 2, addressWidth = 32, cpuDataWidth = 32, memDataWidth = 128, @@ -156,8 +140,8 @@ object VexRiscvSmpClusterGen { catchAccessFault = true, asyncTagMemory = false, twoCycleRam = false, - twoCycleCache = true - // ) + twoCycleCache = true, + reducedBankWidth = true ), memoryTranslatorPortConfig = MmuPortConfig( portTlbSize = 4, @@ -166,16 +150,6 @@ object VexRiscvSmpClusterGen { earlyCacheHits = true ) ), - // ).newTightlyCoupledPort(TightlyCoupledPortParameter("iBusTc", a => a(30 downto 28) === 0x0 && a(5))), - // new DBusSimplePlugin( - // catchAddressMisaligned = true, - // catchAccessFault = true, - // earlyInjection = false, - // withLrSc = true, - // memoryTranslatorPortConfig = withMmu generate MmuPortConfig( - // portTlbSize = 4 - // ) - // ), new DBusCachedPlugin( dBusCmdMasterPipe = true, dBusCmdSlavePipe = true, @@ -204,13 +178,6 @@ object VexRiscvSmpClusterGen { earlyCacheHits = true ) ), - - // new MemoryTranslatorPlugin( - // tlbSize = 32, - // virtualRange = _(31 downto 28) === 0xC, - // ioRange = _(31 downto 28) === 0xF - // ), - new DecoderSimplePlugin( catchIllegalInstruction = true ), @@ -234,8 +201,6 @@ object VexRiscvSmpClusterGen { pessimisticWriteRegFile = false, pessimisticAddressMatch = false ), - // new HazardSimplePlugin(false, true, false, true), - // new HazardSimplePlugin(false, false, false, false), new MulPlugin, new MulDivIterativePlugin( genMul = false, @@ -243,9 +208,7 @@ object VexRiscvSmpClusterGen { mulUnrollFactor = 32, divUnrollFactor = 1 ), - // new DivPlugin, new CsrPlugin(CsrPluginConfig.openSbi(hartId = hartId, misa = Riscv.misaToInt("imas"))), - new BranchPlugin( earlyBranch = false, catchAddressMisaligned = true, diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala index 9bfca0bf..4bf62e96 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala @@ -350,8 +350,8 @@ object VexRiscvLitexSmpClusterGen extends App { debugClockDomain = ClockDomain.current.copy(reset = Bool().setName("debugResetIn")) ) -// SpinalVerilog(Bench.compressIo(dutGen)) - SpinalVerilog(dutGen) + SpinalVerilog(Bench.compressIo(dutGen)) +// SpinalVerilog(dutGen) } From cf60989ae1662a3f9ce0cf0a5226f26d377fb557 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 14 May 2020 00:05:54 +0200 Subject: [PATCH 432/951] Litex smp cluster now blackboxify d$ data ram --- .../scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala index 4bf62e96..03ccc89a 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala @@ -329,7 +329,6 @@ case class VexRiscvLitexSmpCluster(p : VexRiscvLitexSmpClusterParameter, object VexRiscvLitexSmpClusterGen extends App { val cpuCount = 4 - val withStall = false def parameter = VexRiscvLitexSmpClusterParameter( cluster = VexRiscvSmpClusterParameter( @@ -350,8 +349,9 @@ object VexRiscvLitexSmpClusterGen extends App { debugClockDomain = ClockDomain.current.copy(reset = Bool().setName("debugResetIn")) ) - SpinalVerilog(Bench.compressIo(dutGen)) -// SpinalVerilog(dutGen) + val genConfig = SpinalConfig().addStandardMemBlackboxing(blackboxByteEnables) +// genConfig.generateVerilog(Bench.compressIo(dutGen)) + genConfig.generateVerilog(dutGen) } From c74b03b4de44a167f6d17f0713842916b54d22a9 Mon Sep 17 00:00:00 2001 From: Tom Verbeure Date: Tue, 19 May 2020 13:40:46 -0700 Subject: [PATCH 433/951] Add uinstret support. --- src/main/scala/vexriscv/Riscv.scala | 2 ++ src/main/scala/vexriscv/demo/Briey.scala | 3 ++- .../scala/vexriscv/demo/VexRiscvAhbLite3.scala | 3 ++- .../vexriscv/demo/VexRiscvAvalonForSim.scala | 3 ++- .../demo/VexRiscvAvalonWithIntegratedJtag.scala | 3 ++- .../demo/VexRiscvAxi4WithIntegratedJtag.scala | 3 ++- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 17 +++++++++++++---- 7 files changed, 25 insertions(+), 9 deletions(-) diff --git a/src/main/scala/vexriscv/Riscv.scala b/src/main/scala/vexriscv/Riscv.scala index 91cf876b..7874e026 100644 --- a/src/main/scala/vexriscv/Riscv.scala +++ b/src/main/scala/vexriscv/Riscv.scala @@ -159,5 +159,7 @@ object Riscv{ def UCYCLE = 0xC00 // UR Machine ucycle counter. def UCYCLEH = 0xC80 + def UINSTRET = 0xC02 // UR Machine instructions-retired counter. + def UINSTRETH = 0xC82 // UR Upper 32 bits of minstret, RV32I only. } } diff --git a/src/main/scala/vexriscv/demo/Briey.scala b/src/main/scala/vexriscv/demo/Briey.scala index 2bf5947e..dd794a67 100644 --- a/src/main/scala/vexriscv/demo/Briey.scala +++ b/src/main/scala/vexriscv/demo/Briey.scala @@ -147,7 +147,8 @@ object BrieyConfig{ minstretAccess = CsrAccess.NONE, ecallGen = false, wfiGenAsWait = false, - ucycleAccess = CsrAccess.NONE + ucycleAccess = CsrAccess.NONE, + uinstretAccess = CsrAccess.NONE ) ), new YamlPlugin("cpu0.yaml") diff --git a/src/main/scala/vexriscv/demo/VexRiscvAhbLite3.scala b/src/main/scala/vexriscv/demo/VexRiscvAhbLite3.scala index 593d399d..49f51aef 100644 --- a/src/main/scala/vexriscv/demo/VexRiscvAhbLite3.scala +++ b/src/main/scala/vexriscv/demo/VexRiscvAhbLite3.scala @@ -126,7 +126,8 @@ object VexRiscvAhbLite3{ minstretAccess = CsrAccess.NONE, ecallGen = false, wfiGenAsWait = false, - ucycleAccess = CsrAccess.NONE + ucycleAccess = CsrAccess.NONE, + uinstretAccess = CsrAccess.NONE ) ), new YamlPlugin("cpu0.yaml") diff --git a/src/main/scala/vexriscv/demo/VexRiscvAvalonForSim.scala b/src/main/scala/vexriscv/demo/VexRiscvAvalonForSim.scala index 4245cd15..b2c3f69c 100644 --- a/src/main/scala/vexriscv/demo/VexRiscvAvalonForSim.scala +++ b/src/main/scala/vexriscv/demo/VexRiscvAvalonForSim.scala @@ -124,7 +124,8 @@ object VexRiscvAvalonForSim{ minstretAccess = CsrAccess.NONE, ecallGen = false, wfiGenAsWait = false, - ucycleAccess = CsrAccess.NONE + ucycleAccess = CsrAccess.NONE, + uinstretAccess = CsrAccess.NONE ) ), new YamlPlugin("cpu0.yaml") diff --git a/src/main/scala/vexriscv/demo/VexRiscvAvalonWithIntegratedJtag.scala b/src/main/scala/vexriscv/demo/VexRiscvAvalonWithIntegratedJtag.scala index bba065e1..063d945a 100644 --- a/src/main/scala/vexriscv/demo/VexRiscvAvalonWithIntegratedJtag.scala +++ b/src/main/scala/vexriscv/demo/VexRiscvAvalonWithIntegratedJtag.scala @@ -121,7 +121,8 @@ object VexRiscvAvalonWithIntegratedJtag{ minstretAccess = CsrAccess.NONE, ecallGen = false, wfiGenAsWait = false, - ucycleAccess = CsrAccess.NONE + ucycleAccess = CsrAccess.NONE, + uinstretAccess = CsrAccess.NONE ) ), new YamlPlugin("cpu0.yaml") diff --git a/src/main/scala/vexriscv/demo/VexRiscvAxi4WithIntegratedJtag.scala b/src/main/scala/vexriscv/demo/VexRiscvAxi4WithIntegratedJtag.scala index b002c065..67556e94 100644 --- a/src/main/scala/vexriscv/demo/VexRiscvAxi4WithIntegratedJtag.scala +++ b/src/main/scala/vexriscv/demo/VexRiscvAxi4WithIntegratedJtag.scala @@ -122,7 +122,8 @@ object VexRiscvAxi4WithIntegratedJtag{ minstretAccess = CsrAccess.NONE, ecallGen = false, wfiGenAsWait = false, - ucycleAccess = CsrAccess.NONE + ucycleAccess = CsrAccess.NONE, + uinstretAccess = CsrAccess.NONE ) ), new YamlPlugin("cpu0.yaml") diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 0cdc8968..539e534d 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -49,6 +49,7 @@ case class CsrPluginConfig( mcycleAccess : CsrAccess, minstretAccess : CsrAccess, ucycleAccess : CsrAccess, + uinstretAccess : CsrAccess, wfiGenAsWait : Boolean, ecallGen : Boolean, xtvecModeGen : Boolean = false, @@ -100,6 +101,7 @@ object CsrPluginConfig{ mcycleAccess = CsrAccess.NONE, minstretAccess = CsrAccess.NONE, ucycleAccess = CsrAccess.NONE, + uinstretAccess = CsrAccess.NONE, wfiGenAsWait = true, ecallGen = true, xtvecModeGen = false, @@ -140,6 +142,7 @@ object CsrPluginConfig{ mcycleAccess = CsrAccess.READ_WRITE, minstretAccess = CsrAccess.READ_WRITE, ucycleAccess = CsrAccess.READ_ONLY, + uinstretAccess = CsrAccess.READ_ONLY, wfiGenAsWait = true, ecallGen = true, xtvecModeGen = false, @@ -180,7 +183,8 @@ object CsrPluginConfig{ minstretAccess = CsrAccess.READ_WRITE, ecallGen = true, wfiGenAsWait = true, - ucycleAccess = CsrAccess.READ_ONLY + ucycleAccess = CsrAccess.READ_ONLY, + uinstretAccess = CsrAccess.READ_ONLY ) def all2(mtvecInit : BigInt) : CsrPluginConfig = CsrPluginConfig( @@ -202,6 +206,7 @@ object CsrPluginConfig{ ecallGen = true, wfiGenAsWait = true, ucycleAccess = CsrAccess.READ_ONLY, + uinstretAccess = CsrAccess.READ_ONLY, supervisorGen = true, sscratchGen = true, stvecAccess = CsrAccess.READ_WRITE, @@ -233,7 +238,8 @@ object CsrPluginConfig{ minstretAccess = CsrAccess.NONE, ecallGen = false, wfiGenAsWait = false, - ucycleAccess = CsrAccess.NONE + ucycleAccess = CsrAccess.NONE, + uinstretAccess = CsrAccess.NONE ) def smallest(mtvecInit : BigInt) = CsrPluginConfig( @@ -254,7 +260,8 @@ object CsrPluginConfig{ minstretAccess = CsrAccess.NONE, ecallGen = false, wfiGenAsWait = false, - ucycleAccess = CsrAccess.NONE + ucycleAccess = CsrAccess.NONE, + uinstretAccess = CsrAccess.NONE ) } @@ -586,6 +593,8 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep //User CSR ucycleAccess(CSR.UCYCLE, mcycle(31 downto 0)) ucycleAccess(CSR.UCYCLEH, mcycle(63 downto 32)) + uinstretAccess(CSR.UINSTRET, minstret(31 downto 0)) + uinstretAccess(CSR.UINSTRETH, minstret(63 downto 32)) pipeline(MPP) := mstatus.MPP } @@ -1148,4 +1157,4 @@ class UserInterruptPlugin(interruptName : String, code : Int, privilege : Int = csr.rw(csrAddress = CSR.MIE, bitOffset = code, interruptEnable) } override def build(pipeline: VexRiscv): Unit = {} -} \ No newline at end of file +} From b901651ab54174606d189498b8cdcbeb307dbd7b Mon Sep 17 00:00:00 2001 From: Tom Verbeure Date: Tue, 19 May 2020 14:48:35 -0700 Subject: [PATCH 434/951] Add default value of NONE to uinstret CSR. --- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 539e534d..668f1b7e 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -38,7 +38,7 @@ case class CsrPluginConfig( marchid : BigInt, mimpid : BigInt, mhartid : BigInt, - misaExtensionsInit : Int, + misaExtensionsInit : Int, misaAccess : CsrAccess, mtvecAccess : CsrAccess, mtvecInit : BigInt, @@ -49,7 +49,7 @@ case class CsrPluginConfig( mcycleAccess : CsrAccess, minstretAccess : CsrAccess, ucycleAccess : CsrAccess, - uinstretAccess : CsrAccess, + uinstretAccess : CsrAccess = CsrAccess.NONE, wfiGenAsWait : Boolean, ecallGen : Boolean, xtvecModeGen : Boolean = false, From c3540bc6e05982cafbbe27c02b773d99dd44c04a Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 20 May 2020 10:37:52 +0200 Subject: [PATCH 435/951] SpinalHDL 1.4.2 --- build.sbt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.sbt b/build.sbt index c1510b23..6cdb3507 100644 --- a/build.sbt +++ b/build.sbt @@ -5,7 +5,7 @@ lazy val root = (project in file(".")). scalaVersion := "2.11.12", version := "2.0.0" )), - scalacOptions += s"-Xplugin:${new File(baseDirectory.value + "/../SpinalHDL/idslplugin/target/scala-2.11/spinalhdl-idsl-plugin_2.11-1.4.1.jar")}", + scalacOptions += s"-Xplugin:${new File(baseDirectory.value + "/../SpinalHDL/idslplugin/target/scala-2.11/spinalhdl-idsl-plugin_2.11-1.4.2.jar")}", scalacOptions += s"-Xplugin-require:idsl-plugin", libraryDependencies ++= Seq( // "com.github.spinalhdl" % "spinalhdl-core_2.11" % "1.3.6", @@ -20,4 +20,4 @@ lazy val spinalHdlSim = ProjectRef(file("../SpinalHDL"), "sim") lazy val spinalHdlCore = ProjectRef(file("../SpinalHDL"), "core") lazy val spinalHdlLib = ProjectRef(file("../SpinalHDL"), "lib") -fork := true \ No newline at end of file +fork := true From 380afa3130463fe214944366617632ebfb3e01ff Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 20 May 2020 13:45:52 +0200 Subject: [PATCH 436/951] SpinalHDL 1.4.2 --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index c1510b23..5fba42ba 100644 --- a/build.sbt +++ b/build.sbt @@ -5,7 +5,7 @@ lazy val root = (project in file(".")). scalaVersion := "2.11.12", version := "2.0.0" )), - scalacOptions += s"-Xplugin:${new File(baseDirectory.value + "/../SpinalHDL/idslplugin/target/scala-2.11/spinalhdl-idsl-plugin_2.11-1.4.1.jar")}", + scalacOptions += s"-Xplugin:${new File(baseDirectory.value + "/../SpinalHDL/idslplugin/target/scala-2.11/spinalhdl-idsl-plugin_2.11-1.4.2.jar")}", scalacOptions += s"-Xplugin-require:idsl-plugin", libraryDependencies ++= Seq( // "com.github.spinalhdl" % "spinalhdl-core_2.11" % "1.3.6", From a64fd9cf3b9f03b8b1e313c80ab744e4dace15a3 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 20 May 2020 13:49:10 +0200 Subject: [PATCH 437/951] Add CsrPlugin external hartid d$ rsp/sync now decrement pendings by signal amount --- .../demo/smp/VexRiscvSmpCluster.scala | 27 +-- .../demo/smp/VexRiscvSmpLitexCluster.scala | 99 +++++----- src/main/scala/vexriscv/ip/DataCache.scala | 174 ++++++++++++++---- .../scala/vexriscv/plugin/CsrPlugin.scala | 14 +- .../vexriscv/plugin/DBusCachedPlugin.scala | 1 + 5 files changed, 222 insertions(+), 93 deletions(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index 0a8c3ec6..38506f2e 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -54,8 +54,9 @@ case class VexRiscvSmpCluster(p : VexRiscvSmpClusterParameter, val core = new VexRiscv(cpuConfig) core.plugins.foreach { case plugin: IBusCachedPlugin => iBus = plugin.iBus.toBmb() - case plugin: DBusCachedPlugin => dBus = plugin.dBus.toBmb() + case plugin: DBusCachedPlugin => dBus = plugin.dBus.toBmb().pipelined(cmdValid = true) case plugin: CsrPlugin => { + plugin.externalMhartId := cpuId plugin.softwareInterrupt := io.softwareInterrupts(cpuId) plugin.externalInterrupt := io.externalInterrupts(cpuId) plugin.timerInterrupt := io.timerInterrupts(cpuId) @@ -112,9 +113,12 @@ case class VexRiscvSmpCluster(p : VexRiscvSmpClusterParameter, object VexRiscvSmpClusterGen { - def vexRiscvConfig(hartId : Int, + def vexRiscvConfig(hartIdWidth : Int, + hartId : Int, ioRange : UInt => Bool = (x => x(31 downto 28) === 0xF), resetVector : Long = 0x80000000l) = { + val iBusWidth = 128 + val dBusWidth = 64 val config = VexRiscvConfig( plugins = List( new MmuPlugin( @@ -135,7 +139,7 @@ object VexRiscvSmpClusterGen { wayCount = 2, addressWidth = 32, cpuDataWidth = 32, - memDataWidth = 128, + memDataWidth = iBusWidth, catchIllegalAccess = true, catchAccessFault = true, asyncTagMemory = false, @@ -151,7 +155,7 @@ object VexRiscvSmpClusterGen { ) ), new DBusCachedPlugin( - dBusCmdMasterPipe = true, + dBusCmdMasterPipe = dBusWidth == 32, dBusCmdSlavePipe = true, dBusRspSlavePipe = true, relaxedMemoryTranslationRegister = true, @@ -161,14 +165,15 @@ object VexRiscvSmpClusterGen { wayCount = 1, addressWidth = 32, cpuDataWidth = 32, - memDataWidth = 32, + memDataWidth = dBusWidth, catchAccessError = true, catchIllegal = true, catchUnaligned = true, withLrSc = true, withAmo = true, withExclusive = true, - withInvalidate = true + withInvalidate = true, + aggregationWidth = if(dBusWidth == 32) 0 else log2Up(dBusWidth/8) // ) ), memoryTranslatorPortConfig = MmuPortConfig( @@ -208,7 +213,7 @@ object VexRiscvSmpClusterGen { mulUnrollFactor = 32, divUnrollFactor = 1 ), - new CsrPlugin(CsrPluginConfig.openSbi(hartId = hartId, misa = Riscv.misaToInt("imas"))), + new CsrPlugin(CsrPluginConfig.openSbi(misa = Riscv.misaToInt("imas")).copy(withExternalMhartid = true, mhartidWidth = hartIdWidth)), new BranchPlugin( earlyBranch = false, catchAddressMisaligned = true, @@ -224,7 +229,7 @@ object VexRiscvSmpClusterGen { debugClockDomain = ClockDomain.current.copy(reset = Bool().setName("debugResetIn")), p = VexRiscvSmpClusterParameter( cpuConfigs = List.tabulate(cpuCount) { - vexRiscvConfig(_, resetVector = resetVector) + vexRiscvConfig(log2Up(cpuCount), _, resetVector = resetVector) } ) ) @@ -462,7 +467,7 @@ object VexRiscvSmpClusterOpenSbi extends App{ simConfig.allOptimisation simConfig.addSimulatorFlag("--threads 1") - val cpuCount = 1 + val cpuCount = 4 val withStall = false def gen = { @@ -573,8 +578,8 @@ object VexRiscvSmpClusterOpenSbi extends App{ // fork{ // disableSimWave() -// val atMs = 130 -// val durationMs = 15 +// val atMs = 3790 +// val durationMs = 5 // sleep(atMs*1000000) // enableSimWave() // println("** enableSimWave **") diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala index 03ccc89a..3f3047f5 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala @@ -73,13 +73,13 @@ case class LiteDramNative(p : LiteDramNativeParameter) extends Bundle with IMast } var writeCmdCounter, writeDataCounter = 0 - StreamReadyRandomizer(bus.cmd, cd) + StreamReadyRandomizer(bus.cmd, cd).factor = 0.5f StreamMonitor(bus.cmd, cd) { t => cmdQueue.enqueue(Cmd(t.addr.toLong * (p.dataWidth/8) , t.we.toBoolean)) if(t.we.toBoolean) writeCmdCounter += 1 } - StreamReadyRandomizer(bus.wdata, cd) + StreamReadyRandomizer(bus.wdata, cd).factor = 0.5f StreamMonitor(bus.wdata, cd) { p => writeDataCounter += 1 // if(p.data.toBigInt == BigInt("00000002000000020000000200000002",16)){ @@ -175,16 +175,19 @@ case class BmbToLiteDram(bmbParameter : BmbParameter, val halt = Bool() val (cmdFork, dataFork) = StreamFork2(unburstified.cmd.haltWhen(halt)) - io.output.cmd.arbitrationFrom(cmdFork.haltWhen(pendingRead.msb)) - io.output.cmd.addr := (cmdFork.address >> log2Up(liteDramParameter.dataWidth/8)).resized - io.output.cmd.we := cmdFork.isWrite + val outputCmd = Stream(LiteDramNativeCmd(liteDramParameter)) + outputCmd.arbitrationFrom(cmdFork.haltWhen(pendingRead.msb)) + outputCmd.addr := (cmdFork.address >> log2Up(liteDramParameter.dataWidth/8)).resized + outputCmd.we := cmdFork.isWrite + + io.output.cmd <-< outputCmd if(bmbParameter.canWrite) { val wData = Stream(LiteDramNativeWData(liteDramParameter)) wData.arbitrationFrom(dataFork.throwWhen(dataFork.isRead)) wData.data := dataFork.data wData.we := dataFork.mask - io.output.wdata << wData.queue(wdataFifoSize) + io.output.wdata << wData.queueLowLatency(wdataFifoSize, latency = 1) //TODO queue low latency } else { dataFork.ready := True io.output.wdata.valid := False @@ -212,7 +215,7 @@ case class BmbToLiteDram(bmbParameter : BmbParameter, unburstified.rsp.data := rdataFifo.data - pendingRead := pendingRead + U(io.output.cmd.fire && !io.output.cmd.we) - U(rdataFifo.fire) + pendingRead := pendingRead + U(outputCmd.fire && !outputCmd.we) - U(rdataFifo.fire) } object BmbToLiteDramTester extends App{ @@ -241,6 +244,7 @@ case class VexRiscvLitexSmpClusterParameter( cluster : VexRiscvSmpClusterParamet liteDram : LiteDramNativeParameter, liteDramMapping : AddressMapping) +//addAttribute("""mark_debug = "true"""") case class VexRiscvLitexSmpCluster(p : VexRiscvLitexSmpClusterParameter, debugClockDomain : ClockDomain) extends Component{ @@ -308,50 +312,59 @@ case class VexRiscvLitexSmpCluster(p : VexRiscvLitexSmpClusterParameter, iBusDecoder.io.input << iBusArbiter.io.output.pipelined(cmdValid = true) val iMem = LiteDramNative(p.liteDram) - val iMemBridge = iMem.fromBmb(iBusDecoder.io.outputs(1), wdataFifoSize = 0, rdataFifoSize = 32) - iMem.cmd >-> io.iMem.cmd - iMem.wdata >> io.iMem.wdata - iMem.rdata << io.iMem.rdata + io.iMem.fromBmb(iBusDecoder.io.outputs(1), wdataFifoSize = 0, rdataFifoSize = 32) + val iBusDecoderToPeripheral = iBusDecoder.io.outputs(0).resize(dataWidth = 32).pipelined(cmdHalfRate = true, rspValid = true) + val dBusDecoderToPeripheral = dBusDecoder.io.outputs(0).resize(dataWidth = 32).pipelined(cmdHalfRate = true, rspValid = true) + val peripheralAccessLength = Math.max(iBusDecoder.io.outputs(0).p.lengthWidth, dBusDecoder.io.outputs(0).p.lengthWidth) val peripheralArbiter = BmbArbiter( - p = dBusDecoder.io.outputs(0).p.copy(sourceWidth = dBusDecoder.io.outputs(0).p.sourceWidth + 1, lengthWidth = peripheralAccessLength), + p = dBusDecoder.io.outputs(0).p.copy( + sourceWidth = List(iBusDecoderToPeripheral, dBusDecoderToPeripheral).map(_.p.sourceWidth).max + 1, + contextWidth = List(iBusDecoderToPeripheral, dBusDecoderToPeripheral).map(_.p.contextWidth).max, + lengthWidth = peripheralAccessLength, + dataWidth = 32 + ), portCount = 2, lowerFirstPriority = true ) - peripheralArbiter.io.inputs(0) << iBusDecoder.io.outputs(0).resize(dataWidth = 32).pipelined(cmdHalfRate = true, rspValid = true) - peripheralArbiter.io.inputs(1) << dBusDecoder.io.outputs(0).resize(dataWidth = 32).pipelined(cmdHalfRate = true, rspValid = true) + peripheralArbiter.io.inputs(0) << iBusDecoderToPeripheral + peripheralArbiter.io.inputs(1) << dBusDecoderToPeripheral val peripheralWishbone = peripheralArbiter.io.output.pipelined(cmdValid = true).toWishbone() io.peripheral << peripheralWishbone } object VexRiscvLitexSmpClusterGen extends App { - val cpuCount = 4 + for(cpuCount <- List(1,2,4,8)) { + def parameter = VexRiscvLitexSmpClusterParameter( + cluster = VexRiscvSmpClusterParameter( + cpuConfigs = List.tabulate(cpuCount) { hartId => + vexRiscvConfig( + hartIdWidth = log2Up(cpuCount), + hartId = hartId, + ioRange = address => address.msb, + resetVector = 0 + ) + } + ), + liteDram = LiteDramNativeParameter(addressWidth = 32, dataWidth = 128), + liteDramMapping = SizeMapping(0x40000000l, 0x40000000l) + ) - def parameter = VexRiscvLitexSmpClusterParameter( - cluster = VexRiscvSmpClusterParameter( - cpuConfigs = List.tabulate(cpuCount) { hartId => - vexRiscvConfig( - hartId = hartId, - ioRange = address => address.msb, - resetVector = 0 - ) - } - ), - liteDram = LiteDramNativeParameter(addressWidth = 32, dataWidth = 128), - liteDramMapping = SizeMapping(0x40000000l, 0x40000000l) - ) + def dutGen = { + val toplevel = VexRiscvLitexSmpCluster( + p = parameter, + debugClockDomain = ClockDomain.current.copy(reset = Bool().setName("debugResetIn")) + ) + toplevel + } - def dutGen = VexRiscvLitexSmpCluster( - p = parameter, - debugClockDomain = ClockDomain.current.copy(reset = Bool().setName("debugResetIn")) - ) - - val genConfig = SpinalConfig().addStandardMemBlackboxing(blackboxByteEnables) -// genConfig.generateVerilog(Bench.compressIo(dutGen)) - genConfig.generateVerilog(dutGen) + val genConfig = SpinalConfig().addStandardMemBlackboxing(blackboxByteEnables) + // genConfig.generateVerilog(Bench.compressIo(dutGen)) + genConfig.generateVerilog(dutGen.setDefinitionName(s"VexRiscvLitexSmpCluster_${cpuCount}c")) + } } @@ -363,13 +376,13 @@ object VexRiscvLitexSmpClusterOpenSbi extends App{ simConfig.withWave simConfig.allOptimisation - val cpuCount = 4 - val withStall = false + val cpuCount = 8 def parameter = VexRiscvLitexSmpClusterParameter( cluster = VexRiscvSmpClusterParameter( cpuConfigs = List.tabulate(cpuCount) { hartId => vexRiscvConfig( + hartIdWidth = log2Up(cpuCount), hartId = hartId, ioRange = address => address(31 downto 28) === 0xF, resetVector = 0x80000000l @@ -440,12 +453,12 @@ object VexRiscvLitexSmpClusterOpenSbi extends App{ // fork{ // disableSimWave() -// val atMs = 8 -// val durationMs = 3 -// sleep(atMs*1000000) +// val atMs = 3790 +// val durationMs = 5 +// sleep(atMs*1000000l) // enableSimWave() // println("** enableSimWave **") -// sleep(durationMs*1000000) +// sleep(durationMs*1000000l) // println("** disableSimWave **") // while(true) { // disableSimWave() @@ -453,7 +466,7 @@ object VexRiscvLitexSmpClusterOpenSbi extends App{ // enableSimWave() // sleep( 100 * 10) // } -// // simSuccess() +// // simSuccess() // } fork{ diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index 2f2e8c2f..82fa3afa 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -5,7 +5,7 @@ import spinal.core._ import spinal.lib._ import spinal.lib.bus.amba4.axi.{Axi4Config, Axi4Shared} import spinal.lib.bus.avalon.{AvalonMM, AvalonMMConfig} -import spinal.lib.bus.bmb.{Bmb, BmbParameter} +import spinal.lib.bus.bmb.{Bmb, BmbCmd, BmbParameter} import spinal.lib.bus.wishbone.{Wishbone, WishboneConfig} import spinal.lib.bus.simple._ import vexriscv.plugin.DBusSimpleBus @@ -29,7 +29,8 @@ case class DataCacheConfig(cacheSize : Int, withInvalidate : Boolean = false, pendingMax : Int = 32, directTlbHit : Boolean = false, - mergeExecuteMemory : Boolean = false){ + mergeExecuteMemory : Boolean = false, + aggregationWidth : Int = 0){ assert(!(mergeExecuteMemory && (earlyDataMux || earlyWaysHits))) assert(!(earlyDataMux && !earlyWaysHits)) assert(isPow2(pendingMax)) @@ -41,6 +42,8 @@ case class DataCacheConfig(cacheSize : Int, def withInternalLrSc = withLrSc && !withExclusive def withExternalLrSc = withLrSc && withExclusive def withExternalAmo = withAmo && withExclusive + def cpuDataBytes = cpuDataWidth/8 + def memDataBytes = memDataWidth/8 def getAxi4SharedConfig() = Axi4Config( addressWidth = addressWidth, dataWidth = memDataWidth, @@ -79,10 +82,10 @@ case class DataCacheConfig(cacheSize : Int, def getBmbParameter() = BmbParameter( addressWidth = 32, - dataWidth = 32, + dataWidth = memDataWidth, lengthWidth = log2Up(this.bytePerLine), sourceWidth = 0, - contextWidth = if(!withWriteResponse) 1 else 0, + contextWidth = (if(!withWriteResponse) 1 else 0) + (if(cpuDataWidth != memDataWidth) log2Up(memDataBytes) else 0), canRead = true, canWrite = true, alignment = BmbParameter.BurstAlignement.LENGTH, @@ -203,6 +206,7 @@ case class DataCacheMemCmd(p : DataCacheConfig) extends Bundle{ val last = Bool } case class DataCacheMemRsp(p : DataCacheConfig) extends Bundle{ + val aggregated = UInt(p.aggregationWidth bits) val last = Bool() val data = Bits(p.memDataWidth bit) val error = Bool @@ -217,7 +221,7 @@ case class DataCacheAck(p : DataCacheConfig) extends Bundle{ } case class DataCacheSync(p : DataCacheConfig) extends Bundle{ - + val aggregated = UInt(p.aggregationWidth bits) } case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave{ @@ -369,21 +373,133 @@ case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave } - def toBmb() : Bmb = { + def toBmb(syncPendingMax : Int = 16, + timeoutCycles : Int = 16) : Bmb = new Area{ + setCompositeName(DataCacheMemBus.this, "Bridge", true) val pipelinedMemoryBusConfig = p.getBmbParameter() val bus = Bmb(pipelinedMemoryBusConfig).setCompositeName(this,"toBmb", true) + val aggregationMax = p.memDataBytes - bus.cmd.valid := cmd.valid - bus.cmd.last := cmd.last - if(!p.withWriteResponse) bus.cmd.context(0) := cmd.wr - bus.cmd.opcode := (cmd.wr ? B(Bmb.Cmd.Opcode.WRITE) | B(Bmb.Cmd.Opcode.READ)) - bus.cmd.address := cmd.address.resized - bus.cmd.data := cmd.data - bus.cmd.length := (cmd.length << 2) | 3 //TODO better sub word access - bus.cmd.mask := cmd.mask - if(p.withExclusive) bus.cmd.exclusive := cmd.exclusive + case class Context() extends Bundle{ + val isWrite = !p.withWriteResponse generate Bool() + val rspCount = (p.cpuDataWidth != p.memDataWidth) generate UInt(log2Up(aggregationMax) bits) + } + + val withoutWriteBuffer = if(p.cpuDataWidth == p.memDataWidth) new Area { + val busCmdContext = Context() + + bus.cmd.valid := cmd.valid + bus.cmd.last := cmd.last + bus.cmd.opcode := (cmd.wr ? B(Bmb.Cmd.Opcode.WRITE) | B(Bmb.Cmd.Opcode.READ)) + bus.cmd.address := cmd.address.resized + bus.cmd.data := cmd.data + bus.cmd.length := (cmd.length << 2) | 3 + bus.cmd.mask := cmd.mask + if (p.withExclusive) bus.cmd.exclusive := cmd.exclusive + if (!p.withWriteResponse) busCmdContext.isWrite := cmd.wr + bus.cmd.context := B(busCmdContext) + + cmd.ready := bus.cmd.ready + if(p.withInvalidate) sync.arbitrationFrom(bus.sync) + } + + val withWriteBuffer = if(p.cpuDataWidth != p.memDataWidth) new Area { + val buffer = new Area { + val stream = cmd.toEvent().m2sPipe() + val address = Reg(UInt(p.addressWidth bits)) + val length = Reg(UInt(pipelinedMemoryBusConfig.lengthWidth bits)) + val write = Reg(Bool) + val exclusive = Reg(Bool) + val data = Reg(Bits(p.memDataWidth bits)) + val mask = Reg(Bits(p.memDataWidth/8 bits)) init(0) + } + + val aggregationRange = log2Up(p.memDataWidth/8)-1 downto log2Up(p.cpuDataWidth/8) + val tagRange = p.addressWidth-1 downto aggregationRange.high+1 + val aggregationEnabled = Reg(Bool) + val aggregationCounter = Reg(UInt(log2Up(aggregationMax) bits)) init(0) + val aggregationCounterFull = aggregationCounter === aggregationCounter.maxValue + val timer = Reg(UInt(log2Up(timeoutCycles)+1 bits)) init(0) + val timerFull = timer.msb + val hit = cmd.address(tagRange) === buffer.address(tagRange) + val canAggregate = cmd.valid && cmd.wr && !cmd.uncached && !cmd.exclusive && !timerFull && !aggregationCounterFull && (!buffer.stream.valid || aggregationEnabled && hit) + val doFlush = cmd.valid && !canAggregate || timerFull || aggregationCounterFull || !aggregationEnabled +// val canAggregate = False +// val doFlush = True + val busCmdContext = Context() + val halt = False + + when(cmd.fire){ + aggregationCounter := aggregationCounter + 1 + } + when(buffer.stream.valid && !timerFull){ + timer := timer + 1 + } + when(bus.cmd.fire || !buffer.stream.valid){ + buffer.mask := 0 + aggregationCounter := 0 + timer := 0 + } + + buffer.stream.ready := (bus.cmd.ready && doFlush || canAggregate) && !halt + bus.cmd.valid := buffer.stream.valid && doFlush && !halt + bus.cmd.last := True + bus.cmd.opcode := (buffer.write ? B(Bmb.Cmd.Opcode.WRITE) | B(Bmb.Cmd.Opcode.READ)) + bus.cmd.address := buffer.address + bus.cmd.length := buffer.length + bus.cmd.data := buffer.data + bus.cmd.mask := buffer.mask + + if (p.withExclusive) bus.cmd.exclusive := buffer.exclusive + bus.cmd.context.removeAssignments() := B(busCmdContext) + if (!p.withWriteResponse) busCmdContext.isWrite := bus.cmd.isWrite + busCmdContext.rspCount := aggregationCounter + + val aggregationSel = cmd.address(aggregationRange) + when(cmd.fire){ + val dIn = cmd.data.subdivideIn(8 bits) + val dReg = buffer.data.subdivideIn(8 bits) + for(byteId <- 0 until p.memDataBytes){ + when(aggregationSel === byteId / p.cpuDataBytes && cmd.mask(byteId % p.cpuDataBytes)){ + dReg.write(byteId, dIn(byteId % p.cpuDataBytes)) + buffer.mask(byteId) := True + } + } + } + + when(cmd.fire){ + buffer.write := cmd.wr + buffer.address := cmd.address.resized + buffer.length := (cmd.length << 2) | 3 + if (p.withExclusive) buffer.exclusive := cmd.exclusive + + when(cmd.wr && !cmd.uncached && !cmd.exclusive){ + aggregationEnabled := True + buffer.address(aggregationRange.high downto 0) := 0 + buffer.length := p.memDataBytes-1 + } otherwise { + aggregationEnabled := False + } + } + + + val rspCtx = bus.rsp.context.as(Context()) + rsp.aggregated := rspCtx.rspCount + + val syncLogic = p.withInvalidate generate new Area{ + val cmdCtx = Stream(UInt(log2Up(aggregationMax) bits)) + cmdCtx.valid := bus.cmd.fire && bus.cmd.isWrite + cmdCtx.payload := aggregationCounter + halt setWhen(!cmdCtx.ready) + + val syncCtx = cmdCtx.queueLowLatency(syncPendingMax, latency = 1) + syncCtx.ready := bus.sync.fire + + sync.arbitrationFrom(bus.sync) + sync.aggregated := syncCtx.payload + } + } - cmd.ready := bus.cmd.ready rsp.valid := bus.rsp.valid if(!p.withWriteResponse) rsp.valid clearWhen(bus.rsp.context(0)) @@ -399,21 +515,9 @@ case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave inv.enable := bus.inv.all bus.ack.arbitrationFrom(ack) - - sync.arbitrationFrom(bus.sync) - -// bus.ack.arbitrationFrom(ack) -// //TODO manage lenght ? -// inv.address := bus.inv.address -//// inv.opcode := bus.inv.opcode -// ??? -// -// bus.ack.arbitrationFrom(ack) + // //TODO manage lenght ? } - - - bus - } + }.bus } @@ -537,7 +641,7 @@ class DataCache(val p : DataCacheConfig, mmuParameter : MemoryTranslatorBusParam val memCmdSent = RegInit(False) setWhen (io.mem.cmd.ready) clearWhen (!io.cpu.writeBack.isStuck) val pending = withExclusive generate new Area{ val counter = Reg(UInt(log2Up(pendingMax) + 1 bits)) init(0) - val counterNext = counter + U(io.mem.cmd.fire && io.mem.cmd.last) - U(io.mem.rsp.valid && io.mem.rsp.last) + val counterNext = counter + U(io.mem.cmd.fire && io.mem.cmd.last) - ((io.mem.rsp.valid && io.mem.rsp.last) ? (io.mem.rsp.aggregated +^ 1) | 0) counter := counterNext val done = RegNext(counterNext === 0) @@ -554,7 +658,7 @@ class DataCache(val p : DataCacheConfig, mmuParameter : MemoryTranslatorBusParam val sync = withInvalidate generate new Area{ io.mem.sync.ready := True - + val syncCount = io.mem.sync.aggregated +^ 1 val syncContext = new Area{ val history = Mem(Bool, pendingMax) val wPtr, rPtr = Reg(UInt(log2Up(pendingMax)+1 bits)) init(0) @@ -564,7 +668,7 @@ class DataCache(val p : DataCacheConfig, mmuParameter : MemoryTranslatorBusParam } when(io.mem.sync.fire){ - rPtr := rPtr + 1 + rPtr := rPtr + syncCount } val uncached = history.readAsync(rPtr.resized) val full = RegNext(wPtr - rPtr >= pendingMax-1) @@ -573,7 +677,7 @@ class DataCache(val p : DataCacheConfig, mmuParameter : MemoryTranslatorBusParam def pending(inc : Bool, dec : Bool) = new Area { val pendingSync = Reg(UInt(log2Up(pendingMax) + 1 bits)) init(0) - val pendingSyncNext = pendingSync + U(io.mem.cmd.fire && io.mem.cmd.wr && inc) - U(io.mem.sync.fire && dec) + val pendingSyncNext = pendingSync + U(io.mem.cmd.fire && io.mem.cmd.wr && inc) - ((io.mem.sync.fire && dec) ? syncCount | 0) pendingSync := pendingSyncNext } @@ -582,7 +686,7 @@ class DataCache(val p : DataCacheConfig, mmuParameter : MemoryTranslatorBusParam def track(load : Bool, uncached : Boolean) = new Area { val counter = Reg(UInt(log2Up(pendingMax) + 1 bits)) init(0) - counter := counter - U(io.mem.sync.fire && counter =/= 0 && (if(uncached) syncContext.uncached else !syncContext.uncached)) + counter := counter - ((io.mem.sync.fire && counter =/= 0 && (if(uncached) syncContext.uncached else !syncContext.uncached)) ? syncCount | 0) when(load){ counter := (if(uncached) writeUncached.pendingSyncNext else writeCached.pendingSyncNext) } val busy = counter =/= 0 diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 43dbfaf0..23f3323d 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -39,7 +39,7 @@ case class CsrPluginConfig( marchid : BigInt, mimpid : BigInt, mhartid : BigInt, - misaExtensionsInit : Int, + misaExtensionsInit : Int, misaAccess : CsrAccess, mtvecAccess : CsrAccess, mtvecInit : BigInt, @@ -68,6 +68,8 @@ case class CsrPluginConfig( satpAccess : CsrAccess = CsrAccess.NONE, medelegAccess : CsrAccess = CsrAccess.NONE, midelegAccess : CsrAccess = CsrAccess.NONE, + withExternalMhartid : Boolean = false, + mhartidWidth : Int = 0, pipelineCsrRead : Boolean = false, pipelinedInterrupt : Boolean = true, csrOhDecoder : Boolean = true, @@ -85,12 +87,12 @@ object CsrPluginConfig{ def small : CsrPluginConfig = small(0x00000020l) def smallest : CsrPluginConfig = smallest(0x00000020l) - def openSbi(hartId : Int, misa : Int) = CsrPluginConfig( + def openSbi(misa : Int) = CsrPluginConfig( catchIllegalAccess = true, mvendorid = 0, marchid = 0, mimpid = 0, - mhartid = hartId, + mhartid = 0, misaExtensionsInit = misa, misaAccess = CsrAccess.READ_ONLY, mtvecAccess = CsrAccess.READ_WRITE, //Could have been WRITE_ONLY :( @@ -387,6 +389,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep var contextSwitching : Bool = null var thirdPartyWake : Bool = null var inWfi : Bool = null + var externalMhartId : UInt = null override def askWake(): Unit = thirdPartyWake := True @@ -515,6 +518,8 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep pipeline.update(MPP, UInt(2 bits)) + + if(withExternalMhartid) externalMhartId = in UInt(mhartidWidth bits) } def inhibateInterrupts() : Unit = allowInterrupts := False @@ -600,7 +605,8 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep if(mvendorid != null) READ_ONLY(CSR.MVENDORID, U(mvendorid)) if(marchid != null) READ_ONLY(CSR.MARCHID , U(marchid )) if(mimpid != null) READ_ONLY(CSR.MIMPID , U(mimpid )) - if(mhartid != null) READ_ONLY(CSR.MHARTID , U(mhartid )) + if(mhartid != null && !withExternalMhartid) READ_ONLY(CSR.MHARTID , U(mhartid )) + if(withExternalMhartid) READ_ONLY(CSR.MHARTID , externalMhartId) misaAccess(CSR.MISA, xlen-2 -> misa.base , 0 -> misa.extensions) //Machine CSR diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index f1336160..0b580d83 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -195,6 +195,7 @@ class DBusCachedPlugin(val config : DataCacheConfig, rsp.exclusive := RegNext(dBus.rsp.exclusive) rsp.error := RegNext(dBus.rsp.error) rsp.last := RegNext(dBus.rsp.last) + rsp.aggregated := RegNext(dBus.rsp.aggregated) rsp.data := RegNextWhen(dBus.rsp.data, dBus.rsp.valid && !cache.io.cpu.writeBack.keepMemRspData) rsp } From 18cce053a33649c783371662c4150cef5e9f501d Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 27 May 2020 14:19:17 +0200 Subject: [PATCH 438/951] Improve SingleInstructionLimiterPlugin to also include fetch stages --- .../vexriscv/plugin/SingleInstructionLimiterPlugin.scala | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/SingleInstructionLimiterPlugin.scala b/src/main/scala/vexriscv/plugin/SingleInstructionLimiterPlugin.scala index deae767a..c6c97061 100644 --- a/src/main/scala/vexriscv/plugin/SingleInstructionLimiterPlugin.scala +++ b/src/main/scala/vexriscv/plugin/SingleInstructionLimiterPlugin.scala @@ -9,7 +9,9 @@ class SingleInstructionLimiterPlugin() extends Plugin[VexRiscv] { override def build(pipeline: VexRiscv): Unit = { import pipeline._ import pipeline.config._ - - decode.arbitration.haltByOther.setWhen(List(decode,execute,memory,writeBack).map(_.arbitration.isValid).orR) + val fetcher = pipeline.service(classOf[IBusFetcher]) + when(fetcher.incoming() || List(decode,execute,memory,writeBack).map(_.arbitration.isValid).orR) { + fetcher.haltIt() + } } } From bc4a2c37473dc6ffe7d78c91c9d8b6aabb3c2a4a Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 27 May 2020 14:19:37 +0200 Subject: [PATCH 439/951] Fix SmpCluster jtag --- .../vexriscv/demo/smp/VexRiscvSmpCluster.scala | 17 ++++++++--------- .../demo/smp/VexRiscvSmpLitexCluster.scala | 2 -- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 4 ++-- 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index 38506f2e..422b1e28 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -51,12 +51,12 @@ case class VexRiscvSmpCluster(p : VexRiscvSmpClusterParameter, } case _ => } + if(cpuId == 0) cpuConfig.plugins += new DebugPlugin(debugClockDomain) val core = new VexRiscv(cpuConfig) core.plugins.foreach { case plugin: IBusCachedPlugin => iBus = plugin.iBus.toBmb() case plugin: DBusCachedPlugin => dBus = plugin.dBus.toBmb().pipelined(cmdValid = true) case plugin: CsrPlugin => { - plugin.externalMhartId := cpuId plugin.softwareInterrupt := io.softwareInterrupts(cpuId) plugin.externalInterrupt := io.externalInterrupts(cpuId) plugin.timerInterrupt := io.timerInterrupts(cpuId) @@ -113,12 +113,12 @@ case class VexRiscvSmpCluster(p : VexRiscvSmpClusterParameter, object VexRiscvSmpClusterGen { - def vexRiscvConfig(hartIdWidth : Int, - hartId : Int, + def vexRiscvConfig(hartId : Int, ioRange : UInt => Bool = (x => x(31 downto 28) === 0xF), - resetVector : Long = 0x80000000l) = { - val iBusWidth = 128 - val dBusWidth = 64 + resetVector : Long = 0x80000000l, + iBusWidth : Int = 128, + dBusWidth : Int = 64) = { + val config = VexRiscvConfig( plugins = List( new MmuPlugin( @@ -213,7 +213,7 @@ object VexRiscvSmpClusterGen { mulUnrollFactor = 32, divUnrollFactor = 1 ), - new CsrPlugin(CsrPluginConfig.openSbi(misa = Riscv.misaToInt("imas")).copy(withExternalMhartid = true, mhartidWidth = hartIdWidth)), + new CsrPlugin(CsrPluginConfig.openSbi(mhartid = hartId, misa = Riscv.misaToInt("imas"))), new BranchPlugin( earlyBranch = false, catchAddressMisaligned = true, @@ -222,14 +222,13 @@ object VexRiscvSmpClusterGen { new YamlPlugin(s"cpu$hartId.yaml") ) ) - if(hartId == 0) config.plugins += new DebugPlugin(null) config } def vexRiscvCluster(cpuCount : Int, resetVector : Long = 0x80000000l) = VexRiscvSmpCluster( debugClockDomain = ClockDomain.current.copy(reset = Bool().setName("debugResetIn")), p = VexRiscvSmpClusterParameter( cpuConfigs = List.tabulate(cpuCount) { - vexRiscvConfig(log2Up(cpuCount), _, resetVector = resetVector) + vexRiscvConfig(_, resetVector = resetVector) } ) ) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala index 3f3047f5..30753c22 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala @@ -342,7 +342,6 @@ object VexRiscvLitexSmpClusterGen extends App { cluster = VexRiscvSmpClusterParameter( cpuConfigs = List.tabulate(cpuCount) { hartId => vexRiscvConfig( - hartIdWidth = log2Up(cpuCount), hartId = hartId, ioRange = address => address.msb, resetVector = 0 @@ -382,7 +381,6 @@ object VexRiscvLitexSmpClusterOpenSbi extends App{ cluster = VexRiscvSmpClusterParameter( cpuConfigs = List.tabulate(cpuCount) { hartId => vexRiscvConfig( - hartIdWidth = log2Up(cpuCount), hartId = hartId, ioRange = address => address(31 downto 28) === 0xF, resetVector = 0x80000000l diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 23f3323d..ebff1e09 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -87,12 +87,12 @@ object CsrPluginConfig{ def small : CsrPluginConfig = small(0x00000020l) def smallest : CsrPluginConfig = smallest(0x00000020l) - def openSbi(misa : Int) = CsrPluginConfig( + def openSbi(mhartid : Int, misa : Int) = CsrPluginConfig( catchIllegalAccess = true, mvendorid = 0, marchid = 0, mimpid = 0, - mhartid = 0, + mhartid = mhartid, misaExtensionsInit = misa, misaAccess = CsrAccess.READ_ONLY, mtvecAccess = CsrAccess.READ_WRITE, //Could have been WRITE_ONLY :( From 5e5c730959c79896e1c628ccff213d0a7999b30e Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 29 May 2020 10:56:55 +0200 Subject: [PATCH 440/951] Add LitexSmpDevCluster with per cpu dedicated litedram ports --- src/main/scala/vexriscv/demo/smp/Misc.scala | 242 ++++++++++++++++ .../demo/smp/VexRiscvSmpLitexCluster.scala | 221 --------------- .../demo/smp/VexRiscvSmpLitexDevCluster.scala | 262 ++++++++++++++++++ 3 files changed, 504 insertions(+), 221 deletions(-) create mode 100644 src/main/scala/vexriscv/demo/smp/Misc.scala create mode 100644 src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexDevCluster.scala diff --git a/src/main/scala/vexriscv/demo/smp/Misc.scala b/src/main/scala/vexriscv/demo/smp/Misc.scala new file mode 100644 index 00000000..a7965a49 --- /dev/null +++ b/src/main/scala/vexriscv/demo/smp/Misc.scala @@ -0,0 +1,242 @@ +package vexriscv.demo.smp + + +import spinal.core._ +import spinal.lib.bus.bmb._ +import spinal.lib.bus.wishbone.{Wishbone, WishboneConfig, WishboneSlaveFactory} +import spinal.lib.com.jtag.Jtag +import spinal.lib._ +import spinal.lib.bus.bmb.sim.{BmbMemoryMultiPort, BmbMemoryTester} +import spinal.lib.bus.misc.{AddressMapping, DefaultMapping, SizeMapping} +import spinal.lib.eda.bench.Bench +import spinal.lib.misc.Clint +import spinal.lib.sim.{SimData, SparseMemory, StreamDriver, StreamMonitor, StreamReadyRandomizer} +import vexriscv.demo.smp.VexRiscvLitexSmpClusterOpenSbi.{cpuCount, parameter} +import vexriscv.demo.smp.VexRiscvSmpClusterGen.vexRiscvConfig +import vexriscv.{VexRiscv, VexRiscvConfig} +import vexriscv.plugin.{CsrPlugin, DBusCachedPlugin, DebugPlugin, IBusCachedPlugin} + +import scala.collection.mutable +import scala.util.Random + +case class LiteDramNativeParameter(addressWidth : Int, dataWidth : Int) + +case class LiteDramNativeCmd(p : LiteDramNativeParameter) extends Bundle{ + val we = Bool() + val addr = UInt(p.addressWidth bits) +} + +case class LiteDramNativeWData(p : LiteDramNativeParameter) extends Bundle{ + val data = Bits(p.dataWidth bits) + val we = Bits(p.dataWidth/8 bits) +} + +case class LiteDramNativeRData(p : LiteDramNativeParameter) extends Bundle{ + val data = Bits(p.dataWidth bits) +} + + +case class LiteDramNative(p : LiteDramNativeParameter) extends Bundle with IMasterSlave { + val cmd = Stream(LiteDramNativeCmd(p)) + val wdata = Stream(LiteDramNativeWData(p)) + val rdata = Stream(LiteDramNativeRData(p)) + override def asMaster(): Unit = { + master(cmd, wdata) + slave(rdata) + } + + def fromBmb(bmb : Bmb, wdataFifoSize : Int, rdataFifoSize : Int) = { + val bridge = BmbToLiteDram( + bmbParameter = bmb.p, + liteDramParameter = this.p, + wdataFifoSize = wdataFifoSize, + rdataFifoSize = rdataFifoSize + ) + bridge.io.input << bmb + bridge.io.output <> this + bridge + } + + def simSlave(ram : SparseMemory,cd : ClockDomain, bmb : Bmb = null): Unit ={ + import spinal.core.sim._ + def bus = this + case class Cmd(address : Long, we : Boolean) + case class WData(data : BigInt, we : Long) + val cmdQueue = mutable.Queue[Cmd]() + val wdataQueue = mutable.Queue[WData]() + val rdataQueue = mutable.Queue[BigInt]() + + + case class Ref(address : Long, data : BigInt, we : Long, time : Long) + val ref = mutable.Queue[Ref]() + if(bmb != null) StreamMonitor(bmb.cmd, cd){p => + if(bmb.cmd.opcode.toInt == 1) ref.enqueue(Ref(p.fragment.address.toLong, p.fragment.data.toBigInt, p.fragment.mask.toLong, simTime())) + } + + var writeCmdCounter, writeDataCounter = 0 + StreamReadyRandomizer(bus.cmd, cd).factor = 0.5f + StreamMonitor(bus.cmd, cd) { t => + cmdQueue.enqueue(Cmd(t.addr.toLong * (p.dataWidth/8) , t.we.toBoolean)) + if(t.we.toBoolean) writeCmdCounter += 1 + } + + StreamReadyRandomizer(bus.wdata, cd).factor = 0.5f + StreamMonitor(bus.wdata, cd) { p => + writeDataCounter += 1 + // if(p.data.toBigInt == BigInt("00000002000000020000000200000002",16)){ + // println("ASD") + // } + wdataQueue.enqueue(WData(p.data.toBigInt, p.we.toLong)) + } + + // new SimStreamAssert(cmd,cd) + // new SimStreamAssert(wdata,cd) + // new SimStreamAssert(rdata,cd) + + cd.onSamplings{ + if(writeDataCounter-writeCmdCounter > 2){ + println("miaou") + } + if(cmdQueue.nonEmpty && Random.nextFloat() < 0.5){ + val cmd = cmdQueue.head + if(cmd.we){ + if(wdataQueue.nonEmpty){ + // if(cmd.address == 0xc02ae850l) { + // println(s"! $writeCmdCounter $writeDataCounter") + // } + cmdQueue.dequeue() + val wdata = wdataQueue.dequeue() + val raw = wdata.data.toByteArray + val left = wdata.data.toByteArray.size-1 + if(bmb != null){ + assert(ref.nonEmpty) + assert((ref.head.address & 0xFFFFFFF0l) == cmd.address) + assert(ref.head.data == wdata.data) + assert(ref.head.we == wdata.we) + ref.dequeue() + } + // if(cmd.address == 0xc02ae850l) { + // println(s"$cmd $wdata ${simTime()}") + // } + for(i <- 0 until p.dataWidth/8){ + + + if(((wdata.we >> i) & 1) != 0) { + // if(cmd.address == 0xc02ae850l) { + // println(s"W $i ${ if (left - i >= 0) raw(left - i) else 0}") + // } + ram.write(cmd.address + i, if (left - i >= 0) raw(left - i) else 0) + } + } + } + } else { + cmdQueue.dequeue() + val value = new Array[Byte](p.dataWidth/8+1) + val left = value.size-1 + for(i <- 0 until p.dataWidth/8) { + value(left-i) = ram.read(cmd.address+i) + } + rdataQueue.enqueue(BigInt(value)) + } + } + } + + StreamDriver(bus.rdata, cd){ p => + if(rdataQueue.isEmpty){ + false + } else { + p.data #= rdataQueue.dequeue() + true + } + } + } +} + + + +case class BmbToLiteDram(bmbParameter : BmbParameter, + liteDramParameter : LiteDramNativeParameter, + wdataFifoSize : Int, + rdataFifoSize : Int) extends Component{ + val io = new Bundle { + val input = slave(Bmb(bmbParameter)) + val output = master(LiteDramNative(liteDramParameter)) + } + + val resized = io.input.resize(liteDramParameter.dataWidth) + val unburstified = resized.unburstify() + case class Context() extends Bundle { + val context = Bits(unburstified.p.contextWidth bits) + val source = UInt(unburstified.p.sourceWidth bits) + val isWrite = Bool() + } + + assert(isPow2(rdataFifoSize)) + val pendingRead = Reg(UInt(log2Up(rdataFifoSize) + 1 bits)) init(0) + + val halt = Bool() + val (cmdFork, dataFork) = StreamFork2(unburstified.cmd.haltWhen(halt)) + val outputCmd = Stream(LiteDramNativeCmd(liteDramParameter)) + outputCmd.arbitrationFrom(cmdFork.haltWhen(pendingRead.msb)) + outputCmd.addr := (cmdFork.address >> log2Up(liteDramParameter.dataWidth/8)).resized + outputCmd.we := cmdFork.isWrite + + io.output.cmd <-< outputCmd + + if(bmbParameter.canWrite) { + val wData = Stream(LiteDramNativeWData(liteDramParameter)) + wData.arbitrationFrom(dataFork.throwWhen(dataFork.isRead)) + wData.data := dataFork.data + wData.we := dataFork.mask + io.output.wdata << wData.queueLowLatency(wdataFifoSize, latency = 1) //TODO queue low latency + } else { + dataFork.ready := True + io.output.wdata.valid := False + io.output.wdata.data.assignDontCare() + io.output.wdata.we.assignDontCare() + } + + val cmdContext = Stream(Context()) + cmdContext.valid := unburstified.cmd.fire + cmdContext.context := unburstified.cmd.context + cmdContext.source := unburstified.cmd.source + cmdContext.isWrite := unburstified.cmd.isWrite + halt := !cmdContext.ready + + val rspContext = cmdContext.queue(rdataFifoSize) + val rdataFifo = io.output.rdata.queueLowLatency(rdataFifoSize, latency = 1) + + rdataFifo.ready := unburstified.rsp.fire && !rspContext.isWrite + rspContext.ready := unburstified.rsp.fire + unburstified.rsp.valid := rspContext.valid && (rspContext.isWrite || rdataFifo.valid) + unburstified.rsp.setSuccess() + unburstified.rsp.last := True + unburstified.rsp.source := rspContext.source + unburstified.rsp.context := rspContext.context + unburstified.rsp.data := rdataFifo.data + + + pendingRead := pendingRead + U(outputCmd.fire && !outputCmd.we) - U(rdataFifo.fire) +} + +object BmbToLiteDramTester extends App{ + import spinal.core.sim._ + SimConfig.withWave.compile(BmbToLiteDram( + bmbParameter = BmbParameter( + addressWidth = 20, + dataWidth = 32, + lengthWidth = 6, + sourceWidth = 4, + contextWidth = 16 + ), + liteDramParameter = LiteDramNativeParameter( + addressWidth = 20, + dataWidth = 128 + ), + wdataFifoSize = 16, + rdataFifoSize = 16 + )).doSimUntilVoid(seed = 42){dut => + val tester = new BmbMemoryTester(dut.io.input, dut.clockDomain, rspCounterTarget = 3000) + dut.io.output.simSlave(tester.memory.memory, dut.clockDomain) + } +} \ No newline at end of file diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala index 30753c22..f73c8598 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala @@ -18,227 +18,6 @@ import vexriscv.plugin.{CsrPlugin, DBusCachedPlugin, DebugPlugin, IBusCachedPlug import scala.collection.mutable import scala.util.Random -case class LiteDramNativeParameter(addressWidth : Int, dataWidth : Int) - -case class LiteDramNativeCmd(p : LiteDramNativeParameter) extends Bundle{ - val we = Bool() - val addr = UInt(p.addressWidth bits) -} - -case class LiteDramNativeWData(p : LiteDramNativeParameter) extends Bundle{ - val data = Bits(p.dataWidth bits) - val we = Bits(p.dataWidth/8 bits) -} - -case class LiteDramNativeRData(p : LiteDramNativeParameter) extends Bundle{ - val data = Bits(p.dataWidth bits) -} - - -case class LiteDramNative(p : LiteDramNativeParameter) extends Bundle with IMasterSlave { - val cmd = Stream(LiteDramNativeCmd(p)) - val wdata = Stream(LiteDramNativeWData(p)) - val rdata = Stream(LiteDramNativeRData(p)) - override def asMaster(): Unit = { - master(cmd, wdata) - slave(rdata) - } - - def fromBmb(bmb : Bmb, wdataFifoSize : Int, rdataFifoSize : Int) = { - val bridge = BmbToLiteDram( - bmbParameter = bmb.p, - liteDramParameter = this.p, - wdataFifoSize = wdataFifoSize, - rdataFifoSize = rdataFifoSize - ) - bridge.io.input << bmb - bridge.io.output <> this - bridge - } - - def simSlave(ram : SparseMemory,cd : ClockDomain, bmb : Bmb = null): Unit ={ - import spinal.core.sim._ - def bus = this - case class Cmd(address : Long, we : Boolean) - case class WData(data : BigInt, we : Long) - val cmdQueue = mutable.Queue[Cmd]() - val wdataQueue = mutable.Queue[WData]() - val rdataQueue = mutable.Queue[BigInt]() - - - case class Ref(address : Long, data : BigInt, we : Long, time : Long) - val ref = mutable.Queue[Ref]() - if(bmb != null) StreamMonitor(bmb.cmd, cd){p => - if(bmb.cmd.opcode.toInt == 1) ref.enqueue(Ref(p.fragment.address.toLong, p.fragment.data.toBigInt, p.fragment.mask.toLong, simTime())) - } - - var writeCmdCounter, writeDataCounter = 0 - StreamReadyRandomizer(bus.cmd, cd).factor = 0.5f - StreamMonitor(bus.cmd, cd) { t => - cmdQueue.enqueue(Cmd(t.addr.toLong * (p.dataWidth/8) , t.we.toBoolean)) - if(t.we.toBoolean) writeCmdCounter += 1 - } - - StreamReadyRandomizer(bus.wdata, cd).factor = 0.5f - StreamMonitor(bus.wdata, cd) { p => - writeDataCounter += 1 -// if(p.data.toBigInt == BigInt("00000002000000020000000200000002",16)){ -// println("ASD") -// } - wdataQueue.enqueue(WData(p.data.toBigInt, p.we.toLong)) - } - -// new SimStreamAssert(cmd,cd) -// new SimStreamAssert(wdata,cd) -// new SimStreamAssert(rdata,cd) - - cd.onSamplings{ - if(writeDataCounter-writeCmdCounter > 2){ - println("miaou") - } - if(cmdQueue.nonEmpty && Random.nextFloat() < 0.5){ - val cmd = cmdQueue.head - if(cmd.we){ - if(wdataQueue.nonEmpty){ -// if(cmd.address == 0xc02ae850l) { -// println(s"! $writeCmdCounter $writeDataCounter") -// } - cmdQueue.dequeue() - val wdata = wdataQueue.dequeue() - val raw = wdata.data.toByteArray - val left = wdata.data.toByteArray.size-1 - if(bmb != null){ - assert(ref.nonEmpty) - assert((ref.head.address & 0xFFFFFFF0l) == cmd.address) - assert(ref.head.data == wdata.data) - assert(ref.head.we == wdata.we) - ref.dequeue() - } -// if(cmd.address == 0xc02ae850l) { -// println(s"$cmd $wdata ${simTime()}") -// } - for(i <- 0 until p.dataWidth/8){ - - - if(((wdata.we >> i) & 1) != 0) { -// if(cmd.address == 0xc02ae850l) { -// println(s"W $i ${ if (left - i >= 0) raw(left - i) else 0}") -// } - ram.write(cmd.address + i, if (left - i >= 0) raw(left - i) else 0) - } - } - } - } else { - cmdQueue.dequeue() - val value = new Array[Byte](p.dataWidth/8+1) - val left = value.size-1 - for(i <- 0 until p.dataWidth/8) { - value(left-i) = ram.read(cmd.address+i) - } - rdataQueue.enqueue(BigInt(value)) - } - } - } - - StreamDriver(bus.rdata, cd){ p => - if(rdataQueue.isEmpty){ - false - } else { - p.data #= rdataQueue.dequeue() - true - } - } - } -} - - - -case class BmbToLiteDram(bmbParameter : BmbParameter, - liteDramParameter : LiteDramNativeParameter, - wdataFifoSize : Int, - rdataFifoSize : Int) extends Component{ - val io = new Bundle { - val input = slave(Bmb(bmbParameter)) - val output = master(LiteDramNative(liteDramParameter)) - } - - val resized = io.input.resize(liteDramParameter.dataWidth) - val unburstified = resized.unburstify() - case class Context() extends Bundle { - val context = Bits(unburstified.p.contextWidth bits) - val source = UInt(unburstified.p.sourceWidth bits) - val isWrite = Bool() - } - - assert(isPow2(rdataFifoSize)) - val pendingRead = Reg(UInt(log2Up(rdataFifoSize) + 1 bits)) init(0) - - val halt = Bool() - val (cmdFork, dataFork) = StreamFork2(unburstified.cmd.haltWhen(halt)) - val outputCmd = Stream(LiteDramNativeCmd(liteDramParameter)) - outputCmd.arbitrationFrom(cmdFork.haltWhen(pendingRead.msb)) - outputCmd.addr := (cmdFork.address >> log2Up(liteDramParameter.dataWidth/8)).resized - outputCmd.we := cmdFork.isWrite - - io.output.cmd <-< outputCmd - - if(bmbParameter.canWrite) { - val wData = Stream(LiteDramNativeWData(liteDramParameter)) - wData.arbitrationFrom(dataFork.throwWhen(dataFork.isRead)) - wData.data := dataFork.data - wData.we := dataFork.mask - io.output.wdata << wData.queueLowLatency(wdataFifoSize, latency = 1) //TODO queue low latency - } else { - dataFork.ready := True - io.output.wdata.valid := False - io.output.wdata.data.assignDontCare() - io.output.wdata.we.assignDontCare() - } - - val cmdContext = Stream(Context()) - cmdContext.valid := unburstified.cmd.fire - cmdContext.context := unburstified.cmd.context - cmdContext.source := unburstified.cmd.source - cmdContext.isWrite := unburstified.cmd.isWrite - halt := !cmdContext.ready - - val rspContext = cmdContext.queue(rdataFifoSize) - val rdataFifo = io.output.rdata.queueLowLatency(rdataFifoSize, latency = 1) - - rdataFifo.ready := unburstified.rsp.fire && !rspContext.isWrite - rspContext.ready := unburstified.rsp.fire - unburstified.rsp.valid := rspContext.valid && (rspContext.isWrite || rdataFifo.valid) - unburstified.rsp.setSuccess() - unburstified.rsp.last := True - unburstified.rsp.source := rspContext.source - unburstified.rsp.context := rspContext.context - unburstified.rsp.data := rdataFifo.data - - - pendingRead := pendingRead + U(outputCmd.fire && !outputCmd.we) - U(rdataFifo.fire) -} - -object BmbToLiteDramTester extends App{ - import spinal.core.sim._ - SimConfig.withWave.compile(BmbToLiteDram( - bmbParameter = BmbParameter( - addressWidth = 20, - dataWidth = 32, - lengthWidth = 6, - sourceWidth = 4, - contextWidth = 16 - ), - liteDramParameter = LiteDramNativeParameter( - addressWidth = 20, - dataWidth = 128 - ), - wdataFifoSize = 16, - rdataFifoSize = 16 - )).doSimUntilVoid(seed = 42){dut => - val tester = new BmbMemoryTester(dut.io.input, dut.clockDomain, rspCounterTarget = 3000) - dut.io.output.simSlave(tester.memory.memory, dut.clockDomain) - } -} case class VexRiscvLitexSmpClusterParameter( cluster : VexRiscvSmpClusterParameter, liteDram : LiteDramNativeParameter, diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexDevCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexDevCluster.scala new file mode 100644 index 00000000..fbc184e9 --- /dev/null +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexDevCluster.scala @@ -0,0 +1,262 @@ +package vexriscv.demo.smp + +import spinal.core._ +import spinal.lib.bus.bmb._ +import spinal.lib.bus.wishbone.{Wishbone, WishboneConfig, WishboneSlaveFactory} +import spinal.lib.com.jtag.Jtag +import spinal.lib._ +import spinal.lib.bus.bmb.sim.{BmbMemoryMultiPort, BmbMemoryTester} +import spinal.lib.bus.misc.{AddressMapping, DefaultMapping, SizeMapping} +import spinal.lib.eda.bench.Bench +import spinal.lib.misc.Clint +import spinal.lib.sim.{SimData, SparseMemory, StreamDriver, StreamMonitor, StreamReadyRandomizer} +import vexriscv.demo.smp.VexRiscvLitexSmpDevClusterOpenSbi.{cpuCount, parameter} +import vexriscv.demo.smp.VexRiscvSmpClusterGen.vexRiscvConfig +import vexriscv.{VexRiscv, VexRiscvConfig} +import vexriscv.plugin.{CsrPlugin, DBusCachedPlugin, DebugPlugin, IBusCachedPlugin} + +import scala.collection.mutable +import scala.util.Random + + +case class VexRiscvLitexSmpDevClusterParameter( cluster : VexRiscvSmpClusterParameter, + liteDram : LiteDramNativeParameter, + liteDramMapping : AddressMapping) + +//addAttribute("""mark_debug = "true"""") +case class VexRiscvLitexSmpDevCluster(p : VexRiscvLitexSmpDevClusterParameter, + debugClockDomain : ClockDomain) extends Component{ + + val peripheralWishboneConfig = WishboneConfig( + addressWidth = 30, + dataWidth = 32, + selWidth = 4, + useERR = true, + useBTE = true, + useCTI = true + ) + + val cpuCount = p.cluster.cpuConfigs.size + + val io = new Bundle { + val dMem = Vec(master(LiteDramNative(p.liteDram)), cpuCount) + val iMem = Vec(master(LiteDramNative(p.liteDram)), cpuCount) + val peripheral = master(Wishbone(peripheralWishboneConfig)) + val clint = slave(Wishbone(Clint.getWisboneConfig())) + val externalInterrupts = in Bits(p.cluster.cpuConfigs.size bits) + val externalSupervisorInterrupts = in Bits(p.cluster.cpuConfigs.size bits) + val jtag = slave(Jtag()) + val debugReset = out Bool() + } + val clint = Clint(cpuCount) + clint.driveFrom(WishboneSlaveFactory(io.clint)) + + val cluster = VexRiscvSmpCluster(p.cluster, debugClockDomain) + cluster.io.externalInterrupts <> io.externalInterrupts + cluster.io.externalSupervisorInterrupts <> io.externalSupervisorInterrupts + cluster.io.jtag <> io.jtag + cluster.io.debugReset <> io.debugReset + cluster.io.timerInterrupts <> B(clint.harts.map(_.timerInterrupt)) + cluster.io.softwareInterrupts <> B(clint.harts.map(_.softwareInterrupt)) + + val dBusDecoder = BmbDecoderOutOfOrder( + p = cluster.io.dMem.p, + mappings = Seq(DefaultMapping, p.liteDramMapping), + capabilities = Seq(cluster.io.dMem.p, cluster.io.dMem.p), + pendingRspTransactionMax = 32 + ) +// val dBusDecoder = BmbDecoderOut( +// p = cluster.io.dMem.p, +// mappings = Seq(DefaultMapping, p.liteDramMapping), +// capabilities = Seq(cluster.io.dMem.p, cluster.io.dMem.p), +// pendingMax = 31 +// ) + dBusDecoder.io.input << cluster.io.dMem.pipelined(cmdValid = true, cmdReady = true, rspValid = true) + + + val perIBus = for(id <- 0 until cpuCount) yield new Area{ + val decoder = BmbDecoder( + p = cluster.io.iMems(id).p, + mappings = Seq(DefaultMapping, p.liteDramMapping), + capabilities = Seq(cluster.io.iMems(id).p,cluster.io.iMems(id).p), + pendingMax = 15 + ) + + decoder.io.input << cluster.io.iMems(id) + io.iMem(id).fromBmb(decoder.io.outputs(1), wdataFifoSize = 0, rdataFifoSize = 32) + val toPeripheral = decoder.io.outputs(0).resize(dataWidth = 32) + } + + val dBusDecoderToPeripheral = dBusDecoder.io.outputs(0).resize(dataWidth = 32).pipelined(cmdHalfRate = true, rspValid = true) + + val peripheralAccessLength = Math.max(perIBus(0).toPeripheral.p.lengthWidth, dBusDecoder.io.outputs(0).p.lengthWidth) + val peripheralArbiter = BmbArbiter( + p = dBusDecoder.io.outputs(0).p.copy( + sourceWidth = List(perIBus(0).toPeripheral, dBusDecoderToPeripheral).map(_.p.sourceWidth).max + log2Up(cpuCount + 1), + contextWidth = List(perIBus(0).toPeripheral, dBusDecoderToPeripheral).map(_.p.contextWidth).max, + lengthWidth = peripheralAccessLength, + dataWidth = 32 + ), + portCount = cpuCount+1, + lowerFirstPriority = true + ) + + for(id <- 0 until cpuCount){ + peripheralArbiter.io.inputs(id) << perIBus(id).toPeripheral + } + peripheralArbiter.io.inputs(cpuCount) << dBusDecoderToPeripheral + + val peripheralWishbone = peripheralArbiter.io.output.pipelined(cmdValid = true).toWishbone() + io.peripheral << peripheralWishbone + + + val dBusDemux = BmbSourceDecoder(dBusDecoder.io.outputs(1).p) + dBusDemux.io.input << dBusDecoder.io.outputs(1) + val dMemBridge = for(id <- 0 until cpuCount) yield { + io.dMem(id).fromBmb(dBusDemux.io.outputs(id), wdataFifoSize = 32, rdataFifoSize = 32) + } + +} + +object VexRiscvLitexSmpDevClusterGen extends App { + for(cpuCount <- List(1,2,4,8)) { + def parameter = VexRiscvLitexSmpDevClusterParameter( + cluster = VexRiscvSmpClusterParameter( + cpuConfigs = List.tabulate(cpuCount) { hartId => + vexRiscvConfig( + hartId = hartId, + ioRange = address => address.msb, + resetVector = 0 + ) + } + ), + liteDram = LiteDramNativeParameter(addressWidth = 32, dataWidth = 128), + liteDramMapping = SizeMapping(0x40000000l, 0x40000000l) + ) + + def dutGen = { + val toplevel = VexRiscvLitexSmpDevCluster( + p = parameter, + debugClockDomain = ClockDomain.current.copy(reset = Bool().setName("debugResetIn")) + ) + toplevel + } + + val genConfig = SpinalConfig().addStandardMemBlackboxing(blackboxByteEnables) + // genConfig.generateVerilog(Bench.compressIo(dutGen)) + genConfig.generateVerilog(dutGen.setDefinitionName(s"VexRiscvLitexSmpDevCluster_${cpuCount}c")) + } + +} + + +object VexRiscvLitexSmpDevClusterOpenSbi extends App{ + import spinal.core.sim._ + + val simConfig = SimConfig + simConfig.withWave + simConfig.allOptimisation + + val cpuCount = 4 + + def parameter = VexRiscvLitexSmpDevClusterParameter( + cluster = VexRiscvSmpClusterParameter( + cpuConfigs = List.tabulate(cpuCount) { hartId => + vexRiscvConfig( + hartId = hartId, + ioRange = address => address(31 downto 28) === 0xF, + resetVector = 0x80000000l + ) + } + ), + liteDram = LiteDramNativeParameter(addressWidth = 32, dataWidth = 128), + liteDramMapping = SizeMapping(0x80000000l, 0x70000000l) + ) + + def dutGen = { + val top = VexRiscvLitexSmpDevCluster( + p = parameter, + debugClockDomain = ClockDomain.current.copy(reset = Bool().setName("debugResetIn")) + ) + top.rework{ + top.io.clint.setAsDirectionLess.allowDirectionLessIo + top.io.peripheral.setAsDirectionLess.allowDirectionLessIo.simPublic() + + val hit = (top.io.peripheral.ADR <<2 >= 0xF0010000l && top.io.peripheral.ADR<<2 < 0xF0020000l) + top.io.clint.CYC := top.io.peripheral.CYC && hit + top.io.clint.STB := top.io.peripheral.STB + top.io.clint.WE := top.io.peripheral.WE + top.io.clint.ADR := top.io.peripheral.ADR.resized + top.io.clint.DAT_MOSI := top.io.peripheral.DAT_MOSI + top.io.peripheral.DAT_MISO := top.io.clint.DAT_MISO + top.io.peripheral.ACK := top.io.peripheral.CYC && (!hit || top.io.clint.ACK) + top.io.peripheral.ERR := False + +// top.dMemBridge.unburstified.cmd.simPublic() + } + top + } + simConfig.compile(dutGen).doSimUntilVoid(seed = 42){dut => + dut.clockDomain.forkStimulus(10) + fork { + dut.debugClockDomain.resetSim #= false + sleep (0) + dut.debugClockDomain.resetSim #= true + sleep (10) + dut.debugClockDomain.resetSim #= false + } + + + val ram = SparseMemory() + ram.loadBin(0x80000000l, "../opensbi/build/platform/spinal/vexriscv/sim/smp/firmware/fw_jump.bin") + ram.loadBin(0xC0000000l, "../buildroot/output/images/Image") + ram.loadBin(0xC1000000l, "../buildroot/output/images/dtb") + ram.loadBin(0xC2000000l, "../buildroot/output/images/rootfs.cpio") + + for(id <- 0 until cpuCount) { + dut.io.iMem(id).simSlave(ram, dut.clockDomain) + dut.io.dMem(id).simSlave(ram, dut.clockDomain) + } + + dut.io.externalInterrupts #= 0 + dut.io.externalSupervisorInterrupts #= 0 + + dut.clockDomain.onSamplings{ + if(dut.io.peripheral.CYC.toBoolean){ + (dut.io.peripheral.ADR.toLong << 2) match { + case 0xF0000000l => print(dut.io.peripheral.DAT_MOSI.toLong.toChar) + case 0xF0000004l => dut.io.peripheral.DAT_MISO #= (if(System.in.available() != 0) System.in.read() else 0xFFFFFFFFl) + case _ => + } +// println(f"${dut.io.peripheral.ADR.toLong}%x") + } + } + +// fork{ +// disableSimWave() +// val atMs = 3790 +// val durationMs = 5 +// sleep(atMs*1000000l) +// enableSimWave() +// println("** enableSimWave **") +// sleep(durationMs*1000000l) +// println("** disableSimWave **") +// while(true) { +// disableSimWave() +// sleep(100000 * 10) +// enableSimWave() +// sleep( 100 * 10) +// } +// // simSuccess() +// } + + fork{ + while(true) { + disableSimWave() + sleep(100000 * 10) + enableSimWave() + sleep( 100 * 10) + } + } + } + } \ No newline at end of file From 2942d0652a89646c5225bee15dd55cc3b0871766 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 13 Apr 2020 13:01:12 +0200 Subject: [PATCH 441/951] fix Briey verilator --- src/test/cpp/briey/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/cpp/briey/main.cpp b/src/test/cpp/briey/main.cpp index 2243dced..0ee7c456 100644 --- a/src/test/cpp/briey/main.cpp +++ b/src/test/cpp/briey/main.cpp @@ -401,7 +401,7 @@ public: sdramIo->ADDR = &top->io_sdram_ADDR ; sdramIo->DQ_read = (CData*)&top->io_sdram_DQ_read ; sdramIo->DQ_write = (CData*)&top->io_sdram_DQ_write ; - sdramIo->DQ_writeEnable = &top->io_sdram_DQ_writeEnable; + sdramIo->DQ_writeEnable = (CData*)&top->io_sdram_DQ_writeEnable; Sdram *sdram = new Sdram(sdramConfig, sdramIo); axiClk->add(sdram); From 08189ee9073d84e6d7c0df2d3e4cbbaa3d632191 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 2 Jun 2020 19:13:55 +0200 Subject: [PATCH 442/951] DebugPlugin now support Bmb --- .../scala/vexriscv/plugin/DebugPlugin.scala | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/src/main/scala/vexriscv/plugin/DebugPlugin.scala b/src/main/scala/vexriscv/plugin/DebugPlugin.scala index 91185b86..9f2a2436 100644 --- a/src/main/scala/vexriscv/plugin/DebugPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DebugPlugin.scala @@ -9,6 +9,8 @@ import spinal.core._ import spinal.lib._ import spinal.lib.bus.amba3.apb.{Apb3, Apb3Config} import spinal.lib.bus.avalon.{AvalonMM, AvalonMMConfig} +import spinal.lib.bus.bmb.{Bmb, BmbAccessParameter, BmbParameter} +import spinal.lib.bus.simple.PipelinedMemoryBus import scala.collection.mutable.ArrayBuffer @@ -22,6 +24,16 @@ case class DebugExtensionRsp() extends Bundle{ val data = Bits(32 bit) } +object DebugExtensionBus{ + def getBmbAccessParameter(source : BmbAccessParameter) = BmbAccessParameter( + addressWidth = 8, + dataWidth = 32, + lengthWidth = 2, + sourceWidth = source.sourceWidth, + contextWidth = source.contextWidth + ) +} + case class DebugExtensionBus() extends Bundle with IMasterSlave{ val cmd = Stream(DebugExtensionCmd()) val rsp = DebugExtensionRsp() //one cycle latency @@ -63,6 +75,41 @@ case class DebugExtensionBus() extends Bundle with IMasterSlave{ bus } + def fromPipelinedMemoryBus(): PipelinedMemoryBus ={ + val bus = PipelinedMemoryBus(32, 32) + + cmd.arbitrationFrom(bus.cmd) + cmd.wr := bus.cmd.write + cmd.address := bus.cmd.address.resized + cmd.data := bus.cmd.data + + bus.rsp.valid := RegNext(cmd.fire) init(False) + bus.rsp.data := rsp.data + + bus + } + + def fromBmb(): Bmb ={ + val bus = Bmb(BmbParameter( + addressWidth = 8, + dataWidth = 32, + lengthWidth = 2, + sourceWidth = 0, + contextWidth = 0 + )) + + cmd.arbitrationFrom(bus.cmd) + cmd.wr := bus.cmd.isWrite + cmd.address := bus.cmd.address + cmd.data := bus.cmd.data + + bus.rsp.valid := RegNext(cmd.fire) init(False) + bus.rsp.data := rsp.data + bus.rsp.last := True + + bus + } + def from(c : SystemDebuggerConfig) : SystemDebuggerMemBus = { val mem = SystemDebuggerMemBus(c) cmd.valid := mem.cmd.valid From db50f04653606e1ee9498552867b5d8a7b125217 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sun, 31 May 2020 16:54:05 +0200 Subject: [PATCH 443/951] Add litexMpCluster --- .../demo/smp/VexRiscvSmpLitexCluster.scala | 1 + ....scala => VexRiscvSmpLitexMpCluster.scala} | 26 +++++++++---------- 2 files changed, 14 insertions(+), 13 deletions(-) rename src/main/scala/vexriscv/demo/smp/{VexRiscvSmpLitexDevCluster.scala => VexRiscvSmpLitexMpCluster.scala} (91%) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala index f73c8598..acf8e4e6 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala @@ -115,6 +115,7 @@ case class VexRiscvLitexSmpCluster(p : VexRiscvLitexSmpClusterParameter, io.peripheral << peripheralWishbone } +//ifconfig eth0 192.168.0.50 netmask 255.255.255.0 up object VexRiscvLitexSmpClusterGen extends App { for(cpuCount <- List(1,2,4,8)) { def parameter = VexRiscvLitexSmpClusterParameter( diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexDevCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexMpCluster.scala similarity index 91% rename from src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexDevCluster.scala rename to src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexMpCluster.scala index fbc184e9..6883343c 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexDevCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexMpCluster.scala @@ -10,7 +10,7 @@ import spinal.lib.bus.misc.{AddressMapping, DefaultMapping, SizeMapping} import spinal.lib.eda.bench.Bench import spinal.lib.misc.Clint import spinal.lib.sim.{SimData, SparseMemory, StreamDriver, StreamMonitor, StreamReadyRandomizer} -import vexriscv.demo.smp.VexRiscvLitexSmpDevClusterOpenSbi.{cpuCount, parameter} +import vexriscv.demo.smp.VexRiscvLitexSmpMpClusterOpenSbi.{cpuCount, parameter} import vexriscv.demo.smp.VexRiscvSmpClusterGen.vexRiscvConfig import vexriscv.{VexRiscv, VexRiscvConfig} import vexriscv.plugin.{CsrPlugin, DBusCachedPlugin, DebugPlugin, IBusCachedPlugin} @@ -19,12 +19,12 @@ import scala.collection.mutable import scala.util.Random -case class VexRiscvLitexSmpDevClusterParameter( cluster : VexRiscvSmpClusterParameter, +case class VexRiscvLitexSmpMpClusterParameter( cluster : VexRiscvSmpClusterParameter, liteDram : LiteDramNativeParameter, liteDramMapping : AddressMapping) //addAttribute("""mark_debug = "true"""") -case class VexRiscvLitexSmpDevCluster(p : VexRiscvLitexSmpDevClusterParameter, +case class VexRiscvLitexSmpMpCluster(p : VexRiscvLitexSmpMpClusterParameter, debugClockDomain : ClockDomain) extends Component{ val peripheralWishboneConfig = WishboneConfig( @@ -83,8 +83,8 @@ case class VexRiscvLitexSmpDevCluster(p : VexRiscvLitexSmpDevClusterParameter, ) decoder.io.input << cluster.io.iMems(id) - io.iMem(id).fromBmb(decoder.io.outputs(1), wdataFifoSize = 0, rdataFifoSize = 32) - val toPeripheral = decoder.io.outputs(0).resize(dataWidth = 32) + io.iMem(id).fromBmb(decoder.io.outputs(1).pipelined(cmdHalfRate = true), wdataFifoSize = 0, rdataFifoSize = 32) + val toPeripheral = decoder.io.outputs(0).resize(dataWidth = 32).pipelined(cmdHalfRate = true, rspValid = true) } val dBusDecoderToPeripheral = dBusDecoder.io.outputs(0).resize(dataWidth = 32).pipelined(cmdHalfRate = true, rspValid = true) @@ -111,16 +111,16 @@ case class VexRiscvLitexSmpDevCluster(p : VexRiscvLitexSmpDevClusterParameter, val dBusDemux = BmbSourceDecoder(dBusDecoder.io.outputs(1).p) - dBusDemux.io.input << dBusDecoder.io.outputs(1) + dBusDemux.io.input << dBusDecoder.io.outputs(1).pipelined(cmdValid = true, cmdReady = true,rspValid = true) val dMemBridge = for(id <- 0 until cpuCount) yield { io.dMem(id).fromBmb(dBusDemux.io.outputs(id), wdataFifoSize = 32, rdataFifoSize = 32) } } -object VexRiscvLitexSmpDevClusterGen extends App { +object VexRiscvLitexSmpMpClusterGen extends App { for(cpuCount <- List(1,2,4,8)) { - def parameter = VexRiscvLitexSmpDevClusterParameter( + def parameter = VexRiscvLitexSmpMpClusterParameter( cluster = VexRiscvSmpClusterParameter( cpuConfigs = List.tabulate(cpuCount) { hartId => vexRiscvConfig( @@ -135,7 +135,7 @@ object VexRiscvLitexSmpDevClusterGen extends App { ) def dutGen = { - val toplevel = VexRiscvLitexSmpDevCluster( + val toplevel = VexRiscvLitexSmpMpCluster( p = parameter, debugClockDomain = ClockDomain.current.copy(reset = Bool().setName("debugResetIn")) ) @@ -144,13 +144,13 @@ object VexRiscvLitexSmpDevClusterGen extends App { val genConfig = SpinalConfig().addStandardMemBlackboxing(blackboxByteEnables) // genConfig.generateVerilog(Bench.compressIo(dutGen)) - genConfig.generateVerilog(dutGen.setDefinitionName(s"VexRiscvLitexSmpDevCluster_${cpuCount}c")) + genConfig.generateVerilog(dutGen.setDefinitionName(s"VexRiscvLitexSmpMpCluster_${cpuCount}c")) } } -object VexRiscvLitexSmpDevClusterOpenSbi extends App{ +object VexRiscvLitexSmpMpClusterOpenSbi extends App{ import spinal.core.sim._ val simConfig = SimConfig @@ -159,7 +159,7 @@ object VexRiscvLitexSmpDevClusterOpenSbi extends App{ val cpuCount = 4 - def parameter = VexRiscvLitexSmpDevClusterParameter( + def parameter = VexRiscvLitexSmpMpClusterParameter( cluster = VexRiscvSmpClusterParameter( cpuConfigs = List.tabulate(cpuCount) { hartId => vexRiscvConfig( @@ -174,7 +174,7 @@ object VexRiscvLitexSmpDevClusterOpenSbi extends App{ ) def dutGen = { - val top = VexRiscvLitexSmpDevCluster( + val top = VexRiscvLitexSmpMpCluster( p = parameter, debugClockDomain = ClockDomain.current.copy(reset = Bool().setName("debugResetIn")) ) From 73f88e47cb83d71c2bc29669054d165652eb8fcc Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 3 Jun 2020 16:29:21 +0200 Subject: [PATCH 444/951] Fix BmbToLitexDram coherency --- src/main/scala/vexriscv/demo/smp/Misc.scala | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/demo/smp/Misc.scala b/src/main/scala/vexriscv/demo/smp/Misc.scala index a7965a49..b192a9cd 100644 --- a/src/main/scala/vexriscv/demo/smp/Misc.scala +++ b/src/main/scala/vexriscv/demo/smp/Misc.scala @@ -205,10 +205,17 @@ case class BmbToLiteDram(bmbParameter : BmbParameter, val rspContext = cmdContext.queue(rdataFifoSize) val rdataFifo = io.output.rdata.queueLowLatency(rdataFifoSize, latency = 1) + val writeTocken = CounterUpDown( + stateCount = rdataFifoSize*2, + incWhen = io.output.wdata.fire, + decWhen = rspContext.fire && rspContext.isWrite + ) + val canRspWrite = writeTocken =/= 0 + val canRspRead = CombInit(rdataFifo.valid) rdataFifo.ready := unburstified.rsp.fire && !rspContext.isWrite rspContext.ready := unburstified.rsp.fire - unburstified.rsp.valid := rspContext.valid && (rspContext.isWrite || rdataFifo.valid) + unburstified.rsp.valid := rspContext.valid && (rspContext.isWrite ? canRspWrite | canRspRead) unburstified.rsp.setSuccess() unburstified.rsp.last := True unburstified.rsp.source := rspContext.source From 89c13bedbdb90bfcbfd29cddbf5179715ddbecc3 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 3 Jun 2020 16:31:34 +0200 Subject: [PATCH 445/951] Fix litex smp cluster sim --- .../demo/smp/VexRiscvSmpCluster.scala | 2 +- .../demo/smp/VexRiscvSmpLitexCluster.scala | 4 +- .../demo/smp/VexRiscvSmpLitexMpCluster.scala | 76 +++++++++++++------ 3 files changed, 55 insertions(+), 27 deletions(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index 422b1e28..97f18760 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -466,7 +466,7 @@ object VexRiscvSmpClusterOpenSbi extends App{ simConfig.allOptimisation simConfig.addSimulatorFlag("--threads 1") - val cpuCount = 4 + val cpuCount = 2 val withStall = false def gen = { diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala index acf8e4e6..ea5cd39f 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala @@ -155,7 +155,7 @@ object VexRiscvLitexSmpClusterOpenSbi extends App{ simConfig.withWave simConfig.allOptimisation - val cpuCount = 8 + val cpuCount = 2 def parameter = VexRiscvLitexSmpClusterParameter( cluster = VexRiscvSmpClusterParameter( @@ -218,7 +218,7 @@ object VexRiscvLitexSmpClusterOpenSbi extends App{ dut.io.externalInterrupts #= 0 dut.io.externalSupervisorInterrupts #= 0 - dut.clockDomain.onSamplings{ + dut.clockDomain.onFallingEdges{ if(dut.io.peripheral.CYC.toBoolean){ (dut.io.peripheral.ADR.toLong << 2) match { case 0xF0000000l => print(dut.io.peripheral.DAT_MOSI.toLong.toChar) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexMpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexMpCluster.scala index 6883343c..1342b701 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexMpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexMpCluster.scala @@ -115,7 +115,16 @@ case class VexRiscvLitexSmpMpCluster(p : VexRiscvLitexSmpMpClusterParameter, val dMemBridge = for(id <- 0 until cpuCount) yield { io.dMem(id).fromBmb(dBusDemux.io.outputs(id), wdataFifoSize = 32, rdataFifoSize = 32) } - +// +// io.dMem.foreach(_.cmd.valid.addAttribute("""mark_debug = "true"""")) +// io.dMem.foreach(_.cmd.ready.addAttribute("""mark_debug = "true"""")) +// io.iMem.foreach(_.cmd.valid.addAttribute("""mark_debug = "true"""")) +// io.iMem.foreach(_.cmd.ready.addAttribute("""mark_debug = "true"""")) +// +// cluster.io.dMem.cmd.valid.addAttribute("""mark_debug = "true"""") +// cluster.io.dMem.cmd.ready.addAttribute("""mark_debug = "true"""") +// cluster.io.dMem.rsp.valid.addAttribute("""mark_debug = "true"""") +// cluster.io.dMem.rsp.ready.addAttribute("""mark_debug = "true"""") } object VexRiscvLitexSmpMpClusterGen extends App { @@ -155,9 +164,10 @@ object VexRiscvLitexSmpMpClusterOpenSbi extends App{ val simConfig = SimConfig simConfig.withWave + simConfig.withFstWave simConfig.allOptimisation - val cpuCount = 4 + val cpuCount = 2 def parameter = VexRiscvLitexSmpMpClusterParameter( cluster = VexRiscvSmpClusterParameter( @@ -221,41 +231,59 @@ object VexRiscvLitexSmpMpClusterOpenSbi extends App{ dut.io.externalInterrupts #= 0 dut.io.externalSupervisorInterrupts #= 0 - dut.clockDomain.onSamplings{ +// val stdin = mutable.Queue[Byte]() +// def stdInPush(str : String) = stdin ++= str.toCharArray.map(_.toByte) +// fork{ +// sleep(4000*1000000l) +// stdInPush("root\n") +// sleep(1000*1000000l) +// stdInPush("ping localhost -i 0.01 > /dev/null &\n") +// stdInPush("ping localhost -i 0.01 > /dev/null &\n") +// stdInPush("ping localhost -i 0.01 > /dev/null &\n") +// stdInPush("ping localhost -i 0.01 > /dev/null &\n") +// sleep(500*1000000l) +// while(true){ +// sleep(500*1000000l) +// stdInPush("uptime\n") +// printf("\n** uptime **") +// } +// } + dut.clockDomain.onFallingEdges{ if(dut.io.peripheral.CYC.toBoolean){ (dut.io.peripheral.ADR.toLong << 2) match { case 0xF0000000l => print(dut.io.peripheral.DAT_MOSI.toLong.toChar) case 0xF0000004l => dut.io.peripheral.DAT_MISO #= (if(System.in.available() != 0) System.in.read() else 0xFFFFFFFFl) - case _ => - } +// case 0xF0000004l => { +// val c = if(stdin.nonEmpty) { +// stdin.dequeue().toInt & 0xFF +// } else { +// 0xFFFFFFFFl +// } +// dut.io.peripheral.DAT_MISO #= c +// } +// case _ => +// } // println(f"${dut.io.peripheral.ADR.toLong}%x") } } -// fork{ -// disableSimWave() -// val atMs = 3790 -// val durationMs = 5 -// sleep(atMs*1000000l) -// enableSimWave() -// println("** enableSimWave **") -// sleep(durationMs*1000000l) -// println("** disableSimWave **") -// while(true) { -// disableSimWave() -// sleep(100000 * 10) -// enableSimWave() -// sleep( 100 * 10) -// } -// // simSuccess() -// } - fork{ + val at = 0 + val duration = 0 + while(simTime() < at*1000000l) { + disableSimWave() + sleep(100000 * 10) + enableSimWave() + sleep( 200 * 10) + } + println("\n\n********************") + sleep(duration*1000000l) + println("********************\n\n") while(true) { disableSimWave() sleep(100000 * 10) enableSimWave() - sleep( 100 * 10) + sleep( 400 * 10) } } } From 97c2dc270c85b4cc4c984db254507a9c87c4c6c6 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 4 Jun 2020 10:11:30 +0200 Subject: [PATCH 446/951] Fix typo --- .../demo/smp/VexRiscvSmpLitexMpCluster.scala | 191 +++++++++--------- 1 file changed, 96 insertions(+), 95 deletions(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexMpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexMpCluster.scala index 1342b701..ceb5a362 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexMpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexMpCluster.scala @@ -160,76 +160,76 @@ object VexRiscvLitexSmpMpClusterGen extends App { object VexRiscvLitexSmpMpClusterOpenSbi extends App{ - import spinal.core.sim._ + import spinal.core.sim._ - val simConfig = SimConfig - simConfig.withWave - simConfig.withFstWave - simConfig.allOptimisation + val simConfig = SimConfig + simConfig.withWave + simConfig.withFstWave + simConfig.allOptimisation - val cpuCount = 2 + val cpuCount = 2 - def parameter = VexRiscvLitexSmpMpClusterParameter( - cluster = VexRiscvSmpClusterParameter( - cpuConfigs = List.tabulate(cpuCount) { hartId => - vexRiscvConfig( - hartId = hartId, - ioRange = address => address(31 downto 28) === 0xF, - resetVector = 0x80000000l - ) - } - ), - liteDram = LiteDramNativeParameter(addressWidth = 32, dataWidth = 128), - liteDramMapping = SizeMapping(0x80000000l, 0x70000000l) + def parameter = VexRiscvLitexSmpMpClusterParameter( + cluster = VexRiscvSmpClusterParameter( + cpuConfigs = List.tabulate(cpuCount) { hartId => + vexRiscvConfig( + hartId = hartId, + ioRange = address => address(31 downto 28) === 0xF, + resetVector = 0x80000000l + ) + } + ), + liteDram = LiteDramNativeParameter(addressWidth = 32, dataWidth = 128), + liteDramMapping = SizeMapping(0x80000000l, 0x70000000l) + ) + + def dutGen = { + val top = VexRiscvLitexSmpMpCluster( + p = parameter, + debugClockDomain = ClockDomain.current.copy(reset = Bool().setName("debugResetIn")) ) + top.rework{ + top.io.clint.setAsDirectionLess.allowDirectionLessIo + top.io.peripheral.setAsDirectionLess.allowDirectionLessIo.simPublic() - def dutGen = { - val top = VexRiscvLitexSmpMpCluster( - p = parameter, - debugClockDomain = ClockDomain.current.copy(reset = Bool().setName("debugResetIn")) - ) - top.rework{ - top.io.clint.setAsDirectionLess.allowDirectionLessIo - top.io.peripheral.setAsDirectionLess.allowDirectionLessIo.simPublic() - - val hit = (top.io.peripheral.ADR <<2 >= 0xF0010000l && top.io.peripheral.ADR<<2 < 0xF0020000l) - top.io.clint.CYC := top.io.peripheral.CYC && hit - top.io.clint.STB := top.io.peripheral.STB - top.io.clint.WE := top.io.peripheral.WE - top.io.clint.ADR := top.io.peripheral.ADR.resized - top.io.clint.DAT_MOSI := top.io.peripheral.DAT_MOSI - top.io.peripheral.DAT_MISO := top.io.clint.DAT_MISO - top.io.peripheral.ACK := top.io.peripheral.CYC && (!hit || top.io.clint.ACK) - top.io.peripheral.ERR := False + val hit = (top.io.peripheral.ADR <<2 >= 0xF0010000l && top.io.peripheral.ADR<<2 < 0xF0020000l) + top.io.clint.CYC := top.io.peripheral.CYC && hit + top.io.clint.STB := top.io.peripheral.STB + top.io.clint.WE := top.io.peripheral.WE + top.io.clint.ADR := top.io.peripheral.ADR.resized + top.io.clint.DAT_MOSI := top.io.peripheral.DAT_MOSI + top.io.peripheral.DAT_MISO := top.io.clint.DAT_MISO + top.io.peripheral.ACK := top.io.peripheral.CYC && (!hit || top.io.clint.ACK) + top.io.peripheral.ERR := False // top.dMemBridge.unburstified.cmd.simPublic() - } - top } - simConfig.compile(dutGen).doSimUntilVoid(seed = 42){dut => - dut.clockDomain.forkStimulus(10) - fork { - dut.debugClockDomain.resetSim #= false - sleep (0) - dut.debugClockDomain.resetSim #= true - sleep (10) - dut.debugClockDomain.resetSim #= false - } + top + } + simConfig.compile(dutGen).doSimUntilVoid(seed = 42){dut => + dut.clockDomain.forkStimulus(10) + fork { + dut.debugClockDomain.resetSim #= false + sleep (0) + dut.debugClockDomain.resetSim #= true + sleep (10) + dut.debugClockDomain.resetSim #= false + } - val ram = SparseMemory() - ram.loadBin(0x80000000l, "../opensbi/build/platform/spinal/vexriscv/sim/smp/firmware/fw_jump.bin") - ram.loadBin(0xC0000000l, "../buildroot/output/images/Image") - ram.loadBin(0xC1000000l, "../buildroot/output/images/dtb") - ram.loadBin(0xC2000000l, "../buildroot/output/images/rootfs.cpio") + val ram = SparseMemory() + ram.loadBin(0x80000000l, "../opensbi/build/platform/spinal/vexriscv/sim/smp/firmware/fw_jump.bin") + ram.loadBin(0xC0000000l, "../buildroot/output/images/Image") + ram.loadBin(0xC1000000l, "../buildroot/output/images/dtb") + ram.loadBin(0xC2000000l, "../buildroot/output/images/rootfs.cpio") - for(id <- 0 until cpuCount) { - dut.io.iMem(id).simSlave(ram, dut.clockDomain) - dut.io.dMem(id).simSlave(ram, dut.clockDomain) - } + for(id <- 0 until cpuCount) { + dut.io.iMem(id).simSlave(ram, dut.clockDomain) + dut.io.dMem(id).simSlave(ram, dut.clockDomain) + } - dut.io.externalInterrupts #= 0 - dut.io.externalSupervisorInterrupts #= 0 + dut.io.externalInterrupts #= 0 + dut.io.externalSupervisorInterrupts #= 0 // val stdin = mutable.Queue[Byte]() // def stdInPush(str : String) = stdin ++= str.toCharArray.map(_.toByte) @@ -248,43 +248,44 @@ object VexRiscvLitexSmpMpClusterOpenSbi extends App{ // printf("\n** uptime **") // } // } - dut.clockDomain.onFallingEdges{ - if(dut.io.peripheral.CYC.toBoolean){ - (dut.io.peripheral.ADR.toLong << 2) match { - case 0xF0000000l => print(dut.io.peripheral.DAT_MOSI.toLong.toChar) - case 0xF0000004l => dut.io.peripheral.DAT_MISO #= (if(System.in.available() != 0) System.in.read() else 0xFFFFFFFFl) -// case 0xF0000004l => { -// val c = if(stdin.nonEmpty) { -// stdin.dequeue().toInt & 0xFF -// } else { -// 0xFFFFFFFFl -// } -// dut.io.peripheral.DAT_MISO #= c -// } -// case _ => -// } -// println(f"${dut.io.peripheral.ADR.toLong}%x") - } - } - - fork{ - val at = 0 - val duration = 0 - while(simTime() < at*1000000l) { - disableSimWave() - sleep(100000 * 10) - enableSimWave() - sleep( 200 * 10) - } - println("\n\n********************") - sleep(duration*1000000l) - println("********************\n\n") - while(true) { - disableSimWave() - sleep(100000 * 10) - enableSimWave() - sleep( 400 * 10) + dut.clockDomain.onFallingEdges { + if (dut.io.peripheral.CYC.toBoolean) { + (dut.io.peripheral.ADR.toLong << 2) match { + case 0xF0000000l => print(dut.io.peripheral.DAT_MOSI.toLong.toChar) + case 0xF0000004l => dut.io.peripheral.DAT_MISO #= (if (System.in.available() != 0) System.in.read() else 0xFFFFFFFFl) + // case 0xF0000004l => { + // val c = if(stdin.nonEmpty) { + // stdin.dequeue().toInt & 0xFF + // } else { + // 0xFFFFFFFFl + // } + // dut.io.peripheral.DAT_MISO #= c + // } + // case _ => + // } + // println(f"${dut.io.peripheral.ADR.toLong}%x") } } } - } \ No newline at end of file + + fork{ + val at = 0 + val duration = 0 + while(simTime() < at*1000000l) { + disableSimWave() + sleep(100000 * 10) + enableSimWave() + sleep( 200 * 10) + } + println("\n\n********************") + sleep(duration*1000000l) + println("********************\n\n") + while(true) { + disableSimWave() + sleep(100000 * 10) + enableSimWave() + sleep( 400 * 10) + } + } + } +} \ No newline at end of file From 06680464078f0079fdc33434bc32fc70b12b3bcc Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 5 Jun 2020 10:40:51 +0200 Subject: [PATCH 447/951] More smp cluster profiling --- .../demo/smp/VexRiscvSmpCluster.scala | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index 97f18760..0e237c6a 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -497,9 +497,11 @@ object VexRiscvSmpClusterOpenSbi extends App{ ram.memory.loadBin(0xC2000000l, "../buildroot/output/images/rootfs.cpio") import spinal.core.sim._ - var iMemReadBytes, dMemReadBytes, dMemWriteBytes, iMemSequencial,iMemRequests = 0l + var iMemReadBytes, dMemReadBytes, dMemWriteBytes, iMemSequencial,iMemRequests, iMemPrefetchHit = 0l var reportTimer = 0 var reportCycle = 0 + val iMemFetchDelta = mutable.HashMap[Long, Long]() + var iMemFetchDeltaSorted : Seq[(Long, Long)] = null var dMemWrites, dMemWritesCached = 0l val dMemWriteCacheCtx = List(4,8,16,32,64).map(bytes => new { var counter = 0l @@ -512,6 +514,7 @@ object VexRiscvSmpClusterOpenSbi extends App{ val iMemCtx = Array.tabulate(cpuCount)(i => new { var sequencialPrediction = 0l val cache = dut.cpus(i).core.children.find(_.isInstanceOf[InstructionCache]).head.asInstanceOf[InstructionCache].io.cpu.decode + var lastAddress = 0l }) dut.clockDomain.onSamplings{ for(i <- 0 until cpuCount; iMem = dut.io.iMems(i); ctx = iMemCtx(i)){ @@ -527,7 +530,6 @@ object VexRiscvSmpClusterOpenSbi extends App{ val mask = ~(length-1) if(ctx.cache.cacheMiss.toBoolean) { iMemReadBytes += length - iMemRequests += 1 if ((address & mask) == (ctx.sequencialPrediction & mask)) { iMemSequencial += 1 } @@ -536,6 +538,18 @@ object VexRiscvSmpClusterOpenSbi extends App{ ctx.sequencialPrediction = address + length } } + + if(iMem.cmd.valid.toBoolean && iMem.cmd.ready.toBoolean){ + val address = iMem.cmd.address.toLong + iMemRequests += 1 + if(iMemCtx(i).lastAddress + ctx.cache.p.bytePerLine == address){ + iMemPrefetchHit += 1 + } + val delta = address-iMemCtx(i).lastAddress + iMemFetchDelta(delta) = iMemFetchDelta.getOrElse(delta, 0l) + 1l + if(iMemRequests % 1000 == 999) iMemFetchDeltaSorted = iMemFetchDelta.toSeq.sortBy(_._1) + iMemCtx(i).lastAddress = address + } } if(dut.io.dMem.cmd.valid.toBoolean && dut.io.dMem.cmd.ready.toBoolean){ if(dut.io.dMem.cmd.opcode.toInt == Bmb.Cmd.Opcode.WRITE){ @@ -561,7 +575,7 @@ object VexRiscvSmpClusterOpenSbi extends App{ // println(f"\n** c=${reportCycle} ir=${iMemReadBytes*1e-6}%5.2f dr=${dMemReadBytes*1e-6}%5.2f dw=${dMemWriteBytes*1e-6}%5.2f **\n") - csv.write(s"$reportCycle,$iMemReadBytes,$dMemReadBytes,$dMemWriteBytes,$iMemRequests,$iMemSequencial,$dMemWrites,${dMemWriteCacheCtx.map(_.counter).mkString(",")}\n") + csv.write(s"$reportCycle,$iMemReadBytes,$dMemReadBytes,$dMemWriteBytes,$iMemRequests,$iMemSequencial,$dMemWrites,${dMemWriteCacheCtx.map(_.counter).mkString(",")},$iMemPrefetchHit\n") csv.flush() reportCycle = 0 iMemReadBytes = 0 @@ -570,6 +584,7 @@ object VexRiscvSmpClusterOpenSbi extends App{ iMemRequests = 0 iMemSequencial = 0 dMemWrites = 0 + iMemPrefetchHit = 0 for(ctx <- dMemWriteCacheCtx) ctx.counter = 0 } } From 3dafe8708b8acb70b21623671aa10726803f4992 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 5 Jun 2020 10:34:57 +0200 Subject: [PATCH 448/951] Cfu update --- .../demo/GenSmallAndProductiveCfu.scala | 2 +- .../scala/vexriscv/plugin/CfuPlugin.scala | 71 ++++++++++++++++--- 2 files changed, 62 insertions(+), 11 deletions(-) diff --git a/src/main/scala/vexriscv/demo/GenSmallAndProductiveCfu.scala b/src/main/scala/vexriscv/demo/GenSmallAndProductiveCfu.scala index c500452f..960242f2 100644 --- a/src/main/scala/vexriscv/demo/GenSmallAndProductiveCfu.scala +++ b/src/main/scala/vexriscv/demo/GenSmallAndProductiveCfu.scala @@ -53,7 +53,7 @@ object GenSmallAndProductiveCfu extends App{ new CfuPlugin( stageCount = 1, allowZeroLatency = true, - encoding = M"000000-------------------0001011", +// encoding = M"000000-------------------0001011", busParameter = CfuBusParameter( CFU_VERSION = 0, CFU_INTERFACE_ID_W = 0, diff --git a/src/main/scala/vexriscv/plugin/CfuPlugin.scala b/src/main/scala/vexriscv/plugin/CfuPlugin.scala index d5aaf1c5..de0ae915 100644 --- a/src/main/scala/vexriscv/plugin/CfuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CfuPlugin.scala @@ -5,6 +5,7 @@ import spinal.core._ import spinal.lib._ import spinal.lib.bus.bmb.WeakConnector import spinal.lib.bus.misc.{AddressMapping, DefaultMapping} +import vexriscv.Riscv.IMM case class CfuPluginParameter( CFU_VERSION : Int, @@ -78,12 +79,20 @@ case class CfuBus(p : CfuBusParameter) extends Bundle with IMasterSlave{ } } +object CfuPlugin{ + object Input2Kind extends SpinalEnum{ + val RS, IMM_I = newElement() + } +} +case class CfuPluginEncoding(instruction : MaskedLiteral, + functionId : List[Range], + input2Kind : CfuPlugin.Input2Kind.E) class CfuPlugin( val stageCount : Int, val allowZeroLatency : Boolean, - val encoding : MaskedLiteral, - val busParameter : CfuBusParameter) extends Plugin[VexRiscv]{ + val busParameter : CfuBusParameter, + val encodings : List[CfuPluginEncoding] = null) extends Plugin[VexRiscv]{ def p = busParameter assert(p.CFU_INPUTS <= 2) @@ -99,7 +108,8 @@ class CfuPlugin( val stageCount : Int, val CFU_ENABLE = new Stageable(Bool()).setCompositeName(this, "CFU_ENABLE") val CFU_IN_FLIGHT = new Stageable(Bool()).setCompositeName(this, "CFU_IN_FLIGHT") - + val CFU_ENCODING = new Stageable(UInt(log2Up(encodings.size) bits)).setCompositeName(this, "CFU_ENCODING") + val CFU_INPUT_2_KIND = new Stageable(CfuPlugin.Input2Kind()).setCompositeName(this, "CFU_ENCODING") override def setup(pipeline: VexRiscv): Unit = { import pipeline._ @@ -111,17 +121,53 @@ class CfuPlugin( val stageCount : Int, val decoderService = pipeline.service(classOf[DecoderService]) decoderService.addDefault(CFU_ENABLE, False) - //custom-0 - decoderService.add(List( - encoding -> List( + for((encoding, id) <- encodings.zipWithIndex){ + var actions = List( CFU_ENABLE -> True, REGFILE_WRITE_VALID -> True, BYPASSABLE_EXECUTE_STAGE -> Bool(stageCount == 0), BYPASSABLE_MEMORY_STAGE -> Bool(stageCount <= 1), RS1_USE -> True, - RS2_USE -> True + CFU_ENCODING -> id, + CFU_INPUT_2_KIND -> encoding.input2Kind() ) - )) + + encoding.input2Kind match { + case CfuPlugin.Input2Kind.RS => + actions :+= RS2_USE -> True + case CfuPlugin.Input2Kind.IMM_I => + } + + decoderService.add( + key = encoding.instruction, + values = actions + ) + } + +// decoderService.add(List( +// //custom-0 +// M"-------------------------0001011" -> List( +// CFU_ENABLE -> True, +// REGFILE_WRITE_VALID -> True, +// BYPASSABLE_EXECUTE_STAGE -> Bool(stageCount == 0), +// BYPASSABLE_MEMORY_STAGE -> Bool(stageCount <= 1), +// RS1_USE -> True, +// RS2_USE -> True, +// CFU_IMM -> False +// ), +// +// //custom-1 +// M"-------------------------0101011" -> List( +// CFU_ENABLE -> True, +// REGFILE_WRITE_VALID -> True, +// BYPASSABLE_EXECUTE_STAGE -> Bool(stageCount == 0), +// BYPASSABLE_MEMORY_STAGE -> Bool(stageCount <= 1), +// RS1_USE -> True, +// CFU_IMM -> True +// ) +// )) + + } override def build(pipeline: VexRiscv): Unit = { @@ -139,11 +185,16 @@ class CfuPlugin( val stageCount : Int, bus.cmd.valid := (schedule || hold) && !fired arbitration.haltItself setWhen(bus.cmd.valid && !bus.cmd.ready) - bus.cmd.function_id := U(input(INSTRUCTION)(14 downto 12)).resized +// bus.cmd.function_id := U(input(INSTRUCTION)(14 downto 12)).resized + val functionsIds = encodings.map(e => U(Cat(e.functionId.map(r => input(INSTRUCTION)(r))), busParameter.CFU_FUNCTION_ID_W bits)) + bus.cmd.function_id := functionsIds.read(input(CFU_ENCODING)) bus.cmd.reorder_id := 0 bus.cmd.request_id := 0 if(p.CFU_INPUTS >= 1) bus.cmd.inputs(0) := input(RS1) - if(p.CFU_INPUTS >= 2) bus.cmd.inputs(1) := input(RS2) + if(p.CFU_INPUTS >= 2) bus.cmd.inputs(1) := input(CFU_INPUT_2_KIND).mux( + CfuPlugin.Input2Kind.RS -> input(RS2), + CfuPlugin.Input2Kind.IMM_I -> IMM(input(INSTRUCTION)).i_sext + ) } joinStage plug new Area{ From 71760ea3724ed854a1d831fbd9089f66ef2f41cd Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 5 Jun 2020 10:35:50 +0200 Subject: [PATCH 449/951] CsrPlugin now support utime csr to avoid emulation --- src/main/scala/vexriscv/Riscv.scala | 7 +++++-- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 8 ++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/Riscv.scala b/src/main/scala/vexriscv/Riscv.scala index 90a40c5c..ee9be3d0 100644 --- a/src/main/scala/vexriscv/Riscv.scala +++ b/src/main/scala/vexriscv/Riscv.scala @@ -159,7 +159,10 @@ object Riscv{ - def UCYCLE = 0xC00 // UR Machine ucycle counter. - def UCYCLEH = 0xC80 + def UCYCLE = 0xC00 // UR Machine ucycle counter. + def UCYCLEH = 0xC80 + def UTIME = 0xC01 // rdtime + def UTIMEH = 0xC81 + } } diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index ebff1e09..9dfad38c 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -66,6 +66,7 @@ case class CsrPluginConfig( scycleAccess : CsrAccess = CsrAccess.NONE, sinstretAccess : CsrAccess = CsrAccess.NONE, satpAccess : CsrAccess = CsrAccess.NONE, + utimeAccess :CsrAccess = CsrAccess.NONE, medelegAccess : CsrAccess = CsrAccess.NONE, midelegAccess : CsrAccess = CsrAccess.NONE, withExternalMhartid : Boolean = false, @@ -390,6 +391,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep var thirdPartyWake : Bool = null var inWfi : Bool = null var externalMhartId : UInt = null + var utime : UInt = null override def askWake(): Unit = thirdPartyWake := True @@ -520,6 +522,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep pipeline.update(MPP, UInt(2 bits)) if(withExternalMhartid) externalMhartId = in UInt(mhartidWidth bits) + if(utimeAccess != CsrAccess.NONE) utime = in UInt(64 bits) setName("utime") } def inhibateInterrupts() : Unit = allowInterrupts := False @@ -634,6 +637,11 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep ucycleAccess(CSR.UCYCLE, mcycle(31 downto 0)) ucycleAccess(CSR.UCYCLEH, mcycle(63 downto 32)) + if(utimeAccess != CsrAccess.NONE) { + utimeAccess(CSR.UTIME, utime(31 downto 0)) + utimeAccess(CSR.UTIMEH, utime(63 downto 32)) + } + pipeline(MPP) := mstatus.MPP } From d6455817e7e34bb0f7b43a83bcb8b39b04eb6858 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 5 Jun 2020 10:43:00 +0200 Subject: [PATCH 450/951] smp cluster now have 2w*4KB of d$ , no more rdtime emulation --- src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index 0e237c6a..5c1a34b6 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -9,7 +9,7 @@ import spinal.lib.bus.bmb.{Bmb, BmbArbiter, BmbDecoder, BmbExclusiveMonitor, Bmb import spinal.lib.com.jtag.Jtag import spinal.lib.com.jtag.sim.JtagTcp import vexriscv.ip.{DataCacheAck, DataCacheConfig, DataCacheMemBus, InstructionCache, InstructionCacheConfig} -import vexriscv.plugin.{BranchPlugin, CsrPlugin, CsrPluginConfig, DBusCachedPlugin, DBusSimplePlugin, DYNAMIC_TARGET, DebugPlugin, DecoderSimplePlugin, FullBarrelShifterPlugin, HazardSimplePlugin, IBusCachedPlugin, IBusSimplePlugin, IntAluPlugin, MmuPlugin, MmuPortConfig, MulDivIterativePlugin, MulPlugin, RegFilePlugin, STATIC, SrcPlugin, YamlPlugin} +import vexriscv.plugin.{BranchPlugin, CsrAccess, CsrPlugin, CsrPluginConfig, DBusCachedPlugin, DBusSimplePlugin, DYNAMIC_TARGET, DebugPlugin, DecoderSimplePlugin, FullBarrelShifterPlugin, HazardSimplePlugin, IBusCachedPlugin, IBusSimplePlugin, IntAluPlugin, MmuPlugin, MmuPortConfig, MulDivIterativePlugin, MulPlugin, RegFilePlugin, STATIC, SrcPlugin, YamlPlugin} import vexriscv.{Riscv, VexRiscv, VexRiscvConfig, plugin} import scala.collection.mutable @@ -160,9 +160,9 @@ object VexRiscvSmpClusterGen { dBusRspSlavePipe = true, relaxedMemoryTranslationRegister = true, config = new DataCacheConfig( - cacheSize = 4096*1, + cacheSize = 4096*2, bytePerLine = 64, - wayCount = 1, + wayCount = 2, addressWidth = 32, cpuDataWidth = 32, memDataWidth = dBusWidth, @@ -213,7 +213,7 @@ object VexRiscvSmpClusterGen { mulUnrollFactor = 32, divUnrollFactor = 1 ), - new CsrPlugin(CsrPluginConfig.openSbi(mhartid = hartId, misa = Riscv.misaToInt("imas"))), + new CsrPlugin(CsrPluginConfig.openSbi(mhartid = hartId, misa = Riscv.misaToInt("imas")).copy(utimeAccess = CsrAccess.READ_ONLY)), new BranchPlugin( earlyBranch = false, catchAddressMisaligned = true, From 760d2f74d0f2431827b29cacdb7bd440d6dfc48f Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 5 Jun 2020 13:31:24 +0200 Subject: [PATCH 451/951] Update litex cluster to implement utime --- src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala | 5 +++++ .../scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala | 1 + .../scala/vexriscv/demo/smp/VexRiscvSmpLitexMpCluster.scala | 2 ++ 3 files changed, 8 insertions(+) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index 5c1a34b6..de29409d 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -40,6 +40,7 @@ case class VexRiscvSmpCluster(p : VexRiscvSmpClusterParameter, val externalSupervisorInterrupts = in Bits(p.cpuConfigs.size bits) val jtag = slave(Jtag()) val debugReset = out Bool() + val time = in UInt(64 bits) } val cpus = for((cpuConfig, cpuId) <- p.cpuConfigs.zipWithIndex) yield new Area{ @@ -61,6 +62,7 @@ case class VexRiscvSmpCluster(p : VexRiscvSmpClusterParameter, plugin.externalInterrupt := io.externalInterrupts(cpuId) plugin.timerInterrupt := io.timerInterrupts(cpuId) if (plugin.config.supervisorGen) plugin.externalInterruptS := io.externalSupervisorInterrupts(cpuId) + if (plugin.utime != null) plugin.utime := io.time } case plugin: DebugPlugin => debugClockDomain{ io.debugReset := RegNext(plugin.io.resetOut) @@ -517,6 +519,9 @@ object VexRiscvSmpClusterOpenSbi extends App{ var lastAddress = 0l }) dut.clockDomain.onSamplings{ + dut.io.time #= simTime()/10 + + for(i <- 0 until cpuCount; iMem = dut.io.iMems(i); ctx = iMemCtx(i)){ // if(iMem.cmd.valid.toBoolean && iMem.cmd.ready.toBoolean){ // val length = iMem.cmd.length.toInt + 1 diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala index ea5cd39f..9466cfe2 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala @@ -57,6 +57,7 @@ case class VexRiscvLitexSmpCluster(p : VexRiscvLitexSmpClusterParameter, cluster.io.debugReset <> io.debugReset cluster.io.timerInterrupts <> B(clint.harts.map(_.timerInterrupt)) cluster.io.softwareInterrupts <> B(clint.harts.map(_.softwareInterrupt)) + cluster.io.time := clint.time val dBusDecoder = BmbDecoderOutOfOrder( p = cluster.io.dMem.p, diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexMpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexMpCluster.scala index ceb5a362..0f2af9b5 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexMpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexMpCluster.scala @@ -58,6 +58,7 @@ case class VexRiscvLitexSmpMpCluster(p : VexRiscvLitexSmpMpClusterParameter, cluster.io.debugReset <> io.debugReset cluster.io.timerInterrupts <> B(clint.harts.map(_.timerInterrupt)) cluster.io.softwareInterrupts <> B(clint.harts.map(_.softwareInterrupt)) + cluster.io.time := clint.time val dBusDecoder = BmbDecoderOutOfOrder( p = cluster.io.dMem.p, @@ -253,6 +254,7 @@ object VexRiscvLitexSmpMpClusterOpenSbi extends App{ (dut.io.peripheral.ADR.toLong << 2) match { case 0xF0000000l => print(dut.io.peripheral.DAT_MOSI.toLong.toChar) case 0xF0000004l => dut.io.peripheral.DAT_MISO #= (if (System.in.available() != 0) System.in.read() else 0xFFFFFFFFl) + case _ => // case 0xF0000004l => { // val c = if(stdin.nonEmpty) { // stdin.dequeue().toInt & 0xFF From 1f9fce638806fa665610466dcfa84d16213ea761 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sat, 6 Jun 2020 22:12:32 +0200 Subject: [PATCH 452/951] Fix d$ uncached writes exception handeling --- src/main/scala/vexriscv/ip/DataCache.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index 82fa3afa..8d02a40e 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -983,7 +983,7 @@ class DataCache(val p : DataCacheConfig, mmuParameter : MemoryTranslatorBusParam when(bypassCache){ io.cpu.writeBack.data := ioMemRspMuxed - if(catchAccessError) io.cpu.writeBack.accessError := io.mem.rsp.valid && io.mem.rsp.error + if(catchAccessError) io.cpu.writeBack.accessError := !request.wr && pending.last && io.mem.rsp.valid && io.mem.rsp.error } otherwise { io.cpu.writeBack.data := dataMux if(catchAccessError) io.cpu.writeBack.accessError := (waysHits & B(tagsReadRsp.map(_.error))) =/= 0 From cb5597818d10f5c19a394d8ffa62a9f3a12ad374 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sun, 7 Jun 2020 11:29:07 +0200 Subject: [PATCH 453/951] Fix d$ generation crash --- src/main/scala/vexriscv/ip/DataCache.scala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index 8d02a40e..65f29188 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -983,7 +983,8 @@ class DataCache(val p : DataCacheConfig, mmuParameter : MemoryTranslatorBusParam when(bypassCache){ io.cpu.writeBack.data := ioMemRspMuxed - if(catchAccessError) io.cpu.writeBack.accessError := !request.wr && pending.last && io.mem.rsp.valid && io.mem.rsp.error + def isLast = if(pending != null) pending.last else True + if(catchAccessError) io.cpu.writeBack.accessError := !request.wr && isLast && io.mem.rsp.valid && io.mem.rsp.error } otherwise { io.cpu.writeBack.data := dataMux if(catchAccessError) io.cpu.writeBack.accessError := (waysHits & B(tagsReadRsp.map(_.error))) =/= 0 From 2e8a059c77bba4d4136118e42a51347a1da46bd1 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sun, 7 Jun 2020 11:33:24 +0200 Subject: [PATCH 454/951] Fix travis verilator --- scripts/regression/verilator.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/regression/verilator.mk b/scripts/regression/verilator.mk index 9472858e..b97b74f2 100644 --- a/scripts/regression/verilator.mk +++ b/scripts/regression/verilator.mk @@ -3,9 +3,9 @@ verilator/configure: rm -rf verilator* - wget https://www.veripool.org/ftp/verilator-4.032.tgz + wget https://www.veripool.org/ftp/verilator-4.034.tgz tar xvzf verilator*.t*gz - mv verilator-4.012 verilator + mv verilator-4.034 verilator verilator/Makefile: verilator/configure cd verilator From b0cd88c4626b0fe218aa76790145b358e86e055e Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 12 Jun 2020 16:18:41 +0200 Subject: [PATCH 455/951] SmpCluster now with proper jtag and plic --- .../demo/smp/VexRiscvSmpCluster.scala | 42 +++---- .../demo/smp/VexRiscvSmpLitexCluster.scala | 71 ++++++++--- .../demo/smp/VexRiscvSmpLitexMpCluster.scala | 110 +++++++++++++++--- 3 files changed, 172 insertions(+), 51 deletions(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index de29409d..ccc1f571 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -6,8 +6,10 @@ import spinal.core.sim.{onSimEnd, simSuccess} import spinal.lib._ import spinal.lib.bus.bmb.sim.BmbMemoryAgent import spinal.lib.bus.bmb.{Bmb, BmbArbiter, BmbDecoder, BmbExclusiveMonitor, BmbInvalidateMonitor, BmbParameter} -import spinal.lib.com.jtag.Jtag +import spinal.lib.bus.misc.SizeMapping +import spinal.lib.com.jtag.{Jtag, JtagTapInstructionCtrl} import spinal.lib.com.jtag.sim.JtagTcp +import spinal.lib.system.debugger.SystemDebuggerConfig import vexriscv.ip.{DataCacheAck, DataCacheConfig, DataCacheMemBus, InstructionCache, InstructionCacheConfig} import vexriscv.plugin.{BranchPlugin, CsrAccess, CsrPlugin, CsrPluginConfig, DBusCachedPlugin, DBusSimplePlugin, DYNAMIC_TARGET, DebugPlugin, DecoderSimplePlugin, FullBarrelShifterPlugin, HazardSimplePlugin, IBusCachedPlugin, IBusSimplePlugin, IntAluPlugin, MmuPlugin, MmuPortConfig, MulDivIterativePlugin, MulPlugin, RegFilePlugin, STATIC, SrcPlugin, YamlPlugin} import vexriscv.{Riscv, VexRiscv, VexRiscvConfig, plugin} @@ -38,21 +40,23 @@ case class VexRiscvSmpCluster(p : VexRiscvSmpClusterParameter, val externalInterrupts = in Bits(p.cpuConfigs.size bits) val softwareInterrupts = in Bits(p.cpuConfigs.size bits) val externalSupervisorInterrupts = in Bits(p.cpuConfigs.size bits) - val jtag = slave(Jtag()) + val debugBus = slave(Bmb(SystemDebuggerConfig().getBmbParameter.copy(addressWidth = 20))) val debugReset = out Bool() val time = in UInt(64 bits) } + io.debugReset := False val cpus = for((cpuConfig, cpuId) <- p.cpuConfigs.zipWithIndex) yield new Area{ var iBus : Bmb = null var dBus : Bmb = null + var debug : Bmb = null cpuConfig.plugins.foreach { case plugin: DebugPlugin => debugClockDomain{ plugin.debugClockDomain = debugClockDomain } case _ => } - if(cpuId == 0) cpuConfig.plugins += new DebugPlugin(debugClockDomain) + cpuConfig.plugins += new DebugPlugin(debugClockDomain) val core = new VexRiscv(cpuConfig) core.plugins.foreach { case plugin: IBusCachedPlugin => iBus = plugin.iBus.toBmb() @@ -65,8 +69,8 @@ case class VexRiscvSmpCluster(p : VexRiscvSmpClusterParameter, if (plugin.utime != null) plugin.utime := io.time } case plugin: DebugPlugin => debugClockDomain{ - io.debugReset := RegNext(plugin.io.resetOut) - io.jtag <> plugin.io.bus.fromJtag() + io.debugReset setWhen(RegNext(plugin.io.resetOut)) + debug = plugin.io.bus.fromBmb() } case _ => } @@ -97,19 +101,18 @@ case class VexRiscvSmpCluster(p : VexRiscvSmpClusterParameter, io.dMem << invalidateMonitor.io.output -// val iBusArbiter = BmbArbiter( -// p = iBusArbiterParameter, -// portCount = cpus.size, -// pendingRspMax = 64, -// lowerFirstPriority = false, -// inputsWithInv = cpus.map(_ => true), -// inputsWithSync = cpus.map(_ => true), -// pendingInvMax = 16 -// ) -// -// (iBusArbiter.io.inputs, cpus).zipped.foreach(_ << _.iBus) -// io.iMem << iBusArbiter.io.output (io.iMems, cpus).zipped.foreach(_ << _.iBus) + + val debug = debugClockDomain on new Area{ + val arbiter = BmbDecoder( + p = io.debugBus.p, + mappings = List.tabulate(p.cpuConfigs.size)(i => SizeMapping(0x00000 + i*0x1000, 0x1000)), + capabilities = List.fill(p.cpuConfigs.size)(io.debugBus.p), + pendingMax = 2 + ) + arbiter.io.input << io.debugBus + (arbiter.io.outputs, cpus.map(_.debug)).zipped.foreach(_ >> _) + } } @@ -417,10 +420,7 @@ object VexRiscvSmpClusterTestInfrastructure{ import spinal.core.sim._ dut.clockDomain.forkStimulus(10) dut.debugClockDomain.forkStimulus(10) -// JtagTcp(dut.io.jtag, 100) - dut.io.jtag.tck #= false - dut.io.jtag.tdi #= false - dut.io.jtag.tms #= false + dut.io.debugBus.cmd.valid #= false } } diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala index 9466cfe2..43ae2426 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala @@ -3,13 +3,15 @@ package vexriscv.demo.smp import spinal.core._ import spinal.lib.bus.bmb._ import spinal.lib.bus.wishbone.{Wishbone, WishboneConfig, WishboneSlaveFactory} -import spinal.lib.com.jtag.Jtag +import spinal.lib.com.jtag.{Jtag, JtagTapInstructionCtrl} import spinal.lib._ import spinal.lib.bus.bmb.sim.{BmbMemoryMultiPort, BmbMemoryTester} import spinal.lib.bus.misc.{AddressMapping, DefaultMapping, SizeMapping} import spinal.lib.eda.bench.Bench import spinal.lib.misc.Clint +import spinal.lib.misc.plic.{PlicGatewayActiveHigh, PlicMapper, PlicMapping, PlicTarget} import spinal.lib.sim.{SimData, SparseMemory, StreamDriver, StreamMonitor, StreamReadyRandomizer} +import spinal.lib.system.debugger.{JtagBridgeNoTap, SystemDebugger, SystemDebuggerConfig} import vexriscv.demo.smp.VexRiscvLitexSmpClusterOpenSbi.{cpuCount, parameter} import vexriscv.demo.smp.VexRiscvSmpClusterGen.vexRiscvConfig import vexriscv.{VexRiscv, VexRiscvConfig} @@ -25,7 +27,8 @@ case class VexRiscvLitexSmpClusterParameter( cluster : VexRiscvSmpClusterParamet //addAttribute("""mark_debug = "true"""") case class VexRiscvLitexSmpCluster(p : VexRiscvLitexSmpClusterParameter, - debugClockDomain : ClockDomain) extends Component{ + debugClockDomain : ClockDomain, + jtagClockDomain : ClockDomain) extends Component{ val peripheralWishboneConfig = WishboneConfig( addressWidth = 30, @@ -41,9 +44,9 @@ case class VexRiscvLitexSmpCluster(p : VexRiscvLitexSmpClusterParameter, val iMem = master(LiteDramNative(p.liteDram)) val peripheral = master(Wishbone(peripheralWishboneConfig)) val clint = slave(Wishbone(Clint.getWisboneConfig())) - val externalInterrupts = in Bits(p.cluster.cpuConfigs.size bits) - val externalSupervisorInterrupts = in Bits(p.cluster.cpuConfigs.size bits) - val jtag = slave(Jtag()) + val plic = slave(Wishbone(WishboneConfig(addressWidth = 20, dataWidth = 32))) + val interrupts = in Bits(32 bits) + val jtagInstruction = slave(JtagTapInstructionCtrl()) val debugReset = out Bool() } val cpuCount = p.cluster.cpuConfigs.size @@ -51,14 +54,25 @@ case class VexRiscvLitexSmpCluster(p : VexRiscvLitexSmpClusterParameter, clint.driveFrom(WishboneSlaveFactory(io.clint)) val cluster = VexRiscvSmpCluster(p.cluster, debugClockDomain) - cluster.io.externalInterrupts <> io.externalInterrupts - cluster.io.externalSupervisorInterrupts <> io.externalSupervisorInterrupts - cluster.io.jtag <> io.jtag cluster.io.debugReset <> io.debugReset cluster.io.timerInterrupts <> B(clint.harts.map(_.timerInterrupt)) cluster.io.softwareInterrupts <> B(clint.harts.map(_.softwareInterrupt)) cluster.io.time := clint.time + val debug = debugClockDomain on new Area{ + val jtagConfig = SystemDebuggerConfig() + val jtagBridge = new JtagBridgeNoTap( + c = jtagConfig, + jtagClockDomain = jtagClockDomain + ) + jtagBridge.io.ctrl << io.jtagInstruction + + val debugger = new SystemDebugger(jtagConfig) + debugger.io.remote <> jtagBridge.io.remote + + cluster.io.debugBus << debugger.io.mem.toBmb() + } + val dBusDecoder = BmbDecoderOutOfOrder( p = cluster.io.dMem.p, mappings = Seq(DefaultMapping, p.liteDramMapping), @@ -114,9 +128,39 @@ case class VexRiscvLitexSmpCluster(p : VexRiscvLitexSmpClusterParameter, val peripheralWishbone = peripheralArbiter.io.output.pipelined(cmdValid = true).toWishbone() io.peripheral << peripheralWishbone + + val plic = new Area{ + val priorityWidth = 2 + + val gateways = for(i <- 1 until 32) yield PlicGatewayActiveHigh( + source = io.interrupts(i), + id = i, + priorityWidth = priorityWidth + ) + + val bus = WishboneSlaveFactory(io.plic) + + val targets = for(i <- 0 until cpuCount) yield new Area{ + val machine = PlicTarget( + gateways = gateways, + priorityWidth = priorityWidth + ) + val supervisor = PlicTarget( + gateways = gateways, + priorityWidth = priorityWidth + ) + + cluster.io.externalInterrupts(i) := machine.iep + cluster.io.externalSupervisorInterrupts(i) := supervisor.iep + } + + val bridge = PlicMapper(bus, PlicMapping.sifive)( + gateways = gateways, + targets = targets.flatMap(t => List(t.machine, t.supervisor)) + ) + } } -//ifconfig eth0 192.168.0.50 netmask 255.255.255.0 up object VexRiscvLitexSmpClusterGen extends App { for(cpuCount <- List(1,2,4,8)) { def parameter = VexRiscvLitexSmpClusterParameter( @@ -136,7 +180,8 @@ object VexRiscvLitexSmpClusterGen extends App { def dutGen = { val toplevel = VexRiscvLitexSmpCluster( p = parameter, - debugClockDomain = ClockDomain.current.copy(reset = Bool().setName("debugResetIn")) + debugClockDomain = ClockDomain.current.copy(reset = Bool().setName("debugResetIn")), + jtagClockDomain = ClockDomain.external("jtag", withReset = false) ) toplevel } @@ -175,7 +220,8 @@ object VexRiscvLitexSmpClusterOpenSbi extends App{ def dutGen = { val top = VexRiscvLitexSmpCluster( p = parameter, - debugClockDomain = ClockDomain.current.copy(reset = Bool().setName("debugResetIn")) + debugClockDomain = ClockDomain.current.copy(reset = Bool().setName("debugResetIn")), + jtagClockDomain = ClockDomain.external("jtag", withReset = false) ) top.rework{ top.io.clint.setAsDirectionLess.allowDirectionLessIo @@ -216,8 +262,7 @@ object VexRiscvLitexSmpClusterOpenSbi extends App{ dut.io.iMem.simSlave(ram, dut.clockDomain) dut.io.dMem.simSlave(ram, dut.clockDomain, dut.dMemBridge.unburstified) - dut.io.externalInterrupts #= 0 - dut.io.externalSupervisorInterrupts #= 0 + dut.io.interrupts #= 0 dut.clockDomain.onFallingEdges{ if(dut.io.peripheral.CYC.toBoolean){ diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexMpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexMpCluster.scala index 0f2af9b5..3631cfc5 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexMpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexMpCluster.scala @@ -3,13 +3,19 @@ package vexriscv.demo.smp import spinal.core._ import spinal.lib.bus.bmb._ import spinal.lib.bus.wishbone.{Wishbone, WishboneConfig, WishboneSlaveFactory} -import spinal.lib.com.jtag.Jtag +import spinal.lib.com.jtag.{Jtag, JtagTap, JtagTapInstructionCtrl} import spinal.lib._ +import spinal.lib.blackbox.xilinx.s7.BSCANE2 import spinal.lib.bus.bmb.sim.{BmbMemoryMultiPort, BmbMemoryTester} import spinal.lib.bus.misc.{AddressMapping, DefaultMapping, SizeMapping} +import spinal.lib.com.jtag.sim.JtagTcp +import spinal.lib.com.jtag.xilinx.Bscane2BmbMaster import spinal.lib.eda.bench.Bench import spinal.lib.misc.Clint +import spinal.lib.misc.plic.{PlicGatewayActiveHigh, PlicMapper, PlicMapping, PlicTarget} import spinal.lib.sim.{SimData, SparseMemory, StreamDriver, StreamMonitor, StreamReadyRandomizer} +import spinal.lib.system.debugger.{JtagBridgeNoTap, SystemDebugger, SystemDebuggerConfig} +import sun.jvm.hotspot.oops.DataLayout import vexriscv.demo.smp.VexRiscvLitexSmpMpClusterOpenSbi.{cpuCount, parameter} import vexriscv.demo.smp.VexRiscvSmpClusterGen.vexRiscvConfig import vexriscv.{VexRiscv, VexRiscvConfig} @@ -24,8 +30,9 @@ case class VexRiscvLitexSmpMpClusterParameter( cluster : VexRiscvSmpClusterParam liteDramMapping : AddressMapping) //addAttribute("""mark_debug = "true"""") -case class VexRiscvLitexSmpMpCluster(p : VexRiscvLitexSmpMpClusterParameter, - debugClockDomain : ClockDomain) extends Component{ +class VexRiscvLitexSmpMpCluster(val p : VexRiscvLitexSmpMpClusterParameter, + val debugClockDomain : ClockDomain, + val jtagClockDomain : ClockDomain) extends Component{ val peripheralWishboneConfig = WishboneConfig( addressWidth = 30, @@ -43,23 +50,48 @@ case class VexRiscvLitexSmpMpCluster(p : VexRiscvLitexSmpMpClusterParameter, val iMem = Vec(master(LiteDramNative(p.liteDram)), cpuCount) val peripheral = master(Wishbone(peripheralWishboneConfig)) val clint = slave(Wishbone(Clint.getWisboneConfig())) - val externalInterrupts = in Bits(p.cluster.cpuConfigs.size bits) - val externalSupervisorInterrupts = in Bits(p.cluster.cpuConfigs.size bits) - val jtag = slave(Jtag()) + val plic = slave(Wishbone(WishboneConfig(addressWidth = 20, dataWidth = 32))) + val interrupts = in Bits(32 bits) + val jtagInstruction = slave(JtagTapInstructionCtrl()) val debugReset = out Bool() } val clint = Clint(cpuCount) clint.driveFrom(WishboneSlaveFactory(io.clint)) val cluster = VexRiscvSmpCluster(p.cluster, debugClockDomain) - cluster.io.externalInterrupts <> io.externalInterrupts - cluster.io.externalSupervisorInterrupts <> io.externalSupervisorInterrupts - cluster.io.jtag <> io.jtag cluster.io.debugReset <> io.debugReset cluster.io.timerInterrupts <> B(clint.harts.map(_.timerInterrupt)) cluster.io.softwareInterrupts <> B(clint.harts.map(_.softwareInterrupt)) cluster.io.time := clint.time + val debug = debugClockDomain on new Area{ + val jtagConfig = SystemDebuggerConfig() + + val jtagBridge = new JtagBridgeNoTap(jtagConfig, jtagClockDomain) + jtagBridge.io.ctrl << io.jtagInstruction + + val debugger = new SystemDebugger(jtagConfig) + debugger.io.remote <> jtagBridge.io.remote + + cluster.io.debugBus << debugger.io.mem.toBmb() + +// io.jtagInstruction.allowDirectionLessIo.setAsDirectionLess +// val bridge = Bscane2BmbMaster(1) +// cluster.io.debugBus << bridge.io.bmb + + +// val bscane2 = BSCANE2(usedId) +// val jtagClockDomain = ClockDomain(bscane2.TCK) +// +// val jtagBridge = new JtagBridgeNoTap(jtagConfig, jtagClockDomain) +// jtagBridge.io.ctrl << bscane2.toJtagTapInstructionCtrl() +// +// val debugger = new SystemDebugger(jtagConfig) +// debugger.io.remote <> jtagBridge.io.remote +// +// io.bmb << debugger.io.mem.toBmb() + } + val dBusDecoder = BmbDecoderOutOfOrder( p = cluster.io.dMem.p, mappings = Seq(DefaultMapping, p.liteDramMapping), @@ -116,6 +148,38 @@ case class VexRiscvLitexSmpMpCluster(p : VexRiscvLitexSmpMpClusterParameter, val dMemBridge = for(id <- 0 until cpuCount) yield { io.dMem(id).fromBmb(dBusDemux.io.outputs(id), wdataFifoSize = 32, rdataFifoSize = 32) } + + + val plic = new Area{ + val priorityWidth = 2 + + val gateways = for(i <- 1 until 32) yield PlicGatewayActiveHigh( + source = io.interrupts(i), + id = i, + priorityWidth = priorityWidth + ) + + val bus = WishboneSlaveFactory(io.plic) + + val targets = for(i <- 0 until cpuCount) yield new Area{ + val machine = PlicTarget( + gateways = gateways, + priorityWidth = priorityWidth + ) + val supervisor = PlicTarget( + gateways = gateways, + priorityWidth = priorityWidth + ) + + cluster.io.externalInterrupts(i) := machine.iep + cluster.io.externalSupervisorInterrupts(i) := supervisor.iep + } + + val bridge = PlicMapper(bus, PlicMapping.sifive)( + gateways = gateways, + targets = targets.flatMap(t => List(t.machine, t.supervisor)) + ) + } // // io.dMem.foreach(_.cmd.valid.addAttribute("""mark_debug = "true"""")) // io.dMem.foreach(_.cmd.ready.addAttribute("""mark_debug = "true"""")) @@ -145,9 +209,10 @@ object VexRiscvLitexSmpMpClusterGen extends App { ) def dutGen = { - val toplevel = VexRiscvLitexSmpMpCluster( + val toplevel = new VexRiscvLitexSmpMpCluster( p = parameter, - debugClockDomain = ClockDomain.current.copy(reset = Bool().setName("debugResetIn")) + debugClockDomain = ClockDomain.current.copy(reset = Bool().setName("debugResetIn")), + jtagClockDomain = ClockDomain.external("jtag", withReset = false) ) toplevel } @@ -185,10 +250,20 @@ object VexRiscvLitexSmpMpClusterOpenSbi extends App{ ) def dutGen = { - val top = VexRiscvLitexSmpMpCluster( + val top = new VexRiscvLitexSmpMpCluster( p = parameter, - debugClockDomain = ClockDomain.current.copy(reset = Bool().setName("debugResetIn")) - ) + debugClockDomain = ClockDomain.current.copy(reset = Bool().setName("debugResetIn")), + jtagClockDomain = ClockDomain.external("jtag", withReset = false) + ){ + io.jtagInstruction.allowDirectionLessIo.setAsDirectionLess + val jtag = slave(Jtag()) + jtagClockDomain.readClockWire.setAsDirectionLess() := jtag.tck + val jtagLogic = jtagClockDomain on new Area{ + val tap = new JtagTap(jtag, 4) + val idcodeArea = tap.idcode(B"x10001FFF")(1) + val wrapper = tap.map(io.jtagInstruction, instructionId = 2) + } + } top.rework{ top.io.clint.setAsDirectionLess.allowDirectionLessIo top.io.peripheral.setAsDirectionLess.allowDirectionLessIo.simPublic() @@ -217,6 +292,7 @@ object VexRiscvLitexSmpMpClusterOpenSbi extends App{ dut.debugClockDomain.resetSim #= false } + JtagTcp(dut.jtag, 10*20) val ram = SparseMemory() ram.loadBin(0x80000000l, "../opensbi/build/platform/spinal/vexriscv/sim/smp/firmware/fw_jump.bin") @@ -229,8 +305,8 @@ object VexRiscvLitexSmpMpClusterOpenSbi extends App{ dut.io.dMem(id).simSlave(ram, dut.clockDomain) } - dut.io.externalInterrupts #= 0 - dut.io.externalSupervisorInterrupts #= 0 + dut.io.interrupts #= 0 + // val stdin = mutable.Queue[Byte]() // def stdInPush(str : String) = stdin ++= str.toCharArray.map(_.toByte) @@ -272,7 +348,7 @@ object VexRiscvLitexSmpMpClusterOpenSbi extends App{ fork{ val at = 0 - val duration = 0 + val duration = 1000 while(simTime() < at*1000000l) { disableSimWave() sleep(100000 * 10) From 490c1f6b0276f9b09a4ea34bfe6ce47efb7938d1 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 19 Jun 2020 15:56:45 +0200 Subject: [PATCH 456/951] cleanup of old todo --- src/main/scala/vexriscv/TestsWorkspace.scala | 7 ------- src/main/scala/vexriscv/demo/smp/Misc.scala | 2 +- src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala | 3 --- 3 files changed, 1 insertion(+), 11 deletions(-) diff --git a/src/main/scala/vexriscv/TestsWorkspace.scala b/src/main/scala/vexriscv/TestsWorkspace.scala index af1c77b5..b522aed5 100644 --- a/src/main/scala/vexriscv/TestsWorkspace.scala +++ b/src/main/scala/vexriscv/TestsWorkspace.scala @@ -274,10 +274,3 @@ object TestsWorkspace { } } } - -//TODO DivPlugin should not used MixedDivider (double twoComplement) -//TODO DivPlugin should register the twoComplement output before pipeline insertion -//TODO MulPlugin doesn't fit well on Artix (FMAX) -//TODO PcReg design is unoptimized by Artix synthesis -//TODO FMAX SRC mux + bipass mux prioriti -//TODO FMAX, isFiring is to pesimisstinc in some cases(include removeIt flushed ..) \ No newline at end of file diff --git a/src/main/scala/vexriscv/demo/smp/Misc.scala b/src/main/scala/vexriscv/demo/smp/Misc.scala index b192a9cd..9980cf47 100644 --- a/src/main/scala/vexriscv/demo/smp/Misc.scala +++ b/src/main/scala/vexriscv/demo/smp/Misc.scala @@ -188,7 +188,7 @@ case class BmbToLiteDram(bmbParameter : BmbParameter, wData.arbitrationFrom(dataFork.throwWhen(dataFork.isRead)) wData.data := dataFork.data wData.we := dataFork.mask - io.output.wdata << wData.queueLowLatency(wdataFifoSize, latency = 1) //TODO queue low latency + io.output.wdata << wData.queueLowLatency(wdataFifoSize, latency = 1) } else { dataFork.ready := True io.output.wdata.valid := False diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index ccc1f571..efd40101 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -454,12 +454,9 @@ object VexRiscvSmpClusterTest extends App{ // top -b -n 1 // TODO -// litex cluster should use out of order decoder // MultiChannelFifo.toStream arbitration // BmbDecoderOutOfOrder arbitration // DataCache to bmb invalidation that are more than single line -// update fence w to w -// DBusCachedPlugin dBusAccess execute.isValid := True is induce a longe combinatorial path to check conditions, D$ execute valid => execute haltIt object VexRiscvSmpClusterOpenSbi extends App{ import spinal.core.sim._ From c18bc12cb20b1ede650f6eb68628fb8c0a42dec2 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 19 Jun 2020 15:57:21 +0200 Subject: [PATCH 457/951] Fix DebugPlugin.fromBmb --- src/main/scala/vexriscv/plugin/DebugPlugin.scala | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/scala/vexriscv/plugin/DebugPlugin.scala b/src/main/scala/vexriscv/plugin/DebugPlugin.scala index 9f2a2436..4797e213 100644 --- a/src/main/scala/vexriscv/plugin/DebugPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DebugPlugin.scala @@ -106,6 +106,7 @@ case class DebugExtensionBus() extends Bundle with IMasterSlave{ bus.rsp.valid := RegNext(cmd.fire) init(False) bus.rsp.data := rsp.data bus.rsp.last := True + bus.rsp.setSuccess() bus } From f0f2cf61daca13629368a6217a3a35800e546741 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 19 Jun 2020 15:57:56 +0200 Subject: [PATCH 458/951] D$ inv/ack are now fragment, which ease serialisation of wider invalidations --- src/main/scala/vexriscv/ip/DataCache.scala | 38 ++++++++++++---------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index 65f29188..98ba0ab1 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -228,8 +228,8 @@ case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave val cmd = Stream (DataCacheMemCmd(p)) val rsp = Flow (DataCacheMemRsp(p)) - val inv = p.withInvalidate generate Stream(DataCacheInv(p)) - val ack = p.withInvalidate generate Stream(DataCacheAck(p)) + val inv = p.withInvalidate generate Stream(Fragment(DataCacheInv(p))) + val ack = p.withInvalidate generate Stream(Fragment(DataCacheAck(p))) val sync = p.withInvalidate generate Stream(DataCacheSync(p)) override def asMaster(): Unit = { @@ -279,15 +279,7 @@ case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave axi.r.ready := True axi.b.ready := True - - //TODO remove - val axi2 = cloneOf(axi) - // axi.arw >/-> axi2.arw - // axi.w >/-> axi2.w - // axi.r <-/< axi2.r - // axi.b <-/< axi2.b - axi2 << axi - axi2 + axi } @@ -509,13 +501,24 @@ case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave if(p.withExclusive) rsp.exclusive := bus.rsp.exclusive bus.rsp.ready := True - if(p.withInvalidate){ - inv.arbitrationFrom(bus.inv) - inv.address := bus.inv.address - inv.enable := bus.inv.all + val invalidateLogic = p.withInvalidate generate new Area{ + val beatCountMinusOne = bus.inv.transferBeatCountMinusOne(p.bytePerLine) + val counter = Reg(UInt(widthOf(beatCountMinusOne) bits)) init(0) - bus.ack.arbitrationFrom(ack) - // //TODO manage lenght ? + inv.valid := bus.inv.valid + inv.address := bus.inv.address + (counter << log2Up(p.bytePerLine)) + inv.enable := bus.inv.all + inv.last := counter === beatCountMinusOne + bus.inv.ready := inv.last && inv.ready + + if(widthOf(counter) != 0) when(inv.fire){ + counter := counter + 1 + when(inv.last){ + counter := 0 + } + } + + bus.ack.arbitrationFrom(ack.throwWhen(!ack.last)) } }.bus @@ -1112,6 +1115,7 @@ class DataCache(val p : DataCacheConfig, mmuParameter : MemoryTranslatorBusParam } io.mem.ack.arbitrationFrom(input) io.mem.ack.hit := wayHit + io.mem.ack.last := input.last //Manage invalidation read during write hazard s1.invalidations := RegNextWhen((input.valid && input.enable && input.address(lineRange) === s0.input.address(lineRange)) ? wayHits | 0, s0.input.ready) From c12f9a378d2174d0cbca8c76dee6a325a0174e3d Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sat, 20 Jun 2020 13:18:46 +0200 Subject: [PATCH 459/951] Fix inv regression --- src/test/cpp/regression/main.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 717e5340..54685459 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -2496,12 +2496,12 @@ public: if(top->dBus_inv_ready) top->dBus_inv_valid = 0; if(top->dBus_inv_valid == 0 && VL_RANDOM_I(7) < 5){ top->dBus_inv_valid = 1; - top->dBus_inv_payload_enable = VL_RANDOM_I(7) < 100; + top->dBus_inv_payload_fragment_enable = VL_RANDOM_I(7) < 100; if(!invalidationHint.empty()){ - top->dBus_inv_payload_address = invalidationHint.front(); + top->dBus_inv_payload_fragment_address = invalidationHint.front(); invalidationHint.pop(); } else { - top->dBus_inv_payload_address = VL_RANDOM_I(32); + top->dBus_inv_payload_fragment_address = VL_RANDOM_I(32); } } } From 062509deee2939a4f40b85f843566f47237a375d Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 29 Jun 2020 11:44:10 +0200 Subject: [PATCH 460/951] Update Bmb brides and comment out SmpCluster for now --- src/main/scala/vexriscv/demo/smp/Misc.scala | 8 +- .../demo/smp/VexRiscvSmpCluster.scala | 1222 ++++++++--------- .../demo/smp/VexRiscvSmpLitexCluster.scala | 586 ++++---- .../demo/smp/VexRiscvSmpLitexMpCluster.scala | 710 +++++----- src/main/scala/vexriscv/ip/DataCache.scala | 33 +- .../scala/vexriscv/ip/InstructionCache.scala | 21 +- .../vexriscv/plugin/DBusSimplePlugin.scala | 5 +- .../scala/vexriscv/plugin/DebugPlugin.scala | 10 +- .../vexriscv/plugin/IBusSimplePlugin.scala | 2 +- 9 files changed, 1297 insertions(+), 1300 deletions(-) diff --git a/src/main/scala/vexriscv/demo/smp/Misc.scala b/src/main/scala/vexriscv/demo/smp/Misc.scala index 9980cf47..6fa34ba8 100644 --- a/src/main/scala/vexriscv/demo/smp/Misc.scala +++ b/src/main/scala/vexriscv/demo/smp/Misc.scala @@ -11,8 +11,6 @@ import spinal.lib.bus.misc.{AddressMapping, DefaultMapping, SizeMapping} import spinal.lib.eda.bench.Bench import spinal.lib.misc.Clint import spinal.lib.sim.{SimData, SparseMemory, StreamDriver, StreamMonitor, StreamReadyRandomizer} -import vexriscv.demo.smp.VexRiscvLitexSmpClusterOpenSbi.{cpuCount, parameter} -import vexriscv.demo.smp.VexRiscvSmpClusterGen.vexRiscvConfig import vexriscv.{VexRiscv, VexRiscvConfig} import vexriscv.plugin.{CsrPlugin, DBusCachedPlugin, DebugPlugin, IBusCachedPlugin} @@ -166,8 +164,8 @@ case class BmbToLiteDram(bmbParameter : BmbParameter, val resized = io.input.resize(liteDramParameter.dataWidth) val unburstified = resized.unburstify() case class Context() extends Bundle { - val context = Bits(unburstified.p.contextWidth bits) - val source = UInt(unburstified.p.sourceWidth bits) + val context = Bits(unburstified.p.access.contextWidth bits) + val source = UInt(unburstified.p.access.sourceWidth bits) val isWrite = Bool() } @@ -183,7 +181,7 @@ case class BmbToLiteDram(bmbParameter : BmbParameter, io.output.cmd <-< outputCmd - if(bmbParameter.canWrite) { + if(bmbParameter.access.canWrite) { val wData = Stream(LiteDramNativeWData(liteDramParameter)) wData.arbitrationFrom(dataFork.throwWhen(dataFork.isRead)) wData.data := dataFork.data diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index efd40101..ea8ab764 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -1,622 +1,622 @@ -package vexriscv.demo.smp - -import spinal.core -import spinal.core._ -import spinal.core.sim.{onSimEnd, simSuccess} -import spinal.lib._ -import spinal.lib.bus.bmb.sim.BmbMemoryAgent -import spinal.lib.bus.bmb.{Bmb, BmbArbiter, BmbDecoder, BmbExclusiveMonitor, BmbInvalidateMonitor, BmbParameter} -import spinal.lib.bus.misc.SizeMapping -import spinal.lib.com.jtag.{Jtag, JtagTapInstructionCtrl} -import spinal.lib.com.jtag.sim.JtagTcp -import spinal.lib.system.debugger.SystemDebuggerConfig -import vexriscv.ip.{DataCacheAck, DataCacheConfig, DataCacheMemBus, InstructionCache, InstructionCacheConfig} -import vexriscv.plugin.{BranchPlugin, CsrAccess, CsrPlugin, CsrPluginConfig, DBusCachedPlugin, DBusSimplePlugin, DYNAMIC_TARGET, DebugPlugin, DecoderSimplePlugin, FullBarrelShifterPlugin, HazardSimplePlugin, IBusCachedPlugin, IBusSimplePlugin, IntAluPlugin, MmuPlugin, MmuPortConfig, MulDivIterativePlugin, MulPlugin, RegFilePlugin, STATIC, SrcPlugin, YamlPlugin} -import vexriscv.{Riscv, VexRiscv, VexRiscvConfig, plugin} - -import scala.collection.mutable -import scala.collection.mutable.ArrayBuffer - - -case class VexRiscvSmpClusterParameter( cpuConfigs : Seq[VexRiscvConfig]) - -case class VexRiscvSmpCluster(p : VexRiscvSmpClusterParameter, - debugClockDomain : ClockDomain) extends Component{ - val dBusParameter = p.cpuConfigs.head.plugins.find(_.isInstanceOf[DBusCachedPlugin]).get.asInstanceOf[DBusCachedPlugin].config.getBmbParameter() - val dBusArbiterParameter = dBusParameter.copy(sourceWidth = log2Up(p.cpuConfigs.size)) - val exclusiveMonitorParameter = dBusArbiterParameter - val invalidateMonitorParameter = BmbExclusiveMonitor.outputParameter(exclusiveMonitorParameter) - val dMemParameter = BmbInvalidateMonitor.outputParameter(invalidateMonitorParameter) - - val iBusParameter = p.cpuConfigs.head.plugins.find(_.isInstanceOf[IBusCachedPlugin]).get.asInstanceOf[IBusCachedPlugin].config.getBmbParameter() - val iBusArbiterParameter = iBusParameter//.copy(sourceWidth = log2Up(p.cpuConfigs.size)) - val iMemParameter = iBusArbiterParameter - - val io = new Bundle { - val dMem = master(Bmb(dMemParameter)) -// val iMem = master(Bmb(iMemParameter)) - val iMems = Vec(master(Bmb(iMemParameter)), p.cpuConfigs.size) - val timerInterrupts = in Bits(p.cpuConfigs.size bits) - val externalInterrupts = in Bits(p.cpuConfigs.size bits) - val softwareInterrupts = in Bits(p.cpuConfigs.size bits) - val externalSupervisorInterrupts = in Bits(p.cpuConfigs.size bits) - val debugBus = slave(Bmb(SystemDebuggerConfig().getBmbParameter.copy(addressWidth = 20))) - val debugReset = out Bool() - val time = in UInt(64 bits) - } - - io.debugReset := False - val cpus = for((cpuConfig, cpuId) <- p.cpuConfigs.zipWithIndex) yield new Area{ - var iBus : Bmb = null - var dBus : Bmb = null - var debug : Bmb = null - cpuConfig.plugins.foreach { - case plugin: DebugPlugin => debugClockDomain{ - plugin.debugClockDomain = debugClockDomain - } - case _ => - } - cpuConfig.plugins += new DebugPlugin(debugClockDomain) - val core = new VexRiscv(cpuConfig) - core.plugins.foreach { - case plugin: IBusCachedPlugin => iBus = plugin.iBus.toBmb() - case plugin: DBusCachedPlugin => dBus = plugin.dBus.toBmb().pipelined(cmdValid = true) - case plugin: CsrPlugin => { - plugin.softwareInterrupt := io.softwareInterrupts(cpuId) - plugin.externalInterrupt := io.externalInterrupts(cpuId) - plugin.timerInterrupt := io.timerInterrupts(cpuId) - if (plugin.config.supervisorGen) plugin.externalInterruptS := io.externalSupervisorInterrupts(cpuId) - if (plugin.utime != null) plugin.utime := io.time - } - case plugin: DebugPlugin => debugClockDomain{ - io.debugReset setWhen(RegNext(plugin.io.resetOut)) - debug = plugin.io.bus.fromBmb() - } - case _ => - } - } - - val dBusArbiter = BmbArbiter( - p = dBusArbiterParameter, - portCount = cpus.size, - lowerFirstPriority = false, - inputsWithInv = cpus.map(_ => true), - inputsWithSync = cpus.map(_ => true), - pendingInvMax = 16 - ) - - (dBusArbiter.io.inputs, cpus).zipped.foreach(_ << _.dBus.pipelined(invValid = true, ackValid = true, syncValid = true)) - - val exclusiveMonitor = BmbExclusiveMonitor( - inputParameter = exclusiveMonitorParameter, - pendingWriteMax = 64 - ) - exclusiveMonitor.io.input << dBusArbiter.io.output.pipelined(cmdValid = true, cmdReady = true, rspValid = true) - - val invalidateMonitor = BmbInvalidateMonitor( - inputParameter = invalidateMonitorParameter, - pendingInvMax = 16 - ) - invalidateMonitor.io.input << exclusiveMonitor.io.output - - io.dMem << invalidateMonitor.io.output - - (io.iMems, cpus).zipped.foreach(_ << _.iBus) - - val debug = debugClockDomain on new Area{ - val arbiter = BmbDecoder( - p = io.debugBus.p, - mappings = List.tabulate(p.cpuConfigs.size)(i => SizeMapping(0x00000 + i*0x1000, 0x1000)), - capabilities = List.fill(p.cpuConfigs.size)(io.debugBus.p), - pendingMax = 2 - ) - arbiter.io.input << io.debugBus - (arbiter.io.outputs, cpus.map(_.debug)).zipped.foreach(_ >> _) - } -} - - - -object VexRiscvSmpClusterGen { - def vexRiscvConfig(hartId : Int, - ioRange : UInt => Bool = (x => x(31 downto 28) === 0xF), - resetVector : Long = 0x80000000l, - iBusWidth : Int = 128, - dBusWidth : Int = 64) = { - - val config = VexRiscvConfig( - plugins = List( - new MmuPlugin( - ioRange = ioRange - ), - //Uncomment the whole IBusCachedPlugin and comment IBusSimplePlugin if you want cached iBus config - new IBusCachedPlugin( - resetVector = resetVector, - compressedGen = false, - prediction = STATIC, - historyRamSizeLog2 = 9, - relaxPredictorAddress = true, - injectorStage = false, - relaxedPcCalculation = true, - config = InstructionCacheConfig( - cacheSize = 4096*2, - bytePerLine = 64, - wayCount = 2, - addressWidth = 32, - cpuDataWidth = 32, - memDataWidth = iBusWidth, - catchIllegalAccess = true, - catchAccessFault = true, - asyncTagMemory = false, - twoCycleRam = false, - twoCycleCache = true, - reducedBankWidth = true - ), - memoryTranslatorPortConfig = MmuPortConfig( - portTlbSize = 4, - latency = 1, - earlyRequireMmuLockup = true, - earlyCacheHits = true - ) - ), - new DBusCachedPlugin( - dBusCmdMasterPipe = dBusWidth == 32, - dBusCmdSlavePipe = true, - dBusRspSlavePipe = true, - relaxedMemoryTranslationRegister = true, - config = new DataCacheConfig( - cacheSize = 4096*2, - bytePerLine = 64, - wayCount = 2, - addressWidth = 32, - cpuDataWidth = 32, - memDataWidth = dBusWidth, - catchAccessError = true, - catchIllegal = true, - catchUnaligned = true, - withLrSc = true, - withAmo = true, - withExclusive = true, - withInvalidate = true, - aggregationWidth = if(dBusWidth == 32) 0 else log2Up(dBusWidth/8) - // ) - ), - memoryTranslatorPortConfig = MmuPortConfig( - portTlbSize = 4, - latency = 1, - earlyRequireMmuLockup = true, - earlyCacheHits = true - ) - ), - new DecoderSimplePlugin( - catchIllegalInstruction = true - ), - new RegFilePlugin( - regFileReadyKind = plugin.ASYNC, - zeroBoot = true, - x0Init = false - ), - new IntAluPlugin, - new SrcPlugin( - separatedAddSub = false - ), - new FullBarrelShifterPlugin(earlyInjection = false), - // new LightShifterPlugin, - new HazardSimplePlugin( - bypassExecute = true, - bypassMemory = true, - bypassWriteBack = true, - bypassWriteBackBuffer = true, - pessimisticUseSrc = false, - pessimisticWriteRegFile = false, - pessimisticAddressMatch = false - ), - new MulPlugin, - new MulDivIterativePlugin( - genMul = false, - genDiv = true, - mulUnrollFactor = 32, - divUnrollFactor = 1 - ), - new CsrPlugin(CsrPluginConfig.openSbi(mhartid = hartId, misa = Riscv.misaToInt("imas")).copy(utimeAccess = CsrAccess.READ_ONLY)), - new BranchPlugin( - earlyBranch = false, - catchAddressMisaligned = true, - fenceiGenAsAJump = false - ), - new YamlPlugin(s"cpu$hartId.yaml") - ) - ) - config - } - def vexRiscvCluster(cpuCount : Int, resetVector : Long = 0x80000000l) = VexRiscvSmpCluster( - debugClockDomain = ClockDomain.current.copy(reset = Bool().setName("debugResetIn")), - p = VexRiscvSmpClusterParameter( - cpuConfigs = List.tabulate(cpuCount) { - vexRiscvConfig(_, resetVector = resetVector) - } - ) - ) - def main(args: Array[String]): Unit = { - SpinalVerilog { - vexRiscvCluster(4) - } - } -} - - - -object VexRiscvSmpClusterTestInfrastructure{ - val REPORT_OFFSET = 0xF8000000 - val REPORT_THREAD_ID = 0x00 - val REPORT_THREAD_COUNT = 0x04 - val REPORT_END = 0x08 - val REPORT_BARRIER_START = 0x0C - val REPORT_BARRIER_END = 0x10 - val REPORT_CONSISTENCY_VALUES = 0x14 - - val PUTC = 0x00 - val GETC = 0x04 - val CLINT_ADDR = 0x10000 - val CLINT_IPI_ADDR = CLINT_ADDR+0x0000 - val CLINT_CMP_ADDR = CLINT_ADDR+0x4000 - val CLINT_TIME_ADDR = CLINT_ADDR+0xBFF8 - - def ram(dut : VexRiscvSmpCluster, withStall : Boolean) = { - import spinal.core.sim._ - val cpuCount = dut.cpus.size - val ram = new BmbMemoryAgent(0x100000000l){ - case class Report(hart : Int, code : Int, data : Int){ - override def toString: String = { - f"CPU:$hart%2d ${code}%3x -> $data%3d" - } - } - val reports = ArrayBuffer.fill(cpuCount)(ArrayBuffer[Report]()) - - - val writeTable = mutable.HashMap[Int, Int => Unit]() - val readTable = mutable.HashMap[Int, () => Int]() - def onWrite(address : Int)(body : Int => Unit) = writeTable(address) = body - def onRead(address : Int)(body : => Int) = readTable(address) = () => body - - var writeData = 0 - var readData = 0 - var reportWatchdog = 0 - val cpuEnd = Array.fill(cpuCount)(false) - val barriers = mutable.HashMap[Int, Int]() - var consistancyCounter = 0 - var consistancyLast = 0 - var consistancyA = 0 - var consistancyB = 0 - var consistancyAB = 0 - var consistancyNone = 0 - - onSimEnd{ - for((list, hart) <- reports.zipWithIndex){ - println(f"\n\n**** CPU $hart%2d ****") - for((report, reportId) <- list.zipWithIndex){ - println(f" $reportId%3d : ${report.code}%3x -> ${report.data}%3d") - } - } - - println(s"consistancy NONE:$consistancyNone A:$consistancyA B:$consistancyB AB:$consistancyAB") - } - - override def setByte(address: Long, value: Byte): Unit = { - if((address & 0xF0000000l) != 0xF0000000l) return super.setByte(address, value) - val byteId = address & 3 - val mask = 0xFF << (byteId*8) - writeData = (writeData & ~mask) | ((value.toInt << (byteId*8)) & mask) - if(byteId != 3) return - val offset = (address & ~0xF0000000l)-3 - // println(s"W[0x${offset.toHexString}] = $writeData @${simTime()}") - offset match { - case _ if offset >= 0x8000000 && offset < 0x9000000 => { - val report = Report( - hart = ((offset & 0xFF0000) >> 16).toInt, - code = (offset & 0x00FFFF).toInt, - data = writeData - ) -// println(report) - reports(report.hart) += report - reportWatchdog += 1 - import report._ - code match { - case REPORT_THREAD_ID => assert(data == hart) - case REPORT_THREAD_COUNT => assert(data == cpuCount) - case REPORT_END => assert(data == 0); assert(cpuEnd(hart) == false); cpuEnd(hart) = true; if(!cpuEnd.exists(_ == false)) simSuccess() - case REPORT_BARRIER_START => { - val counter = barriers.getOrElse(data, 0) - assert(counter < cpuCount) - barriers(data) = counter + 1 - } - case REPORT_BARRIER_END => { - val counter = barriers.getOrElse(data, 0) - assert(counter == cpuCount) - } - case REPORT_CONSISTENCY_VALUES => consistancyCounter match { - case 0 => { - consistancyCounter = 1 - consistancyLast = data - } - case 1 => { - consistancyCounter = 0 - (data, consistancyLast) match { - case (666, 0) => consistancyA += 1 - case (0, 666) => consistancyB += 1 - case (666, 666) => consistancyAB += 1 - case (0,0) => consistancyNone += 1; simFailure("Consistancy issue :(") - } - } - } - } - } - case _ => writeTable.get(offset.toInt) match { - case Some(x) => x(writeData) - case _ => simFailure(f"\n\nWrite at ${address-3}%8x with $writeData%8x") - } - } - } - - override def getByte(address: Long): Byte = { - if((address & 0xF0000000l) != 0xF0000000l) return super.getByte(address) - val byteId = address & 3 - val offset = (address & ~0xF0000000l) - if(byteId == 0) readData = readTable.get(offset.toInt) match { - case Some(x) => x() - case _ => simFailure(f"\n\nRead at $address%8x") - } - (readData >> (byteId*8)).toByte - } - - val clint = new { - val cmp = Array.fill(cpuCount)(0l) - var time = 0l - periodicaly(100){ - time += 10 - var timerInterrupts = 0l - for(i <- 0 until cpuCount){ - if(cmp(i) < time) timerInterrupts |= 1l << i - } - dut.io.timerInterrupts #= timerInterrupts - } - -// delayed(200*1000000){ -// dut.io.softwareInterrupts #= 0xE -// enableSimWave() -// println("force IPI") +//package vexriscv.demo.smp +// +//import spinal.core +//import spinal.core._ +//import spinal.core.sim.{onSimEnd, simSuccess} +//import spinal.lib._ +//import spinal.lib.bus.bmb.sim.BmbMemoryAgent +//import spinal.lib.bus.bmb.{Bmb, BmbArbiter, BmbDecoder, BmbExclusiveMonitor, BmbInvalidateMonitor, BmbParameter} +//import spinal.lib.bus.misc.SizeMapping +//import spinal.lib.com.jtag.{Jtag, JtagTapInstructionCtrl} +//import spinal.lib.com.jtag.sim.JtagTcp +//import spinal.lib.system.debugger.SystemDebuggerConfig +//import vexriscv.ip.{DataCacheAck, DataCacheConfig, DataCacheMemBus, InstructionCache, InstructionCacheConfig} +//import vexriscv.plugin.{BranchPlugin, CsrAccess, CsrPlugin, CsrPluginConfig, DBusCachedPlugin, DBusSimplePlugin, DYNAMIC_TARGET, DebugPlugin, DecoderSimplePlugin, FullBarrelShifterPlugin, HazardSimplePlugin, IBusCachedPlugin, IBusSimplePlugin, IntAluPlugin, MmuPlugin, MmuPortConfig, MulDivIterativePlugin, MulPlugin, RegFilePlugin, STATIC, SrcPlugin, YamlPlugin} +//import vexriscv.{Riscv, VexRiscv, VexRiscvConfig, plugin} +// +//import scala.collection.mutable +//import scala.collection.mutable.ArrayBuffer +// +// +//case class VexRiscvSmpClusterParameter( cpuConfigs : Seq[VexRiscvConfig]) +// +//case class VexRiscvSmpCluster(p : VexRiscvSmpClusterParameter, +// debugClockDomain : ClockDomain) extends Component{ +// val dBusParameter = p.cpuConfigs.head.plugins.find(_.isInstanceOf[DBusCachedPlugin]).get.asInstanceOf[DBusCachedPlugin].config.getBmbParameter() +// val dBusArbiterParameter = dBusParameter.copy(sourceWidth = log2Up(p.cpuConfigs.size)) +// val exclusiveMonitorParameter = dBusArbiterParameter +// val invalidateMonitorParameter = BmbExclusiveMonitor.outputParameter(exclusiveMonitorParameter) +// val dMemParameter = BmbInvalidateMonitor.outputParameter(invalidateMonitorParameter) +// +// val iBusParameter = p.cpuConfigs.head.plugins.find(_.isInstanceOf[IBusCachedPlugin]).get.asInstanceOf[IBusCachedPlugin].config.getBmbParameter() +// val iBusArbiterParameter = iBusParameter//.copy(sourceWidth = log2Up(p.cpuConfigs.size)) +// val iMemParameter = iBusArbiterParameter +// +// val io = new Bundle { +// val dMem = master(Bmb(dMemParameter)) +//// val iMem = master(Bmb(iMemParameter)) +// val iMems = Vec(master(Bmb(iMemParameter)), p.cpuConfigs.size) +// val timerInterrupts = in Bits(p.cpuConfigs.size bits) +// val externalInterrupts = in Bits(p.cpuConfigs.size bits) +// val softwareInterrupts = in Bits(p.cpuConfigs.size bits) +// val externalSupervisorInterrupts = in Bits(p.cpuConfigs.size bits) +// val debugBus = slave(Bmb(SystemDebuggerConfig().getBmbParameter.copy(addressWidth = 20))) +// val debugReset = out Bool() +// val time = in UInt(64 bits) +// } +// +// io.debugReset := False +// val cpus = for((cpuConfig, cpuId) <- p.cpuConfigs.zipWithIndex) yield new Area{ +// var iBus : Bmb = null +// var dBus : Bmb = null +// var debug : Bmb = null +// cpuConfig.plugins.foreach { +// case plugin: DebugPlugin => debugClockDomain{ +// plugin.debugClockDomain = debugClockDomain +// } +// case _ => +// } +// cpuConfig.plugins += new DebugPlugin(debugClockDomain) +// val core = new VexRiscv(cpuConfig) +// core.plugins.foreach { +// case plugin: IBusCachedPlugin => iBus = plugin.iBus.toBmb() +// case plugin: DBusCachedPlugin => dBus = plugin.dBus.toBmb().pipelined(cmdValid = true) +// case plugin: CsrPlugin => { +// plugin.softwareInterrupt := io.softwareInterrupts(cpuId) +// plugin.externalInterrupt := io.externalInterrupts(cpuId) +// plugin.timerInterrupt := io.timerInterrupts(cpuId) +// if (plugin.config.supervisorGen) plugin.externalInterruptS := io.externalSupervisorInterrupts(cpuId) +// if (plugin.utime != null) plugin.utime := io.time +// } +// case plugin: DebugPlugin => debugClockDomain{ +// io.debugReset setWhen(RegNext(plugin.io.resetOut)) +// debug = plugin.io.bus.fromBmb() +// } +// case _ => +// } +// } +// +// val dBusArbiter = BmbArbiter( +// p = dBusArbiterParameter, +// portCount = cpus.size, +// lowerFirstPriority = false, +// inputsWithInv = cpus.map(_ => true), +// inputsWithSync = cpus.map(_ => true), +// pendingInvMax = 16 +// ) +// +// (dBusArbiter.io.inputs, cpus).zipped.foreach(_ << _.dBus.pipelined(invValid = true, ackValid = true, syncValid = true)) +// +// val exclusiveMonitor = BmbExclusiveMonitor( +// inputParameter = exclusiveMonitorParameter, +// pendingWriteMax = 64 +// ) +// exclusiveMonitor.io.input << dBusArbiter.io.output.pipelined(cmdValid = true, cmdReady = true, rspValid = true) +// +// val invalidateMonitor = BmbInvalidateMonitor( +// inputParameter = invalidateMonitorParameter, +// pendingInvMax = 16 +// ) +// invalidateMonitor.io.input << exclusiveMonitor.io.output +// +// io.dMem << invalidateMonitor.io.output +// +// (io.iMems, cpus).zipped.foreach(_ << _.iBus) +// +// val debug = debugClockDomain on new Area{ +// val arbiter = BmbDecoder( +// p = io.debugBus.p, +// mappings = List.tabulate(p.cpuConfigs.size)(i => SizeMapping(0x00000 + i*0x1000, 0x1000)), +// capabilities = List.fill(p.cpuConfigs.size)(io.debugBus.p), +// pendingMax = 2 +// ) +// arbiter.io.input << io.debugBus +// (arbiter.io.outputs, cpus.map(_.debug)).zipped.foreach(_ >> _) +// } +//} +// +// +// +//object VexRiscvSmpClusterGen { +// def vexRiscvConfig(hartId : Int, +// ioRange : UInt => Bool = (x => x(31 downto 28) === 0xF), +// resetVector : Long = 0x80000000l, +// iBusWidth : Int = 128, +// dBusWidth : Int = 64) = { +// +// val config = VexRiscvConfig( +// plugins = List( +// new MmuPlugin( +// ioRange = ioRange +// ), +// //Uncomment the whole IBusCachedPlugin and comment IBusSimplePlugin if you want cached iBus config +// new IBusCachedPlugin( +// resetVector = resetVector, +// compressedGen = false, +// prediction = STATIC, +// historyRamSizeLog2 = 9, +// relaxPredictorAddress = true, +// injectorStage = false, +// relaxedPcCalculation = true, +// config = InstructionCacheConfig( +// cacheSize = 4096*2, +// bytePerLine = 64, +// wayCount = 2, +// addressWidth = 32, +// cpuDataWidth = 32, +// memDataWidth = iBusWidth, +// catchIllegalAccess = true, +// catchAccessFault = true, +// asyncTagMemory = false, +// twoCycleRam = false, +// twoCycleCache = true, +// reducedBankWidth = true +// ), +// memoryTranslatorPortConfig = MmuPortConfig( +// portTlbSize = 4, +// latency = 1, +// earlyRequireMmuLockup = true, +// earlyCacheHits = true +// ) +// ), +// new DBusCachedPlugin( +// dBusCmdMasterPipe = dBusWidth == 32, +// dBusCmdSlavePipe = true, +// dBusRspSlavePipe = true, +// relaxedMemoryTranslationRegister = true, +// config = new DataCacheConfig( +// cacheSize = 4096*2, +// bytePerLine = 64, +// wayCount = 2, +// addressWidth = 32, +// cpuDataWidth = 32, +// memDataWidth = dBusWidth, +// catchAccessError = true, +// catchIllegal = true, +// catchUnaligned = true, +// withLrSc = true, +// withAmo = true, +// withExclusive = true, +// withInvalidate = true, +// aggregationWidth = if(dBusWidth == 32) 0 else log2Up(dBusWidth/8) +// // ) +// ), +// memoryTranslatorPortConfig = MmuPortConfig( +// portTlbSize = 4, +// latency = 1, +// earlyRequireMmuLockup = true, +// earlyCacheHits = true +// ) +// ), +// new DecoderSimplePlugin( +// catchIllegalInstruction = true +// ), +// new RegFilePlugin( +// regFileReadyKind = plugin.ASYNC, +// zeroBoot = true, +// x0Init = false +// ), +// new IntAluPlugin, +// new SrcPlugin( +// separatedAddSub = false +// ), +// new FullBarrelShifterPlugin(earlyInjection = false), +// // new LightShifterPlugin, +// new HazardSimplePlugin( +// bypassExecute = true, +// bypassMemory = true, +// bypassWriteBack = true, +// bypassWriteBackBuffer = true, +// pessimisticUseSrc = false, +// pessimisticWriteRegFile = false, +// pessimisticAddressMatch = false +// ), +// new MulPlugin, +// new MulDivIterativePlugin( +// genMul = false, +// genDiv = true, +// mulUnrollFactor = 32, +// divUnrollFactor = 1 +// ), +// new CsrPlugin(CsrPluginConfig.openSbi(mhartid = hartId, misa = Riscv.misaToInt("imas")).copy(utimeAccess = CsrAccess.READ_ONLY)), +// new BranchPlugin( +// earlyBranch = false, +// catchAddressMisaligned = true, +// fenceiGenAsAJump = false +// ), +// new YamlPlugin(s"cpu$hartId.yaml") +// ) +// ) +// config +// } +// def vexRiscvCluster(cpuCount : Int, resetVector : Long = 0x80000000l) = VexRiscvSmpCluster( +// debugClockDomain = ClockDomain.current.copy(reset = Bool().setName("debugResetIn")), +// p = VexRiscvSmpClusterParameter( +// cpuConfigs = List.tabulate(cpuCount) { +// vexRiscvConfig(_, resetVector = resetVector) +// } +// ) +// ) +// def main(args: Array[String]): Unit = { +// SpinalVerilog { +// vexRiscvCluster(4) +// } +// } +//} +// +// +// +//object VexRiscvSmpClusterTestInfrastructure{ +// val REPORT_OFFSET = 0xF8000000 +// val REPORT_THREAD_ID = 0x00 +// val REPORT_THREAD_COUNT = 0x04 +// val REPORT_END = 0x08 +// val REPORT_BARRIER_START = 0x0C +// val REPORT_BARRIER_END = 0x10 +// val REPORT_CONSISTENCY_VALUES = 0x14 +// +// val PUTC = 0x00 +// val GETC = 0x04 +// val CLINT_ADDR = 0x10000 +// val CLINT_IPI_ADDR = CLINT_ADDR+0x0000 +// val CLINT_CMP_ADDR = CLINT_ADDR+0x4000 +// val CLINT_TIME_ADDR = CLINT_ADDR+0xBFF8 +// +// def ram(dut : VexRiscvSmpCluster, withStall : Boolean) = { +// import spinal.core.sim._ +// val cpuCount = dut.cpus.size +// val ram = new BmbMemoryAgent(0x100000000l){ +// case class Report(hart : Int, code : Int, data : Int){ +// override def toString: String = { +// f"CPU:$hart%2d ${code}%3x -> $data%3d" // } - } - - onWrite(PUTC)(data => print(data.toChar)) - onRead(GETC)( if(System.in.available() != 0) System.in.read() else -1) - - dut.io.softwareInterrupts #= 0 - dut.io.timerInterrupts #= 0 - dut.io.externalInterrupts #= 0 - dut.io.externalSupervisorInterrupts #= 0 - onRead(CLINT_TIME_ADDR)(clint.time.toInt) - onRead(CLINT_TIME_ADDR+4)((clint.time >> 32).toInt) - for(hartId <- 0 until cpuCount){ - onWrite(CLINT_IPI_ADDR + hartId*4) {data => - val mask = 1l << hartId - val value = (dut.io.softwareInterrupts.toLong & ~mask) | (if(data == 1) mask else 0) - dut.io.softwareInterrupts #= value - } -// onRead(CLINT_CMP_ADDR + hartId*8)(clint.cmp(hartId).toInt) -// onRead(CLINT_CMP_ADDR + hartId*8+4)((clint.cmp(hartId) >> 32).toInt) - onWrite(CLINT_CMP_ADDR + hartId*8){data => clint.cmp(hartId) = (clint.cmp(hartId) & 0xFFFFFFFF00000000l) | data} - onWrite(CLINT_CMP_ADDR + hartId*8+4){data => clint.cmp(hartId) = (clint.cmp(hartId) & 0x00000000FFFFFFFFl) | (data.toLong << 32)} - } - - - - } - dut.io.iMems.foreach(ram.addPort(_,0,dut.clockDomain,true, withStall)) - ram.addPort(dut.io.dMem,0,dut.clockDomain,true, withStall) - ram - } - def init(dut : VexRiscvSmpCluster): Unit ={ - import spinal.core.sim._ - dut.clockDomain.forkStimulus(10) - dut.debugClockDomain.forkStimulus(10) - dut.io.debugBus.cmd.valid #= false - } -} - -object VexRiscvSmpClusterTest extends App{ - import spinal.core.sim._ - - val simConfig = SimConfig - simConfig.withWave - simConfig.allOptimisation - simConfig.addSimulatorFlag("--threads 1") - - val cpuCount = 4 - val withStall = true - - simConfig.compile(VexRiscvSmpClusterGen.vexRiscvCluster(cpuCount)).doSimUntilVoid(seed = 42){dut => - disableSimWave() - SimTimeout(100000000l*10*cpuCount) - dut.clockDomain.forkSimSpeedPrinter(1.0) - VexRiscvSmpClusterTestInfrastructure.init(dut) - val ram = VexRiscvSmpClusterTestInfrastructure.ram(dut, withStall) - ram.memory.loadBin(0x80000000l, "src/test/cpp/raw/smp/build/smp.bin") - periodicaly(20000*10){ - assert(ram.reportWatchdog != 0) - ram.reportWatchdog = 0 - } - } -} - -// echo "echo 10000 | dhrystone >> log" > test -// time sh test & -// top -b -n 1 - -// TODO -// MultiChannelFifo.toStream arbitration -// BmbDecoderOutOfOrder arbitration -// DataCache to bmb invalidation that are more than single line -object VexRiscvSmpClusterOpenSbi extends App{ - import spinal.core.sim._ - - val simConfig = SimConfig - simConfig.withWave - simConfig.allOptimisation - simConfig.addSimulatorFlag("--threads 1") - - val cpuCount = 2 - val withStall = false - - def gen = { - val dut = VexRiscvSmpClusterGen.vexRiscvCluster(cpuCount, resetVector = 0x80000000l) - dut.cpus.foreach{cpu => - cpu.core.children.foreach{ - case cache : InstructionCache => cache.io.cpu.decode.simPublic() - case _ => - } - } - dut - } - - simConfig.workspaceName("rawr_4c").compile(gen).doSimUntilVoid(seed = 42){dut => +// } +// val reports = ArrayBuffer.fill(cpuCount)(ArrayBuffer[Report]()) +// +// +// val writeTable = mutable.HashMap[Int, Int => Unit]() +// val readTable = mutable.HashMap[Int, () => Int]() +// def onWrite(address : Int)(body : Int => Unit) = writeTable(address) = body +// def onRead(address : Int)(body : => Int) = readTable(address) = () => body +// +// var writeData = 0 +// var readData = 0 +// var reportWatchdog = 0 +// val cpuEnd = Array.fill(cpuCount)(false) +// val barriers = mutable.HashMap[Int, Int]() +// var consistancyCounter = 0 +// var consistancyLast = 0 +// var consistancyA = 0 +// var consistancyB = 0 +// var consistancyAB = 0 +// var consistancyNone = 0 +// +// onSimEnd{ +// for((list, hart) <- reports.zipWithIndex){ +// println(f"\n\n**** CPU $hart%2d ****") +// for((report, reportId) <- list.zipWithIndex){ +// println(f" $reportId%3d : ${report.code}%3x -> ${report.data}%3d") +// } +// } +// +// println(s"consistancy NONE:$consistancyNone A:$consistancyA B:$consistancyB AB:$consistancyAB") +// } +// +// override def setByte(address: Long, value: Byte): Unit = { +// if((address & 0xF0000000l) != 0xF0000000l) return super.setByte(address, value) +// val byteId = address & 3 +// val mask = 0xFF << (byteId*8) +// writeData = (writeData & ~mask) | ((value.toInt << (byteId*8)) & mask) +// if(byteId != 3) return +// val offset = (address & ~0xF0000000l)-3 +// // println(s"W[0x${offset.toHexString}] = $writeData @${simTime()}") +// offset match { +// case _ if offset >= 0x8000000 && offset < 0x9000000 => { +// val report = Report( +// hart = ((offset & 0xFF0000) >> 16).toInt, +// code = (offset & 0x00FFFF).toInt, +// data = writeData +// ) +//// println(report) +// reports(report.hart) += report +// reportWatchdog += 1 +// import report._ +// code match { +// case REPORT_THREAD_ID => assert(data == hart) +// case REPORT_THREAD_COUNT => assert(data == cpuCount) +// case REPORT_END => assert(data == 0); assert(cpuEnd(hart) == false); cpuEnd(hart) = true; if(!cpuEnd.exists(_ == false)) simSuccess() +// case REPORT_BARRIER_START => { +// val counter = barriers.getOrElse(data, 0) +// assert(counter < cpuCount) +// barriers(data) = counter + 1 +// } +// case REPORT_BARRIER_END => { +// val counter = barriers.getOrElse(data, 0) +// assert(counter == cpuCount) +// } +// case REPORT_CONSISTENCY_VALUES => consistancyCounter match { +// case 0 => { +// consistancyCounter = 1 +// consistancyLast = data +// } +// case 1 => { +// consistancyCounter = 0 +// (data, consistancyLast) match { +// case (666, 0) => consistancyA += 1 +// case (0, 666) => consistancyB += 1 +// case (666, 666) => consistancyAB += 1 +// case (0,0) => consistancyNone += 1; simFailure("Consistancy issue :(") +// } +// } +// } +// } +// } +// case _ => writeTable.get(offset.toInt) match { +// case Some(x) => x(writeData) +// case _ => simFailure(f"\n\nWrite at ${address-3}%8x with $writeData%8x") +// } +// } +// } +// +// override def getByte(address: Long): Byte = { +// if((address & 0xF0000000l) != 0xF0000000l) return super.getByte(address) +// val byteId = address & 3 +// val offset = (address & ~0xF0000000l) +// if(byteId == 0) readData = readTable.get(offset.toInt) match { +// case Some(x) => x() +// case _ => simFailure(f"\n\nRead at $address%8x") +// } +// (readData >> (byteId*8)).toByte +// } +// +// val clint = new { +// val cmp = Array.fill(cpuCount)(0l) +// var time = 0l +// periodicaly(100){ +// time += 10 +// var timerInterrupts = 0l +// for(i <- 0 until cpuCount){ +// if(cmp(i) < time) timerInterrupts |= 1l << i +// } +// dut.io.timerInterrupts #= timerInterrupts +// } +// +//// delayed(200*1000000){ +//// dut.io.softwareInterrupts #= 0xE +//// enableSimWave() +//// println("force IPI") +//// } +// } +// +// onWrite(PUTC)(data => print(data.toChar)) +// onRead(GETC)( if(System.in.available() != 0) System.in.read() else -1) +// +// dut.io.softwareInterrupts #= 0 +// dut.io.timerInterrupts #= 0 +// dut.io.externalInterrupts #= 0 +// dut.io.externalSupervisorInterrupts #= 0 +// onRead(CLINT_TIME_ADDR)(clint.time.toInt) +// onRead(CLINT_TIME_ADDR+4)((clint.time >> 32).toInt) +// for(hartId <- 0 until cpuCount){ +// onWrite(CLINT_IPI_ADDR + hartId*4) {data => +// val mask = 1l << hartId +// val value = (dut.io.softwareInterrupts.toLong & ~mask) | (if(data == 1) mask else 0) +// dut.io.softwareInterrupts #= value +// } +//// onRead(CLINT_CMP_ADDR + hartId*8)(clint.cmp(hartId).toInt) +//// onRead(CLINT_CMP_ADDR + hartId*8+4)((clint.cmp(hartId) >> 32).toInt) +// onWrite(CLINT_CMP_ADDR + hartId*8){data => clint.cmp(hartId) = (clint.cmp(hartId) & 0xFFFFFFFF00000000l) | data} +// onWrite(CLINT_CMP_ADDR + hartId*8+4){data => clint.cmp(hartId) = (clint.cmp(hartId) & 0x00000000FFFFFFFFl) | (data.toLong << 32)} +// } +// +// +// +// } +// dut.io.iMems.foreach(ram.addPort(_,0,dut.clockDomain,true, withStall)) +// ram.addPort(dut.io.dMem,0,dut.clockDomain,true, withStall) +// ram +// } +// def init(dut : VexRiscvSmpCluster): Unit ={ +// import spinal.core.sim._ +// dut.clockDomain.forkStimulus(10) +// dut.debugClockDomain.forkStimulus(10) +// dut.io.debugBus.cmd.valid #= false +// } +//} +// +//object VexRiscvSmpClusterTest extends App{ +// import spinal.core.sim._ +// +// val simConfig = SimConfig +// simConfig.withWave +// simConfig.allOptimisation +// simConfig.addSimulatorFlag("--threads 1") +// +// val cpuCount = 4 +// val withStall = true +// +// simConfig.compile(VexRiscvSmpClusterGen.vexRiscvCluster(cpuCount)).doSimUntilVoid(seed = 42){dut => +// disableSimWave() +// SimTimeout(100000000l*10*cpuCount) // dut.clockDomain.forkSimSpeedPrinter(1.0) - VexRiscvSmpClusterTestInfrastructure.init(dut) - val ram = VexRiscvSmpClusterTestInfrastructure.ram(dut, withStall) -// ram.memory.loadBin(0x80000000l, "../opensbi/build/platform/spinal/vexriscv/sim/smp/firmware/fw_payload.bin") - -// ram.memory.loadBin(0x40F00000l, "/media/data/open/litex_smp/litex_vexriscv_smp/images/fw_jump.bin") -// ram.memory.loadBin(0x40000000l, "/media/data/open/litex_smp/litex_vexriscv_smp/images/Image") -// ram.memory.loadBin(0x40EF0000l, "/media/data/open/litex_smp/litex_vexriscv_smp/images/dtb") -// ram.memory.loadBin(0x41000000l, "/media/data/open/litex_smp/litex_vexriscv_smp/images/rootfs.cpio") - - ram.memory.loadBin(0x80000000l, "../opensbi/build/platform/spinal/vexriscv/sim/smp/firmware/fw_jump.bin") - ram.memory.loadBin(0xC0000000l, "../buildroot/output/images/Image") - ram.memory.loadBin(0xC1000000l, "../buildroot/output/images/dtb") - ram.memory.loadBin(0xC2000000l, "../buildroot/output/images/rootfs.cpio") - - import spinal.core.sim._ - var iMemReadBytes, dMemReadBytes, dMemWriteBytes, iMemSequencial,iMemRequests, iMemPrefetchHit = 0l - var reportTimer = 0 - var reportCycle = 0 - val iMemFetchDelta = mutable.HashMap[Long, Long]() - var iMemFetchDeltaSorted : Seq[(Long, Long)] = null - var dMemWrites, dMemWritesCached = 0l - val dMemWriteCacheCtx = List(4,8,16,32,64).map(bytes => new { - var counter = 0l - var address = 0l - val mask = ~((1 << log2Up(bytes))-1) - }) - - import java.io._ - val csv = new PrintWriter(new File("bench.csv" )) - val iMemCtx = Array.tabulate(cpuCount)(i => new { - var sequencialPrediction = 0l - val cache = dut.cpus(i).core.children.find(_.isInstanceOf[InstructionCache]).head.asInstanceOf[InstructionCache].io.cpu.decode - var lastAddress = 0l - }) - dut.clockDomain.onSamplings{ - dut.io.time #= simTime()/10 - - - for(i <- 0 until cpuCount; iMem = dut.io.iMems(i); ctx = iMemCtx(i)){ -// if(iMem.cmd.valid.toBoolean && iMem.cmd.ready.toBoolean){ -// val length = iMem.cmd.length.toInt + 1 -// val address = iMem.cmd.address.toLong -// iMemReadBytes += length -// iMemRequests += 1 +// VexRiscvSmpClusterTestInfrastructure.init(dut) +// val ram = VexRiscvSmpClusterTestInfrastructure.ram(dut, withStall) +// ram.memory.loadBin(0x80000000l, "src/test/cpp/raw/smp/build/smp.bin") +// periodicaly(20000*10){ +// assert(ram.reportWatchdog != 0) +// ram.reportWatchdog = 0 +// } +// } +//} +// +//// echo "echo 10000 | dhrystone >> log" > test +//// time sh test & +//// top -b -n 1 +// +//// TODO +//// MultiChannelFifo.toStream arbitration +//// BmbDecoderOutOfOrder arbitration +//// DataCache to bmb invalidation that are more than single line +//object VexRiscvSmpClusterOpenSbi extends App{ +// import spinal.core.sim._ +// +// val simConfig = SimConfig +// simConfig.withWave +// simConfig.allOptimisation +// simConfig.addSimulatorFlag("--threads 1") +// +// val cpuCount = 2 +// val withStall = false +// +// def gen = { +// val dut = VexRiscvSmpClusterGen.vexRiscvCluster(cpuCount, resetVector = 0x80000000l) +// dut.cpus.foreach{cpu => +// cpu.core.children.foreach{ +// case cache : InstructionCache => cache.io.cpu.decode.simPublic() +// case _ => +// } +// } +// dut +// } +// +// simConfig.workspaceName("rawr_4c").compile(gen).doSimUntilVoid(seed = 42){dut => +//// dut.clockDomain.forkSimSpeedPrinter(1.0) +// VexRiscvSmpClusterTestInfrastructure.init(dut) +// val ram = VexRiscvSmpClusterTestInfrastructure.ram(dut, withStall) +//// ram.memory.loadBin(0x80000000l, "../opensbi/build/platform/spinal/vexriscv/sim/smp/firmware/fw_payload.bin") +// +//// ram.memory.loadBin(0x40F00000l, "/media/data/open/litex_smp/litex_vexriscv_smp/images/fw_jump.bin") +//// ram.memory.loadBin(0x40000000l, "/media/data/open/litex_smp/litex_vexriscv_smp/images/Image") +//// ram.memory.loadBin(0x40EF0000l, "/media/data/open/litex_smp/litex_vexriscv_smp/images/dtb") +//// ram.memory.loadBin(0x41000000l, "/media/data/open/litex_smp/litex_vexriscv_smp/images/rootfs.cpio") +// +// ram.memory.loadBin(0x80000000l, "../opensbi/build/platform/spinal/vexriscv/sim/smp/firmware/fw_jump.bin") +// ram.memory.loadBin(0xC0000000l, "../buildroot/output/images/Image") +// ram.memory.loadBin(0xC1000000l, "../buildroot/output/images/dtb") +// ram.memory.loadBin(0xC2000000l, "../buildroot/output/images/rootfs.cpio") +// +// import spinal.core.sim._ +// var iMemReadBytes, dMemReadBytes, dMemWriteBytes, iMemSequencial,iMemRequests, iMemPrefetchHit = 0l +// var reportTimer = 0 +// var reportCycle = 0 +// val iMemFetchDelta = mutable.HashMap[Long, Long]() +// var iMemFetchDeltaSorted : Seq[(Long, Long)] = null +// var dMemWrites, dMemWritesCached = 0l +// val dMemWriteCacheCtx = List(4,8,16,32,64).map(bytes => new { +// var counter = 0l +// var address = 0l +// val mask = ~((1 << log2Up(bytes))-1) +// }) +// +// import java.io._ +// val csv = new PrintWriter(new File("bench.csv" )) +// val iMemCtx = Array.tabulate(cpuCount)(i => new { +// var sequencialPrediction = 0l +// val cache = dut.cpus(i).core.children.find(_.isInstanceOf[InstructionCache]).head.asInstanceOf[InstructionCache].io.cpu.decode +// var lastAddress = 0l +// }) +// dut.clockDomain.onSamplings{ +// dut.io.time #= simTime()/10 +// +// +// for(i <- 0 until cpuCount; iMem = dut.io.iMems(i); ctx = iMemCtx(i)){ +//// if(iMem.cmd.valid.toBoolean && iMem.cmd.ready.toBoolean){ +//// val length = iMem.cmd.length.toInt + 1 +//// val address = iMem.cmd.address.toLong +//// iMemReadBytes += length +//// iMemRequests += 1 +//// } +// if(ctx.cache.isValid.toBoolean && !ctx.cache.mmuRefilling.toBoolean && !ctx.cache.mmuException.toBoolean){ +// val address = ctx.cache.physicalAddress.toLong +// val length = ctx.cache.p.bytePerLine.toLong +// val mask = ~(length-1) +// if(ctx.cache.cacheMiss.toBoolean) { +// iMemReadBytes += length +// if ((address & mask) == (ctx.sequencialPrediction & mask)) { +// iMemSequencial += 1 +// } +// } +// if(!ctx.cache.isStuck.toBoolean) { +// ctx.sequencialPrediction = address + length +// } // } - if(ctx.cache.isValid.toBoolean && !ctx.cache.mmuRefilling.toBoolean && !ctx.cache.mmuException.toBoolean){ - val address = ctx.cache.physicalAddress.toLong - val length = ctx.cache.p.bytePerLine.toLong - val mask = ~(length-1) - if(ctx.cache.cacheMiss.toBoolean) { - iMemReadBytes += length - if ((address & mask) == (ctx.sequencialPrediction & mask)) { - iMemSequencial += 1 - } - } - if(!ctx.cache.isStuck.toBoolean) { - ctx.sequencialPrediction = address + length - } - } - - if(iMem.cmd.valid.toBoolean && iMem.cmd.ready.toBoolean){ - val address = iMem.cmd.address.toLong - iMemRequests += 1 - if(iMemCtx(i).lastAddress + ctx.cache.p.bytePerLine == address){ - iMemPrefetchHit += 1 - } - val delta = address-iMemCtx(i).lastAddress - iMemFetchDelta(delta) = iMemFetchDelta.getOrElse(delta, 0l) + 1l - if(iMemRequests % 1000 == 999) iMemFetchDeltaSorted = iMemFetchDelta.toSeq.sortBy(_._1) - iMemCtx(i).lastAddress = address - } - } - if(dut.io.dMem.cmd.valid.toBoolean && dut.io.dMem.cmd.ready.toBoolean){ - if(dut.io.dMem.cmd.opcode.toInt == Bmb.Cmd.Opcode.WRITE){ - dMemWriteBytes += dut.io.dMem.cmd.length.toInt+1 - val address = dut.io.dMem.cmd.address.toLong - dMemWrites += 1 - for(ctx <- dMemWriteCacheCtx){ - if((address & ctx.mask) == (ctx.address & ctx.mask)){ - ctx.counter += 1 - } else { - ctx.address = address - } - } - }else { - dMemReadBytes += dut.io.dMem.cmd.length.toInt+1 - for(ctx <- dMemWriteCacheCtx) ctx.address = -1 - } - } - reportTimer = reportTimer + 1 - reportCycle = reportCycle + 1 - if(reportTimer == 400000){ - reportTimer = 0 -// println(f"\n** c=${reportCycle} ir=${iMemReadBytes*1e-6}%5.2f dr=${dMemReadBytes*1e-6}%5.2f dw=${dMemWriteBytes*1e-6}%5.2f **\n") - - - csv.write(s"$reportCycle,$iMemReadBytes,$dMemReadBytes,$dMemWriteBytes,$iMemRequests,$iMemSequencial,$dMemWrites,${dMemWriteCacheCtx.map(_.counter).mkString(",")},$iMemPrefetchHit\n") - csv.flush() - reportCycle = 0 - iMemReadBytes = 0 - dMemReadBytes = 0 - dMemWriteBytes = 0 - iMemRequests = 0 - iMemSequencial = 0 - dMemWrites = 0 - iMemPrefetchHit = 0 - for(ctx <- dMemWriteCacheCtx) ctx.counter = 0 - } - } - - +// +// if(iMem.cmd.valid.toBoolean && iMem.cmd.ready.toBoolean){ +// val address = iMem.cmd.address.toLong +// iMemRequests += 1 +// if(iMemCtx(i).lastAddress + ctx.cache.p.bytePerLine == address){ +// iMemPrefetchHit += 1 +// } +// val delta = address-iMemCtx(i).lastAddress +// iMemFetchDelta(delta) = iMemFetchDelta.getOrElse(delta, 0l) + 1l +// if(iMemRequests % 1000 == 999) iMemFetchDeltaSorted = iMemFetchDelta.toSeq.sortBy(_._1) +// iMemCtx(i).lastAddress = address +// } +// } +// if(dut.io.dMem.cmd.valid.toBoolean && dut.io.dMem.cmd.ready.toBoolean){ +// if(dut.io.dMem.cmd.opcode.toInt == Bmb.Cmd.Opcode.WRITE){ +// dMemWriteBytes += dut.io.dMem.cmd.length.toInt+1 +// val address = dut.io.dMem.cmd.address.toLong +// dMemWrites += 1 +// for(ctx <- dMemWriteCacheCtx){ +// if((address & ctx.mask) == (ctx.address & ctx.mask)){ +// ctx.counter += 1 +// } else { +// ctx.address = address +// } +// } +// }else { +// dMemReadBytes += dut.io.dMem.cmd.length.toInt+1 +// for(ctx <- dMemWriteCacheCtx) ctx.address = -1 +// } +// } +// reportTimer = reportTimer + 1 +// reportCycle = reportCycle + 1 +// if(reportTimer == 400000){ +// reportTimer = 0 +//// println(f"\n** c=${reportCycle} ir=${iMemReadBytes*1e-6}%5.2f dr=${dMemReadBytes*1e-6}%5.2f dw=${dMemWriteBytes*1e-6}%5.2f **\n") +// +// +// csv.write(s"$reportCycle,$iMemReadBytes,$dMemReadBytes,$dMemWriteBytes,$iMemRequests,$iMemSequencial,$dMemWrites,${dMemWriteCacheCtx.map(_.counter).mkString(",")},$iMemPrefetchHit\n") +// csv.flush() +// reportCycle = 0 +// iMemReadBytes = 0 +// dMemReadBytes = 0 +// dMemWriteBytes = 0 +// iMemRequests = 0 +// iMemSequencial = 0 +// dMemWrites = 0 +// iMemPrefetchHit = 0 +// for(ctx <- dMemWriteCacheCtx) ctx.counter = 0 +// } +// } +// +// +//// fork{ +//// disableSimWave() +//// val atMs = 3790 +//// val durationMs = 5 +//// sleep(atMs*1000000) +//// enableSimWave() +//// println("** enableSimWave **") +//// sleep(durationMs*1000000) +//// println("** disableSimWave **") +//// while(true) { +//// disableSimWave() +//// sleep(100000 * 10) +//// enableSimWave() +//// sleep( 100 * 10) +//// } +////// simSuccess() +//// } +// // fork{ -// disableSimWave() -// val atMs = 3790 -// val durationMs = 5 -// sleep(atMs*1000000) -// enableSimWave() -// println("** enableSimWave **") -// sleep(durationMs*1000000) -// println("** disableSimWave **") // while(true) { // disableSimWave() // sleep(100000 * 10) // enableSimWave() // sleep( 100 * 10) // } -//// simSuccess() // } - - fork{ - while(true) { - disableSimWave() - sleep(100000 * 10) - enableSimWave() - sleep( 100 * 10) - } - } - } -} \ No newline at end of file +// } +//} \ No newline at end of file diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala index 43ae2426..44beab72 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala @@ -1,305 +1,305 @@ -package vexriscv.demo.smp - -import spinal.core._ -import spinal.lib.bus.bmb._ -import spinal.lib.bus.wishbone.{Wishbone, WishboneConfig, WishboneSlaveFactory} -import spinal.lib.com.jtag.{Jtag, JtagTapInstructionCtrl} -import spinal.lib._ -import spinal.lib.bus.bmb.sim.{BmbMemoryMultiPort, BmbMemoryTester} -import spinal.lib.bus.misc.{AddressMapping, DefaultMapping, SizeMapping} -import spinal.lib.eda.bench.Bench -import spinal.lib.misc.Clint -import spinal.lib.misc.plic.{PlicGatewayActiveHigh, PlicMapper, PlicMapping, PlicTarget} -import spinal.lib.sim.{SimData, SparseMemory, StreamDriver, StreamMonitor, StreamReadyRandomizer} -import spinal.lib.system.debugger.{JtagBridgeNoTap, SystemDebugger, SystemDebuggerConfig} -import vexriscv.demo.smp.VexRiscvLitexSmpClusterOpenSbi.{cpuCount, parameter} -import vexriscv.demo.smp.VexRiscvSmpClusterGen.vexRiscvConfig -import vexriscv.{VexRiscv, VexRiscvConfig} -import vexriscv.plugin.{CsrPlugin, DBusCachedPlugin, DebugPlugin, IBusCachedPlugin} - -import scala.collection.mutable -import scala.util.Random - - -case class VexRiscvLitexSmpClusterParameter( cluster : VexRiscvSmpClusterParameter, - liteDram : LiteDramNativeParameter, - liteDramMapping : AddressMapping) - -//addAttribute("""mark_debug = "true"""") -case class VexRiscvLitexSmpCluster(p : VexRiscvLitexSmpClusterParameter, - debugClockDomain : ClockDomain, - jtagClockDomain : ClockDomain) extends Component{ - - val peripheralWishboneConfig = WishboneConfig( - addressWidth = 30, - dataWidth = 32, - selWidth = 4, - useERR = true, - useBTE = true, - useCTI = true - ) - - val io = new Bundle { - val dMem = master(LiteDramNative(p.liteDram)) - val iMem = master(LiteDramNative(p.liteDram)) - val peripheral = master(Wishbone(peripheralWishboneConfig)) - val clint = slave(Wishbone(Clint.getWisboneConfig())) - val plic = slave(Wishbone(WishboneConfig(addressWidth = 20, dataWidth = 32))) - val interrupts = in Bits(32 bits) - val jtagInstruction = slave(JtagTapInstructionCtrl()) - val debugReset = out Bool() - } - val cpuCount = p.cluster.cpuConfigs.size - val clint = Clint(cpuCount) - clint.driveFrom(WishboneSlaveFactory(io.clint)) - - val cluster = VexRiscvSmpCluster(p.cluster, debugClockDomain) - cluster.io.debugReset <> io.debugReset - cluster.io.timerInterrupts <> B(clint.harts.map(_.timerInterrupt)) - cluster.io.softwareInterrupts <> B(clint.harts.map(_.softwareInterrupt)) - cluster.io.time := clint.time - - val debug = debugClockDomain on new Area{ - val jtagConfig = SystemDebuggerConfig() - val jtagBridge = new JtagBridgeNoTap( - c = jtagConfig, - jtagClockDomain = jtagClockDomain - ) - jtagBridge.io.ctrl << io.jtagInstruction - - val debugger = new SystemDebugger(jtagConfig) - debugger.io.remote <> jtagBridge.io.remote - - cluster.io.debugBus << debugger.io.mem.toBmb() - } - - val dBusDecoder = BmbDecoderOutOfOrder( - p = cluster.io.dMem.p, - mappings = Seq(DefaultMapping, p.liteDramMapping), - capabilities = Seq(cluster.io.dMem.p, cluster.io.dMem.p), - pendingRspTransactionMax = 32 - ) -// val dBusDecoder = BmbDecoderOut( +//package vexriscv.demo.smp +// +//import spinal.core._ +//import spinal.lib.bus.bmb._ +//import spinal.lib.bus.wishbone.{Wishbone, WishboneConfig, WishboneSlaveFactory} +//import spinal.lib.com.jtag.{Jtag, JtagTapInstructionCtrl} +//import spinal.lib._ +//import spinal.lib.bus.bmb.sim.{BmbMemoryMultiPort, BmbMemoryTester} +//import spinal.lib.bus.misc.{AddressMapping, DefaultMapping, SizeMapping} +//import spinal.lib.eda.bench.Bench +//import spinal.lib.misc.Clint +//import spinal.lib.misc.plic.{PlicGatewayActiveHigh, PlicMapper, PlicMapping, PlicTarget} +//import spinal.lib.sim.{SimData, SparseMemory, StreamDriver, StreamMonitor, StreamReadyRandomizer} +//import spinal.lib.system.debugger.{JtagBridgeNoTap, SystemDebugger, SystemDebuggerConfig} +//import vexriscv.demo.smp.VexRiscvLitexSmpClusterOpenSbi.{cpuCount, parameter} +//import vexriscv.demo.smp.VexRiscvSmpClusterGen.vexRiscvConfig +//import vexriscv.{VexRiscv, VexRiscvConfig} +//import vexriscv.plugin.{CsrPlugin, DBusCachedPlugin, DebugPlugin, IBusCachedPlugin} +// +//import scala.collection.mutable +//import scala.util.Random +// +// +//case class VexRiscvLitexSmpClusterParameter( cluster : VexRiscvSmpClusterParameter, +// liteDram : LiteDramNativeParameter, +// liteDramMapping : AddressMapping) +// +////addAttribute("""mark_debug = "true"""") +//case class VexRiscvLitexSmpCluster(p : VexRiscvLitexSmpClusterParameter, +// debugClockDomain : ClockDomain, +// jtagClockDomain : ClockDomain) extends Component{ +// +// val peripheralWishboneConfig = WishboneConfig( +// addressWidth = 30, +// dataWidth = 32, +// selWidth = 4, +// useERR = true, +// useBTE = true, +// useCTI = true +// ) +// +// val io = new Bundle { +// val dMem = master(LiteDramNative(p.liteDram)) +// val iMem = master(LiteDramNative(p.liteDram)) +// val peripheral = master(Wishbone(peripheralWishboneConfig)) +// val clint = slave(Wishbone(Clint.getWisboneConfig())) +// val plic = slave(Wishbone(WishboneConfig(addressWidth = 20, dataWidth = 32))) +// val interrupts = in Bits(32 bits) +// val jtagInstruction = slave(JtagTapInstructionCtrl()) +// val debugReset = out Bool() +// } +// val cpuCount = p.cluster.cpuConfigs.size +// val clint = Clint(cpuCount) +// clint.driveFrom(WishboneSlaveFactory(io.clint)) +// +// val cluster = VexRiscvSmpCluster(p.cluster, debugClockDomain) +// cluster.io.debugReset <> io.debugReset +// cluster.io.timerInterrupts <> B(clint.harts.map(_.timerInterrupt)) +// cluster.io.softwareInterrupts <> B(clint.harts.map(_.softwareInterrupt)) +// cluster.io.time := clint.time +// +// val debug = debugClockDomain on new Area{ +// val jtagConfig = SystemDebuggerConfig() +// val jtagBridge = new JtagBridgeNoTap( +// c = jtagConfig, +// jtagClockDomain = jtagClockDomain +// ) +// jtagBridge.io.ctrl << io.jtagInstruction +// +// val debugger = new SystemDebugger(jtagConfig) +// debugger.io.remote <> jtagBridge.io.remote +// +// cluster.io.debugBus << debugger.io.mem.toBmb() +// } +// +// val dBusDecoder = BmbDecoderOutOfOrder( // p = cluster.io.dMem.p, // mappings = Seq(DefaultMapping, p.liteDramMapping), // capabilities = Seq(cluster.io.dMem.p, cluster.io.dMem.p), -// pendingMax = 31 +// pendingRspTransactionMax = 32 // ) - dBusDecoder.io.input << cluster.io.dMem.pipelined(cmdValid = true, cmdReady = true, rspValid = true) - val dMemBridge = io.dMem.fromBmb(dBusDecoder.io.outputs(1), wdataFifoSize = 32, rdataFifoSize = 32) - - val iBusArbiterParameter = cluster.iBusParameter.copy(sourceWidth = log2Up(cpuCount)) - val iBusArbiter = BmbArbiter( - p = iBusArbiterParameter, - portCount = cpuCount, - lowerFirstPriority = false - ) - - (iBusArbiter.io.inputs, cluster.io.iMems).zipped.foreach(_ << _.pipelined(cmdHalfRate = true, rspValid = true)) - - val iBusDecoder = BmbDecoder( - p = iBusArbiter.io.output.p, - mappings = Seq(DefaultMapping, p.liteDramMapping), - capabilities = Seq(iBusArbiterParameter, iBusArbiterParameter), - pendingMax = 15 - ) - iBusDecoder.io.input << iBusArbiter.io.output.pipelined(cmdValid = true) - - val iMem = LiteDramNative(p.liteDram) - io.iMem.fromBmb(iBusDecoder.io.outputs(1), wdataFifoSize = 0, rdataFifoSize = 32) - - - val iBusDecoderToPeripheral = iBusDecoder.io.outputs(0).resize(dataWidth = 32).pipelined(cmdHalfRate = true, rspValid = true) - val dBusDecoderToPeripheral = dBusDecoder.io.outputs(0).resize(dataWidth = 32).pipelined(cmdHalfRate = true, rspValid = true) - - val peripheralAccessLength = Math.max(iBusDecoder.io.outputs(0).p.lengthWidth, dBusDecoder.io.outputs(0).p.lengthWidth) - val peripheralArbiter = BmbArbiter( - p = dBusDecoder.io.outputs(0).p.copy( - sourceWidth = List(iBusDecoderToPeripheral, dBusDecoderToPeripheral).map(_.p.sourceWidth).max + 1, - contextWidth = List(iBusDecoderToPeripheral, dBusDecoderToPeripheral).map(_.p.contextWidth).max, - lengthWidth = peripheralAccessLength, - dataWidth = 32 - ), - portCount = 2, - lowerFirstPriority = true - ) - peripheralArbiter.io.inputs(0) << iBusDecoderToPeripheral - peripheralArbiter.io.inputs(1) << dBusDecoderToPeripheral - - val peripheralWishbone = peripheralArbiter.io.output.pipelined(cmdValid = true).toWishbone() - io.peripheral << peripheralWishbone - - val plic = new Area{ - val priorityWidth = 2 - - val gateways = for(i <- 1 until 32) yield PlicGatewayActiveHigh( - source = io.interrupts(i), - id = i, - priorityWidth = priorityWidth - ) - - val bus = WishboneSlaveFactory(io.plic) - - val targets = for(i <- 0 until cpuCount) yield new Area{ - val machine = PlicTarget( - gateways = gateways, - priorityWidth = priorityWidth - ) - val supervisor = PlicTarget( - gateways = gateways, - priorityWidth = priorityWidth - ) - - cluster.io.externalInterrupts(i) := machine.iep - cluster.io.externalSupervisorInterrupts(i) := supervisor.iep - } - - val bridge = PlicMapper(bus, PlicMapping.sifive)( - gateways = gateways, - targets = targets.flatMap(t => List(t.machine, t.supervisor)) - ) - } -} - -object VexRiscvLitexSmpClusterGen extends App { - for(cpuCount <- List(1,2,4,8)) { - def parameter = VexRiscvLitexSmpClusterParameter( - cluster = VexRiscvSmpClusterParameter( - cpuConfigs = List.tabulate(cpuCount) { hartId => - vexRiscvConfig( - hartId = hartId, - ioRange = address => address.msb, - resetVector = 0 - ) - } - ), - liteDram = LiteDramNativeParameter(addressWidth = 32, dataWidth = 128), - liteDramMapping = SizeMapping(0x40000000l, 0x40000000l) - ) - - def dutGen = { - val toplevel = VexRiscvLitexSmpCluster( - p = parameter, - debugClockDomain = ClockDomain.current.copy(reset = Bool().setName("debugResetIn")), - jtagClockDomain = ClockDomain.external("jtag", withReset = false) - ) - toplevel - } - - val genConfig = SpinalConfig().addStandardMemBlackboxing(blackboxByteEnables) - // genConfig.generateVerilog(Bench.compressIo(dutGen)) - genConfig.generateVerilog(dutGen.setDefinitionName(s"VexRiscvLitexSmpCluster_${cpuCount}c")) - } - -} - - -object VexRiscvLitexSmpClusterOpenSbi extends App{ - import spinal.core.sim._ - - val simConfig = SimConfig - simConfig.withWave - simConfig.allOptimisation - - val cpuCount = 2 - - def parameter = VexRiscvLitexSmpClusterParameter( - cluster = VexRiscvSmpClusterParameter( - cpuConfigs = List.tabulate(cpuCount) { hartId => - vexRiscvConfig( - hartId = hartId, - ioRange = address => address(31 downto 28) === 0xF, - resetVector = 0x80000000l - ) - } - ), - liteDram = LiteDramNativeParameter(addressWidth = 32, dataWidth = 128), - liteDramMapping = SizeMapping(0x80000000l, 0x70000000l) - ) - - def dutGen = { - val top = VexRiscvLitexSmpCluster( - p = parameter, - debugClockDomain = ClockDomain.current.copy(reset = Bool().setName("debugResetIn")), - jtagClockDomain = ClockDomain.external("jtag", withReset = false) - ) - top.rework{ - top.io.clint.setAsDirectionLess.allowDirectionLessIo - top.io.peripheral.setAsDirectionLess.allowDirectionLessIo.simPublic() - - val hit = (top.io.peripheral.ADR <<2 >= 0xF0010000l && top.io.peripheral.ADR<<2 < 0xF0020000l) - top.io.clint.CYC := top.io.peripheral.CYC && hit - top.io.clint.STB := top.io.peripheral.STB - top.io.clint.WE := top.io.peripheral.WE - top.io.clint.ADR := top.io.peripheral.ADR.resized - top.io.clint.DAT_MOSI := top.io.peripheral.DAT_MOSI - top.io.peripheral.DAT_MISO := top.io.clint.DAT_MISO - top.io.peripheral.ACK := top.io.peripheral.CYC && (!hit || top.io.clint.ACK) - top.io.peripheral.ERR := False - - top.dMemBridge.unburstified.cmd.simPublic() - } - top - } - simConfig.compile(dutGen).doSimUntilVoid(seed = 42){dut => - dut.clockDomain.forkStimulus(10) - fork { - dut.debugClockDomain.resetSim #= false - sleep (0) - dut.debugClockDomain.resetSim #= true - sleep (10) - dut.debugClockDomain.resetSim #= false - } - - - val ram = SparseMemory() - ram.loadBin(0x80000000l, "../opensbi/build/platform/spinal/vexriscv/sim/smp/firmware/fw_jump.bin") - ram.loadBin(0xC0000000l, "../buildroot/output/images/Image") - ram.loadBin(0xC1000000l, "../buildroot/output/images/dtb") - ram.loadBin(0xC2000000l, "../buildroot/output/images/rootfs.cpio") - - - dut.io.iMem.simSlave(ram, dut.clockDomain) - dut.io.dMem.simSlave(ram, dut.clockDomain, dut.dMemBridge.unburstified) - - dut.io.interrupts #= 0 - - dut.clockDomain.onFallingEdges{ - if(dut.io.peripheral.CYC.toBoolean){ - (dut.io.peripheral.ADR.toLong << 2) match { - case 0xF0000000l => print(dut.io.peripheral.DAT_MOSI.toLong.toChar) - case 0xF0000004l => dut.io.peripheral.DAT_MISO #= (if(System.in.available() != 0) System.in.read() else 0xFFFFFFFFl) - case _ => - } -// println(f"${dut.io.peripheral.ADR.toLong}%x") - } - } - +//// val dBusDecoder = BmbDecoderOut( +//// p = cluster.io.dMem.p, +//// mappings = Seq(DefaultMapping, p.liteDramMapping), +//// capabilities = Seq(cluster.io.dMem.p, cluster.io.dMem.p), +//// pendingMax = 31 +//// ) +// dBusDecoder.io.input << cluster.io.dMem.pipelined(cmdValid = true, cmdReady = true, rspValid = true) +// val dMemBridge = io.dMem.fromBmb(dBusDecoder.io.outputs(1), wdataFifoSize = 32, rdataFifoSize = 32) +// +// val iBusArbiterParameter = cluster.iBusParameter.copy(sourceWidth = log2Up(cpuCount)) +// val iBusArbiter = BmbArbiter( +// p = iBusArbiterParameter, +// portCount = cpuCount, +// lowerFirstPriority = false +// ) +// +// (iBusArbiter.io.inputs, cluster.io.iMems).zipped.foreach(_ << _.pipelined(cmdHalfRate = true, rspValid = true)) +// +// val iBusDecoder = BmbDecoder( +// p = iBusArbiter.io.output.p, +// mappings = Seq(DefaultMapping, p.liteDramMapping), +// capabilities = Seq(iBusArbiterParameter, iBusArbiterParameter), +// pendingMax = 15 +// ) +// iBusDecoder.io.input << iBusArbiter.io.output.pipelined(cmdValid = true) +// +// val iMem = LiteDramNative(p.liteDram) +// io.iMem.fromBmb(iBusDecoder.io.outputs(1), wdataFifoSize = 0, rdataFifoSize = 32) +// +// +// val iBusDecoderToPeripheral = iBusDecoder.io.outputs(0).resize(dataWidth = 32).pipelined(cmdHalfRate = true, rspValid = true) +// val dBusDecoderToPeripheral = dBusDecoder.io.outputs(0).resize(dataWidth = 32).pipelined(cmdHalfRate = true, rspValid = true) +// +// val peripheralAccessLength = Math.max(iBusDecoder.io.outputs(0).p.lengthWidth, dBusDecoder.io.outputs(0).p.lengthWidth) +// val peripheralArbiter = BmbArbiter( +// p = dBusDecoder.io.outputs(0).p.copy( +// sourceWidth = List(iBusDecoderToPeripheral, dBusDecoderToPeripheral).map(_.p.sourceWidth).max + 1, +// contextWidth = List(iBusDecoderToPeripheral, dBusDecoderToPeripheral).map(_.p.contextWidth).max, +// lengthWidth = peripheralAccessLength, +// dataWidth = 32 +// ), +// portCount = 2, +// lowerFirstPriority = true +// ) +// peripheralArbiter.io.inputs(0) << iBusDecoderToPeripheral +// peripheralArbiter.io.inputs(1) << dBusDecoderToPeripheral +// +// val peripheralWishbone = peripheralArbiter.io.output.pipelined(cmdValid = true).toWishbone() +// io.peripheral << peripheralWishbone +// +// val plic = new Area{ +// val priorityWidth = 2 +// +// val gateways = for(i <- 1 until 32) yield PlicGatewayActiveHigh( +// source = io.interrupts(i), +// id = i, +// priorityWidth = priorityWidth +// ) +// +// val bus = WishboneSlaveFactory(io.plic) +// +// val targets = for(i <- 0 until cpuCount) yield new Area{ +// val machine = PlicTarget( +// gateways = gateways, +// priorityWidth = priorityWidth +// ) +// val supervisor = PlicTarget( +// gateways = gateways, +// priorityWidth = priorityWidth +// ) +// +// cluster.io.externalInterrupts(i) := machine.iep +// cluster.io.externalSupervisorInterrupts(i) := supervisor.iep +// } +// +// val bridge = PlicMapper(bus, PlicMapping.sifive)( +// gateways = gateways, +// targets = targets.flatMap(t => List(t.machine, t.supervisor)) +// ) +// } +//} +// +//object VexRiscvLitexSmpClusterGen extends App { +// for(cpuCount <- List(1,2,4,8)) { +// def parameter = VexRiscvLitexSmpClusterParameter( +// cluster = VexRiscvSmpClusterParameter( +// cpuConfigs = List.tabulate(cpuCount) { hartId => +// vexRiscvConfig( +// hartId = hartId, +// ioRange = address => address.msb, +// resetVector = 0 +// ) +// } +// ), +// liteDram = LiteDramNativeParameter(addressWidth = 32, dataWidth = 128), +// liteDramMapping = SizeMapping(0x40000000l, 0x40000000l) +// ) +// +// def dutGen = { +// val toplevel = VexRiscvLitexSmpCluster( +// p = parameter, +// debugClockDomain = ClockDomain.current.copy(reset = Bool().setName("debugResetIn")), +// jtagClockDomain = ClockDomain.external("jtag", withReset = false) +// ) +// toplevel +// } +// +// val genConfig = SpinalConfig().addStandardMemBlackboxing(blackboxByteEnables) +// // genConfig.generateVerilog(Bench.compressIo(dutGen)) +// genConfig.generateVerilog(dutGen.setDefinitionName(s"VexRiscvLitexSmpCluster_${cpuCount}c")) +// } +// +//} +// +// +//object VexRiscvLitexSmpClusterOpenSbi extends App{ +// import spinal.core.sim._ +// +// val simConfig = SimConfig +// simConfig.withWave +// simConfig.allOptimisation +// +// val cpuCount = 2 +// +// def parameter = VexRiscvLitexSmpClusterParameter( +// cluster = VexRiscvSmpClusterParameter( +// cpuConfigs = List.tabulate(cpuCount) { hartId => +// vexRiscvConfig( +// hartId = hartId, +// ioRange = address => address(31 downto 28) === 0xF, +// resetVector = 0x80000000l +// ) +// } +// ), +// liteDram = LiteDramNativeParameter(addressWidth = 32, dataWidth = 128), +// liteDramMapping = SizeMapping(0x80000000l, 0x70000000l) +// ) +// +// def dutGen = { +// val top = VexRiscvLitexSmpCluster( +// p = parameter, +// debugClockDomain = ClockDomain.current.copy(reset = Bool().setName("debugResetIn")), +// jtagClockDomain = ClockDomain.external("jtag", withReset = false) +// ) +// top.rework{ +// top.io.clint.setAsDirectionLess.allowDirectionLessIo +// top.io.peripheral.setAsDirectionLess.allowDirectionLessIo.simPublic() +// +// val hit = (top.io.peripheral.ADR <<2 >= 0xF0010000l && top.io.peripheral.ADR<<2 < 0xF0020000l) +// top.io.clint.CYC := top.io.peripheral.CYC && hit +// top.io.clint.STB := top.io.peripheral.STB +// top.io.clint.WE := top.io.peripheral.WE +// top.io.clint.ADR := top.io.peripheral.ADR.resized +// top.io.clint.DAT_MOSI := top.io.peripheral.DAT_MOSI +// top.io.peripheral.DAT_MISO := top.io.clint.DAT_MISO +// top.io.peripheral.ACK := top.io.peripheral.CYC && (!hit || top.io.clint.ACK) +// top.io.peripheral.ERR := False +// +// top.dMemBridge.unburstified.cmd.simPublic() +// } +// top +// } +// simConfig.compile(dutGen).doSimUntilVoid(seed = 42){dut => +// dut.clockDomain.forkStimulus(10) +// fork { +// dut.debugClockDomain.resetSim #= false +// sleep (0) +// dut.debugClockDomain.resetSim #= true +// sleep (10) +// dut.debugClockDomain.resetSim #= false +// } +// +// +// val ram = SparseMemory() +// ram.loadBin(0x80000000l, "../opensbi/build/platform/spinal/vexriscv/sim/smp/firmware/fw_jump.bin") +// ram.loadBin(0xC0000000l, "../buildroot/output/images/Image") +// ram.loadBin(0xC1000000l, "../buildroot/output/images/dtb") +// ram.loadBin(0xC2000000l, "../buildroot/output/images/rootfs.cpio") +// +// +// dut.io.iMem.simSlave(ram, dut.clockDomain) +// dut.io.dMem.simSlave(ram, dut.clockDomain, dut.dMemBridge.unburstified) +// +// dut.io.interrupts #= 0 +// +// dut.clockDomain.onFallingEdges{ +// if(dut.io.peripheral.CYC.toBoolean){ +// (dut.io.peripheral.ADR.toLong << 2) match { +// case 0xF0000000l => print(dut.io.peripheral.DAT_MOSI.toLong.toChar) +// case 0xF0000004l => dut.io.peripheral.DAT_MISO #= (if(System.in.available() != 0) System.in.read() else 0xFFFFFFFFl) +// case _ => +// } +//// println(f"${dut.io.peripheral.ADR.toLong}%x") +// } +// } +// +//// fork{ +//// disableSimWave() +//// val atMs = 3790 +//// val durationMs = 5 +//// sleep(atMs*1000000l) +//// enableSimWave() +//// println("** enableSimWave **") +//// sleep(durationMs*1000000l) +//// println("** disableSimWave **") +//// while(true) { +//// disableSimWave() +//// sleep(100000 * 10) +//// enableSimWave() +//// sleep( 100 * 10) +//// } +//// // simSuccess() +//// } +// // fork{ -// disableSimWave() -// val atMs = 3790 -// val durationMs = 5 -// sleep(atMs*1000000l) -// enableSimWave() -// println("** enableSimWave **") -// sleep(durationMs*1000000l) -// println("** disableSimWave **") // while(true) { // disableSimWave() // sleep(100000 * 10) // enableSimWave() // sleep( 100 * 10) // } -// // simSuccess() // } - - fork{ - while(true) { - disableSimWave() - sleep(100000 * 10) - enableSimWave() - sleep( 100 * 10) - } - } - } - } \ No newline at end of file +// } +// } \ No newline at end of file diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexMpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexMpCluster.scala index 3631cfc5..94ccf8f4 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexMpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexMpCluster.scala @@ -1,369 +1,369 @@ -package vexriscv.demo.smp - -import spinal.core._ -import spinal.lib.bus.bmb._ -import spinal.lib.bus.wishbone.{Wishbone, WishboneConfig, WishboneSlaveFactory} -import spinal.lib.com.jtag.{Jtag, JtagTap, JtagTapInstructionCtrl} -import spinal.lib._ -import spinal.lib.blackbox.xilinx.s7.BSCANE2 -import spinal.lib.bus.bmb.sim.{BmbMemoryMultiPort, BmbMemoryTester} -import spinal.lib.bus.misc.{AddressMapping, DefaultMapping, SizeMapping} -import spinal.lib.com.jtag.sim.JtagTcp -import spinal.lib.com.jtag.xilinx.Bscane2BmbMaster -import spinal.lib.eda.bench.Bench -import spinal.lib.misc.Clint -import spinal.lib.misc.plic.{PlicGatewayActiveHigh, PlicMapper, PlicMapping, PlicTarget} -import spinal.lib.sim.{SimData, SparseMemory, StreamDriver, StreamMonitor, StreamReadyRandomizer} -import spinal.lib.system.debugger.{JtagBridgeNoTap, SystemDebugger, SystemDebuggerConfig} -import sun.jvm.hotspot.oops.DataLayout -import vexriscv.demo.smp.VexRiscvLitexSmpMpClusterOpenSbi.{cpuCount, parameter} -import vexriscv.demo.smp.VexRiscvSmpClusterGen.vexRiscvConfig -import vexriscv.{VexRiscv, VexRiscvConfig} -import vexriscv.plugin.{CsrPlugin, DBusCachedPlugin, DebugPlugin, IBusCachedPlugin} - -import scala.collection.mutable -import scala.util.Random - - -case class VexRiscvLitexSmpMpClusterParameter( cluster : VexRiscvSmpClusterParameter, - liteDram : LiteDramNativeParameter, - liteDramMapping : AddressMapping) - -//addAttribute("""mark_debug = "true"""") -class VexRiscvLitexSmpMpCluster(val p : VexRiscvLitexSmpMpClusterParameter, - val debugClockDomain : ClockDomain, - val jtagClockDomain : ClockDomain) extends Component{ - - val peripheralWishboneConfig = WishboneConfig( - addressWidth = 30, - dataWidth = 32, - selWidth = 4, - useERR = true, - useBTE = true, - useCTI = true - ) - - val cpuCount = p.cluster.cpuConfigs.size - - val io = new Bundle { - val dMem = Vec(master(LiteDramNative(p.liteDram)), cpuCount) - val iMem = Vec(master(LiteDramNative(p.liteDram)), cpuCount) - val peripheral = master(Wishbone(peripheralWishboneConfig)) - val clint = slave(Wishbone(Clint.getWisboneConfig())) - val plic = slave(Wishbone(WishboneConfig(addressWidth = 20, dataWidth = 32))) - val interrupts = in Bits(32 bits) - val jtagInstruction = slave(JtagTapInstructionCtrl()) - val debugReset = out Bool() - } - val clint = Clint(cpuCount) - clint.driveFrom(WishboneSlaveFactory(io.clint)) - - val cluster = VexRiscvSmpCluster(p.cluster, debugClockDomain) - cluster.io.debugReset <> io.debugReset - cluster.io.timerInterrupts <> B(clint.harts.map(_.timerInterrupt)) - cluster.io.softwareInterrupts <> B(clint.harts.map(_.softwareInterrupt)) - cluster.io.time := clint.time - - val debug = debugClockDomain on new Area{ - val jtagConfig = SystemDebuggerConfig() - - val jtagBridge = new JtagBridgeNoTap(jtagConfig, jtagClockDomain) - jtagBridge.io.ctrl << io.jtagInstruction - - val debugger = new SystemDebugger(jtagConfig) - debugger.io.remote <> jtagBridge.io.remote - - cluster.io.debugBus << debugger.io.mem.toBmb() - -// io.jtagInstruction.allowDirectionLessIo.setAsDirectionLess -// val bridge = Bscane2BmbMaster(1) -// cluster.io.debugBus << bridge.io.bmb - - -// val bscane2 = BSCANE2(usedId) -// val jtagClockDomain = ClockDomain(bscane2.TCK) +//package vexriscv.demo.smp +// +//import spinal.core._ +//import spinal.lib.bus.bmb._ +//import spinal.lib.bus.wishbone.{Wishbone, WishboneConfig, WishboneSlaveFactory} +//import spinal.lib.com.jtag.{Jtag, JtagTap, JtagTapInstructionCtrl} +//import spinal.lib._ +//import spinal.lib.blackbox.xilinx.s7.BSCANE2 +//import spinal.lib.bus.bmb.sim.{BmbMemoryMultiPort, BmbMemoryTester} +//import spinal.lib.bus.misc.{AddressMapping, DefaultMapping, SizeMapping} +//import spinal.lib.com.jtag.sim.JtagTcp +//import spinal.lib.com.jtag.xilinx.Bscane2BmbMaster +//import spinal.lib.eda.bench.Bench +//import spinal.lib.misc.Clint +//import spinal.lib.misc.plic.{PlicGatewayActiveHigh, PlicMapper, PlicMapping, PlicTarget} +//import spinal.lib.sim.{SimData, SparseMemory, StreamDriver, StreamMonitor, StreamReadyRandomizer} +//import spinal.lib.system.debugger.{JtagBridgeNoTap, SystemDebugger, SystemDebuggerConfig} +//import sun.jvm.hotspot.oops.DataLayout +//import vexriscv.demo.smp.VexRiscvLitexSmpMpClusterOpenSbi.{cpuCount, parameter} +//import vexriscv.demo.smp.VexRiscvSmpClusterGen.vexRiscvConfig +//import vexriscv.{VexRiscv, VexRiscvConfig} +//import vexriscv.plugin.{CsrPlugin, DBusCachedPlugin, DebugPlugin, IBusCachedPlugin} +// +//import scala.collection.mutable +//import scala.util.Random +// +// +//case class VexRiscvLitexSmpMpClusterParameter( cluster : VexRiscvSmpClusterParameter, +// liteDram : LiteDramNativeParameter, +// liteDramMapping : AddressMapping) +// +////addAttribute("""mark_debug = "true"""") +//class VexRiscvLitexSmpMpCluster(val p : VexRiscvLitexSmpMpClusterParameter, +// val debugClockDomain : ClockDomain, +// val jtagClockDomain : ClockDomain) extends Component{ +// +// val peripheralWishboneConfig = WishboneConfig( +// addressWidth = 30, +// dataWidth = 32, +// selWidth = 4, +// useERR = true, +// useBTE = true, +// useCTI = true +// ) +// +// val cpuCount = p.cluster.cpuConfigs.size +// +// val io = new Bundle { +// val dMem = Vec(master(LiteDramNative(p.liteDram)), cpuCount) +// val iMem = Vec(master(LiteDramNative(p.liteDram)), cpuCount) +// val peripheral = master(Wishbone(peripheralWishboneConfig)) +// val clint = slave(Wishbone(Clint.getWisboneConfig())) +// val plic = slave(Wishbone(WishboneConfig(addressWidth = 20, dataWidth = 32))) +// val interrupts = in Bits(32 bits) +// val jtagInstruction = slave(JtagTapInstructionCtrl()) +// val debugReset = out Bool() +// } +// val clint = Clint(cpuCount) +// clint.driveFrom(WishboneSlaveFactory(io.clint)) +// +// val cluster = VexRiscvSmpCluster(p.cluster, debugClockDomain) +// cluster.io.debugReset <> io.debugReset +// cluster.io.timerInterrupts <> B(clint.harts.map(_.timerInterrupt)) +// cluster.io.softwareInterrupts <> B(clint.harts.map(_.softwareInterrupt)) +// cluster.io.time := clint.time +// +// val debug = debugClockDomain on new Area{ +// val jtagConfig = SystemDebuggerConfig() // // val jtagBridge = new JtagBridgeNoTap(jtagConfig, jtagClockDomain) -// jtagBridge.io.ctrl << bscane2.toJtagTapInstructionCtrl() +// jtagBridge.io.ctrl << io.jtagInstruction // // val debugger = new SystemDebugger(jtagConfig) // debugger.io.remote <> jtagBridge.io.remote // -// io.bmb << debugger.io.mem.toBmb() - } - - val dBusDecoder = BmbDecoderOutOfOrder( - p = cluster.io.dMem.p, - mappings = Seq(DefaultMapping, p.liteDramMapping), - capabilities = Seq(cluster.io.dMem.p, cluster.io.dMem.p), - pendingRspTransactionMax = 32 - ) -// val dBusDecoder = BmbDecoderOut( +// cluster.io.debugBus << debugger.io.mem.toBmb() +// +//// io.jtagInstruction.allowDirectionLessIo.setAsDirectionLess +//// val bridge = Bscane2BmbMaster(1) +//// cluster.io.debugBus << bridge.io.bmb +// +// +//// val bscane2 = BSCANE2(usedId) +//// val jtagClockDomain = ClockDomain(bscane2.TCK) +//// +//// val jtagBridge = new JtagBridgeNoTap(jtagConfig, jtagClockDomain) +//// jtagBridge.io.ctrl << bscane2.toJtagTapInstructionCtrl() +//// +//// val debugger = new SystemDebugger(jtagConfig) +//// debugger.io.remote <> jtagBridge.io.remote +//// +//// io.bmb << debugger.io.mem.toBmb() +// } +// +// val dBusDecoder = BmbDecoderOutOfOrder( // p = cluster.io.dMem.p, // mappings = Seq(DefaultMapping, p.liteDramMapping), // capabilities = Seq(cluster.io.dMem.p, cluster.io.dMem.p), -// pendingMax = 31 +// pendingRspTransactionMax = 32 // ) - dBusDecoder.io.input << cluster.io.dMem.pipelined(cmdValid = true, cmdReady = true, rspValid = true) - - - val perIBus = for(id <- 0 until cpuCount) yield new Area{ - val decoder = BmbDecoder( - p = cluster.io.iMems(id).p, - mappings = Seq(DefaultMapping, p.liteDramMapping), - capabilities = Seq(cluster.io.iMems(id).p,cluster.io.iMems(id).p), - pendingMax = 15 - ) - - decoder.io.input << cluster.io.iMems(id) - io.iMem(id).fromBmb(decoder.io.outputs(1).pipelined(cmdHalfRate = true), wdataFifoSize = 0, rdataFifoSize = 32) - val toPeripheral = decoder.io.outputs(0).resize(dataWidth = 32).pipelined(cmdHalfRate = true, rspValid = true) - } - - val dBusDecoderToPeripheral = dBusDecoder.io.outputs(0).resize(dataWidth = 32).pipelined(cmdHalfRate = true, rspValid = true) - - val peripheralAccessLength = Math.max(perIBus(0).toPeripheral.p.lengthWidth, dBusDecoder.io.outputs(0).p.lengthWidth) - val peripheralArbiter = BmbArbiter( - p = dBusDecoder.io.outputs(0).p.copy( - sourceWidth = List(perIBus(0).toPeripheral, dBusDecoderToPeripheral).map(_.p.sourceWidth).max + log2Up(cpuCount + 1), - contextWidth = List(perIBus(0).toPeripheral, dBusDecoderToPeripheral).map(_.p.contextWidth).max, - lengthWidth = peripheralAccessLength, - dataWidth = 32 - ), - portCount = cpuCount+1, - lowerFirstPriority = true - ) - - for(id <- 0 until cpuCount){ - peripheralArbiter.io.inputs(id) << perIBus(id).toPeripheral - } - peripheralArbiter.io.inputs(cpuCount) << dBusDecoderToPeripheral - - val peripheralWishbone = peripheralArbiter.io.output.pipelined(cmdValid = true).toWishbone() - io.peripheral << peripheralWishbone - - - val dBusDemux = BmbSourceDecoder(dBusDecoder.io.outputs(1).p) - dBusDemux.io.input << dBusDecoder.io.outputs(1).pipelined(cmdValid = true, cmdReady = true,rspValid = true) - val dMemBridge = for(id <- 0 until cpuCount) yield { - io.dMem(id).fromBmb(dBusDemux.io.outputs(id), wdataFifoSize = 32, rdataFifoSize = 32) - } - - - val plic = new Area{ - val priorityWidth = 2 - - val gateways = for(i <- 1 until 32) yield PlicGatewayActiveHigh( - source = io.interrupts(i), - id = i, - priorityWidth = priorityWidth - ) - - val bus = WishboneSlaveFactory(io.plic) - - val targets = for(i <- 0 until cpuCount) yield new Area{ - val machine = PlicTarget( - gateways = gateways, - priorityWidth = priorityWidth - ) - val supervisor = PlicTarget( - gateways = gateways, - priorityWidth = priorityWidth - ) - - cluster.io.externalInterrupts(i) := machine.iep - cluster.io.externalSupervisorInterrupts(i) := supervisor.iep - } - - val bridge = PlicMapper(bus, PlicMapping.sifive)( - gateways = gateways, - targets = targets.flatMap(t => List(t.machine, t.supervisor)) - ) - } +//// val dBusDecoder = BmbDecoderOut( +//// p = cluster.io.dMem.p, +//// mappings = Seq(DefaultMapping, p.liteDramMapping), +//// capabilities = Seq(cluster.io.dMem.p, cluster.io.dMem.p), +//// pendingMax = 31 +//// ) +// dBusDecoder.io.input << cluster.io.dMem.pipelined(cmdValid = true, cmdReady = true, rspValid = true) // -// io.dMem.foreach(_.cmd.valid.addAttribute("""mark_debug = "true"""")) -// io.dMem.foreach(_.cmd.ready.addAttribute("""mark_debug = "true"""")) -// io.iMem.foreach(_.cmd.valid.addAttribute("""mark_debug = "true"""")) -// io.iMem.foreach(_.cmd.ready.addAttribute("""mark_debug = "true"""")) // -// cluster.io.dMem.cmd.valid.addAttribute("""mark_debug = "true"""") -// cluster.io.dMem.cmd.ready.addAttribute("""mark_debug = "true"""") -// cluster.io.dMem.rsp.valid.addAttribute("""mark_debug = "true"""") -// cluster.io.dMem.rsp.ready.addAttribute("""mark_debug = "true"""") -} - -object VexRiscvLitexSmpMpClusterGen extends App { - for(cpuCount <- List(1,2,4,8)) { - def parameter = VexRiscvLitexSmpMpClusterParameter( - cluster = VexRiscvSmpClusterParameter( - cpuConfigs = List.tabulate(cpuCount) { hartId => - vexRiscvConfig( - hartId = hartId, - ioRange = address => address.msb, - resetVector = 0 - ) - } - ), - liteDram = LiteDramNativeParameter(addressWidth = 32, dataWidth = 128), - liteDramMapping = SizeMapping(0x40000000l, 0x40000000l) - ) - - def dutGen = { - val toplevel = new VexRiscvLitexSmpMpCluster( - p = parameter, - debugClockDomain = ClockDomain.current.copy(reset = Bool().setName("debugResetIn")), - jtagClockDomain = ClockDomain.external("jtag", withReset = false) - ) - toplevel - } - - val genConfig = SpinalConfig().addStandardMemBlackboxing(blackboxByteEnables) - // genConfig.generateVerilog(Bench.compressIo(dutGen)) - genConfig.generateVerilog(dutGen.setDefinitionName(s"VexRiscvLitexSmpMpCluster_${cpuCount}c")) - } - -} - - -object VexRiscvLitexSmpMpClusterOpenSbi extends App{ - import spinal.core.sim._ - - val simConfig = SimConfig - simConfig.withWave - simConfig.withFstWave - simConfig.allOptimisation - - val cpuCount = 2 - - def parameter = VexRiscvLitexSmpMpClusterParameter( - cluster = VexRiscvSmpClusterParameter( - cpuConfigs = List.tabulate(cpuCount) { hartId => - vexRiscvConfig( - hartId = hartId, - ioRange = address => address(31 downto 28) === 0xF, - resetVector = 0x80000000l - ) - } - ), - liteDram = LiteDramNativeParameter(addressWidth = 32, dataWidth = 128), - liteDramMapping = SizeMapping(0x80000000l, 0x70000000l) - ) - - def dutGen = { - val top = new VexRiscvLitexSmpMpCluster( - p = parameter, - debugClockDomain = ClockDomain.current.copy(reset = Bool().setName("debugResetIn")), - jtagClockDomain = ClockDomain.external("jtag", withReset = false) - ){ - io.jtagInstruction.allowDirectionLessIo.setAsDirectionLess - val jtag = slave(Jtag()) - jtagClockDomain.readClockWire.setAsDirectionLess() := jtag.tck - val jtagLogic = jtagClockDomain on new Area{ - val tap = new JtagTap(jtag, 4) - val idcodeArea = tap.idcode(B"x10001FFF")(1) - val wrapper = tap.map(io.jtagInstruction, instructionId = 2) - } - } - top.rework{ - top.io.clint.setAsDirectionLess.allowDirectionLessIo - top.io.peripheral.setAsDirectionLess.allowDirectionLessIo.simPublic() - - val hit = (top.io.peripheral.ADR <<2 >= 0xF0010000l && top.io.peripheral.ADR<<2 < 0xF0020000l) - top.io.clint.CYC := top.io.peripheral.CYC && hit - top.io.clint.STB := top.io.peripheral.STB - top.io.clint.WE := top.io.peripheral.WE - top.io.clint.ADR := top.io.peripheral.ADR.resized - top.io.clint.DAT_MOSI := top.io.peripheral.DAT_MOSI - top.io.peripheral.DAT_MISO := top.io.clint.DAT_MISO - top.io.peripheral.ACK := top.io.peripheral.CYC && (!hit || top.io.clint.ACK) - top.io.peripheral.ERR := False - -// top.dMemBridge.unburstified.cmd.simPublic() - } - top - } - simConfig.compile(dutGen).doSimUntilVoid(seed = 42){dut => - dut.clockDomain.forkStimulus(10) - fork { - dut.debugClockDomain.resetSim #= false - sleep (0) - dut.debugClockDomain.resetSim #= true - sleep (10) - dut.debugClockDomain.resetSim #= false - } - - JtagTcp(dut.jtag, 10*20) - - val ram = SparseMemory() - ram.loadBin(0x80000000l, "../opensbi/build/platform/spinal/vexriscv/sim/smp/firmware/fw_jump.bin") - ram.loadBin(0xC0000000l, "../buildroot/output/images/Image") - ram.loadBin(0xC1000000l, "../buildroot/output/images/dtb") - ram.loadBin(0xC2000000l, "../buildroot/output/images/rootfs.cpio") - - for(id <- 0 until cpuCount) { - dut.io.iMem(id).simSlave(ram, dut.clockDomain) - dut.io.dMem(id).simSlave(ram, dut.clockDomain) - } - - dut.io.interrupts #= 0 - - -// val stdin = mutable.Queue[Byte]() -// def stdInPush(str : String) = stdin ++= str.toCharArray.map(_.toByte) -// fork{ -// sleep(4000*1000000l) -// stdInPush("root\n") -// sleep(1000*1000000l) -// stdInPush("ping localhost -i 0.01 > /dev/null &\n") -// stdInPush("ping localhost -i 0.01 > /dev/null &\n") -// stdInPush("ping localhost -i 0.01 > /dev/null &\n") -// stdInPush("ping localhost -i 0.01 > /dev/null &\n") -// sleep(500*1000000l) -// while(true){ -// sleep(500*1000000l) -// stdInPush("uptime\n") -// printf("\n** uptime **") +// val perIBus = for(id <- 0 until cpuCount) yield new Area{ +// val decoder = BmbDecoder( +// p = cluster.io.iMems(id).p, +// mappings = Seq(DefaultMapping, p.liteDramMapping), +// capabilities = Seq(cluster.io.iMems(id).p,cluster.io.iMems(id).p), +// pendingMax = 15 +// ) +// +// decoder.io.input << cluster.io.iMems(id) +// io.iMem(id).fromBmb(decoder.io.outputs(1).pipelined(cmdHalfRate = true), wdataFifoSize = 0, rdataFifoSize = 32) +// val toPeripheral = decoder.io.outputs(0).resize(dataWidth = 32).pipelined(cmdHalfRate = true, rspValid = true) +// } +// +// val dBusDecoderToPeripheral = dBusDecoder.io.outputs(0).resize(dataWidth = 32).pipelined(cmdHalfRate = true, rspValid = true) +// +// val peripheralAccessLength = Math.max(perIBus(0).toPeripheral.p.lengthWidth, dBusDecoder.io.outputs(0).p.lengthWidth) +// val peripheralArbiter = BmbArbiter( +// p = dBusDecoder.io.outputs(0).p.copy( +// sourceWidth = List(perIBus(0).toPeripheral, dBusDecoderToPeripheral).map(_.p.sourceWidth).max + log2Up(cpuCount + 1), +// contextWidth = List(perIBus(0).toPeripheral, dBusDecoderToPeripheral).map(_.p.contextWidth).max, +// lengthWidth = peripheralAccessLength, +// dataWidth = 32 +// ), +// portCount = cpuCount+1, +// lowerFirstPriority = true +// ) +// +// for(id <- 0 until cpuCount){ +// peripheralArbiter.io.inputs(id) << perIBus(id).toPeripheral +// } +// peripheralArbiter.io.inputs(cpuCount) << dBusDecoderToPeripheral +// +// val peripheralWishbone = peripheralArbiter.io.output.pipelined(cmdValid = true).toWishbone() +// io.peripheral << peripheralWishbone +// +// +// val dBusDemux = BmbSourceDecoder(dBusDecoder.io.outputs(1).p) +// dBusDemux.io.input << dBusDecoder.io.outputs(1).pipelined(cmdValid = true, cmdReady = true,rspValid = true) +// val dMemBridge = for(id <- 0 until cpuCount) yield { +// io.dMem(id).fromBmb(dBusDemux.io.outputs(id), wdataFifoSize = 32, rdataFifoSize = 32) +// } +// +// +// val plic = new Area{ +// val priorityWidth = 2 +// +// val gateways = for(i <- 1 until 32) yield PlicGatewayActiveHigh( +// source = io.interrupts(i), +// id = i, +// priorityWidth = priorityWidth +// ) +// +// val bus = WishboneSlaveFactory(io.plic) +// +// val targets = for(i <- 0 until cpuCount) yield new Area{ +// val machine = PlicTarget( +// gateways = gateways, +// priorityWidth = priorityWidth +// ) +// val supervisor = PlicTarget( +// gateways = gateways, +// priorityWidth = priorityWidth +// ) +// +// cluster.io.externalInterrupts(i) := machine.iep +// cluster.io.externalSupervisorInterrupts(i) := supervisor.iep +// } +// +// val bridge = PlicMapper(bus, PlicMapping.sifive)( +// gateways = gateways, +// targets = targets.flatMap(t => List(t.machine, t.supervisor)) +// ) +// } +//// +//// io.dMem.foreach(_.cmd.valid.addAttribute("""mark_debug = "true"""")) +//// io.dMem.foreach(_.cmd.ready.addAttribute("""mark_debug = "true"""")) +//// io.iMem.foreach(_.cmd.valid.addAttribute("""mark_debug = "true"""")) +//// io.iMem.foreach(_.cmd.ready.addAttribute("""mark_debug = "true"""")) +//// +//// cluster.io.dMem.cmd.valid.addAttribute("""mark_debug = "true"""") +//// cluster.io.dMem.cmd.ready.addAttribute("""mark_debug = "true"""") +//// cluster.io.dMem.rsp.valid.addAttribute("""mark_debug = "true"""") +//// cluster.io.dMem.rsp.ready.addAttribute("""mark_debug = "true"""") +//} +// +//object VexRiscvLitexSmpMpClusterGen extends App { +// for(cpuCount <- List(1,2,4,8)) { +// def parameter = VexRiscvLitexSmpMpClusterParameter( +// cluster = VexRiscvSmpClusterParameter( +// cpuConfigs = List.tabulate(cpuCount) { hartId => +// vexRiscvConfig( +// hartId = hartId, +// ioRange = address => address.msb, +// resetVector = 0 +// ) +// } +// ), +// liteDram = LiteDramNativeParameter(addressWidth = 32, dataWidth = 128), +// liteDramMapping = SizeMapping(0x40000000l, 0x40000000l) +// ) +// +// def dutGen = { +// val toplevel = new VexRiscvLitexSmpMpCluster( +// p = parameter, +// debugClockDomain = ClockDomain.current.copy(reset = Bool().setName("debugResetIn")), +// jtagClockDomain = ClockDomain.external("jtag", withReset = false) +// ) +// toplevel +// } +// +// val genConfig = SpinalConfig().addStandardMemBlackboxing(blackboxByteEnables) +// // genConfig.generateVerilog(Bench.compressIo(dutGen)) +// genConfig.generateVerilog(dutGen.setDefinitionName(s"VexRiscvLitexSmpMpCluster_${cpuCount}c")) +// } +// +//} +// +// +//object VexRiscvLitexSmpMpClusterOpenSbi extends App{ +// import spinal.core.sim._ +// +// val simConfig = SimConfig +// simConfig.withWave +// simConfig.withFstWave +// simConfig.allOptimisation +// +// val cpuCount = 2 +// +// def parameter = VexRiscvLitexSmpMpClusterParameter( +// cluster = VexRiscvSmpClusterParameter( +// cpuConfigs = List.tabulate(cpuCount) { hartId => +// vexRiscvConfig( +// hartId = hartId, +// ioRange = address => address(31 downto 28) === 0xF, +// resetVector = 0x80000000l +// ) +// } +// ), +// liteDram = LiteDramNativeParameter(addressWidth = 32, dataWidth = 128), +// liteDramMapping = SizeMapping(0x80000000l, 0x70000000l) +// ) +// +// def dutGen = { +// val top = new VexRiscvLitexSmpMpCluster( +// p = parameter, +// debugClockDomain = ClockDomain.current.copy(reset = Bool().setName("debugResetIn")), +// jtagClockDomain = ClockDomain.external("jtag", withReset = false) +// ){ +// io.jtagInstruction.allowDirectionLessIo.setAsDirectionLess +// val jtag = slave(Jtag()) +// jtagClockDomain.readClockWire.setAsDirectionLess() := jtag.tck +// val jtagLogic = jtagClockDomain on new Area{ +// val tap = new JtagTap(jtag, 4) +// val idcodeArea = tap.idcode(B"x10001FFF")(1) +// val wrapper = tap.map(io.jtagInstruction, instructionId = 2) +// } +// } +// top.rework{ +// top.io.clint.setAsDirectionLess.allowDirectionLessIo +// top.io.peripheral.setAsDirectionLess.allowDirectionLessIo.simPublic() +// +// val hit = (top.io.peripheral.ADR <<2 >= 0xF0010000l && top.io.peripheral.ADR<<2 < 0xF0020000l) +// top.io.clint.CYC := top.io.peripheral.CYC && hit +// top.io.clint.STB := top.io.peripheral.STB +// top.io.clint.WE := top.io.peripheral.WE +// top.io.clint.ADR := top.io.peripheral.ADR.resized +// top.io.clint.DAT_MOSI := top.io.peripheral.DAT_MOSI +// top.io.peripheral.DAT_MISO := top.io.clint.DAT_MISO +// top.io.peripheral.ACK := top.io.peripheral.CYC && (!hit || top.io.clint.ACK) +// top.io.peripheral.ERR := False +// +//// top.dMemBridge.unburstified.cmd.simPublic() +// } +// top +// } +// simConfig.compile(dutGen).doSimUntilVoid(seed = 42){dut => +// dut.clockDomain.forkStimulus(10) +// fork { +// dut.debugClockDomain.resetSim #= false +// sleep (0) +// dut.debugClockDomain.resetSim #= true +// sleep (10) +// dut.debugClockDomain.resetSim #= false +// } +// +// JtagTcp(dut.jtag, 10*20) +// +// val ram = SparseMemory() +// ram.loadBin(0x80000000l, "../opensbi/build/platform/spinal/vexriscv/sim/smp/firmware/fw_jump.bin") +// ram.loadBin(0xC0000000l, "../buildroot/output/images/Image") +// ram.loadBin(0xC1000000l, "../buildroot/output/images/dtb") +// ram.loadBin(0xC2000000l, "../buildroot/output/images/rootfs.cpio") +// +// for(id <- 0 until cpuCount) { +// dut.io.iMem(id).simSlave(ram, dut.clockDomain) +// dut.io.dMem(id).simSlave(ram, dut.clockDomain) +// } +// +// dut.io.interrupts #= 0 +// +// +//// val stdin = mutable.Queue[Byte]() +//// def stdInPush(str : String) = stdin ++= str.toCharArray.map(_.toByte) +//// fork{ +//// sleep(4000*1000000l) +//// stdInPush("root\n") +//// sleep(1000*1000000l) +//// stdInPush("ping localhost -i 0.01 > /dev/null &\n") +//// stdInPush("ping localhost -i 0.01 > /dev/null &\n") +//// stdInPush("ping localhost -i 0.01 > /dev/null &\n") +//// stdInPush("ping localhost -i 0.01 > /dev/null &\n") +//// sleep(500*1000000l) +//// while(true){ +//// sleep(500*1000000l) +//// stdInPush("uptime\n") +//// printf("\n** uptime **") +//// } +//// } +// dut.clockDomain.onFallingEdges { +// if (dut.io.peripheral.CYC.toBoolean) { +// (dut.io.peripheral.ADR.toLong << 2) match { +// case 0xF0000000l => print(dut.io.peripheral.DAT_MOSI.toLong.toChar) +// case 0xF0000004l => dut.io.peripheral.DAT_MISO #= (if (System.in.available() != 0) System.in.read() else 0xFFFFFFFFl) +// case _ => +// // case 0xF0000004l => { +// // val c = if(stdin.nonEmpty) { +// // stdin.dequeue().toInt & 0xFF +// // } else { +// // 0xFFFFFFFFl +// // } +// // dut.io.peripheral.DAT_MISO #= c +// // } +// // case _ => +// // } +// // println(f"${dut.io.peripheral.ADR.toLong}%x") // } // } - dut.clockDomain.onFallingEdges { - if (dut.io.peripheral.CYC.toBoolean) { - (dut.io.peripheral.ADR.toLong << 2) match { - case 0xF0000000l => print(dut.io.peripheral.DAT_MOSI.toLong.toChar) - case 0xF0000004l => dut.io.peripheral.DAT_MISO #= (if (System.in.available() != 0) System.in.read() else 0xFFFFFFFFl) - case _ => - // case 0xF0000004l => { - // val c = if(stdin.nonEmpty) { - // stdin.dequeue().toInt & 0xFF - // } else { - // 0xFFFFFFFFl - // } - // dut.io.peripheral.DAT_MISO #= c - // } - // case _ => - // } - // println(f"${dut.io.peripheral.ADR.toLong}%x") - } - } - } - - fork{ - val at = 0 - val duration = 1000 - while(simTime() < at*1000000l) { - disableSimWave() - sleep(100000 * 10) - enableSimWave() - sleep( 200 * 10) - } - println("\n\n********************") - sleep(duration*1000000l) - println("********************\n\n") - while(true) { - disableSimWave() - sleep(100000 * 10) - enableSimWave() - sleep( 400 * 10) - } - } - } -} \ No newline at end of file +// } +// +// fork{ +// val at = 0 +// val duration = 1000 +// while(simTime() < at*1000000l) { +// disableSimWave() +// sleep(100000 * 10) +// enableSimWave() +// sleep( 200 * 10) +// } +// println("\n\n********************") +// sleep(duration*1000000l) +// println("********************\n\n") +// while(true) { +// disableSimWave() +// sleep(100000 * 10) +// enableSimWave() +// sleep( 400 * 10) +// } +// } +// } +//} \ No newline at end of file diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index 98ba0ab1..d5e688c4 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -5,7 +5,7 @@ import spinal.core._ import spinal.lib._ import spinal.lib.bus.amba4.axi.{Axi4Config, Axi4Shared} import spinal.lib.bus.avalon.{AvalonMM, AvalonMMConfig} -import spinal.lib.bus.bmb.{Bmb, BmbCmd, BmbParameter} +import spinal.lib.bus.bmb.{Bmb, BmbAccessParameter, BmbCmd, BmbInvalidationParameter, BmbParameter, BmbSourceParameter} import spinal.lib.bus.wishbone.{Wishbone, WishboneConfig} import spinal.lib.bus.simple._ import vexriscv.plugin.DBusSimpleBus @@ -81,20 +81,21 @@ case class DataCacheConfig(cacheSize : Int, ) def getBmbParameter() = BmbParameter( - addressWidth = 32, - dataWidth = memDataWidth, - lengthWidth = log2Up(this.bytePerLine), - sourceWidth = 0, - contextWidth = (if(!withWriteResponse) 1 else 0) + (if(cpuDataWidth != memDataWidth) log2Up(memDataBytes) else 0), - canRead = true, - canWrite = true, - alignment = BmbParameter.BurstAlignement.LENGTH, - maximumPendingTransactionPerId = Int.MaxValue, - canInvalidate = withInvalidate, - canSync = withInvalidate, - canExclusive = withExclusive, - invalidateLength = log2Up(this.bytePerLine), - invalidateAlignment = BmbParameter.BurstAlignement.LENGTH + BmbAccessParameter( + addressWidth = 32, + dataWidth = memDataWidth + ).addSources(1, BmbSourceParameter( + lengthWidth = log2Up(this.bytePerLine), + contextWidth = (if(!withWriteResponse) 1 else 0) + (if(cpuDataWidth != memDataWidth) log2Up(memDataBytes) else 0), + alignment = BmbParameter.BurstAlignement.LENGTH, + canExclusive = withExclusive + )), + BmbInvalidationParameter( + canInvalidate = withInvalidate, + canSync = withInvalidate, + invalidateLength = log2Up(this.bytePerLine), + invalidateAlignment = BmbParameter.BurstAlignement.LENGTH + ) ) } @@ -399,7 +400,7 @@ case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave val buffer = new Area { val stream = cmd.toEvent().m2sPipe() val address = Reg(UInt(p.addressWidth bits)) - val length = Reg(UInt(pipelinedMemoryBusConfig.lengthWidth bits)) + val length = Reg(UInt(pipelinedMemoryBusConfig.access.lengthWidth bits)) val write = Reg(Bool) val exclusive = Reg(Bool) val data = Reg(Bits(p.memDataWidth bits)) diff --git a/src/main/scala/vexriscv/ip/InstructionCache.scala b/src/main/scala/vexriscv/ip/InstructionCache.scala index dc974442..856433ee 100644 --- a/src/main/scala/vexriscv/ip/InstructionCache.scala +++ b/src/main/scala/vexriscv/ip/InstructionCache.scala @@ -5,7 +5,7 @@ import spinal.core._ import spinal.lib._ import spinal.lib.bus.amba4.axi.{Axi4Config, Axi4ReadOnly} import spinal.lib.bus.avalon.{AvalonMM, AvalonMMConfig} -import spinal.lib.bus.bmb.{Bmb, BmbParameter} +import spinal.lib.bus.bmb.{Bmb, BmbAccessParameter, BmbParameter, BmbSourceParameter} import spinal.lib.bus.wishbone.{Wishbone, WishboneConfig} import spinal.lib.bus.simple._ import vexriscv.plugin.{IBusSimpleBus, IBusSimplePlugin} @@ -71,15 +71,16 @@ case class InstructionCacheConfig( cacheSize : Int, ) def getBmbParameter() = BmbParameter( - addressWidth = 32, - dataWidth = memDataWidth, - lengthWidth = log2Up(this.bytePerLine), - sourceWidth = 0, - contextWidth = 0, - canRead = true, - canWrite = false, - alignment = BmbParameter.BurstAlignement.LENGTH, - maximumPendingTransactionPerId = 1 + BmbAccessParameter( + addressWidth = 32, + dataWidth = memDataWidth + ).addSources(1, BmbSourceParameter( + lengthWidth = log2Up(this.bytePerLine), + contextWidth = 0, + canWrite = false, + alignment = BmbParameter.BurstAlignement.LENGTH, + maximumPendingTransaction = 1 + )) ) } diff --git a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala index ba896fae..e2731950 100644 --- a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala @@ -83,10 +83,7 @@ object DBusSimpleBus{ lengthWidth = 2, sourceWidth = 0, contextWidth = 1, - canRead = true, - canWrite = true, - alignment = BmbParameter.BurstAlignement.LENGTH, - maximumPendingTransactionPerId = Int.MaxValue + alignment = BmbParameter.BurstAlignement.LENGTH ) } diff --git a/src/main/scala/vexriscv/plugin/DebugPlugin.scala b/src/main/scala/vexriscv/plugin/DebugPlugin.scala index 4797e213..e133642f 100644 --- a/src/main/scala/vexriscv/plugin/DebugPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DebugPlugin.scala @@ -9,7 +9,7 @@ import spinal.core._ import spinal.lib._ import spinal.lib.bus.amba3.apb.{Apb3, Apb3Config} import spinal.lib.bus.avalon.{AvalonMM, AvalonMMConfig} -import spinal.lib.bus.bmb.{Bmb, BmbAccessParameter, BmbParameter} +import spinal.lib.bus.bmb.{Bmb, BmbAccessCapabilities, BmbAccessParameter, BmbParameter} import spinal.lib.bus.simple.PipelinedMemoryBus import scala.collection.mutable.ArrayBuffer @@ -25,12 +25,12 @@ case class DebugExtensionRsp() extends Bundle{ } object DebugExtensionBus{ - def getBmbAccessParameter(source : BmbAccessParameter) = BmbAccessParameter( + def getBmbAccessParameter(source : BmbAccessParameter) = BmbAccessCapabilities( addressWidth = 8, dataWidth = 32, - lengthWidth = 2, - sourceWidth = source.sourceWidth, - contextWidth = source.contextWidth + lengthWidthMax = 2, + sourceWidthMax = source.sourceWidth, + contextWidthMax = source.contextWidth ) } diff --git a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala index 19145f54..6af134cb 100644 --- a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala @@ -83,7 +83,7 @@ object IBusSimpleBus{ canRead = true, canWrite = false, alignment = BmbParameter.BurstAlignement.LENGTH, - maximumPendingTransactionPerId = if(plugin != null) plugin.pendingMax else Int.MaxValue + maximumPendingTransaction = if(plugin != null) plugin.pendingMax else Int.MaxValue ) } From 0da94ac66fd2b6cbacf00c86977c99974b531d02 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 29 Jun 2020 15:49:01 +0200 Subject: [PATCH 461/951] Bring back smp cluster parameters --- .../demo/smp/VexRiscvSmpCluster.scala | 264 +++++++++--------- .../scala/vexriscv/plugin/DebugPlugin.scala | 5 +- 2 files changed, 134 insertions(+), 135 deletions(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index ea8ab764..22e7e7b7 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -1,22 +1,22 @@ -//package vexriscv.demo.smp -// -//import spinal.core -//import spinal.core._ -//import spinal.core.sim.{onSimEnd, simSuccess} -//import spinal.lib._ -//import spinal.lib.bus.bmb.sim.BmbMemoryAgent -//import spinal.lib.bus.bmb.{Bmb, BmbArbiter, BmbDecoder, BmbExclusiveMonitor, BmbInvalidateMonitor, BmbParameter} -//import spinal.lib.bus.misc.SizeMapping -//import spinal.lib.com.jtag.{Jtag, JtagTapInstructionCtrl} -//import spinal.lib.com.jtag.sim.JtagTcp -//import spinal.lib.system.debugger.SystemDebuggerConfig -//import vexriscv.ip.{DataCacheAck, DataCacheConfig, DataCacheMemBus, InstructionCache, InstructionCacheConfig} -//import vexriscv.plugin.{BranchPlugin, CsrAccess, CsrPlugin, CsrPluginConfig, DBusCachedPlugin, DBusSimplePlugin, DYNAMIC_TARGET, DebugPlugin, DecoderSimplePlugin, FullBarrelShifterPlugin, HazardSimplePlugin, IBusCachedPlugin, IBusSimplePlugin, IntAluPlugin, MmuPlugin, MmuPortConfig, MulDivIterativePlugin, MulPlugin, RegFilePlugin, STATIC, SrcPlugin, YamlPlugin} -//import vexriscv.{Riscv, VexRiscv, VexRiscvConfig, plugin} -// -//import scala.collection.mutable -//import scala.collection.mutable.ArrayBuffer -// +package vexriscv.demo.smp + +import spinal.core +import spinal.core._ +import spinal.core.sim.{onSimEnd, simSuccess} +import spinal.lib._ +import spinal.lib.bus.bmb.sim.BmbMemoryAgent +import spinal.lib.bus.bmb.{Bmb, BmbArbiter, BmbDecoder, BmbExclusiveMonitor, BmbInvalidateMonitor, BmbParameter} +import spinal.lib.bus.misc.SizeMapping +import spinal.lib.com.jtag.{Jtag, JtagTapInstructionCtrl} +import spinal.lib.com.jtag.sim.JtagTcp +import spinal.lib.system.debugger.SystemDebuggerConfig +import vexriscv.ip.{DataCacheAck, DataCacheConfig, DataCacheMemBus, InstructionCache, InstructionCacheConfig} +import vexriscv.plugin.{BranchPlugin, CsrAccess, CsrPlugin, CsrPluginConfig, DBusCachedPlugin, DBusSimplePlugin, DYNAMIC_TARGET, DebugPlugin, DecoderSimplePlugin, FullBarrelShifterPlugin, HazardSimplePlugin, IBusCachedPlugin, IBusSimplePlugin, IntAluPlugin, MmuPlugin, MmuPortConfig, MulDivIterativePlugin, MulPlugin, RegFilePlugin, STATIC, SrcPlugin, YamlPlugin} +import vexriscv.{Riscv, VexRiscv, VexRiscvConfig, plugin} + +import scala.collection.mutable +import scala.collection.mutable.ArrayBuffer + // //case class VexRiscvSmpClusterParameter( cpuConfigs : Seq[VexRiscvConfig]) // @@ -117,118 +117,118 @@ // // // -//object VexRiscvSmpClusterGen { -// def vexRiscvConfig(hartId : Int, -// ioRange : UInt => Bool = (x => x(31 downto 28) === 0xF), -// resetVector : Long = 0x80000000l, -// iBusWidth : Int = 128, -// dBusWidth : Int = 64) = { -// -// val config = VexRiscvConfig( -// plugins = List( -// new MmuPlugin( -// ioRange = ioRange -// ), -// //Uncomment the whole IBusCachedPlugin and comment IBusSimplePlugin if you want cached iBus config -// new IBusCachedPlugin( -// resetVector = resetVector, -// compressedGen = false, -// prediction = STATIC, -// historyRamSizeLog2 = 9, -// relaxPredictorAddress = true, -// injectorStage = false, -// relaxedPcCalculation = true, -// config = InstructionCacheConfig( -// cacheSize = 4096*2, -// bytePerLine = 64, -// wayCount = 2, -// addressWidth = 32, -// cpuDataWidth = 32, -// memDataWidth = iBusWidth, -// catchIllegalAccess = true, -// catchAccessFault = true, -// asyncTagMemory = false, -// twoCycleRam = false, -// twoCycleCache = true, -// reducedBankWidth = true -// ), -// memoryTranslatorPortConfig = MmuPortConfig( -// portTlbSize = 4, -// latency = 1, -// earlyRequireMmuLockup = true, -// earlyCacheHits = true -// ) -// ), -// new DBusCachedPlugin( -// dBusCmdMasterPipe = dBusWidth == 32, -// dBusCmdSlavePipe = true, -// dBusRspSlavePipe = true, -// relaxedMemoryTranslationRegister = true, -// config = new DataCacheConfig( -// cacheSize = 4096*2, -// bytePerLine = 64, -// wayCount = 2, -// addressWidth = 32, -// cpuDataWidth = 32, -// memDataWidth = dBusWidth, -// catchAccessError = true, -// catchIllegal = true, -// catchUnaligned = true, -// withLrSc = true, -// withAmo = true, -// withExclusive = true, -// withInvalidate = true, -// aggregationWidth = if(dBusWidth == 32) 0 else log2Up(dBusWidth/8) -// // ) -// ), -// memoryTranslatorPortConfig = MmuPortConfig( -// portTlbSize = 4, -// latency = 1, -// earlyRequireMmuLockup = true, -// earlyCacheHits = true -// ) -// ), -// new DecoderSimplePlugin( -// catchIllegalInstruction = true -// ), -// new RegFilePlugin( -// regFileReadyKind = plugin.ASYNC, -// zeroBoot = true, -// x0Init = false -// ), -// new IntAluPlugin, -// new SrcPlugin( -// separatedAddSub = false -// ), -// new FullBarrelShifterPlugin(earlyInjection = false), -// // new LightShifterPlugin, -// new HazardSimplePlugin( -// bypassExecute = true, -// bypassMemory = true, -// bypassWriteBack = true, -// bypassWriteBackBuffer = true, -// pessimisticUseSrc = false, -// pessimisticWriteRegFile = false, -// pessimisticAddressMatch = false -// ), -// new MulPlugin, -// new MulDivIterativePlugin( -// genMul = false, -// genDiv = true, -// mulUnrollFactor = 32, -// divUnrollFactor = 1 -// ), -// new CsrPlugin(CsrPluginConfig.openSbi(mhartid = hartId, misa = Riscv.misaToInt("imas")).copy(utimeAccess = CsrAccess.READ_ONLY)), -// new BranchPlugin( -// earlyBranch = false, -// catchAddressMisaligned = true, -// fenceiGenAsAJump = false -// ), -// new YamlPlugin(s"cpu$hartId.yaml") -// ) -// ) -// config -// } +object VexRiscvSmpClusterGen { + def vexRiscvConfig(hartId : Int, + ioRange : UInt => Bool = (x => x(31 downto 28) === 0xF), + resetVector : Long = 0x80000000l, + iBusWidth : Int = 128, + dBusWidth : Int = 64) = { + + val config = VexRiscvConfig( + plugins = List( + new MmuPlugin( + ioRange = ioRange + ), + //Uncomment the whole IBusCachedPlugin and comment IBusSimplePlugin if you want cached iBus config + new IBusCachedPlugin( + resetVector = resetVector, + compressedGen = false, + prediction = STATIC, + historyRamSizeLog2 = 9, + relaxPredictorAddress = true, + injectorStage = false, + relaxedPcCalculation = true, + config = InstructionCacheConfig( + cacheSize = 4096*2, + bytePerLine = 64, + wayCount = 2, + addressWidth = 32, + cpuDataWidth = 32, + memDataWidth = iBusWidth, + catchIllegalAccess = true, + catchAccessFault = true, + asyncTagMemory = false, + twoCycleRam = false, + twoCycleCache = true, + reducedBankWidth = true + ), + memoryTranslatorPortConfig = MmuPortConfig( + portTlbSize = 4, + latency = 1, + earlyRequireMmuLockup = true, + earlyCacheHits = true + ) + ), + new DBusCachedPlugin( + dBusCmdMasterPipe = dBusWidth == 32, + dBusCmdSlavePipe = true, + dBusRspSlavePipe = true, + relaxedMemoryTranslationRegister = true, + config = new DataCacheConfig( + cacheSize = 4096*2, + bytePerLine = 64, + wayCount = 2, + addressWidth = 32, + cpuDataWidth = 32, + memDataWidth = dBusWidth, + catchAccessError = true, + catchIllegal = true, + catchUnaligned = true, + withLrSc = true, + withAmo = true, + withExclusive = true, + withInvalidate = true, + aggregationWidth = if(dBusWidth == 32) 0 else log2Up(dBusWidth/8) + // ) + ), + memoryTranslatorPortConfig = MmuPortConfig( + portTlbSize = 4, + latency = 1, + earlyRequireMmuLockup = true, + earlyCacheHits = true + ) + ), + new DecoderSimplePlugin( + catchIllegalInstruction = true + ), + new RegFilePlugin( + regFileReadyKind = plugin.ASYNC, + zeroBoot = true, + x0Init = false + ), + new IntAluPlugin, + new SrcPlugin( + separatedAddSub = false + ), + new FullBarrelShifterPlugin(earlyInjection = false), + // new LightShifterPlugin, + new HazardSimplePlugin( + bypassExecute = true, + bypassMemory = true, + bypassWriteBack = true, + bypassWriteBackBuffer = true, + pessimisticUseSrc = false, + pessimisticWriteRegFile = false, + pessimisticAddressMatch = false + ), + new MulPlugin, + new MulDivIterativePlugin( + genMul = false, + genDiv = true, + mulUnrollFactor = 32, + divUnrollFactor = 1 + ), + new CsrPlugin(CsrPluginConfig.openSbi(mhartid = hartId, misa = Riscv.misaToInt("imas")).copy(utimeAccess = CsrAccess.READ_ONLY)), + new BranchPlugin( + earlyBranch = false, + catchAddressMisaligned = true, + fenceiGenAsAJump = false + ), + new YamlPlugin(s"cpu$hartId.yaml") + ) + ) + config + } // def vexRiscvCluster(cpuCount : Int, resetVector : Long = 0x80000000l) = VexRiscvSmpCluster( // debugClockDomain = ClockDomain.current.copy(reset = Bool().setName("debugResetIn")), // p = VexRiscvSmpClusterParameter( @@ -242,7 +242,7 @@ // vexRiscvCluster(4) // } // } -//} +} // // // diff --git a/src/main/scala/vexriscv/plugin/DebugPlugin.scala b/src/main/scala/vexriscv/plugin/DebugPlugin.scala index e133642f..78171943 100644 --- a/src/main/scala/vexriscv/plugin/DebugPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DebugPlugin.scala @@ -25,12 +25,11 @@ case class DebugExtensionRsp() extends Bundle{ } object DebugExtensionBus{ - def getBmbAccessParameter(source : BmbAccessParameter) = BmbAccessCapabilities( + def getBmbAccessParameter(source : BmbAccessCapabilities) = source.copy( addressWidth = 8, dataWidth = 32, lengthWidthMax = 2, - sourceWidthMax = source.sourceWidth, - contextWidthMax = source.contextWidth + alignment = BmbParameter.BurstAlignement.LENGTH ) } From 32539dfe6de5034b01dc9e0c034cd1e3d6e94e8f Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 30 Jun 2020 22:29:33 +0200 Subject: [PATCH 462/951] Got VexRiscvSmpLitexCluster refractoring to work --- .../scala/vexriscv/VexRiscvBmbGenerator.scala | 156 ++++++ src/main/scala/vexriscv/demo/smp/Misc.scala | 43 +- .../demo/smp/VexRiscvSmpCluster.scala | 103 +++- .../demo/smp/VexRiscvSmpLitexCluster.scala | 451 ++++++------------ 4 files changed, 442 insertions(+), 311 deletions(-) create mode 100644 src/main/scala/vexriscv/VexRiscvBmbGenerator.scala diff --git a/src/main/scala/vexriscv/VexRiscvBmbGenerator.scala b/src/main/scala/vexriscv/VexRiscvBmbGenerator.scala new file mode 100644 index 00000000..d7d578fa --- /dev/null +++ b/src/main/scala/vexriscv/VexRiscvBmbGenerator.scala @@ -0,0 +1,156 @@ +package vexriscv + +import spinal.core._ +import spinal.lib.bus.bmb.{Bmb, BmbAccessCapabilities, BmbAccessParameter, BmbImplicitDebugDecoder, BmbParameter, BmbSmpInterconnectGenerator} +import spinal.lib.bus.misc.AddressMapping +import spinal.lib.com.jtag.{Jtag, JtagTapInstructionCtrl} +import spinal.lib.generator._ +import spinal.lib.slave +import vexriscv.plugin._ + + +object VexRiscvBmbGenerator{ + val DEBUG_NONE = 0 + val DEBUG_JTAG = 1 + val DEBUG_JTAG_CTRL = 2 + val DEBUG_BUS = 3 + val DEBUG_BMB = 4 +} + +case class VexRiscvBmbGenerator()(implicit interconnectSmp: BmbSmpInterconnectGenerator = null) extends Generator { + import VexRiscvBmbGenerator._ + + val config = Handle[VexRiscvConfig] + val withDebug = Handle[Int] + val debugClockDomain = Handle[ClockDomain] + val debugReset = Handle[Bool] + val debugAskReset = Handle[() => Unit] + val hardwareBreakpointCount = Handle(0) + + val iBus, dBus = product[Bmb] + + val externalInterrupt = product[Bool] + val externalSupervisorInterrupt = product[Bool] + val timerInterrupt = product[Bool] + val softwareInterrupt = product[Bool] + + def setTimerInterrupt(that: Handle[Bool]) = Dependable(that, timerInterrupt){timerInterrupt := that} + def setSoftwareInterrupt(that: Handle[Bool]) = Dependable(that, softwareInterrupt){softwareInterrupt := that} + + + def disableDebug() = { + withDebug.load(DEBUG_NONE) + } + + def enableJtag(debugCd : ClockDomainResetGenerator, resetCd : ClockDomainResetGenerator) : Unit = debugCd{ + this.debugClockDomain.merge(debugCd.outputClockDomain) + val resetBridge = resetCd.asyncReset(debugReset, ResetSensitivity.HIGH) + debugAskReset.load(null) + withDebug.load(DEBUG_JTAG) + } + + def enableJtagInstructionCtrl(debugCd : ClockDomainResetGenerator, resetCd : ClockDomainResetGenerator) : Unit = debugCd{ + this.debugClockDomain.merge(debugCd.outputClockDomain) + val resetBridge = resetCd.asyncReset(debugReset, ResetSensitivity.HIGH) + debugAskReset.load(null) + withDebug.load(DEBUG_JTAG_CTRL) + dependencies += jtagClockDomain + } + + def enableDebugBus(debugCd : ClockDomainResetGenerator, resetCd : ClockDomainResetGenerator) : Unit = debugCd{ + this.debugClockDomain.merge(debugCd.outputClockDomain) + val resetBridge = resetCd.asyncReset(debugReset, ResetSensitivity.HIGH) + debugAskReset.load(null) + withDebug.load(DEBUG_BUS) + } + + val debugBmbAccessSource = Handle[BmbAccessCapabilities] + val debugBmbAccessRequirements = Handle[BmbAccessParameter] + def enableDebugBmb(debugCd : ClockDomainResetGenerator, resetCd : ClockDomainResetGenerator, mapping : AddressMapping)(implicit debugMaster : BmbImplicitDebugDecoder = null) : Unit = debugCd{ + this.debugClockDomain.merge(debugCd.outputClockDomain) + val resetBridge = resetCd.asyncReset(debugReset, ResetSensitivity.HIGH) + debugAskReset.load(null) + withDebug.load(DEBUG_BMB) + val slaveModel = interconnectSmp.addSlave( + accessSource = debugBmbAccessSource, + accessCapabilities = debugBmbAccessSource.derivate(DebugExtensionBus.getBmbAccessParameter(_)), + accessRequirements = debugBmbAccessRequirements, + bus = debugBmb, + mapping = mapping + ) + slaveModel.onClockDomain(debugCd.outputClockDomain) + debugBmb.derivatedFrom(debugBmbAccessRequirements)(Bmb(_)) + if(debugMaster != null) interconnectSmp.addConnection(debugMaster.bus, debugBmb) + dependencies += debugBmb + } + + + dependencies ++= List(config) + dependencies += Dependable(withDebug) { + if (withDebug.get != DEBUG_NONE) { + dependencies ++= List(debugClockDomain, debugAskReset) + } + } + + val jtag = add task (withDebug.get == DEBUG_JTAG generate slave(Jtag())) + val jtagInstructionCtrl = withDebug.produce(withDebug.get == DEBUG_JTAG_CTRL generate JtagTapInstructionCtrl()) + val debugBus = withDebug.produce(withDebug.get == DEBUG_BUS generate DebugExtensionBus()) + val debugBmb = Handle[Bmb] + val jtagClockDomain = Handle[ClockDomain] + + val logic = add task new Area { + withDebug.get != DEBUG_NONE generate new Area { + config.add(new DebugPlugin(debugClockDomain, hardwareBreakpointCount)) + } + + val cpu = new VexRiscv(config) + for (plugin <- cpu.plugins) plugin match { + case plugin: IBusSimplePlugin => iBus.load(plugin.iBus.toBmb()) + case plugin: DBusSimplePlugin => dBus.load(plugin.dBus.toBmb()) + case plugin: IBusCachedPlugin => iBus.load(plugin.iBus.toBmb()) + case plugin: DBusCachedPlugin => dBus.load(plugin.dBus.toBmb()) + case plugin: CsrPlugin => { + externalInterrupt load plugin.externalInterrupt + timerInterrupt load plugin.timerInterrupt + softwareInterrupt load plugin.softwareInterrupt + if (plugin.config.supervisorGen) externalSupervisorInterrupt load plugin.externalInterruptS + } + case plugin: DebugPlugin => plugin.debugClockDomain { + if(debugAskReset.get != null) when(RegNext(plugin.io.resetOut)) { + debugAskReset.get() + } else { + debugReset.load(RegNext(plugin.io.resetOut)) + } + + withDebug.get match { + case DEBUG_JTAG => jtag <> plugin.io.bus.fromJtag() + case DEBUG_JTAG_CTRL => jtagInstructionCtrl <> plugin.io.bus.fromJtagInstructionCtrl(jtagClockDomain) + case DEBUG_BUS => debugBus <> plugin.io.bus + case DEBUG_BMB => debugBmb >> plugin.io.bus.fromBmb() + } + } + case _ => + } + } + + val parameterGenerator = new Generator { + val iBusParameter, dBusParameter = product[BmbParameter] + dependencies += config + + add task { + for (plugin <- config.plugins) plugin match { + case plugin: IBusSimplePlugin => iBusParameter.load(IBusSimpleBus.getBmbParameter()) + case plugin: DBusSimplePlugin => dBusParameter.load(DBusSimpleBus.getBmbParameter()) + case plugin: IBusCachedPlugin => iBusParameter.load(plugin.config.getBmbParameter()) + case plugin: DBusCachedPlugin => dBusParameter.load(plugin.config.getBmbParameter()) + case _ => + } + } + } + + if(interconnectSmp != null){ + interconnectSmp.addMaster(accessRequirements = parameterGenerator.iBusParameter.derivate(_.access), bus = iBus) + interconnectSmp.addMaster(accessRequirements = parameterGenerator.dBusParameter.derivate(_.access), bus = dBus) + } + +} diff --git a/src/main/scala/vexriscv/demo/smp/Misc.scala b/src/main/scala/vexriscv/demo/smp/Misc.scala index 6fa34ba8..01135b6b 100644 --- a/src/main/scala/vexriscv/demo/smp/Misc.scala +++ b/src/main/scala/vexriscv/demo/smp/Misc.scala @@ -9,6 +9,7 @@ import spinal.lib._ import spinal.lib.bus.bmb.sim.{BmbMemoryMultiPort, BmbMemoryTester} import spinal.lib.bus.misc.{AddressMapping, DefaultMapping, SizeMapping} import spinal.lib.eda.bench.Bench +import spinal.lib.generator.{Generator, Handle} import spinal.lib.misc.Clint import spinal.lib.sim.{SimData, SparseMemory, StreamDriver, StreamMonitor, StreamReadyRandomizer} import vexriscv.{VexRiscv, VexRiscvConfig} @@ -244,4 +245,44 @@ object BmbToLiteDramTester extends App{ val tester = new BmbMemoryTester(dut.io.input, dut.clockDomain, rspCounterTarget = 3000) dut.io.output.simSlave(tester.memory.memory, dut.clockDomain) } -} \ No newline at end of file +} + +case class BmbToLiteDramGenerator(mapping : AddressMapping)(implicit interconnect : BmbSmpInterconnectGenerator) extends Generator{ + val liteDramParameter = createDependency[LiteDramNativeParameter] + val bmb = produce(logic.io.input) + val dram = produceIo(logic.io.output) + + val accessSource = Handle[BmbAccessCapabilities] + val accessRequirements = createDependency[BmbAccessParameter] + interconnect.addSlave( + accessSource = accessSource, + accessCapabilities = accessSource, + accessRequirements = accessRequirements, + bus = bmb, + mapping = mapping + ) + val logic = add task BmbToLiteDram( + bmbParameter = accessRequirements.toBmbParameter(), + liteDramParameter = liteDramParameter, + wdataFifoSize = 32, + rdataFifoSize = 32 + ) +} + +case class BmbToWishboneGenerator(mapping : AddressMapping)(implicit interconnect : BmbSmpInterconnectGenerator) extends Generator{ + val bmb = produce(logic.io.input) + val wishbone = produce(logic.io.output) + + val accessSource = Handle[BmbAccessCapabilities] + val accessRequirements = createDependency[BmbAccessParameter] + interconnect.addSlave( + accessSource = accessSource, + accessCapabilities = accessSource, + accessRequirements = accessRequirements, + bus = bmb, + mapping = mapping + ) + val logic = add task BmbToWishbone( + p = accessRequirements.toBmbParameter() + ) +} diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index 22e7e7b7..471463c8 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -5,21 +5,110 @@ import spinal.core._ import spinal.core.sim.{onSimEnd, simSuccess} import spinal.lib._ import spinal.lib.bus.bmb.sim.BmbMemoryAgent -import spinal.lib.bus.bmb.{Bmb, BmbArbiter, BmbDecoder, BmbExclusiveMonitor, BmbInvalidateMonitor, BmbParameter} -import spinal.lib.bus.misc.SizeMapping -import spinal.lib.com.jtag.{Jtag, JtagTapInstructionCtrl} +import spinal.lib.bus.bmb._ +import spinal.lib.bus.misc.{DefaultMapping, SizeMapping} +import spinal.lib.bus.wishbone.{Wishbone, WishboneConfig, WishboneToBmb, WishboneToBmbGenerator} +import spinal.lib.com.jtag.{Jtag, JtagInstructionDebuggerGenerator, JtagTapInstructionCtrl} import spinal.lib.com.jtag.sim.JtagTcp +import spinal.lib.com.jtag.xilinx.Bscane2BmbMasterGenerator +import spinal.lib.generator.Handle +import spinal.lib.misc.plic.PlicMapping import spinal.lib.system.debugger.SystemDebuggerConfig import vexriscv.ip.{DataCacheAck, DataCacheConfig, DataCacheMemBus, InstructionCache, InstructionCacheConfig} import vexriscv.plugin.{BranchPlugin, CsrAccess, CsrPlugin, CsrPluginConfig, DBusCachedPlugin, DBusSimplePlugin, DYNAMIC_TARGET, DebugPlugin, DecoderSimplePlugin, FullBarrelShifterPlugin, HazardSimplePlugin, IBusCachedPlugin, IBusSimplePlugin, IntAluPlugin, MmuPlugin, MmuPortConfig, MulDivIterativePlugin, MulPlugin, RegFilePlugin, STATIC, SrcPlugin, YamlPlugin} -import vexriscv.{Riscv, VexRiscv, VexRiscvConfig, plugin} +import vexriscv.{Riscv, VexRiscv, VexRiscvBmbGenerator, VexRiscvConfig, plugin} import scala.collection.mutable import scala.collection.mutable.ArrayBuffer +import spinal.lib.generator._ + +case class VexRiscvSmpClusterParameter( cpuConfigs : Seq[VexRiscvConfig]) + +class VexRiscvSmpClusterBase(p : VexRiscvSmpClusterParameter) extends Generator{ + val cpuCount = p.cpuConfigs.size + + val debugCd = ClockDomainResetGenerator() + debugCd.holdDuration.load(4095) + debugCd.makeExternal() + + val systemCd = ClockDomainResetGenerator() + systemCd.holdDuration.load(63) + systemCd.setInput(debugCd) + + this.onClockDomain(systemCd.outputClockDomain) + + implicit val interconnect = BmbSmpInterconnectGenerator() + + val debugBridge = JtagInstructionDebuggerGenerator() onClockDomain(debugCd.outputClockDomain) + debugBridge.jtagClockDomain.load(ClockDomain.external("jtag", withReset = false)) + + val debugPort = debugBridge.produceIo(debugBridge.logic.jtagBridge.io.ctrl) + + val exclusiveMonitor = BmbExclusiveMonitorGenerator() + val invalidationMonitor = BmbInvalidateMonitorGenerator() + interconnect.addConnection(exclusiveMonitor.output, invalidationMonitor.input) + interconnect.masters(invalidationMonitor.output).withOutOfOrderDecoder() + + val cores = for(cpuId <- 0 until cpuCount) yield new Area{ + val cpu = VexRiscvBmbGenerator() + cpu.config.load(p.cpuConfigs(cpuId)) + interconnect.addConnection( + cpu.dBus -> List(exclusiveMonitor.input) + ) + cpu.enableDebugBmb( + debugCd = debugCd, + resetCd = systemCd, + mapping = SizeMapping(cpuId*0x1000, 0x1000) + ) + interconnect.addConnection(debugBridge.bmb, cpu.debugBmb) + } +} + + +class VexRiscvSmpClusterWithPeripherals(p : VexRiscvSmpClusterParameter) extends VexRiscvSmpClusterBase(p) { + val peripheralBridge = BmbToWishboneGenerator(DefaultMapping) + val peripheral = peripheralBridge.produceIo(peripheralBridge.logic.io.output) + interconnect.slaves(peripheralBridge.bmb).forceAccessSourceDataWidth(32) + + val plic = BmbPlicGenerator(0) + plic.priorityWidth.load(2) + plic.mapping.load(PlicMapping.sifive) + + val plicWishboneBridge = WishboneToBmbGenerator() + val plicWishbone = plicWishboneBridge.produceIo(plicWishboneBridge.logic.io.input) + plicWishboneBridge.config.load(WishboneConfig(20, 32)) + interconnect.addConnection(plicWishboneBridge.bmb, plic.bus) + + val clint = BmbClintGenerator(0) + + val clintWishboneBridge = WishboneToBmbGenerator() + val clintWishbone = clintWishboneBridge.produceIo(clintWishboneBridge.logic.io.input) + clintWishboneBridge.config.load(WishboneConfig(14, 32)) + interconnect.addConnection(clintWishboneBridge.bmb, clint.bus) + + val interrupts = add task (in Bits(32 bits)) + for(i <- 1 to 31) yield plic.addInterrupt(interrupts.derivate(_.apply(i)), i) + + for ((core, cpuId) <- cores.zipWithIndex) { + core.cpu.setTimerInterrupt(clint.timerInterrupt(cpuId)) + core.cpu.setSoftwareInterrupt(clint.softwareInterrupt(cpuId)) + plic.priorityWidth.load(2) + plic.mapping.load(PlicMapping.sifive) + plic.addTarget(core.cpu.externalInterrupt) + plic.addTarget(core.cpu.externalSupervisorInterrupt) + List(clint.logic, core.cpu.logic).produce { + for (plugin <- core.cpu.config.plugins) plugin match { + case plugin: CsrPlugin if plugin.utime != null => plugin.utime := clint.logic.io.time + case _ => + } + } + } + + clint.cpuCount.load(cpuCount) +} + + -// -//case class VexRiscvSmpClusterParameter( cpuConfigs : Seq[VexRiscvConfig]) -// //case class VexRiscvSmpCluster(p : VexRiscvSmpClusterParameter, // debugClockDomain : ClockDomain) extends Component{ // val dBusParameter = p.cpuConfigs.head.plugins.find(_.isInstanceOf[DBusCachedPlugin]).get.asInstanceOf[DBusCachedPlugin].config.getBmbParameter() diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala index 44beab72..e5cda937 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala @@ -1,305 +1,150 @@ -//package vexriscv.demo.smp -// -//import spinal.core._ -//import spinal.lib.bus.bmb._ -//import spinal.lib.bus.wishbone.{Wishbone, WishboneConfig, WishboneSlaveFactory} -//import spinal.lib.com.jtag.{Jtag, JtagTapInstructionCtrl} -//import spinal.lib._ -//import spinal.lib.bus.bmb.sim.{BmbMemoryMultiPort, BmbMemoryTester} -//import spinal.lib.bus.misc.{AddressMapping, DefaultMapping, SizeMapping} -//import spinal.lib.eda.bench.Bench -//import spinal.lib.misc.Clint -//import spinal.lib.misc.plic.{PlicGatewayActiveHigh, PlicMapper, PlicMapping, PlicTarget} -//import spinal.lib.sim.{SimData, SparseMemory, StreamDriver, StreamMonitor, StreamReadyRandomizer} -//import spinal.lib.system.debugger.{JtagBridgeNoTap, SystemDebugger, SystemDebuggerConfig} -//import vexriscv.demo.smp.VexRiscvLitexSmpClusterOpenSbi.{cpuCount, parameter} -//import vexriscv.demo.smp.VexRiscvSmpClusterGen.vexRiscvConfig -//import vexriscv.{VexRiscv, VexRiscvConfig} -//import vexriscv.plugin.{CsrPlugin, DBusCachedPlugin, DebugPlugin, IBusCachedPlugin} -// -//import scala.collection.mutable -//import scala.util.Random -// -// -//case class VexRiscvLitexSmpClusterParameter( cluster : VexRiscvSmpClusterParameter, -// liteDram : LiteDramNativeParameter, -// liteDramMapping : AddressMapping) -// +package vexriscv.demo.smp + +import spinal.core._ +import spinal.lib.bus.bmb._ +import spinal.lib.bus.misc.{AddressMapping, DefaultMapping, SizeMapping} +import spinal.lib.sim.SparseMemory +import vexriscv.demo.smp.VexRiscvSmpClusterGen.vexRiscvConfig + + +case class VexRiscvLitexSmpClusterParameter( cluster : VexRiscvSmpClusterParameter, + liteDram : LiteDramNativeParameter, + liteDramMapping : AddressMapping) + + +class VexRiscvLitexSmpCluster(p : VexRiscvLitexSmpClusterParameter) extends VexRiscvSmpClusterWithPeripherals(p.cluster) { + val iArbiter = BmbSmpBridgeGenerator() + val iBridge = BmbToLiteDramGenerator(p.liteDramMapping) + val dBridge = BmbToLiteDramGenerator(p.liteDramMapping) + + for(core <- cores) interconnect.addConnection(core.cpu.iBus -> List(iArbiter.bmb)) + interconnect.addConnection( + iArbiter.bmb -> List(iBridge.bmb, peripheralBridge.bmb), + invalidationMonitor.output -> List(dBridge.bmb, peripheralBridge.bmb) + ) + interconnect.masters(invalidationMonitor.output).withOutOfOrderDecoder() + + dBridge.liteDramParameter.load(p.liteDram) + iBridge.liteDramParameter.load(p.liteDram) + + // Interconnect pipelining (FMax) + for(core <- cores) { + interconnect.setPipelining(core.cpu.dBus)(cmdValid = true, cmdReady = true, rspValid = true) + interconnect.setPipelining(core.cpu.iBus)(cmdHalfRate = true, rspValid = true) + interconnect.setPipelining(iArbiter.bmb)(cmdHalfRate = true, rspValid = true) + } + interconnect.setPipelining(invalidationMonitor.output)(cmdValid = true, cmdReady = true, rspValid = true) + interconnect.setPipelining(peripheralBridge.bmb)(cmdHalfRate = true, rspValid = true) +} + + +object VexRiscvLitexSmpClusterGen extends App { + for(cpuCount <- List(1,2,4,8)) { + def parameter = VexRiscvLitexSmpClusterParameter( + cluster = VexRiscvSmpClusterParameter( + cpuConfigs = List.tabulate(cpuCount) { hartId => + vexRiscvConfig( + hartId = hartId, + ioRange = address => address.msb, + resetVector = 0 + ) + } + ), + liteDram = LiteDramNativeParameter(addressWidth = 32, dataWidth = 128), + liteDramMapping = SizeMapping(0x40000000l, 0x40000000l) + ) + + def dutGen = { + val toplevel = new VexRiscvLitexSmpCluster( + p = parameter + ).toComponent() + toplevel + } + + val genConfig = SpinalConfig().addStandardMemBlackboxing(blackboxByteEnables) + // genConfig.generateVerilog(Bench.compressIo(dutGen)) + genConfig.generateVerilog(dutGen.setDefinitionName(s"VexRiscvLitexSmpCluster_${cpuCount}c")) + } +} + ////addAttribute("""mark_debug = "true"""") -//case class VexRiscvLitexSmpCluster(p : VexRiscvLitexSmpClusterParameter, -// debugClockDomain : ClockDomain, -// jtagClockDomain : ClockDomain) extends Component{ -// -// val peripheralWishboneConfig = WishboneConfig( -// addressWidth = 30, -// dataWidth = 32, -// selWidth = 4, -// useERR = true, -// useBTE = true, -// useCTI = true -// ) -// -// val io = new Bundle { -// val dMem = master(LiteDramNative(p.liteDram)) -// val iMem = master(LiteDramNative(p.liteDram)) -// val peripheral = master(Wishbone(peripheralWishboneConfig)) -// val clint = slave(Wishbone(Clint.getWisboneConfig())) -// val plic = slave(Wishbone(WishboneConfig(addressWidth = 20, dataWidth = 32))) -// val interrupts = in Bits(32 bits) -// val jtagInstruction = slave(JtagTapInstructionCtrl()) -// val debugReset = out Bool() -// } -// val cpuCount = p.cluster.cpuConfigs.size -// val clint = Clint(cpuCount) -// clint.driveFrom(WishboneSlaveFactory(io.clint)) -// -// val cluster = VexRiscvSmpCluster(p.cluster, debugClockDomain) -// cluster.io.debugReset <> io.debugReset -// cluster.io.timerInterrupts <> B(clint.harts.map(_.timerInterrupt)) -// cluster.io.softwareInterrupts <> B(clint.harts.map(_.softwareInterrupt)) -// cluster.io.time := clint.time -// -// val debug = debugClockDomain on new Area{ -// val jtagConfig = SystemDebuggerConfig() -// val jtagBridge = new JtagBridgeNoTap( -// c = jtagConfig, -// jtagClockDomain = jtagClockDomain -// ) -// jtagBridge.io.ctrl << io.jtagInstruction -// -// val debugger = new SystemDebugger(jtagConfig) -// debugger.io.remote <> jtagBridge.io.remote -// -// cluster.io.debugBus << debugger.io.mem.toBmb() -// } -// -// val dBusDecoder = BmbDecoderOutOfOrder( -// p = cluster.io.dMem.p, -// mappings = Seq(DefaultMapping, p.liteDramMapping), -// capabilities = Seq(cluster.io.dMem.p, cluster.io.dMem.p), -// pendingRspTransactionMax = 32 -// ) -//// val dBusDecoder = BmbDecoderOut( -//// p = cluster.io.dMem.p, -//// mappings = Seq(DefaultMapping, p.liteDramMapping), -//// capabilities = Seq(cluster.io.dMem.p, cluster.io.dMem.p), -//// pendingMax = 31 -//// ) -// dBusDecoder.io.input << cluster.io.dMem.pipelined(cmdValid = true, cmdReady = true, rspValid = true) -// val dMemBridge = io.dMem.fromBmb(dBusDecoder.io.outputs(1), wdataFifoSize = 32, rdataFifoSize = 32) -// -// val iBusArbiterParameter = cluster.iBusParameter.copy(sourceWidth = log2Up(cpuCount)) -// val iBusArbiter = BmbArbiter( -// p = iBusArbiterParameter, -// portCount = cpuCount, -// lowerFirstPriority = false -// ) -// -// (iBusArbiter.io.inputs, cluster.io.iMems).zipped.foreach(_ << _.pipelined(cmdHalfRate = true, rspValid = true)) -// -// val iBusDecoder = BmbDecoder( -// p = iBusArbiter.io.output.p, -// mappings = Seq(DefaultMapping, p.liteDramMapping), -// capabilities = Seq(iBusArbiterParameter, iBusArbiterParameter), -// pendingMax = 15 -// ) -// iBusDecoder.io.input << iBusArbiter.io.output.pipelined(cmdValid = true) -// -// val iMem = LiteDramNative(p.liteDram) -// io.iMem.fromBmb(iBusDecoder.io.outputs(1), wdataFifoSize = 0, rdataFifoSize = 32) -// -// -// val iBusDecoderToPeripheral = iBusDecoder.io.outputs(0).resize(dataWidth = 32).pipelined(cmdHalfRate = true, rspValid = true) -// val dBusDecoderToPeripheral = dBusDecoder.io.outputs(0).resize(dataWidth = 32).pipelined(cmdHalfRate = true, rspValid = true) -// -// val peripheralAccessLength = Math.max(iBusDecoder.io.outputs(0).p.lengthWidth, dBusDecoder.io.outputs(0).p.lengthWidth) -// val peripheralArbiter = BmbArbiter( -// p = dBusDecoder.io.outputs(0).p.copy( -// sourceWidth = List(iBusDecoderToPeripheral, dBusDecoderToPeripheral).map(_.p.sourceWidth).max + 1, -// contextWidth = List(iBusDecoderToPeripheral, dBusDecoderToPeripheral).map(_.p.contextWidth).max, -// lengthWidth = peripheralAccessLength, -// dataWidth = 32 -// ), -// portCount = 2, -// lowerFirstPriority = true -// ) -// peripheralArbiter.io.inputs(0) << iBusDecoderToPeripheral -// peripheralArbiter.io.inputs(1) << dBusDecoderToPeripheral -// -// val peripheralWishbone = peripheralArbiter.io.output.pipelined(cmdValid = true).toWishbone() -// io.peripheral << peripheralWishbone -// -// val plic = new Area{ -// val priorityWidth = 2 -// -// val gateways = for(i <- 1 until 32) yield PlicGatewayActiveHigh( -// source = io.interrupts(i), -// id = i, -// priorityWidth = priorityWidth -// ) -// -// val bus = WishboneSlaveFactory(io.plic) -// -// val targets = for(i <- 0 until cpuCount) yield new Area{ -// val machine = PlicTarget( -// gateways = gateways, -// priorityWidth = priorityWidth -// ) -// val supervisor = PlicTarget( -// gateways = gateways, -// priorityWidth = priorityWidth -// ) -// -// cluster.io.externalInterrupts(i) := machine.iep -// cluster.io.externalSupervisorInterrupts(i) := supervisor.iep -// } -// -// val bridge = PlicMapper(bus, PlicMapping.sifive)( -// gateways = gateways, -// targets = targets.flatMap(t => List(t.machine, t.supervisor)) -// ) -// } -//} -// -//object VexRiscvLitexSmpClusterGen extends App { -// for(cpuCount <- List(1,2,4,8)) { -// def parameter = VexRiscvLitexSmpClusterParameter( -// cluster = VexRiscvSmpClusterParameter( -// cpuConfigs = List.tabulate(cpuCount) { hartId => -// vexRiscvConfig( -// hartId = hartId, -// ioRange = address => address.msb, -// resetVector = 0 -// ) -// } -// ), -// liteDram = LiteDramNativeParameter(addressWidth = 32, dataWidth = 128), -// liteDramMapping = SizeMapping(0x40000000l, 0x40000000l) -// ) -// -// def dutGen = { -// val toplevel = VexRiscvLitexSmpCluster( -// p = parameter, -// debugClockDomain = ClockDomain.current.copy(reset = Bool().setName("debugResetIn")), -// jtagClockDomain = ClockDomain.external("jtag", withReset = false) -// ) -// toplevel -// } -// -// val genConfig = SpinalConfig().addStandardMemBlackboxing(blackboxByteEnables) -// // genConfig.generateVerilog(Bench.compressIo(dutGen)) -// genConfig.generateVerilog(dutGen.setDefinitionName(s"VexRiscvLitexSmpCluster_${cpuCount}c")) -// } -// -//} -// -// -//object VexRiscvLitexSmpClusterOpenSbi extends App{ -// import spinal.core.sim._ -// -// val simConfig = SimConfig -// simConfig.withWave -// simConfig.allOptimisation -// -// val cpuCount = 2 -// -// def parameter = VexRiscvLitexSmpClusterParameter( -// cluster = VexRiscvSmpClusterParameter( -// cpuConfigs = List.tabulate(cpuCount) { hartId => -// vexRiscvConfig( -// hartId = hartId, -// ioRange = address => address(31 downto 28) === 0xF, -// resetVector = 0x80000000l -// ) -// } -// ), -// liteDram = LiteDramNativeParameter(addressWidth = 32, dataWidth = 128), -// liteDramMapping = SizeMapping(0x80000000l, 0x70000000l) -// ) -// -// def dutGen = { -// val top = VexRiscvLitexSmpCluster( -// p = parameter, -// debugClockDomain = ClockDomain.current.copy(reset = Bool().setName("debugResetIn")), -// jtagClockDomain = ClockDomain.external("jtag", withReset = false) -// ) -// top.rework{ -// top.io.clint.setAsDirectionLess.allowDirectionLessIo -// top.io.peripheral.setAsDirectionLess.allowDirectionLessIo.simPublic() -// -// val hit = (top.io.peripheral.ADR <<2 >= 0xF0010000l && top.io.peripheral.ADR<<2 < 0xF0020000l) -// top.io.clint.CYC := top.io.peripheral.CYC && hit -// top.io.clint.STB := top.io.peripheral.STB -// top.io.clint.WE := top.io.peripheral.WE -// top.io.clint.ADR := top.io.peripheral.ADR.resized -// top.io.clint.DAT_MOSI := top.io.peripheral.DAT_MOSI -// top.io.peripheral.DAT_MISO := top.io.clint.DAT_MISO -// top.io.peripheral.ACK := top.io.peripheral.CYC && (!hit || top.io.clint.ACK) -// top.io.peripheral.ERR := False -// +object VexRiscvLitexSmpClusterOpenSbi extends App{ + import spinal.core.sim._ + + val simConfig = SimConfig + simConfig.withWave + simConfig.allOptimisation + + val cpuCount = 2 + + def parameter = VexRiscvLitexSmpClusterParameter( + cluster = VexRiscvSmpClusterParameter( + cpuConfigs = List.tabulate(cpuCount) { hartId => + vexRiscvConfig( + hartId = hartId, + ioRange = address => address(31 downto 28) === 0xF, + resetVector = 0x80000000l + ) + } + ), + liteDram = LiteDramNativeParameter(addressWidth = 32, dataWidth = 128), + liteDramMapping = SizeMapping(0x80000000l, 0x70000000l) + ) + + def dutGen = { + val top = new VexRiscvLitexSmpCluster( + p = parameter + ).toComponent() + top.rework{ + top.clintWishbone.setAsDirectionLess.allowDirectionLessIo + top.peripheral.setAsDirectionLess.allowDirectionLessIo.simPublic() + + val hit = (top.peripheral.ADR <<2 >= 0xF0010000l && top.peripheral.ADR<<2 < 0xF0020000l) + top.clintWishbone.CYC := top.peripheral.CYC && hit + top.clintWishbone.STB := top.peripheral.STB + top.clintWishbone.WE := top.peripheral.WE + top.clintWishbone.ADR := top.peripheral.ADR.resized + top.clintWishbone.DAT_MOSI := top.peripheral.DAT_MOSI + top.peripheral.DAT_MISO := top.clintWishbone.DAT_MISO + top.peripheral.ACK := top.peripheral.CYC && (!hit || top.clintWishbone.ACK) + top.peripheral.ERR := False + // top.dMemBridge.unburstified.cmd.simPublic() -// } -// top -// } -// simConfig.compile(dutGen).doSimUntilVoid(seed = 42){dut => -// dut.clockDomain.forkStimulus(10) -// fork { -// dut.debugClockDomain.resetSim #= false -// sleep (0) -// dut.debugClockDomain.resetSim #= true -// sleep (10) -// dut.debugClockDomain.resetSim #= false -// } -// -// -// val ram = SparseMemory() -// ram.loadBin(0x80000000l, "../opensbi/build/platform/spinal/vexriscv/sim/smp/firmware/fw_jump.bin") -// ram.loadBin(0xC0000000l, "../buildroot/output/images/Image") -// ram.loadBin(0xC1000000l, "../buildroot/output/images/dtb") -// ram.loadBin(0xC2000000l, "../buildroot/output/images/rootfs.cpio") -// -// -// dut.io.iMem.simSlave(ram, dut.clockDomain) -// dut.io.dMem.simSlave(ram, dut.clockDomain, dut.dMemBridge.unburstified) -// -// dut.io.interrupts #= 0 -// -// dut.clockDomain.onFallingEdges{ -// if(dut.io.peripheral.CYC.toBoolean){ -// (dut.io.peripheral.ADR.toLong << 2) match { -// case 0xF0000000l => print(dut.io.peripheral.DAT_MOSI.toLong.toChar) -// case 0xF0000004l => dut.io.peripheral.DAT_MISO #= (if(System.in.available() != 0) System.in.read() else 0xFFFFFFFFl) -// case _ => -// } -//// println(f"${dut.io.peripheral.ADR.toLong}%x") -// } -// } -// -//// fork{ -//// disableSimWave() -//// val atMs = 3790 -//// val durationMs = 5 -//// sleep(atMs*1000000l) -//// enableSimWave() -//// println("** enableSimWave **") -//// sleep(durationMs*1000000l) -//// println("** disableSimWave **") -//// while(true) { -//// disableSimWave() -//// sleep(100000 * 10) -//// enableSimWave() -//// sleep( 100 * 10) -//// } -//// // simSuccess() -//// } -// -// fork{ -// while(true) { -// disableSimWave() -// sleep(100000 * 10) -// enableSimWave() -// sleep( 100 * 10) -// } -// } -// } -// } \ No newline at end of file + } + top + } + simConfig.compile(dutGen).doSimUntilVoid(seed = 42){dut => + dut.debugCd.inputClockDomain.get.forkStimulus(10) + + val ram = SparseMemory() + ram.loadBin(0x80000000l, "../opensbi/build/platform/spinal/vexriscv/sim/smp/firmware/fw_jump.bin") + ram.loadBin(0xC0000000l, "../buildroot/output/images/Image") + ram.loadBin(0xC1000000l, "../buildroot/output/images/dtb") + ram.loadBin(0xC2000000l, "../buildroot/output/images/rootfs.cpio") + + + dut.iBridge.dram.simSlave(ram, dut.debugCd.inputClockDomain) + dut.dBridge.dram.simSlave(ram, dut.debugCd.inputClockDomain/*, dut.dMemBridge.unburstified*/) + + dut.interrupts.get #= 0 + + dut.debugCd.inputClockDomain.get.onFallingEdges{ + if(dut.peripheral.CYC.toBoolean){ + (dut.peripheral.ADR.toLong << 2) match { + case 0xF0000000l => print(dut.peripheral.DAT_MOSI.toLong.toChar) + case 0xF0000004l => dut.peripheral.DAT_MISO #= (if(System.in.available() != 0) System.in.read() else 0xFFFFFFFFl) + case _ => + } + } + } + + fork{ + while(true) { + disableSimWave() + sleep(100000 * 10) + enableSimWave() + sleep( 100 * 10) + } + } + } +} \ No newline at end of file From c51e25f8c48303b86e370a56a3131e81c5611a09 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sun, 5 Jul 2020 13:15:44 +0200 Subject: [PATCH 463/951] Litex SoC add coherent DMA master --- ...nTwoStage.scala => GenTwoThreeStage.scala} | 13 ++- .../demo/smp/VexRiscvSmpCluster.scala | 104 +----------------- .../demo/smp/VexRiscvSmpLitexCluster.scala | 13 +++ .../demo/smp/VexRiscvSmpLitexMpCluster.scala | 100 ++++++++++++----- 4 files changed, 94 insertions(+), 136 deletions(-) rename src/main/scala/vexriscv/demo/{GenTwoStage.scala => GenTwoThreeStage.scala} (87%) diff --git a/src/main/scala/vexriscv/demo/GenTwoStage.scala b/src/main/scala/vexriscv/demo/GenTwoThreeStage.scala similarity index 87% rename from src/main/scala/vexriscv/demo/GenTwoStage.scala rename to src/main/scala/vexriscv/demo/GenTwoThreeStage.scala index b3d08047..c3dd0db7 100644 --- a/src/main/scala/vexriscv/demo/GenTwoStage.scala +++ b/src/main/scala/vexriscv/demo/GenTwoThreeStage.scala @@ -4,12 +4,13 @@ import spinal.core.SpinalVerilog import vexriscv.{VexRiscv, VexRiscvConfig, plugin} import vexriscv.plugin.{BranchPlugin, CsrPlugin, CsrPluginConfig, DBusSimplePlugin, DecoderSimplePlugin, DivPlugin, FullBarrelShifterPlugin, HazardSimplePlugin, IBusSimplePlugin, IntAluPlugin, LightShifterPlugin, MulPlugin, MulSimplePlugin, NONE, RegFilePlugin, SrcPlugin, YamlPlugin} -object GenTwoStage extends App{ +object GenTwoThreeStage extends App{ def cpu(withMulDiv : Boolean, bypass : Boolean, - barrielShifter : Boolean) = new VexRiscv( + barrielShifter : Boolean, + withMemoryStage : Boolean) = new VexRiscv( config = VexRiscvConfig( - withMemoryStage = false, + withMemoryStage = withMemoryStage, withWriteBackStage = false, plugins = List( new IBusSimplePlugin( @@ -42,8 +43,8 @@ object GenTwoStage extends App{ ), new HazardSimplePlugin( bypassExecute = bypass, - bypassMemory = false, - bypassWriteBack = false, + bypassMemory = bypass, + bypassWriteBack = bypass, bypassWriteBackBuffer = bypass, pessimisticUseSrc = false, pessimisticWriteRegFile = false, @@ -67,5 +68,5 @@ object GenTwoStage extends App{ ) ) - SpinalVerilog(cpu(false,false,false)) + SpinalVerilog(cpu(true,true,true,true)) } diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index 471463c8..7cc16516 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -108,104 +108,6 @@ class VexRiscvSmpClusterWithPeripherals(p : VexRiscvSmpClusterParameter) extends } - -//case class VexRiscvSmpCluster(p : VexRiscvSmpClusterParameter, -// debugClockDomain : ClockDomain) extends Component{ -// val dBusParameter = p.cpuConfigs.head.plugins.find(_.isInstanceOf[DBusCachedPlugin]).get.asInstanceOf[DBusCachedPlugin].config.getBmbParameter() -// val dBusArbiterParameter = dBusParameter.copy(sourceWidth = log2Up(p.cpuConfigs.size)) -// val exclusiveMonitorParameter = dBusArbiterParameter -// val invalidateMonitorParameter = BmbExclusiveMonitor.outputParameter(exclusiveMonitorParameter) -// val dMemParameter = BmbInvalidateMonitor.outputParameter(invalidateMonitorParameter) -// -// val iBusParameter = p.cpuConfigs.head.plugins.find(_.isInstanceOf[IBusCachedPlugin]).get.asInstanceOf[IBusCachedPlugin].config.getBmbParameter() -// val iBusArbiterParameter = iBusParameter//.copy(sourceWidth = log2Up(p.cpuConfigs.size)) -// val iMemParameter = iBusArbiterParameter -// -// val io = new Bundle { -// val dMem = master(Bmb(dMemParameter)) -//// val iMem = master(Bmb(iMemParameter)) -// val iMems = Vec(master(Bmb(iMemParameter)), p.cpuConfigs.size) -// val timerInterrupts = in Bits(p.cpuConfigs.size bits) -// val externalInterrupts = in Bits(p.cpuConfigs.size bits) -// val softwareInterrupts = in Bits(p.cpuConfigs.size bits) -// val externalSupervisorInterrupts = in Bits(p.cpuConfigs.size bits) -// val debugBus = slave(Bmb(SystemDebuggerConfig().getBmbParameter.copy(addressWidth = 20))) -// val debugReset = out Bool() -// val time = in UInt(64 bits) -// } -// -// io.debugReset := False -// val cpus = for((cpuConfig, cpuId) <- p.cpuConfigs.zipWithIndex) yield new Area{ -// var iBus : Bmb = null -// var dBus : Bmb = null -// var debug : Bmb = null -// cpuConfig.plugins.foreach { -// case plugin: DebugPlugin => debugClockDomain{ -// plugin.debugClockDomain = debugClockDomain -// } -// case _ => -// } -// cpuConfig.plugins += new DebugPlugin(debugClockDomain) -// val core = new VexRiscv(cpuConfig) -// core.plugins.foreach { -// case plugin: IBusCachedPlugin => iBus = plugin.iBus.toBmb() -// case plugin: DBusCachedPlugin => dBus = plugin.dBus.toBmb().pipelined(cmdValid = true) -// case plugin: CsrPlugin => { -// plugin.softwareInterrupt := io.softwareInterrupts(cpuId) -// plugin.externalInterrupt := io.externalInterrupts(cpuId) -// plugin.timerInterrupt := io.timerInterrupts(cpuId) -// if (plugin.config.supervisorGen) plugin.externalInterruptS := io.externalSupervisorInterrupts(cpuId) -// if (plugin.utime != null) plugin.utime := io.time -// } -// case plugin: DebugPlugin => debugClockDomain{ -// io.debugReset setWhen(RegNext(plugin.io.resetOut)) -// debug = plugin.io.bus.fromBmb() -// } -// case _ => -// } -// } -// -// val dBusArbiter = BmbArbiter( -// p = dBusArbiterParameter, -// portCount = cpus.size, -// lowerFirstPriority = false, -// inputsWithInv = cpus.map(_ => true), -// inputsWithSync = cpus.map(_ => true), -// pendingInvMax = 16 -// ) -// -// (dBusArbiter.io.inputs, cpus).zipped.foreach(_ << _.dBus.pipelined(invValid = true, ackValid = true, syncValid = true)) -// -// val exclusiveMonitor = BmbExclusiveMonitor( -// inputParameter = exclusiveMonitorParameter, -// pendingWriteMax = 64 -// ) -// exclusiveMonitor.io.input << dBusArbiter.io.output.pipelined(cmdValid = true, cmdReady = true, rspValid = true) -// -// val invalidateMonitor = BmbInvalidateMonitor( -// inputParameter = invalidateMonitorParameter, -// pendingInvMax = 16 -// ) -// invalidateMonitor.io.input << exclusiveMonitor.io.output -// -// io.dMem << invalidateMonitor.io.output -// -// (io.iMems, cpus).zipped.foreach(_ << _.iBus) -// -// val debug = debugClockDomain on new Area{ -// val arbiter = BmbDecoder( -// p = io.debugBus.p, -// mappings = List.tabulate(p.cpuConfigs.size)(i => SizeMapping(0x00000 + i*0x1000, 0x1000)), -// capabilities = List.fill(p.cpuConfigs.size)(io.debugBus.p), -// pendingMax = 2 -// ) -// arbiter.io.input << io.debugBus -// (arbiter.io.outputs, cpus.map(_.debug)).zipped.foreach(_ >> _) -// } -//} -// -// -// object VexRiscvSmpClusterGen { def vexRiscvConfig(hartId : Int, ioRange : UInt => Bool = (x => x(31 downto 28) === 0xF), @@ -222,7 +124,7 @@ object VexRiscvSmpClusterGen { new IBusCachedPlugin( resetVector = resetVector, compressedGen = false, - prediction = STATIC, + prediction = vexriscv.plugin.NONE, historyRamSizeLog2 = 9, relaxPredictorAddress = true, injectorStage = false, @@ -309,7 +211,7 @@ object VexRiscvSmpClusterGen { ), new CsrPlugin(CsrPluginConfig.openSbi(mhartid = hartId, misa = Riscv.misaToInt("imas")).copy(utimeAccess = CsrAccess.READ_ONLY)), new BranchPlugin( - earlyBranch = false, + earlyBranch = true, catchAddressMisaligned = true, fenceiGenAsAJump = false ), @@ -318,6 +220,8 @@ object VexRiscvSmpClusterGen { ) config } + + // def vexRiscvCluster(cpuCount : Int, resetVector : Long = 0x80000000l) = VexRiscvSmpCluster( // debugClockDomain = ClockDomain.current.copy(reset = Bool().setName("debugResetIn")), // p = VexRiscvSmpClusterParameter( diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala index e5cda937..910fc23b 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala @@ -3,8 +3,10 @@ package vexriscv.demo.smp import spinal.core._ import spinal.lib.bus.bmb._ import spinal.lib.bus.misc.{AddressMapping, DefaultMapping, SizeMapping} +import spinal.lib.bus.wishbone.{WishboneConfig, WishboneToBmbGenerator} import spinal.lib.sim.SparseMemory import vexriscv.demo.smp.VexRiscvSmpClusterGen.vexRiscvConfig +import vexriscv.plugin.DBusCachedPlugin case class VexRiscvLitexSmpClusterParameter( cluster : VexRiscvSmpClusterParameter, @@ -27,6 +29,17 @@ class VexRiscvLitexSmpCluster(p : VexRiscvLitexSmpClusterParameter) extends VexR dBridge.liteDramParameter.load(p.liteDram) iBridge.liteDramParameter.load(p.liteDram) + // Coherent DMA interface + val dmaBridge = WishboneToBmbGenerator() + val dmaWishbone = dmaBridge.produceIo(dmaBridge.logic.io.input) + val dmaDataWidth = p.cluster.cpuConfigs.head.find(classOf[DBusCachedPlugin]).get.config.memDataWidth + dmaBridge.config.load(WishboneConfig( + addressWidth = 32-log2Up(dmaDataWidth/8), + dataWidth = p.cluster.cpuConfigs.head.find(classOf[DBusCachedPlugin]).get.config.memDataWidth, + useSTALL = true + )) + interconnect.addConnection(dmaBridge.bmb, exclusiveMonitor.input) + // Interconnect pipelining (FMax) for(core <- cores) { interconnect.setPipelining(core.cpu.dBus)(cmdValid = true, cmdReady = true, rspValid = true) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexMpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexMpCluster.scala index 94ccf8f4..a2f35636 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexMpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexMpCluster.scala @@ -1,33 +1,73 @@ -//package vexriscv.demo.smp -// -//import spinal.core._ -//import spinal.lib.bus.bmb._ -//import spinal.lib.bus.wishbone.{Wishbone, WishboneConfig, WishboneSlaveFactory} -//import spinal.lib.com.jtag.{Jtag, JtagTap, JtagTapInstructionCtrl} -//import spinal.lib._ -//import spinal.lib.blackbox.xilinx.s7.BSCANE2 -//import spinal.lib.bus.bmb.sim.{BmbMemoryMultiPort, BmbMemoryTester} -//import spinal.lib.bus.misc.{AddressMapping, DefaultMapping, SizeMapping} -//import spinal.lib.com.jtag.sim.JtagTcp -//import spinal.lib.com.jtag.xilinx.Bscane2BmbMaster -//import spinal.lib.eda.bench.Bench -//import spinal.lib.misc.Clint -//import spinal.lib.misc.plic.{PlicGatewayActiveHigh, PlicMapper, PlicMapping, PlicTarget} -//import spinal.lib.sim.{SimData, SparseMemory, StreamDriver, StreamMonitor, StreamReadyRandomizer} -//import spinal.lib.system.debugger.{JtagBridgeNoTap, SystemDebugger, SystemDebuggerConfig} -//import sun.jvm.hotspot.oops.DataLayout -//import vexriscv.demo.smp.VexRiscvLitexSmpMpClusterOpenSbi.{cpuCount, parameter} -//import vexriscv.demo.smp.VexRiscvSmpClusterGen.vexRiscvConfig -//import vexriscv.{VexRiscv, VexRiscvConfig} -//import vexriscv.plugin.{CsrPlugin, DBusCachedPlugin, DebugPlugin, IBusCachedPlugin} -// -//import scala.collection.mutable -//import scala.util.Random -// -// -//case class VexRiscvLitexSmpMpClusterParameter( cluster : VexRiscvSmpClusterParameter, -// liteDram : LiteDramNativeParameter, -// liteDramMapping : AddressMapping) +package vexriscv.demo.smp + +import spinal.core._ +import spinal.lib.bus.bmb._ +import spinal.lib.bus.misc.{AddressMapping, DefaultMapping, SizeMapping} +import spinal.lib.bus.wishbone.{WishboneConfig, WishboneToBmbGenerator} +import spinal.lib.sim.SparseMemory +import vexriscv.demo.smp.VexRiscvSmpClusterGen.vexRiscvConfig + +case class VexRiscvLitexSmpMpClusterParameter( cluster : VexRiscvSmpClusterParameter, + liteDram : LiteDramNativeParameter, + liteDramMapping : AddressMapping) + +class VexRiscvLitexSmpMpCluster(p : VexRiscvLitexSmpMpClusterParameter) extends VexRiscvSmpClusterWithPeripherals(p.cluster) { + val iArbiter = BmbSmpBridgeGenerator() + val iBridge = BmbToLiteDramGenerator(p.liteDramMapping) + val dBridge = BmbToLiteDramGenerator(p.liteDramMapping) + + for(core <- cores) interconnect.addConnection(core.cpu.iBus -> List(iArbiter.bmb)) + interconnect.addConnection( + iArbiter.bmb -> List(iBridge.bmb, peripheralBridge.bmb), + invalidationMonitor.output -> List(dBridge.bmb, peripheralBridge.bmb) + ) + interconnect.masters(invalidationMonitor.output).withOutOfOrderDecoder() + + dBridge.liteDramParameter.load(p.liteDram) + iBridge.liteDramParameter.load(p.liteDram) + + // Interconnect pipelining (FMax) + for(core <- cores) { + interconnect.setPipelining(core.cpu.dBus)(cmdValid = true, cmdReady = true, rspValid = true) + interconnect.setPipelining(core.cpu.iBus)(cmdHalfRate = true, rspValid = true) + interconnect.setPipelining(iArbiter.bmb)(cmdHalfRate = true, rspValid = true) + } + interconnect.setPipelining(invalidationMonitor.output)(cmdValid = true, cmdReady = true, rspValid = true) + interconnect.setPipelining(peripheralBridge.bmb)(cmdHalfRate = true, rspValid = true) +} + + +object VexRiscvLitexSmpMpClusterGen extends App { + for(cpuCount <- List(1,2,4,8)) { + def parameter = VexRiscvLitexSmpMpClusterParameter( + cluster = VexRiscvSmpClusterParameter( + cpuConfigs = List.tabulate(cpuCount) { hartId => + vexRiscvConfig( + hartId = hartId, + ioRange = address => address.msb, + resetVector = 0 + ) + } + ), + liteDram = LiteDramNativeParameter(addressWidth = 32, dataWidth = 128), + liteDramMapping = SizeMapping(0x40000000l, 0x40000000l) + ) + + def dutGen = { + val toplevel = new VexRiscvLitexSmpMpCluster( + p = parameter + ).toComponent() + toplevel + } + + val genConfig = SpinalConfig().addStandardMemBlackboxing(blackboxByteEnables) + // genConfig.generateVerilog(Bench.compressIo(dutGen)) + genConfig.generateVerilog(dutGen.setDefinitionName(s"VexRiscvLitexSmpMpCluster_${cpuCount}c")) + } +} + + + // ////addAttribute("""mark_debug = "true"""") //class VexRiscvLitexSmpMpCluster(val p : VexRiscvLitexSmpMpClusterParameter, From a404078117b6111cb79c3906ba31836b5c537700 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sun, 5 Jul 2020 13:16:39 +0200 Subject: [PATCH 464/951] Few fixes --- src/main/scala/vexriscv/VexRiscv.scala | 6 ++ .../scala/vexriscv/VexRiscvBmbGenerator.scala | 12 ++- .../scala/vexriscv/demo/SynthesisBench.scala | 71 ++++++++++++-- src/main/scala/vexriscv/ip/DataCache.scala | 3 +- src/test/cpp/regression/main.cpp | 21 ++-- src/test/scala/vexriscv/DhrystoneBench.scala | 98 +++++++++++-------- .../vexriscv/TestIndividualFeatures.scala | 3 +- 7 files changed, 151 insertions(+), 63 deletions(-) diff --git a/src/main/scala/vexriscv/VexRiscv.scala b/src/main/scala/vexriscv/VexRiscv.scala index 3350dc9e..5f7865cf 100644 --- a/src/main/scala/vexriscv/VexRiscv.scala +++ b/src/main/scala/vexriscv/VexRiscv.scala @@ -23,6 +23,12 @@ case class VexRiscvConfig(){ val plugins = ArrayBuffer[Plugin[VexRiscv]]() def add(that : Plugin[VexRiscv]) : this.type = {plugins += that;this} + def find[T](clazz: Class[T]): Option[T] = { + plugins.find(_.getClass == clazz) match { + case Some(x) => Some(x.asInstanceOf[T]) + case None => None + } + } //Default Stageables object IS_RVC extends Stageable(Bool) diff --git a/src/main/scala/vexriscv/VexRiscvBmbGenerator.scala b/src/main/scala/vexriscv/VexRiscvBmbGenerator.scala index d7d578fa..5460299e 100644 --- a/src/main/scala/vexriscv/VexRiscvBmbGenerator.scala +++ b/src/main/scala/vexriscv/VexRiscvBmbGenerator.scala @@ -1,7 +1,7 @@ package vexriscv import spinal.core._ -import spinal.lib.bus.bmb.{Bmb, BmbAccessCapabilities, BmbAccessParameter, BmbImplicitDebugDecoder, BmbParameter, BmbSmpInterconnectGenerator} +import spinal.lib.bus.bmb.{Bmb, BmbAccessCapabilities, BmbAccessParameter, BmbImplicitDebugDecoder, BmbInvalidationParameter, BmbParameter, BmbSmpInterconnectGenerator} import spinal.lib.bus.misc.AddressMapping import spinal.lib.com.jtag.{Jtag, JtagTapInstructionCtrl} import spinal.lib.generator._ @@ -148,9 +148,17 @@ case class VexRiscvBmbGenerator()(implicit interconnectSmp: BmbSmpInterconnectGe } } + val invalidationSource = Handle[BmbInvalidationParameter] + val invalidationRequirements = Handle[BmbInvalidationParameter] if(interconnectSmp != null){ interconnectSmp.addMaster(accessRequirements = parameterGenerator.iBusParameter.derivate(_.access), bus = iBus) - interconnectSmp.addMaster(accessRequirements = parameterGenerator.dBusParameter.derivate(_.access), bus = dBus) + interconnectSmp.addMaster( + accessRequirements = parameterGenerator.dBusParameter.derivate(_.access), + invalidationSource = invalidationSource, + invalidationCapabilities = invalidationSource, + invalidationRequirements = invalidationRequirements, + bus = dBus + ) } } diff --git a/src/main/scala/vexriscv/demo/SynthesisBench.scala b/src/main/scala/vexriscv/demo/SynthesisBench.scala index b6e9f2fd..d0a21186 100644 --- a/src/main/scala/vexriscv/demo/SynthesisBench.scala +++ b/src/main/scala/vexriscv/demo/SynthesisBench.scala @@ -54,39 +54,86 @@ object VexRiscvSynthesisBench { val twoStage = new Rtl { override def getName(): String = "VexRiscv two stages" override def getRtlPath(): String = "VexRiscvTwoStages.v" - SpinalVerilog(wrap(GenTwoStage.cpu( + SpinalVerilog(wrap(GenTwoThreeStage.cpu( withMulDiv = false, bypass = false, - barrielShifter = false + barrielShifter = false, + withMemoryStage = false )).setDefinitionName(getRtlPath().split("\\.").head)) } val twoStageBarell = new Rtl { override def getName(): String = "VexRiscv two stages with barriel" override def getRtlPath(): String = "VexRiscvTwoStagesBar.v" - SpinalVerilog(wrap(GenTwoStage.cpu( + SpinalVerilog(wrap(GenTwoThreeStage.cpu( withMulDiv = false, bypass = true, - barrielShifter = true + barrielShifter = true, + withMemoryStage = false )).setDefinitionName(getRtlPath().split("\\.").head)) } val twoStageMulDiv = new Rtl { override def getName(): String = "VexRiscv two stages with Mul Div" override def getRtlPath(): String = "VexRiscvTwoStagesMD.v" - SpinalVerilog(wrap(GenTwoStage.cpu( + SpinalVerilog(wrap(GenTwoThreeStage.cpu( withMulDiv = true, bypass = false, - barrielShifter = false + barrielShifter = false, + withMemoryStage = false )).setDefinitionName(getRtlPath().split("\\.").head)) } val twoStageAll = new Rtl { override def getName(): String = "VexRiscv two stages with Mul Div fast" override def getRtlPath(): String = "VexRiscvTwoStagesMDfast.v" - SpinalVerilog(wrap(GenTwoStage.cpu( + SpinalVerilog(wrap(GenTwoThreeStage.cpu( withMulDiv = true, bypass = true, - barrielShifter = true + barrielShifter = true, + withMemoryStage = false )).setDefinitionName(getRtlPath().split("\\.").head)) } + + + val threeStage = new Rtl { + override def getName(): String = "VexRiscv three stages" + override def getRtlPath(): String = "VexRiscvThreeStages.v" + SpinalVerilog(wrap(GenTwoThreeStage.cpu( + withMulDiv = false, + bypass = false, + barrielShifter = false, + withMemoryStage = true + )).setDefinitionName(getRtlPath().split("\\.").head)) + } + val threeStageBarell = new Rtl { + override def getName(): String = "VexRiscv three stages with barriel" + override def getRtlPath(): String = "VexRiscvThreeStagesBar.v" + SpinalVerilog(wrap(GenTwoThreeStage.cpu( + withMulDiv = false, + bypass = true, + barrielShifter = true, + withMemoryStage = true + )).setDefinitionName(getRtlPath().split("\\.").head)) + } + val threeStageMulDiv = new Rtl { + override def getName(): String = "VexRiscv three stages with Mul Div" + override def getRtlPath(): String = "VexRiscvThreeStagesMD.v" + SpinalVerilog(wrap(GenTwoThreeStage.cpu( + withMulDiv = true, + bypass = false, + barrielShifter = false, + withMemoryStage = true + )).setDefinitionName(getRtlPath().split("\\.").head)) + } + val threeStageAll = new Rtl { + override def getName(): String = "VexRiscv three stages with Mul Div fast" + override def getRtlPath(): String = "VexRiscvThreeStagesMDfast.v" + SpinalVerilog(wrap(GenTwoThreeStage.cpu( + withMulDiv = true, + bypass = true, + barrielShifter = true, + withMemoryStage = true + )).setDefinitionName(getRtlPath().split("\\.").head)) + } + val smallestNoCsr = new Rtl { override def getName(): String = "VexRiscv smallest no CSR" override def getRtlPath(): String = "VexRiscvSmallestNoCsr.v" @@ -155,8 +202,12 @@ object VexRiscvSynthesisBench { -// val rtls = List(twoStage, twoStageBarell, twoStageMulDiv, twoStageAll, smallestNoCsr, smallest, smallAndProductive, smallAndProductiveWithICache, fullNoMmuNoCache, noCacheNoMmuMaxPerf, fullNoMmuMaxPerf, fullNoMmu, full, linuxBalanced, linuxBalancedSmp) - val rtls = List(linuxBalanced, linuxBalancedSmp) + val rtls = List( + twoStage, twoStageBarell, twoStageMulDiv, twoStageAll, + threeStage, threeStageBarell, threeStageMulDiv, threeStageAll, + smallestNoCsr, smallest, smallAndProductive, smallAndProductiveWithICache, fullNoMmuNoCache, noCacheNoMmuMaxPerf, fullNoMmuMaxPerf, fullNoMmu, full, linuxBalanced, linuxBalancedSmp + ) +// val rtls = List(linuxBalanced, linuxBalancedSmp) // val rtls = List(smallest) val targets = XilinxStdTargets() ++ AlteraStdTargets() ++ IcestormStdTargets().take(1) ++ List( new Target { diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index d5e688c4..78f96078 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -88,7 +88,8 @@ case class DataCacheConfig(cacheSize : Int, lengthWidth = log2Up(this.bytePerLine), contextWidth = (if(!withWriteResponse) 1 else 0) + (if(cpuDataWidth != memDataWidth) log2Up(memDataBytes) else 0), alignment = BmbParameter.BurstAlignement.LENGTH, - canExclusive = withExclusive + canExclusive = withExclusive, + withCachedRead = true )), BmbInvalidationParameter( canInvalidate = withInvalidate, diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 54685459..bc960fb8 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -1248,8 +1248,13 @@ public: }; CpuRef riscvRef = CpuRef(this); - + string vcdName; + Workspace* setVcdName(string name){ + vcdName = name; + return this; + } Workspace(string name){ + vcdName = name; //seed = VL_RANDOM_I(32)^VL_RANDOM_I(32)^0x1093472; //srand48(seed); // setIStall(false); @@ -1450,7 +1455,7 @@ public: Verilated::traceEverOn(true); tfp = new VerilatedVcdC; top->trace(tfp, 99); - tfp->open((string(name)+ ".vcd").c_str()); + tfp->open((vcdName + ".vcd").c_str()); #endif // Reset @@ -1679,7 +1684,7 @@ public: - dump(i); + dump(i+2); dump(i+10); #ifdef TRACE tfp->close(); @@ -1750,6 +1755,7 @@ public: #endif case 0xF00FFF48u: mTimeCmp = (mTimeCmp & 0xFFFFFFFF00000000) | *data;break; case 0xF00FFF4Cu: mTimeCmp = (mTimeCmp & 0x00000000FFFFFFFF) | (((uint64_t)*data) << 32); break; + case 0xF00FFF50u: cout << "mTime " << *data << " : " << mTime << endl; } if((addr & 0xFFFFF000) == 0xF5670000){ uint32_t t = 0x900FF000 | (addr & 0xFFF); @@ -3970,14 +3976,15 @@ int main(int argc, char **argv, char **env) { w.loadHex(RUN_HEX); w.withRiscvRef(); #endif - //w.setIStall(false); - //w.setDStall(false); + w.setIStall(false); + w.setDStall(false); #if defined(TRACE) || defined(TRACE_ACCESS) //w.setCyclesPerSecond(5e3); //printf("Speed reduced 5Khz\n"); #endif w.run(0xFFFFFFFFFFFF); + exit(0); } #endif @@ -4047,11 +4054,11 @@ int main(int argc, char **argv, char **env) { #ifndef COMPRESSED 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("../../cpp/raw/machineCsr/build/machineCsr",machineCsrRef, sizeof(machineCsrRef)/4).withRiscvRef()->run(10e4);) + redo(REDO,TestX28("../../cpp/raw/machineCsr/build/machineCsr",machineCsrRef, sizeof(machineCsrRef)/4).withRiscvRef()->setVcdName("machineCsr")->run(10e4);) #else 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, 14,2, 15,5,16,17,1 }; - redo(REDO,TestX28("../../cpp/raw/machineCsr/build/machineCsrCompressed",machineCsrRef, sizeof(machineCsrRef)/4).withRiscvRef()->run(10e4);) + redo(REDO,TestX28("../../cpp/raw/machineCsr/build/machineCsrCompressed",machineCsrRef, sizeof(machineCsrRef)/4).withRiscvRef()->setVcdName("machineCsrCompressed")->run(10e4);) #endif #endif // #ifdef MMU diff --git a/src/test/scala/vexriscv/DhrystoneBench.scala b/src/test/scala/vexriscv/DhrystoneBench.scala index 39c434a0..31c8c147 100644 --- a/src/test/scala/vexriscv/DhrystoneBench.scala +++ b/src/test/scala/vexriscv/DhrystoneBench.scala @@ -8,27 +8,34 @@ import vexriscv.demo._ import scala.sys.process._ -class DhrystoneBench extends FunSuite{ - def doCmd(cmd : String) : String = { +class DhrystoneBench extends FunSuite { + def doCmd(cmd: String): String = { val stdOut = new StringBuilder() - class Logger extends ProcessLogger {override def err(s: => String): Unit = {if(!s.startsWith("ar: creating ")) println(s)} + class Logger extends ProcessLogger { + override def err(s: => String): Unit = { + if (!s.startsWith("ar: creating ")) println(s) + } + override def out(s: => String): Unit = { println(s) stdOut ++= s } + override def buffer[T](f: => T) = f } Process(cmd, new File("src/test/cpp/regression")).!(new Logger) stdOut.toString() } + val report = new StringBuilder() - def getDmips(name : String, gen : => Unit, testCmd : String): Unit = { + + def getDmips(name: String, gen: => Unit, testCmd: String): Unit = { var genPassed = false test(name + "_gen") { gen genPassed = true } - test(name + "_test"){ + test(name + "_test") { assert(genPassed) val str = doCmd(testCmd) assert(!str.contains("FAIL")) @@ -37,48 +44,55 @@ class DhrystoneBench extends FunSuite{ val coremarkTicks = intFind.findFirstIn("Total ticks \\: (\\d+.?)+".r.findAllIn(str).toList.last).get.toDouble val coremarkIterations = intFind.findFirstIn("Iterations \\: (\\d+.?)+".r.findAllIn(str).toList.last).get.toDouble val coremarkHzs = intFind.findFirstIn("DCLOCKS_PER_SEC=(\\d+.?)+".r.findAllIn(str).toList.last).get.toDouble - val coremarkPerMhz =1e6*coremarkIterations/coremarkTicks + val coremarkPerMhz = 1e6 * coremarkIterations / coremarkTicks report ++= s"$name -> $dmips DMIPS/Mhz $coremarkPerMhz Coremark/Mhz\n" } } - getDmips( - name = "GenTwoStageArty", - gen = SpinalVerilog(GenTwoStage.cpu( - withMulDiv = false, - bypass = false, - barrielShifter = false - )), - testCmd = "make clean run REDO=10 IBUS=SIMPLE DBUS=SIMPLE CSR=no MMU=no DEBUG_PLUGIN=no MUL=no DIV=no COREMARK=yes" - ) - getDmips( - name = "GenTwoStageBarrielArty", - gen = SpinalVerilog(GenTwoStage.cpu( - withMulDiv = false, - bypass = true, - barrielShifter = true - )), - testCmd = "make clean run REDO=10 IBUS=SIMPLE DBUS=SIMPLE CSR=no MMU=no DEBUG_PLUGIN=no MUL=no DIV=no COREMARK=yes" - ) - getDmips( - name = "GenTwoStageMDArty", - gen = SpinalVerilog(GenTwoStage.cpu( - withMulDiv = true, - bypass = false, - barrielShifter = false - )), - testCmd = "make clean run REDO=10 IBUS=SIMPLE DBUS=SIMPLE CSR=no MMU=no DEBUG_PLUGIN=no MUL=yes DIV=yes COREMARK=yes" - ) - getDmips( - name = "GenTwoStageMDBarrielArty", - gen = SpinalVerilog(GenTwoStage.cpu( - withMulDiv = true, - bypass = true, - barrielShifter = true - )), - testCmd = "make clean run REDO=10 IBUS=SIMPLE DBUS=SIMPLE CSR=no MMU=no DEBUG_PLUGIN=no MUL=yes DIV=yes COREMARK=yes" - ) + for(withMemoryStage <- List(false, true)){ + val stages = if(withMemoryStage) "Three" else "Two" + getDmips( + name = s"Gen${stages}StageArty", + gen = SpinalVerilog(GenTwoThreeStage.cpu( + withMulDiv = false, + bypass = false, + barrielShifter = false, + withMemoryStage = withMemoryStage + )), + testCmd = "make clean run REDO=10 IBUS=SIMPLE DBUS=SIMPLE CSR=no MMU=no DEBUG_PLUGIN=no MUL=no DIV=no COREMARK=yes" + ) + getDmips( + name = s"Gen${stages}StageBarrielArty", + gen = SpinalVerilog(GenTwoThreeStage.cpu( + withMulDiv = false, + bypass = true, + barrielShifter = true, + withMemoryStage = withMemoryStage + )), + testCmd = "make clean run REDO=10 IBUS=SIMPLE DBUS=SIMPLE CSR=no MMU=no DEBUG_PLUGIN=no MUL=no DIV=no COREMARK=yes" + ) + getDmips( + name = s"Gen${stages}StageMDArty", + gen = SpinalVerilog(GenTwoThreeStage.cpu( + withMulDiv = true, + bypass = false, + barrielShifter = false, + withMemoryStage = withMemoryStage + )), + testCmd = "make clean run REDO=10 IBUS=SIMPLE DBUS=SIMPLE CSR=no MMU=no DEBUG_PLUGIN=no MUL=yes DIV=yes COREMARK=yes" + ) + getDmips( + name = s"Gen${stages}StageMDBarrielArty", + gen = SpinalVerilog(GenTwoThreeStage.cpu( + withMulDiv = true, + bypass = true, + barrielShifter = true, + withMemoryStage = withMemoryStage + )), + testCmd = "make clean run REDO=10 IBUS=SIMPLE DBUS=SIMPLE CSR=no MMU=no DEBUG_PLUGIN=no MUL=yes DIV=yes COREMARK=yes" + ) + } getDmips( name = "GenSmallestNoCsr", diff --git a/src/test/scala/vexriscv/TestIndividualFeatures.scala b/src/test/scala/vexriscv/TestIndividualFeatures.scala index f3f5b28e..6139bad1 100644 --- a/src/test/scala/vexriscv/TestIndividualFeatures.scala +++ b/src/test/scala/vexriscv/TestIndividualFeatures.scala @@ -669,6 +669,7 @@ class TestIndividualFeatures extends MultithreadedFunSuite(sys.env.getOrElse("VE val zephyrCount = sys.env.getOrElse("VEXRISCV_REGRESSION_ZEPHYR_COUNT", "4") val demwRate = sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_DEMW_RATE", "0.6").toDouble val demRate = sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_DEM_RATE", "0.5").toDouble + val stopOnError = sys.env.getOrElse("VEXRISCV_REGRESSION_STOP_ON_ERROR", "no") val lock = new{} @@ -740,7 +741,7 @@ class TestIndividualFeatures extends MultithreadedFunSuite(sys.env.getOrElse("VE //Test RTL val debug = true - val stdCmd = (s"make run REGRESSION_PATH=../../src/test/cpp/regression VEXRISCV_FILE=VexRiscv.v WITH_USER_IO=no REDO=10 TRACE=${if(debug) "yes" else "no"} TRACE_START=100000000000ll FLOW_INFO=no STOP_ON_ERROR=no DHRYSTONE=yes COREMARK=${coremarkRegression} THREAD_COUNT=1 ") + s" SEED=${testSeed} " + val stdCmd = (s"make run REGRESSION_PATH=../../src/test/cpp/regression VEXRISCV_FILE=VexRiscv.v WITH_USER_IO=no REDO=10 TRACE=${if(debug) "yes" else "no"} TRACE_START=100000000000ll FLOW_INFO=no STOP_ON_ERROR=$stopOnError DHRYSTONE=yes COREMARK=${coremarkRegression} THREAD_COUNT=1 ") + s" SEED=${testSeed} " val testCmd = stdCmd + (positionsToApply).map(_.testParam).mkString(" ") println(testCmd) val str = doCmd(testCmd) From 06584518da0c3cce52f01a58750dc8b59518e022 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sun, 5 Jul 2020 13:17:07 +0200 Subject: [PATCH 465/951] Remove CsrPlugin redoInterface combinatorial depedency from execut_isStuck --- .../scala/vexriscv/plugin/CsrPlugin.scala | 39 ++++++++----------- 1 file changed, 16 insertions(+), 23 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 9dfad38c..bf65b199 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -306,6 +306,7 @@ case class CsrWrite(that : Data, bitOffset : Int) case class CsrRead(that : Data , bitOffset : Int) case class CsrReadToWriteOverride(that : Data, bitOffset : Int) //Used for special cases, as MIP where there shadow stuff case class CsrOnWrite(doThat :() => Unit) +case class CsrDuringWrite(doThat :() => Unit) case class CsrOnRead(doThat : () => Unit) case class CsrMapping() extends CsrInterface{ val mapping = mutable.LinkedHashMap[Int,ArrayBuffer[Any]]() @@ -314,6 +315,7 @@ case class CsrMapping() extends CsrInterface{ override def w(csrAddress : Int, bitOffset : Int, that : Data): Unit = addMappingAt(csrAddress, CsrWrite(that,bitOffset)) override def r2w(csrAddress : Int, bitOffset : Int, that : Data): Unit = addMappingAt(csrAddress, CsrReadToWriteOverride(that,bitOffset)) override def onWrite(csrAddress: Int)(body: => Unit): Unit = addMappingAt(csrAddress, CsrOnWrite(() => body)) + override def duringWrite(csrAddress: Int)(body: => Unit): Unit = addMappingAt(csrAddress, CsrDuringWrite(() => body)) override def onRead(csrAddress: Int)(body: => Unit): Unit = addMappingAt(csrAddress, CsrOnRead(() => {body})) } @@ -321,6 +323,7 @@ case class CsrMapping() extends CsrInterface{ trait CsrInterface{ def onWrite(csrAddress : Int)(doThat : => Unit) : Unit def onRead(csrAddress : Int)(doThat : => Unit) : Unit + def duringWrite(csrAddress: Int)(body: => Unit): Unit def r(csrAddress : Int, bitOffset : Int, that : Data): Unit def w(csrAddress : Int, bitOffset : Int, that : Data): Unit def rw(csrAddress : Int, bitOffset : Int,that : Data): Unit ={ @@ -425,6 +428,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep } } + //Interruption and exception data model case class Delegator(var enable : Bool, privilege : Int) case class InterruptSpec(var cond : Bool, id : Int, privilege : Int, delegators : List[Delegator]) @@ -440,6 +444,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep override def w(csrAddress: Int, bitOffset: Int, that: Data): Unit = csrMapping.w(csrAddress, bitOffset, that) override def r2w(csrAddress: Int, bitOffset: Int, that: Data): Unit = csrMapping.r2w(csrAddress, bitOffset, that) override def onWrite(csrAddress: Int)(body: => Unit): Unit = csrMapping.onWrite(csrAddress)(body) + override def duringWrite(csrAddress: Int)(body: => Unit): Unit = csrMapping.duringWrite(csrAddress)(body) override def onRead(csrAddress: Int)(body: => Unit): Unit = csrMapping.onRead(csrAddress)(body) override def setup(pipeline: VexRiscv): Unit = { @@ -700,7 +705,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep if(supervisorGen) { redoInterface.valid := False redoInterface.payload := decode.input(PC) - onWrite(CSR.SATP){ + duringWrite(CSR.SATP){ execute.arbitration.flushNext := True redoInterface.valid := True } @@ -1011,7 +1016,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep execute plug new Area { import execute._ def previousStage = decode - val blockedBySideEffects = stagesFromExecute.tail.map(s => s.arbitration.isValid).asBits().orR // && s.input(HAS_SIDE_EFFECT) to improve be less pessimistic + val blockedBySideEffects = stagesFromExecute.tail.map(s => s.arbitration.isValid).asBits().orR || pipeline.service(classOf[HazardService]).hazardOnExecuteRS// && s.input(HAS_SIDE_EFFECT) to improve be less pessimistic val illegalAccess = True val illegalInstruction = False @@ -1052,22 +1057,11 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep val imm = IMM(input(INSTRUCTION)) def writeSrc = input(SRC1) - // val readDataValid = True val readData = Bits(32 bits) val writeInstruction = arbitration.isValid && input(IS_CSR) && input(CSR_WRITE_OPCODE) val readInstruction = arbitration.isValid && input(IS_CSR) && input(CSR_READ_OPCODE) - val writeEnable = writeInstruction && ! blockedBySideEffects && !arbitration.isStuckByOthers// && readDataRegValid - val readEnable = readInstruction && ! blockedBySideEffects && !arbitration.isStuckByOthers// && !readDataRegValid - //arbitration.isStuckByOthers, in case of the hazardPlugin is in the executeStage - - -// def readDataReg = memory.input(REGFILE_WRITE_DATA) //PIPE OPT -// val readDataRegValid = Reg(Bool) setWhen(arbitration.isValid) clearWhen(!arbitration.isStuck) -// val writeDataEnable = input(INSTRUCTION)(13) ? writeSrc | B"xFFFFFFFF" -// val writeData = if(noCsrAlu) writeSrc else input(INSTRUCTION)(13).mux( -// False -> writeSrc, -// True -> Mux(input(INSTRUCTION)(12), ~writeSrc, writeSrc) -// ) + val writeEnable = writeInstruction && ! blockedBySideEffects && !arbitration.isStuckByOthers + val readEnable = readInstruction && ! blockedBySideEffects && !arbitration.isStuckByOthers val readToWriteData = CombInit(readData) val writeData = if(noCsrAlu) writeSrc else input(INSTRUCTION)(13).mux( @@ -1075,11 +1069,6 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep True -> Mux(input(INSTRUCTION)(12), readToWriteData & ~writeSrc, readToWriteData | writeSrc) ) - - -// arbitration.haltItself setWhen(writeInstruction && !readDataRegValid) - - when(arbitration.isValid && input(IS_CSR)) { if(!pipelineCsrRead) output(REGFILE_WRITE_DATA) := readData arbitration.haltItself setWhen(blockedBySideEffects) @@ -1101,7 +1090,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep val csrAddress = input(INSTRUCTION)(csrRange) Component.current.afterElaboration{ def doJobs(jobs : ArrayBuffer[Any]): Unit ={ - val withWrite = jobs.exists(j => j.isInstanceOf[CsrWrite] || j.isInstanceOf[CsrOnWrite]) + val withWrite = jobs.exists(j => j.isInstanceOf[CsrWrite] || j.isInstanceOf[CsrOnWrite] || j.isInstanceOf[CsrDuringWrite]) val withRead = jobs.exists(j => j.isInstanceOf[CsrRead] || j.isInstanceOf[CsrOnRead]) if(withRead && withWrite) { illegalAccess := False @@ -1110,11 +1099,15 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep if (withRead) illegalAccess.clearWhen(input(CSR_READ_OPCODE)) } + + for (element <- jobs) element match { + case element : CsrDuringWrite => when(writeInstruction){element.doThat()} + case _ => + } when(writeEnable) { for (element <- jobs) element match { case element: CsrWrite => element.that.assignFromBits(writeData(element.bitOffset, element.that.getBitsWidth bits)) - case element: CsrOnWrite => - element.doThat() + case element: CsrOnWrite => element.doThat() case _ => } } From 51070d0e69aa4f1c30bb717e5be6a74e0c435aa9 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sun, 5 Jul 2020 13:17:39 +0200 Subject: [PATCH 466/951] Fix MmuPlugin when used in multi stage config --- .../scala/vexriscv/plugin/MmuPlugin.scala | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/MmuPlugin.scala b/src/main/scala/vexriscv/plugin/MmuPlugin.scala index e797bcfa..d5f6d561 100644 --- a/src/main/scala/vexriscv/plugin/MmuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/MmuPlugin.scala @@ -105,6 +105,10 @@ class MmuPlugin(ioRange : UInt => Bool, val id = port.id val privilegeService = pipeline.serviceElse(classOf[PrivilegeService], PrivilegeServiceDefault()) val cache = Vec(Reg(CacheLine()) init, port.args.portTlbSize) + val dirty = RegInit(False).allowUnsetRegToAvoidLatch + if(port.args.earlyRequireMmuLockup){ + dirty clearWhen(!port.bus.cmd.last.isStuck) + } def toRsp[T <: Data](data : T, from : MemoryTranslatorCmd) : T = from match { case _ if from == port.bus.cmd.last => data @@ -144,8 +148,8 @@ class MmuPlugin(ioRange : UInt => Bool, port.bus.rsp.allowRead := cacheLine.allowRead || csr.status.mxr && cacheLine.allowExecute port.bus.rsp.allowWrite := cacheLine.allowWrite port.bus.rsp.allowExecute := cacheLine.allowExecute - port.bus.rsp.exception := cacheHit && (cacheLine.exception || cacheLine.allowUser && privilegeService.isSupervisor() && !csr.status.sum || !cacheLine.allowUser && privilegeService.isUser()) - port.bus.rsp.refilling := !cacheHit + port.bus.rsp.exception := !dirty && cacheHit && (cacheLine.exception || cacheLine.allowUser && privilegeService.isSupervisor() && !csr.status.sum || !cacheLine.allowUser && privilegeService.isUser()) + port.bus.rsp.refilling := dirty || !cacheHit } otherwise { port.bus.rsp.physicalAddress := port.bus.cmd.last.virtualAddress port.bus.rsp.allowRead := True @@ -204,7 +208,7 @@ class MmuPlugin(ioRange : UInt => Bool, dBusAccess.cmd.data.assignDontCare() dBusAccess.cmd.writeMask.assignDontCare() - val refills = OHMasking.last(B(sortedPortsInfo.map(port => port.bus.cmd.last.isValid && port.bus.rsp.refilling))) + val refills = OHMasking.last(B(ports.map(port => port.handle.bus.cmd.last.isValid && port.requireMmuLockup && !port.dirty && !port.cacheHit))) switch(state){ is(State.IDLE){ when(refills.orR){ @@ -266,6 +270,9 @@ class MmuPlugin(ioRange : UInt => Bool, for((port, id) <- ports.zipWithIndex) { when(portSortedOh(id)) { port.entryToReplace.increment() + if(port.handle.args.earlyRequireMmuLockup) { + port.dirty := True + } //Avoid having non coherent TLB lookup for ((line, lineId) <- port.cache.zipWithIndex) { when(port.entryToReplace === lineId){ val superPage = state === State.L1_RSP @@ -289,9 +296,16 @@ class MmuPlugin(ioRange : UInt => Bool, val fenceStage = stages.last fenceStage plug new Area{ import fenceStage._ - when(arbitration.isValid && input(IS_SFENCE_VMA)){ // || csrService.isWriting(CSR.SATP) + when(arbitration.isValid && input(IS_SFENCE_VMA)){ for(port <- core.ports; line <- port.cache) line.valid := False //Assume that the instruction already fetched into the pipeline are ok } + + csrService.duringWrite(CSR.SATP){ + for(port <- core.ports; line <- port.cache) line.valid := False + core.ports.filter(_.handle.args.earlyRequireMmuLockup).foreach{p => + p.dirty := True + } + } } } } From 60ee7e2b4cfd6f6b62a368b3a6d586e464ef9e24 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 8 Jul 2020 01:36:40 +0200 Subject: [PATCH 467/951] Better VexRiscvSmpCluster config --- src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index 7cc16516..78b1ddd5 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -128,7 +128,7 @@ object VexRiscvSmpClusterGen { historyRamSizeLog2 = 9, relaxPredictorAddress = true, injectorStage = false, - relaxedPcCalculation = true, + relaxedPcCalculation = false, config = InstructionCacheConfig( cacheSize = 4096*2, bytePerLine = 64, @@ -191,7 +191,7 @@ object VexRiscvSmpClusterGen { new SrcPlugin( separatedAddSub = false ), - new FullBarrelShifterPlugin(earlyInjection = false), + new FullBarrelShifterPlugin(earlyInjection = true), // new LightShifterPlugin, new HazardSimplePlugin( bypassExecute = true, From 32f778613fcbbee9e29c7c768b68d47023f6280e Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 8 Jul 2020 01:36:58 +0200 Subject: [PATCH 468/951] DBusCachedPlugin now support asyncTagMemory --- src/main/scala/vexriscv/ip/DataCache.scala | 11 +++++++++-- src/test/scala/vexriscv/TestIndividualFeatures.scala | 11 +++++++---- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index 78f96078..f712606f 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -30,6 +30,7 @@ case class DataCacheConfig(cacheSize : Int, pendingMax : Int = 32, directTlbHit : Boolean = false, mergeExecuteMemory : Boolean = false, + asyncTagMemory : Boolean = false, aggregationWidth : Int = 0){ assert(!(mergeExecuteMemory && (earlyDataMux || earlyWaysHits))) assert(!(earlyDataMux && !earlyWaysHits)) @@ -591,12 +592,18 @@ class DataCache(val p : DataCacheConfig, mmuParameter : MemoryTranslatorBusParam val data = Mem(Bits(memDataWidth bit), wayMemWordCount) //Reads - val tagsReadRsp = tags.readSync(tagsReadCmd.payload, tagsReadCmd.valid && !io.cpu.memory.isStuck) + val tagsReadRsp = asyncTagMemory match { + case false => tags.readSync(tagsReadCmd.payload, tagsReadCmd.valid && !io.cpu.memory.isStuck) + case true => tags.readAsync(RegNextWhen(tagsReadCmd.payload, io.cpu.execute.isValid && !io.cpu.memory.isStuck)) + } val dataReadRspMem = data.readSync(dataReadCmd.payload, dataReadCmd.valid && !io.cpu.memory.isStuck) val dataReadRspSel = if(mergeExecuteMemory) io.cpu.writeBack.address else io.cpu.memory.address val dataReadRsp = dataReadRspMem.subdivideIn(cpuDataWidth bits).read(dataReadRspSel(memWordToCpuWordRange)) - val tagsInvReadRsp = withInvalidate generate tags.readSync(tagsInvReadCmd.payload, tagsInvReadCmd.valid) + val tagsInvReadRsp = withInvalidate generate(asyncTagMemory match { + case false => tags.readSync(tagsInvReadCmd.payload, tagsInvReadCmd.valid) + case true => tags.readAsync(RegNextWhen(tagsInvReadCmd.payload, tagsInvReadCmd.valid)) + }) //Writes when(tagsWriteCmd.valid && tagsWriteCmd.way(i)){ diff --git a/src/test/scala/vexriscv/TestIndividualFeatures.scala b/src/test/scala/vexriscv/TestIndividualFeatures.scala index 6139bad1..628e057c 100644 --- a/src/test/scala/vexriscv/TestIndividualFeatures.scala +++ b/src/test/scala/vexriscv/TestIndividualFeatures.scala @@ -351,6 +351,7 @@ class IBusDimension(rvcRate : Double) extends VexRiscvDimension("IBus") { } } else { val twoStageMmu = r.nextBoolean() + val asyncTagMemory = r.nextBoolean() val mmuConfig = if(universes.contains(VexRiscvUniverse.MMU)) MmuPortConfig(portTlbSize = 4, latency = if(twoStageMmu) 1 else 0, earlyRequireMmuLockup = Random.nextBoolean() && twoStageMmu, earlyCacheHits = Random.nextBoolean() && twoStageMmu) else null val catchAll = universes.contains(VexRiscvUniverse.CATCH_ALL) @@ -371,7 +372,7 @@ class IBusDimension(rvcRate : Double) extends VexRiscvDimension("IBus") { wayCount = 1 << r.nextInt(3) }while(cacheSize/wayCount < 512 || (catchAll && cacheSize/wayCount > 4096)) - new VexRiscvPosition(s"Cached${memDataWidth}d" + (if(twoCycleCache) "2cc" else "") + (if(injectorStage) "Injstage" else "") + (if(twoCycleRam) "2cr" else "") + "S" + cacheSize + "W" + wayCount + "BPL" + bytePerLine + (if(relaxedPcCalculation) "Relax" else "") + (if(compressed) "Rvc" else "") + prediction.getClass.getTypeName().replace("$","")+ (if(tighlyCoupled)"Tc" else "")) with InstructionAnticipatedPosition{ + new VexRiscvPosition(s"Cached${memDataWidth}d" + (if(twoCycleCache) "2cc" else "") + (if(injectorStage) "Injstage" else "") + (if(twoCycleRam) "2cr" else "") + "S" + cacheSize + "W" + wayCount + "BPL" + bytePerLine + (if(relaxedPcCalculation) "Relax" else "") + (if(compressed) "Rvc" else "") + prediction.getClass.getTypeName().replace("$","")+ (if(tighlyCoupled)"Tc" else "") + (if(asyncTagMemory) "Atm" else "")) with InstructionAnticipatedPosition{ override def testParam = s"IBUS=CACHED IBUS_DATA_WIDTH=$memDataWidth" + (if(compressed) " COMPRESSED=yes" else "") + (if(tighlyCoupled)" IBUS_TC=yes" else "") override def applyOn(config: VexRiscvConfig): Unit = { val p = new IBusCachedPlugin( @@ -390,7 +391,7 @@ class IBusDimension(rvcRate : Double) extends VexRiscvDimension("IBus") { memDataWidth = memDataWidth, catchIllegalAccess = catchAll, catchAccessFault = catchAll, - asyncTagMemory = false, + asyncTagMemory = asyncTagMemory, twoCycleRam = twoCycleRam, twoCycleCache = twoCycleCache, twoCycleRamInnerMux = twoCycleRamInnerMux, @@ -447,12 +448,13 @@ class DBusDimension extends VexRiscvDimension("DBus") { val earlyWaysHits = r.nextBoolean() && !noWriteBack val directTlbHit = r.nextBoolean() && mmuConfig.isInstanceOf[MmuPortConfig] val dBusCmdMasterPipe, dBusCmdSlavePipe = false //As it create test bench issues + val asyncTagMemory = r.nextBoolean() do{ cacheSize = 512 << r.nextInt(5) wayCount = 1 << r.nextInt(3) }while(cacheSize/wayCount < 512 || (catchAll && cacheSize/wayCount > 4096)) - new VexRiscvPosition(s"Cached${memDataWidth}d" + "S" + cacheSize + "W" + wayCount + "BPL" + bytePerLine + (if(dBusCmdMasterPipe) "Cmp " else "") + (if(dBusCmdSlavePipe) "Csp " else "") + (if(dBusRspSlavePipe) "Rsp " else "") + (if(relaxedMemoryTranslationRegister) "Rmtr " else "") + (if(earlyWaysHits) "Ewh " else "") + (if(withAmo) "Amo " else "") + (if(withSmp) "Smp " else "") + (if(directTlbHit) "Dtlb " else "") + (if(twoStageMmu) "Tsmmu " else "")) { + new VexRiscvPosition(s"Cached${memDataWidth}d" + "S" + cacheSize + "W" + wayCount + "BPL" + bytePerLine + (if(dBusCmdMasterPipe) "Cmp " else "") + (if(dBusCmdSlavePipe) "Csp " else "") + (if(dBusRspSlavePipe) "Rsp " else "") + (if(relaxedMemoryTranslationRegister) "Rmtr " else "") + (if(earlyWaysHits) "Ewh " else "") + (if(withAmo) "Amo " else "") + (if(withSmp) "Smp " else "") + (if(directTlbHit) "Dtlb " else "") + (if(twoStageMmu) "Tsmmu " else "") + (if(asyncTagMemory) "Atm" else "")) { override def testParam = s"DBUS=CACHED DBUS_DATA_WIDTH=$memDataWidth " + (if(withLrSc) "LRSC=yes " else "") + (if(withAmo) "AMO=yes " else "") + (if(withSmp) "DBUS_EXCLUSIVE=yes DBUS_INVALIDATE=yes " else "") override def applyOn(config: VexRiscvConfig): Unit = { @@ -472,7 +474,8 @@ class DBusDimension extends VexRiscvDimension("DBus") { earlyWaysHits = earlyWaysHits, withExclusive = withSmp, withInvalidate = withSmp, - directTlbHit = directTlbHit + directTlbHit = directTlbHit, + asyncTagMemory = asyncTagMemory ), dBusCmdMasterPipe = dBusCmdMasterPipe, dBusCmdSlavePipe = dBusCmdSlavePipe, From d0a572de9885b9c50ab1f429dafd03e76947edf8 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 8 Jul 2020 01:37:10 +0200 Subject: [PATCH 469/951] Add openroad config --- src/main/scala/vexriscv/demo/OpenRoad.scala | 103 ++++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 src/main/scala/vexriscv/demo/OpenRoad.scala diff --git a/src/main/scala/vexriscv/demo/OpenRoad.scala b/src/main/scala/vexriscv/demo/OpenRoad.scala new file mode 100644 index 00000000..3938effb --- /dev/null +++ b/src/main/scala/vexriscv/demo/OpenRoad.scala @@ -0,0 +1,103 @@ +package vexriscv.demo + +import spinal.core._ +import vexriscv.ip.{DataCacheConfig, InstructionCacheConfig} +import vexriscv.{Riscv, VexRiscv, VexRiscvConfig, plugin} +import vexriscv.plugin.{BranchPlugin, CsrAccess, CsrPlugin, CsrPluginConfig, DBusCachedPlugin, DecoderSimplePlugin, FullBarrelShifterPlugin, HazardSimplePlugin, IBusCachedPlugin, IntAluPlugin, MmuPlugin, MmuPortConfig, MulDivIterativePlugin, MulPlugin, RegFilePlugin, STATIC, SrcPlugin, YamlPlugin} + +object OpenRoad extends App{ + + def linuxConfig = VexRiscvConfig( + withMemoryStage = true, + withWriteBackStage = true, + List( + // new SingleInstructionLimiterPlugin(), + new IBusCachedPlugin( + resetVector = 0, + compressedGen = false, + prediction = vexriscv.plugin.NONE, + injectorStage = false, + config = InstructionCacheConfig( + cacheSize = 4096, + bytePerLine = 64, + wayCount = 1, + addressWidth = 32, + cpuDataWidth = 32, + memDataWidth = 32, + catchIllegalAccess = true, + catchAccessFault = true, + asyncTagMemory = true, + twoCycleRam = false, + twoCycleCache = true + ), + memoryTranslatorPortConfig = MmuPortConfig( + portTlbSize = 4 + ) + ), + new DBusCachedPlugin( + dBusCmdMasterPipe = true, + dBusCmdSlavePipe = true, + dBusRspSlavePipe = true, + config = new DataCacheConfig( + cacheSize = 4096, + bytePerLine = 64, + wayCount = 1, + addressWidth = 32, + cpuDataWidth = 32, + memDataWidth = 32, + catchAccessError = true, + catchIllegal = true, + catchUnaligned = true, + asyncTagMemory = true, + withLrSc = true, + withAmo = true + // ) + ), + memoryTranslatorPortConfig = MmuPortConfig( + portTlbSize = 4 + ) + ), + new DecoderSimplePlugin( + catchIllegalInstruction = true + ), + new RegFilePlugin( + regFileReadyKind = plugin.SYNC, + zeroBoot = false, + x0Init = true + ), + new IntAluPlugin, + new SrcPlugin( + separatedAddSub = false + ), + new FullBarrelShifterPlugin(earlyInjection = true), + new HazardSimplePlugin( + bypassExecute = true, + bypassMemory = true, + bypassWriteBack = true, + bypassWriteBackBuffer = true, + pessimisticUseSrc = false, + pessimisticWriteRegFile = false, + pessimisticAddressMatch = false + ), + new MulDivIterativePlugin( + genMul = true, + genDiv = true, + mulUnrollFactor = 32, + divUnrollFactor = 8 + ), + new CsrPlugin(CsrPluginConfig.openSbi(0,Riscv.misaToInt("imas")).copy(ebreakGen = false, mtvecAccess = CsrAccess.READ_WRITE)), //mtvecAccess read required by freertos + + new BranchPlugin( + earlyBranch = true, + catchAddressMisaligned = true, + fenceiGenAsAJump = false + ), + new MmuPlugin( + ioRange = (x => x(31)) + ), + new YamlPlugin("cpu0.yaml") + ) + ) + + SpinalConfig().addStandardMemBlackboxing(blackboxAllWhatsYouCan).generateVerilog(new VexRiscv(linuxConfig).setDefinitionName("VexRiscvMsuI4D4")) +} From 5f0aec7570513960af9aa6066dfa1cb3af0d400b Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 15 Jul 2020 17:03:05 +0200 Subject: [PATCH 470/951] BmbInterconnectGenerator refractoring --- src/main/scala/vexriscv/VexRiscvBmbGenerator.scala | 4 ++-- src/main/scala/vexriscv/demo/smp/Misc.scala | 4 ++-- src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/scala/vexriscv/VexRiscvBmbGenerator.scala b/src/main/scala/vexriscv/VexRiscvBmbGenerator.scala index 5460299e..15fc7c83 100644 --- a/src/main/scala/vexriscv/VexRiscvBmbGenerator.scala +++ b/src/main/scala/vexriscv/VexRiscvBmbGenerator.scala @@ -1,7 +1,7 @@ package vexriscv import spinal.core._ -import spinal.lib.bus.bmb.{Bmb, BmbAccessCapabilities, BmbAccessParameter, BmbImplicitDebugDecoder, BmbInvalidationParameter, BmbParameter, BmbSmpInterconnectGenerator} +import spinal.lib.bus.bmb.{Bmb, BmbAccessCapabilities, BmbAccessParameter, BmbImplicitDebugDecoder, BmbInvalidationParameter, BmbParameter, BmbInterconnectGenerator} import spinal.lib.bus.misc.AddressMapping import spinal.lib.com.jtag.{Jtag, JtagTapInstructionCtrl} import spinal.lib.generator._ @@ -17,7 +17,7 @@ object VexRiscvBmbGenerator{ val DEBUG_BMB = 4 } -case class VexRiscvBmbGenerator()(implicit interconnectSmp: BmbSmpInterconnectGenerator = null) extends Generator { +case class VexRiscvBmbGenerator()(implicit interconnectSmp: BmbInterconnectGenerator = null) extends Generator { import VexRiscvBmbGenerator._ val config = Handle[VexRiscvConfig] diff --git a/src/main/scala/vexriscv/demo/smp/Misc.scala b/src/main/scala/vexriscv/demo/smp/Misc.scala index 01135b6b..1306fc17 100644 --- a/src/main/scala/vexriscv/demo/smp/Misc.scala +++ b/src/main/scala/vexriscv/demo/smp/Misc.scala @@ -247,7 +247,7 @@ object BmbToLiteDramTester extends App{ } } -case class BmbToLiteDramGenerator(mapping : AddressMapping)(implicit interconnect : BmbSmpInterconnectGenerator) extends Generator{ +case class BmbToLiteDramGenerator(mapping : AddressMapping)(implicit interconnect : BmbInterconnectGenerator) extends Generator{ val liteDramParameter = createDependency[LiteDramNativeParameter] val bmb = produce(logic.io.input) val dram = produceIo(logic.io.output) @@ -269,7 +269,7 @@ case class BmbToLiteDramGenerator(mapping : AddressMapping)(implicit interconnec ) } -case class BmbToWishboneGenerator(mapping : AddressMapping)(implicit interconnect : BmbSmpInterconnectGenerator) extends Generator{ +case class BmbToWishboneGenerator(mapping : AddressMapping)(implicit interconnect : BmbInterconnectGenerator) extends Generator{ val bmb = produce(logic.io.input) val wishbone = produce(logic.io.output) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index 78b1ddd5..602bd1fb 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -37,7 +37,7 @@ class VexRiscvSmpClusterBase(p : VexRiscvSmpClusterParameter) extends Generator{ this.onClockDomain(systemCd.outputClockDomain) - implicit val interconnect = BmbSmpInterconnectGenerator() + implicit val interconnect = BmbInterconnectGenerator() val debugBridge = JtagInstructionDebuggerGenerator() onClockDomain(debugCd.outputClockDomain) debugBridge.jtagClockDomain.load(ClockDomain.external("jtag", withReset = false)) From da733179125618f9ce3b587a9e359f50a8868879 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 15 Jul 2020 20:51:46 +0200 Subject: [PATCH 471/951] Cleanup BmbGenerators --- src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala | 2 +- .../scala/vexriscv/demo/smp/VexRiscvSmpLitexMpCluster.scala | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala index 910fc23b..e8c7afac 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala @@ -15,7 +15,7 @@ case class VexRiscvLitexSmpClusterParameter( cluster : VexRiscvSmpClusterParamet class VexRiscvLitexSmpCluster(p : VexRiscvLitexSmpClusterParameter) extends VexRiscvSmpClusterWithPeripherals(p.cluster) { - val iArbiter = BmbSmpBridgeGenerator() + val iArbiter = BmbBridgeGenerator() val iBridge = BmbToLiteDramGenerator(p.liteDramMapping) val dBridge = BmbToLiteDramGenerator(p.liteDramMapping) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexMpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexMpCluster.scala index a2f35636..14daae2e 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexMpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexMpCluster.scala @@ -12,7 +12,7 @@ case class VexRiscvLitexSmpMpClusterParameter( cluster : VexRiscvSmpClusterParam liteDramMapping : AddressMapping) class VexRiscvLitexSmpMpCluster(p : VexRiscvLitexSmpMpClusterParameter) extends VexRiscvSmpClusterWithPeripherals(p.cluster) { - val iArbiter = BmbSmpBridgeGenerator() + val iArbiter = BmbBridgeGenerator() val iBridge = BmbToLiteDramGenerator(p.liteDramMapping) val dBridge = BmbToLiteDramGenerator(p.liteDramMapping) From fe5401f83510e1052fcf3c40d2acefbcff0d8519 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 16 Jul 2020 13:04:25 +0200 Subject: [PATCH 472/951] BmbGenerators refractoring (bus -> ctrl) --- src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index 602bd1fb..b8f5f827 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -77,14 +77,14 @@ class VexRiscvSmpClusterWithPeripherals(p : VexRiscvSmpClusterParameter) extends val plicWishboneBridge = WishboneToBmbGenerator() val plicWishbone = plicWishboneBridge.produceIo(plicWishboneBridge.logic.io.input) plicWishboneBridge.config.load(WishboneConfig(20, 32)) - interconnect.addConnection(plicWishboneBridge.bmb, plic.bus) + interconnect.addConnection(plicWishboneBridge.bmb, plic.ctrl) val clint = BmbClintGenerator(0) val clintWishboneBridge = WishboneToBmbGenerator() val clintWishbone = clintWishboneBridge.produceIo(clintWishboneBridge.logic.io.input) clintWishboneBridge.config.load(WishboneConfig(14, 32)) - interconnect.addConnection(clintWishboneBridge.bmb, clint.bus) + interconnect.addConnection(clintWishboneBridge.bmb, clint.ctrl) val interrupts = add task (in Bits(32 bits)) for(i <- 1 to 31) yield plic.addInterrupt(interrupts.derivate(_.apply(i)), i) From da666ade496750449ef4e4a193b8a08fc052aff3 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 21 Jul 2020 15:07:32 +0200 Subject: [PATCH 473/951] Add VexRiscvLitexSmpClusterCmdGen --- .../demo/smp/VexRiscvSmpLitexCluster.scala | 81 ++++++++++++++++--- 1 file changed, 68 insertions(+), 13 deletions(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala index e8c7afac..ea8c95bd 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala @@ -11,7 +11,8 @@ import vexriscv.plugin.DBusCachedPlugin case class VexRiscvLitexSmpClusterParameter( cluster : VexRiscvSmpClusterParameter, liteDram : LiteDramNativeParameter, - liteDramMapping : AddressMapping) + liteDramMapping : AddressMapping, + coherentDma : Boolean) class VexRiscvLitexSmpCluster(p : VexRiscvLitexSmpClusterParameter) extends VexRiscvSmpClusterWithPeripherals(p.cluster) { @@ -24,21 +25,24 @@ class VexRiscvLitexSmpCluster(p : VexRiscvLitexSmpClusterParameter) extends VexR iArbiter.bmb -> List(iBridge.bmb, peripheralBridge.bmb), invalidationMonitor.output -> List(dBridge.bmb, peripheralBridge.bmb) ) - interconnect.masters(invalidationMonitor.output).withOutOfOrderDecoder() + + if(p.coherentDma || p.cluster.cpuConfigs.size > 1) interconnect.masters(invalidationMonitor.output).withOutOfOrderDecoder() dBridge.liteDramParameter.load(p.liteDram) iBridge.liteDramParameter.load(p.liteDram) // Coherent DMA interface - val dmaBridge = WishboneToBmbGenerator() - val dmaWishbone = dmaBridge.produceIo(dmaBridge.logic.io.input) - val dmaDataWidth = p.cluster.cpuConfigs.head.find(classOf[DBusCachedPlugin]).get.config.memDataWidth - dmaBridge.config.load(WishboneConfig( - addressWidth = 32-log2Up(dmaDataWidth/8), - dataWidth = p.cluster.cpuConfigs.head.find(classOf[DBusCachedPlugin]).get.config.memDataWidth, - useSTALL = true - )) - interconnect.addConnection(dmaBridge.bmb, exclusiveMonitor.input) + val dma = p.coherentDma generate new Area { + val bridge = WishboneToBmbGenerator() + val wishbone = bridge.produceIo(bridge.logic.io.input) + val dataWidth = p.cluster.cpuConfigs.head.find(classOf[DBusCachedPlugin]).get.config.memDataWidth + bridge.config.load(WishboneConfig( + addressWidth = 32 - log2Up(dataWidth / 8), + dataWidth = p.cluster.cpuConfigs.head.find(classOf[DBusCachedPlugin]).get.config.memDataWidth, + useSTALL = true + )) + interconnect.addConnection(bridge.bmb, exclusiveMonitor.input) + } // Interconnect pipelining (FMax) for(core <- cores) { @@ -51,6 +55,55 @@ class VexRiscvLitexSmpCluster(p : VexRiscvLitexSmpClusterParameter) extends VexR } +object VexRiscvLitexSmpClusterCmdGen extends App { + var cpuCount = 1 + var iBusWidth = 64 + var dBusWidth = 64 + var liteDramWidth = 128 + var coherentDma = false + var netlistDirectory = "." + var netlistName = "VexRiscvLitexSmpCluster" + assert(new scopt.OptionParser[Unit]("VexRiscvLitexSmpClusterCmdGen") { + help("help").text("prints this usage text") + opt[Unit]("coherent-dma") action { (v, c) => coherentDma = true } + opt[String]("cpu-count") action { (v, c) => cpuCount = v.toInt } + opt[String]("ibus-width") action { (v, c) => iBusWidth = v.toInt } + opt[String]("dbus-width") action { (v, c) => dBusWidth = v.toInt } + opt[String]("litedram-width") action { (v, c) => liteDramWidth = v.toInt } + opt[String]("netlist-directory") action { (v, c) => netlistDirectory = v } + opt[String]("netlist-name") action { (v, c) => netlistName = v } + }.parse(args)) + + def parameter = VexRiscvLitexSmpClusterParameter( + cluster = VexRiscvSmpClusterParameter( + cpuConfigs = List.tabulate(cpuCount) { hartId => + vexRiscvConfig( + hartId = hartId, + ioRange = address => address.msb, + resetVector = 0, + iBusWidth = iBusWidth, + dBusWidth = dBusWidth + ) + } + ), + liteDram = LiteDramNativeParameter(addressWidth = 32, dataWidth = liteDramWidth), + liteDramMapping = SizeMapping(0x40000000l, 0x40000000l), + coherentDma = coherentDma + ) + + def dutGen = { + val toplevel = new VexRiscvLitexSmpCluster( + p = parameter + ).toComponent() + toplevel + } + + val genConfig = SpinalConfig(targetDirectory = netlistDirectory).addStandardMemBlackboxing(blackboxByteEnables) + genConfig.generateVerilog(dutGen.setDefinitionName(netlistName)) + +} + + object VexRiscvLitexSmpClusterGen extends App { for(cpuCount <- List(1,2,4,8)) { def parameter = VexRiscvLitexSmpClusterParameter( @@ -64,7 +117,8 @@ object VexRiscvLitexSmpClusterGen extends App { } ), liteDram = LiteDramNativeParameter(addressWidth = 32, dataWidth = 128), - liteDramMapping = SizeMapping(0x40000000l, 0x40000000l) + liteDramMapping = SizeMapping(0x40000000l, 0x40000000l), + coherentDma = false ) def dutGen = { @@ -101,7 +155,8 @@ object VexRiscvLitexSmpClusterOpenSbi extends App{ } ), liteDram = LiteDramNativeParameter(addressWidth = 32, dataWidth = 128), - liteDramMapping = SizeMapping(0x80000000l, 0x70000000l) + liteDramMapping = SizeMapping(0x80000000l, 0x70000000l), + coherentDma = false ) def dutGen = { From 9f62f375381b10bcc281fa91ac9107e5dcd3928a Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 21 Jul 2020 15:45:02 +0200 Subject: [PATCH 474/951] improve LitexCluster area for single core configuration --- .../demo/smp/VexRiscvSmpCluster.scala | 31 +++-- .../demo/smp/VexRiscvSmpLitexCluster.scala | 23 ++-- .../demo/smp/VexRiscvSmpLitexMpCluster.scala | 116 +++++++++--------- src/main/scala/vexriscv/ip/DataCache.scala | 5 +- 4 files changed, 97 insertions(+), 78 deletions(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index b8f5f827..7fb693d9 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -22,7 +22,7 @@ import scala.collection.mutable import scala.collection.mutable.ArrayBuffer import spinal.lib.generator._ -case class VexRiscvSmpClusterParameter( cpuConfigs : Seq[VexRiscvConfig]) +case class VexRiscvSmpClusterParameter(cpuConfigs : Seq[VexRiscvConfig], withExclusiveAndInvalidation : Boolean) class VexRiscvSmpClusterBase(p : VexRiscvSmpClusterParameter) extends Generator{ val cpuCount = p.cpuConfigs.size @@ -44,16 +44,28 @@ class VexRiscvSmpClusterBase(p : VexRiscvSmpClusterParameter) extends Generator{ val debugPort = debugBridge.produceIo(debugBridge.logic.jtagBridge.io.ctrl) - val exclusiveMonitor = BmbExclusiveMonitorGenerator() - val invalidationMonitor = BmbInvalidateMonitorGenerator() - interconnect.addConnection(exclusiveMonitor.output, invalidationMonitor.input) - interconnect.masters(invalidationMonitor.output).withOutOfOrderDecoder() + val dBusCoherent = BmbBridgeGenerator() + val dBusNonCoherent = BmbBridgeGenerator() + + val smp = p.withExclusiveAndInvalidation generate new Area{ + val exclusiveMonitor = BmbExclusiveMonitorGenerator() + interconnect.addConnection(dBusCoherent.bmb, exclusiveMonitor.input) + + val invalidationMonitor = BmbInvalidateMonitorGenerator() + interconnect.addConnection(exclusiveMonitor.output, invalidationMonitor.input) + interconnect.addConnection(invalidationMonitor.output, dBusNonCoherent.bmb) + interconnect.masters(invalidationMonitor.output).withOutOfOrderDecoder() + } + + val noSmp = !p.withExclusiveAndInvalidation generate new Area{ + interconnect.addConnection(dBusCoherent.bmb, dBusNonCoherent.bmb) + } val cores = for(cpuId <- 0 until cpuCount) yield new Area{ val cpu = VexRiscvBmbGenerator() cpu.config.load(p.cpuConfigs(cpuId)) interconnect.addConnection( - cpu.dBus -> List(exclusiveMonitor.input) + cpu.dBus -> List(dBusCoherent.bmb) ) cpu.enableDebugBmb( debugCd = debugCd, @@ -113,7 +125,8 @@ object VexRiscvSmpClusterGen { ioRange : UInt => Bool = (x => x(31 downto 28) === 0xF), resetVector : Long = 0x80000000l, iBusWidth : Int = 128, - dBusWidth : Int = 64) = { + dBusWidth : Int = 64, + coherency : Boolean = true) = { val config = VexRiscvConfig( plugins = List( @@ -167,8 +180,8 @@ object VexRiscvSmpClusterGen { catchUnaligned = true, withLrSc = true, withAmo = true, - withExclusive = true, - withInvalidate = true, + withExclusive = coherency, + withInvalidate = coherency, aggregationWidth = if(dBusWidth == 32) 0 else log2Up(dBusWidth/8) // ) ), diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala index ea8c95bd..43bcc382 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala @@ -22,11 +22,11 @@ class VexRiscvLitexSmpCluster(p : VexRiscvLitexSmpClusterParameter) extends VexR for(core <- cores) interconnect.addConnection(core.cpu.iBus -> List(iArbiter.bmb)) interconnect.addConnection( - iArbiter.bmb -> List(iBridge.bmb, peripheralBridge.bmb), - invalidationMonitor.output -> List(dBridge.bmb, peripheralBridge.bmb) + iArbiter.bmb -> List(iBridge.bmb, peripheralBridge.bmb), + dBusNonCoherent.bmb -> List(dBridge.bmb, peripheralBridge.bmb) ) - if(p.coherentDma || p.cluster.cpuConfigs.size > 1) interconnect.masters(invalidationMonitor.output).withOutOfOrderDecoder() + if(p.cluster.withExclusiveAndInvalidation) interconnect.masters(dBusNonCoherent.bmb).withOutOfOrderDecoder() dBridge.liteDramParameter.load(p.liteDram) iBridge.liteDramParameter.load(p.liteDram) @@ -41,7 +41,7 @@ class VexRiscvLitexSmpCluster(p : VexRiscvLitexSmpClusterParameter) extends VexR dataWidth = p.cluster.cpuConfigs.head.find(classOf[DBusCachedPlugin]).get.config.memDataWidth, useSTALL = true )) - interconnect.addConnection(bridge.bmb, exclusiveMonitor.input) + interconnect.addConnection(bridge.bmb, dBusCoherent.bmb) } // Interconnect pipelining (FMax) @@ -50,7 +50,7 @@ class VexRiscvLitexSmpCluster(p : VexRiscvLitexSmpClusterParameter) extends VexR interconnect.setPipelining(core.cpu.iBus)(cmdHalfRate = true, rspValid = true) interconnect.setPipelining(iArbiter.bmb)(cmdHalfRate = true, rspValid = true) } - interconnect.setPipelining(invalidationMonitor.output)(cmdValid = true, cmdReady = true, rspValid = true) + interconnect.setPipelining(dBusNonCoherent.bmb)(cmdValid = true, cmdReady = true, rspValid = true) interconnect.setPipelining(peripheralBridge.bmb)(cmdHalfRate = true, rspValid = true) } @@ -74,6 +74,7 @@ object VexRiscvLitexSmpClusterCmdGen extends App { opt[String]("netlist-name") action { (v, c) => netlistName = v } }.parse(args)) + val coherency = coherentDma || cpuCount > 1 def parameter = VexRiscvLitexSmpClusterParameter( cluster = VexRiscvSmpClusterParameter( cpuConfigs = List.tabulate(cpuCount) { hartId => @@ -82,9 +83,11 @@ object VexRiscvLitexSmpClusterCmdGen extends App { ioRange = address => address.msb, resetVector = 0, iBusWidth = iBusWidth, - dBusWidth = dBusWidth + dBusWidth = dBusWidth, + coherency = coherency ) - } + }, + withExclusiveAndInvalidation = coherency ), liteDram = LiteDramNativeParameter(addressWidth = 32, dataWidth = liteDramWidth), liteDramMapping = SizeMapping(0x40000000l, 0x40000000l), @@ -114,7 +117,8 @@ object VexRiscvLitexSmpClusterGen extends App { ioRange = address => address.msb, resetVector = 0 ) - } + }, + withExclusiveAndInvalidation = true ), liteDram = LiteDramNativeParameter(addressWidth = 32, dataWidth = 128), liteDramMapping = SizeMapping(0x40000000l, 0x40000000l), @@ -152,7 +156,8 @@ object VexRiscvLitexSmpClusterOpenSbi extends App{ ioRange = address => address(31 downto 28) === 0xF, resetVector = 0x80000000l ) - } + }, + withExclusiveAndInvalidation = true ), liteDram = LiteDramNativeParameter(addressWidth = 32, dataWidth = 128), liteDramMapping = SizeMapping(0x80000000l, 0x70000000l), diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexMpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexMpCluster.scala index 14daae2e..e662dfee 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexMpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexMpCluster.scala @@ -7,64 +7,64 @@ import spinal.lib.bus.wishbone.{WishboneConfig, WishboneToBmbGenerator} import spinal.lib.sim.SparseMemory import vexriscv.demo.smp.VexRiscvSmpClusterGen.vexRiscvConfig -case class VexRiscvLitexSmpMpClusterParameter( cluster : VexRiscvSmpClusterParameter, - liteDram : LiteDramNativeParameter, - liteDramMapping : AddressMapping) - -class VexRiscvLitexSmpMpCluster(p : VexRiscvLitexSmpMpClusterParameter) extends VexRiscvSmpClusterWithPeripherals(p.cluster) { - val iArbiter = BmbBridgeGenerator() - val iBridge = BmbToLiteDramGenerator(p.liteDramMapping) - val dBridge = BmbToLiteDramGenerator(p.liteDramMapping) - - for(core <- cores) interconnect.addConnection(core.cpu.iBus -> List(iArbiter.bmb)) - interconnect.addConnection( - iArbiter.bmb -> List(iBridge.bmb, peripheralBridge.bmb), - invalidationMonitor.output -> List(dBridge.bmb, peripheralBridge.bmb) - ) - interconnect.masters(invalidationMonitor.output).withOutOfOrderDecoder() - - dBridge.liteDramParameter.load(p.liteDram) - iBridge.liteDramParameter.load(p.liteDram) - - // Interconnect pipelining (FMax) - for(core <- cores) { - interconnect.setPipelining(core.cpu.dBus)(cmdValid = true, cmdReady = true, rspValid = true) - interconnect.setPipelining(core.cpu.iBus)(cmdHalfRate = true, rspValid = true) - interconnect.setPipelining(iArbiter.bmb)(cmdHalfRate = true, rspValid = true) - } - interconnect.setPipelining(invalidationMonitor.output)(cmdValid = true, cmdReady = true, rspValid = true) - interconnect.setPipelining(peripheralBridge.bmb)(cmdHalfRate = true, rspValid = true) -} - - -object VexRiscvLitexSmpMpClusterGen extends App { - for(cpuCount <- List(1,2,4,8)) { - def parameter = VexRiscvLitexSmpMpClusterParameter( - cluster = VexRiscvSmpClusterParameter( - cpuConfigs = List.tabulate(cpuCount) { hartId => - vexRiscvConfig( - hartId = hartId, - ioRange = address => address.msb, - resetVector = 0 - ) - } - ), - liteDram = LiteDramNativeParameter(addressWidth = 32, dataWidth = 128), - liteDramMapping = SizeMapping(0x40000000l, 0x40000000l) - ) - - def dutGen = { - val toplevel = new VexRiscvLitexSmpMpCluster( - p = parameter - ).toComponent() - toplevel - } - - val genConfig = SpinalConfig().addStandardMemBlackboxing(blackboxByteEnables) - // genConfig.generateVerilog(Bench.compressIo(dutGen)) - genConfig.generateVerilog(dutGen.setDefinitionName(s"VexRiscvLitexSmpMpCluster_${cpuCount}c")) - } -} +//case class VexRiscvLitexSmpMpClusterParameter( cluster : VexRiscvSmpClusterParameter, +// liteDram : LiteDramNativeParameter, +// liteDramMapping : AddressMapping) +// +//class VexRiscvLitexSmpMpCluster(p : VexRiscvLitexSmpMpClusterParameter) extends VexRiscvSmpClusterWithPeripherals(p.cluster) { +// val iArbiter = BmbBridgeGenerator() +// val iBridge = BmbToLiteDramGenerator(p.liteDramMapping) +// val dBridge = BmbToLiteDramGenerator(p.liteDramMapping) +// +// for(core <- cores) interconnect.addConnection(core.cpu.iBus -> List(iArbiter.bmb)) +// interconnect.addConnection( +// iArbiter.bmb -> List(iBridge.bmb, peripheralBridge.bmb), +// invalidationMonitor.output -> List(dBridge.bmb, peripheralBridge.bmb) +// ) +// interconnect.masters(invalidationMonitor.output).withOutOfOrderDecoder() +// +// dBridge.liteDramParameter.load(p.liteDram) +// iBridge.liteDramParameter.load(p.liteDram) +// +// // Interconnect pipelining (FMax) +// for(core <- cores) { +// interconnect.setPipelining(core.cpu.dBus)(cmdValid = true, cmdReady = true, rspValid = true) +// interconnect.setPipelining(core.cpu.iBus)(cmdHalfRate = true, rspValid = true) +// interconnect.setPipelining(iArbiter.bmb)(cmdHalfRate = true, rspValid = true) +// } +// interconnect.setPipelining(invalidationMonitor.output)(cmdValid = true, cmdReady = true, rspValid = true) +// interconnect.setPipelining(peripheralBridge.bmb)(cmdHalfRate = true, rspValid = true) +//} +// +// +//object VexRiscvLitexSmpMpClusterGen extends App { +// for(cpuCount <- List(1,2,4,8)) { +// def parameter = VexRiscvLitexSmpMpClusterParameter( +// cluster = VexRiscvSmpClusterParameter( +// cpuConfigs = List.tabulate(cpuCount) { hartId => +// vexRiscvConfig( +// hartId = hartId, +// ioRange = address => address.msb, +// resetVector = 0 +// ) +// } +// ), +// liteDram = LiteDramNativeParameter(addressWidth = 32, dataWidth = 128), +// liteDramMapping = SizeMapping(0x40000000l, 0x40000000l) +// ) +// +// def dutGen = { +// val toplevel = new VexRiscvLitexSmpMpCluster( +// p = parameter +// ).toComponent() +// toplevel +// } +// +// val genConfig = SpinalConfig().addStandardMemBlackboxing(blackboxByteEnables) +// // genConfig.generateVerilog(Bench.compressIo(dutGen)) +// genConfig.generateVerilog(dutGen.setDefinitionName(s"VexRiscvLitexSmpMpCluster_${cpuCount}c")) +// } +//} diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index f712606f..7922db8a 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -417,7 +417,8 @@ case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave val timer = Reg(UInt(log2Up(timeoutCycles)+1 bits)) init(0) val timerFull = timer.msb val hit = cmd.address(tagRange) === buffer.address(tagRange) - val canAggregate = cmd.valid && cmd.wr && !cmd.uncached && !cmd.exclusive && !timerFull && !aggregationCounterFull && (!buffer.stream.valid || aggregationEnabled && hit) + val cmdExclusive = if(p.withExclusive) cmd.exclusive else False + val canAggregate = cmd.valid && cmd.wr && !cmd.uncached && !cmdExclusive && !timerFull && !aggregationCounterFull && (!buffer.stream.valid || aggregationEnabled && hit) val doFlush = cmd.valid && !canAggregate || timerFull || aggregationCounterFull || !aggregationEnabled // val canAggregate = False // val doFlush = True @@ -468,7 +469,7 @@ case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave buffer.length := (cmd.length << 2) | 3 if (p.withExclusive) buffer.exclusive := cmd.exclusive - when(cmd.wr && !cmd.uncached && !cmd.exclusive){ + when(cmd.wr && !cmd.uncached && !cmdExclusive){ aggregationEnabled := True buffer.address(aggregationRange.high downto 0) := 0 buffer.length := p.memDataBytes-1 From 15bda15bc9f02dacd3d4b1fb6db52ee92f563ad2 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 21 Jul 2020 19:35:56 +0200 Subject: [PATCH 475/951] Litex cluster can now set cache layout --- .../vexriscv/demo/smp/VexRiscvSmpCluster.scala | 17 +++++++++++------ .../demo/smp/VexRiscvSmpLitexCluster.scala | 12 ++++++++++++ 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index 7fb693d9..b58cb0f4 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -126,8 +126,13 @@ object VexRiscvSmpClusterGen { resetVector : Long = 0x80000000l, iBusWidth : Int = 128, dBusWidth : Int = 64, - coherency : Boolean = true) = { - + coherency : Boolean = true, + iCacheSize : Int = 8192, + dCacheSize : Int = 8192, + iCacheWays : Int = 2, + dCacheWays : Int = 2) = { + assert(iCacheSize/iCacheWays <= 4096, "Instruction cache ways can't be bigger than 4096 bytes") + assert(dCacheSize/dCacheWays <= 4096, "Data cache ways can't be bigger than 4096 bytes") val config = VexRiscvConfig( plugins = List( new MmuPlugin( @@ -143,9 +148,9 @@ object VexRiscvSmpClusterGen { injectorStage = false, relaxedPcCalculation = false, config = InstructionCacheConfig( - cacheSize = 4096*2, + cacheSize = iCacheSize, bytePerLine = 64, - wayCount = 2, + wayCount = iCacheWays, addressWidth = 32, cpuDataWidth = 32, memDataWidth = iBusWidth, @@ -169,9 +174,9 @@ object VexRiscvSmpClusterGen { dBusRspSlavePipe = true, relaxedMemoryTranslationRegister = true, config = new DataCacheConfig( - cacheSize = 4096*2, + cacheSize = dCacheSize, bytePerLine = 64, - wayCount = 2, + wayCount = dCacheWays, addressWidth = 32, cpuDataWidth = 32, memDataWidth = dBusWidth, diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala index 43bcc382..bbf25cd7 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala @@ -59,6 +59,10 @@ object VexRiscvLitexSmpClusterCmdGen extends App { var cpuCount = 1 var iBusWidth = 64 var dBusWidth = 64 + var iCacheSize = 8192 + var dCacheSize = 8192 + var iCacheWays = 2 + var dCacheWays = 2 var liteDramWidth = 128 var coherentDma = false var netlistDirectory = "." @@ -69,6 +73,10 @@ object VexRiscvLitexSmpClusterCmdGen extends App { opt[String]("cpu-count") action { (v, c) => cpuCount = v.toInt } opt[String]("ibus-width") action { (v, c) => iBusWidth = v.toInt } opt[String]("dbus-width") action { (v, c) => dBusWidth = v.toInt } + opt[String]("icache-size") action { (v, c) => iCacheSize = v.toInt } + opt[String]("dcache-size") action { (v, c) => dCacheSize = v.toInt } + opt[String]("icache-ways") action { (v, c) => iCacheWays = v.toInt } + opt[String]("dcache-ways") action { (v, c) => dCacheWays = v.toInt } opt[String]("litedram-width") action { (v, c) => liteDramWidth = v.toInt } opt[String]("netlist-directory") action { (v, c) => netlistDirectory = v } opt[String]("netlist-name") action { (v, c) => netlistName = v } @@ -84,6 +92,10 @@ object VexRiscvLitexSmpClusterCmdGen extends App { resetVector = 0, iBusWidth = iBusWidth, dBusWidth = dBusWidth, + iCacheSize = iCacheSize, + dCacheSize = dCacheSize, + iCacheWays = iCacheWays, + dCacheWays = dCacheWays, coherency = coherency ) }, From cc423cbe49567b3a1edafd0f7f7b75c887294ed2 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 21 Jul 2020 19:42:27 +0200 Subject: [PATCH 476/951] Litex cluster add DMA sel feature --- .../scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala index bbf25cd7..2a524c37 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala @@ -38,8 +38,9 @@ class VexRiscvLitexSmpCluster(p : VexRiscvLitexSmpClusterParameter) extends VexR val dataWidth = p.cluster.cpuConfigs.head.find(classOf[DBusCachedPlugin]).get.config.memDataWidth bridge.config.load(WishboneConfig( addressWidth = 32 - log2Up(dataWidth / 8), - dataWidth = p.cluster.cpuConfigs.head.find(classOf[DBusCachedPlugin]).get.config.memDataWidth, - useSTALL = true + dataWidth = dataWidth, + useSTALL = true, + selWidth = dataWidth/8 )) interconnect.addConnection(bridge.bmb, dBusCoherent.bmb) } From 69d5ba239a135831f163e348612f94c3c7b7adcf Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 28 Jul 2020 16:15:17 +0200 Subject: [PATCH 477/951] Smp config now initialise regfile using logic --- src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index b58cb0f4..78e48dc2 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -202,8 +202,8 @@ object VexRiscvSmpClusterGen { ), new RegFilePlugin( regFileReadyKind = plugin.ASYNC, - zeroBoot = true, - x0Init = false + zeroBoot = false, + x0Init = true ), new IntAluPlugin, new SrcPlugin( @@ -630,4 +630,4 @@ object VexRiscvSmpClusterGen { // } // } // } -//} \ No newline at end of file +//} From 7dcaa0c390ee10cc461ba0f35e54ac6d70ce9233 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 13 Aug 2020 11:26:11 +0200 Subject: [PATCH 478/951] VexRiscvSmpCluster now avoid useless decoder for plic/clint --- .../demo/smp/VexRiscvSmpCluster.scala | 47 +++++++++++++++---- 1 file changed, 37 insertions(+), 10 deletions(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index 78e48dc2..343d2711 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -82,21 +82,48 @@ class VexRiscvSmpClusterWithPeripherals(p : VexRiscvSmpClusterParameter) extends val peripheral = peripheralBridge.produceIo(peripheralBridge.logic.io.output) interconnect.slaves(peripheralBridge.bmb).forceAccessSourceDataWidth(32) - val plic = BmbPlicGenerator(0) + val plic = BmbPlicGenerator()(interconnect = null) plic.priorityWidth.load(2) plic.mapping.load(PlicMapping.sifive) - val plicWishboneBridge = WishboneToBmbGenerator() - val plicWishbone = plicWishboneBridge.produceIo(plicWishboneBridge.logic.io.input) - plicWishboneBridge.config.load(WishboneConfig(20, 32)) - interconnect.addConnection(plicWishboneBridge.bmb, plic.ctrl) + val plicWishboneBridge = new Generator{ + dependencies += plic.ctrl - val clint = BmbClintGenerator(0) + plic.accessRequirements.load(BmbAccessParameter( + addressWidth = 22, + dataWidth = 32 + ).addSources(1, BmbSourceParameter( + contextWidth = 0, + lengthWidth = 2, + alignment = BmbParameter.BurstAlignement.LENGTH + ))) - val clintWishboneBridge = WishboneToBmbGenerator() - val clintWishbone = clintWishboneBridge.produceIo(clintWishboneBridge.logic.io.input) - clintWishboneBridge.config.load(WishboneConfig(14, 32)) - interconnect.addConnection(clintWishboneBridge.bmb, clint.ctrl) + val logic = add task new Area{ + val bridge = WishboneToBmb(WishboneConfig(20, 32)) + bridge.io.output >> plic.ctrl + } + } + val plicWishbone = plicWishboneBridge.produceIo(plicWishboneBridge.logic.bridge.io.input) + + val clint = BmbClintGenerator(0)(interconnect = null) + val clintWishboneBridge = new Generator{ + dependencies += clint.ctrl + + clint.accessRequirements.load(BmbAccessParameter( + addressWidth = 16, + dataWidth = 32 + ).addSources(1, BmbSourceParameter( + contextWidth = 0, + lengthWidth = 2, + alignment = BmbParameter.BurstAlignement.LENGTH + ))) + + val logic = add task new Area{ + val bridge = WishboneToBmb(WishboneConfig(14, 32)) + bridge.io.output >> clint.ctrl + } + } + val clintWishbone = clintWishboneBridge.produceIo(clintWishboneBridge.logic.bridge.io.input) val interrupts = add task (in Bits(32 bits)) for(i <- 1 to 31) yield plic.addInterrupt(interrupts.derivate(_.apply(i)), i) From c489143442d9ccc23790153cca6ad33c2736114a Mon Sep 17 00:00:00 2001 From: Marcus Comstedt Date: Sun, 30 Aug 2020 15:17:09 +0200 Subject: [PATCH 479/951] Add support for big endian byte ordering --- src/main/scala/vexriscv/demo/Murax.scala | 17 ++-- .../scala/vexriscv/demo/MuraxUtiles.scala | 20 ++-- .../vexriscv/plugin/DBusSimplePlugin.scala | 93 ++++++++++--------- .../vexriscv/plugin/IBusSimplePlugin.scala | 9 +- 4 files changed, 81 insertions(+), 58 deletions(-) diff --git a/src/main/scala/vexriscv/demo/Murax.scala b/src/main/scala/vexriscv/demo/Murax.scala index 6d98907b..a0590ade 100644 --- a/src/main/scala/vexriscv/demo/Murax.scala +++ b/src/main/scala/vexriscv/demo/Murax.scala @@ -52,8 +52,8 @@ case class MuraxConfig(coreFrequency : HertzNumber, object MuraxConfig{ - def default : MuraxConfig = default(false) - def default(withXip : Boolean) = MuraxConfig( + def default : MuraxConfig = default(false, false) + def default(withXip : Boolean = false, bigEndian : Boolean = false) = MuraxConfig( coreFrequency = 12 MHz, onChipRamSize = 8 kB, onChipRamHexFile = null, @@ -75,12 +75,14 @@ object MuraxConfig{ cmdForkPersistence = withXip, //Required by the Xip controller prediction = NONE, catchAccessFault = false, - compressedGen = false + compressedGen = false, + bigEndian = bigEndian ), new DBusSimplePlugin( catchAddressMisaligned = false, catchAccessFault = false, - earlyInjection = false + earlyInjection = false, + bigEndian = bigEndian ), new CsrPlugin(CsrPluginConfig.smallest(mtvecInit = if(withXip) 0xE0040020l else 0x80000020l)), new DecoderSimplePlugin( @@ -214,9 +216,11 @@ case class Murax(config : MuraxConfig) extends Component{ dataWidth = 32 ) + val bigEndianDBus = config.cpuPlugins.exists(_ match{ case plugin : DBusSimplePlugin => plugin.bigEndian case _ => false}) + //Arbiter of the cpu dBus/iBus to drive the mainBus //Priority to dBus, !! cmd transactions can change on the fly !! - val mainBusArbiter = new MuraxMasterArbiter(pipelinedMemoryBusConfig) + val mainBusArbiter = new MuraxMasterArbiter(pipelinedMemoryBusConfig, bigEndianDBus) //Instanciate the CPU val cpu = new VexRiscv( @@ -258,7 +262,8 @@ case class Murax(config : MuraxConfig) extends Component{ val ram = new MuraxPipelinedMemoryBusRam( onChipRamSize = onChipRamSize, onChipRamHexFile = onChipRamHexFile, - pipelinedMemoryBusConfig = pipelinedMemoryBusConfig + pipelinedMemoryBusConfig = pipelinedMemoryBusConfig, + bigEndian = bigEndianDBus ) mainBusMapping += ram.io.bus -> (0x80000000l, onChipRamSize) diff --git a/src/main/scala/vexriscv/demo/MuraxUtiles.scala b/src/main/scala/vexriscv/demo/MuraxUtiles.scala index 1c45bc37..1e221570 100644 --- a/src/main/scala/vexriscv/demo/MuraxUtiles.scala +++ b/src/main/scala/vexriscv/demo/MuraxUtiles.scala @@ -10,10 +10,10 @@ import spinal.lib._ import spinal.lib.bus.simple._ import vexriscv.plugin.{DBusSimpleBus, IBusSimpleBus} -class MuraxMasterArbiter(pipelinedMemoryBusConfig : PipelinedMemoryBusConfig) extends Component{ +class MuraxMasterArbiter(pipelinedMemoryBusConfig : PipelinedMemoryBusConfig, bigEndian : Boolean = false) extends Component{ val io = new Bundle{ val iBus = slave(IBusSimpleBus(null)) - val dBus = slave(DBusSimpleBus()) + val dBus = slave(DBusSimpleBus(bigEndian)) val masterBus = master(PipelinedMemoryBus(pipelinedMemoryBusConfig)) } @@ -21,11 +21,7 @@ class MuraxMasterArbiter(pipelinedMemoryBusConfig : PipelinedMemoryBusConfig) ex 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.cmd.size.mux( - 0 -> B"0001", - 1 -> B"0011", - default -> B"1111" - ) |<< io.dBus.cmd.address(1 downto 0) + 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 @@ -53,7 +49,7 @@ class MuraxMasterArbiter(pipelinedMemoryBusConfig : PipelinedMemoryBusConfig) ex } -case class MuraxPipelinedMemoryBusRam(onChipRamSize : BigInt, onChipRamHexFile : String, pipelinedMemoryBusConfig : PipelinedMemoryBusConfig) extends Component{ +case class MuraxPipelinedMemoryBusRam(onChipRamSize : BigInt, onChipRamHexFile : String, pipelinedMemoryBusConfig : PipelinedMemoryBusConfig, bigEndian : Boolean = false) extends Component{ val io = new Bundle{ val bus = slave(PipelinedMemoryBus(pipelinedMemoryBusConfig)) } @@ -71,6 +67,14 @@ case class MuraxPipelinedMemoryBusRam(onChipRamSize : BigInt, onChipRamHexFile : 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) } } diff --git a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala index e08b6402..c9fe2121 100644 --- a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala @@ -90,7 +90,7 @@ object DBusSimpleBus{ ) } -case class DBusSimpleBus() extends Bundle with IMasterSlave{ +case class DBusSimpleBus(bigEndian : Boolean = false) extends Bundle with IMasterSlave{ val cmd = Stream(DBusSimpleCmd()) val rsp = DBusSimpleRsp() @@ -100,12 +100,27 @@ case class DBusSimpleBus() extends Bundle with IMasterSlave{ } def cmdS2mPipe() : DBusSimpleBus = { - val s = DBusSimpleBus() + val s = DBusSimpleBus(bigEndian) s.cmd << this.cmd.s2mPipe() this.rsp := s.rsp s } + def genMask(cmd : DBusSimpleCmd) = { + if(bigEndian) + cmd.size.mux( + U(0) -> B"1000", + U(1) -> B"1100", + default -> B"1111" + ) |>> cmd.address(1 downto 0) + else + cmd.size.mux( + U(0) -> B"0001", + U(1) -> B"0011", + default -> B"1111" + ) |<< cmd.address(1 downto 0) + } + def toAxi4Shared(stageCmd : Boolean = false, pendingWritesMax : Int = 7): Axi4Shared = { val axi = Axi4Shared(DBusSimpleBus.getAxi4Config()) @@ -130,11 +145,7 @@ case class DBusSimpleBus() extends Bundle with IMasterSlave{ axi.writeData.arbitrationFrom(dataStage) axi.writeData.last := True axi.writeData.data := dataStage.data - axi.writeData.strb := (dataStage.size.mux( - U(0) -> B"0001", - U(1) -> B"0011", - default -> B"1111" - ) << dataStage.address(1 downto 0)).resized + axi.writeData.strb := genMask(dataStage).resized rsp.ready := axi.r.valid @@ -158,11 +169,7 @@ case class DBusSimpleBus() extends Bundle with IMasterSlave{ mm.write := cmdStage.valid && cmdStage.wr mm.address := (cmdStage.address >> 2) @@ U"00" mm.writeData := cmdStage.data(31 downto 0) - mm.byteEnable := (cmdStage.size.mux ( - U(0) -> B"0001", - U(1) -> B"0011", - default -> B"1111" - ) << cmdStage.address(1 downto 0)).resized + mm.byteEnable := genMask(cmdStage).resized cmdStage.ready := mm.waitRequestn @@ -181,11 +188,7 @@ case class DBusSimpleBus() extends Bundle with IMasterSlave{ bus.ADR := cmdStage.address >> 2 bus.CTI :=B"000" bus.BTE := "00" - bus.SEL := (cmdStage.size.mux ( - U(0) -> B"0001", - U(1) -> B"0011", - default -> B"1111" - ) << cmdStage.address(1 downto 0)).resized + bus.SEL := genMask(cmdStage).resized when(!cmdStage.wr) { bus.SEL := "1111" } @@ -209,11 +212,7 @@ case class DBusSimpleBus() extends Bundle with IMasterSlave{ bus.cmd.write := cmd.wr bus.cmd.address := cmd.address.resized bus.cmd.data := cmd.data - bus.cmd.mask := cmd.size.mux( - 0 -> B"0001", - 1 -> B"0011", - default -> B"1111" - ) |<< cmd.address(1 downto 0) + bus.cmd.mask := genMask(cmd) cmd.ready := bus.cmd.ready rsp.ready := bus.rsp.valid @@ -265,11 +264,7 @@ case class DBusSimpleBus() extends Bundle with IMasterSlave{ 1 -> U"01", default -> U"11" ) - bus.cmd.mask := cmd.size.mux( - 0 -> B"0001", - 1 -> B"0011", - default -> B"1111" - ) |<< cmd.address(1 downto 0) + bus.cmd.mask := genMask(cmd) cmd.ready := bus.cmd.ready @@ -289,6 +284,7 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, emitCmdInMemoryStage : Boolean = false, onlyLoadWords : Boolean = false, withLrSc : Boolean = false, + val bigEndian : Boolean = false, memoryTranslatorPortConfig : Any = null) extends Plugin[VexRiscv] with DBusAccessService { var dBus : DBusSimpleBus = null @@ -393,7 +389,7 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, import pipeline._ import pipeline.config._ - dBus = master(DBusSimpleBus()).setName("dBus") + dBus = master(DBusSimpleBus(bigEndian)).setName("dBus") decode plug new Area { @@ -436,11 +432,7 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, insert(MEMORY_ADDRESS_LOW) := dBus.cmd.address(1 downto 0) //formal - val formalMask = dBus.cmd.size.mux( - U(0) -> B"0001", - U(1) -> B"0011", - default -> B"1111" - ) |<< dBus.cmd.address(1 downto 0) + val formalMask = dBus.genMask(dBus.cmd) insert(FORMAL_MEM_ADDR) := dBus.cmd.address & U"xFFFFFFFC" insert(FORMAL_MEM_WMASK) := (dBus.cmd.valid && dBus.cmd.wr) ? formalMask | B"0000" @@ -541,17 +533,32 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, val rspShifted = MEMORY_READ_DATA() rspShifted := input(MEMORY_READ_DATA) - switch(input(MEMORY_ADDRESS_LOW)){ - is(1){rspShifted(7 downto 0) := input(MEMORY_READ_DATA)(15 downto 8)} - is(2){rspShifted(15 downto 0) := input(MEMORY_READ_DATA)(31 downto 16)} - is(3){rspShifted(7 downto 0) := input(MEMORY_READ_DATA)(31 downto 24)} - } + if(bigEndian) + switch(input(MEMORY_ADDRESS_LOW)){ + is(1){rspShifted(31 downto 24) := input(MEMORY_READ_DATA)(23 downto 16)} + is(2){rspShifted(31 downto 16) := input(MEMORY_READ_DATA)(15 downto 0)} + is(3){rspShifted(31 downto 24) := input(MEMORY_READ_DATA)(7 downto 0)} + } + else + switch(input(MEMORY_ADDRESS_LOW)){ + is(1){rspShifted(7 downto 0) := input(MEMORY_READ_DATA)(15 downto 8)} + is(2){rspShifted(15 downto 0) := input(MEMORY_READ_DATA)(31 downto 16)} + is(3){rspShifted(7 downto 0) := input(MEMORY_READ_DATA)(31 downto 24)} + } - val rspFormated = input(INSTRUCTION)(13 downto 12).mux( - 0 -> B((31 downto 8) -> (rspShifted(7) && !input(INSTRUCTION)(14)),(7 downto 0) -> rspShifted(7 downto 0)), - 1 -> B((31 downto 16) -> (rspShifted(15) && ! input(INSTRUCTION)(14)),(15 downto 0) -> rspShifted(15 downto 0)), - default -> rspShifted //W - ) + val rspFormated = + if(bigEndian) + input(INSTRUCTION)(13 downto 12).mux( + 0 -> B((31 downto 8) -> (rspShifted(31) && !input(INSTRUCTION)(14)),(7 downto 0) -> rspShifted(31 downto 24)), + 1 -> B((31 downto 16) -> (rspShifted(31) && ! input(INSTRUCTION)(14)),(15 downto 0) -> rspShifted(31 downto 16)), + default -> rspShifted //W + ) + else + input(INSTRUCTION)(13 downto 12).mux( + 0 -> B((31 downto 8) -> (rspShifted(7) && !input(INSTRUCTION)(14)),(7 downto 0) -> rspShifted(7 downto 0)), + 1 -> B((31 downto 16) -> (rspShifted(15) && ! input(INSTRUCTION)(14)),(15 downto 0) -> rspShifted(15 downto 0)), + default -> rspShifted //W + ) when(arbitration.isValid && input(MEMORY_ENABLE)) { output(REGFILE_WRITE_DATA) := (if(!onlyLoadWords) rspFormated else input(MEMORY_READ_DATA)) diff --git a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala index b8bc9782..22c3606e 100644 --- a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala @@ -234,7 +234,8 @@ class IBusSimplePlugin( resetVector : BigInt, val singleInstructionPipeline : Boolean = false, val memoryTranslatorPortConfig : Any = null, relaxPredictorAddress : Boolean = true, - predictionBuffer : Boolean = true + predictionBuffer : Boolean = true, + bigEndian : Boolean = false ) extends IBusFetcherImpl( resetVector = resetVector, keepPcPlus4 = keepPcPlus4, @@ -371,6 +372,12 @@ class IBusSimplePlugin( resetVector : BigInt, fetchRsp.pc := stages.last.output.payload fetchRsp.rsp := rspBuffer.output.payload fetchRsp.rsp.error.clearWhen(!rspBuffer.output.valid) //Avoid interference with instruction injection from the debug plugin + if(bigEndian){ + // inst(15 downto 0) should contain lower addressed parcel, + // and inst(31 downto 16) the higher addressed parcel + fetchRsp.rsp.inst.allowOverride + fetchRsp.rsp.inst := rspBuffer.output.payload.inst.rotateLeft(16) + } val join = Stream(FetchRsp()) val exceptionDetected = False From 4c3cad97d3db3e708e8065586612ebd624f9cf32 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 4 Sep 2020 10:36:02 +0200 Subject: [PATCH 480/951] fix CfuPlugin generation --- .../scala/vexriscv/demo/GenSmallAndProductiveCfu.scala | 8 +++++++- src/main/scala/vexriscv/plugin/CfuPlugin.scala | 4 ++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/main/scala/vexriscv/demo/GenSmallAndProductiveCfu.scala b/src/main/scala/vexriscv/demo/GenSmallAndProductiveCfu.scala index 960242f2..1810787b 100644 --- a/src/main/scala/vexriscv/demo/GenSmallAndProductiveCfu.scala +++ b/src/main/scala/vexriscv/demo/GenSmallAndProductiveCfu.scala @@ -53,7 +53,13 @@ object GenSmallAndProductiveCfu extends App{ new CfuPlugin( stageCount = 1, allowZeroLatency = true, -// encoding = M"000000-------------------0001011", + encodings = List( + CfuPluginEncoding ( + instruction = M"-------------------------0001011", + functionId = List(14 downto 12), + input2Kind = CfuPlugin.Input2Kind.RS + ) + ), busParameter = CfuBusParameter( CFU_VERSION = 0, CFU_INTERFACE_ID_W = 0, diff --git a/src/main/scala/vexriscv/plugin/CfuPlugin.scala b/src/main/scala/vexriscv/plugin/CfuPlugin.scala index de0ae915..a805bff0 100644 --- a/src/main/scala/vexriscv/plugin/CfuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CfuPlugin.scala @@ -97,7 +97,7 @@ class CfuPlugin( val stageCount : Int, assert(p.CFU_INPUTS <= 2) assert(p.CFU_OUTPUTS == 1) - assert(p.CFU_FUNCTION_ID_W == 3) +// assert(p.CFU_FUNCTION_ID_W == 3) var bus : CfuBus = null var joinException : Flow[ExceptionCause] = null @@ -128,7 +128,7 @@ class CfuPlugin( val stageCount : Int, BYPASSABLE_EXECUTE_STAGE -> Bool(stageCount == 0), BYPASSABLE_MEMORY_STAGE -> Bool(stageCount <= 1), RS1_USE -> True, - CFU_ENCODING -> id, + CFU_ENCODING -> U(id), CFU_INPUT_2_KIND -> encoding.input2Kind() ) From 8e466dd13c8a4c35b7c40a57a8bf772137a39b84 Mon Sep 17 00:00:00 2001 From: Marcus Comstedt Date: Sun, 6 Sep 2020 17:05:31 +0200 Subject: [PATCH 481/951] Add support for RV32E in RegFilePlugin The RV32E extension removes registers x16-x31 from the ISA. This is useful when compiling with -mem2reg to save on BRAMs. On iCE40 HX8K this option saves 1285 LC:s, which also improves the routing situation, when using -mem2reg. Note that the illegal instruction exception required by the RV32E specification for accesses to registers x16-x31 is not implemented. --- .../scala/vexriscv/plugin/RegFilePlugin.scala | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/RegFilePlugin.scala b/src/main/scala/vexriscv/plugin/RegFilePlugin.scala index a34dc462..f2f7a4e9 100644 --- a/src/main/scala/vexriscv/plugin/RegFilePlugin.scala +++ b/src/main/scala/vexriscv/plugin/RegFilePlugin.scala @@ -18,6 +18,7 @@ class RegFilePlugin(regFileReadyKind : RegFileReadKind, writeRfInMemoryStage : Boolean = false, readInExecute : Boolean = false, syncUpdateOnStall : Boolean = true, + rv32e : Boolean = false, withShadow : Boolean = false //shadow registers aren't transition hazard free ) extends Plugin[VexRiscv] with RegFileService{ import Riscv._ @@ -39,8 +40,11 @@ class RegFilePlugin(regFileReadyKind : RegFileReadKind, val readStage = if(readInExecute) execute else decode val writeStage = if(writeRfInMemoryStage) memory else stages.last + val numRegisters = if(rv32e) 16 else 32 + def clipRange(that : Range) = if(rv32e) that.tail else that + val global = pipeline plug new Area{ - val regFileSize = if(withShadow) 64 else 32 + val regFileSize = if(withShadow) numRegisters * 2 else numRegisters val regFile = Mem(Bits(32 bits),regFileSize) addAttribute(Verilator.public) if(zeroBoot) regFile.init(List.fill(regFileSize)(B(0, 32 bits))) @@ -59,6 +63,9 @@ class RegFilePlugin(regFileReadyKind : RegFileReadKind, when(decode.input(INSTRUCTION)(rdRange) === 0) { decode.input(REGFILE_WRITE_VALID) := False } + if(rv32e) when(decode.input(INSTRUCTION)(rdRange.head)) { + decode.input(REGFILE_WRITE_VALID) := False + } //Read register file readStage plug new Area{ @@ -72,8 +79,8 @@ class RegFilePlugin(regFileReadyKind : RegFileReadKind, } def shadowPrefix(that : Bits) = if(withShadow) global.shadow.read ## that else that - val regFileReadAddress1 = U(shadowPrefix(srcInstruction(Riscv.rs1Range))) - val regFileReadAddress2 = U(shadowPrefix(srcInstruction(Riscv.rs2Range))) + val regFileReadAddress1 = U(shadowPrefix(srcInstruction(clipRange(Riscv.rs1Range)))) + val regFileReadAddress2 = U(shadowPrefix(srcInstruction(clipRange(Riscv.rs2Range)))) val (rs1Data,rs2Data) = regFileReadyKind match{ case `ASYNC` => (global.regFile.readAsync(regFileReadAddress1),global.regFile.readAsync(regFileReadAddress2)) @@ -93,7 +100,7 @@ class RegFilePlugin(regFileReadyKind : RegFileReadKind, def shadowPrefix(that : Bits) = if(withShadow) global.shadow.write ## that else that val regFileWrite = global.regFile.writePort.addAttribute(Verilator.public).setName("lastStageRegFileWrite") regFileWrite.valid := output(REGFILE_WRITE_VALID) && arbitration.isFiring - regFileWrite.address := U(shadowPrefix(output(INSTRUCTION)(rdRange))) + regFileWrite.address := U(shadowPrefix(output(INSTRUCTION)(clipRange(rdRange)))) regFileWrite.data := output(REGFILE_WRITE_DATA) //Ensure no boot glitches modify X0 From 49488d19afa5429c4f03f4854542210f37c691d8 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 7 Sep 2020 12:01:03 +0200 Subject: [PATCH 482/951] pipeline data cache unaligned access check --- src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala | 5 +++-- src/main/scala/vexriscv/ip/DataCache.scala | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index 343d2711..2ca7a3eb 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -157,7 +157,8 @@ object VexRiscvSmpClusterGen { iCacheSize : Int = 8192, dCacheSize : Int = 8192, iCacheWays : Int = 2, - dCacheWays : Int = 2) = { + dCacheWays : Int = 2, + iBusRelax : Boolean = false) = { assert(iCacheSize/iCacheWays <= 4096, "Instruction cache ways can't be bigger than 4096 bytes") assert(dCacheSize/dCacheWays <= 4096, "Data cache ways can't be bigger than 4096 bytes") val config = VexRiscvConfig( @@ -173,7 +174,7 @@ object VexRiscvSmpClusterGen { historyRamSizeLog2 = 9, relaxPredictorAddress = true, injectorStage = false, - relaxedPcCalculation = false, + relaxedPcCalculation = iBusRelax, config = InstructionCacheConfig( cacheSize = iCacheSize, bytePerLine = 64, diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index 7922db8a..2d247e25 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -791,6 +791,7 @@ class DataCache(val p : DataCacheConfig, mmuParameter : MemoryTranslatorBusParam val wayInvalidate = stagePipe(stageA. wayInvalidate) val consistancyHazard = if(stageA.consistancyCheck != null) stagePipe(stageA.consistancyCheck.hazard) else False val dataColisions = stagePipe(stageA.dataColisions) + val unaligned = if(!catchUnaligned) False else stagePipe((stageA.request.size === 2 && io.cpu.memory.address(1 downto 0) =/= 0) || (stageA.request.size === 1 && io.cpu.memory.address(0 downto 0) =/= 0)) val waysHitsBeforeInvalidate = if(earlyWaysHits) stagePipe(B(stageA.wayHits)) else B(tagsReadRsp.map(tag => mmuRsp.physicalAddress(tagRange) === tag.address && tag.valid).asBits()) val waysHits = waysHitsBeforeInvalidate & ~wayInvalidate val waysHit = waysHits.orR @@ -891,7 +892,7 @@ class DataCache(val p : DataCacheConfig, mmuParameter : MemoryTranslatorBusParam io.cpu.redo := False io.cpu.writeBack.accessError := False io.cpu.writeBack.mmuException := io.cpu.writeBack.isValid && (if(catchIllegal) mmuRsp.exception || (!mmuRsp.allowWrite && request.wr) || (!mmuRsp.allowRead && (!request.wr || isAmo)) else False) - io.cpu.writeBack.unalignedAccess := io.cpu.writeBack.isValid && (if(catchUnaligned) ((request.size === 2 && mmuRsp.physicalAddress(1 downto 0) =/= 0) || (request.size === 1 && mmuRsp.physicalAddress(0 downto 0) =/= 0)) else False) + io.cpu.writeBack.unalignedAccess := io.cpu.writeBack.isValid && unaligned io.cpu.writeBack.isWrite := request.wr io.mem.cmd.valid := False From de820daf74dd8ffaaabf44ccb05422fee70dbdbe Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sun, 13 Sep 2020 18:33:06 +0200 Subject: [PATCH 483/951] add earlyBranch option to Smp config --- src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index 2ca7a3eb..0eacb271 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -158,7 +158,8 @@ object VexRiscvSmpClusterGen { dCacheSize : Int = 8192, iCacheWays : Int = 2, dCacheWays : Int = 2, - iBusRelax : Boolean = false) = { + iBusRelax : Boolean = false, + earlyBranch : Boolean = true) = { assert(iCacheSize/iCacheWays <= 4096, "Instruction cache ways can't be bigger than 4096 bytes") assert(dCacheSize/dCacheWays <= 4096, "Data cache ways can't be bigger than 4096 bytes") val config = VexRiscvConfig( @@ -257,7 +258,7 @@ object VexRiscvSmpClusterGen { ), new CsrPlugin(CsrPluginConfig.openSbi(mhartid = hartId, misa = Riscv.misaToInt("imas")).copy(utimeAccess = CsrAccess.READ_ONLY)), new BranchPlugin( - earlyBranch = true, + earlyBranch = earlyBranch, catchAddressMisaligned = true, fenceiGenAsAJump = false ), From 3f5e771a5c271e7e865b1040515140e893723b3b Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 17 Sep 2020 22:06:29 +0200 Subject: [PATCH 484/951] dbus mmu access improvement --- src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala | 2 +- src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala | 4 +++- src/main/scala/vexriscv/plugin/SrcPlugin.scala | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index 0eacb271..e067c395 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -159,7 +159,7 @@ object VexRiscvSmpClusterGen { iCacheWays : Int = 2, dCacheWays : Int = 2, iBusRelax : Boolean = false, - earlyBranch : Boolean = true) = { + earlyBranch : Boolean = false) = { assert(iCacheSize/iCacheWays <= 4096, "Instruction cache ways can't be bigger than 4096 bytes") assert(dCacheSize/dCacheWays <= 4096, "Data cache ways can't be bigger than 4096 bytes") val config = VexRiscvConfig( diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index 0b580d83..2901c25b 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -250,8 +250,10 @@ class DBusCachedPlugin(val config : DataCacheConfig, if(twoStageMmu) { mmuBus.cmd(0).isValid := cache.io.cpu.execute.isValid mmuBus.cmd(0).isStuck := arbitration.isStuck - mmuBus.cmd(0).virtualAddress := cache.io.cpu.execute.address + mmuBus.cmd(0).virtualAddress := input(SRC_ADD).asUInt mmuBus.cmd(0).bypassTranslation := False +// KeepAttribute(mmuBus.cmd(0)) +// KeepAttribute(mmuBus.cmd(1)) } cache.io.cpu.flush.valid := arbitration.isValid && input(MEMORY_MANAGMENT) diff --git a/src/main/scala/vexriscv/plugin/SrcPlugin.scala b/src/main/scala/vexriscv/plugin/SrcPlugin.scala index 9085ed1f..eb5ab1f3 100644 --- a/src/main/scala/vexriscv/plugin/SrcPlugin.scala +++ b/src/main/scala/vexriscv/plugin/SrcPlugin.scala @@ -2,6 +2,7 @@ package vexriscv.plugin import vexriscv._ import spinal.core._ +import spinal.lib.KeepAttribute class SrcPlugin(separatedAddSub : Boolean = false, executeInsertion : Boolean = false, decodeAddSub : Boolean = false) extends Plugin[VexRiscv]{ From 9d35e75fb5972af8b3f04fb7fc5dc8cf9d9ef6de Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 1 Oct 2020 16:41:24 +0200 Subject: [PATCH 485/951] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bb37f034..57372fcb 100644 --- a/README.md +++ b/README.md @@ -283,7 +283,7 @@ Note that sometimes Eclipse needs to be restarted in order to be able to place n ## Briey SoC As a demonstration, a SoC named Briey is implemented in `src/main/scala/vexriscv/demo/Briey.scala`. This SoC is very similar to -the [Pinsec SoC](https://spinalhdl.github.io/SpinalDoc/spinal/lib/pinsec/hardware/): +the [Pinsec SoC](https://spinalhdl.github.io/SpinalDoc-RTD/SpinalHDL/Legacy/pinsec/hardware_toplevel.html#): ![Briey SoC](assets/brieySoc.png?raw=true "") From 65e6f6054bcab77d4b93621a5cd47fab5cc67f1f Mon Sep 17 00:00:00 2001 From: bunnie Date: Sun, 4 Oct 2020 15:34:58 +0800 Subject: [PATCH 486/951] Add ASID field to SATP ASID field is missing from the SATP which causes compatibility issues with Xous. While this patch resolves the Xous issue, it has not been tested on Linux. --- src/main/scala/vexriscv/plugin/MmuPlugin.scala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/plugin/MmuPlugin.scala b/src/main/scala/vexriscv/plugin/MmuPlugin.scala index 9dedde5d..49e402d9 100644 --- a/src/main/scala/vexriscv/plugin/MmuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/MmuPlugin.scala @@ -91,11 +91,12 @@ class MmuPlugin(ioRange : UInt => Bool, } val satp = new Area { val mode = RegInit(False) + val asid = Reg(Bits(9 bits)) val ppn = Reg(UInt(20 bits)) } for(offset <- List(CSR.MSTATUS, CSR.SSTATUS)) csrService.rw(offset, 19 -> status.mxr, 18 -> status.sum, 17 -> status.mprv) - csrService.rw(CSR.SATP, 31 -> satp.mode, 0 -> satp.ppn) + csrService.rw(CSR.SATP, 31 -> satp.mode, 22 -> satp.asid, 0 -> satp.ppn) } val core = pipeline plug new Area { From b7e7faebadb5daf83118405fc6bdb0bd9f2a59e0 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sun, 4 Oct 2020 09:57:34 +0200 Subject: [PATCH 487/951] sbt update --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 87130251..329dbaf6 100644 --- a/README.md +++ b/README.md @@ -179,7 +179,7 @@ sbt "runMain vexriscv.demo.GenSmallest" NOTES: - It could take time the first time you run it. - The VexRiscv project may need an unreleased master-head of the SpinalHDL repo. If it fails to compile, just get the SpinalHDL repository and - do a "sbt clean compile publish-local" in it as described in the dependencies chapter. + do a "sbt clean compile publishLocal" in it as described in the dependencies chapter. ## Regression tests From bbaa0520c061b62e6e28059005a49bba4a7a7a82 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 9 Oct 2020 10:45:23 +0200 Subject: [PATCH 488/951] Fix UserInterruptPlugin interrupt enable --- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index bf65b199..897a2063 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -1191,9 +1191,9 @@ class UserInterruptPlugin(interruptName : String, code : Int, privilege : Int = interrupt = in.Bool().setName(interruptName) val interruptPending = RegNext(interrupt) init(False) val interruptEnable = RegInit(False).setName(interruptName + "_enable") - csr.addInterrupt(interruptPending , code, privilege, Nil) + csr.addInterrupt(interruptPending && interruptEnable, code, privilege, Nil) csr.r(csrAddress = CSR.MIP, bitOffset = code,interruptPending) csr.rw(csrAddress = CSR.MIE, bitOffset = code, interruptEnable) } override def build(pipeline: VexRiscv): Unit = {} -} \ No newline at end of file +} From ec55187033eae2db01c93c725ca5b94006411704 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 9 Oct 2020 11:37:39 +0200 Subject: [PATCH 489/951] improve LightShifterPlugin arbitration halt timings --- src/main/scala/vexriscv/plugin/ShiftPlugins.scala | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/ShiftPlugins.scala b/src/main/scala/vexriscv/plugin/ShiftPlugins.scala index fcebe3aa..a4ae716c 100644 --- a/src/main/scala/vexriscv/plugin/ShiftPlugins.scala +++ b/src/main/scala/vexriscv/plugin/ShiftPlugins.scala @@ -178,10 +178,12 @@ class LightShifterPlugin extends Plugin[VexRiscv]{ when(done){ isActive := False - } otherwise{ - arbitration.haltItself := True } } + + when(!done){ + arbitration.haltItself := True + } } when(arbitration.removeIt){ isActive := False From e58daee088b8d38247019451ce3e2664d8630033 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 16 Oct 2020 11:25:25 +0200 Subject: [PATCH 490/951] SpinalHDL++ --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index 6cdb3507..23d41fde 100644 --- a/build.sbt +++ b/build.sbt @@ -5,7 +5,7 @@ lazy val root = (project in file(".")). scalaVersion := "2.11.12", version := "2.0.0" )), - scalacOptions += s"-Xplugin:${new File(baseDirectory.value + "/../SpinalHDL/idslplugin/target/scala-2.11/spinalhdl-idsl-plugin_2.11-1.4.2.jar")}", + scalacOptions += s"-Xplugin:${new File(baseDirectory.value + "/../SpinalHDL/idslplugin/target/scala-2.11/spinalhdl-idsl-plugin_2.11-1.4.3.jar")}", scalacOptions += s"-Xplugin-require:idsl-plugin", libraryDependencies ++= Seq( // "com.github.spinalhdl" % "spinalhdl-core_2.11" % "1.3.6", From 4ece59385d42850a9df930e71bfb592e58fe7e00 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 19 Oct 2020 18:12:20 +0200 Subject: [PATCH 491/951] DataCache split redo / refilling execute stage halt --- src/main/scala/vexriscv/ip/DataCache.scala | 7 +++++-- src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala | 6 +++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index 2d247e25..a5e4d7d4 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -110,10 +110,11 @@ case class DataCacheCpuExecute(p : DataCacheConfig) extends Bundle with IMasterS val address = UInt(p.addressWidth bit) val haltIt = Bool val args = DataCacheCpuExecuteArgs(p) + val refilling = Bool override def asMaster(): Unit = { out(isValid, args, address) - in(haltIt) + in(haltIt, refilling) } } @@ -1072,7 +1073,9 @@ class DataCache(val p : DataCacheConfig, mmuParameter : MemoryTranslatorBusParam waysAllocator := (waysAllocator ## waysAllocator.msb).resized } - io.cpu.redo setWhen(valid) + io.cpu.redo setWhen(valid.rise()) + io.cpu.execute.refilling := valid + stageB.mmuRspFreeze setWhen(stageB.loaderValid || valid) } diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index 2901c25b..20c193f0 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -275,8 +275,8 @@ class DBusCachedPlugin(val config : DataCacheConfig, insert(MEMORY_ADDRESS_LOW) := cache.io.cpu.execute.address(1 downto 0) - when(cache.io.cpu.redo && arbitration.isValid && input(MEMORY_ENABLE)){ - arbitration.haltItself := True + when(cache.io.cpu.execute.refilling && arbitration.isValid){ + arbitration.haltByOther := True } if(relaxedMemoryTranslationRegister) { @@ -400,7 +400,7 @@ class DBusCachedPlugin(val config : DataCacheConfig, decode.arbitration.haltByOther := True val exceptionService = pipeline.service(classOf[ExceptionService]) when(!stagesFromExecute.map(s => s.arbitration.isValid || exceptionService.isExceptionPending(s)).orR){ - when(!cache.io.cpu.redo) { + when(!cache.io.cpu.execute.refilling) { cache.io.cpu.execute.isValid := True dBusAccess.cmd.ready := !execute.arbitration.isStuck } From 6c8e97f825848ff0a1b3544845710f57199883f2 Mon Sep 17 00:00:00 2001 From: Marcus Comstedt Date: Tue, 20 Oct 2020 18:05:31 +0200 Subject: [PATCH 492/951] Update big endian instruction encoding Between draft-20181101-ebe1ca4 and draft-20190622-6993896 of the RISC-V Instruction Set Manual, the wording was changed from requiring "natural endianness" of instruction parcels to require them to be little endian. Update the big endian instruction pipe to reflect the newer requirement. --- src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala index 22c3606e..195b7d1a 100644 --- a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala @@ -373,10 +373,9 @@ class IBusSimplePlugin( resetVector : BigInt, fetchRsp.rsp := rspBuffer.output.payload fetchRsp.rsp.error.clearWhen(!rspBuffer.output.valid) //Avoid interference with instruction injection from the debug plugin if(bigEndian){ - // inst(15 downto 0) should contain lower addressed parcel, - // and inst(31 downto 16) the higher addressed parcel + // instructions are stored in little endian byteorder fetchRsp.rsp.inst.allowOverride - fetchRsp.rsp.inst := rspBuffer.output.payload.inst.rotateLeft(16) + fetchRsp.rsp.inst := EndiannessSwap(rspBuffer.output.payload.inst) } val join = Stream(FetchRsp()) From fe342c347c6e22891b939bfd48085ef8a877e17e Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 23 Oct 2020 11:06:24 +0200 Subject: [PATCH 493/951] CfuBusParameter has now a few default values --- src/main/scala/vexriscv/plugin/CfuPlugin.scala | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/CfuPlugin.scala b/src/main/scala/vexriscv/plugin/CfuPlugin.scala index a805bff0..827aba17 100644 --- a/src/main/scala/vexriscv/plugin/CfuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CfuPlugin.scala @@ -20,11 +20,11 @@ case class CfuPluginParameter( CFU_FLOW_REQ_READY_ALWAYS : Boolean, CFU_FLOW_RESP_READY_ALWAYS : Boolean) -case class CfuBusParameter(CFU_VERSION : Int, - CFU_INTERFACE_ID_W : Int, +case class CfuBusParameter(CFU_VERSION : Int = 0, + CFU_INTERFACE_ID_W : Int = 0, CFU_FUNCTION_ID_W : Int, - CFU_REORDER_ID_W : Int, - CFU_REQ_RESP_ID_W : Int, + CFU_REORDER_ID_W : Int = 0, + CFU_REQ_RESP_ID_W : Int = 0, CFU_INPUTS : Int, CFU_INPUT_DATA_W : Int, CFU_OUTPUTS : Int, From fc2c8a7c371db9ee6556c765ddf634fb31b78455 Mon Sep 17 00:00:00 2001 From: Samuel Lindemer Date: Tue, 20 Oct 2020 11:45:22 +0200 Subject: [PATCH 494/951] Initial commit of PMP plugin --- src/main/scala/vexriscv/demo/GenZephyr.scala | 85 ++++++++ .../scala/vexriscv/plugin/CsrPlugin.scala | 25 +++ .../scala/vexriscv/plugin/PmpPlugin.scala | 182 ++++++++++++++++++ 3 files changed, 292 insertions(+) create mode 100644 src/main/scala/vexriscv/demo/GenZephyr.scala create mode 100644 src/main/scala/vexriscv/plugin/PmpPlugin.scala diff --git a/src/main/scala/vexriscv/demo/GenZephyr.scala b/src/main/scala/vexriscv/demo/GenZephyr.scala new file mode 100644 index 00000000..69302e3a --- /dev/null +++ b/src/main/scala/vexriscv/demo/GenZephyr.scala @@ -0,0 +1,85 @@ +package vexriscv.demo + +import vexriscv.plugin._ +import vexriscv.ip.{DataCacheConfig, InstructionCacheConfig} +import vexriscv.{plugin, VexRiscv, VexRiscvConfig} +import spinal.core._ + +object GenZephyr extends App{ + def cpu() = new VexRiscv( + config = VexRiscvConfig( + plugins = List( + new IBusCachedPlugin( + prediction = STATIC, + config = InstructionCacheConfig( + cacheSize = 4096, + bytePerLine = 32, + wayCount = 1, + addressWidth = 32, + cpuDataWidth = 32, + memDataWidth = 32, + catchIllegalAccess = true, + catchAccessFault = true, + asyncTagMemory = false, + twoCycleRam = true, + twoCycleCache = true + ) + ), + new DBusCachedPlugin( + config = new DataCacheConfig( + cacheSize = 4096, + bytePerLine = 32, + wayCount = 1, + addressWidth = 32, + cpuDataWidth = 32, + memDataWidth = 32, + catchAccessError = true, + catchIllegal = true, + catchUnaligned = true + ) + ), + new PmpPlugin( + regions = 16, + ioRange = _(31 downto 28) === 0xF + ), + new DecoderSimplePlugin( + catchIllegalInstruction = true + ), + new RegFilePlugin( + regFileReadyKind = plugin.SYNC, + zeroBoot = false + ), + new IntAluPlugin, + new SrcPlugin( + separatedAddSub = false, + executeInsertion = true + ), + new FullBarrelShifterPlugin, + new HazardSimplePlugin( + bypassExecute = true, + bypassMemory = true, + bypassWriteBack = true, + bypassWriteBackBuffer = true, + pessimisticUseSrc = false, + pessimisticWriteRegFile = false, + pessimisticAddressMatch = false + ), + new MulDivIterativePlugin( + genMul = true, + genDiv = true, + mulUnrollFactor = 1, + divUnrollFactor = 1 + ), + new CsrPlugin(CsrPluginConfig.zephyr(0x00000020l)), + new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))), + new BranchPlugin( + earlyBranch = false, + catchAddressMisaligned = true + ), + new YamlPlugin("cpu0.yaml") + ) + ) + ) + + SpinalVerilog(cpu()) +} diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 668f1b7e..224ee093 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -264,6 +264,31 @@ object CsrPluginConfig{ uinstretAccess = CsrAccess.NONE ) + def zephyr(mtvecInit : BigInt) = CsrPluginConfig( + catchIllegalAccess = true, + mvendorid = 1, + marchid = 2, + mimpid = 3, + mhartid = 0, + misaExtensionsInit = 0, + misaAccess = CsrAccess.NONE, + mtvecAccess = CsrAccess.READ_WRITE, + mtvecInit = mtvecInit, + mepcAccess = CsrAccess.READ_WRITE, + mscratchGen = true, + mcauseAccess = CsrAccess.READ_ONLY, + mbadaddrAccess = CsrAccess.READ_ONLY, + mcycleAccess = CsrAccess.NONE, + minstretAccess = CsrAccess.NONE, + ucycleAccess = CsrAccess.NONE, + uinstretAccess = CsrAccess.NONE, + wfiGenAsWait = true, + ecallGen = true, + userGen = true, + medelegAccess = CsrAccess.READ_WRITE, + midelegAccess = CsrAccess.READ_WRITE + ) + } case class CsrWrite(that : Data, bitOffset : Int) case class CsrRead(that : Data , bitOffset : Int) diff --git a/src/main/scala/vexriscv/plugin/PmpPlugin.scala b/src/main/scala/vexriscv/plugin/PmpPlugin.scala new file mode 100644 index 00000000..839cb8b0 --- /dev/null +++ b/src/main/scala/vexriscv/plugin/PmpPlugin.scala @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2020 Samuel Lindemer + * + * SPDX-License-Identifier: MIT + */ + +package vexriscv.plugin + +import vexriscv.{VexRiscv, _} +import spinal.core._ +import spinal.lib._ +import scala.collection.mutable.ArrayBuffer + +/* Each 32-bit pmpcfg# register contains four 8-bit configuration sections. + * These section numbers contain flags which apply to region defined by the + * corresponding pmpaddr# register. + * + * 3 2 1 + * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | pmp3cfg | pmp2cfg | pmp1cfg | pmp0cfg | pmpcfg0 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | pmp7cfg | pmp6cfg | pmp5cfg | pmp4cfg | pmpcfg2 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * 7 6 5 4 3 2 1 0 + * +-------+-------+-------+-------+-------+-------+-------+-------+ + * | L | 0 | A | X | W | R | pmp#cfg + * +-------+-------+-------+-------+-------+-------+-------+-------+ + * + * L: locks configuration until system reset (including M-mode) + * 0: hardwired to zero + * A: 0 = OFF (null region / disabled) + * 1 = TOR (top of range) + * 2 = NA4 (naturally aligned four-byte region) + * 3 = NAPOT (naturally aligned power-of-two region, > 7 bytes) + * X: execute + * W: write + * R: read + * + * TOR: Each 32-bit pmpaddr# register defines the upper bound of the pmp region + * right-shifted by two bits. The lower bound of the region is the previous + * pmpaddr# register. In the case of pmpaddr0, the lower bound is address 0x0. + * + * 3 2 1 + * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | address[33:2] | pmpaddr# + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * NAPOT: Each 32-bit pmpaddr# register defines the regionStart address and the size + * of the pmp region. The number of concurrent 1s begging at the LSB indicates + * the size of the region as a power of two (e.g. 0x...0 = 8-byte, 0x...1 = + * 16-byte, 0x...11 = 32-byte, etc.). + * + * 3 2 1 + * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | address[33:2] |0|1|1|1|1| pmpaddr# + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * NA4: This is essentially an edge case of NAPOT where the entire pmpaddr# + * register defines a 4-byte wide region. + */ + +case class PmpRegister() extends Bundle { + + // CSR segments + val x, w, r = Reg(Bool) + val l = Reg(Bool) init(False) + val a = Reg(UInt(2 bits)) init(0) + val address = Reg(UInt(32 bits)) + + // Computed region bounds + val regionStart = UInt(32 bits) + val regionEnd = UInt(32 bits) + val valid = Bool + + // Addressing options + def NA4 = 2 + def NAPOT = 3 + + switch(a) { + is(NA4) { + regionStart := address |<< 2 + regionEnd := regionStart + 4 + valid := True + } + is(NAPOT) { + val mask = address & ~(address + 1) + regionStart := (address & ~mask) |<< 2 + regionEnd := regionStart + ((mask + 1) |<< 3) + valid := True + } + default { + regionStart := 0 + regionEnd := 0 + valid := False + } + } + +} + +case class ProtectedMemoryTranslatorPort(bus : MemoryTranslatorBus) + +class PmpPlugin(regions : Int, ioRange : UInt => Bool) extends Plugin[VexRiscv] with MemoryTranslator { + + // Each pmpcfg# CSR configures four regions. + assert((regions % 4) == 0) + + val pmps = ArrayBuffer[PmpRegister]() + val portsInfo = ArrayBuffer[ProtectedMemoryTranslatorPort]() + + override def newTranslationPort(priority : Int, args : Any): MemoryTranslatorBus = { + val port = ProtectedMemoryTranslatorPort(MemoryTranslatorBus()) + portsInfo += port + port.bus + } + + override def build(pipeline: VexRiscv): Unit = { + import pipeline._ + import pipeline.config._ + import Riscv._ + + val csrService = pipeline.service(classOf[CsrInterface]) + val privilegeService = pipeline.service(classOf[PrivilegeService]) + + val core = pipeline plug new Area { + + // Instantiate pmpaddr0 ... pmpaddr# CSRs. + for (n <- 0 until regions) { + pmps += PmpRegister() + csrService.rw(0x3B0 + n, pmps(n).address) + } + + // Instantiate pmpcfg0 ... pmpcfg# CSRs. + for (n <- 0 until (regions / 4)) { + csrService.rw(0x3A0 + n, + 31 -> pmps((n * 4) + 3).l, 27 -> pmps((n * 4) + 3).a, + 26 -> pmps((n * 4) + 3).x, 25 -> pmps((n * 4) + 3).w, 24 -> pmps((n * 4) + 3).r, + 23 -> pmps((n * 4) + 2).l, 19 -> pmps((n * 4) + 2).a, + 18 -> pmps((n * 4) + 2).x, 17 -> pmps((n * 4) + 2).w, 16 -> pmps((n * 4) + 2).r, + 15 -> pmps((n * 4) + 1).l, 11 -> pmps((n * 4) + 1).a, + 10 -> pmps((n * 4) + 1).x, 9 -> pmps((n * 4) + 1).w, 8 -> pmps((n * 4) + 1).r, + 7 -> pmps((n * 4) ).l, 3 -> pmps((n * 4) ).a, + 2 -> pmps((n * 4) ).x, 1 -> pmps((n * 4) ).w, 0 -> pmps((n * 4) ).r + ) + } + + // Connect memory ports to PMP logic. + val ports = for ((port, portId) <- portsInfo.zipWithIndex) yield new Area { + + val address = port.bus.cmd.virtualAddress + port.bus.rsp.physicalAddress := address + + // Only the first matching PMP region is applied. + val hits = pmps.map(pmp => pmp.valid && + pmp.regionStart <= address && + pmp.regionEnd > address && + (pmp.l || ~privilegeService.isMachine())) + + // M-mode has full access by default. All others have none by default. + when(CountOne(hits) === 0) { + port.bus.rsp.allowRead := privilegeService.isMachine() + port.bus.rsp.allowWrite := privilegeService.isMachine() + port.bus.rsp.allowExecute := privilegeService.isMachine() + } otherwise { + port.bus.rsp.allowRead := MuxOH(OHMasking.first(hits), pmps).r + port.bus.rsp.allowWrite := MuxOH(OHMasking.first(hits), pmps).w + port.bus.rsp.allowExecute := MuxOH(OHMasking.first(hits), pmps).x + } + + port.bus.rsp.isIoAccess := ioRange(port.bus.rsp.physicalAddress) + port.bus.rsp.exception := False + port.bus.rsp.refilling := False + port.bus.busy := False + + } + } + } +} + From abebeaea1f467d5b4acec0442362ea1e802cbb22 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 28 Oct 2020 12:57:20 +0100 Subject: [PATCH 495/951] Fix CsrPlugin privilege crossing --- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 897a2063..3c480333 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -1175,7 +1175,11 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep } } - illegalAccess setWhen(privilege < csrAddress(9 downto 8).asUInt) + when(privilege < csrAddress(9 downto 8).asUInt){ + illegalAccess := True + readInstruction := False + writeInstruction := False + } illegalAccess clearWhen(!arbitration.isValid || !input(IS_CSR)) } } From 576e21d75d59eccc250dec63ef3094d9ee1fd051 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 28 Oct 2020 12:58:24 +0100 Subject: [PATCH 496/951] Do not allow jtag ebreak outside machine mode --- src/main/scala/vexriscv/plugin/DebugPlugin.scala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/plugin/DebugPlugin.scala b/src/main/scala/vexriscv/plugin/DebugPlugin.scala index 78171943..0d987e0c 100644 --- a/src/main/scala/vexriscv/plugin/DebugPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DebugPlugin.scala @@ -262,8 +262,9 @@ class DebugPlugin(var debugClockDomain : ClockDomain, hardwareBreakpointCount : } } + val allowEBreak = if(!pipeline.serviceExist(classOf[PrivilegeService])) True else pipeline.service(classOf[PrivilegeService]).isMachine() - decode.insert(DO_EBREAK) := !haltIt && (decode.input(IS_EBREAK) || hardwareBreakpoints.map(hb => hb.valid && hb.pc === (decode.input(PC) >> 1)).foldLeft(False)(_ || _)) + decode.insert(DO_EBREAK) := !haltIt && (decode.input(IS_EBREAK) || hardwareBreakpoints.map(hb => hb.valid && hb.pc === (decode.input(PC) >> 1)).foldLeft(False)(_ || _)) && allowEBreak when(execute.arbitration.isValid && execute.input(DO_EBREAK)){ execute.arbitration.haltByOther := True busReadDataReg := execute.input(PC).asBits From 4209dc27929da0c55f9e8dcdae2ca27269c0745a Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 28 Oct 2020 12:57:20 +0100 Subject: [PATCH 497/951] Fix CsrPlugin privilege crossing --- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 668f1b7e..0cb6a79f 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -1136,7 +1136,11 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep } } - illegalAccess setWhen(privilege < csrAddress(9 downto 8).asUInt) + when(privilege < csrAddress(9 downto 8).asUInt){ + illegalAccess := True + readInstruction := False + writeInstruction := False + } illegalAccess clearWhen(!arbitration.isValid || !input(IS_CSR)) } } From dc9246715de9ef0618f979f2a9ce15e29677b0fd Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 28 Oct 2020 12:58:24 +0100 Subject: [PATCH 498/951] Do not allow jtag ebreak outside machine mode --- src/main/scala/vexriscv/plugin/DebugPlugin.scala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/plugin/DebugPlugin.scala b/src/main/scala/vexriscv/plugin/DebugPlugin.scala index c04d167b..516571ba 100644 --- a/src/main/scala/vexriscv/plugin/DebugPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DebugPlugin.scala @@ -195,8 +195,9 @@ class DebugPlugin(val debugClockDomain : ClockDomain, hardwareBreakpointCount : } } + val allowEBreak = if(!pipeline.serviceExist(classOf[PrivilegeService])) True else pipeline.service(classOf[PrivilegeService]).isMachine() - decode.insert(DO_EBREAK) := !haltIt && (decode.input(IS_EBREAK) || hardwareBreakpoints.map(hb => hb.valid && hb.pc === (decode.input(PC) >> 1)).foldLeft(False)(_ || _)) + decode.insert(DO_EBREAK) := !haltIt && (decode.input(IS_EBREAK) || hardwareBreakpoints.map(hb => hb.valid && hb.pc === (decode.input(PC) >> 1)).foldLeft(False)(_ || _)) && allowEBreak when(execute.arbitration.isValid && execute.input(DO_EBREAK)){ execute.arbitration.haltByOther := True busReadDataReg := execute.input(PC).asBits From 97fe279f7b0a6f2830fb2b5ff2c87e870216aeff Mon Sep 17 00:00:00 2001 From: Samuel Lindemer Date: Wed, 28 Oct 2020 14:21:47 +0100 Subject: [PATCH 499/951] Enable PMP register lock --- .../scala/vexriscv/plugin/CsrPlugin.scala | 16 +-- .../scala/vexriscv/plugin/PmpPlugin.scala | 107 ++++++++++-------- 2 files changed, 69 insertions(+), 54 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 224ee093..d3c0eb65 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -270,18 +270,18 @@ object CsrPluginConfig{ marchid = 2, mimpid = 3, mhartid = 0, - misaExtensionsInit = 0, - misaAccess = CsrAccess.NONE, + misaExtensionsInit = 0x103124, // RV32CFIMNU + misaAccess = CsrAccess.READ_WRITE, mtvecAccess = CsrAccess.READ_WRITE, mtvecInit = mtvecInit, mepcAccess = CsrAccess.READ_WRITE, mscratchGen = true, - mcauseAccess = CsrAccess.READ_ONLY, - mbadaddrAccess = CsrAccess.READ_ONLY, - mcycleAccess = CsrAccess.NONE, - minstretAccess = CsrAccess.NONE, - ucycleAccess = CsrAccess.NONE, - uinstretAccess = CsrAccess.NONE, + mcauseAccess = CsrAccess.READ_WRITE, + mbadaddrAccess = CsrAccess.READ_WRITE, + mcycleAccess = CsrAccess.READ_WRITE, + minstretAccess = CsrAccess.READ_WRITE, + ucycleAccess = CsrAccess.READ_ONLY, + uinstretAccess = CsrAccess.READ_ONLY, wfiGenAsWait = true, ecallGen = true, userGen = true, diff --git a/src/main/scala/vexriscv/plugin/PmpPlugin.scala b/src/main/scala/vexriscv/plugin/PmpPlugin.scala index 839cb8b0..ceb219bd 100644 --- a/src/main/scala/vexriscv/plugin/PmpPlugin.scala +++ b/src/main/scala/vexriscv/plugin/PmpPlugin.scala @@ -12,7 +12,7 @@ import spinal.lib._ import scala.collection.mutable.ArrayBuffer /* Each 32-bit pmpcfg# register contains four 8-bit configuration sections. - * These section numbers contain flags which apply to region defined by the + * These section numbers contain flags which apply to regions defined by the * corresponding pmpaddr# register. * * 3 2 1 @@ -48,7 +48,7 @@ import scala.collection.mutable.ArrayBuffer * | address[33:2] | pmpaddr# * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * - * NAPOT: Each 32-bit pmpaddr# register defines the regionStart address and the size + * NAPOT: Each 32-bit pmpaddr# register defines the region address and the size * of the pmp region. The number of concurrent 1s begging at the LSB indicates * the size of the region as a power of two (e.g. 0x...0 = 8-byte, 0x...1 = * 16-byte, 0x...11 = 32-byte, etc.). @@ -63,39 +63,52 @@ import scala.collection.mutable.ArrayBuffer * register defines a 4-byte wide region. */ -case class PmpRegister() extends Bundle { - - // CSR segments - val x, w, r = Reg(Bool) - val l = Reg(Bool) init(False) - val a = Reg(UInt(2 bits)) init(0) - val address = Reg(UInt(32 bits)) - - // Computed region bounds - val regionStart = UInt(32 bits) - val regionEnd = UInt(32 bits) - val valid = Bool +case class PmpRegister() extends Area { // Addressing options def NA4 = 2 def NAPOT = 3 - switch(a) { - is(NA4) { - regionStart := address |<< 2 - regionEnd := regionStart + 4 - valid := True - } - is(NAPOT) { - val mask = address & ~(address + 1) - regionStart := (address & ~mask) |<< 2 - regionEnd := regionStart + ((mask + 1) |<< 3) - valid := True - } - default { - regionStart := 0 - regionEnd := 0 - valid := False + val csr = new Area { + val r, w, x, l = RegInit(False) + val a = Reg(UInt(2 bits)) init(0) + val addr = Reg(UInt(32 bits)) + } + + val region = new Area { + val r, w, x = Reg(Bool) + val l = RegInit(False) + val start = Reg(UInt(32 bits)) + val end = Reg(UInt(32 bits)) + val valid = RegInit(False) + } + + // Internal CSR state is locked until reset if L-bit set + when(~region.l) { + region.r := csr.r + region.w := csr.w + region.x := csr.x + region.l := csr.l + + switch(csr.a) { + is(NA4) { + val shifted = csr.addr |<< 2 + region.start := shifted + region.end := shifted + 4 + region.valid := True + } + is(NAPOT) { + val mask = csr.addr & ~(csr.addr + 1) + val shifted = (csr.addr & ~mask) |<< 2 + region.start := shifted + region.end := shifted + ((mask + 1) |<< 3) + region.valid := True + } + default { + region.start := 0 + region.end := 0 + region.valid := False + } } } @@ -130,20 +143,22 @@ class PmpPlugin(regions : Int, ioRange : UInt => Bool) extends Plugin[VexRiscv] // Instantiate pmpaddr0 ... pmpaddr# CSRs. for (n <- 0 until regions) { pmps += PmpRegister() - csrService.rw(0x3B0 + n, pmps(n).address) + csrService.rw(0x3B0 + n, pmps(n).csr.addr) } // Instantiate pmpcfg0 ... pmpcfg# CSRs. for (n <- 0 until (regions / 4)) { csrService.rw(0x3A0 + n, - 31 -> pmps((n * 4) + 3).l, 27 -> pmps((n * 4) + 3).a, - 26 -> pmps((n * 4) + 3).x, 25 -> pmps((n * 4) + 3).w, 24 -> pmps((n * 4) + 3).r, - 23 -> pmps((n * 4) + 2).l, 19 -> pmps((n * 4) + 2).a, - 18 -> pmps((n * 4) + 2).x, 17 -> pmps((n * 4) + 2).w, 16 -> pmps((n * 4) + 2).r, - 15 -> pmps((n * 4) + 1).l, 11 -> pmps((n * 4) + 1).a, - 10 -> pmps((n * 4) + 1).x, 9 -> pmps((n * 4) + 1).w, 8 -> pmps((n * 4) + 1).r, - 7 -> pmps((n * 4) ).l, 3 -> pmps((n * 4) ).a, - 2 -> pmps((n * 4) ).x, 1 -> pmps((n * 4) ).w, 0 -> pmps((n * 4) ).r + 31 -> pmps((n * 4) + 3).csr.l, 23 -> pmps((n * 4) + 2).csr.l, + 15 -> pmps((n * 4) + 1).csr.l, 7 -> pmps((n * 4) ).csr.l, + 27 -> pmps((n * 4) + 3).csr.a, 26 -> pmps((n * 4) + 3).csr.x, + 25 -> pmps((n * 4) + 3).csr.w, 24 -> pmps((n * 4) + 3).csr.r, + 19 -> pmps((n * 4) + 2).csr.a, 18 -> pmps((n * 4) + 2).csr.x, + 17 -> pmps((n * 4) + 2).csr.w, 16 -> pmps((n * 4) + 2).csr.r, + 11 -> pmps((n * 4) + 1).csr.a, 10 -> pmps((n * 4) + 1).csr.x, + 9 -> pmps((n * 4) + 1).csr.w, 8 -> pmps((n * 4) + 1).csr.r, + 3 -> pmps((n * 4) ).csr.a, 2 -> pmps((n * 4) ).csr.x, + 1 -> pmps((n * 4) ).csr.w, 0 -> pmps((n * 4) ).csr.r ) } @@ -154,10 +169,10 @@ class PmpPlugin(regions : Int, ioRange : UInt => Bool) extends Plugin[VexRiscv] port.bus.rsp.physicalAddress := address // Only the first matching PMP region is applied. - val hits = pmps.map(pmp => pmp.valid && - pmp.regionStart <= address && - pmp.regionEnd > address && - (pmp.l || ~privilegeService.isMachine())) + val hits = pmps.map(pmp => pmp.region.valid && + pmp.region.start <= address && + pmp.region.end > address && + (pmp.region.l || ~privilegeService.isMachine())) // M-mode has full access by default. All others have none by default. when(CountOne(hits) === 0) { @@ -165,9 +180,9 @@ class PmpPlugin(regions : Int, ioRange : UInt => Bool) extends Plugin[VexRiscv] port.bus.rsp.allowWrite := privilegeService.isMachine() port.bus.rsp.allowExecute := privilegeService.isMachine() } otherwise { - port.bus.rsp.allowRead := MuxOH(OHMasking.first(hits), pmps).r - port.bus.rsp.allowWrite := MuxOH(OHMasking.first(hits), pmps).w - port.bus.rsp.allowExecute := MuxOH(OHMasking.first(hits), pmps).x + port.bus.rsp.allowRead := MuxOH(OHMasking.first(hits), pmps.map(_.region.r)) + port.bus.rsp.allowWrite := MuxOH(OHMasking.first(hits), pmps.map(_.region.w)) + port.bus.rsp.allowExecute := MuxOH(OHMasking.first(hits), pmps.map(_.region.x)) } port.bus.rsp.isIoAccess := ioRange(port.bus.rsp.physicalAddress) From 9abe19317def428a36ecead853b0a06ff2f5a425 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 2 Nov 2020 17:01:17 +0100 Subject: [PATCH 500/951] RegFilePlugin.x0Init do less assumption on other plugin behaviour --- src/main/scala/vexriscv/plugin/RegFilePlugin.scala | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/RegFilePlugin.scala b/src/main/scala/vexriscv/plugin/RegFilePlugin.scala index a34dc462..0b7bcd2a 100644 --- a/src/main/scala/vexriscv/plugin/RegFilePlugin.scala +++ b/src/main/scala/vexriscv/plugin/RegFilePlugin.scala @@ -105,14 +105,9 @@ class RegFilePlugin(regFileReadyKind : RegFileReadKind, if(x0Init) { val boot = RegNext(False) init (True) regFileWrite.valid setWhen (boot) - if (writeStage != execute) { - inputInit[Bits](REGFILE_WRITE_DATA, 0) - inputInit[Bits](INSTRUCTION, 0) - } else { - when(boot) { - regFileWrite.address := 0 - regFileWrite.data := 0 - } + when(boot) { + regFileWrite.address := 0 + regFileWrite.data := 0 } } } From 05e725174caad24fea6d9c8b93acaaf845ffe060 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 2 Nov 2020 17:14:52 +0100 Subject: [PATCH 501/951] AesPlugin added, work with dropbear encryption, seem ok for decryption (barmetal) --- .../scala/vexriscv/plugin/AesPlugin.scala | 275 ++++++++++++++++++ 1 file changed, 275 insertions(+) create mode 100644 src/main/scala/vexriscv/plugin/AesPlugin.scala diff --git a/src/main/scala/vexriscv/plugin/AesPlugin.scala b/src/main/scala/vexriscv/plugin/AesPlugin.scala new file mode 100644 index 00000000..92617a82 --- /dev/null +++ b/src/main/scala/vexriscv/plugin/AesPlugin.scala @@ -0,0 +1,275 @@ +package vexriscv.plugin + +import spinal.core._ +import spinal.lib._ +import vexriscv.{DecoderService, Stageable, VexRiscv} + + +case class AesPlugin(encoding : MaskedLiteral = M"-----------------000-----0101011") extends Plugin[VexRiscv]{ + + object IS_AES extends Stageable(Bool) + object CALC extends Stageable(Bits(32 bits)) + + val mapping = new { + def DECRYPT = 25 // 0/1 => encrypt/decrypt + def LAST_ROUND = 26 + def ENDIAN = 27 //Not implemented yet + def BYTE_SEL = 28 //Which byte should be used in RS2 + } + + //Callback to setup the plugin and ask for different services + override def setup(pipeline: VexRiscv): Unit = { + import pipeline.config._ + + val decoderService = pipeline.service(classOf[DecoderService]) + + decoderService.addDefault(IS_AES, False) + decoderService.add( + key = encoding, + List( + IS_AES -> True, + REGFILE_WRITE_VALID -> True, + BYPASSABLE_EXECUTE_STAGE -> False, + BYPASSABLE_MEMORY_STAGE -> False, //Late result + RS1_USE -> True, + RS2_USE -> True + ) + ) + } + + override def build(pipeline: VexRiscv): Unit = { + import pipeline._ + import pipeline.config._ + + + + def BANK0 = (TE0, SBOX_INV).zipped.map((te0, inv) => (te0.toLong) | (inv.toLong << 24)) + def BANK1 = TD0 + + + + val onExecute = execute plug new Area{ + import execute._ + val byteSel = input(INSTRUCTION)(mapping.BYTE_SEL, 2 bits).asUInt + val bankSel = input(INSTRUCTION)(mapping.DECRYPT) && !input(INSTRUCTION)(mapping.LAST_ROUND) + val romAddress = U(bankSel ## input(RS2).subdivideIn(8 bits).read(byteSel)) + } + + memory plug new Area{ + import memory._ + + val rom = new Area { + val storage = Mem(Bits(32 bits), 512) initBigInt((BANK0 ++ BANK1).map(BigInt(_))) + + val data = storage.readSync(onExecute.romAddress, !arbitration.isStuck) + val bytes = data.subdivideIn(8 bits) + + def VecUInt(l: Int*) = Vec(l.map(U(_, 2 bits))) + // remap will be used to decode the rom + val remap = Vec( + VecUInt(0, 1, 1, 2), + VecUInt(1, 1, 1, 1), + VecUInt(0, 1, 2, 3), + VecUInt(3, 3, 3, 3) + ) + + val address = U(input(INSTRUCTION)(mapping.DECRYPT) ## input(INSTRUCTION)(mapping.LAST_ROUND)) + val output = remap(address) + } + + val wordDesuffle = new Area{ + val zero = B"0000" + val byteSel = input(INSTRUCTION)(mapping.BYTE_SEL, 2 bits).asUInt + val output = Vec(Bits(8 bits), 4) + + def remap(l : Int*) = Vec(l.map(rom.output(_))) + val sel = byteSel.mux( + 3 -> remap(0, 1, 2, 3), + 2 -> remap(1, 2, 3, 0), + 1 -> remap(2, 3, 0, 1), + 0 -> remap(3, 0, 1, 2) + ) + when(input(INSTRUCTION)(mapping.LAST_ROUND)){ + zero := B"1111" + zero(byteSel) := False + } + + //Finaly, mux the rom data + for(byteId <- 0 to 3){ + output(byteId) := rom.bytes(sel(byteId)) + when(zero(byteId)){ + output(byteId) := 0 + } + } + } + + val xored = wordDesuffle.output.asBits ^ input(RS1) + insert(CALC) := xored + } + + writeBack plug new Area { + import writeBack._ + + when(input(IS_AES)) { + output(REGFILE_WRITE_DATA) := input(CALC) + } + } + } + + // Encryption table which solve a single byte sbox + column mix. Used for all rounds + def TE0 = List( + 0xc663a5, 0xf87c84, 0xee7799, 0xf67b8d, + 0xfff20d, 0xd66bbd, 0xde6fb1, 0x91c554, + 0x603050, 0x020103, 0xce67a9, 0x562b7d, + 0xe7fe19, 0xb5d762, 0x4dabe6, 0xec769a, + 0x8fca45, 0x1f829d, 0x89c940, 0xfa7d87, + 0xeffa15, 0xb259eb, 0x8e47c9, 0xfbf00b, + 0x41adec, 0xb3d467, 0x5fa2fd, 0x45afea, + 0x239cbf, 0x53a4f7, 0xe47296, 0x9bc05b, + 0x75b7c2, 0xe1fd1c, 0x3d93ae, 0x4c266a, + 0x6c365a, 0x7e3f41, 0xf5f702, 0x83cc4f, + 0x68345c, 0x51a5f4, 0xd1e534, 0xf9f108, + 0xe27193, 0xabd873, 0x623153, 0x2a153f, + 0x08040c, 0x95c752, 0x462365, 0x9dc35e, + 0x301828, 0x3796a1, 0x0a050f, 0x2f9ab5, + 0x0e0709, 0x241236, 0x1b809b, 0xdfe23d, + 0xcdeb26, 0x4e2769, 0x7fb2cd, 0xea759f, + 0x12091b, 0x1d839e, 0x582c74, 0x341a2e, + 0x361b2d, 0xdc6eb2, 0xb45aee, 0x5ba0fb, + 0xa452f6, 0x763b4d, 0xb7d661, 0x7db3ce, + 0x52297b, 0xdde33e, 0x5e2f71, 0x138497, + 0xa653f5, 0xb9d168, 0x000000, 0xc1ed2c, + 0x402060, 0xe3fc1f, 0x79b1c8, 0xb65bed, + 0xd46abe, 0x8dcb46, 0x67bed9, 0x72394b, + 0x944ade, 0x984cd4, 0xb058e8, 0x85cf4a, + 0xbbd06b, 0xc5ef2a, 0x4faae5, 0xedfb16, + 0x8643c5, 0x9a4dd7, 0x663355, 0x118594, + 0x8a45cf, 0xe9f910, 0x040206, 0xfe7f81, + 0xa050f0, 0x783c44, 0x259fba, 0x4ba8e3, + 0xa251f3, 0x5da3fe, 0x8040c0, 0x058f8a, + 0x3f92ad, 0x219dbc, 0x703848, 0xf1f504, + 0x63bcdf, 0x77b6c1, 0xafda75, 0x422163, + 0x201030, 0xe5ff1a, 0xfdf30e, 0xbfd26d, + 0x81cd4c, 0x180c14, 0x261335, 0xc3ec2f, + 0xbe5fe1, 0x3597a2, 0x8844cc, 0x2e1739, + 0x93c457, 0x55a7f2, 0xfc7e82, 0x7a3d47, + 0xc864ac, 0xba5de7, 0x32192b, 0xe67395, + 0xc060a0, 0x198198, 0x9e4fd1, 0xa3dc7f, + 0x442266, 0x542a7e, 0x3b90ab, 0x0b8883, + 0x8c46ca, 0xc7ee29, 0x6bb8d3, 0x28143c, + 0xa7de79, 0xbc5ee2, 0x160b1d, 0xaddb76, + 0xdbe03b, 0x643256, 0x743a4e, 0x140a1e, + 0x9249db, 0x0c060a, 0x48246c, 0xb85ce4, + 0x9fc25d, 0xbdd36e, 0x43acef, 0xc462a6, + 0x3991a8, 0x3195a4, 0xd3e437, 0xf2798b, + 0xd5e732, 0x8bc843, 0x6e3759, 0xda6db7, + 0x018d8c, 0xb1d564, 0x9c4ed2, 0x49a9e0, + 0xd86cb4, 0xac56fa, 0xf3f407, 0xcfea25, + 0xca65af, 0xf47a8e, 0x47aee9, 0x100818, + 0x6fbad5, 0xf07888, 0x4a256f, 0x5c2e72, + 0x381c24, 0x57a6f1, 0x73b4c7, 0x97c651, + 0xcbe823, 0xa1dd7c, 0xe8749c, 0x3e1f21, + 0x964bdd, 0x61bddc, 0x0d8b86, 0x0f8a85, + 0xe07090, 0x7c3e42, 0x71b5c4, 0xcc66aa, + 0x9048d8, 0x060305, 0xf7f601, 0x1c0e12, + 0xc261a3, 0x6a355f, 0xae57f9, 0x69b9d0, + 0x178691, 0x99c158, 0x3a1d27, 0x279eb9, + 0xd9e138, 0xebf813, 0x2b98b3, 0x221133, + 0xd269bb, 0xa9d970, 0x078e89, 0x3394a7, + 0x2d9bb6, 0x3c1e22, 0x158792, 0xc9e920, + 0x87ce49, 0xaa55ff, 0x502878, 0xa5df7a, + 0x038c8f, 0x59a1f8, 0x098980, 0x1a0d17, + 0x65bfda, 0xd7e631, 0x8442c6, 0xd068b8, + 0x8241c3, 0x2999b0, 0x5a2d77, 0x1e0f11, + 0x7bb0cb, 0xa854fc, 0x6dbbd6, 0x2c163a + ) + + + // Decryption table which solve a single byte sbox + column mix. Not used in the last round + def TD0 = List( + 0x51f4a750l, 0x7e416553l, 0x1a17a4c3l, 0x3a275e96l, + 0x3bab6bcbl, 0x1f9d45f1l, 0xacfa58abl, 0x4be30393l, + 0x2030fa55l, 0xad766df6l, 0x88cc7691l, 0xf5024c25l, + 0x4fe5d7fcl, 0xc52acbd7l, 0x26354480l, 0xb562a38fl, + 0xdeb15a49l, 0x25ba1b67l, 0x45ea0e98l, 0x5dfec0e1l, + 0xc32f7502l, 0x814cf012l, 0x8d4697a3l, 0x6bd3f9c6l, + 0x038f5fe7l, 0x15929c95l, 0xbf6d7aebl, 0x955259dal, + 0xd4be832dl, 0x587421d3l, 0x49e06929l, 0x8ec9c844l, + 0x75c2896al, 0xf48e7978l, 0x99583e6bl, 0x27b971ddl, + 0xbee14fb6l, 0xf088ad17l, 0xc920ac66l, 0x7dce3ab4l, + 0x63df4a18l, 0xe51a3182l, 0x97513360l, 0x62537f45l, + 0xb16477e0l, 0xbb6bae84l, 0xfe81a01cl, 0xf9082b94l, + 0x70486858l, 0x8f45fd19l, 0x94de6c87l, 0x527bf8b7l, + 0xab73d323l, 0x724b02e2l, 0xe31f8f57l, 0x6655ab2al, + 0xb2eb2807l, 0x2fb5c203l, 0x86c57b9al, 0xd33708a5l, + 0x302887f2l, 0x23bfa5b2l, 0x02036abal, 0xed16825cl, + 0x8acf1c2bl, 0xa779b492l, 0xf307f2f0l, 0x4e69e2a1l, + 0x65daf4cdl, 0x0605bed5l, 0xd134621fl, 0xc4a6fe8al, + 0x342e539dl, 0xa2f355a0l, 0x058ae132l, 0xa4f6eb75l, + 0x0b83ec39l, 0x4060efaal, 0x5e719f06l, 0xbd6e1051l, + 0x3e218af9l, 0x96dd063dl, 0xdd3e05ael, 0x4de6bd46l, + 0x91548db5l, 0x71c45d05l, 0x0406d46fl, 0x605015ffl, + 0x1998fb24l, 0xd6bde997l, 0x894043ccl, 0x67d99e77l, + 0xb0e842bdl, 0x07898b88l, 0xe7195b38l, 0x79c8eedbl, + 0xa17c0a47l, 0x7c420fe9l, 0xf8841ec9l, 0x00000000l, + 0x09808683l, 0x322bed48l, 0x1e1170acl, 0x6c5a724el, + 0xfd0efffbl, 0x0f853856l, 0x3daed51el, 0x362d3927l, + 0x0a0fd964l, 0x685ca621l, 0x9b5b54d1l, 0x24362e3al, + 0x0c0a67b1l, 0x9357e70fl, 0xb4ee96d2l, 0x1b9b919el, + 0x80c0c54fl, 0x61dc20a2l, 0x5a774b69l, 0x1c121a16l, + 0xe293ba0al, 0xc0a02ae5l, 0x3c22e043l, 0x121b171dl, + 0x0e090d0bl, 0xf28bc7adl, 0x2db6a8b9l, 0x141ea9c8l, + 0x57f11985l, 0xaf75074cl, 0xee99ddbbl, 0xa37f60fdl, + 0xf701269fl, 0x5c72f5bcl, 0x44663bc5l, 0x5bfb7e34l, + 0x8b432976l, 0xcb23c6dcl, 0xb6edfc68l, 0xb8e4f163l, + 0xd731dccal, 0x42638510l, 0x13972240l, 0x84c61120l, + 0x854a247dl, 0xd2bb3df8l, 0xaef93211l, 0xc729a16dl, + 0x1d9e2f4bl, 0xdcb230f3l, 0x0d8652ecl, 0x77c1e3d0l, + 0x2bb3166cl, 0xa970b999l, 0x119448fal, 0x47e96422l, + 0xa8fc8cc4l, 0xa0f03f1al, 0x567d2cd8l, 0x223390efl, + 0x87494ec7l, 0xd938d1c1l, 0x8ccaa2fel, 0x98d40b36l, + 0xa6f581cfl, 0xa57ade28l, 0xdab78e26l, 0x3fadbfa4l, + 0x2c3a9de4l, 0x5078920dl, 0x6a5fcc9bl, 0x547e4662l, + 0xf68d13c2l, 0x90d8b8e8l, 0x2e39f75el, 0x82c3aff5l, + 0x9f5d80bel, 0x69d0937cl, 0x6fd52da9l, 0xcf2512b3l, + 0xc8ac993bl, 0x10187da7l, 0xe89c636el, 0xdb3bbb7bl, + 0xcd267809l, 0x6e5918f4l, 0xec9ab701l, 0x834f9aa8l, + 0xe6956e65l, 0xaaffe67el, 0x21bccf08l, 0xef15e8e6l, + 0xbae79bd9l, 0x4a6f36cel, 0xea9f09d4l, 0x29b07cd6l, + 0x31a4b2afl, 0x2a3f2331l, 0xc6a59430l, 0x35a266c0l, + 0x744ebc37l, 0xfc82caa6l, 0xe090d0b0l, 0x33a7d815l, + 0xf104984al, 0x41ecdaf7l, 0x7fcd500el, 0x1791f62fl, + 0x764dd68dl, 0x43efb04dl, 0xccaa4d54l, 0xe49604dfl, + 0x9ed1b5e3l, 0x4c6a881bl, 0xc12c1fb8l, 0x4665517fl, + 0x9d5eea04l, 0x018c355dl, 0xfa877473l, 0xfb0b412el, + 0xb3671d5al, 0x92dbd252l, 0xe9105633l, 0x6dd64713l, + 0x9ad7618cl, 0x37a10c7al, 0x59f8148el, 0xeb133c89l, + 0xcea927eel, 0xb761c935l, 0xe11ce5edl, 0x7a47b13cl, + 0x9cd2df59l, 0x55f2733fl, 0x1814ce79l, 0x73c737bfl, + 0x53f7cdeal, 0x5ffdaa5bl, 0xdf3d6f14l, 0x7844db86l, + 0xcaaff381l, 0xb968c43el, 0x3824342cl, 0xc2a3405fl, + 0x161dc372l, 0xbce2250cl, 0x283c498bl, 0xff0d9541l, + 0x39a80171l, 0x080cb3del, 0xd8b4e49cl, 0x6456c190l, + 0x7bcb8461l, 0xd532b670l, 0x486c5c74l, 0xd0b85742l + ) + + // Last round decryption sbox + def SBOX_INV = List( + 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, + 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, + 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, + 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, + 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, + 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, + 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, + 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, + 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, + 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, + 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, + 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, + 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, + 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, + 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, + 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d + ) +} From 1b2a2ebaca8b594d4fca696e09a02d164d6a9cee Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 12 Nov 2020 15:07:07 +0100 Subject: [PATCH 502/951] DBusCachedPlugin miss decoded aquire fix --- src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index 20c193f0..2d66a582 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -313,10 +313,10 @@ class DBusCachedPlugin(val config : DataCacheConfig, cache.io.cpu.writeBack.isUser := (if(privilegeService != null) privilegeService.isUser() else False) cache.io.cpu.writeBack.address := U(input(REGFILE_WRITE_DATA)) - val fence = if(withInvalidate) { + val fence = if(withInvalidate) new Area { cache.io.cpu.writeBack.fence := input(INSTRUCTION)(31 downto 20).as(FenceFlags()) val aquire = False - if(withWriteResponse) when(input(INSTRUCTION)(26)) { //AQ + if(withWriteResponse) when(input(MEMORY_ENABLE) && input(INSTRUCTION)(26)) { //AQ if(withLrSc) when(input(MEMORY_LRSC)){ aquire := True } From c1b0869c211a2ed20807f663c0cc123b67ad246f Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 12 Nov 2020 15:07:27 +0100 Subject: [PATCH 503/951] AesPlugin is now little endian --- .../scala/vexriscv/plugin/AesPlugin.scala | 272 +++++++++--------- 1 file changed, 136 insertions(+), 136 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/AesPlugin.scala b/src/main/scala/vexriscv/plugin/AesPlugin.scala index 92617a82..c36eaef0 100644 --- a/src/main/scala/vexriscv/plugin/AesPlugin.scala +++ b/src/main/scala/vexriscv/plugin/AesPlugin.scala @@ -5,7 +5,7 @@ import spinal.lib._ import vexriscv.{DecoderService, Stageable, VexRiscv} -case class AesPlugin(encoding : MaskedLiteral = M"-----------------000-----0101011") extends Plugin[VexRiscv]{ +case class AesPlugin(encoding : MaskedLiteral = M"-----------------000-----0001011") extends Plugin[VexRiscv]{ object IS_AES extends Stageable(Bool) object CALC extends Stageable(Bits(32 bits)) @@ -67,9 +67,9 @@ case class AesPlugin(encoding : MaskedLiteral = M"-----------------000-----01010 def VecUInt(l: Int*) = Vec(l.map(U(_, 2 bits))) // remap will be used to decode the rom val remap = Vec( - VecUInt(0, 1, 1, 2), - VecUInt(1, 1, 1, 1), - VecUInt(0, 1, 2, 3), + VecUInt(2, 0, 0, 1), + VecUInt(0, 0, 0, 0), + VecUInt(3, 2, 1, 0), VecUInt(3, 3, 3, 3) ) @@ -84,10 +84,10 @@ case class AesPlugin(encoding : MaskedLiteral = M"-----------------000-----01010 def remap(l : Int*) = Vec(l.map(rom.output(_))) val sel = byteSel.mux( - 3 -> remap(0, 1, 2, 3), - 2 -> remap(1, 2, 3, 0), - 1 -> remap(2, 3, 0, 1), - 0 -> remap(3, 0, 1, 2) + 0 -> remap(3, 2, 1, 0), + 1 -> remap(0, 3, 2, 1), + 2 -> remap(1, 0, 3, 2), + 3 -> remap(2, 1, 0, 3) ) when(input(INSTRUCTION)(mapping.LAST_ROUND)){ zero := B"1111" @@ -118,139 +118,139 @@ case class AesPlugin(encoding : MaskedLiteral = M"-----------------000-----01010 // Encryption table which solve a single byte sbox + column mix. Used for all rounds def TE0 = List( - 0xc663a5, 0xf87c84, 0xee7799, 0xf67b8d, - 0xfff20d, 0xd66bbd, 0xde6fb1, 0x91c554, - 0x603050, 0x020103, 0xce67a9, 0x562b7d, - 0xe7fe19, 0xb5d762, 0x4dabe6, 0xec769a, - 0x8fca45, 0x1f829d, 0x89c940, 0xfa7d87, - 0xeffa15, 0xb259eb, 0x8e47c9, 0xfbf00b, - 0x41adec, 0xb3d467, 0x5fa2fd, 0x45afea, - 0x239cbf, 0x53a4f7, 0xe47296, 0x9bc05b, - 0x75b7c2, 0xe1fd1c, 0x3d93ae, 0x4c266a, - 0x6c365a, 0x7e3f41, 0xf5f702, 0x83cc4f, - 0x68345c, 0x51a5f4, 0xd1e534, 0xf9f108, - 0xe27193, 0xabd873, 0x623153, 0x2a153f, - 0x08040c, 0x95c752, 0x462365, 0x9dc35e, - 0x301828, 0x3796a1, 0x0a050f, 0x2f9ab5, - 0x0e0709, 0x241236, 0x1b809b, 0xdfe23d, - 0xcdeb26, 0x4e2769, 0x7fb2cd, 0xea759f, - 0x12091b, 0x1d839e, 0x582c74, 0x341a2e, - 0x361b2d, 0xdc6eb2, 0xb45aee, 0x5ba0fb, - 0xa452f6, 0x763b4d, 0xb7d661, 0x7db3ce, - 0x52297b, 0xdde33e, 0x5e2f71, 0x138497, - 0xa653f5, 0xb9d168, 0x000000, 0xc1ed2c, - 0x402060, 0xe3fc1f, 0x79b1c8, 0xb65bed, - 0xd46abe, 0x8dcb46, 0x67bed9, 0x72394b, - 0x944ade, 0x984cd4, 0xb058e8, 0x85cf4a, - 0xbbd06b, 0xc5ef2a, 0x4faae5, 0xedfb16, - 0x8643c5, 0x9a4dd7, 0x663355, 0x118594, - 0x8a45cf, 0xe9f910, 0x040206, 0xfe7f81, - 0xa050f0, 0x783c44, 0x259fba, 0x4ba8e3, - 0xa251f3, 0x5da3fe, 0x8040c0, 0x058f8a, - 0x3f92ad, 0x219dbc, 0x703848, 0xf1f504, - 0x63bcdf, 0x77b6c1, 0xafda75, 0x422163, - 0x201030, 0xe5ff1a, 0xfdf30e, 0xbfd26d, - 0x81cd4c, 0x180c14, 0x261335, 0xc3ec2f, - 0xbe5fe1, 0x3597a2, 0x8844cc, 0x2e1739, - 0x93c457, 0x55a7f2, 0xfc7e82, 0x7a3d47, - 0xc864ac, 0xba5de7, 0x32192b, 0xe67395, - 0xc060a0, 0x198198, 0x9e4fd1, 0xa3dc7f, - 0x442266, 0x542a7e, 0x3b90ab, 0x0b8883, - 0x8c46ca, 0xc7ee29, 0x6bb8d3, 0x28143c, - 0xa7de79, 0xbc5ee2, 0x160b1d, 0xaddb76, - 0xdbe03b, 0x643256, 0x743a4e, 0x140a1e, - 0x9249db, 0x0c060a, 0x48246c, 0xb85ce4, - 0x9fc25d, 0xbdd36e, 0x43acef, 0xc462a6, - 0x3991a8, 0x3195a4, 0xd3e437, 0xf2798b, - 0xd5e732, 0x8bc843, 0x6e3759, 0xda6db7, - 0x018d8c, 0xb1d564, 0x9c4ed2, 0x49a9e0, - 0xd86cb4, 0xac56fa, 0xf3f407, 0xcfea25, - 0xca65af, 0xf47a8e, 0x47aee9, 0x100818, - 0x6fbad5, 0xf07888, 0x4a256f, 0x5c2e72, - 0x381c24, 0x57a6f1, 0x73b4c7, 0x97c651, - 0xcbe823, 0xa1dd7c, 0xe8749c, 0x3e1f21, - 0x964bdd, 0x61bddc, 0x0d8b86, 0x0f8a85, - 0xe07090, 0x7c3e42, 0x71b5c4, 0xcc66aa, - 0x9048d8, 0x060305, 0xf7f601, 0x1c0e12, - 0xc261a3, 0x6a355f, 0xae57f9, 0x69b9d0, - 0x178691, 0x99c158, 0x3a1d27, 0x279eb9, - 0xd9e138, 0xebf813, 0x2b98b3, 0x221133, - 0xd269bb, 0xa9d970, 0x078e89, 0x3394a7, - 0x2d9bb6, 0x3c1e22, 0x158792, 0xc9e920, - 0x87ce49, 0xaa55ff, 0x502878, 0xa5df7a, - 0x038c8f, 0x59a1f8, 0x098980, 0x1a0d17, - 0x65bfda, 0xd7e631, 0x8442c6, 0xd068b8, - 0x8241c3, 0x2999b0, 0x5a2d77, 0x1e0f11, - 0x7bb0cb, 0xa854fc, 0x6dbbd6, 0x2c163a + 0xa5c663, 0x84f87c, 0x99ee77, 0x8df67b, + 0x0dfff2, 0xbdd66b, 0xb1de6f, 0x5491c5, + 0x506030, 0x030201, 0xa9ce67, 0x7d562b, + 0x19e7fe, 0x62b5d7, 0xe64dab, 0x9aec76, + 0x458fca, 0x9d1f82, 0x4089c9, 0x87fa7d, + 0x15effa, 0xebb259, 0xc98e47, 0x0bfbf0, + 0xec41ad, 0x67b3d4, 0xfd5fa2, 0xea45af, + 0xbf239c, 0xf753a4, 0x96e472, 0x5b9bc0, + 0xc275b7, 0x1ce1fd, 0xae3d93, 0x6a4c26, + 0x5a6c36, 0x417e3f, 0x02f5f7, 0x4f83cc, + 0x5c6834, 0xf451a5, 0x34d1e5, 0x08f9f1, + 0x93e271, 0x73abd8, 0x536231, 0x3f2a15, + 0x0c0804, 0x5295c7, 0x654623, 0x5e9dc3, + 0x283018, 0xa13796, 0x0f0a05, 0xb52f9a, + 0x090e07, 0x362412, 0x9b1b80, 0x3ddfe2, + 0x26cdeb, 0x694e27, 0xcd7fb2, 0x9fea75, + 0x1b1209, 0x9e1d83, 0x74582c, 0x2e341a, + 0x2d361b, 0xb2dc6e, 0xeeb45a, 0xfb5ba0, + 0xf6a452, 0x4d763b, 0x61b7d6, 0xce7db3, + 0x7b5229, 0x3edde3, 0x715e2f, 0x971384, + 0xf5a653, 0x68b9d1, 0x000000, 0x2cc1ed, + 0x604020, 0x1fe3fc, 0xc879b1, 0xedb65b, + 0xbed46a, 0x468dcb, 0xd967be, 0x4b7239, + 0xde944a, 0xd4984c, 0xe8b058, 0x4a85cf, + 0x6bbbd0, 0x2ac5ef, 0xe54faa, 0x16edfb, + 0xc58643, 0xd79a4d, 0x556633, 0x941185, + 0xcf8a45, 0x10e9f9, 0x060402, 0x81fe7f, + 0xf0a050, 0x44783c, 0xba259f, 0xe34ba8, + 0xf3a251, 0xfe5da3, 0xc08040, 0x8a058f, + 0xad3f92, 0xbc219d, 0x487038, 0x04f1f5, + 0xdf63bc, 0xc177b6, 0x75afda, 0x634221, + 0x302010, 0x1ae5ff, 0x0efdf3, 0x6dbfd2, + 0x4c81cd, 0x14180c, 0x352613, 0x2fc3ec, + 0xe1be5f, 0xa23597, 0xcc8844, 0x392e17, + 0x5793c4, 0xf255a7, 0x82fc7e, 0x477a3d, + 0xacc864, 0xe7ba5d, 0x2b3219, 0x95e673, + 0xa0c060, 0x981981, 0xd19e4f, 0x7fa3dc, + 0x664422, 0x7e542a, 0xab3b90, 0x830b88, + 0xca8c46, 0x29c7ee, 0xd36bb8, 0x3c2814, + 0x79a7de, 0xe2bc5e, 0x1d160b, 0x76addb, + 0x3bdbe0, 0x566432, 0x4e743a, 0x1e140a, + 0xdb9249, 0x0a0c06, 0x6c4824, 0xe4b85c, + 0x5d9fc2, 0x6ebdd3, 0xef43ac, 0xa6c462, + 0xa83991, 0xa43195, 0x37d3e4, 0x8bf279, + 0x32d5e7, 0x438bc8, 0x596e37, 0xb7da6d, + 0x8c018d, 0x64b1d5, 0xd29c4e, 0xe049a9, + 0xb4d86c, 0xfaac56, 0x07f3f4, 0x25cfea, + 0xafca65, 0x8ef47a, 0xe947ae, 0x181008, + 0xd56fba, 0x88f078, 0x6f4a25, 0x725c2e, + 0x24381c, 0xf157a6, 0xc773b4, 0x5197c6, + 0x23cbe8, 0x7ca1dd, 0x9ce874, 0x213e1f, + 0xdd964b, 0xdc61bd, 0x860d8b, 0x850f8a, + 0x90e070, 0x427c3e, 0xc471b5, 0xaacc66, + 0xd89048, 0x050603, 0x01f7f6, 0x121c0e, + 0xa3c261, 0x5f6a35, 0xf9ae57, 0xd069b9, + 0x911786, 0x5899c1, 0x273a1d, 0xb9279e, + 0x38d9e1, 0x13ebf8, 0xb32b98, 0x332211, + 0xbbd269, 0x70a9d9, 0x89078e, 0xa73394, + 0xb62d9b, 0x223c1e, 0x921587, 0x20c9e9, + 0x4987ce, 0xffaa55, 0x785028, 0x7aa5df, + 0x8f038c, 0xf859a1, 0x800989, 0x171a0d, + 0xda65bf, 0x31d7e6, 0xc68442, 0xb8d068, + 0xc38241, 0xb02999, 0x775a2d, 0x111e0f, + 0xcb7bb0, 0xfca854, 0xd66dbb, 0x3a2c16 ) // Decryption table which solve a single byte sbox + column mix. Not used in the last round def TD0 = List( - 0x51f4a750l, 0x7e416553l, 0x1a17a4c3l, 0x3a275e96l, - 0x3bab6bcbl, 0x1f9d45f1l, 0xacfa58abl, 0x4be30393l, - 0x2030fa55l, 0xad766df6l, 0x88cc7691l, 0xf5024c25l, - 0x4fe5d7fcl, 0xc52acbd7l, 0x26354480l, 0xb562a38fl, - 0xdeb15a49l, 0x25ba1b67l, 0x45ea0e98l, 0x5dfec0e1l, - 0xc32f7502l, 0x814cf012l, 0x8d4697a3l, 0x6bd3f9c6l, - 0x038f5fe7l, 0x15929c95l, 0xbf6d7aebl, 0x955259dal, - 0xd4be832dl, 0x587421d3l, 0x49e06929l, 0x8ec9c844l, - 0x75c2896al, 0xf48e7978l, 0x99583e6bl, 0x27b971ddl, - 0xbee14fb6l, 0xf088ad17l, 0xc920ac66l, 0x7dce3ab4l, - 0x63df4a18l, 0xe51a3182l, 0x97513360l, 0x62537f45l, - 0xb16477e0l, 0xbb6bae84l, 0xfe81a01cl, 0xf9082b94l, - 0x70486858l, 0x8f45fd19l, 0x94de6c87l, 0x527bf8b7l, - 0xab73d323l, 0x724b02e2l, 0xe31f8f57l, 0x6655ab2al, - 0xb2eb2807l, 0x2fb5c203l, 0x86c57b9al, 0xd33708a5l, - 0x302887f2l, 0x23bfa5b2l, 0x02036abal, 0xed16825cl, - 0x8acf1c2bl, 0xa779b492l, 0xf307f2f0l, 0x4e69e2a1l, - 0x65daf4cdl, 0x0605bed5l, 0xd134621fl, 0xc4a6fe8al, - 0x342e539dl, 0xa2f355a0l, 0x058ae132l, 0xa4f6eb75l, - 0x0b83ec39l, 0x4060efaal, 0x5e719f06l, 0xbd6e1051l, - 0x3e218af9l, 0x96dd063dl, 0xdd3e05ael, 0x4de6bd46l, - 0x91548db5l, 0x71c45d05l, 0x0406d46fl, 0x605015ffl, - 0x1998fb24l, 0xd6bde997l, 0x894043ccl, 0x67d99e77l, - 0xb0e842bdl, 0x07898b88l, 0xe7195b38l, 0x79c8eedbl, - 0xa17c0a47l, 0x7c420fe9l, 0xf8841ec9l, 0x00000000l, - 0x09808683l, 0x322bed48l, 0x1e1170acl, 0x6c5a724el, - 0xfd0efffbl, 0x0f853856l, 0x3daed51el, 0x362d3927l, - 0x0a0fd964l, 0x685ca621l, 0x9b5b54d1l, 0x24362e3al, - 0x0c0a67b1l, 0x9357e70fl, 0xb4ee96d2l, 0x1b9b919el, - 0x80c0c54fl, 0x61dc20a2l, 0x5a774b69l, 0x1c121a16l, - 0xe293ba0al, 0xc0a02ae5l, 0x3c22e043l, 0x121b171dl, - 0x0e090d0bl, 0xf28bc7adl, 0x2db6a8b9l, 0x141ea9c8l, - 0x57f11985l, 0xaf75074cl, 0xee99ddbbl, 0xa37f60fdl, - 0xf701269fl, 0x5c72f5bcl, 0x44663bc5l, 0x5bfb7e34l, - 0x8b432976l, 0xcb23c6dcl, 0xb6edfc68l, 0xb8e4f163l, - 0xd731dccal, 0x42638510l, 0x13972240l, 0x84c61120l, - 0x854a247dl, 0xd2bb3df8l, 0xaef93211l, 0xc729a16dl, - 0x1d9e2f4bl, 0xdcb230f3l, 0x0d8652ecl, 0x77c1e3d0l, - 0x2bb3166cl, 0xa970b999l, 0x119448fal, 0x47e96422l, - 0xa8fc8cc4l, 0xa0f03f1al, 0x567d2cd8l, 0x223390efl, - 0x87494ec7l, 0xd938d1c1l, 0x8ccaa2fel, 0x98d40b36l, - 0xa6f581cfl, 0xa57ade28l, 0xdab78e26l, 0x3fadbfa4l, - 0x2c3a9de4l, 0x5078920dl, 0x6a5fcc9bl, 0x547e4662l, - 0xf68d13c2l, 0x90d8b8e8l, 0x2e39f75el, 0x82c3aff5l, - 0x9f5d80bel, 0x69d0937cl, 0x6fd52da9l, 0xcf2512b3l, - 0xc8ac993bl, 0x10187da7l, 0xe89c636el, 0xdb3bbb7bl, - 0xcd267809l, 0x6e5918f4l, 0xec9ab701l, 0x834f9aa8l, - 0xe6956e65l, 0xaaffe67el, 0x21bccf08l, 0xef15e8e6l, - 0xbae79bd9l, 0x4a6f36cel, 0xea9f09d4l, 0x29b07cd6l, - 0x31a4b2afl, 0x2a3f2331l, 0xc6a59430l, 0x35a266c0l, - 0x744ebc37l, 0xfc82caa6l, 0xe090d0b0l, 0x33a7d815l, - 0xf104984al, 0x41ecdaf7l, 0x7fcd500el, 0x1791f62fl, - 0x764dd68dl, 0x43efb04dl, 0xccaa4d54l, 0xe49604dfl, - 0x9ed1b5e3l, 0x4c6a881bl, 0xc12c1fb8l, 0x4665517fl, - 0x9d5eea04l, 0x018c355dl, 0xfa877473l, 0xfb0b412el, - 0xb3671d5al, 0x92dbd252l, 0xe9105633l, 0x6dd64713l, - 0x9ad7618cl, 0x37a10c7al, 0x59f8148el, 0xeb133c89l, - 0xcea927eel, 0xb761c935l, 0xe11ce5edl, 0x7a47b13cl, - 0x9cd2df59l, 0x55f2733fl, 0x1814ce79l, 0x73c737bfl, - 0x53f7cdeal, 0x5ffdaa5bl, 0xdf3d6f14l, 0x7844db86l, - 0xcaaff381l, 0xb968c43el, 0x3824342cl, 0xc2a3405fl, - 0x161dc372l, 0xbce2250cl, 0x283c498bl, 0xff0d9541l, - 0x39a80171l, 0x080cb3del, 0xd8b4e49cl, 0x6456c190l, - 0x7bcb8461l, 0xd532b670l, 0x486c5c74l, 0xd0b85742l + 0x50a7f451l, 0x5365417el, 0xc3a4171al, 0x965e273al, + 0xcb6bab3bl, 0xf1459d1fl, 0xab58faacl, 0x9303e34bl, + 0x55fa3020l, 0xf66d76adl, 0x9176cc88l, 0x254c02f5l, + 0xfcd7e54fl, 0xd7cb2ac5l, 0x80443526l, 0x8fa362b5l, + 0x495ab1del, 0x671bba25l, 0x980eea45l, 0xe1c0fe5dl, + 0x02752fc3l, 0x12f04c81l, 0xa397468dl, 0xc6f9d36bl, + 0xe75f8f03l, 0x959c9215l, 0xeb7a6dbfl, 0xda595295l, + 0x2d83bed4l, 0xd3217458l, 0x2969e049l, 0x44c8c98el, + 0x6a89c275l, 0x78798ef4l, 0x6b3e5899l, 0xdd71b927l, + 0xb64fe1bel, 0x17ad88f0l, 0x66ac20c9l, 0xb43ace7dl, + 0x184adf63l, 0x82311ae5l, 0x60335197l, 0x457f5362l, + 0xe07764b1l, 0x84ae6bbbl, 0x1ca081fel, 0x942b08f9l, + 0x58684870l, 0x19fd458fl, 0x876cde94l, 0xb7f87b52l, + 0x23d373abl, 0xe2024b72l, 0x578f1fe3l, 0x2aab5566l, + 0x0728ebb2l, 0x03c2b52fl, 0x9a7bc586l, 0xa50837d3l, + 0xf2872830l, 0xb2a5bf23l, 0xba6a0302l, 0x5c8216edl, + 0x2b1ccf8al, 0x92b479a7l, 0xf0f207f3l, 0xa1e2694el, + 0xcdf4da65l, 0xd5be0506l, 0x1f6234d1l, 0x8afea6c4l, + 0x9d532e34l, 0xa055f3a2l, 0x32e18a05l, 0x75ebf6a4l, + 0x39ec830bl, 0xaaef6040l, 0x069f715el, 0x51106ebdl, + 0xf98a213el, 0x3d06dd96l, 0xae053eddl, 0x46bde64dl, + 0xb58d5491l, 0x055dc471l, 0x6fd40604l, 0xff155060l, + 0x24fb9819l, 0x97e9bdd6l, 0xcc434089l, 0x779ed967l, + 0xbd42e8b0l, 0x888b8907l, 0x385b19e7l, 0xdbeec879l, + 0x470a7ca1l, 0xe90f427cl, 0xc91e84f8l, 0x00000000l, + 0x83868009l, 0x48ed2b32l, 0xac70111el, 0x4e725a6cl, + 0xfbff0efdl, 0x5638850fl, 0x1ed5ae3dl, 0x27392d36l, + 0x64d90f0al, 0x21a65c68l, 0xd1545b9bl, 0x3a2e3624l, + 0xb1670a0cl, 0x0fe75793l, 0xd296eeb4l, 0x9e919b1bl, + 0x4fc5c080l, 0xa220dc61l, 0x694b775al, 0x161a121cl, + 0x0aba93e2l, 0xe52aa0c0l, 0x43e0223cl, 0x1d171b12l, + 0x0b0d090el, 0xadc78bf2l, 0xb9a8b62dl, 0xc8a91e14l, + 0x8519f157l, 0x4c0775afl, 0xbbdd99eel, 0xfd607fa3l, + 0x9f2601f7l, 0xbcf5725cl, 0xc53b6644l, 0x347efb5bl, + 0x7629438bl, 0xdcc623cbl, 0x68fcedb6l, 0x63f1e4b8l, + 0xcadc31d7l, 0x10856342l, 0x40229713l, 0x2011c684l, + 0x7d244a85l, 0xf83dbbd2l, 0x1132f9ael, 0x6da129c7l, + 0x4b2f9e1dl, 0xf330b2dcl, 0xec52860dl, 0xd0e3c177l, + 0x6c16b32bl, 0x99b970a9l, 0xfa489411l, 0x2264e947l, + 0xc48cfca8l, 0x1a3ff0a0l, 0xd82c7d56l, 0xef903322l, + 0xc74e4987l, 0xc1d138d9l, 0xfea2ca8cl, 0x360bd498l, + 0xcf81f5a6l, 0x28de7aa5l, 0x268eb7dal, 0xa4bfad3fl, + 0xe49d3a2cl, 0x0d927850l, 0x9bcc5f6al, 0x62467e54l, + 0xc2138df6l, 0xe8b8d890l, 0x5ef7392el, 0xf5afc382l, + 0xbe805d9fl, 0x7c93d069l, 0xa92dd56fl, 0xb31225cfl, + 0x3b99acc8l, 0xa77d1810l, 0x6e639ce8l, 0x7bbb3bdbl, + 0x097826cdl, 0xf418596el, 0x01b79aecl, 0xa89a4f83l, + 0x656e95e6l, 0x7ee6ffaal, 0x08cfbc21l, 0xe6e815efl, + 0xd99be7bal, 0xce366f4al, 0xd4099feal, 0xd67cb029l, + 0xafb2a431l, 0x31233f2al, 0x3094a5c6l, 0xc066a235l, + 0x37bc4e74l, 0xa6ca82fcl, 0xb0d090e0l, 0x15d8a733l, + 0x4a9804f1l, 0xf7daec41l, 0x0e50cd7fl, 0x2ff69117l, + 0x8dd64d76l, 0x4db0ef43l, 0x544daaccl, 0xdf0496e4l, + 0xe3b5d19el, 0x1b886a4cl, 0xb81f2cc1l, 0x7f516546l, + 0x04ea5e9dl, 0x5d358c01l, 0x737487fal, 0x2e410bfbl, + 0x5a1d67b3l, 0x52d2db92l, 0x335610e9l, 0x1347d66dl, + 0x8c61d79al, 0x7a0ca137l, 0x8e14f859l, 0x893c13ebl, + 0xee27a9cel, 0x35c961b7l, 0xede51ce1l, 0x3cb1477al, + 0x59dfd29cl, 0x3f73f255l, 0x79ce1418l, 0xbf37c773l, + 0xeacdf753l, 0x5baafd5fl, 0x146f3ddfl, 0x86db4478l, + 0x81f3afcal, 0x3ec468b9l, 0x2c342438l, 0x5f40a3c2l, + 0x72c31d16l, 0x0c25e2bcl, 0x8b493c28l, 0x41950dffl, + 0x7101a839l, 0xdeb30c08l, 0x9ce4b4d8l, 0x90c15664l, + 0x6184cb7bl, 0x70b632d5l, 0x745c6c48l, 0x4257b8d0l ) // Last round decryption sbox From d1691e94789950d583e2bb75ee7f26da16a128fa Mon Sep 17 00:00:00 2001 From: banahogg Date: Sat, 14 Nov 2020 17:31:50 -0800 Subject: [PATCH 504/951] Update GCC prebuild instructions for sifive.com reorg --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 57372fcb..5d9c15eb 100644 --- a/README.md +++ b/README.md @@ -412,7 +412,7 @@ Note that VexRiscv can run Linux on both cache full and cache less design. A prebuild GCC toolsuite can be found here: -- https://www.sifive.com/products/tools/ => SiFive GNU Embedded Toolchain +- https://www.sifive.com/software/ => Prebuilt RISC‑V GCC Toolchain and Emulator The VexRiscvSocSoftware makefiles are expecting to find this prebuild version in /opt/riscv/__contentOfThisPreBuild__ From ba523c627a19bd54a42602d6d215d834edf3a763 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 16 Nov 2020 12:37:48 +0100 Subject: [PATCH 505/951] Fix Csr ReadWrite interration with DBusCachedPlugin execute halt --- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 3c480333..7eee6536 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -1060,8 +1060,8 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep val readData = Bits(32 bits) val writeInstruction = arbitration.isValid && input(IS_CSR) && input(CSR_WRITE_OPCODE) val readInstruction = arbitration.isValid && input(IS_CSR) && input(CSR_READ_OPCODE) - val writeEnable = writeInstruction && ! blockedBySideEffects && !arbitration.isStuckByOthers - val readEnable = readInstruction && ! blockedBySideEffects && !arbitration.isStuckByOthers + val writeEnable = writeInstruction && !arbitration.isStuck + val readEnable = readInstruction && !arbitration.isStuck val readToWriteData = CombInit(readData) val writeData = if(noCsrAlu) writeSrc else input(INSTRUCTION)(13).mux( From 832218dbece762de7fd2e874c969670a721d91ac Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 16 Nov 2020 12:38:29 +0100 Subject: [PATCH 506/951] DBusCachedPlugin increase pendingMax to 64 to hide memory latency when saving a full context --- src/main/scala/vexriscv/ip/DataCache.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index a5e4d7d4..d0f7abda 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -27,7 +27,7 @@ case class DataCacheConfig(cacheSize : Int, withAmo : Boolean = false, withExclusive : Boolean = false, withInvalidate : Boolean = false, - pendingMax : Int = 32, + pendingMax : Int = 64, directTlbHit : Boolean = false, mergeExecuteMemory : Boolean = false, asyncTagMemory : Boolean = false, From e0ae46e79491383e1c7caa3e438b4b504d229f86 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 16 Nov 2020 12:37:48 +0100 Subject: [PATCH 507/951] Fix Csr ReadWrite interration with DBusCachedPlugin execute halt # Conflicts: # src/main/scala/vexriscv/plugin/CsrPlugin.scala --- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 0cb6a79f..545c5fe3 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -1010,18 +1010,8 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep val readData = Bits(32 bits) val writeInstruction = arbitration.isValid && input(IS_CSR) && input(CSR_WRITE_OPCODE) val readInstruction = arbitration.isValid && input(IS_CSR) && input(CSR_READ_OPCODE) - val writeEnable = writeInstruction && ! blockedBySideEffects && !arbitration.isStuckByOthers// && readDataRegValid - val readEnable = readInstruction && ! blockedBySideEffects && !arbitration.isStuckByOthers// && !readDataRegValid - //arbitration.isStuckByOthers, in case of the hazardPlugin is in the executeStage - - -// def readDataReg = memory.input(REGFILE_WRITE_DATA) //PIPE OPT -// val readDataRegValid = Reg(Bool) setWhen(arbitration.isValid) clearWhen(!arbitration.isStuck) -// val writeDataEnable = input(INSTRUCTION)(13) ? writeSrc | B"xFFFFFFFF" -// val writeData = if(noCsrAlu) writeSrc else input(INSTRUCTION)(13).mux( -// False -> writeSrc, -// True -> Mux(input(INSTRUCTION)(12), ~writeSrc, writeSrc) -// ) + val writeEnable = writeInstruction && !arbitration.isStuck + val readEnable = readInstruction && !arbitration.isStuck val readToWriteData = CombInit(readData) val writeData = if(noCsrAlu) writeSrc else input(INSTRUCTION)(13).mux( From 2d0ebf1ef55d12ce79deb42804d8543734ad2b82 Mon Sep 17 00:00:00 2001 From: Samuel Lindemer Date: Wed, 25 Nov 2020 12:28:16 +0100 Subject: [PATCH 508/951] Flush pipeline after PMP CSR writes --- src/main/scala/vexriscv/demo/GenZephyr.scala | 2 +- .../scala/vexriscv/plugin/PmpPlugin.scala | 81 ++++++++++++------- 2 files changed, 51 insertions(+), 32 deletions(-) diff --git a/src/main/scala/vexriscv/demo/GenZephyr.scala b/src/main/scala/vexriscv/demo/GenZephyr.scala index 69302e3a..b9d0c7a7 100644 --- a/src/main/scala/vexriscv/demo/GenZephyr.scala +++ b/src/main/scala/vexriscv/demo/GenZephyr.scala @@ -40,7 +40,7 @@ object GenZephyr extends App{ ), new PmpPlugin( regions = 16, - ioRange = _(31 downto 28) === 0xF + ioRange = _(31 downto 28) === 0xf ), new DecoderSimplePlugin( catchIllegalInstruction = true diff --git a/src/main/scala/vexriscv/plugin/PmpPlugin.scala b/src/main/scala/vexriscv/plugin/PmpPlugin.scala index ceb219bd..fce48bec 100644 --- a/src/main/scala/vexriscv/plugin/PmpPlugin.scala +++ b/src/main/scala/vexriscv/plugin/PmpPlugin.scala @@ -65,30 +65,32 @@ import scala.collection.mutable.ArrayBuffer case class PmpRegister() extends Area { - // Addressing options + // Addressing options (TOR not supported) + def TOR = 1 def NA4 = 2 def NAPOT = 3 + // Software-accessible CSR interface val csr = new Area { - val r, w, x, l = RegInit(False) + val r, w, x = Reg(Bool) + val l = RegInit(False) val a = Reg(UInt(2 bits)) init(0) val addr = Reg(UInt(32 bits)) } + // Active region bounds and permissions (internal) val region = new Area { val r, w, x = Reg(Bool) - val l = RegInit(False) - val start = Reg(UInt(32 bits)) - val end = Reg(UInt(32 bits)) - val valid = RegInit(False) + val lock, valid = RegInit(False) + val start, end = Reg(UInt(32 bits)) } - - // Internal CSR state is locked until reset if L-bit set - when(~region.l) { - region.r := csr.r - region.w := csr.w - region.x := csr.x - region.l := csr.l + + // Internal PMP state is locked until reset once the L-bit is set. + when(~region.lock) { + region.r := csr.r + region.w := csr.w + region.x := csr.x + region.lock := csr.l switch(csr.a) { is(NA4) { @@ -123,6 +125,7 @@ class PmpPlugin(regions : Int, ioRange : UInt => Bool) extends Plugin[VexRiscv] val pmps = ArrayBuffer[PmpRegister]() val portsInfo = ArrayBuffer[ProtectedMemoryTranslatorPort]() + var redoInterface : Flow[UInt] = null override def newTranslationPort(priority : Int, args : Any): MemoryTranslatorBus = { val port = ProtectedMemoryTranslatorPort(MemoryTranslatorBus()) @@ -131,35 +134,51 @@ class PmpPlugin(regions : Int, ioRange : UInt => Bool) extends Plugin[VexRiscv] } override def build(pipeline: VexRiscv): Unit = { - import pipeline._ import pipeline.config._ + import pipeline._ import Riscv._ val csrService = pipeline.service(classOf[CsrInterface]) val privilegeService = pipeline.service(classOf[PrivilegeService]) + var pcManagerService = pipeline.service(classOf[JumpService]) + + // Flush proceeding instructions and replay them after any CSR write. + redoInterface = pcManagerService.createJumpInterface(pipeline.execute, -1) + redoInterface.valid := False + redoInterface.payload := decode.input(PC) val core = pipeline plug new Area { + redoInterface.valid := False + // Instantiate pmpaddr0 ... pmpaddr# CSRs. - for (n <- 0 until regions) { + for (i <- 0 until regions) { pmps += PmpRegister() - csrService.rw(0x3B0 + n, pmps(n).csr.addr) + csrService.rw(0x3b0 + i, pmps(i).csr.addr) + csrService.onWrite(0x3b0 + i) { + execute.arbitration.flushNext := True + redoInterface.valid := True + } } // Instantiate pmpcfg0 ... pmpcfg# CSRs. - for (n <- 0 until (regions / 4)) { - csrService.rw(0x3A0 + n, - 31 -> pmps((n * 4) + 3).csr.l, 23 -> pmps((n * 4) + 2).csr.l, - 15 -> pmps((n * 4) + 1).csr.l, 7 -> pmps((n * 4) ).csr.l, - 27 -> pmps((n * 4) + 3).csr.a, 26 -> pmps((n * 4) + 3).csr.x, - 25 -> pmps((n * 4) + 3).csr.w, 24 -> pmps((n * 4) + 3).csr.r, - 19 -> pmps((n * 4) + 2).csr.a, 18 -> pmps((n * 4) + 2).csr.x, - 17 -> pmps((n * 4) + 2).csr.w, 16 -> pmps((n * 4) + 2).csr.r, - 11 -> pmps((n * 4) + 1).csr.a, 10 -> pmps((n * 4) + 1).csr.x, - 9 -> pmps((n * 4) + 1).csr.w, 8 -> pmps((n * 4) + 1).csr.r, - 3 -> pmps((n * 4) ).csr.a, 2 -> pmps((n * 4) ).csr.x, - 1 -> pmps((n * 4) ).csr.w, 0 -> pmps((n * 4) ).csr.r + for (i <- 0 until (regions / 4)) { + csrService.rw(0x3a0 + i, + 31 -> pmps((i * 4) + 3).csr.l, 23 -> pmps((i * 4) + 2).csr.l, + 15 -> pmps((i * 4) + 1).csr.l, 7 -> pmps((i * 4) ).csr.l, + 27 -> pmps((i * 4) + 3).csr.a, 26 -> pmps((i * 4) + 3).csr.x, + 25 -> pmps((i * 4) + 3).csr.w, 24 -> pmps((i * 4) + 3).csr.r, + 19 -> pmps((i * 4) + 2).csr.a, 18 -> pmps((i * 4) + 2).csr.x, + 17 -> pmps((i * 4) + 2).csr.w, 16 -> pmps((i * 4) + 2).csr.r, + 11 -> pmps((i * 4) + 1).csr.a, 10 -> pmps((i * 4) + 1).csr.x, + 9 -> pmps((i * 4) + 1).csr.w, 8 -> pmps((i * 4) + 1).csr.r, + 3 -> pmps((i * 4) ).csr.a, 2 -> pmps((i * 4) ).csr.x, + 1 -> pmps((i * 4) ).csr.w, 0 -> pmps((i * 4) ).csr.r ) + csrService.onWrite(0x3a0 + i) { + execute.arbitration.flushNext := True + redoInterface.valid := True + } } // Connect memory ports to PMP logic. @@ -168,13 +187,13 @@ class PmpPlugin(regions : Int, ioRange : UInt => Bool) extends Plugin[VexRiscv] val address = port.bus.cmd.virtualAddress port.bus.rsp.physicalAddress := address - // Only the first matching PMP region is applied. + // Only the first matching PMP region applies. val hits = pmps.map(pmp => pmp.region.valid && pmp.region.start <= address && pmp.region.end > address && - (pmp.region.l || ~privilegeService.isMachine())) + (pmp.region.lock || ~privilegeService.isMachine())) - // M-mode has full access by default. All others have none by default. + // M-mode has full access by default, others have none. when(CountOne(hits) === 0) { port.bus.rsp.allowRead := privilegeService.isMachine() port.bus.rsp.allowWrite := privilegeService.isMachine() From 1b65a9e523341980de46b5b3f92b41bc7b6a1903 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 30 Nov 2020 16:11:00 +0100 Subject: [PATCH 509/951] remove libts-dev from readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5d9c15eb..32b2f8a2 100644 --- a/README.md +++ b/README.md @@ -296,7 +296,7 @@ sbt "runMain vexriscv.demo.Briey" To run the verilator simulation of the Briey SoC, which can then be connected to OpenOCD/GDB, first get these dependencies: ```sh -sudo apt-get install build-essential xorg-dev libudev-dev libts-dev libgl1-mesa-dev libglu1-mesa-dev libasound2-dev libpulse-dev libopenal-dev libogg-dev libvorbis-dev libaudiofile-dev libpng12-dev libfreetype6-dev libusb-dev libdbus-1-dev zlib1g-dev libdirectfb-dev libsdl2-dev +sudo apt-get install build-essential xorg-dev libudev-dev libgl1-mesa-dev libglu1-mesa-dev libasound2-dev libpulse-dev libopenal-dev libogg-dev libvorbis-dev libaudiofile-dev libpng12-dev libfreetype6-dev libusb-dev libdbus-1-dev zlib1g-dev libdirectfb-dev libsdl2-dev ``` Then go in `src/test/cpp/briey` and run the simulation with (UART TX is printed in the terminal, VGA is displayed in a GUI): From c5023ad973f4d5532645473bb9f7484aca20385c Mon Sep 17 00:00:00 2001 From: Samuel Lindemer Date: Thu, 26 Nov 2020 15:08:08 +0100 Subject: [PATCH 510/951] Add PMP regression test --- .../scala/vexriscv/plugin/PmpPlugin.scala | 2 - src/test/cpp/raw/pmp/build/pmp.asm | 172 ++++++++++++++++++ src/test/cpp/raw/pmp/build/pmp.elf | Bin 0 -> 5324 bytes src/test/cpp/raw/pmp/build/pmp.hex | 39 ++++ src/test/cpp/raw/pmp/build/pmp.map | 35 ++++ src/test/cpp/raw/pmp/makefile | 3 + src/test/cpp/raw/pmp/src/crt.S | 172 ++++++++++++++++++ src/test/cpp/raw/pmp/src/ld | 16 ++ src/test/cpp/regression/main.cpp | 4 + 9 files changed, 441 insertions(+), 2 deletions(-) create mode 100644 src/test/cpp/raw/pmp/build/pmp.asm create mode 100755 src/test/cpp/raw/pmp/build/pmp.elf create mode 100644 src/test/cpp/raw/pmp/build/pmp.hex create mode 100644 src/test/cpp/raw/pmp/build/pmp.map create mode 100644 src/test/cpp/raw/pmp/makefile create mode 100644 src/test/cpp/raw/pmp/src/crt.S create mode 100644 src/test/cpp/raw/pmp/src/ld diff --git a/src/main/scala/vexriscv/plugin/PmpPlugin.scala b/src/main/scala/vexriscv/plugin/PmpPlugin.scala index fce48bec..b2757b87 100644 --- a/src/main/scala/vexriscv/plugin/PmpPlugin.scala +++ b/src/main/scala/vexriscv/plugin/PmpPlugin.scala @@ -107,8 +107,6 @@ case class PmpRegister() extends Area { region.valid := True } default { - region.start := 0 - region.end := 0 region.valid := False } } diff --git a/src/test/cpp/raw/pmp/build/pmp.asm b/src/test/cpp/raw/pmp/build/pmp.asm new file mode 100644 index 00000000..86da5ba5 --- /dev/null +++ b/src/test/cpp/raw/pmp/build/pmp.asm @@ -0,0 +1,172 @@ + +build/pmp.elf: file format elf32-littleriscv + + +Disassembly of section .crt_section: + +80000000 : +80000000: 0240006f j 80000024 <_start> + +80000004 : +80000004: 341f1073 csrw mepc,t5 +80000008: 30200073 mret + +8000000c : +8000000c: 00014337 lui t1,0x14 +80000010: 30033073 csrc mstatus,t1 +80000014: 20000313 li t1,512 +80000018: 30032073 csrs mstatus,t1 +8000001c: 34109073 csrw mepc,ra +80000020: 30200073 mret + +80000024 <_start>: +80000024: 00000097 auipc ra,0x0 +80000028: fe008093 addi ra,ra,-32 # 80000004 +8000002c: 30509073 csrw mtvec,ra + +80000030 : +80000030: 00000e93 li t4,0 +80000034: 00000f17 auipc t5,0x0 +80000038: 1f0f0f13 addi t5,t5,496 # 80000224 +8000003c: 800002b7 lui t0,0x80000 +80000040: 80008e37 lui t3,0x80008 +80000044: deadc337 lui t1,0xdeadc +80000048: eef30313 addi t1,t1,-273 # deadbeef +8000004c: 0062a023 sw t1,0(t0) # 80000000 +80000050: 006e2023 sw t1,0(t3) # 80008000 +80000054: 0002a383 lw t2,0(t0) +80000058: 1c731663 bne t1,t2,80000224 +8000005c: 000e2383 lw t2,0(t3) +80000060: 1c731263 bne t1,t2,80000224 +80000064: 071a1f37 lui t5,0x71a1 +80000068: 808f0f13 addi t5,t5,-2040 # 71a0808 +8000006c: 3a0f1073 csrw pmpcfg0,t5 +80000070: 191c0f37 lui t5,0x191c0 +80000074: 504f0f13 addi t5,t5,1284 # 191c0504 +80000078: 3a1f1073 csrw pmpcfg1,t5 +8000007c: 01800f13 li t5,24 +80000080: 3a2f1073 csrw pmpcfg2,t5 +80000084: 0f1e2f37 lui t5,0xf1e2 +80000088: 900f0f13 addi t5,t5,-1792 # f1e1900 +8000008c: 3a3f1073 csrw pmpcfg3,t5 +80000090: 20000f37 lui t5,0x20000 +80000094: 3b0f1073 csrw pmpaddr0,t5 +80000098: fff00f13 li t5,-1 +8000009c: 3b1f1073 csrw pmpaddr1,t5 +800000a0: 20002f37 lui t5,0x20002 +800000a4: 3b2f1073 csrw pmpaddr2,t5 +800000a8: 20004f37 lui t5,0x20004 +800000ac: ffff0f13 addi t5,t5,-1 # 20003fff +800000b0: 3b3f1073 csrw pmpaddr3,t5 +800000b4: 20004f37 lui t5,0x20004 +800000b8: ffff0f13 addi t5,t5,-1 # 20003fff +800000bc: 3b4f1073 csrw pmpaddr4,t5 +800000c0: 20004f37 lui t5,0x20004 +800000c4: ffff0f13 addi t5,t5,-1 # 20003fff +800000c8: 3b5f1073 csrw pmpaddr5,t5 +800000cc: 20002f37 lui t5,0x20002 +800000d0: ffff0f13 addi t5,t5,-1 # 20001fff +800000d4: 3b6f1073 csrw pmpaddr6,t5 +800000d8: 20004f37 lui t5,0x20004 +800000dc: ffff0f13 addi t5,t5,-1 # 20003fff +800000e0: 3b7f1073 csrw pmpaddr7,t5 +800000e4: 20004f37 lui t5,0x20004 +800000e8: ffff0f13 addi t5,t5,-1 # 20003fff +800000ec: 3b8f1073 csrw pmpaddr8,t5 +800000f0: 00000f13 li t5,0 +800000f4: 3b9f1073 csrw pmpaddr9,t5 +800000f8: 00000f13 li t5,0 +800000fc: 3baf1073 csrw pmpaddr10,t5 +80000100: 00000f13 li t5,0 +80000104: 3bbf1073 csrw pmpaddr11,t5 +80000108: 00000f13 li t5,0 +8000010c: 3bcf1073 csrw pmpaddr12,t5 +80000110: 00000f13 li t5,0 +80000114: 3bdf1073 csrw pmpaddr13,t5 +80000118: 00000f13 li t5,0 +8000011c: 3bef1073 csrw pmpaddr14,t5 +80000120: 00000f13 li t5,0 +80000124: 3bff1073 csrw pmpaddr15,t5 +80000128: 00c10337 lui t1,0xc10 +8000012c: fee30313 addi t1,t1,-18 # c0ffee +80000130: 0062a023 sw t1,0(t0) +80000134: 006e2023 sw t1,0(t3) +80000138: 0002a383 lw t2,0(t0) +8000013c: 0e731463 bne t1,t2,80000224 +80000140: 000e2383 lw t2,0(t3) +80000144: 0e731063 bne t1,t2,80000224 + +80000148 : +80000148: 00100e93 li t4,1 +8000014c: 00000f17 auipc t5,0x0 +80000150: 0d8f0f13 addi t5,t5,216 # 80000224 +80000154: 079a1f37 lui t5,0x79a1 +80000158: 808f0f13 addi t5,t5,-2040 # 79a0808 +8000015c: 3a0f1073 csrw pmpcfg0,t5 +80000160: deadc337 lui t1,0xdeadc +80000164: eef30313 addi t1,t1,-273 # deadbeef +80000168: 006e2023 sw t1,0(t3) +8000016c: 00000f17 auipc t5,0x0 +80000170: 010f0f13 addi t5,t5,16 # 8000017c +80000174: 000e2383 lw t2,0(t3) +80000178: 0ac0006f j 80000224 + +8000017c : +8000017c: 00200e93 li t4,2 +80000180: 00000f17 auipc t5,0x0 +80000184: 0a4f0f13 addi t5,t5,164 # 80000224 +80000188: 071a1f37 lui t5,0x71a1 +8000018c: 808f0f13 addi t5,t5,-2040 # 71a0808 +80000190: 3a0f1073 csrw pmpcfg0,t5 +80000194: deadc337 lui t1,0xdeadc +80000198: eef30313 addi t1,t1,-273 # deadbeef +8000019c: 006e2023 sw t1,0(t3) +800001a0: 00000f17 auipc t5,0x0 +800001a4: 010f0f13 addi t5,t5,16 # 800001b0 +800001a8: 000e2383 lw t2,0(t3) +800001ac: 0780006f j 80000224 + +800001b0 : +800001b0: 00300e93 li t4,3 +800001b4: 00000f17 auipc t5,0x0 +800001b8: 070f0f13 addi t5,t5,112 # 80000224 +800001bc: 00000097 auipc ra,0x0 +800001c0: 00c08093 addi ra,ra,12 # 800001c8 +800001c4: e49ff06f j 8000000c + +800001c8 : +800001c8: 00400e93 li t4,4 +800001cc: 00000f17 auipc t5,0x0 +800001d0: 058f0f13 addi t5,t5,88 # 80000224 +800001d4: deadc337 lui t1,0xdeadc +800001d8: eef30313 addi t1,t1,-273 # deadbeef +800001dc: 006e2023 sw t1,0(t3) +800001e0: 00000f17 auipc t5,0x0 +800001e4: 010f0f13 addi t5,t5,16 # 800001f0 +800001e8: 000e2383 lw t2,0(t3) +800001ec: 0380006f j 80000224 + +800001f0 : +800001f0: 00500e93 li t4,5 +800001f4: 00000f17 auipc t5,0x0 +800001f8: 03cf0f13 addi t5,t5,60 # 80000230 +800001fc: 80010e37 lui t3,0x80010 +80000200: deadc337 lui t1,0xdeadc +80000204: eef30313 addi t1,t1,-273 # deadbeef +80000208: 0062a023 sw t1,0(t0) +8000020c: 0002a383 lw t2,0(t0) +80000210: 00731a63 bne t1,t2,80000224 +80000214: 000e2383 lw t2,0(t3) # 80010000 +80000218: 00000f17 auipc t5,0x0 +8000021c: 018f0f13 addi t5,t5,24 # 80000230 +80000220: 007e2023 sw t2,0(t3) + +80000224 : +80000224: f0100137 lui sp,0xf0100 +80000228: f2410113 addi sp,sp,-220 # f00fff24 +8000022c: 01d12023 sw t4,0(sp) + +80000230 : +80000230: f0100137 lui sp,0xf0100 +80000234: f2010113 addi sp,sp,-224 # f00fff20 +80000238: 00012023 sw zero,0(sp) diff --git a/src/test/cpp/raw/pmp/build/pmp.elf b/src/test/cpp/raw/pmp/build/pmp.elf new file mode 100755 index 0000000000000000000000000000000000000000..22660990f46b47cd5475119569be2e4e97454b49 GIT binary patch literal 5324 zcmeHLO=uHA6#gdLv|8=%+7+d>HVf&Ycu3YZx{wswD*habDR>n^5-SF3x9n^Sg4l)L zO(6%tO9juOH;-1lcq`sT4|>*U?~QNvC)uC{j~?d1%zNLPH}B1SGpDz8ZRt8=46&qe z0D-0ezd-tv5v~+ql7AY5NC)fC1HVtRKbHc;NDEi!7nT&sfMh^2AQ_MhNCqSWk^#wp zWI!??8ITM}2L2NU94w@`o+)scmVK3hTZ&~UFuAE%d`A!bPwA{JABTKr*=ni4Sq(5W zE%PP?-+n^l{majWa_~L-yoRi~hV2(A)X(sV?W~IWD4(!1<3onl^trATZEa%A(8|kH zvuJ2O<9fbm=O;DFx5M>$TBq8&Rx-49hhj>0Uf_JmF2gjm4*BL2b~#~Jg4i&|N%*%C zc9Ze~T;GlKt4P0%^nRqjMEXahJ0)9r2SfRK*muX%Tn+B1bG4=F5iiXVJM*k}-ArB=NZ7y&M8_wN&TfTh+&KjD}ghFr|1vH>(sNtP1eH~2tP_- z+Kbl-e3|fv1fC<@PT(tqtwjDCgsFy4irQQZw@42pFlrl()w_A_*7J4O%Q^6z$_8I? z;jM7b!o6x^H83v*^Gq<$26G{pFJZmPIV#+%x*j~Yx(?*{!v|iqM%r^jeLuFSMuo4` zy@s=fT<{FJs^__l+6L7VXZ%+=M}eZ}HyCd4MGsH(^J1Yp1~N^v0??^KnHvQrV?a9Y rA_|?@jyn|BCZEVN5@{-d<1{E=SC;4#-R`1ZKJgEdak~^({7c+#k7U~* literal 0 HcmV?d00001 diff --git a/src/test/cpp/raw/pmp/build/pmp.hex b/src/test/cpp/raw/pmp/build/pmp.hex new file mode 100644 index 00000000..885cf04f --- /dev/null +++ b/src/test/cpp/raw/pmp/build/pmp.hex @@ -0,0 +1,39 @@ +:0200000480007A +:100000006F00400273101F3473002030374301002B +:1000100073300330130300207320033073901034C7 +:100020007300203097000000938000FE73905030E2 +:10003000930E0000170F0000130F0F1FB702008070 +:10004000378E008037C3ADDE1303F3EE23A06200CA +:1000500023206E0083A302006316731C83230E000B +:100060006312731C371F1A07130F8F8073100F3A18 +:10007000370F1C19130F4F5073101F3A130F8001C5 +:1000800073102F3A372F1E0F130F0F9073103F3A34 +:10009000370F002073100F3B130FF0FF73101F3B3F +:1000A000372F002073102F3B374F0020130FFFFF17 +:1000B00073103F3B374F0020130FFFFF73104F3B70 +:1000C000374F0020130FFFFF73105F3B372F0020C7 +:1000D000130FFFFF73106F3B374F0020130FFFFF0D +:1000E00073107F3B374F0020130FFFFF73108F3BC0 +:1000F000130F000073109F3B130F00007310AF3BF2 +:10010000130F00007310BF3B130F00007310CF3BA1 +:10011000130F00007310DF3B130F00007310EF3B51 +:10012000130F00007310FF3B3703C1001303E3FEFE +:1001300023A0620023206E0083A302006314730EC9 +:1001400083230E006310730E930E1000170F000030 +:10015000130F8F0D371F9A07130F8F8073100F3AED +:1001600037C3ADDE1303F3EE23206E00170F00003C +:10017000130F0F0183230E006F00C00A930E20009F +:10018000170F0000130F4F0A371F1A07130F8F8026 +:1001900073100F3A37C3ADDE1303F3EE23206E0066 +:1001A000170F0000130F0F0183230E006F0080074D +:1001B000930E3000170F0000130F0F079700000079 +:1001C0009380C0006FF09FE4930E4000170F000073 +:1001D000130F8F0537C3ADDE1303F3EE23206E003C +:1001E000170F0000130F0F0183230E006F00800311 +:1001F000930E5000170F0000130FCF03370E01802E +:1002000037C3ADDE1303F3EE23A0620083A3020025 +:10021000631A730083230E00170F0000130F8F0162 +:1002200023207E00370110F0130141F22320D10179 +:0C023000370110F0130101F2232001003F +:040000058000002453 +:00000001FF diff --git a/src/test/cpp/raw/pmp/build/pmp.map b/src/test/cpp/raw/pmp/build/pmp.map new file mode 100644 index 00000000..66d99f25 --- /dev/null +++ b/src/test/cpp/raw/pmp/build/pmp.map @@ -0,0 +1,35 @@ + +Memory Configuration + +Name Origin Length Attributes +onChipRam 0x0000000080000000 0x0000000000020000 w !xr +*default* 0x0000000000000000 0xffffffffffffffff + +Linker script and memory map + +LOAD build/src/crt.o +LOAD /opt/riscv/lib/gcc/riscv64-unknown-elf/10.2.0/libgcc.a +START GROUP +LOAD /opt/riscv/lib/gcc/riscv64-unknown-elf/10.2.0/../../../../riscv64-unknown-elf/lib/libc.a +LOAD /opt/riscv/lib/gcc/riscv64-unknown-elf/10.2.0/../../../../riscv64-unknown-elf/lib/libgloss.a +END GROUP +LOAD /opt/riscv/lib/gcc/riscv64-unknown-elf/10.2.0/libgcc.a + +.crt_section 0x0000000080000000 0x23c + 0x0000000080000000 . = ALIGN (0x4) + *crt.o(.text) + .text 0x0000000080000000 0x23c build/src/crt.o + 0x0000000080000004 trap + 0x0000000080000024 _start +OUTPUT(build/pmp.elf elf32-littleriscv) + +.data 0x000000008000023c 0x0 + .data 0x000000008000023c 0x0 build/src/crt.o + +.bss 0x000000008000023c 0x0 + .bss 0x000000008000023c 0x0 build/src/crt.o + +.riscv.attributes + 0x0000000000000000 0x1e + .riscv.attributes + 0x0000000000000000 0x1e build/src/crt.o diff --git a/src/test/cpp/raw/pmp/makefile b/src/test/cpp/raw/pmp/makefile new file mode 100644 index 00000000..0069df42 --- /dev/null +++ b/src/test/cpp/raw/pmp/makefile @@ -0,0 +1,3 @@ +PROJ_NAME=pmp + +include ../common/asm.mk diff --git a/src/test/cpp/raw/pmp/src/crt.S b/src/test/cpp/raw/pmp/src/crt.S new file mode 100644 index 00000000..e9c85464 --- /dev/null +++ b/src/test/cpp/raw/pmp/src/crt.S @@ -0,0 +1,172 @@ +#define TEST_ID x29 +#define TRAP_RA x30 + +#define PMPCFG0 0x071a0808 +#define PMPCFG0_ 0x079a0808 // lock region 2 +#define PMPCFG1 0x191c0504 +#define PMPCFG2 0x00000018 +#define PMPCFG3 0x0f1e1900 + +#define PMPADDR0 0x20000000 // TOR +#define PMPADDR1 0xffffffff // TOR +#define PMPADDR2 0x20002000 // NA4 W +#define PMPADDR3 0x20003fff // OFF RWX +#define PMPADDR4 0x20003fff // OFF X +#define PMPADDR5 0x20003fff // OFF RW +#define PMPADDR6 0x20001fff // NAPOT RWX +#define PMPADDR7 0x20003fff // NAPOT R +#define PMPADDR8 0x20003fff // NAPOT +#define PMPADDR9 0x00000000 // OFF +#define PMPADDR10 0x00000000 // OFF +#define PMPADDR11 0x00000000 // OFF +#define PMPADDR12 0x00000000 // OFF +#define PMPADDR13 0x00000000 // NAPOT R +#define PMPADDR14 0x00000000 // NAPOT WX +#define PMPADDR15 0x00000000 // TOR RWX + +.global trap +.global _start + + j _start + +trap: + csrw mepc, TRAP_RA + mret + +to_user: + li t1, 0x14000 + csrc mstatus, t1 + li t1, 0x200 + csrs mstatus, t1 + csrw mepc, ra + mret + +_start: + la x1, trap + csrw mtvec, x1 + +// configure PMP, attempt read/write from machine mode +test0: + li TEST_ID, 0 + la TRAP_RA, fail + + li t0, 0x80000000 + li t3, 0x80008000 + li t1, 0xdeadbeef + sw t1, 0x0(t0) + sw t1, 0x0(t3) + lw t2, 0x0(t0) + bne t1, t2, fail + lw t2, 0x0(t3) + bne t1, t2, fail + + li t5, PMPCFG0 + csrw pmpcfg0, t5 + li t5, PMPCFG1 + csrw pmpcfg1, t5 + li t5, PMPCFG2 + csrw pmpcfg2, t5 + li t5, PMPCFG3 + csrw pmpcfg3, t5 + li t5, PMPADDR0 + csrw pmpaddr0, t5 + li t5, PMPADDR1 + csrw pmpaddr1, t5 + li t5, PMPADDR2 + csrw pmpaddr2, t5 + li t5, PMPADDR3 + csrw pmpaddr3, t5 + li t5, PMPADDR4 + csrw pmpaddr4, t5 + li t5, PMPADDR5 + csrw pmpaddr5, t5 + li t5, PMPADDR6 + csrw pmpaddr6, t5 + li t5, PMPADDR7 + csrw pmpaddr7, t5 + li t5, PMPADDR8 + csrw pmpaddr8, t5 + li t5, PMPADDR9 + csrw pmpaddr9, t5 + li t5, PMPADDR10 + csrw pmpaddr10, t5 + li t5, PMPADDR11 + csrw pmpaddr11, t5 + li t5, PMPADDR12 + csrw pmpaddr12, t5 + li t5, PMPADDR13 + csrw pmpaddr13, t5 + li t5, PMPADDR14 + csrw pmpaddr14, t5 + li t5, PMPADDR15 + csrw pmpaddr15, t5 + + li t1, 0x00c0ffee + sw t1, 0x0(t0) + sw t1, 0x0(t3) + lw t2, 0x0(t0) + bne t1, t2, fail + lw t2, 0x0(t3) + bne t1, t2, fail + +// lock region 2, attempt read/write from machine mode +test1: + li TEST_ID, 1 + la TRAP_RA, fail + li t5, PMPCFG0_ + csrw pmpcfg0, t5 // lock region 2 + li t1, 0xdeadbeef + sw t1, 0x0(t3) // should be OK (write 0x80008000) + la TRAP_RA, test2 + lw t2, 0x0(t3) // should fault (read 0x80008000) + j fail + +// "unlock" region 2, attempt read/write from machine mode +test2: + li TEST_ID, 2 + la TRAP_RA, fail + li t5, PMPCFG0 + csrw pmpcfg0, t5 // "unlock" region 2 + li t1, 0xdeadbeef + sw t1, 0x0(t3) // should still be OK (write 0x80008000) + la TRAP_RA, test3 + lw t2, 0x0(t3) // should still fault (read 0x80008000) + j fail + +// jump into user mode +test3: + li TEST_ID, 3 + la TRAP_RA, fail + la ra, test4 + j to_user + +// attempt to read/write region 2 from user mode +test4: + li TEST_ID, 4 + la TRAP_RA, fail + li t1, 0xdeadbeef + sw t1, 0x0(t3) // should be OK (write 0x80008000) + la TRAP_RA, test5 + lw t2, 0x0(t3) // should fault (read 0x80008000) + j fail + +// attempt to read/write other regions from user mode +test5: + li TEST_ID, 5 + la TRAP_RA, pass + li t3, 0x80010000 + li t1, 0xdeadbeef + sw t1, 0x0(t0) + lw t2, 0x0(t0) + bne t1, t2, fail // should be OK + lw t2, 0x0(t3) // should be OK (read 0x80010000) + la TRAP_RA, pass + sw t2, 0x0(t3) // should fault (write 0x80010000) + +fail: + li x2, 0xf00fff24 + sw TEST_ID, 0(x2) + +pass: + li x2, 0xf00fff20 + sw x0, 0(x2) diff --git a/src/test/cpp/raw/pmp/src/ld b/src/test/cpp/raw/pmp/src/ld new file mode 100644 index 00000000..93d8de8e --- /dev/null +++ b/src/test/cpp/raw/pmp/src/ld @@ -0,0 +1,16 @@ +OUTPUT_ARCH( "riscv" ) + +MEMORY { + onChipRam (W!RX)/*(RX)*/ : ORIGIN = 0x80000000, LENGTH = 128K +} + +SECTIONS +{ + + .crt_section : + { + . = ALIGN(4); + *crt.o(.text) + } > onChipRam + +} diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index d983e8e6..a4d3a3bf 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -3870,6 +3870,10 @@ int main(int argc, char **argv, char **env) { redo(REDO,WorkspaceRegression("lrsc").withRiscvRef()->loadHex(string(REGRESSION_PATH) + "../raw/lrsc/build/lrsc.hex")->bootAt(0x00000000u)->run(10e3);); #endif + #ifdef PMP + redo(REDO,WorkspaceRegression("pmp").withRiscvRef()->loadHex(string(REGRESSION_PATH) + "../raw/lrsc/build/pmp.hex")->bootAt(0x00000000u)->run(10e3);); + #endif + #ifdef AMO redo(REDO,WorkspaceRegression("amo").withRiscvRef()->loadHex(string(REGRESSION_PATH) + "../raw/amo/build/amo.hex")->bootAt(0x00000000u)->run(10e3);); #endif From 45ff78d0685aca501fbcdf23b8d91a8a2d73a38e Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 1 Dec 2020 13:51:03 +0100 Subject: [PATCH 511/951] VexRiscvSmpClusterGen.dBusCmdMasterPipe option added --- src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index e067c395..83ac65a0 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -159,7 +159,8 @@ object VexRiscvSmpClusterGen { iCacheWays : Int = 2, dCacheWays : Int = 2, iBusRelax : Boolean = false, - earlyBranch : Boolean = false) = { + earlyBranch : Boolean = false, + dBusCmdMasterPipe : Boolean = false) = { assert(iCacheSize/iCacheWays <= 4096, "Instruction cache ways can't be bigger than 4096 bytes") assert(dCacheSize/dCacheWays <= 4096, "Data cache ways can't be bigger than 4096 bytes") val config = VexRiscvConfig( @@ -198,7 +199,7 @@ object VexRiscvSmpClusterGen { ) ), new DBusCachedPlugin( - dBusCmdMasterPipe = dBusWidth == 32, + dBusCmdMasterPipe = dBusCmdMasterPipe || dBusWidth == 32, dBusCmdSlavePipe = true, dBusRspSlavePipe = true, relaxedMemoryTranslationRegister = true, From d5b1a8f565c44b5966f3378ff67756d8b43537bd Mon Sep 17 00:00:00 2001 From: Samuel Lindemer Date: Tue, 1 Dec 2020 18:35:51 +0100 Subject: [PATCH 512/951] Add PMP test to regression suite --- .../scala/vexriscv/plugin/PmpPlugin.scala | 5 +- src/test/cpp/raw/pmp/build/pmp.asm | 72 +++++++++--------- src/test/cpp/raw/pmp/build/pmp.elf | Bin 5324 -> 5324 bytes src/test/cpp/raw/pmp/build/pmp.hex | 22 +++--- src/test/cpp/raw/pmp/build/pmp.map | 5 +- src/test/cpp/raw/pmp/src/crt.S | 21 +++-- src/test/cpp/regression/main.cpp | 2 +- src/test/cpp/regression/makefile | 5 ++ .../vexriscv/TestIndividualFeatures.scala | 25 ++++-- 9 files changed, 89 insertions(+), 68 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/PmpPlugin.scala b/src/main/scala/vexriscv/plugin/PmpPlugin.scala index b2757b87..96599e06 100644 --- a/src/main/scala/vexriscv/plugin/PmpPlugin.scala +++ b/src/main/scala/vexriscv/plugin/PmpPlugin.scala @@ -140,13 +140,12 @@ class PmpPlugin(regions : Int, ioRange : UInt => Bool) extends Plugin[VexRiscv] val privilegeService = pipeline.service(classOf[PrivilegeService]) var pcManagerService = pipeline.service(classOf[JumpService]) - // Flush proceeding instructions and replay them after any CSR write. redoInterface = pcManagerService.createJumpInterface(pipeline.execute, -1) - redoInterface.valid := False - redoInterface.payload := decode.input(PC) val core = pipeline plug new Area { + // Flush proceeding instructions and replay them after any CSR write. + redoInterface.payload := decode.input(PC) redoInterface.valid := False // Instantiate pmpaddr0 ... pmpaddr# CSRs. diff --git a/src/test/cpp/raw/pmp/build/pmp.asm b/src/test/cpp/raw/pmp/build/pmp.asm index 86da5ba5..1a125560 100644 --- a/src/test/cpp/raw/pmp/build/pmp.asm +++ b/src/test/cpp/raw/pmp/build/pmp.asm @@ -4,28 +4,26 @@ build/pmp.elf: file format elf32-littleriscv Disassembly of section .crt_section: -80000000 : -80000000: 0240006f j 80000024 <_start> +80000000 <_start>: +80000000: 00000097 auipc ra,0x0 +80000004: 01008093 addi ra,ra,16 # 80000010 +80000008: 30509073 csrw mtvec,ra +8000000c: 0240006f j 80000030 -80000004 : -80000004: 341f1073 csrw mepc,t5 -80000008: 30200073 mret +80000010 : +80000010: 341f1073 csrw mepc,t5 +80000014: 30200073 mret -8000000c : -8000000c: 00014337 lui t1,0x14 -80000010: 30033073 csrc mstatus,t1 -80000014: 20000313 li t1,512 -80000018: 30032073 csrs mstatus,t1 -8000001c: 34109073 csrw mepc,ra -80000020: 30200073 mret - -80000024 <_start>: -80000024: 00000097 auipc ra,0x0 -80000028: fe008093 addi ra,ra,-32 # 80000004 -8000002c: 30509073 csrw mtvec,ra +80000018 : +80000018: 00014337 lui t1,0x14 +8000001c: 30033073 csrc mstatus,t1 +80000020: 20000313 li t1,512 +80000024: 30032073 csrs mstatus,t1 +80000028: 34109073 csrw mepc,ra +8000002c: 30200073 mret 80000030 : -80000030: 00000e93 li t4,0 +80000030: 00000e13 li t3,0 80000034: 00000f17 auipc t5,0x0 80000038: 1f0f0f13 addi t5,t5,496 # 80000224 8000003c: 800002b7 lui t0,0x80000 @@ -39,15 +37,15 @@ Disassembly of section .crt_section: 8000005c: 000e2383 lw t2,0(t3) 80000060: 1c731263 bne t1,t2,80000224 80000064: 071a1f37 lui t5,0x71a1 -80000068: 808f0f13 addi t5,t5,-2040 # 71a0808 +80000068: 808f0f13 addi t5,t5,-2040 # 71a0808 <_start-0x78e5f7f8> 8000006c: 3a0f1073 csrw pmpcfg0,t5 80000070: 191c0f37 lui t5,0x191c0 -80000074: 504f0f13 addi t5,t5,1284 # 191c0504 +80000074: 504f0f13 addi t5,t5,1284 # 191c0504 <_start-0x66e3fafc> 80000078: 3a1f1073 csrw pmpcfg1,t5 8000007c: 01800f13 li t5,24 80000080: 3a2f1073 csrw pmpcfg2,t5 80000084: 0f1e2f37 lui t5,0xf1e2 -80000088: 900f0f13 addi t5,t5,-1792 # f1e1900 +80000088: 900f0f13 addi t5,t5,-1792 # f1e1900 <_start-0x70e1e700> 8000008c: 3a3f1073 csrw pmpcfg3,t5 80000090: 20000f37 lui t5,0x20000 80000094: 3b0f1073 csrw pmpaddr0,t5 @@ -56,22 +54,22 @@ Disassembly of section .crt_section: 800000a0: 20002f37 lui t5,0x20002 800000a4: 3b2f1073 csrw pmpaddr2,t5 800000a8: 20004f37 lui t5,0x20004 -800000ac: ffff0f13 addi t5,t5,-1 # 20003fff +800000ac: ffff0f13 addi t5,t5,-1 # 20003fff <_start-0x5fffc001> 800000b0: 3b3f1073 csrw pmpaddr3,t5 800000b4: 20004f37 lui t5,0x20004 -800000b8: ffff0f13 addi t5,t5,-1 # 20003fff +800000b8: ffff0f13 addi t5,t5,-1 # 20003fff <_start-0x5fffc001> 800000bc: 3b4f1073 csrw pmpaddr4,t5 800000c0: 20004f37 lui t5,0x20004 -800000c4: ffff0f13 addi t5,t5,-1 # 20003fff +800000c4: ffff0f13 addi t5,t5,-1 # 20003fff <_start-0x5fffc001> 800000c8: 3b5f1073 csrw pmpaddr5,t5 800000cc: 20002f37 lui t5,0x20002 -800000d0: ffff0f13 addi t5,t5,-1 # 20001fff +800000d0: ffff0f13 addi t5,t5,-1 # 20001fff <_start-0x5fffe001> 800000d4: 3b6f1073 csrw pmpaddr6,t5 800000d8: 20004f37 lui t5,0x20004 -800000dc: ffff0f13 addi t5,t5,-1 # 20003fff +800000dc: ffff0f13 addi t5,t5,-1 # 20003fff <_start-0x5fffc001> 800000e0: 3b7f1073 csrw pmpaddr7,t5 800000e4: 20004f37 lui t5,0x20004 -800000e8: ffff0f13 addi t5,t5,-1 # 20003fff +800000e8: ffff0f13 addi t5,t5,-1 # 20003fff <_start-0x5fffc001> 800000ec: 3b8f1073 csrw pmpaddr8,t5 800000f0: 00000f13 li t5,0 800000f4: 3b9f1073 csrw pmpaddr9,t5 @@ -88,7 +86,7 @@ Disassembly of section .crt_section: 80000120: 00000f13 li t5,0 80000124: 3bff1073 csrw pmpaddr15,t5 80000128: 00c10337 lui t1,0xc10 -8000012c: fee30313 addi t1,t1,-18 # c0ffee +8000012c: fee30313 addi t1,t1,-18 # c0ffee <_start-0x7f3f0012> 80000130: 0062a023 sw t1,0(t0) 80000134: 006e2023 sw t1,0(t3) 80000138: 0002a383 lw t2,0(t0) @@ -97,11 +95,11 @@ Disassembly of section .crt_section: 80000144: 0e731063 bne t1,t2,80000224 80000148 : -80000148: 00100e93 li t4,1 +80000148: 00100e13 li t3,1 8000014c: 00000f17 auipc t5,0x0 80000150: 0d8f0f13 addi t5,t5,216 # 80000224 80000154: 079a1f37 lui t5,0x79a1 -80000158: 808f0f13 addi t5,t5,-2040 # 79a0808 +80000158: 808f0f13 addi t5,t5,-2040 # 79a0808 <_start-0x7865f7f8> 8000015c: 3a0f1073 csrw pmpcfg0,t5 80000160: deadc337 lui t1,0xdeadc 80000164: eef30313 addi t1,t1,-273 # deadbeef @@ -112,11 +110,11 @@ Disassembly of section .crt_section: 80000178: 0ac0006f j 80000224 8000017c : -8000017c: 00200e93 li t4,2 +8000017c: 00200e13 li t3,2 80000180: 00000f17 auipc t5,0x0 80000184: 0a4f0f13 addi t5,t5,164 # 80000224 80000188: 071a1f37 lui t5,0x71a1 -8000018c: 808f0f13 addi t5,t5,-2040 # 71a0808 +8000018c: 808f0f13 addi t5,t5,-2040 # 71a0808 <_start-0x78e5f7f8> 80000190: 3a0f1073 csrw pmpcfg0,t5 80000194: deadc337 lui t1,0xdeadc 80000198: eef30313 addi t1,t1,-273 # deadbeef @@ -127,15 +125,15 @@ Disassembly of section .crt_section: 800001ac: 0780006f j 80000224 800001b0 : -800001b0: 00300e93 li t4,3 +800001b0: 00300e13 li t3,3 800001b4: 00000f17 auipc t5,0x0 800001b8: 070f0f13 addi t5,t5,112 # 80000224 800001bc: 00000097 auipc ra,0x0 800001c0: 00c08093 addi ra,ra,12 # 800001c8 -800001c4: e49ff06f j 8000000c +800001c4: e55ff06f j 80000018 800001c8 : -800001c8: 00400e93 li t4,4 +800001c8: 00400e13 li t3,4 800001cc: 00000f17 auipc t5,0x0 800001d0: 058f0f13 addi t5,t5,88 # 80000224 800001d4: deadc337 lui t1,0xdeadc @@ -147,7 +145,7 @@ Disassembly of section .crt_section: 800001ec: 0380006f j 80000224 800001f0 : -800001f0: 00500e93 li t4,5 +800001f0: 00500e13 li t3,5 800001f4: 00000f17 auipc t5,0x0 800001f8: 03cf0f13 addi t5,t5,60 # 80000230 800001fc: 80010e37 lui t3,0x80010 @@ -164,7 +162,7 @@ Disassembly of section .crt_section: 80000224 : 80000224: f0100137 lui sp,0xf0100 80000228: f2410113 addi sp,sp,-220 # f00fff24 -8000022c: 01d12023 sw t4,0(sp) +8000022c: 01c12023 sw t3,0(sp) 80000230 : 80000230: f0100137 lui sp,0xf0100 diff --git a/src/test/cpp/raw/pmp/build/pmp.elf b/src/test/cpp/raw/pmp/build/pmp.elf index 22660990f46b47cd5475119569be2e4e97454b49..c024632bf007112d3b165f866dd9b3b639d985e9 100755 GIT binary patch delta 262 zcmX@3c}8=B1S7*n$>;n$(-{~TCO0rJ7EcH;m?WUWD7@KFK%9|Lc(SLUF_5eUlN$v^ znd6@dPd+KA4ix(+Xv=tTvc6DZy#WJ515iH@Ffxb(NfjmpUk1qcU_|hhfczRHz6OxL z0g0~%;o&c?48=r!z1xOm1NKS3DuWVDe@|0dYpg$&)<=je%q>nA|8R z$~^zc + * + * SPDX-License-Identifier: MIT + */ + +#define TEST_ID x28 #define TRAP_RA x30 #define PMPCFG0 0x071a0808 @@ -24,15 +30,18 @@ #define PMPADDR14 0x00000000 // NAPOT WX #define PMPADDR15 0x00000000 // TOR RWX -.global trap .global _start +_start: + la x1, trap + csrw mtvec, x1 + j test0 - j _start - +.global trap trap: csrw mepc, TRAP_RA mret +.global to_user to_user: li t1, 0x14000 csrc mstatus, t1 @@ -41,10 +50,6 @@ to_user: csrw mepc, ra mret -_start: - la x1, trap - csrw mtvec, x1 - // configure PMP, attempt read/write from machine mode test0: li TEST_ID, 0 diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index a4d3a3bf..e0703536 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -3871,7 +3871,7 @@ int main(int argc, char **argv, char **env) { #endif #ifdef PMP - redo(REDO,WorkspaceRegression("pmp").withRiscvRef()->loadHex(string(REGRESSION_PATH) + "../raw/lrsc/build/pmp.hex")->bootAt(0x00000000u)->run(10e3);); + redo(REDO,WorkspaceRegression("pmp").withRiscvRef()->loadHex(string(REGRESSION_PATH) + "../raw/pmp/build/pmp.hex")->bootAt(0x00000000u)->run(10e3);); #endif #ifdef AMO diff --git a/src/test/cpp/regression/makefile b/src/test/cpp/regression/makefile index 61fe9d17..c71c8809 100644 --- a/src/test/cpp/regression/makefile +++ b/src/test/cpp/regression/makefile @@ -15,6 +15,7 @@ CSR_SKIP_TEST?=no EBREAK?=no FENCEI?=no MMU?=yes +PMP?=yes SEED?=no LRSC?=no AMO?=no @@ -217,6 +218,10 @@ ifeq ($(MMU),yes) ADDCFLAGS += -CFLAGS -DMMU endif +ifeq ($(PMP),yes) + ADDCFLAGS += -CFLAGS -DPMP +endif + ifeq ($(MUL),yes) ADDCFLAGS += -CFLAGS -DMUL endif diff --git a/src/test/scala/vexriscv/TestIndividualFeatures.scala b/src/test/scala/vexriscv/TestIndividualFeatures.scala index 047c719b..6d072913 100644 --- a/src/test/scala/vexriscv/TestIndividualFeatures.scala +++ b/src/test/scala/vexriscv/TestIndividualFeatures.scala @@ -48,6 +48,7 @@ class VexRiscvUniverse extends ConfigUniverse object VexRiscvUniverse{ val CATCH_ALL = new VexRiscvUniverse val MMU = new VexRiscvUniverse + val PMP = new VexRiscvUniverse val FORCE_MULDIV = new VexRiscvUniverse val SUPERVISOR = new VexRiscvUniverse val NO_WRITEBACK = new VexRiscvUniverse @@ -468,12 +469,12 @@ class DBusDimension extends VexRiscvDimension("DBus") { } -class MmuDimension extends VexRiscvDimension("DBus") { +class MmuPmpDimension extends VexRiscvDimension("DBus") { override def randomPositionImpl(universes: Seq[ConfigUniverse], r: Random) = { if(universes.contains(VexRiscvUniverse.MMU)) { new VexRiscvPosition("WithMmu") { - override def testParam = "MMU=yes" + override def testParam = "MMU=yes PMP=no" override def applyOn(config: VexRiscvConfig): Unit = { config.plugins += new MmuPlugin( @@ -481,9 +482,20 @@ class MmuDimension extends VexRiscvDimension("DBus") { ) } } + } else if (universes.contains(VexRiscvUniverse.PMP)) { + new VexRiscvPosition("WithPmp") { + override def testParam = "MMU=no PMP=yes" + + override def applyOn(config: VexRiscvConfig): Unit = { + config.plugins += new PmpPlugin( + regions = 16, + ioRange = _ (31 downto 28) === 0xF + ) + } + } } else { - new VexRiscvPosition("NoMmu") { - override def testParam = "MMU=no" + new VexRiscvPosition("NoMemProtect") { + override def testParam = "MMU=no PMP=no" override def applyOn(config: VexRiscvConfig): Unit = { config.plugins += new StaticMemoryTranslatorPlugin( @@ -661,7 +673,7 @@ class TestIndividualFeatures extends MultithreadedFunSuite { new CsrDimension(/*sys.env.getOrElse("VEXRISCV_REGRESSION_FREERTOS_COUNT", "1")*/ "0", zephyrCount, linuxRegression), //Freertos old port software is broken new DecoderDimension, new DebugDimension, - new MmuDimension + new MmuPmpDimension ) var clockCounter = 0l @@ -749,6 +761,7 @@ class TestIndividualFeatures extends MultithreadedFunSuite { } else { if(machineOsRate > rand.nextDouble()) { universe += VexRiscvUniverse.CATCH_ALL + universe += VexRiscvUniverse.PMP if(demwRate < rand.nextDouble()){ universe += VexRiscvUniverse.NO_WRITEBACK } @@ -776,4 +789,4 @@ class TestIndividualFeatures extends MultithreadedFunSuite { val clockPerSecond = (clockCounter/time*1e-3).toLong println(s"Duration=${(time/60).toInt}mn clocks=${(clockCounter*1e-6).toLong}M clockPerSecond=${clockPerSecond}K") } -} \ No newline at end of file +} From 872aa19d83288e7fe781780f5be63024d2024b19 Mon Sep 17 00:00:00 2001 From: Samuel Lindemer Date: Wed, 2 Dec 2020 10:25:15 +0100 Subject: [PATCH 513/951] Add PMP to golden model --- src/test/cpp/raw/pmp/build/pmp.asm | 283 +++++++++++++++-------------- src/test/cpp/raw/pmp/build/pmp.elf | Bin 5324 -> 5328 bytes src/test/cpp/raw/pmp/build/pmp.hex | 70 +++---- src/test/cpp/raw/pmp/build/pmp.map | 12 +- src/test/cpp/raw/pmp/src/crt.S | 165 ++++++++--------- src/test/cpp/regression/main.cpp | 162 ++++++++++++++++- 6 files changed, 423 insertions(+), 269 deletions(-) diff --git a/src/test/cpp/raw/pmp/build/pmp.asm b/src/test/cpp/raw/pmp/build/pmp.asm index 1a125560..48395cf9 100644 --- a/src/test/cpp/raw/pmp/build/pmp.asm +++ b/src/test/cpp/raw/pmp/build/pmp.asm @@ -15,156 +15,157 @@ Disassembly of section .crt_section: 80000014: 30200073 mret 80000018 : -80000018: 00014337 lui t1,0x14 -8000001c: 30033073 csrc mstatus,t1 -80000020: 20000313 li t1,512 -80000024: 30032073 csrs mstatus,t1 -80000028: 34109073 csrw mepc,ra +80000018: 00014137 lui sp,0x14 +8000001c: 30013073 csrc mstatus,sp +80000020: 20000113 li sp,512 +80000024: 30012073 csrs mstatus,sp +80000028: 341e9073 csrw mepc,t4 8000002c: 30200073 mret 80000030 : 80000030: 00000e13 li t3,0 80000034: 00000f17 auipc t5,0x0 -80000038: 1f0f0f13 addi t5,t5,496 # 80000224 -8000003c: 800002b7 lui t0,0x80000 -80000040: 80008e37 lui t3,0x80008 -80000044: deadc337 lui t1,0xdeadc -80000048: eef30313 addi t1,t1,-273 # deadbeef -8000004c: 0062a023 sw t1,0(t0) # 80000000 -80000050: 006e2023 sw t1,0(t3) # 80008000 -80000054: 0002a383 lw t2,0(t0) -80000058: 1c731663 bne t1,t2,80000224 -8000005c: 000e2383 lw t2,0(t3) -80000060: 1c731263 bne t1,t2,80000224 -80000064: 071a1f37 lui t5,0x71a1 -80000068: 808f0f13 addi t5,t5,-2040 # 71a0808 <_start-0x78e5f7f8> -8000006c: 3a0f1073 csrw pmpcfg0,t5 -80000070: 191c0f37 lui t5,0x191c0 -80000074: 504f0f13 addi t5,t5,1284 # 191c0504 <_start-0x66e3fafc> -80000078: 3a1f1073 csrw pmpcfg1,t5 -8000007c: 01800f13 li t5,24 -80000080: 3a2f1073 csrw pmpcfg2,t5 -80000084: 0f1e2f37 lui t5,0xf1e2 -80000088: 900f0f13 addi t5,t5,-1792 # f1e1900 <_start-0x70e1e700> -8000008c: 3a3f1073 csrw pmpcfg3,t5 -80000090: 20000f37 lui t5,0x20000 -80000094: 3b0f1073 csrw pmpaddr0,t5 -80000098: fff00f13 li t5,-1 -8000009c: 3b1f1073 csrw pmpaddr1,t5 -800000a0: 20002f37 lui t5,0x20002 -800000a4: 3b2f1073 csrw pmpaddr2,t5 -800000a8: 20004f37 lui t5,0x20004 -800000ac: ffff0f13 addi t5,t5,-1 # 20003fff <_start-0x5fffc001> -800000b0: 3b3f1073 csrw pmpaddr3,t5 -800000b4: 20004f37 lui t5,0x20004 -800000b8: ffff0f13 addi t5,t5,-1 # 20003fff <_start-0x5fffc001> -800000bc: 3b4f1073 csrw pmpaddr4,t5 -800000c0: 20004f37 lui t5,0x20004 -800000c4: ffff0f13 addi t5,t5,-1 # 20003fff <_start-0x5fffc001> -800000c8: 3b5f1073 csrw pmpaddr5,t5 -800000cc: 20002f37 lui t5,0x20002 -800000d0: ffff0f13 addi t5,t5,-1 # 20001fff <_start-0x5fffe001> -800000d4: 3b6f1073 csrw pmpaddr6,t5 -800000d8: 20004f37 lui t5,0x20004 -800000dc: ffff0f13 addi t5,t5,-1 # 20003fff <_start-0x5fffc001> -800000e0: 3b7f1073 csrw pmpaddr7,t5 -800000e4: 20004f37 lui t5,0x20004 -800000e8: ffff0f13 addi t5,t5,-1 # 20003fff <_start-0x5fffc001> -800000ec: 3b8f1073 csrw pmpaddr8,t5 -800000f0: 00000f13 li t5,0 -800000f4: 3b9f1073 csrw pmpaddr9,t5 -800000f8: 00000f13 li t5,0 -800000fc: 3baf1073 csrw pmpaddr10,t5 -80000100: 00000f13 li t5,0 -80000104: 3bbf1073 csrw pmpaddr11,t5 -80000108: 00000f13 li t5,0 -8000010c: 3bcf1073 csrw pmpaddr12,t5 -80000110: 00000f13 li t5,0 -80000114: 3bdf1073 csrw pmpaddr13,t5 -80000118: 00000f13 li t5,0 -8000011c: 3bef1073 csrw pmpaddr14,t5 -80000120: 00000f13 li t5,0 -80000124: 3bff1073 csrw pmpaddr15,t5 -80000128: 00c10337 lui t1,0xc10 -8000012c: fee30313 addi t1,t1,-18 # c0ffee <_start-0x7f3f0012> -80000130: 0062a023 sw t1,0(t0) -80000134: 006e2023 sw t1,0(t3) -80000138: 0002a383 lw t2,0(t0) -8000013c: 0e731463 bne t1,t2,80000224 -80000140: 000e2383 lw t2,0(t3) -80000144: 0e731063 bne t1,t2,80000224 +80000038: 1f4f0f13 addi t5,t5,500 # 80000228 +8000003c: 800000b7 lui ra,0x80000 +80000040: 80008237 lui tp,0x80008 +80000044: deadc137 lui sp,0xdeadc +80000048: eef10113 addi sp,sp,-273 # deadbeef +8000004c: 0020a023 sw sp,0(ra) # 80000000 +80000050: 00222023 sw sp,0(tp) # 80008000 +80000054: 0000a183 lw gp,0(ra) +80000058: 1c311863 bne sp,gp,80000228 +8000005c: 00022183 lw gp,0(tp) # 0 <_start-0x80000000> +80000060: 1c311463 bne sp,gp,80000228 +80000064: 071a12b7 lui t0,0x71a1 +80000068: 80828293 addi t0,t0,-2040 # 71a0808 <_start-0x78e5f7f8> +8000006c: 3a029073 csrw pmpcfg0,t0 +80000070: 191c02b7 lui t0,0x191c0 +80000074: 50428293 addi t0,t0,1284 # 191c0504 <_start-0x66e3fafc> +80000078: 3a129073 csrw pmpcfg1,t0 +8000007c: 01800293 li t0,24 +80000080: 3a229073 csrw pmpcfg2,t0 +80000084: 0f1e22b7 lui t0,0xf1e2 +80000088: 90028293 addi t0,t0,-1792 # f1e1900 <_start-0x70e1e700> +8000008c: 3a329073 csrw pmpcfg3,t0 +80000090: 200002b7 lui t0,0x20000 +80000094: 3b029073 csrw pmpaddr0,t0 +80000098: fff00293 li t0,-1 +8000009c: 3b129073 csrw pmpaddr1,t0 +800000a0: 200022b7 lui t0,0x20002 +800000a4: 3b229073 csrw pmpaddr2,t0 +800000a8: 200042b7 lui t0,0x20004 +800000ac: fff28293 addi t0,t0,-1 # 20003fff <_start-0x5fffc001> +800000b0: 3b329073 csrw pmpaddr3,t0 +800000b4: 200042b7 lui t0,0x20004 +800000b8: fff28293 addi t0,t0,-1 # 20003fff <_start-0x5fffc001> +800000bc: 3b429073 csrw pmpaddr4,t0 +800000c0: 200042b7 lui t0,0x20004 +800000c4: fff28293 addi t0,t0,-1 # 20003fff <_start-0x5fffc001> +800000c8: 3b529073 csrw pmpaddr5,t0 +800000cc: 200022b7 lui t0,0x20002 +800000d0: fff28293 addi t0,t0,-1 # 20001fff <_start-0x5fffe001> +800000d4: 3b629073 csrw pmpaddr6,t0 +800000d8: 200042b7 lui t0,0x20004 +800000dc: fff28293 addi t0,t0,-1 # 20003fff <_start-0x5fffc001> +800000e0: 3b729073 csrw pmpaddr7,t0 +800000e4: 200042b7 lui t0,0x20004 +800000e8: fff28293 addi t0,t0,-1 # 20003fff <_start-0x5fffc001> +800000ec: 3b829073 csrw pmpaddr8,t0 +800000f0: 00000293 li t0,0 +800000f4: 3b929073 csrw pmpaddr9,t0 +800000f8: 00000293 li t0,0 +800000fc: 3ba29073 csrw pmpaddr10,t0 +80000100: 00000293 li t0,0 +80000104: 3bb29073 csrw pmpaddr11,t0 +80000108: 00000293 li t0,0 +8000010c: 3bc29073 csrw pmpaddr12,t0 +80000110: 00000293 li t0,0 +80000114: 3bd29073 csrw pmpaddr13,t0 +80000118: 00000293 li t0,0 +8000011c: 3be29073 csrw pmpaddr14,t0 +80000120: 00000293 li t0,0 +80000124: 3bf29073 csrw pmpaddr15,t0 +80000128: 00c10137 lui sp,0xc10 +8000012c: fee10113 addi sp,sp,-18 # c0ffee <_start-0x7f3f0012> +80000130: 0020a023 sw sp,0(ra) +80000134: 00222023 sw sp,0(tp) # 0 <_start-0x80000000> +80000138: 0000a183 lw gp,0(ra) +8000013c: 0e311663 bne sp,gp,80000228 +80000140: 00022183 lw gp,0(tp) # 0 <_start-0x80000000> +80000144: 0e311263 bne sp,gp,80000228 +80000148: 06c0006f j 800001b4 -80000148 : -80000148: 00100e13 li t3,1 -8000014c: 00000f17 auipc t5,0x0 -80000150: 0d8f0f13 addi t5,t5,216 # 80000224 -80000154: 079a1f37 lui t5,0x79a1 -80000158: 808f0f13 addi t5,t5,-2040 # 79a0808 <_start-0x7865f7f8> -8000015c: 3a0f1073 csrw pmpcfg0,t5 -80000160: deadc337 lui t1,0xdeadc -80000164: eef30313 addi t1,t1,-273 # deadbeef -80000168: 006e2023 sw t1,0(t3) -8000016c: 00000f17 auipc t5,0x0 -80000170: 010f0f13 addi t5,t5,16 # 8000017c -80000174: 000e2383 lw t2,0(t3) -80000178: 0ac0006f j 80000224 +8000014c : +8000014c: 00100e13 li t3,1 +80000150: 00000f17 auipc t5,0x0 +80000154: 0d8f0f13 addi t5,t5,216 # 80000228 +80000158: 079a12b7 lui t0,0x79a1 +8000015c: 80828293 addi t0,t0,-2040 # 79a0808 <_start-0x7865f7f8> +80000160: 3a029073 csrw pmpcfg0,t0 +80000164: deadc137 lui sp,0xdeadc +80000168: eef10113 addi sp,sp,-273 # deadbeef +8000016c: 00222023 sw sp,0(tp) # 0 <_start-0x80000000> +80000170: 00000f17 auipc t5,0x0 +80000174: 010f0f13 addi t5,t5,16 # 80000180 +80000178: 00022183 lw gp,0(tp) # 0 <_start-0x80000000> +8000017c: 0ac0006f j 80000228 -8000017c : -8000017c: 00200e13 li t3,2 -80000180: 00000f17 auipc t5,0x0 -80000184: 0a4f0f13 addi t5,t5,164 # 80000224 -80000188: 071a1f37 lui t5,0x71a1 -8000018c: 808f0f13 addi t5,t5,-2040 # 71a0808 <_start-0x78e5f7f8> -80000190: 3a0f1073 csrw pmpcfg0,t5 -80000194: deadc337 lui t1,0xdeadc -80000198: eef30313 addi t1,t1,-273 # deadbeef -8000019c: 006e2023 sw t1,0(t3) -800001a0: 00000f17 auipc t5,0x0 -800001a4: 010f0f13 addi t5,t5,16 # 800001b0 -800001a8: 000e2383 lw t2,0(t3) -800001ac: 0780006f j 80000224 +80000180 : +80000180: 00200e13 li t3,2 +80000184: 00000f17 auipc t5,0x0 +80000188: 0a4f0f13 addi t5,t5,164 # 80000228 +8000018c: 071a12b7 lui t0,0x71a1 +80000190: 80828293 addi t0,t0,-2040 # 71a0808 <_start-0x78e5f7f8> +80000194: 3a029073 csrw pmpcfg0,t0 +80000198: deadc137 lui sp,0xdeadc +8000019c: eef10113 addi sp,sp,-273 # deadbeef +800001a0: 00222023 sw sp,0(tp) # 0 <_start-0x80000000> +800001a4: 00000f17 auipc t5,0x0 +800001a8: 010f0f13 addi t5,t5,16 # 800001b4 +800001ac: 00022183 lw gp,0(tp) # 0 <_start-0x80000000> +800001b0: 0780006f j 80000228 -800001b0 : -800001b0: 00300e13 li t3,3 -800001b4: 00000f17 auipc t5,0x0 -800001b8: 070f0f13 addi t5,t5,112 # 80000224 -800001bc: 00000097 auipc ra,0x0 -800001c0: 00c08093 addi ra,ra,12 # 800001c8 -800001c4: e55ff06f j 80000018 +800001b4 : +800001b4: 00300e13 li t3,3 +800001b8: 00000f17 auipc t5,0x0 +800001bc: 070f0f13 addi t5,t5,112 # 80000228 +800001c0: 00000e97 auipc t4,0x0 +800001c4: 00ce8e93 addi t4,t4,12 # 800001cc +800001c8: e51ff06f j 80000018 -800001c8 : -800001c8: 00400e13 li t3,4 -800001cc: 00000f17 auipc t5,0x0 -800001d0: 058f0f13 addi t5,t5,88 # 80000224 -800001d4: deadc337 lui t1,0xdeadc -800001d8: eef30313 addi t1,t1,-273 # deadbeef -800001dc: 006e2023 sw t1,0(t3) -800001e0: 00000f17 auipc t5,0x0 -800001e4: 010f0f13 addi t5,t5,16 # 800001f0 -800001e8: 000e2383 lw t2,0(t3) -800001ec: 0380006f j 80000224 +800001cc : +800001cc: 00400e13 li t3,4 +800001d0: 00000f17 auipc t5,0x0 +800001d4: 058f0f13 addi t5,t5,88 # 80000228 +800001d8: deadc137 lui sp,0xdeadc +800001dc: eef10113 addi sp,sp,-273 # deadbeef +800001e0: 00222023 sw sp,0(tp) # 0 <_start-0x80000000> +800001e4: 00000f17 auipc t5,0x0 +800001e8: 010f0f13 addi t5,t5,16 # 800001f4 +800001ec: 00022183 lw gp,0(tp) # 0 <_start-0x80000000> +800001f0: 0380006f j 80000228 -800001f0 : -800001f0: 00500e13 li t3,5 -800001f4: 00000f17 auipc t5,0x0 -800001f8: 03cf0f13 addi t5,t5,60 # 80000230 -800001fc: 80010e37 lui t3,0x80010 -80000200: deadc337 lui t1,0xdeadc -80000204: eef30313 addi t1,t1,-273 # deadbeef -80000208: 0062a023 sw t1,0(t0) -8000020c: 0002a383 lw t2,0(t0) -80000210: 00731a63 bne t1,t2,80000224 -80000214: 000e2383 lw t2,0(t3) # 80010000 -80000218: 00000f17 auipc t5,0x0 -8000021c: 018f0f13 addi t5,t5,24 # 80000230 -80000220: 007e2023 sw t2,0(t3) +800001f4 : +800001f4: 00500e13 li t3,5 +800001f8: 00000f17 auipc t5,0x0 +800001fc: 03cf0f13 addi t5,t5,60 # 80000234 +80000200: 80010237 lui tp,0x80010 +80000204: deadc137 lui sp,0xdeadc +80000208: eef10113 addi sp,sp,-273 # deadbeef +8000020c: 0020a023 sw sp,0(ra) +80000210: 0000a183 lw gp,0(ra) +80000214: 00311a63 bne sp,gp,80000228 +80000218: 00022183 lw gp,0(tp) # 80010000 +8000021c: 00000f17 auipc t5,0x0 +80000220: 018f0f13 addi t5,t5,24 # 80000234 +80000224: 00322023 sw gp,0(tp) # 0 <_start-0x80000000> -80000224 : -80000224: f0100137 lui sp,0xf0100 -80000228: f2410113 addi sp,sp,-220 # f00fff24 -8000022c: 01c12023 sw t3,0(sp) +80000228 : +80000228: f0100137 lui sp,0xf0100 +8000022c: f2410113 addi sp,sp,-220 # f00fff24 +80000230: 01c12023 sw t3,0(sp) -80000230 : -80000230: f0100137 lui sp,0xf0100 -80000234: f2010113 addi sp,sp,-224 # f00fff20 -80000238: 00012023 sw zero,0(sp) +80000234 : +80000234: f0100137 lui sp,0xf0100 +80000238: f2010113 addi sp,sp,-224 # f00fff20 +8000023c: 00012023 sw zero,0(sp) diff --git a/src/test/cpp/raw/pmp/build/pmp.elf b/src/test/cpp/raw/pmp/build/pmp.elf index c024632bf007112d3b165f866dd9b3b639d985e9..9b21344a11a56286768e95efa12760ea87cc49c6 100755 GIT binary patch delta 710 zcmaJ;J4?hs5T0E*4+Im<245VyCWYEaavmHc2C->q(YIRuC!ZhAcwB<*sD)s&@3bIUd8b8Wz<4V-}6)e8= zJu$7+Xdv@XeG}6vN#1o+k&<64jMr!MxKQh`-t7jld0yGZ+Uy{O0OCU+hj>bUxP^Qo z#RriGDL#z+GQ|tX-&5Q}UQq39x^)DW7sRp~+q_y~yQHMLO&jf~IY4IA0@{jNGY2w< K48T)kCi?<-&$jpg literal 5324 zcmeHL&ubGw6#gdLv|4p{?TFPHo5gtODOuadLQ-gp_~TGa!K)CGSTRt$WoKIu#4hx1 z3LXS66+DaHJlf*LTmJ#kgLu_w@5VR#quC$@j~?d1%zNLPH}B1SGpDzCeenik42fiL zfEWd3a(?2`N*NaUr!b6cv~Gs}faYK}1IUq;uE;MfC5i#XfMP%~pcqgLC3xd|AMzv7Zpy!zvOAO) z5av#--^BWTtoLL6CDuP;-K#p<9=P`P_rM*`2tB-`DRi!zF)y7{PX0yzz6m$POUxUS zdtB^}a@~r3wb22Nj@%QBaNSPwj6`p@3%6VU#`XE6e)jM^{;C;hTwjXg_BBUm18*0; z+k}8TUv$KbPPf8Mjy;Un2ZCg{KI=P2nQpk0~ts zTiq0{5VlkK=LnyR>zj1Cn}kUMIZ1pw)P0QRdVA$wNqDVN%kzsa{AJ$iVRW4AV?D-8x8v@zGll{CzhGIkVsR4AVNM^@?$pny2x`plK-QrE diff --git a/src/test/cpp/raw/pmp/build/pmp.hex b/src/test/cpp/raw/pmp/build/pmp.hex index a0a342a5..3f75e5db 100644 --- a/src/test/cpp/raw/pmp/build/pmp.hex +++ b/src/test/cpp/raw/pmp/build/pmp.hex @@ -1,39 +1,39 @@ :0200000480007A :100000009700000093800001739050306F00400211 -:1000100073101F34730020303743010073300330F6 -:1000200013030020732003307390103473002030CA -:10003000130E0000170F0000130F0F1FB7020080F0 -:10004000378E008037C3ADDE1303F3EE23A06200CA -:1000500023206E0083A302006316731C83230E000B -:100060006312731C371F1A07130F8F8073100F3A18 -:10007000370F1C19130F4F5073101F3A130F8001C5 -:1000800073102F3A372F1E0F130F0F9073103F3A34 -:10009000370F002073100F3B130FF0FF73101F3B3F -:1000A000372F002073102F3B374F0020130FFFFF17 -:1000B00073103F3B374F0020130FFFFF73104F3B70 -:1000C000374F0020130FFFFF73105F3B372F0020C7 -:1000D000130FFFFF73106F3B374F0020130FFFFF0D -:1000E00073107F3B374F0020130FFFFF73108F3BC0 -:1000F000130F000073109F3B130F00007310AF3BF2 -:10010000130F00007310BF3B130F00007310CF3BA1 -:10011000130F00007310DF3B130F00007310EF3B51 -:10012000130F00007310FF3B3703C1001303E3FEFE -:1001300023A0620023206E0083A302006314730EC9 -:1001400083230E006310730E130E1000170F0000B0 -:10015000130F8F0D371F9A07130F8F8073100F3AED -:1001600037C3ADDE1303F3EE23206E00170F00003C -:10017000130F0F0183230E006F00C00A130E20001F -:10018000170F0000130F4F0A371F1A07130F8F8026 -:1001900073100F3A37C3ADDE1303F3EE23206E0066 -:1001A000170F0000130F0F0183230E006F0080074D -:1001B000130E3000170F0000130F0F0797000000F9 -:1001C0009380C0006FF05FE5130E4000170F000032 -:1001D000130F8F0537C3ADDE1303F3EE23206E003C -:1001E000170F0000130F0F0183230E006F00800311 -:1001F000130E5000170F0000130FCF03370E0180AE -:1002000037C3ADDE1303F3EE23A0620083A3020025 -:10021000631A730083230E00170F0000130F8F0162 -:1002200023207E00370110F0130141F22320C10189 -:0C023000370110F0130101F2232001003F +:1000100073101F34730020303741010073300130FA +:10002000130100207320013073901E3473002030C0 +:10003000130E0000170F0000130F4F1FB7000080B2 +:100040003782008037C1ADDE1301F1EE23A020001E +:100050002320220083A100006318311C83210200A9 +:100060006314311CB7121A07938282807390023A8C +:10007000B7021C19938242507390123A9302800186 +:100080007390223AB7221E0F938202907390323AF5 +:10009000B70200207390023B9302F0FF7390123B73 +:1000A000B72200207390223BB74200209382F2FFD8 +:1000B0007390323BB74200209382F2FF7390423B31 +:1000C000B74200209382F2FF7390523BB722002088 +:1000D0009382F2FF7390623BB74200209382F2FF5B +:1000E0007390723BB74200209382F2FF7390823B81 +:1000F000930200007390923B930200007390A23B26 +:10010000930200007390B23B930200007390C23BD5 +:10011000930200007390D23B930200007390E23B85 +:10012000930200007390F23B3701C1001301E1FE1E +:1001300023A020002320220083A100006316310E9B +:10014000832102006312310E6F00C006130E1000EF +:10015000170F0000130F8F0DB7129A07938282803A +:100160007390023A37C1ADDE1301F1EE2320220075 +:10017000170F0000130F0F01832102006F00C00A48 +:10018000130E2000170F0000130F4F0AB7121A07A3 +:10019000938282807390023A37C1ADDE1301F1EE93 +:1001A00023202200170F0000130F0F0183210200EC +:1001B0006F008007130E3000170F0000130F0F079A +:1001C000970E0000938ECE006FF01FE5130E4000D7 +:1001D000170F0000130F8F0537C1ADDE1301F1EECD +:1001E00023202200170F0000130F0F0183210200AC +:1001F0006F008003130E5000170F0000130FCF0382 +:100200003702018037C1ADDE1301F1EE23A02000DB +:1002100083A10000631A310083210200170F000040 +:10022000130F8F0123203200370110F0130141F228 +:100230002320C101370110F0130101F22320010036 :040000058000000077 :00000001FF diff --git a/src/test/cpp/raw/pmp/build/pmp.map b/src/test/cpp/raw/pmp/build/pmp.map index ede4c4b9..f2252f37 100644 --- a/src/test/cpp/raw/pmp/build/pmp.map +++ b/src/test/cpp/raw/pmp/build/pmp.map @@ -15,20 +15,20 @@ LOAD /opt/riscv/lib/gcc/riscv64-unknown-elf/10.2.0/../../../../riscv64-unknown-e END GROUP LOAD /opt/riscv/lib/gcc/riscv64-unknown-elf/10.2.0/libgcc.a -.crt_section 0x0000000080000000 0x23c +.crt_section 0x0000000080000000 0x240 0x0000000080000000 . = ALIGN (0x4) *crt.o(.text) - .text 0x0000000080000000 0x23c build/src/crt.o + .text 0x0000000080000000 0x240 build/src/crt.o 0x0000000080000000 _start 0x0000000080000010 trap 0x0000000080000018 to_user OUTPUT(build/pmp.elf elf32-littleriscv) -.data 0x000000008000023c 0x0 - .data 0x000000008000023c 0x0 build/src/crt.o +.data 0x0000000080000240 0x0 + .data 0x0000000080000240 0x0 build/src/crt.o -.bss 0x000000008000023c 0x0 - .bss 0x000000008000023c 0x0 build/src/crt.o +.bss 0x0000000080000240 0x0 + .bss 0x0000000080000240 0x0 build/src/crt.o .riscv.attributes 0x0000000000000000 0x1e diff --git a/src/test/cpp/raw/pmp/src/crt.S b/src/test/cpp/raw/pmp/src/crt.S index 35a4e1ef..6eacc089 100644 --- a/src/test/cpp/raw/pmp/src/crt.S +++ b/src/test/cpp/raw/pmp/src/crt.S @@ -5,6 +5,7 @@ */ #define TEST_ID x28 +#define USER_RA x29 #define TRAP_RA x30 #define PMPCFG0 0x071a0808 @@ -43,11 +44,11 @@ trap: .global to_user to_user: - li t1, 0x14000 - csrc mstatus, t1 - li t1, 0x200 - csrs mstatus, t1 - csrw mepc, ra + li x2, 0x14000 + csrc mstatus, x2 + li x2, 0x200 + csrs mstatus, x2 + csrw mepc, USER_RA mret // configure PMP, attempt read/write from machine mode @@ -55,118 +56,118 @@ test0: li TEST_ID, 0 la TRAP_RA, fail - li t0, 0x80000000 - li t3, 0x80008000 - li t1, 0xdeadbeef - sw t1, 0x0(t0) - sw t1, 0x0(t3) - lw t2, 0x0(t0) - bne t1, t2, fail - lw t2, 0x0(t3) - bne t1, t2, fail + li x1, 0x80000000 + li x4, 0x80008000 + li x2, 0xdeadbeef + sw x2, 0x0(x1) + sw x2, 0x0(x4) + lw x3, 0x0(x1) + bne x2, x3, fail + lw x3, 0x0(x4) + bne x2, x3, fail - li t5, PMPCFG0 - csrw pmpcfg0, t5 - li t5, PMPCFG1 - csrw pmpcfg1, t5 - li t5, PMPCFG2 - csrw pmpcfg2, t5 - li t5, PMPCFG3 - csrw pmpcfg3, t5 - li t5, PMPADDR0 - csrw pmpaddr0, t5 - li t5, PMPADDR1 - csrw pmpaddr1, t5 - li t5, PMPADDR2 - csrw pmpaddr2, t5 - li t5, PMPADDR3 - csrw pmpaddr3, t5 - li t5, PMPADDR4 - csrw pmpaddr4, t5 - li t5, PMPADDR5 - csrw pmpaddr5, t5 - li t5, PMPADDR6 - csrw pmpaddr6, t5 - li t5, PMPADDR7 - csrw pmpaddr7, t5 - li t5, PMPADDR8 - csrw pmpaddr8, t5 - li t5, PMPADDR9 - csrw pmpaddr9, t5 - li t5, PMPADDR10 - csrw pmpaddr10, t5 - li t5, PMPADDR11 - csrw pmpaddr11, t5 - li t5, PMPADDR12 - csrw pmpaddr12, t5 - li t5, PMPADDR13 - csrw pmpaddr13, t5 - li t5, PMPADDR14 - csrw pmpaddr14, t5 - li t5, PMPADDR15 - csrw pmpaddr15, t5 + li x5, PMPCFG0 + csrw pmpcfg0, x5 + li x5, PMPCFG1 + csrw pmpcfg1, x5 + li x5, PMPCFG2 + csrw pmpcfg2, x5 + li x5, PMPCFG3 + csrw pmpcfg3, x5 + li x5, PMPADDR0 + csrw pmpaddr0, x5 + li x5, PMPADDR1 + csrw pmpaddr1, x5 + li x5, PMPADDR2 + csrw pmpaddr2, x5 + li x5, PMPADDR3 + csrw pmpaddr3, x5 + li x5, PMPADDR4 + csrw pmpaddr4, x5 + li x5, PMPADDR5 + csrw pmpaddr5, x5 + li x5, PMPADDR6 + csrw pmpaddr6, x5 + li x5, PMPADDR7 + csrw pmpaddr7, x5 + li x5, PMPADDR8 + csrw pmpaddr8, x5 + li x5, PMPADDR9 + csrw pmpaddr9, x5 + li x5, PMPADDR10 + csrw pmpaddr10, x5 + li x5, PMPADDR11 + csrw pmpaddr11, x5 + li x5, PMPADDR12 + csrw pmpaddr12, x5 + li x5, PMPADDR13 + csrw pmpaddr13, x5 + li x5, PMPADDR14 + csrw pmpaddr14, x5 + li x5, PMPADDR15 + csrw pmpaddr15, x5 - li t1, 0x00c0ffee - sw t1, 0x0(t0) - sw t1, 0x0(t3) - lw t2, 0x0(t0) - bne t1, t2, fail - lw t2, 0x0(t3) - bne t1, t2, fail + li x2, 0x00c0ffee + sw x2, 0x0(x1) + sw x2, 0x0(x4) + lw x3, 0x0(x1) + bne x2, x3, fail + lw x3, 0x0(x4) + bne x2, x3, fail // lock region 2, attempt read/write from machine mode test1: li TEST_ID, 1 la TRAP_RA, fail - li t5, PMPCFG0_ - csrw pmpcfg0, t5 // lock region 2 - li t1, 0xdeadbeef - sw t1, 0x0(t3) // should be OK (write 0x80008000) + li x5, PMPCFG0_ + csrw pmpcfg0, x5 // lock region 2 + li x2, 0xdeadbeef + sw x2, 0x0(x4) // should be OK (write 0x80008000) la TRAP_RA, test2 - lw t2, 0x0(t3) // should fault (read 0x80008000) + lw x3, 0x0(x4) // should fault (read 0x80008000) j fail // "unlock" region 2, attempt read/write from machine mode test2: li TEST_ID, 2 la TRAP_RA, fail - li t5, PMPCFG0 - csrw pmpcfg0, t5 // "unlock" region 2 - li t1, 0xdeadbeef - sw t1, 0x0(t3) // should still be OK (write 0x80008000) + li x5, PMPCFG0 + csrw pmpcfg0, x5 // "unlock" region 2 + li x2, 0xdeadbeef + sw x2, 0x0(x4) // should still be OK (write 0x80008000) la TRAP_RA, test3 - lw t2, 0x0(t3) // should still fault (read 0x80008000) + lw x3, 0x0(x4) // should still fault (read 0x80008000) j fail // jump into user mode test3: li TEST_ID, 3 la TRAP_RA, fail - la ra, test4 + la USER_RA, test4 j to_user // attempt to read/write region 2 from user mode test4: li TEST_ID, 4 la TRAP_RA, fail - li t1, 0xdeadbeef - sw t1, 0x0(t3) // should be OK (write 0x80008000) + li x2, 0xdeadbeef + sw x2, 0x0(x4) // should be OK (write 0x80008000) la TRAP_RA, test5 - lw t2, 0x0(t3) // should fault (read 0x80008000) + lw x3, 0x0(x4) // should fault (read 0x80008000) j fail // attempt to read/write other regions from user mode test5: li TEST_ID, 5 la TRAP_RA, pass - li t3, 0x80010000 - li t1, 0xdeadbeef - sw t1, 0x0(t0) - lw t2, 0x0(t0) - bne t1, t2, fail // should be OK - lw t2, 0x0(t3) // should be OK (read 0x80010000) + li x4, 0x80010000 + li x2, 0xdeadbeef + sw x2, 0x0(x1) + lw x3, 0x0(x1) + bne x2, x3, fail // should be OK + lw x3, 0x0(x4) // should be OK (read 0x80010000) la TRAP_RA, pass - sw t2, 0x0(t3) // should fault (write 0x80010000) + sw x3, 0x0(x4) // should fault (write 0x80010000) fail: li x2, 0xf00fff24 diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index e0703536..dca31a72 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -211,6 +211,26 @@ class success : public std::exception { }; #define MCYCLEH 0xB80 // MRW Upper 32 bits of mcycle, RV32I only. #define MINSTRETH 0xB82 // MRW Upper 32 bits of minstret, RV32I only. +#define PMPCFG0 0x3a0 +#define PMPCFG1 0x3a1 +#define PMPCFG2 0x3a2 +#define PMPCFG3 0x3a3 +#define PMPADDR0 0x3b0 +#define PMPADDR1 0x3b1 +#define PMPADDR2 0x3b2 +#define PMPADDR3 0x3b3 +#define PMPADDR4 0x3b4 +#define PMPADDR5 0x3b5 +#define PMPADDR6 0x3b6 +#define PMPADDR7 0x3b7 +#define PMPADDR8 0x3b8 +#define PMPADDR9 0x3b9 +#define PMPADDR10 0x3ba +#define PMPADDR11 0x3bb +#define PMPADDR12 0x3bc +#define PMPADDR13 0x3bd +#define PMPADDR14 0x3be +#define PMPADDR15 0x3bf #define SSTATUS 0x100 #define SIE 0x104 @@ -373,10 +393,26 @@ public: uint32_t ppn1 : 12; }; }; - - + bool lrscReserved; + struct pmpcfg_s { + uint32_t r : 1; + uint32_t w : 1; + uint32_t x : 1; + uint32_t a : 2; + uint32_t _dummy : 2; + uint32_t l : 1; + } __attribute__((packed)); + + union pmpcfg_u { + uint32_t raw; + pmpcfg_s reg[4]; + }; + + pmpcfg_u pmpcfg[4]; + uint32_t pmpaddr[16]; + RiscvGolden() { pc = 0x80000000; regs[0] = 0; @@ -401,6 +437,10 @@ public: ipInput = 0; stepCounter = 0; lrscReserved = false; + for (int i = 0; i < 4; i++) + pmpcfg[i].raw = 0; + for (int i = 0; i < 16; i++) + pmpaddr[i] = 0; } virtual void rfWrite(int32_t address, int32_t data) { @@ -425,8 +465,55 @@ public: enum AccessKind {READ,WRITE,EXECUTE,READ_WRITE}; virtual bool isMmuRegion(uint32_t v) = 0; - bool v2p(uint32_t v, uint32_t *p, AccessKind kind){ - uint32_t effectivePrivilege = status.mprv && kind != EXECUTE ? status.mpp : privilege; + + bool pmpCheck(uint32_t p, AccessKind kind) { + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + if (privilege != 3 || pmpcfg[i].reg[3-j].l) { + uint32_t start, end; + bool valid = false; + + switch (pmpcfg[i].reg[3-j].a) { + case 0: // OFF + valid = false; + break; + + case 1: // TOR + valid = false; + break; + + case 2: // NA4 + valid = true; + start = pmpaddr[i*4+j] << 2; + end = start + 4; + break; + + case 3: // NAPOT + valid = true; + uint32_t mask = pmpaddr[i*4+j] & ~(pmpaddr[i*4+j] + 1); + start = (pmpaddr[i*4+j] & ~mask) << 2; + end = start + ((mask + 1) << 3); + break; + } + + if (valid && start <= p && end > p) { + if (kind == READ) return (bool)(!pmpcfg[i].reg[3-j].r); + if (kind == WRITE) return (bool)(!pmpcfg[i].reg[3-j].w); + if (kind == EXECUTE) return (bool)(!pmpcfg[i].reg[3-j].x); + return false; + } + } + } + } + return false; + } + + bool v2p(uint32_t v, uint32_t *p, AccessKind kind) { +#ifdef PMP + *p = v; + return pmpCheck(v, kind); +#else + uint32_t effectivePrivilege = status.mprv && kind != EXECUTE ? status.mpp : privilege; if(effectivePrivilege == 3 || satp.mode == 0 || !isMmuRegion(v)){ *p = v; } else { @@ -449,6 +536,7 @@ public: *p = (tlb.ppn1 << 22) | (superPage ? v & 0x3FF000 : tlb.ppn0 << 12) | (v & 0xFFF); } return false; +#endif } void trap(bool interrupt,int32_t cause) { @@ -528,7 +616,7 @@ public: virtual bool csrRead(int32_t csr, uint32_t *value){ if(((csr >> 8) & 0x3) > privilege) return true; - switch(csr){ + switch(csr) { case MSTATUS: *value = status.raw & MSTATUS_READ_MASK; break; case MIP: *value = getIp().raw; break; case MIE: *value = ie.raw; break; @@ -550,6 +638,28 @@ public: case SEPC: *value = sepc; break; case SSCRATCH: *value = sscratch; break; case SATP: *value = satp.raw; break; + + case PMPCFG0: *value = pmpcfg[0].raw; break; + case PMPCFG1: *value = pmpcfg[1].raw; break; + case PMPCFG2: *value = pmpcfg[2].raw; break; + case PMPCFG3: *value = pmpcfg[3].raw; break; + case PMPADDR0: *value = pmpaddr[0]; break; + case PMPADDR1: *value = pmpaddr[1]; break; + case PMPADDR2: *value = pmpaddr[2]; break; + case PMPADDR3: *value = pmpaddr[3]; break; + case PMPADDR4: *value = pmpaddr[4]; break; + case PMPADDR5: *value = pmpaddr[5]; break; + case PMPADDR6: *value = pmpaddr[6]; break; + case PMPADDR7: *value = pmpaddr[7]; break; + case PMPADDR8: *value = pmpaddr[8]; break; + case PMPADDR9: *value = pmpaddr[9]; break; + case PMPADDR10: *value = pmpaddr[10]; break; + case PMPADDR11: *value = pmpaddr[11]; break; + case PMPADDR12: *value = pmpaddr[12]; break; + case PMPADDR13: *value = pmpaddr[13]; break; + case PMPADDR14: *value = pmpaddr[14]; break; + case PMPADDR15: *value = pmpaddr[15]; break; + default: return true; break; } return false; @@ -591,6 +701,48 @@ public: case SSCRATCH: sscratch = value; break; case SATP: satp.raw = value; break; + case PMPCFG0: + if (!pmpcfg[0].reg[3].l) maskedWrite(pmpcfg[0].raw, value, 0xff); + if (!pmpcfg[0].reg[2].l) maskedWrite(pmpcfg[0].raw, value, 0xff00); + if (!pmpcfg[0].reg[1].l) maskedWrite(pmpcfg[0].raw, value, 0xff0000); + if (!pmpcfg[0].reg[0].l) maskedWrite(pmpcfg[0].raw, value, 0xff000000); + break; + case PMPCFG1: + if (!pmpcfg[1].reg[3].l) maskedWrite(pmpcfg[1].raw, value, 0xff); + if (!pmpcfg[1].reg[2].l) maskedWrite(pmpcfg[1].raw, value, 0xff00); + if (!pmpcfg[1].reg[1].l) maskedWrite(pmpcfg[1].raw, value, 0xff0000); + if (!pmpcfg[1].reg[0].l) maskedWrite(pmpcfg[1].raw, value, 0xff000000); + break; + case PMPCFG2: + if (!pmpcfg[2].reg[3].l) maskedWrite(pmpcfg[2].raw, value, 0xff); + if (!pmpcfg[2].reg[2].l) maskedWrite(pmpcfg[2].raw, value, 0xff00); + if (!pmpcfg[2].reg[1].l) maskedWrite(pmpcfg[2].raw, value, 0xff0000); + if (!pmpcfg[2].reg[0].l) maskedWrite(pmpcfg[2].raw, value, 0xff000000); + break; + case PMPCFG3: + if (!pmpcfg[3].reg[3].l) maskedWrite(pmpcfg[3].raw, value, 0xff); + if (!pmpcfg[3].reg[2].l) maskedWrite(pmpcfg[3].raw, value, 0xff00); + if (!pmpcfg[3].reg[1].l) maskedWrite(pmpcfg[3].raw, value, 0xff0000); + if (!pmpcfg[3].reg[0].l) maskedWrite(pmpcfg[3].raw, value, 0xff000000); + break; + + case PMPADDR0: pmpaddr[0] = value; break; + case PMPADDR1: pmpaddr[1] = value; break; + case PMPADDR2: pmpaddr[2] = value; break; + case PMPADDR3: pmpaddr[3] = value; break; + case PMPADDR4: pmpaddr[4] = value; break; + case PMPADDR5: pmpaddr[5] = value; break; + case PMPADDR6: pmpaddr[6] = value; break; + case PMPADDR7: pmpaddr[7] = value; break; + case PMPADDR8: pmpaddr[8] = value; break; + case PMPADDR9: pmpaddr[9] = value; break; + case PMPADDR10: pmpaddr[10] = value; break; + case PMPADDR11: pmpaddr[11] = value; break; + case PMPADDR12: pmpaddr[12] = value; break; + case PMPADDR13: pmpaddr[13] = value; break; + case PMPADDR14: pmpaddr[14] = value; break; + case PMPADDR15: pmpaddr[15] = value; break; + default: ilegalInstruction(); return true; break; } return false; From 987de8fb6a283a7a5d962d854eb7ab1201f7f22c Mon Sep 17 00:00:00 2001 From: Samuel Lindemer Date: Wed, 2 Dec 2020 14:18:17 +0100 Subject: [PATCH 514/951] Lock PMP address registers in golden model --- src/test/cpp/raw/pmp/build/pmp.asm | 153 ++++++++++++++--------------- src/test/cpp/raw/pmp/build/pmp.elf | Bin 5328 -> 5324 bytes src/test/cpp/raw/pmp/build/pmp.hex | 40 ++++---- src/test/cpp/raw/pmp/build/pmp.map | 12 +-- src/test/cpp/regression/main.cpp | 65 ++++++++---- 5 files changed, 150 insertions(+), 120 deletions(-) diff --git a/src/test/cpp/raw/pmp/build/pmp.asm b/src/test/cpp/raw/pmp/build/pmp.asm index 48395cf9..9d5dddf4 100644 --- a/src/test/cpp/raw/pmp/build/pmp.asm +++ b/src/test/cpp/raw/pmp/build/pmp.asm @@ -25,17 +25,17 @@ Disassembly of section .crt_section: 80000030 : 80000030: 00000e13 li t3,0 80000034: 00000f17 auipc t5,0x0 -80000038: 1f4f0f13 addi t5,t5,500 # 80000228 +80000038: 1f0f0f13 addi t5,t5,496 # 80000224 8000003c: 800000b7 lui ra,0x80000 80000040: 80008237 lui tp,0x80008 80000044: deadc137 lui sp,0xdeadc -80000048: eef10113 addi sp,sp,-273 # deadbeef -8000004c: 0020a023 sw sp,0(ra) # 80000000 -80000050: 00222023 sw sp,0(tp) # 80008000 +80000048: eef10113 addi sp,sp,-273 # deadbeef +8000004c: 0020a023 sw sp,0(ra) # 80000000 +80000050: 00222023 sw sp,0(tp) # 80008000 80000054: 0000a183 lw gp,0(ra) -80000058: 1c311863 bne sp,gp,80000228 +80000058: 1c311663 bne sp,gp,80000224 8000005c: 00022183 lw gp,0(tp) # 0 <_start-0x80000000> -80000060: 1c311463 bne sp,gp,80000228 +80000060: 1c311263 bne sp,gp,80000224 80000064: 071a12b7 lui t0,0x71a1 80000068: 80828293 addi t0,t0,-2040 # 71a0808 <_start-0x78e5f7f8> 8000006c: 3a029073 csrw pmpcfg0,t0 @@ -90,82 +90,81 @@ Disassembly of section .crt_section: 80000130: 0020a023 sw sp,0(ra) 80000134: 00222023 sw sp,0(tp) # 0 <_start-0x80000000> 80000138: 0000a183 lw gp,0(ra) -8000013c: 0e311663 bne sp,gp,80000228 +8000013c: 0e311463 bne sp,gp,80000224 80000140: 00022183 lw gp,0(tp) # 0 <_start-0x80000000> -80000144: 0e311263 bne sp,gp,80000228 -80000148: 06c0006f j 800001b4 +80000144: 0e311063 bne sp,gp,80000224 -8000014c : -8000014c: 00100e13 li t3,1 -80000150: 00000f17 auipc t5,0x0 -80000154: 0d8f0f13 addi t5,t5,216 # 80000228 -80000158: 079a12b7 lui t0,0x79a1 -8000015c: 80828293 addi t0,t0,-2040 # 79a0808 <_start-0x7865f7f8> -80000160: 3a029073 csrw pmpcfg0,t0 -80000164: deadc137 lui sp,0xdeadc -80000168: eef10113 addi sp,sp,-273 # deadbeef -8000016c: 00222023 sw sp,0(tp) # 0 <_start-0x80000000> -80000170: 00000f17 auipc t5,0x0 -80000174: 010f0f13 addi t5,t5,16 # 80000180 -80000178: 00022183 lw gp,0(tp) # 0 <_start-0x80000000> -8000017c: 0ac0006f j 80000228 +80000148 : +80000148: 00100e13 li t3,1 +8000014c: 00000f17 auipc t5,0x0 +80000150: 0d8f0f13 addi t5,t5,216 # 80000224 +80000154: 079a12b7 lui t0,0x79a1 +80000158: 80828293 addi t0,t0,-2040 # 79a0808 <_start-0x7865f7f8> +8000015c: 3a029073 csrw pmpcfg0,t0 +80000160: deadc137 lui sp,0xdeadc +80000164: eef10113 addi sp,sp,-273 # deadbeef +80000168: 00222023 sw sp,0(tp) # 0 <_start-0x80000000> +8000016c: 00000f17 auipc t5,0x0 +80000170: 010f0f13 addi t5,t5,16 # 8000017c +80000174: 00022183 lw gp,0(tp) # 0 <_start-0x80000000> +80000178: 0ac0006f j 80000224 -80000180 : -80000180: 00200e13 li t3,2 -80000184: 00000f17 auipc t5,0x0 -80000188: 0a4f0f13 addi t5,t5,164 # 80000228 -8000018c: 071a12b7 lui t0,0x71a1 -80000190: 80828293 addi t0,t0,-2040 # 71a0808 <_start-0x78e5f7f8> -80000194: 3a029073 csrw pmpcfg0,t0 -80000198: deadc137 lui sp,0xdeadc -8000019c: eef10113 addi sp,sp,-273 # deadbeef -800001a0: 00222023 sw sp,0(tp) # 0 <_start-0x80000000> -800001a4: 00000f17 auipc t5,0x0 -800001a8: 010f0f13 addi t5,t5,16 # 800001b4 -800001ac: 00022183 lw gp,0(tp) # 0 <_start-0x80000000> -800001b0: 0780006f j 80000228 +8000017c : +8000017c: 00200e13 li t3,2 +80000180: 00000f17 auipc t5,0x0 +80000184: 0a4f0f13 addi t5,t5,164 # 80000224 +80000188: 071a12b7 lui t0,0x71a1 +8000018c: 80828293 addi t0,t0,-2040 # 71a0808 <_start-0x78e5f7f8> +80000190: 3a029073 csrw pmpcfg0,t0 +80000194: deadc137 lui sp,0xdeadc +80000198: eef10113 addi sp,sp,-273 # deadbeef +8000019c: 00222023 sw sp,0(tp) # 0 <_start-0x80000000> +800001a0: 00000f17 auipc t5,0x0 +800001a4: 010f0f13 addi t5,t5,16 # 800001b0 +800001a8: 00022183 lw gp,0(tp) # 0 <_start-0x80000000> +800001ac: 0780006f j 80000224 -800001b4 : -800001b4: 00300e13 li t3,3 -800001b8: 00000f17 auipc t5,0x0 -800001bc: 070f0f13 addi t5,t5,112 # 80000228 -800001c0: 00000e97 auipc t4,0x0 -800001c4: 00ce8e93 addi t4,t4,12 # 800001cc -800001c8: e51ff06f j 80000018 +800001b0 : +800001b0: 00300e13 li t3,3 +800001b4: 00000f17 auipc t5,0x0 +800001b8: 070f0f13 addi t5,t5,112 # 80000224 +800001bc: 00000e97 auipc t4,0x0 +800001c0: 00ce8e93 addi t4,t4,12 # 800001c8 +800001c4: e55ff06f j 80000018 -800001cc : -800001cc: 00400e13 li t3,4 -800001d0: 00000f17 auipc t5,0x0 -800001d4: 058f0f13 addi t5,t5,88 # 80000228 -800001d8: deadc137 lui sp,0xdeadc -800001dc: eef10113 addi sp,sp,-273 # deadbeef -800001e0: 00222023 sw sp,0(tp) # 0 <_start-0x80000000> -800001e4: 00000f17 auipc t5,0x0 -800001e8: 010f0f13 addi t5,t5,16 # 800001f4 -800001ec: 00022183 lw gp,0(tp) # 0 <_start-0x80000000> -800001f0: 0380006f j 80000228 +800001c8 : +800001c8: 00400e13 li t3,4 +800001cc: 00000f17 auipc t5,0x0 +800001d0: 058f0f13 addi t5,t5,88 # 80000224 +800001d4: deadc137 lui sp,0xdeadc +800001d8: eef10113 addi sp,sp,-273 # deadbeef +800001dc: 00222023 sw sp,0(tp) # 0 <_start-0x80000000> +800001e0: 00000f17 auipc t5,0x0 +800001e4: 010f0f13 addi t5,t5,16 # 800001f0 +800001e8: 00022183 lw gp,0(tp) # 0 <_start-0x80000000> +800001ec: 0380006f j 80000224 -800001f4 : -800001f4: 00500e13 li t3,5 -800001f8: 00000f17 auipc t5,0x0 -800001fc: 03cf0f13 addi t5,t5,60 # 80000234 -80000200: 80010237 lui tp,0x80010 -80000204: deadc137 lui sp,0xdeadc -80000208: eef10113 addi sp,sp,-273 # deadbeef -8000020c: 0020a023 sw sp,0(ra) -80000210: 0000a183 lw gp,0(ra) -80000214: 00311a63 bne sp,gp,80000228 -80000218: 00022183 lw gp,0(tp) # 80010000 -8000021c: 00000f17 auipc t5,0x0 -80000220: 018f0f13 addi t5,t5,24 # 80000234 -80000224: 00322023 sw gp,0(tp) # 0 <_start-0x80000000> +800001f0 : +800001f0: 00500e13 li t3,5 +800001f4: 00000f17 auipc t5,0x0 +800001f8: 03cf0f13 addi t5,t5,60 # 80000230 +800001fc: 80010237 lui tp,0x80010 +80000200: deadc137 lui sp,0xdeadc +80000204: eef10113 addi sp,sp,-273 # deadbeef +80000208: 0020a023 sw sp,0(ra) +8000020c: 0000a183 lw gp,0(ra) +80000210: 00311a63 bne sp,gp,80000224 +80000214: 00022183 lw gp,0(tp) # 80010000 +80000218: 00000f17 auipc t5,0x0 +8000021c: 018f0f13 addi t5,t5,24 # 80000230 +80000220: 00322023 sw gp,0(tp) # 0 <_start-0x80000000> -80000228 : -80000228: f0100137 lui sp,0xf0100 -8000022c: f2410113 addi sp,sp,-220 # f00fff24 -80000230: 01c12023 sw t3,0(sp) +80000224 : +80000224: f0100137 lui sp,0xf0100 +80000228: f2410113 addi sp,sp,-220 # f00fff24 +8000022c: 01c12023 sw t3,0(sp) -80000234 : -80000234: f0100137 lui sp,0xf0100 -80000238: f2010113 addi sp,sp,-224 # f00fff20 -8000023c: 00012023 sw zero,0(sp) +80000230 : +80000230: f0100137 lui sp,0xf0100 +80000234: f2010113 addi sp,sp,-224 # f00fff20 +80000238: 00012023 sw zero,0(sp) diff --git a/src/test/cpp/raw/pmp/build/pmp.elf b/src/test/cpp/raw/pmp/build/pmp.elf index 9b21344a11a56286768e95efa12760ea87cc49c6..381eec7caefa49f471aad8f6fa86a7636b6069c3 100755 GIT binary patch delta 232 zcmcbhc}8=B0^^;Dips1uObiS*8$CbrGxATi7Lel Date: Thu, 3 Dec 2020 16:21:52 +0100 Subject: [PATCH 515/951] CfuPlugin improve writeback buffering --- src/main/scala/vexriscv/plugin/CfuPlugin.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/plugin/CfuPlugin.scala b/src/main/scala/vexriscv/plugin/CfuPlugin.scala index 827aba17..6b82e7f6 100644 --- a/src/main/scala/vexriscv/plugin/CfuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CfuPlugin.scala @@ -208,7 +208,7 @@ class CfuPlugin( val stageCount : Int, latency = 0 ) } else if(forkStage != joinStage && allowZeroLatency) { - bus.rsp.m2sPipe() + bus.rsp.s2mPipe() } else { bus.rsp.combStage() } From 5cb5061d9b4d79a6242f4433af5f69c0161fc133 Mon Sep 17 00:00:00 2001 From: Samuel Lindemer Date: Thu, 3 Dec 2020 17:29:31 +0100 Subject: [PATCH 516/951] PMP passes test with GenZephyr, but pipeline flushes have been disabled --- src/main/scala/vexriscv/demo/GenZephyr.scala | 3 +- .../scala/vexriscv/plugin/PmpPlugin.scala | 8 +- src/test/cpp/raw/pmp/.gdbinit | 3 + src/test/cpp/raw/pmp/build/pmp.asm | 270 +++++++++--------- src/test/cpp/raw/pmp/build/pmp.elf | Bin 5324 -> 5304 bytes src/test/cpp/raw/pmp/build/pmp.hex | 71 +++-- src/test/cpp/raw/pmp/build/pmp.map | 13 +- src/test/cpp/raw/pmp/src/crt.S | 31 +- src/test/cpp/regression/main.cpp | 2 +- 9 files changed, 197 insertions(+), 204 deletions(-) create mode 100644 src/test/cpp/raw/pmp/.gdbinit diff --git a/src/main/scala/vexriscv/demo/GenZephyr.scala b/src/main/scala/vexriscv/demo/GenZephyr.scala index b9d0c7a7..4666ec4f 100644 --- a/src/main/scala/vexriscv/demo/GenZephyr.scala +++ b/src/main/scala/vexriscv/demo/GenZephyr.scala @@ -5,11 +5,12 @@ import vexriscv.ip.{DataCacheConfig, InstructionCacheConfig} import vexriscv.{plugin, VexRiscv, VexRiscvConfig} import spinal.core._ -object GenZephyr extends App{ +object GenZephyr extends App { def cpu() = new VexRiscv( config = VexRiscvConfig( plugins = List( new IBusCachedPlugin( + resetVector = 0x80000000l, prediction = STATIC, config = InstructionCacheConfig( cacheSize = 4096, diff --git a/src/main/scala/vexriscv/plugin/PmpPlugin.scala b/src/main/scala/vexriscv/plugin/PmpPlugin.scala index 96599e06..2d727fdc 100644 --- a/src/main/scala/vexriscv/plugin/PmpPlugin.scala +++ b/src/main/scala/vexriscv/plugin/PmpPlugin.scala @@ -153,8 +153,8 @@ class PmpPlugin(regions : Int, ioRange : UInt => Bool) extends Plugin[VexRiscv] pmps += PmpRegister() csrService.rw(0x3b0 + i, pmps(i).csr.addr) csrService.onWrite(0x3b0 + i) { - execute.arbitration.flushNext := True - redoInterface.valid := True + //execute.arbitration.flushNext := True + //redoInterface.valid := True } } @@ -173,8 +173,8 @@ class PmpPlugin(regions : Int, ioRange : UInt => Bool) extends Plugin[VexRiscv] 1 -> pmps((i * 4) ).csr.w, 0 -> pmps((i * 4) ).csr.r ) csrService.onWrite(0x3a0 + i) { - execute.arbitration.flushNext := True - redoInterface.valid := True + //execute.arbitration.flushNext := True + //redoInterface.valid := True } } diff --git a/src/test/cpp/raw/pmp/.gdbinit b/src/test/cpp/raw/pmp/.gdbinit new file mode 100644 index 00000000..45fceb2d --- /dev/null +++ b/src/test/cpp/raw/pmp/.gdbinit @@ -0,0 +1,3 @@ +target remote localhost:3333 +monitor reset halt +load diff --git a/src/test/cpp/raw/pmp/build/pmp.asm b/src/test/cpp/raw/pmp/build/pmp.asm index 9d5dddf4..d625d876 100644 --- a/src/test/cpp/raw/pmp/build/pmp.asm +++ b/src/test/cpp/raw/pmp/build/pmp.asm @@ -8,163 +8,159 @@ Disassembly of section .crt_section: 80000000: 00000097 auipc ra,0x0 80000004: 01008093 addi ra,ra,16 # 80000010 80000008: 30509073 csrw mtvec,ra -8000000c: 0240006f j 80000030 +8000000c: 00c0006f j 80000018 80000010 : 80000010: 341f1073 csrw mepc,t5 80000014: 30200073 mret -80000018 : -80000018: 00014137 lui sp,0x14 -8000001c: 30013073 csrc mstatus,sp -80000020: 20000113 li sp,512 -80000024: 30012073 csrs mstatus,sp -80000028: 341e9073 csrw mepc,t4 -8000002c: 30200073 mret - -80000030 : -80000030: 00000e13 li t3,0 -80000034: 00000f17 auipc t5,0x0 -80000038: 1f0f0f13 addi t5,t5,496 # 80000224 -8000003c: 800000b7 lui ra,0x80000 -80000040: 80008237 lui tp,0x80008 -80000044: deadc137 lui sp,0xdeadc -80000048: eef10113 addi sp,sp,-273 # deadbeef -8000004c: 0020a023 sw sp,0(ra) # 80000000 -80000050: 00222023 sw sp,0(tp) # 80008000 -80000054: 0000a183 lw gp,0(ra) -80000058: 1c311663 bne sp,gp,80000224 -8000005c: 00022183 lw gp,0(tp) # 0 <_start-0x80000000> -80000060: 1c311263 bne sp,gp,80000224 -80000064: 071a12b7 lui t0,0x71a1 -80000068: 80828293 addi t0,t0,-2040 # 71a0808 <_start-0x78e5f7f8> -8000006c: 3a029073 csrw pmpcfg0,t0 -80000070: 191c02b7 lui t0,0x191c0 -80000074: 50428293 addi t0,t0,1284 # 191c0504 <_start-0x66e3fafc> -80000078: 3a129073 csrw pmpcfg1,t0 -8000007c: 01800293 li t0,24 -80000080: 3a229073 csrw pmpcfg2,t0 -80000084: 0f1e22b7 lui t0,0xf1e2 -80000088: 90028293 addi t0,t0,-1792 # f1e1900 <_start-0x70e1e700> -8000008c: 3a329073 csrw pmpcfg3,t0 -80000090: 200002b7 lui t0,0x20000 -80000094: 3b029073 csrw pmpaddr0,t0 -80000098: fff00293 li t0,-1 -8000009c: 3b129073 csrw pmpaddr1,t0 -800000a0: 200022b7 lui t0,0x20002 -800000a4: 3b229073 csrw pmpaddr2,t0 +80000018 : +80000018: 00000e13 li t3,0 +8000001c: 00000f17 auipc t5,0x0 +80000020: 1f4f0f13 addi t5,t5,500 # 80000210 +80000024: 800000b7 lui ra,0x80000 +80000028: 80008237 lui tp,0x80008 +8000002c: deadc137 lui sp,0xdeadc +80000030: eef10113 addi sp,sp,-273 # deadbeef +80000034: 0020a023 sw sp,0(ra) # 80000000 +80000038: 00222023 sw sp,0(tp) # 80008000 +8000003c: 0000a183 lw gp,0(ra) +80000040: 1c311863 bne sp,gp,80000210 +80000044: 00022183 lw gp,0(tp) # 0 <_start-0x80000000> +80000048: 1c311463 bne sp,gp,80000210 +8000004c: 071212b7 lui t0,0x7121 +80000050: 80828293 addi t0,t0,-2040 # 7120808 <_start-0x78edf7f8> +80000054: 3a029073 csrw pmpcfg0,t0 +80000058: 191f02b7 lui t0,0x191f0 +8000005c: 30428293 addi t0,t0,772 # 191f0304 <_start-0x66e0fcfc> +80000060: 3a129073 csrw pmpcfg1,t0 +80000064: 01800293 li t0,24 +80000068: 3a229073 csrw pmpcfg2,t0 +8000006c: 0f1e22b7 lui t0,0xf1e2 +80000070: 90028293 addi t0,t0,-1792 # f1e1900 <_start-0x70e1e700> +80000074: 3a329073 csrw pmpcfg3,t0 +80000078: 200002b7 lui t0,0x20000 +8000007c: 3b029073 csrw pmpaddr0,t0 +80000080: fff00293 li t0,-1 +80000084: 3b129073 csrw pmpaddr1,t0 +80000088: 200022b7 lui t0,0x20002 +8000008c: 3b229073 csrw pmpaddr2,t0 +80000090: 200042b7 lui t0,0x20004 +80000094: fff28293 addi t0,t0,-1 # 20003fff <_start-0x5fffc001> +80000098: 3b329073 csrw pmpaddr3,t0 +8000009c: 200042b7 lui t0,0x20004 +800000a0: fff28293 addi t0,t0,-1 # 20003fff <_start-0x5fffc001> +800000a4: 3b429073 csrw pmpaddr4,t0 800000a8: 200042b7 lui t0,0x20004 800000ac: fff28293 addi t0,t0,-1 # 20003fff <_start-0x5fffc001> -800000b0: 3b329073 csrw pmpaddr3,t0 -800000b4: 200042b7 lui t0,0x20004 -800000b8: fff28293 addi t0,t0,-1 # 20003fff <_start-0x5fffc001> -800000bc: 3b429073 csrw pmpaddr4,t0 +800000b0: 3b529073 csrw pmpaddr5,t0 +800000b4: 200022b7 lui t0,0x20002 +800000b8: fff28293 addi t0,t0,-1 # 20001fff <_start-0x5fffe001> +800000bc: 3b629073 csrw pmpaddr6,t0 800000c0: 200042b7 lui t0,0x20004 800000c4: fff28293 addi t0,t0,-1 # 20003fff <_start-0x5fffc001> -800000c8: 3b529073 csrw pmpaddr5,t0 -800000cc: 200022b7 lui t0,0x20002 -800000d0: fff28293 addi t0,t0,-1 # 20001fff <_start-0x5fffe001> -800000d4: 3b629073 csrw pmpaddr6,t0 -800000d8: 200042b7 lui t0,0x20004 -800000dc: fff28293 addi t0,t0,-1 # 20003fff <_start-0x5fffc001> -800000e0: 3b729073 csrw pmpaddr7,t0 -800000e4: 200042b7 lui t0,0x20004 -800000e8: fff28293 addi t0,t0,-1 # 20003fff <_start-0x5fffc001> -800000ec: 3b829073 csrw pmpaddr8,t0 +800000c8: 3b729073 csrw pmpaddr7,t0 +800000cc: 200042b7 lui t0,0x20004 +800000d0: fff28293 addi t0,t0,-1 # 20003fff <_start-0x5fffc001> +800000d4: 3b829073 csrw pmpaddr8,t0 +800000d8: 00000293 li t0,0 +800000dc: 3b929073 csrw pmpaddr9,t0 +800000e0: 00000293 li t0,0 +800000e4: 3ba29073 csrw pmpaddr10,t0 +800000e8: 00000293 li t0,0 +800000ec: 3bb29073 csrw pmpaddr11,t0 800000f0: 00000293 li t0,0 -800000f4: 3b929073 csrw pmpaddr9,t0 +800000f4: 3bc29073 csrw pmpaddr12,t0 800000f8: 00000293 li t0,0 -800000fc: 3ba29073 csrw pmpaddr10,t0 +800000fc: 3bd29073 csrw pmpaddr13,t0 80000100: 00000293 li t0,0 -80000104: 3bb29073 csrw pmpaddr11,t0 +80000104: 3be29073 csrw pmpaddr14,t0 80000108: 00000293 li t0,0 -8000010c: 3bc29073 csrw pmpaddr12,t0 -80000110: 00000293 li t0,0 -80000114: 3bd29073 csrw pmpaddr13,t0 -80000118: 00000293 li t0,0 -8000011c: 3be29073 csrw pmpaddr14,t0 -80000120: 00000293 li t0,0 -80000124: 3bf29073 csrw pmpaddr15,t0 -80000128: 00c10137 lui sp,0xc10 -8000012c: fee10113 addi sp,sp,-18 # c0ffee <_start-0x7f3f0012> -80000130: 0020a023 sw sp,0(ra) -80000134: 00222023 sw sp,0(tp) # 0 <_start-0x80000000> -80000138: 0000a183 lw gp,0(ra) -8000013c: 0e311463 bne sp,gp,80000224 -80000140: 00022183 lw gp,0(tp) # 0 <_start-0x80000000> -80000144: 0e311063 bne sp,gp,80000224 +8000010c: 3bf29073 csrw pmpaddr15,t0 +80000110: 00c10137 lui sp,0xc10 +80000114: fee10113 addi sp,sp,-18 # c0ffee <_start-0x7f3f0012> +80000118: 0020a023 sw sp,0(ra) +8000011c: 00222023 sw sp,0(tp) # 0 <_start-0x80000000> +80000120: 0000a183 lw gp,0(ra) +80000124: 0e311663 bne sp,gp,80000210 +80000128: 00000193 li gp,0 +8000012c: 00022183 lw gp,0(tp) # 0 <_start-0x80000000> +80000130: 0e311063 bne sp,gp,80000210 -80000148 : -80000148: 00100e13 li t3,1 -8000014c: 00000f17 auipc t5,0x0 -80000150: 0d8f0f13 addi t5,t5,216 # 80000224 -80000154: 079a12b7 lui t0,0x79a1 -80000158: 80828293 addi t0,t0,-2040 # 79a0808 <_start-0x7865f7f8> -8000015c: 3a029073 csrw pmpcfg0,t0 -80000160: deadc137 lui sp,0xdeadc -80000164: eef10113 addi sp,sp,-273 # deadbeef -80000168: 00222023 sw sp,0(tp) # 0 <_start-0x80000000> +80000134 : +80000134: 00100e13 li t3,1 +80000138: 00000f17 auipc t5,0x0 +8000013c: 0d8f0f13 addi t5,t5,216 # 80000210 +80000140: 079212b7 lui t0,0x7921 +80000144: 80828293 addi t0,t0,-2040 # 7920808 <_start-0x786df7f8> +80000148: 3a029073 csrw pmpcfg0,t0 +8000014c: deadc137 lui sp,0xdeadc +80000150: eef10113 addi sp,sp,-273 # deadbeef +80000154: 00222023 sw sp,0(tp) # 0 <_start-0x80000000> +80000158: 00000f17 auipc t5,0x0 +8000015c: 010f0f13 addi t5,t5,16 # 80000168 +80000160: 00022183 lw gp,0(tp) # 0 <_start-0x80000000> +80000164: 0ac0006f j 80000210 + +80000168 : +80000168: 00200e13 li t3,2 8000016c: 00000f17 auipc t5,0x0 -80000170: 010f0f13 addi t5,t5,16 # 8000017c -80000174: 00022183 lw gp,0(tp) # 0 <_start-0x80000000> -80000178: 0ac0006f j 80000224 +80000170: 0a4f0f13 addi t5,t5,164 # 80000210 +80000174: 071212b7 lui t0,0x7121 +80000178: 80828293 addi t0,t0,-2040 # 7120808 <_start-0x78edf7f8> +8000017c: 3a029073 csrw pmpcfg0,t0 +80000180: deadc137 lui sp,0xdeadc +80000184: eef10113 addi sp,sp,-273 # deadbeef +80000188: 00222023 sw sp,0(tp) # 0 <_start-0x80000000> +8000018c: 00000f17 auipc t5,0x0 +80000190: 010f0f13 addi t5,t5,16 # 8000019c +80000194: 00022183 lw gp,0(tp) # 0 <_start-0x80000000> +80000198: 0780006f j 80000210 -8000017c : -8000017c: 00200e13 li t3,2 -80000180: 00000f17 auipc t5,0x0 -80000184: 0a4f0f13 addi t5,t5,164 # 80000224 -80000188: 071a12b7 lui t0,0x71a1 -8000018c: 80828293 addi t0,t0,-2040 # 71a0808 <_start-0x78e5f7f8> -80000190: 3a029073 csrw pmpcfg0,t0 -80000194: deadc137 lui sp,0xdeadc -80000198: eef10113 addi sp,sp,-273 # deadbeef -8000019c: 00222023 sw sp,0(tp) # 0 <_start-0x80000000> +8000019c : +8000019c: 00300e13 li t3,3 800001a0: 00000f17 auipc t5,0x0 -800001a4: 010f0f13 addi t5,t5,16 # 800001b0 -800001a8: 00022183 lw gp,0(tp) # 0 <_start-0x80000000> -800001ac: 0780006f j 80000224 +800001a4: 070f0f13 addi t5,t5,112 # 80000210 +800001a8: 00000117 auipc sp,0x0 +800001ac: 01010113 addi sp,sp,16 # 800001b8 +800001b0: 34111073 csrw mepc,sp +800001b4: 30200073 mret -800001b0 : -800001b0: 00300e13 li t3,3 -800001b4: 00000f17 auipc t5,0x0 -800001b8: 070f0f13 addi t5,t5,112 # 80000224 -800001bc: 00000e97 auipc t4,0x0 -800001c0: 00ce8e93 addi t4,t4,12 # 800001c8 -800001c4: e55ff06f j 80000018 +800001b8 : +800001b8: 00400e13 li t3,4 +800001bc: 00000f17 auipc t5,0x0 +800001c0: 054f0f13 addi t5,t5,84 # 80000210 +800001c4: deadc137 lui sp,0xdeadc +800001c8: eef10113 addi sp,sp,-273 # deadbeef +800001cc: 00222023 sw sp,0(tp) # 0 <_start-0x80000000> +800001d0: 00000f17 auipc t5,0x0 +800001d4: 010f0f13 addi t5,t5,16 # 800001e0 +800001d8: 00022183 lw gp,0(tp) # 0 <_start-0x80000000> +800001dc: 0340006f j 80000210 -800001c8 : -800001c8: 00400e13 li t3,4 -800001cc: 00000f17 auipc t5,0x0 -800001d0: 058f0f13 addi t5,t5,88 # 80000224 -800001d4: deadc137 lui sp,0xdeadc -800001d8: eef10113 addi sp,sp,-273 # deadbeef -800001dc: 00222023 sw sp,0(tp) # 0 <_start-0x80000000> -800001e0: 00000f17 auipc t5,0x0 -800001e4: 010f0f13 addi t5,t5,16 # 800001f0 -800001e8: 00022183 lw gp,0(tp) # 0 <_start-0x80000000> -800001ec: 0380006f j 80000224 +800001e0 : +800001e0: 00500e13 li t3,5 +800001e4: deadc137 lui sp,0xdeadc +800001e8: eef10113 addi sp,sp,-273 # deadbeef +800001ec: 0020a023 sw sp,0(ra) +800001f0: 0000a183 lw gp,0(ra) +800001f4: 00311e63 bne sp,gp,80000210 -800001f0 : -800001f0: 00500e13 li t3,5 -800001f4: 00000f17 auipc t5,0x0 -800001f8: 03cf0f13 addi t5,t5,60 # 80000230 +800001f8 : +800001f8: 00600e13 li t3,6 800001fc: 80010237 lui tp,0x80010 -80000200: deadc137 lui sp,0xdeadc -80000204: eef10113 addi sp,sp,-273 # deadbeef -80000208: 0020a023 sw sp,0(ra) -8000020c: 0000a183 lw gp,0(ra) -80000210: 00311a63 bne sp,gp,80000224 -80000214: 00022183 lw gp,0(tp) # 80010000 -80000218: 00000f17 auipc t5,0x0 -8000021c: 018f0f13 addi t5,t5,24 # 80000230 -80000220: 00322023 sw gp,0(tp) # 0 <_start-0x80000000> +80000200: 00022183 lw gp,0(tp) # 80010000 +80000204: 00000f17 auipc t5,0x0 +80000208: 018f0f13 addi t5,t5,24 # 8000021c +8000020c: 00322023 sw gp,0(tp) # 0 <_start-0x80000000> -80000224 : -80000224: f0100137 lui sp,0xf0100 -80000228: f2410113 addi sp,sp,-220 # f00fff24 -8000022c: 01c12023 sw t3,0(sp) +80000210 : +80000210: f0100137 lui sp,0xf0100 +80000214: f2410113 addi sp,sp,-220 # f00fff24 +80000218: 01c12023 sw t3,0(sp) -80000230 : -80000230: f0100137 lui sp,0xf0100 -80000234: f2010113 addi sp,sp,-224 # f00fff20 -80000238: 00012023 sw zero,0(sp) +8000021c : +8000021c: 29a00e13 li t3,666 +80000220: f0100137 lui sp,0xf0100 +80000224: f2010113 addi sp,sp,-224 # f00fff20 +80000228: 00012023 sw zero,0(sp) diff --git a/src/test/cpp/raw/pmp/build/pmp.elf b/src/test/cpp/raw/pmp/build/pmp.elf index 381eec7caefa49f471aad8f6fa86a7636b6069c3..e5e89ac443042316240eb8b5347ecdc155167933 100755 GIT binary patch delta 447 zcmYk$%}N4M6bJDCnG_*#oS8fMQG<@nq67&iB*79?XdwvI8yFI_G^RzgNpu;JdbTa> z0a~=uWiEskJwx;aVXazr?E~k)J@@>$_nvcKGUH6orssaz31$@_`&gSsR-WK#sk{d} zCsZI70Yv10ceP|H?pocnf~M(OBf|)Br_=U&N^zv565Ofg_(Ge8qOQsWa9NMifUk9j zFLjL!S-DnB9ta}xH2trC`M-aV8~SRsyd=~^6ebU^fRy6<0l9)xogV8mUNyLUY9=gc~kn%=Pl{6&w1%L zpNrC8K9_+cEZ@L=c|k^do-`2ZToSeA^AqoU2d!hz#z%(h#3Dc3eWNw7(1~8Kk Z0&<1<%v=lZ3E+tPrW3r8Rgo*E_y#*BOd0?H delta 477 zcmY+8F-yZx5XbMO2A4KT^FmwG(58)|9h3wLg;KD(XhEdls#GaDxLACOi(*K3t-e8U z(S86yr?@&497Ml>xVe`44ZMa*U#rNV0(edY`ZtyC< zc!z^QloadHex(string(REGRESSION_PATH) + "../raw/pmp/build/pmp.hex")->bootAt(0x00000000u)->run(10e3);); + redo(REDO,WorkspaceRegression("pmp").loadHex(string(REGRESSION_PATH) + "../raw/pmp/build/pmp.hex")->bootAt(0x00000000u)->run(10e3);); #endif #ifdef AMO From 763eebeeba75d508351e81e77e48b675bdfe6c18 Mon Sep 17 00:00:00 2001 From: Samuel Lindemer Date: Fri, 4 Dec 2020 10:11:49 +0100 Subject: [PATCH 517/951] Add TOR support, tests pass on GenZephyr --- .../scala/vexriscv/plugin/PmpPlugin.scala | 71 +++--- src/test/cpp/raw/pmp/build/pmp.asm | 208 ++++++++++-------- src/test/cpp/raw/pmp/build/pmp.elf | Bin 5304 -> 5436 bytes src/test/cpp/raw/pmp/build/pmp.hex | 58 ++--- src/test/cpp/raw/pmp/build/pmp.map | 12 +- src/test/cpp/raw/pmp/src/crt.S | 62 ++++-- src/test/cpp/regression/main.cpp | 165 +------------- .../vexriscv/TestIndividualFeatures.scala | 4 +- 8 files changed, 237 insertions(+), 343 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/PmpPlugin.scala b/src/main/scala/vexriscv/plugin/PmpPlugin.scala index 2d727fdc..f232ee49 100644 --- a/src/main/scala/vexriscv/plugin/PmpPlugin.scala +++ b/src/main/scala/vexriscv/plugin/PmpPlugin.scala @@ -63,9 +63,9 @@ import scala.collection.mutable.ArrayBuffer * register defines a 4-byte wide region. */ -case class PmpRegister() extends Area { +case class PmpRegister(previous : PmpRegister) extends Area { - // Addressing options (TOR not supported) + def OFF = 0 def TOR = 1 def NA4 = 2 def NAPOT = 3 @@ -81,37 +81,52 @@ case class PmpRegister() extends Area { // Active region bounds and permissions (internal) val region = new Area { val r, w, x = Reg(Bool) - val lock, valid = RegInit(False) + val l, valid = RegInit(False) val start, end = Reg(UInt(32 bits)) } - // Internal PMP state is locked until reset once the L-bit is set. - when(~region.lock) { - region.r := csr.r - region.w := csr.w - region.x := csr.x - region.lock := csr.l + when(~region.l) { + region.r := csr.r + region.w := csr.w + region.x := csr.x + region.l := csr.l + + val shifted = csr.addr |<< 2 + region.valid := True switch(csr.a) { + + is(TOR) { + if (previous == null) { + region.start := 0 + } else { + region.start := previous.region.end + } + if (csr.l == True) { + previous.region.l := True + } + region.end := shifted + } + is(NA4) { - val shifted = csr.addr |<< 2 region.start := shifted region.end := shifted + 4 - region.valid := True } + is(NAPOT) { val mask = csr.addr & ~(csr.addr + 1) - val shifted = (csr.addr & ~mask) |<< 2 - region.start := shifted - region.end := shifted + ((mask + 1) |<< 3) - region.valid := True + val masked = (csr.addr & ~mask) |<< 2 + region.start := masked + region.end := masked + ((mask + 1) |<< 3) } + default { + region.end := shifted region.valid := False } + } } - } case class ProtectedMemoryTranslatorPort(bus : MemoryTranslatorBus) @@ -123,7 +138,6 @@ class PmpPlugin(regions : Int, ioRange : UInt => Bool) extends Plugin[VexRiscv] val pmps = ArrayBuffer[PmpRegister]() val portsInfo = ArrayBuffer[ProtectedMemoryTranslatorPort]() - var redoInterface : Flow[UInt] = null override def newTranslationPort(priority : Int, args : Any): MemoryTranslatorBus = { val port = ProtectedMemoryTranslatorPort(MemoryTranslatorBus()) @@ -138,24 +152,17 @@ class PmpPlugin(regions : Int, ioRange : UInt => Bool) extends Plugin[VexRiscv] val csrService = pipeline.service(classOf[CsrInterface]) val privilegeService = pipeline.service(classOf[PrivilegeService]) - var pcManagerService = pipeline.service(classOf[JumpService]) - - redoInterface = pcManagerService.createJumpInterface(pipeline.execute, -1) val core = pipeline plug new Area { - // Flush proceeding instructions and replay them after any CSR write. - redoInterface.payload := decode.input(PC) - redoInterface.valid := False - // Instantiate pmpaddr0 ... pmpaddr# CSRs. for (i <- 0 until regions) { - pmps += PmpRegister() - csrService.rw(0x3b0 + i, pmps(i).csr.addr) - csrService.onWrite(0x3b0 + i) { - //execute.arbitration.flushNext := True - //redoInterface.valid := True + if (i == 0) { + pmps += PmpRegister(null) + } else { + pmps += PmpRegister(pmps.last) } + csrService.rw(0x3b0 + i, pmps(i).csr.addr) } // Instantiate pmpcfg0 ... pmpcfg# CSRs. @@ -172,10 +179,6 @@ class PmpPlugin(regions : Int, ioRange : UInt => Bool) extends Plugin[VexRiscv] 3 -> pmps((i * 4) ).csr.a, 2 -> pmps((i * 4) ).csr.x, 1 -> pmps((i * 4) ).csr.w, 0 -> pmps((i * 4) ).csr.r ) - csrService.onWrite(0x3a0 + i) { - //execute.arbitration.flushNext := True - //redoInterface.valid := True - } } // Connect memory ports to PMP logic. @@ -188,7 +191,7 @@ class PmpPlugin(regions : Int, ioRange : UInt => Bool) extends Plugin[VexRiscv] val hits = pmps.map(pmp => pmp.region.valid && pmp.region.start <= address && pmp.region.end > address && - (pmp.region.lock || ~privilegeService.isMachine())) + (pmp.region.l || ~privilegeService.isMachine())) // M-mode has full access by default, others have none. when(CountOne(hits) === 0) { diff --git a/src/test/cpp/raw/pmp/build/pmp.asm b/src/test/cpp/raw/pmp/build/pmp.asm index d625d876..294e964c 100644 --- a/src/test/cpp/raw/pmp/build/pmp.asm +++ b/src/test/cpp/raw/pmp/build/pmp.asm @@ -17,24 +17,24 @@ Disassembly of section .crt_section: 80000018 : 80000018: 00000e13 li t3,0 8000001c: 00000f17 auipc t5,0x0 -80000020: 1f4f0f13 addi t5,t5,500 # 80000210 +80000020: 250f0f13 addi t5,t5,592 # 8000026c 80000024: 800000b7 lui ra,0x80000 80000028: 80008237 lui tp,0x80008 8000002c: deadc137 lui sp,0xdeadc -80000030: eef10113 addi sp,sp,-273 # deadbeef -80000034: 0020a023 sw sp,0(ra) # 80000000 -80000038: 00222023 sw sp,0(tp) # 80008000 +80000030: eef10113 addi sp,sp,-273 # deadbeef +80000034: 0020a023 sw sp,0(ra) # 80000000 +80000038: 00222023 sw sp,0(tp) # 80008000 8000003c: 0000a183 lw gp,0(ra) -80000040: 1c311863 bne sp,gp,80000210 +80000040: 22311663 bne sp,gp,8000026c 80000044: 00022183 lw gp,0(tp) # 0 <_start-0x80000000> -80000048: 1c311463 bne sp,gp,80000210 -8000004c: 071212b7 lui t0,0x7121 -80000050: 80828293 addi t0,t0,-2040 # 7120808 <_start-0x78edf7f8> -80000054: 3a029073 csrw pmpcfg0,t0 -80000058: 191f02b7 lui t0,0x191f0 -8000005c: 30428293 addi t0,t0,772 # 191f0304 <_start-0x66e0fcfc> -80000060: 3a129073 csrw pmpcfg1,t0 -80000064: 01800293 li t0,24 +80000048: 22311263 bne sp,gp,8000026c +8000004c: 071202b7 lui t0,0x7120 +80000050: 3a029073 csrw pmpcfg0,t0 +80000054: 191f02b7 lui t0,0x191f0 +80000058: 30428293 addi t0,t0,772 # 191f0304 <_start-0x66e0fcfc> +8000005c: 3a129073 csrw pmpcfg1,t0 +80000060: 000f02b7 lui t0,0xf0 +80000064: 50628293 addi t0,t0,1286 # f0506 <_start-0x7ff0fafa> 80000068: 3a229073 csrw pmpcfg2,t0 8000006c: 0f1e22b7 lui t0,0xf1e2 80000070: 90028293 addi t0,t0,-1792 # f1e1900 <_start-0x70e1e700> @@ -57,70 +57,70 @@ Disassembly of section .crt_section: 800000b4: 200022b7 lui t0,0x20002 800000b8: fff28293 addi t0,t0,-1 # 20001fff <_start-0x5fffe001> 800000bc: 3b629073 csrw pmpaddr6,t0 -800000c0: 200042b7 lui t0,0x20004 -800000c4: fff28293 addi t0,t0,-1 # 20003fff <_start-0x5fffc001> +800000c0: 200062b7 lui t0,0x20006 +800000c4: fff28293 addi t0,t0,-1 # 20005fff <_start-0x5fffa001> 800000c8: 3b729073 csrw pmpaddr7,t0 -800000cc: 200042b7 lui t0,0x20004 -800000d0: fff28293 addi t0,t0,-1 # 20003fff <_start-0x5fffc001> -800000d4: 3b829073 csrw pmpaddr8,t0 -800000d8: 00000293 li t0,0 -800000dc: 3b929073 csrw pmpaddr9,t0 -800000e0: 00000293 li t0,0 -800000e4: 3ba29073 csrw pmpaddr10,t0 -800000e8: 00000293 li t0,0 -800000ec: 3bb29073 csrw pmpaddr11,t0 -800000f0: 00000293 li t0,0 -800000f4: 3bc29073 csrw pmpaddr12,t0 -800000f8: 00000293 li t0,0 -800000fc: 3bd29073 csrw pmpaddr13,t0 -80000100: 00000293 li t0,0 -80000104: 3be29073 csrw pmpaddr14,t0 -80000108: 00000293 li t0,0 -8000010c: 3bf29073 csrw pmpaddr15,t0 -80000110: 00c10137 lui sp,0xc10 -80000114: fee10113 addi sp,sp,-18 # c0ffee <_start-0x7f3f0012> -80000118: 0020a023 sw sp,0(ra) -8000011c: 00222023 sw sp,0(tp) # 0 <_start-0x80000000> -80000120: 0000a183 lw gp,0(ra) -80000124: 0e311663 bne sp,gp,80000210 -80000128: 00000193 li gp,0 -8000012c: 00022183 lw gp,0(tp) # 0 <_start-0x80000000> -80000130: 0e311063 bne sp,gp,80000210 +800000cc: 2000c2b7 lui t0,0x2000c +800000d0: 3b829073 csrw pmpaddr8,t0 +800000d4: 2000d2b7 lui t0,0x2000d +800000d8: 3b929073 csrw pmpaddr9,t0 +800000dc: fff00293 li t0,-1 +800000e0: 3ba29073 csrw pmpaddr10,t0 +800000e4: 00000293 li t0,0 +800000e8: 3bb29073 csrw pmpaddr11,t0 +800000ec: 00000293 li t0,0 +800000f0: 3bc29073 csrw pmpaddr12,t0 +800000f4: 00000293 li t0,0 +800000f8: 3bd29073 csrw pmpaddr13,t0 +800000fc: 00000293 li t0,0 +80000100: 3be29073 csrw pmpaddr14,t0 +80000104: 00000293 li t0,0 +80000108: 3bf29073 csrw pmpaddr15,t0 +8000010c: 00c10137 lui sp,0xc10 +80000110: fee10113 addi sp,sp,-18 # c0ffee <_start-0x7f3f0012> +80000114: 0020a023 sw sp,0(ra) +80000118: 00222023 sw sp,0(tp) # 0 <_start-0x80000000> +8000011c: 0000a183 lw gp,0(ra) +80000120: 14311663 bne sp,gp,8000026c +80000124: 00000193 li gp,0 +80000128: 00022183 lw gp,0(tp) # 0 <_start-0x80000000> +8000012c: 14311063 bne sp,gp,8000026c -80000134 : -80000134: 00100e13 li t3,1 -80000138: 00000f17 auipc t5,0x0 -8000013c: 0d8f0f13 addi t5,t5,216 # 80000210 -80000140: 079212b7 lui t0,0x7921 -80000144: 80828293 addi t0,t0,-2040 # 7920808 <_start-0x786df7f8> -80000148: 3a029073 csrw pmpcfg0,t0 +80000130 : +80000130: 00100e13 li t3,1 +80000134: 00000f17 auipc t5,0x0 +80000138: 138f0f13 addi t5,t5,312 # 8000026c +8000013c: 079212b7 lui t0,0x7921 +80000140: 80828293 addi t0,t0,-2040 # 7920808 <_start-0x786df7f8> +80000144: 3a029073 csrw pmpcfg0,t0 +80000148: 800080b7 lui ra,0x80008 8000014c: deadc137 lui sp,0xdeadc -80000150: eef10113 addi sp,sp,-273 # deadbeef -80000154: 00222023 sw sp,0(tp) # 0 <_start-0x80000000> +80000150: eef10113 addi sp,sp,-273 # deadbeef +80000154: 0020a023 sw sp,0(ra) # 80008000 80000158: 00000f17 auipc t5,0x0 8000015c: 010f0f13 addi t5,t5,16 # 80000168 -80000160: 00022183 lw gp,0(tp) # 0 <_start-0x80000000> -80000164: 0ac0006f j 80000210 +80000160: 0000a183 lw gp,0(ra) +80000164: 1080006f j 8000026c 80000168 : 80000168: 00200e13 li t3,2 8000016c: 00000f17 auipc t5,0x0 -80000170: 0a4f0f13 addi t5,t5,164 # 80000210 -80000174: 071212b7 lui t0,0x7121 -80000178: 80828293 addi t0,t0,-2040 # 7120808 <_start-0x78edf7f8> -8000017c: 3a029073 csrw pmpcfg0,t0 +80000170: 100f0f13 addi t5,t5,256 # 8000026c +80000174: 071202b7 lui t0,0x7120 +80000178: 3a029073 csrw pmpcfg0,t0 +8000017c: 800080b7 lui ra,0x80008 80000180: deadc137 lui sp,0xdeadc -80000184: eef10113 addi sp,sp,-273 # deadbeef -80000188: 00222023 sw sp,0(tp) # 0 <_start-0x80000000> +80000184: eef10113 addi sp,sp,-273 # deadbeef +80000188: 0020a023 sw sp,0(ra) # 80008000 8000018c: 00000f17 auipc t5,0x0 80000190: 010f0f13 addi t5,t5,16 # 8000019c -80000194: 00022183 lw gp,0(tp) # 0 <_start-0x80000000> -80000198: 0780006f j 80000210 +80000194: 0000a183 lw gp,0(ra) +80000198: 0d40006f j 8000026c 8000019c : 8000019c: 00300e13 li t3,3 800001a0: 00000f17 auipc t5,0x0 -800001a4: 070f0f13 addi t5,t5,112 # 80000210 +800001a4: 0ccf0f13 addi t5,t5,204 # 8000026c 800001a8: 00000117 auipc sp,0x0 800001ac: 01010113 addi sp,sp,16 # 800001b8 800001b0: 34111073 csrw mepc,sp @@ -129,38 +129,64 @@ Disassembly of section .crt_section: 800001b8 : 800001b8: 00400e13 li t3,4 800001bc: 00000f17 auipc t5,0x0 -800001c0: 054f0f13 addi t5,t5,84 # 80000210 +800001c0: 0b0f0f13 addi t5,t5,176 # 8000026c 800001c4: deadc137 lui sp,0xdeadc -800001c8: eef10113 addi sp,sp,-273 # deadbeef -800001cc: 00222023 sw sp,0(tp) # 0 <_start-0x80000000> -800001d0: 00000f17 auipc t5,0x0 -800001d4: 010f0f13 addi t5,t5,16 # 800001e0 -800001d8: 00022183 lw gp,0(tp) # 0 <_start-0x80000000> -800001dc: 0340006f j 80000210 +800001c8: eef10113 addi sp,sp,-273 # deadbeef +800001cc: 800080b7 lui ra,0x80008 +800001d0: 0020a023 sw sp,0(ra) # 80008000 +800001d4: 00000f17 auipc t5,0x0 +800001d8: 010f0f13 addi t5,t5,16 # 800001e4 +800001dc: 0000a183 lw gp,0(ra) +800001e0: 08c0006f j 8000026c -800001e0 : -800001e0: 00500e13 li t3,5 -800001e4: deadc137 lui sp,0xdeadc -800001e8: eef10113 addi sp,sp,-273 # deadbeef -800001ec: 0020a023 sw sp,0(ra) -800001f0: 0000a183 lw gp,0(ra) -800001f4: 00311e63 bne sp,gp,80000210 +800001e4 : +800001e4: 00500e13 li t3,5 +800001e8: deadc137 lui sp,0xdeadc +800001ec: eef10113 addi sp,sp,-273 # deadbeef +800001f0: 800000b7 lui ra,0x80000 +800001f4: 0020a023 sw sp,0(ra) # 80000000 +800001f8: 0000a183 lw gp,0(ra) +800001fc: 06311863 bne sp,gp,8000026c -800001f8 : -800001f8: 00600e13 li t3,6 -800001fc: 80010237 lui tp,0x80010 -80000200: 00022183 lw gp,0(tp) # 80010000 -80000204: 00000f17 auipc t5,0x0 -80000208: 018f0f13 addi t5,t5,24 # 8000021c -8000020c: 00322023 sw gp,0(tp) # 0 <_start-0x80000000> +80000200 : +80000200: 00600e13 li t3,6 +80000204: 800100b7 lui ra,0x80010 +80000208: 0000a183 lw gp,0(ra) # 80010000 +8000020c: 00000f17 auipc t5,0x0 +80000210: 06cf0f13 addi t5,t5,108 # 80000278 +80000214: 0030a023 sw gp,0(ra) +80000218: 0540006f j 8000026c -80000210 : -80000210: f0100137 lui sp,0xf0100 -80000214: f2410113 addi sp,sp,-220 # f00fff24 -80000218: 01c12023 sw t3,0(sp) +8000021c : +8000021c: 00700e13 li t3,7 +80000220: 00000f17 auipc t5,0x0 +80000224: 04cf0f13 addi t5,t5,76 # 8000026c +80000228: deadc137 lui sp,0xdeadc +8000022c: eef10113 addi sp,sp,-273 # deadbeef +80000230: 800300b7 lui ra,0x80030 +80000234: ff808093 addi ra,ra,-8 # 8002fff8 +80000238: 00222023 sw sp,0(tp) # 0 <_start-0x80000000> +8000023c: 00000f17 auipc t5,0x0 +80000240: fa8f0f13 addi t5,t5,-88 # 800001e4 +80000244: 00022183 lw gp,0(tp) # 0 <_start-0x80000000> +80000248: 0240006f j 8000026c -8000021c : -8000021c: 29a00e13 li t3,666 -80000220: f0100137 lui sp,0xf0100 -80000224: f2010113 addi sp,sp,-224 # f00fff20 -80000228: 00012023 sw zero,0(sp) +8000024c : +8000024c: 00800e13 li t3,8 +80000250: 800400b7 lui ra,0x80040 +80000254: ff808093 addi ra,ra,-8 # 8003fff8 +80000258: 0000a183 lw gp,0(ra) +8000025c: 00000f17 auipc t5,0x0 +80000260: 01cf0f13 addi t5,t5,28 # 80000278 +80000264: 0030a023 sw gp,0(ra) +80000268: 0040006f j 8000026c + +8000026c : +8000026c: f0100137 lui sp,0xf0100 +80000270: f2410113 addi sp,sp,-220 # f00fff24 +80000274: 01c12023 sw t3,0(sp) + +80000278 : +80000278: f0100137 lui sp,0xf0100 +8000027c: f2010113 addi sp,sp,-224 # f00fff20 +80000280: 00012023 sw zero,0(sp) diff --git a/src/test/cpp/raw/pmp/build/pmp.elf b/src/test/cpp/raw/pmp/build/pmp.elf index e5e89ac443042316240eb8b5347ecdc155167933..75d1010c91fc4338946e1dadf660f4690f889fa6 100755 GIT binary patch delta 682 zcmaJ-ze^lJ7=1IjQ$gLG+gWl-1Sh)$Q3&jTaKS4)6B3YEC`3DZ{Y*JZ^v9vkA+4INRhbA0euvVZ5{zCx%1?0g5-AJ>ANryT2EEy%dnAE$gK7hQ8EUTyn^0lA~7`O*=nx`1?d zW#;Ymn-;NqYY>w9d)B~#obo_)ij5t6Om@y4(kk6X$i>~i$!HRhKi)q zyfqxWjUgjL8^y!nzXznVh&v8NXE}LPBeg#1yhjG6E$-<$ec^sYOE=5X`HbpH{uxdxG67n+^%MbTpZj^811zyD>zai3`c*E<<(9jPi8l6Ng4#3}bXg=FppM zow56`GxoN?Y7*Qk;Mau53ivJIg#un8Or>oTU|2QJhj_CN+g}(h+pKNMen@@N kpBVn(5tGs`k-{}C|4I3$1X|{+AC6RfAm7N^Q4uY#YnVKmx&QzG delta 539 zcmZ`#KTE?<5WkCtVxcdud66mx`)mfObZDedNEK^EK`5x;;wE%)6U->mkWLO_?E31(XDOAqeP@9y2*@7>edV>aN*3%ko?)SLp4>+HX3dk5(d zz$^MvyX`lIpC49>gT*t@xCf{$*k)rzftq2Pp{~b-?|W{bIH8hW6n-V|2D&2@55*Zh zu`0lYKlpZoi&8j_{gRNo+@KkG(W5(cA`l>&N^Qajg_H)swA)0eH^&>sY$TK4x`xA^ zb9jz3!biD-_#~_8Jzk8F{HUj{#Zr<0LqwM*3oh_HBjvw=>hvMy8Ac9aT$g8xPPA+T zBd1VQ&>IpQeFiPQ4n?GWhT8*+caf1+Hp1dczf4jEJctCrl)fP5*w$tb|Fe$Feof%A z#O6fTuEbKjp`n0K6%XuKs73>G;@YsJZ5ykJst(YXFJ`4C#JjPiZZLo&f%BGnBO^z2 G4E6){C3wI9 diff --git a/src/test/cpp/raw/pmp/build/pmp.hex b/src/test/cpp/raw/pmp/build/pmp.hex index c87e1d49..e3fdeabb 100644 --- a/src/test/cpp/raw/pmp/build/pmp.hex +++ b/src/test/cpp/raw/pmp/build/pmp.hex @@ -1,38 +1,44 @@ :0200000480007A :100000009700000093800001739050306F00C00093 :1000100073101F3473002030130E0000170F000000 -:10002000130F4F1FB70000803782008037C1ADDE4D +:10002000130F0F25B70000803782008037C1ADDE87 :100030001301F1EE23A020002320220083A1000061 -:100040006318311C832102006314311CB71212079C -:10005000938282807390023AB7021F1993824230D2 -:100060007390123A930280017390223AB7221E0FC6 +:10004000631631228321020063123122B7021207A4 +:100050007390023AB7021F19938242307390123A9A +:10006000B7020F00938262507390223AB7221E0F9C :10007000938202907390323AB70200207390023B51 :100080009302F0FF7390123BB72200207390223B43 :10009000B74200209382F2FF7390323BB7420020B8 :1000A0009382F2FF7390423BB74200209382F2FFAB :1000B0007390523BB72200209382F2FF7390623B11 -:1000C000B74200209382F2FF7390723BB742002048 -:1000D0009382F2FF7390823B930200007390923BF5 -:1000E000930200007390A23B930200007390B23B16 -:1000F000930200007390C23B930200007390D23BC6 -:10010000930200007390E23B930200007390F23B75 -:100110003701C1001301E1FE23A0200023202200AB -:1001200083A100006316310E9301000083210200B9 -:100130006310310E130E1000170F0000130F8F0DF8 -:10014000B7129207938282807390023A37C1ADDE74 -:100150001301F1EE23202200170F0000130F0F01EF -:10016000832102006F00C00A130E2000170F000049 -:10017000130F4F0AB7121207938282807390023ACC -:1001800037C1ADDE1301F1EE23202200170F00006E -:10019000130F0F01832102006F008007130E300040 -:1001A000170F0000130F0F071701000013010101C3 +:1000C000B76200209382F2FF7390723BB7C20020A8 +:1000D0007390823BB7D200207390923B9302F0FF63 +:1000E0007390A23B930200007390B23B9302000016 +:1000F0007390C23B930200007390D23B93020000C6 +:100100007390E23B930200007390F23B3701C10011 +:100110001301E1FE23A020002320220083A1000080 +:10012000631631149301000083210200631031141F +:10013000130E1000170F0000130F8F13B712920742 +:10014000938282807390023AB780008037C1ADDE1F +:100150001301F1EE23A02000170F0000130F0F0171 +:1001600083A100006F008010130E2000170F000005 +:10017000130F0F10B70212077390023AB780008076 +:1001800037C1ADDE1301F1EE23A02000170F0000F0 +:10019000130F0F0183A100006F00400D130E3000FC +:1001A000170F0000130FCF0C1701000013010101FE :1001B0007310113473002030130E4000170F00002D -:1001C000130F4F0537C1ADDE1301F1EE23202200DE -:1001D000170F0000130F0F01832102006F0040036F -:1001E000130E500037C1ADDE1301F1EE23A0200045 -:1001F00083A10000631E3100130E600037020180EE -:1002000083210200170F0000130F8F0123203200FB -:10021000370110F0130141F22320C101130EA02970 -:0C022000370110F0130101F2232001004F +:1001C000130F0F0B37C1ADDE1301F1EEB7800080C6 +:1001D00023A02000170F0000130F0F0183A10000C0 +:1001E0006F00C008130E500037C1ADDE1301F1EEF1 +:1001F000B700008023A0200083A10000631831060F +:10020000130E6000B700018083A10000170F0000EB +:10021000130FCF0623A030006F004005130E7000AF +:10022000170F0000130FCF0437C1ADDE1301F1EE3D +:10023000B7000380938080FF23202200170F000067 +:10024000130F8FFA832102006F004002130E80000B +:10025000B7000480938080FF83A10000170F000087 +:10026000130FCF0123A030006F004000370110F0C2 +:10027000130141F22320C101370110F0130101F2F3 +:040280002320010036 :040000058000000077 :00000001FF diff --git a/src/test/cpp/raw/pmp/build/pmp.map b/src/test/cpp/raw/pmp/build/pmp.map index f49f55ef..1ba7c62e 100644 --- a/src/test/cpp/raw/pmp/build/pmp.map +++ b/src/test/cpp/raw/pmp/build/pmp.map @@ -15,19 +15,19 @@ LOAD /opt/riscv/lib/gcc/riscv64-unknown-elf/10.2.0/../../../../riscv64-unknown-e END GROUP LOAD /opt/riscv/lib/gcc/riscv64-unknown-elf/10.2.0/libgcc.a -.crt_section 0x0000000080000000 0x22c +.crt_section 0x0000000080000000 0x284 0x0000000080000000 . = ALIGN (0x4) *crt.o(.text) - .text 0x0000000080000000 0x22c build/src/crt.o + .text 0x0000000080000000 0x284 build/src/crt.o 0x0000000080000000 _start 0x0000000080000010 trap OUTPUT(build/pmp.elf elf32-littleriscv) -.data 0x000000008000022c 0x0 - .data 0x000000008000022c 0x0 build/src/crt.o +.data 0x0000000080000284 0x0 + .data 0x0000000080000284 0x0 build/src/crt.o -.bss 0x000000008000022c 0x0 - .bss 0x000000008000022c 0x0 build/src/crt.o +.bss 0x0000000080000284 0x0 + .bss 0x0000000080000284 0x0 build/src/crt.o .riscv.attributes 0x0000000000000000 0x1e diff --git a/src/test/cpp/raw/pmp/src/crt.S b/src/test/cpp/raw/pmp/src/crt.S index d7881ae8..47d36b73 100644 --- a/src/test/cpp/raw/pmp/src/crt.S +++ b/src/test/cpp/raw/pmp/src/crt.S @@ -7,23 +7,23 @@ #define TEST_ID x28 #define TRAP_RA x30 -#define PMPCFG0 0x07120808 -#define PMPCFG0_ 0x07920808 // lock region 2 +#define PMPCFG0 0x07120000 +#define PMPCFG0_ 0x07920808 // locked #define PMPCFG1 0x191f0304 -#define PMPCFG2 0x00000018 +#define PMPCFG2 0x000f0506 #define PMPCFG3 0x0f1e1900 -#define PMPADDR0 0x20000000 // TOR -#define PMPADDR1 0xffffffff // TOR +#define PMPADDR0 0x20000000 // OFF +#define PMPADDR1 0xffffffff // OFF #define PMPADDR2 0x20002000 // NA4 W #define PMPADDR3 0x20003fff // OFF RWX #define PMPADDR4 0x20003fff // OFF X #define PMPADDR5 0x20003fff // OFF RW #define PMPADDR6 0x20001fff // NAPOT RWX -#define PMPADDR7 0x20003fff // NAPOT R -#define PMPADDR8 0x20003fff // NAPOT -#define PMPADDR9 0x00000000 // OFF -#define PMPADDR10 0x00000000 // OFF +#define PMPADDR7 0x20005fff // NAPOT R +#define PMPADDR8 0x2000c000 // TOR W +#define PMPADDR9 0x2000d000 // TOR R +#define PMPADDR10 0xffffffff // TOR RWX #define PMPADDR11 0x00000000 // OFF #define PMPADDR12 0x00000000 // OFF #define PMPADDR13 0x00000000 // NAPOT R @@ -97,7 +97,7 @@ test0: li x5, PMPADDR15 csrw pmpaddr15, x5 - li x2, 0x00c0ffee + li x2, 0xc0ffee sw x2, 0x0(x1) sw x2, 0x0(x4) lw x3, 0x0(x1) @@ -112,10 +112,11 @@ test1: la TRAP_RA, fail li x5, PMPCFG0_ csrw pmpcfg0, x5 // lock region 2 + li x1, 0x80008000 li x2, 0xdeadbeef - sw x2, 0x0(x4) // should be OK (write 0x80008000) + sw x2, 0x0(x1) // should be OK (write 0x80008000) la TRAP_RA, test2 - lw x3, 0x0(x4) // should fault (read 0x80008000) + lw x3, 0x0(x1) // should fault (read 0x80008000) j fail // "unlock" region 2, attempt read/write from machine mode @@ -124,10 +125,11 @@ test2: la TRAP_RA, fail li x5, PMPCFG0 csrw pmpcfg0, x5 // "unlock" region 2 + li x1, 0x80008000 li x2, 0xdeadbeef - sw x2, 0x0(x4) // should still be OK (write 0x80008000) + sw x2, 0x0(x1) // should still be OK (write 0x80008000) la TRAP_RA, test3 - lw x3, 0x0(x4) // should still fault (read 0x80008000) + lw x3, 0x0(x1) // should still fault (read 0x80008000) j fail // jump into user mode @@ -143,31 +145,51 @@ test4: li TEST_ID, 4 la TRAP_RA, fail li x2, 0xdeadbeef - sw x2, 0x0(x4) // should be OK (write 0x80008000) + li x1, 0x80008000 + sw x2, 0x0(x1) // should be OK (write 0x80008000) la TRAP_RA, test5 - lw x3, 0x0(x4) // should fault (read 0x80008000) + lw x3, 0x0(x1) // should fault (read 0x80008000) j fail // attempt to read/write other regions from user mode test5: li TEST_ID, 5 li x2, 0xdeadbeef + li x1, 0x80000000 sw x2, 0x0(x1) lw x3, 0x0(x1) bne x2, x3, fail // should be OK (read/write 0x80000000) test6: li TEST_ID, 6 - li x4, 0x80010000 - lw x3, 0x0(x4) // should be OK (read 0x80010000) + li x1, 0x80010000 + lw x3, 0x0(x1) // should be OK (read 0x80010000) la TRAP_RA, pass - sw x3, 0x0(x4) // should fault (write 0x80010000) + sw x3, 0x0(x1) // should fault (write 0x80010000) + j fail + +test7: + li TEST_ID, 7 + la TRAP_RA, fail + li x2, 0xdeadbeef + li x1, 0x8002fff8 + sw x2, 0x0(x4) // should be OK (write 0x8002fff8) + la TRAP_RA, test5 + lw x3, 0x0(x4) // should fault (read 0x8002fff8) + j fail + +test8: + li TEST_ID, 8 + li x1, 0x8003fff8 + lw x3, 0x0(x1) // should be OK (read 0x8003fff8) + la TRAP_RA, pass + sw x3, 0x0(x1) // should fault (write 0x8003fff8) + j fail fail: li x2, 0xf00fff24 sw TEST_ID, 0(x2) pass: - li TEST_ID, 666 li x2, 0xf00fff20 sw x0, 0(x2) diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 81eae4c4..8b299dea 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -211,27 +211,6 @@ class success : public std::exception { }; #define MCYCLEH 0xB80 // MRW Upper 32 bits of mcycle, RV32I only. #define MINSTRETH 0xB82 // MRW Upper 32 bits of minstret, RV32I only. -#define PMPCFG0 0x3a0 -#define PMPCFG1 0x3a1 -#define PMPCFG2 0x3a2 -#define PMPCFG3 0x3a3 -#define PMPADDR0 0x3b0 -#define PMPADDR1 0x3b1 -#define PMPADDR2 0x3b2 -#define PMPADDR3 0x3b3 -#define PMPADDR4 0x3b4 -#define PMPADDR5 0x3b5 -#define PMPADDR6 0x3b6 -#define PMPADDR7 0x3b7 -#define PMPADDR8 0x3b8 -#define PMPADDR9 0x3b9 -#define PMPADDR10 0x3ba -#define PMPADDR11 0x3bb -#define PMPADDR12 0x3bc -#define PMPADDR13 0x3bd -#define PMPADDR14 0x3be -#define PMPADDR15 0x3bf - #define SSTATUS 0x100 #define SIE 0x104 #define STVEC 0x105 @@ -466,53 +445,8 @@ public: enum AccessKind {READ,WRITE,EXECUTE,READ_WRITE}; virtual bool isMmuRegion(uint32_t v) = 0; - bool pmpCheck(uint32_t p, AccessKind kind) { - for (int i = 0; i < 4; i++) { - for (int j = 0; j < 4; j++) { - if (privilege != 3 || pmpcfg[i].reg[3-j].l) { - uint32_t start, end; - bool valid = false; - - switch (pmpcfg[i].reg[3-j].a) { - case 0: // OFF - valid = false; - break; - - case 1: // TOR - valid = false; - break; - - case 2: // NA4 - valid = true; - start = pmpaddr[i*4+j] << 2; - end = start + 4; - break; - - case 3: // NAPOT - valid = true; - uint32_t mask = pmpaddr[i*4+j] & ~(pmpaddr[i*4+j] + 1); - start = (pmpaddr[i*4+j] & ~mask) << 2; - end = start + ((mask + 1) << 3); - break; - } - - if (valid && start <= p && end > p) { - if (kind == READ) return (bool)(!pmpcfg[i].reg[3-j].r); - if (kind == WRITE) return (bool)(!pmpcfg[i].reg[3-j].w); - if (kind == EXECUTE) return (bool)(!pmpcfg[i].reg[3-j].x); - return false; - } - } - } - } - return false; - } bool v2p(uint32_t v, uint32_t *p, AccessKind kind) { -#ifdef PMP - *p = v; - return pmpCheck(v, kind); -#else uint32_t effectivePrivilege = status.mprv && kind != EXECUTE ? status.mpp : privilege; if(effectivePrivilege == 3 || satp.mode == 0 || !isMmuRegion(v)){ *p = v; @@ -536,7 +470,6 @@ public: *p = (tlb.ppn1 << 22) | (superPage ? v & 0x3FF000 : tlb.ppn0 << 12) | (v & 0xFFF); } return false; -#endif } void trap(bool interrupt,int32_t cause) { @@ -639,27 +572,6 @@ public: case SSCRATCH: *value = sscratch; break; case SATP: *value = satp.raw; break; - case PMPCFG0: *value = pmpcfg[0].raw; break; - case PMPCFG1: *value = pmpcfg[1].raw; break; - case PMPCFG2: *value = pmpcfg[2].raw; break; - case PMPCFG3: *value = pmpcfg[3].raw; break; - case PMPADDR0: *value = pmpaddr[0]; break; - case PMPADDR1: *value = pmpaddr[1]; break; - case PMPADDR2: *value = pmpaddr[2]; break; - case PMPADDR3: *value = pmpaddr[3]; break; - case PMPADDR4: *value = pmpaddr[4]; break; - case PMPADDR5: *value = pmpaddr[5]; break; - case PMPADDR6: *value = pmpaddr[6]; break; - case PMPADDR7: *value = pmpaddr[7]; break; - case PMPADDR8: *value = pmpaddr[8]; break; - case PMPADDR9: *value = pmpaddr[9]; break; - case PMPADDR10: *value = pmpaddr[10]; break; - case PMPADDR11: *value = pmpaddr[11]; break; - case PMPADDR12: *value = pmpaddr[12]; break; - case PMPADDR13: *value = pmpaddr[13]; break; - case PMPADDR14: *value = pmpaddr[14]; break; - case PMPADDR15: *value = pmpaddr[15]; break; - default: return true; break; } return false; @@ -698,81 +610,6 @@ public: case SCAUSE: scause.raw = value; break; case STVAL: sbadaddr = value; break; case SEPC: sepc = value; break; - case SSCRATCH: sscratch = value; break; - case SATP: satp.raw = value; break; - - case PMPCFG0: - if (!pmpcfg[0].reg[3].l) maskedWrite(pmpcfg[0].raw, value, 0xff); - if (!pmpcfg[0].reg[2].l) maskedWrite(pmpcfg[0].raw, value, 0xff00); - if (!pmpcfg[0].reg[1].l) maskedWrite(pmpcfg[0].raw, value, 0xff0000); - if (!pmpcfg[0].reg[0].l) maskedWrite(pmpcfg[0].raw, value, 0xff000000); - break; - case PMPCFG1: - if (!pmpcfg[1].reg[3].l) maskedWrite(pmpcfg[1].raw, value, 0xff); - if (!pmpcfg[1].reg[2].l) maskedWrite(pmpcfg[1].raw, value, 0xff00); - if (!pmpcfg[1].reg[1].l) maskedWrite(pmpcfg[1].raw, value, 0xff0000); - if (!pmpcfg[1].reg[0].l) maskedWrite(pmpcfg[1].raw, value, 0xff000000); - break; - case PMPCFG2: - if (!pmpcfg[2].reg[3].l) maskedWrite(pmpcfg[2].raw, value, 0xff); - if (!pmpcfg[2].reg[2].l) maskedWrite(pmpcfg[2].raw, value, 0xff00); - if (!pmpcfg[2].reg[1].l) maskedWrite(pmpcfg[2].raw, value, 0xff0000); - if (!pmpcfg[2].reg[0].l) maskedWrite(pmpcfg[2].raw, value, 0xff000000); - break; - case PMPCFG3: - if (!pmpcfg[3].reg[3].l) maskedWrite(pmpcfg[3].raw, value, 0xff); - if (!pmpcfg[3].reg[2].l) maskedWrite(pmpcfg[3].raw, value, 0xff00); - if (!pmpcfg[3].reg[1].l) maskedWrite(pmpcfg[3].raw, value, 0xff0000); - if (!pmpcfg[3].reg[0].l) maskedWrite(pmpcfg[3].raw, value, 0xff000000); - break; - case PMPADDR0: - if (!pmpcfg[0].reg[3].l) pmpaddr[0] = value; - break; - case PMPADDR1: - if (!pmpcfg[0].reg[2].l) pmpaddr[1] = value; - break; - case PMPADDR2: - if (!pmpcfg[0].reg[1].l) pmpaddr[2] = value; - break; - case PMPADDR3: - if (!pmpcfg[0].reg[0].l) pmpaddr[3] = value; - break; - case PMPADDR4: - if (!pmpcfg[1].reg[3].l) pmpaddr[4] = value; - break; - case PMPADDR5: - if (!pmpcfg[1].reg[2].l) pmpaddr[5] = value; - break; - case PMPADDR6: - if (!pmpcfg[1].reg[1].l) pmpaddr[6] = value; - break; - case PMPADDR7: - if (!pmpcfg[1].reg[0].l) pmpaddr[7] = value; - break; - case PMPADDR8: - if (!pmpcfg[2].reg[3].l) pmpaddr[8] = value; - break; - case PMPADDR9: - if (!pmpcfg[2].reg[2].l) pmpaddr[9] = value; - break; - case PMPADDR10: - if (!pmpcfg[2].reg[1].l) pmpaddr[10] = value; - break; - case PMPADDR11: - if (!pmpcfg[2].reg[0].l) pmpaddr[11] = value; - break; - case PMPADDR12: - if (!pmpcfg[3].reg[3].l) pmpaddr[12] = value; - break; - case PMPADDR13: - if (!pmpcfg[3].reg[2].l) pmpaddr[13] = value; - break; - case PMPADDR14: - if (!pmpcfg[3].reg[1].l) pmpaddr[14] = value; - break; - case PMPADDR15: - if (!pmpcfg[3].reg[0].l) pmpaddr[15] = value; - break; default: ilegalInstruction(); return true; break; } @@ -4054,7 +3891,7 @@ int main(int argc, char **argv, char **env) { #endif #ifdef PMP - redo(REDO,WorkspaceRegression("pmp").loadHex(string(REGRESSION_PATH) + "../raw/pmp/build/pmp.hex")->bootAt(0x00000000u)->run(10e3);); + redo(REDO,WorkspaceRegression("pmp").loadHex(string(REGRESSION_PATH) + "../raw/pmp/build/pmp.hex")->bootAt(0x80000000u)->run(10e3);); #endif #ifdef AMO diff --git a/src/test/scala/vexriscv/TestIndividualFeatures.scala b/src/test/scala/vexriscv/TestIndividualFeatures.scala index 6d072913..64c8ad6f 100644 --- a/src/test/scala/vexriscv/TestIndividualFeatures.scala +++ b/src/test/scala/vexriscv/TestIndividualFeatures.scala @@ -523,8 +523,8 @@ class CsrDimension(freertos : String, zephyr : String, linux : String) extends V } } else if(catchAll){ new VexRiscvPosition("MachineOs") with CatchAllPosition{ - override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new CsrPlugin(CsrPluginConfig.all(0x80000020l)) - override def testParam = s"CSR=yes FREERTOS=$freertos ZEPHYR=$zephyr" + override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new CsrPlugin(CsrPluginConfig.zephyr(0x80000020l)) + override def testParam = s"CSR=yes CSR_SKIP_TEST=yes FREERTOS=$freertos ZEPHYR=$zephyr" } } else if(r.nextDouble() < 0.3){ new VexRiscvPosition("AllNoException") with CatchAllPosition{ From f2ce2eab002b32aef0c56f49aa33eda89c2dd8a5 Mon Sep 17 00:00:00 2001 From: Samuel Lindemer Date: Mon, 7 Dec 2020 09:11:26 +0100 Subject: [PATCH 518/951] PMP plugin passes regression tests --- src/test/cpp/regression/main.cpp | 34 ++++--------------- src/test/cpp/regression/makefile | 2 +- .../vexriscv/TestIndividualFeatures.scala | 14 ++++---- 3 files changed, 15 insertions(+), 35 deletions(-) diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 8b299dea..99393ac0 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -211,6 +211,7 @@ class success : public std::exception { }; #define MCYCLEH 0xB80 // MRW Upper 32 bits of mcycle, RV32I only. #define MINSTRETH 0xB82 // MRW Upper 32 bits of minstret, RV32I only. + #define SSTATUS 0x100 #define SIE 0x104 #define STVEC 0x105 @@ -373,25 +374,9 @@ public: }; }; + bool lrscReserved; - struct pmpcfg_s { - uint32_t r : 1; - uint32_t w : 1; - uint32_t x : 1; - uint32_t a : 2; - uint32_t _dummy : 2; - uint32_t l : 1; - } __attribute__((packed)); - - union pmpcfg_u { - uint32_t raw; - pmpcfg_s reg[4]; - }; - - pmpcfg_u pmpcfg[4]; - uint32_t pmpaddr[16]; - RiscvGolden() { pc = 0x80000000; regs[0] = 0; @@ -416,10 +401,6 @@ public: ipInput = 0; stepCounter = 0; lrscReserved = false; - for (int i = 0; i < 4; i++) - pmpcfg[i].raw = 0; - for (int i = 0; i < 16; i++) - pmpaddr[i] = 0; } virtual void rfWrite(int32_t address, int32_t data) { @@ -444,10 +425,8 @@ public: enum AccessKind {READ,WRITE,EXECUTE,READ_WRITE}; virtual bool isMmuRegion(uint32_t v) = 0; - - - bool v2p(uint32_t v, uint32_t *p, AccessKind kind) { - uint32_t effectivePrivilege = status.mprv && kind != EXECUTE ? status.mpp : privilege; + bool v2p(uint32_t v, uint32_t *p, AccessKind kind){ + uint32_t effectivePrivilege = status.mprv && kind != EXECUTE ? status.mpp : privilege; if(effectivePrivilege == 3 || satp.mode == 0 || !isMmuRegion(v)){ *p = v; } else { @@ -549,7 +528,7 @@ public: virtual bool csrRead(int32_t csr, uint32_t *value){ if(((csr >> 8) & 0x3) > privilege) return true; - switch(csr) { + switch(csr){ case MSTATUS: *value = status.raw & MSTATUS_READ_MASK; break; case MIP: *value = getIp().raw; break; case MIE: *value = ie.raw; break; @@ -571,7 +550,6 @@ public: case SEPC: *value = sepc; break; case SSCRATCH: *value = sscratch; break; case SATP: *value = satp.raw; break; - default: return true; break; } return false; @@ -610,6 +588,8 @@ public: case SCAUSE: scause.raw = value; break; case STVAL: sbadaddr = value; break; case SEPC: sepc = value; break; + case SSCRATCH: sscratch = value; break; + case SATP: satp.raw = value; break; default: ilegalInstruction(); return true; break; } diff --git a/src/test/cpp/regression/makefile b/src/test/cpp/regression/makefile index c71c8809..5f640348 100644 --- a/src/test/cpp/regression/makefile +++ b/src/test/cpp/regression/makefile @@ -15,7 +15,7 @@ CSR_SKIP_TEST?=no EBREAK?=no FENCEI?=no MMU?=yes -PMP?=yes +PMP?=no SEED?=no LRSC?=no AMO?=no diff --git a/src/test/scala/vexriscv/TestIndividualFeatures.scala b/src/test/scala/vexriscv/TestIndividualFeatures.scala index 64c8ad6f..b2f35aa5 100644 --- a/src/test/scala/vexriscv/TestIndividualFeatures.scala +++ b/src/test/scala/vexriscv/TestIndividualFeatures.scala @@ -46,6 +46,7 @@ abstract class VexRiscvPosition(name: String) extends ConfigPosition[VexRiscvCo class VexRiscvUniverse extends ConfigUniverse object VexRiscvUniverse{ + val CACHE_ALL = new VexRiscvUniverse val CATCH_ALL = new VexRiscvUniverse val MMU = new VexRiscvUniverse val PMP = new VexRiscvUniverse @@ -322,9 +323,10 @@ class IBusDimension(rvcRate : Double) extends VexRiscvDimension("IBus") { override def randomPositionImpl(universes: Seq[ConfigUniverse], r: Random) = { val catchAll = universes.contains(VexRiscvUniverse.CATCH_ALL) + val cacheAll = universes.contains(VexRiscvUniverse.CACHE_ALL) val mmuConfig = if(universes.contains(VexRiscvUniverse.MMU)) MmuPortConfig( portTlbSize = 4) else null - if(r.nextDouble() < 0.5){ + if(r.nextDouble() < 0.5 && !cacheAll){ val latency = r.nextInt(5) + 1 val compressed = r.nextDouble() < rvcRate val injectorStage = r.nextBoolean() || latency == 1 @@ -403,13 +405,14 @@ class DBusDimension extends VexRiscvDimension("DBus") { override def randomPositionImpl(universes: Seq[ConfigUniverse], r: Random) = { val catchAll = universes.contains(VexRiscvUniverse.CATCH_ALL) + val cacheAll = universes.contains(VexRiscvUniverse.CACHE_ALL) val mmuConfig = if(universes.contains(VexRiscvUniverse.MMU)) MmuPortConfig( portTlbSize = 4) else null val noMemory = universes.contains(VexRiscvUniverse.NO_MEMORY) val noWriteBack = universes.contains(VexRiscvUniverse.NO_WRITEBACK) - if(r.nextDouble() < 0.4 || noMemory){ + if((r.nextDouble() < 0.4 || noMemory) && !cacheAll){ val withLrSc = catchAll val earlyInjection = r.nextBoolean() && !universes.contains(VexRiscvUniverse.NO_WRITEBACK) new VexRiscvPosition("Simple" + (if(earlyInjection) "Early" else "Late")) { @@ -760,18 +763,15 @@ class TestIndividualFeatures extends MultithreadedFunSuite { } } else { if(machineOsRate > rand.nextDouble()) { + universe += VexRiscvUniverse.CACHE_ALL universe += VexRiscvUniverse.CATCH_ALL universe += VexRiscvUniverse.PMP if(demwRate < rand.nextDouble()){ universe += VexRiscvUniverse.NO_WRITEBACK } } - if(demwRate > rand.nextDouble()){ - }else if(demRate > rand.nextDouble()){ + if(demRate > rand.nextDouble()){ universe += VexRiscvUniverse.NO_WRITEBACK - } else { - universe += VexRiscvUniverse.NO_WRITEBACK - universe += VexRiscvUniverse.NO_MEMORY } } From 7d699dcc137573e570dc2f2e2588297da7cd6c87 Mon Sep 17 00:00:00 2001 From: Samuel Lindemer Date: Thu, 10 Dec 2020 09:39:56 +0100 Subject: [PATCH 519/951] Remove PMP from MachineOs test defaults --- .../demo/{GenZephyr.scala => GenSecure.scala} | 4 ++-- .../scala/vexriscv/plugin/CsrPlugin.scala | 4 ++-- src/test/cpp/raw/pmp/.gdbinit | 3 --- src/test/cpp/regression/main.cpp | 2 +- .../vexriscv/TestIndividualFeatures.scala | 24 +++++++++++++++---- 5 files changed, 25 insertions(+), 12 deletions(-) rename src/main/scala/vexriscv/demo/{GenZephyr.scala => GenSecure.scala} (96%) delete mode 100644 src/test/cpp/raw/pmp/.gdbinit diff --git a/src/main/scala/vexriscv/demo/GenZephyr.scala b/src/main/scala/vexriscv/demo/GenSecure.scala similarity index 96% rename from src/main/scala/vexriscv/demo/GenZephyr.scala rename to src/main/scala/vexriscv/demo/GenSecure.scala index 4666ec4f..2835b444 100644 --- a/src/main/scala/vexriscv/demo/GenZephyr.scala +++ b/src/main/scala/vexriscv/demo/GenSecure.scala @@ -5,7 +5,7 @@ import vexriscv.ip.{DataCacheConfig, InstructionCacheConfig} import vexriscv.{plugin, VexRiscv, VexRiscvConfig} import spinal.core._ -object GenZephyr extends App { +object GenSecure extends App { def cpu() = new VexRiscv( config = VexRiscvConfig( plugins = List( @@ -71,7 +71,7 @@ object GenZephyr extends App { mulUnrollFactor = 1, divUnrollFactor = 1 ), - new CsrPlugin(CsrPluginConfig.zephyr(0x00000020l)), + new CsrPlugin(CsrPluginConfig.secure(0x00000020l)), new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))), new BranchPlugin( earlyBranch = false, diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index cabc2620..315d3e59 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -264,13 +264,13 @@ object CsrPluginConfig{ uinstretAccess = CsrAccess.NONE ) - def zephyr(mtvecInit : BigInt) = CsrPluginConfig( + def secure(mtvecInit : BigInt) = CsrPluginConfig( catchIllegalAccess = true, mvendorid = 1, marchid = 2, mimpid = 3, mhartid = 0, - misaExtensionsInit = 0x103124, // RV32CFIMNU + misaExtensionsInit = 0x101064, // RV32GCFMU misaAccess = CsrAccess.READ_WRITE, mtvecAccess = CsrAccess.READ_WRITE, mtvecInit = mtvecInit, diff --git a/src/test/cpp/raw/pmp/.gdbinit b/src/test/cpp/raw/pmp/.gdbinit deleted file mode 100644 index 45fceb2d..00000000 --- a/src/test/cpp/raw/pmp/.gdbinit +++ /dev/null @@ -1,3 +0,0 @@ -target remote localhost:3333 -monitor reset halt -load diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 99393ac0..d5788f5b 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -373,7 +373,7 @@ public: uint32_t ppn1 : 12; }; }; - + bool lrscReserved; diff --git a/src/test/scala/vexriscv/TestIndividualFeatures.scala b/src/test/scala/vexriscv/TestIndividualFeatures.scala index b2f35aa5..75d3405c 100644 --- a/src/test/scala/vexriscv/TestIndividualFeatures.scala +++ b/src/test/scala/vexriscv/TestIndividualFeatures.scala @@ -517,6 +517,7 @@ trait CatchAllPosition class CsrDimension(freertos : String, zephyr : String, linux : String) extends VexRiscvDimension("Csr") { override def randomPositionImpl(universes: Seq[ConfigUniverse], r: Random) = { + val pmp = universes.contains(VexRiscvUniverse.PMP) val catchAll = universes.contains(VexRiscvUniverse.CATCH_ALL) val supervisor = universes.contains(VexRiscvUniverse.SUPERVISOR) if(supervisor){ @@ -524,9 +525,14 @@ class CsrDimension(freertos : String, zephyr : String, linux : String) extends V override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new CsrPlugin(CsrPluginConfig.linuxFull(0x80000020l)) override def testParam = s"FREERTOS=$freertos ZEPHYR=$zephyr LINUX_REGRESSION=$linux SUPERVISOR=yes" } + } else if(pmp){ + new VexRiscvPosition("Secure") with CatchAllPosition{ + override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new CsrPlugin(CsrPluginConfig.secure(0x80000020l)) + override def testParam = s"CSR=yes CSR_SKIP_TEST=yes FREERTOS=$freertos ZEPHYR=$zephyr" + } } else if(catchAll){ new VexRiscvPosition("MachineOs") with CatchAllPosition{ - override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new CsrPlugin(CsrPluginConfig.zephyr(0x80000020l)) + override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new CsrPlugin(CsrPluginConfig.all(0x80000020l)) override def testParam = s"CSR=yes CSR_SKIP_TEST=yes FREERTOS=$freertos ZEPHYR=$zephyr" } } else if(r.nextDouble() < 0.3){ @@ -655,6 +661,7 @@ class TestIndividualFeatures extends MultithreadedFunSuite { val rvcRate = sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_RVC_RATE", "0.5").toDouble val linuxRate = sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_LINUX_RATE", "0.3").toDouble val machineOsRate = sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_MACHINE_OS_RATE", "0.5").toDouble + val secureRate = sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_SECURE_RATE", "0.5").toDouble val linuxRegression = sys.env.getOrElse("VEXRISCV_REGRESSION_LINUX_REGRESSION", "yes") val coremarkRegression = sys.env.getOrElse("VEXRISCV_REGRESSION_COREMARK", "yes") val zephyrCount = sys.env.getOrElse("VEXRISCV_REGRESSION_ZEPHYR_COUNT", "4") @@ -761,17 +768,26 @@ class TestIndividualFeatures extends MultithreadedFunSuite { if(demwRate < rand.nextDouble()){ universe += VexRiscvUniverse.NO_WRITEBACK } - } else { - if(machineOsRate > rand.nextDouble()) { + } else if (secureRate > rand.nextDouble()) { universe += VexRiscvUniverse.CACHE_ALL universe += VexRiscvUniverse.CATCH_ALL universe += VexRiscvUniverse.PMP if(demwRate < rand.nextDouble()){ universe += VexRiscvUniverse.NO_WRITEBACK } + } else { + if(machineOsRate > rand.nextDouble()) { + universe += VexRiscvUniverse.CATCH_ALL + if(demwRate < rand.nextDouble()){ + universe += VexRiscvUniverse.NO_WRITEBACK + } } - if(demRate > rand.nextDouble()){ + if(demwRate > rand.nextDouble()){ + }else if(demRate > rand.nextDouble()){ universe += VexRiscvUniverse.NO_WRITEBACK + } else { + universe += VexRiscvUniverse.NO_WRITEBACK + universe += VexRiscvUniverse.NO_MEMORY } } From 6da09967f8f7cae822d82978a1b4c4b30b83a0e7 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 11 Dec 2020 13:46:49 +0100 Subject: [PATCH 520/951] Add comments to the AesPlugin --- .../scala/vexriscv/plugin/AesPlugin.scala | 58 ++++++++++++++++++- 1 file changed, 56 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/AesPlugin.scala b/src/main/scala/vexriscv/plugin/AesPlugin.scala index c36eaef0..2e02eb1f 100644 --- a/src/main/scala/vexriscv/plugin/AesPlugin.scala +++ b/src/main/scala/vexriscv/plugin/AesPlugin.scala @@ -4,6 +4,60 @@ import spinal.core._ import spinal.lib._ import vexriscv.{DecoderService, Stageable, VexRiscv} +/** + * The AesPlugin allow to reduce the instruction count of each AES round by providing the following instruction : + * 1) aes_enc_round(rs1, rs2, sel). rd = rs1 ^ quad_mul(sel, sbox(byte_sel(rs2, sel))) + * 2) aes_enc_round_last(rs1, rs2, sel). rd = rs1 ^ quad_sbox(byte_sel(rs2, sel)) + * 3) aes_dec_round(rs1, rs2, sel). rd = rs1 ^ quad_inv_sbox(quad_mul(sel,byte_sel(rs2, sel))) + * 4) aes_dec_round_last(rs1, rs2, sel). rd = rs1 ^ quad_inv_sbox(byte_sel(rs2, sel)) + * + * Here is what those inner functions mean: + * - sbox apply the sbox transformation on the 'sel' byte of the 32 bits word + * - quad_mul multiply (Galois field) each byte of 32 bits word by a constant (which depend of sel) + * - quad_inv_sbox apply the inverse sbox transformation on each byte of 32 bits word + * + * You can find a complet example of those instruction usage in aes_cusom.h in vexriscv_aes_encrypt and + * vexriscv_aes_decrypt. Those function are made to work on little endian as in the linux kernel default AES + * implementation, but unlike libressl, libopenssl and dropbear ones (swapping the byte of the expended key can fix that). + * + * This plugin implement the processing using a single 32_bits * 512_words rom to fetch the sbox/inv_sbox/multiplication + * results already combined. This rom is formated as following : + * + * From word 0x000 to 0x0FF, it is formatted as follow : (note multiplication are in Galois field) + * [ 7 : 0] : SBox[word_address & 0xFF] * 1 + * [15 : 8] : SBox[word_address & 0xFF] * 2 + * [23 : 16] : SBox[word_address & 0xFF] * 3 + * [31 : 24] : inverse SBox[word_address & 0xFF] * 1 (Used for the last round of the decryption) + * + * From word 0x100 to 0x1FF, it is formatted as follow : + * [ 7 : 0] : inverse SBox[word_address & 0xFF * 14] + * [15 : 8] : inverse SBox[word_address & 0xFF * 9] + * [23 : 16] : inverse SBox[word_address & 0xFF * 13] + * [31 : 24] : inverse SBox[word_address & 0xFF * 11] + * + * So, on each instruction, the following is done (in order) + * 1) Select the 'sel' byte of RS2 + * 2) Read the rom at a address which depend of the RS2 selected byte and the instruction + * 3) Permute the rom read data depending the instruction and the 'sel' argument + * 4) Xor the result with RS1 and return that as instruction result + * + * The instructions are encoded by default as following : + * --SS-LDXXXXXYYYYY000ZZZZZ0001011 + * + * Where : + * - XXXXX is the register file source 2 (RS2) + * - YYYYY is the register file source 1 (RS1) + * - ZZZZZ is the register file destination + * - D=1 mean decrypt, D=0 mean encrypt + * - L=1 mean last round, L=0 mean full round + * - SS specify which byte should be used from RS2 for the processing + * + * In practice the aes-256-cbc performances should improve by a factor 4. See the following results from libopenssl + * from a SoC running linux at 100 Mhz + * type 16 bytes 64 bytes 256 bytes 1024 bytes 8192 bytes 16384 bytes + * aes-256-cbc SW 492.58k 700.22k 796.41k 831.49k 830.09k 832.81k + * aes-256-cbc HW 1099.77k 2320.65k 3164.16k 3484.67k 3528.02k 3511.64k + */ case class AesPlugin(encoding : MaskedLiteral = M"-----------------000-----0001011") extends Plugin[VexRiscv]{ @@ -13,7 +67,6 @@ case class AesPlugin(encoding : MaskedLiteral = M"-----------------000-----00010 val mapping = new { def DECRYPT = 25 // 0/1 => encrypt/decrypt def LAST_ROUND = 26 - def ENDIAN = 27 //Not implemented yet def BYTE_SEL = 28 //Which byte should be used in RS2 } @@ -58,6 +111,7 @@ case class AesPlugin(encoding : MaskedLiteral = M"-----------------000-----00010 memory plug new Area{ import memory._ + //Decode the rom data val rom = new Area { val storage = Mem(Bits(32 bits), 512) initBigInt((BANK0 ++ BANK1).map(BigInt(_))) @@ -76,7 +130,7 @@ case class AesPlugin(encoding : MaskedLiteral = M"-----------------000-----00010 val address = U(input(INSTRUCTION)(mapping.DECRYPT) ## input(INSTRUCTION)(mapping.LAST_ROUND)) val output = remap(address) } - + val wordDesuffle = new Area{ val zero = B"0000" val byteSel = input(INSTRUCTION)(mapping.BYTE_SEL, 2 bits).asUInt From eaff52b26411f363a9da6ccd1f3da737a04aea5b Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 11 Dec 2020 13:51:10 +0100 Subject: [PATCH 521/951] Add comments to the AesPlugin --- src/main/scala/vexriscv/plugin/AesPlugin.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/plugin/AesPlugin.scala b/src/main/scala/vexriscv/plugin/AesPlugin.scala index 2e02eb1f..d41998b2 100644 --- a/src/main/scala/vexriscv/plugin/AesPlugin.scala +++ b/src/main/scala/vexriscv/plugin/AesPlugin.scala @@ -56,7 +56,7 @@ import vexriscv.{DecoderService, Stageable, VexRiscv} * from a SoC running linux at 100 Mhz * type 16 bytes 64 bytes 256 bytes 1024 bytes 8192 bytes 16384 bytes * aes-256-cbc SW 492.58k 700.22k 796.41k 831.49k 830.09k 832.81k - * aes-256-cbc HW 1099.77k 2320.65k 3164.16k 3484.67k 3528.02k 3511.64k + * aes-256 cbc HW 1781.52k 2834.07k 3323.07k 3486.72k 3465.22k 3440.10k */ case class AesPlugin(encoding : MaskedLiteral = M"-----------------000-----0001011") extends Plugin[VexRiscv]{ From c59499ec0356f3bbc43e9bf64d6a3e19778bc1b2 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 11 Dec 2020 14:13:33 +0100 Subject: [PATCH 522/951] typo --- src/main/scala/vexriscv/plugin/AesPlugin.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/AesPlugin.scala b/src/main/scala/vexriscv/plugin/AesPlugin.scala index d41998b2..0d4556a1 100644 --- a/src/main/scala/vexriscv/plugin/AesPlugin.scala +++ b/src/main/scala/vexriscv/plugin/AesPlugin.scala @@ -6,9 +6,9 @@ import vexriscv.{DecoderService, Stageable, VexRiscv} /** * The AesPlugin allow to reduce the instruction count of each AES round by providing the following instruction : - * 1) aes_enc_round(rs1, rs2, sel). rd = rs1 ^ quad_mul(sel, sbox(byte_sel(rs2, sel))) + * 1) aes_enc_round(rs1, rs2, sel). rd = rs1 ^ quad_mul(sel, sbox(byte_sel(rs2, sel))) * 2) aes_enc_round_last(rs1, rs2, sel). rd = rs1 ^ quad_sbox(byte_sel(rs2, sel)) - * 3) aes_dec_round(rs1, rs2, sel). rd = rs1 ^ quad_inv_sbox(quad_mul(sel,byte_sel(rs2, sel))) + * 3) aes_dec_round(rs1, rs2, sel). rd = rs1 ^ quad_inv_sbox(quad_mul(sel,byte_sel(rs2, sel))) * 4) aes_dec_round_last(rs1, rs2, sel). rd = rs1 ^ quad_inv_sbox(byte_sel(rs2, sel)) * * Here is what those inner functions mean: From 780ad01ac0925401ff112e233594ee7dc95a7748 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 21 Dec 2020 11:50:54 +0100 Subject: [PATCH 523/951] Add AES-instruction support --- .../demo/smp/VexRiscvSmpLitexCluster.scala | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala index 2a524c37..bd14d432 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala @@ -6,7 +6,7 @@ import spinal.lib.bus.misc.{AddressMapping, DefaultMapping, SizeMapping} import spinal.lib.bus.wishbone.{WishboneConfig, WishboneToBmbGenerator} import spinal.lib.sim.SparseMemory import vexriscv.demo.smp.VexRiscvSmpClusterGen.vexRiscvConfig -import vexriscv.plugin.DBusCachedPlugin +import vexriscv.plugin.{AesPlugin, DBusCachedPlugin} case class VexRiscvLitexSmpClusterParameter( cluster : VexRiscvSmpClusterParameter, @@ -66,6 +66,7 @@ object VexRiscvLitexSmpClusterCmdGen extends App { var dCacheWays = 2 var liteDramWidth = 128 var coherentDma = false + var aesInstruction = false var netlistDirectory = "." var netlistName = "VexRiscvLitexSmpCluster" assert(new scopt.OptionParser[Unit]("VexRiscvLitexSmpClusterCmdGen") { @@ -81,13 +82,14 @@ object VexRiscvLitexSmpClusterCmdGen extends App { opt[String]("litedram-width") action { (v, c) => liteDramWidth = v.toInt } opt[String]("netlist-directory") action { (v, c) => netlistDirectory = v } opt[String]("netlist-name") action { (v, c) => netlistName = v } + opt[String]("aes-instruction") action { (v, c) => aesInstruction = v.toBoolean } }.parse(args)) val coherency = coherentDma || cpuCount > 1 def parameter = VexRiscvLitexSmpClusterParameter( cluster = VexRiscvSmpClusterParameter( - cpuConfigs = List.tabulate(cpuCount) { hartId => - vexRiscvConfig( + cpuConfigs = List.tabulate(cpuCount) { hartId => { + val c = vexRiscvConfig( hartId = hartId, ioRange = address => address.msb, resetVector = 0, @@ -99,7 +101,9 @@ object VexRiscvLitexSmpClusterCmdGen extends App { dCacheWays = dCacheWays, coherency = coherency ) - }, + if(aesInstruction) c.add(new AesPlugin) + c + }}, withExclusiveAndInvalidation = coherency ), liteDram = LiteDramNativeParameter(addressWidth = 32, dataWidth = liteDramWidth), @@ -114,7 +118,7 @@ object VexRiscvLitexSmpClusterCmdGen extends App { toplevel } - val genConfig = SpinalConfig(targetDirectory = netlistDirectory).addStandardMemBlackboxing(blackboxByteEnables) + val genConfig = SpinalConfig(targetDirectory = netlistDirectory, inlineRom = true).addStandardMemBlackboxing(blackboxByteEnables) genConfig.generateVerilog(dutGen.setDefinitionName(netlistName)) } From 930bdf9ddab5301d8ce3b34f3cdd57775287bc7c Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 1 Jan 2021 23:59:00 +0100 Subject: [PATCH 524/951] DataCache increase syncPendingMax to 32 and use a sync queue instead of async one --- src/main/scala/vexriscv/ip/DataCache.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index d0f7abda..eff10975 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -369,7 +369,7 @@ case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave } - def toBmb(syncPendingMax : Int = 16, + def toBmb(syncPendingMax : Int = 32, timeoutCycles : Int = 16) : Bmb = new Area{ setCompositeName(DataCacheMemBus.this, "Bridge", true) val pipelinedMemoryBusConfig = p.getBmbParameter() @@ -489,7 +489,7 @@ case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave cmdCtx.payload := aggregationCounter halt setWhen(!cmdCtx.ready) - val syncCtx = cmdCtx.queueLowLatency(syncPendingMax, latency = 1) + val syncCtx = cmdCtx.queue(syncPendingMax) syncCtx.ready := bus.sync.fire sync.arbitrationFrom(bus.sync) From 6e0be6e18c97454fda257a99171c18cb5788bfb0 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 11 Jan 2021 13:43:57 +0100 Subject: [PATCH 525/951] Cfu add state index and cfu index --- .../demo/GenSmallAndProductiveCfu.scala | 4 +- .../scala/vexriscv/plugin/CfuPlugin.scala | 60 +++++++++---------- 2 files changed, 30 insertions(+), 34 deletions(-) diff --git a/src/main/scala/vexriscv/demo/GenSmallAndProductiveCfu.scala b/src/main/scala/vexriscv/demo/GenSmallAndProductiveCfu.scala index 1810787b..a571bccd 100644 --- a/src/main/scala/vexriscv/demo/GenSmallAndProductiveCfu.scala +++ b/src/main/scala/vexriscv/demo/GenSmallAndProductiveCfu.scala @@ -53,6 +53,7 @@ object GenSmallAndProductiveCfu extends App{ new CfuPlugin( stageCount = 1, allowZeroLatency = true, + cfuIndexWidth = 4, encodings = List( CfuPluginEncoding ( instruction = M"-------------------------0001011", @@ -63,13 +64,14 @@ object GenSmallAndProductiveCfu extends App{ busParameter = CfuBusParameter( CFU_VERSION = 0, CFU_INTERFACE_ID_W = 0, - CFU_FUNCTION_ID_W = 2, + CFU_FUNCTION_ID_W = 7, CFU_REORDER_ID_W = 0, CFU_REQ_RESP_ID_W = 0, CFU_INPUTS = 2, CFU_INPUT_DATA_W = 32, CFU_OUTPUTS = 1, CFU_OUTPUT_DATA_W = 32, + CFU_STATE_INDEX_NUM = 5, CFU_FLOW_REQ_READY_ALWAYS = false, CFU_FLOW_RESP_READY_ALWAYS = false ) diff --git a/src/main/scala/vexriscv/plugin/CfuPlugin.scala b/src/main/scala/vexriscv/plugin/CfuPlugin.scala index 6b82e7f6..60dd95b0 100644 --- a/src/main/scala/vexriscv/plugin/CfuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CfuPlugin.scala @@ -25,6 +25,7 @@ case class CfuBusParameter(CFU_VERSION : Int = 0, CFU_FUNCTION_ID_W : Int, CFU_REORDER_ID_W : Int = 0, CFU_REQ_RESP_ID_W : Int = 0, + CFU_STATE_INDEX_NUM : Int = 0, CFU_INPUTS : Int, CFU_INPUT_DATA_W : Int, CFU_OUTPUTS : Int, @@ -37,7 +38,7 @@ case class CfuCmd( p : CfuBusParameter ) extends Bundle{ val reorder_id = UInt(p.CFU_REORDER_ID_W bits) val request_id = UInt(p.CFU_REQ_RESP_ID_W bits) val inputs = Vec(Bits(p.CFU_INPUT_DATA_W bits), p.CFU_INPUTS) - + val state_index = UInt(log2Up(p.CFU_STATE_INDEX_NUM) bits) def weakAssignFrom(m : CfuCmd): Unit ={ def s = this WeakConnector(m, s, m.function_id, s.function_id, defaultValue = null, allowUpSize = false, allowDownSize = true , allowDrop = true) @@ -87,12 +88,16 @@ object CfuPlugin{ case class CfuPluginEncoding(instruction : MaskedLiteral, functionId : List[Range], - input2Kind : CfuPlugin.Input2Kind.E) + input2Kind : CfuPlugin.Input2Kind.E){ + val functionIdWidth = functionId.map(_.size).sum +} -class CfuPlugin( val stageCount : Int, - val allowZeroLatency : Boolean, - val busParameter : CfuBusParameter, - val encodings : List[CfuPluginEncoding] = null) extends Plugin[VexRiscv]{ +class CfuPlugin(val stageCount : Int, + val allowZeroLatency : Boolean, + val busParameter : CfuBusParameter, + val encodings : List[CfuPluginEncoding] = null, + val stateAndIndexCsrOffset : Int = 0xBC0, + val cfuIndexWidth : Int = 0) extends Plugin[VexRiscv]{ def p = busParameter assert(p.CFU_INPUTS <= 2) @@ -143,37 +148,25 @@ class CfuPlugin( val stageCount : Int, values = actions ) } - -// decoderService.add(List( -// //custom-0 -// M"-------------------------0001011" -> List( -// CFU_ENABLE -> True, -// REGFILE_WRITE_VALID -> True, -// BYPASSABLE_EXECUTE_STAGE -> Bool(stageCount == 0), -// BYPASSABLE_MEMORY_STAGE -> Bool(stageCount <= 1), -// RS1_USE -> True, -// RS2_USE -> True, -// CFU_IMM -> False -// ), -// -// //custom-1 -// M"-------------------------0101011" -> List( -// CFU_ENABLE -> True, -// REGFILE_WRITE_VALID -> True, -// BYPASSABLE_EXECUTE_STAGE -> Bool(stageCount == 0), -// BYPASSABLE_MEMORY_STAGE -> Bool(stageCount <= 1), -// RS1_USE -> True, -// CFU_IMM -> True -// ) -// )) - - } override def build(pipeline: VexRiscv): Unit = { import pipeline._ import pipeline.config._ + val csr = pipeline plug new Area{ + val stateId = Reg(UInt(log2Up(p.CFU_STATE_INDEX_NUM) bits)) init(0) + if(p.CFU_STATE_INDEX_NUM > 1) { + assert(stateAndIndexCsrOffset != -1, "CfuPlugin stateCsrIndex need to be set in the parameters") + pipeline.service(classOf[CsrInterface]).rw(stateAndIndexCsrOffset, 16, stateId) + } + bus.cmd.state_index := stateId + val cfuIndex = Reg(UInt(cfuIndexWidth bits)) init(0) + if(cfuIndexWidth != 0){ + pipeline.service(classOf[CsrInterface]).rw(stateAndIndexCsrOffset, 0, cfuIndex) + } + } + forkStage plug new Area{ import forkStage._ @@ -186,8 +179,9 @@ class CfuPlugin( val stageCount : Int, arbitration.haltItself setWhen(bus.cmd.valid && !bus.cmd.ready) // bus.cmd.function_id := U(input(INSTRUCTION)(14 downto 12)).resized - val functionsIds = encodings.map(e => U(Cat(e.functionId.map(r => input(INSTRUCTION)(r))), busParameter.CFU_FUNCTION_ID_W bits)) - bus.cmd.function_id := functionsIds.read(input(CFU_ENCODING)) + val functionIdFromInstructinoWidth = encodings.map(_.functionIdWidth).max + val functionsIds = encodings.map(e => U(Cat(e.functionId.map(r => input(INSTRUCTION)(r))), functionIdFromInstructinoWidth bits)) + bus.cmd.function_id := csr.cfuIndex @@ functionsIds.read(input(CFU_ENCODING)) bus.cmd.reorder_id := 0 bus.cmd.request_id := 0 if(p.CFU_INPUTS >= 1) bus.cmd.inputs(0) := input(RS1) From 8761d0d9eed9e3550e3fb7446812038941fce89b Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 13 Jan 2021 18:28:26 +0100 Subject: [PATCH 526/951] FpuCore can add/mul/fma/store/load --- src/main/scala/vexriscv/ip/fpu/FpuCore.scala | 387 ++++++++++++++++++ .../scala/vexriscv/ip/fpu/Interface.scala | 77 ++++ src/test/scala/vexriscv/ip/fpu/FpuTest.scala | 245 +++++++++++ .../scala/vexriscv/ip/fpu/Playground.scala | 39 ++ 4 files changed, 748 insertions(+) create mode 100644 src/main/scala/vexriscv/ip/fpu/FpuCore.scala create mode 100644 src/main/scala/vexriscv/ip/fpu/Interface.scala create mode 100644 src/test/scala/vexriscv/ip/fpu/FpuTest.scala create mode 100644 src/test/scala/vexriscv/ip/fpu/Playground.scala diff --git a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala new file mode 100644 index 00000000..b93dd0fd --- /dev/null +++ b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala @@ -0,0 +1,387 @@ +package vexriscv.ip.fpu + +import spinal.core._ +import spinal.lib._ +import spinal.lib.eda.bench.{Bench, Rtl, XilinxStdTargets} + +import scala.collection.mutable.ArrayBuffer + +case class FpuCore(p : FpuParameter) extends Component{ + val io = new Bundle { + val port = slave(FpuPort(p)) + } + + val rfLockCount = 5 + val lockIdType = HardType(UInt(log2Up(rfLockCount) bits)) + + io.port.rsp.valid := False + io.port.rsp.payload.assignDontCare() + + case class RfReadInput() extends Bundle{ + val source = p.source() + val opcode = p.Opcode() + val rs1, rs2, rs3 = p.rfAddress() + val rd = p.rfAddress() + } + + case class RfReadOutput() extends Bundle{ + val source = p.source() + val opcode = p.Opcode() + val lockId = lockIdType() + val rs1, rs2, rs3 = p.internalFloating() + val rd = p.rfAddress() + } + + + case class LoadInput() extends Bundle{ + val source = p.source() + val rs1 = p.internalFloating() + val rd = p.rfAddress() + val lockId = lockIdType() + } + + case class StoreInput() extends Bundle{ + val source = p.source() + val rs2 = p.internalFloating() + } + + case class MulInput() extends Bundle{ + val source = p.source() + val rs1, rs2, rs3 = p.internalFloating() + val rd = p.rfAddress() + val lockId = lockIdType() + val add = Bool() + val minus = Bool() + } + + case class AddInput() extends Bundle{ + val source = p.source() + val rs1, rs2 = p.internalFloating() + val rd = p.rfAddress() + val lockId = lockIdType() + } + + case class WriteInput() extends Bundle{ + val source = p.source() + val lockId = lockIdType() + val rd = p.rfAddress() + val value = p.internalFloating() + } + + + val rf = new Area{ + val ram = Mem(p.internalFloating, 32*(1 << p.sourceWidth)) + val lock = for(i <- 0 until rfLockCount) yield new Area{ + val valid = RegInit(False) + val source = Reg(p.source) + val address = Reg(p.rfAddress) + } + val lockFree = !lock.map(_.valid).andR + val lockFreeId = OHMasking.first(lock.map(!_.valid)) + } + + val read = new Area{ + val s0 = Stream(RfReadInput()) + s0.arbitrationFrom(io.port.cmd) + s0.payload.assignSomeByName(io.port.cmd.payload) + + val useRs1, useRs2, useRs3, useRd = False + switch(s0.opcode){ + is(p.Opcode.LOAD){ + useRd := True + } + is(p.Opcode.STORE){ + useRs2 := True + } + is(p.Opcode.ADD){ + useRs1 := True + useRs2 := True + useRd := True + } + is(p.Opcode.MUL){ + useRs1 := True + useRs2 := True + useRd := True + } + is(p.Opcode.FMA){ + useRs1 := True + useRs2 := True + useRs3 := True //Can be delayed to have less hazard + useRd := True + } + } + + val hits = List((useRs1, s0.rs1), (useRs2, s0.rs2), (useRs3, s0.rs3), (useRd, s0.rd)).map{case (use, reg) => use && rf.lock.map(l => l.valid && l.source === s0.source && l.address === reg).orR} + val hazard = hits.orR + when(s0.fire && useRd){ + for(i <- 0 until rfLockCount){ + when(rf.lockFreeId(i)){ + rf.lock(i).valid := True + rf.lock(i).source := s0.source + rf.lock(i).address := s0.rd + } + } + } + + val s1 = s0.haltWhen(hazard || !rf.lockFree).m2sPipe() + val output = s1.swapPayload(RfReadOutput()) + val s1LockId = RegNextWhen(OHToUInt(rf.lockFreeId), !output.isStall) + output.source := s1.source + output.opcode := s1.opcode + output.lockId := s1LockId + output.rd := s1.rd + output.rs1 := rf.ram.readSync(s0.rs1,enable = !output.isStall) + output.rs2 := rf.ram.readSync(s0.rs2,enable = !output.isStall) + output.rs3 := rf.ram.readSync(s0.rs3,enable = !output.isStall) + } + + val decode = new Area{ + val input = read.output.combStage() + input.ready := False + + val loadHit = input.opcode === p.Opcode.LOAD + val load = Stream(LoadInput()) + load.valid := input.valid && loadHit + input.ready setWhen(loadHit && load.ready) + load.source := read.output.source + load.rd := read.output.rd + load.rs1 := read.output.rs1 + load.lockId := read.output.lockId + + val storeHit = input.opcode === p.Opcode.STORE + val store = Stream(StoreInput()) + input.ready setWhen(storeHit && store.ready) + store.valid := input.valid && storeHit + store.source := read.output.source + store.rs2 := read.output.rs2 + + + val fmaHit = input.opcode === p.Opcode.FMA + val mulHit = input.opcode === p.Opcode.MUL || fmaHit + val mul = Stream(MulInput()) + input.ready setWhen(mulHit && mul.ready) + mul.valid := input.valid && mulHit + mul.source := read.output.source + mul.rs1 := read.output.rs1 + mul.rs2 := read.output.rs2 + mul.rs3 := read.output.rs3 + mul.rd := read.output.rd + mul.lockId := read.output.lockId + mul.add := fmaHit + mul.minus := False //TODO + + val addHit = input.opcode === p.Opcode.ADD + val add = Stream(AddInput()) + val mulToAdd = Stream(AddInput()) + + input.ready setWhen(addHit && add.ready && !mulToAdd.valid) + add.valid := input.valid && addHit || mulToAdd.valid + + + mulToAdd.ready := add.ready + add.payload := mulToAdd.payload + when(!mulToAdd.valid) { + add.payload.assignSomeByName(read.output.payload) + } + + + } + + val load = new Area{ + def input = decode.load + + val output = input.stage() + } + + + val store = new Area{ + val input = decode.store.stage() + + input.ready := io.port.rsp.ready + when(input.valid){ + io.port.rsp.valid := True + io.port.rsp.source := input.source + io.port.rsp.value := input.rs2.asBits + } + } + + val mul = new Area{ + val input = decode.mul.stage() + + val math = new Area { + val mulA = U"1" @@ input.rs1.mantissa + val mulB = U"1" @@ input.rs2.mantissa + val mulC = mulA * mulB + val exp = input.rs1.exponent +^ input.rs2.exponent - ((1 << p.internalExponentSize - 1) - 1) + } + + val norm = new Area{ + val needShift = math.mulC.msb + val exp = math.exp + U(needShift) + val man = needShift ? math.mulC(p.internalMantissaSize + 1, p.internalMantissaSize bits) | math.mulC(p.internalMantissaSize, p.internalMantissaSize bits) + + val output = FpuFloat(p.internalExponentSize, p.internalMantissaSize) + output.sign := input.rs1.sign ^ input.rs2.sign + output.exponent := exp.resized + output.mantissa := man + } + + val output = Stream(WriteInput()) + output.valid := input.valid && !input.add + output.source := input.source + output.lockId := input.lockId + output.rd := input.rd + output.value := norm.output + + decode.mulToAdd.valid := input.valid && input.add + decode.mulToAdd.source := input.source + decode.mulToAdd.rs1.mantissa := norm.output.mantissa + decode.mulToAdd.rs1.exponent := norm.output.exponent + decode.mulToAdd.rs1.sign := norm.output.sign ^ input.minus + decode.mulToAdd.rs2 := input.rs3 + decode.mulToAdd.rd := input.rd + decode.mulToAdd.lockId := input.lockId + + input.ready := (input.add ? decode.mulToAdd.ready | output.ready) + } + + val add = new Area{ + val input = decode.add.stage() + + val shifter = new Area { + val exp21 = input.rs2.exponent - input.rs1.exponent + val rs1ExponentBigger = exp21.msb + val rs1ExponentEqual = input.rs1.exponent === input.rs2.exponent + val rs1MantissaBigger = input.rs1.mantissa > input.rs2.mantissa + val absRs1Bigger = rs1ExponentBigger|| rs1ExponentEqual && rs1MantissaBigger + val shiftBy = rs1ExponentBigger ? (0-exp21) | exp21 + + //Note that rs1ExponentBigger can be replaced by absRs1Bigger bellow to avoid xsigned two complement in math block at expense of combinatorial path + val xySign = absRs1Bigger ? input.rs1.sign | input.rs2.sign + val xSign = xySign ^ (rs1ExponentBigger ? input.rs1.sign | input.rs2.sign) + val ySign = xySign ^ (rs1ExponentBigger ? input.rs2.sign | input.rs1.sign) + val xMantissa = U"1" @@ (rs1ExponentBigger ? input.rs1.mantissa | input.rs2.mantissa) + val yMantissaUnshifted = U"1" @@ (rs1ExponentBigger ? input.rs2.mantissa | input.rs1.mantissa) + val yMantissa = yMantissaUnshifted >> shiftBy + val xyExponent = rs1ExponentBigger ? input.rs1.exponent | input.rs2.exponent + } + + val math = new Area { + def xSign = shifter.xSign + def ySign = shifter.ySign + def xMantissa = shifter.xMantissa + def yMantissa = shifter.yMantissa + def xyExponent = shifter.xyExponent + def xySign = shifter.xySign + + val xSigned = xMantissa.twoComplement(xSign) + val ySigned = yMantissa.twoComplement(ySign) + val xyMantissa = U(xSigned +^ ySigned).trim(1 bits) + } + + val norm = new Area{ + def xyExponent = math.xyExponent + def xyMantissa = math.xyMantissa + def xySign = math.xySign + + val shiftOh = OHMasking.first(xyMantissa.asBools.reverse) + val shift = OHToUInt(shiftOh) + val mantissa = (xyMantissa |<< shift) >> 1 + val exponent = xyExponent - shift + 1 + } + + + val output = input.swapPayload(WriteInput()) + output.source := input.source + output.lockId := input.lockId + output.rd := input.rd + output.value.sign := norm.xySign + output.value.mantissa := norm.mantissa.resized + output.value.exponent := norm.exponent + } + + + val write = new Area{ + val port = rf.ram.writePort + port.valid := False + port.payload.assignDontCare() + + + val lockFree = Flow(lockIdType) + lockFree.valid := port.fire + lockFree.payload.assignDontCare() + + load.output.ready := False + mul.output.ready := False + add.output.ready := True + io.port.commit.ready := False + when(add.output.valid) { + port.valid := True + port.address := add.output.source @@ add.output.rd + port.data := add.output.value + + lockFree.payload := add.output.lockId + } elsewhen(mul.output.valid) { + port.valid := True + port.address := mul.output.source @@ mul.output.rd + port.data := mul.output.value + + mul.output.ready := True + lockFree.payload := mul.output.lockId + } elsewhen(load.output.valid && io.port.commit.valid) { + port.valid := io.port.commit.write + port.address := load.output.source @@ load.output.rd + port.data.assignFromBits(io.port.commit.value) + + load.output.ready := True + io.port.commit.ready := True + lockFree.payload := load.output.lockId + } + + when(lockFree.fire){ + for(i <- 0 until rfLockCount) when(lockFree.payload === i){ + rf.lock(i).valid := False + } + } + } +} + + + + +object StreamFifoMultiChannelBench extends App{ + val payloadType = HardType(Bits(8 bits)) + class Fpu(name : String, p : FpuParameter) extends Rtl{ + override def getName(): String = "Fpu_" + name + override def getRtlPath(): String = getName() + ".v" + SpinalVerilog(new FpuCore(p){ + + setDefinitionName(Fpu.this.getName()) + }) + } + + + + val rtls = ArrayBuffer[Fpu]() + rtls += new Fpu( + "32", + FpuParameter( + internalMantissaSize = 23, + withDouble = false, + sourceWidth = 0 + ) + ) + rtls += new Fpu( + "64", + FpuParameter( + internalMantissaSize = 52, + withDouble = true, + sourceWidth = 0 + ) + ) + + val targets = XilinxStdTargets()// ++ AlteraStdTargets() + + + Bench(rtls, targets) +} \ No newline at end of file diff --git a/src/main/scala/vexriscv/ip/fpu/Interface.scala b/src/main/scala/vexriscv/ip/fpu/Interface.scala new file mode 100644 index 00000000..a9963903 --- /dev/null +++ b/src/main/scala/vexriscv/ip/fpu/Interface.scala @@ -0,0 +1,77 @@ +package vexriscv.ip.fpu + +import spinal.core._ +import spinal.lib._ + + +object Fpu{ + + object Function{ + val MUL = 0 + val ADD = 1 + } + +} + + + +case class FpuFloat(exponentSize: Int, + mantissaSize: Int) extends Bundle { + val mantissa = UInt(mantissaSize bits) + val exponent = UInt(exponentSize bits) + val sign = Bool +} + +case class FpuOpcode(p : FpuParameter) extends SpinalEnum{ + val LOAD, STORE, MUL, ADD, FMA, I2F, F2I, CMP = newElement() +} + +case class FpuParameter( internalMantissaSize : Int, + withDouble : Boolean, + sourceWidth : Int){ + + val storeLoadType = HardType(Bits(if(withDouble) 64 bits else 32 bits)) + val internalExponentSize = if(withDouble) 11 else 8 + val internalFloating = HardType(FpuFloat(exponentSize = internalExponentSize, mantissaSize = internalMantissaSize)) +// val opcode = HardType(UInt(2 bits)) + val source = HardType(UInt(sourceWidth bits)) + val rfAddress = HardType(UInt(5 bits)) + + val Opcode = new FpuOpcode(this) + val Format = new SpinalEnum{ + val FLOAT = newElement() + val DOUBLE = withDouble generate newElement() + } +} + +case class FpuCmd(p : FpuParameter) extends Bundle{ + val source = UInt(p.sourceWidth bits) + val opcode = p.Opcode() + val value = Bits(32 bits) // Int to float + val function = Bits(3 bits) // Int to float + val rs1, rs2, rs3 = p.rfAddress() + val rd = p.rfAddress() + val format = p.Format() +} + +case class FpuCommit(p : FpuParameter) extends Bundle{ + val source = UInt(p.sourceWidth bits) + val write = Bool() + val value = p.storeLoadType() // IEEE 754 load +} + +case class FpuRsp(p : FpuParameter) extends Bundle{ + val source = UInt(p.sourceWidth bits) + val value = p.storeLoadType() // IEEE754 store || Integer +} + +case class FpuPort(p : FpuParameter) extends Bundle with IMasterSlave { + val cmd = Stream(FpuCmd(p)) + val commit = Stream(FpuCommit(p)) + val rsp = Stream(FpuRsp(p)) + + override def asMaster(): Unit = { + master(cmd, commit) + slave(rsp) + } +} diff --git a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala new file mode 100644 index 00000000..a2cd6d1b --- /dev/null +++ b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala @@ -0,0 +1,245 @@ +package vexriscv.ip.fpu + +import java.lang + +import org.scalatest.FunSuite +import spinal.core.SpinalEnumElement +import spinal.core.sim._ +import spinal.lib.experimental.math.Floating +import spinal.lib.sim._ + +import scala.collection.mutable +import scala.collection.mutable.ArrayBuffer +import scala.util.Random + +class FpuTest extends FunSuite{ + + + test("directed"){ + val p = FpuParameter( + internalMantissaSize = 23, + withDouble = false, + sourceWidth = 0 + ) + + SimConfig.withFstWave.compile(new FpuCore(p)).doSim(seed = 42){ dut => + dut.clockDomain.forkStimulus(10) + + + + + val cpus = for(id <- 0 until 1 << p.sourceWidth) yield new { + val cmdQueue = mutable.Queue[FpuCmd => Unit]() + val commitQueue = mutable.Queue[FpuCommit => Unit]() + val rspQueue = mutable.Queue[FpuRsp => Unit]() + + def loadRaw(rd : Int, value : BigInt): Unit ={ + cmdQueue += {cmd => + cmd.source #= id + cmd.opcode #= cmd.opcode.spinalEnum.LOAD + cmd.value.randomize() + cmd.rs1.randomize() + cmd.rs2.randomize() + cmd.rs3.randomize() + cmd.rd #= rd + } + commitQueue += {cmd => + cmd.source #= id + cmd.write #= true + cmd.value #= value + } + } + + def load(rd : Int, value : Float): Unit ={ + loadRaw(rd, lang.Float.floatToIntBits(value).toLong & 0xFFFFFFFFl) + } + + def storeRaw(rs : Int)(body : FpuRsp => Unit): Unit ={ + cmdQueue += {cmd => + cmd.source #= id + cmd.opcode #= cmd.opcode.spinalEnum.STORE + cmd.value.randomize() + cmd.rs1.randomize() + cmd.rs2 #= rs + cmd.rs3.randomize() + cmd.rd.randomize() + } + + rspQueue += body + } + + def storeFloat(rs : Int)(body : Float => Unit): Unit ={ + storeRaw(rs){rsp => body(lang.Float.intBitsToFloat(rsp.value.toLong.toInt))} + } + + def mul(rd : Int, rs1 : Int, rs2 : Int): Unit ={ + cmdQueue += {cmd => + cmd.source #= id + cmd.opcode #= cmd.opcode.spinalEnum.MUL + cmd.value.randomize() + cmd.rs1 #= rs1 + cmd.rs2 #= rs2 + cmd.rs3.randomize() + cmd.rd #= rd + } + } + + def add(rd : Int, rs1 : Int, rs2 : Int): Unit ={ + cmdQueue += {cmd => + cmd.source #= id + cmd.opcode #= cmd.opcode.spinalEnum.ADD + cmd.value.randomize() + cmd.rs1 #= rs1 + cmd.rs2 #= rs2 + cmd.rs3.randomize() + cmd.rd #= rd + } + } + + def fma(rd : Int, rs1 : Int, rs2 : Int, rs3 : Int): Unit ={ + cmdQueue += {cmd => + cmd.source #= id + cmd.opcode #= cmd.opcode.spinalEnum.FMA + cmd.value.randomize() + cmd.rs1 #= rs1 + cmd.rs2 #= rs2 + cmd.rs3 #= rs3 + cmd.rd #= rd + } + } + } + + StreamDriver(dut.io.port.cmd ,dut.clockDomain){payload => + cpus.map(_.cmdQueue).filter(_.nonEmpty).toSeq match { + case Nil => false + case l => { + l.randomPick().dequeue().apply(payload) + true + } + } + } + + StreamDriver(dut.io.port.commit ,dut.clockDomain){payload => + cpus.map(_.commitQueue).filter(_.nonEmpty).toSeq match { + case Nil => false + case l => { + l.randomPick().dequeue().apply(payload) + true + } + } + } + + + StreamMonitor(dut.io.port.rsp, dut.clockDomain){payload => + cpus(payload.source.toInt).rspQueue.dequeue().apply(payload) + } + + StreamReadyRandomizer(dut.io.port.rsp, dut.clockDomain) + + + + + + val stim = for(cpu <- cpus) yield fork { + import cpu._ + + class RegAllocator(){ + var value = 0 + + def allocate(): Int ={ + while(true){ + val rand = Random.nextInt(32) + val mask = 1 << rand + if((value & mask) == 0) { + value |= mask + return rand + } + } + 0 + } + } + def checkFloat(ref : Float, dut : Float): Boolean ={ + ref.abs * 1.0001 > dut.abs && ref.abs * 0.9999 < dut.abs && ref.signum == dut.signum + } + + def randomFloat(): Float ={ + Random.nextFloat() * 1e2f * (if(Random.nextBoolean()) -1f else 1f) + } + + def testAdd(a : Float, b : Float): Unit ={ + val rs = new RegAllocator() + val rs1, rs2, rs3 = rs.allocate() + val rd = Random.nextInt(32) + load(rs1, a) + load(rs2, b) + + add(rd,rs1,rs2) + storeFloat(rd){v => + val ref = a+b + println(f"$a + $b = $v, $ref") + assert(checkFloat(ref, v)) + } + } + + def testMul(a : Float, b : Float): Unit ={ + val rs = new RegAllocator() + val rs1, rs2, rs3 = rs.allocate() + val rd = Random.nextInt(32) + load(rs1, a) + load(rs2, b) + + mul(rd,rs1,rs2) + storeFloat(rd){v => + val ref = a*b + println(f"$a * $b = $v, $ref") + assert(checkFloat(ref, v)) + } + } + + + def testFma(a : Float, b : Float, c : Float): Unit ={ + val rs = new RegAllocator() + val rs1, rs2, rs3 = rs.allocate() + val rd = Random.nextInt(32) + load(rs1, a) + load(rs2, b) + load(rs3, c) + + fma(rd,rs1,rs2,rs3) + storeFloat(rd){v => + val ref = a * b + c + println(f"$a * $b + $c = $v, $ref") + assert(checkFloat(ref, v)) + } + } + +// testAdd(0.1f, 1.6f) +// testMul(0.1f, 1.6f) + testFma(1.1f, 2.2f, 3.0f) + + for(i <- 0 until 1000){ + testAdd(randomFloat(), randomFloat()) + } + for(i <- 0 until 1000){ + testMul(randomFloat(), randomFloat()) + } + for(i <- 0 until 1000){ + testFma(randomFloat(), randomFloat(), randomFloat()) + } + for(i <- 0 until 1000){ + val tests = ArrayBuffer[() => Unit]() + tests += (() =>{testAdd(randomFloat(), randomFloat())}) + tests += (() =>{testMul(randomFloat(), randomFloat())}) + tests += (() =>{testFma(randomFloat(), randomFloat(), randomFloat())}) + tests.randomPick().apply() + } + + waitUntil(cpu.rspQueue.isEmpty) + } + + + stim.foreach(_.join()) + dut.clockDomain.waitSampling(100) + } + } +} diff --git a/src/test/scala/vexriscv/ip/fpu/Playground.scala b/src/test/scala/vexriscv/ip/fpu/Playground.scala new file mode 100644 index 00000000..2fb99adc --- /dev/null +++ b/src/test/scala/vexriscv/ip/fpu/Playground.scala @@ -0,0 +1,39 @@ +package vexriscv.ip.fpu + +object MiaouDiv extends App{ + val input = 2.5 + var output = 1/(input*0.95) +// def x = output +// def y = input + + def y = output + def x = input + + for(i <- 0 until 10) { + output = 2 * y - x * y * y + println(output) + } + + + //output = x*output + println(1/input) +} + +object MiaouSqrt extends App{ + val input = 2.0 + var output = 1/Math.sqrt(input*0.95) + // def x = output + // def y = input + + def y = output + def x = input + + for(i <- 0 until 10) { + output = y*(1.5-x*y*y/2) + println(output) + } + + output = x*output + println(output) + println(s"ref ${Math.sqrt(input)}") +} From 5e6c64546123fe0126ae5cb523af7b3648e608db Mon Sep 17 00:00:00 2001 From: Samuel Lindemer Date: Thu, 14 Jan 2021 08:34:54 +0100 Subject: [PATCH 527/951] Distinguish between page faults from MMU and access faults from PMP --- src/main/scala/vexriscv/Services.scala | 1 + src/main/scala/vexriscv/ip/DataCache.scala | 23 +++++++++++-------- .../scala/vexriscv/ip/InstructionCache.scala | 8 +++---- .../vexriscv/plugin/DBusCachedPlugin.scala | 9 ++++---- .../scala/vexriscv/plugin/MmuPlugin.scala | 2 ++ .../scala/vexriscv/plugin/PmpPlugin.scala | 1 + .../plugin/StaticMemoryTranslatorPlugin.scala | 1 + 7 files changed, 26 insertions(+), 19 deletions(-) diff --git a/src/main/scala/vexriscv/Services.scala b/src/main/scala/vexriscv/Services.scala index 4b0aeca5..47a16d1a 100644 --- a/src/main/scala/vexriscv/Services.scala +++ b/src/main/scala/vexriscv/Services.scala @@ -71,6 +71,7 @@ case class MemoryTranslatorCmd() extends Bundle{ case class MemoryTranslatorRsp() extends Bundle{ val physicalAddress = UInt(32 bits) val isIoAccess = Bool + val isPaging = Bool val allowRead, allowWrite, allowExecute = Bool val exception = Bool val refilling = Bool diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index 7cbe4ba7..1c606903 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -551,9 +551,20 @@ class DataCache(p : DataCacheConfig) extends Component{ val memCmdSent = RegInit(False) setWhen (io.mem.cmd.ready) clearWhen (!io.cpu.writeBack.isStuck) - io.cpu.redo := False + val badPermissions = (!mmuRsp.allowWrite && request.wr) || (!mmuRsp.allowRead && (!request.wr || isAmo)) + val loadStoreFault = io.cpu.writeBack.isValid && (mmuRsp.exception || badPermissions) + io.cpu.writeBack.accessError := False - io.cpu.writeBack.mmuException := io.cpu.writeBack.isValid && (if(catchIllegal) mmuRsp.exception || (!mmuRsp.allowWrite && request.wr) || (!mmuRsp.allowRead && (!request.wr || isAmo)) else False) + when(mmuRsp.isIoAccess) { + io.cpu.writeBack.data := io.mem.rsp.data + if (catchAccessError) io.cpu.writeBack.accessError := io.mem.rsp.valid && io.mem.rsp.error + } otherwise { + io.cpu.writeBack.data := dataMux + if (catchAccessError) io.cpu.writeBack.accessError := (waysHits & B(tagsReadRsp.map(_.error))) =/= 0 || (loadStoreFault && !mmuRsp.isPaging) + } + + io.cpu.redo := False + io.cpu.writeBack.mmuException := loadStoreFault && (if(catchIllegal) mmuRsp.isPaging else False) io.cpu.writeBack.unalignedAccess := io.cpu.writeBack.isValid && (if(catchUnaligned) ((request.size === 2 && mmuRsp.physicalAddress(1 downto 0) =/= 0) || (request.size === 1 && mmuRsp.physicalAddress(0 downto 0) =/= 0)) else False) io.cpu.writeBack.isWrite := request.wr @@ -626,14 +637,6 @@ class DataCache(p : DataCacheConfig) extends Component{ } } - when(mmuRsp.isIoAccess){ - io.cpu.writeBack.data := io.mem.rsp.data - if(catchAccessError) io.cpu.writeBack.accessError := io.mem.rsp.valid && io.mem.rsp.error - } otherwise { - io.cpu.writeBack.data := dataMux - if(catchAccessError) io.cpu.writeBack.accessError := (waysHits & B(tagsReadRsp.map(_.error))) =/= 0 - } - //remove side effects on exceptions when(mmuRsp.refilling || io.cpu.writeBack.accessError || io.cpu.writeBack.mmuException || io.cpu.writeBack.unalignedAccess){ io.mem.cmd.valid := False diff --git a/src/main/scala/vexriscv/ip/InstructionCache.scala b/src/main/scala/vexriscv/ip/InstructionCache.scala index 4df0f79d..380e6b3a 100644 --- a/src/main/scala/vexriscv/ip/InstructionCache.scala +++ b/src/main/scala/vexriscv/ip/InstructionCache.scala @@ -438,9 +438,9 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{ val mmuRsp = io.cpu.fetch.mmuBus.rsp io.cpu.fetch.cacheMiss := !hit.valid - io.cpu.fetch.error := hit.error + io.cpu.fetch.error := hit.error || (!mmuRsp.isPaging && (mmuRsp.exception || !mmuRsp.allowExecute)) io.cpu.fetch.mmuRefilling := mmuRsp.refilling - io.cpu.fetch.mmuException := !mmuRsp.refilling && (mmuRsp.exception || !mmuRsp.allowExecute) + io.cpu.fetch.mmuException := !mmuRsp.refilling && mmuRsp.isPaging && (mmuRsp.exception || !mmuRsp.allowExecute) }) } @@ -468,9 +468,9 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{ } io.cpu.decode.cacheMiss := !hit.valid - io.cpu.decode.error := hit.error + io.cpu.decode.error := hit.error || (!mmuRsp.isPaging && (mmuRsp.exception || !mmuRsp.allowExecute)) io.cpu.decode.mmuRefilling := mmuRsp.refilling - io.cpu.decode.mmuException := !mmuRsp.refilling && (mmuRsp.exception || !mmuRsp.allowExecute) + io.cpu.decode.mmuException := !mmuRsp.refilling && mmuRsp.isPaging && (mmuRsp.exception || !mmuRsp.allowExecute) io.cpu.decode.physicalAddress := mmuRsp.physicalAddress }) } diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index fd45dd80..1dedd794 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -273,15 +273,14 @@ class DBusCachedPlugin(val config : DataCacheConfig, exceptionBus.valid := True exceptionBus.code := (input(MEMORY_WR) ? U(7) | U(5)).resized } - - if (catchUnaligned) when(cache.io.cpu.writeBack.unalignedAccess) { - exceptionBus.valid := True - exceptionBus.code := (input(MEMORY_WR) ? U(6) | U(4)).resized - } if(catchIllegal) when (cache.io.cpu.writeBack.mmuException) { exceptionBus.valid := True exceptionBus.code := (input(MEMORY_WR) ? U(15) | U(13)).resized } + if (catchUnaligned) when(cache.io.cpu.writeBack.unalignedAccess) { + exceptionBus.valid := True + exceptionBus.code := (input(MEMORY_WR) ? U(6) | U(4)).resized + } when(cache.io.cpu.redo) { redoBranch.valid := True diff --git a/src/main/scala/vexriscv/plugin/MmuPlugin.scala b/src/main/scala/vexriscv/plugin/MmuPlugin.scala index 9dedde5d..6d7f6a8a 100644 --- a/src/main/scala/vexriscv/plugin/MmuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/MmuPlugin.scala @@ -127,6 +127,7 @@ class MmuPlugin(ioRange : UInt => Bool, port.bus.rsp.allowExecute := cacheLine.allowExecute port.bus.rsp.exception := cacheHit && (cacheLine.exception || cacheLine.allowUser && privilegeService.isSupervisor() && !csr.status.sum || !cacheLine.allowUser && privilegeService.isUser()) port.bus.rsp.refilling := !cacheHit + port.bus.rsp.isPaging := True } otherwise { port.bus.rsp.physicalAddress := port.bus.cmd.virtualAddress port.bus.rsp.allowRead := True @@ -134,6 +135,7 @@ class MmuPlugin(ioRange : UInt => Bool, port.bus.rsp.allowExecute := True port.bus.rsp.exception := False port.bus.rsp.refilling := False + port.bus.rsp.isPaging := False } port.bus.rsp.isIoAccess := ioRange(port.bus.rsp.physicalAddress) diff --git a/src/main/scala/vexriscv/plugin/PmpPlugin.scala b/src/main/scala/vexriscv/plugin/PmpPlugin.scala index f232ee49..88be675c 100644 --- a/src/main/scala/vexriscv/plugin/PmpPlugin.scala +++ b/src/main/scala/vexriscv/plugin/PmpPlugin.scala @@ -205,6 +205,7 @@ class PmpPlugin(regions : Int, ioRange : UInt => Bool) extends Plugin[VexRiscv] } port.bus.rsp.isIoAccess := ioRange(port.bus.rsp.physicalAddress) + port.bus.rsp.isPaging := False port.bus.rsp.exception := False port.bus.rsp.refilling := False port.bus.busy := False diff --git a/src/main/scala/vexriscv/plugin/StaticMemoryTranslatorPlugin.scala b/src/main/scala/vexriscv/plugin/StaticMemoryTranslatorPlugin.scala index 351ebc55..7a31d186 100644 --- a/src/main/scala/vexriscv/plugin/StaticMemoryTranslatorPlugin.scala +++ b/src/main/scala/vexriscv/plugin/StaticMemoryTranslatorPlugin.scala @@ -32,6 +32,7 @@ class StaticMemoryTranslatorPlugin(ioRange : UInt => Bool) extends Plugin[VexRis port.bus.rsp.allowWrite := True port.bus.rsp.allowExecute := True port.bus.rsp.isIoAccess := ioRange(port.bus.rsp.physicalAddress) + port.bus.rsp.isPaging := False port.bus.rsp.exception := False port.bus.rsp.refilling := False port.bus.busy := False From 85dd5dbf8e320f5fdab2044e40cff7002905a392 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 14 Jan 2021 15:56:56 +0100 Subject: [PATCH 528/951] fpu div functional, sqrt wip --- src/main/scala/vexriscv/ip/fpu/FpuCore.scala | 229 ++++++++++++++++-- .../scala/vexriscv/ip/fpu/Interface.scala | 2 +- src/test/scala/vexriscv/ip/fpu/FpuTest.scala | 70 +++++- .../scala/vexriscv/ip/fpu/Playground.scala | 4 +- 4 files changed, 281 insertions(+), 24 deletions(-) diff --git a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala index b93dd0fd..8f7657ab 100644 --- a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala +++ b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala @@ -6,6 +6,10 @@ import spinal.lib.eda.bench.{Bench, Rtl, XilinxStdTargets} import scala.collection.mutable.ArrayBuffer +object FpuDivSqrtIterationState extends SpinalEnum{ + val IDLE, YY, XYY, Y2_XYY, DIV, Y_15_XYY2, Y_15_XYY2_RESULT, SQRT = newElement() +} + case class FpuCore(p : FpuParameter) extends Component{ val io = new Bundle { val port = slave(FpuPort(p)) @@ -51,9 +55,19 @@ case class FpuCore(p : FpuParameter) extends Component{ val rd = p.rfAddress() val lockId = lockIdType() val add = Bool() + val divSqrt = Bool() + val msb1, msb2 = Bool() //allow usage of msb bits of mul val minus = Bool() } + case class DivSqrtInput() extends Bundle{ + val source = p.source() + val rs1, rs2 = p.internalFloating() + val rd = p.rfAddress() + val lockId = lockIdType() + val div = Bool() + } + case class AddInput() extends Bundle{ val source = p.source() val rs1, rs2 = p.internalFloating() @@ -103,6 +117,11 @@ case class FpuCore(p : FpuParameter) extends Component{ useRs2 := True useRd := True } + is(p.Opcode.DIV_SQRT){ + useRs1 := True + useRs2 := True //TODO + useRd := True + } is(p.Opcode.FMA){ useRs1 := True useRs2 := True @@ -155,20 +174,35 @@ case class FpuCore(p : FpuParameter) extends Component{ store.source := read.output.source store.rs2 := read.output.rs2 + val divSqrtHit = input.opcode === p.Opcode.DIV_SQRT + val divSqrt = Stream(DivSqrtInput()) + input.ready setWhen(divSqrtHit && divSqrt.ready) + divSqrt.valid := input.valid && divSqrtHit + divSqrt.source := read.output.source + divSqrt.rs1 := read.output.rs1 + divSqrt.rs2 := read.output.rs2 + divSqrt.rd := read.output.rd + divSqrt.lockId := read.output.lockId + divSqrt.div := True //TODO val fmaHit = input.opcode === p.Opcode.FMA val mulHit = input.opcode === p.Opcode.MUL || fmaHit val mul = Stream(MulInput()) - input.ready setWhen(mulHit && mul.ready) - mul.valid := input.valid && mulHit - mul.source := read.output.source - mul.rs1 := read.output.rs1 - mul.rs2 := read.output.rs2 - mul.rs3 := read.output.rs3 - mul.rd := read.output.rd - mul.lockId := read.output.lockId - mul.add := fmaHit - mul.minus := False //TODO + val divSqrtToMul = Stream(MulInput()) + + input.ready setWhen(mulHit && mul.ready && !divSqrtToMul.valid) + mul.valid := input.valid && mulHit || divSqrtToMul.valid + + divSqrtToMul.ready := mul.ready + mul.payload := divSqrtToMul.payload + when(!divSqrtToMul.valid) { + mul.payload.assignSomeByName(read.output.payload) + mul.add := fmaHit + mul.divSqrt := False + mul.msb1 := True + mul.msb2 := True + mul.minus := False //TODO + } val addHit = input.opcode === p.Opcode.ADD val add = Stream(AddInput()) @@ -183,8 +217,6 @@ case class FpuCore(p : FpuParameter) extends Component{ when(!mulToAdd.valid) { add.payload.assignSomeByName(read.output.payload) } - - } val load = new Area{ @@ -209,8 +241,8 @@ case class FpuCore(p : FpuParameter) extends Component{ val input = decode.mul.stage() val math = new Area { - val mulA = U"1" @@ input.rs1.mantissa - val mulB = U"1" @@ input.rs2.mantissa + val mulA = U(input.msb1) @@ input.rs1.mantissa + val mulB = U(input.msb2) @@ input.rs2.mantissa val mulC = mulA * mulB val exp = input.rs1.exponent +^ input.rs2.exponent - ((1 << p.internalExponentSize - 1) - 1) } @@ -226,8 +258,14 @@ case class FpuCore(p : FpuParameter) extends Component{ output.mantissa := man } + val notMul = new Area{ + val output = Flow(UInt(p.internalMantissaSize + 1 bits)) + output.valid := input.valid && input.divSqrt + output.payload := math.mulC(p.internalMantissaSize, p.internalMantissaSize+1 bits) + } + val output = Stream(WriteInput()) - output.valid := input.valid && !input.add + output.valid := input.valid && !input.add && !input.divSqrt output.source := input.source output.lockId := input.lockId output.rd := input.rd @@ -242,7 +280,164 @@ case class FpuCore(p : FpuParameter) extends Component{ decode.mulToAdd.rd := input.rd decode.mulToAdd.lockId := input.lockId - input.ready := (input.add ? decode.mulToAdd.ready | output.ready) + input.ready := (input.add ? decode.mulToAdd.ready | output.ready) || input.divSqrt + } + + val divSqrt = new Area { + val input = decode.divSqrt.stage() + + val aproxWidth = 8 + val aproxDepth = 64 + val divIterationCount = 3 + val sqrtIterationCount = 3 + + val mulWidth = p.internalMantissaSize + 1 + + import FpuDivSqrtIterationState._ + val state = RegInit(FpuDivSqrtIterationState.IDLE()) + val iteration = Reg(UInt(log2Up(divIterationCount max sqrtIterationCount) bits)) + + decode.divSqrtToMul.valid := False + decode.divSqrtToMul.source := input.source + decode.divSqrtToMul.rs1.assignDontCare() + decode.divSqrtToMul.rs2.assignDontCare() + decode.divSqrtToMul.rs3.assignDontCare() + decode.divSqrtToMul.rd := input.rd + decode.divSqrtToMul.lockId := input.lockId + decode.divSqrtToMul.add := False + decode.divSqrtToMul.divSqrt := True + decode.divSqrtToMul.msb1 := True + decode.divSqrtToMul.msb2 := True + decode.divSqrtToMul.minus := False + + + val aprox = new Area { + val rom = Mem(UInt(aproxWidth bits), aproxDepth * 2) + val divTable, sqrtTable = ArrayBuffer[Double]() + for(i <- 0 until aproxDepth){ + val mantissa = 1+(i+0.5)/aproxDepth + divTable += 1/mantissa + sqrtTable += 1/Math.sqrt(mantissa) + } + val romElaboration = (sqrtTable ++ divTable).map(v => BigInt(((v-0.5)*2*(1 << aproxWidth)).round)) + + rom.initBigInt(romElaboration) + val address = U(input.div ## (input.div ? input.rs2.mantissa | input.rs1.mantissa).takeHigh(log2Up(aproxDepth))) + val raw = rom.readAsync(address) + val result = U"01" @@ (raw << (mulWidth-aproxWidth-2)) + } + + val divExp = new Area{ + val value = (1 << p.internalExponentSize) - 3 - input.rs2.exponent + } + val sqrtExp = new Area{ + val value = ((1 << p.internalExponentSize-1) + (1 << p.internalExponentSize-2) - 2) - (input.rs2.exponent >> 1) + input.rs2.exponent.lsb.asUInt + } + + def mulArg(rs1 : UInt, rs2 : UInt): Unit ={ + decode.divSqrtToMul.rs1.mantissa := rs1.resized + decode.divSqrtToMul.rs2.mantissa := rs2.resized + decode.divSqrtToMul.msb1 := rs1.msb + decode.divSqrtToMul.msb2 := rs2.msb + } + + val mulBuffer = mul.notMul.output.toStream.stage + mulBuffer.ready := False + + val iterationValue = Reg(UInt(mulWidth bits)) + //val squareInput = (iteration === 0) ? aprox.result | iterationValue + + input.ready := False + switch(state){ + is(IDLE){ + iterationValue := aprox.result + iteration := 0 + when(input.valid) { + state := YY + } + } + is(YY){ + decode.divSqrtToMul.valid := True + mulArg(iterationValue, iterationValue) + when(decode.divSqrtToMul.ready) { + state := XYY + } + } + is(XYY){ + decode.divSqrtToMul.valid := mulBuffer.valid + mulArg(U"1" @@ (input.div ? input.rs2.mantissa | input.rs1.mantissa), mulBuffer.payload) + when(mulBuffer.valid && decode.divSqrtToMul.ready) { + state := (input.div ? Y2_XYY | Y_15_XYY2) + mulBuffer.ready := input.div + when(!input.div){ + mulBuffer.payload.getDrivingReg := (U"11" << mulWidth-2) - (mulBuffer.payload >> 1) + } + } + } + is(Y2_XYY){ + mulBuffer.ready := True + when(mulBuffer.valid) { + iterationValue := ((iterationValue << 1) - mulBuffer.payload).resized + mulBuffer.ready := True + iteration := iteration + 1 + when(iteration =/= divIterationCount-1){ //TODO + state := YY + } otherwise { + state := DIV + } + } + } + is(DIV){ + decode.divSqrtToMul.valid := True + decode.divSqrtToMul.divSqrt := False + decode.divSqrtToMul.rs1 := input.rs1 + decode.divSqrtToMul.rs2.sign := input.rs2.sign + decode.divSqrtToMul.rs2.exponent := divExp.value + iterationValue.msb.asUInt + decode.divSqrtToMul.rs2.mantissa := (iterationValue << 1).resized + when(decode.divSqrtToMul.ready) { + state := IDLE + input.ready := True + } + } + is(Y_15_XYY2){ + decode.divSqrtToMul.valid := True + mulArg(U"1" @@ input.rs1.mantissa, mulBuffer.payload) + when(decode.divSqrtToMul.ready) { + mulBuffer.ready := True + state := SQRT + } + } + is(Y_15_XYY2_RESULT){ + when(iteration =/= sqrtIterationCount-1 && !input.rs1.exponent.lsb) { + iterationValue := mulBuffer.payload + } otherwise { + val v = 1.0/Math.sqrt(2.0) + val scaled = v* (BigInt(1) << mulWidth-1).toDouble + val bigInt = BigDecimal(scaled).toBigInt() + iterationValue := mulBuffer.payload + U(bigInt) + } + mulBuffer.ready := True + when(mulBuffer.valid) { + when(iteration =/= sqrtIterationCount-1){ + state := YY + } otherwise { + state := SQRT + } + } + } + is(SQRT){ + decode.divSqrtToMul.valid := True + decode.divSqrtToMul.divSqrt := False + decode.divSqrtToMul.rs1 := input.rs1 + decode.divSqrtToMul.rs2.sign := False + decode.divSqrtToMul.rs2.exponent := sqrtExp.value + iterationValue.msb.asUInt + decode.divSqrtToMul.rs2.mantissa := (iterationValue << 1).resized + when(decode.divSqrtToMul.ready) { + state := IDLE + input.ready := True + } + } + } } val add = new Area{ @@ -349,7 +544,7 @@ case class FpuCore(p : FpuParameter) extends Component{ -object StreamFifoMultiChannelBench extends App{ +object FpuSynthesisBench extends App{ val payloadType = HardType(Bits(8 bits)) class Fpu(name : String, p : FpuParameter) extends Rtl{ override def getName(): String = "Fpu_" + name diff --git a/src/main/scala/vexriscv/ip/fpu/Interface.scala b/src/main/scala/vexriscv/ip/fpu/Interface.scala index a9963903..b07c18c9 100644 --- a/src/main/scala/vexriscv/ip/fpu/Interface.scala +++ b/src/main/scala/vexriscv/ip/fpu/Interface.scala @@ -23,7 +23,7 @@ case class FpuFloat(exponentSize: Int, } case class FpuOpcode(p : FpuParameter) extends SpinalEnum{ - val LOAD, STORE, MUL, ADD, FMA, I2F, F2I, CMP = newElement() + val LOAD, STORE, MUL, ADD, FMA, I2F, F2I, CMP, DIV_SQRT = newElement() } case class FpuParameter( internalMantissaSize : Int, diff --git a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala index a2cd6d1b..68c3e461 100644 --- a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala +++ b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala @@ -96,6 +96,18 @@ class FpuTest extends FunSuite{ } } + def div(rd : Int, rs1 : Int, rs2 : Int): Unit ={ + cmdQueue += {cmd => + cmd.source #= id + cmd.opcode #= cmd.opcode.spinalEnum.DIV_SQRT + cmd.value.randomize() + cmd.rs1 #= rs1 + cmd.rs2 #= rs2 + cmd.rs3.randomize() + cmd.rd #= rd + } + } + def fma(rd : Int, rs1 : Int, rs2 : Int, rs3 : Int): Unit ={ cmdQueue += {cmd => cmd.source #= id @@ -213,9 +225,57 @@ class FpuTest extends FunSuite{ } } -// testAdd(0.1f, 1.6f) -// testMul(0.1f, 1.6f) + + def testDiv(a : Float, b : Float): Unit ={ + val rs = new RegAllocator() + val rs1, rs2, rs3 = rs.allocate() + val rd = Random.nextInt(32) + load(rs1, a) + load(rs2, b) + + div(rd,rs1,rs2) + storeFloat(rd){v => + val ref = a/b + val error = Math.abs(ref-v)/ref + println(f"$a / $b = $v, $ref $error") + assert(checkFloat(ref, v)) + } + } + + def testSqrt(a : Float): Unit ={ + val rs = new RegAllocator() + val rs1, rs2, rs3 = rs.allocate() + val rd = Random.nextInt(32) + load(rs1, a) + + div(rd,rs1,rs2) + storeFloat(rd){v => + val ref = Math.sqrt(a).toFloat + val error = Math.abs(ref-v)/ref + println(f"sqrt($a) = $v, $ref $error") + assert(checkFloat(ref, v)) + } + } + + val b2f = lang.Float.intBitsToFloat(_) + + +// testSqrt(2.25f) +// dut.clockDomain.waitSampling(100) +// simFailure() + + testAdd(0.1f, 1.6f) + testMul(0.1f, 1.6f) testFma(1.1f, 2.2f, 3.0f) + testDiv(1.0f, 1.1f) + testDiv(1.0f, 1.5f) + testDiv(1.0f, 1.9f) + testDiv(1.1f, 1.9f) + testDiv(1.0f, b2f(0x3f7ffffe)) + testDiv(1.0f, b2f(0x3f7fffff)) + testDiv(1.0f, b2f(0x3f800000)) + testDiv(1.0f, b2f(0x3f800001)) + testDiv(1.0f, b2f(0x3f800002)) for(i <- 0 until 1000){ testAdd(randomFloat(), randomFloat()) @@ -226,14 +286,18 @@ class FpuTest extends FunSuite{ for(i <- 0 until 1000){ testFma(randomFloat(), randomFloat(), randomFloat()) } + + for(i <- 0 until 1000){ + testDiv(randomFloat(), randomFloat()) + } for(i <- 0 until 1000){ val tests = ArrayBuffer[() => Unit]() tests += (() =>{testAdd(randomFloat(), randomFloat())}) tests += (() =>{testMul(randomFloat(), randomFloat())}) tests += (() =>{testFma(randomFloat(), randomFloat(), randomFloat())}) + tests += (() =>{testDiv(randomFloat(), randomFloat())}) tests.randomPick().apply() } - waitUntil(cpu.rspQueue.isEmpty) } diff --git a/src/test/scala/vexriscv/ip/fpu/Playground.scala b/src/test/scala/vexriscv/ip/fpu/Playground.scala index 2fb99adc..71b500da 100644 --- a/src/test/scala/vexriscv/ip/fpu/Playground.scala +++ b/src/test/scala/vexriscv/ip/fpu/Playground.scala @@ -3,8 +3,6 @@ package vexriscv.ip.fpu object MiaouDiv extends App{ val input = 2.5 var output = 1/(input*0.95) -// def x = output -// def y = input def y = output def x = input @@ -29,7 +27,7 @@ object MiaouSqrt extends App{ def x = input for(i <- 0 until 10) { - output = y*(1.5-x*y*y/2) + output = y * (1.5 - x * y * y / 2) println(output) } From 04499c0b765d0a05b23827108b05a7f899d6653b Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 14 Jan 2021 18:33:24 +0100 Subject: [PATCH 529/951] FPU sqrt functional --- src/main/scala/vexriscv/ip/fpu/FpuCore.scala | 63 +++++++++++-------- .../scala/vexriscv/ip/fpu/Interface.scala | 2 +- src/test/scala/vexriscv/ip/fpu/FpuTest.scala | 46 +++++++++++--- 3 files changed, 74 insertions(+), 37 deletions(-) diff --git a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala index 8f7657ab..8209c11a 100644 --- a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala +++ b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala @@ -7,7 +7,7 @@ import spinal.lib.eda.bench.{Bench, Rtl, XilinxStdTargets} import scala.collection.mutable.ArrayBuffer object FpuDivSqrtIterationState extends SpinalEnum{ - val IDLE, YY, XYY, Y2_XYY, DIV, Y_15_XYY2, Y_15_XYY2_RESULT, SQRT = newElement() + val IDLE, YY, XYY, Y2_XYY, DIV, _15_XYY2, Y_15_XYY2, Y_15_XYY2_RESULT, SQRT = newElement() } case class FpuCore(p : FpuParameter) extends Component{ @@ -117,9 +117,13 @@ case class FpuCore(p : FpuParameter) extends Component{ useRs2 := True useRd := True } - is(p.Opcode.DIV_SQRT){ + is(p.Opcode.DIV){ + useRs1 := True + useRs2 := True + useRd := True + } + is(p.Opcode.SQRT){ useRs1 := True - useRs2 := True //TODO useRd := True } is(p.Opcode.FMA){ @@ -174,7 +178,7 @@ case class FpuCore(p : FpuParameter) extends Component{ store.source := read.output.source store.rs2 := read.output.rs2 - val divSqrtHit = input.opcode === p.Opcode.DIV_SQRT + val divSqrtHit = input.opcode === p.Opcode.DIV || input.opcode === p.Opcode.SQRT val divSqrt = Stream(DivSqrtInput()) input.ready setWhen(divSqrtHit && divSqrt.ready) divSqrt.valid := input.valid && divSqrtHit @@ -183,7 +187,7 @@ case class FpuCore(p : FpuParameter) extends Component{ divSqrt.rs2 := read.output.rs2 divSqrt.rd := read.output.rd divSqrt.lockId := read.output.lockId - divSqrt.div := True //TODO + divSqrt.div := input.opcode === p.Opcode.DIV val fmaHit = input.opcode === p.Opcode.FMA val mulHit = input.opcode === p.Opcode.MUL || fmaHit @@ -315,14 +319,21 @@ case class FpuCore(p : FpuParameter) extends Component{ val rom = Mem(UInt(aproxWidth bits), aproxDepth * 2) val divTable, sqrtTable = ArrayBuffer[Double]() for(i <- 0 until aproxDepth){ - val mantissa = 1+(i+0.5)/aproxDepth - divTable += 1/mantissa - sqrtTable += 1/Math.sqrt(mantissa) + val value = 1+(i+0.5)/aproxDepth + divTable += 1/value + } + for(i <- 0 until aproxDepth){ + val scale = if(i < aproxDepth/2) 2 else 1 + val value = scale+(scale*(i%(aproxDepth/2)+0.5)/aproxDepth*2) +// println(s"$i => $value" ) + sqrtTable += 1/Math.sqrt(value) } val romElaboration = (sqrtTable ++ divTable).map(v => BigInt(((v-0.5)*2*(1 << aproxWidth)).round)) rom.initBigInt(romElaboration) - val address = U(input.div ## (input.div ? input.rs2.mantissa | input.rs1.mantissa).takeHigh(log2Up(aproxDepth))) + val div = input.rs2.mantissa.takeHigh(log2Up(aproxDepth)) + val sqrt = U(input.rs1.exponent.lsb ## input.rs1.mantissa).takeHigh(log2Up(aproxDepth)) + val address = U(input.div ## (input.div ? div | sqrt)) val raw = rom.readAsync(address) val result = U"01" @@ (raw << (mulWidth-aproxWidth-2)) } @@ -331,7 +342,7 @@ case class FpuCore(p : FpuParameter) extends Component{ val value = (1 << p.internalExponentSize) - 3 - input.rs2.exponent } val sqrtExp = new Area{ - val value = ((1 << p.internalExponentSize-1) + (1 << p.internalExponentSize-2) - 2) - (input.rs2.exponent >> 1) + input.rs2.exponent.lsb.asUInt + val value = ((1 << p.internalExponentSize-1) + (1 << p.internalExponentSize-2) - 2 -1) - (input.rs1.exponent >> 1) + U(!input.rs1.exponent.lsb) } def mulArg(rs1 : UInt, rs2 : UInt): Unit ={ @@ -345,7 +356,6 @@ case class FpuCore(p : FpuParameter) extends Component{ mulBuffer.ready := False val iterationValue = Reg(UInt(mulWidth bits)) - //val squareInput = (iteration === 0) ? aprox.result | iterationValue input.ready := False switch(state){ @@ -365,13 +375,12 @@ case class FpuCore(p : FpuParameter) extends Component{ } is(XYY){ decode.divSqrtToMul.valid := mulBuffer.valid - mulArg(U"1" @@ (input.div ? input.rs2.mantissa | input.rs1.mantissa), mulBuffer.payload) + val sqrtIn = !input.rs1.exponent.lsb ? (U"1" @@ input.rs1.mantissa) | ((U"1" @@ input.rs1.mantissa) |>> 1) + val divIn = U"1" @@ input.rs2.mantissa + mulArg(input.div ? divIn| sqrtIn, mulBuffer.payload) when(mulBuffer.valid && decode.divSqrtToMul.ready) { - state := (input.div ? Y2_XYY | Y_15_XYY2) - mulBuffer.ready := input.div - when(!input.div){ - mulBuffer.payload.getDrivingReg := (U"11" << mulWidth-2) - (mulBuffer.payload >> 1) - } + state := (input.div ? Y2_XYY | _15_XYY2) + mulBuffer.ready := True } } is(Y2_XYY){ @@ -399,25 +408,25 @@ case class FpuCore(p : FpuParameter) extends Component{ input.ready := True } } + is(_15_XYY2){ + when(mulBuffer.valid) { + state := Y_15_XYY2 + mulBuffer.payload.getDrivingReg := (U"11" << mulWidth-2) - (mulBuffer.payload) + } + } is(Y_15_XYY2){ decode.divSqrtToMul.valid := True - mulArg(U"1" @@ input.rs1.mantissa, mulBuffer.payload) + mulArg(iterationValue, mulBuffer.payload) when(decode.divSqrtToMul.ready) { mulBuffer.ready := True - state := SQRT + state := Y_15_XYY2_RESULT } } is(Y_15_XYY2_RESULT){ - when(iteration =/= sqrtIterationCount-1 && !input.rs1.exponent.lsb) { - iterationValue := mulBuffer.payload - } otherwise { - val v = 1.0/Math.sqrt(2.0) - val scaled = v* (BigInt(1) << mulWidth-1).toDouble - val bigInt = BigDecimal(scaled).toBigInt() - iterationValue := mulBuffer.payload + U(bigInt) - } + iterationValue := mulBuffer.payload mulBuffer.ready := True when(mulBuffer.valid) { + iteration := iteration + 1 when(iteration =/= sqrtIterationCount-1){ state := YY } otherwise { diff --git a/src/main/scala/vexriscv/ip/fpu/Interface.scala b/src/main/scala/vexriscv/ip/fpu/Interface.scala index b07c18c9..2c5b3f11 100644 --- a/src/main/scala/vexriscv/ip/fpu/Interface.scala +++ b/src/main/scala/vexriscv/ip/fpu/Interface.scala @@ -23,7 +23,7 @@ case class FpuFloat(exponentSize: Int, } case class FpuOpcode(p : FpuParameter) extends SpinalEnum{ - val LOAD, STORE, MUL, ADD, FMA, I2F, F2I, CMP, DIV_SQRT = newElement() + val LOAD, STORE, MUL, ADD, FMA, I2F, F2I, CMP, DIV, SQRT = newElement() } case class FpuParameter( internalMantissaSize : Int, diff --git a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala index 68c3e461..0ca5ca7a 100644 --- a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala +++ b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala @@ -99,7 +99,7 @@ class FpuTest extends FunSuite{ def div(rd : Int, rs1 : Int, rs2 : Int): Unit ={ cmdQueue += {cmd => cmd.source #= id - cmd.opcode #= cmd.opcode.spinalEnum.DIV_SQRT + cmd.opcode #= cmd.opcode.spinalEnum.DIV cmd.value.randomize() cmd.rs1 #= rs1 cmd.rs2 #= rs2 @@ -108,6 +108,18 @@ class FpuTest extends FunSuite{ } } + def sqrt(rd : Int, rs1 : Int): Unit ={ + cmdQueue += {cmd => + cmd.source #= id + cmd.opcode #= cmd.opcode.spinalEnum.SQRT + cmd.value.randomize() + cmd.rs1 #= rs1 + cmd.rs2.randomize() + cmd.rs3.randomize() + cmd.rd #= rd + } + } + def fma(rd : Int, rs1 : Int, rs2 : Int, rs3 : Int): Unit ={ cmdQueue += {cmd => cmd.source #= id @@ -175,7 +187,8 @@ class FpuTest extends FunSuite{ } def randomFloat(): Float ={ - Random.nextFloat() * 1e2f * (if(Random.nextBoolean()) -1f else 1f) + val exp = Random.nextInt(10)-5 + (Random.nextDouble() * (Math.pow(2.0, exp)) * (if(Random.nextBoolean()) -1.0 else 1.0)).toFloat } def testAdd(a : Float, b : Float): Unit ={ @@ -219,9 +232,9 @@ class FpuTest extends FunSuite{ fma(rd,rs1,rs2,rs3) storeFloat(rd){v => - val ref = a * b + c - println(f"$a * $b + $c = $v, $ref") - assert(checkFloat(ref, v)) + val ref = a.toDouble * b.toDouble + c.toDouble + println(f"$a%.20f * $b%.20f + $c%.20f = $v%.20f, $ref%.20f") + assert(checkFloat(ref.toFloat, v)) } } @@ -248,7 +261,7 @@ class FpuTest extends FunSuite{ val rd = Random.nextInt(32) load(rs1, a) - div(rd,rs1,rs2) + sqrt(rd,rs1) storeFloat(rd){v => val ref = Math.sqrt(a).toFloat val error = Math.abs(ref-v)/ref @@ -260,8 +273,20 @@ class FpuTest extends FunSuite{ val b2f = lang.Float.intBitsToFloat(_) -// testSqrt(2.25f) -// dut.clockDomain.waitSampling(100) + testSqrt(1.5625f) + testSqrt(1.5625f*2) + testSqrt(1.8f) + testSqrt(4.4f) + testSqrt(0.3f) + testSqrt(1.5625f*2) + testSqrt(b2f(0x3f7ffffe)) + testSqrt(b2f(0x3f7fffff)) + testSqrt(b2f(0x3f800000)) + testSqrt(b2f(0x3f800001)) + testSqrt(b2f(0x3f800002)) + testSqrt(b2f(0x3f800003)) + + // dut.clockDomain.waitSampling(1000) // simFailure() testAdd(0.1f, 1.6f) @@ -286,16 +311,19 @@ class FpuTest extends FunSuite{ for(i <- 0 until 1000){ testFma(randomFloat(), randomFloat(), randomFloat()) } - for(i <- 0 until 1000){ testDiv(randomFloat(), randomFloat()) } + for(i <- 0 until 1000){ + testSqrt(Math.abs(randomFloat())) //TODO + } for(i <- 0 until 1000){ val tests = ArrayBuffer[() => Unit]() tests += (() =>{testAdd(randomFloat(), randomFloat())}) tests += (() =>{testMul(randomFloat(), randomFloat())}) tests += (() =>{testFma(randomFloat(), randomFloat(), randomFloat())}) tests += (() =>{testDiv(randomFloat(), randomFloat())}) + tests += (() =>{testSqrt(randomFloat().abs)}) tests.randomPick().apply() } waitUntil(cpu.rspQueue.isEmpty) From 3cda7c1f1b9f967ccc9dec38d811ce2acf421905 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 15 Jan 2021 14:03:37 +0100 Subject: [PATCH 530/951] fpu wip --- src/main/scala/vexriscv/ip/fpu/FpuCore.scala | 105 +++++++++++------- .../scala/vexriscv/ip/fpu/Interface.scala | 29 +++-- src/test/scala/vexriscv/ip/fpu/FpuTest.scala | 47 ++++++-- 3 files changed, 116 insertions(+), 65 deletions(-) diff --git a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala index 8209c11a..c64ddb36 100644 --- a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala +++ b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala @@ -15,6 +15,8 @@ case class FpuCore(p : FpuParameter) extends Component{ val port = slave(FpuPort(p)) } + +// val commitPerSourceCount = 8 val rfLockCount = 5 val lockIdType = HardType(UInt(log2Up(rfLockCount) bits)) @@ -89,11 +91,44 @@ case class FpuCore(p : FpuParameter) extends Component{ val valid = RegInit(False) val source = Reg(p.source) val address = Reg(p.rfAddress) + val id = Reg(UInt(log2Up(rfLockCount) bits)) + val commited = Reg(Bool) + val write = Reg(Bool) } val lockFree = !lock.map(_.valid).andR val lockFreeId = OHMasking.first(lock.map(!_.valid)) } + val commitLogic = for(source <- 0 until p.sourceCount) yield new Area{ + val fire = False + val target, hit = Reg(UInt(log2Up(rfLockCount) bits)) init(0) + when(fire){ + hit := hit + 1 + } + + io.port.commit(source).ready := False + when(io.port.commit(source).valid) { + for (lock <- rf.lock) { + when(lock.valid && lock.source === source && lock.id === hit) { + fire := True + lock.commited := True + lock.write := io.port.commit(source).write + io.port.commit(source).ready := True + } + } + } + } + +// case class CommitLine() extends Bundle{ +// val valid = Bool() +// val write = Bool() +// } +// val commits = for(i <- 0 until p.sourceCount) yield new Area{ +// val lines = Vec(CommitLine(), commitPerSourceCount) +// lines.foreach(_.valid init(False)) +// +// } + val read = new Area{ val s0 = Stream(RfReadInput()) s0.arbitrationFrom(io.port.cmd) @@ -137,11 +172,17 @@ case class FpuCore(p : FpuParameter) extends Component{ val hits = List((useRs1, s0.rs1), (useRs2, s0.rs2), (useRs3, s0.rs3), (useRd, s0.rd)).map{case (use, reg) => use && rf.lock.map(l => l.valid && l.source === s0.source && l.address === reg).orR} val hazard = hits.orR when(s0.fire && useRd){ + for(i <- 0 until p.sourceCount){ + when(s0.source === i){ + commitLogic(i).target := commitLogic(i).target + 1 + } + } for(i <- 0 until rfLockCount){ when(rf.lockFreeId(i)){ rf.lock(i).valid := True rf.lock(i).source := s0.source rf.lock(i).address := s0.rd + rf.lock(i).id := commitLogic.map(_.target).read(s0.source) } } } @@ -224,9 +265,16 @@ case class FpuCore(p : FpuParameter) extends Component{ } val load = new Area{ - def input = decode.load - - val output = input.stage() + val input = decode.load.stage() + def feed = io.port.load(input.source) + val hazard = !feed.valid + val output = input.haltWhen(hazard).swapPayload(WriteInput()) + io.port.load.foreach(_.ready := False) + feed.ready := input.valid && output.ready + output.source := input.source + output.lockId := input.lockId + output.rd := input.rd + output.value.assignFromBits(feed.value) } @@ -506,47 +554,20 @@ case class FpuCore(p : FpuParameter) extends Component{ val write = new Area{ - val port = rf.ram.writePort - port.valid := False - port.payload.assignDontCare() + val arbitrated = StreamArbiterFactory.lowerFirst.noLock.on(List(load.output, add.output, mul.output)) + val isCommited = rf.lock.map(_.commited).read(arbitrated.lockId) + val commited = arbitrated.haltWhen(!isCommited).toFlow - - val lockFree = Flow(lockIdType) - lockFree.valid := port.fire - lockFree.payload.assignDontCare() - - load.output.ready := False - mul.output.ready := False - add.output.ready := True - io.port.commit.ready := False - when(add.output.valid) { - port.valid := True - port.address := add.output.source @@ add.output.rd - port.data := add.output.value - - lockFree.payload := add.output.lockId - } elsewhen(mul.output.valid) { - port.valid := True - port.address := mul.output.source @@ mul.output.rd - port.data := mul.output.value - - mul.output.ready := True - lockFree.payload := mul.output.lockId - } elsewhen(load.output.valid && io.port.commit.valid) { - port.valid := io.port.commit.write - port.address := load.output.source @@ load.output.rd - port.data.assignFromBits(io.port.commit.value) - - load.output.ready := True - io.port.commit.ready := True - lockFree.payload := load.output.lockId - } - - when(lockFree.fire){ - for(i <- 0 until rfLockCount) when(lockFree.payload === i){ + when(commited.valid){ + for(i <- 0 until rfLockCount) when(commited.lockId === i){ rf.lock(i).valid := False } } + + val port = rf.ram.writePort + port.valid := commited.valid && rf.lock.map(_.write).read(commited.lockId) + port.address := commited.source @@ commited.rd + port.data := commited.value } } @@ -572,7 +593,7 @@ object FpuSynthesisBench extends App{ FpuParameter( internalMantissaSize = 23, withDouble = false, - sourceWidth = 0 + sourceCount = 1 ) ) rtls += new Fpu( @@ -580,7 +601,7 @@ object FpuSynthesisBench extends App{ FpuParameter( internalMantissaSize = 52, withDouble = true, - sourceWidth = 0 + sourceCount = 1 ) ) diff --git a/src/main/scala/vexriscv/ip/fpu/Interface.scala b/src/main/scala/vexriscv/ip/fpu/Interface.scala index 2c5b3f11..00e526a9 100644 --- a/src/main/scala/vexriscv/ip/fpu/Interface.scala +++ b/src/main/scala/vexriscv/ip/fpu/Interface.scala @@ -22,13 +22,18 @@ case class FpuFloat(exponentSize: Int, val sign = Bool } -case class FpuOpcode(p : FpuParameter) extends SpinalEnum{ +object FpuOpcode extends SpinalEnum{ val LOAD, STORE, MUL, ADD, FMA, I2F, F2I, CMP, DIV, SQRT = newElement() } +object FpuFormat extends SpinalEnum{ + val FLOAT, DOUBLE = newElement() +} + + case class FpuParameter( internalMantissaSize : Int, withDouble : Boolean, - sourceWidth : Int){ + sourceCount : Int){ val storeLoadType = HardType(Bits(if(withDouble) 64 bits else 32 bits)) val internalExponentSize = if(withDouble) 11 else 8 @@ -37,11 +42,9 @@ case class FpuParameter( internalMantissaSize : Int, val source = HardType(UInt(sourceWidth bits)) val rfAddress = HardType(UInt(5 bits)) - val Opcode = new FpuOpcode(this) - val Format = new SpinalEnum{ - val FLOAT = newElement() - val DOUBLE = withDouble generate newElement() - } + val Opcode = FpuOpcode + val Format = FpuFormat + val sourceWidth = log2Up(sourceCount) } case class FpuCmd(p : FpuParameter) extends Bundle{ @@ -55,9 +58,11 @@ case class FpuCmd(p : FpuParameter) extends Bundle{ } case class FpuCommit(p : FpuParameter) extends Bundle{ - val source = UInt(p.sourceWidth bits) val write = Bool() - val value = p.storeLoadType() // IEEE 754 load +} + +case class FpuLoad(p : FpuParameter) extends Bundle{ + val value = p.storeLoadType() // IEEE 754 } case class FpuRsp(p : FpuParameter) extends Bundle{ @@ -67,11 +72,13 @@ case class FpuRsp(p : FpuParameter) extends Bundle{ case class FpuPort(p : FpuParameter) extends Bundle with IMasterSlave { val cmd = Stream(FpuCmd(p)) - val commit = Stream(FpuCommit(p)) + val commit = Vec(Stream(FpuCommit(p)), p.sourceCount) + val load = Vec(Stream(FpuLoad(p)), p.sourceCount) val rsp = Stream(FpuRsp(p)) override def asMaster(): Unit = { - master(cmd, commit) + master(cmd) + (commit ++ load).foreach(master(_)) slave(rsp) } } diff --git a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala index 0ca5ca7a..3190a0cd 100644 --- a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala +++ b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala @@ -19,7 +19,7 @@ class FpuTest extends FunSuite{ val p = FpuParameter( internalMantissaSize = 23, withDouble = false, - sourceWidth = 0 + sourceCount = 1 ) SimConfig.withFstWave.compile(new FpuCore(p)).doSim(seed = 42){ dut => @@ -31,8 +31,23 @@ class FpuTest extends FunSuite{ val cpus = for(id <- 0 until 1 << p.sourceWidth) yield new { val cmdQueue = mutable.Queue[FpuCmd => Unit]() val commitQueue = mutable.Queue[FpuCommit => Unit]() + val loadQueue = mutable.Queue[FpuLoad => Unit]() val rspQueue = mutable.Queue[FpuRsp => Unit]() + StreamDriver(dut.io.port.commit(id) ,dut.clockDomain){payload => + if(commitQueue.isEmpty) false else { + commitQueue.dequeue().apply(payload) + true + } + } + + StreamDriver(dut.io.port.load(id) ,dut.clockDomain){payload => + if(loadQueue.isEmpty) false else { + loadQueue.dequeue().apply(payload) + true + } + } + def loadRaw(rd : Int, value : BigInt): Unit ={ cmdQueue += {cmd => cmd.source #= id @@ -44,8 +59,9 @@ class FpuTest extends FunSuite{ cmd.rd #= rd } commitQueue += {cmd => - cmd.source #= id cmd.write #= true + } + loadQueue += {cmd => cmd.value #= value } } @@ -82,6 +98,9 @@ class FpuTest extends FunSuite{ cmd.rs3.randomize() cmd.rd #= rd } + commitQueue += {cmd => + cmd.write #= true + } } def add(rd : Int, rs1 : Int, rs2 : Int): Unit ={ @@ -94,6 +113,9 @@ class FpuTest extends FunSuite{ cmd.rs3.randomize() cmd.rd #= rd } + commitQueue += {cmd => + cmd.write #= true + } } def div(rd : Int, rs1 : Int, rs2 : Int): Unit ={ @@ -106,6 +128,9 @@ class FpuTest extends FunSuite{ cmd.rs3.randomize() cmd.rd #= rd } + commitQueue += {cmd => + cmd.write #= true + } } def sqrt(rd : Int, rs1 : Int): Unit ={ @@ -118,6 +143,9 @@ class FpuTest extends FunSuite{ cmd.rs3.randomize() cmd.rd #= rd } + commitQueue += {cmd => + cmd.write #= true + } } def fma(rd : Int, rs1 : Int, rs2 : Int, rs3 : Int): Unit ={ @@ -130,6 +158,9 @@ class FpuTest extends FunSuite{ cmd.rs3 #= rs3 cmd.rd #= rd } + commitQueue += {cmd => + cmd.write #= true + } } } @@ -143,15 +174,7 @@ class FpuTest extends FunSuite{ } } - StreamDriver(dut.io.port.commit ,dut.clockDomain){payload => - cpus.map(_.commitQueue).filter(_.nonEmpty).toSeq match { - case Nil => false - case l => { - l.randomPick().dequeue().apply(payload) - true - } - } - } + StreamMonitor(dut.io.port.rsp, dut.clockDomain){payload => @@ -272,6 +295,7 @@ class FpuTest extends FunSuite{ val b2f = lang.Float.intBitsToFloat(_) + testAdd(0.1f, 1.6f) testSqrt(1.5625f) testSqrt(1.5625f*2) @@ -289,7 +313,6 @@ class FpuTest extends FunSuite{ // dut.clockDomain.waitSampling(1000) // simFailure() - testAdd(0.1f, 1.6f) testMul(0.1f, 1.6f) testFma(1.1f, 2.2f, 3.0f) testDiv(1.0f, 1.1f) From a9d8c0a19f04412914d86b0bd9d77e09bb8233ec Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 18 Jan 2021 11:38:26 +0100 Subject: [PATCH 531/951] fpu wip --- src/main/scala/vexriscv/Riscv.scala | 58 +++ src/main/scala/vexriscv/TestsWorkspace.scala | 340 +++++++++--------- src/main/scala/vexriscv/VexRiscv.scala | 1 + src/main/scala/vexriscv/demo/GenFull.scala | 146 ++++---- src/main/scala/vexriscv/ip/DataCache.scala | 37 +- src/main/scala/vexriscv/ip/fpu/FpuCore.scala | 90 ++--- .../scala/vexriscv/ip/fpu/Interface.scala | 16 +- .../vexriscv/plugin/DBusCachedPlugin.scala | 74 +++- .../scala/vexriscv/plugin/FpuPlugin.scala | 124 +++++++ src/test/cpp/raw/common/asm.mk | 3 + src/test/cpp/raw/fpu/.gitignore | 4 + src/test/cpp/raw/fpu/build/amo.asm | 247 +++++++++++++ src/test/cpp/raw/fpu/build/amo.hex | 45 +++ src/test/cpp/raw/fpu/build/fpu.asm | 224 ++++++++++++ src/test/cpp/raw/fpu/build/fpu.hex | 42 +++ src/test/cpp/raw/fpu/makefile | 5 + src/test/cpp/raw/fpu/src/crt.S | 161 +++++++++ src/test/cpp/raw/fpu/src/ld | 16 + src/test/cpp/regression/main.cpp | 4 +- src/test/cpp/regression/makefile | 5 + src/test/scala/vexriscv/DhrystoneBench.scala | 199 +++++----- src/test/scala/vexriscv/ip/fpu/FpuTest.scala | 53 ++- 22 files changed, 1446 insertions(+), 448 deletions(-) create mode 100644 src/main/scala/vexriscv/plugin/FpuPlugin.scala create mode 100644 src/test/cpp/raw/fpu/.gitignore create mode 100644 src/test/cpp/raw/fpu/build/amo.asm create mode 100644 src/test/cpp/raw/fpu/build/amo.hex create mode 100644 src/test/cpp/raw/fpu/build/fpu.asm create mode 100644 src/test/cpp/raw/fpu/build/fpu.hex create mode 100644 src/test/cpp/raw/fpu/makefile create mode 100644 src/test/cpp/raw/fpu/src/crt.S create mode 100644 src/test/cpp/raw/fpu/src/ld diff --git a/src/main/scala/vexriscv/Riscv.scala b/src/main/scala/vexriscv/Riscv.scala index ee9be3d0..ae64bffc 100644 --- a/src/main/scala/vexriscv/Riscv.scala +++ b/src/main/scala/vexriscv/Riscv.scala @@ -11,6 +11,7 @@ object Riscv{ def funct3Range = 14 downto 12 def rs1Range = 19 downto 15 def rs2Range = 24 downto 20 + def rs3Range = 31 downto 27 def csrRange = 31 downto 20 case class IMM(instruction : Bits) extends Area{ @@ -119,6 +120,63 @@ object Riscv{ def FENCE_I = M"-----------------001-----0001111" def SFENCE_VMA = M"0001001----------000000001110011" + def FADD_S = M"0000000------------------1010011" + def FSUB_S = M"0000100------------------1010011" + def FMUL_S = M"0001000------------------1010011" + def FDIV_S = M"0001100------------------1010011" + def FSGNJ_S = M"0010000----------000-----1010011" + def FSGNJN_S = M"0010000----------001-----1010011" + def FSGNJX_S = M"0010000----------010-----1010011" + def FMIN_S = M"0010100----------000-----1010011" + def FMAX_S = M"0010100----------001-----1010011" + def FSQRT_S = M"010110000000-------------1010011" + def FADD_D = M"0000001------------------1010011" + def FSUB_D = M"0000101------------------1010011" + def FMUL_D = M"0001001------------------1010011" + def FDIV_D = M"0001101------------------1010011" + def FSGNJ_D = M"0010001----------000-----1010011" + def FSGNJN_D = M"0010001----------001-----1010011" + def FSGNJX_D = M"0010001----------010-----1010011" + def FMIN_D = M"0010101----------000-----1010011" + def FMAX_D = M"0010101----------001-----1010011" + def FCVT_S_D = M"010000000001-------------1010011" + def FCVT_D_S = M"010000100000-------------1010011" + def FSQRT_D = M"010110100000-------------1010011" + def FCVT_W_S = M"110000000000-------------1010011" + def FCVT_WU_S = M"110000000001-------------1010011" + def FCVT_L_S = M"110000000010-------------1010011" + def FCVT_LU_S = M"110000000011-------------1010011" + def FMV_X_W = M"111000000000-----000-----1010011" + def FCLASS_S = M"111000000000-----001-----1010011" + def FCVT_W_D = M"110000100000-------------1010011" + def FCVT_WU_D = M"110000100001-------------1010011" + def FCVT_L_D = M"110000100010-------------1010011" + def FCVT_LU_D = M"110000100011-------------1010011" + def FMV_X_D = M"111000100000-----000-----1010011" + def FCLASS_D = M"111000100000-----001-----1010011" + def FCVT_S_W = M"110100000000-------------1010011" + def FCVT_S_WU = M"110100000001-------------1010011" + def FCVT_S_L = M"110100000010-------------1010011" + def FCVT_S_LU = M"110100000011-------------1010011" + def FMV_W_X = M"111100000000-----000-----1010011" + def FCVT_D_W = M"110100100000-------------1010011" + def FCVT_D_WU = M"110100100001-------------1010011" + def FCVT_D_L = M"110100100010-------------1010011" + def FCVT_D_LU = M"110100100011-------------1010011" + def FMV_D_X = M"111100100000-----000-----1010011" + def FLW = M"-----------------010-----0000111" + def FLD = M"-----------------011-----0000111" + def FSW = M"-----------------010-----0100111" + def FSD = M"-----------------011-----0100111" + def FMADD_S = M"-----00------------------1000011" + def FMSUB_S = M"-----00------------------1000111" + def FNMSUB_S = M"-----00------------------1001011" + def FNMADD_S = M"-----00------------------1001111" + def FMADD_D = M"-----01------------------1000011" + def FMSUB_D = M"-----01------------------1000111" + def FNMSUB_D = M"-----01------------------1001011" + def FNMADD_D = M"-----01------------------1001111" + object CSR{ def MVENDORID = 0xF11 // MRO Vendor ID. def MARCHID = 0xF12 // MRO Architecture ID. diff --git a/src/main/scala/vexriscv/TestsWorkspace.scala b/src/main/scala/vexriscv/TestsWorkspace.scala index b522aed5..3fc35b87 100644 --- a/src/main/scala/vexriscv/TestsWorkspace.scala +++ b/src/main/scala/vexriscv/TestsWorkspace.scala @@ -19,180 +19,181 @@ package vexriscv import vexriscv.plugin._ -import vexriscv.demo.SimdAddPlugin +import vexriscv.demo.{GenFull, SimdAddPlugin} import spinal.core._ import spinal.lib._ import vexriscv.ip._ import spinal.lib.bus.avalon.AvalonMM import spinal.lib.eda.altera.{InterruptReceiverTag, ResetEmitterTag} +import vexriscv.ip.fpu.FpuParameter // make clean all SEED=42 MMU=no STOP_ON_ERROR=yes DBUS_EXCLUSIVE=yes DBUS_INVALIDATE=yes SUPERVISOR=yes REDO=1 DHRYSTONE=yes LRSC=yes AMO=yes LINUX_REGRESSION=yes TRACE=yes TRACE_START=1000000000 FLOW_INFO=ye IBUS_DATA_WIDTH=128 DBUS_DATA_WIDTH=128 //make clean all SEED=42 MMU=no STOP_ON_ERROR=yes DBUS_EXCLUSIVE=yes DBUS_INVALIDATE=yes SUPERVISOR=yes REDO=1 DHRYSTONE=yes LRSC=yes AMO=yes TRACE=yes TRACE_START=1000000000 FLOW_INFO=ye IBUS_DATA_WIDTH=128 DBUS_DATA_WIDTH=128 LINUX_SOC_SMP=yes VMLINUX=../../../../../buildroot/output/images/Image RAMDISK=../../../../../buildroot/output/images/rootfs.cpio DTB=../../../../../buildroot/output/images/dtb EMULATOR=../../../../../opensbi/build/platform/spinal/vexriscv/sim/smp/firmware/fw_jump.bin object TestsWorkspace { def main(args: Array[String]) { - def configFull = { - val config = VexRiscvConfig( - plugins = List( - new MmuPlugin( - ioRange = x => x(31 downto 28) === 0xF - ), - //Uncomment the whole IBusSimplePlugin and comment IBusCachedPlugin if you want uncached iBus config - // new IBusSimplePlugin( - // resetVector = 0x80000000l, - // cmdForkOnSecondStage = false, - // cmdForkPersistence = false, - // prediction = DYNAMIC_TARGET, - // historyRamSizeLog2 = 10, - // catchAccessFault = true, - // compressedGen = true, - // busLatencyMin = 1, - // injectorStage = true, - // memoryTranslatorPortConfig = withMmu generate MmuPortConfig( - // portTlbSize = 4 - // ) - // ), - - //Uncomment the whole IBusCachedPlugin and comment IBusSimplePlugin if you want cached iBus config - new IBusCachedPlugin( - resetVector = 0x80000000l, - compressedGen = false, - prediction = STATIC, - injectorStage = false, - config = InstructionCacheConfig( - cacheSize = 4096*2, - bytePerLine = 64, - wayCount = 2, - addressWidth = 32, - cpuDataWidth = 32, - memDataWidth = 128, - catchIllegalAccess = true, - catchAccessFault = true, - asyncTagMemory = false, - twoCycleRam = true, - twoCycleCache = true, - reducedBankWidth = true - // ) - ), - memoryTranslatorPortConfig = MmuPortConfig( - portTlbSize = 4, - latency = 1, - earlyRequireMmuLockup = true, - earlyCacheHits = true - ) - ), - // ).newTightlyCoupledPort(TightlyCoupledPortParameter("iBusTc", a => a(30 downto 28) === 0x0 && a(5))), - // new DBusSimplePlugin( - // catchAddressMisaligned = true, - // catchAccessFault = true, - // earlyInjection = false, - // withLrSc = true, - // memoryTranslatorPortConfig = withMmu generate MmuPortConfig( - // portTlbSize = 4 - // ) - // ), - new DBusCachedPlugin( - dBusCmdMasterPipe = true, - dBusCmdSlavePipe = true, - dBusRspSlavePipe = true, - config = new DataCacheConfig( - cacheSize = 4096*1, - bytePerLine = 64, - wayCount = 1, - addressWidth = 32, - cpuDataWidth = 32, - memDataWidth = 128, - catchAccessError = true, - catchIllegal = true, - catchUnaligned = true, - withLrSc = true, - withAmo = true, - withExclusive = true, - withInvalidate = true, - pendingMax = 32 - // ) - ), - memoryTranslatorPortConfig = MmuPortConfig( - portTlbSize = 4, - latency = 1, - earlyRequireMmuLockup = true, - earlyCacheHits = true - ) - ), - - // new MemoryTranslatorPlugin( - // tlbSize = 32, - // virtualRange = _(31 downto 28) === 0xC, - // ioRange = _(31 downto 28) === 0xF - // ), - - new DecoderSimplePlugin( - catchIllegalInstruction = true - ), - new RegFilePlugin( - regFileReadyKind = plugin.ASYNC, - zeroBoot = true - ), - new IntAluPlugin, - new SrcPlugin( - separatedAddSub = false - ), - new FullBarrelShifterPlugin(earlyInjection = false), - // new LightShifterPlugin, - new HazardSimplePlugin( - bypassExecute = true, - bypassMemory = true, - bypassWriteBack = true, - bypassWriteBackBuffer = true, - pessimisticUseSrc = false, - pessimisticWriteRegFile = false, - pessimisticAddressMatch = false - ), - // new HazardSimplePlugin(false, true, false, true), - // new HazardSimplePlugin(false, false, false, false), - new MulPlugin, - new MulDivIterativePlugin( - genMul = false, - genDiv = true, - mulUnrollFactor = 32, - divUnrollFactor = 1 - ), - // new DivPlugin, - new CsrPlugin(CsrPluginConfig.all2(0x80000020l).copy(ebreakGen = false, misaExtensionsInit = Riscv.misaToInt("imas"))), - // new CsrPlugin(//CsrPluginConfig.all2(0x80000020l).copy(ebreakGen = true)/* - // CsrPluginConfig( - // catchIllegalAccess = false, - // mvendorid = null, - // marchid = null, - // mimpid = null, - // mhartid = null, - // misaExtensionsInit = 0, - // misaAccess = CsrAccess.READ_ONLY, - // mtvecAccess = CsrAccess.WRITE_ONLY, - // mtvecInit = 0x80000020l, - // mepcAccess = CsrAccess.READ_WRITE, - // mscratchGen = true, - // mcauseAccess = CsrAccess.READ_ONLY, - // mbadaddrAccess = CsrAccess.READ_ONLY, - // mcycleAccess = CsrAccess.NONE, - // minstretAccess = CsrAccess.NONE, - // ecallGen = true, - // ebreakGen = true, - // wfiGenAsWait = false, - // wfiGenAsNop = true, - // ucycleAccess = CsrAccess.NONE - // )), - new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))), - new BranchPlugin( - earlyBranch = false, - catchAddressMisaligned = true, - fenceiGenAsAJump = false - ), - new YamlPlugin("cpu0.yaml") - ) - ) - config - } +// def configFull = { +// val config = VexRiscvConfig( +// plugins = List( +// new MmuPlugin( +// ioRange = x => x(31 downto 28) === 0xF +// ), +// //Uncomment the whole IBusSimplePlugin and comment IBusCachedPlugin if you want uncached iBus config +// // new IBusSimplePlugin( +// // resetVector = 0x80000000l, +// // cmdForkOnSecondStage = false, +// // cmdForkPersistence = false, +// // prediction = DYNAMIC_TARGET, +// // historyRamSizeLog2 = 10, +// // catchAccessFault = true, +// // compressedGen = true, +// // busLatencyMin = 1, +// // injectorStage = true, +// // memoryTranslatorPortConfig = withMmu generate MmuPortConfig( +// // portTlbSize = 4 +// // ) +// // ), +// +// //Uncomment the whole IBusCachedPlugin and comment IBusSimplePlugin if you want cached iBus config +// new IBusCachedPlugin( +// resetVector = 0x80000000l, +// compressedGen = false, +// prediction = STATIC, +// injectorStage = false, +// config = InstructionCacheConfig( +// cacheSize = 4096*2, +// bytePerLine = 64, +// wayCount = 2, +// addressWidth = 32, +// cpuDataWidth = 32, +// memDataWidth = 128, +// catchIllegalAccess = true, +// catchAccessFault = true, +// asyncTagMemory = false, +// twoCycleRam = true, +// twoCycleCache = true, +// reducedBankWidth = true +// // ) +// ), +// memoryTranslatorPortConfig = MmuPortConfig( +// portTlbSize = 4, +// latency = 1, +// earlyRequireMmuLockup = true, +// earlyCacheHits = true +// ) +// ), +// // ).newTightlyCoupledPort(TightlyCoupledPortParameter("iBusTc", a => a(30 downto 28) === 0x0 && a(5))), +// // new DBusSimplePlugin( +// // catchAddressMisaligned = true, +// // catchAccessFault = true, +// // earlyInjection = false, +// // withLrSc = true, +// // memoryTranslatorPortConfig = withMmu generate MmuPortConfig( +// // portTlbSize = 4 +// // ) +// // ), +// new DBusCachedPlugin( +// dBusCmdMasterPipe = true, +// dBusCmdSlavePipe = true, +// dBusRspSlavePipe = true, +// config = new DataCacheConfig( +// cacheSize = 4096*1, +// bytePerLine = 64, +// wayCount = 1, +// addressWidth = 32, +// cpuDataWidth = 32, +// memDataWidth = 128, +// catchAccessError = true, +// catchIllegal = true, +// catchUnaligned = true, +// withLrSc = true, +// withAmo = true, +// withExclusive = true, +// withInvalidate = true, +// pendingMax = 32 +// // ) +// ), +// memoryTranslatorPortConfig = MmuPortConfig( +// portTlbSize = 4, +// latency = 1, +// earlyRequireMmuLockup = true, +// earlyCacheHits = true +// ) +// ), +// +// // new MemoryTranslatorPlugin( +// // tlbSize = 32, +// // virtualRange = _(31 downto 28) === 0xC, +// // ioRange = _(31 downto 28) === 0xF +// // ), +// +// new DecoderSimplePlugin( +// catchIllegalInstruction = true +// ), +// new RegFilePlugin( +// regFileReadyKind = plugin.ASYNC, +// zeroBoot = true +// ), +// new IntAluPlugin, +// new SrcPlugin( +// separatedAddSub = false +// ), +// new FullBarrelShifterPlugin(earlyInjection = false), +// // new LightShifterPlugin, +// new HazardSimplePlugin( +// bypassExecute = true, +// bypassMemory = true, +// bypassWriteBack = true, +// bypassWriteBackBuffer = true, +// pessimisticUseSrc = false, +// pessimisticWriteRegFile = false, +// pessimisticAddressMatch = false +// ), +// // new HazardSimplePlugin(false, true, false, true), +// // new HazardSimplePlugin(false, false, false, false), +// new MulPlugin, +// new MulDivIterativePlugin( +// genMul = false, +// genDiv = true, +// mulUnrollFactor = 32, +// divUnrollFactor = 1 +// ), +// // new DivPlugin, +// new CsrPlugin(CsrPluginConfig.all2(0x80000020l).copy(ebreakGen = false, misaExtensionsInit = Riscv.misaToInt("imas"))), +// // new CsrPlugin(//CsrPluginConfig.all2(0x80000020l).copy(ebreakGen = true)/* +// // CsrPluginConfig( +// // catchIllegalAccess = false, +// // mvendorid = null, +// // marchid = null, +// // mimpid = null, +// // mhartid = null, +// // misaExtensionsInit = 0, +// // misaAccess = CsrAccess.READ_ONLY, +// // mtvecAccess = CsrAccess.WRITE_ONLY, +// // mtvecInit = 0x80000020l, +// // mepcAccess = CsrAccess.READ_WRITE, +// // mscratchGen = true, +// // mcauseAccess = CsrAccess.READ_ONLY, +// // mbadaddrAccess = CsrAccess.READ_ONLY, +// // mcycleAccess = CsrAccess.NONE, +// // minstretAccess = CsrAccess.NONE, +// // ecallGen = true, +// // ebreakGen = true, +// // wfiGenAsWait = false, +// // wfiGenAsNop = true, +// // ucycleAccess = CsrAccess.NONE +// // )), +// new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))), +// new BranchPlugin( +// earlyBranch = false, +// catchAddressMisaligned = true, +// fenceiGenAsAJump = false +// ), +// new YamlPlugin("cpu0.yaml") +// ) +// ) +// config +// } // import spinal.core.sim._ @@ -211,10 +212,17 @@ object TestsWorkspace { // } // } - SpinalConfig(mergeAsyncProcess = false, anonymSignalPrefix = "zz_").generateVerilog { + SpinalConfig().generateVerilog { - - val toplevel = new VexRiscv(configFull) + val config = GenFull.config + config.plugins += new FpuPlugin( + externalFpu = false, + p = FpuParameter( + internalMantissaSize = 23, + withDouble = false + ) + ) + val toplevel = new VexRiscv(config) // val toplevel = new VexRiscv(configLight) // val toplevel = new VexRiscv(configTest) diff --git a/src/main/scala/vexriscv/VexRiscv.scala b/src/main/scala/vexriscv/VexRiscv.scala index 5f7865cf..a08f9c99 100644 --- a/src/main/scala/vexriscv/VexRiscv.scala +++ b/src/main/scala/vexriscv/VexRiscv.scala @@ -46,6 +46,7 @@ case class VexRiscvConfig(){ object LEGAL_INSTRUCTION extends Stageable(Bool) object REGFILE_WRITE_VALID extends Stageable(Bool) object REGFILE_WRITE_DATA extends Stageable(Bits(32 bits)) + object DBUS_DATA extends Stageable(Bits(32 bits)) object MPP extends PipelineThing[UInt] object DEBUG_BYPASS_CACHE extends PipelineThing[Bool] diff --git a/src/main/scala/vexriscv/demo/GenFull.scala b/src/main/scala/vexriscv/demo/GenFull.scala index dfa7b1e8..eb1dba33 100644 --- a/src/main/scala/vexriscv/demo/GenFull.scala +++ b/src/main/scala/vexriscv/demo/GenFull.scala @@ -9,82 +9,84 @@ import spinal.core._ * Created by spinalvm on 15.06.17. */ object GenFull extends App{ - def cpu() = new VexRiscv( - config = VexRiscvConfig( - plugins = List( - new IBusCachedPlugin( - prediction = DYNAMIC, - config = InstructionCacheConfig( - cacheSize = 4096, - bytePerLine =32, - wayCount = 1, - addressWidth = 32, - cpuDataWidth = 32, - memDataWidth = 32, - catchIllegalAccess = true, - catchAccessFault = true, - asyncTagMemory = false, - twoCycleRam = true, - twoCycleCache = true - ), - memoryTranslatorPortConfig = MmuPortConfig( - portTlbSize = 4 - ) + def config = VexRiscvConfig( + plugins = List( + new IBusCachedPlugin( + prediction = DYNAMIC, + config = InstructionCacheConfig( + cacheSize = 4096, + bytePerLine =32, + wayCount = 1, + addressWidth = 32, + cpuDataWidth = 32, + memDataWidth = 32, + catchIllegalAccess = true, + catchAccessFault = true, + asyncTagMemory = false, + twoCycleRam = true, + twoCycleCache = true ), - new DBusCachedPlugin( - config = new DataCacheConfig( - cacheSize = 4096, - bytePerLine = 32, - wayCount = 1, - addressWidth = 32, - cpuDataWidth = 32, - memDataWidth = 32, - catchAccessError = true, - catchIllegal = true, - catchUnaligned = true - ), - memoryTranslatorPortConfig = MmuPortConfig( - portTlbSize = 6 - ) + memoryTranslatorPortConfig = MmuPortConfig( + portTlbSize = 4 + ) + ), + new DBusCachedPlugin( + config = new DataCacheConfig( + cacheSize = 4096, + bytePerLine = 32, + wayCount = 1, + addressWidth = 32, + cpuDataWidth = 32, + memDataWidth = 32, + catchAccessError = true, + catchIllegal = true, + catchUnaligned = true ), - new MmuPlugin( - virtualRange = _(31 downto 28) === 0xC, - ioRange = _(31 downto 28) === 0xF - ), - new DecoderSimplePlugin( - catchIllegalInstruction = true - ), - new RegFilePlugin( - regFileReadyKind = plugin.SYNC, - zeroBoot = false - ), - new IntAluPlugin, - new SrcPlugin( - separatedAddSub = false, - executeInsertion = true - ), - new FullBarrelShifterPlugin, - new HazardSimplePlugin( - bypassExecute = true, - bypassMemory = true, - bypassWriteBack = true, - bypassWriteBackBuffer = true, - pessimisticUseSrc = false, - pessimisticWriteRegFile = false, - pessimisticAddressMatch = false - ), - new MulPlugin, - new DivPlugin, - new CsrPlugin(CsrPluginConfig.small(0x80000020l)), - new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))), - new BranchPlugin( - earlyBranch = false, - catchAddressMisaligned = true - ), - new YamlPlugin("cpu0.yaml") - ) + memoryTranslatorPortConfig = MmuPortConfig( + portTlbSize = 6 + ) + ), + new MmuPlugin( + virtualRange = _(31 downto 28) === 0xC, + ioRange = _(31 downto 28) === 0xF + ), + new DecoderSimplePlugin( + catchIllegalInstruction = true + ), + new RegFilePlugin( + regFileReadyKind = plugin.SYNC, + zeroBoot = false + ), + new IntAluPlugin, + new SrcPlugin( + separatedAddSub = false, + executeInsertion = true + ), + new FullBarrelShifterPlugin, + new HazardSimplePlugin( + bypassExecute = true, + bypassMemory = true, + bypassWriteBack = true, + bypassWriteBackBuffer = true, + pessimisticUseSrc = false, + pessimisticWriteRegFile = false, + pessimisticAddressMatch = false + ), + new MulPlugin, + new DivPlugin, + new CsrPlugin(CsrPluginConfig.small(0x80000020l)), + new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))), + new BranchPlugin( + earlyBranch = false, + catchAddressMisaligned = true + ), + new YamlPlugin("cpu0.yaml") ) ) + def cpu() = new VexRiscv( + config + ) + SpinalVerilog(cpu()) } diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index eff10975..97f803c9 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -120,7 +120,6 @@ case class DataCacheCpuExecute(p : DataCacheConfig) extends Bundle with IMasterS case class DataCacheCpuExecuteArgs(p : DataCacheConfig) extends Bundle{ val wr = Bool - val data = Bits(p.cpuDataWidth bit) val size = UInt(2 bits) val isLrsc = p.withLrSc generate Bool() val isAmo = p.withAmo generate Bool() @@ -169,6 +168,7 @@ case class DataCacheCpuWriteBack(p : DataCacheConfig) extends Bundle with IMaste val isUser = Bool() val haltIt = Bool() val isWrite = Bool() + val storeData = Bits(p.cpuDataWidth bit) val data = Bits(p.cpuDataWidth bit) val address = UInt(p.addressWidth bit) val mmuException, unalignedAccess, accessError = Bool() @@ -176,7 +176,7 @@ case class DataCacheCpuWriteBack(p : DataCacheConfig) extends Bundle with IMaste val fence = FenceFlags() override def asMaster(): Unit = { - out(isValid,isStuck,isUser, address, fence) + out(isValid,isStuck,isUser, address, fence, storeData) in(haltIt, data, mmuException, unalignedAccess, accessError, isWrite, keepMemRspData) } } @@ -804,35 +804,32 @@ class DataCache(val p : DataCacheConfig, mmuParameter : MemoryTranslatorBusParam val ioMemRspMuxed = io.mem.rsp.data.subdivideIn(cpuDataWidth bits).read(io.cpu.writeBack.address(memWordToCpuWordRange)) - io.cpu.writeBack.haltIt := io.cpu.writeBack.isValid + io.cpu.writeBack.haltIt := True //Evict the cache after reset logics val flusher = new Area { - val valid = RegInit(False) + val waitDone = RegInit(False) clearWhen(io.cpu.flush.ready) val hold = False - when(valid) { - tagsWriteCmd.valid := valid - tagsWriteCmd.address := mmuRsp.physicalAddress(lineRange) + val counter = Reg(UInt(lineRange.size + 1 bits)) init(0) + when(!counter.msb) { + tagsWriteCmd.valid := True + tagsWriteCmd.address := counter.resized tagsWriteCmd.way.setAll() tagsWriteCmd.data.valid := False - io.cpu.writeBack.haltIt := True + io.cpu.execute.haltIt := True when(!hold) { - when(mmuRsp.physicalAddress(lineRange) =/= wayLineCount - 1) { - mmuRsp.physicalAddress.getDrivingReg(lineRange) := mmuRsp.physicalAddress(lineRange) + 1 - } otherwise { - valid := False - } + counter := counter + 1 } } - io.cpu.flush.ready := False + io.cpu.flush.ready := waitDone && counter.msb + val start = RegInit(True) //Used to relax timings - start := !start && io.cpu.flush.valid && !io.cpu.execute.isValid && !io.cpu.memory.isValid && !io.cpu.writeBack.isValid && !io.cpu.redo + start := !waitDone && !start && io.cpu.flush.valid && !io.cpu.execute.isValid && !io.cpu.memory.isValid && !io.cpu.writeBack.isValid && !io.cpu.redo when(start){ - io.cpu.flush.ready := True - mmuRsp.physicalAddress.getDrivingReg(lineRange) := 0 - valid := True + waitDone := True + counter := 0 } } @@ -848,10 +845,10 @@ class DataCache(val p : DataCacheConfig, mmuParameter : MemoryTranslatorBusParam val isExternalLsrc = if(withExternalLrSc) request.isLrsc else False val isExternalAmo = if(withExternalAmo) request.isAmo else False - val requestDataBypass = CombInit(request.data) + val requestDataBypass = CombInit(io.cpu.writeBack.storeData) import DataCacheExternalAmoStates._ val amo = withAmo generate new Area{ - def rf = request.data + def rf = io.cpu.writeBack.storeData def mem = if(withInternalAmo) dataMux else ioMemRspMuxed val compare = request.amoCtrl.alu.msb val unsigned = request.amoCtrl.alu(2 downto 1) === B"11" diff --git a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala index c64ddb36..c95f4aeb 100644 --- a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala +++ b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala @@ -10,28 +10,31 @@ object FpuDivSqrtIterationState extends SpinalEnum{ val IDLE, YY, XYY, Y2_XYY, DIV, _15_XYY2, Y_15_XYY2, Y_15_XYY2_RESULT, SQRT = newElement() } -case class FpuCore(p : FpuParameter) extends Component{ +case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val io = new Bundle { - val port = slave(FpuPort(p)) + val port = Vec(slave(FpuPort(p)), portCount) } + val portCountWidth = log2Up(portCount) + val Source = HardType(UInt(portCountWidth bits)) -// val commitPerSourceCount = 8 + +// val commitPerportCount = 8 val rfLockCount = 5 val lockIdType = HardType(UInt(log2Up(rfLockCount) bits)) - io.port.rsp.valid := False - io.port.rsp.payload.assignDontCare() +// io.port.rsp.valid := False +// io.port.rsp.payload.assignDontCare() case class RfReadInput() extends Bundle{ - val source = p.source() + val source = Source() val opcode = p.Opcode() val rs1, rs2, rs3 = p.rfAddress() val rd = p.rfAddress() } case class RfReadOutput() extends Bundle{ - val source = p.source() + val source = Source() val opcode = p.Opcode() val lockId = lockIdType() val rs1, rs2, rs3 = p.internalFloating() @@ -40,19 +43,19 @@ case class FpuCore(p : FpuParameter) extends Component{ case class LoadInput() extends Bundle{ - val source = p.source() + val source = Source() val rs1 = p.internalFloating() val rd = p.rfAddress() val lockId = lockIdType() } case class StoreInput() extends Bundle{ - val source = p.source() + val source = Source() val rs2 = p.internalFloating() } case class MulInput() extends Bundle{ - val source = p.source() + val source = Source() val rs1, rs2, rs3 = p.internalFloating() val rd = p.rfAddress() val lockId = lockIdType() @@ -63,7 +66,7 @@ case class FpuCore(p : FpuParameter) extends Component{ } case class DivSqrtInput() extends Bundle{ - val source = p.source() + val source = Source() val rs1, rs2 = p.internalFloating() val rd = p.rfAddress() val lockId = lockIdType() @@ -71,14 +74,14 @@ case class FpuCore(p : FpuParameter) extends Component{ } case class AddInput() extends Bundle{ - val source = p.source() + val source = Source() val rs1, rs2 = p.internalFloating() val rd = p.rfAddress() val lockId = lockIdType() } case class WriteInput() extends Bundle{ - val source = p.source() + val source = Source() val lockId = lockIdType() val rd = p.rfAddress() val value = p.internalFloating() @@ -86,10 +89,10 @@ case class FpuCore(p : FpuParameter) extends Component{ val rf = new Area{ - val ram = Mem(p.internalFloating, 32*(1 << p.sourceWidth)) + val ram = Mem(p.internalFloating, 32*portCount) val lock = for(i <- 0 until rfLockCount) yield new Area{ val valid = RegInit(False) - val source = Reg(p.source) + val source = Reg(Source()) val address = Reg(p.rfAddress) val id = Reg(UInt(log2Up(rfLockCount) bits)) val commited = Reg(Bool) @@ -99,21 +102,21 @@ case class FpuCore(p : FpuParameter) extends Component{ val lockFreeId = OHMasking.first(lock.map(!_.valid)) } - val commitLogic = for(source <- 0 until p.sourceCount) yield new Area{ + val commitLogic = for(source <- 0 until portCount) yield new Area{ val fire = False val target, hit = Reg(UInt(log2Up(rfLockCount) bits)) init(0) when(fire){ hit := hit + 1 } - io.port.commit(source).ready := False - when(io.port.commit(source).valid) { + io.port(source).commit.ready := False + when(io.port(source).commit.valid) { for (lock <- rf.lock) { when(lock.valid && lock.source === source && lock.id === hit) { fire := True lock.commited := True - lock.write := io.port.commit(source).write - io.port.commit(source).ready := True + lock.write := io.port(source).commit.write + io.port(source).commit.ready := True } } } @@ -123,16 +126,20 @@ case class FpuCore(p : FpuParameter) extends Component{ // val valid = Bool() // val write = Bool() // } -// val commits = for(i <- 0 until p.sourceCount) yield new Area{ -// val lines = Vec(CommitLine(), commitPerSourceCount) +// val commits = for(i <- 0 until portCount) yield new Area{ +// val lines = Vec(CommitLine(), commitPerportCount) // lines.foreach(_.valid init(False)) // // } val read = new Area{ + val arbiter = StreamArbiterFactory.noLock.lowerFirst.build(FpuCmd(p), portCount) + arbiter.io.inputs <> Vec(io.port.map(_.cmd)) + val s0 = Stream(RfReadInput()) - s0.arbitrationFrom(io.port.cmd) - s0.payload.assignSomeByName(io.port.cmd.payload) + s0.arbitrationFrom(arbiter.io.output) + s0.source := arbiter.io.chosen + s0.payload.assignSomeByName(arbiter.io.output.payload) val useRs1, useRs2, useRs3, useRd = False switch(s0.opcode){ @@ -172,7 +179,7 @@ case class FpuCore(p : FpuParameter) extends Component{ val hits = List((useRs1, s0.rs1), (useRs2, s0.rs2), (useRs3, s0.rs3), (useRd, s0.rd)).map{case (use, reg) => use && rf.lock.map(l => l.valid && l.source === s0.source && l.address === reg).orR} val hazard = hits.orR when(s0.fire && useRd){ - for(i <- 0 until p.sourceCount){ + for(i <- 0 until portCount){ when(s0.source === i){ commitLogic(i).target := commitLogic(i).target + 1 } @@ -183,6 +190,7 @@ case class FpuCore(p : FpuParameter) extends Component{ rf.lock(i).source := s0.source rf.lock(i).address := s0.rd rf.lock(i).id := commitLogic.map(_.target).read(s0.source) + rf.lock(i).commited := False } } } @@ -194,9 +202,9 @@ case class FpuCore(p : FpuParameter) extends Component{ output.opcode := s1.opcode output.lockId := s1LockId output.rd := s1.rd - output.rs1 := rf.ram.readSync(s0.rs1,enable = !output.isStall) - output.rs2 := rf.ram.readSync(s0.rs2,enable = !output.isStall) - output.rs3 := rf.ram.readSync(s0.rs3,enable = !output.isStall) + output.rs1 := rf.ram.readSync(s0.source @@ s0.rs1,enable = !output.isStall) + output.rs2 := rf.ram.readSync(s0.source @@ s0.rs2,enable = !output.isStall) + output.rs3 := rf.ram.readSync(s0.source @@ s0.rs3,enable = !output.isStall) } val decode = new Area{ @@ -266,10 +274,10 @@ case class FpuCore(p : FpuParameter) extends Component{ val load = new Area{ val input = decode.load.stage() - def feed = io.port.load(input.source) + def feed = io.port(input.source).load val hazard = !feed.valid val output = input.haltWhen(hazard).swapPayload(WriteInput()) - io.port.load.foreach(_.ready := False) + io.port.foreach(_.load.ready := False) feed.ready := input.valid && output.ready output.source := input.source output.lockId := input.lockId @@ -281,11 +289,11 @@ case class FpuCore(p : FpuParameter) extends Component{ val store = new Area{ val input = decode.store.stage() - input.ready := io.port.rsp.ready - when(input.valid){ - io.port.rsp.valid := True - io.port.rsp.source := input.source - io.port.rsp.value := input.rs2.asBits + input.ready := io.port.map(_.rsp.ready).read(input.source) + for(i <- 0 until portCount){ + def rsp = io.port(i).rsp + rsp.valid := input.valid && input.source === i + rsp.value := input.rs2.asBits } } @@ -576,10 +584,10 @@ case class FpuCore(p : FpuParameter) extends Component{ object FpuSynthesisBench extends App{ val payloadType = HardType(Bits(8 bits)) - class Fpu(name : String, p : FpuParameter) extends Rtl{ + class Fpu(name : String, portCount : Int, p : FpuParameter) extends Rtl{ override def getName(): String = "Fpu_" + name override def getRtlPath(): String = getName() + ".v" - SpinalVerilog(new FpuCore(p){ + SpinalVerilog(new FpuCore(portCount, p){ setDefinitionName(Fpu.this.getName()) }) @@ -590,18 +598,18 @@ object FpuSynthesisBench extends App{ val rtls = ArrayBuffer[Fpu]() rtls += new Fpu( "32", + portCount = 1, FpuParameter( internalMantissaSize = 23, - withDouble = false, - sourceCount = 1 + withDouble = false ) ) rtls += new Fpu( "64", + portCount = 1, FpuParameter( internalMantissaSize = 52, - withDouble = true, - sourceCount = 1 + withDouble = true ) ) diff --git a/src/main/scala/vexriscv/ip/fpu/Interface.scala b/src/main/scala/vexriscv/ip/fpu/Interface.scala index 00e526a9..34336026 100644 --- a/src/main/scala/vexriscv/ip/fpu/Interface.scala +++ b/src/main/scala/vexriscv/ip/fpu/Interface.scala @@ -32,23 +32,19 @@ object FpuFormat extends SpinalEnum{ case class FpuParameter( internalMantissaSize : Int, - withDouble : Boolean, - sourceCount : Int){ + withDouble : Boolean){ val storeLoadType = HardType(Bits(if(withDouble) 64 bits else 32 bits)) val internalExponentSize = if(withDouble) 11 else 8 val internalFloating = HardType(FpuFloat(exponentSize = internalExponentSize, mantissaSize = internalMantissaSize)) -// val opcode = HardType(UInt(2 bits)) - val source = HardType(UInt(sourceWidth bits)) + val rfAddress = HardType(UInt(5 bits)) val Opcode = FpuOpcode val Format = FpuFormat - val sourceWidth = log2Up(sourceCount) } case class FpuCmd(p : FpuParameter) extends Bundle{ - val source = UInt(p.sourceWidth bits) val opcode = p.Opcode() val value = Bits(32 bits) // Int to float val function = Bits(3 bits) // Int to float @@ -66,19 +62,17 @@ case class FpuLoad(p : FpuParameter) extends Bundle{ } case class FpuRsp(p : FpuParameter) extends Bundle{ - val source = UInt(p.sourceWidth bits) val value = p.storeLoadType() // IEEE754 store || Integer } case class FpuPort(p : FpuParameter) extends Bundle with IMasterSlave { val cmd = Stream(FpuCmd(p)) - val commit = Vec(Stream(FpuCommit(p)), p.sourceCount) - val load = Vec(Stream(FpuLoad(p)), p.sourceCount) + val commit = Stream(FpuCommit(p)) + val load = Stream(FpuLoad(p)) val rsp = Stream(FpuRsp(p)) override def asMaster(): Unit = { - master(cmd) - (commit ++ load).foreach(master(_)) + master(cmd, commit, load) slave(rsp) } } diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index 2d66a582..17062e44 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -18,13 +18,20 @@ class DAxiCachedPlugin(config : DataCacheConfig, memoryTranslatorPortConfig : An } } +trait DBusEncodingService { + def addLoadWordEncoding(key: MaskedLiteral): Unit + def addStoreWordEncoding(key: MaskedLiteral): Unit + def encodingHalt(): Unit + def bypassStore(data : Bits) : Unit +} + class DBusCachedPlugin(val config : DataCacheConfig, memoryTranslatorPortConfig : Any = null, dBusCmdMasterPipe : Boolean = false, dBusCmdSlavePipe : Boolean = false, dBusRspSlavePipe : Boolean = false, relaxedMemoryTranslationRegister : Boolean = false, - csrInfo : Boolean = false) extends Plugin[VexRiscv] with DBusAccessService { + csrInfo : Boolean = false) extends Plugin[VexRiscv] with DBusAccessService with DBusEncodingService { import config._ assert(!(config.withExternalAmo && !dBusRspSlavePipe)) assert(isPow2(cacheSize)) @@ -43,6 +50,54 @@ class DBusCachedPlugin(val config : DataCacheConfig, dBusAccess } + override def addLoadWordEncoding(key : MaskedLiteral): Unit = { + val decoderService = pipeline.service(classOf[DecoderService]) + val cfg = pipeline.config + import cfg._ + + decoderService.add( + key, + List( + SRC1_CTRL -> Src1CtrlEnum.RS, + SRC_USE_SUB_LESS -> False, + MEMORY_ENABLE -> True, + RS1_USE -> True, + IntAluPlugin.ALU_CTRL -> IntAluPlugin.AluCtrlEnum.ADD_SUB, + SRC2_CTRL -> Src2CtrlEnum.IMI, + // REGFILE_WRITE_VALID -> True, + // BYPASSABLE_EXECUTE_STAGE -> False, + // BYPASSABLE_MEMORY_STAGE -> False, + MEMORY_WR -> False + ) ++ (if(catchSomething) List(HAS_SIDE_EFFECT -> True) else Nil) + ) + } + override def addStoreWordEncoding(key : MaskedLiteral): Unit = { + val decoderService = pipeline.service(classOf[DecoderService]) + val cfg = pipeline.config + import cfg._ + + decoderService.add( + key, + List( + SRC1_CTRL -> Src1CtrlEnum.RS, + SRC_USE_SUB_LESS -> False, + MEMORY_ENABLE -> True, + RS1_USE -> True, + IntAluPlugin.ALU_CTRL -> IntAluPlugin.AluCtrlEnum.ADD_SUB, + SRC2_CTRL -> Src2CtrlEnum.IMS, +// RS2_USE -> True, + MEMORY_WR -> True + ) ++ (if(catchSomething) List(HAS_SIDE_EFFECT -> True) else Nil) + ) + } + + var haltFromEncoding : Bool = null + override def encodingHalt(): Unit = haltFromEncoding := True + + override def bypassStore(data: Bits): Unit = { + pipeline.stages.last.input(MEMORY_STORE_DATA) := data + } + object MEMORY_ENABLE extends Stageable(Bool) object MEMORY_MANAGMENT extends Stageable(Bool) object MEMORY_WR extends Stageable(Bool) @@ -53,6 +108,7 @@ class DBusCachedPlugin(val config : DataCacheConfig, object MEMORY_FORCE_CONSTISTENCY extends Stageable(Bool) object IS_DBUS_SHARING extends Stageable(Bool()) object MEMORY_VIRTUAL_ADDRESS extends Stageable(UInt(32 bits)) + object MEMORY_STORE_DATA extends Stageable(Bits(32 bits)) override def setup(pipeline: VexRiscv): Unit = { import Riscv._ @@ -164,6 +220,8 @@ class DBusCachedPlugin(val config : DataCacheConfig, privilegeService = pipeline.service(classOf[PrivilegeService]) pipeline.update(DEBUG_BYPASS_CACHE, False) + + haltFromEncoding = False } override def build(pipeline: VexRiscv): Unit = { @@ -240,7 +298,7 @@ class DBusCachedPlugin(val config : DataCacheConfig, cache.io.cpu.execute.isValid := arbitration.isValid && input(MEMORY_ENABLE) cache.io.cpu.execute.address := input(SRC_ADD).asUInt cache.io.cpu.execute.args.wr := input(MEMORY_WR) - cache.io.cpu.execute.args.data := size.mux( + insert(MEMORY_STORE_DATA) := size.mux( U(0) -> input(RS2)( 7 downto 0) ## input(RS2)( 7 downto 0) ## input(RS2)(7 downto 0) ## input(RS2)(7 downto 0), U(1) -> input(RS2)(15 downto 0) ## input(RS2)(15 downto 0), default -> input(RS2)(31 downto 0) @@ -312,6 +370,7 @@ class DBusCachedPlugin(val config : DataCacheConfig, cache.io.cpu.writeBack.isStuck := arbitration.isStuck cache.io.cpu.writeBack.isUser := (if(privilegeService != null) privilegeService.isUser() else False) cache.io.cpu.writeBack.address := U(input(REGFILE_WRITE_DATA)) + cache.io.cpu.writeBack.storeData := input(MEMORY_STORE_DATA) val fence = if(withInvalidate) new Area { cache.io.cpu.writeBack.fence := input(INSTRUCTION)(31 downto 20).as(FenceFlags()) @@ -371,7 +430,7 @@ class DBusCachedPlugin(val config : DataCacheConfig, } } - arbitration.haltItself.setWhen(cache.io.cpu.writeBack.haltIt) + arbitration.haltItself.setWhen(cache.io.cpu.writeBack.isValid && cache.io.cpu.writeBack.haltIt) val rspShifted = Bits(32 bits) rspShifted := cache.io.cpu.writeBack.data @@ -390,6 +449,8 @@ class DBusCachedPlugin(val config : DataCacheConfig, when(arbitration.isValid && input(MEMORY_ENABLE)) { output(REGFILE_WRITE_DATA) := rspFormated } + + insert(DBUS_DATA) := cache.io.cpu.writeBack.data } //Share access to the dBus (used by self refilled MMU) @@ -405,7 +466,7 @@ class DBusCachedPlugin(val config : DataCacheConfig, dBusAccess.cmd.ready := !execute.arbitration.isStuck } cache.io.cpu.execute.args.wr := dBusAccess.cmd.write - cache.io.cpu.execute.args.data := dBusAccess.cmd.data + execute.insert(MEMORY_STORE_DATA) := dBusAccess.cmd.data cache.io.cpu.execute.args.size := dBusAccess.cmd.size if(withLrSc) cache.io.cpu.execute.args.isLrsc := False if(withAmo) cache.io.cpu.execute.args.isAmo := False @@ -435,6 +496,11 @@ class DBusCachedPlugin(val config : DataCacheConfig, } } + when(haltFromEncoding){ + cache.io.cpu.writeBack.isValid := False + managementStage.arbitration.haltItself := True + } + if(csrInfo){ val csr = service(classOf[CsrPlugin]) csr.r(0xCC0, 0 -> U(cacheSize/wayCount), 20 -> U(bytePerLine)) diff --git a/src/main/scala/vexriscv/plugin/FpuPlugin.scala b/src/main/scala/vexriscv/plugin/FpuPlugin.scala new file mode 100644 index 00000000..a438705a --- /dev/null +++ b/src/main/scala/vexriscv/plugin/FpuPlugin.scala @@ -0,0 +1,124 @@ +package vexriscv.plugin + +import spinal.core._ +import spinal.lib._ +import vexriscv._ +import vexriscv.Riscv._ +import vexriscv.ip.fpu._ + +class FpuPlugin(externalFpu : Boolean = false, + p : FpuParameter) extends Plugin[VexRiscv]{ + + object FPU_ENABLE extends Stageable(Bool()) + object FPU_COMMIT extends Stageable(Bool()) + object FPU_LOAD extends Stageable(Bool()) + object FPU_STORE extends Stageable(Bool()) + object FPU_ALU extends Stageable(Bool()) + object FPU_FORKED extends Stageable(Bool()) + object FPU_OPCODE extends Stageable(FpuOpcode()) + + var port : FpuPort = null + + override def setup(pipeline: VexRiscv): Unit = { + val decoderService = pipeline.service(classOf[DecoderService]) + decoderService.addDefault(FPU_ENABLE, False) + decoderService.add(List( + FADD_S -> List(FPU_ENABLE -> True, FPU_OPCODE -> FpuOpcode.ADD, FPU_COMMIT -> True, FPU_ALU -> True , FPU_LOAD -> False, FPU_STORE -> False), + FLW -> List(FPU_ENABLE -> True, FPU_OPCODE -> FpuOpcode.LOAD, FPU_COMMIT -> True, FPU_ALU -> False, FPU_LOAD -> True , FPU_STORE -> False), + FSW -> List(FPU_ENABLE -> True, FPU_OPCODE -> FpuOpcode.STORE,FPU_COMMIT -> False, FPU_ALU -> False, FPU_LOAD -> False, FPU_STORE -> True) + )) + + port = FpuPort(p) + if(externalFpu) master(port) + + val dBusEncoding = pipeline.service(classOf[DBusEncodingService]) + dBusEncoding.addLoadWordEncoding(FLW) + dBusEncoding.addStoreWordEncoding(FSW) + } + + override def build(pipeline: VexRiscv): Unit = { + import pipeline._ + import pipeline.config._ + + val internal = !externalFpu generate pipeline plug new Area{ + val fpu = FpuCore(1, p) + fpu.io.port(0).cmd << port.cmd + fpu.io.port(0).commit << port.commit + fpu.io.port(0).load << port.load + fpu.io.port(0).rsp >> port.rsp + + } + + + decode plug new Area{ + import decode._ + + //Maybe it might be better to not fork before fire to avoid RF stall on commits + val forked = Reg(Bool) setWhen(port.cmd.fire) clearWhen(!arbitration.isStuck) init(False) + + arbitration.haltItself setWhen(port.cmd.isStall) + port.cmd.valid := arbitration.isValid && input(FPU_ENABLE) && !forked + port.cmd.opcode := input(FPU_OPCODE) + port.cmd.value := output(RS1) + port.cmd.function := 0 + port.cmd.rs1 := input(INSTRUCTION)(rs1Range).asUInt + port.cmd.rs2 := input(INSTRUCTION)(rs2Range).asUInt + port.cmd.rs3 := input(INSTRUCTION)(rs3Range).asUInt + port.cmd.rd := input(INSTRUCTION)(rdRange).asUInt + port.cmd.format := FpuFormat.FLOAT + + insert(FPU_FORKED) := forked || port.cmd.fire + } + + memory plug new Area{ + import memory._ + + val isCommit = input(FPU_FORKED) && input(FPU_COMMIT) + + val commit = Stream(FpuCommit(p)) + commit.valid := isCommit && arbitration.isMoving + commit.write := arbitration.isValid + + arbitration.haltItself setWhen(isCommit && !commit.ready) //Assume commit.ready do not look at commit.valid + + port.commit <-/< commit //TODO can't commit in memory, in case a load fail + } + + writeBack plug new Area{ + import writeBack._ + + val dBusEncoding = pipeline.service(classOf[DBusEncodingService]) + val isLoad = input(FPU_FORKED) && input(FPU_LOAD) + val isStore = input(FPU_FORKED) && input(FPU_STORE) + + //Manage $store and port.rsp + port.rsp.ready := False + when(isStore){ + port.rsp.ready := True + when(arbitration.isValid) { + dBusEncoding.bypassStore(port.rsp.value) + } + when(!port.rsp.valid){ + dBusEncoding.encodingHalt() + } + } + + // Manage $load + val load = Stream(FpuLoad(p)) + load.valid := isLoad && arbitration.isMoving + load.value.assignFromBits(output(DBUS_DATA)) + + when(arbitration.isValid && !load.ready){ + dBusEncoding.encodingHalt() + } + + port.load <-/< load + } + + Component.current.afterElaboration{ + pipeline.stages.tail.foreach(_.input(FPU_FORKED).init(False)) + } + } + + +} diff --git a/src/test/cpp/raw/common/asm.mk b/src/test/cpp/raw/common/asm.mk index b63c80a6..92b51ceb 100644 --- a/src/test/cpp/raw/common/asm.mk +++ b/src/test/cpp/raw/common/asm.mk @@ -18,6 +18,9 @@ endif ifeq ($(COMPRESSED),yes) MARCH := $(MARCH)c endif +ifeq ($(FLOATING),yes) + MARCH := $(MARCH)fd +endif CFLAGS += -march=$(MARCH) -mabi=$(MABI) LDFLAGS += -march=$(MARCH) -mabi=$(MABI) diff --git a/src/test/cpp/raw/fpu/.gitignore b/src/test/cpp/raw/fpu/.gitignore new file mode 100644 index 00000000..c12cb2c2 --- /dev/null +++ b/src/test/cpp/raw/fpu/.gitignore @@ -0,0 +1,4 @@ +*.map +*.v +*.elf +*.o \ No newline at end of file diff --git a/src/test/cpp/raw/fpu/build/amo.asm b/src/test/cpp/raw/fpu/build/amo.asm new file mode 100644 index 00000000..d86b61ca --- /dev/null +++ b/src/test/cpp/raw/fpu/build/amo.asm @@ -0,0 +1,247 @@ + +build/amo.elf: file format elf32-littleriscv + + +Disassembly of section .crt_section: + +80000000 <_start>: +80000000: 00100e13 li t3,1 +80000004: 00000097 auipc ra,0x0 +80000008: 27408093 addi ra,ra,628 # 80000278 +8000000c: 02d00113 li sp,45 +80000010: 0820a1af amoswap.w gp,sp,(ra) +80000014: 0000a203 lw tp,0(ra) +80000018: 02d00a13 li s4,45 +8000001c: 224a1663 bne s4,tp,80000248 +80000020: 00b00a13 li s4,11 +80000024: 223a1263 bne s4,gp,80000248 + +80000028 : +80000028: 00200e13 li t3,2 +8000002c: 00000097 auipc ra,0x0 +80000030: 25008093 addi ra,ra,592 # 8000027c +80000034: 03700113 li sp,55 +80000038: 0820a1af amoswap.w gp,sp,(ra) +8000003c: 0000a203 lw tp,0(ra) +80000040: 03700a13 li s4,55 +80000044: 204a1263 bne s4,tp,80000248 +80000048: 01600a13 li s4,22 +8000004c: 1e3a1e63 bne s4,gp,80000248 + +80000050 : +80000050: 00300e13 li t3,3 +80000054: 00000097 auipc ra,0x0 +80000058: 22c08093 addi ra,ra,556 # 80000280 +8000005c: 04200113 li sp,66 +80000060: 0020a1af amoadd.w gp,sp,(ra) +80000064: 0000a203 lw tp,0(ra) +80000068: 08b00a13 li s4,139 +8000006c: 1c4a1e63 bne s4,tp,80000248 +80000070: 04900a13 li s4,73 +80000074: 1c3a1a63 bne s4,gp,80000248 + +80000078 : +80000078: 00400e13 li t3,4 +8000007c: 00000097 auipc ra,0x0 +80000080: 20808093 addi ra,ra,520 # 80000284 +80000084: 05700113 li sp,87 +80000088: 2020a1af amoxor.w gp,sp,(ra) +8000008c: 0000a203 lw tp,0(ra) +80000090: 06d00a13 li s4,109 +80000094: 1a4a1a63 bne s4,tp,80000248 +80000098: 03a00a13 li s4,58 +8000009c: 1a3a1663 bne s4,gp,80000248 + +800000a0 : +800000a0: 00500e13 li t3,5 +800000a4: 00000097 auipc ra,0x0 +800000a8: 1e408093 addi ra,ra,484 # 80000288 +800000ac: 02c00113 li sp,44 +800000b0: 6020a1af amoand.w gp,sp,(ra) +800000b4: 0000a203 lw tp,0(ra) +800000b8: 02800a13 li s4,40 +800000bc: 184a1663 bne s4,tp,80000248 +800000c0: 03800a13 li s4,56 +800000c4: 183a1263 bne s4,gp,80000248 + +800000c8 : +800000c8: 00600e13 li t3,6 +800000cc: 00000097 auipc ra,0x0 +800000d0: 1c008093 addi ra,ra,448 # 8000028c +800000d4: 01800113 li sp,24 +800000d8: 4020a1af amoor.w gp,sp,(ra) +800000dc: 0000a203 lw tp,0(ra) +800000e0: 05b00a13 li s4,91 +800000e4: 164a1263 bne s4,tp,80000248 +800000e8: 04b00a13 li s4,75 +800000ec: 143a1e63 bne s4,gp,80000248 + +800000f0 : +800000f0: 00700e13 li t3,7 +800000f4: 00000097 auipc ra,0x0 +800000f8: 19c08093 addi ra,ra,412 # 80000290 +800000fc: 01800113 li sp,24 +80000100: 8020a1af amomin.w gp,sp,(ra) +80000104: 0000a203 lw tp,0(ra) +80000108: 01800a13 li s4,24 +8000010c: 124a1e63 bne s4,tp,80000248 +80000110: 03800a13 li s4,56 +80000114: 123a1a63 bne s4,gp,80000248 + +80000118 : +80000118: 00800e13 li t3,8 +8000011c: 00000097 auipc ra,0x0 +80000120: 17808093 addi ra,ra,376 # 80000294 +80000124: 05800113 li sp,88 +80000128: 8020a1af amomin.w gp,sp,(ra) +8000012c: 0000a203 lw tp,0(ra) +80000130: 05300a13 li s4,83 +80000134: 104a1a63 bne s4,tp,80000248 +80000138: 05300a13 li s4,83 +8000013c: 103a1663 bne s4,gp,80000248 + +80000140 : +80000140: 00900e13 li t3,9 +80000144: 00000097 auipc ra,0x0 +80000148: 15408093 addi ra,ra,340 # 80000298 +8000014c: fca00113 li sp,-54 +80000150: 8020a1af amomin.w gp,sp,(ra) +80000154: 0000a203 lw tp,0(ra) +80000158: fca00a13 li s4,-54 +8000015c: 0e4a1663 bne s4,tp,80000248 +80000160: 02100a13 li s4,33 +80000164: 0e3a1263 bne s4,gp,80000248 + +80000168 : +80000168: 00a00e13 li t3,10 +8000016c: 00000097 auipc ra,0x0 +80000170: 13008093 addi ra,ra,304 # 8000029c +80000174: 03400113 li sp,52 +80000178: 8020a1af amomin.w gp,sp,(ra) +8000017c: 0000a203 lw tp,0(ra) +80000180: fbf00a13 li s4,-65 +80000184: 0c4a1263 bne s4,tp,80000248 +80000188: fbf00a13 li s4,-65 +8000018c: 0a3a1e63 bne s4,gp,80000248 + +80000190 : +80000190: 00b00e13 li t3,11 +80000194: 00000097 auipc ra,0x0 +80000198: 10c08093 addi ra,ra,268 # 800002a0 +8000019c: fcc00113 li sp,-52 +800001a0: a020a1af amomax.w gp,sp,(ra) +800001a4: 0000a203 lw tp,0(ra) +800001a8: fcc00a13 li s4,-52 +800001ac: 084a1e63 bne s4,tp,80000248 +800001b0: fa900a13 li s4,-87 +800001b4: 083a1a63 bne s4,gp,80000248 + +800001b8 : +800001b8: 00c00e13 li t3,12 +800001bc: 00000097 auipc ra,0x0 +800001c0: 0e808093 addi ra,ra,232 # 800002a4 +800001c4: 03400113 li sp,52 +800001c8: a020a1af amomax.w gp,sp,(ra) +800001cc: 0000a203 lw tp,0(ra) +800001d0: 03400a13 li s4,52 +800001d4: 064a1a63 bne s4,tp,80000248 +800001d8: fc900a13 li s4,-55 +800001dc: 063a1663 bne s4,gp,80000248 + +800001e0 : +800001e0: 00d00e13 li t3,13 +800001e4: 00000097 auipc ra,0x0 +800001e8: 0c408093 addi ra,ra,196 # 800002a8 +800001ec: ffff0137 lui sp,0xffff0 +800001f0: c020a1af amominu.w gp,sp,(ra) +800001f4: 0000a203 lw tp,0(ra) +800001f8: ffff0a37 lui s4,0xffff0 +800001fc: 044a1663 bne s4,tp,80000248 +80000200: ffff0a37 lui s4,0xffff0 +80000204: 004a0a13 addi s4,s4,4 # ffff0004 +80000208: 043a1063 bne s4,gp,80000248 +8000020c: 0480006f j 80000254 + +80000210 : +80000210: 00e00e13 li t3,14 +80000214: 00000097 auipc ra,0x0 +80000218: 09808093 addi ra,ra,152 # 800002ac +8000021c: ffff0137 lui sp,0xffff0 +80000220: 00c10113 addi sp,sp,12 # ffff000c +80000224: e020a1af amomaxu.w gp,sp,(ra) +80000228: 0000a203 lw tp,0(ra) +8000022c: ffff0a37 lui s4,0xffff0 +80000230: 00ca0a13 addi s4,s4,12 # ffff000c +80000234: 004a1a63 bne s4,tp,80000248 +80000238: ffff0a37 lui s4,0xffff0 +8000023c: 005a0a13 addi s4,s4,5 # ffff0005 +80000240: 003a1463 bne s4,gp,80000248 +80000244: 0100006f j 80000254 + +80000248 : +80000248: f0100137 lui sp,0xf0100 +8000024c: f2410113 addi sp,sp,-220 # f00fff24 +80000250: 01c12023 sw t3,0(sp) + +80000254 : +80000254: f0100137 lui sp,0xf0100 +80000258: f2010113 addi sp,sp,-224 # f00fff20 +8000025c: 00012023 sw zero,0(sp) +80000260: 00000013 nop +80000264: 00000013 nop +80000268: 00000013 nop +8000026c: 00000013 nop +80000270: 00000013 nop +80000274: 00000013 nop + +80000278 : +80000278: 0000000b 0xb + +8000027c : +8000027c: 0016 c.slli zero,0x5 + ... + +80000280 : +80000280: 0049 c.nop 18 + ... + +80000284 : +80000284: 003a c.slli zero,0xe + ... + +80000288 : +80000288: 0038 addi a4,sp,8 + ... + +8000028c : +8000028c: 0000004b fnmsub.s ft0,ft0,ft0,ft0,rne + +80000290 : +80000290: 0038 addi a4,sp,8 + ... + +80000294 : +80000294: 00000053 fadd.s ft0,ft0,ft0,rne + +80000298 : +80000298: 0021 c.nop 8 + ... + +8000029c : +8000029c: ffffffbf 0xffffffbf + +800002a0 : +800002a0: ffa9 bnez a5,800001fa +800002a2: ffff 0xffff + +800002a4 : +800002a4: ffc9 bnez a5,8000023e +800002a6: ffff 0xffff + +800002a8 : +800002a8: 0004 0x4 +800002aa: ffff 0xffff + +800002ac : +800002ac: 0005 c.nop 1 +800002ae: ffff 0xffff diff --git a/src/test/cpp/raw/fpu/build/amo.hex b/src/test/cpp/raw/fpu/build/amo.hex new file mode 100644 index 00000000..74d35678 --- /dev/null +++ b/src/test/cpp/raw/fpu/build/amo.hex @@ -0,0 +1,45 @@ +:0200000480007A +:10000000130E100097000000938040271301D002C8 +:10001000AFA1200803A20000130AD00263164A22EF +:10002000130AB00063123A22130E2000970000005A +:100030009380002513017003AFA1200803A20000E4 +:10004000130A700363124A20130A6001631E3A1EEA +:10005000130E3000970000009380C022130120048B +:10006000AFA1200003A20000130AB008631E4A1CBF +:10007000130A9004631A3A1C130E40009700000004 +:100080009380802013017005AFA1202003A20000FF +:10009000130AD006631A4A1A130AA00363163A1AFF +:1000A000130E5000970000009380401E1301C00201 +:1000B000AFA1206003A20000130A800263164A1851 +:1000C000130A800363123A18130E600097000000B1 +:1000D0009380001C13018001AFA1204003A2000007 +:1000E000130AB00563124A16130AB004631E3A14C9 +:1000F000130E7000970000009380C0191301800157 +:10010000AFA1208003A20000130A8001631E4A12DF +:10011000130A8003631A3A12130E8000970000003E +:100120009380801713018005AFA1208003A20000F7 +:10013000130A3005631A4A10130A300563163A1081 +:10014000130E900097000000938040151301A0FC4F +:10015000AFA1208003A20000130AA0FC63164A0E80 +:10016000130A100263123A0E130EA000970000004B +:100170009380001313014003AFA1208003A200006D +:10018000130AF0FB63124A0C130AF0FB631E3A0ACF +:10019000130EB000970000009380C0101301C0FC44 +:1001A000AFA120A003A20000130AC0FC631E4A08EE +:1001B000130A90FA631A3A08130EC0009700000061 +:1001C0009380800E13014003AFA120A003A2000082 +:1001D000130A4003631A4A06130A90FC63163A0690 +:1001E000130ED000970000009380400C3701FFFFF2 +:1001F000AFA120C003A20000370AFFFF63164A0424 +:10020000370AFFFF130A4A0063103A046F008004A4 +:10021000130EE00097000000938080093701FFFF74 +:100220001301C100AFA120E003A20000370AFFFFC5 +:10023000130ACA00631A4A00370AFFFF130A5A005A +:1002400063143A006F000001370110F0130141F20E +:100250002320C101370110F0130101F22320010016 +:100260001300000013000000130000001300000042 +:1002700013000000130000000B0000001600000037 +:10028000490000003A000000380000004B00000068 +:10029000380000005300000021000000BFFFFFFFF6 +:1002A000A9FFFFFFC9FFFFFF0400FFFF0500FFFFDD +:00000001FF diff --git a/src/test/cpp/raw/fpu/build/fpu.asm b/src/test/cpp/raw/fpu/build/fpu.asm new file mode 100644 index 00000000..4c0a26f8 --- /dev/null +++ b/src/test/cpp/raw/fpu/build/fpu.asm @@ -0,0 +1,224 @@ + +build/fpu.elf: file format elf32-littleriscv + + +Disassembly of section .crt_section: + +80000000 <_start>: +80000000: 00100e13 li t3,1 +80000004: 00000013 nop +80000008: 00000013 nop +8000000c: 00000013 nop +80000010: 00000013 nop +80000014: 00107153 fadd.s ft2,ft0,ft1 +80000018: 00000013 nop +8000001c: 00000013 nop +80000020: 00000013 nop +80000024: 00000013 nop +80000028: 0180006f j 80000040 +8000002c: 00000013 nop +80000030: 00000013 nop +80000034: 00000013 nop +80000038: 00000013 nop +8000003c: 00000013 nop + +80000040 : +80000040: 00200e13 li t3,2 +80000044: 00000097 auipc ra,0x0 +80000048: 1fc0a083 lw ra,508(ra) # 80000240 +8000004c: 00107153 fadd.s ft2,ft0,ft1 +80000050: 00000013 nop +80000054: 00000013 nop +80000058: 00000013 nop +8000005c: 00000013 nop +80000060: 0200006f j 80000080 +80000064: 00000013 nop +80000068: 00000013 nop +8000006c: 00000013 nop +80000070: 00000013 nop +80000074: 00000013 nop +80000078: 00000013 nop +8000007c: 00000013 nop + +80000080 : +80000080: 00300e13 li t3,3 +80000084: 00000013 nop +80000088: 00000013 nop +8000008c: 00000013 nop +80000090: 00000013 nop +80000094: 0080006f j 8000009c +80000098: 00107153 fadd.s ft2,ft0,ft1 + +8000009c : +8000009c: 0240006f j 800000c0 +800000a0: 00000013 nop +800000a4: 00000013 nop +800000a8: 00000013 nop +800000ac: 00000013 nop +800000b0: 00000013 nop +800000b4: 00000013 nop +800000b8: 00000013 nop +800000bc: 00000013 nop + +800000c0 : +800000c0: 00400e13 li t3,4 +800000c4: 00000013 nop +800000c8: 00000013 nop +800000cc: 00000013 nop +800000d0: 00000013 nop +800000d4: 00000097 auipc ra,0x0 +800000d8: 16c08093 addi ra,ra,364 # 80000240 +800000dc: 0000a107 flw ft2,0(ra) +800000e0: 00000013 nop +800000e4: 00000013 nop +800000e8: 00000013 nop +800000ec: 00000013 nop +800000f0: 0100006f j 80000100 +800000f4: 00000013 nop +800000f8: 00000013 nop +800000fc: 00000013 nop + +80000100 : +80000100: 00500e13 li t3,5 +80000104: 00000013 nop +80000108: 00000013 nop +8000010c: 00000013 nop +80000110: 00000013 nop +80000114: 00000097 auipc ra,0x0 +80000118: 12c08093 addi ra,ra,300 # 80000240 +8000011c: 00000117 auipc sp,0x0 +80000120: 12810113 addi sp,sp,296 # 80000244 +80000124: 0000a087 flw ft1,0(ra) +80000128: 00012107 flw ft2,0(sp) +8000012c: 0020f1d3 fadd.s ft3,ft1,ft2 +80000130: 00000013 nop +80000134: 00000013 nop +80000138: 00000013 nop +8000013c: 00000013 nop +80000140: 0400006f j 80000180 +80000144: 00000013 nop +80000148: 00000013 nop +8000014c: 00000013 nop +80000150: 00000013 nop +80000154: 00000013 nop +80000158: 00000013 nop +8000015c: 00000013 nop +80000160: 00000013 nop +80000164: 00000013 nop +80000168: 00000013 nop +8000016c: 00000013 nop +80000170: 00000013 nop +80000174: 00000013 nop +80000178: 00000013 nop +8000017c: 00000013 nop + +80000180 : +80000180: 00600e13 li t3,6 +80000184: 00000013 nop +80000188: 00000013 nop +8000018c: 00000013 nop +80000190: 00000013 nop +80000194: 00000097 auipc ra,0x0 +80000198: 0b408093 addi ra,ra,180 # 80000248 +8000019c: 0030a027 fsw ft3,0(ra) +800001a0: 00000013 nop +800001a4: 00000013 nop +800001a8: 00000013 nop +800001ac: 00000013 nop +800001b0: 0100006f j 800001c0 +800001b4: 00000013 nop +800001b8: 00000013 nop +800001bc: 00000013 nop + +800001c0 : +800001c0: 00700e13 li t3,7 +800001c4: 00000097 auipc ra,0x0 +800001c8: 08408093 addi ra,ra,132 # 80000248 +800001cc: 00000117 auipc sp,0x0 +800001d0: 08010113 addi sp,sp,128 # 8000024c +800001d4: 00000197 auipc gp,0x0 +800001d8: 07c18193 addi gp,gp,124 # 80000250 +800001dc: 00000217 auipc tp,0x0 +800001e0: 07820213 addi tp,tp,120 # 80000254 +800001e4: 0000a207 flw ft4,0(ra) +800001e8: 00427253 fadd.s ft4,ft4,ft4 +800001ec: 0040f2d3 fadd.s ft5,ft1,ft4 +800001f0: 00412027 fsw ft4,0(sp) +800001f4: 0051a027 fsw ft5,0(gp) +800001f8: 00122027 fsw ft1,0(tp) # 0 <_start-0x80000000> +800001fc: 00000013 nop +80000200: 00000013 nop +80000204: 00000013 nop +80000208: 00000013 nop +8000020c: 0100006f j 8000021c + +80000210 : +80000210: f0100137 lui sp,0xf0100 +80000214: f2410113 addi sp,sp,-220 # f00fff24 +80000218: 01c12023 sw t3,0(sp) + +8000021c : +8000021c: f0100137 lui sp,0xf0100 +80000220: f2010113 addi sp,sp,-224 # f00fff20 +80000224: 00012023 sw zero,0(sp) +80000228: 00000013 nop +8000022c: 00000013 nop +80000230: 00000013 nop +80000234: 00000013 nop +80000238: 00000013 nop +8000023c: 00000013 nop + +80000240 : +80000240: 0000 unimp +80000242: 3fc0 fld fs0,184(a5) + +80000244 : +80000244: 0000 unimp +80000246: 40a0 lw s0,64(s1) + +80000248 : +80000248: 0049 c.nop 18 + ... + +8000024c : +8000024c: 003a c.slli zero,0xe + ... + +80000250 : +80000250: 0038 addi a4,sp,8 + ... + +80000254 : +80000254: 0000004b fnmsub.s ft0,ft0,ft0,ft0,rne + +80000258 : +80000258: 0038 addi a4,sp,8 + ... + +8000025c : +8000025c: 00000053 fadd.s ft0,ft0,ft0,rne + +80000260 : +80000260: 0021 c.nop 8 + ... + +80000264 : +80000264: ffffffbf 0xffffffbf + +80000268 : +80000268: ffa9 bnez a5,800001c2 +8000026a: ffff 0xffff + +8000026c : +8000026c: ffc9 bnez a5,80000206 +8000026e: ffff 0xffff + +80000270 : +80000270: 0004 0x4 +80000272: ffff 0xffff + +80000274 : +80000274: 0005 c.nop 1 +80000276: ffff 0xffff +80000278: 0000 unimp + ... diff --git a/src/test/cpp/raw/fpu/build/fpu.hex b/src/test/cpp/raw/fpu/build/fpu.hex new file mode 100644 index 00000000..58fefe0b --- /dev/null +++ b/src/test/cpp/raw/fpu/build/fpu.hex @@ -0,0 +1,42 @@ +:0200000480007A +:10000000130E100013000000130000001300000086 +:1000100013000000537110001300000013000000D3 +:1000200013000000130000006F00800113000000A7 +:100030001300000013000000130000001300000074 +:10004000130E20009700000083A0C01F5371100002 +:100050001300000013000000130000001300000054 +:100060006F000002130000001300000013000000E6 +:100070001300000013000000130000001300000034 +:10008000130E3000130000001300000013000000E6 +:10009000130000006F008000537110006F004002D9 +:1000A0001300000013000000130000001300000004 +:1000B00013000000130000001300000013000000F4 +:1000C000130E400013000000130000001300000096 +:1000D00013000000970000009380C01607A10000E5 +:1000E00013000000130000001300000013000000C4 +:1000F0006F00000113000000130000001300000057 +:10010000130E500013000000130000001300000045 +:1001100013000000970000009380C0121701000038 +:100120001301811287A0000007210100D3F12000F4 +:100130001300000013000000130000001300000073 +:100140006F00000413000000130000001300000003 +:100150001300000013000000130000001300000053 +:100160001300000013000000130000001300000043 +:100170001300000013000000130000001300000033 +:10018000130E6000130000001300000013000000B5 +:1001900013000000970000009380400B27A0300060 +:1001A0001300000013000000130000001300000003 +:1001B0006F00000113000000130000001300000096 +:1001C000130E700097000000938040081701000094 +:1001D00013010108970100009381C1071702000075 +:1001E0001302820707A2000053724200D3F24000BC +:1001F0002720410027A051002720120013000000F3 +:100200001300000013000000130000006F00000145 +:10021000370110F0130141F22320C101370110F022 +:10022000130101F22320010013000000130000005D +:100230001300000013000000130000001300000072 +:100240000000C03F0000A040490000003A0000004C +:10025000380000004B000000380000005300000090 +:1002600021000000BFFFFFFFA9FFFFFFC9FFFFFF45 +:0C0270000400FFFF0500FFFF000000007D +:00000001FF diff --git a/src/test/cpp/raw/fpu/makefile b/src/test/cpp/raw/fpu/makefile new file mode 100644 index 00000000..48920957 --- /dev/null +++ b/src/test/cpp/raw/fpu/makefile @@ -0,0 +1,5 @@ +PROJ_NAME=fpu + +FLOATING=yes + +include ../common/asm.mk \ No newline at end of file diff --git a/src/test/cpp/raw/fpu/src/crt.S b/src/test/cpp/raw/fpu/src/crt.S new file mode 100644 index 00000000..e0ed7652 --- /dev/null +++ b/src/test/cpp/raw/fpu/src/crt.S @@ -0,0 +1,161 @@ +.globl _star +#define TEST_ID x28 + +_start: + +#define assert(reg, value) \ + li x20, value; \ + bne x20, reg, fail; + + +test1: + li TEST_ID, 1 + nop + nop + nop + nop + fadd.s f2, f0, f1 + nop + nop + nop + nop + j test2 + +.align 6 +test2: + li TEST_ID, 2 + lw x1, test1_data + fadd.s f2, f0, f1 + nop + nop + nop + nop + + j test3 + + +.align 6 +test3: + li TEST_ID, 3 + nop + nop + nop + nop + j skip + fadd.s f2, f0, f1 +skip: + j test4 + + + +.align 6 +test4: + li TEST_ID, 4 + nop + nop + nop + nop + la x1, test1_data + flw f2, 0(x1) + nop + nop + nop + nop + + j test5 + +.align 6 +test5: + li TEST_ID, 5 + nop + nop + nop + nop + la x1, test1_data + la x2, test2_data + flw f1, 0(x1) + flw f2, 0(x2) + fadd.s f3, f1, f2 + nop + nop + nop + nop + j test6 + +.align 6 +test6: + li TEST_ID, 6 + nop + nop + nop + nop + la x1, test3_data + fsw f3, 0(x1) + nop + nop + nop + nop + j test7 + +.align 6 +test7: + li TEST_ID, 7 + + la x1, test3_data + la x2, test4_data + la x3, test5_data + la x4, test6_data + flw f4, 0(x1) + fadd.s f4, f4, f4 + fadd.s f5, f1, f4 + fsw f4, 0(x2) + fsw f5, 0(x3) + fsw f1, 0(x4) + nop + nop + nop + nop + + /* la x1, test1_data + li x2, 45 + amoswap.w x3,x2,(x1) + lw x4, 0(x1) + assert(x4, 45) + assert(x3, 11)*/ + + + + + j pass + + +fail: + li x2, 0xF00FFF24 + sw TEST_ID, 0(x2) + +pass: + li x2, 0xF00FFF20 + sw x0, 0(x2) + + nop + nop + nop + nop + nop + nop + + +test1_data: .word 0x3fc00000 //1.5f +test2_data: .word 0x40a00000 //5.0f +test3_data: .word 73 +test4_data: .word 58 +test5_data: .word 56 +test6_data: .word 75 +test7_data: .word 56 +test8_data: .word 83 +test9_data: .word 33 +test10_data: .word -65 +test11_data: .word -87 +test12_data: .word -55 +test13_data: .word 0xFFFF0004 +test14_data: .word 0xFFFF0005 \ No newline at end of file diff --git a/src/test/cpp/raw/fpu/src/ld b/src/test/cpp/raw/fpu/src/ld new file mode 100644 index 00000000..93d8de8e --- /dev/null +++ b/src/test/cpp/raw/fpu/src/ld @@ -0,0 +1,16 @@ +OUTPUT_ARCH( "riscv" ) + +MEMORY { + onChipRam (W!RX)/*(RX)*/ : ORIGIN = 0x80000000, LENGTH = 128K +} + +SECTIONS +{ + + .crt_section : + { + . = ALIGN(4); + *crt.o(.text) + } > onChipRam + +} diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index bc960fb8..f24ec741 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -1309,7 +1309,9 @@ public: } Workspace* withRiscvRef(){ + #ifdef WITH_RISCV_REF riscvRefEnable = true; + #endif return this; } @@ -3862,8 +3864,6 @@ int main(int argc, char **argv, char **env) { timespec startedAt = timer_start(); - - //#ifdef LITEX // LitexSoC("linux") // .withRiscvRef() diff --git a/src/test/cpp/regression/makefile b/src/test/cpp/regression/makefile index c7dcf5f4..adc7d98c 100644 --- a/src/test/cpp/regression/makefile +++ b/src/test/cpp/regression/makefile @@ -27,6 +27,7 @@ NO_STALL?=no DEBUG_PLUGIN?=STD DEBUG_PLUGIN_EXTERNAL?=no RUN_HEX=no +WITH_RISCV_REF=yes CUSTOM_SIMD_ADD?=no CUSTOM_CSR?=no DHRYSTONE=yes @@ -128,6 +129,10 @@ ifeq ($(COREMARK),yes) ADDCFLAGS += -CFLAGS -DCOREMARK endif +ifeq ($(WITH_RISCV_REF),yes) + ADDCFLAGS += -CFLAGS -DWITH_RISCV_REF +endif + ifneq ($(shell grep timerInterrupt ${VEXRISCV_FILE} -w),) diff --git a/src/test/scala/vexriscv/DhrystoneBench.scala b/src/test/scala/vexriscv/DhrystoneBench.scala index 31c8c147..a99b5d8c 100644 --- a/src/test/scala/vexriscv/DhrystoneBench.scala +++ b/src/test/scala/vexriscv/DhrystoneBench.scala @@ -50,100 +50,100 @@ class DhrystoneBench extends FunSuite { } - for(withMemoryStage <- List(false, true)){ - val stages = if(withMemoryStage) "Three" else "Two" - getDmips( - name = s"Gen${stages}StageArty", - gen = SpinalVerilog(GenTwoThreeStage.cpu( - withMulDiv = false, - bypass = false, - barrielShifter = false, - withMemoryStage = withMemoryStage - )), - testCmd = "make clean run REDO=10 IBUS=SIMPLE DBUS=SIMPLE CSR=no MMU=no DEBUG_PLUGIN=no MUL=no DIV=no COREMARK=yes" - ) - getDmips( - name = s"Gen${stages}StageBarrielArty", - gen = SpinalVerilog(GenTwoThreeStage.cpu( - withMulDiv = false, - bypass = true, - barrielShifter = true, - withMemoryStage = withMemoryStage - )), - testCmd = "make clean run REDO=10 IBUS=SIMPLE DBUS=SIMPLE CSR=no MMU=no DEBUG_PLUGIN=no MUL=no DIV=no COREMARK=yes" - ) - getDmips( - name = s"Gen${stages}StageMDArty", - gen = SpinalVerilog(GenTwoThreeStage.cpu( - withMulDiv = true, - bypass = false, - barrielShifter = false, - withMemoryStage = withMemoryStage - )), - testCmd = "make clean run REDO=10 IBUS=SIMPLE DBUS=SIMPLE CSR=no MMU=no DEBUG_PLUGIN=no MUL=yes DIV=yes COREMARK=yes" - ) - getDmips( - name = s"Gen${stages}StageMDBarrielArty", - gen = SpinalVerilog(GenTwoThreeStage.cpu( - withMulDiv = true, - bypass = true, - barrielShifter = true, - withMemoryStage = withMemoryStage - )), - testCmd = "make clean run REDO=10 IBUS=SIMPLE DBUS=SIMPLE CSR=no MMU=no DEBUG_PLUGIN=no MUL=yes DIV=yes COREMARK=yes" - ) - } - - getDmips( - name = "GenSmallestNoCsr", - gen = GenSmallestNoCsr.main(null), - testCmd = "make clean run REDO=10 IBUS=SIMPLE DBUS=SIMPLE CSR=no MMU=no DEBUG_PLUGIN=no MUL=no DIV=no COREMARK=yes" - ) - - - getDmips( - name = "GenSmallest", - gen = GenSmallest.main(null), - testCmd = "make clean run REDO=10 IBUS=SIMPLE DBUS=SIMPLE CSR=no MMU=no DEBUG_PLUGIN=no MUL=no DIV=no COREMARK=yes" - ) - - - getDmips( - name = "GenSmallAndProductive", - gen = GenSmallAndProductive.main(null), - testCmd = "make clean run REDO=10 IBUS=SIMPLE DBUS=SIMPLE CSR=no MMU=no DEBUG_PLUGIN=no MUL=no DIV=no COREMARK=yes" - ) - - getDmips( - name = "GenSmallAndProductiveWithICache", - gen = GenSmallAndProductiveICache.main(null), - testCmd = "make clean run REDO=10 IBUS=CACHED DBUS=SIMPLE CSR=no MMU=no DEBUG_PLUGIN=no MUL=no DIV=no COREMARK=yes" - ) - - - getDmips( - name = "GenFullNoMmuNoCache", - gen = GenFullNoMmuNoCache.main(null), - testCmd = "make clean run REDO=10 IBUS=SIMPLE DBUS=SIMPLE CSR=no MMU=no COREMARK=yes" - ) - - getDmips( - name = "GenNoCacheNoMmuMaxPerf", - gen = GenNoCacheNoMmuMaxPerf.main(null), - testCmd = "make clean run REDO=10 MMU=no CSR=no DBUS=SIMPLE IBUS=SIMPLE COREMARK=yes" - ) - - - getDmips( - name = "GenFullNoMmuMaxPerf", - gen = GenFullNoMmuMaxPerf.main(null), - testCmd = "make clean run REDO=10 MMU=no CSR=no COREMARK=yes" - ) - getDmips( - name = "GenFullNoMmu", - gen = GenFullNoMmu.main(null), - testCmd = "make clean run REDO=10 MMU=no CSR=no COREMARK=yes" - ) +// for(withMemoryStage <- List(false, true)){ +// val stages = if(withMemoryStage) "Three" else "Two" +// getDmips( +// name = s"Gen${stages}StageArty", +// gen = SpinalVerilog(GenTwoThreeStage.cpu( +// withMulDiv = false, +// bypass = false, +// barrielShifter = false, +// withMemoryStage = withMemoryStage +// )), +// testCmd = "make clean run REDO=10 IBUS=SIMPLE DBUS=SIMPLE CSR=no MMU=no DEBUG_PLUGIN=no MUL=no DIV=no COREMARK=yes" +// ) +// getDmips( +// name = s"Gen${stages}StageBarrielArty", +// gen = SpinalVerilog(GenTwoThreeStage.cpu( +// withMulDiv = false, +// bypass = true, +// barrielShifter = true, +// withMemoryStage = withMemoryStage +// )), +// testCmd = "make clean run REDO=10 IBUS=SIMPLE DBUS=SIMPLE CSR=no MMU=no DEBUG_PLUGIN=no MUL=no DIV=no COREMARK=yes" +// ) +// getDmips( +// name = s"Gen${stages}StageMDArty", +// gen = SpinalVerilog(GenTwoThreeStage.cpu( +// withMulDiv = true, +// bypass = false, +// barrielShifter = false, +// withMemoryStage = withMemoryStage +// )), +// testCmd = "make clean run REDO=10 IBUS=SIMPLE DBUS=SIMPLE CSR=no MMU=no DEBUG_PLUGIN=no MUL=yes DIV=yes COREMARK=yes" +// ) +// getDmips( +// name = s"Gen${stages}StageMDBarrielArty", +// gen = SpinalVerilog(GenTwoThreeStage.cpu( +// withMulDiv = true, +// bypass = true, +// barrielShifter = true, +// withMemoryStage = withMemoryStage +// )), +// testCmd = "make clean run REDO=10 IBUS=SIMPLE DBUS=SIMPLE CSR=no MMU=no DEBUG_PLUGIN=no MUL=yes DIV=yes COREMARK=yes" +// ) +// } +// +// getDmips( +// name = "GenSmallestNoCsr", +// gen = GenSmallestNoCsr.main(null), +// testCmd = "make clean run REDO=10 IBUS=SIMPLE DBUS=SIMPLE CSR=no MMU=no DEBUG_PLUGIN=no MUL=no DIV=no COREMARK=yes" +// ) +// +// +// getDmips( +// name = "GenSmallest", +// gen = GenSmallest.main(null), +// testCmd = "make clean run REDO=10 IBUS=SIMPLE DBUS=SIMPLE CSR=no MMU=no DEBUG_PLUGIN=no MUL=no DIV=no COREMARK=yes" +// ) +// +// +// getDmips( +// name = "GenSmallAndProductive", +// gen = GenSmallAndProductive.main(null), +// testCmd = "make clean run REDO=10 IBUS=SIMPLE DBUS=SIMPLE CSR=no MMU=no DEBUG_PLUGIN=no MUL=no DIV=no COREMARK=yes" +// ) +// +// getDmips( +// name = "GenSmallAndProductiveWithICache", +// gen = GenSmallAndProductiveICache.main(null), +// testCmd = "make clean run REDO=10 IBUS=CACHED DBUS=SIMPLE CSR=no MMU=no DEBUG_PLUGIN=no MUL=no DIV=no COREMARK=yes" +// ) +// +// +// getDmips( +// name = "GenFullNoMmuNoCache", +// gen = GenFullNoMmuNoCache.main(null), +// testCmd = "make clean run REDO=10 IBUS=SIMPLE DBUS=SIMPLE CSR=no MMU=no COREMARK=yes" +// ) +// +// getDmips( +// name = "GenNoCacheNoMmuMaxPerf", +// gen = GenNoCacheNoMmuMaxPerf.main(null), +// testCmd = "make clean run REDO=10 MMU=no CSR=no DBUS=SIMPLE IBUS=SIMPLE COREMARK=yes" +// ) +// +// +// getDmips( +// name = "GenFullNoMmuMaxPerf", +// gen = GenFullNoMmuMaxPerf.main(null), +// testCmd = "make clean run REDO=10 MMU=no CSR=no COREMARK=yes" +// ) +// getDmips( +// name = "GenFullNoMmu", +// gen = GenFullNoMmu.main(null), +// testCmd = "make clean run REDO=10 MMU=no CSR=no COREMARK=yes" +// ) getDmips( name = "GenFull", @@ -151,12 +151,11 @@ class DhrystoneBench extends FunSuite { testCmd = "make clean run REDO=10 CSR=no MMU=no COREMARK=yes" ) - getDmips( - name = "GenLinuxBalenced", - gen = LinuxGen.main(Array.fill[String](0)("")), - testCmd = "make clean run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD DHRYSTONE=yes SUPERVISOR=yes MMU=no CSR=yes CSR_SKIP_TEST=yes COMPRESSED=no MUL=yes DIV=yes LRSC=yes AMO=yes REDO=10 TRACE=no COREMARK=yes LINUX_REGRESSION=no" - ) -// //make run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD DHRYSTONE=yess SUPERVISOR=yes CSR=yes COMPRESSED=no MUL=yes DIV=yes LRSC=yes AMO=yes REDO=1 TRACE=no LINUX_REGRESSION=yes SEED=42 +// getDmips( +// name = "GenLinuxBalenced", +// gen = LinuxGen.main(Array.fill[String](0)("")), +// testCmd = "make clean run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD DHRYSTONE=yes SUPERVISOR=yes MMU=no CSR=yes CSR_SKIP_TEST=yes COMPRESSED=no MUL=yes DIV=yes LRSC=yes AMO=yes REDO=10 TRACE=no COREMARK=yes LINUX_REGRESSION=no" +// ) test("final_report") { diff --git a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala index 3190a0cd..c2cd7d7a 100644 --- a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala +++ b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala @@ -16,32 +16,47 @@ class FpuTest extends FunSuite{ test("directed"){ + val portCount = 1 val p = FpuParameter( internalMantissaSize = 23, - withDouble = false, - sourceCount = 1 + withDouble = false ) - SimConfig.withFstWave.compile(new FpuCore(p)).doSim(seed = 42){ dut => + SimConfig.withFstWave.compile(new FpuCore(1, p)).doSim(seed = 42){ dut => dut.clockDomain.forkStimulus(10) - val cpus = for(id <- 0 until 1 << p.sourceWidth) yield new { + val cpus = for(id <- 0 until portCount) yield new { val cmdQueue = mutable.Queue[FpuCmd => Unit]() val commitQueue = mutable.Queue[FpuCommit => Unit]() val loadQueue = mutable.Queue[FpuLoad => Unit]() val rspQueue = mutable.Queue[FpuRsp => Unit]() - StreamDriver(dut.io.port.commit(id) ,dut.clockDomain){payload => + StreamDriver(dut.io.port(id).cmd ,dut.clockDomain){payload => + if(cmdQueue.isEmpty) false else { + cmdQueue.dequeue().apply(payload) + true + } + } + + + StreamMonitor(dut.io.port(id)rsp, dut.clockDomain){payload => + rspQueue.dequeue().apply(payload) + } + + StreamReadyRandomizer(dut.io.port(id).rsp, dut.clockDomain) + + + StreamDriver(dut.io.port(id).commit ,dut.clockDomain){payload => if(commitQueue.isEmpty) false else { commitQueue.dequeue().apply(payload) true } } - StreamDriver(dut.io.port.load(id) ,dut.clockDomain){payload => + StreamDriver(dut.io.port(id).load ,dut.clockDomain){payload => if(loadQueue.isEmpty) false else { loadQueue.dequeue().apply(payload) true @@ -50,7 +65,6 @@ class FpuTest extends FunSuite{ def loadRaw(rd : Int, value : BigInt): Unit ={ cmdQueue += {cmd => - cmd.source #= id cmd.opcode #= cmd.opcode.spinalEnum.LOAD cmd.value.randomize() cmd.rs1.randomize() @@ -72,7 +86,6 @@ class FpuTest extends FunSuite{ def storeRaw(rs : Int)(body : FpuRsp => Unit): Unit ={ cmdQueue += {cmd => - cmd.source #= id cmd.opcode #= cmd.opcode.spinalEnum.STORE cmd.value.randomize() cmd.rs1.randomize() @@ -90,7 +103,6 @@ class FpuTest extends FunSuite{ def mul(rd : Int, rs1 : Int, rs2 : Int): Unit ={ cmdQueue += {cmd => - cmd.source #= id cmd.opcode #= cmd.opcode.spinalEnum.MUL cmd.value.randomize() cmd.rs1 #= rs1 @@ -105,7 +117,6 @@ class FpuTest extends FunSuite{ def add(rd : Int, rs1 : Int, rs2 : Int): Unit ={ cmdQueue += {cmd => - cmd.source #= id cmd.opcode #= cmd.opcode.spinalEnum.ADD cmd.value.randomize() cmd.rs1 #= rs1 @@ -120,7 +131,6 @@ class FpuTest extends FunSuite{ def div(rd : Int, rs1 : Int, rs2 : Int): Unit ={ cmdQueue += {cmd => - cmd.source #= id cmd.opcode #= cmd.opcode.spinalEnum.DIV cmd.value.randomize() cmd.rs1 #= rs1 @@ -135,7 +145,6 @@ class FpuTest extends FunSuite{ def sqrt(rd : Int, rs1 : Int): Unit ={ cmdQueue += {cmd => - cmd.source #= id cmd.opcode #= cmd.opcode.spinalEnum.SQRT cmd.value.randomize() cmd.rs1 #= rs1 @@ -150,7 +159,6 @@ class FpuTest extends FunSuite{ def fma(rd : Int, rs1 : Int, rs2 : Int, rs3 : Int): Unit ={ cmdQueue += {cmd => - cmd.source #= id cmd.opcode #= cmd.opcode.spinalEnum.FMA cmd.value.randomize() cmd.rs1 #= rs1 @@ -164,25 +172,6 @@ class FpuTest extends FunSuite{ } } - StreamDriver(dut.io.port.cmd ,dut.clockDomain){payload => - cpus.map(_.cmdQueue).filter(_.nonEmpty).toSeq match { - case Nil => false - case l => { - l.randomPick().dequeue().apply(payload) - true - } - } - } - - - - - StreamMonitor(dut.io.port.rsp, dut.clockDomain){payload => - cpus(payload.source.toInt).rspQueue.dequeue().apply(payload) - } - - StreamReadyRandomizer(dut.io.port.rsp, dut.clockDomain) - From 6cb498cdb25b838ef3c2da0af4b66bf5e8bcfd47 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 18 Jan 2021 13:09:08 +0100 Subject: [PATCH 532/951] fpu merge load/commit --- src/main/scala/vexriscv/ip/fpu/FpuCore.scala | 25 ++++++++++---- .../scala/vexriscv/ip/fpu/Interface.scala | 7 ++-- .../vexriscv/plugin/DBusCachedPlugin.scala | 9 +---- .../scala/vexriscv/plugin/FpuPlugin.scala | 34 ++++++------------- src/test/scala/vexriscv/ip/fpu/FpuTest.scala | 15 ++++---- 5 files changed, 37 insertions(+), 53 deletions(-) diff --git a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala index c95f4aeb..d7ffddfe 100644 --- a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala +++ b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala @@ -102,6 +102,16 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val lockFreeId = OHMasking.first(lock.map(!_.valid)) } + val commitFork = new Area{ + val load, commit = Vec(Stream(FpuCommit(p)), portCount) + for(i <- 0 until portCount){ + val fork = new StreamFork(FpuCommit(p), 2) + fork.io.input << io.port(i).commit + fork.io.outputs(0) >> load(i) + fork.io.outputs(1) >> commit(i) + } + } + val commitLogic = for(source <- 0 until portCount) yield new Area{ val fire = False val target, hit = Reg(UInt(log2Up(rfLockCount) bits)) init(0) @@ -109,14 +119,14 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ hit := hit + 1 } - io.port(source).commit.ready := False - when(io.port(source).commit.valid) { + commitFork.commit(source).ready := False + when(commitFork.commit(source).valid) { for (lock <- rf.lock) { when(lock.valid && lock.source === source && lock.id === hit) { fire := True lock.commited := True - lock.write := io.port(source).commit.write - io.port(source).commit.ready := True + lock.write := commitFork.commit(source).write + commitFork.commit(source).ready := True } } } @@ -274,10 +284,11 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val load = new Area{ val input = decode.load.stage() - def feed = io.port(input.source).load + val filtred = commitFork.load.map(port => port.takeWhen(port.load)) + def feed = filtred(input.source) val hazard = !feed.valid val output = input.haltWhen(hazard).swapPayload(WriteInput()) - io.port.foreach(_.load.ready := False) + filtred.foreach(_.ready := False) feed.ready := input.valid && output.ready output.source := input.source output.lockId := input.lockId @@ -286,7 +297,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } - val store = new Area{ + val rspLogic = new Area{ val input = decode.store.stage() input.ready := io.port.map(_.rsp.ready).read(input.source) diff --git a/src/main/scala/vexriscv/ip/fpu/Interface.scala b/src/main/scala/vexriscv/ip/fpu/Interface.scala index 34336026..27f3482e 100644 --- a/src/main/scala/vexriscv/ip/fpu/Interface.scala +++ b/src/main/scala/vexriscv/ip/fpu/Interface.scala @@ -55,9 +55,7 @@ case class FpuCmd(p : FpuParameter) extends Bundle{ case class FpuCommit(p : FpuParameter) extends Bundle{ val write = Bool() -} - -case class FpuLoad(p : FpuParameter) extends Bundle{ + val load = Bool() val value = p.storeLoadType() // IEEE 754 } @@ -68,11 +66,10 @@ case class FpuRsp(p : FpuParameter) extends Bundle{ case class FpuPort(p : FpuParameter) extends Bundle with IMasterSlave { val cmd = Stream(FpuCmd(p)) val commit = Stream(FpuCommit(p)) - val load = Stream(FpuLoad(p)) val rsp = Stream(FpuRsp(p)) override def asMaster(): Unit = { - master(cmd, commit, load) + master(cmd, commit) slave(rsp) } } diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index 17062e44..774dbee8 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -21,7 +21,6 @@ class DAxiCachedPlugin(config : DataCacheConfig, memoryTranslatorPortConfig : An trait DBusEncodingService { def addLoadWordEncoding(key: MaskedLiteral): Unit def addStoreWordEncoding(key: MaskedLiteral): Unit - def encodingHalt(): Unit def bypassStore(data : Bits) : Unit } @@ -91,9 +90,6 @@ class DBusCachedPlugin(val config : DataCacheConfig, ) } - var haltFromEncoding : Bool = null - override def encodingHalt(): Unit = haltFromEncoding := True - override def bypassStore(data: Bits): Unit = { pipeline.stages.last.input(MEMORY_STORE_DATA) := data } @@ -220,8 +216,6 @@ class DBusCachedPlugin(val config : DataCacheConfig, privilegeService = pipeline.service(classOf[PrivilegeService]) pipeline.update(DEBUG_BYPASS_CACHE, False) - - haltFromEncoding = False } override def build(pipeline: VexRiscv): Unit = { @@ -496,9 +490,8 @@ class DBusCachedPlugin(val config : DataCacheConfig, } } - when(haltFromEncoding){ + when(stages.last.arbitration.haltByOther){ cache.io.cpu.writeBack.isValid := False - managementStage.arbitration.haltItself := True } if(csrInfo){ diff --git a/src/main/scala/vexriscv/plugin/FpuPlugin.scala b/src/main/scala/vexriscv/plugin/FpuPlugin.scala index a438705a..635d1ec4 100644 --- a/src/main/scala/vexriscv/plugin/FpuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/FpuPlugin.scala @@ -44,9 +44,7 @@ class FpuPlugin(externalFpu : Boolean = false, val fpu = FpuCore(1, p) fpu.io.port(0).cmd << port.cmd fpu.io.port(0).commit << port.commit - fpu.io.port(0).load << port.load fpu.io.port(0).rsp >> port.rsp - } @@ -70,26 +68,12 @@ class FpuPlugin(externalFpu : Boolean = false, insert(FPU_FORKED) := forked || port.cmd.fire } - memory plug new Area{ - import memory._ - - val isCommit = input(FPU_FORKED) && input(FPU_COMMIT) - - val commit = Stream(FpuCommit(p)) - commit.valid := isCommit && arbitration.isMoving - commit.write := arbitration.isValid - - arbitration.haltItself setWhen(isCommit && !commit.ready) //Assume commit.ready do not look at commit.valid - - port.commit <-/< commit //TODO can't commit in memory, in case a load fail - } - writeBack plug new Area{ import writeBack._ val dBusEncoding = pipeline.service(classOf[DBusEncodingService]) - val isLoad = input(FPU_FORKED) && input(FPU_LOAD) val isStore = input(FPU_FORKED) && input(FPU_STORE) + val isCommit = input(FPU_FORKED) && input(FPU_COMMIT) //Manage $store and port.rsp port.rsp.ready := False @@ -99,20 +83,22 @@ class FpuPlugin(externalFpu : Boolean = false, dBusEncoding.bypassStore(port.rsp.value) } when(!port.rsp.valid){ - dBusEncoding.encodingHalt() + arbitration.haltByOther := True } } // Manage $load - val load = Stream(FpuLoad(p)) - load.valid := isLoad && arbitration.isMoving - load.value.assignFromBits(output(DBUS_DATA)) + val commit = Stream(FpuCommit(p)) + commit.valid := isCommit && arbitration.isMoving + commit.value.assignFromBits(output(DBUS_DATA)) + commit.write := arbitration.isValid + commit.load := input(FPU_LOAD) - when(arbitration.isValid && !load.ready){ - dBusEncoding.encodingHalt() + when(arbitration.isValid && !commit.ready){ + arbitration.haltByOther := True } - port.load <-/< load + port.commit <-/< commit } Component.current.afterElaboration{ diff --git a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala index c2cd7d7a..0a2f665a 100644 --- a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala +++ b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala @@ -31,7 +31,6 @@ class FpuTest extends FunSuite{ val cpus = for(id <- 0 until portCount) yield new { val cmdQueue = mutable.Queue[FpuCmd => Unit]() val commitQueue = mutable.Queue[FpuCommit => Unit]() - val loadQueue = mutable.Queue[FpuLoad => Unit]() val rspQueue = mutable.Queue[FpuRsp => Unit]() StreamDriver(dut.io.port(id).cmd ,dut.clockDomain){payload => @@ -56,12 +55,6 @@ class FpuTest extends FunSuite{ } } - StreamDriver(dut.io.port(id).load ,dut.clockDomain){payload => - if(loadQueue.isEmpty) false else { - loadQueue.dequeue().apply(payload) - true - } - } def loadRaw(rd : Int, value : BigInt): Unit ={ cmdQueue += {cmd => @@ -74,9 +67,8 @@ class FpuTest extends FunSuite{ } commitQueue += {cmd => cmd.write #= true - } - loadQueue += {cmd => cmd.value #= value + cmd.load #= true } } @@ -112,6 +104,7 @@ class FpuTest extends FunSuite{ } commitQueue += {cmd => cmd.write #= true + cmd.load #= false } } @@ -126,6 +119,7 @@ class FpuTest extends FunSuite{ } commitQueue += {cmd => cmd.write #= true + cmd.load #= false } } @@ -140,6 +134,7 @@ class FpuTest extends FunSuite{ } commitQueue += {cmd => cmd.write #= true + cmd.load #= false } } @@ -154,6 +149,7 @@ class FpuTest extends FunSuite{ } commitQueue += {cmd => cmd.write #= true + cmd.load #= false } } @@ -168,6 +164,7 @@ class FpuTest extends FunSuite{ } commitQueue += {cmd => cmd.write #= true + cmd.load #= false } } } From d4b877d415acfd7f656d62469772897caffa3f1d Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 18 Jan 2021 15:09:30 +0100 Subject: [PATCH 533/951] fpu vex cmp/fle works --- src/main/scala/vexriscv/Riscv.scala | 6 + src/main/scala/vexriscv/ip/fpu/FpuCore.scala | 57 +++++-- .../scala/vexriscv/ip/fpu/Interface.scala | 10 +- .../scala/vexriscv/plugin/FpuPlugin.scala | 19 ++- src/test/cpp/raw/fpu/build/fpu.asm | 150 +++++++++++------- src/test/cpp/raw/fpu/build/fpu.hex | 40 +++-- src/test/cpp/raw/fpu/src/crt.S | 23 ++- src/test/scala/vexriscv/ip/fpu/FpuTest.scala | 83 +++++++++- 8 files changed, 294 insertions(+), 94 deletions(-) diff --git a/src/main/scala/vexriscv/Riscv.scala b/src/main/scala/vexriscv/Riscv.scala index ae64bffc..df49682b 100644 --- a/src/main/scala/vexriscv/Riscv.scala +++ b/src/main/scala/vexriscv/Riscv.scala @@ -176,6 +176,12 @@ object Riscv{ def FMSUB_D = M"-----01------------------1000111" def FNMSUB_D = M"-----01------------------1001011" def FNMADD_D = M"-----01------------------1001111" + def FLE_S = M"1010000----------000-----1010011" + def FLT_S = M"1010000----------001-----1010011" + def FEQ_S = M"1010000----------010-----1010011" + def FLE_D = M"1010001----------000-----1010011" + def FLT_D = M"1010001----------001-----1010011" + def FEQ_D = M"1010001----------010-----1010011" object CSR{ def MVENDORID = 0xF11 // MRO Vendor ID. diff --git a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala index d7ffddfe..5d31fe9b 100644 --- a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala +++ b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala @@ -17,6 +17,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val portCountWidth = log2Up(portCount) val Source = HardType(UInt(portCountWidth bits)) + val exponentOne = (1 << p.internalExponentSize-1) - 1 // val commitPerportCount = 8 @@ -51,7 +52,8 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ case class StoreInput() extends Bundle{ val source = Source() - val rs2 = p.internalFloating() + val opcode = p.Opcode() + val rs1, rs2 = p.internalFloating() } case class MulInput() extends Bundle{ @@ -184,6 +186,16 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ useRs3 := True //Can be delayed to have less hazard useRd := True } + is(p.Opcode.I2F){ + useRd := True + } + is(p.Opcode.F2I){ + useRs1 := True + } + is(p.Opcode.CMP){ + useRs1 := True + useRs2 := True + } } val hits = List((useRs1, s0.rs1), (useRs2, s0.rs2), (useRs3, s0.rs3), (useRd, s0.rd)).map{case (use, reg) => use && rf.lock.map(l => l.valid && l.source === s0.source && l.address === reg).orR} @@ -230,12 +242,14 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ load.rs1 := read.output.rs1 load.lockId := read.output.lockId - val storeHit = input.opcode === p.Opcode.STORE - val store = Stream(StoreInput()) - input.ready setWhen(storeHit && store.ready) - store.valid := input.valid && storeHit - store.source := read.output.source - store.rs2 := read.output.rs2 + val coreRspHit = List(FpuOpcode.STORE, FpuOpcode.F2I, FpuOpcode.CMP).map(input.opcode === _).orR + val coreRsp = Stream(StoreInput()) + input.ready setWhen(coreRspHit && coreRsp.ready) + coreRsp.valid := input.valid && coreRspHit + coreRsp.source := read.output.source + coreRsp.opcode := read.output.opcode + coreRsp.rs1 := read.output.rs1 + coreRsp.rs2 := read.output.rs2 val divSqrtHit = input.opcode === p.Opcode.DIV || input.opcode === p.Opcode.SQRT val divSqrt = Stream(DivSqrtInput()) @@ -297,14 +311,37 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } - val rspLogic = new Area{ - val input = decode.store.stage() + val coreRsp = new Area{ + val input = decode.coreRsp.stage() + + val result = p.storeLoadType().assignDontCare() + val storeResult = input.rs2.asBits + + val f2iShift = input.rs1.exponent - U(exponentOne) + val f2iShifted = (U"1" @@ input.rs1.mantissa) << (f2iShift.resize(5 bits)) + val f2iResult = f2iShifted.asBits >> p.internalMantissaSize + + val rs1Equal = input.rs1 === input.rs2 + val rs1AbsSmaller = (input.rs1.exponent @@ input.rs1.mantissa) < (input.rs2.exponent @@ input.rs2.mantissa) + val rs1Smaller = (input.rs1.sign ## input.rs2.sign).mux( + 0 -> rs1AbsSmaller, + 1 -> False, + 2 -> True, + 3 -> (!rs1AbsSmaller && !rs1Equal) + ) + val cmpResult = B(rs1Smaller) + + switch(input.opcode){ + is(FpuOpcode.STORE){ result := storeResult } + is(FpuOpcode.F2I) { result := f2iResult } + is(FpuOpcode.CMP) { result := cmpResult.resized } + } input.ready := io.port.map(_.rsp.ready).read(input.source) for(i <- 0 until portCount){ def rsp = io.port(i).rsp rsp.valid := input.valid && input.source === i - rsp.value := input.rs2.asBits + rsp.value := result } } diff --git a/src/main/scala/vexriscv/ip/fpu/Interface.scala b/src/main/scala/vexriscv/ip/fpu/Interface.scala index 27f3482e..0719bffc 100644 --- a/src/main/scala/vexriscv/ip/fpu/Interface.scala +++ b/src/main/scala/vexriscv/ip/fpu/Interface.scala @@ -19,7 +19,15 @@ case class FpuFloat(exponentSize: Int, mantissaSize: Int) extends Bundle { val mantissa = UInt(mantissaSize bits) val exponent = UInt(exponentSize bits) - val sign = Bool + val sign = Bool() + + def withInvertSign : FpuFloat ={ + val ret = FpuFloat(exponentSize,mantissaSize) + ret.sign := !sign + ret.exponent := exponent + ret.mantissa := mantissa + ret + } } object FpuOpcode extends SpinalEnum{ diff --git a/src/main/scala/vexriscv/plugin/FpuPlugin.scala b/src/main/scala/vexriscv/plugin/FpuPlugin.scala index 635d1ec4..e61d224e 100644 --- a/src/main/scala/vexriscv/plugin/FpuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/FpuPlugin.scala @@ -12,7 +12,7 @@ class FpuPlugin(externalFpu : Boolean = false, object FPU_ENABLE extends Stageable(Bool()) object FPU_COMMIT extends Stageable(Bool()) object FPU_LOAD extends Stageable(Bool()) - object FPU_STORE extends Stageable(Bool()) + object FPU_RSP extends Stageable(Bool()) object FPU_ALU extends Stageable(Bool()) object FPU_FORKED extends Stageable(Bool()) object FPU_OPCODE extends Stageable(FpuOpcode()) @@ -20,12 +20,16 @@ class FpuPlugin(externalFpu : Boolean = false, var port : FpuPort = null override def setup(pipeline: VexRiscv): Unit = { + import pipeline.config._ + val decoderService = pipeline.service(classOf[DecoderService]) decoderService.addDefault(FPU_ENABLE, False) decoderService.add(List( - FADD_S -> List(FPU_ENABLE -> True, FPU_OPCODE -> FpuOpcode.ADD, FPU_COMMIT -> True, FPU_ALU -> True , FPU_LOAD -> False, FPU_STORE -> False), - FLW -> List(FPU_ENABLE -> True, FPU_OPCODE -> FpuOpcode.LOAD, FPU_COMMIT -> True, FPU_ALU -> False, FPU_LOAD -> True , FPU_STORE -> False), - FSW -> List(FPU_ENABLE -> True, FPU_OPCODE -> FpuOpcode.STORE,FPU_COMMIT -> False, FPU_ALU -> False, FPU_LOAD -> False, FPU_STORE -> True) + FADD_S -> List(FPU_ENABLE -> True, FPU_OPCODE -> FpuOpcode.ADD, FPU_COMMIT -> True, FPU_ALU -> True , FPU_LOAD -> False, FPU_RSP -> False), + FLW -> List(FPU_ENABLE -> True, FPU_OPCODE -> FpuOpcode.LOAD, FPU_COMMIT -> True, FPU_ALU -> False, FPU_LOAD -> True , FPU_RSP -> False), + FSW -> List(FPU_ENABLE -> True, FPU_OPCODE -> FpuOpcode.STORE, FPU_COMMIT -> False, FPU_ALU -> False, FPU_LOAD -> False, FPU_RSP -> True), + FCVT_WU_S -> List(FPU_ENABLE -> True, FPU_OPCODE -> FpuOpcode.F2I , FPU_COMMIT -> False, FPU_ALU -> False, FPU_LOAD -> False, FPU_RSP -> True, REGFILE_WRITE_VALID -> True, BYPASSABLE_EXECUTE_STAGE -> False, BYPASSABLE_MEMORY_STAGE -> False), + FLE_S -> List(FPU_ENABLE -> True, FPU_OPCODE -> FpuOpcode.CMP , FPU_COMMIT -> False, FPU_ALU -> False, FPU_LOAD -> False, FPU_RSP -> True, REGFILE_WRITE_VALID -> True, BYPASSABLE_EXECUTE_STAGE -> False, BYPASSABLE_MEMORY_STAGE -> False) )) port = FpuPort(p) @@ -72,15 +76,16 @@ class FpuPlugin(externalFpu : Boolean = false, import writeBack._ val dBusEncoding = pipeline.service(classOf[DBusEncodingService]) - val isStore = input(FPU_FORKED) && input(FPU_STORE) + val isRsp = input(FPU_FORKED) && input(FPU_RSP) val isCommit = input(FPU_FORKED) && input(FPU_COMMIT) //Manage $store and port.rsp port.rsp.ready := False - when(isStore){ + when(isRsp){ port.rsp.ready := True when(arbitration.isValid) { dBusEncoding.bypassStore(port.rsp.value) + output(REGFILE_WRITE_DATA) := port.rsp.value } when(!port.rsp.valid){ arbitration.haltByOther := True @@ -105,6 +110,4 @@ class FpuPlugin(externalFpu : Boolean = false, pipeline.stages.tail.foreach(_.input(FPU_FORKED).init(False)) } } - - } diff --git a/src/test/cpp/raw/fpu/build/fpu.asm b/src/test/cpp/raw/fpu/build/fpu.asm index 4c0a26f8..f65b2ab9 100644 --- a/src/test/cpp/raw/fpu/build/fpu.asm +++ b/src/test/cpp/raw/fpu/build/fpu.asm @@ -25,7 +25,7 @@ Disassembly of section .crt_section: 80000040 : 80000040: 00200e13 li t3,2 80000044: 00000097 auipc ra,0x0 -80000048: 1fc0a083 lw ra,508(ra) # 80000240 +80000048: 2900a083 lw ra,656(ra) # 800002d4 8000004c: 00107153 fadd.s ft2,ft0,ft1 80000050: 00000013 nop 80000054: 00000013 nop @@ -67,7 +67,7 @@ Disassembly of section .crt_section: 800000cc: 00000013 nop 800000d0: 00000013 nop 800000d4: 00000097 auipc ra,0x0 -800000d8: 16c08093 addi ra,ra,364 # 80000240 +800000d8: 20008093 addi ra,ra,512 # 800002d4 800000dc: 0000a107 flw ft2,0(ra) 800000e0: 00000013 nop 800000e4: 00000013 nop @@ -85,9 +85,9 @@ Disassembly of section .crt_section: 8000010c: 00000013 nop 80000110: 00000013 nop 80000114: 00000097 auipc ra,0x0 -80000118: 12c08093 addi ra,ra,300 # 80000240 +80000118: 1c008093 addi ra,ra,448 # 800002d4 8000011c: 00000117 auipc sp,0x0 -80000120: 12810113 addi sp,sp,296 # 80000244 +80000120: 1bc10113 addi sp,sp,444 # 800002d8 80000124: 0000a087 flw ft1,0(ra) 80000128: 00012107 flw ft2,0(sp) 8000012c: 0020f1d3 fadd.s ft3,ft1,ft2 @@ -119,7 +119,7 @@ Disassembly of section .crt_section: 8000018c: 00000013 nop 80000190: 00000013 nop 80000194: 00000097 auipc ra,0x0 -80000198: 0b408093 addi ra,ra,180 # 80000248 +80000198: 14808093 addi ra,ra,328 # 800002dc 8000019c: 0030a027 fsw ft3,0(ra) 800001a0: 00000013 nop 800001a4: 00000013 nop @@ -133,13 +133,13 @@ Disassembly of section .crt_section: 800001c0 : 800001c0: 00700e13 li t3,7 800001c4: 00000097 auipc ra,0x0 -800001c8: 08408093 addi ra,ra,132 # 80000248 +800001c8: 11808093 addi ra,ra,280 # 800002dc 800001cc: 00000117 auipc sp,0x0 -800001d0: 08010113 addi sp,sp,128 # 8000024c +800001d0: 11410113 addi sp,sp,276 # 800002e0 800001d4: 00000197 auipc gp,0x0 -800001d8: 07c18193 addi gp,gp,124 # 80000250 +800001d8: 11018193 addi gp,gp,272 # 800002e4 800001dc: 00000217 auipc tp,0x0 -800001e0: 07820213 addi tp,tp,120 # 80000254 +800001e0: 10c20213 addi tp,tp,268 # 800002e8 800001e4: 0000a207 flw ft4,0(ra) 800001e8: 00427253 fadd.s ft4,ft4,ft4 800001ec: 0040f2d3 fadd.s ft5,ft1,ft4 @@ -150,17 +150,13 @@ Disassembly of section .crt_section: 80000200: 00000013 nop 80000204: 00000013 nop 80000208: 00000013 nop -8000020c: 0100006f j 8000021c - -80000210 : -80000210: f0100137 lui sp,0xf0100 -80000214: f2410113 addi sp,sp,-220 # f00fff24 -80000218: 01c12023 sw t3,0(sp) - -8000021c : -8000021c: f0100137 lui sp,0xf0100 -80000220: f2010113 addi sp,sp,-224 # f00fff20 -80000224: 00012023 sw zero,0(sp) +8000020c: 0340006f j 80000240 +80000210: 00000013 nop +80000214: 00000013 nop +80000218: 00000013 nop +8000021c: 00000013 nop +80000220: 00000013 nop +80000224: 00000013 nop 80000228: 00000013 nop 8000022c: 00000013 nop 80000230: 00000013 nop @@ -168,57 +164,101 @@ Disassembly of section .crt_section: 80000238: 00000013 nop 8000023c: 00000013 nop -80000240 : -80000240: 0000 unimp -80000242: 3fc0 fld fs0,184(a5) +80000240 : +80000240: 00800e13 li t3,8 +80000244: c011f0d3 fcvt.wu.s ra,ft3 +80000248: 00000013 nop +8000024c: 00000013 nop +80000250: 00000013 nop +80000254: 00000013 nop +80000258: 0280006f j 80000280 +8000025c: 00000013 nop +80000260: 00000013 nop +80000264: 00000013 nop +80000268: 00000013 nop +8000026c: 00000013 nop +80000270: 00000013 nop +80000274: 00000013 nop +80000278: 00000013 nop +8000027c: 00000013 nop -80000244 : -80000244: 0000 unimp -80000246: 40a0 lw s0,64(s1) +80000280 : +80000280: 00900e13 li t3,9 +80000284: a03100d3 fle.s ra,ft2,ft3 +80000288: a0218153 fle.s sp,ft3,ft2 +8000028c: a03181d3 fle.s gp,ft3,ft3 +80000290: 00000013 nop +80000294: 00000013 nop +80000298: 00000013 nop +8000029c: 00000013 nop +800002a0: 0100006f j 800002b0 -80000248 : -80000248: 0049 c.nop 18 +800002a4 : +800002a4: f0100137 lui sp,0xf0100 +800002a8: f2410113 addi sp,sp,-220 # f00fff24 +800002ac: 01c12023 sw t3,0(sp) + +800002b0 : +800002b0: f0100137 lui sp,0xf0100 +800002b4: f2010113 addi sp,sp,-224 # f00fff20 +800002b8: 00012023 sw zero,0(sp) +800002bc: 00000013 nop +800002c0: 00000013 nop +800002c4: 00000013 nop +800002c8: 00000013 nop +800002cc: 00000013 nop +800002d0: 00000013 nop + +800002d4 : +800002d4: 0000 unimp +800002d6: 3fc0 fld fs0,184(a5) + +800002d8 : +800002d8: 0000 unimp +800002da: 40a0 lw s0,64(s1) + +800002dc : +800002dc: 0049 c.nop 18 ... -8000024c : -8000024c: 003a c.slli zero,0xe +800002e0 : +800002e0: 003a c.slli zero,0xe ... -80000250 : -80000250: 0038 addi a4,sp,8 +800002e4 : +800002e4: 0038 addi a4,sp,8 ... -80000254 : -80000254: 0000004b fnmsub.s ft0,ft0,ft0,ft0,rne +800002e8 : +800002e8: 0000004b fnmsub.s ft0,ft0,ft0,ft0,rne -80000258 : -80000258: 0038 addi a4,sp,8 +800002ec : +800002ec: 0038 addi a4,sp,8 ... -8000025c : -8000025c: 00000053 fadd.s ft0,ft0,ft0,rne +800002f0 : +800002f0: 00000053 fadd.s ft0,ft0,ft0,rne -80000260 : -80000260: 0021 c.nop 8 +800002f4 : +800002f4: 0021 c.nop 8 ... -80000264 : -80000264: ffffffbf 0xffffffbf +800002f8 : +800002f8: ffffffbf 0xffffffbf -80000268 : -80000268: ffa9 bnez a5,800001c2 -8000026a: ffff 0xffff +800002fc : +800002fc: ffa9 bnez a5,80000256 +800002fe: ffff 0xffff -8000026c : -8000026c: ffc9 bnez a5,80000206 -8000026e: ffff 0xffff +80000300 : +80000300: ffc9 bnez a5,8000029a +80000302: ffff 0xffff -80000270 : -80000270: 0004 0x4 -80000272: ffff 0xffff +80000304 : +80000304: 0004 0x4 +80000306: ffff 0xffff -80000274 : -80000274: 0005 c.nop 1 -80000276: ffff 0xffff -80000278: 0000 unimp +80000308 : +80000308: 0005 c.nop 1 +8000030a: ffff 0xffff ... diff --git a/src/test/cpp/raw/fpu/build/fpu.hex b/src/test/cpp/raw/fpu/build/fpu.hex index 58fefe0b..a182b0e5 100644 --- a/src/test/cpp/raw/fpu/build/fpu.hex +++ b/src/test/cpp/raw/fpu/build/fpu.hex @@ -3,7 +3,7 @@ :1000100013000000537110001300000013000000D3 :1000200013000000130000006F00800113000000A7 :100030001300000013000000130000001300000074 -:10004000130E20009700000083A0C01F5371100002 +:10004000130E20009700000083A0002953711000B8 :100050001300000013000000130000001300000054 :100060006F000002130000001300000013000000E6 :100070001300000013000000130000001300000034 @@ -12,31 +12,41 @@ :1000A0001300000013000000130000001300000004 :1000B00013000000130000001300000013000000F4 :1000C000130E400013000000130000001300000096 -:1000D00013000000970000009380C01607A10000E5 +:1000D00013000000970000009380002007A100009B :1000E00013000000130000001300000013000000C4 :1000F0006F00000113000000130000001300000057 :10010000130E500013000000130000001300000045 -:1001100013000000970000009380C0121701000038 -:100120001301811287A0000007210100D3F12000F4 +:1001100013000000970000009380001C17010000EE +:100120001301C11B87A0000007210100D3F12000AB :100130001300000013000000130000001300000073 :100140006F00000413000000130000001300000003 :100150001300000013000000130000001300000053 :100160001300000013000000130000001300000043 :100170001300000013000000130000001300000033 :10018000130E6000130000001300000013000000B5 -:1001900013000000970000009380400B27A0300060 +:1001900013000000970000009380801427A0300017 :1001A0001300000013000000130000001300000003 :1001B0006F00000113000000130000001300000096 -:1001C000130E700097000000938040081701000094 -:1001D00013010108970100009381C1071702000075 -:1001E0001302820707A2000053724200D3F24000BC +:1001C000130E70009700000093808011170100004B +:1001D00013014111970100009381011117020000E2 +:1001E0001302C21007A2000053724200D3F2400073 :1001F0002720410027A051002720120013000000F3 -:100200001300000013000000130000006F00000145 -:10021000370110F0130141F22320C101370110F022 -:10022000130101F22320010013000000130000005D +:100200001300000013000000130000006F00400303 +:100210001300000013000000130000001300000092 +:100220001300000013000000130000001300000082 :100230001300000013000000130000001300000072 -:100240000000C03F0000A040490000003A0000004C -:10025000380000004B000000380000005300000090 -:1002600021000000BFFFFFFFA9FFFFFFC9FFFFFF45 -:0C0270000400FFFF0500FFFF000000007D +:10024000130E8000D3F011C0130000001300000053 +:1002500013000000130000006F0080021300000074 +:100260001300000013000000130000001300000042 +:100270001300000013000000130000001300000032 +:10028000130E9000D30031A0538121A0D38131A05F +:100290001300000013000000130000001300000012 +:1002A0006F000001370110F0130141F22320C1015A +:1002B000370110F0130101F22320010013000000A8 +:1002C00013000000130000001300000013000000E2 +:1002D000130000000000C03F0000A04049000000E3 +:1002E0003A000000380000004B0000003800000019 +:1002F0005300000021000000BFFFFFFFA9FFFFFF28 +:10030000C9FFFFFF0400FFFF0500FFFF0000000022 +:080310000000000000000000E5 :00000001FF diff --git a/src/test/cpp/raw/fpu/src/crt.S b/src/test/cpp/raw/fpu/src/crt.S index e0ed7652..0a3183fe 100644 --- a/src/test/cpp/raw/fpu/src/crt.S +++ b/src/test/cpp/raw/fpu/src/crt.S @@ -100,7 +100,6 @@ test6: .align 6 test7: li TEST_ID, 7 - la x1, test3_data la x2, test4_data la x3, test5_data @@ -115,6 +114,28 @@ test7: nop nop nop + j test8 + +.align 6 +test8: + li TEST_ID, 8 + fcvt.wu.s x1, f3 + nop + nop + nop + nop + j test9 + +.align 6 +test9: + li TEST_ID, 9 + fle.s x1, f2, f3 + fle.s x2, f3, f2 + fle.s x3, f3, f3 + nop + nop + nop + nop /* la x1, test1_data li x2, 45 diff --git a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala index 0a2f665a..7b3dafbd 100644 --- a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala +++ b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala @@ -167,6 +167,31 @@ class FpuTest extends FunSuite{ cmd.load #= false } } + + + def cmp(rs1 : Int, rs2 : Int)(body : FpuRsp => Unit): Unit ={ + cmdQueue += {cmd => + cmd.opcode #= cmd.opcode.spinalEnum.CMP + cmd.value.randomize() + cmd.rs1 #= rs1 + cmd.rs2 #= rs2 + cmd.rs3.randomize() + cmd.rd.randomize() + } + rspQueue += body + } + + def f2i(rs1 : Int)(body : FpuRsp => Unit): Unit ={ + cmdQueue += {cmd => + cmd.opcode #= cmd.opcode.spinalEnum.F2I + cmd.value.randomize() + cmd.rs1 #= rs1 + cmd.rs2.randomize() + cmd.rs3.randomize() + cmd.rd.randomize() + } + rspQueue += body + } } @@ -243,7 +268,8 @@ class FpuTest extends FunSuite{ storeFloat(rd){v => val ref = a.toDouble * b.toDouble + c.toDouble println(f"$a%.20f * $b%.20f + $c%.20f = $v%.20f, $ref%.20f") - assert(checkFloat(ref.toFloat, v)) + val mul = a.toDouble * b.toDouble + if((mul.abs-c.abs)/mul.abs > 0.1) assert(checkFloat(ref.toFloat, v)) } } @@ -279,8 +305,54 @@ class FpuTest extends FunSuite{ } } + def testF2i(a : Float): Unit ={ + val rs = new RegAllocator() + val rs1, rs2, rs3 = rs.allocate() + val rd = Random.nextInt(32) + load(rs1, a) + f2i(rs1){rsp => + val ref = a.toInt + val v = rsp.value.toBigInt + println(f"f2i($a) = $v, $ref") + assert(v === ref) + } + } + + def testCmp(a : Float, b : Float): Unit ={ + val rs = new RegAllocator() + val rs1, rs2, rs3 = rs.allocate() + val rd = Random.nextInt(32) + load(rs1, a) + load(rs2, b) + cmp(rs1, rs2){rsp => + val ref = if(a < b) 1 else 0 + val v = rsp.value.toBigInt + println(f"$a < $b = $v, $ref") + assert(v === ref) + } + } + val b2f = lang.Float.intBitsToFloat(_) + //TODO Test corner cases + testCmp(1.0f, 2.0f) + testCmp(1.5f, 2.0f) + testCmp(1.5f, 3.5f) + testCmp(1.5f, 1.5f) + testCmp(1.5f, -1.5f) + testCmp(-1.5f, 1.5f) + testCmp(-1.5f, -1.5f) + testCmp(1.5f, -3.5f) + + //TODO Test corner cases + testF2i(16.0f) + testF2i(18.0f) + testF2i(1200.0f) + testF2i(1.0f) +// dut.clockDomain.waitSampling(1000) +// simFailure() + + testAdd(0.1f, 1.6f) testSqrt(1.5625f) @@ -296,8 +368,7 @@ class FpuTest extends FunSuite{ testSqrt(b2f(0x3f800002)) testSqrt(b2f(0x3f800003)) - // dut.clockDomain.waitSampling(1000) -// simFailure() + testMul(0.1f, 1.6f) testFma(1.1f, 2.2f, 3.0f) @@ -324,7 +395,10 @@ class FpuTest extends FunSuite{ testDiv(randomFloat(), randomFloat()) } for(i <- 0 until 1000){ - testSqrt(Math.abs(randomFloat())) //TODO + testSqrt(Math.abs(randomFloat())) + } + for(i <- 0 until 1000){ + testCmp(randomFloat(), randomFloat()) } for(i <- 0 until 1000){ val tests = ArrayBuffer[() => Unit]() @@ -333,6 +407,7 @@ class FpuTest extends FunSuite{ tests += (() =>{testFma(randomFloat(), randomFloat(), randomFloat())}) tests += (() =>{testDiv(randomFloat(), randomFloat())}) tests += (() =>{testSqrt(randomFloat().abs)}) + tests += (() =>{testCmp(randomFloat(), randomFloat())}) tests.randomPick().apply() } waitUntil(cpu.rspQueue.isEmpty) From d7220031d47bcbd865de54c2f36c809ff31e432e Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 18 Jan 2021 17:18:01 +0100 Subject: [PATCH 534/951] fpu vex i2f works --- src/main/scala/vexriscv/ip/fpu/FpuCore.scala | 42 ++++- .../scala/vexriscv/plugin/FpuPlugin.scala | 10 +- src/test/cpp/raw/fpu/build/fpu.asm | 148 ++++++++++-------- src/test/cpp/raw/fpu/build/fpu.hex | 42 +++-- src/test/cpp/raw/fpu/src/crt.S | 27 +++- src/test/scala/vexriscv/ip/fpu/FpuTest.scala | 38 ++++- 6 files changed, 210 insertions(+), 97 deletions(-) diff --git a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala index 5d31fe9b..245209e5 100644 --- a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala +++ b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala @@ -32,6 +32,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val opcode = p.Opcode() val rs1, rs2, rs3 = p.rfAddress() val rd = p.rfAddress() + val value = Bits(32 bits) } case class RfReadOutput() extends Bundle{ @@ -40,6 +41,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val lockId = lockIdType() val rs1, rs2, rs3 = p.internalFloating() val rd = p.rfAddress() + val value = Bits(32 bits) } @@ -67,6 +69,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val minus = Bool() } + case class DivSqrtInput() extends Bundle{ val source = Source() val rs1, rs2 = p.internalFloating() @@ -75,6 +78,14 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val div = Bool() } + case class I2fInput() extends Bundle{ + val source = Source() + val rd = p.rfAddress() + val lockId = lockIdType() + val value = Bits(32 bits) + } + + case class AddInput() extends Bundle{ val source = Source() val rs1, rs2 = p.internalFloating() @@ -223,6 +234,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ output.source := s1.source output.opcode := s1.opcode output.lockId := s1LockId + output.value := s1.value output.rd := s1.rd output.rs1 := rf.ram.readSync(s0.source @@ s0.rs1,enable = !output.isStall) output.rs2 := rf.ram.readSync(s0.source @@ s0.rs2,enable = !output.isStall) @@ -251,6 +263,17 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ coreRsp.rs1 := read.output.rs1 coreRsp.rs2 := read.output.rs2 + + val i2fHit = input.opcode === p.Opcode.I2F + val i2f = Stream(I2fInput()) + i2f.valid := input.valid && i2fHit + input.ready setWhen(i2fHit && i2f.ready) + i2f.source := read.output.source + i2f.rd := read.output.rd + i2f.value := read.output.value + i2f.lockId := read.output.lockId + + val divSqrtHit = input.opcode === p.Opcode.DIV || input.opcode === p.Opcode.SQRT val divSqrt = Stream(DivSqrtInput()) input.ready setWhen(divSqrtHit && divSqrt.ready) @@ -296,6 +319,23 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } } + val i2f = new Area{ + val input = decode.i2f.stage() + val output = input.swapPayload(WriteInput()) + + val iLog2 = OHToUInt(OHMasking.last(input.value)) + val shifted = (input.value << p.internalMantissaSize) >> iLog2 + + output.source := input.source + output.lockId := input.lockId + output.rd := input.rd + output.value.sign := False + output.value.exponent := iLog2 +^ exponentOne + output.value.mantissa := U(shifted).resized + } + + + val load = new Area{ val input = decode.load.stage() val filtred = commitFork.load.map(port => port.takeWhen(port.load)) @@ -610,7 +650,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val write = new Area{ - val arbitrated = StreamArbiterFactory.lowerFirst.noLock.on(List(load.output, add.output, mul.output)) + val arbitrated = StreamArbiterFactory.lowerFirst.noLock.on(List(load.output, add.output, mul.output, i2f.output)) val isCommited = rf.lock.map(_.commited).read(arbitrated.lockId) val commited = arbitrated.haltWhen(!isCommited).toFlow diff --git a/src/main/scala/vexriscv/plugin/FpuPlugin.scala b/src/main/scala/vexriscv/plugin/FpuPlugin.scala index e61d224e..7b55ef3a 100644 --- a/src/main/scala/vexriscv/plugin/FpuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/FpuPlugin.scala @@ -27,6 +27,7 @@ class FpuPlugin(externalFpu : Boolean = false, decoderService.add(List( FADD_S -> List(FPU_ENABLE -> True, FPU_OPCODE -> FpuOpcode.ADD, FPU_COMMIT -> True, FPU_ALU -> True , FPU_LOAD -> False, FPU_RSP -> False), FLW -> List(FPU_ENABLE -> True, FPU_OPCODE -> FpuOpcode.LOAD, FPU_COMMIT -> True, FPU_ALU -> False, FPU_LOAD -> True , FPU_RSP -> False), + FCVT_S_WU -> List(FPU_ENABLE -> True, FPU_OPCODE -> FpuOpcode.I2F , FPU_COMMIT -> True , FPU_ALU -> True, FPU_LOAD -> False, FPU_RSP -> False, RS1_USE -> True), FSW -> List(FPU_ENABLE -> True, FPU_OPCODE -> FpuOpcode.STORE, FPU_COMMIT -> False, FPU_ALU -> False, FPU_LOAD -> False, FPU_RSP -> True), FCVT_WU_S -> List(FPU_ENABLE -> True, FPU_OPCODE -> FpuOpcode.F2I , FPU_COMMIT -> False, FPU_ALU -> False, FPU_LOAD -> False, FPU_RSP -> True, REGFILE_WRITE_VALID -> True, BYPASSABLE_EXECUTE_STAGE -> False, BYPASSABLE_MEMORY_STAGE -> False), FLE_S -> List(FPU_ENABLE -> True, FPU_OPCODE -> FpuOpcode.CMP , FPU_COMMIT -> False, FPU_ALU -> False, FPU_LOAD -> False, FPU_RSP -> True, REGFILE_WRITE_VALID -> True, BYPASSABLE_EXECUTE_STAGE -> False, BYPASSABLE_MEMORY_STAGE -> False) @@ -58,10 +59,15 @@ class FpuPlugin(externalFpu : Boolean = false, //Maybe it might be better to not fork before fire to avoid RF stall on commits val forked = Reg(Bool) setWhen(port.cmd.fire) clearWhen(!arbitration.isStuck) init(False) + val i2fReady = Reg(Bool()) setWhen(!arbitration.isStuckByOthers) clearWhen(!arbitration.isStuck) + val i2fHazard = input(FPU_OPCODE) === FpuOpcode.I2F && !i2fReady + + arbitration.haltItself setWhen(arbitration.isValid && i2fHazard) arbitration.haltItself setWhen(port.cmd.isStall) - port.cmd.valid := arbitration.isValid && input(FPU_ENABLE) && !forked + + port.cmd.valid := arbitration.isValid && input(FPU_ENABLE) && !forked && !i2fHazard port.cmd.opcode := input(FPU_OPCODE) - port.cmd.value := output(RS1) + port.cmd.value := RegNext(output(RS1)) port.cmd.function := 0 port.cmd.rs1 := input(INSTRUCTION)(rs1Range).asUInt port.cmd.rs2 := input(INSTRUCTION)(rs2Range).asUInt diff --git a/src/test/cpp/raw/fpu/build/fpu.asm b/src/test/cpp/raw/fpu/build/fpu.asm index f65b2ab9..b7699728 100644 --- a/src/test/cpp/raw/fpu/build/fpu.asm +++ b/src/test/cpp/raw/fpu/build/fpu.asm @@ -25,7 +25,7 @@ Disassembly of section .crt_section: 80000040 : 80000040: 00200e13 li t3,2 80000044: 00000097 auipc ra,0x0 -80000048: 2900a083 lw ra,656(ra) # 800002d4 +80000048: 2e80a083 lw ra,744(ra) # 8000032c 8000004c: 00107153 fadd.s ft2,ft0,ft1 80000050: 00000013 nop 80000054: 00000013 nop @@ -67,7 +67,7 @@ Disassembly of section .crt_section: 800000cc: 00000013 nop 800000d0: 00000013 nop 800000d4: 00000097 auipc ra,0x0 -800000d8: 20008093 addi ra,ra,512 # 800002d4 +800000d8: 25808093 addi ra,ra,600 # 8000032c 800000dc: 0000a107 flw ft2,0(ra) 800000e0: 00000013 nop 800000e4: 00000013 nop @@ -85,9 +85,9 @@ Disassembly of section .crt_section: 8000010c: 00000013 nop 80000110: 00000013 nop 80000114: 00000097 auipc ra,0x0 -80000118: 1c008093 addi ra,ra,448 # 800002d4 +80000118: 21808093 addi ra,ra,536 # 8000032c 8000011c: 00000117 auipc sp,0x0 -80000120: 1bc10113 addi sp,sp,444 # 800002d8 +80000120: 21410113 addi sp,sp,532 # 80000330 80000124: 0000a087 flw ft1,0(ra) 80000128: 00012107 flw ft2,0(sp) 8000012c: 0020f1d3 fadd.s ft3,ft1,ft2 @@ -119,7 +119,7 @@ Disassembly of section .crt_section: 8000018c: 00000013 nop 80000190: 00000013 nop 80000194: 00000097 auipc ra,0x0 -80000198: 14808093 addi ra,ra,328 # 800002dc +80000198: 1a008093 addi ra,ra,416 # 80000334 8000019c: 0030a027 fsw ft3,0(ra) 800001a0: 00000013 nop 800001a4: 00000013 nop @@ -133,13 +133,13 @@ Disassembly of section .crt_section: 800001c0 : 800001c0: 00700e13 li t3,7 800001c4: 00000097 auipc ra,0x0 -800001c8: 11808093 addi ra,ra,280 # 800002dc +800001c8: 17008093 addi ra,ra,368 # 80000334 800001cc: 00000117 auipc sp,0x0 -800001d0: 11410113 addi sp,sp,276 # 800002e0 +800001d0: 16c10113 addi sp,sp,364 # 80000338 800001d4: 00000197 auipc gp,0x0 -800001d8: 11018193 addi gp,gp,272 # 800002e4 +800001d8: 16818193 addi gp,gp,360 # 8000033c 800001dc: 00000217 auipc tp,0x0 -800001e0: 10c20213 addi tp,tp,268 # 800002e8 +800001e0: 16420213 addi tp,tp,356 # 80000340 800001e4: 0000a207 flw ft4,0(ra) 800001e8: 00427253 fadd.s ft4,ft4,ft4 800001ec: 0040f2d3 fadd.s ft5,ft1,ft4 @@ -191,74 +191,86 @@ Disassembly of section .crt_section: 80000294: 00000013 nop 80000298: 00000013 nop 8000029c: 00000013 nop -800002a0: 0100006f j 800002b0 - -800002a4 : -800002a4: f0100137 lui sp,0xf0100 -800002a8: f2410113 addi sp,sp,-220 # f00fff24 -800002ac: 01c12023 sw t3,0(sp) - -800002b0 : -800002b0: f0100137 lui sp,0xf0100 -800002b4: f2010113 addi sp,sp,-224 # f00fff20 -800002b8: 00012023 sw zero,0(sp) +800002a0: 0200006f j 800002c0 +800002a4: 00000013 nop +800002a8: 00000013 nop +800002ac: 00000013 nop +800002b0: 00000013 nop +800002b4: 00000013 nop +800002b8: 00000013 nop 800002bc: 00000013 nop -800002c0: 00000013 nop -800002c4: 00000013 nop -800002c8: 00000013 nop -800002cc: 00000013 nop -800002d0: 00000013 nop -800002d4 : -800002d4: 0000 unimp -800002d6: 3fc0 fld fs0,184(a5) +800002c0 : +800002c0: 00a00e13 li t3,10 +800002c4: 01000093 li ra,16 +800002c8: d010f0d3 fcvt.s.wu ft1,ra +800002cc: 01200113 li sp,18 +800002d0: 20000193 li gp,512 +800002d4: d0117153 fcvt.s.wu ft2,sp +800002d8: d011f1d3 fcvt.s.wu ft3,gp +800002dc: 00000217 auipc tp,0x0 +800002e0: 0a422203 lw tp,164(tp) # 80000380 +800002e4: d01272d3 fcvt.s.wu ft5,tp +800002e8: 00000013 nop +800002ec: 00000013 nop +800002f0: 00000013 nop +800002f4: 00000013 nop +800002f8: 0100006f j 80000308 -800002d8 : -800002d8: 0000 unimp -800002da: 40a0 lw s0,64(s1) +800002fc : +800002fc: f0100137 lui sp,0xf0100 +80000300: f2410113 addi sp,sp,-220 # f00fff24 +80000304: 01c12023 sw t3,0(sp) -800002dc : -800002dc: 0049 c.nop 18 +80000308 : +80000308: f0100137 lui sp,0xf0100 +8000030c: f2010113 addi sp,sp,-224 # f00fff20 +80000310: 00012023 sw zero,0(sp) +80000314: 00000013 nop +80000318: 00000013 nop +8000031c: 00000013 nop +80000320: 00000013 nop +80000324: 00000013 nop +80000328: 00000013 nop + +8000032c : +8000032c: 0000 unimp +8000032e: 3fc0 fld fs0,184(a5) + +80000330 : +80000330: 0000 unimp +80000332: 40a0 lw s0,64(s1) + +80000334 : +80000334: 0049 c.nop 18 ... -800002e0 : -800002e0: 003a c.slli zero,0xe +80000338 : +80000338: 003a c.slli zero,0xe ... -800002e4 : -800002e4: 0038 addi a4,sp,8 +8000033c : +8000033c: 0038 addi a4,sp,8 ... -800002e8 : -800002e8: 0000004b fnmsub.s ft0,ft0,ft0,ft0,rne +80000340 : +80000340: 0000004b fnmsub.s ft0,ft0,ft0,ft0,rne +80000344: 00000013 nop +80000348: 00000013 nop +8000034c: 00000013 nop +80000350: 00000013 nop +80000354: 00000013 nop +80000358: 00000013 nop +8000035c: 00000013 nop +80000360: 00000013 nop +80000364: 00000013 nop +80000368: 00000013 nop +8000036c: 00000013 nop +80000370: 00000013 nop +80000374: 00000013 nop +80000378: 00000013 nop +8000037c: 00000013 nop -800002ec : -800002ec: 0038 addi a4,sp,8 - ... - -800002f0 : -800002f0: 00000053 fadd.s ft0,ft0,ft0,rne - -800002f4 : -800002f4: 0021 c.nop 8 - ... - -800002f8 : -800002f8: ffffffbf 0xffffffbf - -800002fc : -800002fc: ffa9 bnez a5,80000256 -800002fe: ffff 0xffff - -80000300 : -80000300: ffc9 bnez a5,8000029a -80000302: ffff 0xffff - -80000304 : -80000304: 0004 0x4 -80000306: ffff 0xffff - -80000308 : -80000308: 0005 c.nop 1 -8000030a: ffff 0xffff +80000380 : +80000380: 01d4 addi a3,sp,196 ... diff --git a/src/test/cpp/raw/fpu/build/fpu.hex b/src/test/cpp/raw/fpu/build/fpu.hex index a182b0e5..4b83443c 100644 --- a/src/test/cpp/raw/fpu/build/fpu.hex +++ b/src/test/cpp/raw/fpu/build/fpu.hex @@ -3,7 +3,7 @@ :1000100013000000537110001300000013000000D3 :1000200013000000130000006F00800113000000A7 :100030001300000013000000130000001300000074 -:10004000130E20009700000083A0002953711000B8 +:10004000130E20009700000083A0802E5371100033 :100050001300000013000000130000001300000054 :100060006F000002130000001300000013000000E6 :100070001300000013000000130000001300000034 @@ -12,24 +12,24 @@ :1000A0001300000013000000130000001300000004 :1000B00013000000130000001300000013000000F4 :1000C000130E400013000000130000001300000096 -:1000D00013000000970000009380002007A100009B +:1000D00013000000970000009380802507A1000016 :1000E00013000000130000001300000013000000C4 :1000F0006F00000113000000130000001300000057 :10010000130E500013000000130000001300000045 -:1001100013000000970000009380001C17010000EE -:100120001301C11B87A0000007210100D3F12000AB +:100110001300000097000000938080211701000069 +:100120001301412187A0000007210100D3F1200025 :100130001300000013000000130000001300000073 :100140006F00000413000000130000001300000003 :100150001300000013000000130000001300000053 :100160001300000013000000130000001300000043 :100170001300000013000000130000001300000033 :10018000130E6000130000001300000013000000B5 -:1001900013000000970000009380801427A0300017 +:1001900013000000970000009380001A27A0300091 :1001A0001300000013000000130000001300000003 :1001B0006F00000113000000130000001300000096 -:1001C000130E70009700000093808011170100004B -:1001D00013014111970100009381011117020000E2 -:1001E0001302C21007A2000053724200D3F2400073 +:1001C000130E7000970000009380001717010000C5 +:1001D0001301C116970100009381811617020000D8 +:1001E0001302421607A2000053724200D3F24000ED :1001F0002720410027A051002720120013000000F3 :100200001300000013000000130000006F00400303 :100210001300000013000000130000001300000092 @@ -41,12 +41,22 @@ :100270001300000013000000130000001300000032 :10028000130E9000D30031A0538121A0D38131A05F :100290001300000013000000130000001300000012 -:1002A0006F000001370110F0130141F22320C1015A -:1002B000370110F0130101F22320010013000000A8 -:1002C00013000000130000001300000013000000E2 -:1002D000130000000000C03F0000A04049000000E3 -:1002E0003A000000380000004B0000003800000019 -:1002F0005300000021000000BFFFFFFFA9FFFFFF28 -:10030000C9FFFFFF0400FFFF0500FFFF0000000022 -:080310000000000000000000E5 +:1002A0006F000002130000001300000013000000A4 +:1002B00013000000130000001300000013000000F2 +:1002C000130EA00093000001D3F010D01301200101 +:1002D00093010020537111D0D3F111D01702000007 +:1002E0000322420AD37212D0130000001300000050 +:1002F00013000000130000006F000001370110F030 +:10030000130141F22320C101370110F0130101F262 +:100310002320010013000000130000001300000060 +:100320001300000013000000130000000000C03F95 +:100330000000A040490000003A0000003800000022 +:100340004B00000013000000130000001300000029 +:100350001300000013000000130000001300000051 +:100360001300000013000000130000001300000041 +:100370001300000013000000130000001300000031 +:10038000D401000000000000000000000000000098 +:10039000000000000000000000000000000000005D +:1003A000000000000000000000000000000000004D +:0803B000000000000000000045 :00000001FF diff --git a/src/test/cpp/raw/fpu/src/crt.S b/src/test/cpp/raw/fpu/src/crt.S index 0a3183fe..302b98c9 100644 --- a/src/test/cpp/raw/fpu/src/crt.S +++ b/src/test/cpp/raw/fpu/src/crt.S @@ -136,6 +136,23 @@ test9: nop nop nop + j test10 + +.align 6 +test10: + li TEST_ID, 10 + li x1, 16 + fcvt.s.wu f1, x1 + li x2, 18 + li x3, 512 + fcvt.s.wu f2, x2 + fcvt.s.wu f3, x3 + lw x4, test10_data + fcvt.s.wu f5, x4 + nop + nop + nop + nop /* la x1, test1_data li x2, 45 @@ -172,11 +189,5 @@ test3_data: .word 73 test4_data: .word 58 test5_data: .word 56 test6_data: .word 75 -test7_data: .word 56 -test8_data: .word 83 -test9_data: .word 33 -test10_data: .word -65 -test11_data: .word -87 -test12_data: .word -55 -test13_data: .word 0xFFFF0004 -test14_data: .word 0xFFFF0005 \ No newline at end of file +.align 6 +test10_data: .word 468 diff --git a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala index 7b3dafbd..b1645a48 100644 --- a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala +++ b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala @@ -192,6 +192,21 @@ class FpuTest extends FunSuite{ } rspQueue += body } + + def i2f(rd : Int, value : Int): Unit ={ + cmdQueue += {cmd => + cmd.opcode #= cmd.opcode.spinalEnum.I2F + cmd.value #= value + cmd.rs1.randomize() + cmd.rs2.randomize() + cmd.rs3.randomize() + cmd.rd #= rd + } + commitQueue += {cmd => + cmd.write #= true + cmd.load #= false + } + } } @@ -318,6 +333,17 @@ class FpuTest extends FunSuite{ } } + def testI2f(a : Int): Unit ={ + val rs = new RegAllocator() + val rd = Random.nextInt(32) + i2f(rd, a) + storeFloat(rd){v => + val ref = a.toInt + println(f"i2f($a) = $v, $ref") + assert(v === ref) + } + } + def testCmp(a : Float, b : Float): Unit ={ val rs = new RegAllocator() val rs1, rs2, rs3 = rs.allocate() @@ -334,6 +360,15 @@ class FpuTest extends FunSuite{ val b2f = lang.Float.intBitsToFloat(_) + + //TODO Test corner cases + testI2f(17) + testI2f(12) + testI2f(512) + testI2f(1) +// dut.clockDomain.waitSampling(1000) +// simFailure() + //TODO Test corner cases testCmp(1.0f, 2.0f) testCmp(1.5f, 2.0f) @@ -349,8 +384,7 @@ class FpuTest extends FunSuite{ testF2i(18.0f) testF2i(1200.0f) testF2i(1.0f) -// dut.clockDomain.waitSampling(1000) -// simFailure() + testAdd(0.1f, 1.6f) From 8c4fae8bf2eeea749c3c0b8fe5522a6d1f9b37cc Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 19 Jan 2021 13:27:42 +0100 Subject: [PATCH 535/951] fpu add min/sgnj/fmv --- src/main/scala/vexriscv/ip/fpu/FpuCore.scala | 123 +++++++++------ .../scala/vexriscv/ip/fpu/Interface.scala | 2 +- src/test/scala/vexriscv/ip/fpu/FpuTest.scala | 145 ++++++++++++++++++ 3 files changed, 220 insertions(+), 50 deletions(-) diff --git a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala index 245209e5..4ef198e8 100644 --- a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala +++ b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala @@ -56,6 +56,9 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val source = Source() val opcode = p.Opcode() val rs1, rs2 = p.internalFloating() + val lockId = lockIdType() + val rd = p.rfAddress() + val value = Bits(32 bits) } case class MulInput() extends Bundle{ @@ -78,13 +81,6 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val div = Bool() } - case class I2fInput() extends Bundle{ - val source = Source() - val rd = p.rfAddress() - val lockId = lockIdType() - val value = Bits(32 bits) - } - case class AddInput() extends Bundle{ val source = Source() @@ -203,10 +199,26 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ is(p.Opcode.F2I){ useRs1 := True } + is(p.Opcode.MIN_MAX){ + useRd := True + useRs1 := True + useRs2 := True + } is(p.Opcode.CMP){ useRs1 := True useRs2 := True } + is(p.Opcode.SGNJ){ + useRd := True + useRs1 := True + useRs2 := True + } + is(p.Opcode.FMV_X_W){ + useRs1 := True + } + is(p.Opcode.FMV_W_X){ + useRd := True + } } val hits = List((useRs1, s0.rs1), (useRs2, s0.rs2), (useRs3, s0.rs3), (useRd, s0.rd)).map{case (use, reg) => use && rf.lock.map(l => l.valid && l.source === s0.source && l.address === reg).orR} @@ -254,7 +266,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ load.rs1 := read.output.rs1 load.lockId := read.output.lockId - val coreRspHit = List(FpuOpcode.STORE, FpuOpcode.F2I, FpuOpcode.CMP).map(input.opcode === _).orR + val coreRspHit = List(FpuOpcode.STORE, FpuOpcode.F2I, FpuOpcode.CMP, FpuOpcode.I2F, FpuOpcode.MIN_MAX, FpuOpcode.SGNJ, FpuOpcode.FMV_X_W, FpuOpcode.FMV_W_X).map(input.opcode === _).orR val coreRsp = Stream(StoreInput()) input.ready setWhen(coreRspHit && coreRsp.ready) coreRsp.valid := input.valid && coreRspHit @@ -262,17 +274,9 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ coreRsp.opcode := read.output.opcode coreRsp.rs1 := read.output.rs1 coreRsp.rs2 := read.output.rs2 - - - val i2fHit = input.opcode === p.Opcode.I2F - val i2f = Stream(I2fInput()) - i2f.valid := input.valid && i2fHit - input.ready setWhen(i2fHit && i2f.ready) - i2f.source := read.output.source - i2f.rd := read.output.rd - i2f.value := read.output.value - i2f.lockId := read.output.lockId - + coreRsp.lockId := read.output.lockId + coreRsp.rd := read.output.rd + coreRsp.value := read.output.value val divSqrtHit = input.opcode === p.Opcode.DIV || input.opcode === p.Opcode.SQRT val divSqrt = Stream(DivSqrtInput()) @@ -319,21 +323,6 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } } - val i2f = new Area{ - val input = decode.i2f.stage() - val output = input.swapPayload(WriteInput()) - - val iLog2 = OHToUInt(OHMasking.last(input.value)) - val shifted = (input.value << p.internalMantissaSize) >> iLog2 - - output.source := input.source - output.lockId := input.lockId - output.rd := input.rd - output.value.sign := False - output.value.exponent := iLog2 +^ exponentOne - output.value.mantissa := U(shifted).resized - } - val load = new Area{ @@ -351,9 +340,13 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } - val coreRsp = new Area{ + + + val shortPip = new Area{ val input = decode.coreRsp.stage() + val rfOutput = Stream(WriteInput()) + val result = p.storeLoadType().assignDontCare() val storeResult = input.rs2.asBits @@ -361,6 +354,9 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val f2iShifted = (U"1" @@ input.rs1.mantissa) << (f2iShift.resize(5 bits)) val f2iResult = f2iShifted.asBits >> p.internalMantissaSize + val i2fLog2 = OHToUInt(OHMasking.last(input.value)) + val i2fShifted = (input.value << p.internalMantissaSize) >> i2fLog2 + val rs1Equal = input.rs1 === input.rs2 val rs1AbsSmaller = (input.rs1.exponent @@ input.rs1.mantissa) < (input.rs2.exponent @@ input.rs2.mantissa) val rs1Smaller = (input.rs1.sign ## input.rs2.sign).mux( @@ -369,18 +365,47 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ 2 -> True, 3 -> (!rs1AbsSmaller && !rs1Equal) ) + + val minMaxResult = rs1Smaller ? input.rs1 | input.rs2 val cmpResult = B(rs1Smaller) switch(input.opcode){ - is(FpuOpcode.STORE){ result := storeResult } - is(FpuOpcode.F2I) { result := f2iResult } - is(FpuOpcode.CMP) { result := cmpResult.resized } + is(FpuOpcode.STORE) { result := storeResult } + is(FpuOpcode.F2I) { result := f2iResult } + is(FpuOpcode.CMP) { result := cmpResult.resized } //TODO + is(FpuOpcode.FMV_X_W) { result := input.rs1.asBits } //TODO } - input.ready := io.port.map(_.rsp.ready).read(input.source) + val toFpuRf = List(FpuOpcode.MIN_MAX, FpuOpcode.I2F, FpuOpcode.SGNJ, FpuOpcode.FMV_W_X).map(input.opcode === _).orR + + rfOutput.valid := input.valid && toFpuRf + rfOutput.source := input.source + rfOutput.lockId := input.lockId + rfOutput.rd := input.rd + rfOutput.value.assignDontCare() + switch(input.opcode){ + is(FpuOpcode.I2F){ + rfOutput.value.sign := False + rfOutput.value.exponent := i2fLog2 +^ exponentOne + rfOutput.value.mantissa := U(i2fShifted).resized + } + is(FpuOpcode.MIN_MAX){ + rfOutput.value := minMaxResult + } + is(FpuOpcode.SGNJ){ + rfOutput.value.sign := input.rs2.sign + rfOutput.value.exponent := input.rs1.exponent + rfOutput.value.mantissa := input.rs1.mantissa + } + is(FpuOpcode.FMV_W_X){ + rfOutput.value.assignFromBits(input.value) //TODO + } + } + + input.ready := (toFpuRf ? rfOutput.ready | io.port.map(_.rsp.ready).read(input.source)) for(i <- 0 until portCount){ def rsp = io.port(i).rsp - rsp.valid := input.valid && input.source === i + rsp.valid := input.valid && input.source === i && !toFpuRf rsp.value := result } } @@ -650,7 +675,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val write = new Area{ - val arbitrated = StreamArbiterFactory.lowerFirst.noLock.on(List(load.output, add.output, mul.output, i2f.output)) + val arbitrated = StreamArbiterFactory.lowerFirst.noLock.on(List(load.output, add.output, mul.output, shortPip.rfOutput)) val isCommited = rf.lock.map(_.commited).read(arbitrated.lockId) val commited = arbitrated.haltWhen(!isCommited).toFlow @@ -692,14 +717,14 @@ object FpuSynthesisBench extends App{ withDouble = false ) ) - rtls += new Fpu( - "64", - portCount = 1, - FpuParameter( - internalMantissaSize = 52, - withDouble = true - ) - ) +// rtls += new Fpu( +// "64", +// portCount = 1, +// FpuParameter( +// internalMantissaSize = 52, +// withDouble = true +// ) +// ) val targets = XilinxStdTargets()// ++ AlteraStdTargets() diff --git a/src/main/scala/vexriscv/ip/fpu/Interface.scala b/src/main/scala/vexriscv/ip/fpu/Interface.scala index 0719bffc..1003fdbf 100644 --- a/src/main/scala/vexriscv/ip/fpu/Interface.scala +++ b/src/main/scala/vexriscv/ip/fpu/Interface.scala @@ -31,7 +31,7 @@ case class FpuFloat(exponentSize: Int, } object FpuOpcode extends SpinalEnum{ - val LOAD, STORE, MUL, ADD, FMA, I2F, F2I, CMP, DIV, SQRT = newElement() + val LOAD, STORE, MUL, ADD, FMA, I2F, F2I, CMP, DIV, SQRT, MIN_MAX, SGNJ, FMV_X_W, FMV_W_X = newElement() } object FpuFormat extends SpinalEnum{ diff --git a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala index b1645a48..f2904f7c 100644 --- a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala +++ b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala @@ -207,6 +207,64 @@ class FpuTest extends FunSuite{ cmd.load #= false } } + + def fmv_x_w(rs1 : Int)(body : FpuRsp => Unit): Unit ={ + cmdQueue += {cmd => + cmd.opcode #= cmd.opcode.spinalEnum.FMV_X_W + cmd.value.randomize() + cmd.rs1 #= rs1 + cmd.rs2.randomize() + cmd.rs3.randomize() + cmd.rd.randomize() + } + rspQueue += body + } + + def fmv_w_x(rd : Int, value : Int): Unit ={ + cmdQueue += {cmd => + cmd.opcode #= cmd.opcode.spinalEnum.FMV_W_X + cmd.value #= value.toLong & 0xFFFFFFFFl + cmd.rs1.randomize() + cmd.rs2.randomize() + cmd.rs3.randomize() + cmd.rd #= rd + } + commitQueue += {cmd => + cmd.write #= true + cmd.load #= false + } + } + + def min(rd : Int, rs1 : Int, rs2 : Int): Unit ={ + cmdQueue += {cmd => + cmd.opcode #= cmd.opcode.spinalEnum.MIN_MAX + cmd.value.randomize() + cmd.rs1 #= rs1 + cmd.rs2 #= rs2 + cmd.rs3.randomize() + cmd.rd #= rd + } + commitQueue += {cmd => + cmd.write #= true + cmd.load #= false + } + } + + + def sgnj(rd : Int, rs1 : Int, rs2 : Int): Unit ={ + cmdQueue += {cmd => + cmd.opcode #= cmd.opcode.spinalEnum.SGNJ + cmd.value.randomize() + cmd.rs1 #= rs1 + cmd.rs2 #= rs2 + cmd.rs3.randomize() + cmd.rd #= rd + } + commitQueue += {cmd => + cmd.write #= true + cmd.load #= false + } + } } @@ -358,9 +416,90 @@ class FpuTest extends FunSuite{ } } + def testFmv_x_w(a : Float): Unit ={ + val rs = new RegAllocator() + val rs1, rs2, rs3 = rs.allocate() + val rd = Random.nextInt(32) + load(rs1, a) + fmv_x_w(rs1){rsp => + val ref = lang.Float.floatToIntBits(a).toLong & 0xFFFFFFFFl + val v = rsp.value.toBigInt + println(f"fmv_x_w $a = $v, $ref") + assert(v === ref) + } + } + + def testFmv_w_x(a : Int): Unit ={ + val rs = new RegAllocator() + val rs1, rs2, rs3 = rs.allocate() + val rd = Random.nextInt(32) + fmv_w_x(rd, a) + storeFloat(rd){v => + val ref = lang.Float.intBitsToFloat(a) + println(f"fmv_w_x $a = $v, $ref") + assert(v === ref) + } + } + + + + def testMin(a : Float, b : Float): Unit ={ + val rs = new RegAllocator() + val rs1, rs2, rs3 = rs.allocate() + val rd = Random.nextInt(32) + load(rs1, a) + load(rs2, b) + + min(rd,rs1,rs2) + storeFloat(rd){v => + val ref = a min b + println(f"min $a $b = $v, $ref") + assert(ref == v) + } + } + + def testSgnj(a : Float, b : Float): Unit ={ + val rs = new RegAllocator() + val rs1, rs2, rs3 = rs.allocate() + val rd = Random.nextInt(32) + load(rs1, a) + load(rs2, b) + + sgnj(rd,rs1,rs2) + storeFloat(rd){v => + val ref = a * a.signum * b.signum + println(f"sgnf $a $b = $v, $ref") + assert(ref == v) + } + } + + val b2f = lang.Float.intBitsToFloat(_) + testFmv_x_w(1.246f) + testFmv_w_x(lang.Float.floatToIntBits(7.234f)) + + testMin(1.0f, 2.0f) + testMin(1.5f, 2.0f) + testMin(1.5f, 3.5f) + testMin(1.5f, 1.5f) + testMin(1.5f, -1.5f) + testMin(-1.5f, 1.5f) + testMin(-1.5f, -1.5f) + testMin(1.5f, -3.5f) + + testSgnj(1.0f, 2.0f) + testSgnj(1.5f, 2.0f) + testSgnj(1.5f, 3.5f) + testSgnj(1.5f, 1.5f) + testSgnj(1.5f, -1.5f) + testSgnj(-1.5f, 1.5f) + testSgnj(-1.5f, -1.5f) + testSgnj(1.5f, -3.5f) + + + //TODO Test corner cases testI2f(17) testI2f(12) @@ -442,6 +581,12 @@ class FpuTest extends FunSuite{ tests += (() =>{testDiv(randomFloat(), randomFloat())}) tests += (() =>{testSqrt(randomFloat().abs)}) tests += (() =>{testCmp(randomFloat(), randomFloat())}) + tests += (() =>{testFmv_x_w(randomFloat())}) + tests += (() =>{testFmv_w_x(lang.Float.floatToIntBits(randomFloat()))}) + tests += (() =>{testMin(randomFloat(), randomFloat())}) + tests += (() =>{testSgnj(randomFloat(), randomFloat())}) + + tests.randomPick().apply() } waitUntil(cpu.rspQueue.isEmpty) From f826a2ce517277ded0685c5340330f8438c091d4 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 19 Jan 2021 15:13:13 +0100 Subject: [PATCH 536/951] fpu completion interface added + refractoring --- src/main/scala/vexriscv/ip/fpu/FpuCore.scala | 154 ++++++------------ .../scala/vexriscv/ip/fpu/Interface.scala | 11 ++ src/test/scala/vexriscv/ip/fpu/FpuTest.scala | 4 +- 3 files changed, 67 insertions(+), 102 deletions(-) diff --git a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala index 4ef198e8..ca297f84 100644 --- a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala +++ b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala @@ -19,14 +19,9 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val Source = HardType(UInt(portCountWidth bits)) val exponentOne = (1 << p.internalExponentSize-1) - 1 - -// val commitPerportCount = 8 val rfLockCount = 5 val lockIdType = HardType(UInt(log2Up(rfLockCount) bits)) -// io.port.rsp.valid := False -// io.port.rsp.payload.assignDontCare() - case class RfReadInput() extends Bundle{ val source = Source() val opcode = p.Opcode() @@ -52,7 +47,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val lockId = lockIdType() } - case class StoreInput() extends Bundle{ + case class ShortPipInput() extends Bundle{ val source = Source() val opcode = p.Opcode() val rs1, rs2 = p.internalFloating() @@ -88,7 +83,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val rd = p.rfAddress() val lockId = lockIdType() } - + case class WriteInput() extends Bundle{ val source = Source() val lockId = lockIdType() @@ -111,6 +106,31 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val lockFreeId = OHMasking.first(lock.map(!_.valid)) } + val completion = for(source <- 0 until portCount) yield new Area{ + def port = io.port(source) + port.completion.flag.NV := False + port.completion.flag.DZ := False + port.completion.flag.OF := False + port.completion.flag.UF := False + port.completion.flag.NX := False + + val increments = ArrayBuffer[Bool]() + +// def increment(): Unit ={ +// //This is a SpinalHDL trick which allow to go back in time +// val swapContext = dslBody.swap() +// val cond = False +// swapContext.appendBack() +// +// cond := True +// incs += cond +// } + + afterElaboration{ + port.completion.count := increments.map(_.asUInt.resize(log2Up(increments.size + 1))).reduceBalancedTree(_ + _) + } + } + val commitFork = new Area{ val load, commit = Vec(Stream(FpuCommit(p)), portCount) for(i <- 0 until portCount){ @@ -141,16 +161,6 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } } -// case class CommitLine() extends Bundle{ -// val valid = Bool() -// val write = Bool() -// } -// val commits = for(i <- 0 until portCount) yield new Area{ -// val lines = Vec(CommitLine(), commitPerportCount) -// lines.foreach(_.valid init(False)) -// -// } - val read = new Area{ val arbiter = StreamArbiterFactory.noLock.lowerFirst.build(FpuCmd(p), portCount) arbiter.io.inputs <> Vec(io.port.map(_.cmd)) @@ -162,63 +172,20 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val useRs1, useRs2, useRs3, useRd = False switch(s0.opcode){ - is(p.Opcode.LOAD){ - useRd := True - } - is(p.Opcode.STORE){ - useRs2 := True - } - is(p.Opcode.ADD){ - useRs1 := True - useRs2 := True - useRd := True - } - is(p.Opcode.MUL){ - useRs1 := True - useRs2 := True - useRd := True - } - is(p.Opcode.DIV){ - useRs1 := True - useRs2 := True - useRd := True - } - is(p.Opcode.SQRT){ - useRs1 := True - useRd := True - } - is(p.Opcode.FMA){ - useRs1 := True - useRs2 := True - useRs3 := True //Can be delayed to have less hazard - useRd := True - } - is(p.Opcode.I2F){ - useRd := True - } - is(p.Opcode.F2I){ - useRs1 := True - } - is(p.Opcode.MIN_MAX){ - useRd := True - useRs1 := True - useRs2 := True - } - is(p.Opcode.CMP){ - useRs1 := True - useRs2 := True - } - is(p.Opcode.SGNJ){ - useRd := True - useRs1 := True - useRs2 := True - } - is(p.Opcode.FMV_X_W){ - useRs1 := True - } - is(p.Opcode.FMV_W_X){ - useRd := True - } + is(p.Opcode.LOAD) { useRd := True } + is(p.Opcode.STORE) { useRs2 := True } + is(p.Opcode.ADD) { useRd := True; useRs1 := True; useRs2 := True } + is(p.Opcode.MUL) { useRd := True; useRs1 := True; useRs2 := True } + is(p.Opcode.DIV) { useRd := True; useRs1 := True; useRs2 := True } + is(p.Opcode.SQRT) { useRd := True; useRs1 := True } + is(p.Opcode.FMA) { useRd := True; useRs1 := True; useRs2 := True; useRs3 := True } + is(p.Opcode.I2F) { useRd := True } + is(p.Opcode.F2I) { useRs1 := True } + is(p.Opcode.MIN_MAX) { useRd := True; useRs1 := True; useRs2 := True } + is(p.Opcode.CMP) { useRs1 := True; useRs2 := True } + is(p.Opcode.SGNJ) { useRd := True; useRs1 := True; useRs2 := True } + is(p.Opcode.FMV_X_W) { useRs1 := True } + is(p.Opcode.FMV_W_X) { useRd := True} } val hits = List((useRs1, s0.rs1), (useRs2, s0.rs2), (useRs3, s0.rs3), (useRd, s0.rd)).map{case (use, reg) => use && rf.lock.map(l => l.valid && l.source === s0.source && l.address === reg).orR} @@ -261,32 +228,19 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val load = Stream(LoadInput()) load.valid := input.valid && loadHit input.ready setWhen(loadHit && load.ready) - load.source := read.output.source - load.rd := read.output.rd - load.rs1 := read.output.rs1 - load.lockId := read.output.lockId + load.payload.assignSomeByName(read.output.payload) - val coreRspHit = List(FpuOpcode.STORE, FpuOpcode.F2I, FpuOpcode.CMP, FpuOpcode.I2F, FpuOpcode.MIN_MAX, FpuOpcode.SGNJ, FpuOpcode.FMV_X_W, FpuOpcode.FMV_W_X).map(input.opcode === _).orR - val coreRsp = Stream(StoreInput()) - input.ready setWhen(coreRspHit && coreRsp.ready) - coreRsp.valid := input.valid && coreRspHit - coreRsp.source := read.output.source - coreRsp.opcode := read.output.opcode - coreRsp.rs1 := read.output.rs1 - coreRsp.rs2 := read.output.rs2 - coreRsp.lockId := read.output.lockId - coreRsp.rd := read.output.rd - coreRsp.value := read.output.value + val shortPipHit = List(FpuOpcode.STORE, FpuOpcode.F2I, FpuOpcode.CMP, FpuOpcode.I2F, FpuOpcode.MIN_MAX, FpuOpcode.SGNJ, FpuOpcode.FMV_X_W, FpuOpcode.FMV_W_X).map(input.opcode === _).orR + val shortPip = Stream(ShortPipInput()) + input.ready setWhen(shortPipHit && shortPip.ready) + shortPip.valid := input.valid && shortPipHit + shortPip.payload.assignSomeByName(read.output.payload) val divSqrtHit = input.opcode === p.Opcode.DIV || input.opcode === p.Opcode.SQRT val divSqrt = Stream(DivSqrtInput()) input.ready setWhen(divSqrtHit && divSqrt.ready) divSqrt.valid := input.valid && divSqrtHit - divSqrt.source := read.output.source - divSqrt.rs1 := read.output.rs1 - divSqrt.rs2 := read.output.rs2 - divSqrt.rd := read.output.rd - divSqrt.lockId := read.output.lockId + divSqrt.payload.assignSomeByName(read.output.payload) divSqrt.div := input.opcode === p.Opcode.DIV val fmaHit = input.opcode === p.Opcode.FMA @@ -323,8 +277,6 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } } - - val load = new Area{ val input = decode.load.stage() val filtred = commitFork.load.map(port => port.takeWhen(port.load)) @@ -339,11 +291,8 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ output.value.assignFromBits(feed.value) } - - - val shortPip = new Area{ - val input = decode.coreRsp.stage() + val input = decode.shortPip.stage() val rfOutput = Stream(WriteInput()) @@ -407,6 +356,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ def rsp = io.port(i).rsp rsp.valid := input.valid && input.source === i && !toFpuRf rsp.value := result + completion(i).increments += (RegNext(rsp.fire) init(False)) } } @@ -689,6 +639,10 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ port.valid := commited.valid && rf.lock.map(_.write).read(commited.lockId) port.address := commited.source @@ commited.rd port.data := commited.value + + for(i <- 0 until portCount){ + completion(i).increments += (RegNext(port.fire && commited.source === i) init(False)) + } } } diff --git a/src/main/scala/vexriscv/ip/fpu/Interface.scala b/src/main/scala/vexriscv/ip/fpu/Interface.scala index 1003fdbf..a83d5f6c 100644 --- a/src/main/scala/vexriscv/ip/fpu/Interface.scala +++ b/src/main/scala/vexriscv/ip/fpu/Interface.scala @@ -52,6 +52,15 @@ case class FpuParameter( internalMantissaSize : Int, val Format = FpuFormat } +case class FpuFlags() extends Bundle{ + val NV, DZ, OF, UF, NX = Bool() +} + +case class FpuCompletion() extends Bundle{ + val flag = FpuFlags() + val count = UInt(2 bits) +} + case class FpuCmd(p : FpuParameter) extends Bundle{ val opcode = p.Opcode() val value = Bits(32 bits) // Int to float @@ -75,9 +84,11 @@ case class FpuPort(p : FpuParameter) extends Bundle with IMasterSlave { val cmd = Stream(FpuCmd(p)) val commit = Stream(FpuCommit(p)) val rsp = Stream(FpuRsp(p)) + val completion = FpuCompletion() override def asMaster(): Unit = { master(cmd, commit) slave(rsp) + in(completion) } } diff --git a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala index f2904f7c..59b3fc93 100644 --- a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala +++ b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala @@ -16,13 +16,13 @@ class FpuTest extends FunSuite{ test("directed"){ - val portCount = 1 + val portCount = 4 val p = FpuParameter( internalMantissaSize = 23, withDouble = false ) - SimConfig.withFstWave.compile(new FpuCore(1, p)).doSim(seed = 42){ dut => + SimConfig.withFstWave.compile(new FpuCore(portCount, p)).doSim(seed = 42){ dut => dut.clockDomain.forkStimulus(10) From a7d148d0ff5e22a68b5931dbb949a82bd8803c11 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 19 Jan 2021 15:53:11 +0100 Subject: [PATCH 537/951] fpu add vex csr --- src/main/scala/vexriscv/Riscv.scala | 6 ++-- src/main/scala/vexriscv/ip/fpu/FpuCore.scala | 8 ++--- .../scala/vexriscv/ip/fpu/Interface.scala | 2 +- .../scala/vexriscv/plugin/CsrPlugin.scala | 15 +++++++++ .../scala/vexriscv/plugin/FpuPlugin.scala | 33 +++++++++++++++++-- 5 files changed, 54 insertions(+), 10 deletions(-) diff --git a/src/main/scala/vexriscv/Riscv.scala b/src/main/scala/vexriscv/Riscv.scala index df49682b..e22b3240 100644 --- a/src/main/scala/vexriscv/Riscv.scala +++ b/src/main/scala/vexriscv/Riscv.scala @@ -221,12 +221,14 @@ object Riscv{ val SIP = 0x144 val SATP = 0x180 - - def UCYCLE = 0xC00 // UR Machine ucycle counter. def UCYCLEH = 0xC80 def UTIME = 0xC01 // rdtime def UTIMEH = 0xC81 + val FFLAGS = 0x1 + val FRM = 0x2 + val FCSR = 0x3 + } } diff --git a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala index ca297f84..56c0fab2 100644 --- a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala +++ b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala @@ -629,6 +629,10 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val isCommited = rf.lock.map(_.commited).read(arbitrated.lockId) val commited = arbitrated.haltWhen(!isCommited).toFlow + for(i <- 0 until portCount){ + completion(i).increments += (RegNext(commited.fire && commited.source === i) init(False)) + } + when(commited.valid){ for(i <- 0 until rfLockCount) when(commited.lockId === i){ rf.lock(i).valid := False @@ -639,10 +643,6 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ port.valid := commited.valid && rf.lock.map(_.write).read(commited.lockId) port.address := commited.source @@ commited.rd port.data := commited.value - - for(i <- 0 until portCount){ - completion(i).increments += (RegNext(port.fire && commited.source === i) init(False)) - } } } diff --git a/src/main/scala/vexriscv/ip/fpu/Interface.scala b/src/main/scala/vexriscv/ip/fpu/Interface.scala index a83d5f6c..255f9cbb 100644 --- a/src/main/scala/vexriscv/ip/fpu/Interface.scala +++ b/src/main/scala/vexriscv/ip/fpu/Interface.scala @@ -53,7 +53,7 @@ case class FpuParameter( internalMantissaSize : Int, } case class FpuFlags() extends Bundle{ - val NV, DZ, OF, UF, NX = Bool() + val NX, UF, OF, DZ, NV = Bool() } case class FpuCompletion() extends Bundle{ diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 7eee6536..f11abbf1 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -307,6 +307,8 @@ case class CsrRead(that : Data , bitOffset : Int) case class CsrReadToWriteOverride(that : Data, bitOffset : Int) //Used for special cases, as MIP where there shadow stuff case class CsrOnWrite(doThat :() => Unit) case class CsrDuringWrite(doThat :() => Unit) +case class CsrDuringRead(doThat :() => Unit) +case class CsrDuring(doThat :() => Unit) case class CsrOnRead(doThat : () => Unit) case class CsrMapping() extends CsrInterface{ val mapping = mutable.LinkedHashMap[Int,ArrayBuffer[Any]]() @@ -316,7 +318,10 @@ case class CsrMapping() extends CsrInterface{ override def r2w(csrAddress : Int, bitOffset : Int, that : Data): Unit = addMappingAt(csrAddress, CsrReadToWriteOverride(that,bitOffset)) override def onWrite(csrAddress: Int)(body: => Unit): Unit = addMappingAt(csrAddress, CsrOnWrite(() => body)) override def duringWrite(csrAddress: Int)(body: => Unit): Unit = addMappingAt(csrAddress, CsrDuringWrite(() => body)) + override def duringRead(csrAddress: Int)(body: => Unit): Unit = addMappingAt(csrAddress, CsrDuringRead(() => body)) + override def during(csrAddress: Int)(body: => Unit): Unit = addMappingAt(csrAddress, CsrDuring(() => body)) override def onRead(csrAddress: Int)(body: => Unit): Unit = addMappingAt(csrAddress, CsrOnRead(() => {body})) + override def duringAny(): Bool = ??? } @@ -324,6 +329,9 @@ trait CsrInterface{ def onWrite(csrAddress : Int)(doThat : => Unit) : Unit def onRead(csrAddress : Int)(doThat : => Unit) : Unit def duringWrite(csrAddress: Int)(body: => Unit): Unit + def duringRead(csrAddress: Int)(body: => Unit): Unit + def during(csrAddress: Int)(body: => Unit): Unit + def duringAny(): Bool def r(csrAddress : Int, bitOffset : Int, that : Data): Unit def w(csrAddress : Int, bitOffset : Int, that : Data): Unit def rw(csrAddress : Int, bitOffset : Int,that : Data): Unit ={ @@ -380,6 +388,8 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep interface } + + var exceptionPendings : Vec[Bool] = null override def isExceptionPending(stage : Stage): Bool = exceptionPendings(pipeline.stages.indexOf(stage)) @@ -446,6 +456,9 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep override def onWrite(csrAddress: Int)(body: => Unit): Unit = csrMapping.onWrite(csrAddress)(body) override def duringWrite(csrAddress: Int)(body: => Unit): Unit = csrMapping.duringWrite(csrAddress)(body) override def onRead(csrAddress: Int)(body: => Unit): Unit = csrMapping.onRead(csrAddress)(body) + override def duringRead(csrAddress: Int)(body: => Unit): Unit = csrMapping.duringRead(csrAddress)(body) + override def during(csrAddress: Int)(body: => Unit): Unit = csrMapping.during(csrAddress)(body) + override def duringAny(): Bool = pipeline.execute.arbitration.isValid && pipeline.execute.input(IS_CSR) override def setup(pipeline: VexRiscv): Unit = { import pipeline.config._ @@ -1102,6 +1115,8 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep for (element <- jobs) element match { case element : CsrDuringWrite => when(writeInstruction){element.doThat()} + case element : CsrDuringRead => when(readInstruction){element.doThat()} + case element : CsrDuring => {element.doThat()} case _ => } when(writeEnable) { diff --git a/src/main/scala/vexriscv/plugin/FpuPlugin.scala b/src/main/scala/vexriscv/plugin/FpuPlugin.scala index 7b55ef3a..adac48c4 100644 --- a/src/main/scala/vexriscv/plugin/FpuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/FpuPlugin.scala @@ -44,15 +44,42 @@ class FpuPlugin(externalFpu : Boolean = false, override def build(pipeline: VexRiscv): Unit = { import pipeline._ import pipeline.config._ + import Riscv._ val internal = !externalFpu generate pipeline plug new Area{ val fpu = FpuCore(1, p) fpu.io.port(0).cmd << port.cmd fpu.io.port(0).commit << port.commit fpu.io.port(0).rsp >> port.rsp + fpu.io.port(0).completion <> port.completion } + val csr = pipeline plug new Area{ + val pendings = Reg(UInt(5 bits)) init(0) + pendings := pendings + U(port.cmd.fire) - port.completion.count + + val hasPending = pendings =/= 0 + + val flags = Reg(FpuFlags()) + flags.NV init(False) setWhen(port.completion.flag.NV) + flags.DZ init(False) setWhen(port.completion.flag.DZ) + flags.OF init(False) setWhen(port.completion.flag.OF) + flags.UF init(False) setWhen(port.completion.flag.UF) + flags.NX init(False) setWhen(port.completion.flag.NX) + + val service = pipeline.service(classOf[CsrInterface]) + val rm = Reg(Bits(3 bits)) + + service.rw(CSR.FCSR, 5,rm) + service.rw(CSR.FCSR, 0, flags) + service.rw(CSR.FRM, 5,rm) + service.rw(CSR.FFLAGS, 0,flags) + + val csrActive = service.duringAny() + execute.arbitration.haltByOther setWhen(csrActive && hasPending) // pessimistic + } + decode plug new Area{ import decode._ @@ -60,12 +87,12 @@ class FpuPlugin(externalFpu : Boolean = false, val forked = Reg(Bool) setWhen(port.cmd.fire) clearWhen(!arbitration.isStuck) init(False) val i2fReady = Reg(Bool()) setWhen(!arbitration.isStuckByOthers) clearWhen(!arbitration.isStuck) - val i2fHazard = input(FPU_OPCODE) === FpuOpcode.I2F && !i2fReady + val hazard = input(FPU_OPCODE) === FpuOpcode.I2F && !i2fReady || csr.pendings.msb || csr.csrActive - arbitration.haltItself setWhen(arbitration.isValid && i2fHazard) + arbitration.haltItself setWhen(arbitration.isValid && hazard) arbitration.haltItself setWhen(port.cmd.isStall) - port.cmd.valid := arbitration.isValid && input(FPU_ENABLE) && !forked && !i2fHazard + port.cmd.valid := arbitration.isValid && input(FPU_ENABLE) && !forked && !hazard port.cmd.opcode := input(FPU_OPCODE) port.cmd.value := RegNext(output(RS1)) port.cmd.function := 0 From 9f18045329fe5917e438bbf9e1db98ada85c298e Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 19 Jan 2021 16:06:16 +0100 Subject: [PATCH 538/951] fpu add sstatus.fs --- src/main/scala/vexriscv/plugin/FpuPlugin.scala | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/FpuPlugin.scala b/src/main/scala/vexriscv/plugin/FpuPlugin.scala index adac48c4..70b73be2 100644 --- a/src/main/scala/vexriscv/plugin/FpuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/FpuPlugin.scala @@ -71,13 +71,19 @@ class FpuPlugin(externalFpu : Boolean = false, val service = pipeline.service(classOf[CsrInterface]) val rm = Reg(Bits(3 bits)) - service.rw(CSR.FCSR, 5,rm) - service.rw(CSR.FCSR, 0, flags) - service.rw(CSR.FRM, 5,rm) - service.rw(CSR.FFLAGS, 0,flags) + service.rw(CSR.FCSR, 5, rm) + service.rw(CSR.FCSR, 0, flags) + service.rw(CSR.FRM, 5, rm) + service.rw(CSR.FFLAGS, 0, flags) val csrActive = service.duringAny() execute.arbitration.haltByOther setWhen(csrActive && hasPending) // pessimistic + + val fs = Reg(Bits(2 bits)) init(1) + when(hasPending){ + fs := 3 //DIRTY + } + service.rw(CSR.SSTATUS, 13, fs) } decode plug new Area{ @@ -89,7 +95,7 @@ class FpuPlugin(externalFpu : Boolean = false, val i2fReady = Reg(Bool()) setWhen(!arbitration.isStuckByOthers) clearWhen(!arbitration.isStuck) val hazard = input(FPU_OPCODE) === FpuOpcode.I2F && !i2fReady || csr.pendings.msb || csr.csrActive - arbitration.haltItself setWhen(arbitration.isValid && hazard) + arbitration.haltItself setWhen(arbitration.isValid && input(FPU_ENABLE) && hazard) arbitration.haltItself setWhen(port.cmd.isStall) port.cmd.valid := arbitration.isValid && input(FPU_ENABLE) && !forked && !hazard From 11349a71fac176dcc8c3a00b37a7ee8a85247237 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 19 Jan 2021 17:57:41 +0100 Subject: [PATCH 539/951] fpu FpuPlugin now implement all instructions. Remains the FPuCore to implement cmd.arg and floating point corner cases --- src/main/scala/vexriscv/ip/fpu/FpuCore.scala | 7 +- .../scala/vexriscv/ip/fpu/Interface.scala | 4 +- .../scala/vexriscv/plugin/FpuPlugin.scala | 92 +++++++++++++++++-- 3 files changed, 89 insertions(+), 14 deletions(-) diff --git a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala index 56c0fab2..047eaa34 100644 --- a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala +++ b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala @@ -185,7 +185,8 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ is(p.Opcode.CMP) { useRs1 := True; useRs2 := True } is(p.Opcode.SGNJ) { useRd := True; useRs1 := True; useRs2 := True } is(p.Opcode.FMV_X_W) { useRs1 := True } - is(p.Opcode.FMV_W_X) { useRd := True} + is(p.Opcode.FMV_W_X) { useRd := True } + is(p.Opcode.FCLASS ) { useRs1 := True } } val hits = List((useRs1, s0.rs1), (useRs2, s0.rs2), (useRs3, s0.rs3), (useRd, s0.rd)).map{case (use, reg) => use && rf.lock.map(l => l.valid && l.source === s0.source && l.address === reg).orR} @@ -230,7 +231,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ input.ready setWhen(loadHit && load.ready) load.payload.assignSomeByName(read.output.payload) - val shortPipHit = List(FpuOpcode.STORE, FpuOpcode.F2I, FpuOpcode.CMP, FpuOpcode.I2F, FpuOpcode.MIN_MAX, FpuOpcode.SGNJ, FpuOpcode.FMV_X_W, FpuOpcode.FMV_W_X).map(input.opcode === _).orR + val shortPipHit = List(FpuOpcode.STORE, FpuOpcode.F2I, FpuOpcode.CMP, FpuOpcode.I2F, FpuOpcode.MIN_MAX, FpuOpcode.SGNJ, FpuOpcode.FMV_X_W, FpuOpcode.FMV_W_X, FpuOpcode.FCLASS).map(input.opcode === _).orR val shortPip = Stream(ShortPipInput()) input.ready setWhen(shortPipHit && shortPip.ready) shortPip.valid := input.valid && shortPipHit @@ -317,12 +318,14 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val minMaxResult = rs1Smaller ? input.rs1 | input.rs2 val cmpResult = B(rs1Smaller) + val fclassResult = B(0) //TODO switch(input.opcode){ is(FpuOpcode.STORE) { result := storeResult } is(FpuOpcode.F2I) { result := f2iResult } is(FpuOpcode.CMP) { result := cmpResult.resized } //TODO is(FpuOpcode.FMV_X_W) { result := input.rs1.asBits } //TODO + is(FpuOpcode.FCLASS) { result := fclassResult.resized } } val toFpuRf = List(FpuOpcode.MIN_MAX, FpuOpcode.I2F, FpuOpcode.SGNJ, FpuOpcode.FMV_W_X).map(input.opcode === _).orR diff --git a/src/main/scala/vexriscv/ip/fpu/Interface.scala b/src/main/scala/vexriscv/ip/fpu/Interface.scala index 255f9cbb..1a0405d5 100644 --- a/src/main/scala/vexriscv/ip/fpu/Interface.scala +++ b/src/main/scala/vexriscv/ip/fpu/Interface.scala @@ -31,7 +31,7 @@ case class FpuFloat(exponentSize: Int, } object FpuOpcode extends SpinalEnum{ - val LOAD, STORE, MUL, ADD, FMA, I2F, F2I, CMP, DIV, SQRT, MIN_MAX, SGNJ, FMV_X_W, FMV_W_X = newElement() + val LOAD, STORE, MUL, ADD, FMA, I2F, F2I, CMP, DIV, SQRT, MIN_MAX, SGNJ, FMV_X_W, FMV_W_X, FCLASS = newElement() } object FpuFormat extends SpinalEnum{ @@ -64,7 +64,7 @@ case class FpuCompletion() extends Bundle{ case class FpuCmd(p : FpuParameter) extends Bundle{ val opcode = p.Opcode() val value = Bits(32 bits) // Int to float - val function = Bits(3 bits) // Int to float + val arg = Bits(2 bits) val rs1, rs2, rs3 = p.rfAddress() val rd = p.rfAddress() val format = p.Format() diff --git a/src/main/scala/vexriscv/plugin/FpuPlugin.scala b/src/main/scala/vexriscv/plugin/FpuPlugin.scala index 70b73be2..b19fa825 100644 --- a/src/main/scala/vexriscv/plugin/FpuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/FpuPlugin.scala @@ -13,24 +13,96 @@ class FpuPlugin(externalFpu : Boolean = false, object FPU_COMMIT extends Stageable(Bool()) object FPU_LOAD extends Stageable(Bool()) object FPU_RSP extends Stageable(Bool()) - object FPU_ALU extends Stageable(Bool()) object FPU_FORKED extends Stageable(Bool()) object FPU_OPCODE extends Stageable(FpuOpcode()) + object FPU_ARG extends Stageable(Bits(2 bits)) var port : FpuPort = null override def setup(pipeline: VexRiscv): Unit = { import pipeline.config._ + type ENC = (Stageable[_ <: BaseType],Any) + + val intRfWrite = List[ENC]( + FPU_ENABLE -> True, + FPU_COMMIT -> False, + FPU_RSP -> True, + FPU_LOAD -> False, + REGFILE_WRITE_VALID -> True, + BYPASSABLE_EXECUTE_STAGE -> False, + BYPASSABLE_MEMORY_STAGE -> False + ) + + val floatRfWrite = List[ENC]( + FPU_ENABLE -> True, + FPU_COMMIT -> True, + FPU_RSP -> False, + FPU_LOAD -> False + ) + + val addSub = floatRfWrite :+ FPU_OPCODE -> FpuOpcode.ADD + val mul = floatRfWrite :+ FPU_OPCODE -> FpuOpcode.MUL + val fma = floatRfWrite :+ FPU_OPCODE -> FpuOpcode.FMA + val div = floatRfWrite :+ FPU_OPCODE -> FpuOpcode.DIV + val sqrt = floatRfWrite :+ FPU_OPCODE -> FpuOpcode.SQRT + val fsgnj = floatRfWrite :+ FPU_OPCODE -> FpuOpcode.SGNJ + val fminMax = floatRfWrite :+ FPU_OPCODE -> FpuOpcode.MIN_MAX + val fmvWx = floatRfWrite :+ FPU_OPCODE -> FpuOpcode.FMV_W_X :+ RS1_USE -> True + val fcvtI2f = floatRfWrite :+ FPU_OPCODE -> FpuOpcode.I2F :+ RS1_USE -> True + + val fcmp = intRfWrite :+ FPU_OPCODE -> FpuOpcode.CMP + val fclass = intRfWrite :+ FPU_OPCODE -> FpuOpcode.FCLASS + val fmvXw = intRfWrite :+ FPU_OPCODE -> FpuOpcode.FMV_X_W + val fcvtF2i = intRfWrite :+ FPU_OPCODE -> FpuOpcode.F2I + + val fl = List[ENC]( + FPU_ENABLE -> True, + FPU_OPCODE -> FpuOpcode.LOAD, + FPU_COMMIT -> True, + FPU_LOAD -> True, + FPU_RSP -> False + ) + + val fs = List[ENC]( + FPU_ENABLE -> True, + FPU_OPCODE -> FpuOpcode.STORE, + FPU_COMMIT -> False, + FPU_LOAD -> False, + FPU_RSP -> True + ) + + + def arg(v : Int) = FPU_ARG -> U(v, 2 bits) val decoderService = pipeline.service(classOf[DecoderService]) decoderService.addDefault(FPU_ENABLE, False) decoderService.add(List( - FADD_S -> List(FPU_ENABLE -> True, FPU_OPCODE -> FpuOpcode.ADD, FPU_COMMIT -> True, FPU_ALU -> True , FPU_LOAD -> False, FPU_RSP -> False), - FLW -> List(FPU_ENABLE -> True, FPU_OPCODE -> FpuOpcode.LOAD, FPU_COMMIT -> True, FPU_ALU -> False, FPU_LOAD -> True , FPU_RSP -> False), - FCVT_S_WU -> List(FPU_ENABLE -> True, FPU_OPCODE -> FpuOpcode.I2F , FPU_COMMIT -> True , FPU_ALU -> True, FPU_LOAD -> False, FPU_RSP -> False, RS1_USE -> True), - FSW -> List(FPU_ENABLE -> True, FPU_OPCODE -> FpuOpcode.STORE, FPU_COMMIT -> False, FPU_ALU -> False, FPU_LOAD -> False, FPU_RSP -> True), - FCVT_WU_S -> List(FPU_ENABLE -> True, FPU_OPCODE -> FpuOpcode.F2I , FPU_COMMIT -> False, FPU_ALU -> False, FPU_LOAD -> False, FPU_RSP -> True, REGFILE_WRITE_VALID -> True, BYPASSABLE_EXECUTE_STAGE -> False, BYPASSABLE_MEMORY_STAGE -> False), - FLE_S -> List(FPU_ENABLE -> True, FPU_OPCODE -> FpuOpcode.CMP , FPU_COMMIT -> False, FPU_ALU -> False, FPU_LOAD -> False, FPU_RSP -> True, REGFILE_WRITE_VALID -> True, BYPASSABLE_EXECUTE_STAGE -> False, BYPASSABLE_MEMORY_STAGE -> False) + FADD_S -> (addSub :+ arg(0)), + FSUB_S -> (addSub :+ arg(1)), + FMADD_S -> (fma :+ arg(0)), + FMSUB_S -> (fma :+ arg(1)), + FNMSUB_S -> (fma :+ arg(2)), + FNMADD_S -> (fma :+ arg(3)), + FMUL_S -> (mul), + FDIV_S -> (div), + FSQRT_S -> (sqrt), + FLW -> (fl), + FSW -> (fs), + FCVT_S_WU -> (fcvtI2f :+ arg(0)), + FCVT_S_W -> (fcvtI2f :+ arg(1)), + FCVT_WU_S -> (fcvtF2i :+ arg(0)), + FCVT_W_S -> (fcvtF2i :+ arg(1)), + FCLASS_S -> (fclass), + FLE_S -> (fcmp :+ arg(0)), + FEQ_S -> (fcmp :+ arg(1)), + FLT_S -> (fcmp :+ arg(2)), + FSGNJ_S -> (fsgnj :+ arg(0)), + FSGNJN_S -> (fsgnj :+ arg(1)), + FSGNJX_S -> (fsgnj :+ arg(2)), + FMIN_S -> (fminMax :+ arg(0)), + FMAX_S -> (fminMax :+ arg(1)), + FMV_X_W -> (fmvXw), + FMV_W_X -> (fmvWx) )) port = FpuPort(p) @@ -92,8 +164,8 @@ class FpuPlugin(externalFpu : Boolean = false, //Maybe it might be better to not fork before fire to avoid RF stall on commits val forked = Reg(Bool) setWhen(port.cmd.fire) clearWhen(!arbitration.isStuck) init(False) - val i2fReady = Reg(Bool()) setWhen(!arbitration.isStuckByOthers) clearWhen(!arbitration.isStuck) - val hazard = input(FPU_OPCODE) === FpuOpcode.I2F && !i2fReady || csr.pendings.msb || csr.csrActive + val intRfReady = Reg(Bool()) setWhen(!arbitration.isStuckByOthers) clearWhen(!arbitration.isStuck) + val hazard = (input(RS1_USE) && !intRfReady) || csr.pendings.msb || csr.csrActive arbitration.haltItself setWhen(arbitration.isValid && input(FPU_ENABLE) && hazard) arbitration.haltItself setWhen(port.cmd.isStall) @@ -101,7 +173,7 @@ class FpuPlugin(externalFpu : Boolean = false, port.cmd.valid := arbitration.isValid && input(FPU_ENABLE) && !forked && !hazard port.cmd.opcode := input(FPU_OPCODE) port.cmd.value := RegNext(output(RS1)) - port.cmd.function := 0 + port.cmd.arg := input(FPU_ARG) port.cmd.rs1 := input(INSTRUCTION)(rs1Range).asUInt port.cmd.rs2 := input(INSTRUCTION)(rs2Range).asUInt port.cmd.rs3 := input(INSTRUCTION)(rs3Range).asUInt From 828ea960067076055294e24c9afe76aa597fa796 Mon Sep 17 00:00:00 2001 From: Samuel Lindemer Date: Wed, 20 Jan 2021 09:27:35 +0100 Subject: [PATCH 540/951] PMP registers are now WARL --- .../scala/vexriscv/plugin/PmpPlugin.scala | 126 ++++--- src/test/cpp/raw/pmp/build/pmp.asm | 314 +++++++++--------- src/test/cpp/raw/pmp/build/pmp.elf | Bin 5436 -> 5468 bytes src/test/cpp/raw/pmp/build/pmp.hex | 78 ++--- src/test/cpp/raw/pmp/build/pmp.map | 12 +- src/test/cpp/raw/pmp/src/crt.S | 8 + 6 files changed, 293 insertions(+), 245 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/PmpPlugin.scala b/src/main/scala/vexriscv/plugin/PmpPlugin.scala index 88be675c..5f008b41 100644 --- a/src/main/scala/vexriscv/plugin/PmpPlugin.scala +++ b/src/main/scala/vexriscv/plugin/PmpPlugin.scala @@ -70,61 +70,78 @@ case class PmpRegister(previous : PmpRegister) extends Area { def NA4 = 2 def NAPOT = 3 - // Software-accessible CSR interface - val csr = new Area { + val state = new Area { val r, w, x = Reg(Bool) val l = RegInit(False) val a = Reg(UInt(2 bits)) init(0) val addr = Reg(UInt(32 bits)) } - // Active region bounds and permissions (internal) + // CSR writes connect to these signals rather than the internal state + // registers. This makes locking and WARL possible. + val csr = new Area { + val r, w, x = Bool + val l = Bool + val a = UInt(2 bits) + val addr = UInt(32 bits) + } + + // Last assignment wins; nothing happens if a user-initiated write did not + // occur on this clock cycle. + csr.r := state.r + csr.w := state.w + csr.x := state.x + csr.l := state.l + csr.a := state.a + csr.addr := state.addr + + // Computed PMP region bounds val region = new Area { - val r, w, x = Reg(Bool) - val l, valid = RegInit(False) + val valid = Bool val start, end = Reg(UInt(32 bits)) } - - when(~region.l) { - region.r := csr.r - region.w := csr.w - region.x := csr.x - region.l := csr.l - val shifted = csr.addr |<< 2 - region.valid := True + when(~state.l) { + state.r := csr.r + state.w := csr.w + state.x := csr.x + state.l := csr.l + state.a := csr.a + state.addr := csr.addr - switch(csr.a) { + if (csr.l == True & csr.a == TOR) { + previous.state.l := True + } + } - is(TOR) { - if (previous == null) { - region.start := 0 - } else { - region.start := previous.region.end - } - if (csr.l == True) { - previous.region.l := True - } - region.end := shifted + val shifted = csr.addr |<< 2 + region.valid := True + + switch(state.a) { + is(TOR) { + if (previous == null) { + region.start := 0 + } else { + region.start := previous.region.end } + region.end := shifted + } - is(NA4) { - region.start := shifted - region.end := shifted + 4 - } + is(NA4) { + region.start := shifted + region.end := shifted + 4 + } - is(NAPOT) { - val mask = csr.addr & ~(csr.addr + 1) - val masked = (csr.addr & ~mask) |<< 2 - region.start := masked - region.end := masked + ((mask + 1) |<< 3) - } - - default { - region.end := shifted - region.valid := False - } + is(NAPOT) { + val mask = state.addr & ~(state.addr + 1) + val masked = (state.addr & ~mask) |<< 2 + region.start := masked + region.end := masked + ((mask + 1) |<< 3) + } + default { + region.end := shifted + region.valid := False } } } @@ -162,12 +179,25 @@ class PmpPlugin(regions : Int, ioRange : UInt => Bool) extends Plugin[VexRiscv] } else { pmps += PmpRegister(pmps.last) } - csrService.rw(0x3b0 + i, pmps(i).csr.addr) + csrService.r(0x3b0 + i, pmps(i).state.addr) + csrService.w(0x3b0 + i, pmps(i).csr.addr) } // Instantiate pmpcfg0 ... pmpcfg# CSRs. for (i <- 0 until (regions / 4)) { - csrService.rw(0x3a0 + i, + csrService.r(0x3a0 + i, + 31 -> pmps((i * 4) + 3).state.l, 23 -> pmps((i * 4) + 2).state.l, + 15 -> pmps((i * 4) + 1).state.l, 7 -> pmps((i * 4) ).state.l, + 27 -> pmps((i * 4) + 3).state.a, 26 -> pmps((i * 4) + 3).state.x, + 25 -> pmps((i * 4) + 3).state.w, 24 -> pmps((i * 4) + 3).state.r, + 19 -> pmps((i * 4) + 2).state.a, 18 -> pmps((i * 4) + 2).state.x, + 17 -> pmps((i * 4) + 2).state.w, 16 -> pmps((i * 4) + 2).state.r, + 11 -> pmps((i * 4) + 1).state.a, 10 -> pmps((i * 4) + 1).state.x, + 9 -> pmps((i * 4) + 1).state.w, 8 -> pmps((i * 4) + 1).state.r, + 3 -> pmps((i * 4) ).state.a, 2 -> pmps((i * 4) ).state.x, + 1 -> pmps((i * 4) ).state.w, 0 -> pmps((i * 4) ).state.r + ) + csrService.w(0x3a0 + i, 31 -> pmps((i * 4) + 3).csr.l, 23 -> pmps((i * 4) + 2).csr.l, 15 -> pmps((i * 4) + 1).csr.l, 7 -> pmps((i * 4) ).csr.l, 27 -> pmps((i * 4) + 3).csr.a, 26 -> pmps((i * 4) + 3).csr.x, @@ -188,10 +218,10 @@ class PmpPlugin(regions : Int, ioRange : UInt => Bool) extends Plugin[VexRiscv] port.bus.rsp.physicalAddress := address // Only the first matching PMP region applies. - val hits = pmps.map(pmp => pmp.region.valid && - pmp.region.start <= address && - pmp.region.end > address && - (pmp.region.l || ~privilegeService.isMachine())) + val hits = pmps.map(pmp => pmp.region.valid & + pmp.region.start <= address & + pmp.region.end > address & + (pmp.state.l | ~privilegeService.isMachine())) // M-mode has full access by default, others have none. when(CountOne(hits) === 0) { @@ -199,9 +229,9 @@ class PmpPlugin(regions : Int, ioRange : UInt => Bool) extends Plugin[VexRiscv] port.bus.rsp.allowWrite := privilegeService.isMachine() port.bus.rsp.allowExecute := privilegeService.isMachine() } otherwise { - port.bus.rsp.allowRead := MuxOH(OHMasking.first(hits), pmps.map(_.region.r)) - port.bus.rsp.allowWrite := MuxOH(OHMasking.first(hits), pmps.map(_.region.w)) - port.bus.rsp.allowExecute := MuxOH(OHMasking.first(hits), pmps.map(_.region.x)) + port.bus.rsp.allowRead := MuxOH(OHMasking.first(hits), pmps.map(_.state.r)) + port.bus.rsp.allowWrite := MuxOH(OHMasking.first(hits), pmps.map(_.state.w)) + port.bus.rsp.allowExecute := MuxOH(OHMasking.first(hits), pmps.map(_.state.x)) } port.bus.rsp.isIoAccess := ioRange(port.bus.rsp.physicalAddress) diff --git a/src/test/cpp/raw/pmp/build/pmp.asm b/src/test/cpp/raw/pmp/build/pmp.asm index 294e964c..5c7605b6 100644 --- a/src/test/cpp/raw/pmp/build/pmp.asm +++ b/src/test/cpp/raw/pmp/build/pmp.asm @@ -17,176 +17,184 @@ Disassembly of section .crt_section: 80000018 : 80000018: 00000e13 li t3,0 8000001c: 00000f17 auipc t5,0x0 -80000020: 250f0f13 addi t5,t5,592 # 8000026c +80000020: 270f0f13 addi t5,t5,624 # 8000028c 80000024: 800000b7 lui ra,0x80000 80000028: 80008237 lui tp,0x80008 8000002c: deadc137 lui sp,0xdeadc -80000030: eef10113 addi sp,sp,-273 # deadbeef -80000034: 0020a023 sw sp,0(ra) # 80000000 -80000038: 00222023 sw sp,0(tp) # 80008000 +80000030: eef10113 addi sp,sp,-273 # deadbeef +80000034: 0020a023 sw sp,0(ra) # 80000000 +80000038: 00222023 sw sp,0(tp) # 80008000 8000003c: 0000a183 lw gp,0(ra) -80000040: 22311663 bne sp,gp,8000026c +80000040: 24311663 bne sp,gp,8000028c 80000044: 00022183 lw gp,0(tp) # 0 <_start-0x80000000> -80000048: 22311263 bne sp,gp,8000026c +80000048: 24311263 bne sp,gp,8000028c 8000004c: 071202b7 lui t0,0x7120 80000050: 3a029073 csrw pmpcfg0,t0 -80000054: 191f02b7 lui t0,0x191f0 -80000058: 30428293 addi t0,t0,772 # 191f0304 <_start-0x66e0fcfc> -8000005c: 3a129073 csrw pmpcfg1,t0 -80000060: 000f02b7 lui t0,0xf0 -80000064: 50628293 addi t0,t0,1286 # f0506 <_start-0x7ff0fafa> -80000068: 3a229073 csrw pmpcfg2,t0 -8000006c: 0f1e22b7 lui t0,0xf1e2 -80000070: 90028293 addi t0,t0,-1792 # f1e1900 <_start-0x70e1e700> -80000074: 3a329073 csrw pmpcfg3,t0 -80000078: 200002b7 lui t0,0x20000 -8000007c: 3b029073 csrw pmpaddr0,t0 -80000080: fff00293 li t0,-1 -80000084: 3b129073 csrw pmpaddr1,t0 -80000088: 200022b7 lui t0,0x20002 -8000008c: 3b229073 csrw pmpaddr2,t0 -80000090: 200042b7 lui t0,0x20004 -80000094: fff28293 addi t0,t0,-1 # 20003fff <_start-0x5fffc001> -80000098: 3b329073 csrw pmpaddr3,t0 -8000009c: 200042b7 lui t0,0x20004 -800000a0: fff28293 addi t0,t0,-1 # 20003fff <_start-0x5fffc001> -800000a4: 3b429073 csrw pmpaddr4,t0 -800000a8: 200042b7 lui t0,0x20004 -800000ac: fff28293 addi t0,t0,-1 # 20003fff <_start-0x5fffc001> -800000b0: 3b529073 csrw pmpaddr5,t0 -800000b4: 200022b7 lui t0,0x20002 -800000b8: fff28293 addi t0,t0,-1 # 20001fff <_start-0x5fffe001> -800000bc: 3b629073 csrw pmpaddr6,t0 -800000c0: 200062b7 lui t0,0x20006 -800000c4: fff28293 addi t0,t0,-1 # 20005fff <_start-0x5fffa001> -800000c8: 3b729073 csrw pmpaddr7,t0 -800000cc: 2000c2b7 lui t0,0x2000c -800000d0: 3b829073 csrw pmpaddr8,t0 -800000d4: 2000d2b7 lui t0,0x2000d -800000d8: 3b929073 csrw pmpaddr9,t0 -800000dc: fff00293 li t0,-1 -800000e0: 3ba29073 csrw pmpaddr10,t0 -800000e4: 00000293 li t0,0 -800000e8: 3bb29073 csrw pmpaddr11,t0 -800000ec: 00000293 li t0,0 -800000f0: 3bc29073 csrw pmpaddr12,t0 +80000054: 3a002373 csrr t1,pmpcfg0 +80000058: 22629a63 bne t0,t1,8000028c +8000005c: 191f02b7 lui t0,0x191f0 +80000060: 30428293 addi t0,t0,772 # 191f0304 <_start-0x66e0fcfc> +80000064: 3a129073 csrw pmpcfg1,t0 +80000068: 000f02b7 lui t0,0xf0 +8000006c: 50628293 addi t0,t0,1286 # f0506 <_start-0x7ff0fafa> +80000070: 3a229073 csrw pmpcfg2,t0 +80000074: 0f1e22b7 lui t0,0xf1e2 +80000078: 90028293 addi t0,t0,-1792 # f1e1900 <_start-0x70e1e700> +8000007c: 3a329073 csrw pmpcfg3,t0 +80000080: 200002b7 lui t0,0x20000 +80000084: 3b029073 csrw pmpaddr0,t0 +80000088: 3b002373 csrr t1,pmpaddr0 +8000008c: 20629063 bne t0,t1,8000028c +80000090: fff00293 li t0,-1 +80000094: 3b129073 csrw pmpaddr1,t0 +80000098: 200022b7 lui t0,0x20002 +8000009c: 3b229073 csrw pmpaddr2,t0 +800000a0: 200042b7 lui t0,0x20004 +800000a4: fff28293 addi t0,t0,-1 # 20003fff <_start-0x5fffc001> +800000a8: 3b329073 csrw pmpaddr3,t0 +800000ac: 200042b7 lui t0,0x20004 +800000b0: fff28293 addi t0,t0,-1 # 20003fff <_start-0x5fffc001> +800000b4: 3b429073 csrw pmpaddr4,t0 +800000b8: 200042b7 lui t0,0x20004 +800000bc: fff28293 addi t0,t0,-1 # 20003fff <_start-0x5fffc001> +800000c0: 3b529073 csrw pmpaddr5,t0 +800000c4: 200022b7 lui t0,0x20002 +800000c8: fff28293 addi t0,t0,-1 # 20001fff <_start-0x5fffe001> +800000cc: 3b629073 csrw pmpaddr6,t0 +800000d0: 200062b7 lui t0,0x20006 +800000d4: fff28293 addi t0,t0,-1 # 20005fff <_start-0x5fffa001> +800000d8: 3b729073 csrw pmpaddr7,t0 +800000dc: 2000c2b7 lui t0,0x2000c +800000e0: 3b829073 csrw pmpaddr8,t0 +800000e4: 2000d2b7 lui t0,0x2000d +800000e8: 3b929073 csrw pmpaddr9,t0 +800000ec: fff00293 li t0,-1 +800000f0: 3ba29073 csrw pmpaddr10,t0 800000f4: 00000293 li t0,0 -800000f8: 3bd29073 csrw pmpaddr13,t0 +800000f8: 3bb29073 csrw pmpaddr11,t0 800000fc: 00000293 li t0,0 -80000100: 3be29073 csrw pmpaddr14,t0 +80000100: 3bc29073 csrw pmpaddr12,t0 80000104: 00000293 li t0,0 -80000108: 3bf29073 csrw pmpaddr15,t0 -8000010c: 00c10137 lui sp,0xc10 -80000110: fee10113 addi sp,sp,-18 # c0ffee <_start-0x7f3f0012> -80000114: 0020a023 sw sp,0(ra) -80000118: 00222023 sw sp,0(tp) # 0 <_start-0x80000000> -8000011c: 0000a183 lw gp,0(ra) -80000120: 14311663 bne sp,gp,8000026c -80000124: 00000193 li gp,0 -80000128: 00022183 lw gp,0(tp) # 0 <_start-0x80000000> -8000012c: 14311063 bne sp,gp,8000026c +80000108: 3bd29073 csrw pmpaddr13,t0 +8000010c: 00000293 li t0,0 +80000110: 3be29073 csrw pmpaddr14,t0 +80000114: 00000293 li t0,0 +80000118: 3bf29073 csrw pmpaddr15,t0 +8000011c: 00c10137 lui sp,0xc10 +80000120: fee10113 addi sp,sp,-18 # c0ffee <_start-0x7f3f0012> +80000124: 0020a023 sw sp,0(ra) +80000128: 00222023 sw sp,0(tp) # 0 <_start-0x80000000> +8000012c: 0000a183 lw gp,0(ra) +80000130: 14311e63 bne sp,gp,8000028c +80000134: 00000193 li gp,0 +80000138: 00022183 lw gp,0(tp) # 0 <_start-0x80000000> +8000013c: 14311863 bne sp,gp,8000028c -80000130 : -80000130: 00100e13 li t3,1 -80000134: 00000f17 auipc t5,0x0 -80000138: 138f0f13 addi t5,t5,312 # 8000026c -8000013c: 079212b7 lui t0,0x7921 -80000140: 80828293 addi t0,t0,-2040 # 7920808 <_start-0x786df7f8> -80000144: 3a029073 csrw pmpcfg0,t0 -80000148: 800080b7 lui ra,0x80008 -8000014c: deadc137 lui sp,0xdeadc -80000150: eef10113 addi sp,sp,-273 # deadbeef -80000154: 0020a023 sw sp,0(ra) # 80008000 -80000158: 00000f17 auipc t5,0x0 -8000015c: 010f0f13 addi t5,t5,16 # 80000168 -80000160: 0000a183 lw gp,0(ra) -80000164: 1080006f j 8000026c +80000140 : +80000140: 00100e13 li t3,1 +80000144: 00000f17 auipc t5,0x0 +80000148: 148f0f13 addi t5,t5,328 # 8000028c +8000014c: 079212b7 lui t0,0x7921 +80000150: 80828293 addi t0,t0,-2040 # 7920808 <_start-0x786df7f8> +80000154: 3a029073 csrw pmpcfg0,t0 +80000158: 3a002373 csrr t1,pmpcfg0 +8000015c: 12629863 bne t0,t1,8000028c +80000160: 800080b7 lui ra,0x80008 +80000164: deadc137 lui sp,0xdeadc +80000168: eef10113 addi sp,sp,-273 # deadbeef +8000016c: 0020a023 sw sp,0(ra) # 80008000 +80000170: 00000f17 auipc t5,0x0 +80000174: 010f0f13 addi t5,t5,16 # 80000180 +80000178: 0000a183 lw gp,0(ra) +8000017c: 1100006f j 8000028c -80000168 : -80000168: 00200e13 li t3,2 -8000016c: 00000f17 auipc t5,0x0 -80000170: 100f0f13 addi t5,t5,256 # 8000026c -80000174: 071202b7 lui t0,0x7120 -80000178: 3a029073 csrw pmpcfg0,t0 -8000017c: 800080b7 lui ra,0x80008 -80000180: deadc137 lui sp,0xdeadc -80000184: eef10113 addi sp,sp,-273 # deadbeef -80000188: 0020a023 sw sp,0(ra) # 80008000 -8000018c: 00000f17 auipc t5,0x0 -80000190: 010f0f13 addi t5,t5,16 # 8000019c -80000194: 0000a183 lw gp,0(ra) -80000198: 0d40006f j 8000026c +80000180 : +80000180: 00200e13 li t3,2 +80000184: 00000f17 auipc t5,0x0 +80000188: 108f0f13 addi t5,t5,264 # 8000028c +8000018c: 071202b7 lui t0,0x7120 +80000190: 3a029073 csrw pmpcfg0,t0 +80000194: 3a002373 csrr t1,pmpcfg0 +80000198: 0e628a63 beq t0,t1,8000028c +8000019c: 800080b7 lui ra,0x80008 +800001a0: deadc137 lui sp,0xdeadc +800001a4: eef10113 addi sp,sp,-273 # deadbeef +800001a8: 0020a023 sw sp,0(ra) # 80008000 +800001ac: 00000f17 auipc t5,0x0 +800001b0: 010f0f13 addi t5,t5,16 # 800001bc +800001b4: 0000a183 lw gp,0(ra) +800001b8: 0d40006f j 8000028c -8000019c : -8000019c: 00300e13 li t3,3 -800001a0: 00000f17 auipc t5,0x0 -800001a4: 0ccf0f13 addi t5,t5,204 # 8000026c -800001a8: 00000117 auipc sp,0x0 -800001ac: 01010113 addi sp,sp,16 # 800001b8 -800001b0: 34111073 csrw mepc,sp -800001b4: 30200073 mret +800001bc : +800001bc: 00300e13 li t3,3 +800001c0: 00000f17 auipc t5,0x0 +800001c4: 0ccf0f13 addi t5,t5,204 # 8000028c +800001c8: 00000117 auipc sp,0x0 +800001cc: 01010113 addi sp,sp,16 # 800001d8 +800001d0: 34111073 csrw mepc,sp +800001d4: 30200073 mret -800001b8 : -800001b8: 00400e13 li t3,4 -800001bc: 00000f17 auipc t5,0x0 -800001c0: 0b0f0f13 addi t5,t5,176 # 8000026c -800001c4: deadc137 lui sp,0xdeadc -800001c8: eef10113 addi sp,sp,-273 # deadbeef -800001cc: 800080b7 lui ra,0x80008 -800001d0: 0020a023 sw sp,0(ra) # 80008000 -800001d4: 00000f17 auipc t5,0x0 -800001d8: 010f0f13 addi t5,t5,16 # 800001e4 -800001dc: 0000a183 lw gp,0(ra) -800001e0: 08c0006f j 8000026c +800001d8 : +800001d8: 00400e13 li t3,4 +800001dc: 00000f17 auipc t5,0x0 +800001e0: 0b0f0f13 addi t5,t5,176 # 8000028c +800001e4: deadc137 lui sp,0xdeadc +800001e8: eef10113 addi sp,sp,-273 # deadbeef +800001ec: 800080b7 lui ra,0x80008 +800001f0: 0020a023 sw sp,0(ra) # 80008000 +800001f4: 00000f17 auipc t5,0x0 +800001f8: 010f0f13 addi t5,t5,16 # 80000204 +800001fc: 0000a183 lw gp,0(ra) +80000200: 08c0006f j 8000028c -800001e4 : -800001e4: 00500e13 li t3,5 -800001e8: deadc137 lui sp,0xdeadc -800001ec: eef10113 addi sp,sp,-273 # deadbeef -800001f0: 800000b7 lui ra,0x80000 -800001f4: 0020a023 sw sp,0(ra) # 80000000 -800001f8: 0000a183 lw gp,0(ra) -800001fc: 06311863 bne sp,gp,8000026c +80000204 : +80000204: 00500e13 li t3,5 +80000208: deadc137 lui sp,0xdeadc +8000020c: eef10113 addi sp,sp,-273 # deadbeef +80000210: 800000b7 lui ra,0x80000 +80000214: 0020a023 sw sp,0(ra) # 80000000 +80000218: 0000a183 lw gp,0(ra) +8000021c: 06311863 bne sp,gp,8000028c -80000200 : -80000200: 00600e13 li t3,6 -80000204: 800100b7 lui ra,0x80010 -80000208: 0000a183 lw gp,0(ra) # 80010000 -8000020c: 00000f17 auipc t5,0x0 -80000210: 06cf0f13 addi t5,t5,108 # 80000278 -80000214: 0030a023 sw gp,0(ra) -80000218: 0540006f j 8000026c +80000220 : +80000220: 00600e13 li t3,6 +80000224: 800100b7 lui ra,0x80010 +80000228: 0000a183 lw gp,0(ra) # 80010000 +8000022c: 00000f17 auipc t5,0x0 +80000230: 06cf0f13 addi t5,t5,108 # 80000298 +80000234: 0030a023 sw gp,0(ra) +80000238: 0540006f j 8000028c -8000021c : -8000021c: 00700e13 li t3,7 -80000220: 00000f17 auipc t5,0x0 -80000224: 04cf0f13 addi t5,t5,76 # 8000026c -80000228: deadc137 lui sp,0xdeadc -8000022c: eef10113 addi sp,sp,-273 # deadbeef -80000230: 800300b7 lui ra,0x80030 -80000234: ff808093 addi ra,ra,-8 # 8002fff8 -80000238: 00222023 sw sp,0(tp) # 0 <_start-0x80000000> -8000023c: 00000f17 auipc t5,0x0 -80000240: fa8f0f13 addi t5,t5,-88 # 800001e4 -80000244: 00022183 lw gp,0(tp) # 0 <_start-0x80000000> -80000248: 0240006f j 8000026c - -8000024c : -8000024c: 00800e13 li t3,8 -80000250: 800400b7 lui ra,0x80040 -80000254: ff808093 addi ra,ra,-8 # 8003fff8 -80000258: 0000a183 lw gp,0(ra) +8000023c : +8000023c: 00700e13 li t3,7 +80000240: 00000f17 auipc t5,0x0 +80000244: 04cf0f13 addi t5,t5,76 # 8000028c +80000248: deadc137 lui sp,0xdeadc +8000024c: eef10113 addi sp,sp,-273 # deadbeef +80000250: 800300b7 lui ra,0x80030 +80000254: ff808093 addi ra,ra,-8 # 8002fff8 +80000258: 00222023 sw sp,0(tp) # 0 <_start-0x80000000> 8000025c: 00000f17 auipc t5,0x0 -80000260: 01cf0f13 addi t5,t5,28 # 80000278 -80000264: 0030a023 sw gp,0(ra) -80000268: 0040006f j 8000026c +80000260: fa8f0f13 addi t5,t5,-88 # 80000204 +80000264: 00022183 lw gp,0(tp) # 0 <_start-0x80000000> +80000268: 0240006f j 8000028c -8000026c : -8000026c: f0100137 lui sp,0xf0100 -80000270: f2410113 addi sp,sp,-220 # f00fff24 -80000274: 01c12023 sw t3,0(sp) +8000026c : +8000026c: 00800e13 li t3,8 +80000270: 800400b7 lui ra,0x80040 +80000274: ff808093 addi ra,ra,-8 # 8003fff8 +80000278: 0000a183 lw gp,0(ra) +8000027c: 00000f17 auipc t5,0x0 +80000280: 01cf0f13 addi t5,t5,28 # 80000298 +80000284: 0030a023 sw gp,0(ra) +80000288: 0040006f j 8000028c -80000278 : -80000278: f0100137 lui sp,0xf0100 -8000027c: f2010113 addi sp,sp,-224 # f00fff20 -80000280: 00012023 sw zero,0(sp) +8000028c : +8000028c: f0100137 lui sp,0xf0100 +80000290: f2410113 addi sp,sp,-220 # f00fff24 +80000294: 01c12023 sw t3,0(sp) + +80000298 : +80000298: f0100137 lui sp,0xf0100 +8000029c: f2010113 addi sp,sp,-224 # f00fff20 +800002a0: 00012023 sw zero,0(sp) diff --git a/src/test/cpp/raw/pmp/build/pmp.elf b/src/test/cpp/raw/pmp/build/pmp.elf index 75d1010c91fc4338946e1dadf660f4690f889fa6..89007214ac506ba500d1b940ddf23ee6c5aba736 100755 GIT binary patch delta 369 zcmdm^bw_K00%OiZMP=3{ObiT5HhSLTw^ZNGz|dgc1jGl|-VGG8LX0LB`Hk~5zyfPa;%dlBq>a85Ll=$XDBk6 zk%0lMLBdc(m`{K~oS%U~n7?0SyU--|$xTfSa06x}2~DmMl#^o+6y{TaDHA}kqbrGT zbB$mPV|@=3LjwaCFfzyhX$M9GUkS)>K;mlv`FoJ~dO-dSB)$od&w^y06_Brh#CHJl zXCU!i85o2ZY>))JfeLaacMAV!Tr#;+L>Wk~6;WqAGWjZyyfXQ(h&rpG2m^!Fi?2rN_=GZdN3$iM)W7cdkN<`ZBL=VxFL z=IB5$Y($@-vP+2K;pYHFbFZoAPIN_75GeEDg2+Y jW%5c9WgvN0M4fTT Date: Wed, 20 Jan 2021 12:01:08 +0100 Subject: [PATCH 541/951] fpu implement fclass and args for sub, fma, max, fcmp, fsgnj --- src/main/scala/vexriscv/ip/fpu/FpuCore.scala | 33 ++++++++++++++----- .../scala/vexriscv/ip/fpu/Interface.scala | 26 ++++++++++++++- .../scala/vexriscv/plugin/FpuPlugin.scala | 12 +++---- src/test/scala/vexriscv/ip/fpu/FpuTest.scala | 14 ++++++++ 4 files changed, 70 insertions(+), 15 deletions(-) diff --git a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala index 047eaa34..b4cf6bb1 100644 --- a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala +++ b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala @@ -28,6 +28,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val rs1, rs2, rs3 = p.rfAddress() val rd = p.rfAddress() val value = Bits(32 bits) + val arg = p.Arg() } case class RfReadOutput() extends Bundle{ @@ -37,6 +38,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val rs1, rs2, rs3 = p.internalFloating() val rd = p.rfAddress() val value = Bits(32 bits) + val arg = p.Arg() } @@ -54,6 +56,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val lockId = lockIdType() val rd = p.rfAddress() val value = Bits(32 bits) + val arg = Bits(2 bits) } case class MulInput() extends Bundle{ @@ -64,7 +67,6 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val add = Bool() val divSqrt = Bool() val msb1, msb2 = Bool() //allow usage of msb bits of mul - val minus = Bool() } @@ -215,6 +217,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ output.opcode := s1.opcode output.lockId := s1LockId output.value := s1.value + output.arg := s1.arg output.rd := s1.rd output.rs1 := rf.ram.readSync(s0.source @@ s0.rs1,enable = !output.isStall) output.rs2 := rf.ram.readSync(s0.source @@ s0.rs2,enable = !output.isStall) @@ -260,7 +263,8 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ mul.divSqrt := False mul.msb1 := True mul.msb2 := True - mul.minus := False //TODO + mul.rs2.sign.allowOverride(); mul.rs2.sign := read.output.rs2.sign ^ input.arg(0) + mul.rs3.sign.allowOverride(); mul.rs3.sign := read.output.rs3.sign ^ input.arg(1) } val addHit = input.opcode === p.Opcode.ADD @@ -275,6 +279,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ add.payload := mulToAdd.payload when(!mulToAdd.valid) { add.payload.assignSomeByName(read.output.payload) + add.rs2.sign.allowOverride; add.rs2.sign := read.output.rs2.sign ^ input.arg(0) } } @@ -316,9 +321,22 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ 3 -> (!rs1AbsSmaller && !rs1Equal) ) - val minMaxResult = rs1Smaller ? input.rs1 | input.rs2 - val cmpResult = B(rs1Smaller) - val fclassResult = B(0) //TODO + val minMaxResult = (rs1Smaller ^ input.arg(0)) ? input.rs1 | input.rs2 + val cmpResult = B(rs1Smaller && !input.arg(1) || rs1Equal && !input.arg(0)) + val sgnjResult = (input.rs1.sign && input.arg(1)) ^ input.rs2.sign ^ input.arg(0) + val fclassResult = B(0, 32 bits) + val decoded = input.rs1.decode() + fclassResult(0) := input.rs1.sign && decoded.isInfinity + fclassResult(1) := input.rs1.sign && decoded.isNormal + fclassResult(2) := input.rs1.sign && decoded.isSubnormal + fclassResult(3) := input.rs1.sign && decoded.isZero + fclassResult(4) := !input.rs1.sign && decoded.isZero + fclassResult(5) := !input.rs1.sign && decoded.isSubnormal + fclassResult(6) := !input.rs1.sign && decoded.isNormal + fclassResult(7) := !input.rs1.sign && decoded.isInfinity + fclassResult(8) := decoded.isNan && !decoded.isQuiet + fclassResult(9) := decoded.isNan && decoded.isQuiet + switch(input.opcode){ is(FpuOpcode.STORE) { result := storeResult } @@ -345,7 +363,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ rfOutput.value := minMaxResult } is(FpuOpcode.SGNJ){ - rfOutput.value.sign := input.rs2.sign + rfOutput.value.sign := sgnjResult rfOutput.value.exponent := input.rs1.exponent rfOutput.value.mantissa := input.rs1.mantissa } @@ -401,7 +419,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ decode.mulToAdd.source := input.source decode.mulToAdd.rs1.mantissa := norm.output.mantissa decode.mulToAdd.rs1.exponent := norm.output.exponent - decode.mulToAdd.rs1.sign := norm.output.sign ^ input.minus + decode.mulToAdd.rs1.sign := norm.output.sign decode.mulToAdd.rs2 := input.rs3 decode.mulToAdd.rd := input.rd decode.mulToAdd.lockId := input.lockId @@ -434,7 +452,6 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ decode.divSqrtToMul.divSqrt := True decode.divSqrtToMul.msb1 := True decode.divSqrtToMul.msb2 := True - decode.divSqrtToMul.minus := False val aprox = new Area { diff --git a/src/main/scala/vexriscv/ip/fpu/Interface.scala b/src/main/scala/vexriscv/ip/fpu/Interface.scala index 1a0405d5..7b4c9cfd 100644 --- a/src/main/scala/vexriscv/ip/fpu/Interface.scala +++ b/src/main/scala/vexriscv/ip/fpu/Interface.scala @@ -14,7 +14,14 @@ object Fpu{ } - +case class FpuFloatDecoded() extends Bundle{ + val isNan = Bool() + val isNormal = Bool() + val isSubnormal = Bool() + val isZero = Bool() + val isInfinity = Bool() + val isQuiet = Bool() +} case class FpuFloat(exponentSize: Int, mantissaSize: Int) extends Bundle { val mantissa = UInt(mantissaSize bits) @@ -28,6 +35,21 @@ case class FpuFloat(exponentSize: Int, ret.mantissa := mantissa ret } + + + def decode() = { + val ret = FpuFloatDecoded() + val expZero = exponent === 0 + val expOne = exponent === exponent.maxValue + val manZero = mantissa === 0 + ret.isZero := expZero && manZero + ret.isSubnormal := expZero && !manZero + ret.isNormal := !expOne && !expZero + ret.isInfinity := expOne && manZero + ret.isNan := expOne && !manZero// && !sign + ret.isQuiet := mantissa.msb + ret + } } object FpuOpcode extends SpinalEnum{ @@ -50,6 +72,8 @@ case class FpuParameter( internalMantissaSize : Int, val Opcode = FpuOpcode val Format = FpuFormat + val argWidth = 2 + val Arg = HardType(Bits(2 bits)) } case class FpuFlags() extends Bundle{ diff --git a/src/main/scala/vexriscv/plugin/FpuPlugin.scala b/src/main/scala/vexriscv/plugin/FpuPlugin.scala index b19fa825..082ddd21 100644 --- a/src/main/scala/vexriscv/plugin/FpuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/FpuPlugin.scala @@ -80,10 +80,10 @@ class FpuPlugin(externalFpu : Boolean = false, FADD_S -> (addSub :+ arg(0)), FSUB_S -> (addSub :+ arg(1)), FMADD_S -> (fma :+ arg(0)), - FMSUB_S -> (fma :+ arg(1)), - FNMSUB_S -> (fma :+ arg(2)), - FNMADD_S -> (fma :+ arg(3)), - FMUL_S -> (mul), + FMSUB_S -> (fma :+ arg(2)), + FNMADD_S -> (fma :+ arg(1)), + FNMSUB_S -> (fma :+ arg(3)), + FMUL_S -> (mul :+ arg(0)), FDIV_S -> (div), FSQRT_S -> (sqrt), FLW -> (fl), @@ -94,8 +94,8 @@ class FpuPlugin(externalFpu : Boolean = false, FCVT_W_S -> (fcvtF2i :+ arg(1)), FCLASS_S -> (fclass), FLE_S -> (fcmp :+ arg(0)), - FEQ_S -> (fcmp :+ arg(1)), - FLT_S -> (fcmp :+ arg(2)), + FEQ_S -> (fcmp :+ arg(2)), + FLT_S -> (fcmp :+ arg(1)), FSGNJ_S -> (fsgnj :+ arg(0)), FSGNJN_S -> (fsgnj :+ arg(1)), FSGNJX_S -> (fsgnj :+ arg(2)), diff --git a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala index 59b3fc93..8d96a37c 100644 --- a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala +++ b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala @@ -64,6 +64,7 @@ class FpuTest extends FunSuite{ cmd.rs2.randomize() cmd.rs3.randomize() cmd.rd #= rd + cmd.arg.randomize() } commitQueue += {cmd => cmd.write #= true @@ -84,6 +85,7 @@ class FpuTest extends FunSuite{ cmd.rs2 #= rs cmd.rs3.randomize() cmd.rd.randomize() + cmd.arg.randomize() } rspQueue += body @@ -101,6 +103,7 @@ class FpuTest extends FunSuite{ cmd.rs2 #= rs2 cmd.rs3.randomize() cmd.rd #= rd + cmd.arg #= 0 } commitQueue += {cmd => cmd.write #= true @@ -116,6 +119,7 @@ class FpuTest extends FunSuite{ cmd.rs2 #= rs2 cmd.rs3.randomize() cmd.rd #= rd + cmd.arg #= 0 } commitQueue += {cmd => cmd.write #= true @@ -131,6 +135,7 @@ class FpuTest extends FunSuite{ cmd.rs2 #= rs2 cmd.rs3.randomize() cmd.rd #= rd + cmd.arg.randomize() } commitQueue += {cmd => cmd.write #= true @@ -146,6 +151,7 @@ class FpuTest extends FunSuite{ cmd.rs2.randomize() cmd.rs3.randomize() cmd.rd #= rd + cmd.arg.randomize() } commitQueue += {cmd => cmd.write #= true @@ -161,6 +167,7 @@ class FpuTest extends FunSuite{ cmd.rs2 #= rs2 cmd.rs3 #= rs3 cmd.rd #= rd + cmd.arg #= 0 } commitQueue += {cmd => cmd.write #= true @@ -177,6 +184,7 @@ class FpuTest extends FunSuite{ cmd.rs2 #= rs2 cmd.rs3.randomize() cmd.rd.randomize() + cmd.arg #= 1 } rspQueue += body } @@ -189,6 +197,7 @@ class FpuTest extends FunSuite{ cmd.rs2.randomize() cmd.rs3.randomize() cmd.rd.randomize() + cmd.arg.randomize() } rspQueue += body } @@ -201,6 +210,7 @@ class FpuTest extends FunSuite{ cmd.rs2.randomize() cmd.rs3.randomize() cmd.rd #= rd + cmd.arg.randomize() } commitQueue += {cmd => cmd.write #= true @@ -216,6 +226,7 @@ class FpuTest extends FunSuite{ cmd.rs2.randomize() cmd.rs3.randomize() cmd.rd.randomize() + cmd.arg #= 0 } rspQueue += body } @@ -228,6 +239,7 @@ class FpuTest extends FunSuite{ cmd.rs2.randomize() cmd.rs3.randomize() cmd.rd #= rd + cmd.arg #= 0 } commitQueue += {cmd => cmd.write #= true @@ -243,6 +255,7 @@ class FpuTest extends FunSuite{ cmd.rs2 #= rs2 cmd.rs3.randomize() cmd.rd #= rd + cmd.arg #= 0 } commitQueue += {cmd => cmd.write #= true @@ -259,6 +272,7 @@ class FpuTest extends FunSuite{ cmd.rs2 #= rs2 cmd.rs3.randomize() cmd.rd #= rd + cmd.arg #= 0 } commitQueue += {cmd => cmd.write #= true From ac5844f39305ef75cfc3a4a8062b3ac631d4104b Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 20 Jan 2021 13:15:29 +0100 Subject: [PATCH 542/951] fpu add signed i2f/f2i --- src/main/scala/vexriscv/ip/fpu/FpuCore.scala | 11 +++-- src/test/scala/vexriscv/ip/fpu/FpuTest.scala | 51 ++++++++++++-------- 2 files changed, 39 insertions(+), 23 deletions(-) diff --git a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala index b4cf6bb1..b1afe3cf 100644 --- a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala +++ b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala @@ -307,10 +307,13 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val f2iShift = input.rs1.exponent - U(exponentOne) val f2iShifted = (U"1" @@ input.rs1.mantissa) << (f2iShift.resize(5 bits)) - val f2iResult = f2iShifted.asBits >> p.internalMantissaSize + val f2iUnsigned = f2iShifted >> p.internalMantissaSize + val f2iResult = (f2iUnsigned.twoComplement(input.arg(0) && input.rs1.sign)).asBits.resize(32 bits) - val i2fLog2 = OHToUInt(OHMasking.last(input.value)) - val i2fShifted = (input.value << p.internalMantissaSize) >> i2fLog2 + val i2fSign = input.arg(0) && input.value.msb + val i2fUnsigned = input.value.asUInt.twoComplement(i2fSign).resize(32 bits) + val i2fLog2 = OHToUInt(OHMasking.last(i2fUnsigned)) + val i2fShifted = (i2fUnsigned << p.internalMantissaSize) >> i2fLog2 val rs1Equal = input.rs1 === input.rs2 val rs1AbsSmaller = (input.rs1.exponent @@ input.rs1.mantissa) < (input.rs2.exponent @@ input.rs2.mantissa) @@ -355,7 +358,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ rfOutput.value.assignDontCare() switch(input.opcode){ is(FpuOpcode.I2F){ - rfOutput.value.sign := False + rfOutput.value.sign := i2fSign rfOutput.value.exponent := i2fLog2 +^ exponentOne rfOutput.value.mantissa := U(i2fShifted).resized } diff --git a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala index 8d96a37c..25bd4fac 100644 --- a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala +++ b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala @@ -16,7 +16,7 @@ class FpuTest extends FunSuite{ test("directed"){ - val portCount = 4 + val portCount = 1 val p = FpuParameter( internalMantissaSize = 23, withDouble = false @@ -189,7 +189,7 @@ class FpuTest extends FunSuite{ rspQueue += body } - def f2i(rs1 : Int)(body : FpuRsp => Unit): Unit ={ + def f2i(rs1 : Int, signed : Boolean)(body : FpuRsp => Unit): Unit ={ cmdQueue += {cmd => cmd.opcode #= cmd.opcode.spinalEnum.F2I cmd.value.randomize() @@ -197,20 +197,20 @@ class FpuTest extends FunSuite{ cmd.rs2.randomize() cmd.rs3.randomize() cmd.rd.randomize() - cmd.arg.randomize() + cmd.arg #= (if(signed) 1 else 0) } rspQueue += body } - def i2f(rd : Int, value : Int): Unit ={ + def i2f(rd : Int, value : Int, signed : Boolean): Unit ={ cmdQueue += {cmd => cmd.opcode #= cmd.opcode.spinalEnum.I2F - cmd.value #= value + cmd.value #= value.toLong & 0xFFFFFFFFl cmd.rs1.randomize() cmd.rs2.randomize() cmd.rs3.randomize() cmd.rd #= rd - cmd.arg.randomize() + cmd.arg #= (if(signed) 1 else 0) } commitQueue += {cmd => cmd.write #= true @@ -392,23 +392,23 @@ class FpuTest extends FunSuite{ } } - def testF2i(a : Float): Unit ={ + def testF2i(a : Float, signed : Boolean): Unit ={ val rs = new RegAllocator() val rs1, rs2, rs3 = rs.allocate() val rd = Random.nextInt(32) load(rs1, a) - f2i(rs1){rsp => + f2i(rs1, signed){rsp => val ref = a.toInt - val v = rsp.value.toBigInt + val v = (rsp.value.toBigInt & 0xFFFFFFFF).toInt println(f"f2i($a) = $v, $ref") assert(v === ref) } } - def testI2f(a : Int): Unit ={ + def testI2f(a : Int, signed : Boolean): Unit ={ val rs = new RegAllocator() val rd = Random.nextInt(32) - i2f(rd, a) + i2f(rd, a, signed) storeFloat(rd){v => val ref = a.toInt println(f"i2f($a) = $v, $ref") @@ -515,10 +515,17 @@ class FpuTest extends FunSuite{ //TODO Test corner cases - testI2f(17) - testI2f(12) - testI2f(512) - testI2f(1) + for(signed <- List(false, true)) { + testI2f(17, signed) + testI2f(12, signed) + testI2f(512, signed) + testI2f(1, signed) + } + + testI2f(-17, true) + testI2f(-12, true) + testI2f(-512, true) + testI2f(-1, true) // dut.clockDomain.waitSampling(1000) // simFailure() @@ -533,11 +540,17 @@ class FpuTest extends FunSuite{ testCmp(1.5f, -3.5f) //TODO Test corner cases - testF2i(16.0f) - testF2i(18.0f) - testF2i(1200.0f) - testF2i(1.0f) + for(signed <- List(false, true)) { + testF2i(16.0f, signed) + testF2i(18.0f, signed) + testF2i(1200.0f, signed) + testF2i(1.0f, signed) + } + testF2i(-16.0f, true) + testF2i(-18.0f, true) + testF2i(-1200.0f, true) + testF2i(-1.0f, true) testAdd(0.1f, 1.6f) From 6c13e6458f870d229fd662beafabb8251e3e5ca2 Mon Sep 17 00:00:00 2001 From: Samuel Lindemer Date: Wed, 20 Jan 2021 14:16:10 +0100 Subject: [PATCH 543/951] Remove registers storing PMP region bounds --- .../scala/vexriscv/plugin/PmpPlugin.scala | 33 ++-- src/test/cpp/raw/pmp/build/pmp.asm | 185 +++++++++--------- src/test/cpp/raw/pmp/build/pmp.elf | Bin 5468 -> 5480 bytes src/test/cpp/raw/pmp/build/pmp.hex | 54 ++--- src/test/cpp/raw/pmp/build/pmp.map | 12 +- src/test/cpp/raw/pmp/src/crt.S | 3 + 6 files changed, 146 insertions(+), 141 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/PmpPlugin.scala b/src/main/scala/vexriscv/plugin/PmpPlugin.scala index 5f008b41..73c15af3 100644 --- a/src/main/scala/vexriscv/plugin/PmpPlugin.scala +++ b/src/main/scala/vexriscv/plugin/PmpPlugin.scala @@ -86,8 +86,8 @@ case class PmpRegister(previous : PmpRegister) extends Area { val addr = UInt(32 bits) } - // Last assignment wins; nothing happens if a user-initiated write did not - // occur on this clock cycle. + // Last valid assignment wins; nothing happens if a user-initiated write did + // not occur on this clock cycle. csr.r := state.r csr.w := state.w csr.x := state.x @@ -97,8 +97,8 @@ case class PmpRegister(previous : PmpRegister) extends Area { // Computed PMP region bounds val region = new Area { - val valid = Bool - val start, end = Reg(UInt(32 bits)) + val valid, locked = Bool + val start, end = UInt(32 bits) } when(~state.l) { @@ -114,32 +114,31 @@ case class PmpRegister(previous : PmpRegister) extends Area { } } - val shifted = csr.addr |<< 2 + val shifted = state.addr |<< 2 + val mask = state.addr & ~(state.addr + 1) + val masked = (state.addr & ~mask) |<< 2 + + // PMP changes take effect two clock cycles after the initial CSR write (i.e., + // settings propagate from csr -> state -> region). + region.locked := state.l region.valid := True - switch(state.a) { + switch(csr.a) { is(TOR) { - if (previous == null) { - region.start := 0 - } else { - region.start := previous.region.end - } + if (previous == null) region.start := 0 + else region.start := previous.region.end region.end := shifted } - is(NA4) { region.start := shifted region.end := shifted + 4 } - is(NAPOT) { - val mask = state.addr & ~(state.addr + 1) - val masked = (state.addr & ~mask) |<< 2 region.start := masked region.end := masked + ((mask + 1) |<< 3) } - default { + region.start := 0 region.end := shifted region.valid := False } @@ -221,7 +220,7 @@ class PmpPlugin(regions : Int, ioRange : UInt => Bool) extends Plugin[VexRiscv] val hits = pmps.map(pmp => pmp.region.valid & pmp.region.start <= address & pmp.region.end > address & - (pmp.state.l | ~privilegeService.isMachine())) + (pmp.region.locked | ~privilegeService.isMachine())) // M-mode has full access by default, others have none. when(CountOne(hits) === 0) { diff --git a/src/test/cpp/raw/pmp/build/pmp.asm b/src/test/cpp/raw/pmp/build/pmp.asm index 5c7605b6..4508ee60 100644 --- a/src/test/cpp/raw/pmp/build/pmp.asm +++ b/src/test/cpp/raw/pmp/build/pmp.asm @@ -17,21 +17,21 @@ Disassembly of section .crt_section: 80000018 : 80000018: 00000e13 li t3,0 8000001c: 00000f17 auipc t5,0x0 -80000020: 270f0f13 addi t5,t5,624 # 8000028c +80000020: 27cf0f13 addi t5,t5,636 # 80000298 80000024: 800000b7 lui ra,0x80000 80000028: 80008237 lui tp,0x80008 8000002c: deadc137 lui sp,0xdeadc -80000030: eef10113 addi sp,sp,-273 # deadbeef -80000034: 0020a023 sw sp,0(ra) # 80000000 -80000038: 00222023 sw sp,0(tp) # 80008000 +80000030: eef10113 addi sp,sp,-273 # deadbeef +80000034: 0020a023 sw sp,0(ra) # 80000000 +80000038: 00222023 sw sp,0(tp) # 80008000 8000003c: 0000a183 lw gp,0(ra) -80000040: 24311663 bne sp,gp,8000028c +80000040: 24311c63 bne sp,gp,80000298 80000044: 00022183 lw gp,0(tp) # 0 <_start-0x80000000> -80000048: 24311263 bne sp,gp,8000028c +80000048: 24311863 bne sp,gp,80000298 8000004c: 071202b7 lui t0,0x7120 80000050: 3a029073 csrw pmpcfg0,t0 80000054: 3a002373 csrr t1,pmpcfg0 -80000058: 22629a63 bne t0,t1,8000028c +80000058: 24629063 bne t0,t1,80000298 8000005c: 191f02b7 lui t0,0x191f0 80000060: 30428293 addi t0,t0,772 # 191f0304 <_start-0x66e0fcfc> 80000064: 3a129073 csrw pmpcfg1,t0 @@ -44,7 +44,7 @@ Disassembly of section .crt_section: 80000080: 200002b7 lui t0,0x20000 80000084: 3b029073 csrw pmpaddr0,t0 80000088: 3b002373 csrr t1,pmpaddr0 -8000008c: 20629063 bne t0,t1,8000028c +8000008c: 20629663 bne t0,t1,80000298 80000090: fff00293 li t0,-1 80000094: 3b129073 csrw pmpaddr1,t0 80000098: 200022b7 lui t0,0x20002 @@ -85,116 +85,119 @@ Disassembly of section .crt_section: 80000124: 0020a023 sw sp,0(ra) 80000128: 00222023 sw sp,0(tp) # 0 <_start-0x80000000> 8000012c: 0000a183 lw gp,0(ra) -80000130: 14311e63 bne sp,gp,8000028c +80000130: 16311463 bne sp,gp,80000298 80000134: 00000193 li gp,0 80000138: 00022183 lw gp,0(tp) # 0 <_start-0x80000000> -8000013c: 14311863 bne sp,gp,8000028c +8000013c: 14311e63 bne sp,gp,80000298 80000140 : 80000140: 00100e13 li t3,1 80000144: 00000f17 auipc t5,0x0 -80000148: 148f0f13 addi t5,t5,328 # 8000028c +80000148: 154f0f13 addi t5,t5,340 # 80000298 8000014c: 079212b7 lui t0,0x7921 80000150: 80828293 addi t0,t0,-2040 # 7920808 <_start-0x786df7f8> 80000154: 3a029073 csrw pmpcfg0,t0 80000158: 3a002373 csrr t1,pmpcfg0 -8000015c: 12629863 bne t0,t1,8000028c +8000015c: 12629e63 bne t0,t1,80000298 80000160: 800080b7 lui ra,0x80008 80000164: deadc137 lui sp,0xdeadc -80000168: eef10113 addi sp,sp,-273 # deadbeef -8000016c: 0020a023 sw sp,0(ra) # 80008000 +80000168: eef10113 addi sp,sp,-273 # deadbeef +8000016c: 0020a023 sw sp,0(ra) # 80008000 80000170: 00000f17 auipc t5,0x0 80000174: 010f0f13 addi t5,t5,16 # 80000180 80000178: 0000a183 lw gp,0(ra) -8000017c: 1100006f j 8000028c +8000017c: 11c0006f j 80000298 80000180 : 80000180: 00200e13 li t3,2 80000184: 00000f17 auipc t5,0x0 -80000188: 108f0f13 addi t5,t5,264 # 8000028c +80000188: 114f0f13 addi t5,t5,276 # 80000298 8000018c: 071202b7 lui t0,0x7120 80000190: 3a029073 csrw pmpcfg0,t0 80000194: 3a002373 csrr t1,pmpcfg0 -80000198: 0e628a63 beq t0,t1,8000028c -8000019c: 800080b7 lui ra,0x80008 -800001a0: deadc137 lui sp,0xdeadc -800001a4: eef10113 addi sp,sp,-273 # deadbeef -800001a8: 0020a023 sw sp,0(ra) # 80008000 -800001ac: 00000f17 auipc t5,0x0 -800001b0: 010f0f13 addi t5,t5,16 # 800001bc -800001b4: 0000a183 lw gp,0(ra) -800001b8: 0d40006f j 8000028c +80000198: 3b205073 csrwi pmpaddr2,0 +8000019c: 3b202373 csrr t1,pmpaddr2 +800001a0: 0e030c63 beqz t1,80000298 +800001a4: 0e628a63 beq t0,t1,80000298 +800001a8: 800080b7 lui ra,0x80008 +800001ac: deadc137 lui sp,0xdeadc +800001b0: eef10113 addi sp,sp,-273 # deadbeef +800001b4: 0020a023 sw sp,0(ra) # 80008000 +800001b8: 00000f17 auipc t5,0x0 +800001bc: 010f0f13 addi t5,t5,16 # 800001c8 +800001c0: 0000a183 lw gp,0(ra) +800001c4: 0d40006f j 80000298 -800001bc : -800001bc: 00300e13 li t3,3 -800001c0: 00000f17 auipc t5,0x0 -800001c4: 0ccf0f13 addi t5,t5,204 # 8000028c -800001c8: 00000117 auipc sp,0x0 -800001cc: 01010113 addi sp,sp,16 # 800001d8 -800001d0: 34111073 csrw mepc,sp -800001d4: 30200073 mret +800001c8 : +800001c8: 00300e13 li t3,3 +800001cc: 00000f17 auipc t5,0x0 +800001d0: 0ccf0f13 addi t5,t5,204 # 80000298 +800001d4: 00000117 auipc sp,0x0 +800001d8: 01010113 addi sp,sp,16 # 800001e4 +800001dc: 34111073 csrw mepc,sp +800001e0: 30200073 mret -800001d8 : -800001d8: 00400e13 li t3,4 -800001dc: 00000f17 auipc t5,0x0 -800001e0: 0b0f0f13 addi t5,t5,176 # 8000028c -800001e4: deadc137 lui sp,0xdeadc -800001e8: eef10113 addi sp,sp,-273 # deadbeef -800001ec: 800080b7 lui ra,0x80008 -800001f0: 0020a023 sw sp,0(ra) # 80008000 -800001f4: 00000f17 auipc t5,0x0 -800001f8: 010f0f13 addi t5,t5,16 # 80000204 -800001fc: 0000a183 lw gp,0(ra) -80000200: 08c0006f j 8000028c +800001e4 : +800001e4: 00400e13 li t3,4 +800001e8: 00000f17 auipc t5,0x0 +800001ec: 0b0f0f13 addi t5,t5,176 # 80000298 +800001f0: deadc137 lui sp,0xdeadc +800001f4: eef10113 addi sp,sp,-273 # deadbeef +800001f8: 800080b7 lui ra,0x80008 +800001fc: 0020a023 sw sp,0(ra) # 80008000 +80000200: 00000f17 auipc t5,0x0 +80000204: 010f0f13 addi t5,t5,16 # 80000210 +80000208: 0000a183 lw gp,0(ra) +8000020c: 08c0006f j 80000298 -80000204 : -80000204: 00500e13 li t3,5 -80000208: deadc137 lui sp,0xdeadc -8000020c: eef10113 addi sp,sp,-273 # deadbeef -80000210: 800000b7 lui ra,0x80000 -80000214: 0020a023 sw sp,0(ra) # 80000000 -80000218: 0000a183 lw gp,0(ra) -8000021c: 06311863 bne sp,gp,8000028c +80000210 : +80000210: 00500e13 li t3,5 +80000214: deadc137 lui sp,0xdeadc +80000218: eef10113 addi sp,sp,-273 # deadbeef +8000021c: 800000b7 lui ra,0x80000 +80000220: 0020a023 sw sp,0(ra) # 80000000 +80000224: 0000a183 lw gp,0(ra) +80000228: 06311863 bne sp,gp,80000298 -80000220 : -80000220: 00600e13 li t3,6 -80000224: 800100b7 lui ra,0x80010 -80000228: 0000a183 lw gp,0(ra) # 80010000 -8000022c: 00000f17 auipc t5,0x0 -80000230: 06cf0f13 addi t5,t5,108 # 80000298 -80000234: 0030a023 sw gp,0(ra) -80000238: 0540006f j 8000028c +8000022c : +8000022c: 00600e13 li t3,6 +80000230: 800100b7 lui ra,0x80010 +80000234: 0000a183 lw gp,0(ra) # 80010000 +80000238: 00000f17 auipc t5,0x0 +8000023c: 06cf0f13 addi t5,t5,108 # 800002a4 +80000240: 0030a023 sw gp,0(ra) +80000244: 0540006f j 80000298 -8000023c : -8000023c: 00700e13 li t3,7 -80000240: 00000f17 auipc t5,0x0 -80000244: 04cf0f13 addi t5,t5,76 # 8000028c -80000248: deadc137 lui sp,0xdeadc -8000024c: eef10113 addi sp,sp,-273 # deadbeef -80000250: 800300b7 lui ra,0x80030 -80000254: ff808093 addi ra,ra,-8 # 8002fff8 -80000258: 00222023 sw sp,0(tp) # 0 <_start-0x80000000> -8000025c: 00000f17 auipc t5,0x0 -80000260: fa8f0f13 addi t5,t5,-88 # 80000204 -80000264: 00022183 lw gp,0(tp) # 0 <_start-0x80000000> -80000268: 0240006f j 8000028c +80000248 : +80000248: 00700e13 li t3,7 +8000024c: 00000f17 auipc t5,0x0 +80000250: 04cf0f13 addi t5,t5,76 # 80000298 +80000254: deadc137 lui sp,0xdeadc +80000258: eef10113 addi sp,sp,-273 # deadbeef +8000025c: 800300b7 lui ra,0x80030 +80000260: ff808093 addi ra,ra,-8 # 8002fff8 +80000264: 00222023 sw sp,0(tp) # 0 <_start-0x80000000> +80000268: 00000f17 auipc t5,0x0 +8000026c: fa8f0f13 addi t5,t5,-88 # 80000210 +80000270: 00022183 lw gp,0(tp) # 0 <_start-0x80000000> +80000274: 0240006f j 80000298 -8000026c : -8000026c: 00800e13 li t3,8 -80000270: 800400b7 lui ra,0x80040 -80000274: ff808093 addi ra,ra,-8 # 8003fff8 -80000278: 0000a183 lw gp,0(ra) -8000027c: 00000f17 auipc t5,0x0 -80000280: 01cf0f13 addi t5,t5,28 # 80000298 -80000284: 0030a023 sw gp,0(ra) -80000288: 0040006f j 8000028c +80000278 : +80000278: 00800e13 li t3,8 +8000027c: 800400b7 lui ra,0x80040 +80000280: ff808093 addi ra,ra,-8 # 8003fff8 +80000284: 0000a183 lw gp,0(ra) +80000288: 00000f17 auipc t5,0x0 +8000028c: 01cf0f13 addi t5,t5,28 # 800002a4 +80000290: 0030a023 sw gp,0(ra) +80000294: 0040006f j 80000298 -8000028c : -8000028c: f0100137 lui sp,0xf0100 -80000290: f2410113 addi sp,sp,-220 # f00fff24 -80000294: 01c12023 sw t3,0(sp) - -80000298 : +80000298 : 80000298: f0100137 lui sp,0xf0100 -8000029c: f2010113 addi sp,sp,-224 # f00fff20 -800002a0: 00012023 sw zero,0(sp) +8000029c: f2410113 addi sp,sp,-220 # f00fff24 +800002a0: 01c12023 sw t3,0(sp) + +800002a4 : +800002a4: f0100137 lui sp,0xf0100 +800002a8: f2010113 addi sp,sp,-224 # f00fff20 +800002ac: 00012023 sw zero,0(sp) diff --git a/src/test/cpp/raw/pmp/build/pmp.elf b/src/test/cpp/raw/pmp/build/pmp.elf index 89007214ac506ba500d1b940ddf23ee6c5aba736..b844a20189743c473a3eeb6c94fa6b6976f7932d 100755 GIT binary patch delta 334 zcmcbk^+Icc0%OHQMP=3vObiSgHhSLVw>q!Boq?gjya|X8uDvJB`0<_c0tE(T1to^& zg$xYIGKMP6icAd25{4?GOnPe@Xk93x=JIBjyDz+znyL$S$>3=CkE za)u(pd;$#O{0t1j{Qjcbg(k62Zfa_P>zp?^PEbMXfS@p+0!)!0veCr>3f9HS3f9Ry z%zVjRNqmzN1m!mG5{zSHoH1EaSU>RuBSQlN7%(#E0qG}5d=nsFfC(XQ1?1}>@g0Et zB}jZ%Am0Ot?+xTvOkOGcpK-(Fl_JVO@~ntD8p~z%L1_rQ7 z2}2QKJ^==Ceg+0%{(h0|LX+4hH#IfDb^%qd<7)F1CT!hiSG*J+aU41f&84w kTZR8KE}6VlL>Wll6j5h9GMQ0So$< Date: Thu, 21 Jan 2021 12:13:25 +0100 Subject: [PATCH 544/951] fpu zero/nan wip --- src/main/scala/vexriscv/ip/fpu/FpuCore.scala | 10 +++++++++- src/test/scala/vexriscv/ip/fpu/FpuTest.scala | 8 ++++++++ src/test/scala/vexriscv/ip/fpu/Playground.scala | 8 ++++++++ 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala index b1afe3cf..9d39fdf5 100644 --- a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala +++ b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala @@ -628,12 +628,20 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val norm = new Area{ def xyExponent = math.xyExponent def xyMantissa = math.xyMantissa - def xySign = math.xySign + val xySign = CombInit(math.xySign) val shiftOh = OHMasking.first(xyMantissa.asBools.reverse) val shift = OHToUInt(shiftOh) val mantissa = (xyMantissa |<< shift) >> 1 val exponent = xyExponent - shift + 1 + val forceZero = xyMantissa === 0 + val forceOverflow = exponent === exponent.maxValue + val forceNan = +// val + when(forceZero){ //TODO + exponent := 0 + xySign := False + } } diff --git a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala index 25bd4fac..3b8c78db 100644 --- a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala +++ b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala @@ -304,6 +304,7 @@ class FpuTest extends FunSuite{ } } def checkFloat(ref : Float, dut : Float): Boolean ={ + if(ref === dut) return true ref.abs * 1.0001 > dut.abs && ref.abs * 0.9999 < dut.abs && ref.signum == dut.signum } @@ -491,6 +492,13 @@ class FpuTest extends FunSuite{ val b2f = lang.Float.intBitsToFloat(_) + testAdd(1.2f, -1.2f) + testAdd(-1.2f, 1.2f) + testAdd(0.0f, -1.2f) + testAdd(-0.0f, -1.2f) + testAdd(1.2f, -0f) + testAdd(1.2f, 0f) + testFmv_x_w(1.246f) testFmv_w_x(lang.Float.floatToIntBits(7.234f)) diff --git a/src/test/scala/vexriscv/ip/fpu/Playground.scala b/src/test/scala/vexriscv/ip/fpu/Playground.scala index 71b500da..f5df1440 100644 --- a/src/test/scala/vexriscv/ip/fpu/Playground.scala +++ b/src/test/scala/vexriscv/ip/fpu/Playground.scala @@ -35,3 +35,11 @@ object MiaouSqrt extends App{ println(output) println(s"ref ${Math.sqrt(input)}") } + + +object MiaouNan extends App{ + println(Float.NaN + 3.0f) + println(3.0f + Float.NaN ) + println(0.0f*Float.PositiveInfinity ) + println(1.0f/0.0f ) +} \ No newline at end of file From bcd140fc42cf5ebd7c9bc23d1cb24fb1cf7e554b Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 21 Jan 2021 13:28:04 +0100 Subject: [PATCH 545/951] Add vexRiscvConfig.withMmu option --- .../scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index 83ac65a0..29385ca3 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -15,7 +15,7 @@ import spinal.lib.generator.Handle import spinal.lib.misc.plic.PlicMapping import spinal.lib.system.debugger.SystemDebuggerConfig import vexriscv.ip.{DataCacheAck, DataCacheConfig, DataCacheMemBus, InstructionCache, InstructionCacheConfig} -import vexriscv.plugin.{BranchPlugin, CsrAccess, CsrPlugin, CsrPluginConfig, DBusCachedPlugin, DBusSimplePlugin, DYNAMIC_TARGET, DebugPlugin, DecoderSimplePlugin, FullBarrelShifterPlugin, HazardSimplePlugin, IBusCachedPlugin, IBusSimplePlugin, IntAluPlugin, MmuPlugin, MmuPortConfig, MulDivIterativePlugin, MulPlugin, RegFilePlugin, STATIC, SrcPlugin, YamlPlugin} +import vexriscv.plugin.{BranchPlugin, CsrAccess, CsrPlugin, CsrPluginConfig, DBusCachedPlugin, DBusSimplePlugin, DYNAMIC_TARGET, DebugPlugin, DecoderSimplePlugin, FullBarrelShifterPlugin, HazardSimplePlugin, IBusCachedPlugin, IBusSimplePlugin, IntAluPlugin, MmuPlugin, MmuPortConfig, MulDivIterativePlugin, MulPlugin, RegFilePlugin, STATIC, SrcPlugin, StaticMemoryTranslatorPlugin, YamlPlugin} import vexriscv.{Riscv, VexRiscv, VexRiscvBmbGenerator, VexRiscvConfig, plugin} import scala.collection.mutable @@ -160,12 +160,17 @@ object VexRiscvSmpClusterGen { dCacheWays : Int = 2, iBusRelax : Boolean = false, earlyBranch : Boolean = false, - dBusCmdMasterPipe : Boolean = false) = { + dBusCmdMasterPipe : Boolean = false, + withMmu : Boolean = true, + withSupervisor : Boolean = true + ) = { assert(iCacheSize/iCacheWays <= 4096, "Instruction cache ways can't be bigger than 4096 bytes") assert(dCacheSize/dCacheWays <= 4096, "Data cache ways can't be bigger than 4096 bytes") val config = VexRiscvConfig( plugins = List( - new MmuPlugin( + if(withMmu)new MmuPlugin( + ioRange = ioRange + )else new StaticMemoryTranslatorPlugin( ioRange = ioRange ), //Uncomment the whole IBusCachedPlugin and comment IBusSimplePlugin if you want cached iBus config From 4bd637cf88875be4c1533f838955f34e2b5401bd Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 22 Jan 2021 14:55:37 +0100 Subject: [PATCH 546/951] fpu add now support special floats values and better rounding --- src/main/scala/vexriscv/ip/fpu/FpuCore.scala | 135 ++++++++++++++---- .../scala/vexriscv/ip/fpu/Interface.scala | 38 ++++- .../scala/vexriscv/plugin/FpuPlugin.scala | 2 +- src/test/scala/vexriscv/ip/fpu/FpuTest.scala | 57 ++++++-- .../scala/vexriscv/ip/fpu/Playground.scala | 2 + 5 files changed, 194 insertions(+), 40 deletions(-) diff --git a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala index 9d39fdf5..bf5749bb 100644 --- a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala +++ b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala @@ -44,7 +44,6 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ case class LoadInput() extends Bundle{ val source = Source() - val rs1 = p.internalFloating() val rd = p.rfAddress() val lockId = lockIdType() } @@ -175,7 +174,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val useRs1, useRs2, useRs3, useRd = False switch(s0.opcode){ is(p.Opcode.LOAD) { useRd := True } - is(p.Opcode.STORE) { useRs2 := True } + is(p.Opcode.STORE) { useRs1 := True } is(p.Opcode.ADD) { useRd := True; useRs1 := True; useRs2 := True } is(p.Opcode.MUL) { useRd := True; useRs1 := True; useRs2 := True } is(p.Opcode.DIV) { useRd := True; useRs1 := True; useRs2 := True } @@ -288,13 +287,39 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val filtred = commitFork.load.map(port => port.takeWhen(port.load)) def feed = filtred(input.source) val hazard = !feed.valid + + val f32Mantissa = feed.value(0, 23 bits).asUInt + val f32Exponent = feed.value(23, 8 bits).asUInt + val f32Sign = feed.value(31) + + val expZero = f32Exponent === 0 + val expOne = f32Exponent === 255 + val manZero = f32Mantissa === 0 + + val isZero = expZero && manZero + val isSubnormal = expZero && !manZero + val isNormal = !expOne && !expZero + val isInfinity = expOne && manZero + val isNan = expOne && !manZero + val isQuiet = f32Mantissa.msb + + val recoded = p.internalFloating() + recoded.mantissa := f32Mantissa + recoded.exponent := f32Exponent + recoded.sign := f32Sign + recoded.setNormal + when(isZero){recoded.setZero} + when(isSubnormal){recoded.setSubnormal} + when(isInfinity){recoded.setInfinity} + when(isNan){recoded.setNan} + val output = input.haltWhen(hazard).swapPayload(WriteInput()) filtred.foreach(_.ready := False) feed.ready := input.valid && output.ready output.source := input.source output.lockId := input.lockId output.rd := input.rd - output.value.assignFromBits(feed.value) + output.value := recoded } val shortPip = new Area{ @@ -303,7 +328,25 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val rfOutput = Stream(WriteInput()) val result = p.storeLoadType().assignDontCare() - val storeResult = input.rs2.asBits + + val recoded = CombInit(input.rs1) + when(recoded.special){ + switch(input.rs1.exponent(1 downto 0)){ + is(FpuFloat.ZERO){ + recoded.mantissa.clearAll() + recoded.exponent.clearAll() + } + is(FpuFloat.INFINITY){ + recoded.mantissa.clearAll() + recoded.exponent.setAll() + } + is(FpuFloat.NAN){ + recoded.exponent.setAll() + } + } + } + + val recodedResult = recoded.asBits.resize(32 bits) val f2iShift = input.rs1.exponent - U(exponentOne) val f2iShifted = (U"1" @@ input.rs1.mantissa) << (f2iShift.resize(5 bits)) @@ -324,6 +367,33 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ 3 -> (!rs1AbsSmaller && !rs1Equal) ) + val rawToFpu = new Area{ + val f32Mantissa = input.value(0, 23 bits).asUInt + val f32Exponent = input.value(23, 8 bits).asUInt + val f32Sign = input.value(31) + + val expZero = f32Exponent === 0 + val expOne = f32Exponent === 255 + val manZero = f32Mantissa === 0 + + val isZero = expZero && manZero + val isSubnormal = expZero && !manZero + val isNormal = !expOne && !expZero + val isInfinity = expOne && manZero + val isNan = expOne && !manZero + val isQuiet = f32Mantissa.msb + + val recoded = p.internalFloating() + recoded.mantissa := f32Mantissa + recoded.exponent := f32Exponent + recoded.sign := f32Sign + recoded.setNormal + when(isZero){recoded.setZero} + when(isSubnormal){recoded.setSubnormal} + when(isInfinity){recoded.setInfinity} + when(isNan){recoded.setNan} + } + val minMaxResult = (rs1Smaller ^ input.arg(0)) ? input.rs1 | input.rs2 val cmpResult = B(rs1Smaller && !input.arg(1) || rs1Equal && !input.arg(0)) val sgnjResult = (input.rs1.sign && input.arg(1)) ^ input.rs2.sign ^ input.arg(0) @@ -342,10 +412,10 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ switch(input.opcode){ - is(FpuOpcode.STORE) { result := storeResult } + is(FpuOpcode.STORE) { result := recodedResult } + is(FpuOpcode.FMV_X_W) { result := recodedResult } //TODO is(FpuOpcode.F2I) { result := f2iResult } is(FpuOpcode.CMP) { result := cmpResult.resized } //TODO - is(FpuOpcode.FMV_X_W) { result := input.rs1.asBits } //TODO is(FpuOpcode.FCLASS) { result := fclassResult.resized } } @@ -361,6 +431,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ rfOutput.value.sign := i2fSign rfOutput.value.exponent := i2fLog2 +^ exponentOne rfOutput.value.mantissa := U(i2fShifted).resized + rfOutput.value.special := False //TODO } is(FpuOpcode.MIN_MAX){ rfOutput.value := minMaxResult @@ -369,9 +440,10 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ rfOutput.value.sign := sgnjResult rfOutput.value.exponent := input.rs1.exponent rfOutput.value.mantissa := input.rs1.mantissa + rfOutput.value.special := False //TODO } is(FpuOpcode.FMV_W_X){ - rfOutput.value.assignFromBits(input.value) //TODO + rfOutput.value := rawToFpu.recoded } } @@ -403,6 +475,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ output.sign := input.rs1.sign ^ input.rs2.sign output.exponent := exp.resized output.mantissa := man + output.special := False //TODO } val notMul = new Area{ @@ -423,6 +496,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ decode.mulToAdd.rs1.mantissa := norm.output.mantissa decode.mulToAdd.rs1.exponent := norm.output.exponent decode.mulToAdd.rs1.sign := norm.output.sign + decode.mulToAdd.rs1.special := False //TODO decode.mulToAdd.rs2 := input.rs3 decode.mulToAdd.rd := input.rd decode.mulToAdd.lockId := input.lockId @@ -595,20 +669,21 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val input = decode.add.stage() val shifter = new Area { - val exp21 = input.rs2.exponent - input.rs1.exponent - val rs1ExponentBigger = exp21.msb + val exp21 = input.rs2.exponent -^ input.rs1.exponent + val rs1ExponentBigger = exp21.msb || input.rs2.isZeroOrSubnormal val rs1ExponentEqual = input.rs1.exponent === input.rs2.exponent val rs1MantissaBigger = input.rs1.mantissa > input.rs2.mantissa - val absRs1Bigger = rs1ExponentBigger|| rs1ExponentEqual && rs1MantissaBigger + val absRs1Bigger = ((rs1ExponentBigger || rs1ExponentEqual && rs1MantissaBigger) && !input.rs1.isZeroOrSubnormal || input.rs1.isInfinity) && !input.rs2.isInfinity val shiftBy = rs1ExponentBigger ? (0-exp21) | exp21 + val passThrough = shiftBy >= p.internalMantissaSize || (input.rs1.isZeroOrSubnormal) || (input.rs2.isZeroOrSubnormal) //Note that rs1ExponentBigger can be replaced by absRs1Bigger bellow to avoid xsigned two complement in math block at expense of combinatorial path val xySign = absRs1Bigger ? input.rs1.sign | input.rs2.sign val xSign = xySign ^ (rs1ExponentBigger ? input.rs1.sign | input.rs2.sign) val ySign = xySign ^ (rs1ExponentBigger ? input.rs2.sign | input.rs1.sign) - val xMantissa = U"1" @@ (rs1ExponentBigger ? input.rs1.mantissa | input.rs2.mantissa) - val yMantissaUnshifted = U"1" @@ (rs1ExponentBigger ? input.rs2.mantissa | input.rs1.mantissa) - val yMantissa = yMantissaUnshifted >> shiftBy + val xMantissa = U"1" @@ (rs1ExponentBigger ? input.rs1.mantissa | input.rs2.mantissa) @@ U"0" + val yMantissaUnshifted = U"1" @@ (rs1ExponentBigger ? input.rs2.mantissa | input.rs1.mantissa) @@ U"0" + val yMantissa = yMantissaUnshifted >> (passThrough.asUInt @@ shiftBy.resize(log2Up(p.internalMantissaSize))) val xyExponent = rs1ExponentBigger ? input.rs1.exponent | input.rs2.exponent } @@ -621,8 +696,9 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ def xySign = shifter.xySign val xSigned = xMantissa.twoComplement(xSign) - val ySigned = yMantissa.twoComplement(ySign) - val xyMantissa = U(xSigned +^ ySigned).trim(1 bits) +// val ySigned = (yMantissa +^ (yMantissa.lsb && !ySign).asUInt).twoComplement(ySign) + val ySigned = ((ySign ## Mux(ySign, ~yMantissa, yMantissa)).asUInt +^ (ySign || yMantissa.lsb).asUInt).asSInt + val xyMantissa = U(xSigned + ySigned).trim(1 bits) } val norm = new Area{ @@ -632,16 +708,13 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val shiftOh = OHMasking.first(xyMantissa.asBools.reverse) val shift = OHToUInt(shiftOh) - val mantissa = (xyMantissa |<< shift) >> 1 - val exponent = xyExponent - shift + 1 - val forceZero = xyMantissa === 0 - val forceOverflow = exponent === exponent.maxValue - val forceNan = -// val - when(forceZero){ //TODO - exponent := 0 - xySign := False - } + val mantissa = (xyMantissa |<< shift) >> 2 +// val mantissaShifted = (xyMantissa |<< shift) +// val mantissa = ((xyMantissa ) >> 2) + U(xyMantissa(1)) + val exponent = xyExponent -^ shift + 1 + val forceZero = xyMantissa === 0 || exponent.msb || (input.rs1.isZeroOrSubnormal && input.rs2.isZeroOrSubnormal) + val forceOverflow = exponent(7 downto 0) === 255 || (input.rs1.isInfinity || input.rs2.isInfinity) + val forceNan = input.rs1.isNan || input.rs2.isNan || (input.rs1.isInfinity && input.rs2.isInfinity && (input.rs1.sign ^ input.rs2.sign)) } @@ -651,7 +724,17 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ output.rd := input.rd output.value.sign := norm.xySign output.value.mantissa := norm.mantissa.resized - output.value.exponent := norm.exponent + output.value.exponent := norm.exponent.resized + output.value.special := False + + when(norm.forceNan) { + output.value.setNanQuiet + } elsewhen(norm.forceZero) { + output.value.setZero; + output.value.sign := False + } elsewhen(norm.forceOverflow) { + output.value.setInfinity + } } diff --git a/src/main/scala/vexriscv/ip/fpu/Interface.scala b/src/main/scala/vexriscv/ip/fpu/Interface.scala index 7b4c9cfd..42c9bcb8 100644 --- a/src/main/scala/vexriscv/ip/fpu/Interface.scala +++ b/src/main/scala/vexriscv/ip/fpu/Interface.scala @@ -22,11 +22,20 @@ case class FpuFloatDecoded() extends Bundle{ val isInfinity = Bool() val isQuiet = Bool() } + +object FpuFloat{ + val ZERO = 0 + val SUBNORMAL = 1 + val INFINITY = 2 + val NAN = 3 +} + case class FpuFloat(exponentSize: Int, mantissaSize: Int) extends Bundle { val mantissa = UInt(mantissaSize bits) val exponent = UInt(exponentSize bits) val sign = Bool() + val special = Bool() def withInvertSign : FpuFloat ={ val ret = FpuFloat(exponentSize,mantissaSize) @@ -37,7 +46,34 @@ case class FpuFloat(exponentSize: Int, } + def isZeroOrSubnormal = special && exponent(1) === False + + def isNormal = !special + def isZero = special && exponent(1 downto 0) === 0 + def isSubnormal = special && exponent(1 downto 0) === 1 + def isInfinity = special && exponent(1 downto 0) === 2 + def isNan = special && exponent(1 downto 0) === 3 + def isQuiet = mantissa.msb + + def setNormal = { special := False } + def setZero = { special := True; exponent(1 downto 0) := 0 } + def setSubnormal = { special := True; exponent(1 downto 0) := 1 } + def setInfinity = { special := True; exponent(1 downto 0) := 2 } + def setNan = { special := True; exponent(1 downto 0) := 3 } + def setNanQuiet = { special := True; exponent(1 downto 0) := 3; mantissa.msb := True } + def decode() = { + val ret = FpuFloatDecoded() + ret.isZero := isZero + ret.isSubnormal := isSubnormal + ret.isNormal := isNormal + ret.isInfinity := isInfinity + ret.isNan := isNan + ret.isQuiet := mantissa.msb + ret + } + + def decodeIeee754() = { val ret = FpuFloatDecoded() val expZero = exponent === 0 val expOne = exponent === exponent.maxValue @@ -46,7 +82,7 @@ case class FpuFloat(exponentSize: Int, ret.isSubnormal := expZero && !manZero ret.isNormal := !expOne && !expZero ret.isInfinity := expOne && manZero - ret.isNan := expOne && !manZero// && !sign + ret.isNan := expOne && !manZero ret.isQuiet := mantissa.msb ret } diff --git a/src/main/scala/vexriscv/plugin/FpuPlugin.scala b/src/main/scala/vexriscv/plugin/FpuPlugin.scala index 082ddd21..4d639efc 100644 --- a/src/main/scala/vexriscv/plugin/FpuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/FpuPlugin.scala @@ -174,7 +174,7 @@ class FpuPlugin(externalFpu : Boolean = false, port.cmd.opcode := input(FPU_OPCODE) port.cmd.value := RegNext(output(RS1)) port.cmd.arg := input(FPU_ARG) - port.cmd.rs1 := input(INSTRUCTION)(rs1Range).asUInt + port.cmd.rs1 := ((input(FPU_OPCODE) === FpuOpcode.STORE) ? input(INSTRUCTION)(rs2Range).asUInt | input(INSTRUCTION)(rs1Range).asUInt) port.cmd.rs2 := input(INSTRUCTION)(rs2Range).asUInt port.cmd.rs3 := input(INSTRUCTION)(rs3Range).asUInt port.cmd.rd := input(INSTRUCTION)(rdRange).asUInt diff --git a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala index 3b8c78db..23dc1d33 100644 --- a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala +++ b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala @@ -14,6 +14,10 @@ import scala.util.Random class FpuTest extends FunSuite{ + val b2f = lang.Float.intBitsToFloat(_) + def clamp(f : Float) = { + if(f.abs < b2f(0x00800000)) 0.0f*f.signum else f + } test("directed"){ val portCount = 1 @@ -81,8 +85,8 @@ class FpuTest extends FunSuite{ cmdQueue += {cmd => cmd.opcode #= cmd.opcode.spinalEnum.STORE cmd.value.randomize() - cmd.rs1.randomize() - cmd.rs2 #= rs + cmd.rs1 #= rs + cmd.rs2.randomize() cmd.rs3.randomize() cmd.rd.randomize() cmd.arg.randomize() @@ -92,7 +96,7 @@ class FpuTest extends FunSuite{ } def storeFloat(rs : Int)(body : Float => Unit): Unit ={ - storeRaw(rs){rsp => body(lang.Float.intBitsToFloat(rsp.value.toLong.toInt))} + storeRaw(rs){rsp => body(b2f(rsp.value.toLong.toInt))} } def mul(rd : Int, rs1 : Int, rs2 : Int): Unit ={ @@ -304,9 +308,19 @@ class FpuTest extends FunSuite{ } } def checkFloat(ref : Float, dut : Float): Boolean ={ - if(ref === dut) return true - ref.abs * 1.0001 > dut.abs && ref.abs * 0.9999 < dut.abs && ref.signum == dut.signum + if(ref.signum != dut.signum === dut) return false + if(ref.isNaN && dut.isNaN) return true + if(ref == dut) return true + if(ref.abs * 1.0001 > dut.abs && ref.abs * 0.9999 < dut.abs && ref.signum == dut.signum) return true + false } + def checkFloatExact(ref : Float, dut : Float): Boolean ={ + if(ref.signum != dut.signum === dut) return false + if(ref.isNaN && dut.isNaN) return true + if(ref == dut) return true + false + } + def randomFloat(): Float ={ val exp = Random.nextInt(10)-5 @@ -322,7 +336,9 @@ class FpuTest extends FunSuite{ add(rd,rs1,rs2) storeFloat(rd){v => - val ref = a+b + val a_ = clamp(a) + val b_ = clamp(b) + val ref = clamp(a_ + b_) println(f"$a + $b = $v, $ref") assert(checkFloat(ref, v)) } @@ -450,7 +466,7 @@ class FpuTest extends FunSuite{ val rd = Random.nextInt(32) fmv_w_x(rd, a) storeFloat(rd){v => - val ref = lang.Float.intBitsToFloat(a) + val ref = b2f(a) println(f"fmv_w_x $a = $v, $ref") assert(v === ref) } @@ -488,16 +504,35 @@ class FpuTest extends FunSuite{ } } - - val b2f = lang.Float.intBitsToFloat(_) + //Todo negative + def withMinus(that : Seq[Float]) = that.flatMap(f => List(f, -f)) + val fZeros = withMinus(List(0.0f)) + val fSubnormals = withMinus(List(b2f(0x00000000+1), b2f(0x00000000+2), b2f(0x00800000-2), b2f(0x00800000-1))) + val fExpSmall = withMinus(List(b2f(0x00800000), b2f(0x00800000+1), b2f(0x00800000 + 2))) + val fExpNormal = withMinus(List(b2f(0x3f800000-2), b2f(0x3f800000-1), b2f(0x3f800000), b2f(0x3f800000+1), b2f(0x3f800000+2))) + val fExpBig = withMinus(List(b2f(0x7f7fffff-2), b2f(0x7f7fffff-1), b2f(0x7f7fffff))) + val fInfinity = withMinus(List(Float.PositiveInfinity)) + val fNan = List(Float.NaN, b2f(0x7f820000), b2f(0x7fc00000)) + val fAll = fZeros ++ fSubnormals ++ fExpSmall ++ fExpNormal ++ fExpBig ++ fInfinity ++ fNan + testAdd(b2f(0x3f800000), b2f(0x3f800000-1)) + testAdd(1.1f, 2.3f) testAdd(1.2f, -1.2f) testAdd(-1.2f, 1.2f) testAdd(0.0f, -1.2f) testAdd(-0.0f, -1.2f) testAdd(1.2f, -0f) testAdd(1.2f, 0f) + testAdd(1.1f, Float.MinPositiveValue) + + for(a <- fAll; _ <- 0 until 50) testAdd(a, randomFloat()) + for(b <- fAll; _ <- 0 until 50) testAdd(randomFloat(), b) + for(a <- fAll; b <- fAll) testAdd(a, b) + for(_ <- 0 until 1000) testAdd(randomFloat(), randomFloat()) + +// dut.clockDomain.waitSampling(10000000) + testFmv_x_w(1.246f) testFmv_w_x(lang.Float.floatToIntBits(7.234f)) @@ -590,9 +625,7 @@ class FpuTest extends FunSuite{ testDiv(1.0f, b2f(0x3f800001)) testDiv(1.0f, b2f(0x3f800002)) - for(i <- 0 until 1000){ - testAdd(randomFloat(), randomFloat()) - } + for(i <- 0 until 1000){ testMul(randomFloat(), randomFloat()) } diff --git a/src/test/scala/vexriscv/ip/fpu/Playground.scala b/src/test/scala/vexriscv/ip/fpu/Playground.scala index f5df1440..a1552100 100644 --- a/src/test/scala/vexriscv/ip/fpu/Playground.scala +++ b/src/test/scala/vexriscv/ip/fpu/Playground.scala @@ -42,4 +42,6 @@ object MiaouNan extends App{ println(3.0f + Float.NaN ) println(0.0f*Float.PositiveInfinity ) println(1.0f/0.0f ) + println(Float.MaxValue -1 ) + println(Float.PositiveInfinity - Float.PositiveInfinity) } \ No newline at end of file From 7d79685fe241582675b1609220c6f0668f3adfc0 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 22 Jan 2021 18:15:45 +0100 Subject: [PATCH 547/951] fpu mul now support special floats values and better rounding --- src/main/scala/vexriscv/ip/fpu/FpuCore.scala | 46 +++++++++++++++++--- src/test/scala/vexriscv/ip/fpu/FpuTest.scala | 30 ++++++++++--- 2 files changed, 63 insertions(+), 13 deletions(-) diff --git a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala index bf5749bb..606f8fc6 100644 --- a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala +++ b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala @@ -463,19 +463,41 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val mulA = U(input.msb1) @@ input.rs1.mantissa val mulB = U(input.msb2) @@ input.rs2.mantissa val mulC = mulA * mulB - val exp = input.rs1.exponent +^ input.rs2.exponent - ((1 << p.internalExponentSize - 1) - 1) + val expOffset = ((1 << p.internalExponentSize - 1) - 1) + val exp = input.rs1.exponent +^ input.rs2.exponent } val norm = new Area{ - val needShift = math.mulC.msb +// val needShift = math.mulC.msb +// val exp = math.exp + U(needShift) +// val man = needShift ? math.mulC(p.internalMantissaSize + 1, p.internalMantissaSize bits) | math.mulC(p.internalMantissaSize, p.internalMantissaSize bits) + + val mulRounded = (math.mulC >> p.internalMantissaSize) + math.mulC(p.internalMantissaSize-1).asUInt + val needShift = mulRounded.msb val exp = math.exp + U(needShift) - val man = needShift ? math.mulC(p.internalMantissaSize + 1, p.internalMantissaSize bits) | math.mulC(p.internalMantissaSize, p.internalMantissaSize bits) + val man = needShift ? mulRounded(1, p.internalMantissaSize bits) | mulRounded(0, p.internalMantissaSize bits) + + val forceZero = input.rs1.isZeroOrSubnormal || input.rs2.isZeroOrSubnormal + val forceUnderflow = exp <= math.expOffset + val forceOverflow = exp > math.expOffset+254 || input.rs1.isInfinity || input.rs2.isInfinity + val forceNan = input.rs1.isNan || input.rs2.isNan || ((input.rs1.isInfinity || input.rs2.isInfinity) && (input.rs1.isZero || input.rs2.isZero)) val output = FpuFloat(p.internalExponentSize, p.internalMantissaSize) output.sign := input.rs1.sign ^ input.rs2.sign - output.exponent := exp.resized + output.exponent := (exp - math.expOffset).resized output.mantissa := man - output.special := False //TODO + output.setNormal + + when(forceNan) { + output.setNanQuiet + } elsewhen(forceOverflow) { + output.setInfinity + } elsewhen(forceZero) { + output.setZero + } elsewhen(forceUnderflow) { + output.setZero + } + } val notMul = new Area{ @@ -529,6 +551,8 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ decode.divSqrtToMul.divSqrt := True decode.divSqrtToMul.msb1 := True decode.divSqrtToMul.msb2 := True + decode.divSqrtToMul.rs1.special := False //TODO + decode.divSqrtToMul.rs2.special := False val aprox = new Area { @@ -712,6 +736,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ // val mantissaShifted = (xyMantissa |<< shift) // val mantissa = ((xyMantissa ) >> 2) + U(xyMantissa(1)) val exponent = xyExponent -^ shift + 1 + xySign clearWhen(input.rs1.isZeroOrSubnormal && input.rs2.isZeroOrSubnormal) val forceZero = xyMantissa === 0 || exponent.msb || (input.rs1.isZeroOrSubnormal && input.rs2.isZeroOrSubnormal) val forceOverflow = exponent(7 downto 0) === 255 || (input.rs1.isInfinity || input.rs2.isInfinity) val forceNan = input.rs1.isNan || input.rs2.isNan || (input.rs1.isInfinity && input.rs2.isInfinity && (input.rs1.sign ^ input.rs2.sign)) @@ -730,8 +755,10 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ when(norm.forceNan) { output.value.setNanQuiet } elsewhen(norm.forceZero) { - output.value.setZero; - output.value.sign := False + output.value.setZero + when(norm.xyMantissa === 0 || input.rs1.isZeroOrSubnormal && input.rs2.isZeroOrSubnormal){ + output.value.sign := input.rs1.sign && input.rs2.sign + } } elsewhen(norm.forceOverflow) { output.value.setInfinity } @@ -757,6 +784,11 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ port.valid := commited.valid && rf.lock.map(_.write).read(commited.lockId) port.address := commited.source @@ commited.rd port.data := commited.value + + when(port.valid){ + assert(!(port.data.exponent === 0 && !port.data.special)) + assert(!(port.data.exponent === port.data.exponent.maxValue && !port.data.special)) + } } } diff --git a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala index 23dc1d33..b30b4119 100644 --- a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala +++ b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala @@ -15,8 +15,9 @@ import scala.util.Random class FpuTest extends FunSuite{ val b2f = lang.Float.intBitsToFloat(_) + val f2b = lang.Float.floatToIntBits(_) def clamp(f : Float) = { - if(f.abs < b2f(0x00800000)) 0.0f*f.signum else f + if(f.abs < b2f(0x00800000)) b2f(f2b(f) & 0x80000000) else f } test("directed"){ @@ -308,7 +309,8 @@ class FpuTest extends FunSuite{ } } def checkFloat(ref : Float, dut : Float): Boolean ={ - if(ref.signum != dut.signum === dut) return false + if(ref.signum != dut.signum) return false + if(ref == 0.0 && dut == 0.0 && f2b(ref) != f2b(dut)) return false if(ref.isNaN && dut.isNaN) return true if(ref == dut) return true if(ref.abs * 1.0001 > dut.abs && ref.abs * 0.9999 < dut.abs && ref.signum == dut.signum) return true @@ -353,9 +355,13 @@ class FpuTest extends FunSuite{ mul(rd,rs1,rs2) storeFloat(rd){v => - val ref = a*b + val refUnclamped = a*b + val refClamped = clamp(clamp(a)*clamp(b)) + val ref = if(refClamped.isNaN) refUnclamped else refClamped println(f"$a * $b = $v, $ref") - assert(checkFloat(ref, v)) + var checkIt = true + if(v == 0.0f && ref.abs == b2f(0x00800000)) checkIt = false //Rounding + if(checkIt) assert(checkFloat(ref, v)) } } @@ -504,7 +510,7 @@ class FpuTest extends FunSuite{ } } - //Todo negative + def withMinus(that : Seq[Float]) = that.flatMap(f => List(f, -f)) val fZeros = withMinus(List(0.0f)) val fSubnormals = withMinus(List(b2f(0x00000000+1), b2f(0x00000000+2), b2f(0x00800000-2), b2f(0x00800000-1))) @@ -516,6 +522,14 @@ class FpuTest extends FunSuite{ val fAll = fZeros ++ fSubnormals ++ fExpSmall ++ fExpNormal ++ fExpBig ++ fInfinity ++ fNan + + testMul(1.2f, 0f) + for(a <- fAll; _ <- 0 until 50) testMul(a, randomFloat()) + for(b <- fAll; _ <- 0 until 50) testMul(randomFloat(), b) + for(a <- fAll; b <- fAll) testMul(a, b) + for(_ <- 0 until 1000) testMul(randomFloat(), randomFloat()) + + testAdd(b2f(0x3f800000), b2f(0x3f800000-1)) testAdd(1.1f, 2.3f) testAdd(1.2f, -1.2f) @@ -531,7 +545,11 @@ class FpuTest extends FunSuite{ for(a <- fAll; b <- fAll) testAdd(a, b) for(_ <- 0 until 1000) testAdd(randomFloat(), randomFloat()) -// dut.clockDomain.waitSampling(10000000) + + + + + // dut.clockDomain.waitSampling(10000000) testFmv_x_w(1.246f) From bdb5bc118051860ac8e1fed6a485205f5eb8e86c Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 22 Jan 2021 20:47:31 +0100 Subject: [PATCH 548/951] fpu div implement some special values handeling --- src/main/scala/vexriscv/ip/fpu/FpuCore.scala | 55 ++++++++++++++++---- src/test/scala/vexriscv/ip/fpu/FpuTest.scala | 12 ++++- 2 files changed, 57 insertions(+), 10 deletions(-) diff --git a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala index 606f8fc6..33a792ed 100644 --- a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala +++ b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala @@ -643,6 +643,14 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ decode.divSqrtToMul.rs2.sign := input.rs2.sign decode.divSqrtToMul.rs2.exponent := divExp.value + iterationValue.msb.asUInt decode.divSqrtToMul.rs2.mantissa := (iterationValue << 1).resized + val overflow = input.rs2.isZeroOrSubnormal + val nan = input.rs2.isNan || (input.rs1.isZeroOrSubnormal && input.rs2.isZeroOrSubnormal) + + when(nan){ + decode.divSqrtToMul.rs2.setNanQuiet + } elsewhen(overflow) { + decode.divSqrtToMul.rs2.setInfinity + } when(decode.divSqrtToMul.ready) { state := IDLE input.ready := True @@ -806,17 +814,37 @@ object FpuSynthesisBench extends App{ }) } + class Shifter(width : Int) extends Rtl{ + override def getName(): String = "shifter_" + width + override def getRtlPath(): String = getName() + ".v" + SpinalVerilog(new Component{ + val a = in UInt(width bits) + val sel = in UInt(log2Up(width) bits) + val result = out(a >> sel) + setDefinitionName(Shifter.this.getName()) + }) + } + class Rotate(width : Int) extends Rtl{ + override def getName(): String = "rotate_" + width + override def getRtlPath(): String = getName() + ".v" + SpinalVerilog(new Component{ + val a = in UInt(width bits) + val sel = in UInt(log2Up(width) bits) + val result = out(a.rotateLeft(sel)) + setDefinitionName(Rotate.this.getName()) + }) + } - val rtls = ArrayBuffer[Fpu]() - rtls += new Fpu( - "32", - portCount = 1, - FpuParameter( - internalMantissaSize = 23, - withDouble = false - ) - ) + val rtls = ArrayBuffer[Rtl]() +// rtls += new Fpu( +// "32", +// portCount = 1, +// FpuParameter( +// internalMantissaSize = 23, +// withDouble = false +// ) +// ) // rtls += new Fpu( // "64", // portCount = 1, @@ -826,6 +854,15 @@ object FpuSynthesisBench extends App{ // ) // ) +// rtls += new Shifter(24) +// rtls += new Shifter(32) +// rtls += new Shifter(52) +// rtls += new Shifter(64) + rtls += new Rotate(24) + rtls += new Rotate(32) + rtls += new Rotate(52) + rtls += new Rotate(64) + val targets = XilinxStdTargets()// ++ AlteraStdTargets() diff --git a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala index b30b4119..17dafff0 100644 --- a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala +++ b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala @@ -393,7 +393,9 @@ class FpuTest extends FunSuite{ div(rd,rs1,rs2) storeFloat(rd){v => - val ref = a/b + val refUnclamped = a/b + val refClamped = clamp(clamp(a)/clamp(b)) + val ref = refClamped val error = Math.abs(ref-v)/ref println(f"$a / $b = $v, $ref $error") assert(checkFloat(ref, v)) @@ -522,6 +524,14 @@ class FpuTest extends FunSuite{ val fAll = fZeros ++ fSubnormals ++ fExpSmall ++ fExpNormal ++ fExpBig ++ fInfinity ++ fNan +// testDiv(0.0f, 1.2f ) +// testDiv(1.2f, 0.0f ) +// testDiv(0.0f, 0.0f ) +// for(a <- fAll; _ <- 0 until 50) testDiv(a, randomFloat()) +// for(a <- fAll; b <- fAll) testDiv(a, b) +// for(_ <- 0 until 1000) testDiv(randomFloat(), randomFloat()) + + testMul(1.2f, 0f) for(a <- fAll; _ <- 0 until 50) testMul(a, randomFloat()) From ce143e06f23603be402f6aaf4185dfd45afd91f8 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sat, 23 Jan 2021 17:48:34 +0100 Subject: [PATCH 549/951] VexRiscvSmpLitex --in-order-decoder --wishbone-memory added --- .../demo/smp/VexRiscvSmpCluster.scala | 6 +- .../demo/smp/VexRiscvSmpLitexCluster.scala | 97 +++++++++++-------- 2 files changed, 59 insertions(+), 44 deletions(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index 29385ca3..e01bd87c 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -22,7 +22,7 @@ import scala.collection.mutable import scala.collection.mutable.ArrayBuffer import spinal.lib.generator._ -case class VexRiscvSmpClusterParameter(cpuConfigs : Seq[VexRiscvConfig], withExclusiveAndInvalidation : Boolean) +case class VexRiscvSmpClusterParameter(cpuConfigs : Seq[VexRiscvConfig], withExclusiveAndInvalidation : Boolean, forcePeripheralWidth : Boolean = true, outOfOrderDecoder : Boolean = true) class VexRiscvSmpClusterBase(p : VexRiscvSmpClusterParameter) extends Generator{ val cpuCount = p.cpuConfigs.size @@ -54,7 +54,7 @@ class VexRiscvSmpClusterBase(p : VexRiscvSmpClusterParameter) extends Generator{ val invalidationMonitor = BmbInvalidateMonitorGenerator() interconnect.addConnection(exclusiveMonitor.output, invalidationMonitor.input) interconnect.addConnection(invalidationMonitor.output, dBusNonCoherent.bmb) - interconnect.masters(invalidationMonitor.output).withOutOfOrderDecoder() + if(p.outOfOrderDecoder) interconnect.masters(invalidationMonitor.output).withOutOfOrderDecoder() } val noSmp = !p.withExclusiveAndInvalidation generate new Area{ @@ -80,7 +80,7 @@ class VexRiscvSmpClusterBase(p : VexRiscvSmpClusterParameter) extends Generator{ class VexRiscvSmpClusterWithPeripherals(p : VexRiscvSmpClusterParameter) extends VexRiscvSmpClusterBase(p) { val peripheralBridge = BmbToWishboneGenerator(DefaultMapping) val peripheral = peripheralBridge.produceIo(peripheralBridge.logic.io.output) - interconnect.slaves(peripheralBridge.bmb).forceAccessSourceDataWidth(32) + if(p.forcePeripheralWidth) interconnect.slaves(peripheralBridge.bmb).forceAccessSourceDataWidth(32) val plic = BmbPlicGenerator()(interconnect = null) plic.priorityWidth.load(2) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala index bd14d432..585a1a09 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala @@ -12,24 +12,31 @@ import vexriscv.plugin.{AesPlugin, DBusCachedPlugin} case class VexRiscvLitexSmpClusterParameter( cluster : VexRiscvSmpClusterParameter, liteDram : LiteDramNativeParameter, liteDramMapping : AddressMapping, - coherentDma : Boolean) + coherentDma : Boolean, + wishboneMemory : Boolean) class VexRiscvLitexSmpCluster(p : VexRiscvLitexSmpClusterParameter) extends VexRiscvSmpClusterWithPeripherals(p.cluster) { val iArbiter = BmbBridgeGenerator() - val iBridge = BmbToLiteDramGenerator(p.liteDramMapping) - val dBridge = BmbToLiteDramGenerator(p.liteDramMapping) + val iBridge = !p.wishboneMemory generate BmbToLiteDramGenerator(p.liteDramMapping) + val dBridge = !p.wishboneMemory generate BmbToLiteDramGenerator(p.liteDramMapping) for(core <- cores) interconnect.addConnection(core.cpu.iBus -> List(iArbiter.bmb)) + !p.wishboneMemory generate interconnect.addConnection( + iArbiter.bmb -> List(iBridge.bmb), + dBusNonCoherent.bmb -> List(dBridge.bmb) + ) interconnect.addConnection( - iArbiter.bmb -> List(iBridge.bmb, peripheralBridge.bmb), - dBusNonCoherent.bmb -> List(dBridge.bmb, peripheralBridge.bmb) + iArbiter.bmb -> List(peripheralBridge.bmb), + dBusNonCoherent.bmb -> List(peripheralBridge.bmb) ) if(p.cluster.withExclusiveAndInvalidation) interconnect.masters(dBusNonCoherent.bmb).withOutOfOrderDecoder() - dBridge.liteDramParameter.load(p.liteDram) - iBridge.liteDramParameter.load(p.liteDram) + if(!p.wishboneMemory) { + dBridge.liteDramParameter.load(p.liteDram) + iBridge.liteDramParameter.load(p.liteDram) + } // Coherent DMA interface val dma = p.coherentDma generate new Area { @@ -52,7 +59,7 @@ class VexRiscvLitexSmpCluster(p : VexRiscvLitexSmpClusterParameter) extends VexR interconnect.setPipelining(iArbiter.bmb)(cmdHalfRate = true, rspValid = true) } interconnect.setPipelining(dBusNonCoherent.bmb)(cmdValid = true, cmdReady = true, rspValid = true) - interconnect.setPipelining(peripheralBridge.bmb)(cmdHalfRate = true, rspValid = true) + interconnect.setPipelining(peripheralBridge.bmb)(cmdHalfRate = !p.wishboneMemory, cmdValid = p.wishboneMemory, cmdReady = p.wishboneMemory, rspValid = true) } @@ -66,6 +73,8 @@ object VexRiscvLitexSmpClusterCmdGen extends App { var dCacheWays = 2 var liteDramWidth = 128 var coherentDma = false + var wishboneMemory = false + var outOfOrderDecoder = true var aesInstruction = false var netlistDirectory = "." var netlistName = "VexRiscvLitexSmpCluster" @@ -83,6 +92,8 @@ object VexRiscvLitexSmpClusterCmdGen extends App { opt[String]("netlist-directory") action { (v, c) => netlistDirectory = v } opt[String]("netlist-name") action { (v, c) => netlistName = v } opt[String]("aes-instruction") action { (v, c) => aesInstruction = v.toBoolean } + opt[Unit]("in-order-decoder") action { (v, c) => outOfOrderDecoder = false } + opt[Unit]("wishbone-memory") action { (v, c) => wishboneMemory = true } }.parse(args)) val coherency = coherentDma || cpuCount > 1 @@ -104,11 +115,14 @@ object VexRiscvLitexSmpClusterCmdGen extends App { if(aesInstruction) c.add(new AesPlugin) c }}, - withExclusiveAndInvalidation = coherency + withExclusiveAndInvalidation = coherency, + forcePeripheralWidth = !wishboneMemory, + outOfOrderDecoder = outOfOrderDecoder ), liteDram = LiteDramNativeParameter(addressWidth = 32, dataWidth = liteDramWidth), liteDramMapping = SizeMapping(0x40000000l, 0x40000000l), - coherentDma = coherentDma + coherentDma = coherentDma, + wishboneMemory = wishboneMemory ) def dutGen = { @@ -124,36 +138,36 @@ object VexRiscvLitexSmpClusterCmdGen extends App { } -object VexRiscvLitexSmpClusterGen extends App { - for(cpuCount <- List(1,2,4,8)) { - def parameter = VexRiscvLitexSmpClusterParameter( - cluster = VexRiscvSmpClusterParameter( - cpuConfigs = List.tabulate(cpuCount) { hartId => - vexRiscvConfig( - hartId = hartId, - ioRange = address => address.msb, - resetVector = 0 - ) - }, - withExclusiveAndInvalidation = true - ), - liteDram = LiteDramNativeParameter(addressWidth = 32, dataWidth = 128), - liteDramMapping = SizeMapping(0x40000000l, 0x40000000l), - coherentDma = false - ) - - def dutGen = { - val toplevel = new VexRiscvLitexSmpCluster( - p = parameter - ).toComponent() - toplevel - } - - val genConfig = SpinalConfig().addStandardMemBlackboxing(blackboxByteEnables) - // genConfig.generateVerilog(Bench.compressIo(dutGen)) - genConfig.generateVerilog(dutGen.setDefinitionName(s"VexRiscvLitexSmpCluster_${cpuCount}c")) - } -} +//object VexRiscvLitexSmpClusterGen extends App { +// for(cpuCount <- List(1,2,4,8)) { +// def parameter = VexRiscvLitexSmpClusterParameter( +// cluster = VexRiscvSmpClusterParameter( +// cpuConfigs = List.tabulate(cpuCount) { hartId => +// vexRiscvConfig( +// hartId = hartId, +// ioRange = address => address.msb, +// resetVector = 0 +// ) +// }, +// withExclusiveAndInvalidation = true +// ), +// liteDram = LiteDramNativeParameter(addressWidth = 32, dataWidth = 128), +// liteDramMapping = SizeMapping(0x40000000l, 0x40000000l), +// coherentDma = false +// ) +// +// def dutGen = { +// val toplevel = new VexRiscvLitexSmpCluster( +// p = parameter +// ).toComponent() +// toplevel +// } +// +// val genConfig = SpinalConfig().addStandardMemBlackboxing(blackboxByteEnables) +// // genConfig.generateVerilog(Bench.compressIo(dutGen)) +// genConfig.generateVerilog(dutGen.setDefinitionName(s"VexRiscvLitexSmpCluster_${cpuCount}c")) +// } +//} ////addAttribute("""mark_debug = "true"""") object VexRiscvLitexSmpClusterOpenSbi extends App{ @@ -178,7 +192,8 @@ object VexRiscvLitexSmpClusterOpenSbi extends App{ ), liteDram = LiteDramNativeParameter(addressWidth = 32, dataWidth = 128), liteDramMapping = SizeMapping(0x80000000l, 0x70000000l), - coherentDma = false + coherentDma = false, + wishboneMemory = false ) def dutGen = { From d6e8a5ef22042ddb962cfbf627efe909bb23da95 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sat, 23 Jan 2021 20:16:58 +0100 Subject: [PATCH 550/951] VexRiscvSmpLitex options refractoring --- .../scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala index 585a1a09..4098f9e9 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala @@ -92,8 +92,8 @@ object VexRiscvLitexSmpClusterCmdGen extends App { opt[String]("netlist-directory") action { (v, c) => netlistDirectory = v } opt[String]("netlist-name") action { (v, c) => netlistName = v } opt[String]("aes-instruction") action { (v, c) => aesInstruction = v.toBoolean } - opt[Unit]("in-order-decoder") action { (v, c) => outOfOrderDecoder = false } - opt[Unit]("wishbone-memory") action { (v, c) => wishboneMemory = true } + opt[String]("out-of-order-decoder") action { (v, c) => outOfOrderDecoder = v.toBoolean } + opt[String]("wishbone-memory" ) action { (v, c) => wishboneMemory = v.toBoolean } }.parse(args)) val coherency = coherentDma || cpuCount > 1 From f818fb3ba43f746fa8cbafccbaa199d4d4ea57c3 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 26 Jan 2021 10:49:53 +0100 Subject: [PATCH 551/951] fpu got proper subnormal support, pass add/mul --- src/main/scala/vexriscv/ip/fpu/FpuCore.scala | 330 +++++++++++++----- .../scala/vexriscv/ip/fpu/Interface.scala | 10 +- .../scala/vexriscv/plugin/FpuPlugin.scala | 18 +- src/test/scala/vexriscv/ip/fpu/FpuTest.scala | 71 ++-- 4 files changed, 304 insertions(+), 125 deletions(-) diff --git a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala index 33a792ed..88fa0e0d 100644 --- a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala +++ b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala @@ -227,13 +227,13 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val input = read.output.combStage() input.ready := False - val loadHit = input.opcode === p.Opcode.LOAD + val loadHit = List(FpuOpcode.LOAD, FpuOpcode.FMV_W_X).map(input.opcode === _).orR val load = Stream(LoadInput()) load.valid := input.valid && loadHit input.ready setWhen(loadHit && load.ready) load.payload.assignSomeByName(read.output.payload) - val shortPipHit = List(FpuOpcode.STORE, FpuOpcode.F2I, FpuOpcode.CMP, FpuOpcode.I2F, FpuOpcode.MIN_MAX, FpuOpcode.SGNJ, FpuOpcode.FMV_X_W, FpuOpcode.FMV_W_X, FpuOpcode.FCLASS).map(input.opcode === _).orR + val shortPipHit = List(FpuOpcode.STORE, FpuOpcode.F2I, FpuOpcode.CMP, FpuOpcode.I2F, FpuOpcode.MIN_MAX, FpuOpcode.SGNJ, FpuOpcode.FMV_X_W, FpuOpcode.FCLASS).map(input.opcode === _).orR val shortPip = Stream(ShortPipInput()) input.ready setWhen(shortPipHit && shortPip.ready) shortPip.valid := input.valid && shortPipHit @@ -283,43 +283,99 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } val load = new Area{ - val input = decode.load.stage() - val filtred = commitFork.load.map(port => port.takeWhen(port.load)) - def feed = filtred(input.source) - val hazard = !feed.valid - val f32Mantissa = feed.value(0, 23 bits).asUInt - val f32Exponent = feed.value(23, 8 bits).asUInt - val f32Sign = feed.value(31) + case class S0() extends Bundle{ + val source = Source() + val lockId = lockIdType() + val rd = p.rfAddress() + val value = FpuFloat(exponentSize = p.internalExponentSize-1, mantissaSize = p.internalMantissaSize) + } - val expZero = f32Exponent === 0 - val expOne = f32Exponent === 255 - val manZero = f32Mantissa === 0 + val s0 = new Area{ + val input = decode.load.stage() + val filtred = commitFork.load.map(port => port.takeWhen(port.sync)) + def feed = filtred(input.source) + val hazard = !feed.valid - val isZero = expZero && manZero - val isSubnormal = expZero && !manZero - val isNormal = !expOne && !expZero - val isInfinity = expOne && manZero - val isNan = expOne && !manZero - val isQuiet = f32Mantissa.msb + val output = input.haltWhen(hazard).swapPayload(S0()) + filtred.foreach(_.ready := False) + feed.ready := input.valid && output.ready + output.source := input.source + output.lockId := input.lockId + output.rd := input.rd + output.value.mantissa := feed.value(0, 23 bits).asUInt + output.value.exponent := feed.value(23, 8 bits).asUInt + output.value.sign := feed.value(31) + } - val recoded = p.internalFloating() - recoded.mantissa := f32Mantissa - recoded.exponent := f32Exponent - recoded.sign := f32Sign - recoded.setNormal - when(isZero){recoded.setZero} - when(isSubnormal){recoded.setSubnormal} - when(isInfinity){recoded.setInfinity} - when(isNan){recoded.setNan} + val s1 = new Area{ + val input = s0.output.stage() + val busy = False - val output = input.haltWhen(hazard).swapPayload(WriteInput()) - filtred.foreach(_.ready := False) - feed.ready := input.valid && output.ready - output.source := input.source - output.lockId := input.lockId - output.rd := input.rd - output.value := recoded + val f32Mantissa = input.value.mantissa + val f32Exponent = input.value.exponent + val f32Sign = input.value.sign + + val expZero = f32Exponent === 0 + val expOne = f32Exponent === 255 + val manZeroReject = Reg(Bool()) setWhen(busy) clearWhen(!input.isStall) + val manZero = f32Mantissa === 0 && !manZeroReject + + val isZero = expZero && manZero + val isSubnormal = expZero && !manZero + val isNormal = !expOne && !expZero + val isInfinity = expOne && manZero + val isNan = expOne && !manZero + val isQuiet = f32Mantissa.msb + + val subnormal = new Area{ + val manTop = Reg(UInt(log2Up(p.internalMantissaSize) bits)) + val shift = isSubnormal ? manTop | U(0) + val counter = Reg(UInt(log2Up(p.internalMantissaSize+1) bits)) + val done, boot = Reg(Bool()) + when(isSubnormal && !done){ + busy := True + when(boot){ + manTop := OHToUInt(OHMasking.first((f32Mantissa).reversed)) + boot := False + } otherwise { + input.value.mantissa.getDrivingReg := input.value.mantissa |<< 1 + counter := counter + 1 + when(counter === shift) { + done := True + } + } + } + + val expOffset = (UInt(p.internalExponentSize bits)) + expOffset := 0 + when(isSubnormal){ + expOffset := manTop.resized + } + + when(!input.isStall){ + counter := 0 + done := False + boot := True + } + } + + val recoded = p.internalFloating() + recoded.mantissa := f32Mantissa + recoded.exponent := (f32Exponent -^ subnormal.expOffset + (exponentOne - 127)).resized + recoded.sign := f32Sign + recoded.setNormal + when(isZero){recoded.setZero} + //when(isSubnormal){recoded.setSubnormal} + when(isInfinity){recoded.setInfinity} + when(isNan){recoded.setNan} + + val output = input.haltWhen(busy).swapPayload(WriteInput()) + output.source := input.source + output.lockId := input.lockId + output.rd := input.rd + output.value := recoded + } } val shortPip = new Area{ @@ -330,23 +386,62 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val result = p.storeLoadType().assignDontCare() val recoded = CombInit(input.rs1) + + + val halt = False + val recodedResult = Bits(32 bits)//recoded.asBits.resize(32 bits) + val f32 = new Area{ + val exp = (recoded.exponent - (exponentOne-127)).resize(8 bits) + val man = recoded.mantissa + } + recodedResult := recoded.sign ## f32.exp ## f32.man + + val subnormal = new Area{ + val isSubnormal = !recoded.special && recoded.exponent <= exponentOne - 127 + val manTop = Reg(UInt(log2Up(p.internalMantissaSize) bits)) + val shift = isSubnormal ? manTop | U(0) + val counter = Reg(UInt(log2Up(p.internalMantissaSize+1) bits)) + val done, boot = Reg(Bool()) + when(isSubnormal && !done){ + halt := True + when(boot){ + manTop := (U(exponentOne - 127) - recoded.exponent).resized + boot := False + } otherwise { + recoded.mantissa.getDrivingReg := (U(counter === 0) @@ recoded.mantissa) >> 1 + counter := counter + 1 + when(counter === shift) { + done := True + } + } + } + + when(isSubnormal){ + f32.exp := 0 + } + when(!input.isStall){ + counter := 0 + done := False + boot := True + } + } + when(recoded.special){ switch(input.rs1.exponent(1 downto 0)){ is(FpuFloat.ZERO){ - recoded.mantissa.clearAll() - recoded.exponent.clearAll() + recodedResult(0,23 bits).clearAll() + recodedResult(23, 8 bits).clearAll() } is(FpuFloat.INFINITY){ - recoded.mantissa.clearAll() - recoded.exponent.setAll() + recodedResult(0, 23 bits).clearAll() + recodedResult(23, 8 bits).setAll() } is(FpuFloat.NAN){ - recoded.exponent.setAll() + recodedResult(23, 8 bits).setAll() } } } - val recodedResult = recoded.asBits.resize(32 bits) val f2iShift = input.rs1.exponent - U(exponentOne) val f2iShifted = (U"1" @@ input.rs1.mantissa) << (f2iShift.resize(5 bits)) @@ -367,32 +462,33 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ 3 -> (!rs1AbsSmaller && !rs1Equal) ) - val rawToFpu = new Area{ - val f32Mantissa = input.value(0, 23 bits).asUInt - val f32Exponent = input.value(23, 8 bits).asUInt - val f32Sign = input.value(31) - - val expZero = f32Exponent === 0 - val expOne = f32Exponent === 255 - val manZero = f32Mantissa === 0 - - val isZero = expZero && manZero - val isSubnormal = expZero && !manZero - val isNormal = !expOne && !expZero - val isInfinity = expOne && manZero - val isNan = expOne && !manZero - val isQuiet = f32Mantissa.msb - - val recoded = p.internalFloating() - recoded.mantissa := f32Mantissa - recoded.exponent := f32Exponent - recoded.sign := f32Sign - recoded.setNormal - when(isZero){recoded.setZero} - when(isSubnormal){recoded.setSubnormal} - when(isInfinity){recoded.setInfinity} - when(isNan){recoded.setNan} - } + //TODO +// val rawToFpu = new Area{ +// val f32Mantissa = input.value(0, 23 bits).asUInt +// val f32Exponent = input.value(23, 8 bits).asUInt +// val f32Sign = input.value(31) +// +// val expZero = f32Exponent === 0 +// val expOne = f32Exponent === 255 +// val manZero = f32Mantissa === 0 +// +// val isZero = expZero && manZero +// val isSubnormal = expZero && !manZero +// val isNormal = !expOne && !expZero +// val isInfinity = expOne && manZero +// val isNan = expOne && !manZero +// val isQuiet = f32Mantissa.msb +// +// val recoded = p.internalFloating() +// recoded.mantissa := f32Mantissa +// recoded.exponent := f32Exponent +// recoded.sign := f32Sign +// recoded.setNormal +// when(isZero){recoded.setZero} +// when(isSubnormal){recoded.setSubnormal} +// when(isInfinity){recoded.setInfinity} +// when(isNan){recoded.setNan} +// } val minMaxResult = (rs1Smaller ^ input.arg(0)) ? input.rs1 | input.rs2 val cmpResult = B(rs1Smaller && !input.arg(1) || rs1Equal && !input.arg(0)) @@ -401,10 +497,10 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val decoded = input.rs1.decode() fclassResult(0) := input.rs1.sign && decoded.isInfinity fclassResult(1) := input.rs1.sign && decoded.isNormal - fclassResult(2) := input.rs1.sign && decoded.isSubnormal +// fclassResult(2) := input.rs1.sign && decoded.isSubnormal //TODO fclassResult(3) := input.rs1.sign && decoded.isZero fclassResult(4) := !input.rs1.sign && decoded.isZero - fclassResult(5) := !input.rs1.sign && decoded.isSubnormal +// fclassResult(5) := !input.rs1.sign && decoded.isSubnormal //TODO fclassResult(6) := !input.rs1.sign && decoded.isNormal fclassResult(7) := !input.rs1.sign && decoded.isInfinity fclassResult(8) := decoded.isNan && !decoded.isQuiet @@ -419,9 +515,9 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ is(FpuOpcode.FCLASS) { result := fclassResult.resized } } - val toFpuRf = List(FpuOpcode.MIN_MAX, FpuOpcode.I2F, FpuOpcode.SGNJ, FpuOpcode.FMV_W_X).map(input.opcode === _).orR + val toFpuRf = List(FpuOpcode.MIN_MAX, FpuOpcode.I2F, FpuOpcode.SGNJ).map(input.opcode === _).orR - rfOutput.valid := input.valid && toFpuRf + rfOutput.valid := input.valid && toFpuRf && !halt rfOutput.source := input.source rfOutput.lockId := input.lockId rfOutput.rd := input.rd @@ -442,15 +538,12 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ rfOutput.value.mantissa := input.rs1.mantissa rfOutput.value.special := False //TODO } - is(FpuOpcode.FMV_W_X){ - rfOutput.value := rawToFpu.recoded - } } - input.ready := (toFpuRf ? rfOutput.ready | io.port.map(_.rsp.ready).read(input.source)) + input.ready := !halt && (toFpuRf ? rfOutput.ready | io.port.map(_.rsp.ready).read(input.source)) for(i <- 0 until portCount){ def rsp = io.port(i).rsp - rsp.valid := input.valid && input.source === i && !toFpuRf + rsp.valid := input.valid && input.source === i && !toFpuRf && !halt rsp.value := result completion(i).increments += (RegNext(rsp.fire) init(False)) } @@ -463,7 +556,6 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val mulA = U(input.msb1) @@ input.rs1.mantissa val mulB = U(input.msb2) @@ input.rs2.mantissa val mulC = mulA * mulB - val expOffset = ((1 << p.internalExponentSize - 1) - 1) val exp = input.rs1.exponent +^ input.rs2.exponent } @@ -478,13 +570,13 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val man = needShift ? mulRounded(1, p.internalMantissaSize bits) | mulRounded(0, p.internalMantissaSize bits) val forceZero = input.rs1.isZeroOrSubnormal || input.rs2.isZeroOrSubnormal - val forceUnderflow = exp <= math.expOffset - val forceOverflow = exp > math.expOffset+254 || input.rs1.isInfinity || input.rs2.isInfinity + val forceUnderflow = exp <= exponentOne + exponentOne - 127 - 23 // 0x6A //TODO + val forceOverflow = exp > exponentOne + exponentOne + 127 || input.rs1.isInfinity || input.rs2.isInfinity val forceNan = input.rs1.isNan || input.rs2.isNan || ((input.rs1.isInfinity || input.rs2.isInfinity) && (input.rs1.isZero || input.rs2.isZero)) val output = FpuFloat(p.internalExponentSize, p.internalMantissaSize) output.sign := input.rs1.sign ^ input.rs2.sign - output.exponent := (exp - math.expOffset).resized + output.exponent := (exp - exponentOne).resized output.mantissa := man output.setNormal @@ -702,7 +794,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val shifter = new Area { val exp21 = input.rs2.exponent -^ input.rs1.exponent - val rs1ExponentBigger = exp21.msb || input.rs2.isZeroOrSubnormal + val rs1ExponentBigger = (exp21.msb || input.rs2.isZeroOrSubnormal) && !input.rs1.isZeroOrSubnormal val rs1ExponentEqual = input.rs1.exponent === input.rs2.exponent val rs1MantissaBigger = input.rs1.mantissa > input.rs2.mantissa val absRs1Bigger = ((rs1ExponentBigger || rs1ExponentEqual && rs1MantissaBigger) && !input.rs1.isZeroOrSubnormal || input.rs1.isInfinity) && !input.rs2.isInfinity @@ -746,7 +838,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val exponent = xyExponent -^ shift + 1 xySign clearWhen(input.rs1.isZeroOrSubnormal && input.rs2.isZeroOrSubnormal) val forceZero = xyMantissa === 0 || exponent.msb || (input.rs1.isZeroOrSubnormal && input.rs2.isZeroOrSubnormal) - val forceOverflow = exponent(7 downto 0) === 255 || (input.rs1.isInfinity || input.rs2.isInfinity) + val forceOverflow = exponent === exponentOne + 128 || (input.rs1.isInfinity || input.rs2.isInfinity) val forceNan = input.rs1.isNan || input.rs2.isNan || (input.rs1.isInfinity && input.rs2.isInfinity && (input.rs1.sign ^ input.rs2.sign)) } @@ -773,8 +865,28 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } +// val format = new Area{ +// val input = pipeArbiter.arbitrated.combStage() +// +// val rotate = new Area{ +// val input = Bits(p.internalMantissaSize bits) +// val shift = UInt(log2Up(p.internalMantissaSize) bits) +// val output = input.rotateLeft(shift) +// } +// +// val decode = new Area{ +// val sign = input.raw(31) +// val exp = input.raw(23, 8 bits).asUInt +// val man = input.raw(23, 8 bits).asUInt +// val isSubnormal = exp === 0 //zero ? +// val manTop = OHToUInt(OHMasking.first((man ## U"1").reversed)) +// val shift = isSubnormal ? manTop | U(0) +// rotate.shift := shift +// } +// } + val write = new Area{ - val arbitrated = StreamArbiterFactory.lowerFirst.noLock.on(List(load.output, add.output, mul.output, shortPip.rfOutput)) + val arbitrated = StreamArbiterFactory.lowerFirst.noLock.on(List(load.s1.output, add.output, mul.output, shortPip.rfOutput)) val isCommited = rf.lock.map(_.commited).read(arbitrated.lockId) val commited = arbitrated.haltWhen(!isCommited).toFlow @@ -794,8 +906,8 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ port.data := commited.value when(port.valid){ - assert(!(port.data.exponent === 0 && !port.data.special)) - assert(!(port.data.exponent === port.data.exponent.maxValue && !port.data.special)) + assert(!(port.data.exponent === 0 && !port.data.special), "Special violation") + assert(!(port.data.exponent === port.data.exponent.maxValue && !port.data.special), "Special violation") } } } @@ -831,11 +943,47 @@ object FpuSynthesisBench extends App{ SpinalVerilog(new Component{ val a = in UInt(width bits) val sel = in UInt(log2Up(width) bits) - val result = out(a.rotateLeft(sel)) + val result = out(Delay(Delay(a,3).rotateLeft(Delay(sel,3)),3)) setDefinitionName(Rotate.this.getName()) }) } +// rotate2_24 -> +// Artix 7 -> 233 Mhz 96 LUT 167 FF +// Artix 7 -> 420 Mhz 86 LUT 229 FF +// rotate2_32 -> +// Artix 7 -> 222 Mhz 108 LUT 238 FF +// Artix 7 -> 399 Mhz 110 LUT 300 FF +// rotate2_52 -> +// Artix 7 -> 195 Mhz 230 LUT 362 FF +// Artix 7 -> 366 Mhz 225 LUT 486 FF +// rotate2_64 -> +// Artix 7 -> 182 Mhz 257 LUT 465 FF +// Artix 7 -> 359 Mhz 266 LUT 591 FF + class Rotate2(width : Int) extends Rtl{ + override def getName(): String = "rotate2_" + width + override def getRtlPath(): String = getName() + ".v" + SpinalVerilog(new Component{ + val a = in UInt(width bits) + val sel = in UInt(log2Up(width) bits) + val result = out(Delay((U(0, width bits) @@ Delay(a,3)).rotateLeft(Delay(sel,3)),3)) + setDefinitionName(Rotate2.this.getName()) + }) + } + + class Rotate3(width : Int) extends Rtl{ + override def getName(): String = "rotate3_" + width + override def getRtlPath(): String = getName() + ".v" + SpinalVerilog(new Component{ + val a = Delay(in UInt(width bits), 3) + val sel = Delay(in UInt(log2Up(width) bits),3) +// val result = +// val output = Delay(result, 3) + setDefinitionName(Rotate3.this.getName()) + }) + } + + val rtls = ArrayBuffer[Rtl]() // rtls += new Fpu( // "32", @@ -858,10 +1006,14 @@ object FpuSynthesisBench extends App{ // rtls += new Shifter(32) // rtls += new Shifter(52) // rtls += new Shifter(64) - rtls += new Rotate(24) - rtls += new Rotate(32) - rtls += new Rotate(52) - rtls += new Rotate(64) +// rtls += new Rotate(24) +// rtls += new Rotate(32) +// rtls += new Rotate(52) +// rtls += new Rotate(64) + rtls += new Rotate3(24) + rtls += new Rotate3(32) + rtls += new Rotate3(52) + rtls += new Rotate3(64) val targets = XilinxStdTargets()// ++ AlteraStdTargets() diff --git a/src/main/scala/vexriscv/ip/fpu/Interface.scala b/src/main/scala/vexriscv/ip/fpu/Interface.scala index 42c9bcb8..5389e77a 100644 --- a/src/main/scala/vexriscv/ip/fpu/Interface.scala +++ b/src/main/scala/vexriscv/ip/fpu/Interface.scala @@ -50,14 +50,14 @@ case class FpuFloat(exponentSize: Int, def isNormal = !special def isZero = special && exponent(1 downto 0) === 0 - def isSubnormal = special && exponent(1 downto 0) === 1 + //def isSubnormal = special && exponent(1 downto 0) === 1 def isInfinity = special && exponent(1 downto 0) === 2 def isNan = special && exponent(1 downto 0) === 3 def isQuiet = mantissa.msb def setNormal = { special := False } def setZero = { special := True; exponent(1 downto 0) := 0 } - def setSubnormal = { special := True; exponent(1 downto 0) := 1 } + //def setSubnormal = { special := True; exponent(1 downto 0) := 1 } def setInfinity = { special := True; exponent(1 downto 0) := 2 } def setNan = { special := True; exponent(1 downto 0) := 3 } def setNanQuiet = { special := True; exponent(1 downto 0) := 3; mantissa.msb := True } @@ -65,7 +65,7 @@ case class FpuFloat(exponentSize: Int, def decode() = { val ret = FpuFloatDecoded() ret.isZero := isZero - ret.isSubnormal := isSubnormal + //ret.isSubnormal := isSubnormal ret.isNormal := isNormal ret.isInfinity := isInfinity ret.isNan := isNan @@ -101,7 +101,7 @@ case class FpuParameter( internalMantissaSize : Int, withDouble : Boolean){ val storeLoadType = HardType(Bits(if(withDouble) 64 bits else 32 bits)) - val internalExponentSize = if(withDouble) 11 else 8 + val internalExponentSize = (if(withDouble) 11 else 8) + 1 val internalFloating = HardType(FpuFloat(exponentSize = internalExponentSize, mantissaSize = internalMantissaSize)) val rfAddress = HardType(UInt(5 bits)) @@ -132,7 +132,7 @@ case class FpuCmd(p : FpuParameter) extends Bundle{ case class FpuCommit(p : FpuParameter) extends Bundle{ val write = Bool() - val load = Bool() + val sync = Bool() val value = p.storeLoadType() // IEEE 754 } diff --git a/src/main/scala/vexriscv/plugin/FpuPlugin.scala b/src/main/scala/vexriscv/plugin/FpuPlugin.scala index 4d639efc..258c0293 100644 --- a/src/main/scala/vexriscv/plugin/FpuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/FpuPlugin.scala @@ -11,7 +11,8 @@ class FpuPlugin(externalFpu : Boolean = false, object FPU_ENABLE extends Stageable(Bool()) object FPU_COMMIT extends Stageable(Bool()) - object FPU_LOAD extends Stageable(Bool()) + object FPU_COMMIT_SYNC extends Stageable(Bool()) + object FPU_COMMIT_LOAD extends Stageable(Bool()) object FPU_RSP extends Stageable(Bool()) object FPU_FORKED extends Stageable(Bool()) object FPU_OPCODE extends Stageable(FpuOpcode()) @@ -28,7 +29,6 @@ class FpuPlugin(externalFpu : Boolean = false, FPU_ENABLE -> True, FPU_COMMIT -> False, FPU_RSP -> True, - FPU_LOAD -> False, REGFILE_WRITE_VALID -> True, BYPASSABLE_EXECUTE_STAGE -> False, BYPASSABLE_MEMORY_STAGE -> False @@ -37,8 +37,7 @@ class FpuPlugin(externalFpu : Boolean = false, val floatRfWrite = List[ENC]( FPU_ENABLE -> True, FPU_COMMIT -> True, - FPU_RSP -> False, - FPU_LOAD -> False + FPU_RSP -> False ) val addSub = floatRfWrite :+ FPU_OPCODE -> FpuOpcode.ADD @@ -60,7 +59,6 @@ class FpuPlugin(externalFpu : Boolean = false, FPU_ENABLE -> True, FPU_OPCODE -> FpuOpcode.LOAD, FPU_COMMIT -> True, - FPU_LOAD -> True, FPU_RSP -> False ) @@ -68,7 +66,6 @@ class FpuPlugin(externalFpu : Boolean = false, FPU_ENABLE -> True, FPU_OPCODE -> FpuOpcode.STORE, FPU_COMMIT -> False, - FPU_LOAD -> False, FPU_RSP -> True ) @@ -164,7 +161,7 @@ class FpuPlugin(externalFpu : Boolean = false, //Maybe it might be better to not fork before fire to avoid RF stall on commits val forked = Reg(Bool) setWhen(port.cmd.fire) clearWhen(!arbitration.isStuck) init(False) - val intRfReady = Reg(Bool()) setWhen(!arbitration.isStuckByOthers) clearWhen(!arbitration.isStuck) + val intRfReady = Reg(Bool()) setWhen(!arbitration.isStuckByOthers) clearWhen(!arbitration.isStuck) //TODO is that still in use ? val hazard = (input(RS1_USE) && !intRfReady) || csr.pendings.msb || csr.csrActive arbitration.haltItself setWhen(arbitration.isValid && input(FPU_ENABLE) && hazard) @@ -181,6 +178,9 @@ class FpuPlugin(externalFpu : Boolean = false, port.cmd.format := FpuFormat.FLOAT insert(FPU_FORKED) := forked || port.cmd.fire + + insert(FPU_COMMIT_SYNC) := List(FpuOpcode.LOAD, FpuOpcode.FMV_W_X).map(_ === input(FPU_OPCODE)).orR + insert(FPU_COMMIT_LOAD) := input(FPU_OPCODE) === FpuOpcode.LOAD } writeBack plug new Area{ @@ -206,9 +206,9 @@ class FpuPlugin(externalFpu : Boolean = false, // Manage $load val commit = Stream(FpuCommit(p)) commit.valid := isCommit && arbitration.isMoving - commit.value.assignFromBits(output(DBUS_DATA)) + commit.value := (input(FPU_COMMIT_LOAD) ? output(DBUS_DATA) | input(RS1)) commit.write := arbitration.isValid - commit.load := input(FPU_LOAD) + commit.sync := input(FPU_COMMIT_SYNC) when(arbitration.isValid && !commit.ready){ arbitration.haltByOther := True diff --git a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala index 17dafff0..b89d1935 100644 --- a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala +++ b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala @@ -17,7 +17,7 @@ class FpuTest extends FunSuite{ val b2f = lang.Float.intBitsToFloat(_) val f2b = lang.Float.floatToIntBits(_) def clamp(f : Float) = { - if(f.abs < b2f(0x00800000)) b2f(f2b(f) & 0x80000000) else f + f // if(f.abs < b2f(0x00800000)) b2f(f2b(f) & 0x80000000) else f } test("directed"){ @@ -74,7 +74,7 @@ class FpuTest extends FunSuite{ commitQueue += {cmd => cmd.write #= true cmd.value #= value - cmd.load #= true + cmd.sync #= true } } @@ -112,7 +112,7 @@ class FpuTest extends FunSuite{ } commitQueue += {cmd => cmd.write #= true - cmd.load #= false + cmd.sync #= false } } @@ -128,7 +128,7 @@ class FpuTest extends FunSuite{ } commitQueue += {cmd => cmd.write #= true - cmd.load #= false + cmd.sync #= false } } @@ -144,7 +144,7 @@ class FpuTest extends FunSuite{ } commitQueue += {cmd => cmd.write #= true - cmd.load #= false + cmd.sync #= false } } @@ -160,7 +160,7 @@ class FpuTest extends FunSuite{ } commitQueue += {cmd => cmd.write #= true - cmd.load #= false + cmd.sync #= false } } @@ -176,7 +176,7 @@ class FpuTest extends FunSuite{ } commitQueue += {cmd => cmd.write #= true - cmd.load #= false + cmd.sync #= false } } @@ -219,7 +219,7 @@ class FpuTest extends FunSuite{ } commitQueue += {cmd => cmd.write #= true - cmd.load #= false + cmd.sync #= false } } @@ -239,7 +239,7 @@ class FpuTest extends FunSuite{ def fmv_w_x(rd : Int, value : Int): Unit ={ cmdQueue += {cmd => cmd.opcode #= cmd.opcode.spinalEnum.FMV_W_X - cmd.value #= value.toLong & 0xFFFFFFFFl + cmd.value.randomize() cmd.rs1.randomize() cmd.rs2.randomize() cmd.rs3.randomize() @@ -248,7 +248,8 @@ class FpuTest extends FunSuite{ } commitQueue += {cmd => cmd.write #= true - cmd.load #= false + cmd.sync #= true + cmd.value #= value.toLong & 0xFFFFFFFFl } } @@ -264,7 +265,7 @@ class FpuTest extends FunSuite{ } commitQueue += {cmd => cmd.write #= true - cmd.load #= false + cmd.sync #= false } } @@ -281,7 +282,7 @@ class FpuTest extends FunSuite{ } commitQueue += {cmd => cmd.write #= true - cmd.load #= false + cmd.sync #= false } } } @@ -309,11 +310,12 @@ class FpuTest extends FunSuite{ } } def checkFloat(ref : Float, dut : Float): Boolean ={ - if(ref.signum != dut.signum) return false + if((f2b(ref) & 0x80000000) != (f2b(dut) & 0x80000000)) return false if(ref == 0.0 && dut == 0.0 && f2b(ref) != f2b(dut)) return false if(ref.isNaN && dut.isNaN) return true if(ref == dut) return true - if(ref.abs * 1.0001 > dut.abs && ref.abs * 0.9999 < dut.abs && ref.signum == dut.signum) return true + if(ref.abs * 1.0001 + Float.MinPositiveValue >= dut.abs && ref.abs * 0.9999 - Float.MinPositiveValue <= dut.abs) return true +// if(ref + Float.MinPositiveValue*2.0f === dut || dut + Float.MinPositiveValue*2.0f === ref) false } def checkFloatExact(ref : Float, dut : Float): Boolean ={ @@ -346,6 +348,16 @@ class FpuTest extends FunSuite{ } } + def testLoadStore(a : Float): Unit ={ + val rd = Random.nextInt(32) + load(rd, a) + storeFloat(rd){v => + val refUnclamped = a + val ref = a + println(f"$a = $v, $ref") + assert(f2b(v) == f2b(ref)) + } + } def testMul(a : Float, b : Float): Unit ={ val rs = new RegAllocator() val rs1, rs2, rs3 = rs.allocate() @@ -515,7 +527,7 @@ class FpuTest extends FunSuite{ def withMinus(that : Seq[Float]) = that.flatMap(f => List(f, -f)) val fZeros = withMinus(List(0.0f)) - val fSubnormals = withMinus(List(b2f(0x00000000+1), b2f(0x00000000+2), b2f(0x00800000-2), b2f(0x00800000-1))) + val fSubnormals = withMinus(List(b2f(0x00000000+1), b2f(0x00000000+2), b2f(0x00006800), b2f(0x00800000-2), b2f(0x00800000-1))) val fExpSmall = withMinus(List(b2f(0x00800000), b2f(0x00800000+1), b2f(0x00800000 + 2))) val fExpNormal = withMinus(List(b2f(0x3f800000-2), b2f(0x3f800000-1), b2f(0x3f800000), b2f(0x3f800000+1), b2f(0x3f800000+2))) val fExpBig = withMinus(List(b2f(0x7f7fffff-2), b2f(0x7f7fffff-1), b2f(0x7f7fffff))) @@ -533,13 +545,6 @@ class FpuTest extends FunSuite{ - testMul(1.2f, 0f) - for(a <- fAll; _ <- 0 until 50) testMul(a, randomFloat()) - for(b <- fAll; _ <- 0 until 50) testMul(randomFloat(), b) - for(a <- fAll; b <- fAll) testMul(a, b) - for(_ <- 0 until 1000) testMul(randomFloat(), randomFloat()) - - testAdd(b2f(0x3f800000), b2f(0x3f800000-1)) testAdd(1.1f, 2.3f) testAdd(1.2f, -1.2f) @@ -555,6 +560,28 @@ class FpuTest extends FunSuite{ for(a <- fAll; b <- fAll) testAdd(a, b) for(_ <- 0 until 1000) testAdd(randomFloat(), randomFloat()) + testLoadStore(1.2f) + testMul(1.2f, 2.5f) + testMul(b2f(0x00400000), 16.0f) + testMul(b2f(0x00100000), 16.0f) + testMul(b2f(0x00180000), 16.0f) + testMul(b2f(0x00000004), 16.0f) + testMul(b2f(0x00000040), 16.0f) + testMul(b2f(0x00000041), 16.0f) + testMul(b2f(0x00000001), b2f(0x00000001)) + testMul(1.0f, b2f(0x00000001)) + testMul(0.5f, b2f(0x00000001)) + +// dut.clockDomain.waitSampling(1000) +// simSuccess() + + testMul(1.2f, 0f) + for(a <- fAll; _ <- 0 until 50) testMul(a, randomFloat()) + for(b <- fAll; _ <- 0 until 50) testMul(randomFloat(), b) + for(a <- fAll; b <- fAll) testMul(a, b) + for(_ <- 0 until 1000) testMul(randomFloat(), randomFloat()) + + From 3334364f5f69b39349366c92cd79e8b403a83075 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 26 Jan 2021 12:50:23 +0100 Subject: [PATCH 552/951] fpu added more tests for min max sqrt div --- src/main/scala/vexriscv/ip/fpu/FpuCore.scala | 81 +++++++++---------- .../scala/vexriscv/ip/fpu/Interface.scala | 1 - src/test/scala/vexriscv/ip/fpu/FpuTest.scala | 51 +++++++++--- 3 files changed, 77 insertions(+), 56 deletions(-) diff --git a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala index 88fa0e0d..33a20fbe 100644 --- a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala +++ b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala @@ -10,6 +10,7 @@ object FpuDivSqrtIterationState extends SpinalEnum{ val IDLE, YY, XYY, Y2_XYY, DIV, _15_XYY2, Y_15_XYY2, Y_15_XYY2_RESULT, SQRT = newElement() } +//TODO cleanup rounding case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val io = new Bundle { val port = Vec(slave(FpuPort(p)), portCount) @@ -396,13 +397,14 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } recodedResult := recoded.sign ## f32.exp ## f32.man + val isSubnormal = !recoded.special && recoded.exponent <= exponentOne - 127 val subnormal = new Area{ - val isSubnormal = !recoded.special && recoded.exponent <= exponentOne - 127 + val needRecoding = List(FpuOpcode.FMV_X_W, FpuOpcode.STORE).map(_ === input.opcode).orR val manTop = Reg(UInt(log2Up(p.internalMantissaSize) bits)) val shift = isSubnormal ? manTop | U(0) val counter = Reg(UInt(log2Up(p.internalMantissaSize+1) bits)) val done, boot = Reg(Bool()) - when(isSubnormal && !done){ + when(needRecoding && isSubnormal && !done){ halt := True when(boot){ manTop := (U(exponentOne - 127) - recoded.exponent).resized @@ -453,8 +455,13 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val i2fLog2 = OHToUInt(OHMasking.last(i2fUnsigned)) val i2fShifted = (i2fUnsigned << p.internalMantissaSize) >> i2fLog2 + val bothZero = input.rs1.isZero && input.rs2.isZero val rs1Equal = input.rs1 === input.rs2 val rs1AbsSmaller = (input.rs1.exponent @@ input.rs1.mantissa) < (input.rs2.exponent @@ input.rs2.mantissa) + rs1AbsSmaller.setWhen(input.rs2.isInfinity) + rs1AbsSmaller.setWhen(input.rs1.isZero) + rs1AbsSmaller.clearWhen(input.rs2.isZero) + rs1AbsSmaller.clearWhen(input.rs1.isInfinity) val rs1Smaller = (input.rs1.sign ## input.rs2.sign).mux( 0 -> rs1AbsSmaller, 1 -> False, @@ -462,45 +469,19 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ 3 -> (!rs1AbsSmaller && !rs1Equal) ) - //TODO -// val rawToFpu = new Area{ -// val f32Mantissa = input.value(0, 23 bits).asUInt -// val f32Exponent = input.value(23, 8 bits).asUInt -// val f32Sign = input.value(31) -// -// val expZero = f32Exponent === 0 -// val expOne = f32Exponent === 255 -// val manZero = f32Mantissa === 0 -// -// val isZero = expZero && manZero -// val isSubnormal = expZero && !manZero -// val isNormal = !expOne && !expZero -// val isInfinity = expOne && manZero -// val isNan = expOne && !manZero -// val isQuiet = f32Mantissa.msb -// -// val recoded = p.internalFloating() -// recoded.mantissa := f32Mantissa -// recoded.exponent := f32Exponent -// recoded.sign := f32Sign -// recoded.setNormal -// when(isZero){recoded.setZero} -// when(isSubnormal){recoded.setSubnormal} -// when(isInfinity){recoded.setInfinity} -// when(isNan){recoded.setNan} -// } - val minMaxResult = (rs1Smaller ^ input.arg(0)) ? input.rs1 | input.rs2 - val cmpResult = B(rs1Smaller && !input.arg(1) || rs1Equal && !input.arg(0)) + val minMaxResult = ((rs1Smaller ^ input.arg(0)) && !input.rs1.isNan || input.rs2.isNan) ? input.rs1 | input.rs2 + val cmpResult = B(rs1Smaller && !bothZero && !input.arg(1) || (rs1Equal || bothZero) && !input.arg(0)) + when(input.rs1.isNan || input.rs2.isNan) { cmpResult := 0 } val sgnjResult = (input.rs1.sign && input.arg(1)) ^ input.rs2.sign ^ input.arg(0) val fclassResult = B(0, 32 bits) val decoded = input.rs1.decode() fclassResult(0) := input.rs1.sign && decoded.isInfinity fclassResult(1) := input.rs1.sign && decoded.isNormal -// fclassResult(2) := input.rs1.sign && decoded.isSubnormal //TODO + fclassResult(2) := input.rs1.sign && isSubnormal //TODO fclassResult(3) := input.rs1.sign && decoded.isZero fclassResult(4) := !input.rs1.sign && decoded.isZero -// fclassResult(5) := !input.rs1.sign && decoded.isSubnormal //TODO + fclassResult(5) := !input.rs1.sign && isSubnormal //TODO fclassResult(6) := !input.rs1.sign && decoded.isNormal fclassResult(7) := !input.rs1.sign && decoded.isInfinity fclassResult(8) := decoded.isNan && !decoded.isQuiet @@ -735,6 +716,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ decode.divSqrtToMul.rs2.sign := input.rs2.sign decode.divSqrtToMul.rs2.exponent := divExp.value + iterationValue.msb.asUInt decode.divSqrtToMul.rs2.mantissa := (iterationValue << 1).resized + val zero = input.rs2.isInfinity val overflow = input.rs2.isZeroOrSubnormal val nan = input.rs2.isNan || (input.rs1.isZeroOrSubnormal && input.rs2.isZeroOrSubnormal) @@ -742,6 +724,8 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ decode.divSqrtToMul.rs2.setNanQuiet } elsewhen(overflow) { decode.divSqrtToMul.rs2.setInfinity + } elsewhen(zero) { + decode.divSqrtToMul.rs2.setZero } when(decode.divSqrtToMul.ready) { state := IDLE @@ -781,6 +765,13 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ decode.divSqrtToMul.rs2.sign := False decode.divSqrtToMul.rs2.exponent := sqrtExp.value + iterationValue.msb.asUInt decode.divSqrtToMul.rs2.mantissa := (iterationValue << 1).resized + + val nan = input.rs1.sign && !input.rs1.isZero + + when(nan){ + decode.divSqrtToMul.rs2.setNanQuiet + } + when(decode.divSqrtToMul.ready) { state := IDLE input.ready := True @@ -985,14 +976,14 @@ object FpuSynthesisBench extends App{ val rtls = ArrayBuffer[Rtl]() -// rtls += new Fpu( -// "32", -// portCount = 1, -// FpuParameter( -// internalMantissaSize = 23, -// withDouble = false -// ) -// ) + rtls += new Fpu( + "32", + portCount = 1, + FpuParameter( + internalMantissaSize = 23, + withDouble = false + ) + ) // rtls += new Fpu( // "64", // portCount = 1, @@ -1010,10 +1001,10 @@ object FpuSynthesisBench extends App{ // rtls += new Rotate(32) // rtls += new Rotate(52) // rtls += new Rotate(64) - rtls += new Rotate3(24) - rtls += new Rotate3(32) - rtls += new Rotate3(52) - rtls += new Rotate3(64) +// rtls += new Rotate3(24) +// rtls += new Rotate3(32) +// rtls += new Rotate3(52) +// rtls += new Rotate3(64) val targets = XilinxStdTargets()// ++ AlteraStdTargets() diff --git a/src/main/scala/vexriscv/ip/fpu/Interface.scala b/src/main/scala/vexriscv/ip/fpu/Interface.scala index 5389e77a..e079e3e3 100644 --- a/src/main/scala/vexriscv/ip/fpu/Interface.scala +++ b/src/main/scala/vexriscv/ip/fpu/Interface.scala @@ -65,7 +65,6 @@ case class FpuFloat(exponentSize: Int, def decode() = { val ret = FpuFloatDecoded() ret.isZero := isZero - //ret.isSubnormal := isSubnormal ret.isNormal := isNormal ret.isInfinity := isInfinity ret.isNan := isNan diff --git a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala index b89d1935..e349611f 100644 --- a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala +++ b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala @@ -314,7 +314,7 @@ class FpuTest extends FunSuite{ if(ref == 0.0 && dut == 0.0 && f2b(ref) != f2b(dut)) return false if(ref.isNaN && dut.isNaN) return true if(ref == dut) return true - if(ref.abs * 1.0001 + Float.MinPositiveValue >= dut.abs && ref.abs * 0.9999 - Float.MinPositiveValue <= dut.abs) return true + if(ref.abs * 1.0001f + Float.MinPositiveValue >= dut.abs*0.9999f && ref.abs * 0.9999f - Float.MinPositiveValue <= dut.abs*1.0001f) return true // if(ref + Float.MinPositiveValue*2.0f === dut || dut + Float.MinPositiveValue*2.0f === ref) false } @@ -460,7 +460,10 @@ class FpuTest extends FunSuite{ load(rs1, a) load(rs2, b) cmp(rs1, rs2){rsp => - val ref = if(a < b) 1 else 0 + var ref = if(a < b) 1 else 0 + if(a.isNaN || b.isNaN){ + ref = 0 + } val v = rsp.value.toBigInt println(f"$a < $b = $v, $ref") assert(v === ref) @@ -503,9 +506,13 @@ class FpuTest extends FunSuite{ min(rd,rs1,rs2) storeFloat(rd){v => - val ref = a min b + val ref = (a,b) match { + case _ if a.isNaN => b + case _ if b.isNaN => a + case _ => Math.min(a,b) + } println(f"min $a $b = $v, $ref") - assert(ref == v) + assert(f2b(ref) == f2b(v)) } } @@ -535,13 +542,37 @@ class FpuTest extends FunSuite{ val fNan = List(Float.NaN, b2f(0x7f820000), b2f(0x7fc00000)) val fAll = fZeros ++ fSubnormals ++ fExpSmall ++ fExpNormal ++ fExpBig ++ fInfinity ++ fNan + testCmp(0.0f, 1.2f ) + testCmp(1.2f, 0.0f ) + testCmp(0.0f, -0.0f ) + testCmp(-0.0f, 0.0f ) + for(a <- fAll; _ <- 0 until 50) testCmp(a, randomFloat()) + for(b <- fAll; _ <- 0 until 50) testCmp(randomFloat(), b) + for(a <- fAll; b <- fAll) testCmp(a, b) + for(_ <- 0 until 1000) testCmp(randomFloat(), randomFloat()) -// testDiv(0.0f, 1.2f ) -// testDiv(1.2f, 0.0f ) -// testDiv(0.0f, 0.0f ) -// for(a <- fAll; _ <- 0 until 50) testDiv(a, randomFloat()) -// for(a <- fAll; b <- fAll) testDiv(a, b) -// for(_ <- 0 until 1000) testDiv(randomFloat(), randomFloat()) + testMin(0.0f, 1.2f ) + testMin(1.2f, 0.0f ) + testMin(0.0f, -0.0f ) + testMin(-0.0f, 0.0f ) + for(a <- fAll; _ <- 0 until 50) testMin(a, randomFloat()) + for(b <- fAll; _ <- 0 until 50) testMin(randomFloat(), b) + for(a <- fAll; b <- fAll) testMin(a, b) + for(_ <- 0 until 1000) testMin(randomFloat(), randomFloat()) + + testSqrt(1.2f) + testSqrt(0.0f) + for(a <- fAll) testSqrt(a) + for(_ <- 0 until 1000) testSqrt(randomFloat()) + + + testDiv(0.0f, 1.2f ) + testDiv(1.2f, 0.0f ) + testDiv(0.0f, 0.0f ) + for(a <- fAll; _ <- 0 until 50) testDiv(a, randomFloat()) + for(b <- fAll; _ <- 0 until 50) testDiv(randomFloat(), b) + for(a <- fAll; b <- fAll) testDiv(a, b) + for(_ <- 0 until 1000) testDiv(randomFloat(), randomFloat()) From 444bcdba0a04767926ab65790fff13ed2682f2c2 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 26 Jan 2021 15:28:09 +0100 Subject: [PATCH 553/951] fpu merged i2f with load pipeline --- src/main/scala/vexriscv/ip/fpu/FpuCore.scala | 131 +++++++++--------- .../scala/vexriscv/ip/fpu/Interface.scala | 25 ++-- .../scala/vexriscv/plugin/FpuPlugin.scala | 6 +- src/test/scala/vexriscv/ip/fpu/FpuTest.scala | 119 +++++++++------- 4 files changed, 146 insertions(+), 135 deletions(-) diff --git a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala index 33a20fbe..baa0bdda 100644 --- a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala +++ b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala @@ -47,6 +47,8 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val source = Source() val rd = p.rfAddress() val lockId = lockIdType() + val i2f = Bool() + val arg = Bits(2 bits) } case class ShortPipInput() extends Bundle{ @@ -228,13 +230,14 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val input = read.output.combStage() input.ready := False - val loadHit = List(FpuOpcode.LOAD, FpuOpcode.FMV_W_X).map(input.opcode === _).orR + val loadHit = List(FpuOpcode.LOAD, FpuOpcode.FMV_W_X, FpuOpcode.I2F).map(input.opcode === _).orR val load = Stream(LoadInput()) load.valid := input.valid && loadHit input.ready setWhen(loadHit && load.ready) load.payload.assignSomeByName(read.output.payload) + load.i2f := input.opcode === FpuOpcode.I2F - val shortPipHit = List(FpuOpcode.STORE, FpuOpcode.F2I, FpuOpcode.CMP, FpuOpcode.I2F, FpuOpcode.MIN_MAX, FpuOpcode.SGNJ, FpuOpcode.FMV_X_W, FpuOpcode.FCLASS).map(input.opcode === _).orR + val shortPipHit = List(FpuOpcode.STORE, FpuOpcode.F2I, FpuOpcode.CMP, FpuOpcode.MIN_MAX, FpuOpcode.SGNJ, FpuOpcode.FMV_X_W, FpuOpcode.FCLASS).map(input.opcode === _).orR val shortPip = Stream(ShortPipInput()) input.ready setWhen(shortPipHit && shortPip.ready) shortPip.valid := input.valid && shortPipHit @@ -289,7 +292,9 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val source = Source() val lockId = lockIdType() val rd = p.rfAddress() - val value = FpuFloat(exponentSize = p.internalExponentSize-1, mantissaSize = p.internalMantissaSize) + val value = p.storeLoadType() + val i2f = Bool() + val arg = Bits(2 bits) } val s0 = new Area{ @@ -304,18 +309,28 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ output.source := input.source output.lockId := input.lockId output.rd := input.rd - output.value.mantissa := feed.value(0, 23 bits).asUInt - output.value.exponent := feed.value(23, 8 bits).asUInt - output.value.sign := feed.value(31) + output.value := feed.value + output.i2f := input.i2f + output.arg := input.arg } + +// val i2fSign = input.arg(0) && input.value.msb +// val i2fUnsigned = input.value.asUInt.twoComplement(i2fSign).resize(32 bits) +// val i2fLog2 = OHToUInt(OHMasking.last(i2fUnsigned)) +// val i2fShifted = (i2fUnsigned << p.internalMantissaSize) >> i2fLog2 +// rfOutput.value.sign := i2fSign +// rfOutput.value.exponent := i2fLog2 +^ exponentOne +// rfOutput.value.mantissa := U(i2fShifted).resized +// rfOutput.value.special := False //TODO + val s1 = new Area{ val input = s0.output.stage() val busy = False - val f32Mantissa = input.value.mantissa - val f32Exponent = input.value.exponent - val f32Sign = input.value.sign + val f32Mantissa = input.value(0, 23 bits).asUInt + val f32Exponent = input.value(23, 8 bits).asUInt + val f32Sign = input.value(31) val expZero = f32Exponent === 0 val expOne = f32Exponent === 255 @@ -329,18 +344,31 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val isNan = expOne && !manZero val isQuiet = f32Mantissa.msb - val subnormal = new Area{ + val fsm = new Area{ val manTop = Reg(UInt(log2Up(p.internalMantissaSize) bits)) - val shift = isSubnormal ? manTop | U(0) + val shift = CombInit(manTop) val counter = Reg(UInt(log2Up(p.internalMantissaSize+1) bits)) - val done, boot = Reg(Bool()) - when(isSubnormal && !done){ + val done, boot, patched = Reg(Bool()) + val ohInput = CombInit(input.value(0, 32 max p.internalMantissaSize bits)) + when(!input.i2f) { ohInput(9, 23 bits) := input.value(0, 23 bits) } + val i2fZero = Reg(Bool) + when(input.valid && (input.i2f || isSubnormal) && !done){ busy := True when(boot){ - manTop := OHToUInt(OHMasking.first((f32Mantissa).reversed)) - boot := False + when(input.i2f && !patched && input.value.msb && input.arg(0)){ + input.value.getDrivingReg(0, 32 bits) := B(input.value.asUInt.twoComplement(True).resize(32 bits)) + patched := True + } otherwise { + manTop := OHToUInt(OHMasking.first((ohInput).reversed)) + boot := False + i2fZero := input.value(31 downto 0) === 0 + } } otherwise { - input.value.mantissa.getDrivingReg := input.value.mantissa |<< 1 + when(input.i2f){ + input.value.getDrivingReg(0, 32 bits) := input.value(0, 32 bits) |<< 1 + } otherwise { + input.value.getDrivingReg(0, 23 bits) := input.value(0, 23 bits) |<< 1 + } counter := counter + 1 when(counter === shift) { done := True @@ -358,16 +386,20 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ counter := 0 done := False boot := True + patched := False } } + + val i2fSign = fsm.patched + val i2fShifted = input.value.takeHigh(23) + val recoded = p.internalFloating() recoded.mantissa := f32Mantissa - recoded.exponent := (f32Exponent -^ subnormal.expOffset + (exponentOne - 127)).resized + recoded.exponent := (f32Exponent -^ fsm.expOffset + (exponentOne - 127)).resized recoded.sign := f32Sign recoded.setNormal when(isZero){recoded.setZero} - //when(isSubnormal){recoded.setSubnormal} when(isInfinity){recoded.setInfinity} when(isNan){recoded.setNan} @@ -376,6 +408,13 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ output.lockId := input.lockId output.rd := input.rd output.value := recoded + when(input.i2f){ + output.value.sign := i2fSign + output.value.exponent := (U(exponentOne+31) - fsm.manTop).resized + output.value.mantissa := U(i2fShifted) + output.value.setNormal + when(fsm.i2fZero) { output.value.setZero } + } } } @@ -401,10 +440,9 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val subnormal = new Area{ val needRecoding = List(FpuOpcode.FMV_X_W, FpuOpcode.STORE).map(_ === input.opcode).orR val manTop = Reg(UInt(log2Up(p.internalMantissaSize) bits)) - val shift = isSubnormal ? manTop | U(0) val counter = Reg(UInt(log2Up(p.internalMantissaSize+1) bits)) val done, boot = Reg(Bool()) - when(needRecoding && isSubnormal && !done){ + when(input.valid && needRecoding && isSubnormal && !done){ halt := True when(boot){ manTop := (U(exponentOne - 127) - recoded.exponent).resized @@ -412,7 +450,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } otherwise { recoded.mantissa.getDrivingReg := (U(counter === 0) @@ recoded.mantissa) >> 1 counter := counter + 1 - when(counter === shift) { + when(counter === manTop) { done := True } } @@ -450,11 +488,6 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val f2iUnsigned = f2iShifted >> p.internalMantissaSize val f2iResult = (f2iUnsigned.twoComplement(input.arg(0) && input.rs1.sign)).asBits.resize(32 bits) - val i2fSign = input.arg(0) && input.value.msb - val i2fUnsigned = input.value.asUInt.twoComplement(i2fSign).resize(32 bits) - val i2fLog2 = OHToUInt(OHMasking.last(i2fUnsigned)) - val i2fShifted = (i2fUnsigned << p.internalMantissaSize) >> i2fLog2 - val bothZero = input.rs1.isZero && input.rs2.isZero val rs1Equal = input.rs1 === input.rs2 val rs1AbsSmaller = (input.rs1.exponent @@ input.rs1.mantissa) < (input.rs2.exponent @@ input.rs2.mantissa) @@ -496,7 +529,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ is(FpuOpcode.FCLASS) { result := fclassResult.resized } } - val toFpuRf = List(FpuOpcode.MIN_MAX, FpuOpcode.I2F, FpuOpcode.SGNJ).map(input.opcode === _).orR + val toFpuRf = List(FpuOpcode.MIN_MAX, FpuOpcode.SGNJ).map(input.opcode === _).orR rfOutput.valid := input.valid && toFpuRf && !halt rfOutput.source := input.source @@ -504,12 +537,6 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ rfOutput.rd := input.rd rfOutput.value.assignDontCare() switch(input.opcode){ - is(FpuOpcode.I2F){ - rfOutput.value.sign := i2fSign - rfOutput.value.exponent := i2fLog2 +^ exponentOne - rfOutput.value.mantissa := U(i2fShifted).resized - rfOutput.value.special := False //TODO - } is(FpuOpcode.MIN_MAX){ rfOutput.value := minMaxResult } @@ -550,7 +577,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val exp = math.exp + U(needShift) val man = needShift ? mulRounded(1, p.internalMantissaSize bits) | mulRounded(0, p.internalMantissaSize bits) - val forceZero = input.rs1.isZeroOrSubnormal || input.rs2.isZeroOrSubnormal + val forceZero = input.rs1.isZero || input.rs2.isZero val forceUnderflow = exp <= exponentOne + exponentOne - 127 - 23 // 0x6A //TODO val forceOverflow = exp > exponentOne + exponentOne + 127 || input.rs1.isInfinity || input.rs2.isInfinity val forceNan = input.rs1.isNan || input.rs2.isNan || ((input.rs1.isInfinity || input.rs2.isInfinity) && (input.rs1.isZero || input.rs2.isZero)) @@ -717,8 +744,8 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ decode.divSqrtToMul.rs2.exponent := divExp.value + iterationValue.msb.asUInt decode.divSqrtToMul.rs2.mantissa := (iterationValue << 1).resized val zero = input.rs2.isInfinity - val overflow = input.rs2.isZeroOrSubnormal - val nan = input.rs2.isNan || (input.rs1.isZeroOrSubnormal && input.rs2.isZeroOrSubnormal) + val overflow = input.rs2.isZero + val nan = input.rs2.isNan || (input.rs1.isZero && input.rs2.isZero) when(nan){ decode.divSqrtToMul.rs2.setNanQuiet @@ -785,12 +812,12 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val shifter = new Area { val exp21 = input.rs2.exponent -^ input.rs1.exponent - val rs1ExponentBigger = (exp21.msb || input.rs2.isZeroOrSubnormal) && !input.rs1.isZeroOrSubnormal + val rs1ExponentBigger = (exp21.msb || input.rs2.isZero) && !input.rs1.isZero val rs1ExponentEqual = input.rs1.exponent === input.rs2.exponent val rs1MantissaBigger = input.rs1.mantissa > input.rs2.mantissa - val absRs1Bigger = ((rs1ExponentBigger || rs1ExponentEqual && rs1MantissaBigger) && !input.rs1.isZeroOrSubnormal || input.rs1.isInfinity) && !input.rs2.isInfinity + val absRs1Bigger = ((rs1ExponentBigger || rs1ExponentEqual && rs1MantissaBigger) && !input.rs1.isZero || input.rs1.isInfinity) && !input.rs2.isInfinity val shiftBy = rs1ExponentBigger ? (0-exp21) | exp21 - val passThrough = shiftBy >= p.internalMantissaSize || (input.rs1.isZeroOrSubnormal) || (input.rs2.isZeroOrSubnormal) + val passThrough = shiftBy >= p.internalMantissaSize || (input.rs1.isZero) || (input.rs2.isZero) //Note that rs1ExponentBigger can be replaced by absRs1Bigger bellow to avoid xsigned two complement in math block at expense of combinatorial path val xySign = absRs1Bigger ? input.rs1.sign | input.rs2.sign @@ -827,8 +854,8 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ // val mantissaShifted = (xyMantissa |<< shift) // val mantissa = ((xyMantissa ) >> 2) + U(xyMantissa(1)) val exponent = xyExponent -^ shift + 1 - xySign clearWhen(input.rs1.isZeroOrSubnormal && input.rs2.isZeroOrSubnormal) - val forceZero = xyMantissa === 0 || exponent.msb || (input.rs1.isZeroOrSubnormal && input.rs2.isZeroOrSubnormal) + xySign clearWhen(input.rs1.isZero && input.rs2.isZero) + val forceZero = xyMantissa === 0 || exponent.msb || (input.rs1.isZero && input.rs2.isZero) val forceOverflow = exponent === exponentOne + 128 || (input.rs1.isInfinity || input.rs2.isInfinity) val forceNan = input.rs1.isNan || input.rs2.isNan || (input.rs1.isInfinity && input.rs2.isInfinity && (input.rs1.sign ^ input.rs2.sign)) } @@ -847,7 +874,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ output.value.setNanQuiet } elsewhen(norm.forceZero) { output.value.setZero - when(norm.xyMantissa === 0 || input.rs1.isZeroOrSubnormal && input.rs2.isZeroOrSubnormal){ + when(norm.xyMantissa === 0 || input.rs1.isZero && input.rs2.isZero){ output.value.sign := input.rs1.sign && input.rs2.sign } } elsewhen(norm.forceOverflow) { @@ -856,26 +883,6 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } -// val format = new Area{ -// val input = pipeArbiter.arbitrated.combStage() -// -// val rotate = new Area{ -// val input = Bits(p.internalMantissaSize bits) -// val shift = UInt(log2Up(p.internalMantissaSize) bits) -// val output = input.rotateLeft(shift) -// } -// -// val decode = new Area{ -// val sign = input.raw(31) -// val exp = input.raw(23, 8 bits).asUInt -// val man = input.raw(23, 8 bits).asUInt -// val isSubnormal = exp === 0 //zero ? -// val manTop = OHToUInt(OHMasking.first((man ## U"1").reversed)) -// val shift = isSubnormal ? manTop | U(0) -// rotate.shift := shift -// } -// } - val write = new Area{ val arbitrated = StreamArbiterFactory.lowerFirst.noLock.on(List(load.s1.output, add.output, mul.output, shortPip.rfOutput)) val isCommited = rf.lock.map(_.commited).read(arbitrated.lockId) diff --git a/src/main/scala/vexriscv/ip/fpu/Interface.scala b/src/main/scala/vexriscv/ip/fpu/Interface.scala index e079e3e3..82c2ba49 100644 --- a/src/main/scala/vexriscv/ip/fpu/Interface.scala +++ b/src/main/scala/vexriscv/ip/fpu/Interface.scala @@ -25,9 +25,8 @@ case class FpuFloatDecoded() extends Bundle{ object FpuFloat{ val ZERO = 0 - val SUBNORMAL = 1 - val INFINITY = 2 - val NAN = 3 + val INFINITY = 1 + val NAN = 2 } case class FpuFloat(exponentSize: Int, @@ -45,22 +44,17 @@ case class FpuFloat(exponentSize: Int, ret } - - def isZeroOrSubnormal = special && exponent(1) === False - def isNormal = !special - def isZero = special && exponent(1 downto 0) === 0 - //def isSubnormal = special && exponent(1 downto 0) === 1 - def isInfinity = special && exponent(1 downto 0) === 2 - def isNan = special && exponent(1 downto 0) === 3 + def isZero = special && exponent(1 downto 0) === FpuFloat.ZERO + def isInfinity = special && exponent(1 downto 0) === FpuFloat.INFINITY + def isNan = special && exponent(1 downto 0) === FpuFloat.NAN def isQuiet = mantissa.msb def setNormal = { special := False } - def setZero = { special := True; exponent(1 downto 0) := 0 } - //def setSubnormal = { special := True; exponent(1 downto 0) := 1 } - def setInfinity = { special := True; exponent(1 downto 0) := 2 } - def setNan = { special := True; exponent(1 downto 0) := 3 } - def setNanQuiet = { special := True; exponent(1 downto 0) := 3; mantissa.msb := True } + def setZero = { special := True; exponent(1 downto 0) := FpuFloat.ZERO } + def setInfinity = { special := True; exponent(1 downto 0) := FpuFloat.INFINITY } + def setNan = { special := True; exponent(1 downto 0) := FpuFloat.NAN } + def setNanQuiet = { special := True; exponent(1 downto 0) := FpuFloat.NAN ; mantissa.msb := True } def decode() = { val ret = FpuFloatDecoded() @@ -122,7 +116,6 @@ case class FpuCompletion() extends Bundle{ case class FpuCmd(p : FpuParameter) extends Bundle{ val opcode = p.Opcode() - val value = Bits(32 bits) // Int to float val arg = Bits(2 bits) val rs1, rs2, rs3 = p.rfAddress() val rd = p.rfAddress() diff --git a/src/main/scala/vexriscv/plugin/FpuPlugin.scala b/src/main/scala/vexriscv/plugin/FpuPlugin.scala index 258c0293..8f2bfa22 100644 --- a/src/main/scala/vexriscv/plugin/FpuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/FpuPlugin.scala @@ -161,15 +161,13 @@ class FpuPlugin(externalFpu : Boolean = false, //Maybe it might be better to not fork before fire to avoid RF stall on commits val forked = Reg(Bool) setWhen(port.cmd.fire) clearWhen(!arbitration.isStuck) init(False) - val intRfReady = Reg(Bool()) setWhen(!arbitration.isStuckByOthers) clearWhen(!arbitration.isStuck) //TODO is that still in use ? - val hazard = (input(RS1_USE) && !intRfReady) || csr.pendings.msb || csr.csrActive + val hazard = csr.pendings.msb || csr.csrActive arbitration.haltItself setWhen(arbitration.isValid && input(FPU_ENABLE) && hazard) arbitration.haltItself setWhen(port.cmd.isStall) port.cmd.valid := arbitration.isValid && input(FPU_ENABLE) && !forked && !hazard port.cmd.opcode := input(FPU_OPCODE) - port.cmd.value := RegNext(output(RS1)) port.cmd.arg := input(FPU_ARG) port.cmd.rs1 := ((input(FPU_OPCODE) === FpuOpcode.STORE) ? input(INSTRUCTION)(rs2Range).asUInt | input(INSTRUCTION)(rs1Range).asUInt) port.cmd.rs2 := input(INSTRUCTION)(rs2Range).asUInt @@ -179,7 +177,7 @@ class FpuPlugin(externalFpu : Boolean = false, insert(FPU_FORKED) := forked || port.cmd.fire - insert(FPU_COMMIT_SYNC) := List(FpuOpcode.LOAD, FpuOpcode.FMV_W_X).map(_ === input(FPU_OPCODE)).orR + insert(FPU_COMMIT_SYNC) := List(FpuOpcode.LOAD, FpuOpcode.FMV_W_X, FpuOpcode.I2F).map(_ === input(FPU_OPCODE)).orR insert(FPU_COMMIT_LOAD) := input(FPU_OPCODE) === FpuOpcode.LOAD } diff --git a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala index e349611f..0bfeb4c4 100644 --- a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala +++ b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala @@ -64,7 +64,6 @@ class FpuTest extends FunSuite{ def loadRaw(rd : Int, value : BigInt): Unit ={ cmdQueue += {cmd => cmd.opcode #= cmd.opcode.spinalEnum.LOAD - cmd.value.randomize() cmd.rs1.randomize() cmd.rs2.randomize() cmd.rs3.randomize() @@ -85,7 +84,6 @@ class FpuTest extends FunSuite{ def storeRaw(rs : Int)(body : FpuRsp => Unit): Unit ={ cmdQueue += {cmd => cmd.opcode #= cmd.opcode.spinalEnum.STORE - cmd.value.randomize() cmd.rs1 #= rs cmd.rs2.randomize() cmd.rs3.randomize() @@ -103,7 +101,6 @@ class FpuTest extends FunSuite{ def mul(rd : Int, rs1 : Int, rs2 : Int): Unit ={ cmdQueue += {cmd => cmd.opcode #= cmd.opcode.spinalEnum.MUL - cmd.value.randomize() cmd.rs1 #= rs1 cmd.rs2 #= rs2 cmd.rs3.randomize() @@ -119,7 +116,6 @@ class FpuTest extends FunSuite{ def add(rd : Int, rs1 : Int, rs2 : Int): Unit ={ cmdQueue += {cmd => cmd.opcode #= cmd.opcode.spinalEnum.ADD - cmd.value.randomize() cmd.rs1 #= rs1 cmd.rs2 #= rs2 cmd.rs3.randomize() @@ -135,7 +131,6 @@ class FpuTest extends FunSuite{ def div(rd : Int, rs1 : Int, rs2 : Int): Unit ={ cmdQueue += {cmd => cmd.opcode #= cmd.opcode.spinalEnum.DIV - cmd.value.randomize() cmd.rs1 #= rs1 cmd.rs2 #= rs2 cmd.rs3.randomize() @@ -151,7 +146,6 @@ class FpuTest extends FunSuite{ def sqrt(rd : Int, rs1 : Int): Unit ={ cmdQueue += {cmd => cmd.opcode #= cmd.opcode.spinalEnum.SQRT - cmd.value.randomize() cmd.rs1 #= rs1 cmd.rs2.randomize() cmd.rs3.randomize() @@ -167,7 +161,6 @@ class FpuTest extends FunSuite{ def fma(rd : Int, rs1 : Int, rs2 : Int, rs3 : Int): Unit ={ cmdQueue += {cmd => cmd.opcode #= cmd.opcode.spinalEnum.FMA - cmd.value.randomize() cmd.rs1 #= rs1 cmd.rs2 #= rs2 cmd.rs3 #= rs3 @@ -184,7 +177,6 @@ class FpuTest extends FunSuite{ def cmp(rs1 : Int, rs2 : Int)(body : FpuRsp => Unit): Unit ={ cmdQueue += {cmd => cmd.opcode #= cmd.opcode.spinalEnum.CMP - cmd.value.randomize() cmd.rs1 #= rs1 cmd.rs2 #= rs2 cmd.rs3.randomize() @@ -197,7 +189,6 @@ class FpuTest extends FunSuite{ def f2i(rs1 : Int, signed : Boolean)(body : FpuRsp => Unit): Unit ={ cmdQueue += {cmd => cmd.opcode #= cmd.opcode.spinalEnum.F2I - cmd.value.randomize() cmd.rs1 #= rs1 cmd.rs2.randomize() cmd.rs3.randomize() @@ -210,7 +201,6 @@ class FpuTest extends FunSuite{ def i2f(rd : Int, value : Int, signed : Boolean): Unit ={ cmdQueue += {cmd => cmd.opcode #= cmd.opcode.spinalEnum.I2F - cmd.value #= value.toLong & 0xFFFFFFFFl cmd.rs1.randomize() cmd.rs2.randomize() cmd.rs3.randomize() @@ -219,14 +209,14 @@ class FpuTest extends FunSuite{ } commitQueue += {cmd => cmd.write #= true - cmd.sync #= false + cmd.sync #= true + cmd.value #= value.toLong & 0xFFFFFFFFl } } def fmv_x_w(rs1 : Int)(body : FpuRsp => Unit): Unit ={ cmdQueue += {cmd => cmd.opcode #= cmd.opcode.spinalEnum.FMV_X_W - cmd.value.randomize() cmd.rs1 #= rs1 cmd.rs2.randomize() cmd.rs3.randomize() @@ -239,7 +229,6 @@ class FpuTest extends FunSuite{ def fmv_w_x(rd : Int, value : Int): Unit ={ cmdQueue += {cmd => cmd.opcode #= cmd.opcode.spinalEnum.FMV_W_X - cmd.value.randomize() cmd.rs1.randomize() cmd.rs2.randomize() cmd.rs3.randomize() @@ -256,7 +245,6 @@ class FpuTest extends FunSuite{ def min(rd : Int, rs1 : Int, rs2 : Int): Unit ={ cmdQueue += {cmd => cmd.opcode #= cmd.opcode.spinalEnum.MIN_MAX - cmd.value.randomize() cmd.rs1 #= rs1 cmd.rs2 #= rs2 cmd.rs3.randomize() @@ -273,7 +261,6 @@ class FpuTest extends FunSuite{ def sgnj(rd : Int, rs1 : Int, rs2 : Int): Unit ={ cmdQueue += {cmd => cmd.opcode #= cmd.opcode.spinalEnum.SGNJ - cmd.value.randomize() cmd.rs1 #= rs1 cmd.rs2 #= rs2 cmd.rs3.randomize() @@ -447,9 +434,11 @@ class FpuTest extends FunSuite{ val rd = Random.nextInt(32) i2f(rd, a, signed) storeFloat(rd){v => - val ref = a.toInt - println(f"i2f($a) = $v, $ref") - assert(v === ref) + val aLong = if(signed) a.toLong else a.toLong & 0xFFFFFFFFl + val ref = if(signed) a.toFloat else (a.toLong & 0xFFFFFFFFl).toFloat + println(f"i2f($aLong) = $v, $ref") + if(ref.abs < (1 << 22)) assert(v === ref) + assert(checkFloat(v, ref)) } } @@ -542,6 +531,65 @@ class FpuTest extends FunSuite{ val fNan = List(Float.NaN, b2f(0x7f820000), b2f(0x7fc00000)) val fAll = fZeros ++ fSubnormals ++ fExpSmall ++ fExpNormal ++ fExpBig ++ fInfinity ++ fNan + val iSmall = (0 to 20) + val iBigUnsigned = (0 to 20).map(e => 0xFFFFFFFF - e) + val iBigSigned = (0 to 20).map(e => 0x7FFFFFFF - e) ++ (0 to 20).map(e => 0x80000000 + e) + val iUnsigned = iSmall ++ iBigUnsigned + val iSigned = iSmall ++ iSmall.map(-_) ++ iBigSigned + + + testLoadStore(1.17549435082e-38f) + testLoadStore(1.4E-45f) + testLoadStore(3.44383110592e-41f) + + testAdd(b2f(0x3f800000), b2f(0x3f800000-1)) + testAdd(1.1f, 2.3f) + testAdd(1.2f, -1.2f) + testAdd(-1.2f, 1.2f) + testAdd(0.0f, -1.2f) + testAdd(-0.0f, -1.2f) + testAdd(1.2f, -0f) + testAdd(1.2f, 0f) + testAdd(1.1f, Float.MinPositiveValue) + + for(a <- fAll; _ <- 0 until 50) testAdd(a, randomFloat()) + for(b <- fAll; _ <- 0 until 50) testAdd(randomFloat(), b) + for(a <- fAll; b <- fAll) testAdd(a, b) + for(_ <- 0 until 1000) testAdd(randomFloat(), randomFloat()) + + + + testLoadStore(1.2f) + testMul(1.2f, 2.5f) + testMul(b2f(0x00400000), 16.0f) + testMul(b2f(0x00100000), 16.0f) + testMul(b2f(0x00180000), 16.0f) + testMul(b2f(0x00000004), 16.0f) + testMul(b2f(0x00000040), 16.0f) + testMul(b2f(0x00000041), 16.0f) + testMul(b2f(0x00000001), b2f(0x00000001)) + testMul(1.0f, b2f(0x00000001)) + testMul(0.5f, b2f(0x00000001)) + + // dut.clockDomain.waitSampling(1000) + // simSuccess() + + testMul(1.2f, 0f) + for(a <- fAll; _ <- 0 until 50) testMul(a, randomFloat()) + for(b <- fAll; _ <- 0 until 50) testMul(randomFloat(), b) + for(a <- fAll; b <- fAll) testMul(a, b) + for(_ <- 0 until 1000) testMul(randomFloat(), randomFloat()) + + + + testLoadStore(1.765f) + testFmv_w_x(lang.Float.floatToIntBits(7.234f)) + testI2f(64, false) + for(i <- iUnsigned) testI2f(i, false) + for(i <- iSigned) testI2f(i, true) + for(_ <- 0 until 1000) testI2f(Random.nextInt(), Random.nextBoolean()) + + testCmp(0.0f, 1.2f ) testCmp(1.2f, 0.0f ) testCmp(0.0f, -0.0f ) @@ -576,41 +624,6 @@ class FpuTest extends FunSuite{ - testAdd(b2f(0x3f800000), b2f(0x3f800000-1)) - testAdd(1.1f, 2.3f) - testAdd(1.2f, -1.2f) - testAdd(-1.2f, 1.2f) - testAdd(0.0f, -1.2f) - testAdd(-0.0f, -1.2f) - testAdd(1.2f, -0f) - testAdd(1.2f, 0f) - testAdd(1.1f, Float.MinPositiveValue) - - for(a <- fAll; _ <- 0 until 50) testAdd(a, randomFloat()) - for(b <- fAll; _ <- 0 until 50) testAdd(randomFloat(), b) - for(a <- fAll; b <- fAll) testAdd(a, b) - for(_ <- 0 until 1000) testAdd(randomFloat(), randomFloat()) - - testLoadStore(1.2f) - testMul(1.2f, 2.5f) - testMul(b2f(0x00400000), 16.0f) - testMul(b2f(0x00100000), 16.0f) - testMul(b2f(0x00180000), 16.0f) - testMul(b2f(0x00000004), 16.0f) - testMul(b2f(0x00000040), 16.0f) - testMul(b2f(0x00000041), 16.0f) - testMul(b2f(0x00000001), b2f(0x00000001)) - testMul(1.0f, b2f(0x00000001)) - testMul(0.5f, b2f(0x00000001)) - -// dut.clockDomain.waitSampling(1000) -// simSuccess() - - testMul(1.2f, 0f) - for(a <- fAll; _ <- 0 until 50) testMul(a, randomFloat()) - for(b <- fAll; _ <- 0 until 50) testMul(randomFloat(), b) - for(a <- fAll; b <- fAll) testMul(a, b) - for(_ <- 0 until 1000) testMul(randomFloat(), randomFloat()) From 195e4c422dc2891b71a7bbefc7dbc8c23be46b46 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 27 Jan 2021 12:11:30 +0100 Subject: [PATCH 554/951] fpu now integrate f2i shifter withing the subnormal shifter --- src/main/scala/vexriscv/ip/fpu/FpuCore.scala | 48 ++++++++++++++++---- src/test/scala/vexriscv/ip/fpu/FpuTest.scala | 39 ++++++++++++++-- 2 files changed, 73 insertions(+), 14 deletions(-) diff --git a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala index baa0bdda..cfe6e1c2 100644 --- a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala +++ b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala @@ -54,11 +54,13 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ case class ShortPipInput() extends Bundle{ val source = Source() val opcode = p.Opcode() - val rs1, rs2 = p.internalFloating() + val rs2 = p.internalFloating() + val rs1Raw = Bits(widthOf(rs2) bits) val lockId = lockIdType() val rd = p.rfAddress() val value = Bits(32 bits) val arg = Bits(2 bits) + def rs1 = rs1Raw.as(p.internalFloating) } case class MulInput() extends Bundle{ @@ -242,6 +244,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ input.ready setWhen(shortPipHit && shortPip.ready) shortPip.valid := input.valid && shortPipHit shortPip.payload.assignSomeByName(read.output.payload) + shortPip.rs1Raw := read.output.rs1.asBits val divSqrtHit = input.opcode === p.Opcode.DIV || input.opcode === p.Opcode.SQRT val divSqrt = Stream(DivSqrtInput()) @@ -437,18 +440,41 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ recodedResult := recoded.sign ## f32.exp ## f32.man val isSubnormal = !recoded.special && recoded.exponent <= exponentOne - 127 - val subnormal = new Area{ - val needRecoding = List(FpuOpcode.FMV_X_W, FpuOpcode.STORE).map(_ === input.opcode).orR + val fsm = new Area{ + val f2iShift = input.rs1.exponent - U(exponentOne) + val isF2i = input.opcode === FpuOpcode.F2I + val needRecoding = List(FpuOpcode.FMV_X_W, FpuOpcode.STORE).map(_ === input.opcode).orR && isSubnormal val manTop = Reg(UInt(log2Up(p.internalMantissaSize) bits)) val counter = Reg(UInt(log2Up(p.internalMantissaSize+1) bits)) val done, boot = Reg(Bool()) - when(input.valid && needRecoding && isSubnormal && !done){ + val isZero = input.rs1.isZero// || input.rs1.exponent < exponentOne-1 + val overflow = input.rs1.exponent > (input.arg(0) ? U(exponentOne+30) | U(exponentOne+31)) && !input.rs1.sign + val underflow = input.rs1.exponent > (input.arg(0) ? U(exponentOne+30) | U(exponentOne-1)) && input.rs1.sign // && !(input.arg(0) && input.rs1.exponent === exponentOne-31 && input.rs) + + when(input.valid && (needRecoding || isF2i) && !done){ halt := True when(boot){ - manTop := (U(exponentOne - 127) - recoded.exponent).resized + when(isF2i){ + when(underflow || overflow){ + done := True + val low = overflow + val high = input.arg(0) ^ overflow + input.rs1Raw.getDrivingReg(0, 32 bits) := (31 -> high, default -> low) + } otherwise { + manTop := (U(exponentOne + 31) - input.rs1.exponent).resized //TODO merge + input.rs1Raw.getDrivingReg(0, 32 bits) := input.rs1Raw(0, 23 bits) << 9 + } + } otherwise { + manTop := (U(exponentOne - 127) - recoded.exponent).resized + } boot := False + } otherwise { - recoded.mantissa.getDrivingReg := (U(counter === 0) @@ recoded.mantissa) >> 1 + when(isF2i){ + input.rs1Raw.getDrivingReg(0, 32 bits) := (B(counter === 0 && !isZero) ## input.rs1Raw(0, 32 bits)) >> 1 + } otherwise { + input.rs1Raw.getDrivingReg(0, 23 bits) := (B(counter === 0) ## input.rs1Raw(0, 23 bits)) >> 1 + } counter := counter + 1 when(counter === manTop) { done := True @@ -483,9 +509,11 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } - val f2iShift = input.rs1.exponent - U(exponentOne) - val f2iShifted = (U"1" @@ input.rs1.mantissa) << (f2iShift.resize(5 bits)) - val f2iUnsigned = f2iShifted >> p.internalMantissaSize +// val f2iShift = input.rs1.exponent - U(exponentOne) +// val f2iShifted = (U"1" @@ input.rs1.mantissa) << (f2iShift.resize(5 bits)) +// val f2iUnsigned = f2iShifted >> p.internalMantissaSize +// val f2iResult = (f2iUnsigned.twoComplement(input.arg(0) && input.rs1.sign)).asBits.resize(32 bits) + val f2iUnsigned = input.rs1Raw(0, 32 bits).asUInt val f2iResult = (f2iUnsigned.twoComplement(input.arg(0) && input.rs1.sign)).asBits.resize(32 bits) val bothZero = input.rs1.isZero && input.rs2.isZero @@ -839,7 +867,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val xSigned = xMantissa.twoComplement(xSign) // val ySigned = (yMantissa +^ (yMantissa.lsb && !ySign).asUInt).twoComplement(ySign) - val ySigned = ((ySign ## Mux(ySign, ~yMantissa, yMantissa)).asUInt +^ (ySign || yMantissa.lsb).asUInt).asSInt + val ySigned = ((ySign ## Mux(ySign, ~yMantissa, yMantissa)).asUInt +^ (ySign || yMantissa.lsb).asUInt).asSInt //rounding here val xyMantissa = U(xSigned + ySigned).trim(1 bits) } diff --git a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala index 0bfeb4c4..05f27f57 100644 --- a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala +++ b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala @@ -422,10 +422,19 @@ class FpuTest extends FunSuite{ val rd = Random.nextInt(32) load(rs1, a) f2i(rs1, signed){rsp => - val ref = a.toInt - val v = (rsp.value.toBigInt & 0xFFFFFFFF).toInt - println(f"f2i($a) = $v, $ref") - assert(v === ref) + if(signed) { + val ref = a.toInt + val v = (rsp.value.toBigInt & 0xFFFFFFFFl).toInt + println(f"f2i($a) = $v, $ref") + if (a.abs < 1024 * 1024) assert(v == ref) + assert(checkFloat(v, ref)) + } else { + val ref = a.toLong.min(0xFFFFFFFFl) + val v = (rsp.value.toBigInt & 0xFFFFFFFFl).toLong + println(f"f2i($a) = $v, $ref") + if (a.abs < 1024 * 1024) assert(v == ref) + assert(checkFloat(v, ref)) + } } } @@ -542,6 +551,28 @@ class FpuTest extends FunSuite{ testLoadStore(1.4E-45f) testLoadStore(3.44383110592e-41f) +//TODO bring back those tests and test overflow / underflow (F2I) +// testF2i(16.0f , false) +// testF2i(18.0f , false) +// testF2i(1200.0f, false) +// testF2i(1.0f , false) +// testF2i(0.0f , false) +// testF2i(1024*1024*1024*2l , false) +// testF2i(1024*1024*4095l , false) +// testF2i(1024*1024*5000l , false) +// +// val f2iUnsigned = ((0l to 32l) ++ (4060 to 4095).map(_*1024*1024l)).map(_.toFloat) ++ List(-0.0f) +// val f2iSigned = ((-32 to 32) ++ ((2030 to 2047)++(-2047 to -2030)).map(_*1024*1024)).map(_.toFloat) ++ List(-0.0f) +// for(f <- f2iUnsigned) testF2i(f, false) +// for(f <- f2iSigned) testF2i(f, true) +// for(f <- fAll) testF2i(f, false) +// for(f <- fAll) testF2i(f, true) +// for(_ <- 0 until 1000) testF2i(Random.nextFloat(), Random.nextBoolean()) + + + + + testAdd(b2f(0x3f800000), b2f(0x3f800000-1)) testAdd(1.1f, 2.3f) testAdd(1.2f, -1.2f) From 1ae84ea83b781b7c739d45beb43d1c0b843698c4 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 28 Jan 2021 00:25:16 +0100 Subject: [PATCH 555/951] fpu added proper rounding for add (need to manage substraction) --- src/main/scala/vexriscv/ip/fpu/FpuCore.scala | 116 ++++++++++++++---- .../scala/vexriscv/ip/fpu/Interface.scala | 16 +++ .../scala/vexriscv/plugin/FpuPlugin.scala | 20 +-- src/test/cpp/fpu/math/fpu_math.c | 50 ++++++++ src/test/cpp/fpu/math/libcode.version | 4 + src/test/java/vexriscv/ip/fpu/FpuMath.java | 11 ++ src/test/scala/vexriscv/ip/fpu/FpuTest.scala | 87 +++++++++---- 7 files changed, 252 insertions(+), 52 deletions(-) create mode 100644 src/test/cpp/fpu/math/fpu_math.c create mode 100644 src/test/cpp/fpu/math/libcode.version create mode 100644 src/test/java/vexriscv/ip/fpu/FpuMath.java diff --git a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala index cfe6e1c2..b3e3cbb7 100644 --- a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala +++ b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala @@ -30,6 +30,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val rd = p.rfAddress() val value = Bits(32 bits) val arg = p.Arg() + val roundMode = FpuRoundMode() } case class RfReadOutput() extends Bundle{ @@ -40,6 +41,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val rd = p.rfAddress() val value = Bits(32 bits) val arg = p.Arg() + val roundMode = FpuRoundMode() } @@ -49,6 +51,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val lockId = lockIdType() val i2f = Bool() val arg = Bits(2 bits) + val roundMode = FpuRoundMode() } case class ShortPipInput() extends Bundle{ @@ -61,6 +64,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val value = Bits(32 bits) val arg = Bits(2 bits) def rs1 = rs1Raw.as(p.internalFloating) + val roundMode = FpuRoundMode() } case class MulInput() extends Bundle{ @@ -71,6 +75,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val add = Bool() val divSqrt = Bool() val msb1, msb2 = Bool() //allow usage of msb bits of mul + val roundMode = FpuRoundMode() } @@ -80,6 +85,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val rd = p.rfAddress() val lockId = lockIdType() val div = Bool() + val roundMode = FpuRoundMode() } @@ -88,16 +94,26 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val rs1, rs2 = p.internalFloating() val rd = p.rfAddress() val lockId = lockIdType() + val roundMode = FpuRoundMode() } - case class WriteInput() extends Bundle{ + + case class MergeInput() extends Bundle{ + val source = Source() + val lockId = lockIdType() + val rd = p.rfAddress() + val value = p.internalFloating() + val round = UInt(2 bits) + val roundMode = FpuRoundMode() + } + + case class RoundOutput() extends Bundle{ val source = Source() val lockId = lockIdType() val rd = p.rfAddress() val value = p.internalFloating() } - val rf = new Area{ val ram = Mem(p.internalFloating, 32*portCount) val lock = for(i <- 0 until rfLockCount) yield new Area{ @@ -222,6 +238,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ output.lockId := s1LockId output.value := s1.value output.arg := s1.arg + output.roundMode := s1.roundMode output.rd := s1.rd output.rs1 := rf.ram.readSync(s0.source @@ s0.rs1,enable = !output.isStall) output.rs2 := rf.ram.readSync(s0.source @@ s0.rs2,enable = !output.isStall) @@ -298,6 +315,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val value = p.storeLoadType() val i2f = Bool() val arg = Bits(2 bits) + val roundMode = FpuRoundMode() } val s0 = new Area{ @@ -315,6 +333,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ output.value := feed.value output.i2f := input.i2f output.arg := input.arg + output.roundMode := input.roundMode } @@ -406,17 +425,20 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ when(isInfinity){recoded.setInfinity} when(isNan){recoded.setNan} - val output = input.haltWhen(busy).swapPayload(WriteInput()) + val output = input.haltWhen(busy).swapPayload(MergeInput()) output.source := input.source output.lockId := input.lockId + output.roundMode := input.roundMode output.rd := input.rd output.value := recoded + output.round := 0 when(input.i2f){ output.value.sign := i2fSign output.value.exponent := (U(exponentOne+31) - fsm.manTop).resized output.value.mantissa := U(i2fShifted) output.value.setNormal when(fsm.i2fZero) { output.value.setZero } + //TODO ROUND } } } @@ -424,7 +446,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val shortPip = new Area{ val input = decode.shortPip.stage() - val rfOutput = Stream(WriteInput()) + val rfOutput = Stream(MergeInput()) val result = p.storeLoadType().assignDontCare() @@ -563,6 +585,8 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ rfOutput.source := input.source rfOutput.lockId := input.lockId rfOutput.rd := input.rd + rfOutput.roundMode := input.roundMode + rfOutput.round := 0 //TODO rfOutput.value.assignDontCare() switch(input.opcode){ is(FpuOpcode.MIN_MAX){ @@ -634,11 +658,13 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ output.payload := math.mulC(p.internalMantissaSize, p.internalMantissaSize+1 bits) } - val output = Stream(WriteInput()) + val output = Stream(MergeInput()) output.valid := input.valid && !input.add && !input.divSqrt output.source := input.source output.lockId := input.lockId output.rd := input.rd + output.roundMode := input.roundMode + output.round := 0 //TODO output.value := norm.output decode.mulToAdd.valid := input.valid && input.add @@ -650,6 +676,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ decode.mulToAdd.rs2 := input.rs3 decode.mulToAdd.rd := input.rd decode.mulToAdd.lockId := input.lockId + decode.mulToAdd.roundMode := input.roundMode input.ready := (input.add ? decode.mulToAdd.ready | output.ready) || input.divSqrt } @@ -681,6 +708,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ decode.divSqrtToMul.msb2 := True decode.divSqrtToMul.rs1.special := False //TODO decode.divSqrtToMul.rs2.special := False + decode.divSqrtToMul.roundMode := input.roundMode val aprox = new Area { @@ -845,7 +873,8 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val rs1MantissaBigger = input.rs1.mantissa > input.rs2.mantissa val absRs1Bigger = ((rs1ExponentBigger || rs1ExponentEqual && rs1MantissaBigger) && !input.rs1.isZero || input.rs1.isInfinity) && !input.rs2.isInfinity val shiftBy = rs1ExponentBigger ? (0-exp21) | exp21 - val passThrough = shiftBy >= p.internalMantissaSize || (input.rs1.isZero) || (input.rs2.isZero) + val shiftOverflow = shiftBy >= p.internalMantissaSize + val passThrough = shiftOverflow || (input.rs1.isZero) || (input.rs2.isZero) //Note that rs1ExponentBigger can be replaced by absRs1Bigger bellow to avoid xsigned two complement in math block at expense of combinatorial path val xySign = absRs1Bigger ? input.rs1.sign | input.rs2.sign @@ -853,7 +882,14 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val ySign = xySign ^ (rs1ExponentBigger ? input.rs2.sign | input.rs1.sign) val xMantissa = U"1" @@ (rs1ExponentBigger ? input.rs1.mantissa | input.rs2.mantissa) @@ U"0" val yMantissaUnshifted = U"1" @@ (rs1ExponentBigger ? input.rs2.mantissa | input.rs1.mantissa) @@ U"0" - val yMantissa = yMantissaUnshifted >> (passThrough.asUInt @@ shiftBy.resize(log2Up(p.internalMantissaSize))) + var yMantissa = yMantissaUnshifted + val roundingScrap = CombInit(shiftOverflow) + for(i <- 0 until log2Up(p.internalMantissaSize)){ + roundingScrap setWhen(shiftBy(i) && yMantissa(0, 1 << i bits) =/= 0) + yMantissa \= shiftBy(i) ? (yMantissa |>> (BigInt(1) << i)) | yMantissa + } + when(passThrough) { yMantissa := 0 } + // val yMantissa = yMantissaUnshifted >> (passThrough.asUInt @@ shiftBy.resize(log2Up(p.internalMantissaSize))) //Maybe passThrough.asUInt @@ do not infer small logic val xyExponent = rs1ExponentBigger ? input.rs1.exponent | input.rs2.exponent } @@ -866,9 +902,9 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ def xySign = shifter.xySign val xSigned = xMantissa.twoComplement(xSign) -// val ySigned = (yMantissa +^ (yMantissa.lsb && !ySign).asUInt).twoComplement(ySign) - val ySigned = ((ySign ## Mux(ySign, ~yMantissa, yMantissa)).asUInt +^ (ySign || yMantissa.lsb).asUInt).asSInt //rounding here - val xyMantissa = U(xSigned + ySigned).trim(1 bits) + val ySigned = yMantissa.twoComplement(ySign) +// val ySigned = ((ySign ## Mux(ySign, ~yMantissa, yMantissa)).asUInt +^ (ySign || yMantissa.lsb).asUInt).asSInt //rounding here + val xyMantissa = U(xSigned +^ ySigned).trim(1 bits) } val norm = new Area{ @@ -878,9 +914,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val shiftOh = OHMasking.first(xyMantissa.asBools.reverse) val shift = OHToUInt(shiftOh) - val mantissa = (xyMantissa |<< shift) >> 2 -// val mantissaShifted = (xyMantissa |<< shift) -// val mantissa = ((xyMantissa ) >> 2) + U(xyMantissa(1)) + val mantissa = (xyMantissa |<< shift) val exponent = xyExponent -^ shift + 1 xySign clearWhen(input.rs1.isZero && input.rs2.isZero) val forceZero = xyMantissa === 0 || exponent.msb || (input.rs1.isZero && input.rs2.isZero) @@ -889,14 +923,16 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } - val output = input.swapPayload(WriteInput()) + val output = input.swapPayload(MergeInput()) output.source := input.source output.lockId := input.lockId output.rd := input.rd output.value.sign := norm.xySign - output.value.mantissa := norm.mantissa.resized + output.value.mantissa := (norm.mantissa >> 2).resized output.value.exponent := norm.exponent.resized output.value.special := False + output.roundMode := input.roundMode + output.round := norm.mantissa(1 downto 0) | (U"0" @@ shifter.roundingScrap) when(norm.forceNan) { output.value.setNanQuiet @@ -911,25 +947,59 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } - val write = new Area{ + val merge = new Area { val arbitrated = StreamArbiterFactory.lowerFirst.noLock.on(List(load.s1.output, add.output, mul.output, shortPip.rfOutput)) val isCommited = rf.lock.map(_.commited).read(arbitrated.lockId) val commited = arbitrated.haltWhen(!isCommited).toFlow + } - for(i <- 0 until portCount){ - completion(i).increments += (RegNext(commited.fire && commited.source === i) init(False)) + val round = new Area{ + val input = merge.commited.combStage + + val mantissaIncrement = !input.value.special && input.roundMode.mux( + FpuRoundMode.RNE -> (input.round(1) && (input.round(0) || input.value.mantissa.lsb)), + FpuRoundMode.RTZ -> False, + FpuRoundMode.RDN -> (input.round =/= 0 && input.value.sign), + FpuRoundMode.RUP -> (input.round =/= 0 && !input.value.sign), + FpuRoundMode.RMM -> (input.round(1)) + ) + + val math = p.internalFloating() + val adder = (input.value.exponent @@ input.value.mantissa) + U(mantissaIncrement) + math.special := input.value.special + math.sign := input.value.sign + math.exponent := adder(p.internalMantissaSize, p.internalExponentSize bits) + math.mantissa := adder(0, p.internalMantissaSize bits) + + val patched = CombInit(math) + when(!input.value.special && math.exponent === exponentOne + 128){ + patched.setInfinity } - when(commited.valid){ - for(i <- 0 until rfLockCount) when(commited.lockId === i){ + val output = input.swapPayload(RoundOutput()) + output.source := input.source + output.lockId := input.lockId + output.rd := input.rd + output.value := patched + } + + val writeback = new Area{ + val input = round.output.combStage + + for(i <- 0 until portCount){ + completion(i).increments += (RegNext(input.fire && input.source === i) init(False)) + } + + when(input.valid){ + for(i <- 0 until rfLockCount) when(input.lockId === i){ rf.lock(i).valid := False } } val port = rf.ram.writePort - port.valid := commited.valid && rf.lock.map(_.write).read(commited.lockId) - port.address := commited.source @@ commited.rd - port.data := commited.value + port.valid := input.valid && rf.lock.map(_.write).read(input.lockId) + port.address := input.source @@ input.rd + port.data := input.value when(port.valid){ assert(!(port.data.exponent === 0 && !port.data.special), "Special violation") diff --git a/src/main/scala/vexriscv/ip/fpu/Interface.scala b/src/main/scala/vexriscv/ip/fpu/Interface.scala index 82c2ba49..037cd3f0 100644 --- a/src/main/scala/vexriscv/ip/fpu/Interface.scala +++ b/src/main/scala/vexriscv/ip/fpu/Interface.scala @@ -89,6 +89,21 @@ object FpuFormat extends SpinalEnum{ val FLOAT, DOUBLE = newElement() } +object FpuRoundMode extends SpinalEnum(defaultEncoding = binarySequential){ + val RNE, RTZ, RDN, RUP, RMM = newElement() +} +object FpuRoundModeInstr extends SpinalEnum(){ + val RNE, RTZ, RDN, RUP, RMM, DYN = newElement() + defaultEncoding = SpinalEnumEncoding("opt")( + RNE -> 0, + RTZ -> 1, + RDN -> 2, + RUP -> 3, + RMM -> 4, + DYN -> 7 + ) +} + case class FpuParameter( internalMantissaSize : Int, withDouble : Boolean){ @@ -120,6 +135,7 @@ case class FpuCmd(p : FpuParameter) extends Bundle{ val rs1, rs2, rs3 = p.rfAddress() val rd = p.rfAddress() val format = p.Format() + val roundMode = FpuRoundMode() } case class FpuCommit(p : FpuParameter) extends Bundle{ diff --git a/src/main/scala/vexriscv/plugin/FpuPlugin.scala b/src/main/scala/vexriscv/plugin/FpuPlugin.scala index 8f2bfa22..c3673572 100644 --- a/src/main/scala/vexriscv/plugin/FpuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/FpuPlugin.scala @@ -166,14 +166,18 @@ class FpuPlugin(externalFpu : Boolean = false, arbitration.haltItself setWhen(arbitration.isValid && input(FPU_ENABLE) && hazard) arbitration.haltItself setWhen(port.cmd.isStall) - port.cmd.valid := arbitration.isValid && input(FPU_ENABLE) && !forked && !hazard - port.cmd.opcode := input(FPU_OPCODE) - port.cmd.arg := input(FPU_ARG) - port.cmd.rs1 := ((input(FPU_OPCODE) === FpuOpcode.STORE) ? input(INSTRUCTION)(rs2Range).asUInt | input(INSTRUCTION)(rs1Range).asUInt) - port.cmd.rs2 := input(INSTRUCTION)(rs2Range).asUInt - port.cmd.rs3 := input(INSTRUCTION)(rs3Range).asUInt - port.cmd.rd := input(INSTRUCTION)(rdRange).asUInt - port.cmd.format := FpuFormat.FLOAT + val iRoundMode = input(INSTRUCTION)(funct3Range) + val roundMode = (input(INSTRUCTION)(funct3Range) === B"111") ? csr.rm | input(INSTRUCTION)(funct3Range) + + port.cmd.valid := arbitration.isValid && input(FPU_ENABLE) && !forked && !hazard + port.cmd.opcode := input(FPU_OPCODE) + port.cmd.arg := input(FPU_ARG) + port.cmd.rs1 := ((input(FPU_OPCODE) === FpuOpcode.STORE) ? input(INSTRUCTION)(rs2Range).asUInt | input(INSTRUCTION)(rs1Range).asUInt) + port.cmd.rs2 := input(INSTRUCTION)(rs2Range).asUInt + port.cmd.rs3 := input(INSTRUCTION)(rs3Range).asUInt + port.cmd.rd := input(INSTRUCTION)(rdRange).asUInt + port.cmd.format := FpuFormat.FLOAT + port.cmd.roundMode := roundMode.as(FpuRoundMode()) insert(FPU_FORKED) := forked || port.cmd.fire diff --git a/src/test/cpp/fpu/math/fpu_math.c b/src/test/cpp/fpu/math/fpu_math.c new file mode 100644 index 00000000..3d869fea --- /dev/null +++ b/src/test/cpp/fpu/math/fpu_math.c @@ -0,0 +1,50 @@ +#include +#include +#include +#include +#include + +extern void miaou(); + + +//#include +//#pragma STDC FENV_ACCESS ON +//int applyRounding(int rounding){ +// int ret = fegetround( ); +// switch(rounding){ +// case 0: fesetround(FE_TONEAREST); break; +// case 1: fesetround(FE_TOWARDZERO); break; +// case 2: fesetround(FE_DOWNWARD); break; +// case 3: fesetround(FE_UPWARD); break; +// } +// return ret; +//} +// const int originalRounding = applyRounding(rounding); +// fesetround(originalRounding); + +void applyRounding(int rounding){ + switch(rounding){ + case 0: softfloat_roundingMode = 0; break; + case 1: softfloat_roundingMode = 1; break; + case 2: softfloat_roundingMode = 2; break; + case 3: softfloat_roundingMode = 3; break; + case 4: softfloat_roundingMode = 4; break; + } +} + +#define API __attribute__((visibility("default"))) + +//float32_t toF32(float v){ +// float32_t x; +// x.v = ; +// return x; +//} + +#define toF32(v) (*((float32_t*)&v)) +#define fromF32(x) (*((float*)&(x.v))) + +JNIEXPORT jfloat API JNICALL Java_vexriscv_ip_fpu_FpuMath_addF32(JNIEnv * env, jobject obj, jfloat a, jfloat b, jint rounding){ + applyRounding(rounding); + float32_t v = f32_add(toF32(a), toF32(b)); + return fromF32(v); +} \ No newline at end of file diff --git a/src/test/cpp/fpu/math/libcode.version b/src/test/cpp/fpu/math/libcode.version new file mode 100644 index 00000000..f039be60 --- /dev/null +++ b/src/test/cpp/fpu/math/libcode.version @@ -0,0 +1,4 @@ +CODEABI_1.0 { + global: FpuMath_*; + local: *; +} \ No newline at end of file diff --git a/src/test/java/vexriscv/ip/fpu/FpuMath.java b/src/test/java/vexriscv/ip/fpu/FpuMath.java new file mode 100644 index 00000000..136186ef --- /dev/null +++ b/src/test/java/vexriscv/ip/fpu/FpuMath.java @@ -0,0 +1,11 @@ +package vexriscv.ip.fpu; + +import java.io.File; + +public class FpuMath { + public native float addF32(float a, float b, int rounding); + + static{ + System.load(new File("src/test/cpp/fpu/math/fpu_math.so").getAbsolutePath()); + } +} \ No newline at end of file diff --git a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala index 05f27f57..787fbed5 100644 --- a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala +++ b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala @@ -1,12 +1,16 @@ package vexriscv.ip.fpu +import java.io.File import java.lang +import org.apache.commons.io.FileUtils import org.scalatest.FunSuite import spinal.core.SpinalEnumElement import spinal.core.sim._ +import spinal.lib.DoCmd import spinal.lib.experimental.math.Floating import spinal.lib.sim._ +import spinal.sim.Backend.{isMac, isWindows} import scala.collection.mutable import scala.collection.mutable.ArrayBuffer @@ -113,7 +117,7 @@ class FpuTest extends FunSuite{ } } - def add(rd : Int, rs1 : Int, rs2 : Int): Unit ={ + def add(rd : Int, rs1 : Int, rs2 : Int, rounding : FpuRoundMode.E = FpuRoundMode.RNE): Unit ={ cmdQueue += {cmd => cmd.opcode #= cmd.opcode.spinalEnum.ADD cmd.rs1 #= rs1 @@ -121,6 +125,7 @@ class FpuTest extends FunSuite{ cmd.rs3.randomize() cmd.rd #= rd cmd.arg #= 0 + cmd.roundMode #= rounding } commitQueue += {cmd => cmd.write #= true @@ -318,20 +323,21 @@ class FpuTest extends FunSuite{ (Random.nextDouble() * (Math.pow(2.0, exp)) * (if(Random.nextBoolean()) -1.0 else 1.0)).toFloat } - def testAdd(a : Float, b : Float): Unit ={ + def testAdd(a : Float, b : Float, rounding : FpuRoundMode.E = FpuRoundMode.RNE): Unit ={ val rs = new RegAllocator() val rs1, rs2, rs3 = rs.allocate() val rd = Random.nextInt(32) load(rs1, a) load(rs2, b) - add(rd,rs1,rs2) + add(rd,rs1,rs2, rounding) storeFloat(rd){v => val a_ = clamp(a) val b_ = clamp(b) - val ref = clamp(a_ + b_) - println(f"$a + $b = $v, $ref") - assert(checkFloat(ref, v)) + val ref = Clib.math.addF32(a,b, rounding.position) + println(f"${a}%.19f + $b%.19f = $v, $ref $rounding") + println(f"${f2b(a).toHexString} + ${f2b(b).toHexString}") + assert(checkFloatExact(ref, v)) } } @@ -547,6 +553,39 @@ class FpuTest extends FunSuite{ val iSigned = iSmall ++ iSmall.map(-_) ++ iBigSigned + val roundingModes = FpuRoundMode.elements + def foreachRounding(body : FpuRoundMode.E => Unit): Unit ={ + for(rounding <- roundingModes){ + body(rounding) + } + } + + //TODO test and fix a - b rounding + foreachRounding(testAdd(1.0f, b2f(0x3f800001), _)) //1.00001 + foreachRounding(testAdd(4.0f, b2f(0x3f800001), _)) //1.00001 + for(_ <- 0 until 10000; a = randomFloat(); b = randomFloat()) foreachRounding(testAdd(a.abs, b.abs,_)) //TODO negative + + + waitUntil(cmdQueue.isEmpty) + dut.clockDomain.waitSampling(1000) + simSuccess() + + testAdd(b2f(0x3f800000), b2f(0x3f800000-1)) + testAdd(1.1f, 2.3f) + testAdd(1.2f, -1.2f) + testAdd(-1.2f, 1.2f) + testAdd(0.0f, -1.2f) + testAdd(-0.0f, -1.2f) + testAdd(1.2f, -0f) + testAdd(1.2f, 0f) + testAdd(1.1f, Float.MinPositiveValue) + + for(a <- fAll; _ <- 0 until 50) testAdd(a, randomFloat()) + for(b <- fAll; _ <- 0 until 50) testAdd(randomFloat(), b) + for(a <- fAll; b <- fAll) testAdd(a, b) + for(_ <- 0 until 1000) testAdd(randomFloat(), randomFloat()) + + testLoadStore(1.17549435082e-38f) testLoadStore(1.4E-45f) testLoadStore(3.44383110592e-41f) @@ -573,21 +612,6 @@ class FpuTest extends FunSuite{ - testAdd(b2f(0x3f800000), b2f(0x3f800000-1)) - testAdd(1.1f, 2.3f) - testAdd(1.2f, -1.2f) - testAdd(-1.2f, 1.2f) - testAdd(0.0f, -1.2f) - testAdd(-0.0f, -1.2f) - testAdd(1.2f, -0f) - testAdd(1.2f, 0f) - testAdd(1.1f, Float.MinPositiveValue) - - for(a <- fAll; _ <- 0 until 50) testAdd(a, randomFloat()) - for(b <- fAll; _ <- 0 until 50) testAdd(randomFloat(), b) - for(a <- fAll; b <- fAll) testAdd(a, b) - for(_ <- 0 until 1000) testAdd(randomFloat(), randomFloat()) - testLoadStore(1.2f) @@ -796,3 +820,24 @@ class FpuTest extends FunSuite{ } } } + + +object Clib { + val java_home = System.getProperty("java.home") + assert(java_home != "" && java_home != null, "JAVA_HOME need to be set") + val jdk = java_home.replace("/jre","").replace("\\jre","") + val jdkIncludes = jdk + "/include" + val flags = List("-fPIC", "-m64", "-shared", "-Wno-attributes") //-Wl,--whole-archive + val os = new File("/media/data/open/SaxonSoc/berkeley-softfloat-3/build/Linux-x86_64-GCC").listFiles().map(_.getAbsolutePath).filter(_.toString.endsWith(".o")) + val cmd = s"gcc -I/media/data/open/SaxonSoc/berkeley-softfloat-3/source/include -I$jdkIncludes -I$jdkIncludes/linux ${flags.mkString(" ")} -o src/test/cpp/fpu/math/fpu_math.so src/test/cpp/fpu/math/fpu_math.c src/test/cpp/fpu/math/softfloat.a" // src/test/cpp/fpu/math/softfloat.a + DoCmd.doCmd(cmd) + val math = new FpuMath +} + +object FpuCompileSo extends App{ + + println(Clib.math.addF32(1.00000011921f, 4.0f, FpuRoundMode.RNE.position)) + println(Clib.math.addF32(1.00000011921f, 4.0f, FpuRoundMode.RTZ.position)) + println(Clib.math.addF32(1.00000011921f, 4.0f, FpuRoundMode.RDN.position)) + println(Clib.math.addF32(1.00000011921f, 4.0f, FpuRoundMode.RUP.position)) +} From fc3e6a6d0a1143e1ed54683dfb034f10eca8085b Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 28 Jan 2021 20:26:43 +0100 Subject: [PATCH 556/951] fpu add rounding is ok excepted infinity result --- src/main/scala/vexriscv/ip/fpu/FpuCore.scala | 44 ++++-- src/test/scala/vexriscv/ip/fpu/FpuTest.scala | 134 ++++++++++++++++++- 2 files changed, 161 insertions(+), 17 deletions(-) diff --git a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala index b3e3cbb7..9acc624e 100644 --- a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala +++ b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala @@ -873,23 +873,24 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val rs1MantissaBigger = input.rs1.mantissa > input.rs2.mantissa val absRs1Bigger = ((rs1ExponentBigger || rs1ExponentEqual && rs1MantissaBigger) && !input.rs1.isZero || input.rs1.isInfinity) && !input.rs2.isInfinity val shiftBy = rs1ExponentBigger ? (0-exp21) | exp21 - val shiftOverflow = shiftBy >= p.internalMantissaSize + val shiftOverflow = (shiftBy >= p.internalMantissaSize+3) val passThrough = shiftOverflow || (input.rs1.isZero) || (input.rs2.isZero) //Note that rs1ExponentBigger can be replaced by absRs1Bigger bellow to avoid xsigned two complement in math block at expense of combinatorial path val xySign = absRs1Bigger ? input.rs1.sign | input.rs2.sign val xSign = xySign ^ (rs1ExponentBigger ? input.rs1.sign | input.rs2.sign) val ySign = xySign ^ (rs1ExponentBigger ? input.rs2.sign | input.rs1.sign) - val xMantissa = U"1" @@ (rs1ExponentBigger ? input.rs1.mantissa | input.rs2.mantissa) @@ U"0" - val yMantissaUnshifted = U"1" @@ (rs1ExponentBigger ? input.rs2.mantissa | input.rs1.mantissa) @@ U"0" - var yMantissa = yMantissaUnshifted + val xMantissa = U"1" @@ (rs1ExponentBigger ? input.rs1.mantissa | input.rs2.mantissa) @@ U"00" + val yMantissaUnshifted = U"1" @@ (rs1ExponentBigger ? input.rs2.mantissa | input.rs1.mantissa) @@ U"00" + var yMantissa = CombInit(yMantissaUnshifted) val roundingScrap = CombInit(shiftOverflow) for(i <- 0 until log2Up(p.internalMantissaSize)){ roundingScrap setWhen(shiftBy(i) && yMantissa(0, 1 << i bits) =/= 0) yMantissa \= shiftBy(i) ? (yMantissa |>> (BigInt(1) << i)) | yMantissa } when(passThrough) { yMantissa := 0 } - // val yMantissa = yMantissaUnshifted >> (passThrough.asUInt @@ shiftBy.resize(log2Up(p.internalMantissaSize))) //Maybe passThrough.asUInt @@ do not infer small logic + when(shiftOverflow) { roundingScrap := True } + when(input.rs1.special || input.rs2.special){ roundingScrap := False } val xyExponent = rs1ExponentBigger ? input.rs1.exponent | input.rs2.exponent } @@ -901,9 +902,9 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ def xyExponent = shifter.xyExponent def xySign = shifter.xySign - val xSigned = xMantissa.twoComplement(xSign) - val ySigned = yMantissa.twoComplement(ySign) -// val ySigned = ((ySign ## Mux(ySign, ~yMantissa, yMantissa)).asUInt +^ (ySign || yMantissa.lsb).asUInt).asSInt //rounding here + val xSigned = xMantissa.twoComplement(xSign) //TODO Is that necessary ? + val overshot = (ySign && shifter.roundingScrap) + val ySigned = ((ySign ## Mux(ySign, ~yMantissa, yMantissa)).asUInt + (ySign && !shifter.roundingScrap).asUInt).asSInt //rounding here val xyMantissa = U(xSigned +^ ySigned).trim(1 bits) } @@ -915,10 +916,12 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val shiftOh = OHMasking.first(xyMantissa.asBools.reverse) val shift = OHToUInt(shiftOh) val mantissa = (xyMantissa |<< shift) +// val mantissa = ((shifter.roundingScrap.asUInt @@ xyMantissa.reversed) |>> shift).reversed >> 1 val exponent = xyExponent -^ shift + 1 xySign clearWhen(input.rs1.isZero && input.rs2.isZero) val forceZero = xyMantissa === 0 || exponent.msb || (input.rs1.isZero && input.rs2.isZero) - val forceOverflow = exponent === exponentOne + 128 || (input.rs1.isInfinity || input.rs2.isInfinity) + val forceOverflow = exponent === exponentOne + 128 + val forceInfinity = (input.rs1.isInfinity || input.rs2.isInfinity) val forceNan = input.rs1.isNan || input.rs2.isNan || (input.rs1.isInfinity && input.rs2.isInfinity && (input.rs1.sign ^ input.rs2.sign)) } @@ -928,11 +931,11 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ output.lockId := input.lockId output.rd := input.rd output.value.sign := norm.xySign - output.value.mantissa := (norm.mantissa >> 2).resized + output.value.mantissa := (norm.mantissa >> 3).resized output.value.exponent := norm.exponent.resized output.value.special := False output.roundMode := input.roundMode - output.round := norm.mantissa(1 downto 0) | (U"0" @@ shifter.roundingScrap) + output.round := U(norm.mantissa(2)) @@ U(norm.mantissa(1) | norm.mantissa(0) | shifter.roundingScrap) when(norm.forceNan) { output.value.setNanQuiet @@ -941,8 +944,25 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ when(norm.xyMantissa === 0 || input.rs1.isZero && input.rs2.isZero){ output.value.sign := input.rs1.sign && input.rs2.sign } - } elsewhen(norm.forceOverflow) { + when((input.rs1.sign || input.rs2.sign) && input.roundMode === FpuRoundMode.RDN){ + output.value.sign := True + } + } elsewhen(norm.forceInfinity) { output.value.setInfinity + } elsewhen(norm.forceOverflow) { + val doMax = input.roundMode.mux( + FpuRoundMode.RNE -> (True), + FpuRoundMode.RTZ -> (True), + FpuRoundMode.RDN -> (!output.value.sign), + FpuRoundMode.RUP -> (output.value.sign), + FpuRoundMode.RMM -> (True) + ) + when(doMax){ + output.value.exponent := exponentOne + 127 + output.value.mantissa.setAll() + } otherwise { + output.value.setInfinity + } } } diff --git a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala index 787fbed5..7f47669f 100644 --- a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala +++ b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala @@ -2,6 +2,7 @@ package vexriscv.ip.fpu import java.io.File import java.lang +import java.util.Scanner import org.apache.commons.io.FileUtils import org.scalatest.FunSuite @@ -14,12 +15,15 @@ import spinal.sim.Backend.{isMac, isWindows} import scala.collection.mutable import scala.collection.mutable.ArrayBuffer +import scala.sys.process.ProcessLogger import scala.util.Random + class FpuTest extends FunSuite{ val b2f = lang.Float.intBitsToFloat(_) val f2b = lang.Float.floatToIntBits(_) + def clamp(f : Float) = { f // if(f.abs < b2f(0x00800000)) b2f(f2b(f) & 0x80000000) else f } @@ -31,11 +35,41 @@ class FpuTest extends FunSuite{ withDouble = false ) - SimConfig.withFstWave.compile(new FpuCore(portCount, p)).doSim(seed = 42){ dut => + val config = SimConfig +// config.withFstWave + config.compile(new FpuCore(portCount, p)).doSim(seed = 42){ dut => dut.clockDomain.forkStimulus(10) + dut.clockDomain.forkSimSpeedPrinter() + class TestCase(t : String, op : String){ + def build(arg : String) = new ProcessStream(s"testfloat_gen $arg -forever -${t}_$op"){ + def f32_2 ={ + val l = next + val s = new Scanner(l) + (b2f(s.nextLong(16).toInt), b2f(s.nextLong(16).toInt), b2f(s.nextLong(16).toInt), s.nextInt(16)) + } + } + val RNE = build("-rnear_even") + val RTZ = build("-rminMag") + val RDN = build("-rmin") + val RUP = build("-rmax") + val RMM = build("-rnear_maxMag") + val all = List(RNE, RTZ, RDN, RUP, RMM) + def kill = all.foreach(_.kill) + def apply(rounding : FpuRoundMode.E) = rounding match { + case FpuRoundMode.RNE => RNE + case FpuRoundMode.RTZ => RTZ + case FpuRoundMode.RDN => RDN + case FpuRoundMode.RUP => RUP + case FpuRoundMode.RMM => RMM + } + } + + val f32 = new { + val add = new TestCase("f32", "add") + } val cpus = for(id <- 0 until portCount) yield new { val cmdQueue = mutable.Queue[FpuCmd => Unit]() @@ -96,6 +130,7 @@ class FpuTest extends FunSuite{ } rspQueue += body + waitUntil(rspQueue.isEmpty) } def storeFloat(rs : Int)(body : Float => Unit): Unit ={ @@ -341,6 +376,18 @@ class FpuTest extends FunSuite{ } } + def testAddExact(a : Float, b : Float, ref : Float, flag : Int, rounding : FpuRoundMode.E): Unit ={ + val rs = new RegAllocator() + val rs1, rs2, rs3 = rs.allocate() + val rd = Random.nextInt(32) + load(rs1, a) + load(rs2, b) + add(rd,rs1,rs2, rounding) + storeFloat(rd){v => + assert(f2b(v) == f2b(ref), f"## ${a} + $b = $v, $ref $rounding") + } + } + def testLoadStore(a : Float): Unit ={ val rd = Random.nextInt(32) load(rd, a) @@ -560,16 +607,57 @@ class FpuTest extends FunSuite{ } } + + +// roundingModes.foreach(rounding => println(Clib.math.addF32(0.0f, 0.0f, rounding.position))) +// roundingModes.foreach(rounding => println(Clib.math.addF32(1.0f,-1.0f, rounding.position))) + + println() + println(Clib.math.addF32(8.0f, b2f(0xBf800000), 0)) + println(Clib.math.addF32(8.0f, b2f(0xBf800001), 0)) + println(Clib.math.addF32(8.0f, b2f(0xBf800002), 0)) + println(Clib.math.addF32(8.0f, b2f(0xBf800003), 0)) + println(Clib.math.addF32(8.0f, b2f(0xBf800004), 0)) + println(Clib.math.addF32(8.0f, b2f(0xBf800005), 0)) + println(Clib.math.addF32(8.0f, b2f(0xBf800006), 0)) + println(Clib.math.addF32(8.0f, b2f(0xBf800007), 0)) + println(Clib.math.addF32(8.0f, b2f(0xBf800008), 0)) + + testAdd(-5.3687091E8f, 16.249022f, FpuRoundMode.RNE) + testAdd(-5.3687091E8f, 16.0f, FpuRoundMode.RNE) + testAdd(-5.3687091E8f, 15.0f, FpuRoundMode.RNE) + for(i <- 0 until 20) testAdd(4.0f, b2f(0xBf800000 + i), FpuRoundMode.RNE) + for(i <- 0 until 64) testAdd(12.0f, b2f(0xBf801000 + i), FpuRoundMode.RNE) + for(i <- 0 until 64) testAdd(8.0f, b2f(0xBf801000 + i), FpuRoundMode.RNE) + for(i <- 0 until 64) testAdd(12.0f, b2f(0x3f801000 + i), FpuRoundMode.RNE) + for(i <- 0 until 64) testAdd(8.0f, b2f(0x3f801000 + i), FpuRoundMode.RNE) + for(i <- 0 until 20) testAdd(b2f(0x40800000+3), b2f(0xBf800000 + i+1), FpuRoundMode.RNE) + for(i <- 0 until 20) testAdd(8.0f, b2f(0xBf800000 + i), FpuRoundMode.RNE) + for(i <- 0 until 20) testAdd(16.0f, b2f(0xBf800000 + i), FpuRoundMode.RNE) +// testAdd(8.0f, b2f(0xBf800001), FpuRoundMode.RNE) +// testAdd(8.0f, b2f(0xBf800002), FpuRoundMode.RNE) +// testAdd(8.0f, b2f(0xBf800003), FpuRoundMode.RNE) +// testAdd(8.0f, b2f(0xBf800004), FpuRoundMode.RNE) +// testAddExact(-256.2578f,1.8905041f ,-254.36731f,0, FpuRoundMode.RNE) + + + + for(_ <- 0 until 1000000){ + val rounding = FpuRoundMode.elements.randomPick() + val (a,b,c,f) = f32.add(rounding).f32_2 + if(/*a > 0 && b < 0 && */!c.isInfinity) testAddExact(a,b,c,f, rounding) + } + + waitUntil(cmdQueue.isEmpty) + dut.clockDomain.waitSampling(1000) + simSuccess() + //TODO test and fix a - b rounding foreachRounding(testAdd(1.0f, b2f(0x3f800001), _)) //1.00001 foreachRounding(testAdd(4.0f, b2f(0x3f800001), _)) //1.00001 for(_ <- 0 until 10000; a = randomFloat(); b = randomFloat()) foreachRounding(testAdd(a.abs, b.abs,_)) //TODO negative - waitUntil(cmdQueue.isEmpty) - dut.clockDomain.waitSampling(1000) - simSuccess() - testAdd(b2f(0x3f800000), b2f(0x3f800000-1)) testAdd(1.1f, 2.3f) testAdd(1.2f, -1.2f) @@ -841,3 +929,39 @@ object FpuCompileSo extends App{ println(Clib.math.addF32(1.00000011921f, 4.0f, FpuRoundMode.RDN.position)) println(Clib.math.addF32(1.00000011921f, 4.0f, FpuRoundMode.RUP.position)) } + +class ProcessStream(cmd : String){ + import sys.process._ + + val buf = mutable.Queue[() => String]() + val p = Process(cmd).run(new ProcessLogger { + override def out(s: => String): Unit = { + while(buf.size > 10000) Thread.sleep(10) + buf.enqueue(() => s) + } + override def err(s: => String): Unit = {} + override def buffer[T](f: => T): T = f + }) + + def kill = p.destroy() + def next = { + while(buf.isEmpty) { Thread.sleep(10) } + buf.dequeue()() + } +} + +object TestSoftFloat extends App{ + val p = new ProcessStream("testfloat_gen -forever f32_add") + Thread.sleep(1000) + println(p.next) + println(p.next) + println(p.next) + println(p.next) + println(p.next) + Thread.sleep(1000) + println(p.next) + while(true) { + Thread.sleep(10) + println(p.next) + } +} From 3c4df1e963d1e6d34cf81c4bc1fc7e28a3c3b97a Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 29 Jan 2021 14:37:52 +0100 Subject: [PATCH 557/951] fpu moved overflow rounding to writeback --- src/main/scala/vexriscv/ip/fpu/FpuCore.scala | 36 ++++++---- src/test/scala/vexriscv/ip/fpu/FpuTest.scala | 76 +++++++++++++++----- 2 files changed, 84 insertions(+), 28 deletions(-) diff --git a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala index 9acc624e..a0414848 100644 --- a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala +++ b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala @@ -624,7 +624,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ // val exp = math.exp + U(needShift) // val man = needShift ? math.mulC(p.internalMantissaSize + 1, p.internalMantissaSize bits) | math.mulC(p.internalMantissaSize, p.internalMantissaSize bits) - val mulRounded = (math.mulC >> p.internalMantissaSize) + math.mulC(p.internalMantissaSize-1).asUInt + val mulRounded = (math.mulC >> p.internalMantissaSize) val needShift = mulRounded.msb val exp = math.exp + U(needShift) val man = needShift ? mulRounded(1, p.internalMantissaSize bits) | mulRounded(0, p.internalMantissaSize bits) @@ -903,7 +903,6 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ def xySign = shifter.xySign val xSigned = xMantissa.twoComplement(xSign) //TODO Is that necessary ? - val overshot = (ySign && shifter.roundingScrap) val ySigned = ((ySign ## Mux(ySign, ~yMantissa, yMantissa)).asUInt + (ySign && !shifter.roundingScrap).asUInt).asSInt //rounding here val xyMantissa = U(xSigned +^ ySigned).trim(1 bits) } @@ -916,11 +915,9 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val shiftOh = OHMasking.first(xyMantissa.asBools.reverse) val shift = OHToUInt(shiftOh) val mantissa = (xyMantissa |<< shift) -// val mantissa = ((shifter.roundingScrap.asUInt @@ xyMantissa.reversed) |>> shift).reversed >> 1 val exponent = xyExponent -^ shift + 1 - xySign clearWhen(input.rs1.isZero && input.rs2.isZero) - val forceZero = xyMantissa === 0 || exponent.msb || (input.rs1.isZero && input.rs2.isZero) - val forceOverflow = exponent === exponentOne + 128 + val forceZero = xyMantissa === 0 || (input.rs1.isZero && input.rs2.isZero) +// val forceOverflow = exponent === exponentOne + 128 //Handled by writeback rounding val forceInfinity = (input.rs1.isInfinity || input.rs2.isInfinity) val forceNan = input.rs1.isNan || input.rs2.isNan || (input.rs1.isInfinity && input.rs2.isInfinity && (input.rs1.sign ^ input.rs2.sign)) } @@ -949,13 +946,13 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } } elsewhen(norm.forceInfinity) { output.value.setInfinity - } elsewhen(norm.forceOverflow) { + } /*elsewhen(norm.forceOverflow) { val doMax = input.roundMode.mux( - FpuRoundMode.RNE -> (True), + FpuRoundMode.RNE -> (False), FpuRoundMode.RTZ -> (True), FpuRoundMode.RDN -> (!output.value.sign), FpuRoundMode.RUP -> (output.value.sign), - FpuRoundMode.RMM -> (True) + FpuRoundMode.RMM -> (False) ) when(doMax){ output.value.exponent := exponentOne + 127 @@ -963,7 +960,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } otherwise { output.value.setInfinity } - } + }*/ } @@ -992,10 +989,25 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ math.mantissa := adder(0, p.internalMantissaSize bits) val patched = CombInit(math) - when(!input.value.special && math.exponent === exponentOne + 128){ - patched.setInfinity + when(!math.special && math.exponent >= exponentOne + 128){ +// patched.setInfinity + val doMax = input.roundMode.mux( + FpuRoundMode.RNE -> (False), + FpuRoundMode.RTZ -> (True), + FpuRoundMode.RDN -> (!math.sign), + FpuRoundMode.RUP -> (math.sign), + FpuRoundMode.RMM -> (False) + ) + when(doMax){ + patched.exponent := exponentOne + 127 + patched.mantissa.setAll() + } otherwise { + patched.setInfinity + } } + + val output = input.swapPayload(RoundOutput()) output.source := input.source output.lockId := input.lockId diff --git a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala index 7f47669f..1fcd058c 100644 --- a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala +++ b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala @@ -69,6 +69,7 @@ class FpuTest extends FunSuite{ val f32 = new { val add = new TestCase("f32", "add") + val mul = new TestCase("f32", "mul") } val cpus = for(id <- 0 until portCount) yield new { @@ -137,7 +138,7 @@ class FpuTest extends FunSuite{ storeRaw(rs){rsp => body(b2f(rsp.value.toLong.toInt))} } - def mul(rd : Int, rs1 : Int, rs2 : Int): Unit ={ + def mul(rd : Int, rs1 : Int, rs2 : Int, rounding : FpuRoundMode.E = FpuRoundMode.RNE): Unit ={ cmdQueue += {cmd => cmd.opcode #= cmd.opcode.spinalEnum.MUL cmd.rs1 #= rs1 @@ -145,6 +146,7 @@ class FpuTest extends FunSuite{ cmd.rs3.randomize() cmd.rd #= rd cmd.arg #= 0 + cmd.roundMode #= rounding } commitQueue += {cmd => cmd.write #= true @@ -388,6 +390,19 @@ class FpuTest extends FunSuite{ } } + + def testMulExact(a : Float, b : Float, ref : Float, flag : Int, rounding : FpuRoundMode.E): Unit ={ + val rs = new RegAllocator() + val rs1, rs2, rs3 = rs.allocate() + val rd = Random.nextInt(32) + load(rs1, a) + load(rs2, b) + mul(rd,rs1,rs2, rounding) + storeFloat(rd){v => + assert(f2b(v) == f2b(ref), f"## ${a} * $b = $v, $ref $rounding") + } + } + def testLoadStore(a : Float): Unit ={ val rd = Random.nextInt(32) load(rd, a) @@ -418,6 +433,7 @@ class FpuTest extends FunSuite{ } + def testFma(a : Float, b : Float, c : Float): Unit ={ val rs = new RegAllocator() val rs1, rs2, rs3 = rs.allocate() @@ -609,19 +625,34 @@ class FpuTest extends FunSuite{ +// for(_ <- 0 until 1000000){ +// val rounding = FpuRoundMode.RTZ +// val (a,b,c,f) = f32.mul(rounding).f32_2 +// if(a > 0 && b > 0 && !c.isInfinity) testMulExact(a,b,c,f, rounding) +// } + + // roundingModes.foreach(rounding => println(Clib.math.addF32(0.0f, 0.0f, rounding.position))) // roundingModes.foreach(rounding => println(Clib.math.addF32(1.0f,-1.0f, rounding.position))) - println() - println(Clib.math.addF32(8.0f, b2f(0xBf800000), 0)) - println(Clib.math.addF32(8.0f, b2f(0xBf800001), 0)) - println(Clib.math.addF32(8.0f, b2f(0xBf800002), 0)) - println(Clib.math.addF32(8.0f, b2f(0xBf800003), 0)) - println(Clib.math.addF32(8.0f, b2f(0xBf800004), 0)) - println(Clib.math.addF32(8.0f, b2f(0xBf800005), 0)) - println(Clib.math.addF32(8.0f, b2f(0xBf800006), 0)) - println(Clib.math.addF32(8.0f, b2f(0xBf800007), 0)) - println(Clib.math.addF32(8.0f, b2f(0xBf800008), 0)) + println("Mul done") + + for(i <- 0 until 20) println(Clib.math.addF32(b2f(0x7f000000), b2f(0x7f000000-10+i), 0)) +// simSuccess() + + foreachRounding(r => println(Clib.math.addF32(b2f(0x7f7fffff), b2f(0x7f7fffff),r.position))) + println("") + foreachRounding(r => println(Clib.math.addF32(2.5787021E38f, 3.4027196E38f,r.position))) + println("") +// println(Clib.math.addF32(8.0f, b2f(0xBf800000), 0)) +// println(Clib.math.addF32(8.0f, b2f(0xBf800001), 0)) +// println(Clib.math.addF32(8.0f, b2f(0xBf800002), 0)) +// println(Clib.math.addF32(8.0f, b2f(0xBf800003), 0)) +// println(Clib.math.addF32(8.0f, b2f(0xBf800004), 0)) +// println(Clib.math.addF32(8.0f, b2f(0xBf800005), 0)) +// println(Clib.math.addF32(8.0f, b2f(0xBf800006), 0)) +// println(Clib.math.addF32(8.0f, b2f(0xBf800007), 0)) +// println(Clib.math.addF32(8.0f, b2f(0xBf800008), 0)) testAdd(-5.3687091E8f, 16.249022f, FpuRoundMode.RNE) testAdd(-5.3687091E8f, 16.0f, FpuRoundMode.RNE) @@ -645,7 +676,13 @@ class FpuTest extends FunSuite{ for(_ <- 0 until 1000000){ val rounding = FpuRoundMode.elements.randomPick() val (a,b,c,f) = f32.add(rounding).f32_2 - if(/*a > 0 && b < 0 && */!c.isInfinity) testAddExact(a,b,c,f, rounding) +// if(a.isNaN) println("Nan") +// if(b.isNaN) println("Nan") +// if(a.isInfinity) println("Inf") +// if(b.isInfinity) println("Inf") +// if(a == 0f) println("Zero") +// if(b == 0f) println("Zero") + /*if(/*a > 0 && b < 0 && */!c.isInfinity) */testAddExact(a,b,c,f, rounding) } waitUntil(cmdQueue.isEmpty) @@ -924,10 +961,17 @@ object Clib { object FpuCompileSo extends App{ - println(Clib.math.addF32(1.00000011921f, 4.0f, FpuRoundMode.RNE.position)) - println(Clib.math.addF32(1.00000011921f, 4.0f, FpuRoundMode.RTZ.position)) - println(Clib.math.addF32(1.00000011921f, 4.0f, FpuRoundMode.RDN.position)) - println(Clib.math.addF32(1.00000011921f, 4.0f, FpuRoundMode.RUP.position)) + val b2f = lang.Float.intBitsToFloat(_) + for(e <- FpuRoundMode.elements) { + println(e) + for (i <- -2 until 50) println(i + " => " + Clib.math.addF32(b2f(0x7f000000), b2f(0x7f000000 + i), e.position)) + println("") + } + +// println(Clib.math.addF32(1.00000011921f, 4.0f, FpuRoundMode.RNE.position)) +// println(Clib.math.addF32(1.00000011921f, 4.0f, FpuRoundMode.RTZ.position)) +// println(Clib.math.addF32(1.00000011921f, 4.0f, FpuRoundMode.RDN.position)) +// println(Clib.math.addF32(1.00000011921f, 4.0f, FpuRoundMode.RUP.position)) } class ProcessStream(cmd : String){ From 09975927686dd549f93e8ca731b12ad680580591 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 29 Jan 2021 16:13:49 +0100 Subject: [PATCH 558/951] fpu mul sems all good excepted subnormal rounding --- src/main/scala/vexriscv/ip/fpu/FpuCore.scala | 17 ++++++++++------- src/test/cpp/fpu/math/fpu_math.c | 6 ++++++ src/test/java/vexriscv/ip/fpu/FpuMath.java | 1 + src/test/scala/vexriscv/ip/fpu/FpuTest.scala | 20 +++++++++++++++----- 4 files changed, 32 insertions(+), 12 deletions(-) diff --git a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala index a0414848..8c231aab 100644 --- a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala +++ b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala @@ -624,22 +624,25 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ // val exp = math.exp + U(needShift) // val man = needShift ? math.mulC(p.internalMantissaSize + 1, p.internalMantissaSize bits) | math.mulC(p.internalMantissaSize, p.internalMantissaSize bits) - val mulRounded = (math.mulC >> p.internalMantissaSize) - val needShift = mulRounded.msb + val (mulHigh, mulLow) = math.mulC.splitAt(p.internalMantissaSize-1) + val scrap = mulLow =/= 0 + val needShift = mulHigh.msb val exp = math.exp + U(needShift) - val man = needShift ? mulRounded(1, p.internalMantissaSize bits) | mulRounded(0, p.internalMantissaSize bits) - + val man = needShift ? mulHigh(1, p.internalMantissaSize+1 bits) | mulHigh(0, p.internalMantissaSize+1 bits) + scrap setWhen(needShift && mulHigh(0)) val forceZero = input.rs1.isZero || input.rs2.isZero val forceUnderflow = exp <= exponentOne + exponentOne - 127 - 23 // 0x6A //TODO - val forceOverflow = exp > exponentOne + exponentOne + 127 || input.rs1.isInfinity || input.rs2.isInfinity + val forceOverflow = /*exp > exponentOne + exponentOne + 127 || */input.rs1.isInfinity || input.rs2.isInfinity val forceNan = input.rs1.isNan || input.rs2.isNan || ((input.rs1.isInfinity || input.rs2.isInfinity) && (input.rs1.isZero || input.rs2.isZero)) val output = FpuFloat(p.internalExponentSize, p.internalMantissaSize) output.sign := input.rs1.sign ^ input.rs2.sign output.exponent := (exp - exponentOne).resized - output.mantissa := man + output.mantissa := man.asUInt >> 1 output.setNormal + val round = man(0) ## (scrap) + when(forceNan) { output.setNanQuiet } elsewhen(forceOverflow) { @@ -664,7 +667,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ output.lockId := input.lockId output.rd := input.rd output.roundMode := input.roundMode - output.round := 0 //TODO + output.round := norm.round.asUInt output.value := norm.output decode.mulToAdd.valid := input.valid && input.add diff --git a/src/test/cpp/fpu/math/fpu_math.c b/src/test/cpp/fpu/math/fpu_math.c index 3d869fea..ee0b3c04 100644 --- a/src/test/cpp/fpu/math/fpu_math.c +++ b/src/test/cpp/fpu/math/fpu_math.c @@ -47,4 +47,10 @@ JNIEXPORT jfloat API JNICALL Java_vexriscv_ip_fpu_FpuMath_addF32(JNIEnv * env, j applyRounding(rounding); float32_t v = f32_add(toF32(a), toF32(b)); return fromF32(v); +} + +JNIEXPORT jfloat API JNICALL Java_vexriscv_ip_fpu_FpuMath_mulF32(JNIEnv * env, jobject obj, jfloat a, jfloat b, jint rounding){ + applyRounding(rounding); + float32_t v = f32_mul(toF32(a), toF32(b)); + return fromF32(v); } \ No newline at end of file diff --git a/src/test/java/vexriscv/ip/fpu/FpuMath.java b/src/test/java/vexriscv/ip/fpu/FpuMath.java index 136186ef..88da0074 100644 --- a/src/test/java/vexriscv/ip/fpu/FpuMath.java +++ b/src/test/java/vexriscv/ip/fpu/FpuMath.java @@ -4,6 +4,7 @@ import java.io.File; public class FpuMath { public native float addF32(float a, float b, int rounding); + public native float mulF32(float a, float b, int rounding); static{ System.load(new File("src/test/cpp/fpu/math/fpu_math.so").getAbsolutePath()); diff --git a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala index 1fcd058c..7d5d3dc9 100644 --- a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala +++ b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala @@ -624,12 +624,22 @@ class FpuTest extends FunSuite{ } + for(i <- 0 until 64){ + val rounding = FpuRoundMode.RMM + val a = 24f + val b = b2f(0x3f800000+i) + val c = Clib.math.mulF32(a, b, rounding.position) + val f = 0 + testMulExact(a,b,c,f, rounding) + } -// for(_ <- 0 until 1000000){ -// val rounding = FpuRoundMode.RTZ -// val (a,b,c,f) = f32.mul(rounding).f32_2 -// if(a > 0 && b > 0 && !c.isInfinity) testMulExact(a,b,c,f, rounding) -// } +// simSuccess() + + for(_ <- 0 until 1000000){ + val rounding = FpuRoundMode.elements.randomPick() + val (a,b,c,f) = f32.mul(rounding).f32_2 + if(!(c.abs < 1e-35f && c.abs > 0f)) testMulExact(a,b,c,f, rounding) + } // roundingModes.foreach(rounding => println(Clib.math.addF32(0.0f, 0.0f, rounding.position))) From c51b0fcafe4e6de5845c73d6f1793ed330fc79fd Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 29 Jan 2021 22:30:19 +0100 Subject: [PATCH 559/951] fpu mul now pass all roundings --- src/main/scala/vexriscv/ip/fpu/FpuCore.scala | 39 ++++++++++++++++---- src/test/scala/vexriscv/ip/fpu/FpuTest.scala | 3 +- 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala index 8c231aab..51b65d8b 100644 --- a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala +++ b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala @@ -631,7 +631,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val man = needShift ? mulHigh(1, p.internalMantissaSize+1 bits) | mulHigh(0, p.internalMantissaSize+1 bits) scrap setWhen(needShift && mulHigh(0)) val forceZero = input.rs1.isZero || input.rs2.isZero - val forceUnderflow = exp <= exponentOne + exponentOne - 127 - 23 // 0x6A //TODO + val forceUnderflow = exp < exponentOne + exponentOne - 127 - 24 // 0x6A //TODO val forceOverflow = /*exp > exponentOne + exponentOne + 127 || */input.rs1.isInfinity || input.rs2.isInfinity val forceNan = input.rs1.isNan || input.rs2.isNan || ((input.rs1.isInfinity || input.rs2.isInfinity) && (input.rs1.isZero || input.rs2.isZero)) @@ -650,7 +650,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } elsewhen(forceZero) { output.setZero } elsewhen(forceUnderflow) { - output.setZero + output.exponent := exponentOne - 127 - 25 } } @@ -968,6 +968,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val merge = new Area { + //TODO maybe load can bypass merge and round. val arbitrated = StreamArbiterFactory.lowerFirst.noLock.on(List(load.s1.output, add.output, mul.output, shortPip.rfOutput)) val isCommited = rf.lock.map(_.commited).read(arbitrated.lockId) val commited = arbitrated.haltWhen(!isCommited).toFlow @@ -976,16 +977,25 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val round = new Area{ val input = merge.commited.combStage + //TODO do not break NAN payload + val manAggregate = input.value.mantissa @@ input.round + val expDif = (exponentOne-126) - input.value.exponent + val discardCount = expDif.msb ? U(0) | expDif.resize(log2Up(p.internalMantissaSize) bits) + val exactMask = (List(True) ++ (0 until p.internalMantissaSize+1).map(_ < discardCount)).asBits.asUInt + val roundAdjusted = (True ## (manAggregate>>1))(discardCount) ## ((manAggregate & exactMask) =/= 0) + val mantissaIncrement = !input.value.special && input.roundMode.mux( - FpuRoundMode.RNE -> (input.round(1) && (input.round(0) || input.value.mantissa.lsb)), + FpuRoundMode.RNE -> (roundAdjusted(1) && (roundAdjusted(0) || (U"01" ## (manAggregate>>2))(discardCount))), FpuRoundMode.RTZ -> False, - FpuRoundMode.RDN -> (input.round =/= 0 && input.value.sign), - FpuRoundMode.RUP -> (input.round =/= 0 && !input.value.sign), - FpuRoundMode.RMM -> (input.round(1)) + FpuRoundMode.RDN -> (roundAdjusted =/= 0 && input.value.sign), + FpuRoundMode.RUP -> (roundAdjusted =/= 0 && !input.value.sign), + FpuRoundMode.RMM -> (roundAdjusted(1)) ) val math = p.internalFloating() - val adder = (input.value.exponent @@ input.value.mantissa) + U(mantissaIncrement) + val adderMantissa = input.value.mantissa & (mantissaIncrement ? ~(exactMask.trim(1) >> 1) | input.value.mantissa.maxValue) + val adderRightOp = (mantissaIncrement ? (exactMask >> 1)| U(0)).resize(p.internalMantissaSize bits) + val adder = (input.value.exponent @@ adderMantissa) + adderRightOp + U(mantissaIncrement) math.special := input.value.special math.sign := input.value.sign math.exponent := adder(p.internalMantissaSize, p.internalExponentSize bits) @@ -1010,6 +1020,21 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } + when(!math.special && math.exponent <= exponentOne - 127-23){ + val doMin = input.roundMode.mux( + FpuRoundMode.RNE -> (False), + FpuRoundMode.RTZ -> (False), + FpuRoundMode.RDN -> (math.sign), + FpuRoundMode.RUP -> (!math.sign), + FpuRoundMode.RMM -> (False) + ) + when(doMin){ + patched.exponent := exponentOne - 127-23+1 + patched.mantissa := 0 + } otherwise { + patched.setZero + } + } val output = input.swapPayload(RoundOutput()) output.source := input.source diff --git a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala index 7d5d3dc9..b76f970c 100644 --- a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala +++ b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala @@ -638,7 +638,8 @@ class FpuTest extends FunSuite{ for(_ <- 0 until 1000000){ val rounding = FpuRoundMode.elements.randomPick() val (a,b,c,f) = f32.mul(rounding).f32_2 - if(!(c.abs < 1e-35f && c.abs > 0f)) testMulExact(a,b,c,f, rounding) +// if(!(c.abs < 1e-35f && c.abs > 0f)) testMulExact(a,b,c,f, rounding) + /*if(! (a.toDouble*b.toDouble.abs <= 2E-45)) */testMulExact(a,b,c,f, rounding) } From 98eaeaabc8949bb7c8c7f14acfddb6dad273bce3 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sat, 30 Jan 2021 22:34:54 -0100 Subject: [PATCH 560/951] fix regression.mk typo --- scripts/regression/regression.mk | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/regression/regression.mk b/scripts/regression/regression.mk index 20234cf6..8e3fba8f 100644 --- a/scripts/regression/regression.mk +++ b/scripts/regression/regression.mk @@ -13,7 +13,7 @@ regression_random_linux: cd ../.. export VEXRISCV_REGRESSION_CONFIG_COUNT=3 export VEXRISCV_REGRESSION_CONFIG_LINUX_RATE=1.0 - export VEXRISCV_REGRESSION_CONFIG_SECURE_RATE = 0.0 + export VEXRISCV_REGRESSION_CONFIG_SECURE_RATE=0.0 export VEXRISCV_REGRESSION_FREERTOS_COUNT=1 export VEXRISCV_REGRESSION_ZEPHYR_COUNT=2 export VEXRISCV_REGRESSION_THREAD_COUNT=1 @@ -25,7 +25,7 @@ regression_random_machine_os: export VEXRISCV_REGRESSION_CONFIG_COUNT=15 export VEXRISCV_REGRESSION_CONFIG_LINUX_RATE=0.0 export VEXRISCV_REGRESSION_CONFIG_MACHINE_OS_RATE=1.0 - export VEXRISCV_REGRESSION_CONFIG_SECURE_RATE = 0.0 + export VEXRISCV_REGRESSION_CONFIG_SECURE_RATE=0.0 export VEXRISCV_REGRESSION_FREERTOS_COUNT=1 export VEXRISCV_REGRESSION_ZEPHYR_COUNT=2 export VEXRISCV_REGRESSION_THREAD_COUNT=1 @@ -36,7 +36,7 @@ regression_random_baremetal: export VEXRISCV_REGRESSION_CONFIG_COUNT=40 export VEXRISCV_REGRESSION_CONFIG_LINUX_RATE=0.0 export VEXRISCV_REGRESSION_CONFIG_MACHINE_OS_RATE=0.0 - export VEXRISCV_REGRESSION_CONFIG_SECURE_RATE = 0.0 + export VEXRISCV_REGRESSION_CONFIG_SECURE_RATE=0.0 export VEXRISCV_REGRESSION_FREERTOS_COUNT=1 export VEXRISCV_REGRESSION_ZEPHYR_COUNT=no export VEXRISCV_REGRESSION_THREAD_COUNT=1 From 6ee45a1014fb48c6d05f9a5c4ccfdcb1d28e76c4 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 1 Feb 2021 12:28:07 +0100 Subject: [PATCH 561/951] SpinalHDL version++ --- build.sbt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build.sbt b/build.sbt index 23d41fde..dc589753 100644 --- a/build.sbt +++ b/build.sbt @@ -1,3 +1,5 @@ +val spinalVersion = "1.4.3" + lazy val root = (project in file(".")). settings( inThisBuild(List( @@ -5,11 +7,9 @@ lazy val root = (project in file(".")). scalaVersion := "2.11.12", version := "2.0.0" )), - scalacOptions += s"-Xplugin:${new File(baseDirectory.value + "/../SpinalHDL/idslplugin/target/scala-2.11/spinalhdl-idsl-plugin_2.11-1.4.3.jar")}", + scalacOptions += s"-Xplugin:${new File(baseDirectory.value + s"/../SpinalHDL/idslplugin/target/scala-2.11/spinalhdl-idsl-plugin_2.11-$spinalVersion.jar")}", scalacOptions += s"-Xplugin-require:idsl-plugin", libraryDependencies ++= Seq( -// "com.github.spinalhdl" % "spinalhdl-core_2.11" % "1.3.6", -// "com.github.spinalhdl" % "spinalhdl-lib_2.11" % "1.3.6", "org.scalatest" % "scalatest_2.11" % "2.2.1", "org.yaml" % "snakeyaml" % "1.8" ), From d92adfbad008efed9cab71a70ba4041f37f4c4cc Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 1 Feb 2021 15:20:57 +0100 Subject: [PATCH 562/951] SpinalHDL version++ --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index dc589753..51bd3fec 100644 --- a/build.sbt +++ b/build.sbt @@ -1,4 +1,4 @@ -val spinalVersion = "1.4.3" +val spinalVersion = "1.4.4" lazy val root = (project in file(".")). settings( From a87cb202b1f446d38a9b8ca76e8e07e24fe40bc9 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 1 Feb 2021 16:12:38 +0100 Subject: [PATCH 563/951] fpu i2f rounding ok --- src/main/scala/vexriscv/ip/fpu/FpuCore.scala | 17 +-- src/test/scala/vexriscv/ip/fpu/FpuTest.scala | 125 +++++++++---------- 2 files changed, 63 insertions(+), 79 deletions(-) diff --git a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala index 51b65d8b..73654e5a 100644 --- a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala +++ b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala @@ -336,16 +336,6 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ output.roundMode := input.roundMode } - -// val i2fSign = input.arg(0) && input.value.msb -// val i2fUnsigned = input.value.asUInt.twoComplement(i2fSign).resize(32 bits) -// val i2fLog2 = OHToUInt(OHMasking.last(i2fUnsigned)) -// val i2fShifted = (i2fUnsigned << p.internalMantissaSize) >> i2fLog2 -// rfOutput.value.sign := i2fSign -// rfOutput.value.exponent := i2fLog2 +^ exponentOne -// rfOutput.value.mantissa := U(i2fShifted).resized -// rfOutput.value.special := False //TODO - val s1 = new Area{ val input = s0.output.stage() val busy = False @@ -414,7 +404,9 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val i2fSign = fsm.patched - val i2fShifted = input.value.takeHigh(23) + val (i2fHigh, i2fLow) = input.value.splitAt(widthOf(input.value)-24) + val i2fShifted = i2fHigh >> 1 + val i2fRound = U(i2fHigh.lsb ## (i2fLow =/= 0)) val recoded = p.internalFloating() recoded.mantissa := f32Mantissa @@ -437,6 +429,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ output.value.exponent := (U(exponentOne+31) - fsm.manTop).resized output.value.mantissa := U(i2fShifted) output.value.setNormal + output.round := i2fRound when(fsm.i2fZero) { output.value.setZero } //TODO ROUND } @@ -977,7 +970,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val round = new Area{ val input = merge.commited.combStage - //TODO do not break NAN payload + //TODO do not break NAN payload (seems already fine) val manAggregate = input.value.mantissa @@ input.round val expDif = (exponentOne-126) - input.value.exponent val discardCount = expDif.msb ? U(0) | expDif.resize(log2Up(p.internalMantissaSize) bits) diff --git a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala index b76f970c..6e30e710 100644 --- a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala +++ b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala @@ -39,17 +39,23 @@ class FpuTest extends FunSuite{ // config.withFstWave config.compile(new FpuCore(portCount, p)).doSim(seed = 42){ dut => dut.clockDomain.forkStimulus(10) - dut.clockDomain.forkSimSpeedPrinter() + dut.clockDomain.forkSimSpeedPrinter(5.0) - class TestCase(t : String, op : String){ - def build(arg : String) = new ProcessStream(s"testfloat_gen $arg -forever -${t}_$op"){ + class TestCase(op : String){ + def build(arg : String) = new ProcessStream(s"testfloat_gen $arg -forever -$op"){ def f32_2 ={ val l = next val s = new Scanner(l) (b2f(s.nextLong(16).toInt), b2f(s.nextLong(16).toInt), b2f(s.nextLong(16).toInt), s.nextInt(16)) } + + def i32_f32 ={ + val l = next + val s = new Scanner(l) + (s.nextLong(16).toInt, b2f(s.nextLong(16).toInt), s.nextInt(16)) + } } val RNE = build("-rnear_even") val RTZ = build("-rminMag") @@ -68,8 +74,11 @@ class FpuTest extends FunSuite{ } val f32 = new { - val add = new TestCase("f32", "add") - val mul = new TestCase("f32", "mul") + val add = new TestCase("f32_add") + val mul = new TestCase("f32_mul") + val ui2f = new TestCase("ui32_to_f32") + val i2f = new TestCase("i32_to_f32") + val f2ui = new TestCase("f32_to_ui32") } val cpus = for(id <- 0 until portCount) yield new { @@ -240,7 +249,7 @@ class FpuTest extends FunSuite{ rspQueue += body } - def i2f(rd : Int, value : Int, signed : Boolean): Unit ={ + def i2f(rd : Int, value : Int, signed : Boolean, rounding : FpuRoundMode.E = FpuRoundMode.RNE): Unit ={ cmdQueue += {cmd => cmd.opcode #= cmd.opcode.spinalEnum.I2F cmd.rs1.randomize() @@ -248,6 +257,7 @@ class FpuTest extends FunSuite{ cmd.rs3.randomize() cmd.rd #= rd cmd.arg #= (if(signed) 1 else 0) + cmd.roundMode #= rounding } commitQueue += {cmd => cmd.write #= true @@ -520,6 +530,19 @@ class FpuTest extends FunSuite{ } } + def testI2fExact(a : Int, b : Float, f : Int, signed : Boolean, rounding : FpuRoundMode.E): Unit ={ + val rs = new RegAllocator() + val rd = Random.nextInt(32) + i2f(rd, a, signed, rounding) + storeFloat(rd){v => + val aLong = if(signed) a.toLong else a.toLong & 0xFFFFFFFFl + val ref = b +// println(f"i2f($aLong) = $v, $ref") + assert(f2b(v) == f2b(ref)) + } + } + + def testCmp(a : Float, b : Float): Unit ={ val rs = new RegAllocator() val rs1, rs2, rs3 = rs.allocate() @@ -624,78 +647,46 @@ class FpuTest extends FunSuite{ } - for(i <- 0 until 64){ - val rounding = FpuRoundMode.RMM - val a = 24f - val b = b2f(0x3f800000+i) - val c = Clib.math.mulF32(a, b, rounding.position) - val f = 0 +// for(i <- 0 until 64){ +// val rounding = FpuRoundMode.RMM +// val a = 24f +// val b = b2f(0x3f800000+i) +// val c = Clib.math.mulF32(a, b, rounding.position) +// val f = 0 +// testMulExact(a,b,c,f, rounding) +// } + + for(_ <- 0 until 100000){ + val rounding = FpuRoundMode.elements.randomPick() + val (a,b,f) = f32.i2f(rounding).i32_f32 + testI2fExact(a,b,f, true, rounding) + } + for(_ <- 0 until 100000){ + val rounding = FpuRoundMode.elements.randomPick() + val (a,b,f) = f32.ui2f(rounding).i32_f32 + testI2fExact(a,b,f, false, rounding) + } + println("i2f done") + + + for(_ <- 0 until 100000){ + val rounding = FpuRoundMode.elements.randomPick() + val (a,b,c,f) = f32.mul(rounding).f32_2 testMulExact(a,b,c,f, rounding) } -// simSuccess() - - for(_ <- 0 until 1000000){ - val rounding = FpuRoundMode.elements.randomPick() - val (a,b,c,f) = f32.mul(rounding).f32_2 -// if(!(c.abs < 1e-35f && c.abs > 0f)) testMulExact(a,b,c,f, rounding) - /*if(! (a.toDouble*b.toDouble.abs <= 2E-45)) */testMulExact(a,b,c,f, rounding) - } - - -// roundingModes.foreach(rounding => println(Clib.math.addF32(0.0f, 0.0f, rounding.position))) -// roundingModes.foreach(rounding => println(Clib.math.addF32(1.0f,-1.0f, rounding.position))) - println("Mul done") - for(i <- 0 until 20) println(Clib.math.addF32(b2f(0x7f000000), b2f(0x7f000000-10+i), 0)) -// simSuccess() - - foreachRounding(r => println(Clib.math.addF32(b2f(0x7f7fffff), b2f(0x7f7fffff),r.position))) - println("") - foreachRounding(r => println(Clib.math.addF32(2.5787021E38f, 3.4027196E38f,r.position))) - println("") -// println(Clib.math.addF32(8.0f, b2f(0xBf800000), 0)) -// println(Clib.math.addF32(8.0f, b2f(0xBf800001), 0)) -// println(Clib.math.addF32(8.0f, b2f(0xBf800002), 0)) -// println(Clib.math.addF32(8.0f, b2f(0xBf800003), 0)) -// println(Clib.math.addF32(8.0f, b2f(0xBf800004), 0)) -// println(Clib.math.addF32(8.0f, b2f(0xBf800005), 0)) -// println(Clib.math.addF32(8.0f, b2f(0xBf800006), 0)) -// println(Clib.math.addF32(8.0f, b2f(0xBf800007), 0)) -// println(Clib.math.addF32(8.0f, b2f(0xBf800008), 0)) - - testAdd(-5.3687091E8f, 16.249022f, FpuRoundMode.RNE) - testAdd(-5.3687091E8f, 16.0f, FpuRoundMode.RNE) - testAdd(-5.3687091E8f, 15.0f, FpuRoundMode.RNE) - for(i <- 0 until 20) testAdd(4.0f, b2f(0xBf800000 + i), FpuRoundMode.RNE) - for(i <- 0 until 64) testAdd(12.0f, b2f(0xBf801000 + i), FpuRoundMode.RNE) - for(i <- 0 until 64) testAdd(8.0f, b2f(0xBf801000 + i), FpuRoundMode.RNE) - for(i <- 0 until 64) testAdd(12.0f, b2f(0x3f801000 + i), FpuRoundMode.RNE) - for(i <- 0 until 64) testAdd(8.0f, b2f(0x3f801000 + i), FpuRoundMode.RNE) - for(i <- 0 until 20) testAdd(b2f(0x40800000+3), b2f(0xBf800000 + i+1), FpuRoundMode.RNE) - for(i <- 0 until 20) testAdd(8.0f, b2f(0xBf800000 + i), FpuRoundMode.RNE) - for(i <- 0 until 20) testAdd(16.0f, b2f(0xBf800000 + i), FpuRoundMode.RNE) -// testAdd(8.0f, b2f(0xBf800001), FpuRoundMode.RNE) -// testAdd(8.0f, b2f(0xBf800002), FpuRoundMode.RNE) -// testAdd(8.0f, b2f(0xBf800003), FpuRoundMode.RNE) -// testAdd(8.0f, b2f(0xBf800004), FpuRoundMode.RNE) -// testAddExact(-256.2578f,1.8905041f ,-254.36731f,0, FpuRoundMode.RNE) - - for(_ <- 0 until 1000000){ + for(_ <- 0 until 100000){ val rounding = FpuRoundMode.elements.randomPick() val (a,b,c,f) = f32.add(rounding).f32_2 -// if(a.isNaN) println("Nan") -// if(b.isNaN) println("Nan") -// if(a.isInfinity) println("Inf") -// if(b.isInfinity) println("Inf") -// if(a == 0f) println("Zero") -// if(b == 0f) println("Zero") - /*if(/*a > 0 && b < 0 && */!c.isInfinity) */testAddExact(a,b,c,f, rounding) + testAddExact(a,b,c,f, rounding) } + println("Add done") + waitUntil(cmdQueue.isEmpty) dut.clockDomain.waitSampling(1000) simSuccess() From ef011fa0d408c57216c4a2a1ebf10eda5e5d8265 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 2 Feb 2021 11:29:35 +0100 Subject: [PATCH 564/951] fpu moved 1 bit from round to mantissa --- src/main/scala/vexriscv/ip/fpu/FpuCore.scala | 47 ++++++++++--------- .../scala/vexriscv/ip/fpu/Interface.scala | 1 + 2 files changed, 26 insertions(+), 22 deletions(-) diff --git a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala index 73654e5a..2b8f9f20 100644 --- a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala +++ b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala @@ -102,8 +102,8 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val source = Source() val lockId = lockIdType() val rd = p.rfAddress() - val value = p.internalFloating() - val round = UInt(2 bits) + val value = p.writeFloating() + val scrap = Bool() val roundMode = FpuRoundMode() } @@ -405,8 +405,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val i2fSign = fsm.patched val (i2fHigh, i2fLow) = input.value.splitAt(widthOf(input.value)-24) - val i2fShifted = i2fHigh >> 1 - val i2fRound = U(i2fHigh.lsb ## (i2fLow =/= 0)) + val scrap = i2fLow =/= 0 val recoded = p.internalFloating() recoded.mantissa := f32Mantissa @@ -422,14 +421,17 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ output.lockId := input.lockId output.roundMode := input.roundMode output.rd := input.rd - output.value := recoded - output.round := 0 + output.value.sign := recoded.sign + output.value.exponent := recoded.exponent + output.value.mantissa := recoded.mantissa @@ U"0" + output.value.special := recoded.special + output.scrap := False when(input.i2f){ output.value.sign := i2fSign output.value.exponent := (U(exponentOne+31) - fsm.manTop).resized - output.value.mantissa := U(i2fShifted) + output.value.mantissa := U(i2fHigh) output.value.setNormal - output.round := i2fRound + output.scrap := scrap when(fsm.i2fZero) { output.value.setZero } //TODO ROUND } @@ -579,17 +581,19 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ rfOutput.lockId := input.lockId rfOutput.rd := input.rd rfOutput.roundMode := input.roundMode - rfOutput.round := 0 //TODO + rfOutput.scrap := False //TODO rfOutput.value.assignDontCare() switch(input.opcode){ is(FpuOpcode.MIN_MAX){ - rfOutput.value := minMaxResult + rfOutput.value.exponent := minMaxResult.exponent + rfOutput.value.mantissa := minMaxResult.mantissa @@ U"0" + rfOutput.value.special := minMaxResult.special } is(FpuOpcode.SGNJ){ rfOutput.value.sign := sgnjResult rfOutput.value.exponent := input.rs1.exponent - rfOutput.value.mantissa := input.rs1.mantissa - rfOutput.value.special := False //TODO + rfOutput.value.mantissa := input.rs1.mantissa @@ U"0" + rfOutput.value.special := False //TODO } } @@ -628,14 +632,12 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val forceOverflow = /*exp > exponentOne + exponentOne + 127 || */input.rs1.isInfinity || input.rs2.isInfinity val forceNan = input.rs1.isNan || input.rs2.isNan || ((input.rs1.isInfinity || input.rs2.isInfinity) && (input.rs1.isZero || input.rs2.isZero)) - val output = FpuFloat(p.internalExponentSize, p.internalMantissaSize) + val output = p.writeFloating() output.sign := input.rs1.sign ^ input.rs2.sign output.exponent := (exp - exponentOne).resized - output.mantissa := man.asUInt >> 1 + output.mantissa := man.asUInt output.setNormal - val round = man(0) ## (scrap) - when(forceNan) { output.setNanQuiet } elsewhen(forceOverflow) { @@ -660,12 +662,12 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ output.lockId := input.lockId output.rd := input.rd output.roundMode := input.roundMode - output.round := norm.round.asUInt + output.scrap := norm.scrap output.value := norm.output decode.mulToAdd.valid := input.valid && input.add decode.mulToAdd.source := input.source - decode.mulToAdd.rs1.mantissa := norm.output.mantissa + decode.mulToAdd.rs1.mantissa := norm.output.mantissa >> 1 //FMA Precision lost decode.mulToAdd.rs1.exponent := norm.output.exponent decode.mulToAdd.rs1.sign := norm.output.sign decode.mulToAdd.rs1.special := False //TODO @@ -924,11 +926,11 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ output.lockId := input.lockId output.rd := input.rd output.value.sign := norm.xySign - output.value.mantissa := (norm.mantissa >> 3).resized + output.value.mantissa := (norm.mantissa >> 2).resized output.value.exponent := norm.exponent.resized output.value.special := False output.roundMode := input.roundMode - output.round := U(norm.mantissa(2)) @@ U(norm.mantissa(1) | norm.mantissa(0) | shifter.roundingScrap) + output.scrap := (norm.mantissa(1) | norm.mantissa(0) | shifter.roundingScrap) when(norm.forceNan) { output.value.setNanQuiet @@ -971,7 +973,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val input = merge.commited.combStage //TODO do not break NAN payload (seems already fine) - val manAggregate = input.value.mantissa @@ input.round + val manAggregate = input.value.mantissa @@ input.scrap val expDif = (exponentOne-126) - input.value.exponent val discardCount = expDif.msb ? U(0) | expDif.resize(log2Up(p.internalMantissaSize) bits) val exactMask = (List(True) ++ (0 until p.internalMantissaSize+1).map(_ < discardCount)).asBits.asUInt @@ -986,7 +988,8 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ ) val math = p.internalFloating() - val adderMantissa = input.value.mantissa & (mantissaIncrement ? ~(exactMask.trim(1) >> 1) | input.value.mantissa.maxValue) + val mantissaRange = p.internalMantissaSize downto 1 + val adderMantissa = input.value.mantissa(mantissaRange) & (mantissaIncrement ? ~(exactMask.trim(1) >> 1) | input.value.mantissa(mantissaRange).maxValue) val adderRightOp = (mantissaIncrement ? (exactMask >> 1)| U(0)).resize(p.internalMantissaSize bits) val adder = (input.value.exponent @@ adderMantissa) + adderRightOp + U(mantissaIncrement) math.special := input.value.special diff --git a/src/main/scala/vexriscv/ip/fpu/Interface.scala b/src/main/scala/vexriscv/ip/fpu/Interface.scala index 037cd3f0..3c25ad93 100644 --- a/src/main/scala/vexriscv/ip/fpu/Interface.scala +++ b/src/main/scala/vexriscv/ip/fpu/Interface.scala @@ -111,6 +111,7 @@ case class FpuParameter( internalMantissaSize : Int, val storeLoadType = HardType(Bits(if(withDouble) 64 bits else 32 bits)) val internalExponentSize = (if(withDouble) 11 else 8) + 1 val internalFloating = HardType(FpuFloat(exponentSize = internalExponentSize, mantissaSize = internalMantissaSize)) + val writeFloating = HardType(FpuFloat(exponentSize = internalExponentSize, mantissaSize = internalMantissaSize+1)) val rfAddress = HardType(UInt(5 bits)) From 1d0eecdcb0480534fe10217ce0554d3a74c3ca58 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 3 Feb 2021 14:27:52 +0100 Subject: [PATCH 565/951] fpu f2i rounding ok and full shifter --- src/main/scala/vexriscv/ip/fpu/FpuCore.scala | 91 +++++--- .../scala/vexriscv/ip/fpu/Interface.scala | 3 +- src/test/scala/vexriscv/ip/fpu/FpuTest.scala | 212 ++++++++++-------- 3 files changed, 179 insertions(+), 127 deletions(-) diff --git a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala index 2b8f9f20..46143706 100644 --- a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala +++ b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala @@ -57,13 +57,11 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ case class ShortPipInput() extends Bundle{ val source = Source() val opcode = p.Opcode() - val rs2 = p.internalFloating() - val rs1Raw = Bits(widthOf(rs2) bits) + val rs1, rs2 = p.internalFloating() val lockId = lockIdType() val rd = p.rfAddress() val value = Bits(32 bits) val arg = Bits(2 bits) - def rs1 = rs1Raw.as(p.internalFloating) val roundMode = FpuRoundMode() } @@ -261,7 +259,6 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ input.ready setWhen(shortPipHit && shortPip.ready) shortPip.valid := input.valid && shortPipHit shortPip.payload.assignSomeByName(read.output.payload) - shortPip.rs1Raw := read.output.rs1.asBits val divSqrtHit = input.opcode === p.Opcode.DIV || input.opcode === p.Opcode.SQRT val divSqrt = Stream(DivSqrtInput()) @@ -461,49 +458,46 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val f2iShift = input.rs1.exponent - U(exponentOne) val isF2i = input.opcode === FpuOpcode.F2I val needRecoding = List(FpuOpcode.FMV_X_W, FpuOpcode.STORE).map(_ === input.opcode).orR && isSubnormal - val manTop = Reg(UInt(log2Up(p.internalMantissaSize) bits)) - val counter = Reg(UInt(log2Up(p.internalMantissaSize+1) bits)) val done, boot = Reg(Bool()) val isZero = input.rs1.isZero// || input.rs1.exponent < exponentOne-1 - val overflow = input.rs1.exponent > (input.arg(0) ? U(exponentOne+30) | U(exponentOne+31)) && !input.rs1.sign - val underflow = input.rs1.exponent > (input.arg(0) ? U(exponentOne+30) | U(exponentOne-1)) && input.rs1.sign // && !(input.arg(0) && input.rs1.exponent === exponentOne-31 && input.rs) + + val shift = new Area{ + val by = Reg(UInt(log2Up(p.internalMantissaSize max 33) bits)) + val input = UInt(p.internalMantissaSize max 33 bits).assignDontCare() + var logic = input + val scrap = Reg(Bool) + for(i <- by.range){ + scrap setWhen(by(i) && logic(0, 1 << i bits) =/= 0) + logic \= by(i) ? (logic |>> (BigInt(1) << i)) | logic + } + when(boot){ + scrap := False + } + val output = RegNextWhen(logic, !done) + } + + shift.input := (U(!isZero) @@ input.rs1.mantissa) << 9 + when(input.valid && (needRecoding || isF2i) && !done){ halt := True when(boot){ when(isF2i){ - when(underflow || overflow){ - done := True - val low = overflow - val high = input.arg(0) ^ overflow - input.rs1Raw.getDrivingReg(0, 32 bits) := (31 -> high, default -> low) - } otherwise { - manTop := (U(exponentOne + 31) - input.rs1.exponent).resized //TODO merge - input.rs1Raw.getDrivingReg(0, 32 bits) := input.rs1Raw(0, 23 bits) << 9 - } + shift.by := (U(exponentOne + 31) - input.rs1.exponent).min(U(33)).resized //TODO merge } otherwise { - manTop := (U(exponentOne - 127) - recoded.exponent).resized + shift.by := (U(exponentOne - 127+10) - recoded.exponent).resized } boot := False - } otherwise { - when(isF2i){ - input.rs1Raw.getDrivingReg(0, 32 bits) := (B(counter === 0 && !isZero) ## input.rs1Raw(0, 32 bits)) >> 1 - } otherwise { - input.rs1Raw.getDrivingReg(0, 23 bits) := (B(counter === 0) ## input.rs1Raw(0, 23 bits)) >> 1 - } - counter := counter + 1 - when(counter === manTop) { - done := True - } + done := True } } when(isSubnormal){ f32.exp := 0 + f32.man := shift.output(22 downto 0) } when(!input.isStall){ - counter := 0 done := False boot := True } @@ -526,12 +520,30 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } -// val f2iShift = input.rs1.exponent - U(exponentOne) -// val f2iShifted = (U"1" @@ input.rs1.mantissa) << (f2iShift.resize(5 bits)) -// val f2iUnsigned = f2iShifted >> p.internalMantissaSize -// val f2iResult = (f2iUnsigned.twoComplement(input.arg(0) && input.rs1.sign)).asBits.resize(32 bits) - val f2iUnsigned = input.rs1Raw(0, 32 bits).asUInt - val f2iResult = (f2iUnsigned.twoComplement(input.arg(0) && input.rs1.sign)).asBits.resize(32 bits) + + val f2i = new Area{ //Will not work for 64 bits float max value rounding + val unsigned = fsm.shift.output >> 1 + val resign = input.arg(0) && input.rs1.sign + val round = fsm.shift.output(0) ## fsm.shift.scrap + val increment = input.roundMode.mux( + FpuRoundMode.RNE -> (round(1) && (round(0) || unsigned(0))), + FpuRoundMode.RTZ -> False, + FpuRoundMode.RDN -> (round =/= 0 && input.rs1.sign), + FpuRoundMode.RUP -> (round =/= 0 && !input.rs1.sign), + FpuRoundMode.RMM -> (round(1)) + ) + val result = (Mux(resign, ~unsigned, unsigned) + (resign ^ increment).asUInt) + val overflow = RegNext((input.rs1.exponent > (input.arg(0) ? U(exponentOne+30) | U(exponentOne+31)) || input.rs1.isInfinity) && !input.rs1.sign || input.rs1.isNan) + val underflow = RegNext((input.rs1.exponent > U(exponentOne+30) || !input.arg(0) || input.rs1.isInfinity) && input.rs1.sign) + val isZero = input.rs1.isZero + when(isZero){ + result := 0 + } elsewhen(underflow || overflow) { + val low = overflow + val high = input.arg(0) ^ overflow + result := (31 -> high, default -> low) + } + } val bothZero = input.rs1.isZero && input.rs2.isZero val rs1Equal = input.rs1 === input.rs2 @@ -569,7 +581,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ switch(input.opcode){ is(FpuOpcode.STORE) { result := recodedResult } is(FpuOpcode.FMV_X_W) { result := recodedResult } //TODO - is(FpuOpcode.F2I) { result := f2iResult } + is(FpuOpcode.F2I) { result := f2i.result.asBits } is(FpuOpcode.CMP) { result := cmpResult.resized } //TODO is(FpuOpcode.FCLASS) { result := fclassResult.resized } } @@ -1057,6 +1069,13 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ port.address := input.source @@ input.rd port.data := input.value + if(p.sim) when(port.data.isZero || port.data.isInfinity){ + port.data.mantissa.assignDontCare() + } + if(p.sim) when(port.data.special){ + port.data.exponent(p.internalExponentSize-1 downto 2).assignDontCare() + } + when(port.valid){ assert(!(port.data.exponent === 0 && !port.data.special), "Special violation") assert(!(port.data.exponent === port.data.exponent.maxValue && !port.data.special), "Special violation") diff --git a/src/main/scala/vexriscv/ip/fpu/Interface.scala b/src/main/scala/vexriscv/ip/fpu/Interface.scala index 3c25ad93..dff47798 100644 --- a/src/main/scala/vexriscv/ip/fpu/Interface.scala +++ b/src/main/scala/vexriscv/ip/fpu/Interface.scala @@ -106,7 +106,8 @@ object FpuRoundModeInstr extends SpinalEnum(){ case class FpuParameter( internalMantissaSize : Int, - withDouble : Boolean){ + withDouble : Boolean, + sim : Boolean = false){ val storeLoadType = HardType(Bits(if(withDouble) 64 bits else 32 bits)) val internalExponentSize = (if(withDouble) 11 else 8) + 1 diff --git a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala index 6e30e710..e3a6125f 100644 --- a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala +++ b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala @@ -32,7 +32,8 @@ class FpuTest extends FunSuite{ val portCount = 1 val p = FpuParameter( internalMantissaSize = 23, - withDouble = false + withDouble = false, + sim = true ) val config = SimConfig @@ -46,16 +47,19 @@ class FpuTest extends FunSuite{ class TestCase(op : String){ def build(arg : String) = new ProcessStream(s"testfloat_gen $arg -forever -$op"){ def f32_2 ={ - val l = next - val s = new Scanner(l) + val s = new Scanner(next) (b2f(s.nextLong(16).toInt), b2f(s.nextLong(16).toInt), b2f(s.nextLong(16).toInt), s.nextInt(16)) } def i32_f32 ={ - val l = next - val s = new Scanner(l) + val s = new Scanner(next) (s.nextLong(16).toInt, b2f(s.nextLong(16).toInt), s.nextInt(16)) } + + def f32_i32 = { + val s = new Scanner(next) + (b2f(s.nextLong(16).toInt), s.nextLong(16).toInt, s.nextInt(16)) + } } val RNE = build("-rnear_even") val RTZ = build("-rminMag") @@ -75,10 +79,12 @@ class FpuTest extends FunSuite{ val f32 = new { val add = new TestCase("f32_add") + val sub = new TestCase("f32_sub") val mul = new TestCase("f32_mul") val ui2f = new TestCase("ui32_to_f32") val i2f = new TestCase("i32_to_f32") val f2ui = new TestCase("f32_to_ui32") + val f2i = new TestCase("f32_to_i32") } val cpus = for(id <- 0 until portCount) yield new { @@ -147,14 +153,14 @@ class FpuTest extends FunSuite{ storeRaw(rs){rsp => body(b2f(rsp.value.toLong.toInt))} } - def mul(rd : Int, rs1 : Int, rs2 : Int, rounding : FpuRoundMode.E = FpuRoundMode.RNE): Unit ={ + def fpuF2f(rd : Int, rs1 : Int, rs2 : Int, rs3 : Int, opcode : FpuOpcode.E, arg : Int, rounding : FpuRoundMode.E = FpuRoundMode.RNE): Unit ={ cmdQueue += {cmd => - cmd.opcode #= cmd.opcode.spinalEnum.MUL + cmd.opcode #= opcode cmd.rs1 #= rs1 cmd.rs2 #= rs2 cmd.rs3.randomize() cmd.rd #= rd - cmd.arg #= 0 + cmd.arg #= arg cmd.roundMode #= rounding } commitQueue += {cmd => @@ -163,90 +169,51 @@ class FpuTest extends FunSuite{ } } + def fpuF2i(rs1 : Int, rs2 : Int, opcode : FpuOpcode.E, arg : Int, rounding : FpuRoundMode.E = FpuRoundMode.RNE)(body : FpuRsp => Unit): Unit ={ + cmdQueue += {cmd => + cmd.opcode #= opcode + cmd.rs1 #= rs1 + cmd.rs2 #= rs2 + cmd.rs3.randomize() + cmd.rd.randomize() + cmd.arg #= arg + cmd.roundMode #= rounding + } + rspQueue += body + } + + + def mul(rd : Int, rs1 : Int, rs2 : Int, rounding : FpuRoundMode.E = FpuRoundMode.RNE): Unit ={ + fpuF2f(rd, rs1, rs2, Random.nextInt(32), FpuOpcode.MUL, 0, rounding) + } + def add(rd : Int, rs1 : Int, rs2 : Int, rounding : FpuRoundMode.E = FpuRoundMode.RNE): Unit ={ - cmdQueue += {cmd => - cmd.opcode #= cmd.opcode.spinalEnum.ADD - cmd.rs1 #= rs1 - cmd.rs2 #= rs2 - cmd.rs3.randomize() - cmd.rd #= rd - cmd.arg #= 0 - cmd.roundMode #= rounding - } - commitQueue += {cmd => - cmd.write #= true - cmd.sync #= false - } + fpuF2f(rd, rs1, rs2, Random.nextInt(32), FpuOpcode.ADD, 0, rounding) } - def div(rd : Int, rs1 : Int, rs2 : Int): Unit ={ - cmdQueue += {cmd => - cmd.opcode #= cmd.opcode.spinalEnum.DIV - cmd.rs1 #= rs1 - cmd.rs2 #= rs2 - cmd.rs3.randomize() - cmd.rd #= rd - cmd.arg.randomize() - } - commitQueue += {cmd => - cmd.write #= true - cmd.sync #= false - } + def sub(rd : Int, rs1 : Int, rs2 : Int, rounding : FpuRoundMode.E = FpuRoundMode.RNE): Unit ={ + fpuF2f(rd, rs1, rs2, Random.nextInt(32), FpuOpcode.ADD, 1, rounding) } - def sqrt(rd : Int, rs1 : Int): Unit ={ - cmdQueue += {cmd => - cmd.opcode #= cmd.opcode.spinalEnum.SQRT - cmd.rs1 #= rs1 - cmd.rs2.randomize() - cmd.rs3.randomize() - cmd.rd #= rd - cmd.arg.randomize() - } - commitQueue += {cmd => - cmd.write #= true - cmd.sync #= false - } + def div(rd : Int, rs1 : Int, rs2 : Int, rounding : FpuRoundMode.E = FpuRoundMode.RNE): Unit ={ + fpuF2f(rd, rs1, rs2, Random.nextInt(32), FpuOpcode.DIV, Random.nextInt(4), rounding) } - def fma(rd : Int, rs1 : Int, rs2 : Int, rs3 : Int): Unit ={ - cmdQueue += {cmd => - cmd.opcode #= cmd.opcode.spinalEnum.FMA - cmd.rs1 #= rs1 - cmd.rs2 #= rs2 - cmd.rs3 #= rs3 - cmd.rd #= rd - cmd.arg #= 0 - } - commitQueue += {cmd => - cmd.write #= true - cmd.sync #= false - } + def sqrt(rd : Int, rs1 : Int, rounding : FpuRoundMode.E = FpuRoundMode.RNE): Unit ={ + fpuF2f(rd, rs1, Random.nextInt(32), Random.nextInt(32), FpuOpcode.SQRT, Random.nextInt(4), rounding) + } + + def fma(rd : Int, rs1 : Int, rs2 : Int, rs3 : Int, rounding : FpuRoundMode.E = FpuRoundMode.RNE): Unit ={ + fpuF2f(rd, rs1, rs2, rs3, FpuOpcode.FMA, 0, rounding) } def cmp(rs1 : Int, rs2 : Int)(body : FpuRsp => Unit): Unit ={ - cmdQueue += {cmd => - cmd.opcode #= cmd.opcode.spinalEnum.CMP - cmd.rs1 #= rs1 - cmd.rs2 #= rs2 - cmd.rs3.randomize() - cmd.rd.randomize() - cmd.arg #= 1 - } - rspQueue += body + fpuF2i(rs1, rs2, FpuOpcode.CMP, 1, FpuRoundMode.elements.randomPick())(body) } - def f2i(rs1 : Int, signed : Boolean)(body : FpuRsp => Unit): Unit ={ - cmdQueue += {cmd => - cmd.opcode #= cmd.opcode.spinalEnum.F2I - cmd.rs1 #= rs1 - cmd.rs2.randomize() - cmd.rs3.randomize() - cmd.rd.randomize() - cmd.arg #= (if(signed) 1 else 0) - } - rspQueue += body + def f2i(rs1 : Int, signed : Boolean, rounding : FpuRoundMode.E = FpuRoundMode.RNE)(body : FpuRsp => Unit): Unit ={ + fpuF2i(rs1, Random.nextInt(32), FpuOpcode.F2I, if(signed) 1 else 0, rounding)(body) } def i2f(rd : Int, value : Int, signed : Boolean, rounding : FpuRoundMode.E = FpuRoundMode.RNE): Unit ={ @@ -388,6 +355,18 @@ class FpuTest extends FunSuite{ } } + def testBinaryOp(op : (Int,Int,Int,FpuRoundMode.E) => Unit, a : Float, b : Float, ref : Float, flag : Int, rounding : FpuRoundMode.E, opName : String): Unit ={ + val rs = new RegAllocator() + val rs1, rs2, rs3 = rs.allocate() + val rd = Random.nextInt(32) + load(rs1, a) + load(rs2, b) + op(rd,rs1,rs2, rounding) + storeFloat(rd){v => + assert(f2b(v) == f2b(ref), f"## ${a} ${opName} $b = $v, $ref $rounding") + } + } + def testAddExact(a : Float, b : Float, ref : Float, flag : Int, rounding : FpuRoundMode.E): Unit ={ val rs = new RegAllocator() val rs1, rs2, rs3 = rs.allocate() @@ -517,6 +496,31 @@ class FpuTest extends FunSuite{ } } + def testF2iExact(a : Float, ref : Int, flag : Int, signed : Boolean, rounding : FpuRoundMode.E): Unit ={ + val rs = new RegAllocator() + val rs1 = rs.allocate() + val rd = Random.nextInt(32) + load(rs1, a) + f2i(rs1, signed, rounding){rsp => + if(signed) { + val v = rsp.value.toLong.toInt + var ref2 = ref + if(a >= Int.MaxValue) ref2 = Int.MaxValue + if(a <= Int.MinValue) ref2 = Int.MinValue + if(a.isNaN) ref2 = Int.MaxValue + assert(v == (ref2), f" <= f2i($a) = $v, $ref2, $rounding, $flag") + } else { + val v = rsp.value.toLong + var ref2 = ref.toLong & 0xFFFFFFFFl + if(a < 0) ref2 = 0 + if(a >= 0xFFFFFFFFl) ref2 = 0xFFFFFFFFl + if(a.isNaN) ref2 = 0xFFFFFFFFl + assert(v == ref2, f" <= f2ui($a) = $v, $ref2, $rounding $flag") + } + } + } + + def testI2f(a : Int, signed : Boolean): Unit ={ val rs = new RegAllocator() val rd = Random.nextInt(32) @@ -538,7 +542,7 @@ class FpuTest extends FunSuite{ val aLong = if(signed) a.toLong else a.toLong & 0xFFFFFFFFl val ref = b // println(f"i2f($aLong) = $v, $ref") - assert(f2b(v) == f2b(ref)) + assert(f2b(v) == f2b(ref), f"i2f($aLong) = $v, $ref") } } @@ -647,6 +651,7 @@ class FpuTest extends FunSuite{ } + // for(i <- 0 until 64){ // val rounding = FpuRoundMode.RMM // val a = 24f @@ -656,36 +661,63 @@ class FpuTest extends FunSuite{ // testMulExact(a,b,c,f, rounding) // } - for(_ <- 0 until 100000){ + val binaryOps = List[(Int,Int,Int,FpuRoundMode.E) => Unit](add, sub, mul) + + + + for(_ <- 0 until 10000){ val rounding = FpuRoundMode.elements.randomPick() val (a,b,f) = f32.i2f(rounding).i32_f32 testI2fExact(a,b,f, true, rounding) } - for(_ <- 0 until 100000){ + + for(_ <- 0 until 10000){ val rounding = FpuRoundMode.elements.randomPick() val (a,b,f) = f32.ui2f(rounding).i32_f32 testI2fExact(a,b,f, false, rounding) } println("i2f done") + for(_ <- 0 until 10000){ + val rounding = FpuRoundMode.elements.randomPick() + val (a,b,f) = f32.f2ui(rounding).f32_i32 + testF2iExact(a,b, f, false, rounding) + } - for(_ <- 0 until 100000){ + for(_ <- 0 until 10000){ + val rounding = FpuRoundMode.elements.randomPick() + val (a,b,f) = f32.f2i(rounding).f32_i32 + testF2iExact(a,b, f, true, rounding) + } + + println("f2i done") + + + for(_ <- 0 until 10000){ + val rounding = FpuRoundMode.elements.randomPick() + val (a,b,c,f) = f32.add(rounding).f32_2 + testBinaryOp(add,a,b,c,f, rounding,"add") + } + + for(_ <- 0 until 10000){ + val rounding = FpuRoundMode.elements.randomPick() + val (a,b,c,f) = f32.sub(rounding).f32_2 + testBinaryOp(sub,a,b,c,f, rounding,"sub") + } + + println("Add done") + + for(_ <- 0 until 10000){ val rounding = FpuRoundMode.elements.randomPick() val (a,b,c,f) = f32.mul(rounding).f32_2 - testMulExact(a,b,c,f, rounding) + testBinaryOp(mul,a,b,c,f, rounding,"mul") } println("Mul done") - for(_ <- 0 until 100000){ - val rounding = FpuRoundMode.elements.randomPick() - val (a,b,c,f) = f32.add(rounding).f32_2 - testAddExact(a,b,c,f, rounding) - } - println("Add done") waitUntil(cmdQueue.isEmpty) dut.clockDomain.waitSampling(1000) From 8eb8356deafbe3ba9982dede3fb6962a1573274a Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 15 Jan 2021 14:03:37 +0100 Subject: [PATCH 566/951] fpu wip --- src/main/scala/vexriscv/ip/fpu/FpuCore.scala | 105 +++++++++++------- .../scala/vexriscv/ip/fpu/Interface.scala | 29 +++-- src/test/scala/vexriscv/ip/fpu/FpuTest.scala | 47 ++++++-- 3 files changed, 116 insertions(+), 65 deletions(-) diff --git a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala index 8209c11a..c64ddb36 100644 --- a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala +++ b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala @@ -15,6 +15,8 @@ case class FpuCore(p : FpuParameter) extends Component{ val port = slave(FpuPort(p)) } + +// val commitPerSourceCount = 8 val rfLockCount = 5 val lockIdType = HardType(UInt(log2Up(rfLockCount) bits)) @@ -89,11 +91,44 @@ case class FpuCore(p : FpuParameter) extends Component{ val valid = RegInit(False) val source = Reg(p.source) val address = Reg(p.rfAddress) + val id = Reg(UInt(log2Up(rfLockCount) bits)) + val commited = Reg(Bool) + val write = Reg(Bool) } val lockFree = !lock.map(_.valid).andR val lockFreeId = OHMasking.first(lock.map(!_.valid)) } + val commitLogic = for(source <- 0 until p.sourceCount) yield new Area{ + val fire = False + val target, hit = Reg(UInt(log2Up(rfLockCount) bits)) init(0) + when(fire){ + hit := hit + 1 + } + + io.port.commit(source).ready := False + when(io.port.commit(source).valid) { + for (lock <- rf.lock) { + when(lock.valid && lock.source === source && lock.id === hit) { + fire := True + lock.commited := True + lock.write := io.port.commit(source).write + io.port.commit(source).ready := True + } + } + } + } + +// case class CommitLine() extends Bundle{ +// val valid = Bool() +// val write = Bool() +// } +// val commits = for(i <- 0 until p.sourceCount) yield new Area{ +// val lines = Vec(CommitLine(), commitPerSourceCount) +// lines.foreach(_.valid init(False)) +// +// } + val read = new Area{ val s0 = Stream(RfReadInput()) s0.arbitrationFrom(io.port.cmd) @@ -137,11 +172,17 @@ case class FpuCore(p : FpuParameter) extends Component{ val hits = List((useRs1, s0.rs1), (useRs2, s0.rs2), (useRs3, s0.rs3), (useRd, s0.rd)).map{case (use, reg) => use && rf.lock.map(l => l.valid && l.source === s0.source && l.address === reg).orR} val hazard = hits.orR when(s0.fire && useRd){ + for(i <- 0 until p.sourceCount){ + when(s0.source === i){ + commitLogic(i).target := commitLogic(i).target + 1 + } + } for(i <- 0 until rfLockCount){ when(rf.lockFreeId(i)){ rf.lock(i).valid := True rf.lock(i).source := s0.source rf.lock(i).address := s0.rd + rf.lock(i).id := commitLogic.map(_.target).read(s0.source) } } } @@ -224,9 +265,16 @@ case class FpuCore(p : FpuParameter) extends Component{ } val load = new Area{ - def input = decode.load - - val output = input.stage() + val input = decode.load.stage() + def feed = io.port.load(input.source) + val hazard = !feed.valid + val output = input.haltWhen(hazard).swapPayload(WriteInput()) + io.port.load.foreach(_.ready := False) + feed.ready := input.valid && output.ready + output.source := input.source + output.lockId := input.lockId + output.rd := input.rd + output.value.assignFromBits(feed.value) } @@ -506,47 +554,20 @@ case class FpuCore(p : FpuParameter) extends Component{ val write = new Area{ - val port = rf.ram.writePort - port.valid := False - port.payload.assignDontCare() + val arbitrated = StreamArbiterFactory.lowerFirst.noLock.on(List(load.output, add.output, mul.output)) + val isCommited = rf.lock.map(_.commited).read(arbitrated.lockId) + val commited = arbitrated.haltWhen(!isCommited).toFlow - - val lockFree = Flow(lockIdType) - lockFree.valid := port.fire - lockFree.payload.assignDontCare() - - load.output.ready := False - mul.output.ready := False - add.output.ready := True - io.port.commit.ready := False - when(add.output.valid) { - port.valid := True - port.address := add.output.source @@ add.output.rd - port.data := add.output.value - - lockFree.payload := add.output.lockId - } elsewhen(mul.output.valid) { - port.valid := True - port.address := mul.output.source @@ mul.output.rd - port.data := mul.output.value - - mul.output.ready := True - lockFree.payload := mul.output.lockId - } elsewhen(load.output.valid && io.port.commit.valid) { - port.valid := io.port.commit.write - port.address := load.output.source @@ load.output.rd - port.data.assignFromBits(io.port.commit.value) - - load.output.ready := True - io.port.commit.ready := True - lockFree.payload := load.output.lockId - } - - when(lockFree.fire){ - for(i <- 0 until rfLockCount) when(lockFree.payload === i){ + when(commited.valid){ + for(i <- 0 until rfLockCount) when(commited.lockId === i){ rf.lock(i).valid := False } } + + val port = rf.ram.writePort + port.valid := commited.valid && rf.lock.map(_.write).read(commited.lockId) + port.address := commited.source @@ commited.rd + port.data := commited.value } } @@ -572,7 +593,7 @@ object FpuSynthesisBench extends App{ FpuParameter( internalMantissaSize = 23, withDouble = false, - sourceWidth = 0 + sourceCount = 1 ) ) rtls += new Fpu( @@ -580,7 +601,7 @@ object FpuSynthesisBench extends App{ FpuParameter( internalMantissaSize = 52, withDouble = true, - sourceWidth = 0 + sourceCount = 1 ) ) diff --git a/src/main/scala/vexriscv/ip/fpu/Interface.scala b/src/main/scala/vexriscv/ip/fpu/Interface.scala index 2c5b3f11..00e526a9 100644 --- a/src/main/scala/vexriscv/ip/fpu/Interface.scala +++ b/src/main/scala/vexriscv/ip/fpu/Interface.scala @@ -22,13 +22,18 @@ case class FpuFloat(exponentSize: Int, val sign = Bool } -case class FpuOpcode(p : FpuParameter) extends SpinalEnum{ +object FpuOpcode extends SpinalEnum{ val LOAD, STORE, MUL, ADD, FMA, I2F, F2I, CMP, DIV, SQRT = newElement() } +object FpuFormat extends SpinalEnum{ + val FLOAT, DOUBLE = newElement() +} + + case class FpuParameter( internalMantissaSize : Int, withDouble : Boolean, - sourceWidth : Int){ + sourceCount : Int){ val storeLoadType = HardType(Bits(if(withDouble) 64 bits else 32 bits)) val internalExponentSize = if(withDouble) 11 else 8 @@ -37,11 +42,9 @@ case class FpuParameter( internalMantissaSize : Int, val source = HardType(UInt(sourceWidth bits)) val rfAddress = HardType(UInt(5 bits)) - val Opcode = new FpuOpcode(this) - val Format = new SpinalEnum{ - val FLOAT = newElement() - val DOUBLE = withDouble generate newElement() - } + val Opcode = FpuOpcode + val Format = FpuFormat + val sourceWidth = log2Up(sourceCount) } case class FpuCmd(p : FpuParameter) extends Bundle{ @@ -55,9 +58,11 @@ case class FpuCmd(p : FpuParameter) extends Bundle{ } case class FpuCommit(p : FpuParameter) extends Bundle{ - val source = UInt(p.sourceWidth bits) val write = Bool() - val value = p.storeLoadType() // IEEE 754 load +} + +case class FpuLoad(p : FpuParameter) extends Bundle{ + val value = p.storeLoadType() // IEEE 754 } case class FpuRsp(p : FpuParameter) extends Bundle{ @@ -67,11 +72,13 @@ case class FpuRsp(p : FpuParameter) extends Bundle{ case class FpuPort(p : FpuParameter) extends Bundle with IMasterSlave { val cmd = Stream(FpuCmd(p)) - val commit = Stream(FpuCommit(p)) + val commit = Vec(Stream(FpuCommit(p)), p.sourceCount) + val load = Vec(Stream(FpuLoad(p)), p.sourceCount) val rsp = Stream(FpuRsp(p)) override def asMaster(): Unit = { - master(cmd, commit) + master(cmd) + (commit ++ load).foreach(master(_)) slave(rsp) } } diff --git a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala index 0ca5ca7a..3190a0cd 100644 --- a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala +++ b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala @@ -19,7 +19,7 @@ class FpuTest extends FunSuite{ val p = FpuParameter( internalMantissaSize = 23, withDouble = false, - sourceWidth = 0 + sourceCount = 1 ) SimConfig.withFstWave.compile(new FpuCore(p)).doSim(seed = 42){ dut => @@ -31,8 +31,23 @@ class FpuTest extends FunSuite{ val cpus = for(id <- 0 until 1 << p.sourceWidth) yield new { val cmdQueue = mutable.Queue[FpuCmd => Unit]() val commitQueue = mutable.Queue[FpuCommit => Unit]() + val loadQueue = mutable.Queue[FpuLoad => Unit]() val rspQueue = mutable.Queue[FpuRsp => Unit]() + StreamDriver(dut.io.port.commit(id) ,dut.clockDomain){payload => + if(commitQueue.isEmpty) false else { + commitQueue.dequeue().apply(payload) + true + } + } + + StreamDriver(dut.io.port.load(id) ,dut.clockDomain){payload => + if(loadQueue.isEmpty) false else { + loadQueue.dequeue().apply(payload) + true + } + } + def loadRaw(rd : Int, value : BigInt): Unit ={ cmdQueue += {cmd => cmd.source #= id @@ -44,8 +59,9 @@ class FpuTest extends FunSuite{ cmd.rd #= rd } commitQueue += {cmd => - cmd.source #= id cmd.write #= true + } + loadQueue += {cmd => cmd.value #= value } } @@ -82,6 +98,9 @@ class FpuTest extends FunSuite{ cmd.rs3.randomize() cmd.rd #= rd } + commitQueue += {cmd => + cmd.write #= true + } } def add(rd : Int, rs1 : Int, rs2 : Int): Unit ={ @@ -94,6 +113,9 @@ class FpuTest extends FunSuite{ cmd.rs3.randomize() cmd.rd #= rd } + commitQueue += {cmd => + cmd.write #= true + } } def div(rd : Int, rs1 : Int, rs2 : Int): Unit ={ @@ -106,6 +128,9 @@ class FpuTest extends FunSuite{ cmd.rs3.randomize() cmd.rd #= rd } + commitQueue += {cmd => + cmd.write #= true + } } def sqrt(rd : Int, rs1 : Int): Unit ={ @@ -118,6 +143,9 @@ class FpuTest extends FunSuite{ cmd.rs3.randomize() cmd.rd #= rd } + commitQueue += {cmd => + cmd.write #= true + } } def fma(rd : Int, rs1 : Int, rs2 : Int, rs3 : Int): Unit ={ @@ -130,6 +158,9 @@ class FpuTest extends FunSuite{ cmd.rs3 #= rs3 cmd.rd #= rd } + commitQueue += {cmd => + cmd.write #= true + } } } @@ -143,15 +174,7 @@ class FpuTest extends FunSuite{ } } - StreamDriver(dut.io.port.commit ,dut.clockDomain){payload => - cpus.map(_.commitQueue).filter(_.nonEmpty).toSeq match { - case Nil => false - case l => { - l.randomPick().dequeue().apply(payload) - true - } - } - } + StreamMonitor(dut.io.port.rsp, dut.clockDomain){payload => @@ -272,6 +295,7 @@ class FpuTest extends FunSuite{ val b2f = lang.Float.intBitsToFloat(_) + testAdd(0.1f, 1.6f) testSqrt(1.5625f) testSqrt(1.5625f*2) @@ -289,7 +313,6 @@ class FpuTest extends FunSuite{ // dut.clockDomain.waitSampling(1000) // simFailure() - testAdd(0.1f, 1.6f) testMul(0.1f, 1.6f) testFma(1.1f, 2.2f, 3.0f) testDiv(1.0f, 1.1f) From 02b5b9b05c94babac800c3a40cab61e822978ee7 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 3 Feb 2021 16:48:09 +0100 Subject: [PATCH 567/951] fpu load subnormal and i2f now use single cycle shifter --- src/main/scala/vexriscv/ip/fpu/FpuCore.scala | 45 +++++++++++--------- src/test/scala/vexriscv/ip/fpu/FpuTest.scala | 44 ++++++++++--------- 2 files changed, 51 insertions(+), 38 deletions(-) diff --git a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala index 46143706..c16791cc 100644 --- a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala +++ b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala @@ -354,13 +354,22 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val isQuiet = f32Mantissa.msb val fsm = new Area{ - val manTop = Reg(UInt(log2Up(p.internalMantissaSize) bits)) - val shift = CombInit(manTop) - val counter = Reg(UInt(log2Up(p.internalMantissaSize+1) bits)) val done, boot, patched = Reg(Bool()) val ohInput = CombInit(input.value(0, 32 max p.internalMantissaSize bits)) when(!input.i2f) { ohInput(9, 23 bits) := input.value(0, 23 bits) } val i2fZero = Reg(Bool) + + val shift = new Area{ + val by = Reg(UInt(log2Up(p.internalMantissaSize max 32) bits)) + val input = UInt(p.internalMantissaSize max 32 bits).assignDontCare() + var logic = input + for(i <- by.range){ + logic \= by(i) ? (logic |<< (BigInt(1) << i)) | logic + } + val output = RegNextWhen(logic, !done) + } + shift.input := input.value.asUInt |<< 1 + when(input.valid && (input.i2f || isSubnormal) && !done){ busy := True when(boot){ @@ -368,31 +377,27 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ input.value.getDrivingReg(0, 32 bits) := B(input.value.asUInt.twoComplement(True).resize(32 bits)) patched := True } otherwise { - manTop := OHToUInt(OHMasking.first((ohInput).reversed)) + shift.by := OHToUInt(OHMasking.first((ohInput).reversed)) + (input.i2f ? U(0) | U(9)) boot := False i2fZero := input.value(31 downto 0) === 0 } } otherwise { - when(input.i2f){ - input.value.getDrivingReg(0, 32 bits) := input.value(0, 32 bits) |<< 1 - } otherwise { - input.value.getDrivingReg(0, 23 bits) := input.value(0, 23 bits) |<< 1 - } - counter := counter + 1 - when(counter === shift) { - done := True - } +// when(input.i2f){ +// input.value.getDrivingReg(0, 32 bits) := input.value(0, 32 bits) |<< 1 +// } otherwise { +// input.value.getDrivingReg(0, 23 bits) := input.value(0, 23 bits) |<< 1 +// } + done := True } } val expOffset = (UInt(p.internalExponentSize bits)) expOffset := 0 when(isSubnormal){ - expOffset := manTop.resized + expOffset := (shift.by-9).resized } when(!input.isStall){ - counter := 0 done := False boot := True patched := False @@ -401,7 +406,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val i2fSign = fsm.patched - val (i2fHigh, i2fLow) = input.value.splitAt(widthOf(input.value)-24) + val (i2fHigh, i2fLow) = fsm.shift.output.splitAt(widthOf(input.value)-24) val scrap = i2fLow =/= 0 val recoded = p.internalFloating() @@ -425,12 +430,14 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ output.scrap := False when(input.i2f){ output.value.sign := i2fSign - output.value.exponent := (U(exponentOne+31) - fsm.manTop).resized - output.value.mantissa := U(i2fHigh) + output.value.exponent := (U(exponentOne+31) - fsm.shift.by).resized output.value.setNormal output.scrap := scrap when(fsm.i2fZero) { output.value.setZero } - //TODO ROUND + } + + when(input.i2f || isSubnormal){ + output.value.mantissa := U(i2fHigh) } } } diff --git a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala index e3a6125f..c0b58b8d 100644 --- a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala +++ b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala @@ -541,7 +541,6 @@ class FpuTest extends FunSuite{ storeFloat(rd){v => val aLong = if(signed) a.toLong else a.toLong & 0xFFFFFFFFl val ref = b -// println(f"i2f($aLong) = $v, $ref") assert(f2b(v) == f2b(ref), f"i2f($aLong) = $v, $ref") } } @@ -663,28 +662,48 @@ class FpuTest extends FunSuite{ val binaryOps = List[(Int,Int,Int,FpuRoundMode.E) => Unit](add, sub, mul) + testI2f(24, false) + testI2f(17, false) + + testLoadStore(2.5f) + testLoadStore(3.67341984632e-40f) + testLoadStore(5.5321021294e-40f) - for(_ <- 0 until 10000){ + for(_ <- 0 until 100000){ + val rounding = FpuRoundMode.elements.randomPick() + val (a,b,c,f) = f32.add(rounding).f32_2 + testBinaryOp(add,a,b,c,f, rounding,"add") + } + + for(_ <- 0 until 100000){ + val rounding = FpuRoundMode.elements.randomPick() + val (a,b,c,f) = f32.sub(rounding).f32_2 + testBinaryOp(sub,a,b,c,f, rounding,"sub") + } + + println("Add done") + + for(_ <- 0 until 100000){ val rounding = FpuRoundMode.elements.randomPick() val (a,b,f) = f32.i2f(rounding).i32_f32 testI2fExact(a,b,f, true, rounding) } - for(_ <- 0 until 10000){ + for(_ <- 0 until 100000){ val rounding = FpuRoundMode.elements.randomPick() val (a,b,f) = f32.ui2f(rounding).i32_f32 testI2fExact(a,b,f, false, rounding) } println("i2f done") - for(_ <- 0 until 10000){ + for(_ <- 0 until 100000){ val rounding = FpuRoundMode.elements.randomPick() val (a,b,f) = f32.f2ui(rounding).f32_i32 testF2iExact(a,b, f, false, rounding) } - for(_ <- 0 until 10000){ + for(_ <- 0 until 100000){ val rounding = FpuRoundMode.elements.randomPick() val (a,b,f) = f32.f2i(rounding).f32_i32 testF2iExact(a,b, f, true, rounding) @@ -693,21 +712,8 @@ class FpuTest extends FunSuite{ println("f2i done") - for(_ <- 0 until 10000){ - val rounding = FpuRoundMode.elements.randomPick() - val (a,b,c,f) = f32.add(rounding).f32_2 - testBinaryOp(add,a,b,c,f, rounding,"add") - } - for(_ <- 0 until 10000){ - val rounding = FpuRoundMode.elements.randomPick() - val (a,b,c,f) = f32.sub(rounding).f32_2 - testBinaryOp(sub,a,b,c,f, rounding,"sub") - } - - println("Add done") - - for(_ <- 0 until 10000){ + for(_ <- 0 until 100000){ val rounding = FpuRoundMode.elements.randomPick() val (a,b,c,f) = f32.mul(rounding).f32_2 testBinaryOp(mul,a,b,c,f, rounding,"mul") From 3710fd34928f581470f43c000ea3d1fbec5e31ba Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 4 Feb 2021 12:41:31 +0100 Subject: [PATCH 568/951] fix synthesis bench --- src/main/scala/vexriscv/demo/SynthesisBench.scala | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/scala/vexriscv/demo/SynthesisBench.scala b/src/main/scala/vexriscv/demo/SynthesisBench.scala index d0a21186..e021e194 100644 --- a/src/main/scala/vexriscv/demo/SynthesisBench.scala +++ b/src/main/scala/vexriscv/demo/SynthesisBench.scala @@ -217,7 +217,7 @@ object VexRiscvSynthesisBench { frequencyTarget = 50 MHz, vivadoPath=sys.env.getOrElse("VIVADO_ARTIX_7_BIN", null), workspacePath=workspace + "_area", - toplevelPath=rtl.getRtlPath(), + rtl=rtl, family=getFamilyName(), device="xcku035-fbva900-3-e" ) @@ -230,7 +230,7 @@ object VexRiscvSynthesisBench { frequencyTarget = 800 MHz, vivadoPath=sys.env.getOrElse("VIVADO_ARTIX_7_BIN", null), workspacePath=workspace + "_fmax", - toplevelPath=rtl.getRtlPath(), + rtl=rtl, family=getFamilyName(), device="xcku035-fbva900-3-e" ) @@ -243,7 +243,7 @@ object VexRiscvSynthesisBench { frequencyTarget = 50 MHz, vivadoPath=sys.env.getOrElse("VIVADO_ARTIX_7_BIN", null), workspacePath=workspace + "_area", - toplevelPath=rtl.getRtlPath(), + rtl=rtl, family=getFamilyName(), device="xcku3p-ffvd900-3-e" ) @@ -256,7 +256,7 @@ object VexRiscvSynthesisBench { frequencyTarget = 800 MHz, vivadoPath=sys.env.getOrElse("VIVADO_ARTIX_7_BIN", null), workspacePath=workspace + "_fmax", - toplevelPath=rtl.getRtlPath(), + rtl=rtl, family=getFamilyName(), device="xcku3p-ffvd900-3-e" ) From 936e5823dcdca2bc4b6d1e4bdac1d408705e1807 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 4 Feb 2021 12:41:49 +0100 Subject: [PATCH 569/951] fpu test wip --- src/test/scala/vexriscv/ip/fpu/FpuTest.scala | 40 +++++++++++++++----- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala index c0b58b8d..19955faa 100644 --- a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala +++ b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala @@ -8,6 +8,7 @@ import org.apache.commons.io.FileUtils import org.scalatest.FunSuite import spinal.core.SpinalEnumElement import spinal.core.sim._ +import spinal.core._ import spinal.lib.DoCmd import spinal.lib.experimental.math.Floating import spinal.lib.sim._ @@ -38,7 +39,9 @@ class FpuTest extends FunSuite{ val config = SimConfig // config.withFstWave - config.compile(new FpuCore(portCount, p)).doSim(seed = 42){ dut => + config.compile(new FpuCore(portCount, p){ + for(i <- 0 until portCount) out(Bits(5 bits)).setName(s"flagAcc$i") := io.port(i).completion.flag.asBits + }).doSim(seed = 42){ dut => dut.clockDomain.forkStimulus(10) dut.clockDomain.forkSimSpeedPrinter(5.0) @@ -92,6 +95,21 @@ class FpuTest extends FunSuite{ val commitQueue = mutable.Queue[FpuCommit => Unit]() val rspQueue = mutable.Queue[FpuRsp => Unit]() + var pending = 0 + var flagAccumulator = 0 + + def cmdAdd(body : FpuCmd => Unit): Unit ={ + pending += 1 + cmdQueue += body + } + + val flagAggregated = dut.reflectBaseType(s"flagAcc$id").asInstanceOf[Bits] + dut.clockDomain.onSamplings{ + val c = dut.io.port(id).completion + pending -= c.count.toInt + flagAccumulator |= flagAggregated.toInt + } + StreamDriver(dut.io.port(id).cmd ,dut.clockDomain){payload => if(cmdQueue.isEmpty) false else { cmdQueue.dequeue().apply(payload) @@ -114,9 +132,11 @@ class FpuTest extends FunSuite{ } } + + def loadRaw(rd : Int, value : BigInt): Unit ={ - cmdQueue += {cmd => + cmdAdd {cmd => cmd.opcode #= cmd.opcode.spinalEnum.LOAD cmd.rs1.randomize() cmd.rs2.randomize() @@ -136,7 +156,7 @@ class FpuTest extends FunSuite{ } def storeRaw(rs : Int)(body : FpuRsp => Unit): Unit ={ - cmdQueue += {cmd => + cmdAdd {cmd => cmd.opcode #= cmd.opcode.spinalEnum.STORE cmd.rs1 #= rs cmd.rs2.randomize() @@ -154,7 +174,7 @@ class FpuTest extends FunSuite{ } def fpuF2f(rd : Int, rs1 : Int, rs2 : Int, rs3 : Int, opcode : FpuOpcode.E, arg : Int, rounding : FpuRoundMode.E = FpuRoundMode.RNE): Unit ={ - cmdQueue += {cmd => + cmdAdd {cmd => cmd.opcode #= opcode cmd.rs1 #= rs1 cmd.rs2 #= rs2 @@ -170,7 +190,7 @@ class FpuTest extends FunSuite{ } def fpuF2i(rs1 : Int, rs2 : Int, opcode : FpuOpcode.E, arg : Int, rounding : FpuRoundMode.E = FpuRoundMode.RNE)(body : FpuRsp => Unit): Unit ={ - cmdQueue += {cmd => + cmdAdd {cmd => cmd.opcode #= opcode cmd.rs1 #= rs1 cmd.rs2 #= rs2 @@ -217,7 +237,7 @@ class FpuTest extends FunSuite{ } def i2f(rd : Int, value : Int, signed : Boolean, rounding : FpuRoundMode.E = FpuRoundMode.RNE): Unit ={ - cmdQueue += {cmd => + cmdAdd {cmd => cmd.opcode #= cmd.opcode.spinalEnum.I2F cmd.rs1.randomize() cmd.rs2.randomize() @@ -234,7 +254,7 @@ class FpuTest extends FunSuite{ } def fmv_x_w(rs1 : Int)(body : FpuRsp => Unit): Unit ={ - cmdQueue += {cmd => + cmdAdd {cmd => cmd.opcode #= cmd.opcode.spinalEnum.FMV_X_W cmd.rs1 #= rs1 cmd.rs2.randomize() @@ -246,7 +266,7 @@ class FpuTest extends FunSuite{ } def fmv_w_x(rd : Int, value : Int): Unit ={ - cmdQueue += {cmd => + cmdAdd {cmd => cmd.opcode #= cmd.opcode.spinalEnum.FMV_W_X cmd.rs1.randomize() cmd.rs2.randomize() @@ -262,7 +282,7 @@ class FpuTest extends FunSuite{ } def min(rd : Int, rs1 : Int, rs2 : Int): Unit ={ - cmdQueue += {cmd => + cmdAdd {cmd => cmd.opcode #= cmd.opcode.spinalEnum.MIN_MAX cmd.rs1 #= rs1 cmd.rs2 #= rs2 @@ -278,7 +298,7 @@ class FpuTest extends FunSuite{ def sgnj(rd : Int, rs1 : Int, rs2 : Int): Unit ={ - cmdQueue += {cmd => + cmdAdd {cmd => cmd.opcode #= cmd.opcode.spinalEnum.SGNJ cmd.rs1 #= rs1 cmd.rs2 #= rs2 From 0f1ca72171f0a8cac66e79b2fba0d6e0b5f682d4 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 4 Feb 2021 12:41:31 +0100 Subject: [PATCH 570/951] fix synthesis bench --- src/main/scala/vexriscv/demo/SynthesisBench.scala | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/scala/vexriscv/demo/SynthesisBench.scala b/src/main/scala/vexriscv/demo/SynthesisBench.scala index d0a21186..e021e194 100644 --- a/src/main/scala/vexriscv/demo/SynthesisBench.scala +++ b/src/main/scala/vexriscv/demo/SynthesisBench.scala @@ -217,7 +217,7 @@ object VexRiscvSynthesisBench { frequencyTarget = 50 MHz, vivadoPath=sys.env.getOrElse("VIVADO_ARTIX_7_BIN", null), workspacePath=workspace + "_area", - toplevelPath=rtl.getRtlPath(), + rtl=rtl, family=getFamilyName(), device="xcku035-fbva900-3-e" ) @@ -230,7 +230,7 @@ object VexRiscvSynthesisBench { frequencyTarget = 800 MHz, vivadoPath=sys.env.getOrElse("VIVADO_ARTIX_7_BIN", null), workspacePath=workspace + "_fmax", - toplevelPath=rtl.getRtlPath(), + rtl=rtl, family=getFamilyName(), device="xcku035-fbva900-3-e" ) @@ -243,7 +243,7 @@ object VexRiscvSynthesisBench { frequencyTarget = 50 MHz, vivadoPath=sys.env.getOrElse("VIVADO_ARTIX_7_BIN", null), workspacePath=workspace + "_area", - toplevelPath=rtl.getRtlPath(), + rtl=rtl, family=getFamilyName(), device="xcku3p-ffvd900-3-e" ) @@ -256,7 +256,7 @@ object VexRiscvSynthesisBench { frequencyTarget = 800 MHz, vivadoPath=sys.env.getOrElse("VIVADO_ARTIX_7_BIN", null), workspacePath=workspace + "_fmax", - toplevelPath=rtl.getRtlPath(), + rtl=rtl, family=getFamilyName(), device="xcku3p-ffvd900-3-e" ) From f278900cbe6a9c4e21f8ab585b49b9b29fb05381 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 5 Feb 2021 11:09:04 +0100 Subject: [PATCH 571/951] VexRiscvSmpCluster can now set regfile read kind --- src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index e01bd87c..7c6e33d4 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -15,7 +15,7 @@ import spinal.lib.generator.Handle import spinal.lib.misc.plic.PlicMapping import spinal.lib.system.debugger.SystemDebuggerConfig import vexriscv.ip.{DataCacheAck, DataCacheConfig, DataCacheMemBus, InstructionCache, InstructionCacheConfig} -import vexriscv.plugin.{BranchPlugin, CsrAccess, CsrPlugin, CsrPluginConfig, DBusCachedPlugin, DBusSimplePlugin, DYNAMIC_TARGET, DebugPlugin, DecoderSimplePlugin, FullBarrelShifterPlugin, HazardSimplePlugin, IBusCachedPlugin, IBusSimplePlugin, IntAluPlugin, MmuPlugin, MmuPortConfig, MulDivIterativePlugin, MulPlugin, RegFilePlugin, STATIC, SrcPlugin, StaticMemoryTranslatorPlugin, YamlPlugin} +import vexriscv.plugin.{BranchPlugin, CsrAccess, CsrPlugin, CsrPluginConfig, DBusCachedPlugin, DBusSimplePlugin, DYNAMIC_TARGET, DebugPlugin, DecoderSimplePlugin, FullBarrelShifterPlugin, HazardSimplePlugin, IBusCachedPlugin, IBusSimplePlugin, IntAluPlugin, MmuPlugin, MmuPortConfig, MulDivIterativePlugin, MulPlugin, RegFilePlugin, RegFileReadKind, STATIC, SrcPlugin, StaticMemoryTranslatorPlugin, YamlPlugin} import vexriscv.{Riscv, VexRiscv, VexRiscvBmbGenerator, VexRiscvConfig, plugin} import scala.collection.mutable @@ -162,7 +162,8 @@ object VexRiscvSmpClusterGen { earlyBranch : Boolean = false, dBusCmdMasterPipe : Boolean = false, withMmu : Boolean = true, - withSupervisor : Boolean = true + withSupervisor : Boolean = true, + regfileRead : RegFileReadKind = plugin.ASYNC ) = { assert(iCacheSize/iCacheWays <= 4096, "Instruction cache ways can't be bigger than 4096 bytes") assert(dCacheSize/dCacheWays <= 4096, "Data cache ways can't be bigger than 4096 bytes") @@ -236,7 +237,7 @@ object VexRiscvSmpClusterGen { catchIllegalInstruction = true ), new RegFilePlugin( - regFileReadyKind = plugin.ASYNC, + regFileReadyKind = regfileRead, zeroBoot = false, x0Init = true ), From 6170243283d7ab908600962ea88b40c8f5170084 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 5 Feb 2021 16:24:14 +0100 Subject: [PATCH 572/951] fpu got exception flag right for add/sub/mul/i2f/f2i --- src/main/scala/vexriscv/ip/fpu/FpuCore.scala | 73 ++++--- .../scala/vexriscv/ip/fpu/Interface.scala | 7 +- src/test/scala/vexriscv/ip/fpu/FpuTest.scala | 201 ++++++++++++------ 3 files changed, 190 insertions(+), 91 deletions(-) diff --git a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala index c16791cc..5ac7636f 100644 --- a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala +++ b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala @@ -451,6 +451,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val recoded = CombInit(input.rs1) + val flag = io.port(input.source).completion.flag val halt = False val recodedResult = Bits(32 bits)//recoded.asBits.resize(32 bits) @@ -522,6 +523,10 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } is(FpuFloat.NAN){ recodedResult(23, 8 bits).setAll() + when(input.rs1.isCanonical){ + recodedResult(31) := False + recodedResult(0, 22 bits) := 0 + } } } } @@ -540,8 +545,8 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ FpuRoundMode.RMM -> (round(1)) ) val result = (Mux(resign, ~unsigned, unsigned) + (resign ^ increment).asUInt) - val overflow = RegNext((input.rs1.exponent > (input.arg(0) ? U(exponentOne+30) | U(exponentOne+31)) || input.rs1.isInfinity) && !input.rs1.sign || input.rs1.isNan) - val underflow = RegNext((input.rs1.exponent > U(exponentOne+30) || !input.arg(0) || input.rs1.isInfinity) && input.rs1.sign) + val overflow = (input.rs1.exponent > (input.arg(0) ? U(exponentOne+30) | U(exponentOne+31)) || input.rs1.isInfinity) && !input.rs1.sign || input.rs1.isNan + val underflow = (input.rs1.exponent > U(exponentOne+31) || input.arg(0) && unsigned.msb && unsigned(30 downto 0) =/= 0 || !input.arg(0) && (unsigned =/= 0 || increment) || input.rs1.isInfinity) && input.rs1.sign val isZero = input.rs1.isZero when(isZero){ result := 0 @@ -549,6 +554,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val low = overflow val high = input.arg(0) ^ overflow result := (31 -> high, default -> low) + flag.NV := input.valid && input.opcode === FpuOpcode.F2I && fsm.done && !isZero } } @@ -648,8 +654,9 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ scrap setWhen(needShift && mulHigh(0)) val forceZero = input.rs1.isZero || input.rs2.isZero val forceUnderflow = exp < exponentOne + exponentOne - 127 - 24 // 0x6A //TODO - val forceOverflow = /*exp > exponentOne + exponentOne + 127 || */input.rs1.isInfinity || input.rs2.isInfinity - val forceNan = input.rs1.isNan || input.rs2.isNan || ((input.rs1.isInfinity || input.rs2.isInfinity) && (input.rs1.isZero || input.rs2.isZero)) + val forceOverflow = input.rs1.isInfinity || input.rs2.isInfinity + val infinitynan = ((input.rs1.isInfinity || input.rs2.isInfinity) && (input.rs1.isZero || input.rs2.isZero)) + val forceNan = input.rs1.isNan || input.rs2.isNan || infinitynan val output = p.writeFloating() output.sign := input.rs1.sign ^ input.rs2.sign @@ -657,8 +664,10 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ output.mantissa := man.asUInt output.setNormal + val flag = io.port(input.source).completion.flag when(forceNan) { output.setNanQuiet + flag.NV setWhen(input.valid && (infinitynan || input.rs1.isNanSignaling || input.rs2.isNanSignaling)) } elsewhen(forceOverflow) { output.setInfinity } elsewhen(forceZero) { @@ -936,7 +945,8 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val forceZero = xyMantissa === 0 || (input.rs1.isZero && input.rs2.isZero) // val forceOverflow = exponent === exponentOne + 128 //Handled by writeback rounding val forceInfinity = (input.rs1.isInfinity || input.rs2.isInfinity) - val forceNan = input.rs1.isNan || input.rs2.isNan || (input.rs1.isInfinity && input.rs2.isInfinity && (input.rs1.sign ^ input.rs2.sign)) + val infinityNan = (input.rs1.isInfinity && input.rs2.isInfinity && (input.rs1.sign ^ input.rs2.sign)) + val forceNan = input.rs1.isNan || input.rs2.isNan || infinityNan } @@ -951,6 +961,9 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ output.roundMode := input.roundMode output.scrap := (norm.mantissa(1) | norm.mantissa(0) | shifter.roundingScrap) + + val flag = io.port(input.source).completion.flag + flag.NV setWhen(input.valid && (norm.infinityNan || input.rs1.isNanSignaling || input.rs2.isNanSignaling)) when(norm.forceNan) { output.value.setNanQuiet } elsewhen(norm.forceZero) { @@ -963,21 +976,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } } elsewhen(norm.forceInfinity) { output.value.setInfinity - } /*elsewhen(norm.forceOverflow) { - val doMax = input.roundMode.mux( - FpuRoundMode.RNE -> (False), - FpuRoundMode.RTZ -> (True), - FpuRoundMode.RDN -> (!output.value.sign), - FpuRoundMode.RUP -> (output.value.sign), - FpuRoundMode.RMM -> (False) - ) - when(doMax){ - output.value.exponent := exponentOne + 127 - output.value.mantissa.setAll() - } otherwise { - output.value.setInfinity - } - }*/ + } } @@ -993,8 +992,9 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ //TODO do not break NAN payload (seems already fine) val manAggregate = input.value.mantissa @@ input.scrap - val expDif = (exponentOne-126) - input.value.exponent - val discardCount = expDif.msb ? U(0) | expDif.resize(log2Up(p.internalMantissaSize) bits) + val expDif = (exponentOne-126) -^ input.value.exponent + val expSubnormal = !expDif.msb + val discardCount = expSubnormal ? expDif.resize(log2Up(p.internalMantissaSize) bits) | U(0) val exactMask = (List(True) ++ (0 until p.internalMantissaSize+1).map(_ < discardCount)).asBits.asUInt val roundAdjusted = (True ## (manAggregate>>1))(discardCount) ## ((manAggregate & exactMask) =/= 0) @@ -1017,8 +1017,18 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ math.mantissa := adder(0, p.internalMantissaSize bits) val patched = CombInit(math) + val nx,of,uf = False +// val ufPatch = input.roundMode === FpuRoundMode.RUP && !input.value.sign && !input.scrap|| input.roundMode === FpuRoundMode.RDN && input.value.sign && !input.scrap +// when(!math.special && (input.value.exponent <= exponentOne-127 && (math.exponent =/= exponentOne-126 || !input.value.mantissa.lsb || ufPatch)) && roundAdjusted.asUInt =/= 0){ +// uf := True +// } + + when(!math.special && math.exponent <= exponentOne-127 && roundAdjusted.asUInt =/= 0){ //Do not catch exact 1.17549435E-38 underflow, but, who realy care ? + uf := True + } when(!math.special && math.exponent >= exponentOne + 128){ -// patched.setInfinity + nx := True + of := True val doMax = input.roundMode.mux( FpuRoundMode.RNE -> (False), FpuRoundMode.RTZ -> (True), @@ -1036,6 +1046,8 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ when(!math.special && math.exponent <= exponentOne - 127-23){ + nx := True + uf := True val doMin = input.roundMode.mux( FpuRoundMode.RNE -> (False), FpuRoundMode.RTZ -> (False), @@ -1051,6 +1063,14 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } } + + nx setWhen(!input.value.special && (roundAdjusted =/= 0)) + when(input.valid){ + val flag = io.port(input.source).completion.flag + flag.NX setWhen(nx) + flag.OF setWhen(of) + flag.UF setWhen(uf) + } val output = input.swapPayload(RoundOutput()) output.source := input.source output.lockId := input.lockId @@ -1079,8 +1099,11 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ if(p.sim) when(port.data.isZero || port.data.isInfinity){ port.data.mantissa.assignDontCare() } - if(p.sim) when(port.data.special){ - port.data.exponent(p.internalExponentSize-1 downto 2).assignDontCare() + if(p.sim) when(input.value.special){ + port.data.exponent(p.internalExponentSize-1 downto 3).assignDontCare() + when(!input.value.isNan){ + port.data.exponent(2 downto 2).assignDontCare() + } } when(port.valid){ diff --git a/src/main/scala/vexriscv/ip/fpu/Interface.scala b/src/main/scala/vexriscv/ip/fpu/Interface.scala index dff47798..1b804107 100644 --- a/src/main/scala/vexriscv/ip/fpu/Interface.scala +++ b/src/main/scala/vexriscv/ip/fpu/Interface.scala @@ -27,6 +27,7 @@ object FpuFloat{ val ZERO = 0 val INFINITY = 1 val NAN = 2 + val NAN_CANONICAL_BIT = 2 } case class FpuFloat(exponentSize: Int, @@ -49,12 +50,14 @@ case class FpuFloat(exponentSize: Int, def isInfinity = special && exponent(1 downto 0) === FpuFloat.INFINITY def isNan = special && exponent(1 downto 0) === FpuFloat.NAN def isQuiet = mantissa.msb + def isNanSignaling = special && exponent(1 downto 0) === FpuFloat.NAN && !isQuiet + def isCanonical = exponent(FpuFloat.NAN_CANONICAL_BIT) def setNormal = { special := False } def setZero = { special := True; exponent(1 downto 0) := FpuFloat.ZERO } def setInfinity = { special := True; exponent(1 downto 0) := FpuFloat.INFINITY } - def setNan = { special := True; exponent(1 downto 0) := FpuFloat.NAN } - def setNanQuiet = { special := True; exponent(1 downto 0) := FpuFloat.NAN ; mantissa.msb := True } + def setNan = { special := True; exponent(1 downto 0) := FpuFloat.NAN; exponent(FpuFloat.NAN_CANONICAL_BIT) := False} + def setNanQuiet = { special := True; exponent(1 downto 0) := FpuFloat.NAN; exponent(FpuFloat.NAN_CANONICAL_BIT) := True; mantissa.msb := True; } def decode() = { val ret = FpuFloatDecoded() diff --git a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala index 19955faa..496a5d2f 100644 --- a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala +++ b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala @@ -23,7 +23,7 @@ import scala.util.Random class FpuTest extends FunSuite{ val b2f = lang.Float.intBitsToFloat(_) - val f2b = lang.Float.floatToIntBits(_) + val f2b = lang.Float.floatToRawIntBits(_) def clamp(f : Float) = { f // if(f.abs < b2f(0x00800000)) b2f(f2b(f) & 0x80000000) else f @@ -38,9 +38,11 @@ class FpuTest extends FunSuite{ ) val config = SimConfig -// config.withFstWave + config.allOptimisation + config.withFstWave config.compile(new FpuCore(portCount, p){ for(i <- 0 until portCount) out(Bits(5 bits)).setName(s"flagAcc$i") := io.port(i).completion.flag.asBits + setDefinitionName("FpuCore") }).doSim(seed = 42){ dut => dut.clockDomain.forkStimulus(10) dut.clockDomain.forkSimSpeedPrinter(5.0) @@ -48,10 +50,29 @@ class FpuTest extends FunSuite{ class TestCase(op : String){ - def build(arg : String) = new ProcessStream(s"testfloat_gen $arg -forever -$op"){ - def f32_2 ={ + def build(arg : String) = new ProcessStream(s"testfloat_gen $arg -tininessafter -forever -$op"){ + def f32_f32 ={ val s = new Scanner(next) - (b2f(s.nextLong(16).toInt), b2f(s.nextLong(16).toInt), b2f(s.nextLong(16).toInt), s.nextInt(16)) + val a,b,c = (s.nextLong(16).toInt) +// if(b2f(a).isNaN || b2f(b).isNaN){ +// print("NAN => ") +// if(((a >> 23) & 0xFF) == 0xFF && ((a >> 0) & 0xEFFFFF) != 0){ +// print(a.toHexString) +// print(" " + f2b(b2f(a)).toHexString) +// } +// if(((b >> 23) & 0xFF) == 0xFF && ((b >> 0) & 0xEFFFFF) != 0){ +// print(b.toHexString) +// print(" " + f2b(b2f(b)).toHexString) +// } +// if(((c >> 23) & 0xFF) == 0xFF && ((c >> 0) & 0xEFFFFF) != 0){ +// print(" " + c.toHexString) +// print(" " + f2b(b2f(c)).toHexString) +// } +// +// print(" " + simTime()) +// println("") +// } + (b2f(a), b2f(b), b2f(c), s.nextInt(16)) } def i32_f32 ={ @@ -95,21 +116,29 @@ class FpuTest extends FunSuite{ val commitQueue = mutable.Queue[FpuCommit => Unit]() val rspQueue = mutable.Queue[FpuRsp => Unit]() - var pending = 0 + var pendingMiaou = 0 var flagAccumulator = 0 - + def cmdAdd(body : FpuCmd => Unit): Unit ={ - pending += 1 + pendingMiaou += 1 cmdQueue += body } + def softAssert(cond : Boolean, msg : String) = if(!cond)println(msg) + def flagMatch(ref : Int, value : Float, report : String): Unit ={ + waitUntil(pendingMiaou == 0) + val patch = if(value.abs == 1.17549435E-38f) ref & ~2 else ref + assert(flagAccumulator == patch, s"Flag missmatch dut=$flagAccumulator ref=$patch $report") + flagAccumulator = 0 + } + val flagAggregated = dut.reflectBaseType(s"flagAcc$id").asInstanceOf[Bits] dut.clockDomain.onSamplings{ val c = dut.io.port(id).completion - pending -= c.count.toInt + pendingMiaou -= c.count.toInt flagAccumulator |= flagAggregated.toInt } - + StreamDriver(dut.io.port(id).cmd ,dut.clockDomain){payload => if(cmdQueue.isEmpty) false else { cmdQueue.dequeue().apply(payload) @@ -132,8 +161,8 @@ class FpuTest extends FunSuite{ } } - - + + def loadRaw(rd : Int, value : BigInt): Unit ={ cmdAdd {cmd => @@ -152,7 +181,7 @@ class FpuTest extends FunSuite{ } def load(rd : Int, value : Float): Unit ={ - loadRaw(rd, lang.Float.floatToIntBits(value).toLong & 0xFFFFFFFFl) + loadRaw(rd, f2b(value).toLong & 0xFFFFFFFFl) } def storeRaw(rs : Int)(body : FpuRsp => Unit): Unit ={ @@ -166,7 +195,7 @@ class FpuTest extends FunSuite{ } rspQueue += body - waitUntil(rspQueue.isEmpty) +// waitUntil(rspQueue.isEmpty) } def storeFloat(rs : Int)(body : Float => Unit): Unit ={ @@ -385,6 +414,9 @@ class FpuTest extends FunSuite{ storeFloat(rd){v => assert(f2b(v) == f2b(ref), f"## ${a} ${opName} $b = $v, $ref $rounding") } + + + flagMatch(flag, ref, f"## ${opName} ${a} $b $ref $rounding") } def testAddExact(a : Float, b : Float, ref : Float, flag : Int, rounding : FpuRoundMode.E): Unit ={ @@ -538,6 +570,8 @@ class FpuTest extends FunSuite{ assert(v == ref2, f" <= f2ui($a) = $v, $ref2, $rounding $flag") } } + + flagMatch(flag, ref, f" f2${if(signed) "" else "u"}i($a) $ref $flag $rounding") } @@ -563,6 +597,9 @@ class FpuTest extends FunSuite{ val ref = b assert(f2b(v) == f2b(ref), f"i2f($aLong) = $v, $ref") } + + + flagMatch(f, b, f"i2f() = $b") } @@ -589,7 +626,7 @@ class FpuTest extends FunSuite{ val rd = Random.nextInt(32) load(rs1, a) fmv_x_w(rs1){rsp => - val ref = lang.Float.floatToIntBits(a).toLong & 0xFFFFFFFFl + val ref = f2b(a).toLong & 0xFFFFFFFFl val v = rsp.value.toBigInt println(f"fmv_x_w $a = $v, $ref") assert(v === ref) @@ -682,48 +719,16 @@ class FpuTest extends FunSuite{ val binaryOps = List[(Int,Int,Int,FpuRoundMode.E) => Unit](add, sub, mul) - testI2f(24, false) - testI2f(17, false) - testLoadStore(2.5f) - testLoadStore(3.67341984632e-40f) - testLoadStore(5.5321021294e-40f) + testF2iExact(-2.14748365E9f, -2147483648, 0, true, FpuRoundMode.RDN) - - for(_ <- 0 until 100000){ - val rounding = FpuRoundMode.elements.randomPick() - val (a,b,c,f) = f32.add(rounding).f32_2 - testBinaryOp(add,a,b,c,f, rounding,"add") - } - - for(_ <- 0 until 100000){ - val rounding = FpuRoundMode.elements.randomPick() - val (a,b,c,f) = f32.sub(rounding).f32_2 - testBinaryOp(sub,a,b,c,f, rounding,"sub") - } - - println("Add done") - - for(_ <- 0 until 100000){ - val rounding = FpuRoundMode.elements.randomPick() - val (a,b,f) = f32.i2f(rounding).i32_f32 - testI2fExact(a,b,f, true, rounding) - } - - for(_ <- 0 until 100000){ - val rounding = FpuRoundMode.elements.randomPick() - val (a,b,f) = f32.ui2f(rounding).i32_f32 - testI2fExact(a,b,f, false, rounding) - } - println("i2f done") - - for(_ <- 0 until 100000){ + for(_ <- 0 until 10000){ val rounding = FpuRoundMode.elements.randomPick() val (a,b,f) = f32.f2ui(rounding).f32_i32 testF2iExact(a,b, f, false, rounding) } - for(_ <- 0 until 100000){ + for(_ <- 0 until 10000){ val rounding = FpuRoundMode.elements.randomPick() val (a,b,f) = f32.f2i(rounding).f32_i32 testF2iExact(a,b, f, true, rounding) @@ -731,17 +736,63 @@ class FpuTest extends FunSuite{ println("f2i done") - - - for(_ <- 0 until 100000){ + for(_ <- 0 until 10000){ val rounding = FpuRoundMode.elements.randomPick() - val (a,b,c,f) = f32.mul(rounding).f32_2 + val (a,b,f) = f32.i2f(rounding).i32_f32 + testI2fExact(a,b,f, true, rounding) + } + + for(_ <- 0 until 10000){ + val rounding = FpuRoundMode.elements.randomPick() + val (a,b,f) = f32.ui2f(rounding).i32_f32 + testI2fExact(a,b,f, false, rounding) + } + println("i2f done") + + testBinaryOp(mul,1.469368E-39f, 7.9999995f, 1.17549435E-38f,3, FpuRoundMode.RUP,"mul") + testBinaryOp(mul,1.1753509E-38f, 1.0001221f, 1.17549435E-38f ,1, FpuRoundMode.RUP,"mul") + testBinaryOp(mul, 1.1754942E-38f, -1.0000001f, -1.17549435E-38f,1, FpuRoundMode.RNE,"mul") + testBinaryOp(mul, 1.1754942E-38f, -1.0000001f, -1.17549435E-38f,1, FpuRoundMode.RDN,"mul") + testBinaryOp(mul, 1.1754942E-38f, -1.0000001f, -1.17549435E-38f,1, FpuRoundMode.RMM,"mul") + + testBinaryOp(mul, 1.1754945E-38f, 0.9999998f, 1.17549435E-38f, 3, FpuRoundMode.RUP, "mul") + testBinaryOp(mul, 1.1754945E-38f, -0.9999998f, -1.17549435E-38f, 3, FpuRoundMode.RDN, "mul") + testBinaryOp(mul, 1.1754946E-38f, 0.9999997f, 1.17549435E-38f, 3, FpuRoundMode.RUP, "mul") + testBinaryOp(mul, 1.1754946E-38f, -0.9999997f, -1.17549435E-38f, 3, FpuRoundMode.RDN, "mul") + testBinaryOp(mul, 1.1754949E-38f, 0.99999946f, 1.17549435E-38f, 3, FpuRoundMode.RUP, "mul") + testBinaryOp(mul, 1.1754949E-38f, -0.99999946f, -1.17549435E-38f, 3, FpuRoundMode.RDN, "mul") + testBinaryOp(mul, 1.1754955E-38f, 0.999999f, 1.17549435E-38f, 3, FpuRoundMode.RUP, "mul") + + + for(_ <- 0 until 10000){ + val rounding = FpuRoundMode.elements.randomPick() + val (a,b,c,f) = f32.mul(rounding).f32_f32 testBinaryOp(mul,a,b,c,f, rounding,"mul") } println("Mul done") + for(_ <- 0 until 10000){ + val rounding = FpuRoundMode.elements.randomPick() + val (a,b,c,f) = f32.add(rounding).f32_f32 + testBinaryOp(add,a,b,c,f, rounding,"add") + } + + for(_ <- 0 until 10000){ + val rounding = FpuRoundMode.elements.randomPick() + val (a,b,c,f) = f32.sub(rounding).f32_f32 + testBinaryOp(sub,a,b,c,f, rounding,"sub") + } + + println("Add done") + + + + + + + @@ -823,7 +874,7 @@ class FpuTest extends FunSuite{ testLoadStore(1.765f) - testFmv_w_x(lang.Float.floatToIntBits(7.234f)) + testFmv_w_x(f2b(7.234f)) testI2f(64, false) for(i <- iUnsigned) testI2f(i, false) for(i <- iSigned) testI2f(i, true) @@ -874,7 +925,7 @@ class FpuTest extends FunSuite{ testFmv_x_w(1.246f) - testFmv_w_x(lang.Float.floatToIntBits(7.234f)) + testFmv_w_x(f2b(7.234f)) testMin(1.0f, 2.0f) testMin(1.5f, 2.0f) @@ -989,7 +1040,7 @@ class FpuTest extends FunSuite{ tests += (() =>{testSqrt(randomFloat().abs)}) tests += (() =>{testCmp(randomFloat(), randomFloat())}) tests += (() =>{testFmv_x_w(randomFloat())}) - tests += (() =>{testFmv_w_x(lang.Float.floatToIntBits(randomFloat()))}) + tests += (() =>{testFmv_w_x(f2b(randomFloat()))}) tests += (() =>{testMin(randomFloat(), randomFloat())}) tests += (() =>{testSgnj(randomFloat(), randomFloat())}) @@ -1018,15 +1069,37 @@ object Clib { DoCmd.doCmd(cmd) val math = new FpuMath } - +// cd /media/data/open/SaxonSoc/testFloatBuild/berkeley-softfloat-3/build/Linux-x86_64-GCC +// make clean && SPECIALIZE_TYPE=RISCV make -j$(nproc) && cp softfloat.a /media/data/open/SaxonSoc/artyA7SmpUpdate/SaxonSoc/ext/VexRiscv/src/test/cpp/fpu/math object FpuCompileSo extends App{ - val b2f = lang.Float.intBitsToFloat(_) - for(e <- FpuRoundMode.elements) { - println(e) - for (i <- -2 until 50) println(i + " => " + Clib.math.addF32(b2f(0x7f000000), b2f(0x7f000000 + i), e.position)) - println("") - } +// val b2f = lang.Float.intBitsToFloat(_) +// for(e <- FpuRoundMode.elements) { +// println(e) +// for (i <- -2 until 50) println(i + " => " + Clib.math.addF32(b2f(0x7f000000), b2f(0x7f000000 + i), e.position)) +// println("") +// } + //1 did not equal 3 Flag missmatch dut=1 ref=3 ## mul 0.9994812 -1.1754988E-38 -1.174889E-38 RMM + // println(Clib.math.mulF32(0.9994812f, -1.1754988E-38f, FpuRoundMode.RMM.position)) +// miaou ffffffff 7fffffe0 7f +// miaou 0 3ffffff0 70 = 0 + + + println(Clib.math.mulF32( 1.1753509E-38f, 1.0001221f, FpuRoundMode.RUP.position)) + println(Clib.math.mulF32( 1.1754945E-38f, 0.9999998f, FpuRoundMode.RUP.position)) +// testBinaryOp(mul, 1.1753509E-38f, 1.0001221f, 1.17549435E-38f ,1, FpuRoundMode.RUP,"mul") +// testBinaryOp(mul, 1.1754945E-38f, 0.9999998f, 1.17549435E-38f, 3, FpuRoundMode.RUP, "mul") +// miaou ffffffff 7fffffe0 7f +// miaou 0 3ffffff0 70 = 0 +// miaou ffffffff 7fffff7e 7f +// miaou 1 3fffffbf 3f = 1 + +// println(Clib.math.mulF32( 1.1753509E-38f, 1.0001221f, FpuRoundMode.RUP.position)) +// println(Clib.math.mulF32( 1.469368E-39f, 7.9999995f, FpuRoundMode.RUP.position)) +// println(Clib.math.mulF32( 1.40129846432e-45f, 7.9999995f, FpuRoundMode.RUP.position)) +// println(Clib.math.mulF32( 2.93873587706e-39f, 7.9999995f, FpuRoundMode.RUP.position)) +// println(Clib.math.mulF32( 1f, 7.9999995f, FpuRoundMode.RUP.position)) + // println(Clib.math.addF32(1.00000011921f, 4.0f, FpuRoundMode.RNE.position)) // println(Clib.math.addF32(1.00000011921f, 4.0f, FpuRoundMode.RTZ.position)) From 008fadeaa92618dcf99c5039cdf441a44d7c3482 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sat, 6 Feb 2021 13:20:27 +0100 Subject: [PATCH 573/951] fpu eq lt le pass testfloat --- src/main/scala/vexriscv/ip/fpu/FpuCore.scala | 13 ++++ src/test/scala/vexriscv/ip/fpu/FpuTest.scala | 68 ++++++++++++++++---- 2 files changed, 70 insertions(+), 11 deletions(-) diff --git a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala index 5ac7636f..65723d68 100644 --- a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala +++ b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala @@ -16,6 +16,8 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val port = Vec(slave(FpuPort(p)), portCount) } +// io.port(0).completion.flag.setAsDirectionLess.allowDirectionLessIo + val portCountWidth = log2Up(portCount) val Source = HardType(UInt(portCountWidth bits)) val exponentOne = (1 << p.internalExponentSize-1) - 1 @@ -622,6 +624,17 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } } + +// val useRs1 = List(FpuOpcode.CMP).map(input.opcode === _).orR +// val useRs2 = List(FpuOpcode.CMP).map(input.opcode === _).orR + val onlySignalingNan = input.arg === 2 + val rs1Nan = input.rs1.isNan + val rs2Nan = input.rs2.isNan + val rs1NanNv = input.rs1.isNan && !(onlySignalingNan && input.rs1.isQuiet) + val rs2NanNv = input.rs2.isNan && !(onlySignalingNan && input.rs2.isQuiet) + val nv = input.opcode === FpuOpcode.CMP && (rs1NanNv || rs2NanNv) + flag.NV setWhen(input.valid && nv) + input.ready := !halt && (toFpuRf ? rfOutput.ready | io.port.map(_.rsp.ready).read(input.source)) for(i <- 0 until portCount){ def rsp = io.port(i).rsp diff --git a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala index 496a5d2f..0de72d96 100644 --- a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala +++ b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala @@ -39,7 +39,7 @@ class FpuTest extends FunSuite{ val config = SimConfig config.allOptimisation - config.withFstWave +// config.withFstWave config.compile(new FpuCore(portCount, p){ for(i <- 0 until portCount) out(Bits(5 bits)).setName(s"flagAcc$i") := io.port(i).completion.flag.asBits setDefinitionName("FpuCore") @@ -84,13 +84,21 @@ class FpuTest extends FunSuite{ val s = new Scanner(next) (b2f(s.nextLong(16).toInt), s.nextLong(16).toInt, s.nextInt(16)) } + + def f32_f32_i32 = { + val s = new Scanner(next) + val a,b,c = (s.nextLong(16).toInt) + (b2f(a), b2f(b), c, s.nextInt(16)) + } } - val RNE = build("-rnear_even") - val RTZ = build("-rminMag") - val RDN = build("-rmin") - val RUP = build("-rmax") - val RMM = build("-rnear_maxMag") - val all = List(RNE, RTZ, RDN, RUP, RMM) + + lazy val RAW = build("") + lazy val RNE = build("-rnear_even") + lazy val RTZ = build("-rminMag") + lazy val RDN = build("-rmin") + lazy val RUP = build("-rmax") + lazy val RMM = build("-rnear_maxMag") + lazy val all = List(RNE, RTZ, RDN, RUP, RMM, RAW) def kill = all.foreach(_.kill) def apply(rounding : FpuRoundMode.E) = rounding match { case FpuRoundMode.RNE => RNE @@ -109,6 +117,9 @@ class FpuTest extends FunSuite{ val i2f = new TestCase("i32_to_f32") val f2ui = new TestCase("f32_to_ui32") val f2i = new TestCase("f32_to_i32") + val eq = new TestCase("f32_eq") + val lt = new TestCase("f32_lt") + val le = new TestCase("f32_le") } val cpus = for(id <- 0 until portCount) yield new { @@ -126,9 +137,12 @@ class FpuTest extends FunSuite{ def softAssert(cond : Boolean, msg : String) = if(!cond)println(msg) def flagMatch(ref : Int, value : Float, report : String): Unit ={ - waitUntil(pendingMiaou == 0) val patch = if(value.abs == 1.17549435E-38f) ref & ~2 else ref - assert(flagAccumulator == patch, s"Flag missmatch dut=$flagAccumulator ref=$patch $report") + flagMatch(ref, patch, report) + } + def flagMatch(ref : Int, report : String): Unit ={ + waitUntil(pendingMiaou == 0) + assert(flagAccumulator == ref, s"Flag missmatch dut=$flagAccumulator ref=$ref $report") flagAccumulator = 0 } @@ -257,8 +271,8 @@ class FpuTest extends FunSuite{ } - def cmp(rs1 : Int, rs2 : Int)(body : FpuRsp => Unit): Unit ={ - fpuF2i(rs1, rs2, FpuOpcode.CMP, 1, FpuRoundMode.elements.randomPick())(body) + def cmp(rs1 : Int, rs2 : Int, arg : Int = 1)(body : FpuRsp => Unit): Unit ={ + fpuF2i(rs1, rs2, FpuOpcode.CMP, arg, FpuRoundMode.elements.randomPick())(body) } def f2i(rs1 : Int, signed : Boolean, rounding : FpuRoundMode.E = FpuRoundMode.RNE)(body : FpuRsp => Unit): Unit ={ @@ -620,6 +634,23 @@ class FpuTest extends FunSuite{ } } + + def testCmpExact(a : Float, b : Float, ref : Int, flag : Int, arg : Int): Unit ={ + val rs = new RegAllocator() + val rs1, rs2, rs3 = rs.allocate() + val rd = Random.nextInt(32) + load(rs1, a) + load(rs2, b) + cmp(rs1, rs2, arg){rsp => + val v = rsp.value.toLong + assert(v === ref, f"cmp($a, $b, $arg) = $v, $ref") + } + flagMatch(flag,f"$a < $b $ref $flag ${f2b(a).toHexString} ${f2b(b).toHexString}") + } + def testLe(a : Float, b : Float, ref : Int, flag : Int) = testCmpExact(a,b,ref,flag, 0) + def testEq(a : Float, b : Float, ref : Int, flag : Int) = testCmpExact(a,b,ref,flag, 2) + def testLt(a : Float, b : Float, ref : Int, flag : Int) = testCmpExact(a,b,ref,flag, 1) + def testFmv_x_w(a : Float): Unit ={ val rs = new RegAllocator() val rs1, rs2, rs3 = rs.allocate() @@ -719,6 +750,21 @@ class FpuTest extends FunSuite{ val binaryOps = List[(Int,Int,Int,FpuRoundMode.E) => Unit](add, sub, mul) + for(_ <- 0 until 100000){ + val (a,b,i,f) = f32.le.RAW.f32_f32_i32 + testLe(a,b,i, f) + } + for(_ <- 0 until 100000){ + val (a,b,i,f) = f32.lt.RAW.f32_f32_i32 + testLt(a,b,i, f) + } + + for(_ <- 0 until 100000){ + val (a,b,i,f) = f32.eq.RAW.f32_f32_i32 + testEq(a,b,i, f) + } + println("Cmp done") + testF2iExact(-2.14748365E9f, -2147483648, 0, true, FpuRoundMode.RDN) From bf0829231dd523c7a31af3b2cc2b6e53f57ec74a Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sat, 6 Feb 2021 14:08:21 +0100 Subject: [PATCH 574/951] fpu min max pass --- src/main/scala/vexriscv/ip/fpu/FpuCore.scala | 16 ++--- src/test/scala/vexriscv/ip/fpu/FpuTest.scala | 76 +++++++++++--------- 2 files changed, 49 insertions(+), 43 deletions(-) diff --git a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala index 65723d68..c017d24b 100644 --- a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala +++ b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala @@ -571,11 +571,13 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ 0 -> rs1AbsSmaller, 1 -> False, 2 -> True, - 3 -> (!rs1AbsSmaller && !rs1Equal) + 3 -> !rs1AbsSmaller ) val minMaxResult = ((rs1Smaller ^ input.arg(0)) && !input.rs1.isNan || input.rs2.isNan) ? input.rs1 | input.rs2 + when(input.rs1.isNan && input.rs2.isNan) { minMaxResult.setNanQuiet } +// when(input.rs1.isZero && input.rs2.isZero && input.rs1.sign =/= input.rs2.sign){ minMaxResult.sign := !input.arg(0) } val cmpResult = B(rs1Smaller && !bothZero && !input.arg(1) || (rs1Equal || bothZero) && !input.arg(0)) when(input.rs1.isNan || input.rs2.isNan) { cmpResult := 0 } val sgnjResult = (input.rs1.sign && input.arg(1)) ^ input.rs2.sign ^ input.arg(0) @@ -612,6 +614,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ rfOutput.value.assignDontCare() switch(input.opcode){ is(FpuOpcode.MIN_MAX){ + rfOutput.value.sign := minMaxResult.sign rfOutput.value.exponent := minMaxResult.exponent rfOutput.value.mantissa := minMaxResult.mantissa @@ U"0" rfOutput.value.special := minMaxResult.special @@ -624,15 +627,12 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } } - -// val useRs1 = List(FpuOpcode.CMP).map(input.opcode === _).orR -// val useRs2 = List(FpuOpcode.CMP).map(input.opcode === _).orR - val onlySignalingNan = input.arg === 2 + val signalQuiet = input.opcode === FpuOpcode.CMP && input.arg =/= 2 val rs1Nan = input.rs1.isNan val rs2Nan = input.rs2.isNan - val rs1NanNv = input.rs1.isNan && !(onlySignalingNan && input.rs1.isQuiet) - val rs2NanNv = input.rs2.isNan && !(onlySignalingNan && input.rs2.isQuiet) - val nv = input.opcode === FpuOpcode.CMP && (rs1NanNv || rs2NanNv) + val rs1NanNv = input.rs1.isNan && (!input.rs1.isQuiet || signalQuiet) + val rs2NanNv = input.rs2.isNan && (!input.rs2.isQuiet || signalQuiet) + val nv = (input.opcode === FpuOpcode.CMP || input.opcode === FpuOpcode.MIN_MAX) && (rs1NanNv || rs2NanNv) flag.NV setWhen(input.valid && nv) input.ready := !halt && (toFpuRf ? rfOutput.ready | io.port.map(_.rsp.ready).read(input.source)) diff --git a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala index 0de72d96..7dc1496d 100644 --- a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala +++ b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala @@ -51,7 +51,7 @@ class FpuTest extends FunSuite{ class TestCase(op : String){ def build(arg : String) = new ProcessStream(s"testfloat_gen $arg -tininessafter -forever -$op"){ - def f32_f32 ={ + def f32_f32_f32 ={ val s = new Scanner(next) val a,b,c = (s.nextLong(16).toInt) // if(b2f(a).isNaN || b2f(b).isNaN){ @@ -120,6 +120,8 @@ class FpuTest extends FunSuite{ val eq = new TestCase("f32_eq") val lt = new TestCase("f32_lt") val le = new TestCase("f32_le") + val min = new TestCase("f32_le") + val max = new TestCase("f32_lt") } val cpus = for(id <- 0 until portCount) yield new { @@ -138,7 +140,7 @@ class FpuTest extends FunSuite{ def softAssert(cond : Boolean, msg : String) = if(!cond)println(msg) def flagMatch(ref : Int, value : Float, report : String): Unit ={ val patch = if(value.abs == 1.17549435E-38f) ref & ~2 else ref - flagMatch(ref, patch, report) + flagMatch(patch, report) } def flagMatch(ref : Int, report : String): Unit ={ waitUntil(pendingMiaou == 0) @@ -324,14 +326,14 @@ class FpuTest extends FunSuite{ } } - def min(rd : Int, rs1 : Int, rs2 : Int): Unit ={ + def minMax(rd : Int, rs1 : Int, rs2 : Int, arg : Int = 0): Unit ={ cmdAdd {cmd => cmd.opcode #= cmd.opcode.spinalEnum.MIN_MAX cmd.rs1 #= rs1 cmd.rs2 #= rs2 cmd.rs3.randomize() cmd.rd #= rd - cmd.arg #= 0 + cmd.arg #= arg } commitQueue += {cmd => cmd.write #= true @@ -678,25 +680,35 @@ class FpuTest extends FunSuite{ - def testMin(a : Float, b : Float): Unit ={ + def testMinMaxExact(a : Float, b : Float, arg : Int): Unit ={ val rs = new RegAllocator() - val rs1, rs2, rs3 = rs.allocate() + val rs1, rs2 = rs.allocate() val rd = Random.nextInt(32) + val ref = (a,b) match { + case _ if a.isNaN && b.isNaN => b2f(0x7FC00000) + case _ if a.isNaN => b + case _ if b.isNaN => a + case _ => if(arg == 0) Math.min(a,b) else Math.max(a,b) + } + val flag = (a,b) match { + case _ if a.isNaN && ((f2b(a) >> 22 ) & 1) == 0 => 16 + case _ if b.isNaN && ((f2b(b) >> 22 ) & 1) == 0 => 16 + case _ => 0 + } load(rs1, a) load(rs2, b) - min(rd,rs1,rs2) + minMax(rd,rs1,rs2, arg) storeFloat(rd){v => - val ref = (a,b) match { - case _ if a.isNaN => b - case _ if b.isNaN => a - case _ => Math.min(a,b) - } - println(f"min $a $b = $v, $ref") - assert(f2b(ref) == f2b(v)) + assert(f2b(ref) == f2b(v), f"minMax($a $b $arg) = $v, $ref") } + flagMatch(flag, f"minmax($a $b $arg)") } + def testMin(a : Float, b : Float) = testMinMaxExact(a,b,0) + def testMax(a : Float, b : Float) = testMinMaxExact(a,b,1) + + def testSgnj(a : Float, b : Float): Unit ={ val rs = new RegAllocator() val rs1, rs2, rs3 = rs.allocate() @@ -750,6 +762,16 @@ class FpuTest extends FunSuite{ val binaryOps = List[(Int,Int,Int,FpuRoundMode.E) => Unit](add, sub, mul) + for(_ <- 0 until 10000){ + val (a,b,r,f) = f32.min.RAW.f32_f32_f32 + testMin(a,b) + } + for(_ <- 0 until 10000){ + val (a,b,r,f) = f32.max.RAW.f32_f32_f32 + testMax(a,b) + } + println("minMax done") + for(_ <- 0 until 100000){ val (a,b,i,f) = f32.le.RAW.f32_f32_i32 testLe(a,b,i, f) @@ -812,7 +834,7 @@ class FpuTest extends FunSuite{ for(_ <- 0 until 10000){ val rounding = FpuRoundMode.elements.randomPick() - val (a,b,c,f) = f32.mul(rounding).f32_f32 + val (a,b,c,f) = f32.mul(rounding).f32_f32_f32 testBinaryOp(mul,a,b,c,f, rounding,"mul") } @@ -821,13 +843,13 @@ class FpuTest extends FunSuite{ for(_ <- 0 until 10000){ val rounding = FpuRoundMode.elements.randomPick() - val (a,b,c,f) = f32.add(rounding).f32_f32 + val (a,b,c,f) = f32.add(rounding).f32_f32_f32 testBinaryOp(add,a,b,c,f, rounding,"add") } for(_ <- 0 until 10000){ val rounding = FpuRoundMode.elements.randomPick() - val (a,b,c,f) = f32.sub(rounding).f32_f32 + val (a,b,c,f) = f32.sub(rounding).f32_f32_f32 testBinaryOp(sub,a,b,c,f, rounding,"sub") } @@ -936,14 +958,7 @@ class FpuTest extends FunSuite{ for(a <- fAll; b <- fAll) testCmp(a, b) for(_ <- 0 until 1000) testCmp(randomFloat(), randomFloat()) - testMin(0.0f, 1.2f ) - testMin(1.2f, 0.0f ) - testMin(0.0f, -0.0f ) - testMin(-0.0f, 0.0f ) - for(a <- fAll; _ <- 0 until 50) testMin(a, randomFloat()) - for(b <- fAll; _ <- 0 until 50) testMin(randomFloat(), b) - for(a <- fAll; b <- fAll) testMin(a, b) - for(_ <- 0 until 1000) testMin(randomFloat(), randomFloat()) + testSqrt(1.2f) testSqrt(0.0f) @@ -973,15 +988,6 @@ class FpuTest extends FunSuite{ testFmv_x_w(1.246f) testFmv_w_x(f2b(7.234f)) - testMin(1.0f, 2.0f) - testMin(1.5f, 2.0f) - testMin(1.5f, 3.5f) - testMin(1.5f, 1.5f) - testMin(1.5f, -1.5f) - testMin(-1.5f, 1.5f) - testMin(-1.5f, -1.5f) - testMin(1.5f, -3.5f) - testSgnj(1.0f, 2.0f) testSgnj(1.5f, 2.0f) testSgnj(1.5f, 3.5f) @@ -1087,7 +1093,7 @@ class FpuTest extends FunSuite{ tests += (() =>{testCmp(randomFloat(), randomFloat())}) tests += (() =>{testFmv_x_w(randomFloat())}) tests += (() =>{testFmv_w_x(f2b(randomFloat()))}) - tests += (() =>{testMin(randomFloat(), randomFloat())}) +// tests += (() =>{testMin(randomFloat(), randomFloat())}) tests += (() =>{testSgnj(randomFloat(), randomFloat())}) From bf6a64b6b55c7c4c68b2541e574cdd97c1ae1c1f Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 8 Feb 2021 15:29:50 +0100 Subject: [PATCH 575/951] fpu sgnj / fclass / fmv pass --- src/main/scala/vexriscv/ip/fpu/FpuCore.scala | 11 +- src/test/scala/vexriscv/ip/fpu/FpuTest.scala | 198 +++++++++++++------ 2 files changed, 144 insertions(+), 65 deletions(-) diff --git a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala index c017d24b..0f79acae 100644 --- a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala +++ b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala @@ -105,6 +105,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val value = p.writeFloating() val scrap = Bool() val roundMode = FpuRoundMode() + val allowException = Bool() } case class RoundOutput() extends Bundle{ @@ -463,7 +464,9 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } recodedResult := recoded.sign ## f32.exp ## f32.man - val isSubnormal = !recoded.special && recoded.exponent <= exponentOne - 127 + val expInSubnormalRange = recoded.exponent <= exponentOne - 127 + val isSubnormal = !recoded.special && expInSubnormalRange + val isNormal = !recoded.special && !expInSubnormalRange val fsm = new Area{ val f2iShift = input.rs1.exponent - U(exponentOne) val isF2i = input.opcode === FpuOpcode.F2I @@ -584,12 +587,12 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val fclassResult = B(0, 32 bits) val decoded = input.rs1.decode() fclassResult(0) := input.rs1.sign && decoded.isInfinity - fclassResult(1) := input.rs1.sign && decoded.isNormal + fclassResult(1) := input.rs1.sign && isNormal fclassResult(2) := input.rs1.sign && isSubnormal //TODO fclassResult(3) := input.rs1.sign && decoded.isZero fclassResult(4) := !input.rs1.sign && decoded.isZero fclassResult(5) := !input.rs1.sign && isSubnormal //TODO - fclassResult(6) := !input.rs1.sign && decoded.isNormal + fclassResult(6) := !input.rs1.sign && isNormal fclassResult(7) := !input.rs1.sign && decoded.isInfinity fclassResult(8) := decoded.isNan && !decoded.isQuiet fclassResult(9) := decoded.isNan && decoded.isQuiet @@ -623,7 +626,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ rfOutput.value.sign := sgnjResult rfOutput.value.exponent := input.rs1.exponent rfOutput.value.mantissa := input.rs1.mantissa @@ U"0" - rfOutput.value.special := False //TODO + rfOutput.value.special := input.rs1.special } } diff --git a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala index 7dc1496d..d066eb1c 100644 --- a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala +++ b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala @@ -122,6 +122,11 @@ class FpuTest extends FunSuite{ val le = new TestCase("f32_le") val min = new TestCase("f32_le") val max = new TestCase("f32_lt") + val transfer = new TestCase("f32_eq") + val fclass = new TestCase("f32_eq") + val sgnj = new TestCase("f32_eq") + val sgnjn = new TestCase("f32_eq") + val sgnjx = new TestCase("f32_eq") } val cpus = for(id <- 0 until portCount) yield new { @@ -272,6 +277,19 @@ class FpuTest extends FunSuite{ fpuF2f(rd, rs1, rs2, rs3, FpuOpcode.FMA, 0, rounding) } + def sgnjRaw(rd : Int, rs1 : Int, rs2 : Int, arg : Int): Unit ={ + fpuF2f(rd, rs1, rs2, Random.nextInt(32), FpuOpcode.SGNJ, arg, FpuRoundMode.elements.randomPick()) + } + + def sgnj(rd : Int, rs1 : Int, rs2 : Int, rounding : FpuRoundMode.E = null): Unit ={ + sgnjRaw(rd, rs1, rs2, 0) + } + def sgnjn(rd : Int, rs1 : Int, rs2 : Int, rounding : FpuRoundMode.E = null): Unit ={ + sgnjRaw(rd, rs1, rs2, 1) + } + def sgnjx(rd : Int, rs1 : Int, rs2 : Int, rounding : FpuRoundMode.E = null): Unit ={ + sgnjRaw(rd, rs1, rs2, 2) + } def cmp(rs1 : Int, rs2 : Int, arg : Int = 1)(body : FpuRsp => Unit): Unit ={ fpuF2i(rs1, rs2, FpuOpcode.CMP, arg, FpuRoundMode.elements.randomPick())(body) @@ -298,7 +316,7 @@ class FpuTest extends FunSuite{ } } - def fmv_x_w(rs1 : Int)(body : FpuRsp => Unit): Unit ={ + def fmv_x_w(rs1 : Int)(body : Float => Unit): Unit ={ cmdAdd {cmd => cmd.opcode #= cmd.opcode.spinalEnum.FMV_X_W cmd.rs1 #= rs1 @@ -307,7 +325,7 @@ class FpuTest extends FunSuite{ cmd.rd.randomize() cmd.arg #= 0 } - rspQueue += body + rspQueue += {rsp => body(b2f(rsp.value.toLong.toInt))} } def fmv_w_x(rd : Int, value : Int): Unit ={ @@ -342,19 +360,17 @@ class FpuTest extends FunSuite{ } - def sgnj(rd : Int, rs1 : Int, rs2 : Int): Unit ={ + + def fclass(rs1 : Int)(body : Int => Unit) : Unit = { cmdAdd {cmd => - cmd.opcode #= cmd.opcode.spinalEnum.SGNJ + cmd.opcode #= FpuOpcode.FCLASS cmd.rs1 #= rs1 - cmd.rs2 #= rs2 + cmd.rs2.randomize() cmd.rs3.randomize() - cmd.rd #= rd - cmd.arg #= 0 - } - commitQueue += {cmd => - cmd.write #= true - cmd.sync #= false + cmd.rd.randomize() + cmd.arg.randomize() } + rspQueue += {rsp => body(rsp.value.toLong.toInt)} } } @@ -460,16 +476,43 @@ class FpuTest extends FunSuite{ } } - def testLoadStore(a : Float): Unit ={ + def testTransfer(a : Float, iSrc : Boolean, iDst : Boolean): Unit ={ val rd = Random.nextInt(32) - load(rd, a) - storeFloat(rd){v => + + def handle(v : Float): Unit ={ val refUnclamped = a val ref = a - println(f"$a = $v, $ref") - assert(f2b(v) == f2b(ref)) + assert(f2b(v) == f2b(ref), f"$a = $v, $ref") + } + + if(iSrc) fmv_w_x(rd, f2b(a)) else load(rd, a) + if(iDst) fmv_x_w(rd)(handle) else storeFloat(rd)(handle) + + flagMatch(0, f"$a") + } + + def testClass(a : Float) : Unit = { + val rd = Random.nextInt(32) + + + load(rd, a) + fclass(rd){v => + val mantissa = f2b(a) & 0x7FFFFF + val exp = (f2b(a) >> 23) & 0xFF + val sign = (f2b(a) >> 31) & 0x1 + + val refBit = if(a.isInfinite) (if(sign == 0) 7 else 0) + else if(a.isNaN) (if((mantissa >> 22) != 0) 9 else 8) + else if(exp == 0 && mantissa != 0) (if(sign == 0) 5 else 2) + else if(exp == 0 && mantissa == 0) (if(sign == 0) 4 else 3) + else if(sign == 0) 6 else 1 + + val ref = 1 << refBit + + assert(v == ref, f"fclass $a") } } + def testMul(a : Float, b : Float): Unit ={ val rs = new RegAllocator() val rs1, rs2, rs3 = rs.allocate() @@ -653,30 +696,30 @@ class FpuTest extends FunSuite{ def testEq(a : Float, b : Float, ref : Int, flag : Int) = testCmpExact(a,b,ref,flag, 2) def testLt(a : Float, b : Float, ref : Int, flag : Int) = testCmpExact(a,b,ref,flag, 1) - def testFmv_x_w(a : Float): Unit ={ - val rs = new RegAllocator() - val rs1, rs2, rs3 = rs.allocate() - val rd = Random.nextInt(32) - load(rs1, a) - fmv_x_w(rs1){rsp => - val ref = f2b(a).toLong & 0xFFFFFFFFl - val v = rsp.value.toBigInt - println(f"fmv_x_w $a = $v, $ref") - assert(v === ref) - } - } +// def testFmv_x_w(a : Float): Unit ={ +// val rs = new RegAllocator() +// val rs1, rs2, rs3 = rs.allocate() +// val rd = Random.nextInt(32) +// load(rs1, a) +// fmv_x_w(rs1){rsp => +// val ref = f2b(a).toLong & 0xFFFFFFFFl +// val v = rsp.value.toBigInt +// println(f"fmv_x_w $a = $v, $ref") +// assert(v === ref) +// } +// } - def testFmv_w_x(a : Int): Unit ={ - val rs = new RegAllocator() - val rs1, rs2, rs3 = rs.allocate() - val rd = Random.nextInt(32) - fmv_w_x(rd, a) - storeFloat(rd){v => - val ref = b2f(a) - println(f"fmv_w_x $a = $v, $ref") - assert(v === ref) - } - } +// def testFmv_w_x(a : Int): Unit ={ +// val rs = new RegAllocator() +// val rs1, rs2, rs3 = rs.allocate() +// val rd = Random.nextInt(32) +// fmv_w_x(rd, a) +// storeFloat(rd){v => +// val ref = b2f(a) +// println(f"fmv_w_x $a = $v, $ref") +// assert(v === ref) +// } +// } @@ -710,18 +753,16 @@ class FpuTest extends FunSuite{ def testSgnj(a : Float, b : Float): Unit ={ - val rs = new RegAllocator() - val rs1, rs2, rs3 = rs.allocate() - val rd = Random.nextInt(32) - load(rs1, a) - load(rs2, b) - - sgnj(rd,rs1,rs2) - storeFloat(rd){v => - val ref = a * a.signum * b.signum - println(f"sgnf $a $b = $v, $ref") - assert(ref == v) - } + val ref = b2f((f2b(a) & ~0x80000000) | f2b(b) & 0x80000000) + testBinaryOp(sgnj,a,b,ref,0, null,"sgnj") + } + def testSgnjn(a : Float, b : Float): Unit ={ + val ref = b2f((f2b(a) & ~0x80000000) | ((f2b(b) & 0x80000000) ^ 0x80000000)) + testBinaryOp(sgnjn,a,b,ref,0, null,"sgnjn") + } + def testSgnjx(a : Float, b : Float): Unit ={ + val ref = b2f(f2b(a) ^ (f2b(b) & 0x80000000)) + testBinaryOp(sgnjx,a,b,ref,0, null,"sgnjx") } @@ -762,6 +803,41 @@ class FpuTest extends FunSuite{ val binaryOps = List[(Int,Int,Int,FpuRoundMode.E) => Unit](add, sub, mul) + + + for(_ <- 0 until 10000){ + testSgnj(b2f(Random.nextInt()), b2f(Random.nextInt())) + testSgnjn(b2f(Random.nextInt()), b2f(Random.nextInt())) + testSgnjx(b2f(Random.nextInt()), b2f(Random.nextInt())) + val (a,b,r,f) = f32.sgnj.RAW.f32_f32_i32 + testSgnj(a, b) + testSgnjn(a, b) + testSgnjx(a, b) + } + println("f32 sgnj done") + + for(_ <- 0 until 10000){ + testTransfer(b2f(Random.nextInt()), Random.nextBoolean(), Random.nextBoolean()) + } + for(_ <- 0 until 10000){ + val (a,b,r,f) = f32.transfer.RAW.f32_f32_i32 + testTransfer(a, Random.nextBoolean(), Random.nextBoolean()) + } + + println("f32 load/store/rf transfer done") + + + for(_ <- 0 until 10000){ + testClass(b2f(Random.nextInt())) + } + for(_ <- 0 until 10000){ + val (a,b,r,f) = f32.fclass.RAW.f32_f32_i32 + testClass(a) + } + + println("f32 class done") + + for(_ <- 0 until 10000){ val (a,b,r,f) = f32.min.RAW.f32_f32_f32 testMin(a,b) @@ -890,9 +966,9 @@ class FpuTest extends FunSuite{ for(_ <- 0 until 1000) testAdd(randomFloat(), randomFloat()) - testLoadStore(1.17549435082e-38f) - testLoadStore(1.4E-45f) - testLoadStore(3.44383110592e-41f) +// testTransfer(1.17549435082e-38f) +// testTransfer(1.4E-45f) +// testTransfer(3.44383110592e-41f) //TODO bring back those tests and test overflow / underflow (F2I) // testF2i(16.0f , false) @@ -918,7 +994,7 @@ class FpuTest extends FunSuite{ - testLoadStore(1.2f) +// testTransfer(1.2f) testMul(1.2f, 2.5f) testMul(b2f(0x00400000), 16.0f) testMul(b2f(0x00100000), 16.0f) @@ -941,8 +1017,8 @@ class FpuTest extends FunSuite{ - testLoadStore(1.765f) - testFmv_w_x(f2b(7.234f)) +// testTransfer(1.765f) +// testFmv_w_x(f2b(7.234f)) testI2f(64, false) for(i <- iUnsigned) testI2f(i, false) for(i <- iSigned) testI2f(i, true) @@ -985,8 +1061,8 @@ class FpuTest extends FunSuite{ // dut.clockDomain.waitSampling(10000000) - testFmv_x_w(1.246f) - testFmv_w_x(f2b(7.234f)) +// testFmv_x_w(1.246f) +// testFmv_w_x(f2b(7.234f)) testSgnj(1.0f, 2.0f) testSgnj(1.5f, 2.0f) @@ -1091,8 +1167,8 @@ class FpuTest extends FunSuite{ tests += (() =>{testDiv(randomFloat(), randomFloat())}) tests += (() =>{testSqrt(randomFloat().abs)}) tests += (() =>{testCmp(randomFloat(), randomFloat())}) - tests += (() =>{testFmv_x_w(randomFloat())}) - tests += (() =>{testFmv_w_x(f2b(randomFloat()))}) +// tests += (() =>{testFmv_x_w(randomFloat())}) +// tests += (() =>{testFmv_w_x(f2b(randomFloat()))}) // tests += (() =>{testMin(randomFloat(), randomFloat())}) tests += (() =>{testSgnj(randomFloat(), randomFloat())}) From 1fe993ad10a1da099a1bb3b98ffa4fd196231f93 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 9 Feb 2021 18:35:47 +0100 Subject: [PATCH 576/951] fpu fixed corner cases, FpuPlugin coupling, pass rv-test excepted div (accuracy), can run C sinf successfully --- src/main/scala/vexriscv/TestsWorkspace.scala | 2 +- src/main/scala/vexriscv/ip/fpu/FpuCore.scala | 15 +- .../scala/vexriscv/plugin/FpuPlugin.scala | 17 +- src/test/cpp/regression/main.cpp | 37 +- src/test/cpp/regression/makefile | 4 + src/test/resources/asm/rv32uf-p-fadd.dump | 402 +++++++++++ src/test/resources/asm/rv32uf-p-fclass.dump | 218 ++++++ src/test/resources/asm/rv32uf-p-fcmp.dump | 510 ++++++++++++++ src/test/resources/asm/rv32uf-p-fcvt.dump | 219 ++++++ src/test/resources/asm/rv32uf-p-fcvt_w.dump | 632 ++++++++++++++++++ src/test/resources/asm/rv32uf-p-fdiv.dump | 322 +++++++++ src/test/resources/asm/rv32uf-p-fmadd.dump | 439 ++++++++++++ src/test/resources/asm/rv32uf-p-fmin.dump | 581 ++++++++++++++++ src/test/resources/asm/rv32uf-p-ldst.dump | 172 +++++ src/test/resources/asm/rv32uf-p-move.dump | 360 ++++++++++ src/test/resources/asm/rv32uf-p-recoding.dump | 190 ++++++ src/test/resources/hex/rv32uf-p-fadd.hex | 83 +++ src/test/resources/hex/rv32uf-p-fclass.hex | 53 ++ src/test/resources/hex/rv32uf-p-fcmp.hex | 100 +++ src/test/resources/hex/rv32uf-p-fcvt.hex | 50 ++ src/test/resources/hex/rv32uf-p-fcvt_w.hex | 120 ++++ src/test/resources/hex/rv32uf-p-fdiv.hex | 69 ++ src/test/resources/hex/rv32uf-p-fmadd.hex | 89 +++ src/test/resources/hex/rv32uf-p-fmin.hex | 115 ++++ src/test/resources/hex/rv32uf-p-ldst.hex | 43 ++ src/test/resources/hex/rv32uf-p-move.hex | 81 +++ src/test/resources/hex/rv32uf-p-recoding.hex | 46 ++ src/test/scala/vexriscv/ip/fpu/FpuTest.scala | 140 +++- 28 files changed, 5064 insertions(+), 45 deletions(-) create mode 100644 src/test/resources/asm/rv32uf-p-fadd.dump create mode 100644 src/test/resources/asm/rv32uf-p-fclass.dump create mode 100644 src/test/resources/asm/rv32uf-p-fcmp.dump create mode 100644 src/test/resources/asm/rv32uf-p-fcvt.dump create mode 100644 src/test/resources/asm/rv32uf-p-fcvt_w.dump create mode 100644 src/test/resources/asm/rv32uf-p-fdiv.dump create mode 100644 src/test/resources/asm/rv32uf-p-fmadd.dump create mode 100644 src/test/resources/asm/rv32uf-p-fmin.dump create mode 100644 src/test/resources/asm/rv32uf-p-ldst.dump create mode 100644 src/test/resources/asm/rv32uf-p-move.dump create mode 100644 src/test/resources/asm/rv32uf-p-recoding.dump create mode 100755 src/test/resources/hex/rv32uf-p-fadd.hex create mode 100755 src/test/resources/hex/rv32uf-p-fclass.hex create mode 100755 src/test/resources/hex/rv32uf-p-fcmp.hex create mode 100755 src/test/resources/hex/rv32uf-p-fcvt.hex create mode 100755 src/test/resources/hex/rv32uf-p-fcvt_w.hex create mode 100755 src/test/resources/hex/rv32uf-p-fdiv.hex create mode 100755 src/test/resources/hex/rv32uf-p-fmadd.hex create mode 100755 src/test/resources/hex/rv32uf-p-fmin.hex create mode 100755 src/test/resources/hex/rv32uf-p-ldst.hex create mode 100755 src/test/resources/hex/rv32uf-p-move.hex create mode 100755 src/test/resources/hex/rv32uf-p-recoding.hex diff --git a/src/main/scala/vexriscv/TestsWorkspace.scala b/src/main/scala/vexriscv/TestsWorkspace.scala index 3fc35b87..c920e577 100644 --- a/src/main/scala/vexriscv/TestsWorkspace.scala +++ b/src/main/scala/vexriscv/TestsWorkspace.scala @@ -213,7 +213,7 @@ object TestsWorkspace { // } SpinalConfig().generateVerilog { - +// make clean run REDO=10 CSR=no MMU=no COREMARK=no RVF=yes REDO=1 TRACE=yes val config = GenFull.config config.plugins += new FpuPlugin( externalFpu = false, diff --git a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala index 0f79acae..18843413 100644 --- a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala +++ b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala @@ -105,7 +105,6 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val value = p.writeFloating() val scrap = Bool() val roundMode = FpuRoundMode() - val allowException = Bool() } case class RoundOutput() extends Bundle{ @@ -560,6 +559,8 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val high = input.arg(0) ^ overflow result := (31 -> high, default -> low) flag.NV := input.valid && input.opcode === FpuOpcode.F2I && fsm.done && !isZero + } otherwise { + flag.NX := input.valid && input.opcode === FpuOpcode.F2I && fsm.done && round =/= 0 } } @@ -570,11 +571,12 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ rs1AbsSmaller.setWhen(input.rs1.isZero) rs1AbsSmaller.clearWhen(input.rs2.isZero) rs1AbsSmaller.clearWhen(input.rs1.isInfinity) + rs1Equal setWhen(input.rs1.sign === input.rs2.sign && input.rs1.isInfinity && input.rs2.isInfinity) val rs1Smaller = (input.rs1.sign ## input.rs2.sign).mux( 0 -> rs1AbsSmaller, 1 -> False, 2 -> True, - 3 -> !rs1AbsSmaller + 3 -> (!rs1AbsSmaller && !rs1Equal) ) @@ -680,6 +682,8 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ output.mantissa := man.asUInt output.setNormal + when(exp(exp.getWidth-3, 3 bits) >= 5) { output.exponent(p.internalExponentSize-2, 2 bits) := 3 } + val flag = io.port(input.source).completion.flag when(forceNan) { output.setNanQuiet @@ -1112,13 +1116,14 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ port.address := input.source @@ input.rd port.data := input.value + val randomSim = p.sim generate (in UInt(p.internalMantissaSize bits)) if(p.sim) when(port.data.isZero || port.data.isInfinity){ - port.data.mantissa.assignDontCare() + port.data.mantissa := randomSim } if(p.sim) when(input.value.special){ - port.data.exponent(p.internalExponentSize-1 downto 3).assignDontCare() + port.data.exponent(p.internalExponentSize-1 downto 3) := randomSim.resized when(!input.value.isNan){ - port.data.exponent(2 downto 2).assignDontCare() + port.data.exponent(2 downto 2) := randomSim.resized } } diff --git a/src/main/scala/vexriscv/plugin/FpuPlugin.scala b/src/main/scala/vexriscv/plugin/FpuPlugin.scala index c3673572..49bd49a4 100644 --- a/src/main/scala/vexriscv/plugin/FpuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/FpuPlugin.scala @@ -78,8 +78,8 @@ class FpuPlugin(externalFpu : Boolean = false, FSUB_S -> (addSub :+ arg(1)), FMADD_S -> (fma :+ arg(0)), FMSUB_S -> (fma :+ arg(2)), - FNMADD_S -> (fma :+ arg(1)), - FNMSUB_S -> (fma :+ arg(3)), + FNMADD_S -> (fma :+ arg(3)), + FNMSUB_S -> (fma :+ arg(1)), FMUL_S -> (mul :+ arg(0)), FDIV_S -> (div), FSQRT_S -> (sqrt), @@ -138,11 +138,11 @@ class FpuPlugin(externalFpu : Boolean = false, flags.NX init(False) setWhen(port.completion.flag.NX) val service = pipeline.service(classOf[CsrInterface]) - val rm = Reg(Bits(3 bits)) + val rm = Reg(Bits(3 bits)) init(0) service.rw(CSR.FCSR, 5, rm) service.rw(CSR.FCSR, 0, flags) - service.rw(CSR.FRM, 5, rm) + service.rw(CSR.FRM, 0, rm) service.rw(CSR.FFLAGS, 0, flags) val csrActive = service.duringAny() @@ -195,21 +195,22 @@ class FpuPlugin(externalFpu : Boolean = false, //Manage $store and port.rsp port.rsp.ready := False when(isRsp){ - port.rsp.ready := True when(arbitration.isValid) { dBusEncoding.bypassStore(port.rsp.value) output(REGFILE_WRITE_DATA) := port.rsp.value } when(!port.rsp.valid){ arbitration.haltByOther := True + } elsewhen(!arbitration.haltItself){ + port.rsp.ready := True } } // Manage $load val commit = Stream(FpuCommit(p)) - commit.valid := isCommit && arbitration.isMoving + commit.valid := isCommit && !arbitration.isStuck commit.value := (input(FPU_COMMIT_LOAD) ? output(DBUS_DATA) | input(RS1)) - commit.write := arbitration.isValid + commit.write := arbitration.isValid && !arbitration.removeIt commit.sync := input(FPU_COMMIT_SYNC) when(arbitration.isValid && !commit.ready){ @@ -219,6 +220,8 @@ class FpuPlugin(externalFpu : Boolean = false, port.commit <-/< commit } + pipeline.stages.dropRight(1).foreach(s => s.output(FPU_FORKED) clearWhen(s.arbitration.isStuck)) + Component.current.afterElaboration{ pipeline.stages.tail.foreach(_.input(FPU_FORKED).init(False)) } diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 9391da3a..9bfa886a 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -1323,6 +1323,12 @@ public: allowInvalidate = false; return this; } + Workspace* writeWord(uint32_t address, uint32_t data){ + mem.write(address, 4, (uint8_t*)&data); + riscvRef.mem.write(address, 4, (uint8_t*)&data); + return this; + } + virtual bool isPerifRegion(uint32_t addr) { return false; } virtual bool isMmuRegion(uint32_t addr) { return true;} virtual void iBusAccess(uint32_t addr, uint32_t *data, bool *error) { @@ -3016,7 +3022,7 @@ public: if(code == 1 || code2 == 1){ pass(); }else{ - cout << "Error code " << code/2 << endl; + cout << "Error code " << code2/2 << endl; fail(); } } @@ -3624,6 +3630,21 @@ string riscvTestMemory[] = { }; +string riscvTestFloat[] = { + "rv32uf-p-fadd", + "rv32uf-p-fcmp", + "rv32uf-p-fcvt_w", + "rv32uf-p-fmadd", + "rv32uf-p-ldst", + "rv32uf-p-recoding", + "rv32uf-p-fclass", + "rv32uf-p-fcvt", + "rv32uf-p-fdiv", + "rv32uf-p-fmin", + "rv32uf-p-move" +}; + + string riscvTestMul[] = { @@ -3793,6 +3814,8 @@ string complianceTestC[] = { + + struct timespec timer_start(){ struct timespec start_time; clock_gettime(CLOCK_REALTIME, &start_time); //CLOCK_PROCESS_CPUTIME_ID @@ -3863,6 +3886,12 @@ int main(int argc, char **argv, char **env) { printf("BOOT\n"); timespec startedAt = timer_start(); + #ifdef RVF + for(const string &name : riscvTestFloat){ + redo(REDO,RiscvTest(name).bootAt(0x80000188u)->writeWord(0x80000184u, 0x00305073)->run();) + } + #endif + return 0; //#ifdef LITEX // LitexSoC("linux") @@ -4035,6 +4064,12 @@ int main(int argc, char **argv, char **env) { redo(REDO,RiscvTest(name).run();) } + #ifdef RVF + for(const string &name : riscvTestFloat){ + redo(REDO,RiscvTest(name).run();) + } + #endif + #ifdef MUL for(const string &name : riscvTestMul){ redo(REDO,RiscvTest(name).run();) diff --git a/src/test/cpp/regression/makefile b/src/test/cpp/regression/makefile index 7802a00b..f63c812e 100644 --- a/src/test/cpp/regression/makefile +++ b/src/test/cpp/regression/makefile @@ -265,6 +265,10 @@ ifeq ($(MUL),yes) ADDCFLAGS += -CFLAGS -DMUL endif +ifeq ($(RVF),yes) + ADDCFLAGS += -CFLAGS -DRVF +endif + ifeq ($(DIV),yes) ADDCFLAGS += -CFLAGS -DDIV endif diff --git a/src/test/resources/asm/rv32uf-p-fadd.dump b/src/test/resources/asm/rv32uf-p-fadd.dump new file mode 100644 index 00000000..af247c28 --- /dev/null +++ b/src/test/resources/asm/rv32uf-p-fadd.dump @@ -0,0 +1,402 @@ + +rv32uf-p-fadd: file format elf32-littleriscv + + +Disassembly of section .text.init: + +80000000 <_start>: +80000000: 04c0006f j 8000004c + +80000004 : +80000004: 34202f73 csrr t5,mcause +80000008: 00800f93 li t6,8 +8000000c: 03ff0a63 beq t5,t6,80000040 +80000010: 00900f93 li t6,9 +80000014: 03ff0663 beq t5,t6,80000040 +80000018: 00b00f93 li t6,11 +8000001c: 03ff0263 beq t5,t6,80000040 +80000020: 80000f17 auipc t5,0x80000 +80000024: fe0f0f13 addi t5,t5,-32 # 0 <_start-0x80000000> +80000028: 000f0463 beqz t5,80000030 +8000002c: 000f0067 jr t5 +80000030: 34202f73 csrr t5,mcause +80000034: 000f5463 bgez t5,8000003c +80000038: 0040006f j 8000003c + +8000003c : +8000003c: 5391e193 ori gp,gp,1337 + +80000040 : +80000040: 00001f17 auipc t5,0x1 +80000044: fc3f2023 sw gp,-64(t5) # 80001000 +80000048: ff9ff06f j 80000040 + +8000004c : +8000004c: 00000093 li ra,0 +80000050: 00000113 li sp,0 +80000054: 00000193 li gp,0 +80000058: 00000213 li tp,0 +8000005c: 00000293 li t0,0 +80000060: 00000313 li t1,0 +80000064: 00000393 li t2,0 +80000068: 00000413 li s0,0 +8000006c: 00000493 li s1,0 +80000070: 00000513 li a0,0 +80000074: 00000593 li a1,0 +80000078: 00000613 li a2,0 +8000007c: 00000693 li a3,0 +80000080: 00000713 li a4,0 +80000084: 00000793 li a5,0 +80000088: 00000813 li a6,0 +8000008c: 00000893 li a7,0 +80000090: 00000913 li s2,0 +80000094: 00000993 li s3,0 +80000098: 00000a13 li s4,0 +8000009c: 00000a93 li s5,0 +800000a0: 00000b13 li s6,0 +800000a4: 00000b93 li s7,0 +800000a8: 00000c13 li s8,0 +800000ac: 00000c93 li s9,0 +800000b0: 00000d13 li s10,0 +800000b4: 00000d93 li s11,0 +800000b8: 00000e13 li t3,0 +800000bc: 00000e93 li t4,0 +800000c0: 00000f13 li t5,0 +800000c4: 00000f93 li t6,0 +800000c8: f1402573 csrr a0,mhartid +800000cc: 00051063 bnez a0,800000cc +800000d0: 00000297 auipc t0,0x0 +800000d4: 01028293 addi t0,t0,16 # 800000e0 +800000d8: 30529073 csrw mtvec,t0 +800000dc: 18005073 csrwi satp,0 +800000e0: 00000297 auipc t0,0x0 +800000e4: 02028293 addi t0,t0,32 # 80000100 +800000e8: 30529073 csrw mtvec,t0 +800000ec: 800002b7 lui t0,0x80000 +800000f0: fff28293 addi t0,t0,-1 # 7fffffff <_end+0xffffdf5f> +800000f4: 3b029073 csrw pmpaddr0,t0 +800000f8: 01f00293 li t0,31 +800000fc: 3a029073 csrw pmpcfg0,t0 +80000100: 30405073 csrwi mie,0 +80000104: 00000297 auipc t0,0x0 +80000108: 01428293 addi t0,t0,20 # 80000118 +8000010c: 30529073 csrw mtvec,t0 +80000110: 30205073 csrwi medeleg,0 +80000114: 30305073 csrwi mideleg,0 +80000118: 00000193 li gp,0 +8000011c: 00000297 auipc t0,0x0 +80000120: ee828293 addi t0,t0,-280 # 80000004 +80000124: 30529073 csrw mtvec,t0 +80000128: 00100513 li a0,1 +8000012c: 01f51513 slli a0,a0,0x1f +80000130: 00054c63 bltz a0,80000148 +80000134: 0ff0000f fence +80000138: 00100193 li gp,1 +8000013c: 05d00893 li a7,93 +80000140: 00000513 li a0,0 +80000144: 00000073 ecall +80000148: 80000297 auipc t0,0x80000 +8000014c: eb828293 addi t0,t0,-328 # 0 <_start-0x80000000> +80000150: 00028a63 beqz t0,80000164 +80000154: 10529073 csrw stvec,t0 +80000158: 0000b2b7 lui t0,0xb +8000015c: 10928293 addi t0,t0,265 # b109 <_start-0x7fff4ef7> +80000160: 30229073 csrw medeleg,t0 +80000164: 30005073 csrwi mstatus,0 +80000168: 00002537 lui a0,0x2 +8000016c: 30052073 csrs mstatus,a0 +80000170: 00305073 csrwi fcsr,0 +80000174: 00000297 auipc t0,0x0 +80000178: 01428293 addi t0,t0,20 # 80000188 +8000017c: 34129073 csrw mepc,t0 +80000180: f1402573 csrr a0,mhartid +80000184: 30200073 mret + +80000188 : +80000188: 00200193 li gp,2 +8000018c: 00002517 auipc a0,0x2 +80000190: e7450513 addi a0,a0,-396 # 80002000 +80000194: 00052007 flw ft0,0(a0) +80000198: 00452087 flw ft1,4(a0) +8000019c: 00852107 flw ft2,8(a0) +800001a0: 00c52683 lw a3,12(a0) +800001a4: 001071d3 fadd.s ft3,ft0,ft1 +800001a8: e0018553 fmv.x.w a0,ft3 +800001ac: 001015f3 fsflags a1,zero +800001b0: 00000613 li a2,0 +800001b4: 1ed51063 bne a0,a3,80000394 +800001b8: 1cc59e63 bne a1,a2,80000394 + +800001bc : +800001bc: 00300193 li gp,3 +800001c0: 00002517 auipc a0,0x2 +800001c4: e5050513 addi a0,a0,-432 # 80002010 +800001c8: 00052007 flw ft0,0(a0) +800001cc: 00452087 flw ft1,4(a0) +800001d0: 00852107 flw ft2,8(a0) +800001d4: 00c52683 lw a3,12(a0) +800001d8: 001071d3 fadd.s ft3,ft0,ft1 +800001dc: e0018553 fmv.x.w a0,ft3 +800001e0: 001015f3 fsflags a1,zero +800001e4: 00100613 li a2,1 +800001e8: 1ad51663 bne a0,a3,80000394 +800001ec: 1ac59463 bne a1,a2,80000394 + +800001f0 : +800001f0: 00400193 li gp,4 +800001f4: 00002517 auipc a0,0x2 +800001f8: e2c50513 addi a0,a0,-468 # 80002020 +800001fc: 00052007 flw ft0,0(a0) +80000200: 00452087 flw ft1,4(a0) +80000204: 00852107 flw ft2,8(a0) +80000208: 00c52683 lw a3,12(a0) +8000020c: 001071d3 fadd.s ft3,ft0,ft1 +80000210: e0018553 fmv.x.w a0,ft3 +80000214: 001015f3 fsflags a1,zero +80000218: 00100613 li a2,1 +8000021c: 16d51c63 bne a0,a3,80000394 +80000220: 16c59a63 bne a1,a2,80000394 + +80000224 : +80000224: 00500193 li gp,5 +80000228: 00002517 auipc a0,0x2 +8000022c: e0850513 addi a0,a0,-504 # 80002030 +80000230: 00052007 flw ft0,0(a0) +80000234: 00452087 flw ft1,4(a0) +80000238: 00852107 flw ft2,8(a0) +8000023c: 00c52683 lw a3,12(a0) +80000240: 081071d3 fsub.s ft3,ft0,ft1 +80000244: e0018553 fmv.x.w a0,ft3 +80000248: 001015f3 fsflags a1,zero +8000024c: 00000613 li a2,0 +80000250: 14d51263 bne a0,a3,80000394 +80000254: 14c59063 bne a1,a2,80000394 + +80000258 : +80000258: 00600193 li gp,6 +8000025c: 00002517 auipc a0,0x2 +80000260: de450513 addi a0,a0,-540 # 80002040 +80000264: 00052007 flw ft0,0(a0) +80000268: 00452087 flw ft1,4(a0) +8000026c: 00852107 flw ft2,8(a0) +80000270: 00c52683 lw a3,12(a0) +80000274: 081071d3 fsub.s ft3,ft0,ft1 +80000278: e0018553 fmv.x.w a0,ft3 +8000027c: 001015f3 fsflags a1,zero +80000280: 00100613 li a2,1 +80000284: 10d51863 bne a0,a3,80000394 +80000288: 10c59663 bne a1,a2,80000394 + +8000028c : +8000028c: 00700193 li gp,7 +80000290: 00002517 auipc a0,0x2 +80000294: dc050513 addi a0,a0,-576 # 80002050 +80000298: 00052007 flw ft0,0(a0) +8000029c: 00452087 flw ft1,4(a0) +800002a0: 00852107 flw ft2,8(a0) +800002a4: 00c52683 lw a3,12(a0) +800002a8: 081071d3 fsub.s ft3,ft0,ft1 +800002ac: e0018553 fmv.x.w a0,ft3 +800002b0: 001015f3 fsflags a1,zero +800002b4: 00100613 li a2,1 +800002b8: 0cd51e63 bne a0,a3,80000394 +800002bc: 0cc59c63 bne a1,a2,80000394 + +800002c0 : +800002c0: 00800193 li gp,8 +800002c4: 00002517 auipc a0,0x2 +800002c8: d9c50513 addi a0,a0,-612 # 80002060 +800002cc: 00052007 flw ft0,0(a0) +800002d0: 00452087 flw ft1,4(a0) +800002d4: 00852107 flw ft2,8(a0) +800002d8: 00c52683 lw a3,12(a0) +800002dc: 101071d3 fmul.s ft3,ft0,ft1 +800002e0: e0018553 fmv.x.w a0,ft3 +800002e4: 001015f3 fsflags a1,zero +800002e8: 00000613 li a2,0 +800002ec: 0ad51463 bne a0,a3,80000394 +800002f0: 0ac59263 bne a1,a2,80000394 + +800002f4 : +800002f4: 00900193 li gp,9 +800002f8: 00002517 auipc a0,0x2 +800002fc: d7850513 addi a0,a0,-648 # 80002070 +80000300: 00052007 flw ft0,0(a0) +80000304: 00452087 flw ft1,4(a0) +80000308: 00852107 flw ft2,8(a0) +8000030c: 00c52683 lw a3,12(a0) +80000310: 101071d3 fmul.s ft3,ft0,ft1 +80000314: e0018553 fmv.x.w a0,ft3 +80000318: 001015f3 fsflags a1,zero +8000031c: 00100613 li a2,1 +80000320: 06d51a63 bne a0,a3,80000394 +80000324: 06c59863 bne a1,a2,80000394 + +80000328 : +80000328: 00a00193 li gp,10 +8000032c: 00002517 auipc a0,0x2 +80000330: d5450513 addi a0,a0,-684 # 80002080 +80000334: 00052007 flw ft0,0(a0) +80000338: 00452087 flw ft1,4(a0) +8000033c: 00852107 flw ft2,8(a0) +80000340: 00c52683 lw a3,12(a0) +80000344: 101071d3 fmul.s ft3,ft0,ft1 +80000348: e0018553 fmv.x.w a0,ft3 +8000034c: 001015f3 fsflags a1,zero +80000350: 00100613 li a2,1 +80000354: 04d51063 bne a0,a3,80000394 +80000358: 02c59e63 bne a1,a2,80000394 + +8000035c : +8000035c: 00b00193 li gp,11 +80000360: 00002517 auipc a0,0x2 +80000364: d3050513 addi a0,a0,-720 # 80002090 +80000368: 00052007 flw ft0,0(a0) +8000036c: 00452087 flw ft1,4(a0) +80000370: 00852107 flw ft2,8(a0) +80000374: 00c52683 lw a3,12(a0) +80000378: 081071d3 fsub.s ft3,ft0,ft1 +8000037c: e0018553 fmv.x.w a0,ft3 +80000380: 001015f3 fsflags a1,zero +80000384: 01000613 li a2,16 +80000388: 00d51663 bne a0,a3,80000394 +8000038c: 00c59463 bne a1,a2,80000394 +80000390: 02301063 bne zero,gp,800003b0 + +80000394 : +80000394: 0ff0000f fence +80000398: 00018063 beqz gp,80000398 +8000039c: 00119193 slli gp,gp,0x1 +800003a0: 0011e193 ori gp,gp,1 +800003a4: 05d00893 li a7,93 +800003a8: 00018513 mv a0,gp +800003ac: 00000073 ecall + +800003b0 : +800003b0: 0ff0000f fence +800003b4: 00100193 li gp,1 +800003b8: 05d00893 li a7,93 +800003bc: 00000513 li a0,0 +800003c0: 00000073 ecall +800003c4: c0001073 unimp +800003c8: 0000 unimp +800003ca: 0000 unimp +800003cc: 0000 unimp +800003ce: 0000 unimp +800003d0: 0000 unimp +800003d2: 0000 unimp +800003d4: 0000 unimp +800003d6: 0000 unimp +800003d8: 0000 unimp +800003da: 0000 unimp +800003dc: 0000 unimp +800003de: 0000 unimp +800003e0: 0000 unimp +800003e2: 0000 unimp +800003e4: 0000 unimp +800003e6: 0000 unimp +800003e8: 0000 unimp +800003ea: 0000 unimp +800003ec: 0000 unimp +800003ee: 0000 unimp +800003f0: 0000 unimp +800003f2: 0000 unimp +800003f4: 0000 unimp +800003f6: 0000 unimp +800003f8: 0000 unimp +800003fa: 0000 unimp +800003fc: 0000 unimp +800003fe: 0000 unimp +80000400: 0000 unimp +80000402: 0000 unimp + +Disassembly of section .data: + +80002000 : +80002000: 0000 unimp +80002002: 4020 lw s0,64(s0) +80002004: 0000 unimp +80002006: 3f80 fld fs0,56(a5) +80002008: 0000 unimp +8000200a: 0000 unimp +8000200c: 0000 unimp +8000200e: 4060 lw s0,68(s0) + +80002010 : +80002010: c49a6333 0xc49a6333 +80002014: cccd beqz s1,800020ce <_end+0x2e> +80002016: 3f8c fld fa1,56(a5) +80002018: 0000 unimp +8000201a: 0000 unimp +8000201c: 4000 lw s0,0(s0) +8000201e: c49a sw t1,72(sp) + +80002020 : +80002020: 40490fdb 0x40490fdb +80002024: 322bcc77 0x322bcc77 +80002028: 0000 unimp +8000202a: 0000 unimp +8000202c: 40490fdb 0x40490fdb + +80002030 : +80002030: 0000 unimp +80002032: 4020 lw s0,64(s0) +80002034: 0000 unimp +80002036: 3f80 fld fs0,56(a5) +80002038: 0000 unimp +8000203a: 0000 unimp +8000203c: 0000 unimp +8000203e: 3fc0 fld fs0,184(a5) + +80002040 : +80002040: c49a6333 0xc49a6333 +80002044: cccd beqz s1,800020fe <_end+0x5e> +80002046: bf8c fsd fa1,56(a5) +80002048: 0000 unimp +8000204a: 0000 unimp +8000204c: 4000 lw s0,0(s0) +8000204e: c49a sw t1,72(sp) + +80002050 : +80002050: 40490fdb 0x40490fdb +80002054: 322bcc77 0x322bcc77 +80002058: 0000 unimp +8000205a: 0000 unimp +8000205c: 40490fdb 0x40490fdb + +80002060 : +80002060: 0000 unimp +80002062: 4020 lw s0,64(s0) +80002064: 0000 unimp +80002066: 3f80 fld fs0,56(a5) +80002068: 0000 unimp +8000206a: 0000 unimp +8000206c: 0000 unimp +8000206e: 4020 lw s0,64(s0) + +80002070 : +80002070: c49a6333 0xc49a6333 +80002074: cccd beqz s1,8000212e <_end+0x8e> +80002076: bf8c fsd fa1,56(a5) +80002078: 0000 unimp +8000207a: 0000 unimp +8000207c: d385 beqz a5,80001f9c +8000207e: 44a9 li s1,10 + +80002080 : +80002080: 40490fdb 0x40490fdb +80002084: 322bcc77 0x322bcc77 +80002088: 0000 unimp +8000208a: 0000 unimp +8000208c: ee2d bnez a2,80002106 <_end+0x66> +8000208e: 3306 fld ft6,96(sp) + +80002090 : +80002090: 0000 unimp +80002092: 7f80 flw fs0,56(a5) +80002094: 0000 unimp +80002096: 7f80 flw fs0,56(a5) +80002098: 0000 unimp +8000209a: 0000 unimp +8000209c: 0000 unimp +8000209e: 7fc0 flw fs0,60(a5) diff --git a/src/test/resources/asm/rv32uf-p-fclass.dump b/src/test/resources/asm/rv32uf-p-fclass.dump new file mode 100644 index 00000000..38e82863 --- /dev/null +++ b/src/test/resources/asm/rv32uf-p-fclass.dump @@ -0,0 +1,218 @@ + +rv32uf-p-fclass: file format elf32-littleriscv + + +Disassembly of section .text.init: + +80000000 <_start>: +80000000: 04c0006f j 8000004c + +80000004 : +80000004: 34202f73 csrr t5,mcause +80000008: 00800f93 li t6,8 +8000000c: 03ff0a63 beq t5,t6,80000040 +80000010: 00900f93 li t6,9 +80000014: 03ff0663 beq t5,t6,80000040 +80000018: 00b00f93 li t6,11 +8000001c: 03ff0263 beq t5,t6,80000040 +80000020: 80000f17 auipc t5,0x80000 +80000024: fe0f0f13 addi t5,t5,-32 # 0 <_start-0x80000000> +80000028: 000f0463 beqz t5,80000030 +8000002c: 000f0067 jr t5 +80000030: 34202f73 csrr t5,mcause +80000034: 000f5463 bgez t5,8000003c +80000038: 0040006f j 8000003c + +8000003c : +8000003c: 5391e193 ori gp,gp,1337 + +80000040 : +80000040: 00001f17 auipc t5,0x1 +80000044: fc3f2023 sw gp,-64(t5) # 80001000 +80000048: ff9ff06f j 80000040 + +8000004c : +8000004c: 00000093 li ra,0 +80000050: 00000113 li sp,0 +80000054: 00000193 li gp,0 +80000058: 00000213 li tp,0 +8000005c: 00000293 li t0,0 +80000060: 00000313 li t1,0 +80000064: 00000393 li t2,0 +80000068: 00000413 li s0,0 +8000006c: 00000493 li s1,0 +80000070: 00000513 li a0,0 +80000074: 00000593 li a1,0 +80000078: 00000613 li a2,0 +8000007c: 00000693 li a3,0 +80000080: 00000713 li a4,0 +80000084: 00000793 li a5,0 +80000088: 00000813 li a6,0 +8000008c: 00000893 li a7,0 +80000090: 00000913 li s2,0 +80000094: 00000993 li s3,0 +80000098: 00000a13 li s4,0 +8000009c: 00000a93 li s5,0 +800000a0: 00000b13 li s6,0 +800000a4: 00000b93 li s7,0 +800000a8: 00000c13 li s8,0 +800000ac: 00000c93 li s9,0 +800000b0: 00000d13 li s10,0 +800000b4: 00000d93 li s11,0 +800000b8: 00000e13 li t3,0 +800000bc: 00000e93 li t4,0 +800000c0: 00000f13 li t5,0 +800000c4: 00000f93 li t6,0 +800000c8: f1402573 csrr a0,mhartid +800000cc: 00051063 bnez a0,800000cc +800000d0: 00000297 auipc t0,0x0 +800000d4: 01028293 addi t0,t0,16 # 800000e0 +800000d8: 30529073 csrw mtvec,t0 +800000dc: 18005073 csrwi satp,0 +800000e0: 00000297 auipc t0,0x0 +800000e4: 02028293 addi t0,t0,32 # 80000100 +800000e8: 30529073 csrw mtvec,t0 +800000ec: 800002b7 lui t0,0x80000 +800000f0: fff28293 addi t0,t0,-1 # 7fffffff <_end+0xffffdfff> +800000f4: 3b029073 csrw pmpaddr0,t0 +800000f8: 01f00293 li t0,31 +800000fc: 3a029073 csrw pmpcfg0,t0 +80000100: 30405073 csrwi mie,0 +80000104: 00000297 auipc t0,0x0 +80000108: 01428293 addi t0,t0,20 # 80000118 +8000010c: 30529073 csrw mtvec,t0 +80000110: 30205073 csrwi medeleg,0 +80000114: 30305073 csrwi mideleg,0 +80000118: 00000193 li gp,0 +8000011c: 00000297 auipc t0,0x0 +80000120: ee828293 addi t0,t0,-280 # 80000004 +80000124: 30529073 csrw mtvec,t0 +80000128: 00100513 li a0,1 +8000012c: 01f51513 slli a0,a0,0x1f +80000130: 00054c63 bltz a0,80000148 +80000134: 0ff0000f fence +80000138: 00100193 li gp,1 +8000013c: 05d00893 li a7,93 +80000140: 00000513 li a0,0 +80000144: 00000073 ecall +80000148: 80000297 auipc t0,0x80000 +8000014c: eb828293 addi t0,t0,-328 # 0 <_start-0x80000000> +80000150: 00028a63 beqz t0,80000164 +80000154: 10529073 csrw stvec,t0 +80000158: 0000b2b7 lui t0,0xb +8000015c: 10928293 addi t0,t0,265 # b109 <_start-0x7fff4ef7> +80000160: 30229073 csrw medeleg,t0 +80000164: 30005073 csrwi mstatus,0 +80000168: 00002537 lui a0,0x2 +8000016c: 30052073 csrs mstatus,a0 +80000170: 00305073 csrwi fcsr,0 +80000174: 00000297 auipc t0,0x0 +80000178: 01428293 addi t0,t0,20 # 80000188 +8000017c: 34129073 csrw mepc,t0 +80000180: f1402573 csrr a0,mhartid +80000184: 30200073 mret + +80000188 : +80000188: ff800537 lui a0,0xff800 +8000018c: f0050553 fmv.w.x fa0,a0 +80000190: e0051553 fclass.s a0,fa0 +80000194: 00100393 li t2,1 +80000198: 00200193 li gp,2 +8000019c: 0e751663 bne a0,t2,80000288 + +800001a0 : +800001a0: bf800537 lui a0,0xbf800 +800001a4: f0050553 fmv.w.x fa0,a0 +800001a8: e0051553 fclass.s a0,fa0 +800001ac: 00200393 li t2,2 +800001b0: 00300193 li gp,3 +800001b4: 0c751a63 bne a0,t2,80000288 + +800001b8 : +800001b8: 80800537 lui a0,0x80800 +800001bc: fff50513 addi a0,a0,-1 # 807fffff <_end+0x7fdfff> +800001c0: f0050553 fmv.w.x fa0,a0 +800001c4: e0051553 fclass.s a0,fa0 +800001c8: 00400393 li t2,4 +800001cc: 00400193 li gp,4 +800001d0: 0a751c63 bne a0,t2,80000288 + +800001d4 : +800001d4: 80000537 lui a0,0x80000 +800001d8: f0050553 fmv.w.x fa0,a0 +800001dc: e0051553 fclass.s a0,fa0 +800001e0: 00800393 li t2,8 +800001e4: 00500193 li gp,5 +800001e8: 0a751063 bne a0,t2,80000288 + +800001ec : +800001ec: 00000513 li a0,0 +800001f0: f0050553 fmv.w.x fa0,a0 +800001f4: e0051553 fclass.s a0,fa0 +800001f8: 01000393 li t2,16 +800001fc: 00600193 li gp,6 +80000200: 08751463 bne a0,t2,80000288 + +80000204 : +80000204: 00800537 lui a0,0x800 +80000208: fff50513 addi a0,a0,-1 # 7fffff <_start-0x7f800001> +8000020c: f0050553 fmv.w.x fa0,a0 +80000210: e0051553 fclass.s a0,fa0 +80000214: 02000393 li t2,32 +80000218: 00700193 li gp,7 +8000021c: 06751663 bne a0,t2,80000288 + +80000220 : +80000220: 3f800537 lui a0,0x3f800 +80000224: f0050553 fmv.w.x fa0,a0 +80000228: e0051553 fclass.s a0,fa0 +8000022c: 04000393 li t2,64 +80000230: 00800193 li gp,8 +80000234: 04751a63 bne a0,t2,80000288 + +80000238 : +80000238: 7f800537 lui a0,0x7f800 +8000023c: f0050553 fmv.w.x fa0,a0 +80000240: e0051553 fclass.s a0,fa0 +80000244: 08000393 li t2,128 +80000248: 00900193 li gp,9 +8000024c: 02751e63 bne a0,t2,80000288 + +80000250 : +80000250: 7f800537 lui a0,0x7f800 +80000254: 00150513 addi a0,a0,1 # 7f800001 <_start-0x7fffff> +80000258: f0050553 fmv.w.x fa0,a0 +8000025c: e0051553 fclass.s a0,fa0 +80000260: 10000393 li t2,256 +80000264: 00a00193 li gp,10 +80000268: 02751063 bne a0,t2,80000288 + +8000026c : +8000026c: 7fc00537 lui a0,0x7fc00 +80000270: f0050553 fmv.w.x fa0,a0 +80000274: e0051553 fclass.s a0,fa0 +80000278: 20000393 li t2,512 +8000027c: 00b00193 li gp,11 +80000280: 00751463 bne a0,t2,80000288 +80000284: 02301063 bne zero,gp,800002a4 + +80000288 : +80000288: 0ff0000f fence +8000028c: 00018063 beqz gp,8000028c +80000290: 00119193 slli gp,gp,0x1 +80000294: 0011e193 ori gp,gp,1 +80000298: 05d00893 li a7,93 +8000029c: 00018513 mv a0,gp +800002a0: 00000073 ecall + +800002a4 : +800002a4: 0ff0000f fence +800002a8: 00100193 li gp,1 +800002ac: 05d00893 li a7,93 +800002b0: 00000513 li a0,0 +800002b4: 00000073 ecall +800002b8: c0001073 unimp +800002bc: 0000 unimp +800002be: 0000 unimp +800002c0: 0000 unimp +800002c2: 0000 unimp diff --git a/src/test/resources/asm/rv32uf-p-fcmp.dump b/src/test/resources/asm/rv32uf-p-fcmp.dump new file mode 100644 index 00000000..50d75246 --- /dev/null +++ b/src/test/resources/asm/rv32uf-p-fcmp.dump @@ -0,0 +1,510 @@ + +rv32uf-p-fcmp: file format elf32-littleriscv + + +Disassembly of section .text.init: + +80000000 <_start>: +80000000: 04c0006f j 8000004c + +80000004 : +80000004: 34202f73 csrr t5,mcause +80000008: 00800f93 li t6,8 +8000000c: 03ff0a63 beq t5,t6,80000040 +80000010: 00900f93 li t6,9 +80000014: 03ff0663 beq t5,t6,80000040 +80000018: 00b00f93 li t6,11 +8000001c: 03ff0263 beq t5,t6,80000040 +80000020: 80000f17 auipc t5,0x80000 +80000024: fe0f0f13 addi t5,t5,-32 # 0 <_start-0x80000000> +80000028: 000f0463 beqz t5,80000030 +8000002c: 000f0067 jr t5 +80000030: 34202f73 csrr t5,mcause +80000034: 000f5463 bgez t5,8000003c +80000038: 0040006f j 8000003c + +8000003c : +8000003c: 5391e193 ori gp,gp,1337 + +80000040 : +80000040: 00001f17 auipc t5,0x1 +80000044: fc3f2023 sw gp,-64(t5) # 80001000 +80000048: ff9ff06f j 80000040 + +8000004c : +8000004c: 00000093 li ra,0 +80000050: 00000113 li sp,0 +80000054: 00000193 li gp,0 +80000058: 00000213 li tp,0 +8000005c: 00000293 li t0,0 +80000060: 00000313 li t1,0 +80000064: 00000393 li t2,0 +80000068: 00000413 li s0,0 +8000006c: 00000493 li s1,0 +80000070: 00000513 li a0,0 +80000074: 00000593 li a1,0 +80000078: 00000613 li a2,0 +8000007c: 00000693 li a3,0 +80000080: 00000713 li a4,0 +80000084: 00000793 li a5,0 +80000088: 00000813 li a6,0 +8000008c: 00000893 li a7,0 +80000090: 00000913 li s2,0 +80000094: 00000993 li s3,0 +80000098: 00000a13 li s4,0 +8000009c: 00000a93 li s5,0 +800000a0: 00000b13 li s6,0 +800000a4: 00000b93 li s7,0 +800000a8: 00000c13 li s8,0 +800000ac: 00000c93 li s9,0 +800000b0: 00000d13 li s10,0 +800000b4: 00000d93 li s11,0 +800000b8: 00000e13 li t3,0 +800000bc: 00000e93 li t4,0 +800000c0: 00000f13 li t5,0 +800000c4: 00000f93 li t6,0 +800000c8: f1402573 csrr a0,mhartid +800000cc: 00051063 bnez a0,800000cc +800000d0: 00000297 auipc t0,0x0 +800000d4: 01028293 addi t0,t0,16 # 800000e0 +800000d8: 30529073 csrw mtvec,t0 +800000dc: 18005073 csrwi satp,0 +800000e0: 00000297 auipc t0,0x0 +800000e4: 02028293 addi t0,t0,32 # 80000100 +800000e8: 30529073 csrw mtvec,t0 +800000ec: 800002b7 lui t0,0x80000 +800000f0: fff28293 addi t0,t0,-1 # 7fffffff <_end+0xffffdf0f> +800000f4: 3b029073 csrw pmpaddr0,t0 +800000f8: 01f00293 li t0,31 +800000fc: 3a029073 csrw pmpcfg0,t0 +80000100: 30405073 csrwi mie,0 +80000104: 00000297 auipc t0,0x0 +80000108: 01428293 addi t0,t0,20 # 80000118 +8000010c: 30529073 csrw mtvec,t0 +80000110: 30205073 csrwi medeleg,0 +80000114: 30305073 csrwi mideleg,0 +80000118: 00000193 li gp,0 +8000011c: 00000297 auipc t0,0x0 +80000120: ee828293 addi t0,t0,-280 # 80000004 +80000124: 30529073 csrw mtvec,t0 +80000128: 00100513 li a0,1 +8000012c: 01f51513 slli a0,a0,0x1f +80000130: 00054c63 bltz a0,80000148 +80000134: 0ff0000f fence +80000138: 00100193 li gp,1 +8000013c: 05d00893 li a7,93 +80000140: 00000513 li a0,0 +80000144: 00000073 ecall +80000148: 80000297 auipc t0,0x80000 +8000014c: eb828293 addi t0,t0,-328 # 0 <_start-0x80000000> +80000150: 00028a63 beqz t0,80000164 +80000154: 10529073 csrw stvec,t0 +80000158: 0000b2b7 lui t0,0xb +8000015c: 10928293 addi t0,t0,265 # b109 <_start-0x7fff4ef7> +80000160: 30229073 csrw medeleg,t0 +80000164: 30005073 csrwi mstatus,0 +80000168: 00002537 lui a0,0x2 +8000016c: 30052073 csrs mstatus,a0 +80000170: 00305073 csrwi fcsr,0 +80000174: 00000297 auipc t0,0x0 +80000178: 01428293 addi t0,t0,20 # 80000188 +8000017c: 34129073 csrw mepc,t0 +80000180: f1402573 csrr a0,mhartid +80000184: 30200073 mret + +80000188 : +80000188: 00200193 li gp,2 +8000018c: 00002517 auipc a0,0x2 +80000190: e7450513 addi a0,a0,-396 # 80002000 +80000194: 00052007 flw ft0,0(a0) +80000198: 00452087 flw ft1,4(a0) +8000019c: 00852107 flw ft2,8(a0) +800001a0: 00c52683 lw a3,12(a0) +800001a4: a0102553 feq.s a0,ft0,ft1 +800001a8: 001015f3 fsflags a1,zero +800001ac: 00000613 li a2,0 +800001b0: 2ad51663 bne a0,a3,8000045c +800001b4: 2ac59463 bne a1,a2,8000045c + +800001b8 : +800001b8: 00300193 li gp,3 +800001bc: 00002517 auipc a0,0x2 +800001c0: e5450513 addi a0,a0,-428 # 80002010 +800001c4: 00052007 flw ft0,0(a0) +800001c8: 00452087 flw ft1,4(a0) +800001cc: 00852107 flw ft2,8(a0) +800001d0: 00c52683 lw a3,12(a0) +800001d4: a0100553 fle.s a0,ft0,ft1 +800001d8: 001015f3 fsflags a1,zero +800001dc: 00000613 li a2,0 +800001e0: 26d51e63 bne a0,a3,8000045c +800001e4: 26c59c63 bne a1,a2,8000045c + +800001e8 : +800001e8: 00400193 li gp,4 +800001ec: 00002517 auipc a0,0x2 +800001f0: e3450513 addi a0,a0,-460 # 80002020 +800001f4: 00052007 flw ft0,0(a0) +800001f8: 00452087 flw ft1,4(a0) +800001fc: 00852107 flw ft2,8(a0) +80000200: 00c52683 lw a3,12(a0) +80000204: a0101553 flt.s a0,ft0,ft1 +80000208: 001015f3 fsflags a1,zero +8000020c: 00000613 li a2,0 +80000210: 24d51663 bne a0,a3,8000045c +80000214: 24c59463 bne a1,a2,8000045c + +80000218 : +80000218: 00500193 li gp,5 +8000021c: 00002517 auipc a0,0x2 +80000220: e1450513 addi a0,a0,-492 # 80002030 +80000224: 00052007 flw ft0,0(a0) +80000228: 00452087 flw ft1,4(a0) +8000022c: 00852107 flw ft2,8(a0) +80000230: 00c52683 lw a3,12(a0) +80000234: a0102553 feq.s a0,ft0,ft1 +80000238: 001015f3 fsflags a1,zero +8000023c: 00000613 li a2,0 +80000240: 20d51e63 bne a0,a3,8000045c +80000244: 20c59c63 bne a1,a2,8000045c + +80000248 : +80000248: 00600193 li gp,6 +8000024c: 00002517 auipc a0,0x2 +80000250: df450513 addi a0,a0,-524 # 80002040 +80000254: 00052007 flw ft0,0(a0) +80000258: 00452087 flw ft1,4(a0) +8000025c: 00852107 flw ft2,8(a0) +80000260: 00c52683 lw a3,12(a0) +80000264: a0100553 fle.s a0,ft0,ft1 +80000268: 001015f3 fsflags a1,zero +8000026c: 00000613 li a2,0 +80000270: 1ed51663 bne a0,a3,8000045c +80000274: 1ec59463 bne a1,a2,8000045c + +80000278 : +80000278: 00700193 li gp,7 +8000027c: 00002517 auipc a0,0x2 +80000280: dd450513 addi a0,a0,-556 # 80002050 +80000284: 00052007 flw ft0,0(a0) +80000288: 00452087 flw ft1,4(a0) +8000028c: 00852107 flw ft2,8(a0) +80000290: 00c52683 lw a3,12(a0) +80000294: a0101553 flt.s a0,ft0,ft1 +80000298: 001015f3 fsflags a1,zero +8000029c: 00000613 li a2,0 +800002a0: 1ad51e63 bne a0,a3,8000045c +800002a4: 1ac59c63 bne a1,a2,8000045c + +800002a8 : +800002a8: 00800193 li gp,8 +800002ac: 00002517 auipc a0,0x2 +800002b0: db450513 addi a0,a0,-588 # 80002060 +800002b4: 00052007 flw ft0,0(a0) +800002b8: 00452087 flw ft1,4(a0) +800002bc: 00852107 flw ft2,8(a0) +800002c0: 00c52683 lw a3,12(a0) +800002c4: a0102553 feq.s a0,ft0,ft1 +800002c8: 001015f3 fsflags a1,zero +800002cc: 00000613 li a2,0 +800002d0: 18d51663 bne a0,a3,8000045c +800002d4: 18c59463 bne a1,a2,8000045c + +800002d8 : +800002d8: 00900193 li gp,9 +800002dc: 00002517 auipc a0,0x2 +800002e0: d9450513 addi a0,a0,-620 # 80002070 +800002e4: 00052007 flw ft0,0(a0) +800002e8: 00452087 flw ft1,4(a0) +800002ec: 00852107 flw ft2,8(a0) +800002f0: 00c52683 lw a3,12(a0) +800002f4: a0102553 feq.s a0,ft0,ft1 +800002f8: 001015f3 fsflags a1,zero +800002fc: 00000613 li a2,0 +80000300: 14d51e63 bne a0,a3,8000045c +80000304: 14c59c63 bne a1,a2,8000045c + +80000308 : +80000308: 00a00193 li gp,10 +8000030c: 00002517 auipc a0,0x2 +80000310: d7450513 addi a0,a0,-652 # 80002080 +80000314: 00052007 flw ft0,0(a0) +80000318: 00452087 flw ft1,4(a0) +8000031c: 00852107 flw ft2,8(a0) +80000320: 00c52683 lw a3,12(a0) +80000324: a0102553 feq.s a0,ft0,ft1 +80000328: 001015f3 fsflags a1,zero +8000032c: 01000613 li a2,16 +80000330: 12d51663 bne a0,a3,8000045c +80000334: 12c59463 bne a1,a2,8000045c + +80000338 : +80000338: 00b00193 li gp,11 +8000033c: 00002517 auipc a0,0x2 +80000340: d5450513 addi a0,a0,-684 # 80002090 +80000344: 00052007 flw ft0,0(a0) +80000348: 00452087 flw ft1,4(a0) +8000034c: 00852107 flw ft2,8(a0) +80000350: 00c52683 lw a3,12(a0) +80000354: a0101553 flt.s a0,ft0,ft1 +80000358: 001015f3 fsflags a1,zero +8000035c: 01000613 li a2,16 +80000360: 0ed51e63 bne a0,a3,8000045c +80000364: 0ec59c63 bne a1,a2,8000045c + +80000368 : +80000368: 00c00193 li gp,12 +8000036c: 00002517 auipc a0,0x2 +80000370: d3450513 addi a0,a0,-716 # 800020a0 +80000374: 00052007 flw ft0,0(a0) +80000378: 00452087 flw ft1,4(a0) +8000037c: 00852107 flw ft2,8(a0) +80000380: 00c52683 lw a3,12(a0) +80000384: a0101553 flt.s a0,ft0,ft1 +80000388: 001015f3 fsflags a1,zero +8000038c: 01000613 li a2,16 +80000390: 0cd51663 bne a0,a3,8000045c +80000394: 0cc59463 bne a1,a2,8000045c + +80000398 : +80000398: 00d00193 li gp,13 +8000039c: 00002517 auipc a0,0x2 +800003a0: d1450513 addi a0,a0,-748 # 800020b0 +800003a4: 00052007 flw ft0,0(a0) +800003a8: 00452087 flw ft1,4(a0) +800003ac: 00852107 flw ft2,8(a0) +800003b0: 00c52683 lw a3,12(a0) +800003b4: a0101553 flt.s a0,ft0,ft1 +800003b8: 001015f3 fsflags a1,zero +800003bc: 01000613 li a2,16 +800003c0: 08d51e63 bne a0,a3,8000045c +800003c4: 08c59c63 bne a1,a2,8000045c + +800003c8 : +800003c8: 00e00193 li gp,14 +800003cc: 00002517 auipc a0,0x2 +800003d0: cf450513 addi a0,a0,-780 # 800020c0 +800003d4: 00052007 flw ft0,0(a0) +800003d8: 00452087 flw ft1,4(a0) +800003dc: 00852107 flw ft2,8(a0) +800003e0: 00c52683 lw a3,12(a0) +800003e4: a0100553 fle.s a0,ft0,ft1 +800003e8: 001015f3 fsflags a1,zero +800003ec: 01000613 li a2,16 +800003f0: 06d51663 bne a0,a3,8000045c +800003f4: 06c59463 bne a1,a2,8000045c + +800003f8 : +800003f8: 00f00193 li gp,15 +800003fc: 00002517 auipc a0,0x2 +80000400: cd450513 addi a0,a0,-812 # 800020d0 +80000404: 00052007 flw ft0,0(a0) +80000408: 00452087 flw ft1,4(a0) +8000040c: 00852107 flw ft2,8(a0) +80000410: 00c52683 lw a3,12(a0) +80000414: a0100553 fle.s a0,ft0,ft1 +80000418: 001015f3 fsflags a1,zero +8000041c: 01000613 li a2,16 +80000420: 02d51e63 bne a0,a3,8000045c +80000424: 02c59c63 bne a1,a2,8000045c + +80000428 : +80000428: 01000193 li gp,16 +8000042c: 00002517 auipc a0,0x2 +80000430: cb450513 addi a0,a0,-844 # 800020e0 +80000434: 00052007 flw ft0,0(a0) +80000438: 00452087 flw ft1,4(a0) +8000043c: 00852107 flw ft2,8(a0) +80000440: 00c52683 lw a3,12(a0) +80000444: a0100553 fle.s a0,ft0,ft1 +80000448: 001015f3 fsflags a1,zero +8000044c: 01000613 li a2,16 +80000450: 00d51663 bne a0,a3,8000045c +80000454: 00c59463 bne a1,a2,8000045c +80000458: 02301063 bne zero,gp,80000478 + +8000045c : +8000045c: 0ff0000f fence +80000460: 00018063 beqz gp,80000460 +80000464: 00119193 slli gp,gp,0x1 +80000468: 0011e193 ori gp,gp,1 +8000046c: 05d00893 li a7,93 +80000470: 00018513 mv a0,gp +80000474: 00000073 ecall + +80000478 : +80000478: 0ff0000f fence +8000047c: 00100193 li gp,1 +80000480: 05d00893 li a7,93 +80000484: 00000513 li a0,0 +80000488: 00000073 ecall +8000048c: c0001073 unimp +80000490: 0000 unimp +80000492: 0000 unimp +80000494: 0000 unimp +80000496: 0000 unimp +80000498: 0000 unimp +8000049a: 0000 unimp +8000049c: 0000 unimp +8000049e: 0000 unimp +800004a0: 0000 unimp +800004a2: 0000 unimp +800004a4: 0000 unimp +800004a6: 0000 unimp +800004a8: 0000 unimp +800004aa: 0000 unimp +800004ac: 0000 unimp +800004ae: 0000 unimp +800004b0: 0000 unimp +800004b2: 0000 unimp +800004b4: 0000 unimp +800004b6: 0000 unimp +800004b8: 0000 unimp +800004ba: 0000 unimp +800004bc: 0000 unimp +800004be: 0000 unimp +800004c0: 0000 unimp +800004c2: 0000 unimp + +Disassembly of section .data: + +80002000 : +80002000: bfae147b 0xbfae147b +80002004: bfae147b 0xbfae147b +80002008: 0000 unimp +8000200a: 0000 unimp +8000200c: 0001 nop +8000200e: 0000 unimp + +80002010 : +80002010: bfae147b 0xbfae147b +80002014: bfae147b 0xbfae147b +80002018: 0000 unimp +8000201a: 0000 unimp +8000201c: 0001 nop +8000201e: 0000 unimp + +80002020 : +80002020: bfae147b 0xbfae147b +80002024: bfae147b 0xbfae147b +80002028: 0000 unimp +8000202a: 0000 unimp +8000202c: 0000 unimp +8000202e: 0000 unimp + +80002030 : +80002030: 5c29 li s8,-22 +80002032: 147bbfaf 0x147bbfaf +80002036: bfae fsd fa1,504(sp) +80002038: 0000 unimp +8000203a: 0000 unimp +8000203c: 0000 unimp +8000203e: 0000 unimp + +80002040 : +80002040: 5c29 li s8,-22 +80002042: 147bbfaf 0x147bbfaf +80002046: bfae fsd fa1,504(sp) +80002048: 0000 unimp +8000204a: 0000 unimp +8000204c: 0001 nop +8000204e: 0000 unimp + +80002050 : +80002050: 5c29 li s8,-22 +80002052: 147bbfaf 0x147bbfaf +80002056: bfae fsd fa1,504(sp) +80002058: 0000 unimp +8000205a: 0000 unimp +8000205c: 0001 nop +8000205e: 0000 unimp + +80002060 : +80002060: ffff 0xffff +80002062: 7fff 0x7fff +80002064: 0000 unimp +80002066: 0000 unimp +80002068: 0000 unimp +8000206a: 0000 unimp +8000206c: 0000 unimp +8000206e: 0000 unimp + +80002070 : +80002070: ffff 0xffff +80002072: 7fff 0x7fff +80002074: ffff 0xffff +80002076: 7fff 0x7fff +80002078: 0000 unimp +8000207a: 0000 unimp +8000207c: 0000 unimp +8000207e: 0000 unimp + +80002080 : +80002080: 0001 nop +80002082: 7f80 flw fs0,56(a5) +80002084: 0000 unimp +80002086: 0000 unimp +80002088: 0000 unimp +8000208a: 0000 unimp +8000208c: 0000 unimp +8000208e: 0000 unimp + +80002090 : +80002090: ffff 0xffff +80002092: 7fff 0x7fff +80002094: 0000 unimp +80002096: 0000 unimp +80002098: 0000 unimp +8000209a: 0000 unimp +8000209c: 0000 unimp +8000209e: 0000 unimp + +800020a0 : +800020a0: ffff 0xffff +800020a2: 7fff 0x7fff +800020a4: ffff 0xffff +800020a6: 7fff 0x7fff +800020a8: 0000 unimp +800020aa: 0000 unimp +800020ac: 0000 unimp +800020ae: 0000 unimp + +800020b0 : +800020b0: 0001 nop +800020b2: 7f80 flw fs0,56(a5) +800020b4: 0000 unimp +800020b6: 0000 unimp +800020b8: 0000 unimp +800020ba: 0000 unimp +800020bc: 0000 unimp +800020be: 0000 unimp + +800020c0 : +800020c0: ffff 0xffff +800020c2: 7fff 0x7fff +800020c4: 0000 unimp +800020c6: 0000 unimp +800020c8: 0000 unimp +800020ca: 0000 unimp +800020cc: 0000 unimp +800020ce: 0000 unimp + +800020d0 : +800020d0: ffff 0xffff +800020d2: 7fff 0x7fff +800020d4: ffff 0xffff +800020d6: 7fff 0x7fff +800020d8: 0000 unimp +800020da: 0000 unimp +800020dc: 0000 unimp +800020de: 0000 unimp + +800020e0 : +800020e0: 0001 nop +800020e2: 7f80 flw fs0,56(a5) +800020e4: 0000 unimp +800020e6: 0000 unimp +800020e8: 0000 unimp +800020ea: 0000 unimp +800020ec: 0000 unimp +800020ee: 0000 unimp diff --git a/src/test/resources/asm/rv32uf-p-fcvt.dump b/src/test/resources/asm/rv32uf-p-fcvt.dump new file mode 100644 index 00000000..2b648da8 --- /dev/null +++ b/src/test/resources/asm/rv32uf-p-fcvt.dump @@ -0,0 +1,219 @@ + +rv32uf-p-fcvt: file format elf32-littleriscv + + +Disassembly of section .text.init: + +80000000 <_start>: +80000000: 04c0006f j 8000004c + +80000004 : +80000004: 34202f73 csrr t5,mcause +80000008: 00800f93 li t6,8 +8000000c: 03ff0a63 beq t5,t6,80000040 +80000010: 00900f93 li t6,9 +80000014: 03ff0663 beq t5,t6,80000040 +80000018: 00b00f93 li t6,11 +8000001c: 03ff0263 beq t5,t6,80000040 +80000020: 80000f17 auipc t5,0x80000 +80000024: fe0f0f13 addi t5,t5,-32 # 0 <_start-0x80000000> +80000028: 000f0463 beqz t5,80000030 +8000002c: 000f0067 jr t5 +80000030: 34202f73 csrr t5,mcause +80000034: 000f5463 bgez t5,8000003c +80000038: 0040006f j 8000003c + +8000003c : +8000003c: 5391e193 ori gp,gp,1337 + +80000040 : +80000040: 00001f17 auipc t5,0x1 +80000044: fc3f2023 sw gp,-64(t5) # 80001000 +80000048: ff9ff06f j 80000040 + +8000004c : +8000004c: 00000093 li ra,0 +80000050: 00000113 li sp,0 +80000054: 00000193 li gp,0 +80000058: 00000213 li tp,0 +8000005c: 00000293 li t0,0 +80000060: 00000313 li t1,0 +80000064: 00000393 li t2,0 +80000068: 00000413 li s0,0 +8000006c: 00000493 li s1,0 +80000070: 00000513 li a0,0 +80000074: 00000593 li a1,0 +80000078: 00000613 li a2,0 +8000007c: 00000693 li a3,0 +80000080: 00000713 li a4,0 +80000084: 00000793 li a5,0 +80000088: 00000813 li a6,0 +8000008c: 00000893 li a7,0 +80000090: 00000913 li s2,0 +80000094: 00000993 li s3,0 +80000098: 00000a13 li s4,0 +8000009c: 00000a93 li s5,0 +800000a0: 00000b13 li s6,0 +800000a4: 00000b93 li s7,0 +800000a8: 00000c13 li s8,0 +800000ac: 00000c93 li s9,0 +800000b0: 00000d13 li s10,0 +800000b4: 00000d93 li s11,0 +800000b8: 00000e13 li t3,0 +800000bc: 00000e93 li t4,0 +800000c0: 00000f13 li t5,0 +800000c4: 00000f93 li t6,0 +800000c8: f1402573 csrr a0,mhartid +800000cc: 00051063 bnez a0,800000cc +800000d0: 00000297 auipc t0,0x0 +800000d4: 01028293 addi t0,t0,16 # 800000e0 +800000d8: 30529073 csrw mtvec,t0 +800000dc: 18005073 csrwi satp,0 +800000e0: 00000297 auipc t0,0x0 +800000e4: 02028293 addi t0,t0,32 # 80000100 +800000e8: 30529073 csrw mtvec,t0 +800000ec: 800002b7 lui t0,0x80000 +800000f0: fff28293 addi t0,t0,-1 # 7fffffff <_end+0xffffdfef> +800000f4: 3b029073 csrw pmpaddr0,t0 +800000f8: 01f00293 li t0,31 +800000fc: 3a029073 csrw pmpcfg0,t0 +80000100: 30405073 csrwi mie,0 +80000104: 00000297 auipc t0,0x0 +80000108: 01428293 addi t0,t0,20 # 80000118 +8000010c: 30529073 csrw mtvec,t0 +80000110: 30205073 csrwi medeleg,0 +80000114: 30305073 csrwi mideleg,0 +80000118: 00000193 li gp,0 +8000011c: 00000297 auipc t0,0x0 +80000120: ee828293 addi t0,t0,-280 # 80000004 +80000124: 30529073 csrw mtvec,t0 +80000128: 00100513 li a0,1 +8000012c: 01f51513 slli a0,a0,0x1f +80000130: 00054c63 bltz a0,80000148 +80000134: 0ff0000f fence +80000138: 00100193 li gp,1 +8000013c: 05d00893 li a7,93 +80000140: 00000513 li a0,0 +80000144: 00000073 ecall +80000148: 80000297 auipc t0,0x80000 +8000014c: eb828293 addi t0,t0,-328 # 0 <_start-0x80000000> +80000150: 00028a63 beqz t0,80000164 +80000154: 10529073 csrw stvec,t0 +80000158: 0000b2b7 lui t0,0xb +8000015c: 10928293 addi t0,t0,265 # b109 <_start-0x7fff4ef7> +80000160: 30229073 csrw medeleg,t0 +80000164: 30005073 csrwi mstatus,0 +80000168: 00002537 lui a0,0x2 +8000016c: 30052073 csrs mstatus,a0 +80000170: 00305073 csrwi fcsr,0 +80000174: 00000297 auipc t0,0x0 +80000178: 01428293 addi t0,t0,20 # 80000188 +8000017c: 34129073 csrw mepc,t0 +80000180: f1402573 csrr a0,mhartid +80000184: 30200073 mret + +80000188 : +80000188: 00200193 li gp,2 +8000018c: 00002517 auipc a0,0x2 +80000190: e7450513 addi a0,a0,-396 # 80002000 +80000194: 00052683 lw a3,0(a0) +80000198: 00200513 li a0,2 +8000019c: d0057053 fcvt.s.w ft0,a0 +800001a0: 00101073 fsflags zero +800001a4: e0000553 fmv.x.w a0,ft0 +800001a8: 06d51a63 bne a0,a3,8000021c + +800001ac : +800001ac: 00300193 li gp,3 +800001b0: 00002517 auipc a0,0x2 +800001b4: e5450513 addi a0,a0,-428 # 80002004 +800001b8: 00052683 lw a3,0(a0) +800001bc: ffe00513 li a0,-2 +800001c0: d0057053 fcvt.s.w ft0,a0 +800001c4: 00101073 fsflags zero +800001c8: e0000553 fmv.x.w a0,ft0 +800001cc: 04d51863 bne a0,a3,8000021c + +800001d0 : +800001d0: 00400193 li gp,4 +800001d4: 00002517 auipc a0,0x2 +800001d8: e3450513 addi a0,a0,-460 # 80002008 +800001dc: 00052683 lw a3,0(a0) +800001e0: 00200513 li a0,2 +800001e4: d0157053 fcvt.s.wu ft0,a0 +800001e8: 00101073 fsflags zero +800001ec: e0000553 fmv.x.w a0,ft0 +800001f0: 02d51663 bne a0,a3,8000021c + +800001f4 : +800001f4: 00500193 li gp,5 +800001f8: 00002517 auipc a0,0x2 +800001fc: e1450513 addi a0,a0,-492 # 8000200c +80000200: 00052683 lw a3,0(a0) +80000204: ffe00513 li a0,-2 +80000208: d0157053 fcvt.s.wu ft0,a0 +8000020c: 00101073 fsflags zero +80000210: e0000553 fmv.x.w a0,ft0 +80000214: 00d51463 bne a0,a3,8000021c +80000218: 02301063 bne zero,gp,80000238 + +8000021c : +8000021c: 0ff0000f fence +80000220: 00018063 beqz gp,80000220 +80000224: 00119193 slli gp,gp,0x1 +80000228: 0011e193 ori gp,gp,1 +8000022c: 05d00893 li a7,93 +80000230: 00018513 mv a0,gp +80000234: 00000073 ecall + +80000238 : +80000238: 0ff0000f fence +8000023c: 00100193 li gp,1 +80000240: 05d00893 li a7,93 +80000244: 00000513 li a0,0 +80000248: 00000073 ecall +8000024c: c0001073 unimp +80000250: 0000 unimp +80000252: 0000 unimp +80000254: 0000 unimp +80000256: 0000 unimp +80000258: 0000 unimp +8000025a: 0000 unimp +8000025c: 0000 unimp +8000025e: 0000 unimp +80000260: 0000 unimp +80000262: 0000 unimp +80000264: 0000 unimp +80000266: 0000 unimp +80000268: 0000 unimp +8000026a: 0000 unimp +8000026c: 0000 unimp +8000026e: 0000 unimp +80000270: 0000 unimp +80000272: 0000 unimp +80000274: 0000 unimp +80000276: 0000 unimp +80000278: 0000 unimp +8000027a: 0000 unimp +8000027c: 0000 unimp +8000027e: 0000 unimp +80000280: 0000 unimp +80000282: 0000 unimp + +Disassembly of section .data: + +80002000 : +80002000: 0000 unimp +80002002: 4000 lw s0,0(s0) + +80002004 : +80002004: 0000 unimp +80002006: c000 sw s0,0(s0) + +80002008 : +80002008: 0000 unimp +8000200a: 4000 lw s0,0(s0) + +8000200c : +8000200c: 0000 unimp +8000200e: 4f80 lw s0,24(a5) diff --git a/src/test/resources/asm/rv32uf-p-fcvt_w.dump b/src/test/resources/asm/rv32uf-p-fcvt_w.dump new file mode 100644 index 00000000..48a51a35 --- /dev/null +++ b/src/test/resources/asm/rv32uf-p-fcvt_w.dump @@ -0,0 +1,632 @@ + +rv32uf-p-fcvt_w: file format elf32-littleriscv + + +Disassembly of section .text.init: + +80000000 <_start>: +80000000: 04c0006f j 8000004c + +80000004 : +80000004: 34202f73 csrr t5,mcause +80000008: 00800f93 li t6,8 +8000000c: 03ff0a63 beq t5,t6,80000040 +80000010: 00900f93 li t6,9 +80000014: 03ff0663 beq t5,t6,80000040 +80000018: 00b00f93 li t6,11 +8000001c: 03ff0263 beq t5,t6,80000040 +80000020: 80000f17 auipc t5,0x80000 +80000024: fe0f0f13 addi t5,t5,-32 # 0 <_start-0x80000000> +80000028: 000f0463 beqz t5,80000030 +8000002c: 000f0067 jr t5 +80000030: 34202f73 csrr t5,mcause +80000034: 000f5463 bgez t5,8000003c +80000038: 0040006f j 8000003c + +8000003c : +8000003c: 5391e193 ori gp,gp,1337 + +80000040 : +80000040: 00001f17 auipc t5,0x1 +80000044: fc3f2023 sw gp,-64(t5) # 80001000 +80000048: ff9ff06f j 80000040 + +8000004c : +8000004c: 00000093 li ra,0 +80000050: 00000113 li sp,0 +80000054: 00000193 li gp,0 +80000058: 00000213 li tp,0 +8000005c: 00000293 li t0,0 +80000060: 00000313 li t1,0 +80000064: 00000393 li t2,0 +80000068: 00000413 li s0,0 +8000006c: 00000493 li s1,0 +80000070: 00000513 li a0,0 +80000074: 00000593 li a1,0 +80000078: 00000613 li a2,0 +8000007c: 00000693 li a3,0 +80000080: 00000713 li a4,0 +80000084: 00000793 li a5,0 +80000088: 00000813 li a6,0 +8000008c: 00000893 li a7,0 +80000090: 00000913 li s2,0 +80000094: 00000993 li s3,0 +80000098: 00000a13 li s4,0 +8000009c: 00000a93 li s5,0 +800000a0: 00000b13 li s6,0 +800000a4: 00000b93 li s7,0 +800000a8: 00000c13 li s8,0 +800000ac: 00000c93 li s9,0 +800000b0: 00000d13 li s10,0 +800000b4: 00000d93 li s11,0 +800000b8: 00000e13 li t3,0 +800000bc: 00000e93 li t4,0 +800000c0: 00000f13 li t5,0 +800000c4: 00000f93 li t6,0 +800000c8: f1402573 csrr a0,mhartid +800000cc: 00051063 bnez a0,800000cc +800000d0: 00000297 auipc t0,0x0 +800000d4: 01028293 addi t0,t0,16 # 800000e0 +800000d8: 30529073 csrw mtvec,t0 +800000dc: 18005073 csrwi satp,0 +800000e0: 00000297 auipc t0,0x0 +800000e4: 02028293 addi t0,t0,32 # 80000100 +800000e8: 30529073 csrw mtvec,t0 +800000ec: 800002b7 lui t0,0x80000 +800000f0: fff28293 addi t0,t0,-1 # 7fffffff <_end+0xffffdecf> +800000f4: 3b029073 csrw pmpaddr0,t0 +800000f8: 01f00293 li t0,31 +800000fc: 3a029073 csrw pmpcfg0,t0 +80000100: 30405073 csrwi mie,0 +80000104: 00000297 auipc t0,0x0 +80000108: 01428293 addi t0,t0,20 # 80000118 +8000010c: 30529073 csrw mtvec,t0 +80000110: 30205073 csrwi medeleg,0 +80000114: 30305073 csrwi mideleg,0 +80000118: 00000193 li gp,0 +8000011c: 00000297 auipc t0,0x0 +80000120: ee828293 addi t0,t0,-280 # 80000004 +80000124: 30529073 csrw mtvec,t0 +80000128: 00100513 li a0,1 +8000012c: 01f51513 slli a0,a0,0x1f +80000130: 00054c63 bltz a0,80000148 +80000134: 0ff0000f fence +80000138: 00100193 li gp,1 +8000013c: 05d00893 li a7,93 +80000140: 00000513 li a0,0 +80000144: 00000073 ecall +80000148: 80000297 auipc t0,0x80000 +8000014c: eb828293 addi t0,t0,-328 # 0 <_start-0x80000000> +80000150: 00028a63 beqz t0,80000164 +80000154: 10529073 csrw stvec,t0 +80000158: 0000b2b7 lui t0,0xb +8000015c: 10928293 addi t0,t0,265 # b109 <_start-0x7fff4ef7> +80000160: 30229073 csrw medeleg,t0 +80000164: 30005073 csrwi mstatus,0 +80000168: 00002537 lui a0,0x2 +8000016c: 30052073 csrs mstatus,a0 +80000170: 00305073 csrwi fcsr,0 +80000174: 00000297 auipc t0,0x0 +80000178: 01428293 addi t0,t0,20 # 80000188 +8000017c: 34129073 csrw mepc,t0 +80000180: f1402573 csrr a0,mhartid +80000184: 30200073 mret + +80000188 : +80000188: 00200193 li gp,2 +8000018c: 00002517 auipc a0,0x2 +80000190: e7450513 addi a0,a0,-396 # 80002000 +80000194: 00052007 flw ft0,0(a0) +80000198: 00452087 flw ft1,4(a0) +8000019c: 00852107 flw ft2,8(a0) +800001a0: 00c52683 lw a3,12(a0) +800001a4: c0001553 fcvt.w.s a0,ft0,rtz +800001a8: 001015f3 fsflags a1,zero +800001ac: 00100613 li a2,1 +800001b0: 3cd51463 bne a0,a3,80000578 +800001b4: 3cc59263 bne a1,a2,80000578 + +800001b8 : +800001b8: 00300193 li gp,3 +800001bc: 00002517 auipc a0,0x2 +800001c0: e5450513 addi a0,a0,-428 # 80002010 +800001c4: 00052007 flw ft0,0(a0) +800001c8: 00452087 flw ft1,4(a0) +800001cc: 00852107 flw ft2,8(a0) +800001d0: 00c52683 lw a3,12(a0) +800001d4: c0001553 fcvt.w.s a0,ft0,rtz +800001d8: 001015f3 fsflags a1,zero +800001dc: 00000613 li a2,0 +800001e0: 38d51c63 bne a0,a3,80000578 +800001e4: 38c59a63 bne a1,a2,80000578 + +800001e8 : +800001e8: 00400193 li gp,4 +800001ec: 00002517 auipc a0,0x2 +800001f0: e3450513 addi a0,a0,-460 # 80002020 +800001f4: 00052007 flw ft0,0(a0) +800001f8: 00452087 flw ft1,4(a0) +800001fc: 00852107 flw ft2,8(a0) +80000200: 00c52683 lw a3,12(a0) +80000204: c0001553 fcvt.w.s a0,ft0,rtz +80000208: 001015f3 fsflags a1,zero +8000020c: 00100613 li a2,1 +80000210: 36d51463 bne a0,a3,80000578 +80000214: 36c59263 bne a1,a2,80000578 + +80000218 : +80000218: 00500193 li gp,5 +8000021c: 00002517 auipc a0,0x2 +80000220: e1450513 addi a0,a0,-492 # 80002030 +80000224: 00052007 flw ft0,0(a0) +80000228: 00452087 flw ft1,4(a0) +8000022c: 00852107 flw ft2,8(a0) +80000230: 00c52683 lw a3,12(a0) +80000234: c0001553 fcvt.w.s a0,ft0,rtz +80000238: 001015f3 fsflags a1,zero +8000023c: 00100613 li a2,1 +80000240: 32d51c63 bne a0,a3,80000578 +80000244: 32c59a63 bne a1,a2,80000578 + +80000248 : +80000248: 00600193 li gp,6 +8000024c: 00002517 auipc a0,0x2 +80000250: df450513 addi a0,a0,-524 # 80002040 +80000254: 00052007 flw ft0,0(a0) +80000258: 00452087 flw ft1,4(a0) +8000025c: 00852107 flw ft2,8(a0) +80000260: 00c52683 lw a3,12(a0) +80000264: c0001553 fcvt.w.s a0,ft0,rtz +80000268: 001015f3 fsflags a1,zero +8000026c: 00000613 li a2,0 +80000270: 30d51463 bne a0,a3,80000578 +80000274: 30c59263 bne a1,a2,80000578 + +80000278 : +80000278: 00700193 li gp,7 +8000027c: 00002517 auipc a0,0x2 +80000280: dd450513 addi a0,a0,-556 # 80002050 +80000284: 00052007 flw ft0,0(a0) +80000288: 00452087 flw ft1,4(a0) +8000028c: 00852107 flw ft2,8(a0) +80000290: 00c52683 lw a3,12(a0) +80000294: c0001553 fcvt.w.s a0,ft0,rtz +80000298: 001015f3 fsflags a1,zero +8000029c: 00100613 li a2,1 +800002a0: 2cd51c63 bne a0,a3,80000578 +800002a4: 2cc59a63 bne a1,a2,80000578 + +800002a8 : +800002a8: 00800193 li gp,8 +800002ac: 00002517 auipc a0,0x2 +800002b0: db450513 addi a0,a0,-588 # 80002060 +800002b4: 00052007 flw ft0,0(a0) +800002b8: 00452087 flw ft1,4(a0) +800002bc: 00852107 flw ft2,8(a0) +800002c0: 00c52683 lw a3,12(a0) +800002c4: c0001553 fcvt.w.s a0,ft0,rtz +800002c8: 001015f3 fsflags a1,zero +800002cc: 01000613 li a2,16 +800002d0: 2ad51463 bne a0,a3,80000578 +800002d4: 2ac59263 bne a1,a2,80000578 + +800002d8 : +800002d8: 00900193 li gp,9 +800002dc: 00002517 auipc a0,0x2 +800002e0: d9450513 addi a0,a0,-620 # 80002070 +800002e4: 00052007 flw ft0,0(a0) +800002e8: 00452087 flw ft1,4(a0) +800002ec: 00852107 flw ft2,8(a0) +800002f0: 00c52683 lw a3,12(a0) +800002f4: c0001553 fcvt.w.s a0,ft0,rtz +800002f8: 001015f3 fsflags a1,zero +800002fc: 01000613 li a2,16 +80000300: 26d51c63 bne a0,a3,80000578 +80000304: 26c59a63 bne a1,a2,80000578 + +80000308 : +80000308: 00c00193 li gp,12 +8000030c: 00002517 auipc a0,0x2 +80000310: d7450513 addi a0,a0,-652 # 80002080 +80000314: 00052007 flw ft0,0(a0) +80000318: 00452087 flw ft1,4(a0) +8000031c: 00852107 flw ft2,8(a0) +80000320: 00c52683 lw a3,12(a0) +80000324: c0101553 fcvt.wu.s a0,ft0,rtz +80000328: 001015f3 fsflags a1,zero +8000032c: 01000613 li a2,16 +80000330: 24d51463 bne a0,a3,80000578 +80000334: 24c59263 bne a1,a2,80000578 + +80000338 : +80000338: 00d00193 li gp,13 +8000033c: 00002517 auipc a0,0x2 +80000340: d5450513 addi a0,a0,-684 # 80002090 +80000344: 00052007 flw ft0,0(a0) +80000348: 00452087 flw ft1,4(a0) +8000034c: 00852107 flw ft2,8(a0) +80000350: 00c52683 lw a3,12(a0) +80000354: c0101553 fcvt.wu.s a0,ft0,rtz +80000358: 001015f3 fsflags a1,zero +8000035c: 01000613 li a2,16 +80000360: 20d51c63 bne a0,a3,80000578 +80000364: 20c59a63 bne a1,a2,80000578 + +80000368 : +80000368: 00e00193 li gp,14 +8000036c: 00002517 auipc a0,0x2 +80000370: d3450513 addi a0,a0,-716 # 800020a0 +80000374: 00052007 flw ft0,0(a0) +80000378: 00452087 flw ft1,4(a0) +8000037c: 00852107 flw ft2,8(a0) +80000380: 00c52683 lw a3,12(a0) +80000384: c0101553 fcvt.wu.s a0,ft0,rtz +80000388: 001015f3 fsflags a1,zero +8000038c: 00100613 li a2,1 +80000390: 1ed51463 bne a0,a3,80000578 +80000394: 1ec59263 bne a1,a2,80000578 + +80000398 : +80000398: 00f00193 li gp,15 +8000039c: 00002517 auipc a0,0x2 +800003a0: d1450513 addi a0,a0,-748 # 800020b0 +800003a4: 00052007 flw ft0,0(a0) +800003a8: 00452087 flw ft1,4(a0) +800003ac: 00852107 flw ft2,8(a0) +800003b0: 00c52683 lw a3,12(a0) +800003b4: c0101553 fcvt.wu.s a0,ft0,rtz +800003b8: 001015f3 fsflags a1,zero +800003bc: 00100613 li a2,1 +800003c0: 1ad51c63 bne a0,a3,80000578 +800003c4: 1ac59a63 bne a1,a2,80000578 + +800003c8 : +800003c8: 01000193 li gp,16 +800003cc: 00002517 auipc a0,0x2 +800003d0: cf450513 addi a0,a0,-780 # 800020c0 +800003d4: 00052007 flw ft0,0(a0) +800003d8: 00452087 flw ft1,4(a0) +800003dc: 00852107 flw ft2,8(a0) +800003e0: 00c52683 lw a3,12(a0) +800003e4: c0101553 fcvt.wu.s a0,ft0,rtz +800003e8: 001015f3 fsflags a1,zero +800003ec: 00000613 li a2,0 +800003f0: 18d51463 bne a0,a3,80000578 +800003f4: 18c59263 bne a1,a2,80000578 + +800003f8 : +800003f8: 01100193 li gp,17 +800003fc: 00002517 auipc a0,0x2 +80000400: cd450513 addi a0,a0,-812 # 800020d0 +80000404: 00052007 flw ft0,0(a0) +80000408: 00452087 flw ft1,4(a0) +8000040c: 00852107 flw ft2,8(a0) +80000410: 00c52683 lw a3,12(a0) +80000414: c0101553 fcvt.wu.s a0,ft0,rtz +80000418: 001015f3 fsflags a1,zero +8000041c: 00100613 li a2,1 +80000420: 14d51c63 bne a0,a3,80000578 +80000424: 14c59a63 bne a1,a2,80000578 + +80000428 : +80000428: 01200193 li gp,18 +8000042c: 00002517 auipc a0,0x2 +80000430: cb450513 addi a0,a0,-844 # 800020e0 +80000434: 00052007 flw ft0,0(a0) +80000438: 00452087 flw ft1,4(a0) +8000043c: 00852107 flw ft2,8(a0) +80000440: 00c52683 lw a3,12(a0) +80000444: c0101553 fcvt.wu.s a0,ft0,rtz +80000448: 001015f3 fsflags a1,zero +8000044c: 01000613 li a2,16 +80000450: 12d51463 bne a0,a3,80000578 +80000454: 12c59263 bne a1,a2,80000578 + +80000458 : +80000458: 01300193 li gp,19 +8000045c: 00002517 auipc a0,0x2 +80000460: c9450513 addi a0,a0,-876 # 800020f0 +80000464: 00052007 flw ft0,0(a0) +80000468: 00452087 flw ft1,4(a0) +8000046c: 00852107 flw ft2,8(a0) +80000470: 00c52683 lw a3,12(a0) +80000474: c0101553 fcvt.wu.s a0,ft0,rtz +80000478: 001015f3 fsflags a1,zero +8000047c: 00000613 li a2,0 +80000480: 0ed51c63 bne a0,a3,80000578 +80000484: 0ec59a63 bne a1,a2,80000578 + +80000488 : +80000488: 00002097 auipc ra,0x2 +8000048c: c7808093 addi ra,ra,-904 # 80002100 +80000490: 0000a087 flw ft1,0(ra) +80000494: c000f0d3 fcvt.w.s ra,ft1 +80000498: 800003b7 lui t2,0x80000 +8000049c: fff38393 addi t2,t2,-1 # 7fffffff <_end+0xffffdecf> +800004a0: 02a00193 li gp,42 +800004a4: 0c709a63 bne ra,t2,80000578 + +800004a8 : +800004a8: 00002097 auipc ra,0x2 +800004ac: c5808093 addi ra,ra,-936 # 80002100 +800004b0: 0080a087 flw ft1,8(ra) +800004b4: c000f0d3 fcvt.w.s ra,ft1 +800004b8: 800003b7 lui t2,0x80000 +800004bc: 02c00193 li gp,44 +800004c0: 0a709c63 bne ra,t2,80000578 + +800004c4 : +800004c4: 00002097 auipc ra,0x2 +800004c8: c3c08093 addi ra,ra,-964 # 80002100 +800004cc: 0040a087 flw ft1,4(ra) +800004d0: c000f0d3 fcvt.w.s ra,ft1 +800004d4: 800003b7 lui t2,0x80000 +800004d8: fff38393 addi t2,t2,-1 # 7fffffff <_end+0xffffdecf> +800004dc: 03400193 li gp,52 +800004e0: 08709c63 bne ra,t2,80000578 + +800004e4 : +800004e4: 00002097 auipc ra,0x2 +800004e8: c1c08093 addi ra,ra,-996 # 80002100 +800004ec: 00c0a087 flw ft1,12(ra) +800004f0: c000f0d3 fcvt.w.s ra,ft1 +800004f4: 800003b7 lui t2,0x80000 +800004f8: fff38393 addi t2,t2,-1 # 7fffffff <_end+0xffffdecf> +800004fc: 03600193 li gp,54 +80000500: 06709c63 bne ra,t2,80000578 + +80000504 : +80000504: 00002097 auipc ra,0x2 +80000508: bfc08093 addi ra,ra,-1028 # 80002100 +8000050c: 0000a087 flw ft1,0(ra) +80000510: c010f0d3 fcvt.wu.s ra,ft1 +80000514: fff00393 li t2,-1 +80000518: 03e00193 li gp,62 +8000051c: 04709e63 bne ra,t2,80000578 + +80000520 : +80000520: 00002097 auipc ra,0x2 +80000524: be008093 addi ra,ra,-1056 # 80002100 +80000528: 0040a087 flw ft1,4(ra) +8000052c: c010f0d3 fcvt.wu.s ra,ft1 +80000530: fff00393 li t2,-1 +80000534: 03f00193 li gp,63 +80000538: 04709063 bne ra,t2,80000578 + +8000053c : +8000053c: 00002097 auipc ra,0x2 +80000540: bc408093 addi ra,ra,-1084 # 80002100 +80000544: 0080a087 flw ft1,8(ra) +80000548: c010f0d3 fcvt.wu.s ra,ft1 +8000054c: 00000393 li t2,0 +80000550: 04000193 li gp,64 +80000554: 02709263 bne ra,t2,80000578 + +80000558 : +80000558: 00002097 auipc ra,0x2 +8000055c: ba808093 addi ra,ra,-1112 # 80002100 +80000560: 00c0a087 flw ft1,12(ra) +80000564: c010f0d3 fcvt.wu.s ra,ft1 +80000568: fff00393 li t2,-1 +8000056c: 04100193 li gp,65 +80000570: 00709463 bne ra,t2,80000578 +80000574: 02301063 bne zero,gp,80000594 + +80000578 : +80000578: 0ff0000f fence +8000057c: 00018063 beqz gp,8000057c +80000580: 00119193 slli gp,gp,0x1 +80000584: 0011e193 ori gp,gp,1 +80000588: 05d00893 li a7,93 +8000058c: 00018513 mv a0,gp +80000590: 00000073 ecall + +80000594 : +80000594: 0ff0000f fence +80000598: 00100193 li gp,1 +8000059c: 05d00893 li a7,93 +800005a0: 00000513 li a0,0 +800005a4: 00000073 ecall +800005a8: c0001073 unimp +800005ac: 0000 unimp +800005ae: 0000 unimp +800005b0: 0000 unimp +800005b2: 0000 unimp +800005b4: 0000 unimp +800005b6: 0000 unimp +800005b8: 0000 unimp +800005ba: 0000 unimp +800005bc: 0000 unimp +800005be: 0000 unimp +800005c0: 0000 unimp +800005c2: 0000 unimp + +Disassembly of section .data: + +80002000 : +80002000: cccd beqz s1,800020ba +80002002: bf8c fsd fa1,56(a5) +80002004: 0000 unimp +80002006: 0000 unimp +80002008: 0000 unimp +8000200a: 0000 unimp +8000200c: ffff 0xffff +8000200e: ffff 0xffff + +80002010 : +80002010: 0000 unimp +80002012: bf80 fsd fs0,56(a5) +80002014: 0000 unimp +80002016: 0000 unimp +80002018: 0000 unimp +8000201a: 0000 unimp +8000201c: ffff 0xffff +8000201e: ffff 0xffff + +80002020 : +80002020: 6666 flw fa2,88(sp) +80002022: bf66 fsd fs9,440(sp) +80002024: 0000 unimp +80002026: 0000 unimp +80002028: 0000 unimp +8000202a: 0000 unimp +8000202c: 0000 unimp +8000202e: 0000 unimp + +80002030 : +80002030: 6666 flw fa2,88(sp) +80002032: 3f66 fld ft10,120(sp) +80002034: 0000 unimp +80002036: 0000 unimp +80002038: 0000 unimp +8000203a: 0000 unimp +8000203c: 0000 unimp +8000203e: 0000 unimp + +80002040 : +80002040: 0000 unimp +80002042: 3f80 fld fs0,56(a5) +80002044: 0000 unimp +80002046: 0000 unimp +80002048: 0000 unimp +8000204a: 0000 unimp +8000204c: 0001 nop +8000204e: 0000 unimp + +80002050 : +80002050: cccd beqz s1,8000210a +80002052: 3f8c fld fa1,56(a5) +80002054: 0000 unimp +80002056: 0000 unimp +80002058: 0000 unimp +8000205a: 0000 unimp +8000205c: 0001 nop +8000205e: 0000 unimp + +80002060 : +80002060: d05e sw s7,32(sp) +80002062: cf32 sw a2,156(sp) +80002064: 0000 unimp +80002066: 0000 unimp +80002068: 0000 unimp +8000206a: 0000 unimp +8000206c: 0000 unimp +8000206e: 8000 0x8000 + +80002070 : +80002070: d05e sw s7,32(sp) +80002072: 4f32 lw t5,12(sp) +80002074: 0000 unimp +80002076: 0000 unimp +80002078: 0000 unimp +8000207a: 0000 unimp +8000207c: ffff 0xffff +8000207e: 7fff 0x7fff + +80002080 : +80002080: 0000 unimp +80002082: c040 sw s0,4(s0) +80002084: 0000 unimp +80002086: 0000 unimp +80002088: 0000 unimp +8000208a: 0000 unimp +8000208c: 0000 unimp +8000208e: 0000 unimp + +80002090 : +80002090: 0000 unimp +80002092: bf80 fsd fs0,56(a5) +80002094: 0000 unimp +80002096: 0000 unimp +80002098: 0000 unimp +8000209a: 0000 unimp +8000209c: 0000 unimp +8000209e: 0000 unimp + +800020a0 : +800020a0: 6666 flw fa2,88(sp) +800020a2: bf66 fsd fs9,440(sp) +800020a4: 0000 unimp +800020a6: 0000 unimp +800020a8: 0000 unimp +800020aa: 0000 unimp +800020ac: 0000 unimp +800020ae: 0000 unimp + +800020b0 : +800020b0: 6666 flw fa2,88(sp) +800020b2: 3f66 fld ft10,120(sp) +800020b4: 0000 unimp +800020b6: 0000 unimp +800020b8: 0000 unimp +800020ba: 0000 unimp +800020bc: 0000 unimp +800020be: 0000 unimp + +800020c0 : +800020c0: 0000 unimp +800020c2: 3f80 fld fs0,56(a5) +800020c4: 0000 unimp +800020c6: 0000 unimp +800020c8: 0000 unimp +800020ca: 0000 unimp +800020cc: 0001 nop +800020ce: 0000 unimp + +800020d0 : +800020d0: cccd beqz s1,8000218a <_end+0x5a> +800020d2: 3f8c fld fa1,56(a5) +800020d4: 0000 unimp +800020d6: 0000 unimp +800020d8: 0000 unimp +800020da: 0000 unimp +800020dc: 0001 nop +800020de: 0000 unimp + +800020e0 : +800020e0: d05e sw s7,32(sp) +800020e2: cf32 sw a2,156(sp) +800020e4: 0000 unimp +800020e6: 0000 unimp +800020e8: 0000 unimp +800020ea: 0000 unimp +800020ec: 0000 unimp +800020ee: 0000 unimp + +800020f0 : +800020f0: d05e sw s7,32(sp) +800020f2: 4f32 lw t5,12(sp) +800020f4: 0000 unimp +800020f6: 0000 unimp +800020f8: 0000 unimp +800020fa: 0000 unimp +800020fc: 5e00 lw s0,56(a2) +800020fe: b2d0 fsd fa2,160(a3) + +80002100 : +80002100: ffff 0xffff +80002102: ffff 0xffff +80002104: ffff 0xffff +80002106: 7fff 0x7fff +80002108: 0000 unimp +8000210a: ff80 fsw fs0,56(a5) +8000210c: 0000 unimp +8000210e: 7f80 flw fs0,56(a5) + +80002110 : +80002110: ffff 0xffff +80002112: ffff 0xffff +80002114: ffff 0xffff +80002116: ffff 0xffff +80002118: ffff 0xffff +8000211a: ffff 0xffff +8000211c: ffff 0xffff +8000211e: 7fff 0x7fff +80002120: 0000 unimp +80002122: 0000 unimp +80002124: 0000 unimp +80002126: fff0 fsw fa2,124(a5) +80002128: 0000 unimp +8000212a: 0000 unimp +8000212c: 0000 unimp +8000212e: 7ff0 flw fa2,124(a5) diff --git a/src/test/resources/asm/rv32uf-p-fdiv.dump b/src/test/resources/asm/rv32uf-p-fdiv.dump new file mode 100644 index 00000000..0f13dda3 --- /dev/null +++ b/src/test/resources/asm/rv32uf-p-fdiv.dump @@ -0,0 +1,322 @@ + +rv32uf-p-fdiv: file format elf32-littleriscv + + +Disassembly of section .text.init: + +80000000 <_start>: +80000000: 04c0006f j 8000004c + +80000004 : +80000004: 34202f73 csrr t5,mcause +80000008: 00800f93 li t6,8 +8000000c: 03ff0a63 beq t5,t6,80000040 +80000010: 00900f93 li t6,9 +80000014: 03ff0663 beq t5,t6,80000040 +80000018: 00b00f93 li t6,11 +8000001c: 03ff0263 beq t5,t6,80000040 +80000020: 80000f17 auipc t5,0x80000 +80000024: fe0f0f13 addi t5,t5,-32 # 0 <_start-0x80000000> +80000028: 000f0463 beqz t5,80000030 +8000002c: 000f0067 jr t5 +80000030: 34202f73 csrr t5,mcause +80000034: 000f5463 bgez t5,8000003c +80000038: 0040006f j 8000003c + +8000003c : +8000003c: 5391e193 ori gp,gp,1337 + +80000040 : +80000040: 00001f17 auipc t5,0x1 +80000044: fc3f2023 sw gp,-64(t5) # 80001000 +80000048: ff9ff06f j 80000040 + +8000004c : +8000004c: 00000093 li ra,0 +80000050: 00000113 li sp,0 +80000054: 00000193 li gp,0 +80000058: 00000213 li tp,0 +8000005c: 00000293 li t0,0 +80000060: 00000313 li t1,0 +80000064: 00000393 li t2,0 +80000068: 00000413 li s0,0 +8000006c: 00000493 li s1,0 +80000070: 00000513 li a0,0 +80000074: 00000593 li a1,0 +80000078: 00000613 li a2,0 +8000007c: 00000693 li a3,0 +80000080: 00000713 li a4,0 +80000084: 00000793 li a5,0 +80000088: 00000813 li a6,0 +8000008c: 00000893 li a7,0 +80000090: 00000913 li s2,0 +80000094: 00000993 li s3,0 +80000098: 00000a13 li s4,0 +8000009c: 00000a93 li s5,0 +800000a0: 00000b13 li s6,0 +800000a4: 00000b93 li s7,0 +800000a8: 00000c13 li s8,0 +800000ac: 00000c93 li s9,0 +800000b0: 00000d13 li s10,0 +800000b4: 00000d93 li s11,0 +800000b8: 00000e13 li t3,0 +800000bc: 00000e93 li t4,0 +800000c0: 00000f13 li t5,0 +800000c4: 00000f93 li t6,0 +800000c8: f1402573 csrr a0,mhartid +800000cc: 00051063 bnez a0,800000cc +800000d0: 00000297 auipc t0,0x0 +800000d4: 01028293 addi t0,t0,16 # 800000e0 +800000d8: 30529073 csrw mtvec,t0 +800000dc: 18005073 csrwi satp,0 +800000e0: 00000297 auipc t0,0x0 +800000e4: 02028293 addi t0,t0,32 # 80000100 +800000e8: 30529073 csrw mtvec,t0 +800000ec: 800002b7 lui t0,0x80000 +800000f0: fff28293 addi t0,t0,-1 # 7fffffff <_end+0xffffdf7f> +800000f4: 3b029073 csrw pmpaddr0,t0 +800000f8: 01f00293 li t0,31 +800000fc: 3a029073 csrw pmpcfg0,t0 +80000100: 30405073 csrwi mie,0 +80000104: 00000297 auipc t0,0x0 +80000108: 01428293 addi t0,t0,20 # 80000118 +8000010c: 30529073 csrw mtvec,t0 +80000110: 30205073 csrwi medeleg,0 +80000114: 30305073 csrwi mideleg,0 +80000118: 00000193 li gp,0 +8000011c: 00000297 auipc t0,0x0 +80000120: ee828293 addi t0,t0,-280 # 80000004 +80000124: 30529073 csrw mtvec,t0 +80000128: 00100513 li a0,1 +8000012c: 01f51513 slli a0,a0,0x1f +80000130: 00054c63 bltz a0,80000148 +80000134: 0ff0000f fence +80000138: 00100193 li gp,1 +8000013c: 05d00893 li a7,93 +80000140: 00000513 li a0,0 +80000144: 00000073 ecall +80000148: 80000297 auipc t0,0x80000 +8000014c: eb828293 addi t0,t0,-328 # 0 <_start-0x80000000> +80000150: 00028a63 beqz t0,80000164 +80000154: 10529073 csrw stvec,t0 +80000158: 0000b2b7 lui t0,0xb +8000015c: 10928293 addi t0,t0,265 # b109 <_start-0x7fff4ef7> +80000160: 30229073 csrw medeleg,t0 +80000164: 30005073 csrwi mstatus,0 +80000168: 00002537 lui a0,0x2 +8000016c: 30052073 csrs mstatus,a0 +80000170: 00305073 csrwi fcsr,0 +80000174: 00000297 auipc t0,0x0 +80000178: 01428293 addi t0,t0,20 # 80000188 +8000017c: 34129073 csrw mepc,t0 +80000180: f1402573 csrr a0,mhartid +80000184: 30200073 mret + +80000188 : +80000188: 00200193 li gp,2 +8000018c: 00002517 auipc a0,0x2 +80000190: e7450513 addi a0,a0,-396 # 80002000 +80000194: 00052007 flw ft0,0(a0) +80000198: 00452087 flw ft1,4(a0) +8000019c: 00852107 flw ft2,8(a0) +800001a0: 00c52683 lw a3,12(a0) +800001a4: 181071d3 fdiv.s ft3,ft0,ft1 +800001a8: e0018553 fmv.x.w a0,ft3 +800001ac: 001015f3 fsflags a1,zero +800001b0: 00100613 li a2,1 +800001b4: 14d51263 bne a0,a3,800002f8 +800001b8: 14c59063 bne a1,a2,800002f8 + +800001bc : +800001bc: 00300193 li gp,3 +800001c0: 00002517 auipc a0,0x2 +800001c4: e5050513 addi a0,a0,-432 # 80002010 +800001c8: 00052007 flw ft0,0(a0) +800001cc: 00452087 flw ft1,4(a0) +800001d0: 00852107 flw ft2,8(a0) +800001d4: 00c52683 lw a3,12(a0) +800001d8: 181071d3 fdiv.s ft3,ft0,ft1 +800001dc: e0018553 fmv.x.w a0,ft3 +800001e0: 001015f3 fsflags a1,zero +800001e4: 00100613 li a2,1 +800001e8: 10d51863 bne a0,a3,800002f8 +800001ec: 10c59663 bne a1,a2,800002f8 + +800001f0 : +800001f0: 00400193 li gp,4 +800001f4: 00002517 auipc a0,0x2 +800001f8: e2c50513 addi a0,a0,-468 # 80002020 +800001fc: 00052007 flw ft0,0(a0) +80000200: 00452087 flw ft1,4(a0) +80000204: 00852107 flw ft2,8(a0) +80000208: 00c52683 lw a3,12(a0) +8000020c: 181071d3 fdiv.s ft3,ft0,ft1 +80000210: e0018553 fmv.x.w a0,ft3 +80000214: 001015f3 fsflags a1,zero +80000218: 00000613 li a2,0 +8000021c: 0cd51e63 bne a0,a3,800002f8 +80000220: 0cc59c63 bne a1,a2,800002f8 + +80000224 : +80000224: 00500193 li gp,5 +80000228: 00002517 auipc a0,0x2 +8000022c: e0850513 addi a0,a0,-504 # 80002030 +80000230: 00052007 flw ft0,0(a0) +80000234: 00452087 flw ft1,4(a0) +80000238: 00852107 flw ft2,8(a0) +8000023c: 00c52683 lw a3,12(a0) +80000240: 580071d3 fsqrt.s ft3,ft0 +80000244: e0018553 fmv.x.w a0,ft3 +80000248: 001015f3 fsflags a1,zero +8000024c: 00100613 li a2,1 +80000250: 0ad51463 bne a0,a3,800002f8 +80000254: 0ac59263 bne a1,a2,800002f8 + +80000258 : +80000258: 00600193 li gp,6 +8000025c: 00002517 auipc a0,0x2 +80000260: de450513 addi a0,a0,-540 # 80002040 +80000264: 00052007 flw ft0,0(a0) +80000268: 00452087 flw ft1,4(a0) +8000026c: 00852107 flw ft2,8(a0) +80000270: 00c52683 lw a3,12(a0) +80000274: 580071d3 fsqrt.s ft3,ft0 +80000278: e0018553 fmv.x.w a0,ft3 +8000027c: 001015f3 fsflags a1,zero +80000280: 00000613 li a2,0 +80000284: 06d51a63 bne a0,a3,800002f8 +80000288: 06c59863 bne a1,a2,800002f8 + +8000028c : +8000028c: 00700193 li gp,7 +80000290: 00002517 auipc a0,0x2 +80000294: dc050513 addi a0,a0,-576 # 80002050 +80000298: 00052007 flw ft0,0(a0) +8000029c: 00452087 flw ft1,4(a0) +800002a0: 00852107 flw ft2,8(a0) +800002a4: 00c52683 lw a3,12(a0) +800002a8: 580071d3 fsqrt.s ft3,ft0 +800002ac: e0018553 fmv.x.w a0,ft3 +800002b0: 001015f3 fsflags a1,zero +800002b4: 01000613 li a2,16 +800002b8: 04d51063 bne a0,a3,800002f8 +800002bc: 02c59e63 bne a1,a2,800002f8 + +800002c0 : +800002c0: 00800193 li gp,8 +800002c4: 00002517 auipc a0,0x2 +800002c8: da050513 addi a0,a0,-608 # 80002064 +800002cc: 00052007 flw ft0,0(a0) +800002d0: 00452087 flw ft1,4(a0) +800002d4: 00852107 flw ft2,8(a0) +800002d8: 00c52683 lw a3,12(a0) +800002dc: 580071d3 fsqrt.s ft3,ft0 +800002e0: e0018553 fmv.x.w a0,ft3 +800002e4: 001015f3 fsflags a1,zero +800002e8: 00100613 li a2,1 +800002ec: 00d51663 bne a0,a3,800002f8 +800002f0: 00c59463 bne a1,a2,800002f8 +800002f4: 02301063 bne zero,gp,80000314 + +800002f8 : +800002f8: 0ff0000f fence +800002fc: 00018063 beqz gp,800002fc +80000300: 00119193 slli gp,gp,0x1 +80000304: 0011e193 ori gp,gp,1 +80000308: 05d00893 li a7,93 +8000030c: 00018513 mv a0,gp +80000310: 00000073 ecall + +80000314 : +80000314: 0ff0000f fence +80000318: 00100193 li gp,1 +8000031c: 05d00893 li a7,93 +80000320: 00000513 li a0,0 +80000324: 00000073 ecall +80000328: c0001073 unimp +8000032c: 0000 unimp +8000032e: 0000 unimp +80000330: 0000 unimp +80000332: 0000 unimp +80000334: 0000 unimp +80000336: 0000 unimp +80000338: 0000 unimp +8000033a: 0000 unimp +8000033c: 0000 unimp +8000033e: 0000 unimp +80000340: 0000 unimp +80000342: 0000 unimp + +Disassembly of section .data: + +80002000 : +80002000: 40490fdb 0x40490fdb +80002004: f854 fsw fa3,52(s0) +80002006: 402d c.li zero,11 +80002008: 0000 unimp +8000200a: 0000 unimp +8000200c: eee0 fsw fs0,92(a3) +8000200e: sltiu t6,zero,1024 + +80002010 : +80002010: 4000 lw s0,0(s0) +80002012: c49a sw t1,72(sp) +80002014: 449a6333 0x449a6333 +80002018: 0000 unimp +8000201a: 0000 unimp +8000201c: c5a2 sw s0,200(sp) +8000201e: bf7f 0xbf7f + +80002020 : +80002020: 40490fdb 0x40490fdb +80002024: 0000 unimp +80002026: 3f80 fld fs0,56(a5) +80002028: 0000 unimp +8000202a: 0000 unimp +8000202c: 40490fdb 0x40490fdb + +80002030 : +80002030: 40490fdb 0x40490fdb +80002034: 0000 unimp +80002036: 0000 unimp +80002038: 0000 unimp +8000203a: 0000 unimp +8000203c: dfc5 beqz a5,80001ff4 +8000203e: 3fe2 fld ft11,56(sp) + +80002040 : +80002040: 4000 lw s0,0(s0) +80002042: 461c lw a5,8(a2) +80002044: 0000 unimp +80002046: 0000 unimp +80002048: 0000 unimp +8000204a: 0000 unimp +8000204c: 0000 unimp +8000204e: 42c8 lw a0,4(a3) + +80002050 : +80002050: 0000 unimp +80002052: bf80 fsd fs0,56(a5) +80002054: 0000 unimp +80002056: 0000 unimp +80002058: 0000 unimp +8000205a: 0000 unimp +8000205c: 0000 unimp +8000205e: 7fc0 flw fs0,60(a5) +80002060: 0000 unimp +80002062: 0000 unimp + +80002064 : +80002064: 0000 unimp +80002066: 0000432b 0x432b +8000206a: 0000 unimp +8000206c: 0000 unimp +8000206e: 0000 unimp +80002070: 3a26 fld fs4,104(sp) +80002072: 4151 li sp,20 +80002074: 0000 unimp +80002076: 0000 unimp +80002078: 0000 unimp +8000207a: 0000 unimp +8000207c: 0000 unimp +8000207e: 0000 unimp diff --git a/src/test/resources/asm/rv32uf-p-fmadd.dump b/src/test/resources/asm/rv32uf-p-fmadd.dump new file mode 100644 index 00000000..bfec06c4 --- /dev/null +++ b/src/test/resources/asm/rv32uf-p-fmadd.dump @@ -0,0 +1,439 @@ + +rv32uf-p-fmadd: file format elf32-littleriscv + + +Disassembly of section .text.init: + +80000000 <_start>: +80000000: 04c0006f j 8000004c + +80000004 : +80000004: 34202f73 csrr t5,mcause +80000008: 00800f93 li t6,8 +8000000c: 03ff0a63 beq t5,t6,80000040 +80000010: 00900f93 li t6,9 +80000014: 03ff0663 beq t5,t6,80000040 +80000018: 00b00f93 li t6,11 +8000001c: 03ff0263 beq t5,t6,80000040 +80000020: 80000f17 auipc t5,0x80000 +80000024: fe0f0f13 addi t5,t5,-32 # 0 <_start-0x80000000> +80000028: 000f0463 beqz t5,80000030 +8000002c: 000f0067 jr t5 +80000030: 34202f73 csrr t5,mcause +80000034: 000f5463 bgez t5,8000003c +80000038: 0040006f j 8000003c + +8000003c : +8000003c: 5391e193 ori gp,gp,1337 + +80000040 : +80000040: 00001f17 auipc t5,0x1 +80000044: fc3f2023 sw gp,-64(t5) # 80001000 +80000048: ff9ff06f j 80000040 + +8000004c : +8000004c: 00000093 li ra,0 +80000050: 00000113 li sp,0 +80000054: 00000193 li gp,0 +80000058: 00000213 li tp,0 +8000005c: 00000293 li t0,0 +80000060: 00000313 li t1,0 +80000064: 00000393 li t2,0 +80000068: 00000413 li s0,0 +8000006c: 00000493 li s1,0 +80000070: 00000513 li a0,0 +80000074: 00000593 li a1,0 +80000078: 00000613 li a2,0 +8000007c: 00000693 li a3,0 +80000080: 00000713 li a4,0 +80000084: 00000793 li a5,0 +80000088: 00000813 li a6,0 +8000008c: 00000893 li a7,0 +80000090: 00000913 li s2,0 +80000094: 00000993 li s3,0 +80000098: 00000a13 li s4,0 +8000009c: 00000a93 li s5,0 +800000a0: 00000b13 li s6,0 +800000a4: 00000b93 li s7,0 +800000a8: 00000c13 li s8,0 +800000ac: 00000c93 li s9,0 +800000b0: 00000d13 li s10,0 +800000b4: 00000d93 li s11,0 +800000b8: 00000e13 li t3,0 +800000bc: 00000e93 li t4,0 +800000c0: 00000f13 li t5,0 +800000c4: 00000f93 li t6,0 +800000c8: f1402573 csrr a0,mhartid +800000cc: 00051063 bnez a0,800000cc +800000d0: 00000297 auipc t0,0x0 +800000d4: 01028293 addi t0,t0,16 # 800000e0 +800000d8: 30529073 csrw mtvec,t0 +800000dc: 18005073 csrwi satp,0 +800000e0: 00000297 auipc t0,0x0 +800000e4: 02028293 addi t0,t0,32 # 80000100 +800000e8: 30529073 csrw mtvec,t0 +800000ec: 800002b7 lui t0,0x80000 +800000f0: fff28293 addi t0,t0,-1 # 7fffffff <_end+0xffffdf3f> +800000f4: 3b029073 csrw pmpaddr0,t0 +800000f8: 01f00293 li t0,31 +800000fc: 3a029073 csrw pmpcfg0,t0 +80000100: 30405073 csrwi mie,0 +80000104: 00000297 auipc t0,0x0 +80000108: 01428293 addi t0,t0,20 # 80000118 +8000010c: 30529073 csrw mtvec,t0 +80000110: 30205073 csrwi medeleg,0 +80000114: 30305073 csrwi mideleg,0 +80000118: 00000193 li gp,0 +8000011c: 00000297 auipc t0,0x0 +80000120: ee828293 addi t0,t0,-280 # 80000004 +80000124: 30529073 csrw mtvec,t0 +80000128: 00100513 li a0,1 +8000012c: 01f51513 slli a0,a0,0x1f +80000130: 00054c63 bltz a0,80000148 +80000134: 0ff0000f fence +80000138: 00100193 li gp,1 +8000013c: 05d00893 li a7,93 +80000140: 00000513 li a0,0 +80000144: 00000073 ecall +80000148: 80000297 auipc t0,0x80000 +8000014c: eb828293 addi t0,t0,-328 # 0 <_start-0x80000000> +80000150: 00028a63 beqz t0,80000164 +80000154: 10529073 csrw stvec,t0 +80000158: 0000b2b7 lui t0,0xb +8000015c: 10928293 addi t0,t0,265 # b109 <_start-0x7fff4ef7> +80000160: 30229073 csrw medeleg,t0 +80000164: 30005073 csrwi mstatus,0 +80000168: 00002537 lui a0,0x2 +8000016c: 30052073 csrs mstatus,a0 +80000170: 00305073 csrwi fcsr,0 +80000174: 00000297 auipc t0,0x0 +80000178: 01428293 addi t0,t0,20 # 80000188 +8000017c: 34129073 csrw mepc,t0 +80000180: f1402573 csrr a0,mhartid +80000184: 30200073 mret + +80000188 : +80000188: 00200193 li gp,2 +8000018c: 00002517 auipc a0,0x2 +80000190: e7450513 addi a0,a0,-396 # 80002000 +80000194: 00052007 flw ft0,0(a0) +80000198: 00452087 flw ft1,4(a0) +8000019c: 00852107 flw ft2,8(a0) +800001a0: 00c52683 lw a3,12(a0) +800001a4: 101071c3 fmadd.s ft3,ft0,ft1,ft2 +800001a8: e0018553 fmv.x.w a0,ft3 +800001ac: 001015f3 fsflags a1,zero +800001b0: 00000613 li a2,0 +800001b4: 24d51463 bne a0,a3,800003fc +800001b8: 24c59263 bne a1,a2,800003fc + +800001bc : +800001bc: 00300193 li gp,3 +800001c0: 00002517 auipc a0,0x2 +800001c4: e5050513 addi a0,a0,-432 # 80002010 +800001c8: 00052007 flw ft0,0(a0) +800001cc: 00452087 flw ft1,4(a0) +800001d0: 00852107 flw ft2,8(a0) +800001d4: 00c52683 lw a3,12(a0) +800001d8: 101071c3 fmadd.s ft3,ft0,ft1,ft2 +800001dc: e0018553 fmv.x.w a0,ft3 +800001e0: 001015f3 fsflags a1,zero +800001e4: 00100613 li a2,1 +800001e8: 20d51a63 bne a0,a3,800003fc +800001ec: 20c59863 bne a1,a2,800003fc + +800001f0 : +800001f0: 00400193 li gp,4 +800001f4: 00002517 auipc a0,0x2 +800001f8: e2c50513 addi a0,a0,-468 # 80002020 +800001fc: 00052007 flw ft0,0(a0) +80000200: 00452087 flw ft1,4(a0) +80000204: 00852107 flw ft2,8(a0) +80000208: 00c52683 lw a3,12(a0) +8000020c: 101071c3 fmadd.s ft3,ft0,ft1,ft2 +80000210: e0018553 fmv.x.w a0,ft3 +80000214: 001015f3 fsflags a1,zero +80000218: 00000613 li a2,0 +8000021c: 1ed51063 bne a0,a3,800003fc +80000220: 1cc59e63 bne a1,a2,800003fc + +80000224 : +80000224: 00500193 li gp,5 +80000228: 00002517 auipc a0,0x2 +8000022c: e0850513 addi a0,a0,-504 # 80002030 +80000230: 00052007 flw ft0,0(a0) +80000234: 00452087 flw ft1,4(a0) +80000238: 00852107 flw ft2,8(a0) +8000023c: 00c52683 lw a3,12(a0) +80000240: 101071cf fnmadd.s ft3,ft0,ft1,ft2 +80000244: e0018553 fmv.x.w a0,ft3 +80000248: 001015f3 fsflags a1,zero +8000024c: 00000613 li a2,0 +80000250: 1ad51663 bne a0,a3,800003fc +80000254: 1ac59463 bne a1,a2,800003fc + +80000258 : +80000258: 00600193 li gp,6 +8000025c: 00002517 auipc a0,0x2 +80000260: de450513 addi a0,a0,-540 # 80002040 +80000264: 00052007 flw ft0,0(a0) +80000268: 00452087 flw ft1,4(a0) +8000026c: 00852107 flw ft2,8(a0) +80000270: 00c52683 lw a3,12(a0) +80000274: 101071cf fnmadd.s ft3,ft0,ft1,ft2 +80000278: e0018553 fmv.x.w a0,ft3 +8000027c: 001015f3 fsflags a1,zero +80000280: 00100613 li a2,1 +80000284: 16d51c63 bne a0,a3,800003fc +80000288: 16c59a63 bne a1,a2,800003fc + +8000028c : +8000028c: 00700193 li gp,7 +80000290: 00002517 auipc a0,0x2 +80000294: dc050513 addi a0,a0,-576 # 80002050 +80000298: 00052007 flw ft0,0(a0) +8000029c: 00452087 flw ft1,4(a0) +800002a0: 00852107 flw ft2,8(a0) +800002a4: 00c52683 lw a3,12(a0) +800002a8: 101071cf fnmadd.s ft3,ft0,ft1,ft2 +800002ac: e0018553 fmv.x.w a0,ft3 +800002b0: 001015f3 fsflags a1,zero +800002b4: 00000613 li a2,0 +800002b8: 14d51263 bne a0,a3,800003fc +800002bc: 14c59063 bne a1,a2,800003fc + +800002c0 : +800002c0: 00800193 li gp,8 +800002c4: 00002517 auipc a0,0x2 +800002c8: d9c50513 addi a0,a0,-612 # 80002060 +800002cc: 00052007 flw ft0,0(a0) +800002d0: 00452087 flw ft1,4(a0) +800002d4: 00852107 flw ft2,8(a0) +800002d8: 00c52683 lw a3,12(a0) +800002dc: 101071c7 fmsub.s ft3,ft0,ft1,ft2 +800002e0: e0018553 fmv.x.w a0,ft3 +800002e4: 001015f3 fsflags a1,zero +800002e8: 00000613 li a2,0 +800002ec: 10d51863 bne a0,a3,800003fc +800002f0: 10c59663 bne a1,a2,800003fc + +800002f4 : +800002f4: 00900193 li gp,9 +800002f8: 00002517 auipc a0,0x2 +800002fc: d7850513 addi a0,a0,-648 # 80002070 +80000300: 00052007 flw ft0,0(a0) +80000304: 00452087 flw ft1,4(a0) +80000308: 00852107 flw ft2,8(a0) +8000030c: 00c52683 lw a3,12(a0) +80000310: 101071c7 fmsub.s ft3,ft0,ft1,ft2 +80000314: e0018553 fmv.x.w a0,ft3 +80000318: 001015f3 fsflags a1,zero +8000031c: 00100613 li a2,1 +80000320: 0cd51e63 bne a0,a3,800003fc +80000324: 0cc59c63 bne a1,a2,800003fc + +80000328 : +80000328: 00a00193 li gp,10 +8000032c: 00002517 auipc a0,0x2 +80000330: d5450513 addi a0,a0,-684 # 80002080 +80000334: 00052007 flw ft0,0(a0) +80000338: 00452087 flw ft1,4(a0) +8000033c: 00852107 flw ft2,8(a0) +80000340: 00c52683 lw a3,12(a0) +80000344: 101071c7 fmsub.s ft3,ft0,ft1,ft2 +80000348: e0018553 fmv.x.w a0,ft3 +8000034c: 001015f3 fsflags a1,zero +80000350: 00000613 li a2,0 +80000354: 0ad51463 bne a0,a3,800003fc +80000358: 0ac59263 bne a1,a2,800003fc + +8000035c : +8000035c: 00b00193 li gp,11 +80000360: 00002517 auipc a0,0x2 +80000364: d3050513 addi a0,a0,-720 # 80002090 +80000368: 00052007 flw ft0,0(a0) +8000036c: 00452087 flw ft1,4(a0) +80000370: 00852107 flw ft2,8(a0) +80000374: 00c52683 lw a3,12(a0) +80000378: 101071cb fnmsub.s ft3,ft0,ft1,ft2 +8000037c: e0018553 fmv.x.w a0,ft3 +80000380: 001015f3 fsflags a1,zero +80000384: 00000613 li a2,0 +80000388: 06d51a63 bne a0,a3,800003fc +8000038c: 06c59863 bne a1,a2,800003fc + +80000390 : +80000390: 00c00193 li gp,12 +80000394: 00002517 auipc a0,0x2 +80000398: d0c50513 addi a0,a0,-756 # 800020a0 +8000039c: 00052007 flw ft0,0(a0) +800003a0: 00452087 flw ft1,4(a0) +800003a4: 00852107 flw ft2,8(a0) +800003a8: 00c52683 lw a3,12(a0) +800003ac: 101071cb fnmsub.s ft3,ft0,ft1,ft2 +800003b0: e0018553 fmv.x.w a0,ft3 +800003b4: 001015f3 fsflags a1,zero +800003b8: 00100613 li a2,1 +800003bc: 04d51063 bne a0,a3,800003fc +800003c0: 02c59e63 bne a1,a2,800003fc + +800003c4 : +800003c4: 00d00193 li gp,13 +800003c8: 00002517 auipc a0,0x2 +800003cc: ce850513 addi a0,a0,-792 # 800020b0 +800003d0: 00052007 flw ft0,0(a0) +800003d4: 00452087 flw ft1,4(a0) +800003d8: 00852107 flw ft2,8(a0) +800003dc: 00c52683 lw a3,12(a0) +800003e0: 101071cb fnmsub.s ft3,ft0,ft1,ft2 +800003e4: e0018553 fmv.x.w a0,ft3 +800003e8: 001015f3 fsflags a1,zero +800003ec: 00000613 li a2,0 +800003f0: 00d51663 bne a0,a3,800003fc +800003f4: 00c59463 bne a1,a2,800003fc +800003f8: 02301063 bne zero,gp,80000418 + +800003fc : +800003fc: 0ff0000f fence +80000400: 00018063 beqz gp,80000400 +80000404: 00119193 slli gp,gp,0x1 +80000408: 0011e193 ori gp,gp,1 +8000040c: 05d00893 li a7,93 +80000410: 00018513 mv a0,gp +80000414: 00000073 ecall + +80000418 : +80000418: 0ff0000f fence +8000041c: 00100193 li gp,1 +80000420: 05d00893 li a7,93 +80000424: 00000513 li a0,0 +80000428: 00000073 ecall +8000042c: c0001073 unimp +80000430: 0000 unimp +80000432: 0000 unimp +80000434: 0000 unimp +80000436: 0000 unimp +80000438: 0000 unimp +8000043a: 0000 unimp +8000043c: 0000 unimp +8000043e: 0000 unimp +80000440: 0000 unimp +80000442: 0000 unimp + +Disassembly of section .data: + +80002000 : +80002000: 0000 unimp +80002002: 3f80 fld fs0,56(a5) +80002004: 0000 unimp +80002006: 4020 lw s0,64(s0) +80002008: 0000 unimp +8000200a: 3f80 fld fs0,56(a5) +8000200c: 0000 unimp +8000200e: 4060 lw s0,68(s0) + +80002010 : +80002010: 0000 unimp +80002012: bf80 fsd fs0,56(a5) +80002014: c49a6333 0xc49a6333 +80002018: cccd beqz s1,800020d2 <_end+0x12> +8000201a: 3f8c fld fa1,56(a5) +8000201c: 8666 mv a2,s9 +8000201e: 449a lw s1,132(sp) + +80002020 : +80002020: 0000 unimp +80002022: 4000 lw s0,0(s0) +80002024: 0000 unimp +80002026: c0a0 sw s0,64(s1) +80002028: 0000 unimp +8000202a: c000 sw s0,0(s0) +8000202c: 0000 unimp +8000202e: c140 sw s0,4(a0) + +80002030 : +80002030: 0000 unimp +80002032: 3f80 fld fs0,56(a5) +80002034: 0000 unimp +80002036: 4020 lw s0,64(s0) +80002038: 0000 unimp +8000203a: 3f80 fld fs0,56(a5) +8000203c: 0000 unimp +8000203e: c060 sw s0,68(s0) + +80002040 : +80002040: 0000 unimp +80002042: bf80 fsd fs0,56(a5) +80002044: c49a6333 0xc49a6333 +80002048: cccd beqz s1,80002102 <_end+0x42> +8000204a: 3f8c fld fa1,56(a5) +8000204c: 8666 mv a2,s9 +8000204e: c49a sw t1,72(sp) + +80002050 : +80002050: 0000 unimp +80002052: 4000 lw s0,0(s0) +80002054: 0000 unimp +80002056: c0a0 sw s0,64(s1) +80002058: 0000 unimp +8000205a: c000 sw s0,0(s0) +8000205c: 0000 unimp +8000205e: 4140 lw s0,4(a0) + +80002060 : +80002060: 0000 unimp +80002062: 3f80 fld fs0,56(a5) +80002064: 0000 unimp +80002066: 4020 lw s0,64(s0) +80002068: 0000 unimp +8000206a: 3f80 fld fs0,56(a5) +8000206c: 0000 unimp +8000206e: 3fc0 fld fs0,184(a5) + +80002070 : +80002070: 0000 unimp +80002072: bf80 fsd fs0,56(a5) +80002074: c49a6333 0xc49a6333 +80002078: cccd beqz s1,80002132 <_end+0x72> +8000207a: 3f8c fld fa1,56(a5) +8000207c: 4000 lw s0,0(s0) +8000207e: 449a lw s1,132(sp) + +80002080 : +80002080: 0000 unimp +80002082: 4000 lw s0,0(s0) +80002084: 0000 unimp +80002086: c0a0 sw s0,64(s1) +80002088: 0000 unimp +8000208a: c000 sw s0,0(s0) +8000208c: 0000 unimp +8000208e: c100 sw s0,0(a0) + +80002090 : +80002090: 0000 unimp +80002092: 3f80 fld fs0,56(a5) +80002094: 0000 unimp +80002096: 4020 lw s0,64(s0) +80002098: 0000 unimp +8000209a: 3f80 fld fs0,56(a5) +8000209c: 0000 unimp +8000209e: bfc0 fsd fs0,184(a5) + +800020a0 : +800020a0: 0000 unimp +800020a2: bf80 fsd fs0,56(a5) +800020a4: c49a6333 0xc49a6333 +800020a8: cccd beqz s1,80002162 <_end+0xa2> +800020aa: 3f8c fld fa1,56(a5) +800020ac: 4000 lw s0,0(s0) +800020ae: c49a sw t1,72(sp) + +800020b0 : +800020b0: 0000 unimp +800020b2: 4000 lw s0,0(s0) +800020b4: 0000 unimp +800020b6: c0a0 sw s0,64(s1) +800020b8: 0000 unimp +800020ba: c000 sw s0,0(s0) +800020bc: 0000 unimp +800020be: 4100 lw s0,0(a0) diff --git a/src/test/resources/asm/rv32uf-p-fmin.dump b/src/test/resources/asm/rv32uf-p-fmin.dump new file mode 100644 index 00000000..7d751804 --- /dev/null +++ b/src/test/resources/asm/rv32uf-p-fmin.dump @@ -0,0 +1,581 @@ + +rv32uf-p-fmin: file format elf32-littleriscv + + +Disassembly of section .text.init: + +80000000 <_start>: +80000000: 04c0006f j 8000004c + +80000004 : +80000004: 34202f73 csrr t5,mcause +80000008: 00800f93 li t6,8 +8000000c: 03ff0a63 beq t5,t6,80000040 +80000010: 00900f93 li t6,9 +80000014: 03ff0663 beq t5,t6,80000040 +80000018: 00b00f93 li t6,11 +8000001c: 03ff0263 beq t5,t6,80000040 +80000020: 80000f17 auipc t5,0x80000 +80000024: fe0f0f13 addi t5,t5,-32 # 0 <_start-0x80000000> +80000028: 000f0463 beqz t5,80000030 +8000002c: 000f0067 jr t5 +80000030: 34202f73 csrr t5,mcause +80000034: 000f5463 bgez t5,8000003c +80000038: 0040006f j 8000003c + +8000003c : +8000003c: 5391e193 ori gp,gp,1337 + +80000040 : +80000040: 00001f17 auipc t5,0x1 +80000044: fc3f2023 sw gp,-64(t5) # 80001000 +80000048: ff9ff06f j 80000040 + +8000004c : +8000004c: 00000093 li ra,0 +80000050: 00000113 li sp,0 +80000054: 00000193 li gp,0 +80000058: 00000213 li tp,0 +8000005c: 00000293 li t0,0 +80000060: 00000313 li t1,0 +80000064: 00000393 li t2,0 +80000068: 00000413 li s0,0 +8000006c: 00000493 li s1,0 +80000070: 00000513 li a0,0 +80000074: 00000593 li a1,0 +80000078: 00000613 li a2,0 +8000007c: 00000693 li a3,0 +80000080: 00000713 li a4,0 +80000084: 00000793 li a5,0 +80000088: 00000813 li a6,0 +8000008c: 00000893 li a7,0 +80000090: 00000913 li s2,0 +80000094: 00000993 li s3,0 +80000098: 00000a13 li s4,0 +8000009c: 00000a93 li s5,0 +800000a0: 00000b13 li s6,0 +800000a4: 00000b93 li s7,0 +800000a8: 00000c13 li s8,0 +800000ac: 00000c93 li s9,0 +800000b0: 00000d13 li s10,0 +800000b4: 00000d93 li s11,0 +800000b8: 00000e13 li t3,0 +800000bc: 00000e93 li t4,0 +800000c0: 00000f13 li t5,0 +800000c4: 00000f93 li t6,0 +800000c8: f1402573 csrr a0,mhartid +800000cc: 00051063 bnez a0,800000cc +800000d0: 00000297 auipc t0,0x0 +800000d4: 01028293 addi t0,t0,16 # 800000e0 +800000d8: 30529073 csrw mtvec,t0 +800000dc: 18005073 csrwi satp,0 +800000e0: 00000297 auipc t0,0x0 +800000e4: 02028293 addi t0,t0,32 # 80000100 +800000e8: 30529073 csrw mtvec,t0 +800000ec: 800002b7 lui t0,0x80000 +800000f0: fff28293 addi t0,t0,-1 # 7fffffff <_end+0xffffdedf> +800000f4: 3b029073 csrw pmpaddr0,t0 +800000f8: 01f00293 li t0,31 +800000fc: 3a029073 csrw pmpcfg0,t0 +80000100: 30405073 csrwi mie,0 +80000104: 00000297 auipc t0,0x0 +80000108: 01428293 addi t0,t0,20 # 80000118 +8000010c: 30529073 csrw mtvec,t0 +80000110: 30205073 csrwi medeleg,0 +80000114: 30305073 csrwi mideleg,0 +80000118: 00000193 li gp,0 +8000011c: 00000297 auipc t0,0x0 +80000120: ee828293 addi t0,t0,-280 # 80000004 +80000124: 30529073 csrw mtvec,t0 +80000128: 00100513 li a0,1 +8000012c: 01f51513 slli a0,a0,0x1f +80000130: 00054c63 bltz a0,80000148 +80000134: 0ff0000f fence +80000138: 00100193 li gp,1 +8000013c: 05d00893 li a7,93 +80000140: 00000513 li a0,0 +80000144: 00000073 ecall +80000148: 80000297 auipc t0,0x80000 +8000014c: eb828293 addi t0,t0,-328 # 0 <_start-0x80000000> +80000150: 00028a63 beqz t0,80000164 +80000154: 10529073 csrw stvec,t0 +80000158: 0000b2b7 lui t0,0xb +8000015c: 10928293 addi t0,t0,265 # b109 <_start-0x7fff4ef7> +80000160: 30229073 csrw medeleg,t0 +80000164: 30005073 csrwi mstatus,0 +80000168: 00002537 lui a0,0x2 +8000016c: 30052073 csrs mstatus,a0 +80000170: 00305073 csrwi fcsr,0 +80000174: 00000297 auipc t0,0x0 +80000178: 01428293 addi t0,t0,20 # 80000188 +8000017c: 34129073 csrw mepc,t0 +80000180: f1402573 csrr a0,mhartid +80000184: 30200073 mret + +80000188 : +80000188: 00200193 li gp,2 +8000018c: 00002517 auipc a0,0x2 +80000190: e7450513 addi a0,a0,-396 # 80002000 +80000194: 00052007 flw ft0,0(a0) +80000198: 00452087 flw ft1,4(a0) +8000019c: 00852107 flw ft2,8(a0) +800001a0: 00c52683 lw a3,12(a0) +800001a4: 281001d3 fmin.s ft3,ft0,ft1 +800001a8: e0018553 fmv.x.w a0,ft3 +800001ac: 001015f3 fsflags a1,zero +800001b0: 00000613 li a2,0 +800001b4: 38d51063 bne a0,a3,80000534 +800001b8: 36c59e63 bne a1,a2,80000534 + +800001bc : +800001bc: 00300193 li gp,3 +800001c0: 00002517 auipc a0,0x2 +800001c4: e5050513 addi a0,a0,-432 # 80002010 +800001c8: 00052007 flw ft0,0(a0) +800001cc: 00452087 flw ft1,4(a0) +800001d0: 00852107 flw ft2,8(a0) +800001d4: 00c52683 lw a3,12(a0) +800001d8: 281001d3 fmin.s ft3,ft0,ft1 +800001dc: e0018553 fmv.x.w a0,ft3 +800001e0: 001015f3 fsflags a1,zero +800001e4: 00000613 li a2,0 +800001e8: 34d51663 bne a0,a3,80000534 +800001ec: 34c59463 bne a1,a2,80000534 + +800001f0 : +800001f0: 00400193 li gp,4 +800001f4: 00002517 auipc a0,0x2 +800001f8: e2c50513 addi a0,a0,-468 # 80002020 +800001fc: 00052007 flw ft0,0(a0) +80000200: 00452087 flw ft1,4(a0) +80000204: 00852107 flw ft2,8(a0) +80000208: 00c52683 lw a3,12(a0) +8000020c: 281001d3 fmin.s ft3,ft0,ft1 +80000210: e0018553 fmv.x.w a0,ft3 +80000214: 001015f3 fsflags a1,zero +80000218: 00000613 li a2,0 +8000021c: 30d51c63 bne a0,a3,80000534 +80000220: 30c59a63 bne a1,a2,80000534 + +80000224 : +80000224: 00500193 li gp,5 +80000228: 00002517 auipc a0,0x2 +8000022c: e0850513 addi a0,a0,-504 # 80002030 +80000230: 00052007 flw ft0,0(a0) +80000234: 00452087 flw ft1,4(a0) +80000238: 00852107 flw ft2,8(a0) +8000023c: 00c52683 lw a3,12(a0) +80000240: 281001d3 fmin.s ft3,ft0,ft1 +80000244: e0018553 fmv.x.w a0,ft3 +80000248: 001015f3 fsflags a1,zero +8000024c: 00000613 li a2,0 +80000250: 2ed51263 bne a0,a3,80000534 +80000254: 2ec59063 bne a1,a2,80000534 + +80000258 : +80000258: 00600193 li gp,6 +8000025c: 00002517 auipc a0,0x2 +80000260: de450513 addi a0,a0,-540 # 80002040 +80000264: 00052007 flw ft0,0(a0) +80000268: 00452087 flw ft1,4(a0) +8000026c: 00852107 flw ft2,8(a0) +80000270: 00c52683 lw a3,12(a0) +80000274: 281001d3 fmin.s ft3,ft0,ft1 +80000278: e0018553 fmv.x.w a0,ft3 +8000027c: 001015f3 fsflags a1,zero +80000280: 00000613 li a2,0 +80000284: 2ad51863 bne a0,a3,80000534 +80000288: 2ac59663 bne a1,a2,80000534 + +8000028c : +8000028c: 00700193 li gp,7 +80000290: 00002517 auipc a0,0x2 +80000294: dc050513 addi a0,a0,-576 # 80002050 +80000298: 00052007 flw ft0,0(a0) +8000029c: 00452087 flw ft1,4(a0) +800002a0: 00852107 flw ft2,8(a0) +800002a4: 00c52683 lw a3,12(a0) +800002a8: 281001d3 fmin.s ft3,ft0,ft1 +800002ac: e0018553 fmv.x.w a0,ft3 +800002b0: 001015f3 fsflags a1,zero +800002b4: 00000613 li a2,0 +800002b8: 26d51e63 bne a0,a3,80000534 +800002bc: 26c59c63 bne a1,a2,80000534 + +800002c0 : +800002c0: 00c00193 li gp,12 +800002c4: 00002517 auipc a0,0x2 +800002c8: d9c50513 addi a0,a0,-612 # 80002060 +800002cc: 00052007 flw ft0,0(a0) +800002d0: 00452087 flw ft1,4(a0) +800002d4: 00852107 flw ft2,8(a0) +800002d8: 00c52683 lw a3,12(a0) +800002dc: 281011d3 fmax.s ft3,ft0,ft1 +800002e0: e0018553 fmv.x.w a0,ft3 +800002e4: 001015f3 fsflags a1,zero +800002e8: 00000613 li a2,0 +800002ec: 24d51463 bne a0,a3,80000534 +800002f0: 24c59263 bne a1,a2,80000534 + +800002f4 : +800002f4: 00d00193 li gp,13 +800002f8: 00002517 auipc a0,0x2 +800002fc: d7850513 addi a0,a0,-648 # 80002070 +80000300: 00052007 flw ft0,0(a0) +80000304: 00452087 flw ft1,4(a0) +80000308: 00852107 flw ft2,8(a0) +8000030c: 00c52683 lw a3,12(a0) +80000310: 281011d3 fmax.s ft3,ft0,ft1 +80000314: e0018553 fmv.x.w a0,ft3 +80000318: 001015f3 fsflags a1,zero +8000031c: 00000613 li a2,0 +80000320: 20d51a63 bne a0,a3,80000534 +80000324: 20c59863 bne a1,a2,80000534 + +80000328 : +80000328: 00e00193 li gp,14 +8000032c: 00002517 auipc a0,0x2 +80000330: d5450513 addi a0,a0,-684 # 80002080 +80000334: 00052007 flw ft0,0(a0) +80000338: 00452087 flw ft1,4(a0) +8000033c: 00852107 flw ft2,8(a0) +80000340: 00c52683 lw a3,12(a0) +80000344: 281011d3 fmax.s ft3,ft0,ft1 +80000348: e0018553 fmv.x.w a0,ft3 +8000034c: 001015f3 fsflags a1,zero +80000350: 00000613 li a2,0 +80000354: 1ed51063 bne a0,a3,80000534 +80000358: 1cc59e63 bne a1,a2,80000534 + +8000035c : +8000035c: 00f00193 li gp,15 +80000360: 00002517 auipc a0,0x2 +80000364: d3050513 addi a0,a0,-720 # 80002090 +80000368: 00052007 flw ft0,0(a0) +8000036c: 00452087 flw ft1,4(a0) +80000370: 00852107 flw ft2,8(a0) +80000374: 00c52683 lw a3,12(a0) +80000378: 281011d3 fmax.s ft3,ft0,ft1 +8000037c: e0018553 fmv.x.w a0,ft3 +80000380: 001015f3 fsflags a1,zero +80000384: 00000613 li a2,0 +80000388: 1ad51663 bne a0,a3,80000534 +8000038c: 1ac59463 bne a1,a2,80000534 + +80000390 : +80000390: 01000193 li gp,16 +80000394: 00002517 auipc a0,0x2 +80000398: d0c50513 addi a0,a0,-756 # 800020a0 +8000039c: 00052007 flw ft0,0(a0) +800003a0: 00452087 flw ft1,4(a0) +800003a4: 00852107 flw ft2,8(a0) +800003a8: 00c52683 lw a3,12(a0) +800003ac: 281011d3 fmax.s ft3,ft0,ft1 +800003b0: e0018553 fmv.x.w a0,ft3 +800003b4: 001015f3 fsflags a1,zero +800003b8: 00000613 li a2,0 +800003bc: 16d51c63 bne a0,a3,80000534 +800003c0: 16c59a63 bne a1,a2,80000534 + +800003c4 : +800003c4: 01100193 li gp,17 +800003c8: 00002517 auipc a0,0x2 +800003cc: ce850513 addi a0,a0,-792 # 800020b0 +800003d0: 00052007 flw ft0,0(a0) +800003d4: 00452087 flw ft1,4(a0) +800003d8: 00852107 flw ft2,8(a0) +800003dc: 00c52683 lw a3,12(a0) +800003e0: 281011d3 fmax.s ft3,ft0,ft1 +800003e4: e0018553 fmv.x.w a0,ft3 +800003e8: 001015f3 fsflags a1,zero +800003ec: 00000613 li a2,0 +800003f0: 14d51263 bne a0,a3,80000534 +800003f4: 14c59063 bne a1,a2,80000534 + +800003f8 : +800003f8: 01400193 li gp,20 +800003fc: 00002517 auipc a0,0x2 +80000400: cc450513 addi a0,a0,-828 # 800020c0 +80000404: 00052007 flw ft0,0(a0) +80000408: 00452087 flw ft1,4(a0) +8000040c: 00852107 flw ft2,8(a0) +80000410: 00c52683 lw a3,12(a0) +80000414: 281011d3 fmax.s ft3,ft0,ft1 +80000418: e0018553 fmv.x.w a0,ft3 +8000041c: 001015f3 fsflags a1,zero +80000420: 01000613 li a2,16 +80000424: 10d51863 bne a0,a3,80000534 +80000428: 10c59663 bne a1,a2,80000534 + +8000042c : +8000042c: 01500193 li gp,21 +80000430: 00002517 auipc a0,0x2 +80000434: ca050513 addi a0,a0,-864 # 800020d0 +80000438: 00052007 flw ft0,0(a0) +8000043c: 00452087 flw ft1,4(a0) +80000440: 00852107 flw ft2,8(a0) +80000444: 00c52683 lw a3,12(a0) +80000448: 281011d3 fmax.s ft3,ft0,ft1 +8000044c: e0018553 fmv.x.w a0,ft3 +80000450: 001015f3 fsflags a1,zero +80000454: 00000613 li a2,0 +80000458: 0cd51e63 bne a0,a3,80000534 +8000045c: 0cc59c63 bne a1,a2,80000534 + +80000460 : +80000460: 01e00193 li gp,30 +80000464: 00002517 auipc a0,0x2 +80000468: c7c50513 addi a0,a0,-900 # 800020e0 +8000046c: 00052007 flw ft0,0(a0) +80000470: 00452087 flw ft1,4(a0) +80000474: 00852107 flw ft2,8(a0) +80000478: 00c52683 lw a3,12(a0) +8000047c: 281001d3 fmin.s ft3,ft0,ft1 +80000480: e0018553 fmv.x.w a0,ft3 +80000484: 001015f3 fsflags a1,zero +80000488: 00000613 li a2,0 +8000048c: 0ad51463 bne a0,a3,80000534 +80000490: 0ac59263 bne a1,a2,80000534 + +80000494 : +80000494: 01f00193 li gp,31 +80000498: 00002517 auipc a0,0x2 +8000049c: c5850513 addi a0,a0,-936 # 800020f0 +800004a0: 00052007 flw ft0,0(a0) +800004a4: 00452087 flw ft1,4(a0) +800004a8: 00852107 flw ft2,8(a0) +800004ac: 00c52683 lw a3,12(a0) +800004b0: 281001d3 fmin.s ft3,ft0,ft1 +800004b4: e0018553 fmv.x.w a0,ft3 +800004b8: 001015f3 fsflags a1,zero +800004bc: 00000613 li a2,0 +800004c0: 06d51a63 bne a0,a3,80000534 +800004c4: 06c59863 bne a1,a2,80000534 + +800004c8 : +800004c8: 02000193 li gp,32 +800004cc: 00002517 auipc a0,0x2 +800004d0: c3450513 addi a0,a0,-972 # 80002100 +800004d4: 00052007 flw ft0,0(a0) +800004d8: 00452087 flw ft1,4(a0) +800004dc: 00852107 flw ft2,8(a0) +800004e0: 00c52683 lw a3,12(a0) +800004e4: 281011d3 fmax.s ft3,ft0,ft1 +800004e8: e0018553 fmv.x.w a0,ft3 +800004ec: 001015f3 fsflags a1,zero +800004f0: 00000613 li a2,0 +800004f4: 04d51063 bne a0,a3,80000534 +800004f8: 02c59e63 bne a1,a2,80000534 + +800004fc : +800004fc: 02100193 li gp,33 +80000500: 00002517 auipc a0,0x2 +80000504: c1050513 addi a0,a0,-1008 # 80002110 +80000508: 00052007 flw ft0,0(a0) +8000050c: 00452087 flw ft1,4(a0) +80000510: 00852107 flw ft2,8(a0) +80000514: 00c52683 lw a3,12(a0) +80000518: 281011d3 fmax.s ft3,ft0,ft1 +8000051c: e0018553 fmv.x.w a0,ft3 +80000520: 001015f3 fsflags a1,zero +80000524: 00000613 li a2,0 +80000528: 00d51663 bne a0,a3,80000534 +8000052c: 00c59463 bne a1,a2,80000534 +80000530: 02301063 bne zero,gp,80000550 + +80000534 : +80000534: 0ff0000f fence +80000538: 00018063 beqz gp,80000538 +8000053c: 00119193 slli gp,gp,0x1 +80000540: 0011e193 ori gp,gp,1 +80000544: 05d00893 li a7,93 +80000548: 00018513 mv a0,gp +8000054c: 00000073 ecall + +80000550 : +80000550: 0ff0000f fence +80000554: 00100193 li gp,1 +80000558: 05d00893 li a7,93 +8000055c: 00000513 li a0,0 +80000560: 00000073 ecall +80000564: c0001073 unimp +80000568: 0000 unimp +8000056a: 0000 unimp +8000056c: 0000 unimp +8000056e: 0000 unimp +80000570: 0000 unimp +80000572: 0000 unimp +80000574: 0000 unimp +80000576: 0000 unimp +80000578: 0000 unimp +8000057a: 0000 unimp +8000057c: 0000 unimp +8000057e: 0000 unimp +80000580: 0000 unimp +80000582: 0000 unimp + +Disassembly of section .data: + +80002000 : +80002000: 0000 unimp +80002002: 4020 lw s0,64(s0) +80002004: 0000 unimp +80002006: 3f80 fld fs0,56(a5) +80002008: 0000 unimp +8000200a: 0000 unimp +8000200c: 0000 unimp +8000200e: 3f80 fld fs0,56(a5) + +80002010 : +80002010: c49a6333 0xc49a6333 +80002014: cccd beqz s1,800020ce +80002016: 3f8c fld fa1,56(a5) +80002018: 0000 unimp +8000201a: 0000 unimp +8000201c: c49a6333 0xc49a6333 + +80002020 : +80002020: cccd beqz s1,800020da +80002022: 3f8c fld fa1,56(a5) +80002024: c49a6333 0xc49a6333 +80002028: 0000 unimp +8000202a: 0000 unimp +8000202c: c49a6333 0xc49a6333 + +80002030 : +80002030: ffff 0xffff +80002032: 7fff 0x7fff +80002034: c49a6333 0xc49a6333 +80002038: 0000 unimp +8000203a: 0000 unimp +8000203c: c49a6333 0xc49a6333 + +80002040 : +80002040: 40490fdb 0x40490fdb +80002044: 322bcc77 0x322bcc77 +80002048: 0000 unimp +8000204a: 0000 unimp +8000204c: 322bcc77 0x322bcc77 + +80002050 : +80002050: 0000 unimp +80002052: bf80 fsd fs0,56(a5) +80002054: 0000 unimp +80002056: c000 sw s0,0(s0) +80002058: 0000 unimp +8000205a: 0000 unimp +8000205c: 0000 unimp +8000205e: c000 sw s0,0(s0) + +80002060 : +80002060: 0000 unimp +80002062: 4020 lw s0,64(s0) +80002064: 0000 unimp +80002066: 3f80 fld fs0,56(a5) +80002068: 0000 unimp +8000206a: 0000 unimp +8000206c: 0000 unimp +8000206e: 4020 lw s0,64(s0) + +80002070 : +80002070: c49a6333 0xc49a6333 +80002074: cccd beqz s1,8000212e <_end+0xe> +80002076: 3f8c fld fa1,56(a5) +80002078: 0000 unimp +8000207a: 0000 unimp +8000207c: cccd beqz s1,80002136 <_end+0x16> +8000207e: 3f8c fld fa1,56(a5) + +80002080 : +80002080: cccd beqz s1,8000213a <_end+0x1a> +80002082: 3f8c fld fa1,56(a5) +80002084: c49a6333 0xc49a6333 +80002088: 0000 unimp +8000208a: 0000 unimp +8000208c: cccd beqz s1,80002146 <_end+0x26> +8000208e: 3f8c fld fa1,56(a5) + +80002090 : +80002090: ffff 0xffff +80002092: 7fff 0x7fff +80002094: c49a6333 0xc49a6333 +80002098: 0000 unimp +8000209a: 0000 unimp +8000209c: c49a6333 0xc49a6333 + +800020a0 : +800020a0: 40490fdb 0x40490fdb +800020a4: 322bcc77 0x322bcc77 +800020a8: 0000 unimp +800020aa: 0000 unimp +800020ac: 40490fdb 0x40490fdb + +800020b0 : +800020b0: 0000 unimp +800020b2: bf80 fsd fs0,56(a5) +800020b4: 0000 unimp +800020b6: c000 sw s0,0(s0) +800020b8: 0000 unimp +800020ba: 0000 unimp +800020bc: 0000 unimp +800020be: bf80 fsd fs0,56(a5) + +800020c0 : +800020c0: 0001 nop +800020c2: 7f80 flw fs0,56(a5) +800020c4: 0000 unimp +800020c6: 3f80 fld fs0,56(a5) +800020c8: 0000 unimp +800020ca: 0000 unimp +800020cc: 0000 unimp +800020ce: 3f80 fld fs0,56(a5) + +800020d0 : +800020d0: ffff 0xffff +800020d2: 7fff 0x7fff +800020d4: ffff 0xffff +800020d6: 7fff 0x7fff +800020d8: 0000 unimp +800020da: 0000 unimp +800020dc: 0000 unimp +800020de: 7fc0 flw fs0,60(a5) + +800020e0 : +800020e0: 0000 unimp +800020e2: 8000 0x8000 +800020e4: 0000 unimp +800020e6: 0000 unimp +800020e8: 0000 unimp +800020ea: 0000 unimp +800020ec: 0000 unimp +800020ee: 8000 0x8000 + +800020f0 : +800020f0: 0000 unimp +800020f2: 0000 unimp +800020f4: 0000 unimp +800020f6: 8000 0x8000 +800020f8: 0000 unimp +800020fa: 0000 unimp +800020fc: 0000 unimp +800020fe: 8000 0x8000 + +80002100 : +80002100: 0000 unimp +80002102: 8000 0x8000 +80002104: 0000 unimp +80002106: 0000 unimp +80002108: 0000 unimp +8000210a: 0000 unimp +8000210c: 0000 unimp +8000210e: 0000 unimp + +80002110 : +80002110: 0000 unimp +80002112: 0000 unimp +80002114: 0000 unimp +80002116: 8000 0x8000 +80002118: 0000 unimp +8000211a: 0000 unimp +8000211c: 0000 unimp +8000211e: 0000 unimp diff --git a/src/test/resources/asm/rv32uf-p-ldst.dump b/src/test/resources/asm/rv32uf-p-ldst.dump new file mode 100644 index 00000000..7550b730 --- /dev/null +++ b/src/test/resources/asm/rv32uf-p-ldst.dump @@ -0,0 +1,172 @@ + +rv32uf-p-ldst: file format elf32-littleriscv + + +Disassembly of section .text.init: + +80000000 <_start>: +80000000: 04c0006f j 8000004c + +80000004 : +80000004: 34202f73 csrr t5,mcause +80000008: 00800f93 li t6,8 +8000000c: 03ff0a63 beq t5,t6,80000040 +80000010: 00900f93 li t6,9 +80000014: 03ff0663 beq t5,t6,80000040 +80000018: 00b00f93 li t6,11 +8000001c: 03ff0263 beq t5,t6,80000040 +80000020: 80000f17 auipc t5,0x80000 +80000024: fe0f0f13 addi t5,t5,-32 # 0 <_start-0x80000000> +80000028: 000f0463 beqz t5,80000030 +8000002c: 000f0067 jr t5 +80000030: 34202f73 csrr t5,mcause +80000034: 000f5463 bgez t5,8000003c +80000038: 0040006f j 8000003c + +8000003c : +8000003c: 5391e193 ori gp,gp,1337 + +80000040 : +80000040: 00001f17 auipc t5,0x1 +80000044: fc3f2023 sw gp,-64(t5) # 80001000 +80000048: ff9ff06f j 80000040 + +8000004c : +8000004c: 00000093 li ra,0 +80000050: 00000113 li sp,0 +80000054: 00000193 li gp,0 +80000058: 00000213 li tp,0 +8000005c: 00000293 li t0,0 +80000060: 00000313 li t1,0 +80000064: 00000393 li t2,0 +80000068: 00000413 li s0,0 +8000006c: 00000493 li s1,0 +80000070: 00000513 li a0,0 +80000074: 00000593 li a1,0 +80000078: 00000613 li a2,0 +8000007c: 00000693 li a3,0 +80000080: 00000713 li a4,0 +80000084: 00000793 li a5,0 +80000088: 00000813 li a6,0 +8000008c: 00000893 li a7,0 +80000090: 00000913 li s2,0 +80000094: 00000993 li s3,0 +80000098: 00000a13 li s4,0 +8000009c: 00000a93 li s5,0 +800000a0: 00000b13 li s6,0 +800000a4: 00000b93 li s7,0 +800000a8: 00000c13 li s8,0 +800000ac: 00000c93 li s9,0 +800000b0: 00000d13 li s10,0 +800000b4: 00000d93 li s11,0 +800000b8: 00000e13 li t3,0 +800000bc: 00000e93 li t4,0 +800000c0: 00000f13 li t5,0 +800000c4: 00000f93 li t6,0 +800000c8: f1402573 csrr a0,mhartid +800000cc: 00051063 bnez a0,800000cc +800000d0: 00000297 auipc t0,0x0 +800000d4: 01028293 addi t0,t0,16 # 800000e0 +800000d8: 30529073 csrw mtvec,t0 +800000dc: 18005073 csrwi satp,0 +800000e0: 00000297 auipc t0,0x0 +800000e4: 02028293 addi t0,t0,32 # 80000100 +800000e8: 30529073 csrw mtvec,t0 +800000ec: 800002b7 lui t0,0x80000 +800000f0: fff28293 addi t0,t0,-1 # 7fffffff <_end+0xffffdfdf> +800000f4: 3b029073 csrw pmpaddr0,t0 +800000f8: 01f00293 li t0,31 +800000fc: 3a029073 csrw pmpcfg0,t0 +80000100: 30405073 csrwi mie,0 +80000104: 00000297 auipc t0,0x0 +80000108: 01428293 addi t0,t0,20 # 80000118 +8000010c: 30529073 csrw mtvec,t0 +80000110: 30205073 csrwi medeleg,0 +80000114: 30305073 csrwi mideleg,0 +80000118: 00000193 li gp,0 +8000011c: 00000297 auipc t0,0x0 +80000120: ee828293 addi t0,t0,-280 # 80000004 +80000124: 30529073 csrw mtvec,t0 +80000128: 00100513 li a0,1 +8000012c: 01f51513 slli a0,a0,0x1f +80000130: 00054c63 bltz a0,80000148 +80000134: 0ff0000f fence +80000138: 00100193 li gp,1 +8000013c: 05d00893 li a7,93 +80000140: 00000513 li a0,0 +80000144: 00000073 ecall +80000148: 80000297 auipc t0,0x80000 +8000014c: eb828293 addi t0,t0,-328 # 0 <_start-0x80000000> +80000150: 00028a63 beqz t0,80000164 +80000154: 10529073 csrw stvec,t0 +80000158: 0000b2b7 lui t0,0xb +8000015c: 10928293 addi t0,t0,265 # b109 <_start-0x7fff4ef7> +80000160: 30229073 csrw medeleg,t0 +80000164: 30005073 csrwi mstatus,0 +80000168: 00002537 lui a0,0x2 +8000016c: 30052073 csrs mstatus,a0 +80000170: 00305073 csrwi fcsr,0 +80000174: 00000297 auipc t0,0x0 +80000178: 01428293 addi t0,t0,20 # 80000188 +8000017c: 34129073 csrw mepc,t0 +80000180: f1402573 csrr a0,mhartid +80000184: 30200073 mret + +80000188 : +80000188: 00002597 auipc a1,0x2 +8000018c: e7858593 addi a1,a1,-392 # 80002000 +80000190: 0045a087 flw ft1,4(a1) +80000194: 0015aa27 fsw ft1,20(a1) +80000198: 0145a503 lw a0,20(a1) +8000019c: 400003b7 lui t2,0x40000 +800001a0: 00200193 li gp,2 +800001a4: 02751463 bne a0,t2,800001cc + +800001a8 : +800001a8: 00002597 auipc a1,0x2 +800001ac: e5858593 addi a1,a1,-424 # 80002000 +800001b0: 0005a087 flw ft1,0(a1) +800001b4: 0015ac27 fsw ft1,24(a1) +800001b8: 0185a503 lw a0,24(a1) +800001bc: bf8003b7 lui t2,0xbf800 +800001c0: 00300193 li gp,3 +800001c4: 00751463 bne a0,t2,800001cc +800001c8: 02301063 bne zero,gp,800001e8 + +800001cc : +800001cc: 0ff0000f fence +800001d0: 00018063 beqz gp,800001d0 +800001d4: 00119193 slli gp,gp,0x1 +800001d8: 0011e193 ori gp,gp,1 +800001dc: 05d00893 li a7,93 +800001e0: 00018513 mv a0,gp +800001e4: 00000073 ecall + +800001e8 : +800001e8: 0ff0000f fence +800001ec: 00100193 li gp,1 +800001f0: 05d00893 li a7,93 +800001f4: 00000513 li a0,0 +800001f8: 00000073 ecall +800001fc: c0001073 unimp +80000200: 0000 unimp +80000202: 0000 unimp + +Disassembly of section .data: + +80002000 : +80002000: 0000 unimp +80002002: bf80 fsd fs0,56(a5) +80002004: 0000 unimp +80002006: 4000 lw s0,0(s0) +80002008: 0000 unimp +8000200a: 4040 lw s0,4(s0) +8000200c: 0000 unimp +8000200e: c080 sw s0,0(s1) +80002010: deadbeef jal t4,7ffdd5fa <_start-0x22a06> +80002014: babe fsd fa5,368(sp) +80002016: cafe sw t6,84(sp) +80002018: 1dea slli s11,s11,0x3a +8000201a: abad j 80002594 <_end+0x574> +8000201c: d00d beqz s0,80001f3e +8000201e: lui t1,0x1 diff --git a/src/test/resources/asm/rv32uf-p-move.dump b/src/test/resources/asm/rv32uf-p-move.dump new file mode 100644 index 00000000..045df286 --- /dev/null +++ b/src/test/resources/asm/rv32uf-p-move.dump @@ -0,0 +1,360 @@ + +rv32uf-p-move: file format elf32-littleriscv + + +Disassembly of section .text.init: + +80000000 <_start>: +80000000: 04c0006f j 8000004c + +80000004 : +80000004: 34202f73 csrr t5,mcause +80000008: 00800f93 li t6,8 +8000000c: 03ff0a63 beq t5,t6,80000040 +80000010: 00900f93 li t6,9 +80000014: 03ff0663 beq t5,t6,80000040 +80000018: 00b00f93 li t6,11 +8000001c: 03ff0263 beq t5,t6,80000040 +80000020: 80000f17 auipc t5,0x80000 +80000024: fe0f0f13 addi t5,t5,-32 # 0 <_start-0x80000000> +80000028: 000f0463 beqz t5,80000030 +8000002c: 000f0067 jr t5 +80000030: 34202f73 csrr t5,mcause +80000034: 000f5463 bgez t5,8000003c +80000038: 0040006f j 8000003c + +8000003c : +8000003c: 5391e193 ori gp,gp,1337 + +80000040 : +80000040: 00001f17 auipc t5,0x1 +80000044: fc3f2023 sw gp,-64(t5) # 80001000 +80000048: ff9ff06f j 80000040 + +8000004c : +8000004c: 00000093 li ra,0 +80000050: 00000113 li sp,0 +80000054: 00000193 li gp,0 +80000058: 00000213 li tp,0 +8000005c: 00000293 li t0,0 +80000060: 00000313 li t1,0 +80000064: 00000393 li t2,0 +80000068: 00000413 li s0,0 +8000006c: 00000493 li s1,0 +80000070: 00000513 li a0,0 +80000074: 00000593 li a1,0 +80000078: 00000613 li a2,0 +8000007c: 00000693 li a3,0 +80000080: 00000713 li a4,0 +80000084: 00000793 li a5,0 +80000088: 00000813 li a6,0 +8000008c: 00000893 li a7,0 +80000090: 00000913 li s2,0 +80000094: 00000993 li s3,0 +80000098: 00000a13 li s4,0 +8000009c: 00000a93 li s5,0 +800000a0: 00000b13 li s6,0 +800000a4: 00000b93 li s7,0 +800000a8: 00000c13 li s8,0 +800000ac: 00000c93 li s9,0 +800000b0: 00000d13 li s10,0 +800000b4: 00000d93 li s11,0 +800000b8: 00000e13 li t3,0 +800000bc: 00000e93 li t4,0 +800000c0: 00000f13 li t5,0 +800000c4: 00000f93 li t6,0 +800000c8: f1402573 csrr a0,mhartid +800000cc: 00051063 bnez a0,800000cc +800000d0: 00000297 auipc t0,0x0 +800000d4: 01028293 addi t0,t0,16 # 800000e0 +800000d8: 30529073 csrw mtvec,t0 +800000dc: 18005073 csrwi satp,0 +800000e0: 00000297 auipc t0,0x0 +800000e4: 02028293 addi t0,t0,32 # 80000100 +800000e8: 30529073 csrw mtvec,t0 +800000ec: 800002b7 lui t0,0x80000 +800000f0: fff28293 addi t0,t0,-1 # 7fffffff <_end+0xffffdfff> +800000f4: 3b029073 csrw pmpaddr0,t0 +800000f8: 01f00293 li t0,31 +800000fc: 3a029073 csrw pmpcfg0,t0 +80000100: 30405073 csrwi mie,0 +80000104: 00000297 auipc t0,0x0 +80000108: 01428293 addi t0,t0,20 # 80000118 +8000010c: 30529073 csrw mtvec,t0 +80000110: 30205073 csrwi medeleg,0 +80000114: 30305073 csrwi mideleg,0 +80000118: 00000193 li gp,0 +8000011c: 00000297 auipc t0,0x0 +80000120: ee828293 addi t0,t0,-280 # 80000004 +80000124: 30529073 csrw mtvec,t0 +80000128: 00100513 li a0,1 +8000012c: 01f51513 slli a0,a0,0x1f +80000130: 00054c63 bltz a0,80000148 +80000134: 0ff0000f fence +80000138: 00100193 li gp,1 +8000013c: 05d00893 li a7,93 +80000140: 00000513 li a0,0 +80000144: 00000073 ecall +80000148: 80000297 auipc t0,0x80000 +8000014c: eb828293 addi t0,t0,-328 # 0 <_start-0x80000000> +80000150: 00028a63 beqz t0,80000164 +80000154: 10529073 csrw stvec,t0 +80000158: 0000b2b7 lui t0,0xb +8000015c: 10928293 addi t0,t0,265 # b109 <_start-0x7fff4ef7> +80000160: 30229073 csrw medeleg,t0 +80000164: 30005073 csrwi mstatus,0 +80000168: 00002537 lui a0,0x2 +8000016c: 30052073 csrs mstatus,a0 +80000170: 00305073 csrwi fcsr,0 +80000174: 00000297 auipc t0,0x0 +80000178: 01428293 addi t0,t0,20 # 80000188 +8000017c: 34129073 csrw mepc,t0 +80000180: f1402573 csrr a0,mhartid +80000184: 30200073 mret + +80000188 : +80000188: 0030d073 csrwi fcsr,1 +8000018c: 00001537 lui a0,0x1 +80000190: 23450513 addi a0,a0,564 # 1234 <_start-0x7fffedcc> +80000194: 003515f3 fscsr a1,a0 +80000198: 00100393 li t2,1 +8000019c: 00200193 li gp,2 +800001a0: 26759c63 bne a1,t2,80000418 + +800001a4 : +800001a4: 00302573 frcsr a0 +800001a8: 03400393 li t2,52 +800001ac: 00300193 li gp,3 +800001b0: 26751463 bne a0,t2,80000418 + +800001b4 : +800001b4: 00102573 frflags a0 +800001b8: 01400393 li t2,20 +800001bc: 00400193 li gp,4 +800001c0: 24751c63 bne a0,t2,80000418 + +800001c4 : +800001c4: 00215573 fsrmi a0,2 +800001c8: 00100393 li t2,1 +800001cc: 00500193 li gp,5 +800001d0: 24751463 bne a0,t2,80000418 + +800001d4 : +800001d4: 00302573 frcsr a0 +800001d8: 05400393 li t2,84 +800001dc: 00600193 li gp,6 +800001e0: 22751c63 bne a0,t2,80000418 + +800001e4 : +800001e4: 00127573 csrrci a0,fflags,4 +800001e8: 01400393 li t2,20 +800001ec: 00700193 li gp,7 +800001f0: 22751463 bne a0,t2,80000418 + +800001f4 : +800001f4: 00302573 frcsr a0 +800001f8: 05000393 li t2,80 +800001fc: 00800193 li gp,8 +80000200: 20751c63 bne a0,t2,80000418 + +80000204 : +80000204: 123455b7 lui a1,0x12345 +80000208: 67858593 addi a1,a1,1656 # 12345678 <_start-0x6dcba988> +8000020c: 00000613 li a2,0 +80000210: f00580d3 fmv.w.x ft1,a1 +80000214: f0060153 fmv.w.x ft2,a2 +80000218: 20208053 fsgnj.s ft0,ft1,ft2 +8000021c: e0000553 fmv.x.w a0,ft0 +80000220: 123453b7 lui t2,0x12345 +80000224: 67838393 addi t2,t2,1656 # 12345678 <_start-0x6dcba988> +80000228: 00a00193 li gp,10 +8000022c: 1e751663 bne a0,t2,80000418 + +80000230 : +80000230: 123455b7 lui a1,0x12345 +80000234: 67858593 addi a1,a1,1656 # 12345678 <_start-0x6dcba988> +80000238: fff00613 li a2,-1 +8000023c: f00580d3 fmv.w.x ft1,a1 +80000240: f0060153 fmv.w.x ft2,a2 +80000244: 20208053 fsgnj.s ft0,ft1,ft2 +80000248: e0000553 fmv.x.w a0,ft0 +8000024c: 923453b7 lui t2,0x92345 +80000250: 67838393 addi t2,t2,1656 # 92345678 <_end+0x12343678> +80000254: 00b00193 li gp,11 +80000258: 1c751063 bne a0,t2,80000418 + +8000025c : +8000025c: 923455b7 lui a1,0x92345 +80000260: 67858593 addi a1,a1,1656 # 92345678 <_end+0x12343678> +80000264: 00000613 li a2,0 +80000268: f00580d3 fmv.w.x ft1,a1 +8000026c: f0060153 fmv.w.x ft2,a2 +80000270: 20208053 fsgnj.s ft0,ft1,ft2 +80000274: e0000553 fmv.x.w a0,ft0 +80000278: 123453b7 lui t2,0x12345 +8000027c: 67838393 addi t2,t2,1656 # 12345678 <_start-0x6dcba988> +80000280: 00c00193 li gp,12 +80000284: 18751a63 bne a0,t2,80000418 + +80000288 : +80000288: 923455b7 lui a1,0x92345 +8000028c: 67858593 addi a1,a1,1656 # 92345678 <_end+0x12343678> +80000290: fff00613 li a2,-1 +80000294: f00580d3 fmv.w.x ft1,a1 +80000298: f0060153 fmv.w.x ft2,a2 +8000029c: 20208053 fsgnj.s ft0,ft1,ft2 +800002a0: e0000553 fmv.x.w a0,ft0 +800002a4: 923453b7 lui t2,0x92345 +800002a8: 67838393 addi t2,t2,1656 # 92345678 <_end+0x12343678> +800002ac: 00d00193 li gp,13 +800002b0: 16751463 bne a0,t2,80000418 + +800002b4 : +800002b4: 123455b7 lui a1,0x12345 +800002b8: 67858593 addi a1,a1,1656 # 12345678 <_start-0x6dcba988> +800002bc: 00000613 li a2,0 +800002c0: f00580d3 fmv.w.x ft1,a1 +800002c4: f0060153 fmv.w.x ft2,a2 +800002c8: 20209053 fsgnjn.s ft0,ft1,ft2 +800002cc: e0000553 fmv.x.w a0,ft0 +800002d0: 923453b7 lui t2,0x92345 +800002d4: 67838393 addi t2,t2,1656 # 92345678 <_end+0x12343678> +800002d8: 01400193 li gp,20 +800002dc: 12751e63 bne a0,t2,80000418 + +800002e0 : +800002e0: 123455b7 lui a1,0x12345 +800002e4: 67858593 addi a1,a1,1656 # 12345678 <_start-0x6dcba988> +800002e8: fff00613 li a2,-1 +800002ec: f00580d3 fmv.w.x ft1,a1 +800002f0: f0060153 fmv.w.x ft2,a2 +800002f4: 20209053 fsgnjn.s ft0,ft1,ft2 +800002f8: e0000553 fmv.x.w a0,ft0 +800002fc: 123453b7 lui t2,0x12345 +80000300: 67838393 addi t2,t2,1656 # 12345678 <_start-0x6dcba988> +80000304: 01500193 li gp,21 +80000308: 10751863 bne a0,t2,80000418 + +8000030c : +8000030c: 923455b7 lui a1,0x92345 +80000310: 67858593 addi a1,a1,1656 # 92345678 <_end+0x12343678> +80000314: 00000613 li a2,0 +80000318: f00580d3 fmv.w.x ft1,a1 +8000031c: f0060153 fmv.w.x ft2,a2 +80000320: 20209053 fsgnjn.s ft0,ft1,ft2 +80000324: e0000553 fmv.x.w a0,ft0 +80000328: 923453b7 lui t2,0x92345 +8000032c: 67838393 addi t2,t2,1656 # 92345678 <_end+0x12343678> +80000330: 01600193 li gp,22 +80000334: 0e751263 bne a0,t2,80000418 + +80000338 : +80000338: 923455b7 lui a1,0x92345 +8000033c: 67858593 addi a1,a1,1656 # 92345678 <_end+0x12343678> +80000340: fff00613 li a2,-1 +80000344: f00580d3 fmv.w.x ft1,a1 +80000348: f0060153 fmv.w.x ft2,a2 +8000034c: 20209053 fsgnjn.s ft0,ft1,ft2 +80000350: e0000553 fmv.x.w a0,ft0 +80000354: 123453b7 lui t2,0x12345 +80000358: 67838393 addi t2,t2,1656 # 12345678 <_start-0x6dcba988> +8000035c: 01700193 li gp,23 +80000360: 0a751c63 bne a0,t2,80000418 + +80000364 : +80000364: 123455b7 lui a1,0x12345 +80000368: 67858593 addi a1,a1,1656 # 12345678 <_start-0x6dcba988> +8000036c: 00000613 li a2,0 +80000370: f00580d3 fmv.w.x ft1,a1 +80000374: f0060153 fmv.w.x ft2,a2 +80000378: 2020a053 fsgnjx.s ft0,ft1,ft2 +8000037c: e0000553 fmv.x.w a0,ft0 +80000380: 123453b7 lui t2,0x12345 +80000384: 67838393 addi t2,t2,1656 # 12345678 <_start-0x6dcba988> +80000388: 01e00193 li gp,30 +8000038c: 08751663 bne a0,t2,80000418 + +80000390 : +80000390: 123455b7 lui a1,0x12345 +80000394: 67858593 addi a1,a1,1656 # 12345678 <_start-0x6dcba988> +80000398: fff00613 li a2,-1 +8000039c: f00580d3 fmv.w.x ft1,a1 +800003a0: f0060153 fmv.w.x ft2,a2 +800003a4: 2020a053 fsgnjx.s ft0,ft1,ft2 +800003a8: e0000553 fmv.x.w a0,ft0 +800003ac: 923453b7 lui t2,0x92345 +800003b0: 67838393 addi t2,t2,1656 # 92345678 <_end+0x12343678> +800003b4: 01f00193 li gp,31 +800003b8: 06751063 bne a0,t2,80000418 + +800003bc : +800003bc: 923455b7 lui a1,0x92345 +800003c0: 67858593 addi a1,a1,1656 # 92345678 <_end+0x12343678> +800003c4: 00000613 li a2,0 +800003c8: f00580d3 fmv.w.x ft1,a1 +800003cc: f0060153 fmv.w.x ft2,a2 +800003d0: 2020a053 fsgnjx.s ft0,ft1,ft2 +800003d4: e0000553 fmv.x.w a0,ft0 +800003d8: 923453b7 lui t2,0x92345 +800003dc: 67838393 addi t2,t2,1656 # 92345678 <_end+0x12343678> +800003e0: 02000193 li gp,32 +800003e4: 02751a63 bne a0,t2,80000418 + +800003e8 : +800003e8: 923455b7 lui a1,0x92345 +800003ec: 67858593 addi a1,a1,1656 # 92345678 <_end+0x12343678> +800003f0: fff00613 li a2,-1 +800003f4: f00580d3 fmv.w.x ft1,a1 +800003f8: f0060153 fmv.w.x ft2,a2 +800003fc: 2020a053 fsgnjx.s ft0,ft1,ft2 +80000400: e0000553 fmv.x.w a0,ft0 +80000404: 123453b7 lui t2,0x12345 +80000408: 67838393 addi t2,t2,1656 # 12345678 <_start-0x6dcba988> +8000040c: 02100193 li gp,33 +80000410: 00751463 bne a0,t2,80000418 +80000414: 02301063 bne zero,gp,80000434 + +80000418 : +80000418: 0ff0000f fence +8000041c: 00018063 beqz gp,8000041c +80000420: 00119193 slli gp,gp,0x1 +80000424: 0011e193 ori gp,gp,1 +80000428: 05d00893 li a7,93 +8000042c: 00018513 mv a0,gp +80000430: 00000073 ecall + +80000434 : +80000434: 0ff0000f fence +80000438: 00100193 li gp,1 +8000043c: 05d00893 li a7,93 +80000440: 00000513 li a0,0 +80000444: 00000073 ecall +80000448: c0001073 unimp +8000044c: 0000 unimp +8000044e: 0000 unimp +80000450: 0000 unimp +80000452: 0000 unimp +80000454: 0000 unimp +80000456: 0000 unimp +80000458: 0000 unimp +8000045a: 0000 unimp +8000045c: 0000 unimp +8000045e: 0000 unimp +80000460: 0000 unimp +80000462: 0000 unimp +80000464: 0000 unimp +80000466: 0000 unimp +80000468: 0000 unimp +8000046a: 0000 unimp +8000046c: 0000 unimp +8000046e: 0000 unimp +80000470: 0000 unimp +80000472: 0000 unimp +80000474: 0000 unimp +80000476: 0000 unimp +80000478: 0000 unimp +8000047a: 0000 unimp +8000047c: 0000 unimp +8000047e: 0000 unimp +80000480: 0000 unimp +80000482: 0000 unimp diff --git a/src/test/resources/asm/rv32uf-p-recoding.dump b/src/test/resources/asm/rv32uf-p-recoding.dump new file mode 100644 index 00000000..12d0f41b --- /dev/null +++ b/src/test/resources/asm/rv32uf-p-recoding.dump @@ -0,0 +1,190 @@ + +rv32uf-p-recoding: file format elf32-littleriscv + + +Disassembly of section .text.init: + +80000000 <_start>: +80000000: 04c0006f j 8000004c + +80000004 : +80000004: 34202f73 csrr t5,mcause +80000008: 00800f93 li t6,8 +8000000c: 03ff0a63 beq t5,t6,80000040 +80000010: 00900f93 li t6,9 +80000014: 03ff0663 beq t5,t6,80000040 +80000018: 00b00f93 li t6,11 +8000001c: 03ff0263 beq t5,t6,80000040 +80000020: 80000f17 auipc t5,0x80000 +80000024: fe0f0f13 addi t5,t5,-32 # 0 <_start-0x80000000> +80000028: 000f0463 beqz t5,80000030 +8000002c: 000f0067 jr t5 +80000030: 34202f73 csrr t5,mcause +80000034: 000f5463 bgez t5,8000003c +80000038: 0040006f j 8000003c + +8000003c : +8000003c: 5391e193 ori gp,gp,1337 + +80000040 : +80000040: 00001f17 auipc t5,0x1 +80000044: fc3f2023 sw gp,-64(t5) # 80001000 +80000048: ff9ff06f j 80000040 + +8000004c : +8000004c: 00000093 li ra,0 +80000050: 00000113 li sp,0 +80000054: 00000193 li gp,0 +80000058: 00000213 li tp,0 +8000005c: 00000293 li t0,0 +80000060: 00000313 li t1,0 +80000064: 00000393 li t2,0 +80000068: 00000413 li s0,0 +8000006c: 00000493 li s1,0 +80000070: 00000513 li a0,0 +80000074: 00000593 li a1,0 +80000078: 00000613 li a2,0 +8000007c: 00000693 li a3,0 +80000080: 00000713 li a4,0 +80000084: 00000793 li a5,0 +80000088: 00000813 li a6,0 +8000008c: 00000893 li a7,0 +80000090: 00000913 li s2,0 +80000094: 00000993 li s3,0 +80000098: 00000a13 li s4,0 +8000009c: 00000a93 li s5,0 +800000a0: 00000b13 li s6,0 +800000a4: 00000b93 li s7,0 +800000a8: 00000c13 li s8,0 +800000ac: 00000c93 li s9,0 +800000b0: 00000d13 li s10,0 +800000b4: 00000d93 li s11,0 +800000b8: 00000e13 li t3,0 +800000bc: 00000e93 li t4,0 +800000c0: 00000f13 li t5,0 +800000c4: 00000f93 li t6,0 +800000c8: f1402573 csrr a0,mhartid +800000cc: 00051063 bnez a0,800000cc +800000d0: 00000297 auipc t0,0x0 +800000d4: 01028293 addi t0,t0,16 # 800000e0 +800000d8: 30529073 csrw mtvec,t0 +800000dc: 18005073 csrwi satp,0 +800000e0: 00000297 auipc t0,0x0 +800000e4: 02028293 addi t0,t0,32 # 80000100 +800000e8: 30529073 csrw mtvec,t0 +800000ec: 800002b7 lui t0,0x80000 +800000f0: fff28293 addi t0,t0,-1 # 7fffffff <_end+0xffffdfef> +800000f4: 3b029073 csrw pmpaddr0,t0 +800000f8: 01f00293 li t0,31 +800000fc: 3a029073 csrw pmpcfg0,t0 +80000100: 30405073 csrwi mie,0 +80000104: 00000297 auipc t0,0x0 +80000108: 01428293 addi t0,t0,20 # 80000118 +8000010c: 30529073 csrw mtvec,t0 +80000110: 30205073 csrwi medeleg,0 +80000114: 30305073 csrwi mideleg,0 +80000118: 00000193 li gp,0 +8000011c: 00000297 auipc t0,0x0 +80000120: ee828293 addi t0,t0,-280 # 80000004 +80000124: 30529073 csrw mtvec,t0 +80000128: 00100513 li a0,1 +8000012c: 01f51513 slli a0,a0,0x1f +80000130: 00054c63 bltz a0,80000148 +80000134: 0ff0000f fence +80000138: 00100193 li gp,1 +8000013c: 05d00893 li a7,93 +80000140: 00000513 li a0,0 +80000144: 00000073 ecall +80000148: 80000297 auipc t0,0x80000 +8000014c: eb828293 addi t0,t0,-328 # 0 <_start-0x80000000> +80000150: 00028a63 beqz t0,80000164 +80000154: 10529073 csrw stvec,t0 +80000158: 0000b2b7 lui t0,0xb +8000015c: 10928293 addi t0,t0,265 # b109 <_start-0x7fff4ef7> +80000160: 30229073 csrw medeleg,t0 +80000164: 30005073 csrwi mstatus,0 +80000168: 00002537 lui a0,0x2 +8000016c: 30052073 csrs mstatus,a0 +80000170: 00305073 csrwi fcsr,0 +80000174: 00000297 auipc t0,0x0 +80000178: 01428293 addi t0,t0,20 # 80000188 +8000017c: 34129073 csrw mepc,t0 +80000180: f1402573 csrr a0,mhartid +80000184: 30200073 mret +80000188: 00002517 auipc a0,0x2 +8000018c: e7852007 flw ft0,-392(a0) # 80002000 +80000190: 00002517 auipc a0,0x2 +80000194: e7452087 flw ft1,-396(a0) # 80002004 +80000198: 1000f0d3 fmul.s ft1,ft1,ft0 + +8000019c : +8000019c: a0102553 feq.s a0,ft0,ft1 +800001a0: 00100393 li t2,1 +800001a4: 00200193 li gp,2 +800001a8: 06751463 bne a0,t2,80000210 + +800001ac : +800001ac: a0100553 fle.s a0,ft0,ft1 +800001b0: 00100393 li t2,1 +800001b4: 00300193 li gp,3 +800001b8: 04751c63 bne a0,t2,80000210 + +800001bc : +800001bc: a0101553 flt.s a0,ft0,ft1 +800001c0: 00000393 li t2,0 +800001c4: 00400193 li gp,4 +800001c8: 04751463 bne a0,t2,80000210 +800001cc: d0007053 fcvt.s.w ft0,zero +800001d0: 00100513 li a0,1 +800001d4: d00570d3 fcvt.s.w ft1,a0 +800001d8: 1000f0d3 fmul.s ft1,ft1,ft0 + +800001dc : +800001dc: a0102553 feq.s a0,ft0,ft1 +800001e0: 00100393 li t2,1 +800001e4: 00500193 li gp,5 +800001e8: 02751463 bne a0,t2,80000210 + +800001ec : +800001ec: a0100553 fle.s a0,ft0,ft1 +800001f0: 00100393 li t2,1 +800001f4: 00600193 li gp,6 +800001f8: 00751c63 bne a0,t2,80000210 + +800001fc : +800001fc: a0101553 flt.s a0,ft0,ft1 +80000200: 00000393 li t2,0 +80000204: 00700193 li gp,7 +80000208: 00751463 bne a0,t2,80000210 +8000020c: 02301063 bne zero,gp,8000022c + +80000210 : +80000210: 0ff0000f fence +80000214: 00018063 beqz gp,80000214 +80000218: 00119193 slli gp,gp,0x1 +8000021c: 0011e193 ori gp,gp,1 +80000220: 05d00893 li a7,93 +80000224: 00018513 mv a0,gp +80000228: 00000073 ecall + +8000022c : +8000022c: 0ff0000f fence +80000230: 00100193 li gp,1 +80000234: 05d00893 li a7,93 +80000238: 00000513 li a0,0 +8000023c: 00000073 ecall +80000240: c0001073 unimp + +Disassembly of section .data: + +80002000 : +80002000: 0000 unimp +80002002: ff80 fsw fs0,56(a5) + +80002004 : +80002004: 0000 unimp +80002006: 4040 lw s0,4(s0) +80002008: 0000 unimp +8000200a: 0000 unimp +8000200c: 0000 unimp +8000200e: 0000 unimp diff --git a/src/test/resources/hex/rv32uf-p-fadd.hex b/src/test/resources/hex/rv32uf-p-fadd.hex new file mode 100755 index 00000000..f174c681 --- /dev/null +++ b/src/test/resources/hex/rv32uf-p-fadd.hex @@ -0,0 +1,83 @@ +:0200000480007A +:100000006F00C004732F2034930F8000630AFF0336 +:10001000930F90006306FF03930FB0006302FF038A +:10002000170F0080130F0FFE63040F0067000F000F +:10003000732F203463540F006F00400093E19153FD +:10004000171F000023203FFC6FF09FFF930000006C +:10005000130100009301000013020000930200004E +:100060001303000093030000130400009304000036 +:10007000130500009305000013060000930600001E +:100080001307000093070000130800009308000006 +:100090001309000093090000130A0000930A0000EE +:1000A000130B0000930B0000130C0000930C0000D6 +:1000B000130D0000930D0000130E0000930E0000BE +:1000C000130F0000930F0000732540F1631005002B +:1000D000970200009382020173905230735000180F +:1000E000970200009382020273905230B7020080A0 +:1000F0009382F2FF7390023B9302F0017390023AF5 +:100100007350403097020000938242017390523046 +:10011000735020307350303093010000970200007C +:10012000938282EE73905230130510001315F5017F +:10013000634C05000F00F00F930110009308D005E9 +:10014000130500007300000097020080938282EB89 +:10015000638A020073905210B7B20000938292102B +:100160007390223073500030372500007320053023 +:100170007350300097020000938242017390123452 +:10018000732540F1730020309301200017250000F3 +:10019000130545E707200500872045000721850056 +:1001A0008326C500D3711000538501E0F3151000BC +:1001B000130600006310D51E639EC51C930130001A +:1001C00017250000130505E50720050087204500D9 +:1001D000072185008326C500D3711000538501E0F7 +:1001E000F3151000130610006316D51A6394C51A90 +:1001F00093014000172500001305C5E20720050004 +:1002000087204500072185008326C500D371100093 +:10021000538501E0F315100013061000631CD5167A +:10022000639AC5169301500017250000130585E059 +:100230000720050087204500072185008326C5008B +:10024000D3711008538501E0F31510001306000068 +:100250006312D5146390C514930160001725000044 +:10026000130545DE0720050087204500072185008E +:100270008326C500D3711008538501E0F3151000E3 +:10028000130610006318D5106396C5109301700013 +:1002900017250000130505DC072005008720450011 +:1002A000072185008326C500D3711008538501E01E +:1002B000F315100013061000631ED50C639CC50CCB +:1002C00093018000172500001305C5D907200500FC +:1002D00087204500072185008326C500D3711010B3 +:1002E000538501E0F3151000130600006314D50ACE +:1002F0006392C50A9301900017250000130585D766 +:100300000720050087204500072185008326C500BA +:10031000D3711010538501E0F3151000130610007F +:10032000631AD5066398C5069301A000172500003F +:10033000130545D5072005008720450007218500C6 +:100340008326C500D3711010538501E0F31510000A +:10035000130610006310D504639EC5029301B0001C +:1003600017250000130505D3072005008720450049 +:10037000072185008326C500D3711008538501E04D +:10038000F3151000130600016316D5006394C50031 +:10039000631030020F00F00F638001009391110091 +:1003A00093E111009308D00513850100730000004C +:1003B0000F00F00F930110009308D0051305000003 +:1003C00073000000731000C0000000000000000077 +:1003D000000000000000000000000000000000001D +:1003E000000000000000000000000000000000000D +:1003F00000000000000000000000000000000000FD +:0404000000000000F8 +:1010000000000000000000000000000000000000E0 +:1010100000000000000000000000000000000000D0 +:1010200000000000000000000000000000000000C0 +:1010300000000000000000000000000000000000B0 +:081040000000000000000000A8 +:10200000000020400000803F000000000000604011 +:1020100033639AC4CDCC8C3F0000000000409AC4CA +:10202000DB0F494077CC2B3200000000DB0F49402A +:10203000000020400000803F000000000000C03F82 +:1020400033639AC4CDCC8CBF0000000000409AC41A +:10205000DB0F494077CC2B3200000000DB0F4940FA +:10206000000020400000803F0000000000002040F1 +:1020700033639AC4CDCC8CBF0000000085D3A94443 +:10208000DB0F494077CC2B32000000002DEE0633E9 +:102090000000807F0000807F000000000000C07F03 +:040000058000000077 +:00000001FF diff --git a/src/test/resources/hex/rv32uf-p-fclass.hex b/src/test/resources/hex/rv32uf-p-fclass.hex new file mode 100755 index 00000000..849f4aab --- /dev/null +++ b/src/test/resources/hex/rv32uf-p-fclass.hex @@ -0,0 +1,53 @@ +:0200000480007A +:100000006F00C004732F2034930F8000630AFF0336 +:10001000930F90006306FF03930FB0006302FF038A +:10002000170F0080130F0FFE63040F0067000F000F +:10003000732F203463540F006F00400093E19153FD +:10004000171F000023203FFC6FF09FFF930000006C +:10005000130100009301000013020000930200004E +:100060001303000093030000130400009304000036 +:10007000130500009305000013060000930600001E +:100080001307000093070000130800009308000006 +:100090001309000093090000130A0000930A0000EE +:1000A000130B0000930B0000130C0000930C0000D6 +:1000B000130D0000930D0000130E0000930E0000BE +:1000C000130F0000930F0000732540F1631005002B +:1000D000970200009382020173905230735000180F +:1000E000970200009382020273905230B7020080A0 +:1000F0009382F2FF7390023B9302F0017390023AF5 +:100100007350403097020000938242017390523046 +:10011000735020307350303093010000970200007C +:10012000938282EE73905230130510001315F5017F +:10013000634C05000F00F00F930110009308D005E9 +:10014000130500007300000097020080938282EB89 +:10015000638A020073905210B7B20000938292102B +:100160007390223073500030372500007320053023 +:100170007350300097020000938242017390123452 +:10018000732540F173002030370580FF530505F0DB +:10019000531505E093031000930120006316750EBC +:1001A000370580BF530505F0531505E09303200084 +:1001B00093013000631A750C370580801305F5FF35 +:1001C000530505F0531505E09303400093014000EB +:1001D000631C750A37050080530505F0531505E0CB +:1001E00093038000930150006310750A130500000B +:1001F000530505F0531505E09303000193016000DA +:1002000063147508370580001305F5FF530505F0E5 +:10021000531505E093030002930170006316750601 +:100220003705803F530505F0531505E0930300049F +:1002300093018000631A75043705807F530505F02C +:10024000531505E09303000893019000631E7502A7 +:100250003705807F13051500530505F0531505E09C +:10026000930300109301A000631075023705C07F4F +:10027000530505F0531505E0930300209301B000EA +:1002800063147500631030020F00F00F63800100EB +:100290009391110093E111009308D005138501009B +:1002A000730000000F00F00F930110009308D005B9 +:1002B0001305000073000000731000C00000000070 +:0402C000000000003A +:1010000000000000000000000000000000000000E0 +:1010100000000000000000000000000000000000D0 +:1010200000000000000000000000000000000000C0 +:1010300000000000000000000000000000000000B0 +:081040000000000000000000A8 +:040000058000000077 +:00000001FF diff --git a/src/test/resources/hex/rv32uf-p-fcmp.hex b/src/test/resources/hex/rv32uf-p-fcmp.hex new file mode 100755 index 00000000..8ba2a82c --- /dev/null +++ b/src/test/resources/hex/rv32uf-p-fcmp.hex @@ -0,0 +1,100 @@ +:0200000480007A +:100000006F00C004732F2034930F8000630AFF0336 +:10001000930F90006306FF03930FB0006302FF038A +:10002000170F0080130F0FFE63040F0067000F000F +:10003000732F203463540F006F00400093E19153FD +:10004000171F000023203FFC6FF09FFF930000006C +:10005000130100009301000013020000930200004E +:100060001303000093030000130400009304000036 +:10007000130500009305000013060000930600001E +:100080001307000093070000130800009308000006 +:100090001309000093090000130A0000930A0000EE +:1000A000130B0000930B0000130C0000930C0000D6 +:1000B000130D0000930D0000130E0000930E0000BE +:1000C000130F0000930F0000732540F1631005002B +:1000D000970200009382020173905230735000180F +:1000E000970200009382020273905230B7020080A0 +:1000F0009382F2FF7390023B9302F0017390023AF5 +:100100007350403097020000938242017390523046 +:10011000735020307350303093010000970200007C +:10012000938282EE73905230130510001315F5017F +:10013000634C05000F00F00F930110009308D005E9 +:10014000130500007300000097020080938282EB89 +:10015000638A020073905210B7B20000938292102B +:100160007390223073500030372500007320053023 +:100170007350300097020000938242017390123452 +:10018000732540F1730020309301200017250000F3 +:10019000130545E707200500872045000721850056 +:1001A0008326C500532510A0F31510001306000088 +:1001B0006316D52A6394C52A9301300017250000E1 +:1001C000130545E507200500872045000721850028 +:1001D0008326C500530510A0F31510001306000078 +:1001E000631ED526639CC526930140001725000099 +:1001F000130545E3072005008720450007218500FA +:100200008326C500531510A0F31510001306000037 +:100210006316D5246394C52493015000172500006C +:10022000130545E1072005008720450007218500CB +:100230008326C500532510A0F315100013060000F7 +:10024000631ED520639CC520930160001725000024 +:10025000130545DF0720050087204500072185009D +:100260008326C500530510A0F315100013060000E7 +:100270006316D51E6394C51E9301700017250000F8 +:10028000130545DD0720050087204500072185006F +:100290008326C500531510A0F315100013060000A7 +:1002A000631ED51A639CC51A9301800017250000B0 +:1002B000130545DB07200500872045000721850041 +:1002C0008326C500532510A0F31510001306000067 +:1002D0006316D5186394C518930190001725000084 +:1002E000130545D907200500872045000721850013 +:1002F0008326C500532510A0F31510001306000037 +:10030000631ED514639CC5149301A000172500003B +:10031000130545D7072005008720450007218500E4 +:100320008326C500532510A0F31510001306000105 +:100330006316D5126394C5129301B000172500000F +:10034000130545D5072005008720450007218500B6 +:100350008326C500531510A0F315100013060001E5 +:10036000631ED50E639CC50E9301C00017250000C7 +:10037000130545D307200500872045000721850088 +:100380008326C500531510A0F315100013060001B5 +:100390006316D50C6394C50C9301D000172500009B +:1003A000130545D10720050087204500072185005A +:1003B0008326C500531510A0F31510001306000185 +:1003C000631ED508639CC5089301E0001725000053 +:1003D000130545CF0720050087204500072185002C +:1003E0008326C500530510A0F31510001306000165 +:1003F0006316D5066394C5069301F0001725000027 +:10040000130545CD072005008720450007218500FD +:100410008326C500530510A0F31510001306000134 +:10042000631ED502639CC5029301000117250000DD +:10043000130545CB072005008720450007218500CF +:100440008326C500530510A0F31510001306000104 +:100450006316D5006394C500631030020F00F00FDF +:10046000638001009391110093E111009308D0057E +:1004700013850100730000000F00F00F93011000BE +:100480009308D0051305000073000000731000C02E +:10049000000000000000000000000000000000005C +:1004A000000000000000000000000000000000004C +:1004B000000000000000000000000000000000003C +:0404C0000000000038 +:1010000000000000000000000000000000000000E0 +:1010100000000000000000000000000000000000D0 +:1010200000000000000000000000000000000000C0 +:1010300000000000000000000000000000000000B0 +:081040000000000000000000A8 +:102000007B14AEBF7B14AEBF0000000001000000D7 +:102010007B14AEBF7B14AEBF0000000001000000C7 +:102020007B14AEBF7B14AEBF0000000000000000B8 +:10203000295CAFBF7B14AEBF0000000000000000B1 +:10204000295CAFBF7B14AEBF0000000001000000A0 +:10205000295CAFBF7B14AEBF000000000100000090 +:10206000FFFFFF7F000000000000000000000000F4 +:10207000FFFFFF7FFFFFFF7F000000000000000068 +:102080000100807F00000000000000000000000050 +:10209000FFFFFF7F000000000000000000000000C4 +:1020A000FFFFFF7FFFFFFF7F000000000000000038 +:1020B0000100807F00000000000000000000000020 +:1020C000FFFFFF7F00000000000000000000000094 +:1020D000FFFFFF7FFFFFFF7F000000000000000008 +:1020E0000100807F000000000000000000000000F0 +:040000058000000077 +:00000001FF diff --git a/src/test/resources/hex/rv32uf-p-fcvt.hex b/src/test/resources/hex/rv32uf-p-fcvt.hex new file mode 100755 index 00000000..01905348 --- /dev/null +++ b/src/test/resources/hex/rv32uf-p-fcvt.hex @@ -0,0 +1,50 @@ +:0200000480007A +:100000006F00C004732F2034930F8000630AFF0336 +:10001000930F90006306FF03930FB0006302FF038A +:10002000170F0080130F0FFE63040F0067000F000F +:10003000732F203463540F006F00400093E19153FD +:10004000171F000023203FFC6FF09FFF930000006C +:10005000130100009301000013020000930200004E +:100060001303000093030000130400009304000036 +:10007000130500009305000013060000930600001E +:100080001307000093070000130800009308000006 +:100090001309000093090000130A0000930A0000EE +:1000A000130B0000930B0000130C0000930C0000D6 +:1000B000130D0000930D0000130E0000930E0000BE +:1000C000130F0000930F0000732540F1631005002B +:1000D000970200009382020173905230735000180F +:1000E000970200009382020273905230B7020080A0 +:1000F0009382F2FF7390023B9302F0017390023AF5 +:100100007350403097020000938242017390523046 +:10011000735020307350303093010000970200007C +:10012000938282EE73905230130510001315F5017F +:10013000634C05000F00F00F930110009308D005E9 +:10014000130500007300000097020080938282EB89 +:10015000638A020073905210B7B20000938292102B +:100160007390223073500030372500007320053023 +:100170007350300097020000938242017390123452 +:10018000732540F1730020309301200017250000F3 +:10019000130545E78326050013052000537005D09D +:1001A00073101000530500E0631AD5069301300068 +:1001B00017250000130545E5832605001305E0FF1C +:1001C000537005D073101000530500E06318D50478 +:1001D0009301400017250000130545E38326050021 +:1001E00013052000537015D073101000530500E064 +:1001F0006316D5029301500017250000130545E151 +:10020000832605001305E0FF537015D0731010000E +:10021000530500E06314D500631030020F00F00FA7 +:10022000638001009391110093E111009308D005C0 +:1002300013850100730000000F00F00F9301100000 +:100240009308D0051305000073000000731000C070 +:10025000000000000000000000000000000000009E +:10026000000000000000000000000000000000008E +:10027000000000000000000000000000000000007E +:04028000000000007A +:1010000000000000000000000000000000000000E0 +:1010100000000000000000000000000000000000D0 +:1010200000000000000000000000000000000000C0 +:1010300000000000000000000000000000000000B0 +:081040000000000000000000A8 +:1020000000000040000000C0000000400000804FC1 +:040000058000000077 +:00000001FF diff --git a/src/test/resources/hex/rv32uf-p-fcvt_w.hex b/src/test/resources/hex/rv32uf-p-fcvt_w.hex new file mode 100755 index 00000000..f7588581 --- /dev/null +++ b/src/test/resources/hex/rv32uf-p-fcvt_w.hex @@ -0,0 +1,120 @@ +:0200000480007A +:100000006F00C004732F2034930F8000630AFF0336 +:10001000930F90006306FF03930FB0006302FF038A +:10002000170F0080130F0FFE63040F0067000F000F +:10003000732F203463540F006F00400093E19153FD +:10004000171F000023203FFC6FF09FFF930000006C +:10005000130100009301000013020000930200004E +:100060001303000093030000130400009304000036 +:10007000130500009305000013060000930600001E +:100080001307000093070000130800009308000006 +:100090001309000093090000130A0000930A0000EE +:1000A000130B0000930B0000130C0000930C0000D6 +:1000B000130D0000930D0000130E0000930E0000BE +:1000C000130F0000930F0000732540F1631005002B +:1000D000970200009382020173905230735000180F +:1000E000970200009382020273905230B7020080A0 +:1000F0009382F2FF7390023B9302F0017390023AF5 +:100100007350403097020000938242017390523046 +:10011000735020307350303093010000970200007C +:10012000938282EE73905230130510001315F5017F +:10013000634C05000F00F00F930110009308D005E9 +:10014000130500007300000097020080938282EB89 +:10015000638A020073905210B7B20000938292102B +:100160007390223073500030372500007320053023 +:100170007350300097020000938242017390123452 +:10018000732540F1730020309301200017250000F3 +:10019000130545E707200500872045000721850056 +:1001A0008326C500531500C0F31510001306100078 +:1001B0006314D53C6392C53C9301300017250000C1 +:1001C000130545E507200500872045000721850028 +:1001D0008326C500531500C0F31510001306000058 +:1001E000631CD538639AC538930140001725000079 +:1001F000130545E3072005008720450007218500FA +:100200008326C500531500C0F31510001306100017 +:100210006314D5366392C53693015000172500004C +:10022000130545E1072005008720450007218500CB +:100230008326C500531500C0F315100013061000E7 +:10024000631CD532639AC532930160001725000004 +:10025000130545DF0720050087204500072185009D +:100260008326C500531500C0F315100013060000C7 +:100270006314D5306392C5309301700017250000D8 +:10028000130545DD0720050087204500072185006F +:100290008326C500531500C0F31510001306100087 +:1002A000631CD52C639AC52C930180001725000090 +:1002B000130545DB07200500872045000721850041 +:1002C0008326C500531500C0F31510001306000166 +:1002D0006314D52A6392C52A930190001725000064 +:1002E000130545D907200500872045000721850013 +:1002F0008326C500531500C0F31510001306000136 +:10030000631CD526639AC5269301C00017250000FB +:10031000130545D7072005008720450007218500E4 +:100320008326C500531510C0F315100013060001F5 +:100330006314D5246392C5249301D00017250000CF +:10034000130545D5072005008720450007218500B6 +:100350008326C500531510C0F315100013060001C5 +:10036000631CD520639AC5209301E0001725000087 +:10037000130545D307200500872045000721850088 +:100380008326C500531510C0F31510001306100086 +:100390006314D51E6392C51E9301F000172500005B +:1003A000130545D10720050087204500072185005A +:1003B0008326C500531510C0F31510001306100056 +:1003C000631CD51A639AC51A930100011725000012 +:1003D000130545CF0720050087204500072185002C +:1003E0008326C500531510C0F31510001306000036 +:1003F0006314D5186392C5189301100117250000E6 +:10040000130545CD072005008720450007218500FD +:100410008326C500531510C0F315100013061000F5 +:10042000631CD514639AC51493012001172500009D +:10043000130545CB072005008720450007218500CF +:100440008326C500531510C0F315100013060001D4 +:100450006314D5126392C512930130011725000071 +:10046000130545C9072005008720450007218500A1 +:100470008326C500531510C0F315100013060000A5 +:10048000631CD50E639AC50E97200000938080C729 +:1004900087A00000D3F000C0B70300809383F3FF70 +:1004A0009301A002639A700C97200000938080C58E +:1004B00087A08000D3F000C0B70300809301C00282 +:1004C000639C700A972000009380C0C387A04000FF +:1004D000D3F000C0B70300809383F3FF9301400380 +:1004E000639C7008972000009380C0C187A0C00063 +:1004F000D3F000C0B70300809383F3FF9301600340 +:10050000639C7006972000009380C0BF87A0000006 +:10051000D3F010C09303F0FF9301E003639E7004D7 +:1005200097200000938000BE87A04000D3F010C049 +:100530009303F0FF9301F003639070049720000091 +:10054000938040BC87A08000D3F010C093030000CC +:10055000930100046392700297200000938080BA98 +:1005600087A0C000D3F010C09303F0FF93011004E4 +:1005700063947000631030020F00F00F638001007D +:100580009391110093E111009308D00513850100A8 +:10059000730000000F00F00F930110009308D005C6 +:1005A0001305000073000000731000C0000000007D +:1005B000000000000000000000000000000000003B +:0405C0000000000037 +:1010000000000000000000000000000000000000E0 +:1010100000000000000000000000000000000000D0 +:1010200000000000000000000000000000000000C0 +:1010300000000000000000000000000000000000B0 +:081040000000000000000000A8 +:10200000CDCC8CBF0000000000000000FFFFFFFFF0 +:10201000000080BF0000000000000000FFFFFFFF85 +:10202000666666BF000000000000000000000000BF +:102030006666663F0000000000000000000000002F +:102040000000803F000000000000000001000000D0 +:10205000CDCC8C3F0000000000000000010000001B +:102060005ED032CF000000000000000000000080C1 +:102070005ED0324F0000000000000000FFFFFF7F35 +:10208000000040C000000000000000000000000050 +:10209000000080BF00000000000000000000000001 +:1020A000666666BF0000000000000000000000003F +:1020B0006666663F000000000000000000000000AF +:1020C0000000803F00000000000000000100000050 +:1020D000CDCC8C3F0000000000000000010000009B +:1020E0005ED032CF000000000000000000000000C1 +:1020F0005ED0324F0000000000000000005ED0B251 +:10210000FFFFFFFFFFFFFF7F000080FF0000807FD9 +:10211000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7F4F +:10212000000000000000F0FF000000000000F07F51 +:040000058000000077 +:00000001FF diff --git a/src/test/resources/hex/rv32uf-p-fdiv.hex b/src/test/resources/hex/rv32uf-p-fdiv.hex new file mode 100755 index 00000000..2d48fa4b --- /dev/null +++ b/src/test/resources/hex/rv32uf-p-fdiv.hex @@ -0,0 +1,69 @@ +:0200000480007A +:100000006F00C004732F2034930F8000630AFF0336 +:10001000930F90006306FF03930FB0006302FF038A +:10002000170F0080130F0FFE63040F0067000F000F +:10003000732F203463540F006F00400093E19153FD +:10004000171F000023203FFC6FF09FFF930000006C +:10005000130100009301000013020000930200004E +:100060001303000093030000130400009304000036 +:10007000130500009305000013060000930600001E +:100080001307000093070000130800009308000006 +:100090001309000093090000130A0000930A0000EE +:1000A000130B0000930B0000130C0000930C0000D6 +:1000B000130D0000930D0000130E0000930E0000BE +:1000C000130F0000930F0000732540F1631005002B +:1000D000970200009382020173905230735000180F +:1000E000970200009382020273905230B7020080A0 +:1000F0009382F2FF7390023B9302F0017390023AF5 +:100100007350403097020000938242017390523046 +:10011000735020307350303093010000970200007C +:10012000938282EE73905230130510001315F5017F +:10013000634C05000F00F00F930110009308D005E9 +:10014000130500007300000097020080938282EB89 +:10015000638A020073905210B7B20000938292102B +:100160007390223073500030372500007320053023 +:100170007350300097020000938242017390123452 +:10018000732540F1730020309301200017250000F3 +:10019000130545E707200500872045000721850056 +:1001A0008326C500D3711018538501E0F3151000A4 +:1001B000130610006312D5146390C5149301300028 +:1001C00017250000130505E50720050087204500D9 +:1001D000072185008326C500D3711018538501E0DF +:1001E000F3151000130610006318D5106396C510A0 +:1001F00093014000172500001305C5E20720050004 +:1002000087204500072185008326C500D37110187B +:10021000538501E0F315100013060000631ED50C92 +:10022000639CC50C9301500017250000130585E061 +:100230000720050087204500072185008326C5008B +:10024000D3710058538501E0F31510001306100018 +:100250006314D50A6392C50A930160001725000054 +:10026000130545DE0720050087204500072185008E +:100270008326C500D3710058538501E0F3151000A3 +:1002800013060000631AD5066398C5069301700033 +:1002900017250000130505DC072005008720450011 +:1002A000072185008326C500D3710058538501E0DE +:1002B000F3151000130600016310D504639EC502F8 +:1002C0009301800017250000130505DA07200500BB +:1002D00087204500072185008326C500D37100587B +:1002E000538501E0F3151000130610006316D500C6 +:1002F0006394C500631030020F00F00F63800100AB +:100300009391110093E111009308D005138501002A +:10031000730000000F00F00F930110009308D00548 +:100320001305000073000000731000C000000000FF +:1003300000000000000000000000000000000000BD +:0403400000000000B9 +:1010000000000000000000000000000000000000E0 +:1010100000000000000000000000000000000000D0 +:1010200000000000000000000000000000000000C0 +:1010300000000000000000000000000000000000B0 +:081040000000000000000000A8 +:10200000DB0F494054F82D4000000000E0EE933F04 +:1020100000409AC433639A4400000000A2C57FBF09 +:10202000DB0F49400000803F00000000DB0F49400B +:10203000DB0F49400000000000000000C5DFE23F68 +:1020400000401C4600000000000000000000C842E4 +:10205000000080BF00000000000000000000C07F02 +:102060000000000000002B43000000000000000002 +:10207000263A51410000000000000000000000006E +:040000058000000077 +:00000001FF diff --git a/src/test/resources/hex/rv32uf-p-fmadd.hex b/src/test/resources/hex/rv32uf-p-fmadd.hex new file mode 100755 index 00000000..b8ead879 --- /dev/null +++ b/src/test/resources/hex/rv32uf-p-fmadd.hex @@ -0,0 +1,89 @@ +:0200000480007A +:100000006F00C004732F2034930F8000630AFF0336 +:10001000930F90006306FF03930FB0006302FF038A +:10002000170F0080130F0FFE63040F0067000F000F +:10003000732F203463540F006F00400093E19153FD +:10004000171F000023203FFC6FF09FFF930000006C +:10005000130100009301000013020000930200004E +:100060001303000093030000130400009304000036 +:10007000130500009305000013060000930600001E +:100080001307000093070000130800009308000006 +:100090001309000093090000130A0000930A0000EE +:1000A000130B0000930B0000130C0000930C0000D6 +:1000B000130D0000930D0000130E0000930E0000BE +:1000C000130F0000930F0000732540F1631005002B +:1000D000970200009382020173905230735000180F +:1000E000970200009382020273905230B7020080A0 +:1000F0009382F2FF7390023B9302F0017390023AF5 +:100100007350403097020000938242017390523046 +:10011000735020307350303093010000970200007C +:10012000938282EE73905230130510001315F5017F +:10013000634C05000F00F00F930110009308D005E9 +:10014000130500007300000097020080938282EB89 +:10015000638A020073905210B7B20000938292102B +:100160007390223073500030372500007320053023 +:100170007350300097020000938242017390123452 +:10018000732540F1730020309301200017250000F3 +:10019000130545E707200500872045000721850056 +:1001A0008326C500C3711010538501E0F3151000BC +:1001B000130600006314D5246392C5249301300014 +:1001C00017250000130505E50720050087204500D9 +:1001D000072185008326C500C3711010538501E0F7 +:1001E000F315100013061000631AD5206398C5207C +:1001F00093014000172500001305C5E20720050004 +:1002000087204500072185008326C500C371101093 +:10021000538501E0F3151000130600006310D51E8E +:10022000639EC51C9301500017250000130585E04F +:100230000720050087204500072185008326C5008B +:10024000CF711010538501E0F31510001306000064 +:100250006316D51A6394C51A930160001725000030 +:10026000130545DE0720050087204500072185008E +:100270008326C500CF711010538501E0F3151000DF +:1002800013061000631CD516639AC51693017000FF +:1002900017250000130505DC072005008720450011 +:1002A000072185008326C500CF711010538501E01A +:1002B000F3151000130600006312D5146390C514E3 +:1002C00093018000172500001305C5D907200500FC +:1002D00087204500072185008326C500C7711010BF +:1002E000538501E0F3151000130600006318D510C4 +:1002F0006396C5109301900017250000130585D75C +:100300000720050087204500072185008326C500BA +:10031000C7711010538501E0F3151000130610008B +:10032000631ED50C639CC50C9301A000172500002B +:10033000130545D5072005008720450007218500C6 +:100340008326C500C7711010538501E0F315100016 +:10035000130600006314D50A6392C50A9301B00026 +:1003600017250000130505D3072005008720450049 +:10037000072185008326C500CB711010538501E04D +:10038000F315100013060000631AD5066398C5061E +:100390009301C000172500001305C5D007200500F4 +:1003A00087204500072185008326C500CB711010EA +:1003B000538501E0F3151000130610006310D504F7 +:1003C000639EC5029301D00017250000130585CE5A +:1003D0000720050087204500072185008326C500EA +:1003E000CB711010538501E0F315100013060000C7 +:1003F0006316D5006394C500631030020F00F00F40 +:10040000638001009391110093E111009308D005DE +:1004100013850100730000000F00F00F930110001E +:100420009308D0051305000073000000731000C08E +:1004300000000000000000000000000000000000BC +:0404400000000000B8 +:1010000000000000000000000000000000000000E0 +:1010100000000000000000000000000000000000D0 +:1010200000000000000000000000000000000000C0 +:1010300000000000000000000000000000000000B0 +:081040000000000000000000A8 +:102000000000803F000020400000803F0000604052 +:10201000000080BF33639AC4CDCC8C3F66869A445F +:10202000000000400000A0C0000000C0000040C14F +:102030000000803F000020400000803F000060C0A2 +:10204000000080BF33639AC4CDCC8C3F66869AC4AF +:10205000000000400000A0C0000000C0000040419F +:102060000000803F000020400000803F0000C03F93 +:10207000000080BF33639AC4CDCC8C3F00409A44AB +:10208000000000400000A0C0000000C0000000C12F +:102090000000803F000020400000803F0000C0BFE3 +:1020A000000080BF33639AC4CDCC8C3F00409AC4FB +:1020B000000000400000A0C0000000C0000000417F +:040000058000000077 +:00000001FF diff --git a/src/test/resources/hex/rv32uf-p-fmin.hex b/src/test/resources/hex/rv32uf-p-fmin.hex new file mode 100755 index 00000000..b1126d3d --- /dev/null +++ b/src/test/resources/hex/rv32uf-p-fmin.hex @@ -0,0 +1,115 @@ +:0200000480007A +:100000006F00C004732F2034930F8000630AFF0336 +:10001000930F90006306FF03930FB0006302FF038A +:10002000170F0080130F0FFE63040F0067000F000F +:10003000732F203463540F006F00400093E19153FD +:10004000171F000023203FFC6FF09FFF930000006C +:10005000130100009301000013020000930200004E +:100060001303000093030000130400009304000036 +:10007000130500009305000013060000930600001E +:100080001307000093070000130800009308000006 +:100090001309000093090000130A0000930A0000EE +:1000A000130B0000930B0000130C0000930C0000D6 +:1000B000130D0000930D0000130E0000930E0000BE +:1000C000130F0000930F0000732540F1631005002B +:1000D000970200009382020173905230735000180F +:1000E000970200009382020273905230B7020080A0 +:1000F0009382F2FF7390023B9302F0017390023AF5 +:100100007350403097020000938242017390523046 +:10011000735020307350303093010000970200007C +:10012000938282EE73905230130510001315F5017F +:10013000634C05000F00F00F930110009308D005E9 +:10014000130500007300000097020080938282EB89 +:10015000638A020073905210B7B20000938292102B +:100160007390223073500030372500007320053023 +:100170007350300097020000938242017390123452 +:10018000732540F1730020309301200017250000F3 +:10019000130545E707200500872045000721850056 +:1001A0008326C500D3011028538501E0F315100004 +:1001B000130600006310D538639EC53693013000E6 +:1001C00017250000130505E50720050087204500D9 +:1001D000072185008326C500D3011028538501E03F +:1001E000F3151000130600006316D5346394C5346C +:1001F00093014000172500001305C5E20720050004 +:1002000087204500072185008326C500D3011028DB +:10021000538501E0F315100013060000631CD53070 +:10022000639AC5309301500017250000130585E03F +:100230000720050087204500072185008326C5008B +:10024000D3011028538501E0F315100013060000B8 +:100250006312D52E6390C52E930160001725000010 +:10026000130545DE0720050087204500072185008E +:100270008326C500D3011028538501E0F315100033 +:10028000130600006318D52A6396C52A93017000EF +:1002900017250000130505DC072005008720450011 +:1002A000072185008326C500D3011028538501E06E +:1002B000F315100013060000631ED526639CC526A7 +:1002C0009301C000172500001305C5D907200500BC +:1002D00087204500072185008326C500D3111028FB +:1002E000538501E0F3151000130600006314D524B4 +:1002F0006392C5249301D00017250000130585D70C +:100300000720050087204500072185008326C500BA +:10031000D3111028538501E0F315100013060000D7 +:10032000631AD5206398C5209301E00017250000CB +:10033000130545D5072005008720450007218500C6 +:100340008326C500D3111028538501E0F315100052 +:10035000130600006310D51E639EC51C9301F000B8 +:1003600017250000130505D3072005008720450049 +:10037000072185008326C500D3111028538501E08D +:10038000F3151000130600006316D51A6394C51AFE +:1003900093010001172500001305C5D007200500B3 +:1003A00087204500072185008326C500D31110282A +:1003B000538501E0F315100013060000631CD516E9 +:1003C000639AC5169301100117250000130585CE09 +:1003D0000720050087204500072185008326C500EA +:1003E000D3111028538501E0F31510001306000007 +:1003F0006312D5146390C5149301400117250000C2 +:10040000130545CC072005008720450007218500FE +:100410008326C500D3111028538501E0F315100081 +:10042000130600016318D5106396C510930150019F +:1004300017250000130505CA072005008720450081 +:10044000072185008326C500D3111028538501E0BC +:10045000F315100013060000631ED50C639CC50C39 +:100460009301E001172500001305C5C7072005000B +:1004700087204500072185008326C500D301102869 +:10048000538501E0F3151000130600006314D50A2C +:100490006392C50A9301F00117250000130585C575 +:1004A0000720050087204500072185008326C50019 +:1004B000D3011028538501E0F31510001306000046 +:1004C000631AD5066398C50693010002172500003C +:1004D000130545C307200500872045000721850037 +:1004E0008326C500D3111028538501E0F3151000B1 +:1004F000130600006310D504639EC5029301100229 +:1005000017250000130505C10720050087204500B9 +:10051000072185008326C500D3111028538501E0EB +:10052000F3151000130600006316D5006394C50090 +:10053000631030020F00F00F6380010093911100EF +:1005400093E111009308D0051385010073000000AA +:100550000F00F00F930110009308D0051305000061 +:1005600073000000731000C00000000000000000D5 +:10057000000000000000000000000000000000007B +:040580000000000077 +:1010000000000000000000000000000000000000E0 +:1010100000000000000000000000000000000000D0 +:1010200000000000000000000000000000000000C0 +:1010300000000000000000000000000000000000B0 +:081040000000000000000000A8 +:10200000000020400000803F000000000000803FF2 +:1020100033639AC4CDCC8C3F0000000033639AC474 +:10202000CDCC8C3F33639AC40000000033639AC464 +:10203000FFFFFF7F33639AC40000000033639AC43C +:10204000DB0F494077CC2B320000000077CC2B32DD +:10205000000080BF000000C000000000000000C0C1 +:10206000000020400000803F0000000000002040F1 +:1020700033639AC4CDCC8C3F00000000CDCC8C3FA4 +:10208000CDCC8C3F33639AC400000000CDCC8C3F94 +:10209000FFFFFF7F33639AC40000000033639AC4DC +:1020A000DB0F494077CC2B3200000000DB0F4940AA +:1020B000000080BF000000C000000000000080BFE2 +:1020C0000100807F0000803F000000000000803F92 +:1020D000FFFFFF7FFFFFFF7F000000000000C07FC9 +:1020E00000000080000000000000000000000080F0 +:1020F00000000000000000800000000000000080E0 +:10210000000000800000000000000000000000004F +:10211000000000000000008000000000000000003F +:040000058000000077 +:00000001FF diff --git a/src/test/resources/hex/rv32uf-p-ldst.hex b/src/test/resources/hex/rv32uf-p-ldst.hex new file mode 100755 index 00000000..3626fdb5 --- /dev/null +++ b/src/test/resources/hex/rv32uf-p-ldst.hex @@ -0,0 +1,43 @@ +:0200000480007A +:100000006F00C004732F2034930F8000630AFF0336 +:10001000930F90006306FF03930FB0006302FF038A +:10002000170F0080130F0FFE63040F0067000F000F +:10003000732F203463540F006F00400093E19153FD +:10004000171F000023203FFC6FF09FFF930000006C +:10005000130100009301000013020000930200004E +:100060001303000093030000130400009304000036 +:10007000130500009305000013060000930600001E +:100080001307000093070000130800009308000006 +:100090001309000093090000130A0000930A0000EE +:1000A000130B0000930B0000130C0000930C0000D6 +:1000B000130D0000930D0000130E0000930E0000BE +:1000C000130F0000930F0000732540F1631005002B +:1000D000970200009382020173905230735000180F +:1000E000970200009382020273905230B7020080A0 +:1000F0009382F2FF7390023B9302F0017390023AF5 +:100100007350403097020000938242017390523046 +:10011000735020307350303093010000970200007C +:10012000938282EE73905230130510001315F5017F +:10013000634C05000F00F00F930110009308D005E9 +:10014000130500007300000097020080938282EB89 +:10015000638A020073905210B7B20000938292102B +:100160007390223073500030372500007320053023 +:100170007350300097020000938242017390123452 +:10018000732540F17300203097250000938585E7A3 +:1001900087A0450027AA150003A54501B703004025 +:1001A000930120006314750297250000938585E56F +:1001B00087A0050027AC150003A58501B70380BF04 +:1001C0009301300063147500631030020F00F00FCC +:1001D000638001009391110093E111009308D00511 +:1001E00013850100730000000F00F00F9301100051 +:1001F0009308D0051305000073000000731000C0C1 +:0402000000000000FA +:1010000000000000000000000000000000000000E0 +:1010100000000000000000000000000000000000D0 +:1010200000000000000000000000000000000000C0 +:1010300000000000000000000000000000000000B0 +:081040000000000000000000A8 +:10200000000080BF0000004000004040000080C091 +:10201000EFBEADDEBEBAFECAEA1DADAB0DD03713C2 +:040000058000000077 +:00000001FF diff --git a/src/test/resources/hex/rv32uf-p-move.hex b/src/test/resources/hex/rv32uf-p-move.hex new file mode 100755 index 00000000..7b8c19ac --- /dev/null +++ b/src/test/resources/hex/rv32uf-p-move.hex @@ -0,0 +1,81 @@ +:0200000480007A +:100000006F00C004732F2034930F8000630AFF0336 +:10001000930F90006306FF03930FB0006302FF038A +:10002000170F0080130F0FFE63040F0067000F000F +:10003000732F203463540F006F00400093E19153FD +:10004000171F000023203FFC6FF09FFF930000006C +:10005000130100009301000013020000930200004E +:100060001303000093030000130400009304000036 +:10007000130500009305000013060000930600001E +:100080001307000093070000130800009308000006 +:100090001309000093090000130A0000930A0000EE +:1000A000130B0000930B0000130C0000930C0000D6 +:1000B000130D0000930D0000130E0000930E0000BE +:1000C000130F0000930F0000732540F1631005002B +:1000D000970200009382020173905230735000180F +:1000E000970200009382020273905230B7020080A0 +:1000F0009382F2FF7390023B9302F0017390023AF5 +:100100007350403097020000938242017390523046 +:10011000735020307350303093010000970200007C +:10012000938282EE73905230130510001315F5017F +:10013000634C05000F00F00F930110009308D005E9 +:10014000130500007300000097020080938282EB89 +:10015000638A020073905210B7B20000938292102B +:100160007390223073500030372500007320053023 +:100170007350300097020000938242017390123452 +:10018000732540F17300203073D030003715000024 +:1001900013054523F3153500930310009301200048 +:1001A000639C752673253000930340039301300050 +:1001B00063147526732510009303400193014000DA +:1001C000631C7524735521009303100093015000A4 +:1001D0006314752473253000930340059301600078 +:1001E000631C752273751200930340019301700024 +:1001F000631475227325300093030005930180007A +:10020000631C7520B755341293858567130600006B +:10021000D38005F0530106F053802020530500E001 +:10022000B7533412938383679301A0006316751E3E +:10023000B7553412938585671306F0FFD38005F018 +:10024000530106F053802020530500E0B753349249 +:10025000938383679301B0006310751CB755349284 +:100260009385856713060000D38005F0530106F0DF +:1002700053802020530500E0B753341293838367E3 +:100280009301C000631A7518B7553492938585673A +:100290001306F0FFD38005F0530106F053802020B1 +:1002A000530500E0B7533492938383679301D000E2 +:1002B00063147516B75534129385856713060000CD +:1002C000D38005F0530106F053902020530500E041 +:1002D000B75334929383836793014001631E751271 +:1002E000B7553412938585671306F0FFD38005F068 +:1002F000530106F053902020530500E0B753341209 +:10030000938383679301500163187510B755349236 +:100310009385856713060000D38005F0530106F02E +:1003200053902020530500E0B753349293838367A2 +:10033000930160016312750EB755349293858567FA +:100340001306F0FFD38005F0530106F053902020F0 +:10035000530500E0B7533412938383679301700110 +:10036000631C750AB7553412938585671306000020 +:10037000D38005F0530106F053A02020530500E080 +:10038000B7533412938383679301E00163167508B2 +:10039000B7553412938585671306F0FFD38005F0B7 +:1003A000530106F053A02020530500E0B7533492C8 +:1003B000938383679301F00163107506B7553492F8 +:1003C0009385856713060000D38005F0530106F07E +:1003D00053A02020530500E0B753349293838367E2 +:1003E00093010002631A7502B755349293858567AD +:1003F0001306F0FFD38005F0530106F053A0202030 +:10040000530500E0B75334129383836793011002BE +:1004100063147500631030020F00F00F6380010059 +:100420009391110093E111009308D0051385010009 +:10043000730000000F00F00F930110009308D00527 +:100440001305000073000000731000C000000000DE +:10045000000000000000000000000000000000009C +:10046000000000000000000000000000000000008C +:10047000000000000000000000000000000000007C +:040480000000000078 +:1010000000000000000000000000000000000000E0 +:1010100000000000000000000000000000000000D0 +:1010200000000000000000000000000000000000C0 +:1010300000000000000000000000000000000000B0 +:081040000000000000000000A8 +:040000058000000077 +:00000001FF diff --git a/src/test/resources/hex/rv32uf-p-recoding.hex b/src/test/resources/hex/rv32uf-p-recoding.hex new file mode 100755 index 00000000..bd12e2a8 --- /dev/null +++ b/src/test/resources/hex/rv32uf-p-recoding.hex @@ -0,0 +1,46 @@ +:0200000480007A +:100000006F00C004732F2034930F8000630AFF0336 +:10001000930F90006306FF03930FB0006302FF038A +:10002000170F0080130F0FFE63040F0067000F000F +:10003000732F203463540F006F00400093E19153FD +:10004000171F000023203FFC6FF09FFF930000006C +:10005000130100009301000013020000930200004E +:100060001303000093030000130400009304000036 +:10007000130500009305000013060000930600001E +:100080001307000093070000130800009308000006 +:100090001309000093090000130A0000930A0000EE +:1000A000130B0000930B0000130C0000930C0000D6 +:1000B000130D0000930D0000130E0000930E0000BE +:1000C000130F0000930F0000732540F1631005002B +:1000D000970200009382020173905230735000180F +:1000E000970200009382020273905230B7020080A0 +:1000F0009382F2FF7390023B9302F0017390023AF5 +:100100007350403097020000938242017390523046 +:10011000735020307350303093010000970200007C +:10012000938282EE73905230130510001315F5017F +:10013000634C05000F00F00F930110009308D005E9 +:10014000130500007300000097020080938282EB89 +:10015000638A020073905210B7B20000938292102B +:100160007390223073500030372500007320053023 +:100170007350300097020000938242017390123452 +:10018000732540F17300203017250000072085E714 +:1001900017250000872045E7D3F00010532510A055 +:1001A000930310009301200063147506530510A0FB +:1001B0009303100093013000631C7504531510A0C5 +:1001C000930300009301400063147504537000D042 +:1001D00013051000D37005D0D3F00010532510A0E4 +:1001E000930310009301500063147502530510A08F +:1001F0009303100093016000631C7500531510A059 +:1002000093030000930170006314750063103002C3 +:100210000F00F00F638001009391110093E1110032 +:100220009308D00513850100730000000F00F00F44 +:10023000930110009308D00513050000730000001F +:04024000731000C077 +:1010000000000000000000000000000000000000E0 +:1010100000000000000000000000000000000000D0 +:1010200000000000000000000000000000000000C0 +:1010300000000000000000000000000000000000B0 +:081040000000000000000000A8 +:10200000000080FF000040400000000000000000D1 +:040000058000000077 +:00000001FF diff --git a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala index d066eb1c..8465fa4f 100644 --- a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala +++ b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala @@ -90,8 +90,14 @@ class FpuTest extends FunSuite{ val a,b,c = (s.nextLong(16).toInt) (b2f(a), b2f(b), c, s.nextInt(16)) } + + def f32_f32 = { + val s = new Scanner(next) + val a,b = (s.nextLong(16).toInt) + (b2f(a), b2f(b), s.nextInt(16)) } + } lazy val RAW = build("") lazy val RNE = build("-rnear_even") lazy val RTZ = build("-rminMag") @@ -115,8 +121,8 @@ class FpuTest extends FunSuite{ val mul = new TestCase("f32_mul") val ui2f = new TestCase("ui32_to_f32") val i2f = new TestCase("i32_to_f32") - val f2ui = new TestCase("f32_to_ui32") - val f2i = new TestCase("f32_to_i32") + val f2ui = new TestCase("f32_to_ui32 -exact") + val f2i = new TestCase("f32_to_i32 -exact") val eq = new TestCase("f32_eq") val lt = new TestCase("f32_lt") val le = new TestCase("f32_le") @@ -127,6 +133,8 @@ class FpuTest extends FunSuite{ val sgnj = new TestCase("f32_eq") val sgnjn = new TestCase("f32_eq") val sgnjx = new TestCase("f32_eq") + val sqrt = new TestCase("f32_sqrt") + val div = new TestCase("f32_div") } val cpus = for(id <- 0 until portCount) yield new { @@ -152,12 +160,17 @@ class FpuTest extends FunSuite{ assert(flagAccumulator == ref, s"Flag missmatch dut=$flagAccumulator ref=$ref $report") flagAccumulator = 0 } + def flagClear(): Unit ={ + waitUntil(pendingMiaou == 0) + flagAccumulator = 0 + } val flagAggregated = dut.reflectBaseType(s"flagAcc$id").asInstanceOf[Bits] dut.clockDomain.onSamplings{ val c = dut.io.port(id).completion pendingMiaou -= c.count.toInt flagAccumulator |= flagAggregated.toInt + dut.writeback.randomSim.randomize() } StreamDriver(dut.io.port(id).cmd ,dut.clockDomain){payload => @@ -228,7 +241,7 @@ class FpuTest extends FunSuite{ cmd.opcode #= opcode cmd.rs1 #= rs1 cmd.rs2 #= rs2 - cmd.rs3.randomize() + cmd.rs3 #= rs3 cmd.rd #= rd cmd.arg #= arg cmd.roundMode #= rounding @@ -447,7 +460,6 @@ class FpuTest extends FunSuite{ assert(f2b(v) == f2b(ref), f"## ${a} ${opName} $b = $v, $ref $rounding") } - flagMatch(flag, ref, f"## ${opName} ${a} $b $ref $rounding") } @@ -585,6 +597,37 @@ class FpuTest extends FunSuite{ } } + + + def testSqrtExact(a : Float, ref : Float, flag : Int, rounding : FpuRoundMode.E): Unit ={ + val rs = new RegAllocator() + val rs1, rs2, rs3 = rs.allocate() + val rd = Random.nextInt(32) + load(rs1, a) + + sqrt(rd,rs1) + storeFloat(rd){v => + val error = Math.abs(ref-v)/ref + println(f"sqrt($a) = $v, $ref $error $rounding") + assert(checkFloat(ref, v)) + } + } + + def testDivExact(a : Float, b : Float, ref : Float, flag : Int, rounding : FpuRoundMode.E): Unit ={ + val rs = new RegAllocator() + val rs1, rs2, rs3 = rs.allocate() + val rd = Random.nextInt(32) + load(rs1, a) + load(rs2, b) + + div(rd,rs1, rs2) + storeFloat(rd){v => + val error = Math.abs(ref-v)/ref + println(f"div($a, $b) = $v, $ref $error $rounding") + assert(checkFloat(ref, v)) + } + } + def testF2i(a : Float, signed : Boolean): Unit ={ val rs = new RegAllocator() val rs1, rs2, rs3 = rs.allocate() @@ -803,8 +846,70 @@ class FpuTest extends FunSuite{ val binaryOps = List[(Int,Int,Int,FpuRoundMode.E) => Unit](add, sub, mul) +// testSqrt(0.0f) + // testSqrt(1.2f) + // for(a <- fAll) testSqrt(a) +// for(_ <- 0 until 1000) testSqrt(randomFloat()) + + for(i <- 0 until 1000){ + testFma(randomFloat(), randomFloat(), randomFloat()) + } + flagClear() + println("fma done") //TODO + + + testF2iExact(-2.14748365E9f, -2147483648, 0, true, FpuRoundMode.RDN) + + testEq(Float.PositiveInfinity,Float.PositiveInfinity,1, 0) + testEq(0f, 0f,1, 0) + + for(_ <- 0 until 10000){ + val (a,b,i,f) = f32.le.RAW.f32_f32_i32 + testLe(a,b,i, f) + } + for(_ <- 0 until 10000){ + val (a,b,i,f) = f32.lt.RAW.f32_f32_i32 + testLt(a,b,i, f) + } + + for(r <- 0 until 10000){ + val (a,b,i,f) = f32.eq.RAW.f32_f32_i32 + testEq(a,b,i, f) + if(r % 100000 == 0) println(r) + } + println("Cmp done") + + for(_ <- 0 until 1000000){ + val rounding = FpuRoundMode.elements.randomPick() + val (a,b,f) = f32.f2ui(rounding).f32_i32 + testF2iExact(a,b, f, false, rounding) + } + + for(_ <- 0 until 1000000){ + val rounding = FpuRoundMode.elements.randomPick() + val (a,b,f) = f32.f2i(rounding).f32_i32 + testF2iExact(a,b, f, true, rounding) + } + + println("f2i done") + + for(_ <- 0 until 10000){ + val rounding = FpuRoundMode.elements.randomPick() + val (a,b,r,f) = f32.div(rounding).f32_f32_f32 + testDivExact(a, b, r, f, rounding) + } + println("f32 div done") + + for(_ <- 0 until 10000){ + val rounding = FpuRoundMode.elements.randomPick() + val (a,r,f) = f32.sqrt(rounding).f32_f32 + testSqrtExact(a, r, f, rounding) + } + println("f32 sqrt done") + flagClear() + for(_ <- 0 until 10000){ testSgnj(b2f(Random.nextInt()), b2f(Random.nextInt())) testSgnjn(b2f(Random.nextInt()), b2f(Random.nextInt())) @@ -848,37 +953,10 @@ class FpuTest extends FunSuite{ } println("minMax done") - for(_ <- 0 until 100000){ - val (a,b,i,f) = f32.le.RAW.f32_f32_i32 - testLe(a,b,i, f) - } - for(_ <- 0 until 100000){ - val (a,b,i,f) = f32.lt.RAW.f32_f32_i32 - testLt(a,b,i, f) - } - - for(_ <- 0 until 100000){ - val (a,b,i,f) = f32.eq.RAW.f32_f32_i32 - testEq(a,b,i, f) - } - println("Cmp done") - testF2iExact(-2.14748365E9f, -2147483648, 0, true, FpuRoundMode.RDN) - for(_ <- 0 until 10000){ - val rounding = FpuRoundMode.elements.randomPick() - val (a,b,f) = f32.f2ui(rounding).f32_i32 - testF2iExact(a,b, f, false, rounding) - } - for(_ <- 0 until 10000){ - val rounding = FpuRoundMode.elements.randomPick() - val (a,b,f) = f32.f2i(rounding).f32_i32 - testF2iExact(a,b, f, true, rounding) - } - - println("f2i done") for(_ <- 0 until 10000){ val rounding = FpuRoundMode.elements.randomPick() From 889cc5fde228a8648f5eb80ae52d26340e360f69 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 10 Feb 2021 12:16:44 +0100 Subject: [PATCH 577/951] fpu refractoring --- src/main/scala/vexriscv/ip/fpu/FpuCore.scala | 20 - src/test/scala/vexriscv/ip/fpu/FpuTest.scala | 625 +++++-------------- 2 files changed, 165 insertions(+), 480 deletions(-) diff --git a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala index 18843413..791a5eef 100644 --- a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala +++ b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala @@ -16,8 +16,6 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val port = Vec(slave(FpuPort(p)), portCount) } -// io.port(0).completion.flag.setAsDirectionLess.allowDirectionLessIo - val portCountWidth = log2Up(portCount) val Source = HardType(UInt(portCountWidth bits)) val exponentOne = (1 << p.internalExponentSize-1) - 1 @@ -30,7 +28,6 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val opcode = p.Opcode() val rs1, rs2, rs3 = p.rfAddress() val rd = p.rfAddress() - val value = Bits(32 bits) val arg = p.Arg() val roundMode = FpuRoundMode() } @@ -41,7 +38,6 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val lockId = lockIdType() val rs1, rs2, rs3 = p.internalFloating() val rd = p.rfAddress() - val value = Bits(32 bits) val arg = p.Arg() val roundMode = FpuRoundMode() } @@ -138,16 +134,6 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val increments = ArrayBuffer[Bool]() -// def increment(): Unit ={ -// //This is a SpinalHDL trick which allow to go back in time -// val swapContext = dslBody.swap() -// val cond = False -// swapContext.appendBack() -// -// cond := True -// incs += cond -// } - afterElaboration{ port.completion.count := increments.map(_.asUInt.resize(log2Up(increments.size + 1))).reduceBalancedTree(_ + _) } @@ -236,7 +222,6 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ output.source := s1.source output.opcode := s1.opcode output.lockId := s1LockId - output.value := s1.value output.arg := s1.arg output.roundMode := s1.roundMode output.rd := s1.rd @@ -384,11 +369,6 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ i2fZero := input.value(31 downto 0) === 0 } } otherwise { -// when(input.i2f){ -// input.value.getDrivingReg(0, 32 bits) := input.value(0, 32 bits) |<< 1 -// } otherwise { -// input.value.getDrivingReg(0, 23 bits) := input.value(0, 23 bits) |<< 1 -// } done := True } } diff --git a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala index 8465fa4f..49dd2113 100644 --- a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala +++ b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala @@ -431,23 +431,6 @@ class FpuTest extends FunSuite{ (Random.nextDouble() * (Math.pow(2.0, exp)) * (if(Random.nextBoolean()) -1.0 else 1.0)).toFloat } - def testAdd(a : Float, b : Float, rounding : FpuRoundMode.E = FpuRoundMode.RNE): Unit ={ - val rs = new RegAllocator() - val rs1, rs2, rs3 = rs.allocate() - val rd = Random.nextInt(32) - load(rs1, a) - load(rs2, b) - - add(rd,rs1,rs2, rounding) - storeFloat(rd){v => - val a_ = clamp(a) - val b_ = clamp(b) - val ref = Clib.math.addF32(a,b, rounding.position) - println(f"${a}%.19f + $b%.19f = $v, $ref $rounding") - println(f"${f2b(a).toHexString} + ${f2b(b).toHexString}") - assert(checkFloatExact(ref, v)) - } - } def testBinaryOp(op : (Int,Int,Int,FpuRoundMode.E) => Unit, a : Float, b : Float, ref : Float, flag : Int, rounding : FpuRoundMode.E, opName : String): Unit ={ val rs = new RegAllocator() @@ -463,32 +446,9 @@ class FpuTest extends FunSuite{ flagMatch(flag, ref, f"## ${opName} ${a} $b $ref $rounding") } - def testAddExact(a : Float, b : Float, ref : Float, flag : Int, rounding : FpuRoundMode.E): Unit ={ - val rs = new RegAllocator() - val rs1, rs2, rs3 = rs.allocate() - val rd = Random.nextInt(32) - load(rs1, a) - load(rs2, b) - add(rd,rs1,rs2, rounding) - storeFloat(rd){v => - assert(f2b(v) == f2b(ref), f"## ${a} + $b = $v, $ref $rounding") - } - } - def testMulExact(a : Float, b : Float, ref : Float, flag : Int, rounding : FpuRoundMode.E): Unit ={ - val rs = new RegAllocator() - val rs1, rs2, rs3 = rs.allocate() - val rd = Random.nextInt(32) - load(rs1, a) - load(rs2, b) - mul(rd,rs1,rs2, rounding) - storeFloat(rd){v => - assert(f2b(v) == f2b(ref), f"## ${a} * $b = $v, $ref $rounding") - } - } - - def testTransfer(a : Float, iSrc : Boolean, iDst : Boolean): Unit ={ + def testTransferRaw(a : Float, iSrc : Boolean, iDst : Boolean): Unit ={ val rd = Random.nextInt(32) def handle(v : Float): Unit ={ @@ -503,7 +463,7 @@ class FpuTest extends FunSuite{ flagMatch(0, f"$a") } - def testClass(a : Float) : Unit = { + def testClassRaw(a : Float) : Unit = { val rd = Random.nextInt(32) @@ -525,28 +485,8 @@ class FpuTest extends FunSuite{ } } - def testMul(a : Float, b : Float): Unit ={ - val rs = new RegAllocator() - val rs1, rs2, rs3 = rs.allocate() - val rd = Random.nextInt(32) - load(rs1, a) - load(rs2, b) - mul(rd,rs1,rs2) - storeFloat(rd){v => - val refUnclamped = a*b - val refClamped = clamp(clamp(a)*clamp(b)) - val ref = if(refClamped.isNaN) refUnclamped else refClamped - println(f"$a * $b = $v, $ref") - var checkIt = true - if(v == 0.0f && ref.abs == b2f(0x00800000)) checkIt = false //Rounding - if(checkIt) assert(checkFloat(ref, v)) - } - } - - - - def testFma(a : Float, b : Float, c : Float): Unit ={ + def testFmaRaw(a : Float, b : Float, c : Float): Unit ={ val rs = new RegAllocator() val rs1, rs2, rs3 = rs.allocate() val rd = Random.nextInt(32) @@ -564,7 +504,7 @@ class FpuTest extends FunSuite{ } - def testDiv(a : Float, b : Float): Unit ={ + def testDivRaw(a : Float, b : Float): Unit ={ val rs = new RegAllocator() val rs1, rs2, rs3 = rs.allocate() val rd = Random.nextInt(32) @@ -582,7 +522,7 @@ class FpuTest extends FunSuite{ } } - def testSqrt(a : Float): Unit ={ + def testSqrtRaw(a : Float): Unit ={ val rs = new RegAllocator() val rs1, rs2, rs3 = rs.allocate() val rd = Random.nextInt(32) @@ -628,27 +568,7 @@ class FpuTest extends FunSuite{ } } - def testF2i(a : Float, signed : Boolean): Unit ={ - val rs = new RegAllocator() - val rs1, rs2, rs3 = rs.allocate() - val rd = Random.nextInt(32) - load(rs1, a) - f2i(rs1, signed){rsp => - if(signed) { - val ref = a.toInt - val v = (rsp.value.toBigInt & 0xFFFFFFFFl).toInt - println(f"f2i($a) = $v, $ref") - if (a.abs < 1024 * 1024) assert(v == ref) - assert(checkFloat(v, ref)) - } else { - val ref = a.toLong.min(0xFFFFFFFFl) - val v = (rsp.value.toBigInt & 0xFFFFFFFFl).toLong - println(f"f2i($a) = $v, $ref") - if (a.abs < 1024 * 1024) assert(v == ref) - assert(checkFloat(v, ref)) - } - } - } + def testF2iExact(a : Float, ref : Int, flag : Int, signed : Boolean, rounding : FpuRoundMode.E): Unit ={ val rs = new RegAllocator() @@ -677,18 +597,7 @@ class FpuTest extends FunSuite{ } - def testI2f(a : Int, signed : Boolean): Unit ={ - val rs = new RegAllocator() - val rd = Random.nextInt(32) - i2f(rd, a, signed) - storeFloat(rd){v => - val aLong = if(signed) a.toLong else a.toLong & 0xFFFFFFFFl - val ref = if(signed) a.toFloat else (a.toLong & 0xFFFFFFFFl).toFloat - println(f"i2f($aLong) = $v, $ref") - if(ref.abs < (1 << 22)) assert(v === ref) - assert(checkFloat(v, ref)) - } - } + def testI2fExact(a : Int, b : Float, f : Int, signed : Boolean, rounding : FpuRoundMode.E): Unit ={ val rs = new RegAllocator() @@ -705,23 +614,6 @@ class FpuTest extends FunSuite{ } - def testCmp(a : Float, b : Float): Unit ={ - val rs = new RegAllocator() - val rs1, rs2, rs3 = rs.allocate() - val rd = Random.nextInt(32) - load(rs1, a) - load(rs2, b) - cmp(rs1, rs2){rsp => - var ref = if(a < b) 1 else 0 - if(a.isNaN || b.isNaN){ - ref = 0 - } - val v = rsp.value.toBigInt - println(f"$a < $b = $v, $ref") - assert(v === ref) - } - } - def testCmpExact(a : Float, b : Float, ref : Int, flag : Int, arg : Int): Unit ={ val rs = new RegAllocator() @@ -735,15 +627,15 @@ class FpuTest extends FunSuite{ } flagMatch(flag,f"$a < $b $ref $flag ${f2b(a).toHexString} ${f2b(b).toHexString}") } - def testLe(a : Float, b : Float, ref : Int, flag : Int) = testCmpExact(a,b,ref,flag, 0) - def testEq(a : Float, b : Float, ref : Int, flag : Int) = testCmpExact(a,b,ref,flag, 2) - def testLt(a : Float, b : Float, ref : Int, flag : Int) = testCmpExact(a,b,ref,flag, 1) + def testLeRaw(a : Float, b : Float, ref : Int, flag : Int) = testCmpExact(a,b,ref,flag, 0) + def testEqRaw(a : Float, b : Float, ref : Int, flag : Int) = testCmpExact(a,b,ref,flag, 2) + def testLtRaw(a : Float, b : Float, ref : Int, flag : Int) = testCmpExact(a,b,ref,flag, 1) // def testFmv_x_w(a : Float): Unit ={ // val rs = new RegAllocator() // val rs1, rs2, rs3 = rs.allocate() // val rd = Random.nextInt(32) -// load(rs1, a) +// load(rs1, a)tes // fmv_x_w(rs1){rsp => // val ref = f2b(a).toLong & 0xFFFFFFFFl // val v = rsp.value.toBigInt @@ -791,19 +683,19 @@ class FpuTest extends FunSuite{ flagMatch(flag, f"minmax($a $b $arg)") } - def testMin(a : Float, b : Float) = testMinMaxExact(a,b,0) - def testMax(a : Float, b : Float) = testMinMaxExact(a,b,1) + def testMinExact(a : Float, b : Float) : Unit = testMinMaxExact(a,b,0) + def testMaxExact(a : Float, b : Float) : Unit = testMinMaxExact(a,b,1) - def testSgnj(a : Float, b : Float): Unit ={ + def testSgnjRaw(a : Float, b : Float): Unit ={ val ref = b2f((f2b(a) & ~0x80000000) | f2b(b) & 0x80000000) testBinaryOp(sgnj,a,b,ref,0, null,"sgnj") } - def testSgnjn(a : Float, b : Float): Unit ={ + def testSgnjnRaw(a : Float, b : Float): Unit ={ val ref = b2f((f2b(a) & ~0x80000000) | ((f2b(b) & 0x80000000) ^ 0x80000000)) testBinaryOp(sgnjn,a,b,ref,0, null,"sgnjn") } - def testSgnjx(a : Float, b : Float): Unit ={ + def testSgnjxRaw(a : Float, b : Float): Unit ={ val ref = b2f(f2b(a) ^ (f2b(b) & 0x80000000)) testBinaryOp(sgnjx,a,b,ref,0, null,"sgnjx") } @@ -853,122 +745,176 @@ class FpuTest extends FunSuite{ - for(i <- 0 until 1000){ - testFma(randomFloat(), randomFloat(), randomFloat()) + + + + def testFma() : Unit = { + testFmaRaw(randomFloat(), randomFloat(), randomFloat()) + flagClear() } + + def testLe() : Unit = { + val (a,b,i,f) = f32.le.RAW.f32_f32_i32 + testLeRaw(a,b,i, f) + } + def testLt() : Unit = { + val (a,b,i,f) = f32.lt.RAW.f32_f32_i32 + testLtRaw(a,b,i, f) + } + + def testEq() : Unit = { + val (a,b,i,f) = f32.eq.RAW.f32_f32_i32 + testEqRaw(a,b,i, f) + } + + def testF2ui() : Unit = { + val rounding = FpuRoundMode.elements.randomPick() + val (a,b,f) = f32.f2ui(rounding).f32_i32 + testF2iExact(a,b, f, false, rounding) + } + + def testF2i() : Unit = { + val rounding = FpuRoundMode.elements.randomPick() + val (a,b,f) = f32.f2i(rounding).f32_i32 + testF2iExact(a,b, f, true, rounding) + } + + + def testDiv() : Unit = { + val rounding = FpuRoundMode.elements.randomPick() + val (a,b,r,f) = f32.div(rounding).f32_f32_f32 + testDivExact(a, b, r, f, rounding) + flagClear() + } + + def testSqrt() : Unit = { + val rounding = FpuRoundMode.elements.randomPick() + val (a,r,f) = f32.sqrt(rounding).f32_f32 + testSqrtExact(a, r, f, rounding) + flagClear() + } + + def testSgnj() : Unit = { + testSgnjRaw(b2f(Random.nextInt()), b2f(Random.nextInt())) + testSgnjnRaw(b2f(Random.nextInt()), b2f(Random.nextInt())) + testSgnjxRaw(b2f(Random.nextInt()), b2f(Random.nextInt())) + val (a,b,r,f) = f32.sgnj.RAW.f32_f32_i32 + testSgnjRaw(a, b) + testSgnjnRaw(a, b) + testSgnjxRaw(a, b) + } + + def testTransfer() : Unit = { + val (a,b,r,f) = f32.transfer.RAW.f32_f32_i32 + testTransferRaw(a, Random.nextBoolean(), Random.nextBoolean()) + } + + def testClass() : Unit = { + val (a,b,r,f) = f32.fclass.RAW.f32_f32_i32 + testClassRaw(a) + } + + def testMin() : Unit = { + val (a,b,r,f) = f32.min.RAW.f32_f32_f32 + testMinExact(a,b) + } + def testMax() : Unit = { + val (a,b,r,f) = f32.max.RAW.f32_f32_f32 + testMaxExact(a,b) + } + + def testUI2f() : Unit = { + val rounding = FpuRoundMode.elements.randomPick() + val (a,b,f) = f32.i2f(rounding).i32_f32 + testI2fExact(a,b,f, true, rounding) + } + + def testI2f() : Unit = { + val rounding = FpuRoundMode.elements.randomPick() + val (a,b,f) = f32.ui2f(rounding).i32_f32 + testI2fExact(a,b,f, false, rounding) + } + + def testMul() : Unit = { + val rounding = FpuRoundMode.elements.randomPick() + val (a,b,c,f) = f32.mul(rounding).f32_f32_f32 + testBinaryOp(mul,a,b,c,f, rounding,"mul") + } + + def testAdd() : Unit = { + val rounding = FpuRoundMode.elements.randomPick() + val (a,b,c,f) = f32.add(rounding).f32_f32_f32 + testBinaryOp(add,a,b,c,f, rounding,"add") + } + + def testSub() : Unit = { + val rounding = FpuRoundMode.elements.randomPick() + val (a,b,c,f) = f32.sub(rounding).f32_f32_f32 + testBinaryOp(sub,a,b,c,f, rounding,"sub") + } + + + val f32Tests = List[() => Unit](testSub, testAdd, testMul, testI2f, testUI2f, testMin, testMax, testSgnj, testTransfer, testDiv, testSqrt, testF2i, testF2ui, testLe, testEq, testLt, testClass, testFma) + + + + + + + + + + + + + + + + + for(i <- 0 until 1000) testFma() flagClear() println("fma done") //TODO testF2iExact(-2.14748365E9f, -2147483648, 0, true, FpuRoundMode.RDN) - testEq(Float.PositiveInfinity,Float.PositiveInfinity,1, 0) - testEq(0f, 0f,1, 0) + testEqRaw(Float.PositiveInfinity,Float.PositiveInfinity,1, 0) + testEqRaw(0f, 0f,1, 0) - for(_ <- 0 until 10000){ - val (a,b,i,f) = f32.le.RAW.f32_f32_i32 - testLe(a,b,i, f) - } - for(_ <- 0 until 10000){ - val (a,b,i,f) = f32.lt.RAW.f32_f32_i32 - testLt(a,b,i, f) - } - - for(r <- 0 until 10000){ - val (a,b,i,f) = f32.eq.RAW.f32_f32_i32 - testEq(a,b,i, f) - if(r % 100000 == 0) println(r) - } + for(_ <- 0 until 10000) testLe() + for(_ <- 0 until 10000) testLt() + for(_ <- 0 until 10000) testEq() println("Cmp done") - for(_ <- 0 until 1000000){ - val rounding = FpuRoundMode.elements.randomPick() - val (a,b,f) = f32.f2ui(rounding).f32_i32 - testF2iExact(a,b, f, false, rounding) - } - - for(_ <- 0 until 1000000){ - val rounding = FpuRoundMode.elements.randomPick() - val (a,b,f) = f32.f2i(rounding).f32_i32 - testF2iExact(a,b, f, true, rounding) - } + for(_ <- 0 until 10000) testF2ui() + for(_ <- 0 until 10000) testF2i() println("f2i done") - for(_ <- 0 until 10000){ - val rounding = FpuRoundMode.elements.randomPick() - val (a,b,r,f) = f32.div(rounding).f32_f32_f32 - testDivExact(a, b, r, f, rounding) - } + for(_ <- 0 until 10000) testDiv() println("f32 div done") - for(_ <- 0 until 10000){ - val rounding = FpuRoundMode.elements.randomPick() - val (a,r,f) = f32.sqrt(rounding).f32_f32 - testSqrtExact(a, r, f, rounding) - } + for(_ <- 0 until 10000) testSqrt() println("f32 sqrt done") - flagClear() - for(_ <- 0 until 10000){ - testSgnj(b2f(Random.nextInt()), b2f(Random.nextInt())) - testSgnjn(b2f(Random.nextInt()), b2f(Random.nextInt())) - testSgnjx(b2f(Random.nextInt()), b2f(Random.nextInt())) - val (a,b,r,f) = f32.sgnj.RAW.f32_f32_i32 - testSgnj(a, b) - testSgnjn(a, b) - testSgnjx(a, b) - } + for(_ <- 0 until 10000) testSgnj() println("f32 sgnj done") - for(_ <- 0 until 10000){ - testTransfer(b2f(Random.nextInt()), Random.nextBoolean(), Random.nextBoolean()) - } - for(_ <- 0 until 10000){ - val (a,b,r,f) = f32.transfer.RAW.f32_f32_i32 - testTransfer(a, Random.nextBoolean(), Random.nextBoolean()) - } - + for(_ <- 0 until 10000) testTransfer() println("f32 load/store/rf transfer done") - for(_ <- 0 until 10000){ - testClass(b2f(Random.nextInt())) - } - for(_ <- 0 until 10000){ - val (a,b,r,f) = f32.fclass.RAW.f32_f32_i32 - testClass(a) - } - + for(_ <- 0 until 10000) testClass() println("f32 class done") - for(_ <- 0 until 10000){ - val (a,b,r,f) = f32.min.RAW.f32_f32_f32 - testMin(a,b) - } - for(_ <- 0 until 10000){ - val (a,b,r,f) = f32.max.RAW.f32_f32_f32 - testMax(a,b) - } + for(_ <- 0 until 10000) testMin() + for(_ <- 0 until 10000) testMax() println("minMax done") - - - - - for(_ <- 0 until 10000){ - val rounding = FpuRoundMode.elements.randomPick() - val (a,b,f) = f32.i2f(rounding).i32_f32 - testI2fExact(a,b,f, true, rounding) - } - - for(_ <- 0 until 10000){ - val rounding = FpuRoundMode.elements.randomPick() - val (a,b,f) = f32.ui2f(rounding).i32_f32 - testI2fExact(a,b,f, false, rounding) - } + for(_ <- 0 until 10000) testUI2f() + for(_ <- 0 until 10000) testI2f() println("i2f done") testBinaryOp(mul,1.469368E-39f, 7.9999995f, 1.17549435E-38f,3, FpuRoundMode.RUP,"mul") @@ -986,26 +932,15 @@ class FpuTest extends FunSuite{ testBinaryOp(mul, 1.1754955E-38f, 0.999999f, 1.17549435E-38f, 3, FpuRoundMode.RUP, "mul") - for(_ <- 0 until 10000){ - val rounding = FpuRoundMode.elements.randomPick() - val (a,b,c,f) = f32.mul(rounding).f32_f32_f32 - testBinaryOp(mul,a,b,c,f, rounding,"mul") - } + + for(_ <- 0 until 10000) testMul() println("Mul done") - for(_ <- 0 until 10000){ - val rounding = FpuRoundMode.elements.randomPick() - val (a,b,c,f) = f32.add(rounding).f32_f32_f32 - testBinaryOp(add,a,b,c,f, rounding,"add") - } - for(_ <- 0 until 10000){ - val rounding = FpuRoundMode.elements.randomPick() - val (a,b,c,f) = f32.sub(rounding).f32_f32_f32 - testBinaryOp(sub,a,b,c,f, rounding,"sub") - } + for(_ <- 0 until 10000) testAdd() + for(_ <- 0 until 10000) testSub() println("Add done") @@ -1018,241 +953,11 @@ class FpuTest extends FunSuite{ - waitUntil(cmdQueue.isEmpty) - dut.clockDomain.waitSampling(1000) - simSuccess() - - //TODO test and fix a - b rounding - foreachRounding(testAdd(1.0f, b2f(0x3f800001), _)) //1.00001 - foreachRounding(testAdd(4.0f, b2f(0x3f800001), _)) //1.00001 - for(_ <- 0 until 10000; a = randomFloat(); b = randomFloat()) foreachRounding(testAdd(a.abs, b.abs,_)) //TODO negative - - - testAdd(b2f(0x3f800000), b2f(0x3f800000-1)) - testAdd(1.1f, 2.3f) - testAdd(1.2f, -1.2f) - testAdd(-1.2f, 1.2f) - testAdd(0.0f, -1.2f) - testAdd(-0.0f, -1.2f) - testAdd(1.2f, -0f) - testAdd(1.2f, 0f) - testAdd(1.1f, Float.MinPositiveValue) - - for(a <- fAll; _ <- 0 until 50) testAdd(a, randomFloat()) - for(b <- fAll; _ <- 0 until 50) testAdd(randomFloat(), b) - for(a <- fAll; b <- fAll) testAdd(a, b) - for(_ <- 0 until 1000) testAdd(randomFloat(), randomFloat()) - - -// testTransfer(1.17549435082e-38f) -// testTransfer(1.4E-45f) -// testTransfer(3.44383110592e-41f) - -//TODO bring back those tests and test overflow / underflow (F2I) -// testF2i(16.0f , false) -// testF2i(18.0f , false) -// testF2i(1200.0f, false) -// testF2i(1.0f , false) -// testF2i(0.0f , false) -// testF2i(1024*1024*1024*2l , false) -// testF2i(1024*1024*4095l , false) -// testF2i(1024*1024*5000l , false) -// -// val f2iUnsigned = ((0l to 32l) ++ (4060 to 4095).map(_*1024*1024l)).map(_.toFloat) ++ List(-0.0f) -// val f2iSigned = ((-32 to 32) ++ ((2030 to 2047)++(-2047 to -2030)).map(_*1024*1024)).map(_.toFloat) ++ List(-0.0f) -// for(f <- f2iUnsigned) testF2i(f, false) -// for(f <- f2iSigned) testF2i(f, true) -// for(f <- fAll) testF2i(f, false) -// for(f <- fAll) testF2i(f, true) -// for(_ <- 0 until 1000) testF2i(Random.nextFloat(), Random.nextBoolean()) - - - - - - - -// testTransfer(1.2f) - testMul(1.2f, 2.5f) - testMul(b2f(0x00400000), 16.0f) - testMul(b2f(0x00100000), 16.0f) - testMul(b2f(0x00180000), 16.0f) - testMul(b2f(0x00000004), 16.0f) - testMul(b2f(0x00000040), 16.0f) - testMul(b2f(0x00000041), 16.0f) - testMul(b2f(0x00000001), b2f(0x00000001)) - testMul(1.0f, b2f(0x00000001)) - testMul(0.5f, b2f(0x00000001)) - - // dut.clockDomain.waitSampling(1000) - // simSuccess() - - testMul(1.2f, 0f) - for(a <- fAll; _ <- 0 until 50) testMul(a, randomFloat()) - for(b <- fAll; _ <- 0 until 50) testMul(randomFloat(), b) - for(a <- fAll; b <- fAll) testMul(a, b) - for(_ <- 0 until 1000) testMul(randomFloat(), randomFloat()) - - - -// testTransfer(1.765f) -// testFmv_w_x(f2b(7.234f)) - testI2f(64, false) - for(i <- iUnsigned) testI2f(i, false) - for(i <- iSigned) testI2f(i, true) - for(_ <- 0 until 1000) testI2f(Random.nextInt(), Random.nextBoolean()) - - - testCmp(0.0f, 1.2f ) - testCmp(1.2f, 0.0f ) - testCmp(0.0f, -0.0f ) - testCmp(-0.0f, 0.0f ) - for(a <- fAll; _ <- 0 until 50) testCmp(a, randomFloat()) - for(b <- fAll; _ <- 0 until 50) testCmp(randomFloat(), b) - for(a <- fAll; b <- fAll) testCmp(a, b) - for(_ <- 0 until 1000) testCmp(randomFloat(), randomFloat()) - - - - testSqrt(1.2f) - testSqrt(0.0f) - for(a <- fAll) testSqrt(a) - for(_ <- 0 until 1000) testSqrt(randomFloat()) - - - testDiv(0.0f, 1.2f ) - testDiv(1.2f, 0.0f ) - testDiv(0.0f, 0.0f ) - for(a <- fAll; _ <- 0 until 50) testDiv(a, randomFloat()) - for(b <- fAll; _ <- 0 until 50) testDiv(randomFloat(), b) - for(a <- fAll; b <- fAll) testDiv(a, b) - for(_ <- 0 until 1000) testDiv(randomFloat(), randomFloat()) - - - - - - - - - - // dut.clockDomain.waitSampling(10000000) - - -// testFmv_x_w(1.246f) -// testFmv_w_x(f2b(7.234f)) - - testSgnj(1.0f, 2.0f) - testSgnj(1.5f, 2.0f) - testSgnj(1.5f, 3.5f) - testSgnj(1.5f, 1.5f) - testSgnj(1.5f, -1.5f) - testSgnj(-1.5f, 1.5f) - testSgnj(-1.5f, -1.5f) - testSgnj(1.5f, -3.5f) - - - - //TODO Test corner cases - for(signed <- List(false, true)) { - testI2f(17, signed) - testI2f(12, signed) - testI2f(512, signed) - testI2f(1, signed) - } - - testI2f(-17, true) - testI2f(-12, true) - testI2f(-512, true) - testI2f(-1, true) +// waitUntil(cmdQueue.isEmpty) // dut.clockDomain.waitSampling(1000) -// simFailure() +// simSuccess() - //TODO Test corner cases - testCmp(1.0f, 2.0f) - testCmp(1.5f, 2.0f) - testCmp(1.5f, 3.5f) - testCmp(1.5f, 1.5f) - testCmp(1.5f, -1.5f) - testCmp(-1.5f, 1.5f) - testCmp(-1.5f, -1.5f) - testCmp(1.5f, -3.5f) - - //TODO Test corner cases - for(signed <- List(false, true)) { - testF2i(16.0f, signed) - testF2i(18.0f, signed) - testF2i(1200.0f, signed) - testF2i(1.0f, signed) - } - - testF2i(-16.0f, true) - testF2i(-18.0f, true) - testF2i(-1200.0f, true) - testF2i(-1.0f, true) - - - testAdd(0.1f, 1.6f) - - testSqrt(1.5625f) - testSqrt(1.5625f*2) - testSqrt(1.8f) - testSqrt(4.4f) - testSqrt(0.3f) - testSqrt(1.5625f*2) - testSqrt(b2f(0x3f7ffffe)) - testSqrt(b2f(0x3f7fffff)) - testSqrt(b2f(0x3f800000)) - testSqrt(b2f(0x3f800001)) - testSqrt(b2f(0x3f800002)) - testSqrt(b2f(0x3f800003)) - - - - testMul(0.1f, 1.6f) - testFma(1.1f, 2.2f, 3.0f) - testDiv(1.0f, 1.1f) - testDiv(1.0f, 1.5f) - testDiv(1.0f, 1.9f) - testDiv(1.1f, 1.9f) - testDiv(1.0f, b2f(0x3f7ffffe)) - testDiv(1.0f, b2f(0x3f7fffff)) - testDiv(1.0f, b2f(0x3f800000)) - testDiv(1.0f, b2f(0x3f800001)) - testDiv(1.0f, b2f(0x3f800002)) - - - for(i <- 0 until 1000){ - testMul(randomFloat(), randomFloat()) - } - for(i <- 0 until 1000){ - testFma(randomFloat(), randomFloat(), randomFloat()) - } - for(i <- 0 until 1000){ - testDiv(randomFloat(), randomFloat()) - } - for(i <- 0 until 1000){ - testSqrt(Math.abs(randomFloat())) - } - for(i <- 0 until 1000){ - testCmp(randomFloat(), randomFloat()) - } - for(i <- 0 until 1000){ - val tests = ArrayBuffer[() => Unit]() - tests += (() =>{testAdd(randomFloat(), randomFloat())}) - tests += (() =>{testMul(randomFloat(), randomFloat())}) - tests += (() =>{testFma(randomFloat(), randomFloat(), randomFloat())}) - tests += (() =>{testDiv(randomFloat(), randomFloat())}) - tests += (() =>{testSqrt(randomFloat().abs)}) - tests += (() =>{testCmp(randomFloat(), randomFloat())}) -// tests += (() =>{testFmv_x_w(randomFloat())}) -// tests += (() =>{testFmv_w_x(f2b(randomFloat()))}) -// tests += (() =>{testMin(randomFloat(), randomFloat())}) - tests += (() =>{testSgnj(randomFloat(), randomFloat())}) - - - tests.randomPick().apply() - } + for(i <- 0 until 1000) f32Tests.randomPick()() waitUntil(cpu.rspQueue.isEmpty) } From 88dffc21f75fca0d7084ff7c6a4c27496f9c8dc9 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 10 Feb 2021 13:20:17 +0100 Subject: [PATCH 578/951] fpu f64 wip --- src/main/scala/vexriscv/TestsWorkspace.scala | 1 - src/main/scala/vexriscv/ip/fpu/FpuCore.scala | 108 +++++++++++------- .../scala/vexriscv/ip/fpu/Interface.scala | 10 +- src/test/scala/vexriscv/ip/fpu/FpuTest.scala | 29 +++-- 4 files changed, 93 insertions(+), 55 deletions(-) diff --git a/src/main/scala/vexriscv/TestsWorkspace.scala b/src/main/scala/vexriscv/TestsWorkspace.scala index c920e577..96f2551f 100644 --- a/src/main/scala/vexriscv/TestsWorkspace.scala +++ b/src/main/scala/vexriscv/TestsWorkspace.scala @@ -218,7 +218,6 @@ object TestsWorkspace { config.plugins += new FpuPlugin( externalFpu = false, p = FpuParameter( - internalMantissaSize = 23, withDouble = false ) ) diff --git a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala index 791a5eef..c5423865 100644 --- a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala +++ b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala @@ -30,6 +30,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val rd = p.rfAddress() val arg = p.Arg() val roundMode = FpuRoundMode() + val format = p.withDouble generate FpuFormat() } case class RfReadOutput() extends Bundle{ @@ -40,6 +41,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val rd = p.rfAddress() val arg = p.Arg() val roundMode = FpuRoundMode() + val format = p.withDouble generate FpuFormat() } @@ -50,6 +52,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val i2f = Bool() val arg = Bits(2 bits) val roundMode = FpuRoundMode() + val format = p.withDouble generate FpuFormat() } case class ShortPipInput() extends Bundle{ @@ -61,6 +64,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val value = Bits(32 bits) val arg = Bits(2 bits) val roundMode = FpuRoundMode() + val format = p.withDouble generate FpuFormat() } case class MulInput() extends Bundle{ @@ -72,6 +76,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val divSqrt = Bool() val msb1, msb2 = Bool() //allow usage of msb bits of mul val roundMode = FpuRoundMode() + val format = p.withDouble generate FpuFormat() } @@ -82,6 +87,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val lockId = lockIdType() val div = Bool() val roundMode = FpuRoundMode() + val format = p.withDouble generate FpuFormat() } @@ -91,6 +97,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val rd = p.rfAddress() val lockId = lockIdType() val roundMode = FpuRoundMode() + val format = p.withDouble generate FpuFormat() } @@ -101,6 +108,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val value = p.writeFloating() val scrap = Bool() val roundMode = FpuRoundMode() + val format = p.withDouble generate FpuFormat() } case class RoundOutput() extends Bundle{ @@ -111,7 +119,11 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } val rf = new Area{ - val ram = Mem(p.internalFloating, 32*portCount) + case class Entry() extends Bundle{ + val value = p.internalFloating() + val f32 = p.withDouble generate Bool() + } + val ram = Mem(Entry(), 32*portCount) val lock = for(i <- 0 until rfLockCount) yield new Area{ val valid = RegInit(False) val source = Reg(Source()) @@ -219,15 +231,19 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val s1 = s0.haltWhen(hazard || !rf.lockFree).m2sPipe() val output = s1.swapPayload(RfReadOutput()) val s1LockId = RegNextWhen(OHToUInt(rf.lockFreeId), !output.isStall) + val rs1Entry = rf.ram.readSync(s0.source @@ s0.rs1,enable = !output.isStall) + val rs2Entry = rf.ram.readSync(s0.source @@ s0.rs2,enable = !output.isStall) + val rs3Entry = rf.ram.readSync(s0.source @@ s0.rs3,enable = !output.isStall) output.source := s1.source output.opcode := s1.opcode output.lockId := s1LockId output.arg := s1.arg output.roundMode := s1.roundMode output.rd := s1.rd - output.rs1 := rf.ram.readSync(s0.source @@ s0.rs1,enable = !output.isStall) - output.rs2 := rf.ram.readSync(s0.source @@ s0.rs2,enable = !output.isStall) - output.rs3 := rf.ram.readSync(s0.source @@ s0.rs3,enable = !output.isStall) + if(p.withDouble) output.format := s1.format + output.rs1 := rs1Entry.value + output.rs2 := rs2Entry.value + output.rs3 := rs3Entry.value } val decode = new Area{ @@ -249,44 +265,53 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val divSqrtHit = input.opcode === p.Opcode.DIV || input.opcode === p.Opcode.SQRT val divSqrt = Stream(DivSqrtInput()) - input.ready setWhen(divSqrtHit && divSqrt.ready) - divSqrt.valid := input.valid && divSqrtHit - divSqrt.payload.assignSomeByName(read.output.payload) - divSqrt.div := input.opcode === p.Opcode.DIV + if(p.withDivSqrt) { + input.ready setWhen (divSqrtHit && divSqrt.ready) + divSqrt.valid := input.valid && divSqrtHit + divSqrt.payload.assignSomeByName(read.output.payload) + divSqrt.div := input.opcode === p.Opcode.DIV + } val fmaHit = input.opcode === p.Opcode.FMA val mulHit = input.opcode === p.Opcode.MUL || fmaHit val mul = Stream(MulInput()) val divSqrtToMul = Stream(MulInput()) - input.ready setWhen(mulHit && mul.ready && !divSqrtToMul.valid) - mul.valid := input.valid && mulHit || divSqrtToMul.valid + if(p.withMul) { + input.ready setWhen (mulHit && mul.ready && !divSqrtToMul.valid) + mul.valid := input.valid && mulHit || divSqrtToMul.valid - divSqrtToMul.ready := mul.ready - mul.payload := divSqrtToMul.payload - when(!divSqrtToMul.valid) { - mul.payload.assignSomeByName(read.output.payload) - mul.add := fmaHit - mul.divSqrt := False - mul.msb1 := True - mul.msb2 := True - mul.rs2.sign.allowOverride(); mul.rs2.sign := read.output.rs2.sign ^ input.arg(0) - mul.rs3.sign.allowOverride(); mul.rs3.sign := read.output.rs3.sign ^ input.arg(1) + divSqrtToMul.ready := mul.ready + mul.payload := divSqrtToMul.payload + when(!divSqrtToMul.valid) { + mul.payload.assignSomeByName(read.output.payload) + mul.add := fmaHit + mul.divSqrt := False + mul.msb1 := True + mul.msb2 := True + mul.rs2.sign.allowOverride(); + mul.rs2.sign := read.output.rs2.sign ^ input.arg(0) + mul.rs3.sign.allowOverride(); + mul.rs3.sign := read.output.rs3.sign ^ input.arg(1) + } } val addHit = input.opcode === p.Opcode.ADD val add = Stream(AddInput()) val mulToAdd = Stream(AddInput()) - input.ready setWhen(addHit && add.ready && !mulToAdd.valid) - add.valid := input.valid && addHit || mulToAdd.valid + if(p.withAdd) { + input.ready setWhen (addHit && add.ready && !mulToAdd.valid) + add.valid := input.valid && addHit || mulToAdd.valid - mulToAdd.ready := add.ready - add.payload := mulToAdd.payload - when(!mulToAdd.valid) { - add.payload.assignSomeByName(read.output.payload) - add.rs2.sign.allowOverride; add.rs2.sign := read.output.rs2.sign ^ input.arg(0) + mulToAdd.ready := add.ready + add.payload := mulToAdd.payload + when(!mulToAdd.valid) { + add.payload.assignSomeByName(read.output.payload) + add.rs2.sign.allowOverride; + add.rs2.sign := read.output.rs2.sign ^ input.arg(0) + } } } @@ -629,7 +654,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } } - val mul = new Area{ + val mul = p.withMul generate new Area{ val input = decode.mul.stage() val math = new Area { @@ -707,7 +732,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ input.ready := (input.add ? decode.mulToAdd.ready | output.ready) || input.divSqrt } - val divSqrt = new Area { + val divSqrt = p.withDivSqrt generate new Area { val input = decode.divSqrt.stage() val aproxWidth = 8 @@ -889,7 +914,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } } - val add = new Area{ + val add = p.withAdd generate new Area{ val input = decode.add.stage() val shifter = new Area { @@ -982,7 +1007,12 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val merge = new Area { //TODO maybe load can bypass merge and round. - val arbitrated = StreamArbiterFactory.lowerFirst.noLock.on(List(load.s1.output, add.output, mul.output, shortPip.rfOutput)) + val inputs = ArrayBuffer[Stream[MergeInput]]() + inputs += load.s1.output + if(p.withAdd) (inputs += add.output) + if(p.withMul) (inputs += mul.output) + if(p.withShortPipMisc) (inputs += shortPip.rfOutput) + val arbitrated = StreamArbiterFactory.lowerFirst.noLock.on(inputs) val isCommited = rf.lock.map(_.commited).read(arbitrated.lockId) val commited = arbitrated.haltWhen(!isCommited).toFlow } @@ -1094,22 +1124,23 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val port = rf.ram.writePort port.valid := input.valid && rf.lock.map(_.write).read(input.lockId) port.address := input.source @@ input.rd - port.data := input.value + port.data.value := input.value + if(p.withDouble) port.data.f32 := ??? val randomSim = p.sim generate (in UInt(p.internalMantissaSize bits)) - if(p.sim) when(port.data.isZero || port.data.isInfinity){ - port.data.mantissa := randomSim + if(p.sim) when(port.data.value.isZero || port.data.value.isInfinity){ + port.data.value.mantissa := randomSim } if(p.sim) when(input.value.special){ - port.data.exponent(p.internalExponentSize-1 downto 3) := randomSim.resized + port.data.value.exponent(p.internalExponentSize-1 downto 3) := randomSim.resized when(!input.value.isNan){ - port.data.exponent(2 downto 2) := randomSim.resized + port.data.value.exponent(2 downto 2) := randomSim.resized } } when(port.valid){ - assert(!(port.data.exponent === 0 && !port.data.special), "Special violation") - assert(!(port.data.exponent === port.data.exponent.maxValue && !port.data.special), "Special violation") + assert(!(port.data.value.exponent === 0 && !port.data.value.special), "Special violation") + assert(!(port.data.value.exponent === port.data.value.exponent.maxValue && !port.data.value.special), "Special violation") } } } @@ -1191,7 +1222,6 @@ object FpuSynthesisBench extends App{ "32", portCount = 1, FpuParameter( - internalMantissaSize = 23, withDouble = false ) ) diff --git a/src/main/scala/vexriscv/ip/fpu/Interface.scala b/src/main/scala/vexriscv/ip/fpu/Interface.scala index 1b804107..0f4b17f9 100644 --- a/src/main/scala/vexriscv/ip/fpu/Interface.scala +++ b/src/main/scala/vexriscv/ip/fpu/Interface.scala @@ -108,10 +108,14 @@ object FpuRoundModeInstr extends SpinalEnum(){ } -case class FpuParameter( internalMantissaSize : Int, - withDouble : Boolean, - sim : Boolean = false){ +case class FpuParameter( withDouble : Boolean, + sim : Boolean = false, + withAdd : Boolean = true, + withMul : Boolean = true, + withDivSqrt : Boolean = true, + withShortPipMisc : Boolean = true){ + val internalMantissaSize = if(withDouble) 52 else 23 val storeLoadType = HardType(Bits(if(withDouble) 64 bits else 32 bits)) val internalExponentSize = (if(withDouble) 11 else 8) + 1 val internalFloating = HardType(FpuFloat(exponentSize = internalExponentSize, mantissaSize = internalMantissaSize)) diff --git a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala index 49dd2113..a03f5924 100644 --- a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala +++ b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala @@ -32,8 +32,11 @@ class FpuTest extends FunSuite{ test("directed"){ val portCount = 1 val p = FpuParameter( - internalMantissaSize = 23, withDouble = false, +// withAdd = false, +// withMul = false, +// withDivSqrt = false, +// withShortPipMisc = true sim = true ) @@ -866,9 +869,21 @@ class FpuTest extends FunSuite{ + for(_ <- 0 until 10000) testTransfer() + println("f32 load/store/rf transfer done") + + for(_ <- 0 until 10000) testF2ui() + for(_ <- 0 until 10000) testF2i() + println("f2i done") + + for(_ <- 0 until 10000) testUI2f() + for(_ <- 0 until 10000) testI2f() + println("i2f done") - +// waitUntil(cmdQueue.isEmpty) +// dut.clockDomain.waitSampling(1000) +// simSuccess() for(i <- 0 until 1000) testFma() @@ -886,10 +901,6 @@ class FpuTest extends FunSuite{ for(_ <- 0 until 10000) testEq() println("Cmp done") - for(_ <- 0 until 10000) testF2ui() - for(_ <- 0 until 10000) testF2i() - - println("f2i done") for(_ <- 0 until 10000) testDiv() println("f32 div done") @@ -900,9 +911,6 @@ class FpuTest extends FunSuite{ for(_ <- 0 until 10000) testSgnj() println("f32 sgnj done") - for(_ <- 0 until 10000) testTransfer() - println("f32 load/store/rf transfer done") - for(_ <- 0 until 10000) testClass() println("f32 class done") @@ -913,9 +921,6 @@ class FpuTest extends FunSuite{ println("minMax done") - for(_ <- 0 until 10000) testUI2f() - for(_ <- 0 until 10000) testI2f() - println("i2f done") testBinaryOp(mul,1.469368E-39f, 7.9999995f, 1.17549435E-38f,3, FpuRoundMode.RUP,"mul") testBinaryOp(mul,1.1753509E-38f, 1.0001221f, 1.17549435E-38f ,1, FpuRoundMode.RUP,"mul") From e97c2de837b2e6d3db1c7e9d91a07144b95b801b Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 10 Feb 2021 19:27:26 +0100 Subject: [PATCH 579/951] fpu f64 wip --- src/main/scala/vexriscv/ip/fpu/FpuCore.scala | 235 +++++++++++++------ src/test/scala/vexriscv/ip/fpu/FpuTest.scala | 55 +++-- 2 files changed, 207 insertions(+), 83 deletions(-) diff --git a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala index c5423865..dd4352e2 100644 --- a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala +++ b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala @@ -19,10 +19,17 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val portCountWidth = log2Up(portCount) val Source = HardType(UInt(portCountWidth bits)) val exponentOne = (1 << p.internalExponentSize-1) - 1 + val exponentF32Subnormal = exponentOne-127 + val exponentF64Subnormal = exponentOne-1023 val rfLockCount = 5 val lockIdType = HardType(UInt(log2Up(rfLockCount) bits)) + def whenDouble(format : FpuFormat.C)(yes : => Unit)(no : => Unit): Unit ={ + if(p.withDouble) when(format === FpuFormat.DOUBLE) { yes } otherwise{ no } + if(!p.withDouble) no + } + case class RfReadInput() extends Bundle{ val source = Source() val opcode = p.Opcode() @@ -116,12 +123,13 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val lockId = lockIdType() val rd = p.rfAddress() val value = p.internalFloating() + val format = p.withDouble generate FpuFormat() } val rf = new Area{ case class Entry() extends Bundle{ val value = p.internalFloating() - val f32 = p.withDouble generate Bool() + val boxed = p.withDouble generate Bool() } val ram = Mem(Entry(), 32*portCount) val lock = for(i <- 0 until rfLockCount) yield new Area{ @@ -181,6 +189,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } } + //TODO nan boxing decoding val read = new Area{ val arbiter = StreamArbiterFactory.noLock.lowerFirst.build(FpuCmd(p), portCount) arbiter.io.inputs <> Vec(io.port.map(_.cmd)) @@ -240,10 +249,21 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ output.arg := s1.arg output.roundMode := s1.roundMode output.rd := s1.rd - if(p.withDouble) output.format := s1.format output.rs1 := rs1Entry.value output.rs2 := rs2Entry.value output.rs3 := rs3Entry.value + if(p.withDouble){ + output.format := s1.format + when(s1.format === FpuFormat.FLOAT =/= rs1Entry.boxed){ + output.rs1.setNanQuiet + } + when(s1.format === FpuFormat.FLOAT =/= rs2Entry.boxed){ + output.rs2.setNanQuiet + } + when(s1.format === FpuFormat.FLOAT =/= rs3Entry.boxed){ + output.rs3.setNanQuiet + } + } } val decode = new Area{ @@ -325,6 +345,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val i2f = Bool() val arg = Bits(2 bits) val roundMode = FpuRoundMode() + val format = p.withDouble generate FpuFormat() } val s0 = new Area{ @@ -343,44 +364,72 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ output.i2f := input.i2f output.arg := input.arg output.roundMode := input.roundMode + if(p.withDouble) output.format := input.format } val s1 = new Area{ val input = s0.output.stage() val busy = False - val f32Mantissa = input.value(0, 23 bits).asUInt - val f32Exponent = input.value(23, 8 bits).asUInt - val f32Sign = input.value(31) + val f32 = new Area{ + val mantissa = input.value(0, 23 bits).asUInt + val exponent = input.value(23, 8 bits).asUInt + val sign = input.value(31) + } + val f64 = p.withDouble generate new Area{ + val mantissa = input.value(0, 52 bits).asUInt + val exponent = input.value(11, 52 bits).asUInt + val sign = input.value(63) + } - val expZero = f32Exponent === 0 - val expOne = f32Exponent === 255 - val manZeroReject = Reg(Bool()) setWhen(busy) clearWhen(!input.isStall) - val manZero = f32Mantissa === 0 && !manZeroReject + val passThroughFloat = p.internalFloating() + passThroughFloat.special := False + passThroughFloat.sign := f32.sign + passThroughFloat.exponent := f32.exponent.resized + passThroughFloat.mantissa := f32.mantissa << (if(p.withDouble) 29 else 0) + if(p.withDouble) when(input.format === FpuFormat.DOUBLE){ + passThroughFloat.sign := f64.sign + passThroughFloat.exponent := f64.exponent.resized + passThroughFloat.mantissa := f64.mantissa + } + + val manZero = passThroughFloat.mantissa === 0 + val expZero = passThroughFloat.exponent === 0 + val expOne = passThroughFloat.exponent(7 downto 0).andR + if(p.withDouble) expOne.clearWhen(input.format === FpuFormat.DOUBLE && !passThroughFloat.exponent(11 downto 8).andR) val isZero = expZero && manZero val isSubnormal = expZero && !manZero - val isNormal = !expOne && !expZero val isInfinity = expOne && manZero val isNan = expOne && !manZero - val isQuiet = f32Mantissa.msb + val fsm = new Area{ val done, boot, patched = Reg(Bool()) - val ohInput = CombInit(input.value(0, 32 max p.internalMantissaSize bits)) - when(!input.i2f) { ohInput(9, 23 bits) := input.value(0, 23 bits) } + val ohInputWidth = 32 max p.internalMantissaSize + val ohInput = Bits(ohInputWidth bits).assignDontCare() + when(!input.i2f) { + if(!p.withDouble) ohInput(ohInputWidth-23, 23 bits) := input.value(0, 23 bits) + if( p.withDouble) ohInput := passThroughFloat.mantissa.asBits + } otherwise { + ohInput(ohInputWidth-32, 32 bits) := input.value(31 downto 0) + } + val i2fZero = Reg(Bool) val shift = new Area{ - val by = Reg(UInt(log2Up(p.internalMantissaSize max 32) bits)) - val input = UInt(p.internalMantissaSize max 32 bits).assignDontCare() + val by = Reg(UInt(log2Up(ohInputWidth) bits)) + val input = UInt(ohInputWidth bits).assignDontCare() var logic = input for(i <- by.range){ logic \= by(i) ? (logic |<< (BigInt(1) << i)) | logic } val output = RegNextWhen(logic, !done) } - shift.input := input.value.asUInt |<< 1 + shift.input := (input.value.asUInt |<< 1).resized + + val subnormalShiftOffset = if(!p.withDouble) U(9) else ((input.format === FpuFormat.DOUBLE) ? U(0) | U(0)) + val subnormalExpOffset = if(!p.withDouble) U(9) else ((input.format === FpuFormat.DOUBLE) ? U(0) | U(0)) when(input.valid && (input.i2f || isSubnormal) && !done){ busy := True @@ -389,7 +438,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ input.value.getDrivingReg(0, 32 bits) := B(input.value.asUInt.twoComplement(True).resize(32 bits)) patched := True } otherwise { - shift.by := OHToUInt(OHMasking.first((ohInput).reversed)) + (input.i2f ? U(0) | U(9)) + shift.by := OHToUInt(OHMasking.first((ohInput).reversed)) + (input.i2f ? U(0) | subnormalShiftOffset) boot := False i2fZero := input.value(31 downto 0) === 0 } @@ -401,7 +450,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val expOffset = (UInt(p.internalExponentSize bits)) expOffset := 0 when(isSubnormal){ - expOffset := (shift.by-9).resized + expOffset := (shift.by-subnormalExpOffset).resized } when(!input.isStall){ @@ -413,13 +462,13 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val i2fSign = fsm.patched - val (i2fHigh, i2fLow) = fsm.shift.output.splitAt(widthOf(input.value)-24) + val (i2fHigh, i2fLow) = fsm.shift.output.splitAt(if(p.withDouble) 0 else widthOf(input.value)-24) val scrap = i2fLow =/= 0 val recoded = p.internalFloating() - recoded.mantissa := f32Mantissa - recoded.exponent := (f32Exponent -^ fsm.expOffset + (exponentOne - 127)).resized - recoded.sign := f32Sign + recoded.mantissa := passThroughFloat.mantissa + recoded.exponent := (passThroughFloat.exponent -^ fsm.expOffset + exponentF32Subnormal).resized + recoded.sign := passThroughFloat.sign recoded.setNormal when(isZero){recoded.setZero} when(isInfinity){recoded.setInfinity} @@ -429,6 +478,12 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ output.source := input.source output.lockId := input.lockId output.roundMode := input.roundMode + if(p.withDouble) { + output.format := input.format + when(!input.i2f && input.format === FpuFormat.DOUBLE && input.value(63 downto 23).andR){ //Detect boxing + output.format := FpuFormat.FLOAT + } + } output.rd := input.rd output.value.sign := recoded.sign output.value.exponent := recoded.exponent @@ -444,7 +499,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } when(input.i2f || isSubnormal){ - output.value.mantissa := U(i2fHigh) + output.value.mantissa := U(i2fHigh) @@ (if(p.withDouble) U"0" else U"") } } } @@ -456,21 +511,23 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val result = p.storeLoadType().assignDontCare() - val recoded = CombInit(input.rs1) - val flag = io.port(input.source).completion.flag val halt = False - val recodedResult = Bits(32 bits)//recoded.asBits.resize(32 bits) + val recodedResult = p.storeLoadType() val f32 = new Area{ - val exp = (recoded.exponent - (exponentOne-127)).resize(8 bits) - val man = recoded.mantissa + val exp = (input.rs1.exponent - (exponentOne-127)).resize(8 bits) + val man = CombInit(input.rs1.mantissa(if(p.withDouble) 51 downto 29 else 22 downto 0)) } - recodedResult := recoded.sign ## f32.exp ## f32.man + val f64 = p.withDouble generate new Area{ + val exp = (input.rs1.exponent - (exponentOne-1023)).resize(11 bits) + val man = CombInit(input.rs1.mantissa) + } + recodedResult := (if(p.withDouble) B"xFFFFFFFF" else B"") ## input.rs1.sign ## f32.exp ## f32.man - val expInSubnormalRange = recoded.exponent <= exponentOne - 127 - val isSubnormal = !recoded.special && expInSubnormalRange - val isNormal = !recoded.special && !expInSubnormalRange + val expInSubnormalRange = input.rs1.exponent <= exponentOne - 127 + val isSubnormal = !input.rs1.special && expInSubnormalRange + val isNormal = !input.rs1.special && !expInSubnormalRange val fsm = new Area{ val f2iShift = input.rs1.exponent - U(exponentOne) val isF2i = input.opcode === FpuOpcode.F2I @@ -479,8 +536,8 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val isZero = input.rs1.isZero// || input.rs1.exponent < exponentOne-1 val shift = new Area{ - val by = Reg(UInt(log2Up(p.internalMantissaSize max 33) bits)) - val input = UInt(p.internalMantissaSize max 33 bits).assignDontCare() + val by = Reg(UInt(log2Up(p.internalMantissaSize+1 max 33) bits)) + val input = UInt(p.internalMantissaSize+1 max 33 bits).assignDontCare() var logic = input val scrap = Reg(Bool) for(i <- by.range){ @@ -493,7 +550,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val output = RegNextWhen(logic, !done) } - shift.input := (U(!isZero) @@ input.rs1.mantissa) << 9 + shift.input := (U(!isZero) @@ input.rs1.mantissa) << (if(p.withDouble) 0 else 9) when(input.valid && (needRecoding || isF2i) && !done){ @@ -502,7 +559,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ when(isF2i){ shift.by := (U(exponentOne + 31) - input.rs1.exponent).min(U(33)).resized //TODO merge } otherwise { - shift.by := (U(exponentOne - 127+10) - recoded.exponent).resized + shift.by := (U(exponentOne - 127+10) - input.rs1.exponent).resized } boot := False } otherwise { @@ -510,31 +567,40 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } } - when(isSubnormal){ - f32.exp := 0 - f32.man := shift.output(22 downto 0) - } when(!input.isStall){ done := False boot := True } } - when(recoded.special){ + val mantissaForced = False + val exponentForced = False + val mantissaForcedValue = Bool().assignDontCare() + val exponentForcedValue = Bool().assignDontCare() + val cononicalForced = False + + + when(input.rs1.special){ switch(input.rs1.exponent(1 downto 0)){ is(FpuFloat.ZERO){ - recodedResult(0,23 bits).clearAll() - recodedResult(23, 8 bits).clearAll() + mantissaForced := True + exponentForced := True + mantissaForcedValue := False + exponentForcedValue := False } is(FpuFloat.INFINITY){ - recodedResult(0, 23 bits).clearAll() - recodedResult(23, 8 bits).setAll() + mantissaForced := True + exponentForced := True + mantissaForcedValue := False + exponentForcedValue := True } is(FpuFloat.NAN){ - recodedResult(23, 8 bits).setAll() + exponentForced := True + exponentForcedValue := True when(input.rs1.isCanonical){ - recodedResult(31) := False - recodedResult(0, 22 bits) := 0 + cononicalForced := True + mantissaForced := True + mantissaForcedValue := False } } } @@ -542,8 +608,41 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ + when(isSubnormal){ + exponentForced := True + exponentForcedValue := False + recodedResult(0,23 bits) := fsm.shift.output(22 downto 0).asBits + whenDouble(input.format){ + recodedResult(51 downto 23) := fsm.shift.output(51 downto 23).asBits + }{} + } + when(mantissaForced){ + recodedResult(0,23 bits) := (default -> mantissaForcedValue) + whenDouble(input.format){ + recodedResult(52-23, 52-23 bits) := (default -> exponentForcedValue) + }{} + } + when(exponentForced){ + whenDouble(input.format){ + recodedResult(52, 11 bits) := (default -> exponentForcedValue) + } { + recodedResult(23, 8 bits) := (default -> exponentForcedValue) + } + } + when(cononicalForced){ + whenDouble(input.format){ + recodedResult(63) := False + recodedResult(51) := True + } { + recodedResult(31) := False + recodedResult(22) := True + } + } + + + val f2i = new Area{ //Will not work for 64 bits float max value rounding - val unsigned = fsm.shift.output >> 1 + val unsigned = fsm.shift.output(32 downto 0) >> 1 val resign = input.arg(0) && input.rs1.sign val round = fsm.shift.output(0) ## fsm.shift.scrap val increment = input.roundMode.mux( @@ -587,7 +686,6 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val minMaxResult = ((rs1Smaller ^ input.arg(0)) && !input.rs1.isNan || input.rs2.isNan) ? input.rs1 | input.rs2 when(input.rs1.isNan && input.rs2.isNan) { minMaxResult.setNanQuiet } -// when(input.rs1.isZero && input.rs2.isZero && input.rs1.sign =/= input.rs2.sign){ minMaxResult.sign := !input.arg(0) } val cmpResult = B(rs1Smaller && !bothZero && !input.arg(1) || (rs1Equal || bothZero) && !input.arg(0)) when(input.rs1.isNan || input.rs2.isNan) { cmpResult := 0 } val sgnjResult = (input.rs1.sign && input.arg(1)) ^ input.rs2.sign ^ input.arg(0) @@ -595,10 +693,10 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val decoded = input.rs1.decode() fclassResult(0) := input.rs1.sign && decoded.isInfinity fclassResult(1) := input.rs1.sign && isNormal - fclassResult(2) := input.rs1.sign && isSubnormal //TODO + fclassResult(2) := input.rs1.sign && isSubnormal fclassResult(3) := input.rs1.sign && decoded.isZero fclassResult(4) := !input.rs1.sign && decoded.isZero - fclassResult(5) := !input.rs1.sign && isSubnormal //TODO + fclassResult(5) := !input.rs1.sign && isSubnormal fclassResult(6) := !input.rs1.sign && isNormal fclassResult(7) := !input.rs1.sign && decoded.isInfinity fclassResult(8) := decoded.isNan && !decoded.isQuiet @@ -607,10 +705,10 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ switch(input.opcode){ is(FpuOpcode.STORE) { result := recodedResult } - is(FpuOpcode.FMV_X_W) { result := recodedResult } //TODO - is(FpuOpcode.F2I) { result := f2i.result.asBits } - is(FpuOpcode.CMP) { result := cmpResult.resized } //TODO - is(FpuOpcode.FCLASS) { result := fclassResult.resized } + is(FpuOpcode.FMV_X_W) { result := recodedResult } + is(FpuOpcode.F2I) { result(31 downto 0) := f2i.result.asBits } + is(FpuOpcode.CMP) { result(31 downto 0) := cmpResult.resized } + is(FpuOpcode.FCLASS) { result(31 downto 0) := fclassResult.resized } } val toFpuRf = List(FpuOpcode.MIN_MAX, FpuOpcode.SGNJ).map(input.opcode === _).orR @@ -620,7 +718,8 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ rfOutput.lockId := input.lockId rfOutput.rd := input.rd rfOutput.roundMode := input.roundMode - rfOutput.scrap := False //TODO + if(p.withDouble) rfOutput.format := input.format + rfOutput.scrap := False rfOutput.value.assignDontCare() switch(input.opcode){ is(FpuOpcode.MIN_MAX){ @@ -714,6 +813,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ output.source := input.source output.lockId := input.lockId output.rd := input.rd + if(p.withDouble) output.format := input.format output.roundMode := input.roundMode output.scrap := norm.scrap output.value := norm.output @@ -728,6 +828,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ decode.mulToAdd.rd := input.rd decode.mulToAdd.lockId := input.lockId decode.mulToAdd.roundMode := input.roundMode + if(p.withDouble) decode.mulToAdd.format := input.format input.ready := (input.add ? decode.mulToAdd.ready | output.ready) || input.divSqrt } @@ -760,6 +861,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ decode.divSqrtToMul.rs1.special := False //TODO decode.divSqrtToMul.rs2.special := False decode.divSqrtToMul.roundMode := input.roundMode + if(p.withDouble) decode.divSqrtToMul.format := input.format val aprox = new Area { @@ -984,6 +1086,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ output.value.exponent := norm.exponent.resized output.value.special := False output.roundMode := input.roundMode + if(p.withDouble) output.format := input.format output.scrap := (norm.mantissa(1) | norm.mantissa(0) | shifter.roundingScrap) @@ -1105,6 +1208,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ output.source := input.source output.lockId := input.lockId output.rd := input.rd + if(p.withDouble) output.format := input.format output.value := patched } @@ -1125,7 +1229,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ port.valid := input.valid && rf.lock.map(_.write).read(input.lockId) port.address := input.source @@ input.rd port.data.value := input.value - if(p.withDouble) port.data.f32 := ??? + if(p.withDouble) port.data.boxed := input.format === FpuFormat.FLOAT val randomSim = p.sim generate (in UInt(p.internalMantissaSize bits)) if(p.sim) when(port.data.value.isZero || port.data.value.isInfinity){ @@ -1225,14 +1329,13 @@ object FpuSynthesisBench extends App{ withDouble = false ) ) -// rtls += new Fpu( -// "64", -// portCount = 1, -// FpuParameter( -// internalMantissaSize = 52, -// withDouble = true -// ) -// ) + rtls += new Fpu( + "64", + portCount = 1, + FpuParameter( + withDouble = true + ) + ) // rtls += new Shifter(24) // rtls += new Shifter(32) diff --git a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala index a03f5924..6d5b4954 100644 --- a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala +++ b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala @@ -25,27 +25,34 @@ class FpuTest extends FunSuite{ val b2f = lang.Float.intBitsToFloat(_) val f2b = lang.Float.floatToRawIntBits(_) - def clamp(f : Float) = { - f // if(f.abs < b2f(0x00800000)) b2f(f2b(f) & 0x80000000) else f - } - test("directed"){ - val portCount = 1 + test("f32f64") { val p = FpuParameter( - withDouble = false, + withDouble = true, // withAdd = false, // withMul = false, // withDivSqrt = false, -// withShortPipMisc = true sim = true ) + testP(p) + } + test("f32") { + val p = FpuParameter( + withDouble = false, + sim = true + ) + testP(p) + } + + def testP(p : FpuParameter){ + val portCount = 1 val config = SimConfig config.allOptimisation -// config.withFstWave + if(p.withDouble) config.withFstWave config.compile(new FpuCore(portCount, p){ for(i <- 0 until portCount) out(Bits(5 bits)).setName(s"flagAcc$i") := io.port(i).completion.flag.asBits - setDefinitionName("FpuCore") + setDefinitionName("FpuCore"+ (if(p.withDouble) "Double" else "")) }).doSim(seed = 42){ dut => dut.clockDomain.forkStimulus(10) dut.clockDomain.forkSimSpeedPrinter(5.0) @@ -201,7 +208,7 @@ class FpuTest extends FunSuite{ - def loadRaw(rd : Int, value : BigInt): Unit ={ + def loadRaw(rd : Int, value : BigInt, format : FpuFormat.E): Unit ={ cmdAdd {cmd => cmd.opcode #= cmd.opcode.spinalEnum.LOAD cmd.rs1.randomize() @@ -209,6 +216,8 @@ class FpuTest extends FunSuite{ cmd.rs3.randomize() cmd.rd #= rd cmd.arg.randomize() + cmd.roundMode.randomize() + cmd.format #= format } commitQueue += {cmd => cmd.write #= true @@ -217,11 +226,12 @@ class FpuTest extends FunSuite{ } } + def load(rd : Int, value : Float): Unit ={ - loadRaw(rd, f2b(value).toLong & 0xFFFFFFFFl) + loadRaw(rd, f2b(value).toLong & 0xFFFFFFFFl, FpuFormat.FLOAT) } - def storeRaw(rs : Int)(body : FpuRsp => Unit): Unit ={ + def storeRaw(rs : Int, format : FpuFormat.E)(body : FpuRsp => Unit): Unit ={ cmdAdd {cmd => cmd.opcode #= cmd.opcode.spinalEnum.STORE cmd.rs1 #= rs @@ -229,6 +239,8 @@ class FpuTest extends FunSuite{ cmd.rs3.randomize() cmd.rd.randomize() cmd.arg.randomize() + cmd.roundMode.randomize() + cmd.format #= format } rspQueue += body @@ -236,7 +248,7 @@ class FpuTest extends FunSuite{ } def storeFloat(rs : Int)(body : Float => Unit): Unit ={ - storeRaw(rs){rsp => body(b2f(rsp.value.toLong.toInt))} + storeRaw(rs, FpuFormat.FLOAT){rsp => body(b2f(rsp.value.toBigInt.toInt))} } def fpuF2f(rd : Int, rs1 : Int, rs2 : Int, rs3 : Int, opcode : FpuOpcode.E, arg : Int, rounding : FpuRoundMode.E = FpuRoundMode.RNE): Unit ={ @@ -315,7 +327,7 @@ class FpuTest extends FunSuite{ fpuF2i(rs1, Random.nextInt(32), FpuOpcode.F2I, if(signed) 1 else 0, rounding)(body) } - def i2f(rd : Int, value : Int, signed : Boolean, rounding : FpuRoundMode.E = FpuRoundMode.RNE): Unit ={ + def i2f(rd : Int, value : Int, signed : Boolean, rounding : FpuRoundMode.E): Unit ={ cmdAdd {cmd => cmd.opcode #= cmd.opcode.spinalEnum.I2F cmd.rs1.randomize() @@ -340,8 +352,10 @@ class FpuTest extends FunSuite{ cmd.rs3.randomize() cmd.rd.randomize() cmd.arg #= 0 + cmd.roundMode.randomize() + cmd.format #= FpuFormat.FLOAT } - rspQueue += {rsp => body(b2f(rsp.value.toLong.toInt))} + rspQueue += {rsp => body(b2f(rsp.value.toBigInt.toInt))} } def fmv_w_x(rd : Int, value : Int): Unit ={ @@ -352,6 +366,8 @@ class FpuTest extends FunSuite{ cmd.rs3.randomize() cmd.rd #= rd cmd.arg #= 0 + cmd.roundMode.randomize() + cmd.format #= FpuFormat.FLOAT } commitQueue += {cmd => cmd.write #= true @@ -517,7 +533,7 @@ class FpuTest extends FunSuite{ div(rd,rs1,rs2) storeFloat(rd){v => val refUnclamped = a/b - val refClamped = clamp(clamp(a)/clamp(b)) + val refClamped = ((a)/(b)) val ref = refClamped val error = Math.abs(ref-v)/ref println(f"$a / $b = $v, $ref $error") @@ -863,7 +879,12 @@ class FpuTest extends FunSuite{ - + testTransferRaw(1.0f, false, false) + testTransferRaw(2.0f, false, false) + testTransferRaw(2.5f, false, false) + testTransferRaw(6.97949770801e-39f, false, false) + testTransferRaw(8.72437213501e-40f, false, false) + testTransferRaw(5.6E-45f, false, false) From b6eda1ad7a1e7611e9221192f6ea79274c22a22b Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 11 Feb 2021 16:07:47 +0100 Subject: [PATCH 580/951] fpu f64 load/store/mv/mul seems ok --- src/main/scala/vexriscv/ip/fpu/FpuCore.scala | 112 ++++-- src/test/scala/vexriscv/ip/fpu/FpuTest.scala | 400 +++++++++++++------ 2 files changed, 346 insertions(+), 166 deletions(-) diff --git a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala index dd4352e2..edb6dba8 100644 --- a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala +++ b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala @@ -21,6 +21,8 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val exponentOne = (1 << p.internalExponentSize-1) - 1 val exponentF32Subnormal = exponentOne-127 val exponentF64Subnormal = exponentOne-1023 + val exponentF32Infinity = exponentOne+127+1 + val exponentF64Infinity = exponentOne+1023+1 val rfLockCount = 5 val lockIdType = HardType(UInt(log2Up(rfLockCount) bits)) @@ -30,6 +32,11 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ if(!p.withDouble) no } + def muxDouble[T <: Data](format : FpuFormat.C)(yes : => T)(no : => T): T ={ + if(p.withDouble) ((format === FpuFormat.DOUBLE) ? { yes } | { no }) + else no + } + case class RfReadInput() extends Bundle{ val source = Source() val opcode = p.Opcode() @@ -254,11 +261,16 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ output.rs3 := rs3Entry.value if(p.withDouble){ output.format := s1.format - when(s1.format === FpuFormat.FLOAT =/= rs1Entry.boxed){ + val store = s1.opcode === FpuOpcode.STORE ||s1.opcode === FpuOpcode.FMV_X_W + when(store){ //Pass through + output.format := rs1Entry.boxed ? FpuFormat.FLOAT | FpuFormat.DOUBLE + } elsewhen(s1.format === FpuFormat.FLOAT =/= rs1Entry.boxed){ output.rs1.setNanQuiet + output.rs1.sign := False } when(s1.format === FpuFormat.FLOAT =/= rs2Entry.boxed){ output.rs2.setNanQuiet + output.rs2.sign := False } when(s1.format === FpuFormat.FLOAT =/= rs3Entry.boxed){ output.rs3.setNanQuiet @@ -364,7 +376,13 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ output.i2f := input.i2f output.arg := input.arg output.roundMode := input.roundMode - if(p.withDouble) output.format := input.format + if(p.withDouble) { + output.format := input.format + when(!input.i2f && input.format === FpuFormat.DOUBLE && output.value(63 downto 32).andR){ //Detect boxing + output.format := FpuFormat.FLOAT + } + } + } val s1 = new Area{ @@ -378,25 +396,34 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } val f64 = p.withDouble generate new Area{ val mantissa = input.value(0, 52 bits).asUInt - val exponent = input.value(11, 52 bits).asUInt + val exponent = input.value(52, 11 bits).asUInt val sign = input.value(63) } + val recodedExpOffset = UInt(p.internalExponentSize bits) val passThroughFloat = p.internalFloating() passThroughFloat.special := False - passThroughFloat.sign := f32.sign - passThroughFloat.exponent := f32.exponent.resized - passThroughFloat.mantissa := f32.mantissa << (if(p.withDouble) 29 else 0) - if(p.withDouble) when(input.format === FpuFormat.DOUBLE){ + + whenDouble(input.format){ passThroughFloat.sign := f64.sign passThroughFloat.exponent := f64.exponent.resized passThroughFloat.mantissa := f64.mantissa + recodedExpOffset := exponentF64Subnormal + } { + passThroughFloat.sign := f32.sign + passThroughFloat.exponent := f32.exponent.resized + passThroughFloat.mantissa := f32.mantissa << (if (p.withDouble) 29 else 0) + recodedExpOffset := exponentF32Subnormal } + val manZero = passThroughFloat.mantissa === 0 val expZero = passThroughFloat.exponent === 0 val expOne = passThroughFloat.exponent(7 downto 0).andR - if(p.withDouble) expOne.clearWhen(input.format === FpuFormat.DOUBLE && !passThroughFloat.exponent(11 downto 8).andR) + if(p.withDouble) { + expZero.clearWhen(input.format === FpuFormat.DOUBLE && input.value(62 downto 60) =/= 0) + expOne.clearWhen(input.format === FpuFormat.DOUBLE && input.value(62 downto 60) =/= 7) + } val isZero = expZero && manZero val isSubnormal = expZero && !manZero @@ -409,9 +436,10 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val ohInputWidth = 32 max p.internalMantissaSize val ohInput = Bits(ohInputWidth bits).assignDontCare() when(!input.i2f) { - if(!p.withDouble) ohInput(ohInputWidth-23, 23 bits) := input.value(0, 23 bits) + if(!p.withDouble) ohInput := input.value(0, 23 bits) << 9 if( p.withDouble) ohInput := passThroughFloat.mantissa.asBits } otherwise { + ohInput(ohInputWidth-32-1 downto 0) := 0 ohInput(ohInputWidth-32, 32 bits) := input.value(31 downto 0) } @@ -426,15 +454,15 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } val output = RegNextWhen(logic, !done) } - shift.input := (input.value.asUInt |<< 1).resized + shift.input := (ohInput.asUInt |<< 1).resized - val subnormalShiftOffset = if(!p.withDouble) U(9) else ((input.format === FpuFormat.DOUBLE) ? U(0) | U(0)) - val subnormalExpOffset = if(!p.withDouble) U(9) else ((input.format === FpuFormat.DOUBLE) ? U(0) | U(0)) + val subnormalShiftOffset = if(!p.withDouble) U(0) else ((input.format === FpuFormat.DOUBLE) ? U(0) | U(0)) //TODO remove ? + val subnormalExpOffset = if(!p.withDouble) U(0) else ((input.format === FpuFormat.DOUBLE) ? U(0) | U(0)) when(input.valid && (input.i2f || isSubnormal) && !done){ busy := True when(boot){ - when(input.i2f && !patched && input.value.msb && input.arg(0)){ + when(input.i2f && !patched && input.value(31) && input.arg(0)){ input.value.getDrivingReg(0, 32 bits) := B(input.value.asUInt.twoComplement(True).resize(32 bits)) patched := True } otherwise { @@ -467,7 +495,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val recoded = p.internalFloating() recoded.mantissa := passThroughFloat.mantissa - recoded.exponent := (passThroughFloat.exponent -^ fsm.expOffset + exponentF32Subnormal).resized + recoded.exponent := (passThroughFloat.exponent -^ fsm.expOffset + recodedExpOffset).resized recoded.sign := passThroughFloat.sign recoded.setNormal when(isZero){recoded.setZero} @@ -480,9 +508,6 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ output.roundMode := input.roundMode if(p.withDouble) { output.format := input.format - when(!input.i2f && input.format === FpuFormat.DOUBLE && input.value(63 downto 23).andR){ //Detect boxing - output.format := FpuFormat.FLOAT - } } output.rd := input.rd output.value.sign := recoded.sign @@ -523,9 +548,15 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val exp = (input.rs1.exponent - (exponentOne-1023)).resize(11 bits) val man = CombInit(input.rs1.mantissa) } - recodedResult := (if(p.withDouble) B"xFFFFFFFF" else B"") ## input.rs1.sign ## f32.exp ## f32.man - val expInSubnormalRange = input.rs1.exponent <= exponentOne - 127 + whenDouble(input.format){ + recodedResult := input.rs1.sign ## f64.exp ## f64.man + } { + recodedResult := (if(p.withDouble) B"xFFFFFFFF" else B"") ## input.rs1.sign ## f32.exp ## f32.man + } + + val expSubnormalThreshold = muxDouble[UInt](input.format)(exponentF64Subnormal)(exponentF32Subnormal) + val expInSubnormalRange = input.rs1.exponent <= expSubnormalThreshold val isSubnormal = !input.rs1.special && expInSubnormalRange val isNormal = !input.rs1.special && !expInSubnormalRange val fsm = new Area{ @@ -552,14 +583,14 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ shift.input := (U(!isZero) @@ input.rs1.mantissa) << (if(p.withDouble) 0 else 9) - + val formatShiftOffset = muxDouble[UInt](input.format)(exponentOne-1023+1)(exponentOne - (if(p.withDouble) (127+34) else (127-10))) when(input.valid && (needRecoding || isF2i) && !done){ halt := True when(boot){ when(isF2i){ - shift.by := (U(exponentOne + 31) - input.rs1.exponent).min(U(33)).resized //TODO merge + shift.by := ((U(exponentOne + 31) - input.rs1.exponent).min(U(33)) + (if(p.withDouble) 20 else 0)).resized //TODO merge } otherwise { - shift.by := (U(exponentOne - 127+10) - input.rs1.exponent).resized + shift.by := (formatShiftOffset - input.rs1.exponent).resized } boot := False } otherwise { @@ -619,7 +650,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ when(mantissaForced){ recodedResult(0,23 bits) := (default -> mantissaForcedValue) whenDouble(input.format){ - recodedResult(52-23, 52-23 bits) := (default -> exponentForcedValue) + recodedResult(23, 52-23 bits) := (default -> mantissaForcedValue) }{} } when(exponentForced){ @@ -764,10 +795,6 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } val norm = new Area{ -// val needShift = math.mulC.msb -// val exp = math.exp + U(needShift) -// val man = needShift ? math.mulC(p.internalMantissaSize + 1, p.internalMantissaSize bits) | math.mulC(p.internalMantissaSize, p.internalMantissaSize bits) - val (mulHigh, mulLow) = math.mulC.splitAt(p.internalMantissaSize-1) val scrap = mulLow =/= 0 val needShift = mulHigh.msb @@ -775,7 +802,9 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val man = needShift ? mulHigh(1, p.internalMantissaSize+1 bits) | mulHigh(0, p.internalMantissaSize+1 bits) scrap setWhen(needShift && mulHigh(0)) val forceZero = input.rs1.isZero || input.rs2.isZero - val forceUnderflow = exp < exponentOne + exponentOne - 127 - 24 // 0x6A //TODO + val underflowThreshold = muxDouble[UInt](input.format)(exponentOne + exponentOne - 1023 - 53) (exponentOne + exponentOne - 127 - 24) + val underflowExp = muxDouble[UInt](input.format)(exponentOne - 1023 - 54) (exponentOne - 127 - 25) + val forceUnderflow = exp < underflowThreshold val forceOverflow = input.rs1.isInfinity || input.rs2.isInfinity val infinitynan = ((input.rs1.isInfinity || input.rs2.isInfinity) && (input.rs1.isZero || input.rs2.isZero)) val forceNan = input.rs1.isNan || input.rs2.isNan || infinitynan @@ -797,7 +826,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } elsewhen(forceZero) { output.setZero } elsewhen(forceUnderflow) { - output.exponent := exponentOne - 127 - 25 + output.exponent := underflowExp.resized } } @@ -1123,11 +1152,14 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val round = new Area{ val input = merge.commited.combStage - //TODO do not break NAN payload (seems already fine) val manAggregate = input.value.mantissa @@ input.scrap - val expDif = (exponentOne-126) -^ input.value.exponent + val expBase = muxDouble[UInt](input.format)(exponentF64Subnormal+1)(exponentF32Subnormal+1) + val expDif = expBase -^ input.value.exponent val expSubnormal = !expDif.msb - val discardCount = expSubnormal ? expDif.resize(log2Up(p.internalMantissaSize) bits) | U(0) + var discardCount = (expSubnormal ? expDif.resize(log2Up(p.internalMantissaSize) bits) | U(0)) + if(p.withDouble) when(input.format === FpuFormat.FLOAT){ + discardCount \= discardCount + 29 + } val exactMask = (List(True) ++ (0 until p.internalMantissaSize+1).map(_ < discardCount)).asBits.asUInt val roundAdjusted = (True ## (manAggregate>>1))(discardCount) ## ((manAggregate & exactMask) =/= 0) @@ -1156,10 +1188,16 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ // uf := True // } - when(!math.special && math.exponent <= exponentOne-127 && roundAdjusted.asUInt =/= 0){ //Do not catch exact 1.17549435E-38 underflow, but, who realy care ? + + + val ufSubnormalThreshold = muxDouble[UInt](input.format)(exponentF64Subnormal)(exponentF32Subnormal) + val ufThreshold = muxDouble[UInt](input.format)(exponentF64Subnormal-52+1)(exponentF32Subnormal-23+1) + val ofThreshold = muxDouble[UInt](input.format)(exponentF64Infinity-1)(exponentF32Infinity-1) + + when(!math.special && math.exponent <= ufSubnormalThreshold && roundAdjusted.asUInt =/= 0){ //Do not catch exact 1.17549435E-38 underflow, but, who realy care ? uf := True } - when(!math.special && math.exponent >= exponentOne + 128){ + when(!math.special && math.exponent > ofThreshold){ nx := True of := True val doMax = input.roundMode.mux( @@ -1170,7 +1208,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ FpuRoundMode.RMM -> (False) ) when(doMax){ - patched.exponent := exponentOne + 127 + patched.exponent := ofThreshold patched.mantissa.setAll() } otherwise { patched.setInfinity @@ -1178,7 +1216,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } - when(!math.special && math.exponent <= exponentOne - 127-23){ + when(!math.special && math.exponent < ufThreshold){ nx := True uf := True val doMin = input.roundMode.mux( @@ -1189,7 +1227,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ FpuRoundMode.RMM -> (False) ) when(doMin){ - patched.exponent := exponentOne - 127-23+1 + patched.exponent := ufThreshold.resized patched.mantissa := 0 } otherwise { patched.setZero diff --git a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala index 6d5b4954..79ea6b85 100644 --- a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala +++ b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala @@ -23,7 +23,17 @@ import scala.util.Random class FpuTest extends FunSuite{ val b2f = lang.Float.intBitsToFloat(_) + val b2d = lang.Double.longBitsToDouble(_) val f2b = lang.Float.floatToRawIntBits(_) + val d2bOffset = BigInt("10000000000000000",16) + def d2b(that : Double) = { + val l = lang.Double.doubleToRawLongBits(that) + var a = BigInt(l) + if(l < 0) { + a = d2bOffset + a + } + a + } test("f32f64") { @@ -64,24 +74,6 @@ class FpuTest extends FunSuite{ def f32_f32_f32 ={ val s = new Scanner(next) val a,b,c = (s.nextLong(16).toInt) -// if(b2f(a).isNaN || b2f(b).isNaN){ -// print("NAN => ") -// if(((a >> 23) & 0xFF) == 0xFF && ((a >> 0) & 0xEFFFFF) != 0){ -// print(a.toHexString) -// print(" " + f2b(b2f(a)).toHexString) -// } -// if(((b >> 23) & 0xFF) == 0xFF && ((b >> 0) & 0xEFFFFF) != 0){ -// print(b.toHexString) -// print(" " + f2b(b2f(b)).toHexString) -// } -// if(((c >> 23) & 0xFF) == 0xFF && ((c >> 0) & 0xEFFFFF) != 0){ -// print(" " + c.toHexString) -// print(" " + f2b(b2f(c)).toHexString) -// } -// -// print(" " + simTime()) -// println("") -// } (b2f(a), b2f(b), b2f(c), s.nextInt(16)) } @@ -105,8 +97,39 @@ class FpuTest extends FunSuite{ val s = new Scanner(next) val a,b = (s.nextLong(16).toInt) (b2f(a), b2f(b), s.nextInt(16)) - } + } + + def nextLong(s : Scanner) : Long = java.lang.Long.parseUnsignedLong( s.next(),16) + + def f64_f64_f64 ={ + val s = new Scanner(next) + val a,b,c = nextLong(s) + (b2d(a), b2d(b), b2d(c), s.nextInt(16)) + } + + def i32_f64 ={ + val s = new Scanner(next) + (s.nextLong(16).toInt, b2d(nextLong(s)), s.nextInt(16)) + } + + def f64_i32 = { + val s = new Scanner(next) + (b2d(nextLong(s)), s.nextLong(16).toInt, s.nextInt(16)) + } + + def f64_f64_i32 = { + val str = next + val s = new Scanner(str) + val a,b,c = (nextLong(s)) + (b2d(a), b2d(b), c, s.nextInt(16)) + } + + def f64_f64 = { + val s = new Scanner(next) + val a,b = (s.nextLong(16)) + (b2d(a), b2d(b), s.nextInt(16)) + } } lazy val RAW = build("") lazy val RNE = build("-rnear_even") @@ -125,28 +148,33 @@ class FpuTest extends FunSuite{ } } - val f32 = new { - val add = new TestCase("f32_add") - val sub = new TestCase("f32_sub") - val mul = new TestCase("f32_mul") - val ui2f = new TestCase("ui32_to_f32") - val i2f = new TestCase("i32_to_f32") - val f2ui = new TestCase("f32_to_ui32 -exact") - val f2i = new TestCase("f32_to_i32 -exact") - val eq = new TestCase("f32_eq") - val lt = new TestCase("f32_lt") - val le = new TestCase("f32_le") - val min = new TestCase("f32_le") - val max = new TestCase("f32_lt") - val transfer = new TestCase("f32_eq") - val fclass = new TestCase("f32_eq") - val sgnj = new TestCase("f32_eq") - val sgnjn = new TestCase("f32_eq") - val sgnjx = new TestCase("f32_eq") - val sqrt = new TestCase("f32_sqrt") - val div = new TestCase("f32_div") + class TestVector(f : String) { + val add = new TestCase(s"${f}_add") + val sub = new TestCase(s"${f}_sub") + val mul = new TestCase(s"${f}_mul") + val ui2f = new TestCase(s"ui32_to_${f}") + val i2f = new TestCase(s"i32_to_${f}") + val f2ui = new TestCase(s"${f}_to_ui32 -exact") + val f2i = new TestCase(s"${f}_to_i32 -exact") + val eq = new TestCase(s"${f}_eq") + val lt = new TestCase(s"${f}_lt") + val le = new TestCase(s"${f}_le") + val min = new TestCase(s"${f}_le") + val max = new TestCase(s"${f}_lt") + val transfer = new TestCase(s"${f}_eq") + val fclass = new TestCase(s"${f}_eq") + val sgnj = new TestCase(s"${f}_eq") + val sgnjn = new TestCase(s"${f}_eq") + val sgnjx = new TestCase(s"${f}_eq") + val sqrt = new TestCase(s"${f}_sqrt") + val div = new TestCase(s"${f}_div") + val f32 = new TestCase(s"${f}_eq") + val f64 = new TestCase(s"${f}_eq") } + val f32 = new TestVector("f32") + val f64 = new TestVector("f64") + val cpus = for(id <- 0 until portCount) yield new { val cmdQueue = mutable.Queue[FpuCmd => Unit]() val commitQueue = mutable.Queue[FpuCommit => Unit]() @@ -165,9 +193,15 @@ class FpuTest extends FunSuite{ val patch = if(value.abs == 1.17549435E-38f) ref & ~2 else ref flagMatch(patch, report) } + + def flagMatch(ref : Int, value : Double, report : String): Unit ={ + val patch = if(value.abs == b2d(1 << 52)) ref & ~2 else ref + flagMatch(patch, report) + } + def flagMatch(ref : Int, report : String): Unit ={ waitUntil(pendingMiaou == 0) - assert(flagAccumulator == ref, s"Flag missmatch dut=$flagAccumulator ref=$ref $report") + softAssert(flagAccumulator == ref, s"Flag missmatch dut=$flagAccumulator ref=$ref $report") flagAccumulator = 0 } def flagClear(): Unit ={ @@ -231,6 +265,10 @@ class FpuTest extends FunSuite{ loadRaw(rd, f2b(value).toLong & 0xFFFFFFFFl, FpuFormat.FLOAT) } + def load(rd : Int, value : Double): Unit ={ + loadRaw(rd, d2b(value), FpuFormat.DOUBLE) + } + def storeRaw(rs : Int, format : FpuFormat.E)(body : FpuRsp => Unit): Unit ={ cmdAdd {cmd => cmd.opcode #= cmd.opcode.spinalEnum.STORE @@ -250,8 +288,11 @@ class FpuTest extends FunSuite{ def storeFloat(rs : Int)(body : Float => Unit): Unit ={ storeRaw(rs, FpuFormat.FLOAT){rsp => body(b2f(rsp.value.toBigInt.toInt))} } + def store(rs : Int)(body : Double => Unit): Unit ={ + storeRaw(rs, FpuFormat.DOUBLE){rsp => body(b2d(rsp.value.toBigInt.toLong))} + } - def fpuF2f(rd : Int, rs1 : Int, rs2 : Int, rs3 : Int, opcode : FpuOpcode.E, arg : Int, rounding : FpuRoundMode.E = FpuRoundMode.RNE): Unit ={ + def fpuF2f(rd : Int, rs1 : Int, rs2 : Int, rs3 : Int, opcode : FpuOpcode.E, arg : Int, rounding : FpuRoundMode.E, format : FpuFormat.E): Unit ={ cmdAdd {cmd => cmd.opcode #= opcode cmd.rs1 #= rs1 @@ -260,6 +301,7 @@ class FpuTest extends FunSuite{ cmd.rd #= rd cmd.arg #= arg cmd.roundMode #= rounding + cmd.format #= format } commitQueue += {cmd => cmd.write #= true @@ -267,7 +309,7 @@ class FpuTest extends FunSuite{ } } - def fpuF2i(rs1 : Int, rs2 : Int, opcode : FpuOpcode.E, arg : Int, rounding : FpuRoundMode.E = FpuRoundMode.RNE)(body : FpuRsp => Unit): Unit ={ + def fpuF2i(rs1 : Int, rs2 : Int, opcode : FpuOpcode.E, arg : Int, rounding : FpuRoundMode.E, format : FpuFormat.E)(body : FpuRsp => Unit): Unit ={ cmdAdd {cmd => cmd.opcode #= opcode cmd.rs1 #= rs1 @@ -276,58 +318,59 @@ class FpuTest extends FunSuite{ cmd.rd.randomize() cmd.arg #= arg cmd.roundMode #= rounding + cmd.format #= format } rspQueue += body } - def mul(rd : Int, rs1 : Int, rs2 : Int, rounding : FpuRoundMode.E = FpuRoundMode.RNE): Unit ={ - fpuF2f(rd, rs1, rs2, Random.nextInt(32), FpuOpcode.MUL, 0, rounding) + def mul(rd : Int, rs1 : Int, rs2 : Int, rounding : FpuRoundMode.E, format : FpuFormat.E): Unit ={ + fpuF2f(rd, rs1, rs2, Random.nextInt(32), FpuOpcode.MUL, 0, rounding, format) } - def add(rd : Int, rs1 : Int, rs2 : Int, rounding : FpuRoundMode.E = FpuRoundMode.RNE): Unit ={ - fpuF2f(rd, rs1, rs2, Random.nextInt(32), FpuOpcode.ADD, 0, rounding) + def add(rd : Int, rs1 : Int, rs2 : Int, rounding : FpuRoundMode.E = FpuRoundMode.RNE, format : FpuFormat.E): Unit ={ + fpuF2f(rd, rs1, rs2, Random.nextInt(32), FpuOpcode.ADD, 0, rounding, format) } - def sub(rd : Int, rs1 : Int, rs2 : Int, rounding : FpuRoundMode.E = FpuRoundMode.RNE): Unit ={ - fpuF2f(rd, rs1, rs2, Random.nextInt(32), FpuOpcode.ADD, 1, rounding) + def sub(rd : Int, rs1 : Int, rs2 : Int, rounding : FpuRoundMode.E = FpuRoundMode.RNE, format : FpuFormat.E): Unit ={ + fpuF2f(rd, rs1, rs2, Random.nextInt(32), FpuOpcode.ADD, 1, rounding, format) } - def div(rd : Int, rs1 : Int, rs2 : Int, rounding : FpuRoundMode.E = FpuRoundMode.RNE): Unit ={ - fpuF2f(rd, rs1, rs2, Random.nextInt(32), FpuOpcode.DIV, Random.nextInt(4), rounding) + def div(rd : Int, rs1 : Int, rs2 : Int, rounding : FpuRoundMode.E = FpuRoundMode.RNE, format : FpuFormat.E): Unit ={ + fpuF2f(rd, rs1, rs2, Random.nextInt(32), FpuOpcode.DIV, Random.nextInt(4), rounding, format) } - def sqrt(rd : Int, rs1 : Int, rounding : FpuRoundMode.E = FpuRoundMode.RNE): Unit ={ - fpuF2f(rd, rs1, Random.nextInt(32), Random.nextInt(32), FpuOpcode.SQRT, Random.nextInt(4), rounding) + def sqrt(rd : Int, rs1 : Int, rounding : FpuRoundMode.E = FpuRoundMode.RNE, format : FpuFormat.E): Unit ={ + fpuF2f(rd, rs1, Random.nextInt(32), Random.nextInt(32), FpuOpcode.SQRT, Random.nextInt(4), rounding, format) } - def fma(rd : Int, rs1 : Int, rs2 : Int, rs3 : Int, rounding : FpuRoundMode.E = FpuRoundMode.RNE): Unit ={ - fpuF2f(rd, rs1, rs2, rs3, FpuOpcode.FMA, 0, rounding) + def fma(rd : Int, rs1 : Int, rs2 : Int, rs3 : Int, rounding : FpuRoundMode.E, format : FpuFormat.E): Unit ={ + fpuF2f(rd, rs1, rs2, rs3, FpuOpcode.FMA, 0, rounding, format) } - def sgnjRaw(rd : Int, rs1 : Int, rs2 : Int, arg : Int): Unit ={ - fpuF2f(rd, rs1, rs2, Random.nextInt(32), FpuOpcode.SGNJ, arg, FpuRoundMode.elements.randomPick()) + def sgnjRaw(rd : Int, rs1 : Int, rs2 : Int, arg : Int, format : FpuFormat.E): Unit ={ + fpuF2f(rd, rs1, rs2, Random.nextInt(32), FpuOpcode.SGNJ, arg, FpuRoundMode.elements.randomPick(), format) } - def sgnj(rd : Int, rs1 : Int, rs2 : Int, rounding : FpuRoundMode.E = null): Unit ={ - sgnjRaw(rd, rs1, rs2, 0) + def sgnj(rd : Int, rs1 : Int, rs2 : Int, rounding : FpuRoundMode.E = null, format : FpuFormat.E): Unit ={ + sgnjRaw(rd, rs1, rs2, 0, format) } - def sgnjn(rd : Int, rs1 : Int, rs2 : Int, rounding : FpuRoundMode.E = null): Unit ={ - sgnjRaw(rd, rs1, rs2, 1) + def sgnjn(rd : Int, rs1 : Int, rs2 : Int, rounding : FpuRoundMode.E = null, format : FpuFormat.E): Unit ={ + sgnjRaw(rd, rs1, rs2, 1, format) } - def sgnjx(rd : Int, rs1 : Int, rs2 : Int, rounding : FpuRoundMode.E = null): Unit ={ - sgnjRaw(rd, rs1, rs2, 2) + def sgnjx(rd : Int, rs1 : Int, rs2 : Int, rounding : FpuRoundMode.E = null, format : FpuFormat.E): Unit ={ + sgnjRaw(rd, rs1, rs2, 2, format) } - def cmp(rs1 : Int, rs2 : Int, arg : Int = 1)(body : FpuRsp => Unit): Unit ={ - fpuF2i(rs1, rs2, FpuOpcode.CMP, arg, FpuRoundMode.elements.randomPick())(body) + def cmp(rs1 : Int, rs2 : Int, arg : Int, format : FpuFormat.E)(body : FpuRsp => Unit): Unit ={ + fpuF2i(rs1, rs2, FpuOpcode.CMP, arg, FpuRoundMode.elements.randomPick(), format)(body) } - def f2i(rs1 : Int, signed : Boolean, rounding : FpuRoundMode.E = FpuRoundMode.RNE)(body : FpuRsp => Unit): Unit ={ - fpuF2i(rs1, Random.nextInt(32), FpuOpcode.F2I, if(signed) 1 else 0, rounding)(body) + def f2i(rs1 : Int, signed : Boolean, rounding : FpuRoundMode.E, format : FpuFormat.E)(body : FpuRsp => Unit): Unit ={ + fpuF2i(rs1, Random.nextInt(32), FpuOpcode.F2I, if(signed) 1 else 0, rounding, format)(body) } - def i2f(rd : Int, value : Int, signed : Boolean, rounding : FpuRoundMode.E): Unit ={ + def i2f(rd : Int, value : Int, signed : Boolean, rounding : FpuRoundMode.E, format : FpuFormat.E): Unit ={ cmdAdd {cmd => cmd.opcode #= cmd.opcode.spinalEnum.I2F cmd.rs1.randomize() @@ -336,6 +379,7 @@ class FpuTest extends FunSuite{ cmd.rd #= rd cmd.arg #= (if(signed) 1 else 0) cmd.roundMode #= rounding + cmd.format #= format } commitQueue += {cmd => cmd.write #= true @@ -451,13 +495,13 @@ class FpuTest extends FunSuite{ } - def testBinaryOp(op : (Int,Int,Int,FpuRoundMode.E) => Unit, a : Float, b : Float, ref : Float, flag : Int, rounding : FpuRoundMode.E, opName : String): Unit ={ + def testBinaryOp(op : (Int,Int,Int,FpuRoundMode.E, FpuFormat.E) => Unit, a : Float, b : Float, ref : Float, flag : Int, rounding : FpuRoundMode.E, opName : String): Unit ={ val rs = new RegAllocator() val rs1, rs2, rs3 = rs.allocate() val rd = Random.nextInt(32) load(rs1, a) load(rs2, b) - op(rd,rs1,rs2, rounding) + op(rd,rs1,rs2, rounding, FpuFormat.FLOAT) storeFloat(rd){v => assert(f2b(v) == f2b(ref), f"## ${a} ${opName} $b = $v, $ref $rounding") } @@ -466,12 +510,25 @@ class FpuTest extends FunSuite{ } + def testBinaryOpF64(op : (Int,Int,Int,FpuRoundMode.E, FpuFormat.E) => Unit, a : Double, b : Double, ref : Double, flag : Int, rounding : FpuRoundMode.E, opName : String): Unit ={ + val rs = new RegAllocator() + val rs1, rs2, rs3 = rs.allocate() + val rd = Random.nextInt(32) + load(rs1, a) + load(rs2, b) + op(rd,rs1,rs2, rounding, FpuFormat.DOUBLE) + store(rd){v => + assert(d2b(v) == d2b(ref), f"## ${a} ${opName} $b = $v, $ref $rounding") + } - def testTransferRaw(a : Float, iSrc : Boolean, iDst : Boolean): Unit ={ + flagMatch(flag, ref, f"## ${opName} ${a} $b $ref $rounding") + } + + + def testTransferF32Raw(a : Float, iSrc : Boolean, iDst : Boolean): Unit ={ val rd = Random.nextInt(32) def handle(v : Float): Unit ={ - val refUnclamped = a val ref = a assert(f2b(v) == f2b(ref), f"$a = $v, $ref") } @@ -482,6 +539,49 @@ class FpuTest extends FunSuite{ flagMatch(0, f"$a") } + + def testTransferF64Raw(a : Double): Unit ={ + val rd = Random.nextInt(32) + + def handle(v : Double): Unit ={ + val ref = a + assert(d2b(v) == d2b(ref), f"$a = $v, $ref") + } + + load(rd, a) + store(rd)(handle) + + flagMatch(0, f"$a") + } + + def testTransferF32F64Raw(a : Float, iSrc : Boolean): Unit ={ + val rd = Random.nextInt(32) + if(iSrc) fmv_w_x(rd, f2b(a)) else load(rd, a) + storeRaw(rd, FpuFormat.DOUBLE){rsp => + val v = rsp.value.toBigInt.toLong + val ref = (0xFFFFFFFFl << 32) | f2b(a) + assert(v == ref, f"$a = $v, $ref") + } + flagMatch(0, f"$a") + } + + def testTransferF64F32Raw(a : Double, iDst : Boolean): Unit ={ + val rd = Random.nextInt(32) + load(rd, a) + if(iDst)fmv_x_w(rd){v_ => + val v = f2b(v_).toLong & 0xFFFFFFFFl + val ref = d2b(a) & 0xFFFFFFFFl + assert(v == ref, f"$a = $v, $ref") + } + else storeRaw(rd, FpuFormat.FLOAT){rsp => + val v = rsp.value.toBigInt.toLong & 0xFFFFFFFFl + val ref = d2b(a) & 0xFFFFFFFFl + assert(v == ref, f"$a = $v, $ref") + } + flagMatch(0, f"$a") + } + + def testClassRaw(a : Float) : Unit = { val rd = Random.nextInt(32) @@ -513,7 +613,7 @@ class FpuTest extends FunSuite{ load(rs2, b) load(rs3, c) - fma(rd,rs1,rs2,rs3) + fma(rd,rs1,rs2,rs3, FpuRoundMode.RNE, FpuFormat.FLOAT) storeFloat(rd){v => val ref = a.toDouble * b.toDouble + c.toDouble println(f"$a%.20f * $b%.20f + $c%.20f = $v%.20f, $ref%.20f") @@ -530,7 +630,7 @@ class FpuTest extends FunSuite{ load(rs1, a) load(rs2, b) - div(rd,rs1,rs2) + div(rd,rs1,rs2, FpuRoundMode.RNE, FpuFormat.FLOAT) storeFloat(rd){v => val refUnclamped = a/b val refClamped = ((a)/(b)) @@ -547,7 +647,7 @@ class FpuTest extends FunSuite{ val rd = Random.nextInt(32) load(rs1, a) - sqrt(rd,rs1) + sqrt(rd,rs1, FpuRoundMode.RNE, FpuFormat.FLOAT) storeFloat(rd){v => val ref = Math.sqrt(a).toFloat val error = Math.abs(ref-v)/ref @@ -564,7 +664,7 @@ class FpuTest extends FunSuite{ val rd = Random.nextInt(32) load(rs1, a) - sqrt(rd,rs1) + sqrt(rd,rs1, FpuRoundMode.RNE, FpuFormat.FLOAT) storeFloat(rd){v => val error = Math.abs(ref-v)/ref println(f"sqrt($a) = $v, $ref $error $rounding") @@ -579,7 +679,7 @@ class FpuTest extends FunSuite{ load(rs1, a) load(rs2, b) - div(rd,rs1, rs2) + div(rd,rs1, rs2, FpuRoundMode.RNE, FpuFormat.FLOAT) storeFloat(rd){v => val error = Math.abs(ref-v)/ref println(f"div($a, $b) = $v, $ref $error $rounding") @@ -594,16 +694,16 @@ class FpuTest extends FunSuite{ val rs1 = rs.allocate() val rd = Random.nextInt(32) load(rs1, a) - f2i(rs1, signed, rounding){rsp => + f2i(rs1, signed, rounding, FpuFormat.FLOAT){rsp => if(signed) { - val v = rsp.value.toLong.toInt + val v = rsp.value.toBigInt.toInt var ref2 = ref if(a >= Int.MaxValue) ref2 = Int.MaxValue if(a <= Int.MinValue) ref2 = Int.MinValue if(a.isNaN) ref2 = Int.MaxValue assert(v == (ref2), f" <= f2i($a) = $v, $ref2, $rounding, $flag") } else { - val v = rsp.value.toLong + val v = rsp.value.toBigInt.toLong & 0xFFFFFFFFl var ref2 = ref.toLong & 0xFFFFFFFFl if(a < 0) ref2 = 0 if(a >= 0xFFFFFFFFl) ref2 = 0xFFFFFFFFl @@ -621,15 +721,15 @@ class FpuTest extends FunSuite{ def testI2fExact(a : Int, b : Float, f : Int, signed : Boolean, rounding : FpuRoundMode.E): Unit ={ val rs = new RegAllocator() val rd = Random.nextInt(32) - i2f(rd, a, signed, rounding) + i2f(rd, a, signed, rounding, FpuFormat.FLOAT) storeFloat(rd){v => val aLong = if(signed) a.toLong else a.toLong & 0xFFFFFFFFl val ref = b - assert(f2b(v) == f2b(ref), f"i2f($aLong) = $v, $ref") + assert(f2b(v) == f2b(ref), f"i2f($aLong) = $v, $ref $rounding") } - flagMatch(f, b, f"i2f() = $b") + flagMatch(f, b, f"i2f($a) = $b") } @@ -640,7 +740,7 @@ class FpuTest extends FunSuite{ val rd = Random.nextInt(32) load(rs1, a) load(rs2, b) - cmp(rs1, rs2, arg){rsp => + cmp(rs1, rs2, arg, FpuFormat.FLOAT){rsp => val v = rsp.value.toLong assert(v === ref, f"cmp($a, $b, $arg) = $v, $ref") } @@ -744,29 +844,6 @@ class FpuTest extends FunSuite{ } } - - -// for(i <- 0 until 64){ -// val rounding = FpuRoundMode.RMM -// val a = 24f -// val b = b2f(0x3f800000+i) -// val c = Clib.math.mulF32(a, b, rounding.position) -// val f = 0 -// testMulExact(a,b,c,f, rounding) -// } - - val binaryOps = List[(Int,Int,Int,FpuRoundMode.E) => Unit](add, sub, mul) - -// testSqrt(0.0f) - // testSqrt(1.2f) - // for(a <- fAll) testSqrt(a) -// for(_ <- 0 until 1000) testSqrt(randomFloat()) - - - - - - def testFma() : Unit = { testFmaRaw(randomFloat(), randomFloat(), randomFloat()) flagClear() @@ -786,13 +863,13 @@ class FpuTest extends FunSuite{ testEqRaw(a,b,i, f) } - def testF2ui() : Unit = { + def testF2uiF32() : Unit = { val rounding = FpuRoundMode.elements.randomPick() val (a,b,f) = f32.f2ui(rounding).f32_i32 testF2iExact(a,b, f, false, rounding) } - def testF2i() : Unit = { + def testF2iF32() : Unit = { val rounding = FpuRoundMode.elements.randomPick() val (a,b,f) = f32.f2i(rounding).f32_i32 testF2iExact(a,b, f, true, rounding) @@ -823,11 +900,26 @@ class FpuTest extends FunSuite{ testSgnjxRaw(a, b) } - def testTransfer() : Unit = { + def testTransferF32() : Unit = { val (a,b,r,f) = f32.transfer.RAW.f32_f32_i32 - testTransferRaw(a, Random.nextBoolean(), Random.nextBoolean()) + testTransferF32Raw(a, Random.nextBoolean(), Random.nextBoolean()) } + def testTransferF64() : Unit = { + val (a,b,r,f) = f64.transfer.RAW.f64_f64_i32 + testTransferF64Raw(a) + } + + def testTransferF64F32() : Unit = { + val (a,b,r,f) = f64.f32.RAW.f64_f64_i32 + testTransferF64F32Raw(a, Random.nextBoolean()) + } + def testTransferF32F64() : Unit = { + val (a,b,r,f) = f32.f64.RAW.f32_f32_i32 + testTransferF32F64Raw(a, Random.nextBoolean()) + } + + def testClass() : Unit = { val (a,b,r,f) = f32.fclass.RAW.f32_f32_i32 testClassRaw(a) @@ -854,59 +946,112 @@ class FpuTest extends FunSuite{ testI2fExact(a,b,f, false, rounding) } - def testMul() : Unit = { + def testMulF32() : Unit = { val rounding = FpuRoundMode.elements.randomPick() val (a,b,c,f) = f32.mul(rounding).f32_f32_f32 testBinaryOp(mul,a,b,c,f, rounding,"mul") } - def testAdd() : Unit = { + def testAddF32() : Unit = { val rounding = FpuRoundMode.elements.randomPick() val (a,b,c,f) = f32.add(rounding).f32_f32_f32 testBinaryOp(add,a,b,c,f, rounding,"add") } - def testSub() : Unit = { + def testSubF32() : Unit = { val rounding = FpuRoundMode.elements.randomPick() val (a,b,c,f) = f32.sub(rounding).f32_f32_f32 testBinaryOp(sub,a,b,c,f, rounding,"sub") } + def testMulF64() : Unit = { + val rounding = FpuRoundMode.elements.randomPick() + val (a,b,c,f) = f64.mul(rounding).f64_f64_f64 + testBinaryOpF64(mul,a,b,c,f, rounding,"mul") + } - val f32Tests = List[() => Unit](testSub, testAdd, testMul, testI2f, testUI2f, testMin, testMax, testSgnj, testTransfer, testDiv, testSqrt, testF2i, testF2ui, testLe, testEq, testLt, testClass, testFma) + + val f32Tests = List[() => Unit](testSubF32, testAddF32, testMulF32, testI2f, testUI2f, testMin, testMax, testSgnj, testTransferF32, testDiv, testSqrt, testF2iF32, testF2uiF32, testLe, testEq, testLt, testClass, testFma) + + //TODO test boxing + if(p.withDouble) { +// for(_ <- 0 until 10000) testUI2f64() +// for(_ <- 0 until 10000) testI2f64() +// println("f64 i2f done") +// +// for(_ <- 0 until 10000) testF2uiF64() +// for(_ <- 0 until 10000) testF2iF64() +// println("f64 f2i done") + +// testF2iExact(1.0f,1, 0, false, FpuRoundMode.RTZ) +// testF2iExact(2.0f,2, 0, false, FpuRoundMode.RTZ) +// testF2iExact(2.5f,2, 1, false, FpuRoundMode.RTZ) + testBinaryOpF64(mul,1.0, 1.0, 1.0,0 , FpuRoundMode.RNE,"mul") + testBinaryOpF64(mul,1.0, 2.0, 2.0,0 , FpuRoundMode.RNE,"mul") + testBinaryOpF64(mul,2.5, 2.0, 5.0,0 , FpuRoundMode.RNE,"mul") - testTransferRaw(1.0f, false, false) - testTransferRaw(2.0f, false, false) - testTransferRaw(2.5f, false, false) - testTransferRaw(6.97949770801e-39f, false, false) - testTransferRaw(8.72437213501e-40f, false, false) - testTransferRaw(5.6E-45f, false, false) + for(_ <- 0 until 10000) testMulF64() + println("f64 Mul done") + testTransferF64Raw(1.0) + testTransferF64Raw(2.0) + testTransferF64Raw(2.5) + testTransferF64Raw(6.97949770801e-39) + testTransferF64Raw(8.72437213501e-40) + testTransferF64Raw(5.6E-45) + testTransferF32F64Raw(b2f(0xFFFF1234), false) + testTransferF64F32Raw(b2d(0xFFF123498765463l << 4), false) + testTransferF32F64Raw(b2f(0xFFFF1234), true) + testTransferF64F32Raw(b2d(0xFFF123498765463l << 4), true) + for (_ <- 0 until 10000) testTransferF64() + println("f64 load/store/rf transfer done") + for (_ <- 0 until 10000) testTransferF64F32() + println("f64 -> f32 load/store/rf transfer done") - for(_ <- 0 until 10000) testTransfer() + for (_ <- 0 until 10000) testTransferF32F64() + println("f32 -> f64 load/store/rf transfer done") + + } + + for(_ <- 0 until 10000) testTransferF32() println("f32 load/store/rf transfer done") - for(_ <- 0 until 10000) testF2ui() - for(_ <- 0 until 10000) testF2i() - println("f2i done") + for(_ <- 0 until 10000) testMulF32() + println("Mul done") + for(_ <- 0 until 10000) testUI2f() for(_ <- 0 until 10000) testI2f() println("i2f done") + testF2iExact(1.0f,1, 0, false, FpuRoundMode.RTZ) + testF2iExact(2.0f,2, 0, false, FpuRoundMode.RTZ) + testF2iExact(2.5f,2, 1, false, FpuRoundMode.RTZ) + + + + + + for(_ <- 0 until 10000) testF2uiF32() + for(_ <- 0 until 10000) testF2iF32() + println("f2i done") + + + // waitUntil(cmdQueue.isEmpty) // dut.clockDomain.waitSampling(1000) // simSuccess() + for(i <- 0 until 1000) testFma() flagClear() println("fma done") //TODO @@ -959,14 +1104,11 @@ class FpuTest extends FunSuite{ - for(_ <- 0 until 10000) testMul() - - println("Mul done") - for(_ <- 0 until 10000) testAdd() - for(_ <- 0 until 10000) testSub() + for(_ <- 0 until 10000) testAddF32() + for(_ <- 0 until 10000) testSubF32() println("Add done") From 82dfd10dba4a8eec142a298c6c68f16a1c265b18 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 11 Feb 2021 16:42:17 +0100 Subject: [PATCH 581/951] fpu fix f32 tests for f64 fpu --- src/test/scala/vexriscv/ip/fpu/FpuTest.scala | 133 ++++++++++++++++--- 1 file changed, 111 insertions(+), 22 deletions(-) diff --git a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala index 79ea6b85..8290d390 100644 --- a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala +++ b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala @@ -59,7 +59,7 @@ class FpuTest extends FunSuite{ val config = SimConfig config.allOptimisation - if(p.withDouble) config.withFstWave +// if(p.withDouble) config.withFstWave config.compile(new FpuCore(portCount, p){ for(i <- 0 until portCount) out(Bits(5 bits)).setName(s"flagAcc$i") := io.port(i).completion.flag.asBits setDefinitionName("FpuCore"+ (if(p.withDouble) "Double" else "")) @@ -420,7 +420,7 @@ class FpuTest extends FunSuite{ } } - def minMax(rd : Int, rs1 : Int, rs2 : Int, arg : Int = 0): Unit ={ + def minMax(rd : Int, rs1 : Int, rs2 : Int, arg : Int, format : FpuFormat.E): Unit ={ cmdAdd {cmd => cmd.opcode #= cmd.opcode.spinalEnum.MIN_MAX cmd.rs1 #= rs1 @@ -428,6 +428,8 @@ class FpuTest extends FunSuite{ cmd.rs3.randomize() cmd.rd #= rd cmd.arg #= arg + cmd.roundMode.randomize() + cmd.format #= format } commitQueue += {cmd => cmd.write #= true @@ -437,7 +439,7 @@ class FpuTest extends FunSuite{ - def fclass(rs1 : Int)(body : Int => Unit) : Unit = { + def fclass(rs1 : Int, format : FpuFormat.E)(body : Int => Unit) : Unit = { cmdAdd {cmd => cmd.opcode #= FpuOpcode.FCLASS cmd.rs1 #= rs1 @@ -445,8 +447,10 @@ class FpuTest extends FunSuite{ cmd.rs3.randomize() cmd.rd.randomize() cmd.arg.randomize() + cmd.roundMode.randomize() + cmd.format #= format } - rspQueue += {rsp => body(rsp.value.toLong.toInt)} + rspQueue += {rsp => body(rsp.value.toBigInt.toInt)} } } @@ -587,7 +591,7 @@ class FpuTest extends FunSuite{ load(rd, a) - fclass(rd){v => + fclass(rd, FpuFormat.FLOAT){v => val mantissa = f2b(a) & 0x7FFFFF val exp = (f2b(a) >> 23) & 0xFF val sign = (f2b(a) >> 31) & 0x1 @@ -717,23 +721,63 @@ class FpuTest extends FunSuite{ + def testF642iExact(a : Double, ref : Int, flag : Int, signed : Boolean, rounding : FpuRoundMode.E): Unit ={ + val rs = new RegAllocator() + val rs1 = rs.allocate() + val rd = Random.nextInt(32) + load(rs1, a) + f2i(rs1, signed, rounding, FpuFormat.DOUBLE){rsp => + if(signed) { + val v = rsp.value.toBigInt.toInt + var ref2 = ref + if(a >= Int.MaxValue) ref2 = Int.MaxValue + if(a <= Int.MinValue) ref2 = Int.MinValue + if(a.isNaN) ref2 = Int.MaxValue + assert(v == (ref2), f" <= f2i($a) = $v, $ref2, $rounding, $flag") + } else { + val v = rsp.value.toBigInt.toLong & 0xFFFFFFFFl + var ref2 = ref.toLong & 0xFFFFFFFFl + if(a < 0) ref2 = 0 + if(a >= 0xFFFFFFFFl) ref2 = 0xFFFFFFFFl + if(a.isNaN) ref2 = 0xFFFFFFFFl + assert(v == ref2, f" <= f2ui($a) = $v, $ref2, $rounding $flag") + } + } - def testI2fExact(a : Int, b : Float, f : Int, signed : Boolean, rounding : FpuRoundMode.E): Unit ={ + flagMatch(flag, ref, f" f2${if(signed) "" else "u"}i($a) $ref $flag $rounding") + } + + + + def testI2fExact(a : Int, ref : Float, f : Int, signed : Boolean, rounding : FpuRoundMode.E): Unit ={ val rs = new RegAllocator() val rd = Random.nextInt(32) i2f(rd, a, signed, rounding, FpuFormat.FLOAT) storeFloat(rd){v => val aLong = if(signed) a.toLong else a.toLong & 0xFFFFFFFFl - val ref = b assert(f2b(v) == f2b(ref), f"i2f($aLong) = $v, $ref $rounding") } - flagMatch(f, b, f"i2f($a) = $b") + flagMatch(f, ref, f"i2f($a) = $ref") } + def testI2f64Exact(a : Int, ref : Double, f : Int, signed : Boolean, rounding : FpuRoundMode.E): Unit ={ + val rs = new RegAllocator() + val rd = Random.nextInt(32) + i2f(rd, a, signed, rounding, FpuFormat.DOUBLE) + store(rd){v => + val aLong = if(signed) a.toLong else a.toLong & 0xFFFFFFFFl + assert(d2b(v) == d2b(ref), f"i2f($aLong) = $v, $ref $rounding") + } + + + flagMatch(f, ref, f"i2f($a) = $ref") + } + + def testCmpExact(a : Float, b : Float, ref : Int, flag : Int, arg : Int): Unit ={ val rs = new RegAllocator() val rs1, rs2, rs3 = rs.allocate() @@ -741,7 +785,7 @@ class FpuTest extends FunSuite{ load(rs1, a) load(rs2, b) cmp(rs1, rs2, arg, FpuFormat.FLOAT){rsp => - val v = rsp.value.toLong + val v = rsp.value.toBigInt.toInt assert(v === ref, f"cmp($a, $b, $arg) = $v, $ref") } flagMatch(flag,f"$a < $b $ref $flag ${f2b(a).toHexString} ${f2b(b).toHexString}") @@ -795,7 +839,7 @@ class FpuTest extends FunSuite{ load(rs1, a) load(rs2, b) - minMax(rd,rs1,rs2, arg) + minMax(rd,rs1,rs2, arg, FpuFormat.FLOAT) storeFloat(rd){v => assert(f2b(ref) == f2b(v), f"minMax($a $b $arg) = $v, $ref") } @@ -875,6 +919,18 @@ class FpuTest extends FunSuite{ testF2iExact(a,b, f, true, rounding) } + def testF2uiF64() : Unit = { + val rounding = FpuRoundMode.elements.randomPick() + val (a,b,f) = f64.f2ui(rounding).f64_i32 + testF642iExact(a,b, f, false, rounding) + } + + def testF2iF64() : Unit = { + val rounding = FpuRoundMode.elements.randomPick() + val (a,b,f) = f64.f2i(rounding).f64_i32 + testF642iExact(a,b, f, true, rounding) + } + def testDiv() : Unit = { val rounding = FpuRoundMode.elements.randomPick() @@ -934,18 +990,30 @@ class FpuTest extends FunSuite{ testMaxExact(a,b) } - def testUI2f() : Unit = { + def testUI2f32() : Unit = { val rounding = FpuRoundMode.elements.randomPick() val (a,b,f) = f32.i2f(rounding).i32_f32 testI2fExact(a,b,f, true, rounding) } - def testI2f() : Unit = { + def testI2f32() : Unit = { val rounding = FpuRoundMode.elements.randomPick() val (a,b,f) = f32.ui2f(rounding).i32_f32 testI2fExact(a,b,f, false, rounding) } + def testUI2f64() : Unit = { + val rounding = FpuRoundMode.elements.randomPick() + val (a,b,f) = f64.i2f(rounding).i32_f64 + testI2f64Exact(a,b,f, true, rounding) + } + + def testI2f64() : Unit = { + val rounding = FpuRoundMode.elements.randomPick() + val (a,b,f) = f64.ui2f(rounding).i32_f64 + testI2f64Exact(a,b,f, false, rounding) + } + def testMulF32() : Unit = { val rounding = FpuRoundMode.elements.randomPick() val (a,b,c,f) = f32.mul(rounding).f32_f32_f32 @@ -964,24 +1032,45 @@ class FpuTest extends FunSuite{ testBinaryOp(sub,a,b,c,f, rounding,"sub") } + def testMulF64() : Unit = { val rounding = FpuRoundMode.elements.randomPick() val (a,b,c,f) = f64.mul(rounding).f64_f64_f64 testBinaryOpF64(mul,a,b,c,f, rounding,"mul") } + def testAddF64() : Unit = { + val rounding = FpuRoundMode.elements.randomPick() + val (a,b,c,f) = f64.add(rounding).f64_f64_f64 + testBinaryOpF64(add,a,b,c,f, rounding,"add") + } - val f32Tests = List[() => Unit](testSubF32, testAddF32, testMulF32, testI2f, testUI2f, testMin, testMax, testSgnj, testTransferF32, testDiv, testSqrt, testF2iF32, testF2uiF32, testLe, testEq, testLt, testClass, testFma) + def testSubF64() : Unit = { + val rounding = FpuRoundMode.elements.randomPick() + val (a,b,c,f) = f64.sub(rounding).f64_f64_f64 + testBinaryOpF64(sub,a,b,c,f, rounding,"sub") + } + + + val f32Tests = List[() => Unit](testSubF32, testAddF32, testMulF32, testI2f32, testUI2f32, testMin, testMax, testSgnj, testTransferF32, testDiv, testSqrt, testF2iF32, testF2uiF32, testLe, testEq, testLt, testClass, testFma) //TODO test boxing + //TODO double <-> simple convertions if(p.withDouble) { -// for(_ <- 0 until 10000) testUI2f64() -// for(_ <- 0 until 10000) testI2f64() -// println("f64 i2f done") -// -// for(_ <- 0 until 10000) testF2uiF64() -// for(_ <- 0 until 10000) testF2iF64() -// println("f64 f2i done") + + for(_ <- 0 until 10000) testAddF64() + for(_ <- 0 until 10000) testSubF64() + println("Add done") + + + // testI2f64Exact(0x7FFFFFF5, 0x7FFFFFF5, 0, true, FpuRoundMode.RNE) + for(_ <- 0 until 10000) testUI2f64() + for(_ <- 0 until 10000) testI2f64() + println("f64 i2f done") + + for(_ <- 0 until 10000) testF2uiF64() + for(_ <- 0 until 10000) testF2iF64() + println("f64 f2i done") // testF2iExact(1.0f,1, 0, false, FpuRoundMode.RTZ) // testF2iExact(2.0f,2, 0, false, FpuRoundMode.RTZ) @@ -1027,8 +1116,8 @@ class FpuTest extends FunSuite{ println("Mul done") - for(_ <- 0 until 10000) testUI2f() - for(_ <- 0 until 10000) testI2f() + for(_ <- 0 until 10000) testUI2f32() + for(_ <- 0 until 10000) testI2f32() println("i2f done") From 9a25a12879712a8fc9ee67e6ec129e89369b4a2c Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 11 Feb 2021 17:40:35 +0100 Subject: [PATCH 582/951] fpu add FCVT_X_X --- src/main/scala/vexriscv/ip/fpu/FpuCore.scala | 42 ++++--- .../scala/vexriscv/ip/fpu/Interface.scala | 2 +- .../scala/vexriscv/plugin/FpuPlugin.scala | 2 + src/test/scala/vexriscv/ip/fpu/FpuTest.scala | 107 ++++++++++-------- 4 files changed, 92 insertions(+), 61 deletions(-) diff --git a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala index edb6dba8..f5350b02 100644 --- a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala +++ b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala @@ -223,6 +223,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ is(p.Opcode.FMV_X_W) { useRs1 := True } is(p.Opcode.FMV_W_X) { useRd := True } is(p.Opcode.FCLASS ) { useRs1 := True } + is(p.Opcode.FCVT_X_X ) { useRd := True; useRs1 := True } } val hits = List((useRs1, s0.rs1), (useRs2, s0.rs2), (useRs3, s0.rs3), (useRd, s0.rd)).map{case (use, reg) => use && rf.lock.map(l => l.valid && l.source === s0.source && l.address === reg).orR} @@ -289,7 +290,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ load.payload.assignSomeByName(read.output.payload) load.i2f := input.opcode === FpuOpcode.I2F - val shortPipHit = List(FpuOpcode.STORE, FpuOpcode.F2I, FpuOpcode.CMP, FpuOpcode.MIN_MAX, FpuOpcode.SGNJ, FpuOpcode.FMV_X_W, FpuOpcode.FCLASS).map(input.opcode === _).orR + val shortPipHit = List(FpuOpcode.STORE, FpuOpcode.F2I, FpuOpcode.CMP, FpuOpcode.MIN_MAX, FpuOpcode.SGNJ, FpuOpcode.FMV_X_W, FpuOpcode.FCLASS, FpuOpcode.FCVT_X_X).map(input.opcode === _).orR val shortPip = Stream(ShortPipInput()) input.ready setWhen(shortPipHit && shortPip.ready) shortPip.valid := input.valid && shortPipHit @@ -715,8 +716,8 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ ) - val minMaxResult = ((rs1Smaller ^ input.arg(0)) && !input.rs1.isNan || input.rs2.isNan) ? input.rs1 | input.rs2 - when(input.rs1.isNan && input.rs2.isNan) { minMaxResult.setNanQuiet } + val minMaxSelectRs2 = !(((rs1Smaller ^ input.arg(0)) && !input.rs1.isNan || input.rs2.isNan)) + val minMaxSelectNanQuiet = input.rs1.isNan && input.rs2.isNan val cmpResult = B(rs1Smaller && !bothZero && !input.arg(1) || (rs1Equal || bothZero) && !input.arg(0)) when(input.rs1.isNan || input.rs2.isNan) { cmpResult := 0 } val sgnjResult = (input.rs1.sign && input.arg(1)) ^ input.rs2.sign ^ input.arg(0) @@ -742,7 +743,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ is(FpuOpcode.FCLASS) { result(31 downto 0) := fclassResult.resized } } - val toFpuRf = List(FpuOpcode.MIN_MAX, FpuOpcode.SGNJ).map(input.opcode === _).orR + val toFpuRf = List(FpuOpcode.MIN_MAX, FpuOpcode.SGNJ, FpuOpcode.FCVT_X_X).map(input.opcode === _).orR rfOutput.valid := input.valid && toFpuRf && !halt rfOutput.source := input.source @@ -751,19 +752,31 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ rfOutput.roundMode := input.roundMode if(p.withDouble) rfOutput.format := input.format rfOutput.scrap := False - rfOutput.value.assignDontCare() + rfOutput.value.sign := input.rs1.sign + rfOutput.value.exponent := input.rs1.exponent + rfOutput.value.mantissa := input.rs1.mantissa @@ U"0" + rfOutput.value.special := input.rs1.special + switch(input.opcode){ is(FpuOpcode.MIN_MAX){ - rfOutput.value.sign := minMaxResult.sign - rfOutput.value.exponent := minMaxResult.exponent - rfOutput.value.mantissa := minMaxResult.mantissa @@ U"0" - rfOutput.value.special := minMaxResult.special + when(minMaxSelectRs2) { + rfOutput.value.sign := input.rs2.sign + rfOutput.value.exponent := input.rs2.exponent + rfOutput.value.mantissa := input.rs2.mantissa @@ U"0" + rfOutput.value.special := input.rs2.special + } + when(minMaxSelectNanQuiet){ + rfOutput.value.setNanQuiet + } } is(FpuOpcode.SGNJ){ - rfOutput.value.sign := sgnjResult - rfOutput.value.exponent := input.rs1.exponent - rfOutput.value.mantissa := input.rs1.mantissa @@ U"0" - rfOutput.value.special := input.rs1.special + rfOutput.value.sign := sgnjResult + } + if(p.withDouble) is(FpuOpcode.FCVT_X_X){ + rfOutput.format := ((input.format === FpuFormat.FLOAT) ? FpuFormat.DOUBLE | FpuFormat.FLOAT) + when(input.rs1.isNan){ + rfOutput.value.setNanQuiet + } } } @@ -772,7 +785,8 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val rs2Nan = input.rs2.isNan val rs1NanNv = input.rs1.isNan && (!input.rs1.isQuiet || signalQuiet) val rs2NanNv = input.rs2.isNan && (!input.rs2.isQuiet || signalQuiet) - val nv = (input.opcode === FpuOpcode.CMP || input.opcode === FpuOpcode.MIN_MAX) && (rs1NanNv || rs2NanNv) + val nv = List(FpuOpcode.CMP, FpuOpcode.MIN_MAX, FpuOpcode.FCVT_X_X).map(input.opcode === _).orR && rs1NanNv || + List(FpuOpcode.CMP, FpuOpcode.MIN_MAX).map(input.opcode === _).orR && rs2NanNv flag.NV setWhen(input.valid && nv) input.ready := !halt && (toFpuRf ? rfOutput.ready | io.port.map(_.rsp.ready).read(input.source)) diff --git a/src/main/scala/vexriscv/ip/fpu/Interface.scala b/src/main/scala/vexriscv/ip/fpu/Interface.scala index 0f4b17f9..604dd10e 100644 --- a/src/main/scala/vexriscv/ip/fpu/Interface.scala +++ b/src/main/scala/vexriscv/ip/fpu/Interface.scala @@ -85,7 +85,7 @@ case class FpuFloat(exponentSize: Int, } object FpuOpcode extends SpinalEnum{ - val LOAD, STORE, MUL, ADD, FMA, I2F, F2I, CMP, DIV, SQRT, MIN_MAX, SGNJ, FMV_X_W, FMV_W_X, FCLASS = newElement() + val LOAD, STORE, MUL, ADD, FMA, I2F, F2I, CMP, DIV, SQRT, MIN_MAX, SGNJ, FMV_X_W, FMV_W_X, FCLASS, FCVT_X_X = newElement() } object FpuFormat extends SpinalEnum{ diff --git a/src/main/scala/vexriscv/plugin/FpuPlugin.scala b/src/main/scala/vexriscv/plugin/FpuPlugin.scala index 49bd49a4..468f14b6 100644 --- a/src/main/scala/vexriscv/plugin/FpuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/FpuPlugin.scala @@ -102,6 +102,8 @@ class FpuPlugin(externalFpu : Boolean = false, FMV_W_X -> (fmvWx) )) + //TODO FMV_X_X + doubles + port = FpuPort(p) if(externalFpu) master(port) diff --git a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala index 8290d390..2e882656 100644 --- a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala +++ b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala @@ -130,6 +130,18 @@ class FpuTest extends FunSuite{ val a,b = (s.nextLong(16)) (b2d(a), b2d(b), s.nextInt(16)) } + + + def f32_f64_i32 = { + val s = new Scanner(next) + val a,b = nextLong(s) + (b2f(a.toInt), b2d(b), s.nextInt(16)) + } + def f64_f32_i32 = { + val s = new Scanner(next) + val a,b = nextLong(s) + (b2d(a), b2f(b.toInt), s.nextInt(16)) + } } lazy val RAW = build("") lazy val RNE = build("-rnear_even") @@ -168,12 +180,16 @@ class FpuTest extends FunSuite{ val sgnjx = new TestCase(s"${f}_eq") val sqrt = new TestCase(s"${f}_sqrt") val div = new TestCase(s"${f}_div") - val f32 = new TestCase(s"${f}_eq") - val f64 = new TestCase(s"${f}_eq") } - val f32 = new TestVector("f32") - val f64 = new TestVector("f64") + val f32 = new TestVector("f32"){ + val f64 = new TestCase(s"f32_eq") + val cvt64 = new TestCase(s"f32_to_f64") + } + val f64 = new TestVector("f64"){ + val f32 = new TestCase(s"f64_eq") + val cvt32 = new TestCase(s"f64_to_f32") + } val cpus = for(id <- 0 until portCount) yield new { val cmdQueue = mutable.Queue[FpuCmd => Unit]() @@ -201,7 +217,7 @@ class FpuTest extends FunSuite{ def flagMatch(ref : Int, report : String): Unit ={ waitUntil(pendingMiaou == 0) - softAssert(flagAccumulator == ref, s"Flag missmatch dut=$flagAccumulator ref=$ref $report") + assert(flagAccumulator == ref, s"Flag missmatch dut=$flagAccumulator ref=$ref $report") flagAccumulator = 0 } def flagClear(): Unit ={ @@ -586,6 +602,27 @@ class FpuTest extends FunSuite{ } + def testCvtF32F64Raw(a : Float, ref : Double, flag : Int, rounding : FpuRoundMode.E): Unit ={ + val rs, rd = Random.nextInt(32) + load(rs, a) + fpuF2f(rd, rs, Random.nextInt(32), Random.nextInt(32), FpuOpcode.FCVT_X_X, Random.nextInt(3), rounding, FpuFormat.FLOAT) + store(rd){v => + assert(d2b(v) == d2b(ref), f"testCvtF32F64Raw $a $ref $rounding") + } + flagMatch(flag, f"testCvtF32F64Raw $a $ref $rounding") + } + + def testCvtF64F32Raw(a : Double, ref : Float, flag : Int, rounding : FpuRoundMode.E): Unit ={ + val rs, rd = Random.nextInt(32) + load(rs, a) + fpuF2f(rd, rs, Random.nextInt(32), Random.nextInt(32), FpuOpcode.FCVT_X_X, Random.nextInt(3), rounding, FpuFormat.DOUBLE) + storeFloat(rd){v => + assert(d2b(v) == d2b(ref), f"testCvtF64F32Raw $a $ref $rounding") + } + flagMatch(flag, f"testCvtF64F32Raw $a $ref $rounding") + } + + def testClassRaw(a : Float) : Unit = { val rd = Random.nextInt(32) @@ -620,48 +657,12 @@ class FpuTest extends FunSuite{ fma(rd,rs1,rs2,rs3, FpuRoundMode.RNE, FpuFormat.FLOAT) storeFloat(rd){v => val ref = a.toDouble * b.toDouble + c.toDouble - println(f"$a%.20f * $b%.20f + $c%.20f = $v%.20f, $ref%.20f") val mul = a.toDouble * b.toDouble - if((mul.abs-c.abs)/mul.abs > 0.1) assert(checkFloat(ref.toFloat, v)) + if((mul.abs-c.abs)/mul.abs > 0.1) assert(checkFloat(ref.toFloat, v), f"$a%.20f * $b%.20f + $c%.20f = $v%.20f, $ref%.20f") } } - def testDivRaw(a : Float, b : Float): Unit ={ - val rs = new RegAllocator() - val rs1, rs2, rs3 = rs.allocate() - val rd = Random.nextInt(32) - load(rs1, a) - load(rs2, b) - - div(rd,rs1,rs2, FpuRoundMode.RNE, FpuFormat.FLOAT) - storeFloat(rd){v => - val refUnclamped = a/b - val refClamped = ((a)/(b)) - val ref = refClamped - val error = Math.abs(ref-v)/ref - println(f"$a / $b = $v, $ref $error") - assert(checkFloat(ref, v)) - } - } - - def testSqrtRaw(a : Float): Unit ={ - val rs = new RegAllocator() - val rs1, rs2, rs3 = rs.allocate() - val rd = Random.nextInt(32) - load(rs1, a) - - sqrt(rd,rs1, FpuRoundMode.RNE, FpuFormat.FLOAT) - storeFloat(rd){v => - val ref = Math.sqrt(a).toFloat - val error = Math.abs(ref-v)/ref - println(f"sqrt($a) = $v, $ref $error") - assert(checkFloat(ref, v)) - } - } - - - def testSqrtExact(a : Float, ref : Float, flag : Int, rounding : FpuRoundMode.E): Unit ={ val rs = new RegAllocator() val rs1, rs2, rs3 = rs.allocate() @@ -671,8 +672,7 @@ class FpuTest extends FunSuite{ sqrt(rd,rs1, FpuRoundMode.RNE, FpuFormat.FLOAT) storeFloat(rd){v => val error = Math.abs(ref-v)/ref - println(f"sqrt($a) = $v, $ref $error $rounding") - assert(checkFloat(ref, v)) + assert(checkFloat(ref, v), f"sqrt($a) = $v, $ref $error $rounding") } } @@ -686,8 +686,7 @@ class FpuTest extends FunSuite{ div(rd,rs1, rs2, FpuRoundMode.RNE, FpuFormat.FLOAT) storeFloat(rd){v => val error = Math.abs(ref-v)/ref - println(f"div($a, $b) = $v, $ref $error $rounding") - assert(checkFloat(ref, v)) + assert(checkFloat(ref, v), f"div($a, $b) = $v, $ref $error $rounding") } } @@ -975,6 +974,16 @@ class FpuTest extends FunSuite{ testTransferF32F64Raw(a, Random.nextBoolean()) } + def testCvtF32F64() : Unit = { + val rounding = FpuRoundMode.elements.randomPick() + val (a,r,f) = f32.cvt64(rounding).f32_f64_i32 + testCvtF32F64Raw(a, r, f, rounding) + } + def testCvtF64F32() : Unit = { + val rounding = FpuRoundMode.elements.randomPick() + val (a,r,f) = f64.cvt32(rounding).f64_f32_i32 + testCvtF64F32Raw(a, r, f, rounding) + } def testClass() : Unit = { val (a,b,r,f) = f32.fclass.RAW.f32_f32_i32 @@ -1057,6 +1066,12 @@ class FpuTest extends FunSuite{ //TODO test boxing //TODO double <-> simple convertions if(p.withDouble) { + for(_ <- 0 until 10000) testCvtF32F64() + println("FCVT_S_D done") + for(_ <- 0 until 10000) testCvtF64F32() + println("FCVT_D_S done") + + for(_ <- 0 until 10000) testAddF64() for(_ <- 0 until 10000) testSubF64() From 7d3b35c32c64ef0ebd527e06e3fd7d738700f437 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 12 Feb 2021 14:48:44 +0100 Subject: [PATCH 583/951] fpu f64/f32 pass all tests --- src/main/scala/vexriscv/ip/fpu/FpuCore.scala | 64 +++- .../scala/vexriscv/plugin/FpuPlugin.scala | 90 +++-- src/test/scala/vexriscv/ip/fpu/FpuTest.scala | 316 ++++++++++++++++-- 3 files changed, 396 insertions(+), 74 deletions(-) diff --git a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala index f5350b02..c674bfe1 100644 --- a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala +++ b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala @@ -56,6 +56,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val arg = p.Arg() val roundMode = FpuRoundMode() val format = p.withDouble generate FpuFormat() + val rs1Boxed, rs2Boxed = p.withDouble generate Bool() } @@ -79,6 +80,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val arg = Bits(2 bits) val roundMode = FpuRoundMode() val format = p.withDouble generate FpuFormat() + val rs1Boxed, rs2Boxed = p.withDouble generate Bool() } case class MulInput() extends Bundle{ @@ -198,7 +200,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ //TODO nan boxing decoding val read = new Area{ - val arbiter = StreamArbiterFactory.noLock.lowerFirst.build(FpuCmd(p), portCount) + val arbiter = StreamArbiterFactory.noLock.roundRobin.build(FpuCmd(p), portCount) arbiter.io.inputs <> Vec(io.port.map(_.cmd)) val s0 = Stream(RfReadInput()) @@ -208,7 +210,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val useRs1, useRs2, useRs3, useRd = False switch(s0.opcode){ - is(p.Opcode.LOAD) { useRd := True } + is(p.Opcode.LOAD) { useRd := True } is(p.Opcode.STORE) { useRs1 := True } is(p.Opcode.ADD) { useRd := True; useRs1 := True; useRs2 := True } is(p.Opcode.MUL) { useRd := True; useRs1 := True; useRs2 := True } @@ -261,20 +263,25 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ output.rs2 := rs2Entry.value output.rs3 := rs3Entry.value if(p.withDouble){ + output.rs1Boxed := rs1Entry.boxed + output.rs2Boxed := rs2Entry.boxed output.format := s1.format val store = s1.opcode === FpuOpcode.STORE ||s1.opcode === FpuOpcode.FMV_X_W - when(store){ //Pass through - output.format := rs1Entry.boxed ? FpuFormat.FLOAT | FpuFormat.DOUBLE - } elsewhen(s1.format === FpuFormat.FLOAT =/= rs1Entry.boxed){ - output.rs1.setNanQuiet - output.rs1.sign := False - } - when(s1.format === FpuFormat.FLOAT =/= rs2Entry.boxed){ - output.rs2.setNanQuiet - output.rs2.sign := False - } - when(s1.format === FpuFormat.FLOAT =/= rs3Entry.boxed){ - output.rs3.setNanQuiet + val sgnjBypass = s1.opcode === FpuOpcode.SGNJ && s1.format === FpuFormat.DOUBLE + when(!sgnjBypass) { + when(store) { //Pass through + output.format := rs1Entry.boxed ? FpuFormat.FLOAT | FpuFormat.DOUBLE + } elsewhen (s1.format === FpuFormat.FLOAT =/= rs1Entry.boxed) { + output.rs1.setNanQuiet + output.rs1.sign := False + } + when(s1.format === FpuFormat.FLOAT =/= rs2Entry.boxed) { + output.rs2.setNanQuiet + output.rs2.sign := False + } + when(s1.format === FpuFormat.FLOAT =/= rs3Entry.boxed) { + output.rs3.setNanQuiet + } } } } @@ -686,8 +693,11 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ ) val result = (Mux(resign, ~unsigned, unsigned) + (resign ^ increment).asUInt) val overflow = (input.rs1.exponent > (input.arg(0) ? U(exponentOne+30) | U(exponentOne+31)) || input.rs1.isInfinity) && !input.rs1.sign || input.rs1.isNan - val underflow = (input.rs1.exponent > U(exponentOne+31) || input.arg(0) && unsigned.msb && unsigned(30 downto 0) =/= 0 || !input.arg(0) && (unsigned =/= 0 || increment) || input.rs1.isInfinity) && input.rs1.sign + val underflow = (input.rs1.exponent > U(exponentOne+31) || input.arg(0) && unsigned.msb && (unsigned(30 downto 0) =/= 0 || increment) || !input.arg(0) && (unsigned =/= 0 || increment) || input.rs1.isInfinity) && input.rs1.sign val isZero = input.rs1.isZero + if(p.withDouble){ + overflow setWhen(!input.rs1.sign && increment && unsigned(30 downto 0).andR && (input.arg(0) || unsigned(31))) + } when(isZero){ result := 0 } elsewhen(underflow || overflow) { @@ -720,7 +730,13 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val minMaxSelectNanQuiet = input.rs1.isNan && input.rs2.isNan val cmpResult = B(rs1Smaller && !bothZero && !input.arg(1) || (rs1Equal || bothZero) && !input.arg(0)) when(input.rs1.isNan || input.rs2.isNan) { cmpResult := 0 } - val sgnjResult = (input.rs1.sign && input.arg(1)) ^ input.rs2.sign ^ input.arg(0) + val sgnjRs1Sign = CombInit(input.rs1.sign) + val sgnjRs2Sign = CombInit(input.rs2.sign) + if(p.withDouble){ + sgnjRs1Sign setWhen(input.rs1Boxed && input.format === FpuFormat.DOUBLE) + sgnjRs2Sign setWhen(input.rs2Boxed && input.format === FpuFormat.DOUBLE) + } + val sgnjResult = (sgnjRs1Sign && input.arg(1)) ^ sgnjRs2Sign ^ input.arg(0) val fclassResult = B(0, 32 bits) val decoded = input.rs1.decode() fclassResult(0) := input.rs1.sign && decoded.isInfinity @@ -771,6 +787,22 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } is(FpuOpcode.SGNJ){ rfOutput.value.sign := sgnjResult + if(p.withDouble) when(input.format === FpuFormat.DOUBLE){ + when(input.rs1Boxed){ + rfOutput.value.sign := input.rs1.sign + rfOutput.format := FpuFormat.FLOAT + } +// //kill boxing => F32 -> F64 NAN +// when(input.rs1Boxed && !sgnjResult){ +// rfOutput.value.setNan +// rfOutput.value.mantissa.setAll() +// rfOutput.value.mantissa(31 downto 0) := input.rs1.sign ## input.rs1.exponent +// } +// //Spawn boxing => F64 NAN -> F32 +// when(!input.rs1Boxed && input.rs1.exponent === exponentOne + 1024 && input.rs1.mantissa(32, 52-32 bits).andR && sgnjResult){ +// +// } + } } if(p.withDouble) is(FpuOpcode.FCVT_X_X){ rfOutput.format := ((input.format === FpuFormat.FLOAT) ? FpuFormat.DOUBLE | FpuFormat.FLOAT) diff --git a/src/main/scala/vexriscv/plugin/FpuPlugin.scala b/src/main/scala/vexriscv/plugin/FpuPlugin.scala index 468f14b6..855c3970 100644 --- a/src/main/scala/vexriscv/plugin/FpuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/FpuPlugin.scala @@ -17,6 +17,7 @@ class FpuPlugin(externalFpu : Boolean = false, object FPU_FORKED extends Stageable(Bool()) object FPU_OPCODE extends Stageable(FpuOpcode()) object FPU_ARG extends Stageable(Bits(2 bits)) + object FPU_FORMAT extends Stageable(FpuFormat()) var port : FpuPort = null @@ -49,6 +50,7 @@ class FpuPlugin(externalFpu : Boolean = false, val fminMax = floatRfWrite :+ FPU_OPCODE -> FpuOpcode.MIN_MAX val fmvWx = floatRfWrite :+ FPU_OPCODE -> FpuOpcode.FMV_W_X :+ RS1_USE -> True val fcvtI2f = floatRfWrite :+ FPU_OPCODE -> FpuOpcode.I2F :+ RS1_USE -> True + val fcvtxx = floatRfWrite :+ FPU_OPCODE -> FpuOpcode.FCVT_X_X val fcmp = intRfWrite :+ FPU_OPCODE -> FpuOpcode.CMP val fclass = intRfWrite :+ FPU_OPCODE -> FpuOpcode.FCLASS @@ -73,35 +75,69 @@ class FpuPlugin(externalFpu : Boolean = false, def arg(v : Int) = FPU_ARG -> U(v, 2 bits) val decoderService = pipeline.service(classOf[DecoderService]) decoderService.addDefault(FPU_ENABLE, False) + + val f32 = FPU_FORMAT -> FpuFormat.FLOAT + val f64 = FPU_FORMAT -> FpuFormat.DOUBLE + decoderService.add(List( - FADD_S -> (addSub :+ arg(0)), - FSUB_S -> (addSub :+ arg(1)), - FMADD_S -> (fma :+ arg(0)), - FMSUB_S -> (fma :+ arg(2)), - FNMADD_S -> (fma :+ arg(3)), - FNMSUB_S -> (fma :+ arg(1)), - FMUL_S -> (mul :+ arg(0)), - FDIV_S -> (div), - FSQRT_S -> (sqrt), - FLW -> (fl), - FSW -> (fs), - FCVT_S_WU -> (fcvtI2f :+ arg(0)), - FCVT_S_W -> (fcvtI2f :+ arg(1)), - FCVT_WU_S -> (fcvtF2i :+ arg(0)), - FCVT_W_S -> (fcvtF2i :+ arg(1)), - FCLASS_S -> (fclass), - FLE_S -> (fcmp :+ arg(0)), - FEQ_S -> (fcmp :+ arg(2)), - FLT_S -> (fcmp :+ arg(1)), - FSGNJ_S -> (fsgnj :+ arg(0)), - FSGNJN_S -> (fsgnj :+ arg(1)), - FSGNJX_S -> (fsgnj :+ arg(2)), - FMIN_S -> (fminMax :+ arg(0)), - FMAX_S -> (fminMax :+ arg(1)), - FMV_X_W -> (fmvXw), - FMV_W_X -> (fmvWx) + FADD_S -> (addSub :+ f32 :+ arg(0)), + FSUB_S -> (addSub :+ f32 :+ arg(1)), + FMADD_S -> (fma :+ f32 :+ arg(0)), + FMSUB_S -> (fma :+ f32 :+ arg(2)), + FNMADD_S -> (fma :+ f32 :+ arg(3)), + FNMSUB_S -> (fma :+ f32 :+ arg(1)), + FMUL_S -> (mul :+ f32 :+ arg(0)), + FDIV_S -> (div :+ f32 ), + FSQRT_S -> (sqrt :+ f32 ), + FLW -> (fl :+ f32 ), + FSW -> (fs :+ f32 ), + FCVT_S_WU -> (fcvtI2f :+ f32 :+ arg(0)), + FCVT_S_W -> (fcvtI2f :+ f32 :+ arg(1)), + FCVT_WU_S -> (fcvtF2i :+ f32 :+ arg(0)), + FCVT_W_S -> (fcvtF2i :+ f32 :+ arg(1)), + FCLASS_S -> (fclass :+ f32 ), + FLE_S -> (fcmp :+ f32 :+ arg(0)), + FEQ_S -> (fcmp :+ f32 :+ arg(2)), + FLT_S -> (fcmp :+ f32 :+ arg(1)), + FSGNJ_S -> (fsgnj :+ f32 :+ arg(0)), + FSGNJN_S -> (fsgnj :+ f32 :+ arg(1)), + FSGNJX_S -> (fsgnj :+ f32 :+ arg(2)), + FMIN_S -> (fminMax :+ f32 :+ arg(0)), + FMAX_S -> (fminMax :+ f32 :+ arg(1)), + FMV_X_W -> (fmvXw :+ f32 ), + FMV_W_X -> (fmvWx :+ f32 ) )) + if(p.withDouble){ + decoderService.add(List( + FADD_D -> (addSub :+ f64 :+ arg(0)), + FSUB_D -> (addSub :+ f64 :+ arg(1)), + FMADD_D -> (fma :+ f64 :+ arg(0)), + FMSUB_D -> (fma :+ f64 :+ arg(2)), + FNMADD_D -> (fma :+ f64 :+ arg(3)), + FNMSUB_D -> (fma :+ f64 :+ arg(1)), + FMUL_D -> (mul :+ f64 :+ arg(0)), + FDIV_D -> (div :+ f64 ), + FSQRT_D -> (sqrt :+ f64 ), + FLW -> (fl :+ f64 ), + FSW -> (fs :+ f64 ), + FCVT_S_WU -> (fcvtI2f :+ f64 :+ arg(0)), + FCVT_S_W -> (fcvtI2f :+ f64 :+ arg(1)), + FCVT_WU_D -> (fcvtF2i :+ f64 :+ arg(0)), + FCVT_W_D -> (fcvtF2i :+ f64 :+ arg(1)), + FCLASS_D -> (fclass :+ f64 ), + FLE_D -> (fcmp :+ f64 :+ arg(0)), + FEQ_D -> (fcmp :+ f64 :+ arg(2)), + FLT_D -> (fcmp :+ f64 :+ arg(1)), + FSGNJ_D -> (fsgnj :+ f64 :+ arg(0)), + FSGNJN_D -> (fsgnj :+ f64 :+ arg(1)), + FSGNJX_D -> (fsgnj :+ f64 :+ arg(2)), + FMIN_D -> (fminMax :+ f64 :+ arg(0)), + FMAX_D -> (fminMax :+ f64 :+ arg(1)), + FCVT_D_S -> (fcvtxx :+ f32), + FCVT_S_D -> (fcvtxx :+ f64) + )) + } //TODO FMV_X_X + doubles port = FpuPort(p) @@ -178,7 +214,7 @@ class FpuPlugin(externalFpu : Boolean = false, port.cmd.rs2 := input(INSTRUCTION)(rs2Range).asUInt port.cmd.rs3 := input(INSTRUCTION)(rs3Range).asUInt port.cmd.rd := input(INSTRUCTION)(rdRange).asUInt - port.cmd.format := FpuFormat.FLOAT + port.cmd.format := (if(p.withDouble) input(FPU_FORMAT) else FpuFormat.FLOAT()) port.cmd.roundMode := roundMode.as(FpuRoundMode()) insert(FPU_FORKED) := forked || port.cmd.fire diff --git a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala index 2e882656..43265f8f 100644 --- a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala +++ b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala @@ -55,7 +55,7 @@ class FpuTest extends FunSuite{ } def testP(p : FpuParameter){ - val portCount = 1 + val portCount = 4 val config = SimConfig config.allOptimisation @@ -121,13 +121,13 @@ class FpuTest extends FunSuite{ def f64_f64_i32 = { val str = next val s = new Scanner(str) - val a,b,c = (nextLong(s)) - (b2d(a), b2d(b), c, s.nextInt(16)) + val a,b = (nextLong(s)) + (b2d(a), b2d(b), s.nextInt(16), s.nextInt(16)) } def f64_f64 = { val s = new Scanner(next) - val a,b = (s.nextLong(16)) + val a,b = nextLong(s) (b2d(a), b2d(b), s.nextInt(16)) } @@ -501,6 +501,16 @@ class FpuTest extends FunSuite{ // if(ref + Float.MinPositiveValue*2.0f === dut || dut + Float.MinPositiveValue*2.0f === ref) false } + + def checkDouble(ref : Double, dut : Double): Boolean ={ + if((d2b(ref) & Long.MinValue) != (d2b(dut) & Long.MinValue)) return false + if(ref == 0.0 && dut == 0.0 && d2b(ref) != d2b(dut)) return false + if(ref.isNaN && dut.isNaN) return true + if(ref == dut) return true + if(ref.abs * 1.0001 + Float.MinPositiveValue >= dut.abs*0.9999 && ref.abs * 0.9999 - Double.MinPositiveValue <= dut.abs*1.0001) return true + // if(ref + Float.MinPositiveValue*2.0f === dut || dut + Float.MinPositiveValue*2.0f === ref) + false + } def checkFloatExact(ref : Float, dut : Float): Boolean ={ if(ref.signum != dut.signum === dut) return false if(ref.isNaN && dut.isNaN) return true @@ -514,6 +524,11 @@ class FpuTest extends FunSuite{ (Random.nextDouble() * (Math.pow(2.0, exp)) * (if(Random.nextBoolean()) -1.0 else 1.0)).toFloat } + def randomDouble(): Double ={ + val exp = Random.nextInt(10)-5 + (Random.nextDouble() * (Math.pow(2.0, exp)) * (if(Random.nextBoolean()) -1.0 else 1.0)) + } + def testBinaryOp(op : (Int,Int,Int,FpuRoundMode.E, FpuFormat.E) => Unit, a : Float, b : Float, ref : Float, flag : Int, rounding : FpuRoundMode.E, opName : String): Unit ={ val rs = new RegAllocator() @@ -538,7 +553,7 @@ class FpuTest extends FunSuite{ load(rs2, b) op(rd,rs1,rs2, rounding, FpuFormat.DOUBLE) store(rd){v => - assert(d2b(v) == d2b(ref), f"## ${a} ${opName} $b = $v, $ref $rounding") + assert(d2b(v) == d2b(ref), f"## ${a} ${opName} $b = $v, $ref $rounding, ${d2b(a).toString(16)} ${d2b(b).toString(16)} ${d2b(ref).toString(16)}") } flagMatch(flag, ref, f"## ${opName} ${a} $b $ref $rounding") @@ -609,7 +624,7 @@ class FpuTest extends FunSuite{ store(rd){v => assert(d2b(v) == d2b(ref), f"testCvtF32F64Raw $a $ref $rounding") } - flagMatch(flag, f"testCvtF32F64Raw $a $ref $rounding") + flagMatch(flag,ref, f"testCvtF32F64Raw $a $ref $rounding") } def testCvtF64F32Raw(a : Double, ref : Float, flag : Int, rounding : FpuRoundMode.E): Unit ={ @@ -619,7 +634,7 @@ class FpuTest extends FunSuite{ storeFloat(rd){v => assert(d2b(v) == d2b(ref), f"testCvtF64F32Raw $a $ref $rounding") } - flagMatch(flag, f"testCvtF64F32Raw $a $ref $rounding") + flagMatch(flag, ref, f"testCvtF64F32Raw $a $ref $rounding") } @@ -646,6 +661,30 @@ class FpuTest extends FunSuite{ } + def testClassF64Raw(a : Double) : Unit = { + val rd = Random.nextInt(32) + + + load(rd, a) + fclass(rd, FpuFormat.DOUBLE){v => + val mantissa = d2b(a) & 0x000FFFFFFFFFFFFFl + val exp = (d2b(a) >> 52) & 0x7FF + val sign = (d2b(a) >> 63) & 0x1 + + val refBit = if(a.isInfinite) (if(sign == 0) 7 else 0) + else if(a.isNaN) (if((mantissa >> 51) != 0) 9 else 8) + else if(exp == 0 && mantissa != 0) (if(sign == 0) 5 else 2) + else if(exp == 0 && mantissa == 0) (if(sign == 0) 4 else 3) + else if(sign == 0) 6 else 1 + + val ref = 1 << refBit + + assert(v == ref, f"fclass $a") + } + } + + + def testFmaRaw(a : Float, b : Float, c : Float): Unit ={ val rs = new RegAllocator() val rs1, rs2, rs3 = rs.allocate() @@ -663,6 +702,23 @@ class FpuTest extends FunSuite{ } + + def testFmaF64Raw(a : Double, b : Double, c : Double): Unit ={ + val rs = new RegAllocator() + val rs1, rs2, rs3 = rs.allocate() + val rd = Random.nextInt(32) + load(rs1, a) + load(rs2, b) + load(rs3, c) + + fma(rd,rs1,rs2,rs3, FpuRoundMode.RNE, FpuFormat.DOUBLE) + store(rd){v => + val ref = a.toDouble * b.toDouble + c.toDouble + val mul = a.toDouble * b.toDouble + if((mul.abs-c.abs)/mul.abs > 0.1) assert(checkDouble(ref, v), f"$a%.20f * $b%.20f + $c%.20f = $v%.20f, $ref%.20f") + } + } + def testSqrtExact(a : Float, ref : Float, flag : Int, rounding : FpuRoundMode.E): Unit ={ val rs = new RegAllocator() val rs1, rs2, rs3 = rs.allocate() @@ -690,6 +746,32 @@ class FpuTest extends FunSuite{ } } + def testSqrtF64Exact(a : Double, ref : Double, flag : Int, rounding : FpuRoundMode.E): Unit ={ + val rs = new RegAllocator() + val rs1, rs2, rs3 = rs.allocate() + val rd = Random.nextInt(32) + load(rs1, a) + + sqrt(rd,rs1, FpuRoundMode.RNE, FpuFormat.DOUBLE) + store(rd){v => + val error = Math.abs(ref-v)/ref + assert(checkDouble(ref, v), f"sqrt($a) = $v, $ref $error $rounding") + } + } + + def testDivF64Exact(a : Double, b : Double, ref : Double, flag : Int, rounding : FpuRoundMode.E): Unit ={ + val rs = new RegAllocator() + val rs1, rs2, rs3 = rs.allocate() + val rd = Random.nextInt(32) + load(rs1, a) + load(rs2, b) + + div(rd,rs1, rs2, FpuRoundMode.RNE, FpuFormat.DOUBLE) + store(rd){v => + val error = Math.abs(ref-v)/ref + assert(checkDouble(ref, v), f"div($a, $b) = $v, $ref $error $rounding") + } + } def testF2iExact(a : Float, ref : Int, flag : Int, signed : Boolean, rounding : FpuRoundMode.E): Unit ={ @@ -793,6 +875,23 @@ class FpuTest extends FunSuite{ def testEqRaw(a : Float, b : Float, ref : Int, flag : Int) = testCmpExact(a,b,ref,flag, 2) def testLtRaw(a : Float, b : Float, ref : Int, flag : Int) = testCmpExact(a,b,ref,flag, 1) + + def testCmpF64Exact(a : Double, b : Double, ref : Int, flag : Int, arg : Int): Unit ={ + val rs = new RegAllocator() + val rs1, rs2, rs3 = rs.allocate() + val rd = Random.nextInt(32) + load(rs1, a) + load(rs2, b) + cmp(rs1, rs2, arg, FpuFormat.DOUBLE){rsp => + val v = rsp.value.toBigInt.toInt + assert(v === ref, f"cmp($a, $b, $arg) = $v, $ref") + } + flagMatch(flag,f"$a < $b $ref $flag ${d2b(a)} ${d2b(b)}") + } + def testLeF64Raw(a : Double, b : Double, ref : Int, flag : Int) = testCmpF64Exact(a,b,ref,flag, 0) + def testEqF64Raw(a : Double, b : Double, ref : Int, flag : Int) = testCmpF64Exact(a,b,ref,flag, 2) + def testLtF64Raw(a : Double, b : Double, ref : Int, flag : Int) = testCmpF64Exact(a,b,ref,flag, 1) + // def testFmv_x_w(a : Float): Unit ={ // val rs = new RegAllocator() // val rs1, rs2, rs3 = rs.allocate() @@ -849,6 +948,35 @@ class FpuTest extends FunSuite{ def testMaxExact(a : Float, b : Float) : Unit = testMinMaxExact(a,b,1) + def testMinMaxF64Exact(a : Double, b : Double, arg : Int): Unit ={ + val rs = new RegAllocator() + val rs1, rs2 = rs.allocate() + val rd = Random.nextInt(32) + val ref = (a,b) match { + case _ if a.isNaN && b.isNaN => b2d(0x7ff8000000000000l) + case _ if a.isNaN => b + case _ if b.isNaN => a + case _ => if(arg == 0) Math.min(a,b) else Math.max(a,b) + } + val flag = (a,b) match { + case _ if a.isNaN && ((d2b(a) >> 51 ) & 1) == 0 => 16 + case _ if b.isNaN && ((d2b(b) >> 51 ) & 1) == 0 => 16 + case _ => 0 + } + load(rs1, a) + load(rs2, b) + + minMax(rd,rs1,rs2, arg, FpuFormat.DOUBLE) + store(rd){v => + assert(d2b(ref) == d2b(v), f"minMax($a $b $arg) = $v, $ref") + } + flagMatch(flag, f"minmax($a $b $arg)") + } + + def testMinF64Exact(a : Double, b : Double) : Unit = testMinMaxF64Exact(a,b,0) + def testMaxF64Exact(a : Double, b : Double) : Unit = testMinMaxF64Exact(a,b,1) + + def testSgnjRaw(a : Float, b : Float): Unit ={ val ref = b2f((f2b(a) & ~0x80000000) | f2b(b) & 0x80000000) testBinaryOp(sgnj,a,b,ref,0, null,"sgnj") @@ -862,6 +990,23 @@ class FpuTest extends FunSuite{ testBinaryOp(sgnjx,a,b,ref,0, null,"sgnjx") } + val f64SignMask = 1l << 63 + def testSgnjF64Raw(a : Double, b : Double): Unit ={ + var ref = b2d((d2b(a).toLong & ~f64SignMask) | d2b(b).toLong & f64SignMask) + if(d2b(a).toLong >> 32 == -1) ref = a + testBinaryOpF64(sgnj,a,b,ref,0, null,"sgnj") + } + def testSgnjnF64Raw(a : Double, b : Double): Unit ={ + var ref = b2d((d2b(a).toLong & ~f64SignMask) | ((d2b(b).toLong & f64SignMask) ^ f64SignMask)) + if(d2b(a).toLong >> 32 == -1) ref = a + testBinaryOpF64(sgnjn,a,b,ref,0, null,"sgnjn") + } + def testSgnjxF64Raw(a : Double, b : Double): Unit ={ + var ref = b2d(d2b(a).toLong ^ (d2b(b).toLong & f64SignMask)) + if(d2b(a).toLong >> 32 == -1) ref = a + testBinaryOpF64(sgnjx,a,b,ref,0, null,"sgnjx") + } + def withMinus(that : Seq[Float]) = that.flatMap(f => List(f, -f)) val fZeros = withMinus(List(0.0f)) @@ -887,25 +1032,46 @@ class FpuTest extends FunSuite{ } } - def testFma() : Unit = { + def testFmaF32() : Unit = { testFmaRaw(randomFloat(), randomFloat(), randomFloat()) flagClear() } - def testLe() : Unit = { + + def testFmaF64() : Unit = { + testFmaF64Raw(randomDouble(), randomDouble(), randomDouble()) + flagClear() + } + + def testLeF32() : Unit = { val (a,b,i,f) = f32.le.RAW.f32_f32_i32 testLeRaw(a,b,i, f) } - def testLt() : Unit = { + def testLtF32() : Unit = { val (a,b,i,f) = f32.lt.RAW.f32_f32_i32 testLtRaw(a,b,i, f) } - def testEq() : Unit = { + def testEqF32() : Unit = { val (a,b,i,f) = f32.eq.RAW.f32_f32_i32 testEqRaw(a,b,i, f) } + def testLeF64() : Unit = { + val (a,b,i,f) = f64.le.RAW.f64_f64_i32 + testLeF64Raw(a,b,i, f) + } + def testLtF64() : Unit = { + val (a,b,i,f) = f64.lt.RAW.f64_f64_i32 + testLtF64Raw(a,b,i, f) + } + + def testEqF64() : Unit = { + val (a,b,i,f) = f64.eq.RAW.f64_f64_i32 + testEqF64Raw(a,b,i, f) + } + + def testF2uiF32() : Unit = { val rounding = FpuRoundMode.elements.randomPick() val (a,b,f) = f32.f2ui(rounding).f32_i32 @@ -945,7 +1111,7 @@ class FpuTest extends FunSuite{ flagClear() } - def testSgnj() : Unit = { + def testSgnjF32() : Unit = { testSgnjRaw(b2f(Random.nextInt()), b2f(Random.nextInt())) testSgnjnRaw(b2f(Random.nextInt()), b2f(Random.nextInt())) testSgnjxRaw(b2f(Random.nextInt()), b2f(Random.nextInt())) @@ -955,6 +1121,31 @@ class FpuTest extends FunSuite{ testSgnjxRaw(a, b) } + def testDivF64() : Unit = { + val rounding = FpuRoundMode.elements.randomPick() + val (a,b,r,f) = f64.div(rounding).f64_f64_f64 + testDivF64Exact(a, b, r, f, rounding) + flagClear() + } + + def testSqrtF64() : Unit = { + val rounding = FpuRoundMode.elements.randomPick() + val (a,r,f) = f64.sqrt(rounding).f64_f64 + testSqrtF64Exact(a, r, f, rounding) + flagClear() + } + + def testSgnjF64() : Unit = { + testSgnjF64Raw(b2d(Random.nextLong()), b2d(Random.nextLong())) + testSgnjnF64Raw(b2d(Random.nextLong()), b2d(Random.nextLong())) + testSgnjxF64Raw(b2d(Random.nextLong()), b2d(Random.nextLong())) + val (a,b,r,f) = f64.sgnj.RAW.f64_f64_i32 + testSgnjF64Raw(a, b) + testSgnjnF64Raw(a, b) + testSgnjxF64Raw(a, b) + } + + def testTransferF32() : Unit = { val (a,b,r,f) = f32.transfer.RAW.f32_f32_i32 testTransferF32Raw(a, Random.nextBoolean(), Random.nextBoolean()) @@ -985,20 +1176,35 @@ class FpuTest extends FunSuite{ testCvtF64F32Raw(a, r, f, rounding) } - def testClass() : Unit = { + def testClassF32() : Unit = { val (a,b,r,f) = f32.fclass.RAW.f32_f32_i32 testClassRaw(a) } - def testMin() : Unit = { + def testMinF32() : Unit = { val (a,b,r,f) = f32.min.RAW.f32_f32_f32 testMinExact(a,b) } - def testMax() : Unit = { + def testMaxF32() : Unit = { val (a,b,r,f) = f32.max.RAW.f32_f32_f32 testMaxExact(a,b) } + def testClassF64() : Unit = { + val (a,b,r,f) = f64.fclass.RAW.f64_f64_i32 + testClassF64Raw(a) + } + + def testMinF64() : Unit = { + val (a,b,r,f) = f64.min.RAW.f64_f64_f64 + testMinF64Exact(a,b) + } + def testMaxF64() : Unit = { + val (a,b,r,f) = f64.max.RAW.f64_f64_f64 + testMaxF64Exact(a,b) + } + + def testUI2f32() : Unit = { val rounding = FpuRoundMode.elements.randomPick() val (a,b,f) = f32.i2f(rounding).i32_f32 @@ -1061,21 +1267,69 @@ class FpuTest extends FunSuite{ } - val f32Tests = List[() => Unit](testSubF32, testAddF32, testMulF32, testI2f32, testUI2f32, testMin, testMax, testSgnj, testTransferF32, testDiv, testSqrt, testF2iF32, testF2uiF32, testLe, testEq, testLt, testClass, testFma) + val f32Tests = List[() => Unit](testSubF32, testAddF32, testMulF32, testI2f32, testUI2f32, testMinF32, testMaxF32, testSgnjF32, testTransferF32, testDiv, testSqrt, testF2iF32, testF2uiF32, testLeF32, testEqF32, testLtF32, testClassF32, testFmaF32) + val f64Tests = List[() => Unit](testSubF64, testAddF64, testMulF64, testI2f64, testUI2f64, testMinF64, testMaxF64, testSgnjF64, testTransferF64, testDiv, testSqrt, testF2iF64, testF2uiF64, testLeF64, testEqF64, testLtF64, testClassF64, testFmaF64, testCvtF32F64, testCvtF64F32) + var fxxTests = f32Tests + if(p.withDouble) fxxTests ++= f64Tests + + //TODO test boxing //TODO double <-> simple convertions if(p.withDouble) { + for(_ <- 0 until 10000) testCvtF64F32() // 1 did not equal 3 Flag missmatch dut=1 ref=3 testCvtF64F32Raw 1.1754942807573643E-38 1.17549435E-38 RMM + println("FCVT_D_S done") for(_ <- 0 until 10000) testCvtF32F64() println("FCVT_S_D done") - for(_ <- 0 until 10000) testCvtF64F32() - println("FCVT_D_S done") + + for(_ <- 0 until 10000) testF2iF64() + println("f64 f2i done") + for(_ <- 0 until 10000) testF2uiF64() + println("f64 f2ui done") + + + for(_ <- 0 until 10000) testSgnjF64() + println("f64 sgnj done") + + + + for(_ <- 0 until 10000) testMinF64() + for(_ <- 0 until 10000) testMaxF64() + println("f64 minMax done") + + + + for(i <- 0 until 1000) testFmaF64() + flagClear() + println("f64 fma done") //TODO + + + for(_ <- 0 until 10000) testLeF64() + for(_ <- 0 until 10000) testLtF64() + for(_ <- 0 until 10000) testEqF64() + println("f64 Cmp done") + + + for(_ <- 0 until 10000) testDivF64() + println("f64 div done") + + for(_ <- 0 until 10000) testSqrtF64() + println("f64 sqrt done") + + for(_ <- 0 until 10000) testClassF64() + println("f64 class done") +// + + + + + for(_ <- 0 until 10000) testAddF64() for(_ <- 0 until 10000) testSubF64() - println("Add done") + println("f64 Add done") // testI2f64Exact(0x7FFFFFF5, 0x7FFFFFF5, 0, true, FpuRoundMode.RNE) @@ -1083,9 +1337,7 @@ class FpuTest extends FunSuite{ for(_ <- 0 until 10000) testI2f64() println("f64 i2f done") - for(_ <- 0 until 10000) testF2uiF64() - for(_ <- 0 until 10000) testF2iF64() - println("f64 f2i done") + // testF2iExact(1.0f,1, 0, false, FpuRoundMode.RTZ) // testF2iExact(2.0f,2, 0, false, FpuRoundMode.RTZ) @@ -1156,7 +1408,7 @@ class FpuTest extends FunSuite{ - for(i <- 0 until 1000) testFma() + for(i <- 0 until 1000) testFmaF32() flagClear() println("fma done") //TODO @@ -1166,9 +1418,9 @@ class FpuTest extends FunSuite{ testEqRaw(Float.PositiveInfinity,Float.PositiveInfinity,1, 0) testEqRaw(0f, 0f,1, 0) - for(_ <- 0 until 10000) testLe() - for(_ <- 0 until 10000) testLt() - for(_ <- 0 until 10000) testEq() + for(_ <- 0 until 10000) testLeF32() + for(_ <- 0 until 10000) testLtF32() + for(_ <- 0 until 10000) testEqF32() println("Cmp done") @@ -1178,16 +1430,16 @@ class FpuTest extends FunSuite{ for(_ <- 0 until 10000) testSqrt() println("f32 sqrt done") - for(_ <- 0 until 10000) testSgnj() + for(_ <- 0 until 10000) testSgnjF32() println("f32 sgnj done") - for(_ <- 0 until 10000) testClass() + for(_ <- 0 until 10000) testClassF32() println("f32 class done") - for(_ <- 0 until 10000) testMin() - for(_ <- 0 until 10000) testMax() + for(_ <- 0 until 10000) testMinF32() + for(_ <- 0 until 10000) testMaxF32() println("minMax done") @@ -1229,11 +1481,13 @@ class FpuTest extends FunSuite{ // dut.clockDomain.waitSampling(1000) // simSuccess() - for(i <- 0 until 1000) f32Tests.randomPick()() + for(i <- 0 until 10000) fxxTests.randomPick()() waitUntil(cpu.rspQueue.isEmpty) } + + stim.foreach(_.join()) dut.clockDomain.waitSampling(100) } From 3b99090879a0da8d8e7373b2bda8ca492628d43d Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 16 Feb 2021 14:15:20 +0100 Subject: [PATCH 584/951] VexRiscvConfig.get added --- src/main/scala/vexriscv/VexRiscv.scala | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/scala/vexriscv/VexRiscv.scala b/src/main/scala/vexriscv/VexRiscv.scala index 5f7865cf..57308981 100644 --- a/src/main/scala/vexriscv/VexRiscv.scala +++ b/src/main/scala/vexriscv/VexRiscv.scala @@ -29,6 +29,11 @@ case class VexRiscvConfig(){ case None => None } } + def get[T](clazz: Class[T]): T = { + plugins.find(_.getClass == clazz) match { + case Some(x) => x.asInstanceOf[T] + } + } //Default Stageables object IS_RVC extends Stageable(Bool) From fe690528f7c3b8b2002e5d97081690d7cddbeac9 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 16 Feb 2021 14:16:57 +0100 Subject: [PATCH 585/951] MulPlugin.outputBuffer feature added --- .../scala/vexriscv/plugin/MulPlugin.scala | 46 +++++++++++++++---- .../vexriscv/TestIndividualFeatures.scala | 33 +++++++------ 2 files changed, 56 insertions(+), 23 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/MulPlugin.scala b/src/main/scala/vexriscv/plugin/MulPlugin.scala index 31714e82..c1619d2b 100644 --- a/src/main/scala/vexriscv/plugin/MulPlugin.scala +++ b/src/main/scala/vexriscv/plugin/MulPlugin.scala @@ -5,7 +5,8 @@ import spinal.core._ import spinal.lib.KeepAttribute //Input buffer generaly avoid the FPGA synthesis to duplicate reg inside the DSP cell, which could stress timings quite much. -class MulPlugin(inputBuffer : Boolean = false) extends Plugin[VexRiscv]{ +class MulPlugin(var inputBuffer : Boolean = false, + var outputBuffer : Boolean = false) extends Plugin[VexRiscv]{ object MUL_LL extends Stageable(UInt(32 bits)) object MUL_LH extends Stageable(SInt(34 bits)) object MUL_HL extends Stageable(SInt(34 bits)) @@ -53,16 +54,26 @@ class MulPlugin(inputBuffer : Boolean = false) extends Plugin[VexRiscv]{ // a := input(SRC1) // b := input(SRC2) + val delay = (if(inputBuffer) 1 else 0) + (if(outputBuffer) 1 else 0) + + val delayLogic = (delay != 0) generate new Area{ + val counter = Reg(UInt(log2Up(delay+1) bits)) + when(arbitration.isValid && input(IS_MUL) && counter =/= delay){ + arbitration.haltItself := True + } + when(!arbitration.isStuckByOthers){ + counter := counter + 1 + } + when(!arbitration.isStuck){ + counter := 0 + } + } + val withInputBuffer = inputBuffer generate new Area{ val rs1 = RegNext(input(RS1)) val rs2 = RegNext(input(RS2)) a := rs1 b := rs2 - - val delay = RegNext(arbitration.isStuck) - when(arbitration.isValid && input(IS_MUL) && !delay){ - arbitration.haltItself := True - } } val noInputBuffer = (!inputBuffer) generate new Area{ @@ -91,10 +102,25 @@ class MulPlugin(inputBuffer : Boolean = false) extends Plugin[VexRiscv]{ val bSLow = (False ## b(15 downto 0)).asSInt val aHigh = (((aSigned && a.msb) ## a(31 downto 16))).asSInt val bHigh = (((bSigned && b.msb) ## b(31 downto 16))).asSInt - insert(MUL_LL) := aULow * bULow - insert(MUL_LH) := aSLow * bHigh - insert(MUL_HL) := aHigh * bSLow - insert(MUL_HH) := aHigh * bHigh + + val withOuputBuffer = outputBuffer generate new Area{ + val mul_ll = RegNext(aULow * bULow) + val mul_lh = RegNext(aSLow * bHigh) + val mul_hl = RegNext(aHigh * bSLow) + val mul_hh = RegNext(aHigh * bHigh) + + insert(MUL_LL) := mul_ll + insert(MUL_LH) := mul_lh + insert(MUL_HL) := mul_hl + insert(MUL_HH) := mul_hh + } + + val noOutputBuffer = (!outputBuffer) generate new Area{ + insert(MUL_LL) := aULow * bULow + insert(MUL_LH) := aSLow * bHigh + insert(MUL_HL) := aHigh * bSLow + insert(MUL_HH) := aHigh * bHigh + } Component.current.afterElaboration{ //Avoid synthesis tools to retime RS1 RS2 from execute stage to decode stage leading to bad timings (ex : Vivado, even if retiming is disabled) diff --git a/src/test/scala/vexriscv/TestIndividualFeatures.scala b/src/test/scala/vexriscv/TestIndividualFeatures.scala index 0cf5ce65..429ad3e3 100644 --- a/src/test/scala/vexriscv/TestIndividualFeatures.scala +++ b/src/test/scala/vexriscv/TestIndividualFeatures.scala @@ -173,19 +173,26 @@ class MulDivDimension extends VexRiscvDimension("MulDiv") { } :: l - if(!noMemory && !noWriteBack) l = - new VexRiscvPosition("MulDivFpga") { - override def testParam = "MUL=yes DIV=yes" - override def applyOn(config: VexRiscvConfig): Unit = { - config.plugins += new MulPlugin - config.plugins += new MulDivIterativePlugin( - genMul = false, - genDiv = true, - mulUnrollFactor = 32, - divUnrollFactor = 1 - ) - } - } :: l + if(!noMemory && !noWriteBack) { + val inputBuffer = r.nextBoolean() + val outputBuffer = r.nextBoolean() + l = new VexRiscvPosition(s"MulDivFpga$inputBuffer$outputBuffer") { + override def testParam = "MUL=yes DIV=yes" + + override def applyOn(config: VexRiscvConfig): Unit = { + config.plugins += new MulPlugin( + inputBuffer = inputBuffer, + outputBuffer = outputBuffer + ) + config.plugins += new MulDivIterativePlugin( + genMul = false, + genDiv = true, + mulUnrollFactor = 32, + divUnrollFactor = 1 + ) + } + } :: l + } random(r, l) } From 1752b9e6d629e89fa6cb8ebb88fe8222e44effd3 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 16 Feb 2021 14:17:21 +0100 Subject: [PATCH 586/951] DataCache.toBmb with aggregation sync path pipelined --- src/main/scala/vexriscv/ip/DataCache.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index 6a7cbb76..2dac851c 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -489,7 +489,7 @@ case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave cmdCtx.payload := aggregationCounter halt setWhen(!cmdCtx.ready) - val syncCtx = cmdCtx.queue(syncPendingMax) + val syncCtx = cmdCtx.queue(syncPendingMax).s2mPipe().m2sPipe() //Assume latency of sync is at least 3 cycles syncCtx.ready := bus.sync.fire sync.arbitrationFrom(bus.sync) From 8b2a2afb6fbcc954d333e6085e8bab71542c504f Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 16 Feb 2021 14:42:31 +0100 Subject: [PATCH 587/951] VexRIscvSmpCluster add options --- src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index 7c6e33d4..3f61c0de 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -159,6 +159,7 @@ object VexRiscvSmpClusterGen { iCacheWays : Int = 2, dCacheWays : Int = 2, iBusRelax : Boolean = false, + injectorStage : Boolean = false, earlyBranch : Boolean = false, dBusCmdMasterPipe : Boolean = false, withMmu : Boolean = true, @@ -181,7 +182,7 @@ object VexRiscvSmpClusterGen { prediction = vexriscv.plugin.NONE, historyRamSizeLog2 = 9, relaxPredictorAddress = true, - injectorStage = false, + injectorStage = injectorStage, relaxedPcCalculation = iBusRelax, config = InstructionCacheConfig( cacheSize = iCacheSize, From f180ba2fc96a0899c3627840f60bdb169b19ee40 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 16 Feb 2021 15:38:51 +0100 Subject: [PATCH 588/951] fpu double fixes DataCache now support wide load/store --- src/main/scala/vexriscv/TestsWorkspace.scala | 258 ++++++------------ src/main/scala/vexriscv/VexRiscv.scala | 1 - src/main/scala/vexriscv/ip/DataCache.scala | 111 +++++--- src/main/scala/vexriscv/ip/fpu/FpuCore.scala | 37 +-- .../vexriscv/plugin/DBusCachedPlugin.scala | 52 ++-- .../scala/vexriscv/plugin/FpuPlugin.scala | 9 +- src/test/cpp/regression/main.cpp | 237 +++++++--------- src/test/cpp/regression/makefile | 9 +- src/test/scala/vexriscv/DhrystoneBench.scala | 198 +++++++------- .../vexriscv/TestIndividualFeatures.scala | 9 +- src/test/scala/vexriscv/ip/fpu/FpuTest.scala | 34 ++- 11 files changed, 434 insertions(+), 521 deletions(-) diff --git a/src/main/scala/vexriscv/TestsWorkspace.scala b/src/main/scala/vexriscv/TestsWorkspace.scala index 96f2551f..01540367 100644 --- a/src/main/scala/vexriscv/TestsWorkspace.scala +++ b/src/main/scala/vexriscv/TestsWorkspace.scala @@ -32,189 +32,83 @@ import vexriscv.ip.fpu.FpuParameter //make clean all SEED=42 MMU=no STOP_ON_ERROR=yes DBUS_EXCLUSIVE=yes DBUS_INVALIDATE=yes SUPERVISOR=yes REDO=1 DHRYSTONE=yes LRSC=yes AMO=yes TRACE=yes TRACE_START=1000000000 FLOW_INFO=ye IBUS_DATA_WIDTH=128 DBUS_DATA_WIDTH=128 LINUX_SOC_SMP=yes VMLINUX=../../../../../buildroot/output/images/Image RAMDISK=../../../../../buildroot/output/images/rootfs.cpio DTB=../../../../../buildroot/output/images/dtb EMULATOR=../../../../../opensbi/build/platform/spinal/vexriscv/sim/smp/firmware/fw_jump.bin object TestsWorkspace { def main(args: Array[String]) { -// def configFull = { -// val config = VexRiscvConfig( -// plugins = List( -// new MmuPlugin( -// ioRange = x => x(31 downto 28) === 0xF -// ), -// //Uncomment the whole IBusSimplePlugin and comment IBusCachedPlugin if you want uncached iBus config -// // new IBusSimplePlugin( -// // resetVector = 0x80000000l, -// // cmdForkOnSecondStage = false, -// // cmdForkPersistence = false, -// // prediction = DYNAMIC_TARGET, -// // historyRamSizeLog2 = 10, -// // catchAccessFault = true, -// // compressedGen = true, -// // busLatencyMin = 1, -// // injectorStage = true, -// // memoryTranslatorPortConfig = withMmu generate MmuPortConfig( -// // portTlbSize = 4 -// // ) -// // ), -// -// //Uncomment the whole IBusCachedPlugin and comment IBusSimplePlugin if you want cached iBus config -// new IBusCachedPlugin( -// resetVector = 0x80000000l, -// compressedGen = false, -// prediction = STATIC, -// injectorStage = false, -// config = InstructionCacheConfig( -// cacheSize = 4096*2, -// bytePerLine = 64, -// wayCount = 2, -// addressWidth = 32, -// cpuDataWidth = 32, -// memDataWidth = 128, -// catchIllegalAccess = true, -// catchAccessFault = true, -// asyncTagMemory = false, -// twoCycleRam = true, -// twoCycleCache = true, -// reducedBankWidth = true -// // ) -// ), -// memoryTranslatorPortConfig = MmuPortConfig( -// portTlbSize = 4, -// latency = 1, -// earlyRequireMmuLockup = true, -// earlyCacheHits = true -// ) -// ), -// // ).newTightlyCoupledPort(TightlyCoupledPortParameter("iBusTc", a => a(30 downto 28) === 0x0 && a(5))), -// // new DBusSimplePlugin( -// // catchAddressMisaligned = true, -// // catchAccessFault = true, -// // earlyInjection = false, -// // withLrSc = true, -// // memoryTranslatorPortConfig = withMmu generate MmuPortConfig( -// // portTlbSize = 4 -// // ) -// // ), -// new DBusCachedPlugin( -// dBusCmdMasterPipe = true, -// dBusCmdSlavePipe = true, -// dBusRspSlavePipe = true, -// config = new DataCacheConfig( -// cacheSize = 4096*1, -// bytePerLine = 64, -// wayCount = 1, -// addressWidth = 32, -// cpuDataWidth = 32, -// memDataWidth = 128, -// catchAccessError = true, -// catchIllegal = true, -// catchUnaligned = true, -// withLrSc = true, -// withAmo = true, -// withExclusive = true, -// withInvalidate = true, -// pendingMax = 32 -// // ) -// ), -// memoryTranslatorPortConfig = MmuPortConfig( -// portTlbSize = 4, -// latency = 1, -// earlyRequireMmuLockup = true, -// earlyCacheHits = true -// ) -// ), -// -// // new MemoryTranslatorPlugin( -// // tlbSize = 32, -// // virtualRange = _(31 downto 28) === 0xC, -// // ioRange = _(31 downto 28) === 0xF -// // ), -// -// new DecoderSimplePlugin( -// catchIllegalInstruction = true -// ), -// new RegFilePlugin( -// regFileReadyKind = plugin.ASYNC, -// zeroBoot = true -// ), -// new IntAluPlugin, -// new SrcPlugin( -// separatedAddSub = false -// ), -// new FullBarrelShifterPlugin(earlyInjection = false), -// // new LightShifterPlugin, -// new HazardSimplePlugin( -// bypassExecute = true, -// bypassMemory = true, -// bypassWriteBack = true, -// bypassWriteBackBuffer = true, -// pessimisticUseSrc = false, -// pessimisticWriteRegFile = false, -// pessimisticAddressMatch = false -// ), -// // new HazardSimplePlugin(false, true, false, true), -// // new HazardSimplePlugin(false, false, false, false), -// new MulPlugin, -// new MulDivIterativePlugin( -// genMul = false, -// genDiv = true, -// mulUnrollFactor = 32, -// divUnrollFactor = 1 -// ), -// // new DivPlugin, -// new CsrPlugin(CsrPluginConfig.all2(0x80000020l).copy(ebreakGen = false, misaExtensionsInit = Riscv.misaToInt("imas"))), -// // new CsrPlugin(//CsrPluginConfig.all2(0x80000020l).copy(ebreakGen = true)/* -// // CsrPluginConfig( -// // catchIllegalAccess = false, -// // mvendorid = null, -// // marchid = null, -// // mimpid = null, -// // mhartid = null, -// // misaExtensionsInit = 0, -// // misaAccess = CsrAccess.READ_ONLY, -// // mtvecAccess = CsrAccess.WRITE_ONLY, -// // mtvecInit = 0x80000020l, -// // mepcAccess = CsrAccess.READ_WRITE, -// // mscratchGen = true, -// // mcauseAccess = CsrAccess.READ_ONLY, -// // mbadaddrAccess = CsrAccess.READ_ONLY, -// // mcycleAccess = CsrAccess.NONE, -// // minstretAccess = CsrAccess.NONE, -// // ecallGen = true, -// // ebreakGen = true, -// // wfiGenAsWait = false, -// // wfiGenAsNop = true, -// // ucycleAccess = CsrAccess.NONE -// // )), -// new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))), -// new BranchPlugin( -// earlyBranch = false, -// catchAddressMisaligned = true, -// fenceiGenAsAJump = false -// ), -// new YamlPlugin("cpu0.yaml") -// ) -// ) -// config -// } - - -// import spinal.core.sim._ -// SimConfig.withConfig(SpinalConfig(mergeAsyncProcess = false, anonymSignalPrefix = "zz_")).allOptimisation.compile(new VexRiscv(configFull)).doSimUntilVoid{ dut => -// dut.clockDomain.forkStimulus(10) -// dut.clockDomain.forkSimSpeedPrinter(4) -// var iBus : InstructionCacheMemBus = null -// -// dut.plugins.foreach{ -// case plugin: IBusCachedPlugin => iBus = plugin.iBus -// case _ => -// } -// dut.clockDomain.onSamplings{ -//// iBus.cmd.ready.randomize() -// iBus.rsp.data #= 0x13 -// } -// } - SpinalConfig().generateVerilog { -// make clean run REDO=10 CSR=no MMU=no COREMARK=no RVF=yes REDO=1 TRACE=yes - val config = GenFull.config +// make clean all REDO=10 CSR=no MMU=no COREMARK=no RVF=no REDO=1 DBUS_LOAD_DATA_WIDTH=64 DBUS_STORE_DATA_WIDTH=64 DEBUG=ye TRACE=ye + val config = VexRiscvConfig( + plugins = List( + new IBusCachedPlugin( + prediction = DYNAMIC, + config = InstructionCacheConfig( + cacheSize = 4096, + bytePerLine =32, + wayCount = 1, + addressWidth = 32, + cpuDataWidth = 32, + memDataWidth = 32, + catchIllegalAccess = true, + catchAccessFault = true, + asyncTagMemory = false, + twoCycleRam = true, + twoCycleCache = true + ), + memoryTranslatorPortConfig = MmuPortConfig( + portTlbSize = 4 + ) + ), + new DBusCachedPlugin( + config = new DataCacheConfig( + cacheSize = 4096, + bytePerLine = 32, + wayCount = 1, + addressWidth = 32, + rfDataWidth = 32, + cpuDataWidth = 64, + memDataWidth = 64, + catchAccessError = true, + catchIllegal = true, + catchUnaligned = true + ), + memoryTranslatorPortConfig = MmuPortConfig( + portTlbSize = 6 + ) + ), + new MmuPlugin( + virtualRange = _(31 downto 28) === 0xC, + ioRange = _(31 downto 28) === 0xF + ), + new DecoderSimplePlugin( + catchIllegalInstruction = true + ), + new RegFilePlugin( + regFileReadyKind = plugin.SYNC, + zeroBoot = false + ), + new IntAluPlugin, + new SrcPlugin( + separatedAddSub = false, + executeInsertion = true + ), + new FullBarrelShifterPlugin, + new HazardSimplePlugin( + bypassExecute = true, + bypassMemory = true, + bypassWriteBack = true, + bypassWriteBackBuffer = true, + pessimisticUseSrc = false, + pessimisticWriteRegFile = false, + pessimisticAddressMatch = false + ), + new MulPlugin, + new DivPlugin, + new CsrPlugin(CsrPluginConfig.small(0x80000020l)), + new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))), + new BranchPlugin( + earlyBranch = false, + catchAddressMisaligned = true + ), + new YamlPlugin("cpu0.yaml") + ) + ) config.plugins += new FpuPlugin( externalFpu = false, p = FpuParameter( diff --git a/src/main/scala/vexriscv/VexRiscv.scala b/src/main/scala/vexriscv/VexRiscv.scala index a08f9c99..5f7865cf 100644 --- a/src/main/scala/vexriscv/VexRiscv.scala +++ b/src/main/scala/vexriscv/VexRiscv.scala @@ -46,7 +46,6 @@ case class VexRiscvConfig(){ object LEGAL_INSTRUCTION extends Stageable(Bool) object REGFILE_WRITE_VALID extends Stageable(Bool) object REGFILE_WRITE_DATA extends Stageable(Bits(32 bits)) - object DBUS_DATA extends Stageable(Bits(32 bits)) object MPP extends PipelineThing[UInt] object DEBUG_BYPASS_CACHE extends PipelineThing[Bool] diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index 0e5ca7a1..1f766523 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -16,6 +16,7 @@ case class DataCacheConfig(cacheSize : Int, wayCount : Int, addressWidth : Int, cpuDataWidth : Int, + var rfDataWidth : Int = -1, //-1 mean cpuDataWidth memDataWidth : Int, catchAccessError : Boolean, catchIllegal : Boolean, @@ -31,10 +32,17 @@ case class DataCacheConfig(cacheSize : Int, directTlbHit : Boolean = false, mergeExecuteMemory : Boolean = false, asyncTagMemory : Boolean = false, - aggregationWidth : Int = 0){ + withWriteAggregation : Boolean = false){ + + if(rfDataWidth == -1) rfDataWidth = cpuDataWidth assert(!(mergeExecuteMemory && (earlyDataMux || earlyWaysHits))) assert(!(earlyDataMux && !earlyWaysHits)) assert(isPow2(pendingMax)) + assert(rfDataWidth <= memDataWidth) + + def sizeMax = log2Up(bytePerLine) + def sizeWidth = log2Up(sizeMax + 1) + val aggregationWidth = if(withWriteAggregation) log2Up(memDataBytes+1) else 0 def withWriteResponse = withExclusive def burstSize = bytePerLine*8/memDataWidth val burstLength = bytePerLine/(cpuDataWidth/8) @@ -44,6 +52,7 @@ case class DataCacheConfig(cacheSize : Int, def withExternalLrSc = withLrSc && withExclusive def withExternalAmo = withAmo && withExclusive def cpuDataBytes = cpuDataWidth/8 + def rfDataBytes = rfDataWidth/8 def memDataBytes = memDataWidth/8 def getAxi4SharedConfig() = Axi4Config( addressWidth = addressWidth, @@ -55,6 +64,7 @@ case class DataCacheConfig(cacheSize : Int, useQos = false ) + def getAvalonConfig() = AvalonMMConfig.bursted( addressWidth = addressWidth, dataWidth = memDataWidth, @@ -87,7 +97,7 @@ case class DataCacheConfig(cacheSize : Int, dataWidth = memDataWidth ).addSources(1, BmbSourceParameter( lengthWidth = log2Up(this.bytePerLine), - contextWidth = (if(!withWriteResponse) 1 else 0) + (if(cpuDataWidth != memDataWidth) log2Up(memDataBytes) else 0), + contextWidth = (if(!withWriteResponse) 1 else 0) + aggregationWidth, alignment = BmbParameter.BurstAlignement.LENGTH, canExclusive = withExclusive, withCachedRead = true @@ -120,7 +130,7 @@ case class DataCacheCpuExecute(p : DataCacheConfig) extends Bundle with IMasterS case class DataCacheCpuExecuteArgs(p : DataCacheConfig) extends Bundle{ val wr = Bool - val size = UInt(2 bits) + val size = UInt(log2Up(log2Up(p.cpuDataBytes)+1) bits) val isLrsc = p.withLrSc generate Bool() val isAmo = p.withAmo generate Bool() val amoCtrl = p.withAmo generate new Bundle { @@ -174,10 +184,11 @@ case class DataCacheCpuWriteBack(p : DataCacheConfig) extends Bundle with IMaste val mmuException, unalignedAccess, accessError = Bool() val keepMemRspData = Bool() //Used by external AMO to avoid having an internal buffer val fence = FenceFlags() + val exclusiveOk = Bool() override def asMaster(): Unit = { out(isValid,isStuck,isUser, address, fence, storeData) - in(haltIt, data, mmuException, unalignedAccess, accessError, isWrite, keepMemRspData) + in(haltIt, data, mmuException, unalignedAccess, accessError, isWrite, keepMemRspData, exclusiveOk) } } @@ -205,9 +216,18 @@ case class DataCacheMemCmd(p : DataCacheConfig) extends Bundle{ val address = UInt(p.addressWidth bit) val data = Bits(p.cpuDataWidth bits) val mask = Bits(p.cpuDataWidth/8 bits) - val length = UInt(log2Up(p.burstLength) bits) + val size = UInt(p.sizeWidth bits) //... 1 => 2 bytes ... 2 => 4 bytes ... val exclusive = p.withExclusive generate Bool() val last = Bool + +// def beatCountMinusOne = size.muxListDc((0 to p.sizeMax).map(i => i -> U((1 << i)/p.memDataBytes))) +// def beatCount = size.muxListDc((0 to p.sizeMax).map(i => i -> U((1 << i)/p.memDataBytes-1))) + + //Utilities which does quite a few assumtions about the bus utilisation + def byteCountMinusOne = size.muxListDc((0 to p.sizeMax).map(i => i -> U((1 << i)-1, log2Up(p.bytePerLine) bits))) + def beatCountMinusOne = (size === log2Up(p.bytePerLine)) ? U(p.burstSize-1) | U(0) + def beatCount = (size === log2Up(p.bytePerLine)) ? U(p.burstSize) | U(1) + def isBurst = size === log2Up(p.bytePerLine) } case class DataCacheMemRsp(p : DataCacheConfig) extends Bundle{ val aggregated = UInt(p.aggregationWidth bits) @@ -267,9 +287,9 @@ case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave axi.sharedCmd.write := cmdStage.wr axi.sharedCmd.prot := "010" axi.sharedCmd.cache := "1111" - axi.sharedCmd.size := log2Up(p.memDataWidth/8) + axi.sharedCmd.size := cmd.size.max(log2Up(p.memDataBytes)) axi.sharedCmd.addr := cmdStage.address - axi.sharedCmd.len := cmdStage.length.resized + axi.sharedCmd.len := cmd.beatCountMinusOne.resized axi.writeData.arbitrationFrom(dataStage) axi.writeData.data := dataStage.data @@ -293,7 +313,7 @@ case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave mm.read := cmd.valid && !cmd.wr mm.write := cmd.valid && cmd.wr mm.address := cmd.address(cmd.address.high downto log2Up(p.memDataWidth/8)) @@ U(0,log2Up(p.memDataWidth/8) bits) - mm.burstCount := cmd.length + U(1, widthOf(mm.burstCount) bits) + mm.burstCount := cmd.beatCount mm.byteEnable := cmd.mask mm.writeData := cmd.data @@ -302,23 +322,25 @@ case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave rsp.data := mm.readData rsp.error := mm.response =/= AvalonMM.Response.OKAY + assert(p.cpuDataWidth == p.rfDataWidth) mm } def toWishbone(): Wishbone = { + assert(p.cpuDataWidth == p.rfDataWidth) val wishboneConfig = p.getWishboneConfig() val bus = Wishbone(wishboneConfig) val counter = Reg(UInt(log2Up(p.burstSize) bits)) init(0) val cmdBridge = Stream (DataCacheMemCmd(p)) - val isBurst = cmdBridge.length =/= 0 + val isBurst = cmdBridge.isBurst cmdBridge.valid := cmd.valid cmdBridge.address := (isBurst ? (cmd.address(31 downto widthOf(counter) + 2) @@ counter @@ U"00") | (cmd.address(31 downto 2) @@ U"00")) cmdBridge.wr := cmd.wr cmdBridge.mask := cmd.mask cmdBridge.data := cmd.data - cmdBridge.length := cmd.length - cmdBridge.last := counter === cmd.length + cmdBridge.size := cmd.size + cmdBridge.last := !isBurst || counter === p.burstSize-1 cmd.ready := cmdBridge.ready && (cmdBridge.wr || cmdBridge.last) @@ -351,6 +373,7 @@ case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave def toPipelinedMemoryBus(): PipelinedMemoryBus = { val bus = PipelinedMemoryBus(32,32) + assert(p.cpuDataWidth == p.rfDataWidth) val counter = Reg(UInt(log2Up(p.burstSize) bits)) init(0) when(bus.cmd.fire){ counter := counter + 1 } @@ -361,7 +384,7 @@ case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave bus.cmd.write := cmd.wr bus.cmd.mask := cmd.mask bus.cmd.data := cmd.data - cmd.ready := bus.cmd.ready && (cmd.wr || counter === cmd.length) + cmd.ready := bus.cmd.ready && (cmd.wr || counter === p.burstSize-1) rsp.valid := bus.rsp.valid rsp.data := bus.rsp.payload.data rsp.error := False @@ -374,14 +397,16 @@ case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave setCompositeName(DataCacheMemBus.this, "Bridge", true) val pipelinedMemoryBusConfig = p.getBmbParameter() val bus = Bmb(pipelinedMemoryBusConfig).setCompositeName(this,"toBmb", true) - val aggregationMax = p.memDataBytes case class Context() extends Bundle{ val isWrite = !p.withWriteResponse generate Bool() - val rspCount = (p.cpuDataWidth != p.memDataWidth) generate UInt(log2Up(aggregationMax) bits) + val rspCount = (p.aggregationWidth != 0) generate UInt(p.aggregationWidth bits) } - val withoutWriteBuffer = if(p.cpuDataWidth == p.memDataWidth) new Area { + + def sizeToLength(size : UInt) = size.muxListDc((0 to log2Up(p.cpuDataBytes)).map(i => U(i) -> U((1 << i)-1, log2Up(p.cpuDataBytes) bits))) + + val withoutWriteBuffer = if(p.aggregationWidth == 0) new Area { val busCmdContext = Context() bus.cmd.valid := cmd.valid @@ -389,7 +414,7 @@ case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave bus.cmd.opcode := (cmd.wr ? B(Bmb.Cmd.Opcode.WRITE) | B(Bmb.Cmd.Opcode.READ)) bus.cmd.address := cmd.address.resized bus.cmd.data := cmd.data - bus.cmd.length := (cmd.length << 2) | 3 + bus.cmd.length := cmd.byteCountMinusOne bus.cmd.mask := cmd.mask if (p.withExclusive) bus.cmd.exclusive := cmd.exclusive if (!p.withWriteResponse) busCmdContext.isWrite := cmd.wr @@ -399,7 +424,7 @@ case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave if(p.withInvalidate) sync.arbitrationFrom(bus.sync) } - val withWriteBuffer = if(p.cpuDataWidth != p.memDataWidth) new Area { + val withWriteBuffer = if(p.aggregationWidth != 0) new Area { val buffer = new Area { val stream = cmd.toEvent().m2sPipe() val address = Reg(UInt(p.addressWidth bits)) @@ -413,7 +438,7 @@ case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave val aggregationRange = log2Up(p.memDataWidth/8)-1 downto log2Up(p.cpuDataWidth/8) val tagRange = p.addressWidth-1 downto aggregationRange.high+1 val aggregationEnabled = Reg(Bool) - val aggregationCounter = Reg(UInt(log2Up(aggregationMax) bits)) init(0) + val aggregationCounter = Reg(UInt(p.aggregationWidth bits)) init(0) val aggregationCounterFull = aggregationCounter === aggregationCounter.maxValue val timer = Reg(UInt(log2Up(timeoutCycles)+1 bits)) init(0) val timerFull = timer.msb @@ -467,7 +492,7 @@ case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave when(cmd.fire){ buffer.write := cmd.wr buffer.address := cmd.address.resized - buffer.length := (cmd.length << 2) | 3 + buffer.length := cmd.byteCountMinusOne if (p.withExclusive) buffer.exclusive := cmd.exclusive when(cmd.wr && !cmd.uncached && !cmdExclusive){ @@ -484,7 +509,7 @@ case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave rsp.aggregated := rspCtx.rspCount val syncLogic = p.withInvalidate generate new Area{ - val cmdCtx = Stream(UInt(log2Up(aggregationMax) bits)) + val cmdCtx = Stream(UInt(p.aggregationWidth bits)) cmdCtx.valid := bus.cmd.fire && bus.cmd.isWrite cmdCtx.payload := aggregationCounter halt setWhen(!cmdCtx.ready) @@ -563,6 +588,7 @@ class DataCache(val p : DataCacheConfig, mmuParameter : MemoryTranslatorBusParam val memWordRange = log2Up(bytePerLine)-1 downto log2Up(bytePerMemWord) val hitRange = tagRange.high downto lineRange.low val memWordToCpuWordRange = log2Up(bytePerMemWord)-1 downto log2Up(bytePerWord) + val cpuWordToRfWordRange = log2Up(bytePerWord)-1 downto log2Up(p.rfDataBytes) class LineInfo() extends Bundle{ @@ -721,11 +747,15 @@ class DataCache(val p : DataCacheConfig, mmuParameter : MemoryTranslatorBusParam val stage0 = new Area{ - val mask = io.cpu.execute.size.mux ( - U(0) -> B"0001", - U(1) -> B"0011", - default -> B"1111" - ) |<< io.cpu.execute.address(1 downto 0) +// val mask = io.cpu.execute.size.mux ( +// U(0) -> B"0001", +// U(1) -> B"0011", +// default -> B"1111" +// ) |<< io.cpu.execute.address(1 downto 0) + + val mask = io.cpu.execute.size.muxListDc((0 to log2Up(p.cpuDataBytes)).map(i => U(i) -> B((1 << (1 << i)) -1, p.cpuDataBytes bits))) |<< io.cpu.execute.address(log2Up(p.cpuDataBytes)-1 downto 0) + + val dataColisions = collisionProcess(io.cpu.execute.address(lineRange.high downto cpuWordRange.low), mask) val wayInvalidate = B(0, wayCount bits) //Used if invalidate enabled @@ -792,7 +822,8 @@ class DataCache(val p : DataCacheConfig, mmuParameter : MemoryTranslatorBusParam val wayInvalidate = stagePipe(stageA. wayInvalidate) val consistancyHazard = if(stageA.consistancyCheck != null) stagePipe(stageA.consistancyCheck.hazard) else False val dataColisions = stagePipe(stageA.dataColisions) - val unaligned = if(!catchUnaligned) False else stagePipe((stageA.request.size === 2 && io.cpu.memory.address(1 downto 0) =/= 0) || (stageA.request.size === 1 && io.cpu.memory.address(0 downto 0) =/= 0)) +// val unaligned = if(!catchUnaligned) False else stagePipe((stageA.request.size === 2 && io.cpu.memory.address(1 downto 0) =/= 0) || (stageA.request.size === 1 && io.cpu.memory.address(0 downto 0) =/= 0)) + val unaligned = if(!catchUnaligned) False else stagePipe((1 to log2Up(p.cpuDataBytes)).map(i => stageA.request.size === i && io.cpu.memory.address(i-1 downto 0) =/= 0).orR) val waysHitsBeforeInvalidate = if(earlyWaysHits) stagePipe(B(stageA.wayHits)) else B(tagsReadRsp.map(tag => mmuRsp.physicalAddress(tagRange) === tag.address && tag.valid).asBits()) val waysHits = waysHitsBeforeInvalidate & ~wayInvalidate val waysHit = waysHits.orR @@ -848,8 +879,9 @@ class DataCache(val p : DataCacheConfig, mmuParameter : MemoryTranslatorBusParam val requestDataBypass = CombInit(io.cpu.writeBack.storeData) import DataCacheExternalAmoStates._ val amo = withAmo generate new Area{ - def rf = io.cpu.writeBack.storeData - def mem = if(withInternalAmo) dataMux else ioMemRspMuxed + def rf = io.cpu.writeBack.storeData(p.rfDataWidth-1 downto 0) + def memLarger = if(withInternalAmo) dataMux else ioMemRspMuxed + def mem = memLarger.subdivideIn(rfDataWidth bits).read(io.cpu.writeBack.address(cpuWordToRfWordRange)) val compare = request.amoCtrl.alu.msb val unsigned = request.amoCtrl.alu(2 downto 1) === B"11" val addSub = (rf.asSInt + Mux(compare, ~mem, mem).asSInt + Mux(compare, S(1), S(0))).asBits @@ -898,13 +930,13 @@ class DataCache(val p : DataCacheConfig, mmuParameter : MemoryTranslatorBusParam io.mem.cmd.valid := False - io.mem.cmd.address := mmuRsp.physicalAddress(tagRange.high downto cpuWordRange.low) @@ U(0, cpuWordRange.low bits) - io.mem.cmd.length := 0 + io.mem.cmd.address := mmuRsp.physicalAddress io.mem.cmd.last := True io.mem.cmd.wr := request.wr io.mem.cmd.mask := mask io.mem.cmd.data := requestDataBypass io.mem.cmd.uncached := mmuRsp.isIoAccess + io.mem.cmd.size := request.size.resized if(withExternalLrSc) io.mem.cmd.exclusive := request.isLrsc || isAmo @@ -962,8 +994,6 @@ class DataCache(val p : DataCacheConfig, mmuParameter : MemoryTranslatorBusParam //Write through io.mem.cmd.valid setWhen(request.wr) - io.mem.cmd.address := mmuRsp.physicalAddress(tagRange.high downto cpuWordRange.low) @@ U(0, cpuWordRange.low bits) - io.mem.cmd.length := 0 io.cpu.writeBack.haltIt clearWhen(!request.wr || io.mem.cmd.ready) if(withInternalAmo) when(isAmo){ @@ -989,8 +1019,8 @@ class DataCache(val p : DataCacheConfig, mmuParameter : MemoryTranslatorBusParam //Emit cmd io.mem.cmd.valid setWhen(!memCmdSent) io.mem.cmd.wr := False - io.mem.cmd.address := mmuRsp.physicalAddress(tagRange.high downto lineRange.low) @@ U(0,lineRange.low bit) - io.mem.cmd.length := p.burstLength-1 + io.mem.cmd.address(0, lineRange.low bits) := 0 + io.mem.cmd.size := log2Up(p.bytePerLine) loaderValid setWhen(io.mem.cmd.ready) } @@ -1006,15 +1036,18 @@ class DataCache(val p : DataCacheConfig, mmuParameter : MemoryTranslatorBusParam if(catchAccessError) io.cpu.writeBack.accessError := (waysHits & B(tagsReadRsp.map(_.error))) =/= 0 || (loadStoreFault && !mmuRsp.isPaging) } - if(withLrSc) when(request.isLrsc && request.wr){ + if(withLrSc) { val success = if(withInternalLrSc)lrSc.reserved else io.mem.rsp.exclusive - io.cpu.writeBack.data := B(!success).resized - if(withExternalLrSc) when(io.cpu.writeBack.isValid && io.mem.rsp.valid && rspSync && success && waysHit){ - cpuWriteToCache := True + io.cpu.writeBack.exclusiveOk := success + when(request.isLrsc && request.wr){ + // io.cpu.writeBack.data := B(!success).resized + if(withExternalLrSc) when(io.cpu.writeBack.isValid && io.mem.rsp.valid && rspSync && success && waysHit){ + cpuWriteToCache := True + } } } if(withAmo) when(request.isAmo){ - requestDataBypass := amo.resultReg + requestDataBypass.subdivideIn(p.rfDataWidth bits).foreach(_ := amo.resultReg) } //remove side effects on exceptions diff --git a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala index c674bfe1..df953f32 100644 --- a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala +++ b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala @@ -275,13 +275,13 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ output.rs1.setNanQuiet output.rs1.sign := False } - when(s1.format === FpuFormat.FLOAT =/= rs2Entry.boxed) { - output.rs2.setNanQuiet - output.rs2.sign := False - } - when(s1.format === FpuFormat.FLOAT =/= rs3Entry.boxed) { - output.rs3.setNanQuiet - } + } + when(s1.format === FpuFormat.FLOAT =/= rs2Entry.boxed) { + output.rs2.setNanQuiet + output.rs2.sign := False + } + when(s1.format === FpuFormat.FLOAT =/= rs3Entry.boxed) { + output.rs3.setNanQuiet } } } @@ -733,7 +733,6 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val sgnjRs1Sign = CombInit(input.rs1.sign) val sgnjRs2Sign = CombInit(input.rs2.sign) if(p.withDouble){ - sgnjRs1Sign setWhen(input.rs1Boxed && input.format === FpuFormat.DOUBLE) sgnjRs2Sign setWhen(input.rs2Boxed && input.format === FpuFormat.DOUBLE) } val sgnjResult = (sgnjRs1Sign && input.arg(1)) ^ sgnjRs2Sign ^ input.arg(0) @@ -786,22 +785,12 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } } is(FpuOpcode.SGNJ){ - rfOutput.value.sign := sgnjResult - if(p.withDouble) when(input.format === FpuFormat.DOUBLE){ - when(input.rs1Boxed){ - rfOutput.value.sign := input.rs1.sign - rfOutput.format := FpuFormat.FLOAT - } -// //kill boxing => F32 -> F64 NAN -// when(input.rs1Boxed && !sgnjResult){ -// rfOutput.value.setNan -// rfOutput.value.mantissa.setAll() -// rfOutput.value.mantissa(31 downto 0) := input.rs1.sign ## input.rs1.exponent -// } -// //Spawn boxing => F64 NAN -> F32 -// when(!input.rs1Boxed && input.rs1.exponent === exponentOne + 1024 && input.rs1.mantissa(32, 52-32 bits).andR && sgnjResult){ -// -// } + when(!input.rs1.isNan) { + rfOutput.value.sign := sgnjResult + } + if(p.withDouble) when(input.rs1Boxed && input.format === FpuFormat.DOUBLE){ + rfOutput.value.sign := input.rs1.sign + rfOutput.format := FpuFormat.FLOAT } } if(p.withDouble) is(FpuOpcode.FCVT_X_X){ diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index a9562d04..20145714 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -6,6 +6,8 @@ import spinal.core._ import spinal.lib._ import spinal.lib.bus.amba4.axi.Axi4 +import scala.collection.mutable.ArrayBuffer + class DAxiCachedPlugin(config : DataCacheConfig, memoryTranslatorPortConfig : Any = null) extends DBusCachedPlugin(config, memoryTranslatorPortConfig) { var dAxi : Axi4 = null @@ -22,6 +24,7 @@ trait DBusEncodingService { def addLoadWordEncoding(key: MaskedLiteral): Unit def addStoreWordEncoding(key: MaskedLiteral): Unit def bypassStore(data : Bits) : Unit + def loadData() : Bits } class DBusCachedPlugin(val config : DataCacheConfig, @@ -90,10 +93,15 @@ class DBusCachedPlugin(val config : DataCacheConfig, ) } + val bypassStoreList = ArrayBuffer[(Bool, Bits)]() + override def bypassStore(data: Bits): Unit = { - pipeline.stages.last.input(MEMORY_STORE_DATA) := data + bypassStoreList += ConditionalContext.isTrue() -> data } + + override def loadData(): Bits = pipeline.stages.last.output(MEMORY_LOAD_DATA) + object MEMORY_ENABLE extends Stageable(Bool) object MEMORY_MANAGMENT extends Stageable(Bool) object MEMORY_WR extends Stageable(Bool) @@ -104,7 +112,9 @@ class DBusCachedPlugin(val config : DataCacheConfig, object MEMORY_FORCE_CONSTISTENCY extends Stageable(Bool) object IS_DBUS_SHARING extends Stageable(Bool()) object MEMORY_VIRTUAL_ADDRESS extends Stageable(UInt(32 bits)) - object MEMORY_STORE_DATA extends Stageable(Bits(32 bits)) + object MEMORY_STORE_DATA_RF extends Stageable(Bits(config.rfDataWidth bits)) +// object MEMORY_STORE_DATA_CPU extends Stageable(Bits(config.cpuDataWidth bits)) + object MEMORY_LOAD_DATA extends Stageable(Bits(config.cpuDataWidth bits)) override def setup(pipeline: VexRiscv): Unit = { import Riscv._ @@ -292,12 +302,12 @@ class DBusCachedPlugin(val config : DataCacheConfig, cache.io.cpu.execute.isValid := arbitration.isValid && input(MEMORY_ENABLE) cache.io.cpu.execute.address := input(SRC_ADD).asUInt cache.io.cpu.execute.args.wr := input(MEMORY_WR) - insert(MEMORY_STORE_DATA) := size.mux( + insert(MEMORY_STORE_DATA_RF) := size.mux( U(0) -> input(RS2)( 7 downto 0) ## input(RS2)( 7 downto 0) ## input(RS2)(7 downto 0) ## input(RS2)(7 downto 0), U(1) -> input(RS2)(15 downto 0) ## input(RS2)(15 downto 0), default -> input(RS2)(31 downto 0) ) - cache.io.cpu.execute.args.size := size + cache.io.cpu.execute.args.size := size.resized if(twoStageMmu) { mmuBus.cmd(0).isValid := cache.io.cpu.execute.isValid @@ -358,13 +368,16 @@ class DBusCachedPlugin(val config : DataCacheConfig, } val managementStage = stages.last - managementStage plug new Area{ + val mgs = managementStage plug new Area{ import managementStage._ 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() else False) cache.io.cpu.writeBack.address := U(input(REGFILE_WRITE_DATA)) - cache.io.cpu.writeBack.storeData := input(MEMORY_STORE_DATA) + cache.io.cpu.writeBack.storeData.subdivideIn(32 bits).foreach(_ := input(MEMORY_STORE_DATA_RF)) + for((cond, value) <- bypassStoreList) when(cond){ + cache.io.cpu.writeBack.storeData := value + } val fence = if(withInvalidate) new Area { cache.io.cpu.writeBack.fence := input(INSTRUCTION)(31 downto 20).as(FenceFlags()) @@ -425,12 +438,15 @@ class DBusCachedPlugin(val config : DataCacheConfig, arbitration.haltItself.setWhen(cache.io.cpu.writeBack.isValid && cache.io.cpu.writeBack.haltIt) - val rspShifted = Bits(32 bits) - rspShifted := cache.io.cpu.writeBack.data + val rspRf = cache.io.cpu.writeBack.data.subdivideIn(32 bits).read(cache.io.cpu.writeBack.address(cache.cpuWordToRfWordRange)) + val rspShifted = CombInit(rspRf) switch(input(MEMORY_ADDRESS_LOW)){ - is(1){rspShifted(7 downto 0) := cache.io.cpu.writeBack.data(15 downto 8)} - is(2){rspShifted(15 downto 0) := cache.io.cpu.writeBack.data(31 downto 16)} - is(3){rspShifted(7 downto 0) := cache.io.cpu.writeBack.data(31 downto 24)} + is(1){rspShifted(7 downto 0) := rspRf(15 downto 8)} + is(2){rspShifted(15 downto 0) := rspRf(31 downto 16)} + is(3){rspShifted(7 downto 0) := rspRf(31 downto 24)} + } + if(withLrSc) when(input(MEMORY_LRSC) && input(MEMORY_WR)){ + rspShifted := B(!cache.io.cpu.writeBack.exclusiveOk).resized } val rspFormated = input(INSTRUCTION)(13 downto 12).mux( @@ -443,7 +459,7 @@ class DBusCachedPlugin(val config : DataCacheConfig, output(REGFILE_WRITE_DATA) := rspFormated } - insert(DBUS_DATA) := cache.io.cpu.writeBack.data + insert(MEMORY_LOAD_DATA) := cache.io.cpu.writeBack.data } //Share access to the dBus (used by self refilled MMU) @@ -458,11 +474,11 @@ class DBusCachedPlugin(val config : DataCacheConfig, cache.io.cpu.execute.isValid := True dBusAccess.cmd.ready := !execute.arbitration.isStuck } - cache.io.cpu.execute.args.wr := dBusAccess.cmd.write - execute.insert(MEMORY_STORE_DATA) := dBusAccess.cmd.data - cache.io.cpu.execute.args.size := dBusAccess.cmd.size - if(withLrSc) cache.io.cpu.execute.args.isLrsc := False - if(withAmo) cache.io.cpu.execute.args.isAmo := False + cache.io.cpu.execute.args.wr := False //dBusAccess.cmd.write +// execute.insert(MEMORY_STORE_DATA_RF) := dBusAccess.cmd.data //Not implemented + cache.io.cpu.execute.args.size := dBusAccess.cmd.size.resized + if(withLrSc) execute.input(MEMORY_LRSC) := False + if(withAmo) execute.input(MEMORY_AMO) := False cache.io.cpu.execute.address := dBusAccess.cmd.address //Will only be 12 muxes forceDatapath := True } @@ -474,7 +490,7 @@ class DBusCachedPlugin(val config : DataCacheConfig, if(mmuAndBufferStage != execute) (cache.io.cpu.memory.isValid setWhen(mmuAndBufferStage.input(IS_DBUS_SHARING))) cache.io.cpu.writeBack.isValid setWhen(managementStage.input(IS_DBUS_SHARING)) dBusAccess.rsp.valid := managementStage.input(IS_DBUS_SHARING) && !cache.io.cpu.writeBack.isWrite && (cache.io.cpu.redo || !cache.io.cpu.writeBack.haltIt) - dBusAccess.rsp.data := cache.io.cpu.writeBack.data + dBusAccess.rsp.data := mgs.rspRf dBusAccess.rsp.error := cache.io.cpu.writeBack.unalignedAccess || cache.io.cpu.writeBack.accessError dBusAccess.rsp.redo := cache.io.cpu.redo component.addPrePopTask{() => diff --git a/src/main/scala/vexriscv/plugin/FpuPlugin.scala b/src/main/scala/vexriscv/plugin/FpuPlugin.scala index 855c3970..a7454ea7 100644 --- a/src/main/scala/vexriscv/plugin/FpuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/FpuPlugin.scala @@ -146,6 +146,10 @@ class FpuPlugin(externalFpu : Boolean = false, val dBusEncoding = pipeline.service(classOf[DBusEncodingService]) dBusEncoding.addLoadWordEncoding(FLW) dBusEncoding.addStoreWordEncoding(FSW) + if(p.withDouble) { + dBusEncoding.addLoadWordEncoding(FLD) + dBusEncoding.addStoreWordEncoding(FSD) + } } override def build(pipeline: VexRiscv): Unit = { @@ -235,7 +239,7 @@ class FpuPlugin(externalFpu : Boolean = false, when(isRsp){ when(arbitration.isValid) { dBusEncoding.bypassStore(port.rsp.value) - output(REGFILE_WRITE_DATA) := port.rsp.value + output(REGFILE_WRITE_DATA) := port.rsp.value(31 downto 0) } when(!port.rsp.valid){ arbitration.haltByOther := True @@ -247,7 +251,8 @@ class FpuPlugin(externalFpu : Boolean = false, // Manage $load val commit = Stream(FpuCommit(p)) commit.valid := isCommit && !arbitration.isStuck - commit.value := (input(FPU_COMMIT_LOAD) ? output(DBUS_DATA) | input(RS1)) + commit.value(31 downto 0) := (input(FPU_COMMIT_LOAD) ? dBusEncoding.loadData()(31 downto 0) | input(RS1)) + if(p.withDouble) commit.value(63 downto 32) := dBusEncoding.loadData()(63 downto 32) commit.write := arbitration.isValid && !arbitration.removeIt commit.sync := input(FPU_COMMIT_SYNC) diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 9bfa886a..6f1dcff1 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -4,7 +4,7 @@ #include "VVexRiscv_RiscvCore.h" #endif #include "verilated.h" -#include "verilated_vcd_c.h" +#include "verilated_fst_c.h" #include #include #include @@ -175,8 +175,12 @@ void loadBinImpl(string path,Memory* mem, uint32_t offset) { #define TEXTIFY(A) #A +void breakMe(){ + int a = 0; +} #define assertEq(x,ref) if(x != ref) {\ printf("\n*** %s is %d but should be %d ***\n\n",TEXTIFY(x),x,ref);\ + breakMe();\ throw std::exception();\ } @@ -1106,7 +1110,7 @@ public: uint32_t bootPc = -1; uint32_t iStall = STALL,dStall = STALL; #ifdef TRACE - VerilatedVcdC* tfp; + VerilatedFstC* tfp; #endif bool allowInvalidate = true; @@ -1129,13 +1133,13 @@ public: class MemWrite { public: int32_t address, size; - uint32_t data; + uint8_t data42[64]; }; class MemRead { public: int32_t address, size; - uint32_t data; + uint8_t data42[64]; bool error; }; @@ -1186,7 +1190,10 @@ public: cout << " DUT : address=" << t.address << " size=" << t.size << endl; fail(); } - *data = t.data; + + for(int i = 0; i < size; i++){ + ((uint8_t*)data)[i] = t.data42[i]; + } periphRead.pop(); return t.error; }else { @@ -1205,10 +1212,8 @@ public: MemWrite w; w.address = address; w.size = size; - switch(size){ - case 1: w.data = data & 0xFF; break; - case 2: w.data = data & 0xFFFF; break; - case 4: w.data = data; break; + for(int i = 0; i < size; i++){ + w.data42[i] = ((uint8_t*)&data)[i]; } periphWritesGolden.push(w); if(periphWritesGolden.size() > 10){ @@ -1231,10 +1236,12 @@ public: case 0: MemWrite t = periphWrites.front(); MemWrite t2 = periphWritesGolden.front(); - if(t.address != t2.address || t.size != t2.size || t.data != t2.data){ + bool dataMatch = true; + for(int i = 0;i < min(t.size, t2.size);i++) dataMatch &= t.data42[i] == t2.data42[i]; + if(t.address != t2.address || t.size != t2.size || !dataMatch){ cout << hex << "periphWrite missmatch" << endl; - cout << " DUT address=" << t.address << " size=" << t.size << " data=" << t.data << endl; - cout << " REF address=" << t2.address << " size=" << t2.size << " data=" << t2.data << endl; + cout << " DUT address=" << t.address << " size=" << t.size << " data=" << *((uint32_t*)t.data42) << endl; + cout << " REF address=" << t2.address << " size=" << t2.size << " data=" << *((uint32_t*)t2.data42) << endl; fail(); } periphWrites.pop(); @@ -1345,43 +1352,19 @@ public: virtual bool isDBusCheckedRegion(uint32_t address){ return isPerifRegion(address);} - virtual void dBusAccess(uint32_t addr,bool wr, uint32_t size,uint32_t mask, uint32_t *data, bool *error) { - assertEq(addr % (1 << size), 0); + virtual void dBusAccess(uint32_t addr,bool wr, uint32_t size, uint8_t *data, bool *error) { + assertEq(addr % size, 0); if(!isPerifRegion(addr)) { if(wr){ - memTraces << - #ifdef TRACE_WITH_TIME - (currentTime - #ifdef REF - -2 - #endif - ) << - #endif - " : WRITE mem" << hex << (1 << size) << "[" << addr << "] = " << *data << dec << endl; - for(uint32_t b = 0;b < (1 << size);b++){ - uint32_t offset = (addr+b)&0x3; - if((mask >> offset) & 1 == 1) - *mem.get(addr + b) = *data >> (offset*8); + for(uint32_t b = 0;b < size;b++){ + *mem.get(addr + b) = ((uint8_t*)data)[b]; } }else{ - *data = VL_RANDOM_I(32); - for(uint32_t b = 0;b < (1 << size);b++){ - uint32_t offset = (addr+b)&0x3; - *data &= ~(0xFF << (offset*8)); - *data |= mem[addr + b] << (offset*8); + uint32_t innerOffset = addr & (DBUS_LOAD_DATA_WIDTH/8-1); + for(uint32_t b = 0;b < size;b++){ + ((uint8_t*)data)[b] = mem[addr + b]; } - /* - memTraces << - #ifdef TRACE_WITH_TIME - (currentTime - #ifdef REF - -2 - #endif - ) << - #endif - " : READ mem" << (1 << size) << "[" << addr << "] = " << *data << endl;*/ - } } @@ -1390,21 +1373,9 @@ public: if(isDBusCheckedRegion(addr)){ CpuRef::MemWrite w; w.address = addr; - while((mask & 1) == 0){ - mask >>= 1; - w.address++; - w.data >>= 8; - } - switch(mask){ - case 1: size = 0; break; - case 3: size = min(1u, size); break; - case 15: size = min(2u, size); break; - } - w.size = 1 << size; - switch(size){ - case 0: w.data = *data & 0xFF; break; - case 1: w.data = *data & 0xFFFF; break; - case 2: w.data = *data ; break; + w.size = size; + for(uint32_t b = 0;b < size;b++){ + w.data42[b] = data[b]; } riscvRef.periphWrites.push(w); } @@ -1412,8 +1383,10 @@ public: if(isPerifRegion(addr)){ CpuRef::MemRead r; r.address = addr; - r.size = 1 << size; - r.data = *data; + r.size = size; + for(uint32_t b = 0;b < size;b++){ + r.data42[b] = data[b]; + } r.error = *error; riscvRef.periphRead.push(r); } @@ -1461,9 +1434,9 @@ public: // init trace dump #ifdef TRACE Verilated::traceEverOn(true); - tfp = new VerilatedVcdC; + tfp = new VerilatedFstC; top->trace(tfp, 99); - tfp->open((vcdName + ".vcd").c_str()); + tfp->open((vcdName + ".fst").c_str()); #endif // Reset @@ -1725,7 +1698,8 @@ public: virtual void dutPutChar(char c){} - virtual void dBusAccess(uint32_t addr,bool wr, uint32_t size,uint32_t mask, uint32_t *data, bool *error) { + virtual void dBusAccess(uint32_t addr,bool wr, uint32_t size, uint8_t *dataBytes, bool *error) { + uint32_t *data = ((uint32_t*)dataBytes); if(wr){ switch(addr){ case 0xF0010000u: { @@ -1788,19 +1762,10 @@ public: case 0xF00FFF4Cu: *data = mTimeCmp >> 32; break; case 0xF0010004u: *data = ~0; break; } - memTraces << - #ifdef TRACE_WITH_TIME - (currentTime - #ifdef REF - -2 - #endif - ) << - #endif - " : READ mem" << (1 << size) << "[" << addr << "] = " << *data << endl; } *error = addr == 0xF00FFF60u; - Workspace::dBusAccess(addr,wr,size,mask,data,error); + Workspace::dBusAccess(addr,wr,size,dataBytes,error); } @@ -2195,7 +2160,7 @@ public: if (top->dBus_cmd_valid && top->dBus_cmd_ready) { pending = true; data_next = top->dBus_cmd_payload_data; - ws->dBusAccess(top->dBus_cmd_payload_address,top->dBus_cmd_payload_wr,top->dBus_cmd_payload_size,0xF,&data_next,&error_next); + ws->dBusAccess(top->dBus_cmd_payload_address,top->dBus_cmd_payload_wr,1 << top->dBus_cmd_payload_size,((uint8_t*)&data_next) + (top->dBus_cmd_payload_address & 3),&error_next); } } @@ -2370,7 +2335,7 @@ public: #include struct DBusCachedTask{ - char data[DBUS_DATA_WIDTH/8]; + char data[DBUS_LOAD_DATA_WIDTH/8]; bool error; bool last; bool exclusive; @@ -2407,12 +2372,14 @@ public: virtual void preCycle(){ if (top->dBus_cmd_valid && top->dBus_cmd_ready) { if(top->dBus_cmd_payload_wr){ + int size = 1 << top->dBus_cmd_payload_size; #ifdef DBUS_INVALIDATE pendingSync += 1; #endif #ifndef DBUS_EXCLUSIVE bool error; - ws->dBusAccess(top->dBus_cmd_payload_address,1,2,top->dBus_cmd_payload_mask,&top->dBus_cmd_payload_data,&error); + int shift = top->dBus_cmd_payload_address & (DBUS_STORE_DATA_WIDTH/8-1); + ws->dBusAccess(top->dBus_cmd_payload_address,1,size,((uint8_t*)&top->dBus_cmd_payload_data) + shift,&error); #else bool cancel = false, error = false; if(top->dBus_cmd_payload_exclusive){ @@ -2424,31 +2391,28 @@ public: if(!cancel) { for(int idx = 0;idx < 1;idx++){ bool localError = false; - ws->dBusAccess(top->dBus_cmd_payload_address+idx*4,1,2,top->dBus_cmd_payload_mask >> idx*4,((uint32_t*)&top->dBus_cmd_payload_data)+idx, &localError); + int shift = top->dBus_cmd_payload_address & (DBUS_STORE_DATA_WIDTH/8-1); + ws->dBusAccess(top->dBus_cmd_payload_address,1,size,((uint8_t*)&top->dBus_cmd_payload_data) + shift,&localError); error |= localError; - - //printf("%d ", (int)localError); } } - // printf("%x %d\n", top->dBus_cmd_payload_address, (int)error); rsp.last = true; rsp.error = error; rsps.push(rsp); #endif } else { bool error = false; - uint32_t beatCount = top->dBus_cmd_payload_length*32/DBUS_DATA_WIDTH; + uint32_t beatCount = (((1 << top->dBus_cmd_payload_size)*8+DBUS_LOAD_DATA_WIDTH-1) / DBUS_LOAD_DATA_WIDTH)-1; + uint32_t startAt = top->dBus_cmd_payload_address; + uint32_t endAt = top->dBus_cmd_payload_address + (1 << top->dBus_cmd_payload_size); + uint32_t address = top->dBus_cmd_payload_address & ~(DBUS_LOAD_DATA_WIDTH/8-1); + uint8_t buffer[64]; + ws->dBusAccess(top->dBus_cmd_payload_address,0,1 << top->dBus_cmd_payload_size,buffer, &error); for(int beat = 0;beat <= beatCount;beat++){ - if(top->dBus_cmd_payload_length == 0){ - uint32_t sel = (top->dBus_cmd_payload_address >> 2) & (DBUS_DATA_WIDTH/32-1); - ws->dBusAccess(top->dBus_cmd_payload_address,0,2,0,((uint32_t*)rsp.data) + sel,&error); - } else { - for(int idx = 0;idx < DBUS_DATA_WIDTH/32;idx++){ - bool localError = false; - ws->dBusAccess(top->dBus_cmd_payload_address + beat * DBUS_DATA_WIDTH/8 + idx*4,0,2,0,((uint32_t*)rsp.data)+idx, &localError); - error |= localError; - } + for(int i = 0;i < DBUS_LOAD_DATA_WIDTH/8;i++){ + rsp.data[i] = (address >= startAt && address < endAt) ? buffer[address-top->dBus_cmd_payload_address] : VL_RANDOM_I(8); + address += 1; } rsp.last = beat == beatCount; #ifdef DBUS_EXCLUSIVE @@ -2485,7 +2449,7 @@ public: rsps.pop(); top->dBus_rsp_valid = 1; top->dBus_rsp_payload_error = rsp.error; - for(int idx = 0;idx < DBUS_DATA_WIDTH/32;idx++){ + for(int idx = 0;idx < DBUS_LOAD_DATA_WIDTH/32;idx++){ ((uint32_t*)&top->dBus_rsp_payload_data)[idx] = ((uint32_t*)rsp.data)[idx]; } top->dBus_rsp_payload_last = rsp.last; @@ -2494,7 +2458,7 @@ public: #endif } else{ top->dBus_rsp_valid = 0; - for(int idx = 0;idx < DBUS_DATA_WIDTH/32;idx++){ + for(int idx = 0;idx < DBUS_LOAD_DATA_WIDTH/32;idx++){ ((uint32_t*)&top->dBus_rsp_payload_data)[idx] = VL_RANDOM_I(32); } top->dBus_rsp_payload_error = VL_RANDOM_I(1); @@ -3092,12 +3056,13 @@ public: } - virtual void dBusAccess(uint32_t addr,bool wr, uint32_t size,uint32_t mask, uint32_t *data, bool *error) { + virtual void dBusAccess(uint32_t addr,bool wr, uint32_t size, uint8_t *dataBytes, bool *error) { if(wr && addr == 0xF00FFF2C){ + uint32_t *data = (uint32_t*)dataBytes; out32 << hex << setw(8) << std::setfill('0') << *data << dec; if(++out32Counter % 4 == 0) out32 << "\n"; } - WorkspaceRegression::dBusAccess(addr,wr,size,mask,data,error); + WorkspaceRegression::dBusAccess(addr,wr,size,dataBytes,error); } virtual void checks(){ @@ -3437,41 +3402,43 @@ public: - virtual void dBusAccess(uint32_t addr,bool wr, uint32_t size,uint32_t mask, uint32_t *data, bool *error) { - if(isPerifRegion(addr)) switch(addr){ - //TODO Emulate peripherals here - case 0xFFFFFFE0: if(wr) fail(); else *data = mTime; break; - case 0xFFFFFFE4: if(wr) fail(); else *data = mTime >> 32; break; - case 0xFFFFFFE8: if(wr) mTimeCmp = (mTimeCmp & 0xFFFFFFFF00000000) | *data; else *data = mTimeCmp; break; - case 0xFFFFFFEC: if(wr) mTimeCmp = (mTimeCmp & 0x00000000FFFFFFFF) | (((uint64_t)*data) << 32); else *data = mTimeCmp >> 32; break; - case 0xFFFFFFF8: - if(wr){ - char c = (char)*data; - cout << c; - logTraces << c; - logTraces.flush(); - onStdout(c); - } else { - #ifdef WITH_USER_IO - if(stdinNonEmpty()){ - char c; - read(0, &c, 1); - *data = c; - } else - #endif - if(!customCin.empty()){ - *data = customCin.front(); - customCin.pop(); - } else { - *data = -1; - } - } - break; - case 0xFFFFFFFC: fail(); break; //Simulation end - default: cout << "Unmapped peripheral access : addr=0x" << hex << addr << " wr=" << wr << " mask=0x" << mask << " data=0x" << data << dec << endl; fail(); break; - } + virtual void dBusAccess(uint32_t addr,bool wr, uint32_t size,uint8_t *dataBytes, bool *error) { + uint32_t *data = (uint32_t*)dataBytes; - Workspace::dBusAccess(addr,wr,size,mask,data,error); + if(isPerifRegion(addr)) { + switch(addr){ + case 0xFFFFFFE0: if(wr) fail(); else *data = mTime; break; + case 0xFFFFFFE4: if(wr) fail(); else *data = mTime >> 32; break; + case 0xFFFFFFE8: if(wr) mTimeCmp = (mTimeCmp & 0xFFFFFFFF00000000) | *data; else *data = mTimeCmp; break; + case 0xFFFFFFEC: if(wr) mTimeCmp = (mTimeCmp & 0x00000000FFFFFFFF) | (((uint64_t)*data) << 32); else *data = mTimeCmp >> 32; break; + case 0xFFFFFFF8: + if(wr){ + char c = (char)*data; + cout << c; + logTraces << c; + logTraces.flush(); + onStdout(c); + } else { + #ifdef WITH_USER_IO + if(stdinNonEmpty()){ + char c; + read(0, &c, 1); + *data = c; + } else + #endif + if(!customCin.empty()){ + *data = customCin.front(); + customCin.pop(); + } else { + *data = -1; + } + } + break; + case 0xFFFFFFFC: fail(); break; //Simulation end + default: cout << "Unmapped peripheral access : addr=0x" << hex << addr << " wr=" << wr << " mask=0x" << " data=0x" << data << dec << endl; fail(); break; + } + } + Workspace::dBusAccess(addr,wr,size,dataBytes,error); } virtual void onStdout(char c){ @@ -3541,9 +3508,9 @@ public: - virtual void dBusAccess(uint32_t addr,bool wr, uint32_t size,uint32_t mask, uint32_t *data, bool *error) { + virtual void dBusAccess(uint32_t addr,bool wr, uint32_t size,uint64_t mask, uint8_t *dataBytes, bool *error) { + uint32_t *data = (uint32_t*)dataBytes; if(isPerifRegion(addr)) switch(addr){ - //TODO Emulate peripherals here case 0xF0010000: if(wr && *data != 0) fail(); else *data = 0; break; case 0xF001BFF8: if(wr) fail(); else *data = mTime; break; case 0xF001BFFC: if(wr) fail(); else *data = mTime >> 32; break; @@ -3576,8 +3543,7 @@ public: break; default: cout << "Unmapped peripheral access : addr=0x" << hex << addr << " wr=" << wr << " mask=0x" << mask << " data=0x" << data << dec << endl; fail(); break; } - - Workspace::dBusAccess(addr,wr,size,mask,data,error); + Workspace::dBusAccess(addr,wr,size,mask,data,error); } virtual void onStdout(char c){ @@ -3891,7 +3857,7 @@ int main(int argc, char **argv, char **env) { redo(REDO,RiscvTest(name).bootAt(0x80000188u)->writeWord(0x80000184u, 0x00305073)->run();) } #endif - return 0; + //return 0; //#ifdef LITEX // LitexSoC("linux") @@ -4064,11 +4030,6 @@ int main(int argc, char **argv, char **env) { redo(REDO,RiscvTest(name).run();) } - #ifdef RVF - for(const string &name : riscvTestFloat){ - redo(REDO,RiscvTest(name).run();) - } - #endif #ifdef MUL for(const string &name : riscvTestMul){ diff --git a/src/test/cpp/regression/makefile b/src/test/cpp/regression/makefile index f63c812e..74f85f54 100644 --- a/src/test/cpp/regression/makefile +++ b/src/test/cpp/regression/makefile @@ -5,7 +5,8 @@ IBUS?=CACHED IBUS_TC?=no IBUS_DATA_WIDTH?=32 DBUS?=CACHED -DBUS_DATA_WIDTH?=32 +DBUS_LOAD_DATA_WIDTH?=32 +DBUS_STORE_DATA_WIDTH?=32 TRACE?=no TRACE_ACCESS?=no TRACE_START=0 @@ -50,7 +51,8 @@ WITH_USER_IO?=no ADDCFLAGS += -CFLAGS -DREGRESSION_PATH='\"$(REGRESSION_PATH)/\"' ADDCFLAGS += -CFLAGS -DIBUS_${IBUS} ADDCFLAGS += -CFLAGS -DIBUS_DATA_WIDTH=${IBUS_DATA_WIDTH} -ADDCFLAGS += -CFLAGS -DDBUS_DATA_WIDTH=${DBUS_DATA_WIDTH} +ADDCFLAGS += -CFLAGS -DDBUS_LOAD_DATA_WIDTH=${DBUS_LOAD_DATA_WIDTH} +ADDCFLAGS += -CFLAGS -DDBUS_STORE_DATA_WIDTH=${DBUS_STORE_DATA_WIDTH} ADDCFLAGS += -CFLAGS -DDBUS_${DBUS} ADDCFLAGS += -CFLAGS -DREDO=${REDO} @@ -197,9 +199,8 @@ ifneq ($(SEED),no) ADDCFLAGS += -CFLAGS -DSEED=${SEED} endif - ifeq ($(TRACE),yes) - VERILATOR_ARGS += --trace + VERILATOR_ARGS += --trace-fst ADDCFLAGS += -CFLAGS -DTRACE endif diff --git a/src/test/scala/vexriscv/DhrystoneBench.scala b/src/test/scala/vexriscv/DhrystoneBench.scala index a99b5d8c..a98377c5 100644 --- a/src/test/scala/vexriscv/DhrystoneBench.scala +++ b/src/test/scala/vexriscv/DhrystoneBench.scala @@ -50,100 +50,100 @@ class DhrystoneBench extends FunSuite { } -// for(withMemoryStage <- List(false, true)){ -// val stages = if(withMemoryStage) "Three" else "Two" -// getDmips( -// name = s"Gen${stages}StageArty", -// gen = SpinalVerilog(GenTwoThreeStage.cpu( -// withMulDiv = false, -// bypass = false, -// barrielShifter = false, -// withMemoryStage = withMemoryStage -// )), -// testCmd = "make clean run REDO=10 IBUS=SIMPLE DBUS=SIMPLE CSR=no MMU=no DEBUG_PLUGIN=no MUL=no DIV=no COREMARK=yes" -// ) -// getDmips( -// name = s"Gen${stages}StageBarrielArty", -// gen = SpinalVerilog(GenTwoThreeStage.cpu( -// withMulDiv = false, -// bypass = true, -// barrielShifter = true, -// withMemoryStage = withMemoryStage -// )), -// testCmd = "make clean run REDO=10 IBUS=SIMPLE DBUS=SIMPLE CSR=no MMU=no DEBUG_PLUGIN=no MUL=no DIV=no COREMARK=yes" -// ) -// getDmips( -// name = s"Gen${stages}StageMDArty", -// gen = SpinalVerilog(GenTwoThreeStage.cpu( -// withMulDiv = true, -// bypass = false, -// barrielShifter = false, -// withMemoryStage = withMemoryStage -// )), -// testCmd = "make clean run REDO=10 IBUS=SIMPLE DBUS=SIMPLE CSR=no MMU=no DEBUG_PLUGIN=no MUL=yes DIV=yes COREMARK=yes" -// ) -// getDmips( -// name = s"Gen${stages}StageMDBarrielArty", -// gen = SpinalVerilog(GenTwoThreeStage.cpu( -// withMulDiv = true, -// bypass = true, -// barrielShifter = true, -// withMemoryStage = withMemoryStage -// )), -// testCmd = "make clean run REDO=10 IBUS=SIMPLE DBUS=SIMPLE CSR=no MMU=no DEBUG_PLUGIN=no MUL=yes DIV=yes COREMARK=yes" -// ) -// } -// -// getDmips( -// name = "GenSmallestNoCsr", -// gen = GenSmallestNoCsr.main(null), -// testCmd = "make clean run REDO=10 IBUS=SIMPLE DBUS=SIMPLE CSR=no MMU=no DEBUG_PLUGIN=no MUL=no DIV=no COREMARK=yes" -// ) -// -// -// getDmips( -// name = "GenSmallest", -// gen = GenSmallest.main(null), -// testCmd = "make clean run REDO=10 IBUS=SIMPLE DBUS=SIMPLE CSR=no MMU=no DEBUG_PLUGIN=no MUL=no DIV=no COREMARK=yes" -// ) -// -// -// getDmips( -// name = "GenSmallAndProductive", -// gen = GenSmallAndProductive.main(null), -// testCmd = "make clean run REDO=10 IBUS=SIMPLE DBUS=SIMPLE CSR=no MMU=no DEBUG_PLUGIN=no MUL=no DIV=no COREMARK=yes" -// ) -// -// getDmips( -// name = "GenSmallAndProductiveWithICache", -// gen = GenSmallAndProductiveICache.main(null), -// testCmd = "make clean run REDO=10 IBUS=CACHED DBUS=SIMPLE CSR=no MMU=no DEBUG_PLUGIN=no MUL=no DIV=no COREMARK=yes" -// ) -// -// -// getDmips( -// name = "GenFullNoMmuNoCache", -// gen = GenFullNoMmuNoCache.main(null), -// testCmd = "make clean run REDO=10 IBUS=SIMPLE DBUS=SIMPLE CSR=no MMU=no COREMARK=yes" -// ) -// -// getDmips( -// name = "GenNoCacheNoMmuMaxPerf", -// gen = GenNoCacheNoMmuMaxPerf.main(null), -// testCmd = "make clean run REDO=10 MMU=no CSR=no DBUS=SIMPLE IBUS=SIMPLE COREMARK=yes" -// ) -// -// -// getDmips( -// name = "GenFullNoMmuMaxPerf", -// gen = GenFullNoMmuMaxPerf.main(null), -// testCmd = "make clean run REDO=10 MMU=no CSR=no COREMARK=yes" -// ) -// getDmips( -// name = "GenFullNoMmu", -// gen = GenFullNoMmu.main(null), -// testCmd = "make clean run REDO=10 MMU=no CSR=no COREMARK=yes" -// ) + for(withMemoryStage <- List(false, true)){ + val stages = if(withMemoryStage) "Three" else "Two" + getDmips( + name = s"Gen${stages}StageArty", + gen = SpinalVerilog(GenTwoThreeStage.cpu( + withMulDiv = false, + bypass = false, + barrielShifter = false, + withMemoryStage = withMemoryStage + )), + testCmd = "make clean run REDO=10 IBUS=SIMPLE DBUS=SIMPLE CSR=no MMU=no DEBUG_PLUGIN=no MUL=no DIV=no COREMARK=yes" + ) + getDmips( + name = s"Gen${stages}StageBarrielArty", + gen = SpinalVerilog(GenTwoThreeStage.cpu( + withMulDiv = false, + bypass = true, + barrielShifter = true, + withMemoryStage = withMemoryStage + )), + testCmd = "make clean run REDO=10 IBUS=SIMPLE DBUS=SIMPLE CSR=no MMU=no DEBUG_PLUGIN=no MUL=no DIV=no COREMARK=yes" + ) + getDmips( + name = s"Gen${stages}StageMDArty", + gen = SpinalVerilog(GenTwoThreeStage.cpu( + withMulDiv = true, + bypass = false, + barrielShifter = false, + withMemoryStage = withMemoryStage + )), + testCmd = "make clean run REDO=10 IBUS=SIMPLE DBUS=SIMPLE CSR=no MMU=no DEBUG_PLUGIN=no MUL=yes DIV=yes COREMARK=yes" + ) + getDmips( + name = s"Gen${stages}StageMDBarrielArty", + gen = SpinalVerilog(GenTwoThreeStage.cpu( + withMulDiv = true, + bypass = true, + barrielShifter = true, + withMemoryStage = withMemoryStage + )), + testCmd = "make clean run REDO=10 IBUS=SIMPLE DBUS=SIMPLE CSR=no MMU=no DEBUG_PLUGIN=no MUL=yes DIV=yes COREMARK=yes" + ) + } + + getDmips( + name = "GenSmallestNoCsr", + gen = GenSmallestNoCsr.main(null), + testCmd = "make clean run REDO=10 IBUS=SIMPLE DBUS=SIMPLE CSR=no MMU=no DEBUG_PLUGIN=no MUL=no DIV=no COREMARK=yes" + ) + + + getDmips( + name = "GenSmallest", + gen = GenSmallest.main(null), + testCmd = "make clean run REDO=10 IBUS=SIMPLE DBUS=SIMPLE CSR=no MMU=no DEBUG_PLUGIN=no MUL=no DIV=no COREMARK=yes" + ) + + + getDmips( + name = "GenSmallAndProductive", + gen = GenSmallAndProductive.main(null), + testCmd = "make clean run REDO=10 IBUS=SIMPLE DBUS=SIMPLE CSR=no MMU=no DEBUG_PLUGIN=no MUL=no DIV=no COREMARK=yes" + ) + + getDmips( + name = "GenSmallAndProductiveWithICache", + gen = GenSmallAndProductiveICache.main(null), + testCmd = "make clean run REDO=10 IBUS=CACHED DBUS=SIMPLE CSR=no MMU=no DEBUG_PLUGIN=no MUL=no DIV=no COREMARK=yes" + ) + + + getDmips( + name = "GenFullNoMmuNoCache", + gen = GenFullNoMmuNoCache.main(null), + testCmd = "make clean run REDO=10 IBUS=SIMPLE DBUS=SIMPLE CSR=no MMU=no COREMARK=yes" + ) + + getDmips( + name = "GenNoCacheNoMmuMaxPerf", + gen = GenNoCacheNoMmuMaxPerf.main(null), + testCmd = "make clean run REDO=10 MMU=no CSR=no DBUS=SIMPLE IBUS=SIMPLE COREMARK=yes" + ) + + + getDmips( + name = "GenFullNoMmuMaxPerf", + gen = GenFullNoMmuMaxPerf.main(null), + testCmd = "make clean run REDO=10 MMU=no CSR=no COREMARK=yes" + ) + getDmips( + name = "GenFullNoMmu", + gen = GenFullNoMmu.main(null), + testCmd = "make clean run REDO=10 MMU=no CSR=no COREMARK=yes" + ) getDmips( name = "GenFull", @@ -151,11 +151,11 @@ class DhrystoneBench extends FunSuite { testCmd = "make clean run REDO=10 CSR=no MMU=no COREMARK=yes" ) -// getDmips( -// name = "GenLinuxBalenced", -// gen = LinuxGen.main(Array.fill[String](0)("")), -// testCmd = "make clean run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD DHRYSTONE=yes SUPERVISOR=yes MMU=no CSR=yes CSR_SKIP_TEST=yes COMPRESSED=no MUL=yes DIV=yes LRSC=yes AMO=yes REDO=10 TRACE=no COREMARK=yes LINUX_REGRESSION=no" -// ) + getDmips( + name = "GenLinuxBalenced", + gen = LinuxGen.main(Array.fill[String](0)("")), + testCmd = "make clean run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD DHRYSTONE=yes SUPERVISOR=yes MMU=no CSR=yes CSR_SKIP_TEST=yes COMPRESSED=no MUL=yes DIV=yes LRSC=yes AMO=yes REDO=10 TRACE=no COREMARK=yes LINUX_REGRESSION=no" + ) test("final_report") { diff --git a/src/test/scala/vexriscv/TestIndividualFeatures.scala b/src/test/scala/vexriscv/TestIndividualFeatures.scala index 0cf5ce65..5e015acc 100644 --- a/src/test/scala/vexriscv/TestIndividualFeatures.scala +++ b/src/test/scala/vexriscv/TestIndividualFeatures.scala @@ -438,6 +438,8 @@ class DBusDimension extends VexRiscvDimension("DBus") { val twoStageMmu = r.nextBoolean() && !noMemory && !noWriteBack val mmuConfig = if(universes.contains(VexRiscvUniverse.MMU)) MmuPortConfig(portTlbSize = 4, latency = if(twoStageMmu) 1 else 0, earlyRequireMmuLockup = Random.nextBoolean() && twoStageMmu, earlyCacheHits = Random.nextBoolean() && twoStageMmu) else null val memDataWidth = List(32,64,128)(r.nextInt(3)) + val cpuDataWidthChoices = List(32,64,128).filter(_ <= memDataWidth) + val cpuDataWidth = cpuDataWidthChoices(r.nextInt(cpuDataWidthChoices.size)) val bytePerLine = Math.max(memDataWidth/8, List(8,16,32,64)(r.nextInt(4))) var cacheSize = 0 var wayCount = 0 @@ -455,8 +457,8 @@ class DBusDimension extends VexRiscvDimension("DBus") { cacheSize = 512 << r.nextInt(5) wayCount = 1 << r.nextInt(3) }while(cacheSize/wayCount < 512 || (catchAll && cacheSize/wayCount > 4096)) - new VexRiscvPosition(s"Cached${memDataWidth}d" + "S" + cacheSize + "W" + wayCount + "BPL" + bytePerLine + (if(dBusCmdMasterPipe) "Cmp " else "") + (if(dBusCmdSlavePipe) "Csp " else "") + (if(dBusRspSlavePipe) "Rsp " else "") + (if(relaxedMemoryTranslationRegister) "Rmtr " else "") + (if(earlyWaysHits) "Ewh " else "") + (if(withAmo) "Amo " else "") + (if(withSmp) "Smp " else "") + (if(directTlbHit) "Dtlb " else "") + (if(twoStageMmu) "Tsmmu " else "") + (if(asyncTagMemory) "Atm" else "")) { - override def testParam = s"DBUS=CACHED DBUS_DATA_WIDTH=$memDataWidth " + (if(withLrSc) "LRSC=yes " else "") + (if(withAmo) "AMO=yes " else "") + (if(withSmp) "DBUS_EXCLUSIVE=yes DBUS_INVALIDATE=yes " else "") + new VexRiscvPosition(s"Cached${memDataWidth}d${cpuDataWidth}c" + "S" + cacheSize + "W" + wayCount + "BPL" + bytePerLine + (if(dBusCmdMasterPipe) "Cmp " else "") + (if(dBusCmdSlavePipe) "Csp " else "") + (if(dBusRspSlavePipe) "Rsp " else "") + (if(relaxedMemoryTranslationRegister) "Rmtr " else "") + (if(earlyWaysHits) "Ewh " else "") + (if(withAmo) "Amo " else "") + (if(withSmp) "Smp " else "") + (if(directTlbHit) "Dtlb " else "") + (if(twoStageMmu) "Tsmmu " else "") + (if(asyncTagMemory) "Atm" else "")) { + override def testParam = s"DBUS=CACHED DBUS_LOAD_DATA_WIDTH=$memDataWidth DBUS_STORE_DATA_WIDTH=$cpuDataWidth " + (if(withLrSc) "LRSC=yes " else "") + (if(withAmo) "AMO=yes " else "") + (if(withSmp) "DBUS_EXCLUSIVE=yes DBUS_INVALIDATE=yes " else "") override def applyOn(config: VexRiscvConfig): Unit = { config.plugins += new DBusCachedPlugin( @@ -465,7 +467,8 @@ class DBusDimension extends VexRiscvDimension("DBus") { bytePerLine = bytePerLine, wayCount = wayCount, addressWidth = 32, - cpuDataWidth = 32, + rfDataWidth = 32, + cpuDataWidth = cpuDataWidth, //Not tested memDataWidth = memDataWidth, catchAccessError = catchAll, catchIllegal = catchAll, diff --git a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala index 43265f8f..112252f1 100644 --- a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala +++ b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala @@ -19,7 +19,7 @@ import scala.collection.mutable.ArrayBuffer import scala.sys.process.ProcessLogger import scala.util.Random - +//TODO Warning DataCache write aggregation will disable itself class FpuTest extends FunSuite{ val b2f = lang.Float.intBitsToFloat(_) @@ -55,7 +55,7 @@ class FpuTest extends FunSuite{ } def testP(p : FpuParameter){ - val portCount = 4 + val portCount = 1 val config = SimConfig config.allOptimisation @@ -978,32 +978,35 @@ class FpuTest extends FunSuite{ def testSgnjRaw(a : Float, b : Float): Unit ={ - val ref = b2f((f2b(a) & ~0x80000000) | f2b(b) & 0x80000000) + var ref = b2f((f2b(a) & ~0x80000000) | f2b(b) & 0x80000000) + if(a.isNaN) ref = a testBinaryOp(sgnj,a,b,ref,0, null,"sgnj") } def testSgnjnRaw(a : Float, b : Float): Unit ={ - val ref = b2f((f2b(a) & ~0x80000000) | ((f2b(b) & 0x80000000) ^ 0x80000000)) + var ref = b2f((f2b(a) & ~0x80000000) | ((f2b(b) & 0x80000000) ^ 0x80000000)) + if(a.isNaN) ref = a testBinaryOp(sgnjn,a,b,ref,0, null,"sgnjn") } def testSgnjxRaw(a : Float, b : Float): Unit ={ - val ref = b2f(f2b(a) ^ (f2b(b) & 0x80000000)) + var ref = b2f(f2b(a) ^ (f2b(b) & 0x80000000)) + if(a.isNaN) ref = a testBinaryOp(sgnjx,a,b,ref,0, null,"sgnjx") } val f64SignMask = 1l << 63 def testSgnjF64Raw(a : Double, b : Double): Unit ={ var ref = b2d((d2b(a).toLong & ~f64SignMask) | d2b(b).toLong & f64SignMask) - if(d2b(a).toLong >> 32 == -1) ref = a + if(a.isNaN) ref = a testBinaryOpF64(sgnj,a,b,ref,0, null,"sgnj") } def testSgnjnF64Raw(a : Double, b : Double): Unit ={ var ref = b2d((d2b(a).toLong & ~f64SignMask) | ((d2b(b).toLong & f64SignMask) ^ f64SignMask)) - if(d2b(a).toLong >> 32 == -1) ref = a + if(a.isNaN) ref = a testBinaryOpF64(sgnjn,a,b,ref,0, null,"sgnjn") } def testSgnjxF64Raw(a : Double, b : Double): Unit ={ var ref = b2d(d2b(a).toLong ^ (d2b(b).toLong & f64SignMask)) - if(d2b(a).toLong >> 32 == -1) ref = a + if(a.isNaN) ref = a testBinaryOpF64(sgnjx,a,b,ref,0, null,"sgnjx") } @@ -1277,6 +1280,17 @@ class FpuTest extends FunSuite{ //TODO test boxing //TODO double <-> simple convertions if(p.withDouble) { + + for(_ <- 0 until 10000) testSgnjF64() + println("f64 sgnj done") + + for(_ <- 0 until 10000) testSgnjF32() + println("f32 sgnj done") + + //380000000001ffef 5fffffffffff9ff 8000000000100000 +// testBinaryOpF64(mul,-5.877471754282472E-39, 8.814425663400984E-280, -5.180654E-318 ,1, FpuRoundMode.RMM,"mul") +// 5.877471754282472E-39 8.814425663400984E-280 -5.180654E-318 RMM + for(_ <- 0 until 10000) testCvtF64F32() // 1 did not equal 3 Flag missmatch dut=1 ref=3 testCvtF64F32Raw 1.1754942807573643E-38 1.17549435E-38 RMM println("FCVT_D_S done") for(_ <- 0 until 10000) testCvtF32F64() @@ -1288,8 +1302,6 @@ class FpuTest extends FunSuite{ println("f64 f2ui done") - for(_ <- 0 until 10000) testSgnjF64() - println("f64 sgnj done") @@ -1481,7 +1493,7 @@ class FpuTest extends FunSuite{ // dut.clockDomain.waitSampling(1000) // simSuccess() - for(i <- 0 until 10000) fxxTests.randomPick()() + for(i <- 0 until 100000) fxxTests.randomPick()() waitUntil(cpu.rspQueue.isEmpty) } From 06b7a91de4b288345d9be82324975c19a6ea1136 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 17 Feb 2021 11:35:17 +0100 Subject: [PATCH 589/951] MulPlugin fix buffer interraction with partial regfile bypass --- .../vexriscv/plugin/HazardSimplePlugin.scala | 113 +++++++++--------- .../scala/vexriscv/plugin/MulPlugin.scala | 7 +- 2 files changed, 61 insertions(+), 59 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/HazardSimplePlugin.scala b/src/main/scala/vexriscv/plugin/HazardSimplePlugin.scala index 1ed1d83e..1b650e3f 100644 --- a/src/main/scala/vexriscv/plugin/HazardSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/HazardSimplePlugin.scala @@ -31,29 +31,62 @@ class HazardSimplePlugin(bypassExecute : Boolean = false, override def build(pipeline: VexRiscv): Unit = { import pipeline._ import pipeline.config._ - val src0Hazard = False - val src1Hazard = False - val readStage = service(classOf[RegFileService]).readStage() + pipeline plug new Area { + val src0Hazard = False + val src1Hazard = False - def trackHazardWithStage(stage : Stage,bypassable : Boolean, runtimeBypassable : Stageable[Bool]): Unit ={ - val runtimeBypassableValue = if(runtimeBypassable != null) stage.input(runtimeBypassable) else True - val addr0Match = if(pessimisticAddressMatch) True else stage.input(INSTRUCTION)(rdRange) === readStage.input(INSTRUCTION)(rs1Range) - val addr1Match = if(pessimisticAddressMatch) True else stage.input(INSTRUCTION)(rdRange) === readStage.input(INSTRUCTION)(rs2Range) - when(stage.arbitration.isValid && stage.input(REGFILE_WRITE_VALID)) { - if (bypassable) { - when(runtimeBypassableValue) { + val readStage = service(classOf[RegFileService]).readStage() + + def trackHazardWithStage(stage: Stage, bypassable: Boolean, runtimeBypassable: Stageable[Bool]): Unit = { + val runtimeBypassableValue = if (runtimeBypassable != null) stage.input(runtimeBypassable) else True + val addr0Match = if (pessimisticAddressMatch) True else stage.input(INSTRUCTION)(rdRange) === readStage.input(INSTRUCTION)(rs1Range) + val addr1Match = if (pessimisticAddressMatch) True else stage.input(INSTRUCTION)(rdRange) === readStage.input(INSTRUCTION)(rs2Range) + when(stage.arbitration.isValid && stage.input(REGFILE_WRITE_VALID)) { + if (bypassable) { + when(runtimeBypassableValue) { + when(addr0Match) { + readStage.input(RS1) := stage.output(REGFILE_WRITE_DATA) + } + when(addr1Match) { + readStage.input(RS2) := stage.output(REGFILE_WRITE_DATA) + } + } + } + } + when(stage.arbitration.isValid && (if (pessimisticWriteRegFile) True else stage.input(REGFILE_WRITE_VALID))) { + when((Bool(!bypassable) || !runtimeBypassableValue)) { when(addr0Match) { - readStage.input(RS1) := stage.output(REGFILE_WRITE_DATA) + src0Hazard := True } when(addr1Match) { - readStage.input(RS2) := stage.output(REGFILE_WRITE_DATA) + src1Hazard := True } } } } - when(stage.arbitration.isValid && (if(pessimisticWriteRegFile) True else stage.input(REGFILE_WRITE_VALID))) { - when((Bool(!bypassable) || !runtimeBypassableValue)) { + + + val writeBackWrites = Flow(cloneable(new Bundle { + val address = Bits(5 bits) + val data = Bits(32 bits) + })) + writeBackWrites.valid := stages.last.output(REGFILE_WRITE_VALID) && stages.last.arbitration.isFiring + writeBackWrites.address := stages.last.output(INSTRUCTION)(rdRange) + writeBackWrites.data := stages.last.output(REGFILE_WRITE_DATA) + val writeBackBuffer = writeBackWrites.stage() + + val addr0Match = if (pessimisticAddressMatch) True else writeBackBuffer.address === readStage.input(INSTRUCTION)(rs1Range) + val addr1Match = if (pessimisticAddressMatch) True else writeBackBuffer.address === readStage.input(INSTRUCTION)(rs2Range) + when(writeBackBuffer.valid) { + if (bypassWriteBackBuffer) { + when(addr0Match) { + readStage.input(RS1) := writeBackBuffer.data + } + when(addr1Match) { + readStage.input(RS2) := writeBackBuffer.data + } + } else { when(addr0Match) { src0Hazard := True } @@ -62,54 +95,24 @@ class HazardSimplePlugin(bypassExecute : Boolean = false, } } } - } + + if (withWriteBackStage) trackHazardWithStage(writeBack, bypassWriteBack, null) + if (withMemoryStage) trackHazardWithStage(memory, bypassMemory, if (stages.last == memory) null else BYPASSABLE_MEMORY_STAGE) + if (readStage != execute) trackHazardWithStage(execute, bypassExecute, if (stages.last == execute) null else BYPASSABLE_EXECUTE_STAGE) - val writeBackWrites = Flow(cloneable(new Bundle{ - val address = Bits(5 bits) - val data = Bits(32 bits) - })) - writeBackWrites.valid := stages.last.output(REGFILE_WRITE_VALID) && stages.last.arbitration.isFiring - writeBackWrites.address := stages.last.output(INSTRUCTION)(rdRange) - writeBackWrites.data := stages.last.output(REGFILE_WRITE_DATA) - val writeBackBuffer = writeBackWrites.stage() - - val addr0Match = if(pessimisticAddressMatch) True else writeBackBuffer.address === readStage.input(INSTRUCTION)(rs1Range) - val addr1Match = if(pessimisticAddressMatch) True else writeBackBuffer.address === readStage.input(INSTRUCTION)(rs2Range) - when(writeBackBuffer.valid) { - if (bypassWriteBackBuffer) { - when(addr0Match) { - readStage.input(RS1) := writeBackBuffer.data + if (!pessimisticUseSrc) { + when(!readStage.input(RS1_USE)) { + src0Hazard := False } - when(addr1Match) { - readStage.input(RS2) := writeBackBuffer.data - } - } else { - when(addr0Match) { - src0Hazard := True - } - when(addr1Match) { - src1Hazard := True + when(!readStage.input(RS2_USE)) { + src1Hazard := False } } - } - if(withWriteBackStage) trackHazardWithStage(writeBack,bypassWriteBack,null) - if(withMemoryStage) trackHazardWithStage(memory ,bypassMemory, if(stages.last == memory) null else BYPASSABLE_MEMORY_STAGE) - if(readStage != execute) trackHazardWithStage(execute ,bypassExecute , if(stages.last == execute) null else BYPASSABLE_EXECUTE_STAGE) - - - if(!pessimisticUseSrc) { - when(!readStage.input(RS1_USE)) { - src0Hazard := False + when(readStage.arbitration.isValid && (src0Hazard || src1Hazard)) { + readStage.arbitration.haltByOther := True } - when(!readStage.input(RS2_USE)) { - src1Hazard := False - } - } - - when(readStage.arbitration.isValid && (src0Hazard || src1Hazard)){ - readStage.arbitration.haltByOther := True } } } diff --git a/src/main/scala/vexriscv/plugin/MulPlugin.scala b/src/main/scala/vexriscv/plugin/MulPlugin.scala index c1619d2b..997857bd 100644 --- a/src/main/scala/vexriscv/plugin/MulPlugin.scala +++ b/src/main/scala/vexriscv/plugin/MulPlugin.scala @@ -61,10 +61,9 @@ class MulPlugin(var inputBuffer : Boolean = false, when(arbitration.isValid && input(IS_MUL) && counter =/= delay){ arbitration.haltItself := True } - when(!arbitration.isStuckByOthers){ - counter := counter + 1 - } - when(!arbitration.isStuck){ + + counter := counter + 1 + when(!arbitration.isStuck || arbitration.isStuckByOthers){ counter := 0 } } From 1e647f799c87f3cfe44ec32cefa245d03abac760 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 17 Feb 2021 12:33:27 +0100 Subject: [PATCH 590/951] fpu Fix VexRiscv integration and add software f64 tests (pass) --- .gitignore | 1 + src/main/scala/vexriscv/Riscv.scala | 51 +- src/main/scala/vexriscv/TestsWorkspace.scala | 3 +- .../demo/smp/VexRiscvSmpCluster.scala | 6 +- src/main/scala/vexriscv/ip/DataCache.scala | 3 - src/main/scala/vexriscv/ip/fpu/FpuCore.scala | 6 + .../vexriscv/plugin/DBusCachedPlugin.scala | 45 +- .../scala/vexriscv/plugin/FpuPlugin.scala | 15 +- src/test/cpp/fpu/math/.gitignore | 2 + src/test/cpp/regression/main.cpp | 19 + src/test/cpp/regression/makefile | 6 + src/test/resources/asm/rv32ud-p-fadd.dump | 506 +++++++++++ src/test/resources/asm/rv32ud-p-fclass.dump | 305 +++++++ src/test/resources/asm/rv32ud-p-fcmp.dump | 640 ++++++++++++++ src/test/resources/asm/rv32ud-p-fcvt.dump | 346 ++++++++ src/test/resources/asm/rv32ud-p-fcvt_w.dump | 632 ++++++++++++++ src/test/resources/asm/rv32ud-p-fdiv.dump | 435 ++++++++++ src/test/resources/asm/rv32ud-p-fmadd.dump | 583 +++++++++++++ src/test/resources/asm/rv32ud-p-fmin.dump | 820 ++++++++++++++++++ src/test/resources/asm/rv32ud-p-ldst.dump | 267 ++++++ src/test/resources/asm/rv32ud-p-recoding.dump | 190 ++++ src/test/resources/hex/rv32ud-p-fadd.hex | 101 +++ src/test/resources/hex/rv32ud-p-fclass.hex | 62 ++ src/test/resources/hex/rv32ud-p-fcmp.hex | 123 +++ src/test/resources/hex/rv32ud-p-fcvt.hex | 72 ++ src/test/resources/hex/rv32ud-p-fcvt_w.hex | 120 +++ src/test/resources/hex/rv32ud-p-fdiv.hex | 89 ++ src/test/resources/hex/rv32ud-p-fmadd.hex | 113 +++ src/test/resources/hex/rv32ud-p-fmin.hex | 153 ++++ src/test/resources/hex/rv32ud-p-ldst.hex | 58 ++ src/test/resources/hex/rv32ud-p-recoding.hex | 46 + .../vexriscv/TestIndividualFeatures.scala | 1 - src/test/scala/vexriscv/ip/fpu/FpuTest.scala | 130 +-- 33 files changed, 5827 insertions(+), 122 deletions(-) create mode 100644 src/test/cpp/fpu/math/.gitignore create mode 100644 src/test/resources/asm/rv32ud-p-fadd.dump create mode 100644 src/test/resources/asm/rv32ud-p-fclass.dump create mode 100644 src/test/resources/asm/rv32ud-p-fcmp.dump create mode 100644 src/test/resources/asm/rv32ud-p-fcvt.dump create mode 100644 src/test/resources/asm/rv32ud-p-fcvt_w.dump create mode 100644 src/test/resources/asm/rv32ud-p-fdiv.dump create mode 100644 src/test/resources/asm/rv32ud-p-fmadd.dump create mode 100644 src/test/resources/asm/rv32ud-p-fmin.dump create mode 100644 src/test/resources/asm/rv32ud-p-ldst.dump create mode 100644 src/test/resources/asm/rv32ud-p-recoding.dump create mode 100755 src/test/resources/hex/rv32ud-p-fadd.hex create mode 100755 src/test/resources/hex/rv32ud-p-fclass.hex create mode 100755 src/test/resources/hex/rv32ud-p-fcmp.hex create mode 100755 src/test/resources/hex/rv32ud-p-fcvt.hex create mode 100755 src/test/resources/hex/rv32ud-p-fcvt_w.hex create mode 100755 src/test/resources/hex/rv32ud-p-fdiv.hex create mode 100755 src/test/resources/hex/rv32ud-p-fmadd.hex create mode 100755 src/test/resources/hex/rv32ud-p-fmin.hex create mode 100755 src/test/resources/hex/rv32ud-p-ldst.hex create mode 100755 src/test/resources/hex/rv32ud-p-recoding.hex diff --git a/.gitignore b/.gitignore index c4dcdfe5..239d9b71 100644 --- a/.gitignore +++ b/.gitignore @@ -35,6 +35,7 @@ bin/ *.cf *.json *.vcd +*.fst* !tester/src/test/resources/*.vhd obj_dir *.logTrace diff --git a/src/main/scala/vexriscv/Riscv.scala b/src/main/scala/vexriscv/Riscv.scala index 99683a84..9fbbf5b0 100644 --- a/src/main/scala/vexriscv/Riscv.scala +++ b/src/main/scala/vexriscv/Riscv.scala @@ -120,6 +120,7 @@ object Riscv{ def FENCE_I = M"-----------------001-----0001111" def SFENCE_VMA = M"0001001----------000000001110011" + def FMV_W_X = M"111100000000-----000-----1010011" def FADD_S = M"0000000------------------1010011" def FSUB_S = M"0000100------------------1010011" def FMUL_S = M"0001000------------------1010011" @@ -130,6 +131,23 @@ object Riscv{ def FMIN_S = M"0010100----------000-----1010011" def FMAX_S = M"0010100----------001-----1010011" def FSQRT_S = M"010110000000-------------1010011" + def FCVT_S_W = M"110100000000-------------1010011" + def FCVT_S_WU = M"110100000001-------------1010011" + def FCVT_S_L = M"110100000010-------------1010011" + def FCVT_S_LU = M"110100000011-------------1010011" + def FCVT_W_S = M"110000000000-------------1010011" + def FCVT_WU_S = M"110000000001-------------1010011" + def FCVT_L_S = M"110000000010-------------1010011" + def FCVT_LU_S = M"110000000011-------------1010011" + def FCLASS_S = M"111000000000-----001-----1010011" + def FMADD_S = M"-----00------------------1000011" + def FMSUB_S = M"-----00------------------1000111" + def FNMSUB_S = M"-----00------------------1001011" + def FNMADD_S = M"-----00------------------1001111" + + def FLE_S = M"1010000----------000-----1010011" + def FLT_S = M"1010000----------001-----1010011" + def FEQ_S = M"1010000----------010-----1010011" def FADD_D = M"0000001------------------1010011" def FSUB_D = M"0000101------------------1010011" def FMUL_D = M"0001001------------------1010011" @@ -139,50 +157,37 @@ object Riscv{ def FSGNJX_D = M"0010001----------010-----1010011" def FMIN_D = M"0010101----------000-----1010011" def FMAX_D = M"0010101----------001-----1010011" - def FCVT_S_D = M"010000000001-------------1010011" - def FCVT_D_S = M"010000100000-------------1010011" def FSQRT_D = M"010110100000-------------1010011" - def FCVT_W_S = M"110000000000-------------1010011" - def FCVT_WU_S = M"110000000001-------------1010011" - def FCVT_L_S = M"110000000010-------------1010011" - def FCVT_LU_S = M"110000000011-------------1010011" def FMV_X_W = M"111000000000-----000-----1010011" - def FCLASS_S = M"111000000000-----001-----1010011" def FCVT_W_D = M"110000100000-------------1010011" def FCVT_WU_D = M"110000100001-------------1010011" def FCVT_L_D = M"110000100010-------------1010011" def FCVT_LU_D = M"110000100011-------------1010011" def FMV_X_D = M"111000100000-----000-----1010011" def FCLASS_D = M"111000100000-----001-----1010011" - def FCVT_S_W = M"110100000000-------------1010011" - def FCVT_S_WU = M"110100000001-------------1010011" - def FCVT_S_L = M"110100000010-------------1010011" - def FCVT_S_LU = M"110100000011-------------1010011" - def FMV_W_X = M"111100000000-----000-----1010011" def FCVT_D_W = M"110100100000-------------1010011" def FCVT_D_WU = M"110100100001-------------1010011" def FCVT_D_L = M"110100100010-------------1010011" def FCVT_D_LU = M"110100100011-------------1010011" def FMV_D_X = M"111100100000-----000-----1010011" - def FLW = M"-----------------010-----0000111" - def FLD = M"-----------------011-----0000111" - def FSW = M"-----------------010-----0100111" - def FSD = M"-----------------011-----0100111" - def FMADD_S = M"-----00------------------1000011" - def FMSUB_S = M"-----00------------------1000111" - def FNMSUB_S = M"-----00------------------1001011" - def FNMADD_S = M"-----00------------------1001111" def FMADD_D = M"-----01------------------1000011" def FMSUB_D = M"-----01------------------1000111" def FNMSUB_D = M"-----01------------------1001011" def FNMADD_D = M"-----01------------------1001111" - def FLE_S = M"1010000----------000-----1010011" - def FLT_S = M"1010000----------001-----1010011" - def FEQ_S = M"1010000----------010-----1010011" def FLE_D = M"1010001----------000-----1010011" def FLT_D = M"1010001----------001-----1010011" def FEQ_D = M"1010001----------010-----1010011" + def FCVT_S_D = M"010000000001-------------1010011" + def FCVT_D_S = M"010000100000-------------1010011" + + def FLW = M"-----------------010-----0000111" + def FLD = M"-----------------011-----0000111" + def FSW = M"-----------------010-----0100111" + def FSD = M"-----------------011-----0100111" + + + object CSR{ def MVENDORID = 0xF11 // MRO Vendor ID. def MARCHID = 0xF12 // MRO Architecture ID. diff --git a/src/main/scala/vexriscv/TestsWorkspace.scala b/src/main/scala/vexriscv/TestsWorkspace.scala index 01540367..ac07cb88 100644 --- a/src/main/scala/vexriscv/TestsWorkspace.scala +++ b/src/main/scala/vexriscv/TestsWorkspace.scala @@ -61,7 +61,6 @@ object TestsWorkspace { bytePerLine = 32, wayCount = 1, addressWidth = 32, - rfDataWidth = 32, cpuDataWidth = 64, memDataWidth = 64, catchAccessError = true, @@ -112,7 +111,7 @@ object TestsWorkspace { config.plugins += new FpuPlugin( externalFpu = false, p = FpuParameter( - withDouble = false + withDouble = true ) ) val toplevel = new VexRiscv(config) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index e01bd87c..d3da4b3f 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -153,6 +153,7 @@ object VexRiscvSmpClusterGen { resetVector : Long = 0x80000000l, iBusWidth : Int = 128, dBusWidth : Int = 64, + loadStoreWidth : Int = 32, coherency : Boolean = true, iCacheSize : Int = 8192, dCacheSize : Int = 8192, @@ -213,7 +214,7 @@ object VexRiscvSmpClusterGen { bytePerLine = 64, wayCount = dCacheWays, addressWidth = 32, - cpuDataWidth = 32, + cpuDataWidth = loadStoreWidth, memDataWidth = dBusWidth, catchAccessError = true, catchIllegal = true, @@ -222,8 +223,7 @@ object VexRiscvSmpClusterGen { withAmo = true, withExclusive = coherency, withInvalidate = coherency, - aggregationWidth = if(dBusWidth == 32) 0 else log2Up(dBusWidth/8) - // ) + withWriteAggregation = dBusWidth > 32 ), memoryTranslatorPortConfig = MmuPortConfig( portTlbSize = 4, diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index 1f766523..4fbcdeb2 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -322,12 +322,10 @@ case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave rsp.data := mm.readData rsp.error := mm.response =/= AvalonMM.Response.OKAY - assert(p.cpuDataWidth == p.rfDataWidth) mm } def toWishbone(): Wishbone = { - assert(p.cpuDataWidth == p.rfDataWidth) val wishboneConfig = p.getWishboneConfig() val bus = Wishbone(wishboneConfig) val counter = Reg(UInt(log2Up(p.burstSize) bits)) init(0) @@ -373,7 +371,6 @@ case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave def toPipelinedMemoryBus(): PipelinedMemoryBus = { val bus = PipelinedMemoryBus(32,32) - assert(p.cpuDataWidth == p.rfDataWidth) val counter = Reg(UInt(log2Up(p.burstSize) bits)) init(0) when(bus.cmd.fire){ counter := counter + 1 } diff --git a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala index df953f32..1448d89d 100644 --- a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala +++ b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala @@ -1393,6 +1393,12 @@ object FpuSynthesisBench extends App{ }) } +//Fpu_32 -> +//Artix 7 -> 46 Mhz 1786 LUT 628 FF +//Artix 7 -> 47 Mhz 1901 LUT 628 FF +//Fpu_64 -> +//Artix 7 -> 37 Mhz 3407 LUT 1006 FF +//Artix 7 -> 36 Mhz 3564 LUT 1006 FF val rtls = ArrayBuffer[Rtl]() rtls += new Fpu( diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index 20145714..df501378 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -96,7 +96,8 @@ class DBusCachedPlugin(val config : DataCacheConfig, val bypassStoreList = ArrayBuffer[(Bool, Bits)]() override def bypassStore(data: Bits): Unit = { - bypassStoreList += ConditionalContext.isTrue() -> data + val prefix = s"DBusBypass${bypassStoreList.size}" + bypassStoreList += ConditionalContext.isTrue().setName(prefix + "_cond") -> CombInit(data).setName(prefix + "_value") } @@ -105,14 +106,13 @@ 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_ADDRESS_LOW extends Stageable(UInt(2 bits)) object MEMORY_LRSC extends Stageable(Bool) object MEMORY_AMO extends Stageable(Bool) object MEMORY_FENCE extends Stageable(Bool) object MEMORY_FORCE_CONSTISTENCY extends Stageable(Bool) object IS_DBUS_SHARING extends Stageable(Bool()) object MEMORY_VIRTUAL_ADDRESS extends Stageable(UInt(32 bits)) - object MEMORY_STORE_DATA_RF extends Stageable(Bits(config.rfDataWidth bits)) + object MEMORY_STORE_DATA_RF extends Stageable(Bits(32 bits)) // object MEMORY_STORE_DATA_CPU extends Stageable(Bits(config.cpuDataWidth bits)) object MEMORY_LOAD_DATA extends Stageable(Bits(config.cpuDataWidth bits)) @@ -239,7 +239,8 @@ class DBusCachedPlugin(val config : DataCacheConfig, val cache = new DataCache( this.config.copy( - mergeExecuteMemory = writeBack == null + mergeExecuteMemory = writeBack == null, + rfDataWidth = 32 ), mmuParameter = mmuBus.p ) @@ -335,7 +336,6 @@ class DBusCachedPlugin(val config : DataCacheConfig, cache.io.cpu.execute.amoCtrl.swap := input(INSTRUCTION)(27) } - insert(MEMORY_ADDRESS_LOW) := cache.io.cpu.execute.address(1 downto 0) when(cache.io.cpu.execute.refilling && arbitration.isValid){ arbitration.haltByOther := True @@ -375,9 +375,9 @@ class DBusCachedPlugin(val config : DataCacheConfig, cache.io.cpu.writeBack.isUser := (if(privilegeService != null) privilegeService.isUser() else False) cache.io.cpu.writeBack.address := U(input(REGFILE_WRITE_DATA)) cache.io.cpu.writeBack.storeData.subdivideIn(32 bits).foreach(_ := input(MEMORY_STORE_DATA_RF)) - for((cond, value) <- bypassStoreList) when(cond){ - cache.io.cpu.writeBack.storeData := value - } + afterElaboration(for((cond, value) <- bypassStoreList) when(cond){ + cache.io.cpu.writeBack.storeData.subdivideIn(widthOf(value) bits).foreach(_ := value) //Not optimal, but ok + }) val fence = if(withInvalidate) new Area { cache.io.cpu.writeBack.fence := input(INSTRUCTION)(31 downto 20).as(FenceFlags()) @@ -438,28 +438,35 @@ class DBusCachedPlugin(val config : DataCacheConfig, arbitration.haltItself.setWhen(cache.io.cpu.writeBack.isValid && cache.io.cpu.writeBack.haltIt) - val rspRf = cache.io.cpu.writeBack.data.subdivideIn(32 bits).read(cache.io.cpu.writeBack.address(cache.cpuWordToRfWordRange)) - val rspShifted = CombInit(rspRf) - switch(input(MEMORY_ADDRESS_LOW)){ - is(1){rspShifted(7 downto 0) := rspRf(15 downto 8)} - is(2){rspShifted(15 downto 0) := rspRf(31 downto 16)} - is(3){rspShifted(7 downto 0) := rspRf(31 downto 24)} + val rspSplits = cache.io.cpu.writeBack.data.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){ + val srcSize = 1 << (log2Up(cpuDataBytes) - log2Up(i+1)) + val srcZipped = rspSplits.zipWithIndex.filter{case (v, b) => b % (cpuDataBytes/srcSize) == i} + val src = srcZipped.map(_._1) + val range = cache.cpuWordToRfWordRange.high downto cache.cpuWordToRfWordRange.high+1-log2Up(srcSize) + val sel = cache.io.cpu.writeBack.address(range) +// println(s"$i $srcSize $range ${srcZipped.map(_._2).mkString(",")}") + rspShifted(i*8, 8 bits) := src.read(sel) } + + val rspRf = CombInit(rspShifted(31 downto 0)) if(withLrSc) when(input(MEMORY_LRSC) && input(MEMORY_WR)){ - rspShifted := B(!cache.io.cpu.writeBack.exclusiveOk).resized + rspRf := B(!cache.io.cpu.writeBack.exclusiveOk).resized } val rspFormated = input(INSTRUCTION)(13 downto 12).mux( - 0 -> B((31 downto 8) -> (rspShifted(7) && !input(INSTRUCTION)(14)),(7 downto 0) -> rspShifted(7 downto 0)), - 1 -> B((31 downto 16) -> (rspShifted(15) && ! input(INSTRUCTION)(14)),(15 downto 0) -> rspShifted(15 downto 0)), - default -> rspShifted //W + 0 -> B((31 downto 8) -> (rspRf(7) && !input(INSTRUCTION)(14)),(7 downto 0) -> rspRf(7 downto 0)), + 1 -> B((31 downto 16) -> (rspRf(15) && ! input(INSTRUCTION)(14)),(15 downto 0) -> rspRf(15 downto 0)), + default -> rspRf //W ) when(arbitration.isValid && input(MEMORY_ENABLE)) { output(REGFILE_WRITE_DATA) := rspFormated } - insert(MEMORY_LOAD_DATA) := cache.io.cpu.writeBack.data + insert(MEMORY_LOAD_DATA) := rspShifted } //Share access to the dBus (used by self refilled MMU) diff --git a/src/main/scala/vexriscv/plugin/FpuPlugin.scala b/src/main/scala/vexriscv/plugin/FpuPlugin.scala index a7454ea7..88f3481e 100644 --- a/src/main/scala/vexriscv/plugin/FpuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/FpuPlugin.scala @@ -119,10 +119,10 @@ class FpuPlugin(externalFpu : Boolean = false, FMUL_D -> (mul :+ f64 :+ arg(0)), FDIV_D -> (div :+ f64 ), FSQRT_D -> (sqrt :+ f64 ), - FLW -> (fl :+ f64 ), - FSW -> (fs :+ f64 ), - FCVT_S_WU -> (fcvtI2f :+ f64 :+ arg(0)), - FCVT_S_W -> (fcvtI2f :+ f64 :+ arg(1)), + FLD -> (fl :+ f64 ), + FSD -> (fs :+ f64 ), + FCVT_D_WU -> (fcvtI2f :+ f64 :+ arg(0)), + FCVT_D_W -> (fcvtI2f :+ f64 :+ arg(1)), FCVT_WU_D -> (fcvtF2i :+ f64 :+ arg(0)), FCVT_W_D -> (fcvtF2i :+ f64 :+ arg(1)), FCLASS_D -> (fclass :+ f64 ), @@ -233,12 +233,15 @@ class FpuPlugin(externalFpu : Boolean = false, val dBusEncoding = pipeline.service(classOf[DBusEncodingService]) val isRsp = input(FPU_FORKED) && input(FPU_RSP) val isCommit = input(FPU_FORKED) && input(FPU_COMMIT) - + val storeFormated = CombInit(port.rsp.value) + if(p.withDouble) when(!input(INSTRUCTION)(12)){ + storeFormated(32, 32 bits) := port.rsp.value(0, 32 bits) + } //Manage $store and port.rsp port.rsp.ready := False when(isRsp){ when(arbitration.isValid) { - dBusEncoding.bypassStore(port.rsp.value) + dBusEncoding.bypassStore(storeFormated) output(REGFILE_WRITE_DATA) := port.rsp.value(31 downto 0) } when(!port.rsp.valid){ diff --git a/src/test/cpp/fpu/math/.gitignore b/src/test/cpp/fpu/math/.gitignore new file mode 100644 index 00000000..56d9c77a --- /dev/null +++ b/src/test/cpp/fpu/math/.gitignore @@ -0,0 +1,2 @@ +*.so +*.a diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 6f1dcff1..4d500190 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -3611,6 +3611,20 @@ string riscvTestFloat[] = { }; +string riscvTestDouble[] = { + "rv32ud-p-fadd", + "rv32ud-p-fcvt", + "rv32ud-p-fmadd", + "rv32ud-p-recoding", + "rv32ud-p-fclass", + "rv32ud-p-fcvt_w", + "rv32ud-p-fmin", + "rv32ud-p-fcmp", + "rv32ud-p-fdiv", + "rv32ud-p-ldst" +}; + + string riscvTestMul[] = { @@ -3857,6 +3871,11 @@ int main(int argc, char **argv, char **env) { redo(REDO,RiscvTest(name).bootAt(0x80000188u)->writeWord(0x80000184u, 0x00305073)->run();) } #endif + #ifdef RVD + for(const string &name : riscvTestDouble){ + redo(REDO,RiscvTest(name).bootAt(0x80000188u)->writeWord(0x80000184u, 0x00305073)->run();) + } + #endif //return 0; //#ifdef LITEX diff --git a/src/test/cpp/regression/makefile b/src/test/cpp/regression/makefile index 74f85f54..19bee06a 100644 --- a/src/test/cpp/regression/makefile +++ b/src/test/cpp/regression/makefile @@ -14,6 +14,8 @@ TRACE_SPORADIC?=no ISA_TEST?=yes MUL?=yes DIV?=yes +RVF?=no +RVD?=no CSR?=yes CSR_SKIP_TEST?=no EBREAK?=no @@ -270,6 +272,10 @@ ifeq ($(RVF),yes) ADDCFLAGS += -CFLAGS -DRVF endif +ifeq ($(RVD),yes) + ADDCFLAGS += -CFLAGS -DRVD +endif + ifeq ($(DIV),yes) ADDCFLAGS += -CFLAGS -DDIV endif diff --git a/src/test/resources/asm/rv32ud-p-fadd.dump b/src/test/resources/asm/rv32ud-p-fadd.dump new file mode 100644 index 00000000..0155a03d --- /dev/null +++ b/src/test/resources/asm/rv32ud-p-fadd.dump @@ -0,0 +1,506 @@ + +rv32ud-p-fadd: file format elf32-littleriscv + + +Disassembly of section .text.init: + +80000000 <_start>: +80000000: 04c0006f j 8000004c + +80000004 : +80000004: 34202f73 csrr t5,mcause +80000008: 00800f93 li t6,8 +8000000c: 03ff0a63 beq t5,t6,80000040 +80000010: 00900f93 li t6,9 +80000014: 03ff0663 beq t5,t6,80000040 +80000018: 00b00f93 li t6,11 +8000001c: 03ff0263 beq t5,t6,80000040 +80000020: 80000f17 auipc t5,0x80000 +80000024: fe0f0f13 addi t5,t5,-32 # 0 <_start-0x80000000> +80000028: 000f0463 beqz t5,80000030 +8000002c: 000f0067 jr t5 +80000030: 34202f73 csrr t5,mcause +80000034: 000f5463 bgez t5,8000003c +80000038: 0040006f j 8000003c + +8000003c : +8000003c: 5391e193 ori gp,gp,1337 + +80000040 : +80000040: 00001f17 auipc t5,0x1 +80000044: fc3f2023 sw gp,-64(t5) # 80001000 +80000048: ff9ff06f j 80000040 + +8000004c : +8000004c: 00000093 li ra,0 +80000050: 00000113 li sp,0 +80000054: 00000193 li gp,0 +80000058: 00000213 li tp,0 +8000005c: 00000293 li t0,0 +80000060: 00000313 li t1,0 +80000064: 00000393 li t2,0 +80000068: 00000413 li s0,0 +8000006c: 00000493 li s1,0 +80000070: 00000513 li a0,0 +80000074: 00000593 li a1,0 +80000078: 00000613 li a2,0 +8000007c: 00000693 li a3,0 +80000080: 00000713 li a4,0 +80000084: 00000793 li a5,0 +80000088: 00000813 li a6,0 +8000008c: 00000893 li a7,0 +80000090: 00000913 li s2,0 +80000094: 00000993 li s3,0 +80000098: 00000a13 li s4,0 +8000009c: 00000a93 li s5,0 +800000a0: 00000b13 li s6,0 +800000a4: 00000b93 li s7,0 +800000a8: 00000c13 li s8,0 +800000ac: 00000c93 li s9,0 +800000b0: 00000d13 li s10,0 +800000b4: 00000d93 li s11,0 +800000b8: 00000e13 li t3,0 +800000bc: 00000e93 li t4,0 +800000c0: 00000f13 li t5,0 +800000c4: 00000f93 li t6,0 +800000c8: f1402573 csrr a0,mhartid +800000cc: 00051063 bnez a0,800000cc +800000d0: 00000297 auipc t0,0x0 +800000d4: 01028293 addi t0,t0,16 # 800000e0 +800000d8: 30529073 csrw mtvec,t0 +800000dc: 18005073 csrwi satp,0 +800000e0: 00000297 auipc t0,0x0 +800000e4: 02028293 addi t0,t0,32 # 80000100 +800000e8: 30529073 csrw mtvec,t0 +800000ec: 800002b7 lui t0,0x80000 +800000f0: fff28293 addi t0,t0,-1 # 7fffffff <_end+0xffffdebf> +800000f4: 3b029073 csrw pmpaddr0,t0 +800000f8: 01f00293 li t0,31 +800000fc: 3a029073 csrw pmpcfg0,t0 +80000100: 30405073 csrwi mie,0 +80000104: 00000297 auipc t0,0x0 +80000108: 01428293 addi t0,t0,20 # 80000118 +8000010c: 30529073 csrw mtvec,t0 +80000110: 30205073 csrwi medeleg,0 +80000114: 30305073 csrwi mideleg,0 +80000118: 00000193 li gp,0 +8000011c: 00000297 auipc t0,0x0 +80000120: ee828293 addi t0,t0,-280 # 80000004 +80000124: 30529073 csrw mtvec,t0 +80000128: 00100513 li a0,1 +8000012c: 01f51513 slli a0,a0,0x1f +80000130: 00054c63 bltz a0,80000148 +80000134: 0ff0000f fence +80000138: 00100193 li gp,1 +8000013c: 05d00893 li a7,93 +80000140: 00000513 li a0,0 +80000144: 00000073 ecall +80000148: 80000297 auipc t0,0x80000 +8000014c: eb828293 addi t0,t0,-328 # 0 <_start-0x80000000> +80000150: 00028a63 beqz t0,80000164 +80000154: 10529073 csrw stvec,t0 +80000158: 0000b2b7 lui t0,0xb +8000015c: 10928293 addi t0,t0,265 # b109 <_start-0x7fff4ef7> +80000160: 30229073 csrw medeleg,t0 +80000164: 30005073 csrwi mstatus,0 +80000168: 00002537 lui a0,0x2 +8000016c: 30052073 csrs mstatus,a0 +80000170: 00305073 csrwi fcsr,0 +80000174: 00000297 auipc t0,0x0 +80000178: 01428293 addi t0,t0,20 # 80000188 +8000017c: 34129073 csrw mepc,t0 +80000180: f1402573 csrr a0,mhartid +80000184: 30200073 mret + +80000188 : +80000188: 00200193 li gp,2 +8000018c: 00002517 auipc a0,0x2 +80000190: e7450513 addi a0,a0,-396 # 80002000 +80000194: 00053007 fld ft0,0(a0) +80000198: 00853087 fld ft1,8(a0) +8000019c: 01053107 fld ft2,16(a0) +800001a0: 01852683 lw a3,24(a0) +800001a4: 01c52303 lw t1,28(a0) +800001a8: 021071d3 fadd.d ft3,ft0,ft1 +800001ac: 00353027 fsd ft3,0(a0) +800001b0: 00452383 lw t2,4(a0) +800001b4: 00052503 lw a0,0(a0) +800001b8: 001015f3 fsflags a1,zero +800001bc: 00000613 li a2,0 +800001c0: 26d51a63 bne a0,a3,80000434 +800001c4: 26731863 bne t1,t2,80000434 +800001c8: 26c59663 bne a1,a2,80000434 + +800001cc : +800001cc: 00300193 li gp,3 +800001d0: 00002517 auipc a0,0x2 +800001d4: e5050513 addi a0,a0,-432 # 80002020 +800001d8: 00053007 fld ft0,0(a0) +800001dc: 00853087 fld ft1,8(a0) +800001e0: 01053107 fld ft2,16(a0) +800001e4: 01852683 lw a3,24(a0) +800001e8: 01c52303 lw t1,28(a0) +800001ec: 021071d3 fadd.d ft3,ft0,ft1 +800001f0: 00353027 fsd ft3,0(a0) +800001f4: 00452383 lw t2,4(a0) +800001f8: 00052503 lw a0,0(a0) +800001fc: 001015f3 fsflags a1,zero +80000200: 00100613 li a2,1 +80000204: 22d51863 bne a0,a3,80000434 +80000208: 22731663 bne t1,t2,80000434 +8000020c: 22c59463 bne a1,a2,80000434 + +80000210 : +80000210: 00400193 li gp,4 +80000214: 00002517 auipc a0,0x2 +80000218: e2c50513 addi a0,a0,-468 # 80002040 +8000021c: 00053007 fld ft0,0(a0) +80000220: 00853087 fld ft1,8(a0) +80000224: 01053107 fld ft2,16(a0) +80000228: 01852683 lw a3,24(a0) +8000022c: 01c52303 lw t1,28(a0) +80000230: 021071d3 fadd.d ft3,ft0,ft1 +80000234: 00353027 fsd ft3,0(a0) +80000238: 00452383 lw t2,4(a0) +8000023c: 00052503 lw a0,0(a0) +80000240: 001015f3 fsflags a1,zero +80000244: 00100613 li a2,1 +80000248: 1ed51663 bne a0,a3,80000434 +8000024c: 1e731463 bne t1,t2,80000434 +80000250: 1ec59263 bne a1,a2,80000434 + +80000254 : +80000254: 00500193 li gp,5 +80000258: 00002517 auipc a0,0x2 +8000025c: e0850513 addi a0,a0,-504 # 80002060 +80000260: 00053007 fld ft0,0(a0) +80000264: 00853087 fld ft1,8(a0) +80000268: 01053107 fld ft2,16(a0) +8000026c: 01852683 lw a3,24(a0) +80000270: 01c52303 lw t1,28(a0) +80000274: 0a1071d3 fsub.d ft3,ft0,ft1 +80000278: 00353027 fsd ft3,0(a0) +8000027c: 00452383 lw t2,4(a0) +80000280: 00052503 lw a0,0(a0) +80000284: 001015f3 fsflags a1,zero +80000288: 00000613 li a2,0 +8000028c: 1ad51463 bne a0,a3,80000434 +80000290: 1a731263 bne t1,t2,80000434 +80000294: 1ac59063 bne a1,a2,80000434 + +80000298 : +80000298: 00600193 li gp,6 +8000029c: 00002517 auipc a0,0x2 +800002a0: de450513 addi a0,a0,-540 # 80002080 +800002a4: 00053007 fld ft0,0(a0) +800002a8: 00853087 fld ft1,8(a0) +800002ac: 01053107 fld ft2,16(a0) +800002b0: 01852683 lw a3,24(a0) +800002b4: 01c52303 lw t1,28(a0) +800002b8: 0a1071d3 fsub.d ft3,ft0,ft1 +800002bc: 00353027 fsd ft3,0(a0) +800002c0: 00452383 lw t2,4(a0) +800002c4: 00052503 lw a0,0(a0) +800002c8: 001015f3 fsflags a1,zero +800002cc: 00100613 li a2,1 +800002d0: 16d51263 bne a0,a3,80000434 +800002d4: 16731063 bne t1,t2,80000434 +800002d8: 14c59e63 bne a1,a2,80000434 + +800002dc : +800002dc: 00700193 li gp,7 +800002e0: 00002517 auipc a0,0x2 +800002e4: dc050513 addi a0,a0,-576 # 800020a0 +800002e8: 00053007 fld ft0,0(a0) +800002ec: 00853087 fld ft1,8(a0) +800002f0: 01053107 fld ft2,16(a0) +800002f4: 01852683 lw a3,24(a0) +800002f8: 01c52303 lw t1,28(a0) +800002fc: 0a1071d3 fsub.d ft3,ft0,ft1 +80000300: 00353027 fsd ft3,0(a0) +80000304: 00452383 lw t2,4(a0) +80000308: 00052503 lw a0,0(a0) +8000030c: 001015f3 fsflags a1,zero +80000310: 00100613 li a2,1 +80000314: 12d51063 bne a0,a3,80000434 +80000318: 10731e63 bne t1,t2,80000434 +8000031c: 10c59c63 bne a1,a2,80000434 + +80000320 : +80000320: 00800193 li gp,8 +80000324: 00002517 auipc a0,0x2 +80000328: d9c50513 addi a0,a0,-612 # 800020c0 +8000032c: 00053007 fld ft0,0(a0) +80000330: 00853087 fld ft1,8(a0) +80000334: 01053107 fld ft2,16(a0) +80000338: 01852683 lw a3,24(a0) +8000033c: 01c52303 lw t1,28(a0) +80000340: 121071d3 fmul.d ft3,ft0,ft1 +80000344: 00353027 fsd ft3,0(a0) +80000348: 00452383 lw t2,4(a0) +8000034c: 00052503 lw a0,0(a0) +80000350: 001015f3 fsflags a1,zero +80000354: 00000613 li a2,0 +80000358: 0cd51e63 bne a0,a3,80000434 +8000035c: 0c731c63 bne t1,t2,80000434 +80000360: 0cc59a63 bne a1,a2,80000434 + +80000364 : +80000364: 00900193 li gp,9 +80000368: 00002517 auipc a0,0x2 +8000036c: d7850513 addi a0,a0,-648 # 800020e0 +80000370: 00053007 fld ft0,0(a0) +80000374: 00853087 fld ft1,8(a0) +80000378: 01053107 fld ft2,16(a0) +8000037c: 01852683 lw a3,24(a0) +80000380: 01c52303 lw t1,28(a0) +80000384: 121071d3 fmul.d ft3,ft0,ft1 +80000388: 00353027 fsd ft3,0(a0) +8000038c: 00452383 lw t2,4(a0) +80000390: 00052503 lw a0,0(a0) +80000394: 001015f3 fsflags a1,zero +80000398: 00100613 li a2,1 +8000039c: 08d51c63 bne a0,a3,80000434 +800003a0: 08731a63 bne t1,t2,80000434 +800003a4: 08c59863 bne a1,a2,80000434 + +800003a8 : +800003a8: 00a00193 li gp,10 +800003ac: 00002517 auipc a0,0x2 +800003b0: d5450513 addi a0,a0,-684 # 80002100 +800003b4: 00053007 fld ft0,0(a0) +800003b8: 00853087 fld ft1,8(a0) +800003bc: 01053107 fld ft2,16(a0) +800003c0: 01852683 lw a3,24(a0) +800003c4: 01c52303 lw t1,28(a0) +800003c8: 121071d3 fmul.d ft3,ft0,ft1 +800003cc: 00353027 fsd ft3,0(a0) +800003d0: 00452383 lw t2,4(a0) +800003d4: 00052503 lw a0,0(a0) +800003d8: 001015f3 fsflags a1,zero +800003dc: 00100613 li a2,1 +800003e0: 04d51a63 bne a0,a3,80000434 +800003e4: 04731863 bne t1,t2,80000434 +800003e8: 04c59663 bne a1,a2,80000434 + +800003ec : +800003ec: 00b00193 li gp,11 +800003f0: 00002517 auipc a0,0x2 +800003f4: d3050513 addi a0,a0,-720 # 80002120 +800003f8: 00053007 fld ft0,0(a0) +800003fc: 00853087 fld ft1,8(a0) +80000400: 01053107 fld ft2,16(a0) +80000404: 01852683 lw a3,24(a0) +80000408: 01c52303 lw t1,28(a0) +8000040c: 0a1071d3 fsub.d ft3,ft0,ft1 +80000410: 00353027 fsd ft3,0(a0) +80000414: 00452383 lw t2,4(a0) +80000418: 00052503 lw a0,0(a0) +8000041c: 001015f3 fsflags a1,zero +80000420: 01000613 li a2,16 +80000424: 00d51863 bne a0,a3,80000434 +80000428: 00731663 bne t1,t2,80000434 +8000042c: 00c59463 bne a1,a2,80000434 +80000430: 02301063 bne zero,gp,80000450 + +80000434 : +80000434: 0ff0000f fence +80000438: 00018063 beqz gp,80000438 +8000043c: 00119193 slli gp,gp,0x1 +80000440: 0011e193 ori gp,gp,1 +80000444: 05d00893 li a7,93 +80000448: 00018513 mv a0,gp +8000044c: 00000073 ecall + +80000450 : +80000450: 0ff0000f fence +80000454: 00100193 li gp,1 +80000458: 05d00893 li a7,93 +8000045c: 00000513 li a0,0 +80000460: 00000073 ecall +80000464: c0001073 unimp +80000468: 0000 unimp +8000046a: 0000 unimp +8000046c: 0000 unimp +8000046e: 0000 unimp +80000470: 0000 unimp +80000472: 0000 unimp +80000474: 0000 unimp +80000476: 0000 unimp +80000478: 0000 unimp +8000047a: 0000 unimp +8000047c: 0000 unimp +8000047e: 0000 unimp +80000480: 0000 unimp +80000482: 0000 unimp + +Disassembly of section .data: + +80002000 : +80002000: 0000 unimp +80002002: 0000 unimp +80002004: 0000 unimp +80002006: 4004 lw s1,0(s0) +80002008: 0000 unimp +8000200a: 0000 unimp +8000200c: 0000 unimp +8000200e: 3ff0 fld fa2,248(a5) +80002010: 0000 unimp +80002012: 0000 unimp +80002014: 0000 unimp +80002016: 0000 unimp +80002018: 0000 unimp +8000201a: 0000 unimp +8000201c: 0000 unimp +8000201e: 400c lw a1,0(s0) + +80002020 : +80002020: 6666 flw fa2,88(sp) +80002022: 6666 flw fa2,88(sp) +80002024: 4c66 lw s8,88(sp) +80002026: 999ac093 xori ra,s5,-1639 +8000202a: 9999 andi a1,a1,-26 +8000202c: 9999 andi a1,a1,-26 +8000202e: 3ff1 jal 8000200a +80002030: 0000 unimp +80002032: 0000 unimp +80002034: 0000 unimp +80002036: 0000 unimp +80002038: 0000 unimp +8000203a: 0000 unimp +8000203c: 4800 lw s0,16(s0) +8000203e: xori ra,gp,-689 + +80002040 : +80002040: d4f1 beqz s1,8000200c +80002042: 53c8 lw a0,36(a5) +80002044: 400921fb 0x400921fb +80002048: 8c3a mv s8,a4 +8000204a: e230 fsw fa2,64(a2) +8000204c: 798e flw fs3,224(sp) +8000204e: 3e45 jal 80001bfe +80002050: 0000 unimp +80002052: 0000 unimp +80002054: 0000 unimp +80002056: 0000 unimp +80002058: 6ddf 5520 21fb 0x21fb55206ddf +8000205e: 4009 c.li zero,2 + +80002060 : +80002060: 0000 unimp +80002062: 0000 unimp +80002064: 0000 unimp +80002066: 4004 lw s1,0(s0) +80002068: 0000 unimp +8000206a: 0000 unimp +8000206c: 0000 unimp +8000206e: 3ff0 fld fa2,248(a5) +80002070: 0000 unimp +80002072: 0000 unimp +80002074: 0000 unimp +80002076: 0000 unimp +80002078: 0000 unimp +8000207a: 0000 unimp +8000207c: 0000 unimp +8000207e: 3ff8 fld fa4,248(a5) + +80002080 : +80002080: 6666 flw fa2,88(sp) +80002082: 6666 flw fa2,88(sp) +80002084: 4c66 lw s8,88(sp) +80002086: 999ac093 xori ra,s5,-1639 +8000208a: 9999 andi a1,a1,-26 +8000208c: 9999 andi a1,a1,-26 +8000208e: bff1 j 8000206a +80002090: 0000 unimp +80002092: 0000 unimp +80002094: 0000 unimp +80002096: 0000 unimp +80002098: 0000 unimp +8000209a: 0000 unimp +8000209c: 4800 lw s0,16(s0) +8000209e: xori ra,gp,-689 + +800020a0 : +800020a0: d4f1 beqz s1,8000206c +800020a2: 53c8 lw a0,36(a5) +800020a4: 400921fb 0x400921fb +800020a8: 8c3a mv s8,a4 +800020aa: e230 fsw fa2,64(a2) +800020ac: 798e flw fs3,224(sp) +800020ae: 3e45 jal 80001c5e +800020b0: 0000 unimp +800020b2: 0000 unimp +800020b4: 0000 unimp +800020b6: 0000 unimp +800020b8: 52713c03 0x52713c03 +800020bc: 400921fb 0x400921fb + +800020c0 : +800020c0: 0000 unimp +800020c2: 0000 unimp +800020c4: 0000 unimp +800020c6: 4004 lw s1,0(s0) +800020c8: 0000 unimp +800020ca: 0000 unimp +800020cc: 0000 unimp +800020ce: 3ff0 fld fa2,248(a5) +800020d0: 0000 unimp +800020d2: 0000 unimp +800020d4: 0000 unimp +800020d6: 0000 unimp +800020d8: 0000 unimp +800020da: 0000 unimp +800020dc: 0000 unimp +800020de: 4004 lw s1,0(s0) + +800020e0 : +800020e0: 6666 flw fa2,88(sp) +800020e2: 6666 flw fa2,88(sp) +800020e4: 4c66 lw s8,88(sp) +800020e6: 999ac093 xori ra,s5,-1639 +800020ea: 9999 andi a1,a1,-26 +800020ec: 9999 andi a1,a1,-26 +800020ee: bff1 j 800020ca +800020f0: 0000 unimp +800020f2: 0000 unimp +800020f4: 0000 unimp +800020f6: 0000 unimp +800020f8: 0a3d addi s4,s4,15 +800020fa: 3a70a3d7 0x3a70a3d7 +800020fe: 4095 li ra,5 + +80002100 : +80002100: d4f1 beqz s1,800020cc +80002102: 53c8 lw a0,36(a5) +80002104: 400921fb 0x400921fb +80002108: 8c3a mv s8,a4 +8000210a: e230 fsw fa2,64(a2) +8000210c: 798e flw fs3,224(sp) +8000210e: 3e45 jal 80001cbe +80002110: 0000 unimp +80002112: 0000 unimp +80002114: 0000 unimp +80002116: 0000 unimp +80002118: ff09 bnez a4,80002032 +8000211a: a5c1 j 800027da <_end+0x69a> +8000211c: ddc5 beqz a1,800020d4 +8000211e: 3e60 fld fs0,248(a2) + +80002120 : +80002120: 0000 unimp +80002122: 0000 unimp +80002124: 0000 unimp +80002126: 7ff0 flw fa2,124(a5) +80002128: 0000 unimp +8000212a: 0000 unimp +8000212c: 0000 unimp +8000212e: 7ff0 flw fa2,124(a5) +80002130: 0000 unimp +80002132: 0000 unimp +80002134: 0000 unimp +80002136: 0000 unimp +80002138: 0000 unimp +8000213a: 0000 unimp +8000213c: 0000 unimp +8000213e: 7ff8 flw fa4,124(a5) diff --git a/src/test/resources/asm/rv32ud-p-fclass.dump b/src/test/resources/asm/rv32ud-p-fclass.dump new file mode 100644 index 00000000..2b11d2a6 --- /dev/null +++ b/src/test/resources/asm/rv32ud-p-fclass.dump @@ -0,0 +1,305 @@ + +rv32ud-p-fclass: file format elf32-littleriscv + + +Disassembly of section .text.init: + +80000000 <_start>: +80000000: 04c0006f j 8000004c + +80000004 : +80000004: 34202f73 csrr t5,mcause +80000008: 00800f93 li t6,8 +8000000c: 03ff0a63 beq t5,t6,80000040 +80000010: 00900f93 li t6,9 +80000014: 03ff0663 beq t5,t6,80000040 +80000018: 00b00f93 li t6,11 +8000001c: 03ff0263 beq t5,t6,80000040 +80000020: 80000f17 auipc t5,0x80000 +80000024: fe0f0f13 addi t5,t5,-32 # 0 <_start-0x80000000> +80000028: 000f0463 beqz t5,80000030 +8000002c: 000f0067 jr t5 +80000030: 34202f73 csrr t5,mcause +80000034: 000f5463 bgez t5,8000003c +80000038: 0040006f j 8000003c + +8000003c : +8000003c: 5391e193 ori gp,gp,1337 + +80000040 : +80000040: 00001f17 auipc t5,0x1 +80000044: fc3f2023 sw gp,-64(t5) # 80001000 +80000048: ff9ff06f j 80000040 + +8000004c : +8000004c: 00000093 li ra,0 +80000050: 00000113 li sp,0 +80000054: 00000193 li gp,0 +80000058: 00000213 li tp,0 +8000005c: 00000293 li t0,0 +80000060: 00000313 li t1,0 +80000064: 00000393 li t2,0 +80000068: 00000413 li s0,0 +8000006c: 00000493 li s1,0 +80000070: 00000513 li a0,0 +80000074: 00000593 li a1,0 +80000078: 00000613 li a2,0 +8000007c: 00000693 li a3,0 +80000080: 00000713 li a4,0 +80000084: 00000793 li a5,0 +80000088: 00000813 li a6,0 +8000008c: 00000893 li a7,0 +80000090: 00000913 li s2,0 +80000094: 00000993 li s3,0 +80000098: 00000a13 li s4,0 +8000009c: 00000a93 li s5,0 +800000a0: 00000b13 li s6,0 +800000a4: 00000b93 li s7,0 +800000a8: 00000c13 li s8,0 +800000ac: 00000c93 li s9,0 +800000b0: 00000d13 li s10,0 +800000b4: 00000d93 li s11,0 +800000b8: 00000e13 li t3,0 +800000bc: 00000e93 li t4,0 +800000c0: 00000f13 li t5,0 +800000c4: 00000f93 li t6,0 +800000c8: f1402573 csrr a0,mhartid +800000cc: 00051063 bnez a0,800000cc +800000d0: 00000297 auipc t0,0x0 +800000d4: 01028293 addi t0,t0,16 # 800000e0 +800000d8: 30529073 csrw mtvec,t0 +800000dc: 18005073 csrwi satp,0 +800000e0: 00000297 auipc t0,0x0 +800000e4: 02028293 addi t0,t0,32 # 80000100 +800000e8: 30529073 csrw mtvec,t0 +800000ec: 800002b7 lui t0,0x80000 +800000f0: fff28293 addi t0,t0,-1 # 7fffffff <_end+0xffffdfaf> +800000f4: 3b029073 csrw pmpaddr0,t0 +800000f8: 01f00293 li t0,31 +800000fc: 3a029073 csrw pmpcfg0,t0 +80000100: 30405073 csrwi mie,0 +80000104: 00000297 auipc t0,0x0 +80000108: 01428293 addi t0,t0,20 # 80000118 +8000010c: 30529073 csrw mtvec,t0 +80000110: 30205073 csrwi medeleg,0 +80000114: 30305073 csrwi mideleg,0 +80000118: 00000193 li gp,0 +8000011c: 00000297 auipc t0,0x0 +80000120: ee828293 addi t0,t0,-280 # 80000004 +80000124: 30529073 csrw mtvec,t0 +80000128: 00100513 li a0,1 +8000012c: 01f51513 slli a0,a0,0x1f +80000130: 00054c63 bltz a0,80000148 +80000134: 0ff0000f fence +80000138: 00100193 li gp,1 +8000013c: 05d00893 li a7,93 +80000140: 00000513 li a0,0 +80000144: 00000073 ecall +80000148: 80000297 auipc t0,0x80000 +8000014c: eb828293 addi t0,t0,-328 # 0 <_start-0x80000000> +80000150: 00028a63 beqz t0,80000164 +80000154: 10529073 csrw stvec,t0 +80000158: 0000b2b7 lui t0,0xb +8000015c: 10928293 addi t0,t0,265 # b109 <_start-0x7fff4ef7> +80000160: 30229073 csrw medeleg,t0 +80000164: 30005073 csrwi mstatus,0 +80000168: 00002537 lui a0,0x2 +8000016c: 30052073 csrs mstatus,a0 +80000170: 00305073 csrwi fcsr,0 +80000174: 00000297 auipc t0,0x0 +80000178: 01428293 addi t0,t0,20 # 80000188 +8000017c: 34129073 csrw mepc,t0 +80000180: f1402573 csrr a0,mhartid +80000184: 30200073 mret + +80000188 : +80000188: 00002517 auipc a0,0x2 +8000018c: e7850513 addi a0,a0,-392 # 80002000 +80000190: 00053507 fld fa0,0(a0) +80000194: e2051553 fclass.d a0,fa0 +80000198: 00100393 li t2,1 +8000019c: 00200193 li gp,2 +800001a0: 10751263 bne a0,t2,800002a4 + +800001a4 : +800001a4: 00002517 auipc a0,0x2 +800001a8: e6450513 addi a0,a0,-412 # 80002008 +800001ac: 00053507 fld fa0,0(a0) +800001b0: e2051553 fclass.d a0,fa0 +800001b4: 00200393 li t2,2 +800001b8: 00300193 li gp,3 +800001bc: 0e751463 bne a0,t2,800002a4 + +800001c0 : +800001c0: 00002517 auipc a0,0x2 +800001c4: e5050513 addi a0,a0,-432 # 80002010 +800001c8: 00053507 fld fa0,0(a0) +800001cc: e2051553 fclass.d a0,fa0 +800001d0: 00400393 li t2,4 +800001d4: 00400193 li gp,4 +800001d8: 0c751663 bne a0,t2,800002a4 + +800001dc : +800001dc: 00002517 auipc a0,0x2 +800001e0: e3c50513 addi a0,a0,-452 # 80002018 +800001e4: 00053507 fld fa0,0(a0) +800001e8: e2051553 fclass.d a0,fa0 +800001ec: 00800393 li t2,8 +800001f0: 00500193 li gp,5 +800001f4: 0a751863 bne a0,t2,800002a4 + +800001f8 : +800001f8: 00002517 auipc a0,0x2 +800001fc: e2850513 addi a0,a0,-472 # 80002020 +80000200: 00053507 fld fa0,0(a0) +80000204: e2051553 fclass.d a0,fa0 +80000208: 01000393 li t2,16 +8000020c: 00600193 li gp,6 +80000210: 08751a63 bne a0,t2,800002a4 + +80000214 : +80000214: 00002517 auipc a0,0x2 +80000218: e1450513 addi a0,a0,-492 # 80002028 +8000021c: 00053507 fld fa0,0(a0) +80000220: e2051553 fclass.d a0,fa0 +80000224: 02000393 li t2,32 +80000228: 00700193 li gp,7 +8000022c: 06751c63 bne a0,t2,800002a4 + +80000230 : +80000230: 00002517 auipc a0,0x2 +80000234: e0050513 addi a0,a0,-512 # 80002030 +80000238: 00053507 fld fa0,0(a0) +8000023c: e2051553 fclass.d a0,fa0 +80000240: 04000393 li t2,64 +80000244: 00800193 li gp,8 +80000248: 04751e63 bne a0,t2,800002a4 + +8000024c : +8000024c: 00002517 auipc a0,0x2 +80000250: dec50513 addi a0,a0,-532 # 80002038 +80000254: 00053507 fld fa0,0(a0) +80000258: e2051553 fclass.d a0,fa0 +8000025c: 08000393 li t2,128 +80000260: 00900193 li gp,9 +80000264: 04751063 bne a0,t2,800002a4 + +80000268 : +80000268: 00002517 auipc a0,0x2 +8000026c: dd850513 addi a0,a0,-552 # 80002040 +80000270: 00053507 fld fa0,0(a0) +80000274: e2051553 fclass.d a0,fa0 +80000278: 10000393 li t2,256 +8000027c: 00a00193 li gp,10 +80000280: 02751263 bne a0,t2,800002a4 + +80000284 : +80000284: 00002517 auipc a0,0x2 +80000288: dc450513 addi a0,a0,-572 # 80002048 +8000028c: 00053507 fld fa0,0(a0) +80000290: e2051553 fclass.d a0,fa0 +80000294: 20000393 li t2,512 +80000298: 00b00193 li gp,11 +8000029c: 00751463 bne a0,t2,800002a4 +800002a0: 02301063 bne zero,gp,800002c0 + +800002a4 : +800002a4: 0ff0000f fence +800002a8: 00018063 beqz gp,800002a8 +800002ac: 00119193 slli gp,gp,0x1 +800002b0: 0011e193 ori gp,gp,1 +800002b4: 05d00893 li a7,93 +800002b8: 00018513 mv a0,gp +800002bc: 00000073 ecall + +800002c0 : +800002c0: 0ff0000f fence +800002c4: 00100193 li gp,1 +800002c8: 05d00893 li a7,93 +800002cc: 00000513 li a0,0 +800002d0: 00000073 ecall +800002d4: c0001073 unimp +800002d8: 0000 unimp +800002da: 0000 unimp +800002dc: 0000 unimp +800002de: 0000 unimp +800002e0: 0000 unimp +800002e2: 0000 unimp +800002e4: 0000 unimp +800002e6: 0000 unimp +800002e8: 0000 unimp +800002ea: 0000 unimp +800002ec: 0000 unimp +800002ee: 0000 unimp +800002f0: 0000 unimp +800002f2: 0000 unimp +800002f4: 0000 unimp +800002f6: 0000 unimp +800002f8: 0000 unimp +800002fa: 0000 unimp +800002fc: 0000 unimp +800002fe: 0000 unimp +80000300: 0000 unimp +80000302: 0000 unimp + +Disassembly of section .data: + +80002000 : +80002000: 0000 unimp +80002002: 0000 unimp +80002004: 0000 unimp +80002006: fff0 fsw fa2,124(a5) + +80002008 : +80002008: 0000 unimp +8000200a: 0000 unimp +8000200c: 0000 unimp +8000200e: bff0 fsd fa2,248(a5) + +80002010 : +80002010: ffff 0xffff +80002012: ffff 0xffff +80002014: ffff 0xffff +80002016: 0x800f + +80002018 : +80002018: 0000 unimp +8000201a: 0000 unimp +8000201c: 0000 unimp +8000201e: 8000 0x8000 + +80002020 : +80002020: 0000 unimp +80002022: 0000 unimp +80002024: 0000 unimp +80002026: 0000 unimp + +80002028 : +80002028: ffff 0xffff +8000202a: ffff 0xffff +8000202c: ffff 0xffff +8000202e: fence unknown,unknown + +80002030 : +80002030: 0000 unimp +80002032: 0000 unimp +80002034: 0000 unimp +80002036: 3ff0 fld fa2,248(a5) + +80002038 : +80002038: 0000 unimp +8000203a: 0000 unimp +8000203c: 0000 unimp +8000203e: 7ff0 flw fa2,124(a5) + +80002040 : +80002040: 0001 nop +80002042: 0000 unimp +80002044: 0000 unimp +80002046: 7ff0 flw fa2,124(a5) + +80002048 : +80002048: 0000 unimp +8000204a: 0000 unimp +8000204c: 0000 unimp +8000204e: 7ff8 flw fa4,124(a5) diff --git a/src/test/resources/asm/rv32ud-p-fcmp.dump b/src/test/resources/asm/rv32ud-p-fcmp.dump new file mode 100644 index 00000000..1fc9013e --- /dev/null +++ b/src/test/resources/asm/rv32ud-p-fcmp.dump @@ -0,0 +1,640 @@ + +rv32ud-p-fcmp: file format elf32-littleriscv + + +Disassembly of section .text.init: + +80000000 <_start>: +80000000: 04c0006f j 8000004c + +80000004 : +80000004: 34202f73 csrr t5,mcause +80000008: 00800f93 li t6,8 +8000000c: 03ff0a63 beq t5,t6,80000040 +80000010: 00900f93 li t6,9 +80000014: 03ff0663 beq t5,t6,80000040 +80000018: 00b00f93 li t6,11 +8000001c: 03ff0263 beq t5,t6,80000040 +80000020: 80000f17 auipc t5,0x80000 +80000024: fe0f0f13 addi t5,t5,-32 # 0 <_start-0x80000000> +80000028: 000f0463 beqz t5,80000030 +8000002c: 000f0067 jr t5 +80000030: 34202f73 csrr t5,mcause +80000034: 000f5463 bgez t5,8000003c +80000038: 0040006f j 8000003c + +8000003c : +8000003c: 5391e193 ori gp,gp,1337 + +80000040 : +80000040: 00001f17 auipc t5,0x1 +80000044: fc3f2023 sw gp,-64(t5) # 80001000 +80000048: ff9ff06f j 80000040 + +8000004c : +8000004c: 00000093 li ra,0 +80000050: 00000113 li sp,0 +80000054: 00000193 li gp,0 +80000058: 00000213 li tp,0 +8000005c: 00000293 li t0,0 +80000060: 00000313 li t1,0 +80000064: 00000393 li t2,0 +80000068: 00000413 li s0,0 +8000006c: 00000493 li s1,0 +80000070: 00000513 li a0,0 +80000074: 00000593 li a1,0 +80000078: 00000613 li a2,0 +8000007c: 00000693 li a3,0 +80000080: 00000713 li a4,0 +80000084: 00000793 li a5,0 +80000088: 00000813 li a6,0 +8000008c: 00000893 li a7,0 +80000090: 00000913 li s2,0 +80000094: 00000993 li s3,0 +80000098: 00000a13 li s4,0 +8000009c: 00000a93 li s5,0 +800000a0: 00000b13 li s6,0 +800000a4: 00000b93 li s7,0 +800000a8: 00000c13 li s8,0 +800000ac: 00000c93 li s9,0 +800000b0: 00000d13 li s10,0 +800000b4: 00000d93 li s11,0 +800000b8: 00000e13 li t3,0 +800000bc: 00000e93 li t4,0 +800000c0: 00000f13 li t5,0 +800000c4: 00000f93 li t6,0 +800000c8: f1402573 csrr a0,mhartid +800000cc: 00051063 bnez a0,800000cc +800000d0: 00000297 auipc t0,0x0 +800000d4: 01028293 addi t0,t0,16 # 800000e0 +800000d8: 30529073 csrw mtvec,t0 +800000dc: 18005073 csrwi satp,0 +800000e0: 00000297 auipc t0,0x0 +800000e4: 02028293 addi t0,t0,32 # 80000100 +800000e8: 30529073 csrw mtvec,t0 +800000ec: 800002b7 lui t0,0x80000 +800000f0: fff28293 addi t0,t0,-1 # 7fffffff <_end+0xffffde1f> +800000f4: 3b029073 csrw pmpaddr0,t0 +800000f8: 01f00293 li t0,31 +800000fc: 3a029073 csrw pmpcfg0,t0 +80000100: 30405073 csrwi mie,0 +80000104: 00000297 auipc t0,0x0 +80000108: 01428293 addi t0,t0,20 # 80000118 +8000010c: 30529073 csrw mtvec,t0 +80000110: 30205073 csrwi medeleg,0 +80000114: 30305073 csrwi mideleg,0 +80000118: 00000193 li gp,0 +8000011c: 00000297 auipc t0,0x0 +80000120: ee828293 addi t0,t0,-280 # 80000004 +80000124: 30529073 csrw mtvec,t0 +80000128: 00100513 li a0,1 +8000012c: 01f51513 slli a0,a0,0x1f +80000130: 00054c63 bltz a0,80000148 +80000134: 0ff0000f fence +80000138: 00100193 li gp,1 +8000013c: 05d00893 li a7,93 +80000140: 00000513 li a0,0 +80000144: 00000073 ecall +80000148: 80000297 auipc t0,0x80000 +8000014c: eb828293 addi t0,t0,-328 # 0 <_start-0x80000000> +80000150: 00028a63 beqz t0,80000164 +80000154: 10529073 csrw stvec,t0 +80000158: 0000b2b7 lui t0,0xb +8000015c: 10928293 addi t0,t0,265 # b109 <_start-0x7fff4ef7> +80000160: 30229073 csrw medeleg,t0 +80000164: 30005073 csrwi mstatus,0 +80000168: 00002537 lui a0,0x2 +8000016c: 30052073 csrs mstatus,a0 +80000170: 00305073 csrwi fcsr,0 +80000174: 00000297 auipc t0,0x0 +80000178: 01428293 addi t0,t0,20 # 80000188 +8000017c: 34129073 csrw mepc,t0 +80000180: f1402573 csrr a0,mhartid +80000184: 30200073 mret + +80000188 : +80000188: 00200193 li gp,2 +8000018c: 00002517 auipc a0,0x2 +80000190: e7450513 addi a0,a0,-396 # 80002000 +80000194: 00053007 fld ft0,0(a0) +80000198: 00853087 fld ft1,8(a0) +8000019c: 01053107 fld ft2,16(a0) +800001a0: 01852683 lw a3,24(a0) +800001a4: 01c52303 lw t1,28(a0) +800001a8: a2102553 feq.d a0,ft0,ft1 +800001ac: 00000393 li t2,0 +800001b0: 001015f3 fsflags a1,zero +800001b4: 00000613 li a2,0 +800001b8: 34d51c63 bne a0,a3,80000510 +800001bc: 34731a63 bne t1,t2,80000510 +800001c0: 34c59863 bne a1,a2,80000510 + +800001c4 : +800001c4: 00300193 li gp,3 +800001c8: 00002517 auipc a0,0x2 +800001cc: e5850513 addi a0,a0,-424 # 80002020 +800001d0: 00053007 fld ft0,0(a0) +800001d4: 00853087 fld ft1,8(a0) +800001d8: 01053107 fld ft2,16(a0) +800001dc: 01852683 lw a3,24(a0) +800001e0: 01c52303 lw t1,28(a0) +800001e4: a2100553 fle.d a0,ft0,ft1 +800001e8: 00000393 li t2,0 +800001ec: 001015f3 fsflags a1,zero +800001f0: 00000613 li a2,0 +800001f4: 30d51e63 bne a0,a3,80000510 +800001f8: 30731c63 bne t1,t2,80000510 +800001fc: 30c59a63 bne a1,a2,80000510 + +80000200 : +80000200: 00400193 li gp,4 +80000204: 00002517 auipc a0,0x2 +80000208: e3c50513 addi a0,a0,-452 # 80002040 +8000020c: 00053007 fld ft0,0(a0) +80000210: 00853087 fld ft1,8(a0) +80000214: 01053107 fld ft2,16(a0) +80000218: 01852683 lw a3,24(a0) +8000021c: 01c52303 lw t1,28(a0) +80000220: a2101553 flt.d a0,ft0,ft1 +80000224: 00000393 li t2,0 +80000228: 001015f3 fsflags a1,zero +8000022c: 00000613 li a2,0 +80000230: 2ed51063 bne a0,a3,80000510 +80000234: 2c731e63 bne t1,t2,80000510 +80000238: 2cc59c63 bne a1,a2,80000510 + +8000023c : +8000023c: 00500193 li gp,5 +80000240: 00002517 auipc a0,0x2 +80000244: e2050513 addi a0,a0,-480 # 80002060 +80000248: 00053007 fld ft0,0(a0) +8000024c: 00853087 fld ft1,8(a0) +80000250: 01053107 fld ft2,16(a0) +80000254: 01852683 lw a3,24(a0) +80000258: 01c52303 lw t1,28(a0) +8000025c: a2102553 feq.d a0,ft0,ft1 +80000260: 00000393 li t2,0 +80000264: 001015f3 fsflags a1,zero +80000268: 00000613 li a2,0 +8000026c: 2ad51263 bne a0,a3,80000510 +80000270: 2a731063 bne t1,t2,80000510 +80000274: 28c59e63 bne a1,a2,80000510 + +80000278 : +80000278: 00600193 li gp,6 +8000027c: 00002517 auipc a0,0x2 +80000280: e0450513 addi a0,a0,-508 # 80002080 +80000284: 00053007 fld ft0,0(a0) +80000288: 00853087 fld ft1,8(a0) +8000028c: 01053107 fld ft2,16(a0) +80000290: 01852683 lw a3,24(a0) +80000294: 01c52303 lw t1,28(a0) +80000298: a2100553 fle.d a0,ft0,ft1 +8000029c: 00000393 li t2,0 +800002a0: 001015f3 fsflags a1,zero +800002a4: 00000613 li a2,0 +800002a8: 26d51463 bne a0,a3,80000510 +800002ac: 26731263 bne t1,t2,80000510 +800002b0: 26c59063 bne a1,a2,80000510 + +800002b4 : +800002b4: 00700193 li gp,7 +800002b8: 00002517 auipc a0,0x2 +800002bc: de850513 addi a0,a0,-536 # 800020a0 +800002c0: 00053007 fld ft0,0(a0) +800002c4: 00853087 fld ft1,8(a0) +800002c8: 01053107 fld ft2,16(a0) +800002cc: 01852683 lw a3,24(a0) +800002d0: 01c52303 lw t1,28(a0) +800002d4: a2101553 flt.d a0,ft0,ft1 +800002d8: 00000393 li t2,0 +800002dc: 001015f3 fsflags a1,zero +800002e0: 00000613 li a2,0 +800002e4: 22d51663 bne a0,a3,80000510 +800002e8: 22731463 bne t1,t2,80000510 +800002ec: 22c59263 bne a1,a2,80000510 + +800002f0 : +800002f0: 00800193 li gp,8 +800002f4: 00002517 auipc a0,0x2 +800002f8: dcc50513 addi a0,a0,-564 # 800020c0 +800002fc: 00053007 fld ft0,0(a0) +80000300: 00853087 fld ft1,8(a0) +80000304: 01053107 fld ft2,16(a0) +80000308: 01852683 lw a3,24(a0) +8000030c: 01c52303 lw t1,28(a0) +80000310: a2102553 feq.d a0,ft0,ft1 +80000314: 00000393 li t2,0 +80000318: 001015f3 fsflags a1,zero +8000031c: 00000613 li a2,0 +80000320: 1ed51863 bne a0,a3,80000510 +80000324: 1e731663 bne t1,t2,80000510 +80000328: 1ec59463 bne a1,a2,80000510 + +8000032c : +8000032c: 00900193 li gp,9 +80000330: 00002517 auipc a0,0x2 +80000334: db050513 addi a0,a0,-592 # 800020e0 +80000338: 00053007 fld ft0,0(a0) +8000033c: 00853087 fld ft1,8(a0) +80000340: 01053107 fld ft2,16(a0) +80000344: 01852683 lw a3,24(a0) +80000348: 01c52303 lw t1,28(a0) +8000034c: a2102553 feq.d a0,ft0,ft1 +80000350: 00000393 li t2,0 +80000354: 001015f3 fsflags a1,zero +80000358: 00000613 li a2,0 +8000035c: 1ad51a63 bne a0,a3,80000510 +80000360: 1a731863 bne t1,t2,80000510 +80000364: 1ac59663 bne a1,a2,80000510 + +80000368 : +80000368: 00a00193 li gp,10 +8000036c: 00002517 auipc a0,0x2 +80000370: d9450513 addi a0,a0,-620 # 80002100 +80000374: 00053007 fld ft0,0(a0) +80000378: 00853087 fld ft1,8(a0) +8000037c: 01053107 fld ft2,16(a0) +80000380: 01852683 lw a3,24(a0) +80000384: 01c52303 lw t1,28(a0) +80000388: a2102553 feq.d a0,ft0,ft1 +8000038c: 00000393 li t2,0 +80000390: 001015f3 fsflags a1,zero +80000394: 01000613 li a2,16 +80000398: 16d51c63 bne a0,a3,80000510 +8000039c: 16731a63 bne t1,t2,80000510 +800003a0: 16c59863 bne a1,a2,80000510 + +800003a4 : +800003a4: 00b00193 li gp,11 +800003a8: 00002517 auipc a0,0x2 +800003ac: d7850513 addi a0,a0,-648 # 80002120 +800003b0: 00053007 fld ft0,0(a0) +800003b4: 00853087 fld ft1,8(a0) +800003b8: 01053107 fld ft2,16(a0) +800003bc: 01852683 lw a3,24(a0) +800003c0: 01c52303 lw t1,28(a0) +800003c4: a2101553 flt.d a0,ft0,ft1 +800003c8: 00000393 li t2,0 +800003cc: 001015f3 fsflags a1,zero +800003d0: 01000613 li a2,16 +800003d4: 12d51e63 bne a0,a3,80000510 +800003d8: 12731c63 bne t1,t2,80000510 +800003dc: 12c59a63 bne a1,a2,80000510 + +800003e0 : +800003e0: 00c00193 li gp,12 +800003e4: 00002517 auipc a0,0x2 +800003e8: d5c50513 addi a0,a0,-676 # 80002140 +800003ec: 00053007 fld ft0,0(a0) +800003f0: 00853087 fld ft1,8(a0) +800003f4: 01053107 fld ft2,16(a0) +800003f8: 01852683 lw a3,24(a0) +800003fc: 01c52303 lw t1,28(a0) +80000400: a2101553 flt.d a0,ft0,ft1 +80000404: 00000393 li t2,0 +80000408: 001015f3 fsflags a1,zero +8000040c: 01000613 li a2,16 +80000410: 10d51063 bne a0,a3,80000510 +80000414: 0e731e63 bne t1,t2,80000510 +80000418: 0ec59c63 bne a1,a2,80000510 + +8000041c : +8000041c: 00d00193 li gp,13 +80000420: 00002517 auipc a0,0x2 +80000424: d4050513 addi a0,a0,-704 # 80002160 +80000428: 00053007 fld ft0,0(a0) +8000042c: 00853087 fld ft1,8(a0) +80000430: 01053107 fld ft2,16(a0) +80000434: 01852683 lw a3,24(a0) +80000438: 01c52303 lw t1,28(a0) +8000043c: a2101553 flt.d a0,ft0,ft1 +80000440: 00000393 li t2,0 +80000444: 001015f3 fsflags a1,zero +80000448: 01000613 li a2,16 +8000044c: 0cd51263 bne a0,a3,80000510 +80000450: 0c731063 bne t1,t2,80000510 +80000454: 0ac59e63 bne a1,a2,80000510 + +80000458 : +80000458: 00e00193 li gp,14 +8000045c: 00002517 auipc a0,0x2 +80000460: d2450513 addi a0,a0,-732 # 80002180 +80000464: 00053007 fld ft0,0(a0) +80000468: 00853087 fld ft1,8(a0) +8000046c: 01053107 fld ft2,16(a0) +80000470: 01852683 lw a3,24(a0) +80000474: 01c52303 lw t1,28(a0) +80000478: a2100553 fle.d a0,ft0,ft1 +8000047c: 00000393 li t2,0 +80000480: 001015f3 fsflags a1,zero +80000484: 01000613 li a2,16 +80000488: 08d51463 bne a0,a3,80000510 +8000048c: 08731263 bne t1,t2,80000510 +80000490: 08c59063 bne a1,a2,80000510 + +80000494 : +80000494: 00f00193 li gp,15 +80000498: 00002517 auipc a0,0x2 +8000049c: d0850513 addi a0,a0,-760 # 800021a0 +800004a0: 00053007 fld ft0,0(a0) +800004a4: 00853087 fld ft1,8(a0) +800004a8: 01053107 fld ft2,16(a0) +800004ac: 01852683 lw a3,24(a0) +800004b0: 01c52303 lw t1,28(a0) +800004b4: a2100553 fle.d a0,ft0,ft1 +800004b8: 00000393 li t2,0 +800004bc: 001015f3 fsflags a1,zero +800004c0: 01000613 li a2,16 +800004c4: 04d51663 bne a0,a3,80000510 +800004c8: 04731463 bne t1,t2,80000510 +800004cc: 04c59263 bne a1,a2,80000510 + +800004d0 : +800004d0: 01000193 li gp,16 +800004d4: 00002517 auipc a0,0x2 +800004d8: cec50513 addi a0,a0,-788 # 800021c0 +800004dc: 00053007 fld ft0,0(a0) +800004e0: 00853087 fld ft1,8(a0) +800004e4: 01053107 fld ft2,16(a0) +800004e8: 01852683 lw a3,24(a0) +800004ec: 01c52303 lw t1,28(a0) +800004f0: a2100553 fle.d a0,ft0,ft1 +800004f4: 00000393 li t2,0 +800004f8: 001015f3 fsflags a1,zero +800004fc: 01000613 li a2,16 +80000500: 00d51863 bne a0,a3,80000510 +80000504: 00731663 bne t1,t2,80000510 +80000508: 00c59463 bne a1,a2,80000510 +8000050c: 02301063 bne zero,gp,8000052c + +80000510 : +80000510: 0ff0000f fence +80000514: 00018063 beqz gp,80000514 +80000518: 00119193 slli gp,gp,0x1 +8000051c: 0011e193 ori gp,gp,1 +80000520: 05d00893 li a7,93 +80000524: 00018513 mv a0,gp +80000528: 00000073 ecall + +8000052c : +8000052c: 0ff0000f fence +80000530: 00100193 li gp,1 +80000534: 05d00893 li a7,93 +80000538: 00000513 li a0,0 +8000053c: 00000073 ecall +80000540: c0001073 unimp + +Disassembly of section .data: + +80002000 : +80002000: 5c28f5c3 0x5c28f5c3 +80002004: bff5c28f 0xbff5c28f +80002008: 5c28f5c3 0x5c28f5c3 +8000200c: bff5c28f 0xbff5c28f +80002010: 0000 unimp +80002012: 0000 unimp +80002014: 0000 unimp +80002016: 0000 unimp +80002018: 0001 nop +8000201a: 0000 unimp +8000201c: 0000 unimp +8000201e: 0000 unimp + +80002020 : +80002020: 5c28f5c3 0x5c28f5c3 +80002024: bff5c28f 0xbff5c28f +80002028: 5c28f5c3 0x5c28f5c3 +8000202c: bff5c28f 0xbff5c28f +80002030: 0000 unimp +80002032: 0000 unimp +80002034: 0000 unimp +80002036: 0000 unimp +80002038: 0001 nop +8000203a: 0000 unimp +8000203c: 0000 unimp +8000203e: 0000 unimp + +80002040 : +80002040: 5c28f5c3 0x5c28f5c3 +80002044: bff5c28f 0xbff5c28f +80002048: 5c28f5c3 0x5c28f5c3 +8000204c: bff5c28f 0xbff5c28f +80002050: 0000 unimp +80002052: 0000 unimp +80002054: 0000 unimp +80002056: 0000 unimp +80002058: 0000 unimp +8000205a: 0000 unimp +8000205c: 0000 unimp +8000205e: 0000 unimp + +80002060 : +80002060: 51ec lw a1,100(a1) +80002062: 1eb8 addi a4,sp,888 +80002064: eb85 bnez a5,80002094 +80002066: bff5 j 80002062 +80002068: 5c28f5c3 0x5c28f5c3 +8000206c: bff5c28f 0xbff5c28f +80002070: 0000 unimp +80002072: 0000 unimp +80002074: 0000 unimp +80002076: 0000 unimp +80002078: 0000 unimp +8000207a: 0000 unimp +8000207c: 0000 unimp +8000207e: 0000 unimp + +80002080 : +80002080: 51ec lw a1,100(a1) +80002082: 1eb8 addi a4,sp,888 +80002084: eb85 bnez a5,800020b4 +80002086: bff5 j 80002082 +80002088: 5c28f5c3 0x5c28f5c3 +8000208c: bff5c28f 0xbff5c28f +80002090: 0000 unimp +80002092: 0000 unimp +80002094: 0000 unimp +80002096: 0000 unimp +80002098: 0001 nop +8000209a: 0000 unimp +8000209c: 0000 unimp +8000209e: 0000 unimp + +800020a0 : +800020a0: 51ec lw a1,100(a1) +800020a2: 1eb8 addi a4,sp,888 +800020a4: eb85 bnez a5,800020d4 +800020a6: bff5 j 800020a2 +800020a8: 5c28f5c3 0x5c28f5c3 +800020ac: bff5c28f 0xbff5c28f +800020b0: 0000 unimp +800020b2: 0000 unimp +800020b4: 0000 unimp +800020b6: 0000 unimp +800020b8: 0001 nop +800020ba: 0000 unimp +800020bc: 0000 unimp +800020be: 0000 unimp + +800020c0 : +800020c0: ffff 0xffff +800020c2: ffff 0xffff +800020c4: ffff 0xffff +800020c6: 7fff 0x7fff +800020c8: 0000 unimp +800020ca: 0000 unimp +800020cc: 0000 unimp +800020ce: 0000 unimp +800020d0: 0000 unimp +800020d2: 0000 unimp +800020d4: 0000 unimp +800020d6: 0000 unimp +800020d8: 0000 unimp +800020da: 0000 unimp +800020dc: 0000 unimp +800020de: 0000 unimp + +800020e0 : +800020e0: ffff 0xffff +800020e2: ffff 0xffff +800020e4: ffff 0xffff +800020e6: 7fff 0x7fff +800020e8: ffff 0xffff +800020ea: ffff 0xffff +800020ec: ffff 0xffff +800020ee: 7fff 0x7fff +800020f0: 0000 unimp +800020f2: 0000 unimp +800020f4: 0000 unimp +800020f6: 0000 unimp +800020f8: 0000 unimp +800020fa: 0000 unimp +800020fc: 0000 unimp +800020fe: 0000 unimp + +80002100 : +80002100: 0001 nop +80002102: 0000 unimp +80002104: 0000 unimp +80002106: 7ff0 flw fa2,124(a5) +80002108: 0000 unimp +8000210a: 0000 unimp +8000210c: 0000 unimp +8000210e: 0000 unimp +80002110: 0000 unimp +80002112: 0000 unimp +80002114: 0000 unimp +80002116: 0000 unimp +80002118: 0000 unimp +8000211a: 0000 unimp +8000211c: 0000 unimp +8000211e: 0000 unimp + +80002120 : +80002120: ffff 0xffff +80002122: ffff 0xffff +80002124: ffff 0xffff +80002126: 7fff 0x7fff +80002128: 0000 unimp +8000212a: 0000 unimp +8000212c: 0000 unimp +8000212e: 0000 unimp +80002130: 0000 unimp +80002132: 0000 unimp +80002134: 0000 unimp +80002136: 0000 unimp +80002138: 0000 unimp +8000213a: 0000 unimp +8000213c: 0000 unimp +8000213e: 0000 unimp + +80002140 : +80002140: ffff 0xffff +80002142: ffff 0xffff +80002144: ffff 0xffff +80002146: 7fff 0x7fff +80002148: ffff 0xffff +8000214a: ffff 0xffff +8000214c: ffff 0xffff +8000214e: 7fff 0x7fff +80002150: 0000 unimp +80002152: 0000 unimp +80002154: 0000 unimp +80002156: 0000 unimp +80002158: 0000 unimp +8000215a: 0000 unimp +8000215c: 0000 unimp +8000215e: 0000 unimp + +80002160 : +80002160: 0001 nop +80002162: 0000 unimp +80002164: 0000 unimp +80002166: 7ff0 flw fa2,124(a5) +80002168: 0000 unimp +8000216a: 0000 unimp +8000216c: 0000 unimp +8000216e: 0000 unimp +80002170: 0000 unimp +80002172: 0000 unimp +80002174: 0000 unimp +80002176: 0000 unimp +80002178: 0000 unimp +8000217a: 0000 unimp +8000217c: 0000 unimp +8000217e: 0000 unimp + +80002180 : +80002180: ffff 0xffff +80002182: ffff 0xffff +80002184: ffff 0xffff +80002186: 7fff 0x7fff +80002188: 0000 unimp +8000218a: 0000 unimp +8000218c: 0000 unimp +8000218e: 0000 unimp +80002190: 0000 unimp +80002192: 0000 unimp +80002194: 0000 unimp +80002196: 0000 unimp +80002198: 0000 unimp +8000219a: 0000 unimp +8000219c: 0000 unimp +8000219e: 0000 unimp + +800021a0 : +800021a0: ffff 0xffff +800021a2: ffff 0xffff +800021a4: ffff 0xffff +800021a6: 7fff 0x7fff +800021a8: ffff 0xffff +800021aa: ffff 0xffff +800021ac: ffff 0xffff +800021ae: 7fff 0x7fff +800021b0: 0000 unimp +800021b2: 0000 unimp +800021b4: 0000 unimp +800021b6: 0000 unimp +800021b8: 0000 unimp +800021ba: 0000 unimp +800021bc: 0000 unimp +800021be: 0000 unimp + +800021c0 : +800021c0: 0001 nop +800021c2: 0000 unimp +800021c4: 0000 unimp +800021c6: 7ff0 flw fa2,124(a5) +800021c8: 0000 unimp +800021ca: 0000 unimp +800021cc: 0000 unimp +800021ce: 0000 unimp +800021d0: 0000 unimp +800021d2: 0000 unimp +800021d4: 0000 unimp +800021d6: 0000 unimp +800021d8: 0000 unimp +800021da: 0000 unimp +800021dc: 0000 unimp +800021de: 0000 unimp diff --git a/src/test/resources/asm/rv32ud-p-fcvt.dump b/src/test/resources/asm/rv32ud-p-fcvt.dump new file mode 100644 index 00000000..f489b6c2 --- /dev/null +++ b/src/test/resources/asm/rv32ud-p-fcvt.dump @@ -0,0 +1,346 @@ + +rv32ud-p-fcvt: file format elf32-littleriscv + + +Disassembly of section .text.init: + +80000000 <_start>: +80000000: 04c0006f j 8000004c + +80000004 : +80000004: 34202f73 csrr t5,mcause +80000008: 00800f93 li t6,8 +8000000c: 03ff0a63 beq t5,t6,80000040 +80000010: 00900f93 li t6,9 +80000014: 03ff0663 beq t5,t6,80000040 +80000018: 00b00f93 li t6,11 +8000001c: 03ff0263 beq t5,t6,80000040 +80000020: 80000f17 auipc t5,0x80000 +80000024: fe0f0f13 addi t5,t5,-32 # 0 <_start-0x80000000> +80000028: 000f0463 beqz t5,80000030 +8000002c: 000f0067 jr t5 +80000030: 34202f73 csrr t5,mcause +80000034: 000f5463 bgez t5,8000003c +80000038: 0040006f j 8000003c + +8000003c : +8000003c: 5391e193 ori gp,gp,1337 + +80000040 : +80000040: 00001f17 auipc t5,0x1 +80000044: fc3f2023 sw gp,-64(t5) # 80001000 +80000048: ff9ff06f j 80000040 + +8000004c : +8000004c: 00000093 li ra,0 +80000050: 00000113 li sp,0 +80000054: 00000193 li gp,0 +80000058: 00000213 li tp,0 +8000005c: 00000293 li t0,0 +80000060: 00000313 li t1,0 +80000064: 00000393 li t2,0 +80000068: 00000413 li s0,0 +8000006c: 00000493 li s1,0 +80000070: 00000513 li a0,0 +80000074: 00000593 li a1,0 +80000078: 00000613 li a2,0 +8000007c: 00000693 li a3,0 +80000080: 00000713 li a4,0 +80000084: 00000793 li a5,0 +80000088: 00000813 li a6,0 +8000008c: 00000893 li a7,0 +80000090: 00000913 li s2,0 +80000094: 00000993 li s3,0 +80000098: 00000a13 li s4,0 +8000009c: 00000a93 li s5,0 +800000a0: 00000b13 li s6,0 +800000a4: 00000b93 li s7,0 +800000a8: 00000c13 li s8,0 +800000ac: 00000c93 li s9,0 +800000b0: 00000d13 li s10,0 +800000b4: 00000d93 li s11,0 +800000b8: 00000e13 li t3,0 +800000bc: 00000e93 li t4,0 +800000c0: 00000f13 li t5,0 +800000c4: 00000f93 li t6,0 +800000c8: f1402573 csrr a0,mhartid +800000cc: 00051063 bnez a0,800000cc +800000d0: 00000297 auipc t0,0x0 +800000d4: 01028293 addi t0,t0,16 # 800000e0 +800000d8: 30529073 csrw mtvec,t0 +800000dc: 18005073 csrwi satp,0 +800000e0: 00000297 auipc t0,0x0 +800000e4: 02028293 addi t0,t0,32 # 80000100 +800000e8: 30529073 csrw mtvec,t0 +800000ec: 800002b7 lui t0,0x80000 +800000f0: fff28293 addi t0,t0,-1 # 7fffffff <_end+0xffffdf8f> +800000f4: 3b029073 csrw pmpaddr0,t0 +800000f8: 01f00293 li t0,31 +800000fc: 3a029073 csrw pmpcfg0,t0 +80000100: 30405073 csrwi mie,0 +80000104: 00000297 auipc t0,0x0 +80000108: 01428293 addi t0,t0,20 # 80000118 +8000010c: 30529073 csrw mtvec,t0 +80000110: 30205073 csrwi medeleg,0 +80000114: 30305073 csrwi mideleg,0 +80000118: 00000193 li gp,0 +8000011c: 00000297 auipc t0,0x0 +80000120: ee828293 addi t0,t0,-280 # 80000004 +80000124: 30529073 csrw mtvec,t0 +80000128: 00100513 li a0,1 +8000012c: 01f51513 slli a0,a0,0x1f +80000130: 00054c63 bltz a0,80000148 +80000134: 0ff0000f fence +80000138: 00100193 li gp,1 +8000013c: 05d00893 li a7,93 +80000140: 00000513 li a0,0 +80000144: 00000073 ecall +80000148: 80000297 auipc t0,0x80000 +8000014c: eb828293 addi t0,t0,-328 # 0 <_start-0x80000000> +80000150: 00028a63 beqz t0,80000164 +80000154: 10529073 csrw stvec,t0 +80000158: 0000b2b7 lui t0,0xb +8000015c: 10928293 addi t0,t0,265 # b109 <_start-0x7fff4ef7> +80000160: 30229073 csrw medeleg,t0 +80000164: 30005073 csrwi mstatus,0 +80000168: 00002537 lui a0,0x2 +8000016c: 30052073 csrs mstatus,a0 +80000170: 00305073 csrwi fcsr,0 +80000174: 00000297 auipc t0,0x0 +80000178: 01428293 addi t0,t0,20 # 80000188 +8000017c: 34129073 csrw mepc,t0 +80000180: f1402573 csrr a0,mhartid +80000184: 30200073 mret + +80000188 : +80000188: 00200193 li gp,2 +8000018c: 00002517 auipc a0,0x2 +80000190: e7450513 addi a0,a0,-396 # 80002000 +80000194: 00052683 lw a3,0(a0) +80000198: 00452703 lw a4,4(a0) +8000019c: 00200593 li a1,2 +800001a0: d2058053 fcvt.d.w ft0,a1 +800001a4: 00053027 fsd ft0,0(a0) +800001a8: 00452583 lw a1,4(a0) +800001ac: 00052503 lw a0,0(a0) +800001b0: 00101073 fsflags zero +800001b4: 16d51263 bne a0,a3,80000318 +800001b8: 16e59063 bne a1,a4,80000318 + +800001bc : +800001bc: 00300193 li gp,3 +800001c0: 00002517 auipc a0,0x2 +800001c4: e4850513 addi a0,a0,-440 # 80002008 +800001c8: 00052683 lw a3,0(a0) +800001cc: 00452703 lw a4,4(a0) +800001d0: ffe00593 li a1,-2 +800001d4: d2058053 fcvt.d.w ft0,a1 +800001d8: 00053027 fsd ft0,0(a0) +800001dc: 00452583 lw a1,4(a0) +800001e0: 00052503 lw a0,0(a0) +800001e4: 00101073 fsflags zero +800001e8: 12d51863 bne a0,a3,80000318 +800001ec: 12e59663 bne a1,a4,80000318 + +800001f0 : +800001f0: 00400193 li gp,4 +800001f4: 00002517 auipc a0,0x2 +800001f8: e1c50513 addi a0,a0,-484 # 80002010 +800001fc: 00052683 lw a3,0(a0) +80000200: 00452703 lw a4,4(a0) +80000204: 00200593 li a1,2 +80000208: d2158053 fcvt.d.wu ft0,a1 +8000020c: 00053027 fsd ft0,0(a0) +80000210: 00452583 lw a1,4(a0) +80000214: 00052503 lw a0,0(a0) +80000218: 00101073 fsflags zero +8000021c: 0ed51e63 bne a0,a3,80000318 +80000220: 0ee59c63 bne a1,a4,80000318 + +80000224 : +80000224: 00500193 li gp,5 +80000228: 00002517 auipc a0,0x2 +8000022c: df050513 addi a0,a0,-528 # 80002018 +80000230: 00052683 lw a3,0(a0) +80000234: 00452703 lw a4,4(a0) +80000238: ffe00593 li a1,-2 +8000023c: d2158053 fcvt.d.wu ft0,a1 +80000240: 00053027 fsd ft0,0(a0) +80000244: 00452583 lw a1,4(a0) +80000248: 00052503 lw a0,0(a0) +8000024c: 00101073 fsflags zero +80000250: 0cd51463 bne a0,a3,80000318 +80000254: 0ce59263 bne a1,a4,80000318 + +80000258 : +80000258: 00a00193 li gp,10 +8000025c: 00002517 auipc a0,0x2 +80000260: dc450513 addi a0,a0,-572 # 80002020 +80000264: 00053007 fld ft0,0(a0) +80000268: 00853087 fld ft1,8(a0) +8000026c: 01053107 fld ft2,16(a0) +80000270: 01852683 lw a3,24(a0) +80000274: 01c52303 lw t1,28(a0) +80000278: 401071d3 fcvt.s.d ft3,ft0 +8000027c: 420181d3 fcvt.d.s ft3,ft3 +80000280: 00353027 fsd ft3,0(a0) +80000284: 00452383 lw t2,4(a0) +80000288: 00052503 lw a0,0(a0) +8000028c: 001015f3 fsflags a1,zero +80000290: 00000613 li a2,0 +80000294: 08d51263 bne a0,a3,80000318 +80000298: 08731063 bne t1,t2,80000318 +8000029c: 06c59e63 bne a1,a2,80000318 + +800002a0 : +800002a0: 00b00193 li gp,11 +800002a4: 00002517 auipc a0,0x2 +800002a8: d9c50513 addi a0,a0,-612 # 80002040 +800002ac: 00052007 flw ft0,0(a0) +800002b0: 00452087 flw ft1,4(a0) +800002b4: 00852107 flw ft2,8(a0) +800002b8: 00c52683 lw a3,12(a0) +800002bc: 420001d3 fcvt.d.s ft3,ft0 +800002c0: 4011f1d3 fcvt.s.d ft3,ft3 +800002c4: e0018553 fmv.x.w a0,ft3 +800002c8: 001015f3 fsflags a1,zero +800002cc: 00000613 li a2,0 +800002d0: 04d51463 bne a0,a3,80000318 +800002d4: 04c59263 bne a1,a2,80000318 + +800002d8 : +800002d8: 00002597 auipc a1,0x2 +800002dc: d8858593 addi a1,a1,-632 # 80002060 +800002e0: 0005b107 fld ft2,0(a1) +800002e4: 40117153 fcvt.s.d ft2,ft2 +800002e8: 42010153 fcvt.d.s ft2,ft2 +800002ec: 0025b027 fsd ft2,0(a1) +800002f0: 0005a503 lw a0,0(a1) +800002f4: 0045a583 lw a1,4(a1) +800002f8: 00002797 auipc a5,0x2 +800002fc: d5878793 addi a5,a5,-680 # 80002050 +80000300: 0007a383 lw t2,0(a5) +80000304: 0047a783 lw a5,4(a5) +80000308: 00c00193 li gp,12 +8000030c: 00751663 bne a0,t2,80000318 +80000310: 00f59463 bne a1,a5,80000318 +80000314: 02301063 bne zero,gp,80000334 + +80000318 : +80000318: 0ff0000f fence +8000031c: 00018063 beqz gp,8000031c +80000320: 00119193 slli gp,gp,0x1 +80000324: 0011e193 ori gp,gp,1 +80000328: 05d00893 li a7,93 +8000032c: 00018513 mv a0,gp +80000330: 00000073 ecall + +80000334 : +80000334: 0ff0000f fence +80000338: 00100193 li gp,1 +8000033c: 05d00893 li a7,93 +80000340: 00000513 li a0,0 +80000344: 00000073 ecall +80000348: c0001073 unimp +8000034c: 0000 unimp +8000034e: 0000 unimp +80000350: 0000 unimp +80000352: 0000 unimp +80000354: 0000 unimp +80000356: 0000 unimp +80000358: 0000 unimp +8000035a: 0000 unimp +8000035c: 0000 unimp +8000035e: 0000 unimp +80000360: 0000 unimp +80000362: 0000 unimp +80000364: 0000 unimp +80000366: 0000 unimp +80000368: 0000 unimp +8000036a: 0000 unimp +8000036c: 0000 unimp +8000036e: 0000 unimp +80000370: 0000 unimp +80000372: 0000 unimp +80000374: 0000 unimp +80000376: 0000 unimp +80000378: 0000 unimp +8000037a: 0000 unimp +8000037c: 0000 unimp +8000037e: 0000 unimp +80000380: 0000 unimp +80000382: 0000 unimp + +Disassembly of section .data: + +80002000 : +80002000: 0000 unimp +80002002: 0000 unimp +80002004: 0000 unimp +80002006: 4000 lw s0,0(s0) + +80002008 : +80002008: 0000 unimp +8000200a: 0000 unimp +8000200c: 0000 unimp +8000200e: c000 sw s0,0(s0) + +80002010 : +80002010: 0000 unimp +80002012: 0000 unimp +80002014: 0000 unimp +80002016: 4000 lw s0,0(s0) + +80002018 : +80002018: 0000 unimp +8000201a: ffc0 fsw fs0,60(a5) +8000201c: ffff 0xffff +8000201e: jal gp,8000601e <_end+0x3fae> + +80002020 : +80002020: 0000 unimp +80002022: 0000 unimp +80002024: 0000 unimp +80002026: bff8 fsd fa4,248(a5) +80002028: 0000 unimp +8000202a: 0000 unimp +8000202c: 0000 unimp +8000202e: 0000 unimp +80002030: 0000 unimp +80002032: 0000 unimp +80002034: 0000 unimp +80002036: 0000 unimp +80002038: 0000 unimp +8000203a: 0000 unimp +8000203c: 0000 unimp +8000203e: bff8 fsd fa4,248(a5) + +80002040 : +80002040: 0000 unimp +80002042: bfc0 fsd fs0,184(a5) +80002044: 0000 unimp +80002046: 0000 unimp +80002048: 0000 unimp +8000204a: 0000 unimp +8000204c: 0000 unimp +8000204e: bfc0 fsd fs0,184(a5) + +80002050 : +80002050: 0000 unimp +80002052: 0000 unimp +80002054: 0000 unimp +80002056: 7ff8 flw fa4,124(a5) +80002058: 0000 unimp +8000205a: 0000 unimp +8000205c: 0000 unimp +8000205e: 0000 unimp + +80002060 : +80002060: 8004 0x8004 +80002062: ffff 0xffff +80002064: ffff 0xffff +80002066: 7ffc flw fa5,124(a5) +80002068: 0000 unimp +8000206a: 0000 unimp +8000206c: 0000 unimp +8000206e: 0000 unimp diff --git a/src/test/resources/asm/rv32ud-p-fcvt_w.dump b/src/test/resources/asm/rv32ud-p-fcvt_w.dump new file mode 100644 index 00000000..4d0e4e4a --- /dev/null +++ b/src/test/resources/asm/rv32ud-p-fcvt_w.dump @@ -0,0 +1,632 @@ + +rv32ud-p-fcvt_w: file format elf32-littleriscv + + +Disassembly of section .text.init: + +80000000 <_start>: +80000000: 04c0006f j 8000004c + +80000004 : +80000004: 34202f73 csrr t5,mcause +80000008: 00800f93 li t6,8 +8000000c: 03ff0a63 beq t5,t6,80000040 +80000010: 00900f93 li t6,9 +80000014: 03ff0663 beq t5,t6,80000040 +80000018: 00b00f93 li t6,11 +8000001c: 03ff0263 beq t5,t6,80000040 +80000020: 80000f17 auipc t5,0x80000 +80000024: fe0f0f13 addi t5,t5,-32 # 0 <_start-0x80000000> +80000028: 000f0463 beqz t5,80000030 +8000002c: 000f0067 jr t5 +80000030: 34202f73 csrr t5,mcause +80000034: 000f5463 bgez t5,8000003c +80000038: 0040006f j 8000003c + +8000003c : +8000003c: 5391e193 ori gp,gp,1337 + +80000040 : +80000040: 00001f17 auipc t5,0x1 +80000044: fc3f2023 sw gp,-64(t5) # 80001000 +80000048: ff9ff06f j 80000040 + +8000004c : +8000004c: 00000093 li ra,0 +80000050: 00000113 li sp,0 +80000054: 00000193 li gp,0 +80000058: 00000213 li tp,0 +8000005c: 00000293 li t0,0 +80000060: 00000313 li t1,0 +80000064: 00000393 li t2,0 +80000068: 00000413 li s0,0 +8000006c: 00000493 li s1,0 +80000070: 00000513 li a0,0 +80000074: 00000593 li a1,0 +80000078: 00000613 li a2,0 +8000007c: 00000693 li a3,0 +80000080: 00000713 li a4,0 +80000084: 00000793 li a5,0 +80000088: 00000813 li a6,0 +8000008c: 00000893 li a7,0 +80000090: 00000913 li s2,0 +80000094: 00000993 li s3,0 +80000098: 00000a13 li s4,0 +8000009c: 00000a93 li s5,0 +800000a0: 00000b13 li s6,0 +800000a4: 00000b93 li s7,0 +800000a8: 00000c13 li s8,0 +800000ac: 00000c93 li s9,0 +800000b0: 00000d13 li s10,0 +800000b4: 00000d93 li s11,0 +800000b8: 00000e13 li t3,0 +800000bc: 00000e93 li t4,0 +800000c0: 00000f13 li t5,0 +800000c4: 00000f93 li t6,0 +800000c8: f1402573 csrr a0,mhartid +800000cc: 00051063 bnez a0,800000cc +800000d0: 00000297 auipc t0,0x0 +800000d4: 01028293 addi t0,t0,16 # 800000e0 +800000d8: 30529073 csrw mtvec,t0 +800000dc: 18005073 csrwi satp,0 +800000e0: 00000297 auipc t0,0x0 +800000e4: 02028293 addi t0,t0,32 # 80000100 +800000e8: 30529073 csrw mtvec,t0 +800000ec: 800002b7 lui t0,0x80000 +800000f0: fff28293 addi t0,t0,-1 # 7fffffff <_end+0xffffdecf> +800000f4: 3b029073 csrw pmpaddr0,t0 +800000f8: 01f00293 li t0,31 +800000fc: 3a029073 csrw pmpcfg0,t0 +80000100: 30405073 csrwi mie,0 +80000104: 00000297 auipc t0,0x0 +80000108: 01428293 addi t0,t0,20 # 80000118 +8000010c: 30529073 csrw mtvec,t0 +80000110: 30205073 csrwi medeleg,0 +80000114: 30305073 csrwi mideleg,0 +80000118: 00000193 li gp,0 +8000011c: 00000297 auipc t0,0x0 +80000120: ee828293 addi t0,t0,-280 # 80000004 +80000124: 30529073 csrw mtvec,t0 +80000128: 00100513 li a0,1 +8000012c: 01f51513 slli a0,a0,0x1f +80000130: 00054c63 bltz a0,80000148 +80000134: 0ff0000f fence +80000138: 00100193 li gp,1 +8000013c: 05d00893 li a7,93 +80000140: 00000513 li a0,0 +80000144: 00000073 ecall +80000148: 80000297 auipc t0,0x80000 +8000014c: eb828293 addi t0,t0,-328 # 0 <_start-0x80000000> +80000150: 00028a63 beqz t0,80000164 +80000154: 10529073 csrw stvec,t0 +80000158: 0000b2b7 lui t0,0xb +8000015c: 10928293 addi t0,t0,265 # b109 <_start-0x7fff4ef7> +80000160: 30229073 csrw medeleg,t0 +80000164: 30005073 csrwi mstatus,0 +80000168: 00002537 lui a0,0x2 +8000016c: 30052073 csrs mstatus,a0 +80000170: 00305073 csrwi fcsr,0 +80000174: 00000297 auipc t0,0x0 +80000178: 01428293 addi t0,t0,20 # 80000188 +8000017c: 34129073 csrw mepc,t0 +80000180: f1402573 csrr a0,mhartid +80000184: 30200073 mret + +80000188 : +80000188: 00200193 li gp,2 +8000018c: 00002517 auipc a0,0x2 +80000190: e7450513 addi a0,a0,-396 # 80002000 +80000194: 00052007 flw ft0,0(a0) +80000198: 00452087 flw ft1,4(a0) +8000019c: 00852107 flw ft2,8(a0) +800001a0: 00c52683 lw a3,12(a0) +800001a4: c0001553 fcvt.w.s a0,ft0,rtz +800001a8: 001015f3 fsflags a1,zero +800001ac: 00100613 li a2,1 +800001b0: 3cd51463 bne a0,a3,80000578 +800001b4: 3cc59263 bne a1,a2,80000578 + +800001b8 : +800001b8: 00300193 li gp,3 +800001bc: 00002517 auipc a0,0x2 +800001c0: e5450513 addi a0,a0,-428 # 80002010 +800001c4: 00052007 flw ft0,0(a0) +800001c8: 00452087 flw ft1,4(a0) +800001cc: 00852107 flw ft2,8(a0) +800001d0: 00c52683 lw a3,12(a0) +800001d4: c0001553 fcvt.w.s a0,ft0,rtz +800001d8: 001015f3 fsflags a1,zero +800001dc: 00000613 li a2,0 +800001e0: 38d51c63 bne a0,a3,80000578 +800001e4: 38c59a63 bne a1,a2,80000578 + +800001e8 : +800001e8: 00400193 li gp,4 +800001ec: 00002517 auipc a0,0x2 +800001f0: e3450513 addi a0,a0,-460 # 80002020 +800001f4: 00052007 flw ft0,0(a0) +800001f8: 00452087 flw ft1,4(a0) +800001fc: 00852107 flw ft2,8(a0) +80000200: 00c52683 lw a3,12(a0) +80000204: c0001553 fcvt.w.s a0,ft0,rtz +80000208: 001015f3 fsflags a1,zero +8000020c: 00100613 li a2,1 +80000210: 36d51463 bne a0,a3,80000578 +80000214: 36c59263 bne a1,a2,80000578 + +80000218 : +80000218: 00500193 li gp,5 +8000021c: 00002517 auipc a0,0x2 +80000220: e1450513 addi a0,a0,-492 # 80002030 +80000224: 00052007 flw ft0,0(a0) +80000228: 00452087 flw ft1,4(a0) +8000022c: 00852107 flw ft2,8(a0) +80000230: 00c52683 lw a3,12(a0) +80000234: c0001553 fcvt.w.s a0,ft0,rtz +80000238: 001015f3 fsflags a1,zero +8000023c: 00100613 li a2,1 +80000240: 32d51c63 bne a0,a3,80000578 +80000244: 32c59a63 bne a1,a2,80000578 + +80000248 : +80000248: 00600193 li gp,6 +8000024c: 00002517 auipc a0,0x2 +80000250: df450513 addi a0,a0,-524 # 80002040 +80000254: 00052007 flw ft0,0(a0) +80000258: 00452087 flw ft1,4(a0) +8000025c: 00852107 flw ft2,8(a0) +80000260: 00c52683 lw a3,12(a0) +80000264: c0001553 fcvt.w.s a0,ft0,rtz +80000268: 001015f3 fsflags a1,zero +8000026c: 00000613 li a2,0 +80000270: 30d51463 bne a0,a3,80000578 +80000274: 30c59263 bne a1,a2,80000578 + +80000278 : +80000278: 00700193 li gp,7 +8000027c: 00002517 auipc a0,0x2 +80000280: dd450513 addi a0,a0,-556 # 80002050 +80000284: 00052007 flw ft0,0(a0) +80000288: 00452087 flw ft1,4(a0) +8000028c: 00852107 flw ft2,8(a0) +80000290: 00c52683 lw a3,12(a0) +80000294: c0001553 fcvt.w.s a0,ft0,rtz +80000298: 001015f3 fsflags a1,zero +8000029c: 00100613 li a2,1 +800002a0: 2cd51c63 bne a0,a3,80000578 +800002a4: 2cc59a63 bne a1,a2,80000578 + +800002a8 : +800002a8: 00800193 li gp,8 +800002ac: 00002517 auipc a0,0x2 +800002b0: db450513 addi a0,a0,-588 # 80002060 +800002b4: 00052007 flw ft0,0(a0) +800002b8: 00452087 flw ft1,4(a0) +800002bc: 00852107 flw ft2,8(a0) +800002c0: 00c52683 lw a3,12(a0) +800002c4: c0001553 fcvt.w.s a0,ft0,rtz +800002c8: 001015f3 fsflags a1,zero +800002cc: 01000613 li a2,16 +800002d0: 2ad51463 bne a0,a3,80000578 +800002d4: 2ac59263 bne a1,a2,80000578 + +800002d8 : +800002d8: 00900193 li gp,9 +800002dc: 00002517 auipc a0,0x2 +800002e0: d9450513 addi a0,a0,-620 # 80002070 +800002e4: 00052007 flw ft0,0(a0) +800002e8: 00452087 flw ft1,4(a0) +800002ec: 00852107 flw ft2,8(a0) +800002f0: 00c52683 lw a3,12(a0) +800002f4: c0001553 fcvt.w.s a0,ft0,rtz +800002f8: 001015f3 fsflags a1,zero +800002fc: 01000613 li a2,16 +80000300: 26d51c63 bne a0,a3,80000578 +80000304: 26c59a63 bne a1,a2,80000578 + +80000308 : +80000308: 00c00193 li gp,12 +8000030c: 00002517 auipc a0,0x2 +80000310: d7450513 addi a0,a0,-652 # 80002080 +80000314: 00052007 flw ft0,0(a0) +80000318: 00452087 flw ft1,4(a0) +8000031c: 00852107 flw ft2,8(a0) +80000320: 00c52683 lw a3,12(a0) +80000324: c0101553 fcvt.wu.s a0,ft0,rtz +80000328: 001015f3 fsflags a1,zero +8000032c: 01000613 li a2,16 +80000330: 24d51463 bne a0,a3,80000578 +80000334: 24c59263 bne a1,a2,80000578 + +80000338 : +80000338: 00d00193 li gp,13 +8000033c: 00002517 auipc a0,0x2 +80000340: d5450513 addi a0,a0,-684 # 80002090 +80000344: 00052007 flw ft0,0(a0) +80000348: 00452087 flw ft1,4(a0) +8000034c: 00852107 flw ft2,8(a0) +80000350: 00c52683 lw a3,12(a0) +80000354: c0101553 fcvt.wu.s a0,ft0,rtz +80000358: 001015f3 fsflags a1,zero +8000035c: 01000613 li a2,16 +80000360: 20d51c63 bne a0,a3,80000578 +80000364: 20c59a63 bne a1,a2,80000578 + +80000368 : +80000368: 00e00193 li gp,14 +8000036c: 00002517 auipc a0,0x2 +80000370: d3450513 addi a0,a0,-716 # 800020a0 +80000374: 00052007 flw ft0,0(a0) +80000378: 00452087 flw ft1,4(a0) +8000037c: 00852107 flw ft2,8(a0) +80000380: 00c52683 lw a3,12(a0) +80000384: c0101553 fcvt.wu.s a0,ft0,rtz +80000388: 001015f3 fsflags a1,zero +8000038c: 00100613 li a2,1 +80000390: 1ed51463 bne a0,a3,80000578 +80000394: 1ec59263 bne a1,a2,80000578 + +80000398 : +80000398: 00f00193 li gp,15 +8000039c: 00002517 auipc a0,0x2 +800003a0: d1450513 addi a0,a0,-748 # 800020b0 +800003a4: 00052007 flw ft0,0(a0) +800003a8: 00452087 flw ft1,4(a0) +800003ac: 00852107 flw ft2,8(a0) +800003b0: 00c52683 lw a3,12(a0) +800003b4: c0101553 fcvt.wu.s a0,ft0,rtz +800003b8: 001015f3 fsflags a1,zero +800003bc: 00100613 li a2,1 +800003c0: 1ad51c63 bne a0,a3,80000578 +800003c4: 1ac59a63 bne a1,a2,80000578 + +800003c8 : +800003c8: 01000193 li gp,16 +800003cc: 00002517 auipc a0,0x2 +800003d0: cf450513 addi a0,a0,-780 # 800020c0 +800003d4: 00052007 flw ft0,0(a0) +800003d8: 00452087 flw ft1,4(a0) +800003dc: 00852107 flw ft2,8(a0) +800003e0: 00c52683 lw a3,12(a0) +800003e4: c0101553 fcvt.wu.s a0,ft0,rtz +800003e8: 001015f3 fsflags a1,zero +800003ec: 00000613 li a2,0 +800003f0: 18d51463 bne a0,a3,80000578 +800003f4: 18c59263 bne a1,a2,80000578 + +800003f8 : +800003f8: 01100193 li gp,17 +800003fc: 00002517 auipc a0,0x2 +80000400: cd450513 addi a0,a0,-812 # 800020d0 +80000404: 00052007 flw ft0,0(a0) +80000408: 00452087 flw ft1,4(a0) +8000040c: 00852107 flw ft2,8(a0) +80000410: 00c52683 lw a3,12(a0) +80000414: c0101553 fcvt.wu.s a0,ft0,rtz +80000418: 001015f3 fsflags a1,zero +8000041c: 00100613 li a2,1 +80000420: 14d51c63 bne a0,a3,80000578 +80000424: 14c59a63 bne a1,a2,80000578 + +80000428 : +80000428: 01200193 li gp,18 +8000042c: 00002517 auipc a0,0x2 +80000430: cb450513 addi a0,a0,-844 # 800020e0 +80000434: 00052007 flw ft0,0(a0) +80000438: 00452087 flw ft1,4(a0) +8000043c: 00852107 flw ft2,8(a0) +80000440: 00c52683 lw a3,12(a0) +80000444: c0101553 fcvt.wu.s a0,ft0,rtz +80000448: 001015f3 fsflags a1,zero +8000044c: 01000613 li a2,16 +80000450: 12d51463 bne a0,a3,80000578 +80000454: 12c59263 bne a1,a2,80000578 + +80000458 : +80000458: 01300193 li gp,19 +8000045c: 00002517 auipc a0,0x2 +80000460: c9450513 addi a0,a0,-876 # 800020f0 +80000464: 00052007 flw ft0,0(a0) +80000468: 00452087 flw ft1,4(a0) +8000046c: 00852107 flw ft2,8(a0) +80000470: 00c52683 lw a3,12(a0) +80000474: c0101553 fcvt.wu.s a0,ft0,rtz +80000478: 001015f3 fsflags a1,zero +8000047c: 00000613 li a2,0 +80000480: 0ed51c63 bne a0,a3,80000578 +80000484: 0ec59a63 bne a1,a2,80000578 + +80000488 : +80000488: 00002097 auipc ra,0x2 +8000048c: c7808093 addi ra,ra,-904 # 80002100 +80000490: 0000a087 flw ft1,0(ra) +80000494: c000f0d3 fcvt.w.s ra,ft1 +80000498: 800003b7 lui t2,0x80000 +8000049c: fff38393 addi t2,t2,-1 # 7fffffff <_end+0xffffdecf> +800004a0: 02a00193 li gp,42 +800004a4: 0c709a63 bne ra,t2,80000578 + +800004a8 : +800004a8: 00002097 auipc ra,0x2 +800004ac: c5808093 addi ra,ra,-936 # 80002100 +800004b0: 0080a087 flw ft1,8(ra) +800004b4: c000f0d3 fcvt.w.s ra,ft1 +800004b8: 800003b7 lui t2,0x80000 +800004bc: 02c00193 li gp,44 +800004c0: 0a709c63 bne ra,t2,80000578 + +800004c4 : +800004c4: 00002097 auipc ra,0x2 +800004c8: c3c08093 addi ra,ra,-964 # 80002100 +800004cc: 0040a087 flw ft1,4(ra) +800004d0: c000f0d3 fcvt.w.s ra,ft1 +800004d4: 800003b7 lui t2,0x80000 +800004d8: fff38393 addi t2,t2,-1 # 7fffffff <_end+0xffffdecf> +800004dc: 03400193 li gp,52 +800004e0: 08709c63 bne ra,t2,80000578 + +800004e4 : +800004e4: 00002097 auipc ra,0x2 +800004e8: c1c08093 addi ra,ra,-996 # 80002100 +800004ec: 00c0a087 flw ft1,12(ra) +800004f0: c000f0d3 fcvt.w.s ra,ft1 +800004f4: 800003b7 lui t2,0x80000 +800004f8: fff38393 addi t2,t2,-1 # 7fffffff <_end+0xffffdecf> +800004fc: 03600193 li gp,54 +80000500: 06709c63 bne ra,t2,80000578 + +80000504 : +80000504: 00002097 auipc ra,0x2 +80000508: bfc08093 addi ra,ra,-1028 # 80002100 +8000050c: 0000a087 flw ft1,0(ra) +80000510: c010f0d3 fcvt.wu.s ra,ft1 +80000514: fff00393 li t2,-1 +80000518: 03e00193 li gp,62 +8000051c: 04709e63 bne ra,t2,80000578 + +80000520 : +80000520: 00002097 auipc ra,0x2 +80000524: be008093 addi ra,ra,-1056 # 80002100 +80000528: 0040a087 flw ft1,4(ra) +8000052c: c010f0d3 fcvt.wu.s ra,ft1 +80000530: fff00393 li t2,-1 +80000534: 03f00193 li gp,63 +80000538: 04709063 bne ra,t2,80000578 + +8000053c : +8000053c: 00002097 auipc ra,0x2 +80000540: bc408093 addi ra,ra,-1084 # 80002100 +80000544: 0080a087 flw ft1,8(ra) +80000548: c010f0d3 fcvt.wu.s ra,ft1 +8000054c: 00000393 li t2,0 +80000550: 04000193 li gp,64 +80000554: 02709263 bne ra,t2,80000578 + +80000558 : +80000558: 00002097 auipc ra,0x2 +8000055c: ba808093 addi ra,ra,-1112 # 80002100 +80000560: 00c0a087 flw ft1,12(ra) +80000564: c010f0d3 fcvt.wu.s ra,ft1 +80000568: fff00393 li t2,-1 +8000056c: 04100193 li gp,65 +80000570: 00709463 bne ra,t2,80000578 +80000574: 02301063 bne zero,gp,80000594 + +80000578 : +80000578: 0ff0000f fence +8000057c: 00018063 beqz gp,8000057c +80000580: 00119193 slli gp,gp,0x1 +80000584: 0011e193 ori gp,gp,1 +80000588: 05d00893 li a7,93 +8000058c: 00018513 mv a0,gp +80000590: 00000073 ecall + +80000594 : +80000594: 0ff0000f fence +80000598: 00100193 li gp,1 +8000059c: 05d00893 li a7,93 +800005a0: 00000513 li a0,0 +800005a4: 00000073 ecall +800005a8: c0001073 unimp +800005ac: 0000 unimp +800005ae: 0000 unimp +800005b0: 0000 unimp +800005b2: 0000 unimp +800005b4: 0000 unimp +800005b6: 0000 unimp +800005b8: 0000 unimp +800005ba: 0000 unimp +800005bc: 0000 unimp +800005be: 0000 unimp +800005c0: 0000 unimp +800005c2: 0000 unimp + +Disassembly of section .data: + +80002000 : +80002000: cccd beqz s1,800020ba +80002002: bf8c fsd fa1,56(a5) +80002004: 0000 unimp +80002006: 0000 unimp +80002008: 0000 unimp +8000200a: 0000 unimp +8000200c: ffff 0xffff +8000200e: ffff 0xffff + +80002010 : +80002010: 0000 unimp +80002012: bf80 fsd fs0,56(a5) +80002014: 0000 unimp +80002016: 0000 unimp +80002018: 0000 unimp +8000201a: 0000 unimp +8000201c: ffff 0xffff +8000201e: ffff 0xffff + +80002020 : +80002020: 6666 flw fa2,88(sp) +80002022: bf66 fsd fs9,440(sp) +80002024: 0000 unimp +80002026: 0000 unimp +80002028: 0000 unimp +8000202a: 0000 unimp +8000202c: 0000 unimp +8000202e: 0000 unimp + +80002030 : +80002030: 6666 flw fa2,88(sp) +80002032: 3f66 fld ft10,120(sp) +80002034: 0000 unimp +80002036: 0000 unimp +80002038: 0000 unimp +8000203a: 0000 unimp +8000203c: 0000 unimp +8000203e: 0000 unimp + +80002040 : +80002040: 0000 unimp +80002042: 3f80 fld fs0,56(a5) +80002044: 0000 unimp +80002046: 0000 unimp +80002048: 0000 unimp +8000204a: 0000 unimp +8000204c: 0001 nop +8000204e: 0000 unimp + +80002050 : +80002050: cccd beqz s1,8000210a +80002052: 3f8c fld fa1,56(a5) +80002054: 0000 unimp +80002056: 0000 unimp +80002058: 0000 unimp +8000205a: 0000 unimp +8000205c: 0001 nop +8000205e: 0000 unimp + +80002060 : +80002060: d05e sw s7,32(sp) +80002062: cf32 sw a2,156(sp) +80002064: 0000 unimp +80002066: 0000 unimp +80002068: 0000 unimp +8000206a: 0000 unimp +8000206c: 0000 unimp +8000206e: 8000 0x8000 + +80002070 : +80002070: d05e sw s7,32(sp) +80002072: 4f32 lw t5,12(sp) +80002074: 0000 unimp +80002076: 0000 unimp +80002078: 0000 unimp +8000207a: 0000 unimp +8000207c: ffff 0xffff +8000207e: 7fff 0x7fff + +80002080 : +80002080: 0000 unimp +80002082: c040 sw s0,4(s0) +80002084: 0000 unimp +80002086: 0000 unimp +80002088: 0000 unimp +8000208a: 0000 unimp +8000208c: 0000 unimp +8000208e: 0000 unimp + +80002090 : +80002090: 0000 unimp +80002092: bf80 fsd fs0,56(a5) +80002094: 0000 unimp +80002096: 0000 unimp +80002098: 0000 unimp +8000209a: 0000 unimp +8000209c: 0000 unimp +8000209e: 0000 unimp + +800020a0 : +800020a0: 6666 flw fa2,88(sp) +800020a2: bf66 fsd fs9,440(sp) +800020a4: 0000 unimp +800020a6: 0000 unimp +800020a8: 0000 unimp +800020aa: 0000 unimp +800020ac: 0000 unimp +800020ae: 0000 unimp + +800020b0 : +800020b0: 6666 flw fa2,88(sp) +800020b2: 3f66 fld ft10,120(sp) +800020b4: 0000 unimp +800020b6: 0000 unimp +800020b8: 0000 unimp +800020ba: 0000 unimp +800020bc: 0000 unimp +800020be: 0000 unimp + +800020c0 : +800020c0: 0000 unimp +800020c2: 3f80 fld fs0,56(a5) +800020c4: 0000 unimp +800020c6: 0000 unimp +800020c8: 0000 unimp +800020ca: 0000 unimp +800020cc: 0001 nop +800020ce: 0000 unimp + +800020d0 : +800020d0: cccd beqz s1,8000218a <_end+0x5a> +800020d2: 3f8c fld fa1,56(a5) +800020d4: 0000 unimp +800020d6: 0000 unimp +800020d8: 0000 unimp +800020da: 0000 unimp +800020dc: 0001 nop +800020de: 0000 unimp + +800020e0 : +800020e0: d05e sw s7,32(sp) +800020e2: cf32 sw a2,156(sp) +800020e4: 0000 unimp +800020e6: 0000 unimp +800020e8: 0000 unimp +800020ea: 0000 unimp +800020ec: 0000 unimp +800020ee: 0000 unimp + +800020f0 : +800020f0: d05e sw s7,32(sp) +800020f2: 4f32 lw t5,12(sp) +800020f4: 0000 unimp +800020f6: 0000 unimp +800020f8: 0000 unimp +800020fa: 0000 unimp +800020fc: 5e00 lw s0,56(a2) +800020fe: b2d0 fsd fa2,160(a3) + +80002100 : +80002100: ffff 0xffff +80002102: ffff 0xffff +80002104: ffff 0xffff +80002106: 7fff 0x7fff +80002108: 0000 unimp +8000210a: ff80 fsw fs0,56(a5) +8000210c: 0000 unimp +8000210e: 7f80 flw fs0,56(a5) + +80002110 : +80002110: ffff 0xffff +80002112: ffff 0xffff +80002114: ffff 0xffff +80002116: ffff 0xffff +80002118: ffff 0xffff +8000211a: ffff 0xffff +8000211c: ffff 0xffff +8000211e: 7fff 0x7fff +80002120: 0000 unimp +80002122: 0000 unimp +80002124: 0000 unimp +80002126: fff0 fsw fa2,124(a5) +80002128: 0000 unimp +8000212a: 0000 unimp +8000212c: 0000 unimp +8000212e: 7ff0 flw fa2,124(a5) diff --git a/src/test/resources/asm/rv32ud-p-fdiv.dump b/src/test/resources/asm/rv32ud-p-fdiv.dump new file mode 100644 index 00000000..71c3cf45 --- /dev/null +++ b/src/test/resources/asm/rv32ud-p-fdiv.dump @@ -0,0 +1,435 @@ + +rv32ud-p-fdiv: file format elf32-littleriscv + + +Disassembly of section .text.init: + +80000000 <_start>: +80000000: 04c0006f j 8000004c + +80000004 : +80000004: 34202f73 csrr t5,mcause +80000008: 00800f93 li t6,8 +8000000c: 03ff0a63 beq t5,t6,80000040 +80000010: 00900f93 li t6,9 +80000014: 03ff0663 beq t5,t6,80000040 +80000018: 00b00f93 li t6,11 +8000001c: 03ff0263 beq t5,t6,80000040 +80000020: 80000f17 auipc t5,0x80000 +80000024: fe0f0f13 addi t5,t5,-32 # 0 <_start-0x80000000> +80000028: 000f0463 beqz t5,80000030 +8000002c: 000f0067 jr t5 +80000030: 34202f73 csrr t5,mcause +80000034: 000f5463 bgez t5,8000003c +80000038: 0040006f j 8000003c + +8000003c : +8000003c: 5391e193 ori gp,gp,1337 + +80000040 : +80000040: 00001f17 auipc t5,0x1 +80000044: fc3f2023 sw gp,-64(t5) # 80001000 +80000048: ff9ff06f j 80000040 + +8000004c : +8000004c: 00000093 li ra,0 +80000050: 00000113 li sp,0 +80000054: 00000193 li gp,0 +80000058: 00000213 li tp,0 +8000005c: 00000293 li t0,0 +80000060: 00000313 li t1,0 +80000064: 00000393 li t2,0 +80000068: 00000413 li s0,0 +8000006c: 00000493 li s1,0 +80000070: 00000513 li a0,0 +80000074: 00000593 li a1,0 +80000078: 00000613 li a2,0 +8000007c: 00000693 li a3,0 +80000080: 00000713 li a4,0 +80000084: 00000793 li a5,0 +80000088: 00000813 li a6,0 +8000008c: 00000893 li a7,0 +80000090: 00000913 li s2,0 +80000094: 00000993 li s3,0 +80000098: 00000a13 li s4,0 +8000009c: 00000a93 li s5,0 +800000a0: 00000b13 li s6,0 +800000a4: 00000b93 li s7,0 +800000a8: 00000c13 li s8,0 +800000ac: 00000c93 li s9,0 +800000b0: 00000d13 li s10,0 +800000b4: 00000d93 li s11,0 +800000b8: 00000e13 li t3,0 +800000bc: 00000e93 li t4,0 +800000c0: 00000f13 li t5,0 +800000c4: 00000f93 li t6,0 +800000c8: f1402573 csrr a0,mhartid +800000cc: 00051063 bnez a0,800000cc +800000d0: 00000297 auipc t0,0x0 +800000d4: 01028293 addi t0,t0,16 # 800000e0 +800000d8: 30529073 csrw mtvec,t0 +800000dc: 18005073 csrwi satp,0 +800000e0: 00000297 auipc t0,0x0 +800000e4: 02028293 addi t0,t0,32 # 80000100 +800000e8: 30529073 csrw mtvec,t0 +800000ec: 800002b7 lui t0,0x80000 +800000f0: fff28293 addi t0,t0,-1 # 7fffffff <_end+0xffffdeff> +800000f4: 3b029073 csrw pmpaddr0,t0 +800000f8: 01f00293 li t0,31 +800000fc: 3a029073 csrw pmpcfg0,t0 +80000100: 30405073 csrwi mie,0 +80000104: 00000297 auipc t0,0x0 +80000108: 01428293 addi t0,t0,20 # 80000118 +8000010c: 30529073 csrw mtvec,t0 +80000110: 30205073 csrwi medeleg,0 +80000114: 30305073 csrwi mideleg,0 +80000118: 00000193 li gp,0 +8000011c: 00000297 auipc t0,0x0 +80000120: ee828293 addi t0,t0,-280 # 80000004 +80000124: 30529073 csrw mtvec,t0 +80000128: 00100513 li a0,1 +8000012c: 01f51513 slli a0,a0,0x1f +80000130: 00054c63 bltz a0,80000148 +80000134: 0ff0000f fence +80000138: 00100193 li gp,1 +8000013c: 05d00893 li a7,93 +80000140: 00000513 li a0,0 +80000144: 00000073 ecall +80000148: 80000297 auipc t0,0x80000 +8000014c: eb828293 addi t0,t0,-328 # 0 <_start-0x80000000> +80000150: 00028a63 beqz t0,80000164 +80000154: 10529073 csrw stvec,t0 +80000158: 0000b2b7 lui t0,0xb +8000015c: 10928293 addi t0,t0,265 # b109 <_start-0x7fff4ef7> +80000160: 30229073 csrw medeleg,t0 +80000164: 30005073 csrwi mstatus,0 +80000168: 00002537 lui a0,0x2 +8000016c: 30052073 csrs mstatus,a0 +80000170: 00305073 csrwi fcsr,0 +80000174: 00000297 auipc t0,0x0 +80000178: 01428293 addi t0,t0,20 # 80000188 +8000017c: 34129073 csrw mepc,t0 +80000180: f1402573 csrr a0,mhartid +80000184: 30200073 mret + +80000188 : +80000188: 00200193 li gp,2 +8000018c: 00002517 auipc a0,0x2 +80000190: e7450513 addi a0,a0,-396 # 80002000 +80000194: 00053007 fld ft0,0(a0) +80000198: 00853087 fld ft1,8(a0) +8000019c: 01053107 fld ft2,16(a0) +800001a0: 01852683 lw a3,24(a0) +800001a4: 01c52303 lw t1,28(a0) +800001a8: 1a1071d3 fdiv.d ft3,ft0,ft1 +800001ac: 00353027 fsd ft3,0(a0) +800001b0: 00452383 lw t2,4(a0) +800001b4: 00052503 lw a0,0(a0) +800001b8: 001015f3 fsflags a1,zero +800001bc: 00100613 li a2,1 +800001c0: 1ed51663 bne a0,a3,800003ac +800001c4: 1e731463 bne t1,t2,800003ac +800001c8: 1ec59263 bne a1,a2,800003ac + +800001cc : +800001cc: 00300193 li gp,3 +800001d0: 00002517 auipc a0,0x2 +800001d4: e5050513 addi a0,a0,-432 # 80002020 +800001d8: 00053007 fld ft0,0(a0) +800001dc: 00853087 fld ft1,8(a0) +800001e0: 01053107 fld ft2,16(a0) +800001e4: 01852683 lw a3,24(a0) +800001e8: 01c52303 lw t1,28(a0) +800001ec: 1a1071d3 fdiv.d ft3,ft0,ft1 +800001f0: 00353027 fsd ft3,0(a0) +800001f4: 00452383 lw t2,4(a0) +800001f8: 00052503 lw a0,0(a0) +800001fc: 001015f3 fsflags a1,zero +80000200: 00100613 li a2,1 +80000204: 1ad51463 bne a0,a3,800003ac +80000208: 1a731263 bne t1,t2,800003ac +8000020c: 1ac59063 bne a1,a2,800003ac + +80000210 : +80000210: 00400193 li gp,4 +80000214: 00002517 auipc a0,0x2 +80000218: e2c50513 addi a0,a0,-468 # 80002040 +8000021c: 00053007 fld ft0,0(a0) +80000220: 00853087 fld ft1,8(a0) +80000224: 01053107 fld ft2,16(a0) +80000228: 01852683 lw a3,24(a0) +8000022c: 01c52303 lw t1,28(a0) +80000230: 1a1071d3 fdiv.d ft3,ft0,ft1 +80000234: 00353027 fsd ft3,0(a0) +80000238: 00452383 lw t2,4(a0) +8000023c: 00052503 lw a0,0(a0) +80000240: 001015f3 fsflags a1,zero +80000244: 00000613 li a2,0 +80000248: 16d51263 bne a0,a3,800003ac +8000024c: 16731063 bne t1,t2,800003ac +80000250: 14c59e63 bne a1,a2,800003ac + +80000254 : +80000254: 00500193 li gp,5 +80000258: 00002517 auipc a0,0x2 +8000025c: e0850513 addi a0,a0,-504 # 80002060 +80000260: 00053007 fld ft0,0(a0) +80000264: 00853087 fld ft1,8(a0) +80000268: 01053107 fld ft2,16(a0) +8000026c: 01852683 lw a3,24(a0) +80000270: 01c52303 lw t1,28(a0) +80000274: 5a0071d3 fsqrt.d ft3,ft0 +80000278: 00353027 fsd ft3,0(a0) +8000027c: 00452383 lw t2,4(a0) +80000280: 00052503 lw a0,0(a0) +80000284: 001015f3 fsflags a1,zero +80000288: 00100613 li a2,1 +8000028c: 12d51063 bne a0,a3,800003ac +80000290: 10731e63 bne t1,t2,800003ac +80000294: 10c59c63 bne a1,a2,800003ac + +80000298 : +80000298: 00600193 li gp,6 +8000029c: 00002517 auipc a0,0x2 +800002a0: de450513 addi a0,a0,-540 # 80002080 +800002a4: 00053007 fld ft0,0(a0) +800002a8: 00853087 fld ft1,8(a0) +800002ac: 01053107 fld ft2,16(a0) +800002b0: 01852683 lw a3,24(a0) +800002b4: 01c52303 lw t1,28(a0) +800002b8: 5a0071d3 fsqrt.d ft3,ft0 +800002bc: 00353027 fsd ft3,0(a0) +800002c0: 00452383 lw t2,4(a0) +800002c4: 00052503 lw a0,0(a0) +800002c8: 001015f3 fsflags a1,zero +800002cc: 00000613 li a2,0 +800002d0: 0cd51e63 bne a0,a3,800003ac +800002d4: 0c731c63 bne t1,t2,800003ac +800002d8: 0cc59a63 bne a1,a2,800003ac + +800002dc : +800002dc: 01000193 li gp,16 +800002e0: 00002517 auipc a0,0x2 +800002e4: dc050513 addi a0,a0,-576 # 800020a0 +800002e8: 00053007 fld ft0,0(a0) +800002ec: 00853087 fld ft1,8(a0) +800002f0: 01053107 fld ft2,16(a0) +800002f4: 01852683 lw a3,24(a0) +800002f8: 01c52303 lw t1,28(a0) +800002fc: 5a0071d3 fsqrt.d ft3,ft0 +80000300: 00353027 fsd ft3,0(a0) +80000304: 00452383 lw t2,4(a0) +80000308: 00052503 lw a0,0(a0) +8000030c: 001015f3 fsflags a1,zero +80000310: 01000613 li a2,16 +80000314: 08d51c63 bne a0,a3,800003ac +80000318: 08731a63 bne t1,t2,800003ac +8000031c: 08c59863 bne a1,a2,800003ac + +80000320 : +80000320: 00700193 li gp,7 +80000324: 00002517 auipc a0,0x2 +80000328: d9c50513 addi a0,a0,-612 # 800020c0 +8000032c: 00053007 fld ft0,0(a0) +80000330: 00853087 fld ft1,8(a0) +80000334: 01053107 fld ft2,16(a0) +80000338: 01852683 lw a3,24(a0) +8000033c: 01c52303 lw t1,28(a0) +80000340: 5a0071d3 fsqrt.d ft3,ft0 +80000344: 00353027 fsd ft3,0(a0) +80000348: 00452383 lw t2,4(a0) +8000034c: 00052503 lw a0,0(a0) +80000350: 001015f3 fsflags a1,zero +80000354: 00100613 li a2,1 +80000358: 04d51a63 bne a0,a3,800003ac +8000035c: 04731863 bne t1,t2,800003ac +80000360: 04c59663 bne a1,a2,800003ac + +80000364 : +80000364: 00800193 li gp,8 +80000368: 00002517 auipc a0,0x2 +8000036c: d7850513 addi a0,a0,-648 # 800020e0 +80000370: 00053007 fld ft0,0(a0) +80000374: 00853087 fld ft1,8(a0) +80000378: 01053107 fld ft2,16(a0) +8000037c: 01852683 lw a3,24(a0) +80000380: 01c52303 lw t1,28(a0) +80000384: 5a0071d3 fsqrt.d ft3,ft0 +80000388: 00353027 fsd ft3,0(a0) +8000038c: 00452383 lw t2,4(a0) +80000390: 00052503 lw a0,0(a0) +80000394: 001015f3 fsflags a1,zero +80000398: 00100613 li a2,1 +8000039c: 00d51863 bne a0,a3,800003ac +800003a0: 00731663 bne t1,t2,800003ac +800003a4: 00c59463 bne a1,a2,800003ac +800003a8: 02301063 bne zero,gp,800003c8 + +800003ac : +800003ac: 0ff0000f fence +800003b0: 00018063 beqz gp,800003b0 +800003b4: 00119193 slli gp,gp,0x1 +800003b8: 0011e193 ori gp,gp,1 +800003bc: 05d00893 li a7,93 +800003c0: 00018513 mv a0,gp +800003c4: 00000073 ecall + +800003c8 : +800003c8: 0ff0000f fence +800003cc: 00100193 li gp,1 +800003d0: 05d00893 li a7,93 +800003d4: 00000513 li a0,0 +800003d8: 00000073 ecall +800003dc: c0001073 unimp +800003e0: 0000 unimp +800003e2: 0000 unimp +800003e4: 0000 unimp +800003e6: 0000 unimp +800003e8: 0000 unimp +800003ea: 0000 unimp +800003ec: 0000 unimp +800003ee: 0000 unimp +800003f0: 0000 unimp +800003f2: 0000 unimp +800003f4: 0000 unimp +800003f6: 0000 unimp +800003f8: 0000 unimp +800003fa: 0000 unimp +800003fc: 0000 unimp +800003fe: 0000 unimp +80000400: 0000 unimp +80000402: 0000 unimp + +Disassembly of section .data: + +80002000 : +80002000: d4f1 beqz s1,80001fcc +80002002: 53c8 lw a0,36(a5) +80002004: 400921fb 0x400921fb +80002008: b0dd j 800018ee +8000200a: 89f1 andi a1,a1,28 +8000200c: bf0a fsd ft2,440(sp) +8000200e: 4005 c.li zero,1 +80002010: 0000 unimp +80002012: 0000 unimp +80002014: 0000 unimp +80002016: 0000 unimp +80002018: 83ec 0x83ec +8000201a: 7ddbf6c3 0x7ddbf6c3 +8000201e: 3ff2 fld ft11,312(sp) + +80002020 : +80002020: 0000 unimp +80002022: 0000 unimp +80002024: 4800 lw s0,16(s0) +80002026: 6666c093 xori ra,a3,1638 +8000202a: 6666 flw fa2,88(sp) +8000202c: 4c66 lw s8,88(sp) +8000202e: 00004093 xori ra,zero,0 +80002032: 0000 unimp +80002034: 0000 unimp +80002036: 0000 unimp +80002038: 29a5 jal 800024b0 <_end+0x3b0> +8000203a: 3e19 jal 80001b50 +8000203c: f8b4 fsw fa3,112(s1) +8000203e: jal t6,7ff1dd8c <_start-0xe2274> + +80002040 : +80002040: d4f1 beqz s1,8000200c +80002042: 53c8 lw a0,36(a5) +80002044: 400921fb 0x400921fb +80002048: 0000 unimp +8000204a: 0000 unimp +8000204c: 0000 unimp +8000204e: 3ff0 fld fa2,248(a5) +80002050: 0000 unimp +80002052: 0000 unimp +80002054: 0000 unimp +80002056: 0000 unimp +80002058: d4f1 beqz s1,80002024 +8000205a: 53c8 lw a0,36(a5) +8000205c: 400921fb 0x400921fb + +80002060 : +80002060: d4f1 beqz s1,8000202c +80002062: 53c8 lw a0,36(a5) +80002064: 400921fb 0x400921fb +80002068: 0000 unimp +8000206a: 0000 unimp +8000206c: 0000 unimp +8000206e: 0000 unimp +80002070: 0000 unimp +80002072: 0000 unimp +80002074: 0000 unimp +80002076: 0000 unimp +80002078: 916f587b 0x916f587b +8000207c: 5bf8 lw a4,116(a5) +8000207e: 3ffc fld fa5,248(a5) + +80002080 : +80002080: 0000 unimp +80002082: 0000 unimp +80002084: 8800 0x8800 +80002086: 000040c3 fmadd.s ft1,ft0,ft0,ft0,rmm +8000208a: 0000 unimp +8000208c: 0000 unimp +8000208e: 0000 unimp +80002090: 0000 unimp +80002092: 0000 unimp +80002094: 0000 unimp +80002096: 0000 unimp +80002098: 0000 unimp +8000209a: 0000 unimp +8000209c: 0000 unimp +8000209e: 4059 c.li zero,22 + +800020a0 : +800020a0: 0000 unimp +800020a2: 0000 unimp +800020a4: 0000 unimp +800020a6: bff0 fsd fa2,248(a5) +800020a8: 0000 unimp +800020aa: 0000 unimp +800020ac: 0000 unimp +800020ae: 0000 unimp +800020b0: 0000 unimp +800020b2: 0000 unimp +800020b4: 0000 unimp +800020b6: 0000 unimp +800020b8: 0000 unimp +800020ba: 0000 unimp +800020bc: 0000 unimp +800020be: 7ff8 flw fa4,124(a5) + +800020c0 : +800020c0: 0000 unimp +800020c2: 0000 unimp +800020c4: 6000 flw fs0,0(s0) +800020c6: 4065 c.li zero,25 +800020c8: 0000 unimp +800020ca: 0000 unimp +800020cc: 0000 unimp +800020ce: 0000 unimp +800020d0: 0000 unimp +800020d2: 0000 unimp +800020d4: 0000 unimp +800020d6: 0000 unimp +800020d8: 74f5 lui s1,0xffffd +800020da: ce96 sw t0,92(sp) +800020dc: 2744 fld fs1,136(a4) +800020de: 402a 0x402a + +800020e0 : +800020e0: a105 j 80002500 <_end+0x400> +800020e2: c70a sw sp,140(sp) +800020e4: 94df 3e85 0000 0x3e8594df +800020ea: 0000 unimp +800020ec: 0000 unimp +800020ee: 0000 unimp +800020f0: 0000 unimp +800020f2: 0000 unimp +800020f4: 0000 unimp +800020f6: 0000 unimp +800020f8: 7f99 lui t6,0xfffe6 +800020fa: 4789c0e3 blt s3,s8,80002d5a <_end+0xc5a> +800020fe: 3f3a fld ft10,424(sp) diff --git a/src/test/resources/asm/rv32ud-p-fmadd.dump b/src/test/resources/asm/rv32ud-p-fmadd.dump new file mode 100644 index 00000000..7bf600a7 --- /dev/null +++ b/src/test/resources/asm/rv32ud-p-fmadd.dump @@ -0,0 +1,583 @@ + +rv32ud-p-fmadd: file format elf32-littleriscv + + +Disassembly of section .text.init: + +80000000 <_start>: +80000000: 04c0006f j 8000004c + +80000004 : +80000004: 34202f73 csrr t5,mcause +80000008: 00800f93 li t6,8 +8000000c: 03ff0a63 beq t5,t6,80000040 +80000010: 00900f93 li t6,9 +80000014: 03ff0663 beq t5,t6,80000040 +80000018: 00b00f93 li t6,11 +8000001c: 03ff0263 beq t5,t6,80000040 +80000020: 80000f17 auipc t5,0x80000 +80000024: fe0f0f13 addi t5,t5,-32 # 0 <_start-0x80000000> +80000028: 000f0463 beqz t5,80000030 +8000002c: 000f0067 jr t5 +80000030: 34202f73 csrr t5,mcause +80000034: 000f5463 bgez t5,8000003c +80000038: 0040006f j 8000003c + +8000003c : +8000003c: 5391e193 ori gp,gp,1337 + +80000040 : +80000040: 00001f17 auipc t5,0x1 +80000044: fc3f2023 sw gp,-64(t5) # 80001000 +80000048: ff9ff06f j 80000040 + +8000004c : +8000004c: 00000093 li ra,0 +80000050: 00000113 li sp,0 +80000054: 00000193 li gp,0 +80000058: 00000213 li tp,0 +8000005c: 00000293 li t0,0 +80000060: 00000313 li t1,0 +80000064: 00000393 li t2,0 +80000068: 00000413 li s0,0 +8000006c: 00000493 li s1,0 +80000070: 00000513 li a0,0 +80000074: 00000593 li a1,0 +80000078: 00000613 li a2,0 +8000007c: 00000693 li a3,0 +80000080: 00000713 li a4,0 +80000084: 00000793 li a5,0 +80000088: 00000813 li a6,0 +8000008c: 00000893 li a7,0 +80000090: 00000913 li s2,0 +80000094: 00000993 li s3,0 +80000098: 00000a13 li s4,0 +8000009c: 00000a93 li s5,0 +800000a0: 00000b13 li s6,0 +800000a4: 00000b93 li s7,0 +800000a8: 00000c13 li s8,0 +800000ac: 00000c93 li s9,0 +800000b0: 00000d13 li s10,0 +800000b4: 00000d93 li s11,0 +800000b8: 00000e13 li t3,0 +800000bc: 00000e93 li t4,0 +800000c0: 00000f13 li t5,0 +800000c4: 00000f93 li t6,0 +800000c8: f1402573 csrr a0,mhartid +800000cc: 00051063 bnez a0,800000cc +800000d0: 00000297 auipc t0,0x0 +800000d4: 01028293 addi t0,t0,16 # 800000e0 +800000d8: 30529073 csrw mtvec,t0 +800000dc: 18005073 csrwi satp,0 +800000e0: 00000297 auipc t0,0x0 +800000e4: 02028293 addi t0,t0,32 # 80000100 +800000e8: 30529073 csrw mtvec,t0 +800000ec: 800002b7 lui t0,0x80000 +800000f0: fff28293 addi t0,t0,-1 # 7fffffff <_end+0xffffde7f> +800000f4: 3b029073 csrw pmpaddr0,t0 +800000f8: 01f00293 li t0,31 +800000fc: 3a029073 csrw pmpcfg0,t0 +80000100: 30405073 csrwi mie,0 +80000104: 00000297 auipc t0,0x0 +80000108: 01428293 addi t0,t0,20 # 80000118 +8000010c: 30529073 csrw mtvec,t0 +80000110: 30205073 csrwi medeleg,0 +80000114: 30305073 csrwi mideleg,0 +80000118: 00000193 li gp,0 +8000011c: 00000297 auipc t0,0x0 +80000120: ee828293 addi t0,t0,-280 # 80000004 +80000124: 30529073 csrw mtvec,t0 +80000128: 00100513 li a0,1 +8000012c: 01f51513 slli a0,a0,0x1f +80000130: 00054c63 bltz a0,80000148 +80000134: 0ff0000f fence +80000138: 00100193 li gp,1 +8000013c: 05d00893 li a7,93 +80000140: 00000513 li a0,0 +80000144: 00000073 ecall +80000148: 80000297 auipc t0,0x80000 +8000014c: eb828293 addi t0,t0,-328 # 0 <_start-0x80000000> +80000150: 00028a63 beqz t0,80000164 +80000154: 10529073 csrw stvec,t0 +80000158: 0000b2b7 lui t0,0xb +8000015c: 10928293 addi t0,t0,265 # b109 <_start-0x7fff4ef7> +80000160: 30229073 csrw medeleg,t0 +80000164: 30005073 csrwi mstatus,0 +80000168: 00002537 lui a0,0x2 +8000016c: 30052073 csrs mstatus,a0 +80000170: 00305073 csrwi fcsr,0 +80000174: 00000297 auipc t0,0x0 +80000178: 01428293 addi t0,t0,20 # 80000188 +8000017c: 34129073 csrw mepc,t0 +80000180: f1402573 csrr a0,mhartid +80000184: 30200073 mret + +80000188 : +80000188: 00200193 li gp,2 +8000018c: 00002517 auipc a0,0x2 +80000190: e7450513 addi a0,a0,-396 # 80002000 +80000194: 00053007 fld ft0,0(a0) +80000198: 00853087 fld ft1,8(a0) +8000019c: 01053107 fld ft2,16(a0) +800001a0: 01852683 lw a3,24(a0) +800001a4: 01c52303 lw t1,28(a0) +800001a8: 121071c3 fmadd.d ft3,ft0,ft1,ft2 +800001ac: 00353027 fsd ft3,0(a0) +800001b0: 00452383 lw t2,4(a0) +800001b4: 00052503 lw a0,0(a0) +800001b8: 001015f3 fsflags a1,zero +800001bc: 00000613 li a2,0 +800001c0: 2ed51e63 bne a0,a3,800004bc +800001c4: 2e731c63 bne t1,t2,800004bc +800001c8: 2ec59a63 bne a1,a2,800004bc + +800001cc : +800001cc: 00300193 li gp,3 +800001d0: 00002517 auipc a0,0x2 +800001d4: e5050513 addi a0,a0,-432 # 80002020 +800001d8: 00053007 fld ft0,0(a0) +800001dc: 00853087 fld ft1,8(a0) +800001e0: 01053107 fld ft2,16(a0) +800001e4: 01852683 lw a3,24(a0) +800001e8: 01c52303 lw t1,28(a0) +800001ec: 121071c3 fmadd.d ft3,ft0,ft1,ft2 +800001f0: 00353027 fsd ft3,0(a0) +800001f4: 00452383 lw t2,4(a0) +800001f8: 00052503 lw a0,0(a0) +800001fc: 001015f3 fsflags a1,zero +80000200: 00100613 li a2,1 +80000204: 2ad51c63 bne a0,a3,800004bc +80000208: 2a731a63 bne t1,t2,800004bc +8000020c: 2ac59863 bne a1,a2,800004bc + +80000210 : +80000210: 00400193 li gp,4 +80000214: 00002517 auipc a0,0x2 +80000218: e2c50513 addi a0,a0,-468 # 80002040 +8000021c: 00053007 fld ft0,0(a0) +80000220: 00853087 fld ft1,8(a0) +80000224: 01053107 fld ft2,16(a0) +80000228: 01852683 lw a3,24(a0) +8000022c: 01c52303 lw t1,28(a0) +80000230: 121071c3 fmadd.d ft3,ft0,ft1,ft2 +80000234: 00353027 fsd ft3,0(a0) +80000238: 00452383 lw t2,4(a0) +8000023c: 00052503 lw a0,0(a0) +80000240: 001015f3 fsflags a1,zero +80000244: 00000613 li a2,0 +80000248: 26d51a63 bne a0,a3,800004bc +8000024c: 26731863 bne t1,t2,800004bc +80000250: 26c59663 bne a1,a2,800004bc + +80000254 : +80000254: 00500193 li gp,5 +80000258: 00002517 auipc a0,0x2 +8000025c: e0850513 addi a0,a0,-504 # 80002060 +80000260: 00053007 fld ft0,0(a0) +80000264: 00853087 fld ft1,8(a0) +80000268: 01053107 fld ft2,16(a0) +8000026c: 01852683 lw a3,24(a0) +80000270: 01c52303 lw t1,28(a0) +80000274: 121071cf fnmadd.d ft3,ft0,ft1,ft2 +80000278: 00353027 fsd ft3,0(a0) +8000027c: 00452383 lw t2,4(a0) +80000280: 00052503 lw a0,0(a0) +80000284: 001015f3 fsflags a1,zero +80000288: 00000613 li a2,0 +8000028c: 22d51863 bne a0,a3,800004bc +80000290: 22731663 bne t1,t2,800004bc +80000294: 22c59463 bne a1,a2,800004bc + +80000298 : +80000298: 00600193 li gp,6 +8000029c: 00002517 auipc a0,0x2 +800002a0: de450513 addi a0,a0,-540 # 80002080 +800002a4: 00053007 fld ft0,0(a0) +800002a8: 00853087 fld ft1,8(a0) +800002ac: 01053107 fld ft2,16(a0) +800002b0: 01852683 lw a3,24(a0) +800002b4: 01c52303 lw t1,28(a0) +800002b8: 121071cf fnmadd.d ft3,ft0,ft1,ft2 +800002bc: 00353027 fsd ft3,0(a0) +800002c0: 00452383 lw t2,4(a0) +800002c4: 00052503 lw a0,0(a0) +800002c8: 001015f3 fsflags a1,zero +800002cc: 00100613 li a2,1 +800002d0: 1ed51663 bne a0,a3,800004bc +800002d4: 1e731463 bne t1,t2,800004bc +800002d8: 1ec59263 bne a1,a2,800004bc + +800002dc : +800002dc: 00700193 li gp,7 +800002e0: 00002517 auipc a0,0x2 +800002e4: dc050513 addi a0,a0,-576 # 800020a0 +800002e8: 00053007 fld ft0,0(a0) +800002ec: 00853087 fld ft1,8(a0) +800002f0: 01053107 fld ft2,16(a0) +800002f4: 01852683 lw a3,24(a0) +800002f8: 01c52303 lw t1,28(a0) +800002fc: 121071cf fnmadd.d ft3,ft0,ft1,ft2 +80000300: 00353027 fsd ft3,0(a0) +80000304: 00452383 lw t2,4(a0) +80000308: 00052503 lw a0,0(a0) +8000030c: 001015f3 fsflags a1,zero +80000310: 00000613 li a2,0 +80000314: 1ad51463 bne a0,a3,800004bc +80000318: 1a731263 bne t1,t2,800004bc +8000031c: 1ac59063 bne a1,a2,800004bc + +80000320 : +80000320: 00800193 li gp,8 +80000324: 00002517 auipc a0,0x2 +80000328: d9c50513 addi a0,a0,-612 # 800020c0 +8000032c: 00053007 fld ft0,0(a0) +80000330: 00853087 fld ft1,8(a0) +80000334: 01053107 fld ft2,16(a0) +80000338: 01852683 lw a3,24(a0) +8000033c: 01c52303 lw t1,28(a0) +80000340: 121071c7 fmsub.d ft3,ft0,ft1,ft2 +80000344: 00353027 fsd ft3,0(a0) +80000348: 00452383 lw t2,4(a0) +8000034c: 00052503 lw a0,0(a0) +80000350: 001015f3 fsflags a1,zero +80000354: 00000613 li a2,0 +80000358: 16d51263 bne a0,a3,800004bc +8000035c: 16731063 bne t1,t2,800004bc +80000360: 14c59e63 bne a1,a2,800004bc + +80000364 : +80000364: 00900193 li gp,9 +80000368: 00002517 auipc a0,0x2 +8000036c: d7850513 addi a0,a0,-648 # 800020e0 +80000370: 00053007 fld ft0,0(a0) +80000374: 00853087 fld ft1,8(a0) +80000378: 01053107 fld ft2,16(a0) +8000037c: 01852683 lw a3,24(a0) +80000380: 01c52303 lw t1,28(a0) +80000384: 121071c7 fmsub.d ft3,ft0,ft1,ft2 +80000388: 00353027 fsd ft3,0(a0) +8000038c: 00452383 lw t2,4(a0) +80000390: 00052503 lw a0,0(a0) +80000394: 001015f3 fsflags a1,zero +80000398: 00100613 li a2,1 +8000039c: 12d51063 bne a0,a3,800004bc +800003a0: 10731e63 bne t1,t2,800004bc +800003a4: 10c59c63 bne a1,a2,800004bc + +800003a8 : +800003a8: 00a00193 li gp,10 +800003ac: 00002517 auipc a0,0x2 +800003b0: d5450513 addi a0,a0,-684 # 80002100 +800003b4: 00053007 fld ft0,0(a0) +800003b8: 00853087 fld ft1,8(a0) +800003bc: 01053107 fld ft2,16(a0) +800003c0: 01852683 lw a3,24(a0) +800003c4: 01c52303 lw t1,28(a0) +800003c8: 121071c7 fmsub.d ft3,ft0,ft1,ft2 +800003cc: 00353027 fsd ft3,0(a0) +800003d0: 00452383 lw t2,4(a0) +800003d4: 00052503 lw a0,0(a0) +800003d8: 001015f3 fsflags a1,zero +800003dc: 00000613 li a2,0 +800003e0: 0cd51e63 bne a0,a3,800004bc +800003e4: 0c731c63 bne t1,t2,800004bc +800003e8: 0cc59a63 bne a1,a2,800004bc + +800003ec : +800003ec: 00b00193 li gp,11 +800003f0: 00002517 auipc a0,0x2 +800003f4: d3050513 addi a0,a0,-720 # 80002120 +800003f8: 00053007 fld ft0,0(a0) +800003fc: 00853087 fld ft1,8(a0) +80000400: 01053107 fld ft2,16(a0) +80000404: 01852683 lw a3,24(a0) +80000408: 01c52303 lw t1,28(a0) +8000040c: 121071cb fnmsub.d ft3,ft0,ft1,ft2 +80000410: 00353027 fsd ft3,0(a0) +80000414: 00452383 lw t2,4(a0) +80000418: 00052503 lw a0,0(a0) +8000041c: 001015f3 fsflags a1,zero +80000420: 00000613 li a2,0 +80000424: 08d51c63 bne a0,a3,800004bc +80000428: 08731a63 bne t1,t2,800004bc +8000042c: 08c59863 bne a1,a2,800004bc + +80000430 : +80000430: 00c00193 li gp,12 +80000434: 00002517 auipc a0,0x2 +80000438: d0c50513 addi a0,a0,-756 # 80002140 +8000043c: 00053007 fld ft0,0(a0) +80000440: 00853087 fld ft1,8(a0) +80000444: 01053107 fld ft2,16(a0) +80000448: 01852683 lw a3,24(a0) +8000044c: 01c52303 lw t1,28(a0) +80000450: 121071cb fnmsub.d ft3,ft0,ft1,ft2 +80000454: 00353027 fsd ft3,0(a0) +80000458: 00452383 lw t2,4(a0) +8000045c: 00052503 lw a0,0(a0) +80000460: 001015f3 fsflags a1,zero +80000464: 00100613 li a2,1 +80000468: 04d51a63 bne a0,a3,800004bc +8000046c: 04731863 bne t1,t2,800004bc +80000470: 04c59663 bne a1,a2,800004bc + +80000474 : +80000474: 00d00193 li gp,13 +80000478: 00002517 auipc a0,0x2 +8000047c: ce850513 addi a0,a0,-792 # 80002160 +80000480: 00053007 fld ft0,0(a0) +80000484: 00853087 fld ft1,8(a0) +80000488: 01053107 fld ft2,16(a0) +8000048c: 01852683 lw a3,24(a0) +80000490: 01c52303 lw t1,28(a0) +80000494: 121071cb fnmsub.d ft3,ft0,ft1,ft2 +80000498: 00353027 fsd ft3,0(a0) +8000049c: 00452383 lw t2,4(a0) +800004a0: 00052503 lw a0,0(a0) +800004a4: 001015f3 fsflags a1,zero +800004a8: 00000613 li a2,0 +800004ac: 00d51863 bne a0,a3,800004bc +800004b0: 00731663 bne t1,t2,800004bc +800004b4: 00c59463 bne a1,a2,800004bc +800004b8: 02301063 bne zero,gp,800004d8 + +800004bc : +800004bc: 0ff0000f fence +800004c0: 00018063 beqz gp,800004c0 +800004c4: 00119193 slli gp,gp,0x1 +800004c8: 0011e193 ori gp,gp,1 +800004cc: 05d00893 li a7,93 +800004d0: 00018513 mv a0,gp +800004d4: 00000073 ecall + +800004d8 : +800004d8: 0ff0000f fence +800004dc: 00100193 li gp,1 +800004e0: 05d00893 li a7,93 +800004e4: 00000513 li a0,0 +800004e8: 00000073 ecall +800004ec: c0001073 unimp +800004f0: 0000 unimp +800004f2: 0000 unimp +800004f4: 0000 unimp +800004f6: 0000 unimp +800004f8: 0000 unimp +800004fa: 0000 unimp +800004fc: 0000 unimp +800004fe: 0000 unimp +80000500: 0000 unimp +80000502: 0000 unimp + +Disassembly of section .data: + +80002000 : +80002000: 0000 unimp +80002002: 0000 unimp +80002004: 0000 unimp +80002006: 3ff0 fld fa2,248(a5) +80002008: 0000 unimp +8000200a: 0000 unimp +8000200c: 0000 unimp +8000200e: 4004 lw s1,0(s0) +80002010: 0000 unimp +80002012: 0000 unimp +80002014: 0000 unimp +80002016: 3ff0 fld fa2,248(a5) +80002018: 0000 unimp +8000201a: 0000 unimp +8000201c: 0000 unimp +8000201e: 400c lw a1,0(s0) + +80002020 : +80002020: 0000 unimp +80002022: 0000 unimp +80002024: 0000 unimp +80002026: bff0 fsd fa2,248(a5) +80002028: 6666 flw fa2,88(sp) +8000202a: 6666 flw fa2,88(sp) +8000202c: 4c66 lw s8,88(sp) +8000202e: 999ac093 xori ra,s5,-1639 +80002032: 9999 andi a1,a1,-26 +80002034: 9999 andi a1,a1,-26 +80002036: 3ff1 jal 80002012 +80002038: cccc sw a1,28(s1) +8000203a: cccc sw a1,28(s1) +8000203c: 50cc lw a1,36(s1) +8000203e: xori ra,zero,0 + +80002040 : +80002040: 0000 unimp +80002042: 0000 unimp +80002044: 0000 unimp +80002046: 4000 lw s0,0(s0) +80002048: 0000 unimp +8000204a: 0000 unimp +8000204c: 0000 unimp +8000204e: c014 sw a3,0(s0) +80002050: 0000 unimp +80002052: 0000 unimp +80002054: 0000 unimp +80002056: c000 sw s0,0(s0) +80002058: 0000 unimp +8000205a: 0000 unimp +8000205c: 0000 unimp +8000205e: c028 sw a0,64(s0) + +80002060 : +80002060: 0000 unimp +80002062: 0000 unimp +80002064: 0000 unimp +80002066: 3ff0 fld fa2,248(a5) +80002068: 0000 unimp +8000206a: 0000 unimp +8000206c: 0000 unimp +8000206e: 4004 lw s1,0(s0) +80002070: 0000 unimp +80002072: 0000 unimp +80002074: 0000 unimp +80002076: 3ff0 fld fa2,248(a5) +80002078: 0000 unimp +8000207a: 0000 unimp +8000207c: 0000 unimp +8000207e: c00c sw a1,0(s0) + +80002080 : +80002080: 0000 unimp +80002082: 0000 unimp +80002084: 0000 unimp +80002086: bff0 fsd fa2,248(a5) +80002088: 6666 flw fa2,88(sp) +8000208a: 6666 flw fa2,88(sp) +8000208c: 4c66 lw s8,88(sp) +8000208e: 999ac093 xori ra,s5,-1639 +80002092: 9999 andi a1,a1,-26 +80002094: 9999 andi a1,a1,-26 +80002096: 3ff1 jal 80002072 +80002098: cccc sw a1,28(s1) +8000209a: cccc sw a1,28(s1) +8000209c: 50cc lw a1,36(s1) +8000209e: xori ra,ra,0 + +800020a0 : +800020a0: 0000 unimp +800020a2: 0000 unimp +800020a4: 0000 unimp +800020a6: 4000 lw s0,0(s0) +800020a8: 0000 unimp +800020aa: 0000 unimp +800020ac: 0000 unimp +800020ae: c014 sw a3,0(s0) +800020b0: 0000 unimp +800020b2: 0000 unimp +800020b4: 0000 unimp +800020b6: c000 sw s0,0(s0) +800020b8: 0000 unimp +800020ba: 0000 unimp +800020bc: 0000 unimp +800020be: 4028 lw a0,64(s0) + +800020c0 : +800020c0: 0000 unimp +800020c2: 0000 unimp +800020c4: 0000 unimp +800020c6: 3ff0 fld fa2,248(a5) +800020c8: 0000 unimp +800020ca: 0000 unimp +800020cc: 0000 unimp +800020ce: 4004 lw s1,0(s0) +800020d0: 0000 unimp +800020d2: 0000 unimp +800020d4: 0000 unimp +800020d6: 3ff0 fld fa2,248(a5) +800020d8: 0000 unimp +800020da: 0000 unimp +800020dc: 0000 unimp +800020de: 3ff8 fld fa4,248(a5) + +800020e0 : +800020e0: 0000 unimp +800020e2: 0000 unimp +800020e4: 0000 unimp +800020e6: bff0 fsd fa2,248(a5) +800020e8: 6666 flw fa2,88(sp) +800020ea: 6666 flw fa2,88(sp) +800020ec: 4c66 lw s8,88(sp) +800020ee: 999ac093 xori ra,s5,-1639 +800020f2: 9999 andi a1,a1,-26 +800020f4: 9999 andi a1,a1,-26 +800020f6: 3ff1 jal 800020d2 +800020f8: 0000 unimp +800020fa: 0000 unimp +800020fc: 4800 lw s0,16(s0) +800020fe: xori ra,zero,0 + +80002100 : +80002100: 0000 unimp +80002102: 0000 unimp +80002104: 0000 unimp +80002106: 4000 lw s0,0(s0) +80002108: 0000 unimp +8000210a: 0000 unimp +8000210c: 0000 unimp +8000210e: c014 sw a3,0(s0) +80002110: 0000 unimp +80002112: 0000 unimp +80002114: 0000 unimp +80002116: c000 sw s0,0(s0) +80002118: 0000 unimp +8000211a: 0000 unimp +8000211c: 0000 unimp +8000211e: c020 sw s0,64(s0) + +80002120 : +80002120: 0000 unimp +80002122: 0000 unimp +80002124: 0000 unimp +80002126: 3ff0 fld fa2,248(a5) +80002128: 0000 unimp +8000212a: 0000 unimp +8000212c: 0000 unimp +8000212e: 4004 lw s1,0(s0) +80002130: 0000 unimp +80002132: 0000 unimp +80002134: 0000 unimp +80002136: 3ff0 fld fa2,248(a5) +80002138: 0000 unimp +8000213a: 0000 unimp +8000213c: 0000 unimp +8000213e: bff8 fsd fa4,248(a5) + +80002140 : +80002140: 0000 unimp +80002142: 0000 unimp +80002144: 0000 unimp +80002146: bff0 fsd fa2,248(a5) +80002148: 6666 flw fa2,88(sp) +8000214a: 6666 flw fa2,88(sp) +8000214c: 4c66 lw s8,88(sp) +8000214e: 999ac093 xori ra,s5,-1639 +80002152: 9999 andi a1,a1,-26 +80002154: 9999 andi a1,a1,-26 +80002156: 3ff1 jal 80002132 +80002158: 0000 unimp +8000215a: 0000 unimp +8000215c: 4800 lw s0,16(s0) +8000215e: xori ra,ra,0 + +80002160 : +80002160: 0000 unimp +80002162: 0000 unimp +80002164: 0000 unimp +80002166: 4000 lw s0,0(s0) +80002168: 0000 unimp +8000216a: 0000 unimp +8000216c: 0000 unimp +8000216e: c014 sw a3,0(s0) +80002170: 0000 unimp +80002172: 0000 unimp +80002174: 0000 unimp +80002176: c000 sw s0,0(s0) +80002178: 0000 unimp +8000217a: 0000 unimp +8000217c: 0000 unimp +8000217e: 4020 lw s0,64(s0) diff --git a/src/test/resources/asm/rv32ud-p-fmin.dump b/src/test/resources/asm/rv32ud-p-fmin.dump new file mode 100644 index 00000000..e1234a2e --- /dev/null +++ b/src/test/resources/asm/rv32ud-p-fmin.dump @@ -0,0 +1,820 @@ + +rv32ud-p-fmin: file format elf32-littleriscv + + +Disassembly of section .text.init: + +80000000 <_start>: +80000000: 04c0006f j 8000004c + +80000004 : +80000004: 34202f73 csrr t5,mcause +80000008: 00800f93 li t6,8 +8000000c: 03ff0a63 beq t5,t6,80000040 +80000010: 00900f93 li t6,9 +80000014: 03ff0663 beq t5,t6,80000040 +80000018: 00b00f93 li t6,11 +8000001c: 03ff0263 beq t5,t6,80000040 +80000020: 80000f17 auipc t5,0x80000 +80000024: fe0f0f13 addi t5,t5,-32 # 0 <_start-0x80000000> +80000028: 000f0463 beqz t5,80000030 +8000002c: 000f0067 jr t5 +80000030: 34202f73 csrr t5,mcause +80000034: 000f5463 bgez t5,8000003c +80000038: 0040006f j 8000003c + +8000003c : +8000003c: 5391e193 ori gp,gp,1337 + +80000040 : +80000040: 00001f17 auipc t5,0x1 +80000044: fc3f2023 sw gp,-64(t5) # 80001000 +80000048: ff9ff06f j 80000040 + +8000004c : +8000004c: 00000093 li ra,0 +80000050: 00000113 li sp,0 +80000054: 00000193 li gp,0 +80000058: 00000213 li tp,0 +8000005c: 00000293 li t0,0 +80000060: 00000313 li t1,0 +80000064: 00000393 li t2,0 +80000068: 00000413 li s0,0 +8000006c: 00000493 li s1,0 +80000070: 00000513 li a0,0 +80000074: 00000593 li a1,0 +80000078: 00000613 li a2,0 +8000007c: 00000693 li a3,0 +80000080: 00000713 li a4,0 +80000084: 00000793 li a5,0 +80000088: 00000813 li a6,0 +8000008c: 00000893 li a7,0 +80000090: 00000913 li s2,0 +80000094: 00000993 li s3,0 +80000098: 00000a13 li s4,0 +8000009c: 00000a93 li s5,0 +800000a0: 00000b13 li s6,0 +800000a4: 00000b93 li s7,0 +800000a8: 00000c13 li s8,0 +800000ac: 00000c93 li s9,0 +800000b0: 00000d13 li s10,0 +800000b4: 00000d93 li s11,0 +800000b8: 00000e13 li t3,0 +800000bc: 00000e93 li t4,0 +800000c0: 00000f13 li t5,0 +800000c4: 00000f93 li t6,0 +800000c8: f1402573 csrr a0,mhartid +800000cc: 00051063 bnez a0,800000cc +800000d0: 00000297 auipc t0,0x0 +800000d4: 01028293 addi t0,t0,16 # 800000e0 +800000d8: 30529073 csrw mtvec,t0 +800000dc: 18005073 csrwi satp,0 +800000e0: 00000297 auipc t0,0x0 +800000e4: 02028293 addi t0,t0,32 # 80000100 +800000e8: 30529073 csrw mtvec,t0 +800000ec: 800002b7 lui t0,0x80000 +800000f0: fff28293 addi t0,t0,-1 # 7fffffff <_end+0xffffddbf> +800000f4: 3b029073 csrw pmpaddr0,t0 +800000f8: 01f00293 li t0,31 +800000fc: 3a029073 csrw pmpcfg0,t0 +80000100: 30405073 csrwi mie,0 +80000104: 00000297 auipc t0,0x0 +80000108: 01428293 addi t0,t0,20 # 80000118 +8000010c: 30529073 csrw mtvec,t0 +80000110: 30205073 csrwi medeleg,0 +80000114: 30305073 csrwi mideleg,0 +80000118: 00000193 li gp,0 +8000011c: 00000297 auipc t0,0x0 +80000120: ee828293 addi t0,t0,-280 # 80000004 +80000124: 30529073 csrw mtvec,t0 +80000128: 00100513 li a0,1 +8000012c: 01f51513 slli a0,a0,0x1f +80000130: 00054c63 bltz a0,80000148 +80000134: 0ff0000f fence +80000138: 00100193 li gp,1 +8000013c: 05d00893 li a7,93 +80000140: 00000513 li a0,0 +80000144: 00000073 ecall +80000148: 80000297 auipc t0,0x80000 +8000014c: eb828293 addi t0,t0,-328 # 0 <_start-0x80000000> +80000150: 00028a63 beqz t0,80000164 +80000154: 10529073 csrw stvec,t0 +80000158: 0000b2b7 lui t0,0xb +8000015c: 10928293 addi t0,t0,265 # b109 <_start-0x7fff4ef7> +80000160: 30229073 csrw medeleg,t0 +80000164: 30005073 csrwi mstatus,0 +80000168: 00002537 lui a0,0x2 +8000016c: 30052073 csrs mstatus,a0 +80000170: 00305073 csrwi fcsr,0 +80000174: 00000297 auipc t0,0x0 +80000178: 01428293 addi t0,t0,20 # 80000188 +8000017c: 34129073 csrw mepc,t0 +80000180: f1402573 csrr a0,mhartid +80000184: 30200073 mret + +80000188 : +80000188: 00200193 li gp,2 +8000018c: 00002517 auipc a0,0x2 +80000190: e7450513 addi a0,a0,-396 # 80002000 +80000194: 00053007 fld ft0,0(a0) +80000198: 00853087 fld ft1,8(a0) +8000019c: 01053107 fld ft2,16(a0) +800001a0: 01852683 lw a3,24(a0) +800001a4: 01c52303 lw t1,28(a0) +800001a8: 2a1001d3 fmin.d ft3,ft0,ft1 +800001ac: 00353027 fsd ft3,0(a0) +800001b0: 00452383 lw t2,4(a0) +800001b4: 00052503 lw a0,0(a0) +800001b8: 001015f3 fsflags a1,zero +800001bc: 00000613 li a2,0 +800001c0: 48d51a63 bne a0,a3,80000654 +800001c4: 48731863 bne t1,t2,80000654 +800001c8: 48c59663 bne a1,a2,80000654 + +800001cc : +800001cc: 00300193 li gp,3 +800001d0: 00002517 auipc a0,0x2 +800001d4: e5050513 addi a0,a0,-432 # 80002020 +800001d8: 00053007 fld ft0,0(a0) +800001dc: 00853087 fld ft1,8(a0) +800001e0: 01053107 fld ft2,16(a0) +800001e4: 01852683 lw a3,24(a0) +800001e8: 01c52303 lw t1,28(a0) +800001ec: 2a1001d3 fmin.d ft3,ft0,ft1 +800001f0: 00353027 fsd ft3,0(a0) +800001f4: 00452383 lw t2,4(a0) +800001f8: 00052503 lw a0,0(a0) +800001fc: 001015f3 fsflags a1,zero +80000200: 00000613 li a2,0 +80000204: 44d51863 bne a0,a3,80000654 +80000208: 44731663 bne t1,t2,80000654 +8000020c: 44c59463 bne a1,a2,80000654 + +80000210 : +80000210: 00400193 li gp,4 +80000214: 00002517 auipc a0,0x2 +80000218: e2c50513 addi a0,a0,-468 # 80002040 +8000021c: 00053007 fld ft0,0(a0) +80000220: 00853087 fld ft1,8(a0) +80000224: 01053107 fld ft2,16(a0) +80000228: 01852683 lw a3,24(a0) +8000022c: 01c52303 lw t1,28(a0) +80000230: 2a1001d3 fmin.d ft3,ft0,ft1 +80000234: 00353027 fsd ft3,0(a0) +80000238: 00452383 lw t2,4(a0) +8000023c: 00052503 lw a0,0(a0) +80000240: 001015f3 fsflags a1,zero +80000244: 00000613 li a2,0 +80000248: 40d51663 bne a0,a3,80000654 +8000024c: 40731463 bne t1,t2,80000654 +80000250: 40c59263 bne a1,a2,80000654 + +80000254 : +80000254: 00500193 li gp,5 +80000258: 00002517 auipc a0,0x2 +8000025c: e0850513 addi a0,a0,-504 # 80002060 +80000260: 00053007 fld ft0,0(a0) +80000264: 00853087 fld ft1,8(a0) +80000268: 01053107 fld ft2,16(a0) +8000026c: 01852683 lw a3,24(a0) +80000270: 01c52303 lw t1,28(a0) +80000274: 2a1001d3 fmin.d ft3,ft0,ft1 +80000278: 00353027 fsd ft3,0(a0) +8000027c: 00452383 lw t2,4(a0) +80000280: 00052503 lw a0,0(a0) +80000284: 001015f3 fsflags a1,zero +80000288: 00000613 li a2,0 +8000028c: 3cd51463 bne a0,a3,80000654 +80000290: 3c731263 bne t1,t2,80000654 +80000294: 3cc59063 bne a1,a2,80000654 + +80000298 : +80000298: 00600193 li gp,6 +8000029c: 00002517 auipc a0,0x2 +800002a0: de450513 addi a0,a0,-540 # 80002080 +800002a4: 00053007 fld ft0,0(a0) +800002a8: 00853087 fld ft1,8(a0) +800002ac: 01053107 fld ft2,16(a0) +800002b0: 01852683 lw a3,24(a0) +800002b4: 01c52303 lw t1,28(a0) +800002b8: 2a1001d3 fmin.d ft3,ft0,ft1 +800002bc: 00353027 fsd ft3,0(a0) +800002c0: 00452383 lw t2,4(a0) +800002c4: 00052503 lw a0,0(a0) +800002c8: 001015f3 fsflags a1,zero +800002cc: 00000613 li a2,0 +800002d0: 38d51263 bne a0,a3,80000654 +800002d4: 38731063 bne t1,t2,80000654 +800002d8: 36c59e63 bne a1,a2,80000654 + +800002dc : +800002dc: 00700193 li gp,7 +800002e0: 00002517 auipc a0,0x2 +800002e4: dc050513 addi a0,a0,-576 # 800020a0 +800002e8: 00053007 fld ft0,0(a0) +800002ec: 00853087 fld ft1,8(a0) +800002f0: 01053107 fld ft2,16(a0) +800002f4: 01852683 lw a3,24(a0) +800002f8: 01c52303 lw t1,28(a0) +800002fc: 2a1001d3 fmin.d ft3,ft0,ft1 +80000300: 00353027 fsd ft3,0(a0) +80000304: 00452383 lw t2,4(a0) +80000308: 00052503 lw a0,0(a0) +8000030c: 001015f3 fsflags a1,zero +80000310: 00000613 li a2,0 +80000314: 34d51063 bne a0,a3,80000654 +80000318: 32731e63 bne t1,t2,80000654 +8000031c: 32c59c63 bne a1,a2,80000654 + +80000320 : +80000320: 00c00193 li gp,12 +80000324: 00002517 auipc a0,0x2 +80000328: d9c50513 addi a0,a0,-612 # 800020c0 +8000032c: 00053007 fld ft0,0(a0) +80000330: 00853087 fld ft1,8(a0) +80000334: 01053107 fld ft2,16(a0) +80000338: 01852683 lw a3,24(a0) +8000033c: 01c52303 lw t1,28(a0) +80000340: 2a1011d3 fmax.d ft3,ft0,ft1 +80000344: 00353027 fsd ft3,0(a0) +80000348: 00452383 lw t2,4(a0) +8000034c: 00052503 lw a0,0(a0) +80000350: 001015f3 fsflags a1,zero +80000354: 00000613 li a2,0 +80000358: 2ed51e63 bne a0,a3,80000654 +8000035c: 2e731c63 bne t1,t2,80000654 +80000360: 2ec59a63 bne a1,a2,80000654 + +80000364 : +80000364: 00d00193 li gp,13 +80000368: 00002517 auipc a0,0x2 +8000036c: d7850513 addi a0,a0,-648 # 800020e0 +80000370: 00053007 fld ft0,0(a0) +80000374: 00853087 fld ft1,8(a0) +80000378: 01053107 fld ft2,16(a0) +8000037c: 01852683 lw a3,24(a0) +80000380: 01c52303 lw t1,28(a0) +80000384: 2a1011d3 fmax.d ft3,ft0,ft1 +80000388: 00353027 fsd ft3,0(a0) +8000038c: 00452383 lw t2,4(a0) +80000390: 00052503 lw a0,0(a0) +80000394: 001015f3 fsflags a1,zero +80000398: 00000613 li a2,0 +8000039c: 2ad51c63 bne a0,a3,80000654 +800003a0: 2a731a63 bne t1,t2,80000654 +800003a4: 2ac59863 bne a1,a2,80000654 + +800003a8 : +800003a8: 00e00193 li gp,14 +800003ac: 00002517 auipc a0,0x2 +800003b0: d5450513 addi a0,a0,-684 # 80002100 +800003b4: 00053007 fld ft0,0(a0) +800003b8: 00853087 fld ft1,8(a0) +800003bc: 01053107 fld ft2,16(a0) +800003c0: 01852683 lw a3,24(a0) +800003c4: 01c52303 lw t1,28(a0) +800003c8: 2a1011d3 fmax.d ft3,ft0,ft1 +800003cc: 00353027 fsd ft3,0(a0) +800003d0: 00452383 lw t2,4(a0) +800003d4: 00052503 lw a0,0(a0) +800003d8: 001015f3 fsflags a1,zero +800003dc: 00000613 li a2,0 +800003e0: 26d51a63 bne a0,a3,80000654 +800003e4: 26731863 bne t1,t2,80000654 +800003e8: 26c59663 bne a1,a2,80000654 + +800003ec : +800003ec: 00f00193 li gp,15 +800003f0: 00002517 auipc a0,0x2 +800003f4: d3050513 addi a0,a0,-720 # 80002120 +800003f8: 00053007 fld ft0,0(a0) +800003fc: 00853087 fld ft1,8(a0) +80000400: 01053107 fld ft2,16(a0) +80000404: 01852683 lw a3,24(a0) +80000408: 01c52303 lw t1,28(a0) +8000040c: 2a1011d3 fmax.d ft3,ft0,ft1 +80000410: 00353027 fsd ft3,0(a0) +80000414: 00452383 lw t2,4(a0) +80000418: 00052503 lw a0,0(a0) +8000041c: 001015f3 fsflags a1,zero +80000420: 00000613 li a2,0 +80000424: 22d51863 bne a0,a3,80000654 +80000428: 22731663 bne t1,t2,80000654 +8000042c: 22c59463 bne a1,a2,80000654 + +80000430 : +80000430: 01000193 li gp,16 +80000434: 00002517 auipc a0,0x2 +80000438: d0c50513 addi a0,a0,-756 # 80002140 +8000043c: 00053007 fld ft0,0(a0) +80000440: 00853087 fld ft1,8(a0) +80000444: 01053107 fld ft2,16(a0) +80000448: 01852683 lw a3,24(a0) +8000044c: 01c52303 lw t1,28(a0) +80000450: 2a1011d3 fmax.d ft3,ft0,ft1 +80000454: 00353027 fsd ft3,0(a0) +80000458: 00452383 lw t2,4(a0) +8000045c: 00052503 lw a0,0(a0) +80000460: 001015f3 fsflags a1,zero +80000464: 00000613 li a2,0 +80000468: 1ed51663 bne a0,a3,80000654 +8000046c: 1e731463 bne t1,t2,80000654 +80000470: 1ec59263 bne a1,a2,80000654 + +80000474 : +80000474: 01100193 li gp,17 +80000478: 00002517 auipc a0,0x2 +8000047c: ce850513 addi a0,a0,-792 # 80002160 +80000480: 00053007 fld ft0,0(a0) +80000484: 00853087 fld ft1,8(a0) +80000488: 01053107 fld ft2,16(a0) +8000048c: 01852683 lw a3,24(a0) +80000490: 01c52303 lw t1,28(a0) +80000494: 2a1011d3 fmax.d ft3,ft0,ft1 +80000498: 00353027 fsd ft3,0(a0) +8000049c: 00452383 lw t2,4(a0) +800004a0: 00052503 lw a0,0(a0) +800004a4: 001015f3 fsflags a1,zero +800004a8: 00000613 li a2,0 +800004ac: 1ad51463 bne a0,a3,80000654 +800004b0: 1a731263 bne t1,t2,80000654 +800004b4: 1ac59063 bne a1,a2,80000654 + +800004b8 : +800004b8: 01400193 li gp,20 +800004bc: 00002517 auipc a0,0x2 +800004c0: cc450513 addi a0,a0,-828 # 80002180 +800004c4: 00053007 fld ft0,0(a0) +800004c8: 00853087 fld ft1,8(a0) +800004cc: 01053107 fld ft2,16(a0) +800004d0: 01852683 lw a3,24(a0) +800004d4: 01c52303 lw t1,28(a0) +800004d8: 2a1011d3 fmax.d ft3,ft0,ft1 +800004dc: 00353027 fsd ft3,0(a0) +800004e0: 00452383 lw t2,4(a0) +800004e4: 00052503 lw a0,0(a0) +800004e8: 001015f3 fsflags a1,zero +800004ec: 01000613 li a2,16 +800004f0: 16d51263 bne a0,a3,80000654 +800004f4: 16731063 bne t1,t2,80000654 +800004f8: 14c59e63 bne a1,a2,80000654 + +800004fc : +800004fc: 01500193 li gp,21 +80000500: 00002517 auipc a0,0x2 +80000504: ca050513 addi a0,a0,-864 # 800021a0 +80000508: 00053007 fld ft0,0(a0) +8000050c: 00853087 fld ft1,8(a0) +80000510: 01053107 fld ft2,16(a0) +80000514: 01852683 lw a3,24(a0) +80000518: 01c52303 lw t1,28(a0) +8000051c: 2a1011d3 fmax.d ft3,ft0,ft1 +80000520: 00353027 fsd ft3,0(a0) +80000524: 00452383 lw t2,4(a0) +80000528: 00052503 lw a0,0(a0) +8000052c: 001015f3 fsflags a1,zero +80000530: 00000613 li a2,0 +80000534: 12d51063 bne a0,a3,80000654 +80000538: 10731e63 bne t1,t2,80000654 +8000053c: 10c59c63 bne a1,a2,80000654 + +80000540 : +80000540: 01e00193 li gp,30 +80000544: 00002517 auipc a0,0x2 +80000548: c7c50513 addi a0,a0,-900 # 800021c0 +8000054c: 00053007 fld ft0,0(a0) +80000550: 00853087 fld ft1,8(a0) +80000554: 01053107 fld ft2,16(a0) +80000558: 01852683 lw a3,24(a0) +8000055c: 01c52303 lw t1,28(a0) +80000560: 2a1001d3 fmin.d ft3,ft0,ft1 +80000564: 00353027 fsd ft3,0(a0) +80000568: 00452383 lw t2,4(a0) +8000056c: 00052503 lw a0,0(a0) +80000570: 001015f3 fsflags a1,zero +80000574: 00000613 li a2,0 +80000578: 0cd51e63 bne a0,a3,80000654 +8000057c: 0c731c63 bne t1,t2,80000654 +80000580: 0cc59a63 bne a1,a2,80000654 + +80000584 : +80000584: 01f00193 li gp,31 +80000588: 00002517 auipc a0,0x2 +8000058c: c5850513 addi a0,a0,-936 # 800021e0 +80000590: 00053007 fld ft0,0(a0) +80000594: 00853087 fld ft1,8(a0) +80000598: 01053107 fld ft2,16(a0) +8000059c: 01852683 lw a3,24(a0) +800005a0: 01c52303 lw t1,28(a0) +800005a4: 2a1001d3 fmin.d ft3,ft0,ft1 +800005a8: 00353027 fsd ft3,0(a0) +800005ac: 00452383 lw t2,4(a0) +800005b0: 00052503 lw a0,0(a0) +800005b4: 001015f3 fsflags a1,zero +800005b8: 00000613 li a2,0 +800005bc: 08d51c63 bne a0,a3,80000654 +800005c0: 08731a63 bne t1,t2,80000654 +800005c4: 08c59863 bne a1,a2,80000654 + +800005c8 : +800005c8: 02000193 li gp,32 +800005cc: 00002517 auipc a0,0x2 +800005d0: c3450513 addi a0,a0,-972 # 80002200 +800005d4: 00053007 fld ft0,0(a0) +800005d8: 00853087 fld ft1,8(a0) +800005dc: 01053107 fld ft2,16(a0) +800005e0: 01852683 lw a3,24(a0) +800005e4: 01c52303 lw t1,28(a0) +800005e8: 2a1011d3 fmax.d ft3,ft0,ft1 +800005ec: 00353027 fsd ft3,0(a0) +800005f0: 00452383 lw t2,4(a0) +800005f4: 00052503 lw a0,0(a0) +800005f8: 001015f3 fsflags a1,zero +800005fc: 00000613 li a2,0 +80000600: 04d51a63 bne a0,a3,80000654 +80000604: 04731863 bne t1,t2,80000654 +80000608: 04c59663 bne a1,a2,80000654 + +8000060c : +8000060c: 02100193 li gp,33 +80000610: 00002517 auipc a0,0x2 +80000614: c1050513 addi a0,a0,-1008 # 80002220 +80000618: 00053007 fld ft0,0(a0) +8000061c: 00853087 fld ft1,8(a0) +80000620: 01053107 fld ft2,16(a0) +80000624: 01852683 lw a3,24(a0) +80000628: 01c52303 lw t1,28(a0) +8000062c: 2a1011d3 fmax.d ft3,ft0,ft1 +80000630: 00353027 fsd ft3,0(a0) +80000634: 00452383 lw t2,4(a0) +80000638: 00052503 lw a0,0(a0) +8000063c: 001015f3 fsflags a1,zero +80000640: 00000613 li a2,0 +80000644: 00d51863 bne a0,a3,80000654 +80000648: 00731663 bne t1,t2,80000654 +8000064c: 00c59463 bne a1,a2,80000654 +80000650: 02301063 bne zero,gp,80000670 + +80000654 : +80000654: 0ff0000f fence +80000658: 00018063 beqz gp,80000658 +8000065c: 00119193 slli gp,gp,0x1 +80000660: 0011e193 ori gp,gp,1 +80000664: 05d00893 li a7,93 +80000668: 00018513 mv a0,gp +8000066c: 00000073 ecall + +80000670 : +80000670: 0ff0000f fence +80000674: 00100193 li gp,1 +80000678: 05d00893 li a7,93 +8000067c: 00000513 li a0,0 +80000680: 00000073 ecall +80000684: c0001073 unimp +80000688: 0000 unimp +8000068a: 0000 unimp +8000068c: 0000 unimp +8000068e: 0000 unimp +80000690: 0000 unimp +80000692: 0000 unimp +80000694: 0000 unimp +80000696: 0000 unimp +80000698: 0000 unimp +8000069a: 0000 unimp +8000069c: 0000 unimp +8000069e: 0000 unimp +800006a0: 0000 unimp +800006a2: 0000 unimp +800006a4: 0000 unimp +800006a6: 0000 unimp +800006a8: 0000 unimp +800006aa: 0000 unimp +800006ac: 0000 unimp +800006ae: 0000 unimp +800006b0: 0000 unimp +800006b2: 0000 unimp +800006b4: 0000 unimp +800006b6: 0000 unimp +800006b8: 0000 unimp +800006ba: 0000 unimp +800006bc: 0000 unimp +800006be: 0000 unimp +800006c0: 0000 unimp +800006c2: 0000 unimp + +Disassembly of section .data: + +80002000 : +80002000: 0000 unimp +80002002: 0000 unimp +80002004: 0000 unimp +80002006: 4004 lw s1,0(s0) +80002008: 0000 unimp +8000200a: 0000 unimp +8000200c: 0000 unimp +8000200e: 3ff0 fld fa2,248(a5) +80002010: 0000 unimp +80002012: 0000 unimp +80002014: 0000 unimp +80002016: 0000 unimp +80002018: 0000 unimp +8000201a: 0000 unimp +8000201c: 0000 unimp +8000201e: 3ff0 fld fa2,248(a5) + +80002020 : +80002020: 6666 flw fa2,88(sp) +80002022: 6666 flw fa2,88(sp) +80002024: 4c66 lw s8,88(sp) +80002026: 999ac093 xori ra,s5,-1639 +8000202a: 9999 andi a1,a1,-26 +8000202c: 9999 andi a1,a1,-26 +8000202e: 3ff1 jal 8000200a +80002030: 0000 unimp +80002032: 0000 unimp +80002034: 0000 unimp +80002036: 0000 unimp +80002038: 6666 flw fa2,88(sp) +8000203a: 6666 flw fa2,88(sp) +8000203c: 4c66 lw s8,88(sp) +8000203e: xori ra,s5,-1639 + +80002040 : +80002040: 999a add s3,s3,t1 +80002042: 9999 andi a1,a1,-26 +80002044: 9999 andi a1,a1,-26 +80002046: 3ff1 jal 80002022 +80002048: 6666 flw fa2,88(sp) +8000204a: 6666 flw fa2,88(sp) +8000204c: 4c66 lw s8,88(sp) +8000204e: 0000c093 xori ra,ra,0 +80002052: 0000 unimp +80002054: 0000 unimp +80002056: 0000 unimp +80002058: 6666 flw fa2,88(sp) +8000205a: 6666 flw fa2,88(sp) +8000205c: 4c66 lw s8,88(sp) +8000205e: not ra,t6 + +80002060 : +80002060: ffff 0xffff +80002062: ffff 0xffff +80002064: ffff 0xffff +80002066: 7fff 0x7fff +80002068: 6666 flw fa2,88(sp) +8000206a: 6666 flw fa2,88(sp) +8000206c: 4c66 lw s8,88(sp) +8000206e: 0000c093 xori ra,ra,0 +80002072: 0000 unimp +80002074: 0000 unimp +80002076: 0000 unimp +80002078: 6666 flw fa2,88(sp) +8000207a: 6666 flw fa2,88(sp) +8000207c: 4c66 lw s8,88(sp) +8000207e: xori ra,gp,-689 + +80002080 : +80002080: d4f1 beqz s1,8000204c +80002082: 53c8 lw a0,36(a5) +80002084: 400921fb 0x400921fb +80002088: 8c3a mv s8,a4 +8000208a: e230 fsw fa2,64(a2) +8000208c: 798e flw fs3,224(sp) +8000208e: 3e45 jal 80001c3e +80002090: 0000 unimp +80002092: 0000 unimp +80002094: 0000 unimp +80002096: 0000 unimp +80002098: 8c3a mv s8,a4 +8000209a: e230 fsw fa2,64(a2) +8000209c: 798e flw fs3,224(sp) +8000209e: 3e45 jal 80001c4e + +800020a0 : +800020a0: 0000 unimp +800020a2: 0000 unimp +800020a4: 0000 unimp +800020a6: bff0 fsd fa2,248(a5) +800020a8: 0000 unimp +800020aa: 0000 unimp +800020ac: 0000 unimp +800020ae: c000 sw s0,0(s0) +800020b0: 0000 unimp +800020b2: 0000 unimp +800020b4: 0000 unimp +800020b6: 0000 unimp +800020b8: 0000 unimp +800020ba: 0000 unimp +800020bc: 0000 unimp +800020be: c000 sw s0,0(s0) + +800020c0 : +800020c0: 0000 unimp +800020c2: 0000 unimp +800020c4: 0000 unimp +800020c6: 4004 lw s1,0(s0) +800020c8: 0000 unimp +800020ca: 0000 unimp +800020cc: 0000 unimp +800020ce: 3ff0 fld fa2,248(a5) +800020d0: 0000 unimp +800020d2: 0000 unimp +800020d4: 0000 unimp +800020d6: 0000 unimp +800020d8: 0000 unimp +800020da: 0000 unimp +800020dc: 0000 unimp +800020de: 4004 lw s1,0(s0) + +800020e0 : +800020e0: 6666 flw fa2,88(sp) +800020e2: 6666 flw fa2,88(sp) +800020e4: 4c66 lw s8,88(sp) +800020e6: 999ac093 xori ra,s5,-1639 +800020ea: 9999 andi a1,a1,-26 +800020ec: 9999 andi a1,a1,-26 +800020ee: 3ff1 jal 800020ca +800020f0: 0000 unimp +800020f2: 0000 unimp +800020f4: 0000 unimp +800020f6: 0000 unimp +800020f8: 999a add s3,s3,t1 +800020fa: 9999 andi a1,a1,-26 +800020fc: 9999 andi a1,a1,-26 +800020fe: 3ff1 jal 800020da + +80002100 : +80002100: 999a add s3,s3,t1 +80002102: 9999 andi a1,a1,-26 +80002104: 9999 andi a1,a1,-26 +80002106: 3ff1 jal 800020e2 +80002108: 6666 flw fa2,88(sp) +8000210a: 6666 flw fa2,88(sp) +8000210c: 4c66 lw s8,88(sp) +8000210e: 0000c093 xori ra,ra,0 +80002112: 0000 unimp +80002114: 0000 unimp +80002116: 0000 unimp +80002118: 999a add s3,s3,t1 +8000211a: 9999 andi a1,a1,-26 +8000211c: 9999 andi a1,a1,-26 +8000211e: 3ff1 jal 800020fa + +80002120 : +80002120: ffff 0xffff +80002122: ffff 0xffff +80002124: ffff 0xffff +80002126: 7fff 0x7fff +80002128: 6666 flw fa2,88(sp) +8000212a: 6666 flw fa2,88(sp) +8000212c: 4c66 lw s8,88(sp) +8000212e: 0000c093 xori ra,ra,0 +80002132: 0000 unimp +80002134: 0000 unimp +80002136: 0000 unimp +80002138: 6666 flw fa2,88(sp) +8000213a: 6666 flw fa2,88(sp) +8000213c: 4c66 lw s8,88(sp) +8000213e: xori ra,gp,-689 + +80002140 : +80002140: d4f1 beqz s1,8000210c +80002142: 53c8 lw a0,36(a5) +80002144: 400921fb 0x400921fb +80002148: 8c3a mv s8,a4 +8000214a: e230 fsw fa2,64(a2) +8000214c: 798e flw fs3,224(sp) +8000214e: 3e45 jal 80001cfe +80002150: 0000 unimp +80002152: 0000 unimp +80002154: 0000 unimp +80002156: 0000 unimp +80002158: d4f1 beqz s1,80002124 +8000215a: 53c8 lw a0,36(a5) +8000215c: 400921fb 0x400921fb + +80002160 : +80002160: 0000 unimp +80002162: 0000 unimp +80002164: 0000 unimp +80002166: bff0 fsd fa2,248(a5) +80002168: 0000 unimp +8000216a: 0000 unimp +8000216c: 0000 unimp +8000216e: c000 sw s0,0(s0) +80002170: 0000 unimp +80002172: 0000 unimp +80002174: 0000 unimp +80002176: 0000 unimp +80002178: 0000 unimp +8000217a: 0000 unimp +8000217c: 0000 unimp +8000217e: bff0 fsd fa2,248(a5) + +80002180 : +80002180: 0001 nop +80002182: 0000 unimp +80002184: 0000 unimp +80002186: 7ff0 flw fa2,124(a5) +80002188: 0000 unimp +8000218a: 0000 unimp +8000218c: 0000 unimp +8000218e: 3ff0 fld fa2,248(a5) +80002190: 0000 unimp +80002192: 0000 unimp +80002194: 0000 unimp +80002196: 0000 unimp +80002198: 0000 unimp +8000219a: 0000 unimp +8000219c: 0000 unimp +8000219e: 3ff0 fld fa2,248(a5) + +800021a0 : +800021a0: ffff 0xffff +800021a2: ffff 0xffff +800021a4: ffff 0xffff +800021a6: 7fff 0x7fff +800021a8: ffff 0xffff +800021aa: ffff 0xffff +800021ac: ffff 0xffff +800021ae: 7fff 0x7fff +800021b0: 0000 unimp +800021b2: 0000 unimp +800021b4: 0000 unimp +800021b6: 0000 unimp +800021b8: 0000 unimp +800021ba: 0000 unimp +800021bc: 0000 unimp +800021be: 7ff8 flw fa4,124(a5) + +800021c0 : +800021c0: 0000 unimp +800021c2: 0000 unimp +800021c4: 0000 unimp +800021c6: 8000 0x8000 +800021c8: 0000 unimp +800021ca: 0000 unimp +800021cc: 0000 unimp +800021ce: 0000 unimp +800021d0: 0000 unimp +800021d2: 0000 unimp +800021d4: 0000 unimp +800021d6: 0000 unimp +800021d8: 0000 unimp +800021da: 0000 unimp +800021dc: 0000 unimp +800021de: 8000 0x8000 + +800021e0 : +800021e0: 0000 unimp +800021e2: 0000 unimp +800021e4: 0000 unimp +800021e6: 0000 unimp +800021e8: 0000 unimp +800021ea: 0000 unimp +800021ec: 0000 unimp +800021ee: 8000 0x8000 +800021f0: 0000 unimp +800021f2: 0000 unimp +800021f4: 0000 unimp +800021f6: 0000 unimp +800021f8: 0000 unimp +800021fa: 0000 unimp +800021fc: 0000 unimp +800021fe: 8000 0x8000 + +80002200 : +80002200: 0000 unimp +80002202: 0000 unimp +80002204: 0000 unimp +80002206: 8000 0x8000 +80002208: 0000 unimp +8000220a: 0000 unimp +8000220c: 0000 unimp +8000220e: 0000 unimp +80002210: 0000 unimp +80002212: 0000 unimp +80002214: 0000 unimp +80002216: 0000 unimp +80002218: 0000 unimp +8000221a: 0000 unimp +8000221c: 0000 unimp +8000221e: 0000 unimp + +80002220 : +80002220: 0000 unimp +80002222: 0000 unimp +80002224: 0000 unimp +80002226: 0000 unimp +80002228: 0000 unimp +8000222a: 0000 unimp +8000222c: 0000 unimp +8000222e: 8000 0x8000 +80002230: 0000 unimp +80002232: 0000 unimp +80002234: 0000 unimp +80002236: 0000 unimp +80002238: 0000 unimp +8000223a: 0000 unimp +8000223c: 0000 unimp +8000223e: 0000 unimp diff --git a/src/test/resources/asm/rv32ud-p-ldst.dump b/src/test/resources/asm/rv32ud-p-ldst.dump new file mode 100644 index 00000000..d17d1b6c --- /dev/null +++ b/src/test/resources/asm/rv32ud-p-ldst.dump @@ -0,0 +1,267 @@ + +rv32ud-p-ldst: file format elf32-littleriscv + + +Disassembly of section .text.init: + +80000000 <_start>: +80000000: 04c0006f j 8000004c + +80000004 : +80000004: 34202f73 csrr t5,mcause +80000008: 00800f93 li t6,8 +8000000c: 03ff0a63 beq t5,t6,80000040 +80000010: 00900f93 li t6,9 +80000014: 03ff0663 beq t5,t6,80000040 +80000018: 00b00f93 li t6,11 +8000001c: 03ff0263 beq t5,t6,80000040 +80000020: 80000f17 auipc t5,0x80000 +80000024: fe0f0f13 addi t5,t5,-32 # 0 <_start-0x80000000> +80000028: 000f0463 beqz t5,80000030 +8000002c: 000f0067 jr t5 +80000030: 34202f73 csrr t5,mcause +80000034: 000f5463 bgez t5,8000003c +80000038: 0040006f j 8000003c + +8000003c : +8000003c: 5391e193 ori gp,gp,1337 + +80000040 : +80000040: 00001f17 auipc t5,0x1 +80000044: fc3f2023 sw gp,-64(t5) # 80001000 +80000048: ff9ff06f j 80000040 + +8000004c : +8000004c: 00000093 li ra,0 +80000050: 00000113 li sp,0 +80000054: 00000193 li gp,0 +80000058: 00000213 li tp,0 +8000005c: 00000293 li t0,0 +80000060: 00000313 li t1,0 +80000064: 00000393 li t2,0 +80000068: 00000413 li s0,0 +8000006c: 00000493 li s1,0 +80000070: 00000513 li a0,0 +80000074: 00000593 li a1,0 +80000078: 00000613 li a2,0 +8000007c: 00000693 li a3,0 +80000080: 00000713 li a4,0 +80000084: 00000793 li a5,0 +80000088: 00000813 li a6,0 +8000008c: 00000893 li a7,0 +80000090: 00000913 li s2,0 +80000094: 00000993 li s3,0 +80000098: 00000a13 li s4,0 +8000009c: 00000a93 li s5,0 +800000a0: 00000b13 li s6,0 +800000a4: 00000b93 li s7,0 +800000a8: 00000c13 li s8,0 +800000ac: 00000c93 li s9,0 +800000b0: 00000d13 li s10,0 +800000b4: 00000d93 li s11,0 +800000b8: 00000e13 li t3,0 +800000bc: 00000e93 li t4,0 +800000c0: 00000f13 li t5,0 +800000c4: 00000f93 li t6,0 +800000c8: f1402573 csrr a0,mhartid +800000cc: 00051063 bnez a0,800000cc +800000d0: 00000297 auipc t0,0x0 +800000d4: 01028293 addi t0,t0,16 # 800000e0 +800000d8: 30529073 csrw mtvec,t0 +800000dc: 18005073 csrwi satp,0 +800000e0: 00000297 auipc t0,0x0 +800000e4: 02028293 addi t0,t0,32 # 80000100 +800000e8: 30529073 csrw mtvec,t0 +800000ec: 800002b7 lui t0,0x80000 +800000f0: fff28293 addi t0,t0,-1 # 7fffffff <_end+0xffffdfaf> +800000f4: 3b029073 csrw pmpaddr0,t0 +800000f8: 01f00293 li t0,31 +800000fc: 3a029073 csrw pmpcfg0,t0 +80000100: 30405073 csrwi mie,0 +80000104: 00000297 auipc t0,0x0 +80000108: 01428293 addi t0,t0,20 # 80000118 +8000010c: 30529073 csrw mtvec,t0 +80000110: 30205073 csrwi medeleg,0 +80000114: 30305073 csrwi mideleg,0 +80000118: 00000193 li gp,0 +8000011c: 00000297 auipc t0,0x0 +80000120: ee828293 addi t0,t0,-280 # 80000004 +80000124: 30529073 csrw mtvec,t0 +80000128: 00100513 li a0,1 +8000012c: 01f51513 slli a0,a0,0x1f +80000130: 00054c63 bltz a0,80000148 +80000134: 0ff0000f fence +80000138: 00100193 li gp,1 +8000013c: 05d00893 li a7,93 +80000140: 00000513 li a0,0 +80000144: 00000073 ecall +80000148: 80000297 auipc t0,0x80000 +8000014c: eb828293 addi t0,t0,-328 # 0 <_start-0x80000000> +80000150: 00028a63 beqz t0,80000164 +80000154: 10529073 csrw stvec,t0 +80000158: 0000b2b7 lui t0,0xb +8000015c: 10928293 addi t0,t0,265 # b109 <_start-0x7fff4ef7> +80000160: 30229073 csrw medeleg,t0 +80000164: 30005073 csrwi mstatus,0 +80000168: 00002537 lui a0,0x2 +8000016c: 30052073 csrs mstatus,a0 +80000170: 00305073 csrwi fcsr,0 +80000174: 00000297 auipc t0,0x0 +80000178: 01428293 addi t0,t0,20 # 80000188 +8000017c: 34129073 csrw mepc,t0 +80000180: f1402573 csrr a0,mhartid +80000184: 30200073 mret +80000188: 00002417 auipc s0,0x2 +8000018c: ea840413 addi s0,s0,-344 # 80002030 + +80000190 : +80000190: 00043107 fld ft2,0(s0) +80000194: 00243827 fsd ft2,16(s0) +80000198: 01042503 lw a0,16(s0) +8000019c: 01442583 lw a1,20(s0) +800001a0: 00002797 auipc a5,0x2 +800001a4: e6078793 addi a5,a5,-416 # 80002000 +800001a8: 0007a383 lw t2,0(a5) +800001ac: 0047a783 lw a5,4(a5) +800001b0: 00200193 li gp,2 +800001b4: 0a751e63 bne a0,t2,80000270 +800001b8: 0af59c63 bne a1,a5,80000270 + +800001bc : +800001bc: 00043107 fld ft2,0(s0) +800001c0: 00242827 fsw ft2,16(s0) +800001c4: 01042503 lw a0,16(s0) +800001c8: 01442583 lw a1,20(s0) +800001cc: 00002797 auipc a5,0x2 +800001d0: e3c78793 addi a5,a5,-452 # 80002008 +800001d4: 0007a383 lw t2,0(a5) +800001d8: 0047a783 lw a5,4(a5) +800001dc: 00300193 li gp,3 +800001e0: 08751863 bne a0,t2,80000270 +800001e4: 08f59663 bne a1,a5,80000270 + +800001e8 : +800001e8: 00042107 flw ft2,0(s0) +800001ec: 00242827 fsw ft2,16(s0) +800001f0: 01042503 lw a0,16(s0) +800001f4: 01442583 lw a1,20(s0) +800001f8: 00002797 auipc a5,0x2 +800001fc: e1878793 addi a5,a5,-488 # 80002010 +80000200: 0007a383 lw t2,0(a5) +80000204: 0047a783 lw a5,4(a5) +80000208: 00400193 li gp,4 +8000020c: 06751263 bne a0,t2,80000270 +80000210: 06f59063 bne a1,a5,80000270 + +80000214 : +80000214: 00843107 fld ft2,8(s0) +80000218: 00243827 fsd ft2,16(s0) +8000021c: 01042503 lw a0,16(s0) +80000220: 01442583 lw a1,20(s0) +80000224: 00002797 auipc a5,0x2 +80000228: df478793 addi a5,a5,-524 # 80002018 +8000022c: 0007a383 lw t2,0(a5) +80000230: 0047a783 lw a5,4(a5) +80000234: 00500193 li gp,5 +80000238: 02751c63 bne a0,t2,80000270 +8000023c: 02f59a63 bne a1,a5,80000270 + +80000240 : +80000240: 00842107 flw ft2,8(s0) +80000244: 00243827 fsd ft2,16(s0) +80000248: 01042503 lw a0,16(s0) +8000024c: 01442583 lw a1,20(s0) +80000250: 00002797 auipc a5,0x2 +80000254: dd078793 addi a5,a5,-560 # 80002020 +80000258: 0007a383 lw t2,0(a5) +8000025c: 0047a783 lw a5,4(a5) +80000260: 00600193 li gp,6 +80000264: 00751663 bne a0,t2,80000270 +80000268: 00f59463 bne a1,a5,80000270 +8000026c: 02301063 bne zero,gp,8000028c + +80000270 : +80000270: 0ff0000f fence +80000274: 00018063 beqz gp,80000274 +80000278: 00119193 slli gp,gp,0x1 +8000027c: 0011e193 ori gp,gp,1 +80000280: 05d00893 li a7,93 +80000284: 00018513 mv a0,gp +80000288: 00000073 ecall + +8000028c : +8000028c: 0ff0000f fence +80000290: 00100193 li gp,1 +80000294: 05d00893 li a7,93 +80000298: 00000513 li a0,0 +8000029c: 00000073 ecall +800002a0: c0001073 unimp +800002a4: 0000 unimp +800002a6: 0000 unimp +800002a8: 0000 unimp +800002aa: 0000 unimp +800002ac: 0000 unimp +800002ae: 0000 unimp +800002b0: 0000 unimp +800002b2: 0000 unimp +800002b4: 0000 unimp +800002b6: 0000 unimp +800002b8: 0000 unimp +800002ba: 0000 unimp +800002bc: 0000 unimp +800002be: 0000 unimp +800002c0: 0000 unimp +800002c2: 0000 unimp + +Disassembly of section .data: + +80002000 : +80002000: 0000 unimp +80002002: bf80 fsd fs0,56(a5) +80002004: 0000 unimp +80002006: 4000 lw s0,0(s0) + +80002008 : +80002008: 0000 unimp +8000200a: bf80 fsd fs0,56(a5) +8000200c: 0000 unimp +8000200e: 4000 lw s0,0(s0) + +80002010 : +80002010: 0000 unimp +80002012: bf80 fsd fs0,56(a5) +80002014: 0000 unimp +80002016: 4000 lw s0,0(s0) + +80002018 : +80002018: 0000 unimp +8000201a: 4040 lw s0,4(s0) +8000201c: 0000 unimp +8000201e: c080 sw s0,0(s1) + +80002020 : +80002020: 0000 unimp +80002022: 4040 lw s0,4(s0) +80002024: ffff 0xffff +80002026: ffff 0xffff +80002028: 0000 unimp +8000202a: 0000 unimp +8000202c: 0000 unimp +8000202e: 0000 unimp + +80002030 : +80002030: 0000 unimp +80002032: bf80 fsd fs0,56(a5) +80002034: 0000 unimp +80002036: 4000 lw s0,0(s0) +80002038: 0000 unimp +8000203a: 4040 lw s0,4(s0) +8000203c: 0000 unimp +8000203e: c080 sw s0,0(s1) +80002040: deadbeef jal t4,7ffdd62a <_start-0x229d6> +80002044: babe fsd fa5,368(sp) +80002046: cafe sw t6,84(sp) +80002048: 1dea slli s11,s11,0x3a +8000204a: abad j 800025c4 <_end+0x574> +8000204c: d00d beqz s0,80001f6e +8000204e: lui t1,0x1 diff --git a/src/test/resources/asm/rv32ud-p-recoding.dump b/src/test/resources/asm/rv32ud-p-recoding.dump new file mode 100644 index 00000000..11364393 --- /dev/null +++ b/src/test/resources/asm/rv32ud-p-recoding.dump @@ -0,0 +1,190 @@ + +rv32ud-p-recoding: file format elf32-littleriscv + + +Disassembly of section .text.init: + +80000000 <_start>: +80000000: 04c0006f j 8000004c + +80000004 : +80000004: 34202f73 csrr t5,mcause +80000008: 00800f93 li t6,8 +8000000c: 03ff0a63 beq t5,t6,80000040 +80000010: 00900f93 li t6,9 +80000014: 03ff0663 beq t5,t6,80000040 +80000018: 00b00f93 li t6,11 +8000001c: 03ff0263 beq t5,t6,80000040 +80000020: 80000f17 auipc t5,0x80000 +80000024: fe0f0f13 addi t5,t5,-32 # 0 <_start-0x80000000> +80000028: 000f0463 beqz t5,80000030 +8000002c: 000f0067 jr t5 +80000030: 34202f73 csrr t5,mcause +80000034: 000f5463 bgez t5,8000003c +80000038: 0040006f j 8000003c + +8000003c : +8000003c: 5391e193 ori gp,gp,1337 + +80000040 : +80000040: 00001f17 auipc t5,0x1 +80000044: fc3f2023 sw gp,-64(t5) # 80001000 +80000048: ff9ff06f j 80000040 + +8000004c : +8000004c: 00000093 li ra,0 +80000050: 00000113 li sp,0 +80000054: 00000193 li gp,0 +80000058: 00000213 li tp,0 +8000005c: 00000293 li t0,0 +80000060: 00000313 li t1,0 +80000064: 00000393 li t2,0 +80000068: 00000413 li s0,0 +8000006c: 00000493 li s1,0 +80000070: 00000513 li a0,0 +80000074: 00000593 li a1,0 +80000078: 00000613 li a2,0 +8000007c: 00000693 li a3,0 +80000080: 00000713 li a4,0 +80000084: 00000793 li a5,0 +80000088: 00000813 li a6,0 +8000008c: 00000893 li a7,0 +80000090: 00000913 li s2,0 +80000094: 00000993 li s3,0 +80000098: 00000a13 li s4,0 +8000009c: 00000a93 li s5,0 +800000a0: 00000b13 li s6,0 +800000a4: 00000b93 li s7,0 +800000a8: 00000c13 li s8,0 +800000ac: 00000c93 li s9,0 +800000b0: 00000d13 li s10,0 +800000b4: 00000d93 li s11,0 +800000b8: 00000e13 li t3,0 +800000bc: 00000e93 li t4,0 +800000c0: 00000f13 li t5,0 +800000c4: 00000f93 li t6,0 +800000c8: f1402573 csrr a0,mhartid +800000cc: 00051063 bnez a0,800000cc +800000d0: 00000297 auipc t0,0x0 +800000d4: 01028293 addi t0,t0,16 # 800000e0 +800000d8: 30529073 csrw mtvec,t0 +800000dc: 18005073 csrwi satp,0 +800000e0: 00000297 auipc t0,0x0 +800000e4: 02028293 addi t0,t0,32 # 80000100 +800000e8: 30529073 csrw mtvec,t0 +800000ec: 800002b7 lui t0,0x80000 +800000f0: fff28293 addi t0,t0,-1 # 7fffffff <_end+0xffffdfef> +800000f4: 3b029073 csrw pmpaddr0,t0 +800000f8: 01f00293 li t0,31 +800000fc: 3a029073 csrw pmpcfg0,t0 +80000100: 30405073 csrwi mie,0 +80000104: 00000297 auipc t0,0x0 +80000108: 01428293 addi t0,t0,20 # 80000118 +8000010c: 30529073 csrw mtvec,t0 +80000110: 30205073 csrwi medeleg,0 +80000114: 30305073 csrwi mideleg,0 +80000118: 00000193 li gp,0 +8000011c: 00000297 auipc t0,0x0 +80000120: ee828293 addi t0,t0,-280 # 80000004 +80000124: 30529073 csrw mtvec,t0 +80000128: 00100513 li a0,1 +8000012c: 01f51513 slli a0,a0,0x1f +80000130: 00054c63 bltz a0,80000148 +80000134: 0ff0000f fence +80000138: 00100193 li gp,1 +8000013c: 05d00893 li a7,93 +80000140: 00000513 li a0,0 +80000144: 00000073 ecall +80000148: 80000297 auipc t0,0x80000 +8000014c: eb828293 addi t0,t0,-328 # 0 <_start-0x80000000> +80000150: 00028a63 beqz t0,80000164 +80000154: 10529073 csrw stvec,t0 +80000158: 0000b2b7 lui t0,0xb +8000015c: 10928293 addi t0,t0,265 # b109 <_start-0x7fff4ef7> +80000160: 30229073 csrw medeleg,t0 +80000164: 30005073 csrwi mstatus,0 +80000168: 00002537 lui a0,0x2 +8000016c: 30052073 csrs mstatus,a0 +80000170: 00305073 csrwi fcsr,0 +80000174: 00000297 auipc t0,0x0 +80000178: 01428293 addi t0,t0,20 # 80000188 +8000017c: 34129073 csrw mepc,t0 +80000180: f1402573 csrr a0,mhartid +80000184: 30200073 mret +80000188: 00002517 auipc a0,0x2 +8000018c: e7852007 flw ft0,-392(a0) # 80002000 +80000190: 00002517 auipc a0,0x2 +80000194: e7452087 flw ft1,-396(a0) # 80002004 +80000198: 1000f0d3 fmul.s ft1,ft1,ft0 + +8000019c : +8000019c: a0102553 feq.s a0,ft0,ft1 +800001a0: 00100393 li t2,1 +800001a4: 00200193 li gp,2 +800001a8: 06751463 bne a0,t2,80000210 + +800001ac : +800001ac: a0100553 fle.s a0,ft0,ft1 +800001b0: 00100393 li t2,1 +800001b4: 00300193 li gp,3 +800001b8: 04751c63 bne a0,t2,80000210 + +800001bc : +800001bc: a0101553 flt.s a0,ft0,ft1 +800001c0: 00000393 li t2,0 +800001c4: 00400193 li gp,4 +800001c8: 04751463 bne a0,t2,80000210 +800001cc: d0007053 fcvt.s.w ft0,zero +800001d0: 00100513 li a0,1 +800001d4: d00570d3 fcvt.s.w ft1,a0 +800001d8: 1000f0d3 fmul.s ft1,ft1,ft0 + +800001dc : +800001dc: a0102553 feq.s a0,ft0,ft1 +800001e0: 00100393 li t2,1 +800001e4: 00500193 li gp,5 +800001e8: 02751463 bne a0,t2,80000210 + +800001ec : +800001ec: a0100553 fle.s a0,ft0,ft1 +800001f0: 00100393 li t2,1 +800001f4: 00600193 li gp,6 +800001f8: 00751c63 bne a0,t2,80000210 + +800001fc : +800001fc: a0101553 flt.s a0,ft0,ft1 +80000200: 00000393 li t2,0 +80000204: 00700193 li gp,7 +80000208: 00751463 bne a0,t2,80000210 +8000020c: 02301063 bne zero,gp,8000022c + +80000210 : +80000210: 0ff0000f fence +80000214: 00018063 beqz gp,80000214 +80000218: 00119193 slli gp,gp,0x1 +8000021c: 0011e193 ori gp,gp,1 +80000220: 05d00893 li a7,93 +80000224: 00018513 mv a0,gp +80000228: 00000073 ecall + +8000022c : +8000022c: 0ff0000f fence +80000230: 00100193 li gp,1 +80000234: 05d00893 li a7,93 +80000238: 00000513 li a0,0 +8000023c: 00000073 ecall +80000240: c0001073 unimp + +Disassembly of section .data: + +80002000 : +80002000: 0000 unimp +80002002: ff80 fsw fs0,56(a5) + +80002004 : +80002004: 0000 unimp +80002006: 4040 lw s0,4(s0) +80002008: 0000 unimp +8000200a: 0000 unimp +8000200c: 0000 unimp +8000200e: 0000 unimp diff --git a/src/test/resources/hex/rv32ud-p-fadd.hex b/src/test/resources/hex/rv32ud-p-fadd.hex new file mode 100755 index 00000000..af0e7c27 --- /dev/null +++ b/src/test/resources/hex/rv32ud-p-fadd.hex @@ -0,0 +1,101 @@ +:0200000480007A +:100000006F00C004732F2034930F8000630AFF0336 +:10001000930F90006306FF03930FB0006302FF038A +:10002000170F0080130F0FFE63040F0067000F000F +:10003000732F203463540F006F00400093E19153FD +:10004000171F000023203FFC6FF09FFF930000006C +:10005000130100009301000013020000930200004E +:100060001303000093030000130400009304000036 +:10007000130500009305000013060000930600001E +:100080001307000093070000130800009308000006 +:100090001309000093090000130A0000930A0000EE +:1000A000130B0000930B0000130C0000930C0000D6 +:1000B000130D0000930D0000130E0000930E0000BE +:1000C000130F0000930F0000732540F1631005002B +:1000D000970200009382020173905230735000180F +:1000E000970200009382020273905230B7020080A0 +:1000F0009382F2FF7390023B9302F0017390023AF5 +:100100007350403097020000938242017390523046 +:10011000735020307350303093010000970200007C +:10012000938282EE73905230130510001315F5017F +:10013000634C05000F00F00F930110009308D005E9 +:10014000130500007300000097020080938282EB89 +:10015000638A020073905210B7B20000938292102B +:100160007390223073500030372500007320053023 +:100170007350300097020000938242017390123452 +:10018000732540F1730020309301200017250000F3 +:10019000130545E707300500873085000731050165 +:1001A000832685010323C501D37110022730350052 +:1001B0008323450003250500F315100013060000F6 +:1001C000631AD526631873266396C52693013000FB +:1001D00017250000130505E5073005008730850069 +:1001E00007310501832685010323C501D371100260 +:1001F000273035008323450003250500F315100043 +:10020000130610006318D522631673226394C52267 +:1002100093014000172500001305C5E207300500D3 +:100220008730850007310501832685010323C50139 +:10023000D3711002273035008323450003250500C4 +:10024000F3151000130610006316D51E6314731EF9 +:100250006392C51E9301500017250000130585E029 +:1002600007300500873085000731050183268501A9 +:100270000323C501D371100A2730350083234500BD +:1002800003250500F3151000130600006314D51AAA +:100290006312731A6390C51A93016000172500005A +:1002A000130545DE0730050087308500073105015D +:1002B000832685010323C501D371100A2730350039 +:1002C0008323450003250500F315100013061000D5 +:1002D0006312D51663107316639EC51493017000E4 +:1002E00017250000130505DC073005008730850061 +:1002F00007310501832685010323C501D371100A47 +:10030000273035008323450003250500F315100031 +:10031000130610006310D512631E7310639CC51082 +:1003200093018000172500001305C5D9073005008B +:100330008730850007310501832685010323C50128 +:10034000D3711012273035008323450003250500A3 +:10035000F315100013060000631ED50C631C730C0C +:10036000639AC50C9301900017250000130585D7EB +:100370000730050087308500073105018326850198 +:100380000323C501D37110122730350083234500A4 +:1003900003250500F315100013061000631CD50893 +:1003A000631A73086398C5089301A000172500001D +:1003B000130545D507300500873085000731050155 +:1003C000832685010323C501D37110122730350020 +:1003D0008323450003250500F315100013061000C4 +:1003E000631AD504631873046396C5049301B000BF +:1003F00017250000130505D3073005008730850059 +:1004000007310501832685010323C501D371100A35 +:10041000273035008323450003250500F315100020 +:10042000130600016318D500631673006394C500BA +:10043000631030020F00F00F6380010093911100F0 +:1004400093E111009308D0051385010073000000AB +:100450000F00F00F930110009308D0051305000062 +:1004600073000000731000C00000000000000000D6 +:10047000000000000000000000000000000000007C +:040480000000000078 +:1010000000000000000000000000000000000000E0 +:1010100000000000000000000000000000000000D0 +:1010200000000000000000000000000000000000C0 +:1010300000000000000000000000000000000000B0 +:081040000000000000000000A8 +:102000000000000000000440000000000000F03F5D +:1020100000000000000000000000000000000C4074 +:1020200066666666664C93C09A9999999999F13F4C +:10203000000000000000000000000000004893C005 +:10204000F1D4C853FB2109403A8C30E28E79453EE9 +:102050000000000000000000DF6D2055FB2109405A +:102060000000000000000440000000000000F03FFD +:102070000000000000000000000000000000F83F29 +:1020800066666666664C93C09A9999999999F1BF6C +:10209000000000000000000000000000004893C0A5 +:1020A000F1D4C853FB2109403A8C30E28E79453E89 +:1020B0000000000000000000033C7152FB210940B9 +:1020C0000000000000000440000000000000F03F9D +:1020D00000000000000000000000000000000440BC +:1020E00066666666664C93C09A9999999999F1BF0C +:1020F00000000000000000003D0AD7A3703A9540A0 +:10210000F1D4C853FB2109403A8C30E28E79453E28 +:10211000000000000000000009FFC1A5C5DD603E11 +:10212000000000000000F07F000000000000F07FD1 +:102130000000000000000000000000000000F87F28 +:040000058000000077 +:00000001FF diff --git a/src/test/resources/hex/rv32ud-p-fclass.hex b/src/test/resources/hex/rv32ud-p-fclass.hex new file mode 100755 index 00000000..bd420da7 --- /dev/null +++ b/src/test/resources/hex/rv32ud-p-fclass.hex @@ -0,0 +1,62 @@ +:0200000480007A +:100000006F00C004732F2034930F8000630AFF0336 +:10001000930F90006306FF03930FB0006302FF038A +:10002000170F0080130F0FFE63040F0067000F000F +:10003000732F203463540F006F00400093E19153FD +:10004000171F000023203FFC6FF09FFF930000006C +:10005000130100009301000013020000930200004E +:100060001303000093030000130400009304000036 +:10007000130500009305000013060000930600001E +:100080001307000093070000130800009308000006 +:100090001309000093090000130A0000930A0000EE +:1000A000130B0000930B0000130C0000930C0000D6 +:1000B000130D0000930D0000130E0000930E0000BE +:1000C000130F0000930F0000732540F1631005002B +:1000D000970200009382020173905230735000180F +:1000E000970200009382020273905230B7020080A0 +:1000F0009382F2FF7390023B9302F0017390023AF5 +:100100007350403097020000938242017390523046 +:10011000735020307350303093010000970200007C +:10012000938282EE73905230130510001315F5017F +:10013000634C05000F00F00F930110009308D005E9 +:10014000130500007300000097020080938282EB89 +:10015000638A020073905210B7B20000938292102B +:100160007390223073500030372500007320053023 +:100170007350300097020000938242017390123452 +:10018000732540F17300203017250000130585E723 +:1001900007350500531505E2930310009301200075 +:1001A0006312751017250000130545E60735050095 +:1001B000531505E293032000930130006314750E7C +:1001C00017250000130505E507350500531505E261 +:1001D00093034000930140006316750C172500003F +:1001E0001305C5E307350500531505E293038000A9 +:1001F000930150006318750A17250000130585E266 +:1002000007350500531505E29303000193016000D3 +:10021000631A750817250000130545E10735050029 +:10022000531505E29303000293017000631C7506E9 +:1002300017250000130505E007350500531505E2F5 +:100240009303000493018000631E750417250000CA +:100250001305C5DE07350500531505E293030008B5 +:10026000930190006310750417250000130585DDC8 +:1002700007350500531505E2930300109301A00014 +:100280006312750217250000130545DC07350500CC +:10029000531505E2930300209301B0006314750029 +:1002A000631030020F00F00F638001009391110082 +:1002B00093E111009308D00513850100730000003D +:1002C0000F00F00F930110009308D00513050000F4 +:1002D00073000000731000C0000000000000000068 +:1002E000000000000000000000000000000000000E +:1002F00000000000000000000000000000000000FE +:0403000000000000F9 +:1010000000000000000000000000000000000000E0 +:1010100000000000000000000000000000000000D0 +:1010200000000000000000000000000000000000C0 +:1010300000000000000000000000000000000000B0 +:081040000000000000000000A8 +:10200000000000000000F0FF000000000000F0BF32 +:10201000FFFFFFFFFFFF0F800000000000000080B7 +:102020000000000000000000FFFFFFFFFFFF0F00A7 +:10203000000000000000F03F000000000000F07F02 +:10204000010000000000F07F000000000000F87FA9 +:040000058000000077 +:00000001FF diff --git a/src/test/resources/hex/rv32ud-p-fcmp.hex b/src/test/resources/hex/rv32ud-p-fcmp.hex new file mode 100755 index 00000000..1b0ec55d --- /dev/null +++ b/src/test/resources/hex/rv32ud-p-fcmp.hex @@ -0,0 +1,123 @@ +:0200000480007A +:100000006F00C004732F2034930F8000630AFF0336 +:10001000930F90006306FF03930FB0006302FF038A +:10002000170F0080130F0FFE63040F0067000F000F +:10003000732F203463540F006F00400093E19153FD +:10004000171F000023203FFC6FF09FFF930000006C +:10005000130100009301000013020000930200004E +:100060001303000093030000130400009304000036 +:10007000130500009305000013060000930600001E +:100080001307000093070000130800009308000006 +:100090001309000093090000130A0000930A0000EE +:1000A000130B0000930B0000130C0000930C0000D6 +:1000B000130D0000930D0000130E0000930E0000BE +:1000C000130F0000930F0000732540F1631005002B +:1000D000970200009382020173905230735000180F +:1000E000970200009382020273905230B7020080A0 +:1000F0009382F2FF7390023B9302F0017390023AF5 +:100100007350403097020000938242017390523046 +:10011000735020307350303093010000970200007C +:10012000938282EE73905230130510001315F5017F +:10013000634C05000F00F00F930110009308D005E9 +:10014000130500007300000097020080938282EB89 +:10015000638A020073905210B7B20000938292102B +:100160007390223073500030372500007320053023 +:100170007350300097020000938242017390123452 +:10018000732540F1730020309301200017250000F3 +:10019000130545E707300500873085000731050165 +:1001A000832685010323C501532510A29303000074 +:1001B000F315100013060000631CD534631A733462 +:1001C0006398C5349301300017250000130585E5B9 +:1001D000073005008730850007310501832685013A +:1001E0000323C501530510A293030000F31510006B +:1001F00013060000631ED530631C7330639AC5304C +:1002000093014000172500001305C5E307300500E2 +:100210008730850007310501832685010323C50149 +:10022000531510A293030000F315100013060000ED +:100230006310D52E631E732C639CC52C9301500054 +:1002400017250000130505E20730050087308500FB +:1002500007310501832685010323C501532510A21B +:1002600093030000F3151000130600006312D52A53 +:100270006310732A639EC528930160001725000050 +:10028000130545E00730050087308500073105017B +:10029000832685010323C501530510A293030000A3 +:1002A000F3151000130600006314D526631273269D +:1002B0006390C5269301700017250000130585DEA5 +:1002C0000730050087308500073105018326850149 +:1002D0000323C501531510A293030000F31510006A +:1002E000130600006316D522631473226392C5229D +:1002F00093018000172500001305C5DC07300500B9 +:100300008730850007310501832685010323C50158 +:10031000532510A293030000F315100013060000EC +:100320006318D51E6316731E6394C51E9301900057 +:1003300017250000130505DB073005008730850011 +:1003400007310501832685010323C501532510A22A +:1003500093030000F315100013060000631AD51A6A +:100360006318731A6396C51A9301A000172500003D +:10037000130545D907300500873085000731050191 +:10038000832685010323C501532510A29303000092 +:10039000F315100013060001631CD516631A7316BB +:1003A0006398C5169301B00017250000130585D783 +:1003B0000730050087308500073105018326850158 +:1003C0000323C501531510A293030000F315100079 +:1003D00013060001631ED512631C7312639AC512C3 +:1003E0009301C000172500001305C5D5073005008F +:1003F0008730850007310501832685010323C50168 +:10040000531510A293030000F3151000130600010A +:100410006310D510631E730E639CC50E9301D0004C +:1004200017250000130505D4073005008730850027 +:1004300007310501832685010323C501531510A249 +:1004400093030000F3151000130600016312D50C8E +:100450006310730C639EC50A9301E000172500002A +:10046000130545D2073005008730850007310501A7 +:10047000832685010323C501530510A293030000C1 +:10048000F3151000130600016314D50863127308F6 +:100490006390C5089301F00017250000130585D06F +:1004A0000730050087308500073105018326850167 +:1004B0000323C501530510A293030000F315100098 +:1004C000130600016316D504631473046392C50414 +:1004D00093010001172500001305C5CE0730050064 +:1004E0008730850007310501832685010323C50177 +:1004F000530510A293030000F3151000130600012A +:100500006318D500631673006394C500631030024E +:100510000F00F00F638001009391110093E111002F +:100520009308D00513850100730000000F00F00F41 +:10053000930110009308D00513050000730000001C +:04054000731000C074 +:1010000000000000000000000000000000000000E0 +:1010100000000000000000000000000000000000D0 +:1010200000000000000000000000000000000000C0 +:1010300000000000000000000000000000000000B0 +:081040000000000000000000A8 +:10200000C3F5285C8FC2F5BFC3F5285C8FC2F5BF4E +:1020100000000000000000000100000000000000BF +:10202000C3F5285C8FC2F5BFC3F5285C8FC2F5BF2E +:10203000000000000000000001000000000000009F +:10204000C3F5285C8FC2F5BFC3F5285C8FC2F5BF0E +:102050000000000000000000000000000000000080 +:10206000EC51B81E85EBF5BFC3F5285C8FC2F5BFF8 +:102070000000000000000000000000000000000060 +:10208000EC51B81E85EBF5BFC3F5285C8FC2F5BFD8 +:10209000000000000000000001000000000000003F +:1020A000EC51B81E85EBF5BFC3F5285C8FC2F5BFB8 +:1020B000000000000000000001000000000000001F +:1020C000FFFFFFFFFFFFFF7F000000000000000098 +:1020D0000000000000000000000000000000000000 +:1020E000FFFFFFFFFFFFFF7FFFFFFFFFFFFFFF7F00 +:1020F00000000000000000000000000000000000E0 +:10210000010000000000F07F00000000000000005F +:1021100000000000000000000000000000000000BF +:10212000FFFFFFFFFFFFFF7F000000000000000037 +:10213000000000000000000000000000000000009F +:10214000FFFFFFFFFFFFFF7FFFFFFFFFFFFFFF7F9F +:10215000000000000000000000000000000000007F +:10216000010000000000F07F0000000000000000FF +:10217000000000000000000000000000000000005F +:10218000FFFFFFFFFFFFFF7F0000000000000000D7 +:10219000000000000000000000000000000000003F +:1021A000FFFFFFFFFFFFFF7FFFFFFFFFFFFFFF7F3F +:1021B000000000000000000000000000000000001F +:1021C000010000000000F07F00000000000000009F +:1021D00000000000000000000000000000000000FF +:040000058000000077 +:00000001FF diff --git a/src/test/resources/hex/rv32ud-p-fcvt.hex b/src/test/resources/hex/rv32ud-p-fcvt.hex new file mode 100755 index 00000000..78064fa2 --- /dev/null +++ b/src/test/resources/hex/rv32ud-p-fcvt.hex @@ -0,0 +1,72 @@ +:0200000480007A +:100000006F00C004732F2034930F8000630AFF0336 +:10001000930F90006306FF03930FB0006302FF038A +:10002000170F0080130F0FFE63040F0067000F000F +:10003000732F203463540F006F00400093E19153FD +:10004000171F000023203FFC6FF09FFF930000006C +:10005000130100009301000013020000930200004E +:100060001303000093030000130400009304000036 +:10007000130500009305000013060000930600001E +:100080001307000093070000130800009308000006 +:100090001309000093090000130A0000930A0000EE +:1000A000130B0000930B0000130C0000930C0000D6 +:1000B000130D0000930D0000130E0000930E0000BE +:1000C000130F0000930F0000732540F1631005002B +:1000D000970200009382020173905230735000180F +:1000E000970200009382020273905230B7020080A0 +:1000F0009382F2FF7390023B9302F0017390023AF5 +:100100007350403097020000938242017390523046 +:10011000735020307350303093010000970200007C +:10012000938282EE73905230130510001315F5017F +:10013000634C05000F00F00F930110009308D005E9 +:10014000130500007300000097020080938282EB89 +:10015000638A020073905210B7B20000938292102B +:100160007390223073500030372500007320053023 +:100170007350300097020000938242017390123452 +:10018000732540F1730020309301200017250000F3 +:10019000130545E783260500032745009305200046 +:1001A000538005D22730050083254500032505002F +:1001B000731010006312D5166390E516930130009A +:1001C00017250000130585E4832605000327450055 +:1001D0009305E0FF538005D22730050083254500B5 +:1001E00003250500731010006318D5126396E512FD +:1001F00093014000172500001305C5E18326050083 +:100200000327450093052000538015D227300500B1 +:10021000832545000325050073101000631ED50ECD +:10022000639CE50E9301500017250000130505DFC0 +:1002300083260500032745009305E0FF538015D270 +:1002400027300500832545000325050073101000A5 +:100250006314D50C6392E50C9301A00017250000F0 +:10026000130545DC0730050087308500073105019F +:10027000832685010323C501D3711040D381014238 +:10028000273035008323450003250500F3151000B2 +:10029000130600006312D50863107308639EC50639 +:1002A0009301B000172500001305C5D907200500EC +:1002B00087204500072185008326C500D301004221 +:1002C000D3F11140538501E0F3151000130600002F +:1002D0006314D5046392C50497250000938585D8DF +:1002E00007B10500537111405301014227B02500A9 +:1002F00003A5050083A5450097270000938787D5B0 +:1003000083A3070083A747009301C000631675000D +:100310006394F500631030020F00F00F638001005A +:100320009391110093E111009308D005138501000A +:10033000730000000F00F00F930110009308D00528 +:100340001305000073000000731000C000000000DF +:10035000000000000000000000000000000000009D +:10036000000000000000000000000000000000008D +:10037000000000000000000000000000000000007D +:040380000000000079 +:1010000000000000000000000000000000000000E0 +:1010100000000000000000000000000000000000D0 +:1010200000000000000000000000000000000000C0 +:1010300000000000000000000000000000000000B0 +:081040000000000000000000A8 +:10200000000000000000004000000000000000C0D0 +:1020100000000000000000400000C0FFFFFFEF4193 +:10202000000000000000F8BF0000000000000000F9 +:102030000000000000000000000000000000F8BFE9 +:102040000000C0BF00000000000000000000C0BF92 +:10205000000000000000F87F000000000000000009 +:102060000480FFFFFFFFFC7F000000000000000075 +:040000058000000077 +:00000001FF diff --git a/src/test/resources/hex/rv32ud-p-fcvt_w.hex b/src/test/resources/hex/rv32ud-p-fcvt_w.hex new file mode 100755 index 00000000..f7588581 --- /dev/null +++ b/src/test/resources/hex/rv32ud-p-fcvt_w.hex @@ -0,0 +1,120 @@ +:0200000480007A +:100000006F00C004732F2034930F8000630AFF0336 +:10001000930F90006306FF03930FB0006302FF038A +:10002000170F0080130F0FFE63040F0067000F000F +:10003000732F203463540F006F00400093E19153FD +:10004000171F000023203FFC6FF09FFF930000006C +:10005000130100009301000013020000930200004E +:100060001303000093030000130400009304000036 +:10007000130500009305000013060000930600001E +:100080001307000093070000130800009308000006 +:100090001309000093090000130A0000930A0000EE +:1000A000130B0000930B0000130C0000930C0000D6 +:1000B000130D0000930D0000130E0000930E0000BE +:1000C000130F0000930F0000732540F1631005002B +:1000D000970200009382020173905230735000180F +:1000E000970200009382020273905230B7020080A0 +:1000F0009382F2FF7390023B9302F0017390023AF5 +:100100007350403097020000938242017390523046 +:10011000735020307350303093010000970200007C +:10012000938282EE73905230130510001315F5017F +:10013000634C05000F00F00F930110009308D005E9 +:10014000130500007300000097020080938282EB89 +:10015000638A020073905210B7B20000938292102B +:100160007390223073500030372500007320053023 +:100170007350300097020000938242017390123452 +:10018000732540F1730020309301200017250000F3 +:10019000130545E707200500872045000721850056 +:1001A0008326C500531500C0F31510001306100078 +:1001B0006314D53C6392C53C9301300017250000C1 +:1001C000130545E507200500872045000721850028 +:1001D0008326C500531500C0F31510001306000058 +:1001E000631CD538639AC538930140001725000079 +:1001F000130545E3072005008720450007218500FA +:100200008326C500531500C0F31510001306100017 +:100210006314D5366392C53693015000172500004C +:10022000130545E1072005008720450007218500CB +:100230008326C500531500C0F315100013061000E7 +:10024000631CD532639AC532930160001725000004 +:10025000130545DF0720050087204500072185009D +:100260008326C500531500C0F315100013060000C7 +:100270006314D5306392C5309301700017250000D8 +:10028000130545DD0720050087204500072185006F +:100290008326C500531500C0F31510001306100087 +:1002A000631CD52C639AC52C930180001725000090 +:1002B000130545DB07200500872045000721850041 +:1002C0008326C500531500C0F31510001306000166 +:1002D0006314D52A6392C52A930190001725000064 +:1002E000130545D907200500872045000721850013 +:1002F0008326C500531500C0F31510001306000136 +:10030000631CD526639AC5269301C00017250000FB +:10031000130545D7072005008720450007218500E4 +:100320008326C500531510C0F315100013060001F5 +:100330006314D5246392C5249301D00017250000CF +:10034000130545D5072005008720450007218500B6 +:100350008326C500531510C0F315100013060001C5 +:10036000631CD520639AC5209301E0001725000087 +:10037000130545D307200500872045000721850088 +:100380008326C500531510C0F31510001306100086 +:100390006314D51E6392C51E9301F000172500005B +:1003A000130545D10720050087204500072185005A +:1003B0008326C500531510C0F31510001306100056 +:1003C000631CD51A639AC51A930100011725000012 +:1003D000130545CF0720050087204500072185002C +:1003E0008326C500531510C0F31510001306000036 +:1003F0006314D5186392C5189301100117250000E6 +:10040000130545CD072005008720450007218500FD +:100410008326C500531510C0F315100013061000F5 +:10042000631CD514639AC51493012001172500009D +:10043000130545CB072005008720450007218500CF +:100440008326C500531510C0F315100013060001D4 +:100450006314D5126392C512930130011725000071 +:10046000130545C9072005008720450007218500A1 +:100470008326C500531510C0F315100013060000A5 +:10048000631CD50E639AC50E97200000938080C729 +:1004900087A00000D3F000C0B70300809383F3FF70 +:1004A0009301A002639A700C97200000938080C58E +:1004B00087A08000D3F000C0B70300809301C00282 +:1004C000639C700A972000009380C0C387A04000FF +:1004D000D3F000C0B70300809383F3FF9301400380 +:1004E000639C7008972000009380C0C187A0C00063 +:1004F000D3F000C0B70300809383F3FF9301600340 +:10050000639C7006972000009380C0BF87A0000006 +:10051000D3F010C09303F0FF9301E003639E7004D7 +:1005200097200000938000BE87A04000D3F010C049 +:100530009303F0FF9301F003639070049720000091 +:10054000938040BC87A08000D3F010C093030000CC +:10055000930100046392700297200000938080BA98 +:1005600087A0C000D3F010C09303F0FF93011004E4 +:1005700063947000631030020F00F00F638001007D +:100580009391110093E111009308D00513850100A8 +:10059000730000000F00F00F930110009308D005C6 +:1005A0001305000073000000731000C0000000007D +:1005B000000000000000000000000000000000003B +:0405C0000000000037 +:1010000000000000000000000000000000000000E0 +:1010100000000000000000000000000000000000D0 +:1010200000000000000000000000000000000000C0 +:1010300000000000000000000000000000000000B0 +:081040000000000000000000A8 +:10200000CDCC8CBF0000000000000000FFFFFFFFF0 +:10201000000080BF0000000000000000FFFFFFFF85 +:10202000666666BF000000000000000000000000BF +:102030006666663F0000000000000000000000002F +:102040000000803F000000000000000001000000D0 +:10205000CDCC8C3F0000000000000000010000001B +:102060005ED032CF000000000000000000000080C1 +:102070005ED0324F0000000000000000FFFFFF7F35 +:10208000000040C000000000000000000000000050 +:10209000000080BF00000000000000000000000001 +:1020A000666666BF0000000000000000000000003F +:1020B0006666663F000000000000000000000000AF +:1020C0000000803F00000000000000000100000050 +:1020D000CDCC8C3F0000000000000000010000009B +:1020E0005ED032CF000000000000000000000000C1 +:1020F0005ED0324F0000000000000000005ED0B251 +:10210000FFFFFFFFFFFFFF7F000080FF0000807FD9 +:10211000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7F4F +:10212000000000000000F0FF000000000000F07F51 +:040000058000000077 +:00000001FF diff --git a/src/test/resources/hex/rv32ud-p-fdiv.hex b/src/test/resources/hex/rv32ud-p-fdiv.hex new file mode 100755 index 00000000..c203f41b --- /dev/null +++ b/src/test/resources/hex/rv32ud-p-fdiv.hex @@ -0,0 +1,89 @@ +:0200000480007A +:100000006F00C004732F2034930F8000630AFF0336 +:10001000930F90006306FF03930FB0006302FF038A +:10002000170F0080130F0FFE63040F0067000F000F +:10003000732F203463540F006F00400093E19153FD +:10004000171F000023203FFC6FF09FFF930000006C +:10005000130100009301000013020000930200004E +:100060001303000093030000130400009304000036 +:10007000130500009305000013060000930600001E +:100080001307000093070000130800009308000006 +:100090001309000093090000130A0000930A0000EE +:1000A000130B0000930B0000130C0000930C0000D6 +:1000B000130D0000930D0000130E0000930E0000BE +:1000C000130F0000930F0000732540F1631005002B +:1000D000970200009382020173905230735000180F +:1000E000970200009382020273905230B7020080A0 +:1000F0009382F2FF7390023B9302F0017390023AF5 +:100100007350403097020000938242017390523046 +:10011000735020307350303093010000970200007C +:10012000938282EE73905230130510001315F5017F +:10013000634C05000F00F00F930110009308D005E9 +:10014000130500007300000097020080938282EB89 +:10015000638A020073905210B7B20000938292102B +:100160007390223073500030372500007320053023 +:100170007350300097020000938242017390123452 +:10018000732540F1730020309301200017250000F3 +:10019000130545E707300500873085000731050165 +:1001A000832685010323C501D371101A273035003A +:1001B0008323450003250500F315100013061000E6 +:1001C0006316D51E6314731E6392C51E930130001F +:1001D00017250000130505E5073005008730850069 +:1001E00007310501832685010323C501D371101A48 +:1001F000273035008323450003250500F315100043 +:10020000130610006314D51A6312731A6390C51A8B +:1002100093014000172500001305C5E207300500D3 +:100220008730850007310501832685010323C50139 +:10023000D371101A273035008323450003250500AC +:10024000F3151000130600006312D5166310731621 +:10025000639EC5149301500017250000130585E027 +:1002600007300500873085000731050183268501A9 +:100270000323C501D371005A27303500832345007D +:1002800003250500F3151000130610006310D512A6 +:10029000631E7310639CC510930160001725000056 +:1002A000130545DE0730050087308500073105015D +:1002B000832685010323C501D371005A27303500F9 +:1002C0008323450003250500F315100013060000E5 +:1002D000631ED50C631C730C639AC50C930100015B +:1002E00017250000130505DC073005008730850061 +:1002F00007310501832685010323C501D371005A07 +:10030000273035008323450003250500F315100031 +:1003100013060001631CD508631A73086398C508A7 +:1003200093017000172500001305C5D9073005009B +:100330008730850007310501832685010323C50128 +:10034000D371005A2730350083234500032505006B +:10035000F315100013061000631AD5046318730414 +:100360006396C5049301800017250000130585D707 +:100370000730050087308500073105018326850198 +:100380000323C501D371005A27303500832345006C +:1003900003250500F3151000130610006318D5009F +:1003A000631673006394C500631030020F00F00FF2 +:1003B000638001009391110093E111009308D0052F +:1003C00013850100730000000F00F00F930110006F +:1003D0009308D0051305000073000000731000C0DF +:1003E000000000000000000000000000000000000D +:1003F00000000000000000000000000000000000FD +:0404000000000000F8 +:1010000000000000000000000000000000000000E0 +:1010100000000000000000000000000000000000D0 +:1010200000000000000000000000000000000000C0 +:1010300000000000000000000000000000000000B0 +:081040000000000000000000A8 +:10200000F1D4C853FB210940DDB0F1890ABF054076 +:102010000000000000000000EC83C3F6DB7DF23F0F +:1020200000000000004893C066666666664C9340F8 +:102030000000000000000000A529193EB4F8EFBF21 +:10204000F1D4C853FB210940000000000000F03F1C +:102050000000000000000000F1D4C853FB2109403B +:10206000F1D4C853FB21094000000000000000002B +:1020700000000000000000007B586F91F85BFC3FFF +:10208000000000000088C3400000000000000000C5 +:1020900000000000000000000000000000005940A7 +:1020A000000000000000F0BF000000000000000081 +:1020B0000000000000000000000000000000F87FA9 +:1020C000000000000060654000000000000000000B +:1020D0000000000000000000F57496CE44272A405E +:1020E00005A10AC7DF94853E000000000000000043 +:1020F0000000000000000000997FE3C089473A3FDC +:040000058000000077 +:00000001FF diff --git a/src/test/resources/hex/rv32ud-p-fmadd.hex b/src/test/resources/hex/rv32ud-p-fmadd.hex new file mode 100755 index 00000000..7744209e --- /dev/null +++ b/src/test/resources/hex/rv32ud-p-fmadd.hex @@ -0,0 +1,113 @@ +:0200000480007A +:100000006F00C004732F2034930F8000630AFF0336 +:10001000930F90006306FF03930FB0006302FF038A +:10002000170F0080130F0FFE63040F0067000F000F +:10003000732F203463540F006F00400093E19153FD +:10004000171F000023203FFC6FF09FFF930000006C +:10005000130100009301000013020000930200004E +:100060001303000093030000130400009304000036 +:10007000130500009305000013060000930600001E +:100080001307000093070000130800009308000006 +:100090001309000093090000130A0000930A0000EE +:1000A000130B0000930B0000130C0000930C0000D6 +:1000B000130D0000930D0000130E0000930E0000BE +:1000C000130F0000930F0000732540F1631005002B +:1000D000970200009382020173905230735000180F +:1000E000970200009382020273905230B7020080A0 +:1000F0009382F2FF7390023B9302F0017390023AF5 +:100100007350403097020000938242017390523046 +:10011000735020307350303093010000970200007C +:10012000938282EE73905230130510001315F5017F +:10013000634C05000F00F00F930110009308D005E9 +:10014000130500007300000097020080938282EB89 +:10015000638A020073905210B7B20000938292102B +:100160007390223073500030372500007320053023 +:100170007350300097020000938242017390123452 +:10018000732540F1730020309301200017250000F3 +:10019000130545E707300500873085000731050165 +:1001A000832685010323C501C37110122730350052 +:1001B0008323450003250500F315100013060000F6 +:1001C000631ED52E631C732E639AC52E93013000D7 +:1001D00017250000130505E5073005008730850069 +:1001E00007310501832685010323C501C371101260 +:1001F000273035008323450003250500F315100043 +:1002000013061000631CD52A631A732A6398C52A43 +:1002100093014000172500001305C5E207300500D3 +:100220008730850007310501832685010323C50139 +:10023000C3711012273035008323450003250500C4 +:10024000F315100013060000631AD52663187326F1 +:100250006396C5269301500017250000130585E01D +:1002600007300500873085000731050183268501A9 +:100270000323C501CF7110122730350083234500B9 +:1002800003250500F3151000130600006318D5229E +:10029000631673226394C522930160001725000042 +:1002A000130545DE0730050087308500073105015D +:1002B000832685010323C501CF7110122730350035 +:1002C0008323450003250500F315100013061000D5 +:1002D0006316D51E6314731E6392C51E93017000CE +:1002E00017250000130505DC073005008730850061 +:1002F00007310501832685010323C501CF71101243 +:10030000273035008323450003250500F315100031 +:10031000130600006314D51A6312731A6390C51A8A +:1003200093018000172500001305C5D9073005008B +:100330008730850007310501832685010323C50128 +:10034000C7711012273035008323450003250500AF +:10035000F3151000130600006312D5166310731610 +:10036000639EC5149301900017250000130585D7DF +:100370000730050087308500073105018326850198 +:100380000323C501C77110122730350083234500B0 +:1003900003250500F3151000130610006310D51295 +:1003A000631E7310639CC5109301A0001725000005 +:1003B000130545D507300500873085000731050155 +:1003C000832685010323C501C7711012273035002C +:1003D0008323450003250500F315100013060000D4 +:1003E000631ED50C631C730C639AC50C9301B0009B +:1003F00017250000130505D3073005008730850059 +:1004000007310501832685010323C501CB71101235 +:10041000273035008323450003250500F315100020 +:1004200013060000631CD508631A73086398C50897 +:100430009301C000172500001305C5D00730050043 +:100440008730850007310501832685010323C50117 +:10045000CB7110122730350083234500032505009A +:10046000F315100013061000631AD5046318730403 +:100470006396C5049301D00017250000130585CEAF +:100480000730050087308500073105018326850187 +:100490000323C501CB71101227303500832345009B +:1004A00003250500F3151000130600006318D5009E +:1004B000631673006394C500631030020F00F00FE1 +:1004C000638001009391110093E111009308D0051E +:1004D00013850100730000000F00F00F930110005E +:1004E0009308D0051305000073000000731000C0CE +:1004F00000000000000000000000000000000000FC +:0405000000000000F7 +:1010000000000000000000000000000000000000E0 +:1010100000000000000000000000000000000000D0 +:1010200000000000000000000000000000000000C0 +:1010300000000000000000000000000000000000B0 +:081040000000000000000000A8 +:10200000000000000000F03F00000000000004405D +:10201000000000000000F03F0000000000000C4045 +:10202000000000000000F0BF66666666664C93C064 +:102030009A9999999999F13FCCCCCCCCCC509340BA +:10204000000000000000004000000000000014C07C +:1020500000000000000000C000000000000028C0D8 +:10206000000000000000F03F0000000000000440FD +:10207000000000000000F03F0000000000000CC065 +:10208000000000000000F0BF66666666664C93C004 +:102090009A9999999999F13FCCCCCCCCCC5093C0DA +:1020A000000000000000004000000000000014C01C +:1020B00000000000000000C00000000000002840F8 +:1020C000000000000000F03F00000000000004409D +:1020D000000000000000F03F000000000000F83F9A +:1020E000000000000000F0BF66666666664C93C0A4 +:1020F0009A9999999999F13F0000000000489340FE +:10210000000000000000004000000000000014C0BB +:1021100000000000000000C000000000000020C01F +:10212000000000000000F03F00000000000004403C +:10213000000000000000F03F000000000000F8BFB9 +:10214000000000000000F0BF66666666664C93C043 +:102150009A9999999999F13F00000000004893C01D +:10216000000000000000004000000000000014C05B +:1021700000000000000000C000000000000020403F +:040000058000000077 +:00000001FF diff --git a/src/test/resources/hex/rv32ud-p-fmin.hex b/src/test/resources/hex/rv32ud-p-fmin.hex new file mode 100755 index 00000000..5c18421b --- /dev/null +++ b/src/test/resources/hex/rv32ud-p-fmin.hex @@ -0,0 +1,153 @@ +:0200000480007A +:100000006F00C004732F2034930F8000630AFF0336 +:10001000930F90006306FF03930FB0006302FF038A +:10002000170F0080130F0FFE63040F0067000F000F +:10003000732F203463540F006F00400093E19153FD +:10004000171F000023203FFC6FF09FFF930000006C +:10005000130100009301000013020000930200004E +:100060001303000093030000130400009304000036 +:10007000130500009305000013060000930600001E +:100080001307000093070000130800009308000006 +:100090001309000093090000130A0000930A0000EE +:1000A000130B0000930B0000130C0000930C0000D6 +:1000B000130D0000930D0000130E0000930E0000BE +:1000C000130F0000930F0000732540F1631005002B +:1000D000970200009382020173905230735000180F +:1000E000970200009382020273905230B7020080A0 +:1000F0009382F2FF7390023B9302F0017390023AF5 +:100100007350403097020000938242017390523046 +:10011000735020307350303093010000970200007C +:10012000938282EE73905230130510001315F5017F +:10013000634C05000F00F00F930110009308D005E9 +:10014000130500007300000097020080938282EB89 +:10015000638A020073905210B7B20000938292102B +:100160007390223073500030372500007320053023 +:100170007350300097020000938242017390123452 +:10018000732540F1730020309301200017250000F3 +:10019000130545E707300500873085000731050165 +:1001A000832685010323C501D301102A273035009A +:1001B0008323450003250500F315100013060000F6 +:1001C000631AD548631873486396C5489301300095 +:1001D00017250000130505E5073005008730850069 +:1001E00007310501832685010323C501D301102AA8 +:1001F000273035008323450003250500F315100043 +:10020000130600006318D544631673446394C54411 +:1002100093014000172500001305C5E207300500D3 +:100220008730850007310501832685010323C50139 +:10023000D301102A2730350083234500032505000C +:10024000F3151000130600006316D54063147340C5 +:100250006392C5409301500017250000130585E007 +:1002600007300500873085000731050183268501A9 +:100270000323C501D301102A27303500832345000D +:1002800003250500F3151000130600006314D53C88 +:100290006312733C6390C53C930160001725000016 +:1002A000130545DE0730050087308500073105015D +:1002B000832685010323C501D301102A2730350089 +:1002C0008323450003250500F315100013060000E5 +:1002D0006312D53863107338639EC536930170007E +:1002E00017250000130505DC073005008730850061 +:1002F00007310501832685010323C501D301102A97 +:10030000273035008323450003250500F315100031 +:10031000130600006310D534631E7332639CC5322C +:100320009301C000172500001305C5D9073005004B +:100330008730850007310501832685010323C50128 +:10034000D311102A273035008323450003250500EB +:10035000F315100013060000631ED52E631C732EC8 +:10036000639AC52E9301D00017250000130585D789 +:100370000730050087308500073105018326850198 +:100380000323C501D311102A2730350083234500EC +:1003900003250500F315100013060000631CD52A81 +:1003A000631A732A6398C52A9301E0001725000099 +:1003B000130545D507300500873085000731050155 +:1003C000832685010323C501D311102A2730350068 +:1003D0008323450003250500F315100013060000D4 +:1003E000631AD526631873266396C5269301F00019 +:1003F00017250000130505D3073005008730850059 +:1004000007310501832685010323C501D311102A75 +:10041000273035008323450003250500F315100020 +:10042000130600006318D522631673226394C52255 +:1004300093010001172500001305C5D00730050002 +:100440008730850007310501832685010323C50117 +:10045000D311102A273035008323450003250500DA +:10046000F3151000130600006316D51E6314731EE7 +:100470006392C51E9301100117250000130585CE58 +:100480000730050087308500073105018326850187 +:100490000323C501D311102A2730350083234500DB +:1004A00003250500F3151000130600006314D51A88 +:1004B0006312731A6390C51A930140011725000057 +:1004C000130545CC0730050087308500073105014D +:1004D000832685010323C501D311102A2730350057 +:1004E0008323450003250500F315100013060001C2 +:1004F0006312D51663107316639EC51493015001E1 +:1005000017250000130505CA073005008730850050 +:1005100007310501832685010323C501D311102A64 +:10052000273035008323450003250500F31510000F +:10053000130600006310D512631E7310639CC51070 +:100540009301E001172500001305C5C7073005001A +:100550008730850007310501832685010323C50106 +:10056000D301102A273035008323450003250500D9 +:10057000F315100013060000631ED50C631C730CEA +:10058000639AC50C9301F00117250000130585C57A +:100590000730050087308500073105018326850176 +:1005A0000323C501D301102A2730350083234500DA +:1005B00003250500F315100013060000631CD50881 +:1005C000631A73086398C508930100021725000099 +:1005D000130545C307300500873085000731050145 +:1005E000832685010323C501D311102A2730350046 +:1005F0008323450003250500F315100013060000B2 +:10060000631AD504631873046396C504930110023A +:1006100017250000130505C1073005008730850048 +:1006200007310501832685010323C501D311102A53 +:10063000273035008323450003250500F3151000FE +:10064000130600006318D500631673006394C50099 +:10065000631030020F00F00F6380010093911100CE +:1006600093E111009308D005138501007300000089 +:100670000F00F00F930110009308D0051305000040 +:1006800073000000731000C00000000000000000B4 +:10069000000000000000000000000000000000005A +:1006A000000000000000000000000000000000004A +:1006B000000000000000000000000000000000003A +:0406C0000000000036 +:1010000000000000000000000000000000000000E0 +:1010100000000000000000000000000000000000D0 +:1010200000000000000000000000000000000000C0 +:1010300000000000000000000000000000000000B0 +:081040000000000000000000A8 +:102000000000000000000440000000000000F03F5D +:102010000000000000000000000000000000F03F91 +:1020200066666666664C93C09A9999999999F13F4C +:10203000000000000000000066666666664C93C003 +:102040009A9999999999F13F66666666664C93C02C +:10205000000000000000000066666666664C93C0E3 +:10206000FFFFFFFFFFFFFF7F66666666664C93C05B +:10207000000000000000000066666666664C93C0C3 +:10208000F1D4C853FB2109403A8C30E28E79453EA9 +:1020900000000000000000003A8C30E28E79453EDE +:1020A000000000000000F0BF00000000000000C0C1 +:1020B000000000000000000000000000000000C060 +:1020C0000000000000000440000000000000F03F9D +:1020D00000000000000000000000000000000440BC +:1020E00066666666664C93C09A9999999999F13F8C +:1020F00000000000000000009A9999999999F13F19 +:102100009A9999999999F13F66666666664C93C06B +:1021100000000000000000009A9999999999F13FF8 +:10212000FFFFFFFFFFFFFF7F66666666664C93C09A +:10213000000000000000000066666666664C93C002 +:10214000F1D4C853FB2109403A8C30E28E79453EE8 +:102150000000000000000000F1D4C853FB2109403A +:10216000000000000000F0BF00000000000000C000 +:102170000000000000000000000000000000F0BFB0 +:10218000010000000000F07F000000000000F03FB0 +:102190000000000000000000000000000000F03F10 +:1021A000FFFFFFFFFFFFFF7FFFFFFFFFFFFFFF7F3F +:1021B0000000000000000000000000000000F87FA8 +:1021C000000000000000008000000000000000008F +:1021D000000000000000000000000000000000807F +:1021E000000000000000000000000000000000806F +:1021F000000000000000000000000000000000805F +:10220000000000000000008000000000000000004E +:1022100000000000000000000000000000000000BE +:10222000000000000000000000000000000000802E +:10223000000000000000000000000000000000009E +:040000058000000077 +:00000001FF diff --git a/src/test/resources/hex/rv32ud-p-ldst.hex b/src/test/resources/hex/rv32ud-p-ldst.hex new file mode 100755 index 00000000..408d2d38 --- /dev/null +++ b/src/test/resources/hex/rv32ud-p-ldst.hex @@ -0,0 +1,58 @@ +:0200000480007A +:100000006F00C004732F2034930F8000630AFF0336 +:10001000930F90006306FF03930FB0006302FF038A +:10002000170F0080130F0FFE63040F0067000F000F +:10003000732F203463540F006F00400093E19153FD +:10004000171F000023203FFC6FF09FFF930000006C +:10005000130100009301000013020000930200004E +:100060001303000093030000130400009304000036 +:10007000130500009305000013060000930600001E +:100080001307000093070000130800009308000006 +:100090001309000093090000130A0000930A0000EE +:1000A000130B0000930B0000130C0000930C0000D6 +:1000B000130D0000930D0000130E0000930E0000BE +:1000C000130F0000930F0000732540F1631005002B +:1000D000970200009382020173905230735000180F +:1000E000970200009382020273905230B7020080A0 +:1000F0009382F2FF7390023B9302F0017390023AF5 +:100100007350403097020000938242017390523046 +:10011000735020307350303093010000970200007C +:10012000938282EE73905230130510001315F5017F +:10013000634C05000F00F00F930110009308D005E9 +:10014000130500007300000097020080938282EB89 +:10015000638A020073905210B7B20000938292102B +:100160007390223073500030372500007320053023 +:100170007350300097020000938242017390123452 +:10018000732540F17300203017240000130484EA23 +:100190000731040027382400032504018325440186 +:1001A00097270000938707E683A3070083A74700EC +:1001B00093012000631E750A639CF50A0731040051 +:1001C00027282400032504018325440197270000E4 +:1001D0009387C7E383A3070083A7470093013000F9 +:1001E000631875086396F508072104002728240082 +:1001F000032504018325440197270000938787E1A5 +:1002000083A3070083A7470093014000631275068C +:100210006390F50607318400273824000325040184 +:100220008325440197270000938747DF83A30700B6 +:1002300083A7470093015000631C7502639AF5027F +:100240000721840027382400032504018325440165 +:1002500097270000938707DD83A3070083A7470044 +:1002600093016000631675006394F500631030021B +:100270000F00F00F638001009391110093E11100D2 +:100280009308D00513850100730000000F00F00FE4 +:10029000930110009308D0051305000073000000BF +:1002A000731000C00000000000000000000000000B +:1002B000000000000000000000000000000000003E +:0402C000000000003A +:1010000000000000000000000000000000000000E0 +:1010100000000000000000000000000000000000D0 +:1010200000000000000000000000000000000000C0 +:1010300000000000000000000000000000000000B0 +:081040000000000000000000A8 +:10200000000080BF00000040000080BF00000040D2 +:10201000000080BF0000004000004040000080C081 +:1020200000004040FFFFFFFF000000000000000034 +:10203000000080BF0000004000004040000080C061 +:10204000EFBEADDEBEBAFECAEA1DADAB0DD0371392 +:040000058000000077 +:00000001FF diff --git a/src/test/resources/hex/rv32ud-p-recoding.hex b/src/test/resources/hex/rv32ud-p-recoding.hex new file mode 100755 index 00000000..bd12e2a8 --- /dev/null +++ b/src/test/resources/hex/rv32ud-p-recoding.hex @@ -0,0 +1,46 @@ +:0200000480007A +:100000006F00C004732F2034930F8000630AFF0336 +:10001000930F90006306FF03930FB0006302FF038A +:10002000170F0080130F0FFE63040F0067000F000F +:10003000732F203463540F006F00400093E19153FD +:10004000171F000023203FFC6FF09FFF930000006C +:10005000130100009301000013020000930200004E +:100060001303000093030000130400009304000036 +:10007000130500009305000013060000930600001E +:100080001307000093070000130800009308000006 +:100090001309000093090000130A0000930A0000EE +:1000A000130B0000930B0000130C0000930C0000D6 +:1000B000130D0000930D0000130E0000930E0000BE +:1000C000130F0000930F0000732540F1631005002B +:1000D000970200009382020173905230735000180F +:1000E000970200009382020273905230B7020080A0 +:1000F0009382F2FF7390023B9302F0017390023AF5 +:100100007350403097020000938242017390523046 +:10011000735020307350303093010000970200007C +:10012000938282EE73905230130510001315F5017F +:10013000634C05000F00F00F930110009308D005E9 +:10014000130500007300000097020080938282EB89 +:10015000638A020073905210B7B20000938292102B +:100160007390223073500030372500007320053023 +:100170007350300097020000938242017390123452 +:10018000732540F17300203017250000072085E714 +:1001900017250000872045E7D3F00010532510A055 +:1001A000930310009301200063147506530510A0FB +:1001B0009303100093013000631C7504531510A0C5 +:1001C000930300009301400063147504537000D042 +:1001D00013051000D37005D0D3F00010532510A0E4 +:1001E000930310009301500063147502530510A08F +:1001F0009303100093016000631C7500531510A059 +:1002000093030000930170006314750063103002C3 +:100210000F00F00F638001009391110093E1110032 +:100220009308D00513850100730000000F00F00F44 +:10023000930110009308D00513050000730000001F +:04024000731000C077 +:1010000000000000000000000000000000000000E0 +:1010100000000000000000000000000000000000D0 +:1010200000000000000000000000000000000000C0 +:1010300000000000000000000000000000000000B0 +:081040000000000000000000A8 +:10200000000080FF000040400000000000000000D1 +:040000058000000077 +:00000001FF diff --git a/src/test/scala/vexriscv/TestIndividualFeatures.scala b/src/test/scala/vexriscv/TestIndividualFeatures.scala index 5e015acc..cd4b9e9a 100644 --- a/src/test/scala/vexriscv/TestIndividualFeatures.scala +++ b/src/test/scala/vexriscv/TestIndividualFeatures.scala @@ -467,7 +467,6 @@ class DBusDimension extends VexRiscvDimension("DBus") { bytePerLine = bytePerLine, wayCount = wayCount, addressWidth = 32, - rfDataWidth = 32, cpuDataWidth = cpuDataWidth, //Not tested memDataWidth = memDataWidth, catchAccessError = catchAll, diff --git a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala index 112252f1..7f37a622 100644 --- a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala +++ b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala @@ -1507,55 +1507,55 @@ class FpuTest extends FunSuite{ } -object Clib { - val java_home = System.getProperty("java.home") - assert(java_home != "" && java_home != null, "JAVA_HOME need to be set") - val jdk = java_home.replace("/jre","").replace("\\jre","") - val jdkIncludes = jdk + "/include" - val flags = List("-fPIC", "-m64", "-shared", "-Wno-attributes") //-Wl,--whole-archive - val os = new File("/media/data/open/SaxonSoc/berkeley-softfloat-3/build/Linux-x86_64-GCC").listFiles().map(_.getAbsolutePath).filter(_.toString.endsWith(".o")) - val cmd = s"gcc -I/media/data/open/SaxonSoc/berkeley-softfloat-3/source/include -I$jdkIncludes -I$jdkIncludes/linux ${flags.mkString(" ")} -o src/test/cpp/fpu/math/fpu_math.so src/test/cpp/fpu/math/fpu_math.c src/test/cpp/fpu/math/softfloat.a" // src/test/cpp/fpu/math/softfloat.a - DoCmd.doCmd(cmd) - val math = new FpuMath -} -// cd /media/data/open/SaxonSoc/testFloatBuild/berkeley-softfloat-3/build/Linux-x86_64-GCC -// make clean && SPECIALIZE_TYPE=RISCV make -j$(nproc) && cp softfloat.a /media/data/open/SaxonSoc/artyA7SmpUpdate/SaxonSoc/ext/VexRiscv/src/test/cpp/fpu/math -object FpuCompileSo extends App{ - -// val b2f = lang.Float.intBitsToFloat(_) -// for(e <- FpuRoundMode.elements) { -// println(e) -// for (i <- -2 until 50) println(i + " => " + Clib.math.addF32(b2f(0x7f000000), b2f(0x7f000000 + i), e.position)) -// println("") -// } - //1 did not equal 3 Flag missmatch dut=1 ref=3 ## mul 0.9994812 -1.1754988E-38 -1.174889E-38 RMM - // println(Clib.math.mulF32(0.9994812f, -1.1754988E-38f, FpuRoundMode.RMM.position)) -// miaou ffffffff 7fffffe0 7f -// miaou 0 3ffffff0 70 = 0 - - - println(Clib.math.mulF32( 1.1753509E-38f, 1.0001221f, FpuRoundMode.RUP.position)) - println(Clib.math.mulF32( 1.1754945E-38f, 0.9999998f, FpuRoundMode.RUP.position)) -// testBinaryOp(mul, 1.1753509E-38f, 1.0001221f, 1.17549435E-38f ,1, FpuRoundMode.RUP,"mul") -// testBinaryOp(mul, 1.1754945E-38f, 0.9999998f, 1.17549435E-38f, 3, FpuRoundMode.RUP, "mul") -// miaou ffffffff 7fffffe0 7f -// miaou 0 3ffffff0 70 = 0 -// miaou ffffffff 7fffff7e 7f -// miaou 1 3fffffbf 3f = 1 - -// println(Clib.math.mulF32( 1.1753509E-38f, 1.0001221f, FpuRoundMode.RUP.position)) -// println(Clib.math.mulF32( 1.469368E-39f, 7.9999995f, FpuRoundMode.RUP.position)) -// println(Clib.math.mulF32( 1.40129846432e-45f, 7.9999995f, FpuRoundMode.RUP.position)) -// println(Clib.math.mulF32( 2.93873587706e-39f, 7.9999995f, FpuRoundMode.RUP.position)) -// println(Clib.math.mulF32( 1f, 7.9999995f, FpuRoundMode.RUP.position)) - - -// println(Clib.math.addF32(1.00000011921f, 4.0f, FpuRoundMode.RNE.position)) -// println(Clib.math.addF32(1.00000011921f, 4.0f, FpuRoundMode.RTZ.position)) -// println(Clib.math.addF32(1.00000011921f, 4.0f, FpuRoundMode.RDN.position)) -// println(Clib.math.addF32(1.00000011921f, 4.0f, FpuRoundMode.RUP.position)) -} - +//object Clib { +// val java_home = System.getProperty("java.home") +// assert(java_home != "" && java_home != null, "JAVA_HOME need to be set") +// val jdk = java_home.replace("/jre","").replace("\\jre","") +// val jdkIncludes = jdk + "/include" +// val flags = List("-fPIC", "-m64", "-shared", "-Wno-attributes") //-Wl,--whole-archive +// val os = new File("/media/data/open/SaxonSoc/berkeley-softfloat-3/build/Linux-x86_64-GCC").listFiles().map(_.getAbsolutePath).filter(_.toString.endsWith(".o")) +// val cmd = s"gcc -I/media/data/open/SaxonSoc/berkeley-softfloat-3/source/include -I$jdkIncludes -I$jdkIncludes/linux ${flags.mkString(" ")} -o src/test/cpp/fpu/math/fpu_math.so src/test/cpp/fpu/math/fpu_math.c src/test/cpp/fpu/math/softfloat.a" // src/test/cpp/fpu/math/softfloat.a +// DoCmd.doCmd(cmd) +// val math = new FpuMath +//} +//// cd /media/data/open/SaxonSoc/testFloatBuild/berkeley-softfloat-3/build/Linux-x86_64-GCC +//// make clean && SPECIALIZE_TYPE=RISCV make -j$(nproc) && cp softfloat.a /media/data/open/SaxonSoc/artyA7SmpUpdate/SaxonSoc/ext/VexRiscv/src/test/cpp/fpu/math +//object FpuCompileSo extends App{ +// +//// val b2f = lang.Float.intBitsToFloat(_) +//// for(e <- FpuRoundMode.elements) { +//// println(e) +//// for (i <- -2 until 50) println(i + " => " + Clib.math.addF32(b2f(0x7f000000), b2f(0x7f000000 + i), e.position)) +//// println("") +//// } +// //1 did not equal 3 Flag missmatch dut=1 ref=3 ## mul 0.9994812 -1.1754988E-38 -1.174889E-38 RMM +// // println(Clib.math.mulF32(0.9994812f, -1.1754988E-38f, FpuRoundMode.RMM.position)) +//// miaou ffffffff 7fffffe0 7f +//// miaou 0 3ffffff0 70 = 0 +// +// +// println(Clib.math.mulF32( 1.1753509E-38f, 1.0001221f, FpuRoundMode.RUP.position)) +// println(Clib.math.mulF32( 1.1754945E-38f, 0.9999998f, FpuRoundMode.RUP.position)) +//// testBinaryOp(mul, 1.1753509E-38f, 1.0001221f, 1.17549435E-38f ,1, FpuRoundMode.RUP,"mul") +//// testBinaryOp(mul, 1.1754945E-38f, 0.9999998f, 1.17549435E-38f, 3, FpuRoundMode.RUP, "mul") +//// miaou ffffffff 7fffffe0 7f +//// miaou 0 3ffffff0 70 = 0 +//// miaou ffffffff 7fffff7e 7f +//// miaou 1 3fffffbf 3f = 1 +// +//// println(Clib.math.mulF32( 1.1753509E-38f, 1.0001221f, FpuRoundMode.RUP.position)) +//// println(Clib.math.mulF32( 1.469368E-39f, 7.9999995f, FpuRoundMode.RUP.position)) +//// println(Clib.math.mulF32( 1.40129846432e-45f, 7.9999995f, FpuRoundMode.RUP.position)) +//// println(Clib.math.mulF32( 2.93873587706e-39f, 7.9999995f, FpuRoundMode.RUP.position)) +//// println(Clib.math.mulF32( 1f, 7.9999995f, FpuRoundMode.RUP.position)) +// +// +//// println(Clib.math.addF32(1.00000011921f, 4.0f, FpuRoundMode.RNE.position)) +//// println(Clib.math.addF32(1.00000011921f, 4.0f, FpuRoundMode.RTZ.position)) +//// println(Clib.math.addF32(1.00000011921f, 4.0f, FpuRoundMode.RDN.position)) +//// println(Clib.math.addF32(1.00000011921f, 4.0f, FpuRoundMode.RUP.position)) +//} +// class ProcessStream(cmd : String){ import sys.process._ @@ -1575,19 +1575,19 @@ class ProcessStream(cmd : String){ buf.dequeue()() } } - -object TestSoftFloat extends App{ - val p = new ProcessStream("testfloat_gen -forever f32_add") - Thread.sleep(1000) - println(p.next) - println(p.next) - println(p.next) - println(p.next) - println(p.next) - Thread.sleep(1000) - println(p.next) - while(true) { - Thread.sleep(10) - println(p.next) - } -} +// +//object TestSoftFloat extends App{ +// val p = new ProcessStream("testfloat_gen -forever f32_add") +// Thread.sleep(1000) +// println(p.next) +// println(p.next) +// println(p.next) +// println(p.next) +// println(p.next) +// Thread.sleep(1000) +// println(p.next) +// while(true) { +// Thread.sleep(10) +// println(p.next) +// } +//} From 8537d18b161c665fef95af30691d1d280632e695 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 17 Feb 2021 16:35:52 +0100 Subject: [PATCH 591/951] fpu improve fmax --- src/main/scala/vexriscv/ip/fpu/FpuCore.scala | 323 +++++++++++------- .../scala/vexriscv/ip/fpu/Interface.scala | 2 + 2 files changed, 203 insertions(+), 122 deletions(-) diff --git a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala index 1448d89d..dca4f196 100644 --- a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala +++ b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala @@ -83,7 +83,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val rs1Boxed, rs2Boxed = p.withDouble generate Bool() } - case class MulInput() extends Bundle{ + class MulInput() extends Bundle{ val source = Source() val rs1, rs2, rs3 = p.internalFloating() val rd = p.rfAddress() @@ -117,7 +117,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } - case class MergeInput() extends Bundle{ + class MergeInput() extends Bundle{ val source = Source() val lockId = lockIdType() val rd = p.rfAddress() @@ -174,7 +174,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val fork = new StreamFork(FpuCommit(p), 2) fork.io.input << io.port(i).commit fork.io.outputs(0) >> load(i) - fork.io.outputs(1) >> commit(i) + fork.io.outputs(1).pipelined(m2s = true, s2m = true) >> commit(i) //Pipelining here is light, as it only use the flags of the payload } } @@ -198,16 +198,16 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } } - //TODO nan boxing decoding val read = new Area{ val arbiter = StreamArbiterFactory.noLock.roundRobin.build(FpuCmd(p), portCount) arbiter.io.inputs <> Vec(io.port.map(_.cmd)) - val s0 = Stream(RfReadInput()) - s0.arbitrationFrom(arbiter.io.output) - s0.source := arbiter.io.chosen - s0.payload.assignSomeByName(arbiter.io.output.payload) + val arbiterOutput = Stream(RfReadInput()) + arbiterOutput.arbitrationFrom(arbiter.io.output) + arbiterOutput.source := arbiter.io.chosen + arbiterOutput.payload.assignSomeByName(arbiter.io.output.payload) + val s0 = arbiterOutput.pipelined(m2s = true, s2m = true) val useRs1, useRs2, useRs3, useRd = False switch(s0.opcode){ is(p.Opcode.LOAD) { useRd := True } @@ -314,8 +314,8 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val fmaHit = input.opcode === p.Opcode.FMA val mulHit = input.opcode === p.Opcode.MUL || fmaHit - val mul = Stream(MulInput()) - val divSqrtToMul = Stream(MulInput()) + val mul = Stream(new MulInput()) + val divSqrtToMul = Stream(new MulInput()) if(p.withMul) { input.ready setWhen (mulHit && mul.ready && !divSqrtToMul.valid) @@ -369,7 +369,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } val s0 = new Area{ - val input = decode.load.stage() + val input = decode.load.pipelined(m2s = true, s2m = true) val filtred = commitFork.load.map(port => port.takeWhen(port.sync)) def feed = filtred(input.source) val hazard = !feed.valid @@ -390,7 +390,6 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ output.format := FpuFormat.FLOAT } } - } val s1 = new Area{ @@ -510,7 +509,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ when(isInfinity){recoded.setInfinity} when(isNan){recoded.setNan} - val output = input.haltWhen(busy).swapPayload(MergeInput()) + val output = input.haltWhen(busy).swapPayload(new MergeInput()) output.source := input.source output.lockId := input.lockId output.roundMode := input.roundMode @@ -540,7 +539,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val shortPip = new Area{ val input = decode.shortPip.stage() - val rfOutput = Stream(MergeInput()) + val rfOutput = Stream(new MergeInput()) val result = p.storeLoadType().assignDontCare() @@ -820,20 +819,61 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } val mul = p.withMul generate new Area{ - val input = decode.mul.stage() + val inWidthA = p.internalMantissaSize+1 + val inWidthB = p.internalMantissaSize+1 + val outWidth = p.internalMantissaSize*2+2 - val math = new Area { + case class MulSplit(offsetA : Int, offsetB : Int, widthA : Int, widthB : Int, id : Int){ + val offsetC = offsetA+offsetB + } + val splitsUnordered = for(offsetA <- 0 until inWidthA by p.mulWidthA; + offsetB <- 0 until inWidthB by p.mulWidthB; + widthA = (inWidthA - offsetA) min p.mulWidthA; + widthB = (inWidthB - offsetB) min p.mulWidthB) yield { + MulSplit(offsetA, offsetB, widthA, widthB, -1) + } + val splits = splitsUnordered.sortWith(_.offsetC < _.offsetC).zipWithIndex.map(e => e._1.copy(id=e._2)) + + class MathWithExp extends MulInput{ + val exp = UInt(p.internalExponentSize+1 bits) + } + val preMul = new Area{ + val input = decode.mul.stage() + val output = input.swapPayload(new MathWithExp()) + output.payload.assignSomeByName(input.payload) + output.exp := input.rs1.exponent +^ input.rs2.exponent + } + class MathWithMul extends MathWithExp{ + val muls = Vec(splits.map(e => UInt(e.widthA + e.widthB bits))) + } + val mul = new Area{ + val input = preMul.output.stage() + val output = input.swapPayload(new MathWithMul()) val mulA = U(input.msb1) @@ input.rs1.mantissa val mulB = U(input.msb2) @@ input.rs2.mantissa - val mulC = mulA * mulB - val exp = input.rs1.exponent +^ input.rs2.exponent + output.payload.assignSomeByName(input.payload) + splits.foreach(e => output.muls(e.id) := mulA(e.offsetA, e.widthA bits) * mulB(e.offsetB, e.widthB bits)) + } + + class MathOutput extends MathWithExp{ + val mulC = UInt(p.internalMantissaSize*2+2 bits) + } + + val math = new Area { + val input = mul.output.stage() + val sum = splits.map(e => (input.muls(e.id) << e.offsetC).resize(outWidth)).reduceBalancedTree(_ + _) + + val output = input.swapPayload(new MathOutput()) + output.payload.assignSomeByName(input.payload) + output.mulC := sum } val norm = new Area{ - val (mulHigh, mulLow) = math.mulC.splitAt(p.internalMantissaSize-1) + val input = math.output.stage() + val (mulHigh, mulLow) = input.mulC.splitAt(p.internalMantissaSize-1) val scrap = mulLow =/= 0 val needShift = mulHigh.msb - val exp = math.exp + U(needShift) + val exp = input.exp + U(needShift) val man = needShift ? mulHigh(1, p.internalMantissaSize+1 bits) | mulHigh(0, p.internalMantissaSize+1 bits) scrap setWhen(needShift && mulHigh(0)) val forceZero = input.rs1.isZero || input.rs2.isZero @@ -863,38 +903,40 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } elsewhen(forceUnderflow) { output.exponent := underflowExp.resized } - } - val notMul = new Area{ - val output = Flow(UInt(p.internalMantissaSize + 1 bits)) - output.valid := input.valid && input.divSqrt - output.payload := math.mulC(p.internalMantissaSize, p.internalMantissaSize+1 bits) + val result = new Area { + def input = norm.input + val notMul = new Area { + val output = Flow(UInt(p.internalMantissaSize + 1 bits)) + output.valid := input.valid && input.divSqrt + output.payload := input.mulC(p.internalMantissaSize, p.internalMantissaSize + 1 bits) + } + + val output = Stream(new MergeInput()) + output.valid := input.valid && !input.add && !input.divSqrt + output.source := input.source + output.lockId := input.lockId + output.rd := input.rd + if (p.withDouble) output.format := input.format + output.roundMode := input.roundMode + output.scrap := norm.scrap + output.value := norm.output + + decode.mulToAdd.valid := input.valid && input.add + decode.mulToAdd.source := input.source + decode.mulToAdd.rs1.mantissa := norm.output.mantissa >> 1 //FMA Precision lost + decode.mulToAdd.rs1.exponent := norm.output.exponent + decode.mulToAdd.rs1.sign := norm.output.sign + decode.mulToAdd.rs1.special := False //TODO + decode.mulToAdd.rs2 := input.rs3 + decode.mulToAdd.rd := input.rd + decode.mulToAdd.lockId := input.lockId + decode.mulToAdd.roundMode := input.roundMode + if (p.withDouble) decode.mulToAdd.format := input.format + + input.ready := (input.add ? decode.mulToAdd.ready | output.ready) || input.divSqrt } - - val output = Stream(MergeInput()) - output.valid := input.valid && !input.add && !input.divSqrt - output.source := input.source - output.lockId := input.lockId - output.rd := input.rd - if(p.withDouble) output.format := input.format - output.roundMode := input.roundMode - output.scrap := norm.scrap - output.value := norm.output - - decode.mulToAdd.valid := input.valid && input.add - decode.mulToAdd.source := input.source - decode.mulToAdd.rs1.mantissa := norm.output.mantissa >> 1 //FMA Precision lost - decode.mulToAdd.rs1.exponent := norm.output.exponent - decode.mulToAdd.rs1.sign := norm.output.sign - decode.mulToAdd.rs1.special := False //TODO - decode.mulToAdd.rs2 := input.rs3 - decode.mulToAdd.rd := input.rd - decode.mulToAdd.lockId := input.lockId - decode.mulToAdd.roundMode := input.roundMode - if(p.withDouble) decode.mulToAdd.format := input.format - - input.ready := (input.add ? decode.mulToAdd.ready | output.ready) || input.divSqrt } val divSqrt = p.withDivSqrt generate new Area { @@ -965,7 +1007,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ decode.divSqrtToMul.msb2 := rs2.msb } - val mulBuffer = mul.notMul.output.toStream.stage + val mulBuffer = mul.result.notMul.output.toStream.stage mulBuffer.ready := False val iterationValue = Reg(UInt(mulWidth bits)) @@ -1081,9 +1123,20 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } val add = p.withAdd generate new Area{ - val input = decode.add.stage() + + class ShifterOutput extends AddInput{ + val xSign, ySign = Bool() + val xMantissa, yMantissa = UInt(p.internalMantissaSize+3 bits) + val xyExponent = UInt(p.internalExponentSize bits) + val xySign = Bool() + val roundingScrap = Bool() + } val shifter = new Area { + val input = decode.add.stage() + val output = input.swapPayload(new ShifterOutput) + output.payload.assignSomeByName(input.payload) + val exp21 = input.rs2.exponent -^ input.rs1.exponent val rs1ExponentBigger = (exp21.msb || input.rs2.isZero) && !input.rs1.isZero val rs1ExponentEqual = input.rs1.exponent === input.rs2.exponent @@ -1095,8 +1148,8 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ //Note that rs1ExponentBigger can be replaced by absRs1Bigger bellow to avoid xsigned two complement in math block at expense of combinatorial path val xySign = absRs1Bigger ? input.rs1.sign | input.rs2.sign - val xSign = xySign ^ (rs1ExponentBigger ? input.rs1.sign | input.rs2.sign) - val ySign = xySign ^ (rs1ExponentBigger ? input.rs2.sign | input.rs1.sign) + output.xSign := xySign ^ (rs1ExponentBigger ? input.rs1.sign | input.rs2.sign) + output.ySign := xySign ^ (rs1ExponentBigger ? input.rs2.sign | input.rs1.sign) val xMantissa = U"1" @@ (rs1ExponentBigger ? input.rs1.mantissa | input.rs2.mantissa) @@ U"00" val yMantissaUnshifted = U"1" @@ (rs1ExponentBigger ? input.rs2.mantissa | input.rs1.mantissa) @@ U"00" var yMantissa = CombInit(yMantissaUnshifted) @@ -1108,66 +1161,86 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ when(passThrough) { yMantissa := 0 } when(shiftOverflow) { roundingScrap := True } when(input.rs1.special || input.rs2.special){ roundingScrap := False } - val xyExponent = rs1ExponentBigger ? input.rs1.exponent | input.rs2.exponent + output.xyExponent := rs1ExponentBigger ? input.rs1.exponent | input.rs2.exponent + output.xMantissa := xMantissa + output.yMantissa := yMantissa + output.xySign := xySign + output.roundingScrap := roundingScrap + } + + class MathOutput extends ShifterOutput{ + val xyMantissa = UInt(p.internalMantissaSize+4 bits) } val math = new Area { - def xSign = shifter.xSign - def ySign = shifter.ySign - def xMantissa = shifter.xMantissa - def yMantissa = shifter.yMantissa - def xyExponent = shifter.xyExponent - def xySign = shifter.xySign + val input = shifter.output.stage() + val output = input.swapPayload(new MathOutput) + output.payload.assignSomeByName(input.payload) + import input.payload._ val xSigned = xMantissa.twoComplement(xSign) //TODO Is that necessary ? - val ySigned = ((ySign ## Mux(ySign, ~yMantissa, yMantissa)).asUInt + (ySign && !shifter.roundingScrap).asUInt).asSInt //rounding here - val xyMantissa = U(xSigned +^ ySigned).trim(1 bits) + val ySigned = ((ySign ## Mux(ySign, ~yMantissa, yMantissa)).asUInt + (ySign && !roundingScrap).asUInt).asSInt //rounding here + output.xyMantissa := U(xSigned +^ ySigned).trim(1 bits) + } + + + class NormOutput extends AddInput{ + val mantissa = UInt(p.internalMantissaSize+4 bits) + val exponent = UInt(p.internalExponentSize+1 bits) + val infinityNan, forceNan, forceZero, forceInfinity = Bool() + val xySign, roundingScrap = Bool() + val xyMantissaZero = Bool() } val norm = new Area{ - def xyExponent = math.xyExponent - def xyMantissa = math.xyMantissa - val xySign = CombInit(math.xySign) + val input = math.output.stage() + val output = input.swapPayload(new NormOutput) + output.payload.assignSomeByName(input.payload) + import input.payload._ val shiftOh = OHMasking.first(xyMantissa.asBools.reverse) val shift = OHToUInt(shiftOh) - val mantissa = (xyMantissa |<< shift) - val exponent = xyExponent -^ shift + 1 - val forceZero = xyMantissa === 0 || (input.rs1.isZero && input.rs2.isZero) -// val forceOverflow = exponent === exponentOne + 128 //Handled by writeback rounding - val forceInfinity = (input.rs1.isInfinity || input.rs2.isInfinity) - val infinityNan = (input.rs1.isInfinity && input.rs2.isInfinity && (input.rs1.sign ^ input.rs2.sign)) - val forceNan = input.rs1.isNan || input.rs2.isNan || infinityNan + output.mantissa := (xyMantissa |<< shift) + output.exponent := xyExponent -^ shift + 1 + output.forceInfinity := (input.rs1.isInfinity || input.rs2.isInfinity) + output.forceZero := xyMantissa === 0 || (input.rs1.isZero && input.rs2.isZero) + output.infinityNan := (input.rs1.isInfinity && input.rs2.isInfinity && (input.rs1.sign ^ input.rs2.sign)) + output.forceNan := input.rs1.isNan || input.rs2.isNan || output.infinityNan + output.xyMantissaZero := xyMantissa === 0 } + val result = new Area { + val input = norm.output.stage() + val output = input.swapPayload(new MergeInput()) + import input.payload._ - val output = input.swapPayload(MergeInput()) - output.source := input.source - output.lockId := input.lockId - output.rd := input.rd - output.value.sign := norm.xySign - output.value.mantissa := (norm.mantissa >> 2).resized - output.value.exponent := norm.exponent.resized - output.value.special := False - output.roundMode := input.roundMode - if(p.withDouble) output.format := input.format - output.scrap := (norm.mantissa(1) | norm.mantissa(0) | shifter.roundingScrap) + output.source := input.source + output.lockId := input.lockId + output.rd := input.rd + output.value.sign := xySign + output.value.mantissa := (mantissa >> 2).resized + output.value.exponent := exponent.resized + output.value.special := False + output.roundMode := input.roundMode + if (p.withDouble) output.format := input.format + output.scrap := (mantissa(1) | mantissa(0) | roundingScrap) - val flag = io.port(input.source).completion.flag - flag.NV setWhen(input.valid && (norm.infinityNan || input.rs1.isNanSignaling || input.rs2.isNanSignaling)) - when(norm.forceNan) { - output.value.setNanQuiet - } elsewhen(norm.forceZero) { - output.value.setZero - when(norm.xyMantissa === 0 || input.rs1.isZero && input.rs2.isZero){ - output.value.sign := input.rs1.sign && input.rs2.sign + val flag = io.port(input.source).completion.flag + flag.NV setWhen (input.valid && (infinityNan || input.rs1.isNanSignaling || input.rs2.isNanSignaling)) + when(forceNan) { + output.value.setNanQuiet + } elsewhen (forceZero) { + output.value.setZero + when(xyMantissaZero || input.rs1.isZero && input.rs2.isZero) { + output.value.sign := input.rs1.sign && input.rs2.sign + } + when((input.rs1.sign || input.rs2.sign) && input.roundMode === FpuRoundMode.RDN) { + output.value.sign := True + } + } elsewhen (forceInfinity) { + output.value.setInfinity } - when((input.rs1.sign || input.rs2.sign) && input.roundMode === FpuRoundMode.RDN){ - output.value.sign := True - } - } elsewhen(norm.forceInfinity) { - output.value.setInfinity } } @@ -1175,37 +1248,55 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val merge = new Area { //TODO maybe load can bypass merge and round. val inputs = ArrayBuffer[Stream[MergeInput]]() - inputs += load.s1.output - if(p.withAdd) (inputs += add.output) - if(p.withMul) (inputs += mul.output) + inputs += load.s1.output.stage() + if(p.withAdd) (inputs += add.result.output) + if(p.withMul) (inputs += mul.result.output) if(p.withShortPipMisc) (inputs += shortPip.rfOutput) val arbitrated = StreamArbiterFactory.lowerFirst.noLock.on(inputs) val isCommited = rf.lock.map(_.commited).read(arbitrated.lockId) val commited = arbitrated.haltWhen(!isCommited).toFlow } - val round = new Area{ - val input = merge.commited.combStage + class RoundFront extends MergeInput{ + val mantissaIncrement = Bool() + val roundAdjusted = Bits(2 bits) + val exactMask = UInt(p.internalMantissaSize + 2 bits) + } + + val roundFront = new Area { + val input = merge.commited.stage() + val output = input.swapPayload(new RoundFront()) + output.payload.assignSomeByName(input.payload) val manAggregate = input.value.mantissa @@ input.scrap - val expBase = muxDouble[UInt](input.format)(exponentF64Subnormal+1)(exponentF32Subnormal+1) + val expBase = muxDouble[UInt](input.format)(exponentF64Subnormal + 1)(exponentF32Subnormal + 1) val expDif = expBase -^ input.value.exponent val expSubnormal = !expDif.msb - var discardCount = (expSubnormal ? expDif.resize(log2Up(p.internalMantissaSize) bits) | U(0)) - if(p.withDouble) when(input.format === FpuFormat.FLOAT){ + var discardCount = (expSubnormal ? expDif.resize(log2Up(p.internalMantissaSize) bits) | U(0)) + if (p.withDouble) when(input.format === FpuFormat.FLOAT) { discardCount \= discardCount + 29 } - val exactMask = (List(True) ++ (0 until p.internalMantissaSize+1).map(_ < discardCount)).asBits.asUInt - val roundAdjusted = (True ## (manAggregate>>1))(discardCount) ## ((manAggregate & exactMask) =/= 0) + val exactMask = (List(True) ++ (0 until p.internalMantissaSize + 1).map(_ < discardCount)).asBits.asUInt + val roundAdjusted = (True ## (manAggregate >> 1)) (discardCount) ## ((manAggregate & exactMask) =/= 0) val mantissaIncrement = !input.value.special && input.roundMode.mux( - FpuRoundMode.RNE -> (roundAdjusted(1) && (roundAdjusted(0) || (U"01" ## (manAggregate>>2))(discardCount))), + FpuRoundMode.RNE -> (roundAdjusted(1) && (roundAdjusted(0) || (U"01" ## (manAggregate >> 2)) (discardCount))), FpuRoundMode.RTZ -> False, - FpuRoundMode.RDN -> (roundAdjusted =/= 0 && input.value.sign), + FpuRoundMode.RDN -> (roundAdjusted =/= 0 && input.value.sign), FpuRoundMode.RUP -> (roundAdjusted =/= 0 && !input.value.sign), FpuRoundMode.RMM -> (roundAdjusted(1)) ) + output.mantissaIncrement := mantissaIncrement + output.roundAdjusted := roundAdjusted + output.exactMask := exactMask + } + + val roundBack = new Area{ + val input = roundFront.output.stage() + val output = input.swapPayload(RoundOutput()) + import input.payload._ + val math = p.internalFloating() val mantissaRange = p.internalMantissaSize downto 1 val adderMantissa = input.value.mantissa(mantissaRange) & (mantissaIncrement ? ~(exactMask.trim(1) >> 1) | input.value.mantissa(mantissaRange).maxValue) @@ -1218,12 +1309,6 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val patched = CombInit(math) val nx,of,uf = False -// val ufPatch = input.roundMode === FpuRoundMode.RUP && !input.value.sign && !input.scrap|| input.roundMode === FpuRoundMode.RDN && input.value.sign && !input.scrap -// when(!math.special && (input.value.exponent <= exponentOne-127 && (math.exponent =/= exponentOne-126 || !input.value.mantissa.lsb || ufPatch)) && roundAdjusted.asUInt =/= 0){ -// uf := True -// } - - val ufSubnormalThreshold = muxDouble[UInt](input.format)(exponentF64Subnormal)(exponentF32Subnormal) val ufThreshold = muxDouble[UInt](input.format)(exponentF64Subnormal-52+1)(exponentF32Subnormal-23+1) @@ -1277,7 +1362,6 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ flag.OF setWhen(of) flag.UF setWhen(uf) } - val output = input.swapPayload(RoundOutput()) output.source := input.source output.lockId := input.lockId output.rd := input.rd @@ -1286,7 +1370,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } val writeback = new Area{ - val input = round.output.combStage + val input = roundBack.output.stage() for(i <- 0 until portCount){ completion(i).increments += (RegNext(input.fire && input.source === i) init(False)) @@ -1393,12 +1477,7 @@ object FpuSynthesisBench extends App{ }) } -//Fpu_32 -> -//Artix 7 -> 46 Mhz 1786 LUT 628 FF -//Artix 7 -> 47 Mhz 1901 LUT 628 FF -//Fpu_64 -> -//Artix 7 -> 37 Mhz 3407 LUT 1006 FF -//Artix 7 -> 36 Mhz 3564 LUT 1006 FF + val rtls = ArrayBuffer[Rtl]() rtls += new Fpu( diff --git a/src/main/scala/vexriscv/ip/fpu/Interface.scala b/src/main/scala/vexriscv/ip/fpu/Interface.scala index 604dd10e..8f968fe4 100644 --- a/src/main/scala/vexriscv/ip/fpu/Interface.scala +++ b/src/main/scala/vexriscv/ip/fpu/Interface.scala @@ -109,6 +109,8 @@ object FpuRoundModeInstr extends SpinalEnum(){ case class FpuParameter( withDouble : Boolean, + mulWidthA : Int = 18, + mulWidthB : Int = 18, sim : Boolean = false, withAdd : Boolean = true, withMul : Boolean = true, From e504afbf1897fcec8037473e38dc2f92525dfcb1 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 19 Feb 2021 11:26:28 +0100 Subject: [PATCH 592/951] fpu integration wip, got mandelbrot to work in linux with no inline (crash when inlined) --- src/main/scala/vexriscv/TestsWorkspace.scala | 2 +- .../demo/smp/VexRiscvSmpCluster.scala | 17 ++++- src/main/scala/vexriscv/ip/DataCache.scala | 2 +- src/main/scala/vexriscv/ip/fpu/FpuCore.scala | 65 ++++++++++++------- .../scala/vexriscv/ip/fpu/Interface.scala | 6 ++ .../vexriscv/plugin/DBusCachedPlugin.scala | 7 ++ .../scala/vexriscv/plugin/FpuPlugin.scala | 7 +- 7 files changed, 75 insertions(+), 31 deletions(-) diff --git a/src/main/scala/vexriscv/TestsWorkspace.scala b/src/main/scala/vexriscv/TestsWorkspace.scala index ac07cb88..bcda45ff 100644 --- a/src/main/scala/vexriscv/TestsWorkspace.scala +++ b/src/main/scala/vexriscv/TestsWorkspace.scala @@ -33,7 +33,7 @@ import vexriscv.ip.fpu.FpuParameter object TestsWorkspace { def main(args: Array[String]) { SpinalConfig().generateVerilog { -// make clean all REDO=10 CSR=no MMU=no COREMARK=no RVF=no REDO=1 DBUS_LOAD_DATA_WIDTH=64 DBUS_STORE_DATA_WIDTH=64 DEBUG=ye TRACE=ye + // make clean all REDO=10 CSR=no MMU=no COREMARK=no RVF=yes RVD=yes REDO=1 DBUS_LOAD_DATA_WIDTH=64 DBUS_STORE_DATA_WIDTH=64 DEBUG=ye TRACE=ye val config = VexRiscvConfig( plugins = List( new IBusCachedPlugin( diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index d3da4b3f..5b66670a 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -15,12 +15,13 @@ import spinal.lib.generator.Handle import spinal.lib.misc.plic.PlicMapping import spinal.lib.system.debugger.SystemDebuggerConfig import vexriscv.ip.{DataCacheAck, DataCacheConfig, DataCacheMemBus, InstructionCache, InstructionCacheConfig} -import vexriscv.plugin.{BranchPlugin, CsrAccess, CsrPlugin, CsrPluginConfig, DBusCachedPlugin, DBusSimplePlugin, DYNAMIC_TARGET, DebugPlugin, DecoderSimplePlugin, FullBarrelShifterPlugin, HazardSimplePlugin, IBusCachedPlugin, IBusSimplePlugin, IntAluPlugin, MmuPlugin, MmuPortConfig, MulDivIterativePlugin, MulPlugin, RegFilePlugin, STATIC, SrcPlugin, StaticMemoryTranslatorPlugin, YamlPlugin} +import vexriscv.plugin.{BranchPlugin, CsrAccess, CsrPlugin, CsrPluginConfig, DBusCachedPlugin, DBusSimplePlugin, DYNAMIC_TARGET, DebugPlugin, DecoderSimplePlugin, FpuPlugin, FullBarrelShifterPlugin, HazardSimplePlugin, IBusCachedPlugin, IBusSimplePlugin, IntAluPlugin, MmuPlugin, MmuPortConfig, MulDivIterativePlugin, MulPlugin, RegFilePlugin, STATIC, SrcPlugin, StaticMemoryTranslatorPlugin, YamlPlugin} import vexriscv.{Riscv, VexRiscv, VexRiscvBmbGenerator, VexRiscvConfig, plugin} import scala.collection.mutable import scala.collection.mutable.ArrayBuffer import spinal.lib.generator._ +import vexriscv.ip.fpu.FpuParameter case class VexRiscvSmpClusterParameter(cpuConfigs : Seq[VexRiscvConfig], withExclusiveAndInvalidation : Boolean, forcePeripheralWidth : Boolean = true, outOfOrderDecoder : Boolean = true) @@ -163,10 +164,15 @@ object VexRiscvSmpClusterGen { earlyBranch : Boolean = false, dBusCmdMasterPipe : Boolean = false, withMmu : Boolean = true, - withSupervisor : Boolean = true + withSupervisor : Boolean = true, + withFloat : Boolean = false, + withDouble : Boolean = false, + externalFpu : Boolean = true ) = { assert(iCacheSize/iCacheWays <= 4096, "Instruction cache ways can't be bigger than 4096 bytes") assert(dCacheSize/dCacheWays <= 4096, "Data cache ways can't be bigger than 4096 bytes") + assert(!(withDouble && !withFloat)) + val config = VexRiscvConfig( plugins = List( if(withMmu)new MmuPlugin( @@ -262,7 +268,7 @@ object VexRiscvSmpClusterGen { mulUnrollFactor = 32, divUnrollFactor = 1 ), - new CsrPlugin(CsrPluginConfig.openSbi(mhartid = hartId, misa = Riscv.misaToInt("imas")).copy(utimeAccess = CsrAccess.READ_ONLY)), + new CsrPlugin(CsrPluginConfig.openSbi(mhartid = hartId, misa = Riscv.misaToInt(s"ima${if(withFloat) "f" else ""}${if(withDouble) "d" else ""}s")).copy(utimeAccess = CsrAccess.READ_ONLY)), new BranchPlugin( earlyBranch = earlyBranch, catchAddressMisaligned = true, @@ -271,6 +277,11 @@ object VexRiscvSmpClusterGen { new YamlPlugin(s"cpu$hartId.yaml") ) ) + + if(withFloat) config.plugins += new FpuPlugin( + externalFpu = true, + p = FpuParameter(withDouble = withDouble) + ) config } diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index 4fbcdeb2..f12250b2 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -675,7 +675,7 @@ class DataCache(val p : DataCacheConfig, mmuParameter : MemoryTranslatorBusParam val rspSync = True val rspLast = True - val memCmdSent = RegInit(False) setWhen (io.mem.cmd.ready) clearWhen (!io.cpu.writeBack.isStuck) + val memCmdSent = RegInit(False) setWhen (io.mem.cmd.fire) clearWhen (!io.cpu.writeBack.isStuck) val pending = withExclusive generate new Area{ val counter = Reg(UInt(log2Up(pendingMax) + 1 bits)) init(0) val counterNext = counter + U(io.mem.cmd.fire && io.mem.cmd.last) - ((io.mem.rsp.valid && io.mem.rsp.last) ? (io.mem.rsp.aggregated +^ 1) | 0) diff --git a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala index dca4f196..4a2e2086 100644 --- a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala +++ b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala @@ -207,7 +207,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ arbiterOutput.source := arbiter.io.chosen arbiterOutput.payload.assignSomeByName(arbiter.io.output.payload) - val s0 = arbiterOutput.pipelined(m2s = true, s2m = true) + val s0 = arbiterOutput.pipelined(m2s = true, s2m = true) //TODO may need to remove m2s for store latency val useRs1, useRs2, useRs3, useRd = False switch(s0.opcode){ is(p.Opcode.LOAD) { useRd := True } @@ -287,28 +287,28 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } val decode = new Area{ - val input = read.output.combStage() + val input = read.output/*.s2mPipe()*/.combStage() input.ready := False val loadHit = List(FpuOpcode.LOAD, FpuOpcode.FMV_W_X, FpuOpcode.I2F).map(input.opcode === _).orR val load = Stream(LoadInput()) load.valid := input.valid && loadHit input.ready setWhen(loadHit && load.ready) - load.payload.assignSomeByName(read.output.payload) + load.payload.assignSomeByName(input.payload) load.i2f := input.opcode === FpuOpcode.I2F val shortPipHit = List(FpuOpcode.STORE, FpuOpcode.F2I, FpuOpcode.CMP, FpuOpcode.MIN_MAX, FpuOpcode.SGNJ, FpuOpcode.FMV_X_W, FpuOpcode.FCLASS, FpuOpcode.FCVT_X_X).map(input.opcode === _).orR val shortPip = Stream(ShortPipInput()) input.ready setWhen(shortPipHit && shortPip.ready) shortPip.valid := input.valid && shortPipHit - shortPip.payload.assignSomeByName(read.output.payload) + shortPip.payload.assignSomeByName(input.payload) val divSqrtHit = input.opcode === p.Opcode.DIV || input.opcode === p.Opcode.SQRT val divSqrt = Stream(DivSqrtInput()) if(p.withDivSqrt) { input.ready setWhen (divSqrtHit && divSqrt.ready) divSqrt.valid := input.valid && divSqrtHit - divSqrt.payload.assignSomeByName(read.output.payload) + divSqrt.payload.assignSomeByName(input.payload) divSqrt.div := input.opcode === p.Opcode.DIV } @@ -324,15 +324,15 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ divSqrtToMul.ready := mul.ready mul.payload := divSqrtToMul.payload when(!divSqrtToMul.valid) { - mul.payload.assignSomeByName(read.output.payload) + mul.payload.assignSomeByName(input.payload) mul.add := fmaHit mul.divSqrt := False mul.msb1 := True mul.msb2 := True mul.rs2.sign.allowOverride(); - mul.rs2.sign := read.output.rs2.sign ^ input.arg(0) + mul.rs2.sign := input.rs2.sign ^ input.arg(0) mul.rs3.sign.allowOverride(); - mul.rs3.sign := read.output.rs3.sign ^ input.arg(1) + mul.rs3.sign := input.rs3.sign ^ input.arg(1) } } @@ -348,9 +348,9 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ mulToAdd.ready := add.ready add.payload := mulToAdd.payload when(!mulToAdd.valid) { - add.payload.assignSomeByName(read.output.payload) + add.payload.assignSomeByName(input.payload) add.rs2.sign.allowOverride; - add.rs2.sign := read.output.rs2.sign ^ input.arg(0) + add.rs2.sign := input.rs2.sign ^ input.arg(0) } } } @@ -578,7 +578,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val input = UInt(p.internalMantissaSize+1 max 33 bits).assignDontCare() var logic = input val scrap = Reg(Bool) - for(i <- by.range){ + for(i <- by.range.reverse){ scrap setWhen(by(i) && logic(0, 1 << i bits) =/= 0) logic \= by(i) ? (logic |>> (BigInt(1) << i)) | logic } @@ -809,11 +809,13 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ List(FpuOpcode.CMP, FpuOpcode.MIN_MAX).map(input.opcode === _).orR && rs2NanNv flag.NV setWhen(input.valid && nv) - input.ready := !halt && (toFpuRf ? rfOutput.ready | io.port.map(_.rsp.ready).read(input.source)) + val rspStreams = Vec(Stream(FpuRsp(p)), portCount) + input.ready := !halt && (toFpuRf ? rfOutput.ready | rspStreams.map(_.ready).read(input.source)) for(i <- 0 until portCount){ - def rsp = io.port(i).rsp + def rsp = rspStreams(i) rsp.valid := input.valid && input.source === i && !toFpuRf && !halt rsp.value := result + io.port(i).rsp << rsp.stage() completion(i).increments += (RegNext(rsp.fire) init(False)) } } @@ -940,7 +942,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } val divSqrt = p.withDivSqrt generate new Area { - val input = decode.divSqrt.stage() + val input = decode.divSqrt.halfPipe() val aproxWidth = 8 val aproxDepth = 64 @@ -1142,7 +1144,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val rs1ExponentEqual = input.rs1.exponent === input.rs2.exponent val rs1MantissaBigger = input.rs1.mantissa > input.rs2.mantissa val absRs1Bigger = ((rs1ExponentBigger || rs1ExponentEqual && rs1MantissaBigger) && !input.rs1.isZero || input.rs1.isInfinity) && !input.rs2.isInfinity - val shiftBy = rs1ExponentBigger ? (0-exp21) | exp21 + val shiftBy = exp21.asSInt.abs//rs1ExponentBigger ? (0-exp21) | exp21 val shiftOverflow = (shiftBy >= p.internalMantissaSize+3) val passThrough = shiftOverflow || (input.rs1.isZero) || (input.rs2.isZero) @@ -1153,8 +1155,8 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val xMantissa = U"1" @@ (rs1ExponentBigger ? input.rs1.mantissa | input.rs2.mantissa) @@ U"00" val yMantissaUnshifted = U"1" @@ (rs1ExponentBigger ? input.rs2.mantissa | input.rs1.mantissa) @@ U"00" var yMantissa = CombInit(yMantissaUnshifted) - val roundingScrap = CombInit(shiftOverflow) - for(i <- 0 until log2Up(p.internalMantissaSize)){ + val roundingScrap = False + for(i <- log2Up(p.internalMantissaSize) - 1 downto 0){ roundingScrap setWhen(shiftBy(i) && yMantissa(0, 1 << i bits) =/= 0) yMantissa \= shiftBy(i) ? (yMantissa |>> (BigInt(1) << i)) | yMantissa } @@ -1181,6 +1183,25 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val xSigned = xMantissa.twoComplement(xSign) //TODO Is that necessary ? val ySigned = ((ySign ## Mux(ySign, ~yMantissa, yMantissa)).asUInt + (ySign && !roundingScrap).asUInt).asSInt //rounding here output.xyMantissa := U(xSigned +^ ySigned).trim(1 bits) + + } + + class OhOutput extends MathOutput{ +// val shiftOh = Vec(Bool, p.internalMantissaSize+4) + val shift = UInt(log2Up(p.internalMantissaSize+4) bits) + } + + val oh = new Area { + val input = math.output.stage() + val output = input.swapPayload(new OhOutput) + output.payload.assignSomeByName(input.payload) + import input.payload._ + + val shiftOh = OHMasking.first(output.xyMantissa.asBools.reverse) //The OhMasking.first can be processed in parallel to the xyMantissa carry chaine +// output.shiftOh := shiftOh + + val shift = OHToUInt(shiftOh) + output.shift := shift } @@ -1193,13 +1214,11 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } val norm = new Area{ - val input = math.output.stage() + val input = oh.output.stage() val output = input.swapPayload(new NormOutput) output.payload.assignSomeByName(input.payload) import input.payload._ - val shiftOh = OHMasking.first(xyMantissa.asBools.reverse) - val shift = OHToUInt(shiftOh) output.mantissa := (xyMantissa |<< shift) output.exponent := xyExponent -^ shift + 1 output.forceInfinity := (input.rs1.isInfinity || input.rs2.isInfinity) @@ -1210,7 +1229,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } val result = new Area { - val input = norm.output.stage() + val input = norm.output.pipelined() val output = input.swapPayload(new MergeInput()) import input.payload._ @@ -1251,7 +1270,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ inputs += load.s1.output.stage() if(p.withAdd) (inputs += add.result.output) if(p.withMul) (inputs += mul.result.output) - if(p.withShortPipMisc) (inputs += shortPip.rfOutput) + if(p.withShortPipMisc) (inputs += shortPip.rfOutput.pipelined(m2s = true)) val arbitrated = StreamArbiterFactory.lowerFirst.noLock.on(inputs) val isCommited = rf.lock.map(_.commited).read(arbitrated.lockId) val commited = arbitrated.haltWhen(!isCommited).toFlow @@ -1301,7 +1320,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val mantissaRange = p.internalMantissaSize downto 1 val adderMantissa = input.value.mantissa(mantissaRange) & (mantissaIncrement ? ~(exactMask.trim(1) >> 1) | input.value.mantissa(mantissaRange).maxValue) val adderRightOp = (mantissaIncrement ? (exactMask >> 1)| U(0)).resize(p.internalMantissaSize bits) - val adder = (input.value.exponent @@ adderMantissa) + adderRightOp + U(mantissaIncrement) + val adder = KeepAttribute(KeepAttribute(input.value.exponent @@ adderMantissa) + KeepAttribute(adderRightOp) + KeepAttribute(U(mantissaIncrement))) math.special := input.value.special math.sign := input.value.sign math.exponent := adder(p.internalMantissaSize, p.internalExponentSize bits) diff --git a/src/main/scala/vexriscv/ip/fpu/Interface.scala b/src/main/scala/vexriscv/ip/fpu/Interface.scala index 8f968fe4..3f6542c2 100644 --- a/src/main/scala/vexriscv/ip/fpu/Interface.scala +++ b/src/main/scala/vexriscv/ip/fpu/Interface.scala @@ -138,6 +138,12 @@ case class FpuFlags() extends Bundle{ case class FpuCompletion() extends Bundle{ val flag = FpuFlags() val count = UInt(2 bits) + + def stage() = { + val ret = FpuCompletion().setCompositeName(this, "stage", true) + ret := this + ret + } } case class FpuCmd(p : FpuParameter) extends Bundle{ diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index df501378..9c939bff 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -72,6 +72,9 @@ class DBusCachedPlugin(val config : DataCacheConfig, MEMORY_WR -> False ) ++ (if(catchSomething) List(HAS_SIDE_EFFECT -> True) else Nil) ) + + if(withLrSc) decoderService.add(key, Seq(MEMORY_LRSC -> False)) + if(withAmo) decoderService.add(key, Seq(MEMORY_AMO -> False)) } override def addStoreWordEncoding(key : MaskedLiteral): Unit = { val decoderService = pipeline.service(classOf[DecoderService]) @@ -91,6 +94,9 @@ class DBusCachedPlugin(val config : DataCacheConfig, MEMORY_WR -> True ) ++ (if(catchSomething) List(HAS_SIDE_EFFECT -> True) else Nil) ) + + if(withLrSc) decoderService.add(key, Seq(MEMORY_LRSC -> False)) + if(withAmo) decoderService.add(key, Seq(MEMORY_AMO -> False)) } val bypassStoreList = ArrayBuffer[(Bool, Bits)]() @@ -501,6 +507,7 @@ class DBusCachedPlugin(val config : DataCacheConfig, dBusAccess.rsp.error := cache.io.cpu.writeBack.unalignedAccess || cache.io.cpu.writeBack.accessError dBusAccess.rsp.redo := cache.io.cpu.redo component.addPrePopTask{() => + managementStage.input(IS_DBUS_SHARING).getDrivingReg clearWhen(dBusAccess.rsp.fire) when(forceDatapath){ execute.output(REGFILE_WRITE_DATA) := dBusAccess.cmd.address.asBits } diff --git a/src/main/scala/vexriscv/plugin/FpuPlugin.scala b/src/main/scala/vexriscv/plugin/FpuPlugin.scala index 88f3481e..b42fd179 100644 --- a/src/main/scala/vexriscv/plugin/FpuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/FpuPlugin.scala @@ -157,13 +157,13 @@ class FpuPlugin(externalFpu : Boolean = false, import pipeline.config._ import Riscv._ - val internal = !externalFpu generate pipeline plug new Area{ + val internal = (!externalFpu).generate (pipeline plug new Area{ val fpu = FpuCore(1, p) fpu.io.port(0).cmd << port.cmd fpu.io.port(0).commit << port.commit fpu.io.port(0).rsp >> port.rsp fpu.io.port(0).completion <> port.completion - } + }) val csr = pipeline plug new Area{ @@ -195,6 +195,7 @@ class FpuPlugin(externalFpu : Boolean = false, fs := 3 //DIRTY } service.rw(CSR.SSTATUS, 13, fs) + service.rw(CSR.MSTATUS, 13, fs) } decode plug new Area{ @@ -259,7 +260,7 @@ class FpuPlugin(externalFpu : Boolean = false, commit.write := arbitration.isValid && !arbitration.removeIt commit.sync := input(FPU_COMMIT_SYNC) - when(arbitration.isValid && !commit.ready){ + when(isCommit && !commit.ready){ arbitration.haltByOther := True } From 3f226b758c9a1a9706dae1a16368bc447bdf3200 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 19 Feb 2021 13:03:48 +0100 Subject: [PATCH 593/951] fpu fix exception flag handeling --- src/main/scala/vexriscv/ip/fpu/FpuCore.scala | 100 +++++++++++------- .../scala/vexriscv/ip/fpu/Interface.scala | 13 +-- .../scala/vexriscv/plugin/FpuPlugin.scala | 18 ++-- src/test/cpp/regression/main.cpp | 13 ++- src/test/scala/vexriscv/ip/fpu/FpuTest.scala | 13 ++- 5 files changed, 94 insertions(+), 63 deletions(-) diff --git a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala index 4a2e2086..a2410998 100644 --- a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala +++ b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala @@ -125,6 +125,8 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val scrap = Bool() val roundMode = FpuRoundMode() val format = p.withDouble generate FpuFormat() + val NV = Bool() + val DZ = Bool() //TODO } case class RoundOutput() extends Bundle{ @@ -133,6 +135,8 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val rd = p.rfAddress() val value = p.internalFloating() val format = p.withDouble generate FpuFormat() + val NV, NX, OF, UF, DZ = Bool() + val write = Bool() } val rf = new Area{ @@ -153,20 +157,20 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val lockFreeId = OHMasking.first(lock.map(!_.valid)) } - val completion = for(source <- 0 until portCount) yield new Area{ - def port = io.port(source) - port.completion.flag.NV := False - port.completion.flag.DZ := False - port.completion.flag.OF := False - port.completion.flag.UF := False - port.completion.flag.NX := False - - val increments = ArrayBuffer[Bool]() - - afterElaboration{ - port.completion.count := increments.map(_.asUInt.resize(log2Up(increments.size + 1))).reduceBalancedTree(_ + _) - } - } +// val completion = for(source <- 0 until portCount) yield new Area{ +// def port = io.port(source) +// port.completion.flag.NV := False +// port.completion.flag.DZ := False +// port.completion.flag.OF := False +// port.completion.flag.UF := False +// port.completion.flag.NX := False +// +// val increments = ArrayBuffer[Bool]() +// +// afterElaboration{ +// port.completion.count := increments.map(_.asUInt.resize(log2Up(increments.size + 1))).reduceBalancedTree(_ + _) +// } +// } val commitFork = new Area{ val load, commit = Vec(Stream(FpuCommit(p)), portCount) @@ -522,6 +526,8 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ output.value.mantissa := recoded.mantissa @@ U"0" output.value.special := recoded.special output.scrap := False + output.NV := False + output.DZ := False when(input.i2f){ output.value.sign := i2fSign output.value.exponent := (U(exponentOne+31) - fsm.shift.by).resized @@ -534,6 +540,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ output.value.mantissa := U(i2fHigh) @@ (if(p.withDouble) U"0" else U"") } } + } val shortPip = new Area{ @@ -543,8 +550,6 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val result = p.storeLoadType().assignDontCare() - val flag = io.port(input.source).completion.flag - val halt = False val recodedResult = p.storeLoadType() val f32 = new Area{ @@ -677,7 +682,8 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } } - + val rspNv = False + val rspNx = False val f2i = new Area{ //Will not work for 64 bits float max value rounding val unsigned = fsm.shift.output(32 downto 0) >> 1 @@ -703,9 +709,9 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val low = overflow val high = input.arg(0) ^ overflow result := (31 -> high, default -> low) - flag.NV := input.valid && input.opcode === FpuOpcode.F2I && fsm.done && !isZero + rspNv := input.valid && input.opcode === FpuOpcode.F2I && fsm.done && !isZero } otherwise { - flag.NX := input.valid && input.opcode === FpuOpcode.F2I && fsm.done && round =/= 0 + rspNx := input.valid && input.opcode === FpuOpcode.F2I && fsm.done && round =/= 0 } } @@ -805,9 +811,9 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val rs2Nan = input.rs2.isNan val rs1NanNv = input.rs1.isNan && (!input.rs1.isQuiet || signalQuiet) val rs2NanNv = input.rs2.isNan && (!input.rs2.isQuiet || signalQuiet) - val nv = List(FpuOpcode.CMP, FpuOpcode.MIN_MAX, FpuOpcode.FCVT_X_X).map(input.opcode === _).orR && rs1NanNv || + val NV = List(FpuOpcode.CMP, FpuOpcode.MIN_MAX, FpuOpcode.FCVT_X_X).map(input.opcode === _).orR && rs1NanNv || List(FpuOpcode.CMP, FpuOpcode.MIN_MAX).map(input.opcode === _).orR && rs2NanNv - flag.NV setWhen(input.valid && nv) + rspNv setWhen(NV) val rspStreams = Vec(Stream(FpuRsp(p)), portCount) input.ready := !halt && (toFpuRf ? rfOutput.ready | rspStreams.map(_.ready).read(input.source)) @@ -815,9 +821,14 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ def rsp = rspStreams(i) rsp.valid := input.valid && input.source === i && !toFpuRf && !halt rsp.value := result + rsp.NV := rspNv + rsp.NX := rspNx io.port(i).rsp << rsp.stage() - completion(i).increments += (RegNext(rsp.fire) init(False)) } + + + rfOutput.NV := NV + rfOutput.DZ := False } val mul = p.withMul generate new Area{ @@ -891,13 +902,14 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ output.exponent := (exp - exponentOne).resized output.mantissa := man.asUInt output.setNormal + val NV = False when(exp(exp.getWidth-3, 3 bits) >= 5) { output.exponent(p.internalExponentSize-2, 2 bits) := 3 } - val flag = io.port(input.source).completion.flag +// val flag = io.port(input.source).completion.flag when(forceNan) { output.setNanQuiet - flag.NV setWhen(input.valid && (infinitynan || input.rs1.isNanSignaling || input.rs2.isNanSignaling)) + NV setWhen(input.valid && (infinitynan || input.rs1.isNanSignaling || input.rs2.isNanSignaling)) } elsewhen(forceOverflow) { output.setInfinity } elsewhen(forceZero) { @@ -909,6 +921,8 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val result = new Area { def input = norm.input + def NV = norm.NV + val notMul = new Area { val output = Flow(UInt(p.internalMantissaSize + 1 bits)) output.valid := input.valid && input.divSqrt @@ -924,6 +938,8 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ output.roundMode := input.roundMode output.scrap := norm.scrap output.value := norm.output + output.NV := NV + output.DZ := False decode.mulToAdd.valid := input.valid && input.add decode.mulToAdd.source := input.source @@ -1245,8 +1261,9 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ output.scrap := (mantissa(1) | mantissa(0) | roundingScrap) - val flag = io.port(input.source).completion.flag - flag.NV setWhen (input.valid && (infinityNan || input.rs1.isNanSignaling || input.rs2.isNanSignaling)) +// val flag = io.port(input.source).completion.flag + output.NV := (input.valid && (infinityNan || input.rs1.isNanSignaling || input.rs2.isNanSignaling)) + output.DZ := False when(forceNan) { output.value.setNanQuiet } elsewhen (forceZero) { @@ -1272,8 +1289,6 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ if(p.withMul) (inputs += mul.result.output) if(p.withShortPipMisc) (inputs += shortPip.rfOutput.pipelined(m2s = true)) val arbitrated = StreamArbiterFactory.lowerFirst.noLock.on(inputs) - val isCommited = rf.lock.map(_.commited).read(arbitrated.lockId) - val commited = arbitrated.haltWhen(!isCommited).toFlow } class RoundFront extends MergeInput{ @@ -1283,7 +1298,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } val roundFront = new Area { - val input = merge.commited.stage() + val input = merge.arbitrated.stage() val output = input.swapPayload(new RoundFront()) output.payload.assignSomeByName(input.payload) @@ -1313,7 +1328,8 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val roundBack = new Area{ val input = roundFront.output.stage() - val output = input.swapPayload(RoundOutput()) + val isCommited = rf.lock.map(_.commited).read(input.lockId) + val output = input.haltWhen(!isCommited).toFlow.swapPayload(RoundOutput()) import input.payload._ val math = p.internalFloating() @@ -1375,15 +1391,16 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ nx setWhen(!input.value.special && (roundAdjusted =/= 0)) - when(input.valid){ - val flag = io.port(input.source).completion.flag - flag.NX setWhen(nx) - flag.OF setWhen(of) - flag.UF setWhen(uf) - } + val write = rf.lock.map(_.write).read(input.lockId) + output.NX := nx & write + output.OF := of & write + output.UF := uf & write + output.NV := input.NV & write + output.DZ := input.DZ & write output.source := input.source output.lockId := input.lockId output.rd := input.rd + output.write := write if(p.withDouble) output.format := input.format output.value := patched } @@ -1392,7 +1409,14 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val input = roundBack.output.stage() for(i <- 0 until portCount){ - completion(i).increments += (RegNext(input.fire && input.source === i) init(False)) + val c = io.port(i).completion + c.valid := input.fire && input.source === i + c.flags.NX := input.NX + c.flags.OF := input.OF + c.flags.UF := input.UF + c.flags.NV := input.NV + c.flags.DZ := input.DZ + c.written := input.write } when(input.valid){ @@ -1402,7 +1426,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } val port = rf.ram.writePort - port.valid := input.valid && rf.lock.map(_.write).read(input.lockId) + port.valid := input.valid && input.write port.address := input.source @@ input.rd port.data.value := input.value if(p.withDouble) port.data.boxed := input.format === FpuFormat.FLOAT diff --git a/src/main/scala/vexriscv/ip/fpu/Interface.scala b/src/main/scala/vexriscv/ip/fpu/Interface.scala index 3f6542c2..9e021619 100644 --- a/src/main/scala/vexriscv/ip/fpu/Interface.scala +++ b/src/main/scala/vexriscv/ip/fpu/Interface.scala @@ -136,14 +136,8 @@ case class FpuFlags() extends Bundle{ } case class FpuCompletion() extends Bundle{ - val flag = FpuFlags() - val count = UInt(2 bits) - - def stage() = { - val ret = FpuCompletion().setCompositeName(this, "stage", true) - ret := this - ret - } + val flags = FpuFlags() + val written = Bool() //Used for verification purposes } case class FpuCmd(p : FpuParameter) extends Bundle{ @@ -163,13 +157,14 @@ case class FpuCommit(p : FpuParameter) extends Bundle{ case class FpuRsp(p : FpuParameter) extends Bundle{ val value = p.storeLoadType() // IEEE754 store || Integer + val NV, NX = Bool() } case class FpuPort(p : FpuParameter) extends Bundle with IMasterSlave { val cmd = Stream(FpuCmd(p)) val commit = Stream(FpuCommit(p)) val rsp = Stream(FpuRsp(p)) - val completion = FpuCompletion() + val completion = Flow(FpuCompletion()) override def asMaster(): Unit = { master(cmd, commit) diff --git a/src/main/scala/vexriscv/plugin/FpuPlugin.scala b/src/main/scala/vexriscv/plugin/FpuPlugin.scala index b42fd179..decf981c 100644 --- a/src/main/scala/vexriscv/plugin/FpuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/FpuPlugin.scala @@ -140,7 +140,7 @@ class FpuPlugin(externalFpu : Boolean = false, } //TODO FMV_X_X + doubles - port = FpuPort(p) + port = FpuPort(p).addTag(Verilator.public) if(externalFpu) master(port) val dBusEncoding = pipeline.service(classOf[DBusEncodingService]) @@ -168,16 +168,16 @@ class FpuPlugin(externalFpu : Boolean = false, val csr = pipeline plug new Area{ val pendings = Reg(UInt(5 bits)) init(0) - pendings := pendings + U(port.cmd.fire) - port.completion.count + pendings := pendings + U(port.cmd.fire) - U(port.completion.fire) - U(port.rsp.fire) val hasPending = pendings =/= 0 val flags = Reg(FpuFlags()) - flags.NV init(False) setWhen(port.completion.flag.NV) - flags.DZ init(False) setWhen(port.completion.flag.DZ) - flags.OF init(False) setWhen(port.completion.flag.OF) - flags.UF init(False) setWhen(port.completion.flag.UF) - flags.NX init(False) setWhen(port.completion.flag.NX) + flags.NV init(False) setWhen(port.completion.fire && port.completion.flags.NV) + flags.DZ init(False) setWhen(port.completion.fire && port.completion.flags.DZ) + flags.OF init(False) setWhen(port.completion.fire && port.completion.flags.OF) + flags.UF init(False) setWhen(port.completion.fire && port.completion.flags.UF) + flags.NX init(False) setWhen(port.completion.fire && port.completion.flags.NX) val service = pipeline.service(classOf[CsrInterface]) val rm = Reg(Bits(3 bits)) init(0) @@ -244,6 +244,10 @@ class FpuPlugin(externalFpu : Boolean = false, when(arbitration.isValid) { dBusEncoding.bypassStore(storeFormated) output(REGFILE_WRITE_DATA) := port.rsp.value(31 downto 0) + when(!arbitration.isStuck && !arbitration.isRemoved){ + csr.flags.NV setWhen(port.rsp.NV) + csr.flags.NX setWhen(port.rsp.NX) + } } when(!port.rsp.valid){ arbitration.haltByOther := True diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 4d500190..f2cf452a 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -239,6 +239,9 @@ class success : public std::exception { }; #define MSTATUS_READ_MASK 0x1888 #endif +#define u32 uint32_t +#define u32 uint64_t + class RiscvGolden { public: @@ -4043,26 +4046,26 @@ int main(int argc, char **argv, char **env) { #endif for(const string &name : riscvTestMain){ - redo(REDO,RiscvTest(name).run();) + redo(REDO,RiscvTest(name).withRiscvRef()->run();) } for(const string &name : riscvTestMemory){ - redo(REDO,RiscvTest(name).run();) + redo(REDO,RiscvTest(name).withRiscvRef()->run();) } #ifdef MUL for(const string &name : riscvTestMul){ - redo(REDO,RiscvTest(name).run();) + redo(REDO,RiscvTest(name).withRiscvRef()->run();) } #endif #ifdef DIV for(const string &name : riscvTestDiv){ - redo(REDO,RiscvTest(name).run();) + redo(REDO,RiscvTest(name).withRiscvRef()->run();) } #endif #ifdef COMPRESSED - redo(REDO,RiscvTest("rv32uc-p-rvc").bootAt(0x800000FCu)->run()); + redo(REDO,RiscvTest("rv32uc-p-rvc").withRiscvRef()->bootAt(0x800000FCu)->run()); #endif #if defined(CSR) && !defined(CSR_SKIP_TEST) diff --git a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala index 7f37a622..163460d8 100644 --- a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala +++ b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala @@ -55,13 +55,13 @@ class FpuTest extends FunSuite{ } def testP(p : FpuParameter){ - val portCount = 1 + val portCount = 4 val config = SimConfig config.allOptimisation // if(p.withDouble) config.withFstWave config.compile(new FpuCore(portCount, p){ - for(i <- 0 until portCount) out(Bits(5 bits)).setName(s"flagAcc$i") := io.port(i).completion.flag.asBits + for(i <- 0 until portCount) out(Bits(5 bits)).setName(s"flagAcc$i") := io.port(i).completion.flags.asBits setDefinitionName("FpuCore"+ (if(p.withDouble) "Double" else "")) }).doSim(seed = 42){ dut => dut.clockDomain.forkStimulus(10) @@ -228,8 +228,10 @@ class FpuTest extends FunSuite{ val flagAggregated = dut.reflectBaseType(s"flagAcc$id").asInstanceOf[Bits] dut.clockDomain.onSamplings{ val c = dut.io.port(id).completion - pendingMiaou -= c.count.toInt - flagAccumulator |= flagAggregated.toInt + if(c.valid.toBoolean) { + pendingMiaou -= 1 + flagAccumulator |= flagAggregated.toInt + } dut.writeback.randomSim.randomize() } @@ -242,6 +244,9 @@ class FpuTest extends FunSuite{ StreamMonitor(dut.io.port(id)rsp, dut.clockDomain){payload => + pendingMiaou -= 1 + if(payload.NV.toBoolean) flagAccumulator |= 1 << 4 + if(payload.NX.toBoolean) flagAccumulator |= 1 << 0 rspQueue.dequeue().apply(payload) } From a6e89fe05cf1232e82b28d5efbee1bdc92f4d227 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 19 Feb 2021 17:55:56 +0100 Subject: [PATCH 594/951] fpu vex regression goldenModel can now assert FPU interface --- .../scala/vexriscv/plugin/FpuPlugin.scala | 69 ++++- src/test/cpp/regression/main.cpp | 245 ++++++++++++++++-- 2 files changed, 284 insertions(+), 30 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/FpuPlugin.scala b/src/main/scala/vexriscv/plugin/FpuPlugin.scala index decf981c..c8af1d91 100644 --- a/src/main/scala/vexriscv/plugin/FpuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/FpuPlugin.scala @@ -1,11 +1,14 @@ package vexriscv.plugin import spinal.core._ +import spinal.core.internals.{BoolLiteral, Literal} import spinal.lib._ import vexriscv._ import vexriscv.Riscv._ import vexriscv.ip.fpu._ +import scala.collection.mutable.ArrayBuffer + class FpuPlugin(externalFpu : Boolean = false, p : FpuParameter) extends Plugin[VexRiscv]{ @@ -150,6 +153,68 @@ class FpuPlugin(externalFpu : Boolean = false, dBusEncoding.addLoadWordEncoding(FLD) dBusEncoding.addStoreWordEncoding(FSD) } + + exposeEncoding() + } + + def exposeEncoding(): Unit ={ + val d = pipeline.service(classOf[DecoderSimplePlugin]) + val commits, rsps, rs1, commitsN, rspsN, rs1N = ArrayBuffer[MaskedLiteral]() + def filter(encoding : Int, list : ArrayBuffer[MaskedLiteral]) = list.filter(e => (e.value & 0x7F) == encoding) + def filterNotLs(list : ArrayBuffer[MaskedLiteral]) = list.filter(e => !List(0x7, 0x27).contains(e.value & 0x7F)) + + for((key, t) <- d.encodings; if(t.map(_._1).contains(FPU_ENABLE)); + (s, v) <- t){ + def isSet = v.head.source.asInstanceOf[Literal].getValue == 1 + if(s == FPU_COMMIT) (if(isSet)commits += key else commitsN += key) + if(s == FPU_RSP) (if(isSet)rsps += key else rspsN += key) + if(s == pipeline.config.RS1_USE) (if(isSet)rs1 += key else rs1N += key) + } + +// println("COMMIT => ") +// filter(0x53, commits).foreach(println) +// println("COMMITN => ") +// filter(0x53, commitsN).foreach(println) +// println("RSP => ") +// filter(0x53, rsps).foreach(println) +// println("RSPN => ") +// filter(0x53, rspsN).foreach(println) + + val commitLut, rspLut, rs1Lut = Array.fill(32)(false) + filter(0x53,commits).foreach{m => + val idx = (m.value >> 27).toInt + commitLut(idx) = true + } + filter(0x53,commitsN).foreach{m => + val idx = (m.value >> 27).toInt + assert(!commitLut(idx)) + } + println("COMMIT => ") + println(commitLut.mkString(",")) + + + filter(0x53,rsps).foreach{m => + val idx = (m.value >> 27).toInt + rspLut(idx) = true + } + filter(0x53,rspsN).foreach{m => + val idx = (m.value >> 27).toInt + assert(!rspLut(idx)) + } + println("RSP => ") + println(rspLut.mkString(",")) + + filter(0x53,rs1).foreach{m => + val idx = (m.value >> 27).toInt + rs1Lut(idx) = true + } + filter(0x53,rs1N).foreach{m => + val idx = (m.value >> 27).toInt + assert(!rs1Lut(idx)) + } + println("rs1 => ") + println(rs1Lut.mkString(",")) + } override def build(pipeline: VexRiscv): Unit = { @@ -228,7 +293,7 @@ class FpuPlugin(externalFpu : Boolean = false, insert(FPU_COMMIT_LOAD) := input(FPU_OPCODE) === FpuOpcode.LOAD } - writeBack plug new Area{ + writeBack plug new Area{ //WARNING IF STAGE CHANGE, update the regression rsp capture filter for the golden model (top->VexRiscv->lastStageIsFiring) import writeBack._ val dBusEncoding = pipeline.service(classOf[DBusEncodingService]) @@ -257,7 +322,7 @@ class FpuPlugin(externalFpu : Boolean = false, } // Manage $load - val commit = Stream(FpuCommit(p)) + val commit = Stream(FpuCommit(p)).addTag(Verilator.public) commit.valid := isCommit && !arbitration.isStuck commit.value(31 downto 0) := (input(FPU_COMMIT_LOAD) ? dBusEncoding.loadData()(31 downto 0) | input(RS1)) if(p.withDouble) commit.value(63 downto 32) := dBusEncoding.loadData()(63 downto 32) diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index f2cf452a..c6330a79 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -236,13 +236,42 @@ class success : public std::exception { }; #ifdef SUPERVISOR #define MSTATUS_READ_MASK 0xFFFFFFFF #else -#define MSTATUS_READ_MASK 0x1888 +#define MSTATUS_READ_MASK 0x7888 #endif +#ifdef RVF +#define STATUS_FS_MASK 0x6000 +#else +#define STATUS_FS_MASK 0x0000 +#endif + +#define FFLAGS 0x1 +#define FRM 0x2 +#define FCSR 0x3 + #define u32 uint32_t -#define u32 uint64_t +#define u64 uint64_t + +class FpuRsp{ +public: + u32 flags; + u64 value; +}; + +class FpuCommit{ +public: + u64 value; +}; + +class FpuCompletion{ +public: + u32 flags; +}; +bool fpuCommitLut[32] = {true,true,true,true,true,true,false,false,true,false,false,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,false,false,false,true,false}; +bool fpuRspLut[32] = {false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,false,false,false,true,false,false,false,true,false,false,false}; +bool fpuRs1Lut[32] = {false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,false,false,false,true,false}; class RiscvGolden { public: int32_t pc, lastPc; @@ -257,6 +286,9 @@ public: uint32_t medeleg; uint32_t mideleg; + queue fpuRsp; + queue fpuCommit; + queue fpuCompletion; union status { uint32_t raw; @@ -272,7 +304,8 @@ public: uint32_t spp : 1; uint32_t _3 : 2; uint32_t mpp : 2; - uint32_t _4 : 4; + uint32_t fs : 2; + uint32_t _4 : 2; uint32_t mprv : 1; uint32_t sum : 1; uint32_t mxr : 1; @@ -381,9 +414,18 @@ public: }; }; + union fcsr { + uint32_t raw; + struct __attribute__((packed)){ + uint32_t flags : 5; + uint32_t frm : 3; + }; + }fcsr; + bool lrscReserved; uint32_t lrscReservedAddress; + u32 fpuCompletionTockens; RiscvGolden() { pc = 0x80000000; @@ -391,7 +433,6 @@ public: for (int i = 0; i < 32; i++) regs[i] = 0; - status.raw = 0; ie.raw = 0; mtvec.raw = 0x80000020; mcause.raw = 0; @@ -401,6 +442,11 @@ public: status.raw = 0; status.mpp = 3; status.spp = 1; + #ifdef RVF + status.fs = 1; + #endif + fcsr.flags = 0; + fcsr.frm = 0; privilege = 3; medeleg = 0; mideleg = 0; @@ -410,6 +456,7 @@ public: stepCounter = 0; sbadaddr = 42; lrscReserved = false; + fpuCompletionTockens = 0; } virtual void rfWrite(int32_t address, int32_t data) { @@ -429,8 +476,8 @@ public: uint32_t mepc, sepc; virtual bool iRead(int32_t address, uint32_t *data) = 0; - virtual bool dRead(int32_t address, int32_t size, uint32_t *data) = 0; - virtual void dWrite(int32_t address, int32_t size, uint32_t data) = 0; + virtual bool dRead(int32_t address, int32_t size, uint8_t *data) = 0; + virtual void dWrite(int32_t address, int32_t size, uint8_t *data) = 0; enum AccessKind {READ,WRITE,EXECUTE,READ_WRITE}; virtual bool isMmuRegion(uint32_t v) = 0; @@ -440,11 +487,11 @@ public: *p = v; } else { Tlb tlb; - dRead((satp.ppn << 12) | ((v >> 22) << 2), 4, &tlb.raw); + dRead((satp.ppn << 12) | ((v >> 22) << 2), 4, (uint8_t*)&tlb.raw); if(!tlb.v) return true; bool superPage = true; if(!tlb.x && !tlb.r && !tlb.w){ - dRead((tlb.ppn << 12) | (((v >> 12) & 0x3FF) << 2), 4, &tlb.raw); + dRead((tlb.ppn << 12) | (((v >> 12) & 0x3FF) << 2), 4, (uint8_t*)&tlb.raw); if(!tlb.v) return true; superPage = false; } @@ -559,6 +606,13 @@ public: case SEPC: *value = sepc; break; case SSCRATCH: *value = sscratch; break; case SATP: *value = satp.raw; break; + + #ifdef RVF + case FCSR: *value = fcsr.raw; break; + case FRM: *value = fcsr.frm; break; + case FFLAGS: *value = fcsr.flags; break; + #endif + default: return true; break; } return false; @@ -590,7 +644,7 @@ public: case MEDELEG: medeleg = value & (~0x8); break; case MIDELEG: mideleg = value; break; - case SSTATUS: maskedWrite(status.raw, value,0xC0133); break; + case SSTATUS: maskedWrite(status.raw, value,0xC0133 | STATUS_FS_MASK); break; case SIP: maskedWrite(ipSoft, value,0x333); break; case SIE: maskedWrite(ie.raw, value,0x333); break; case STVEC: stvec.raw = value; break; @@ -600,6 +654,13 @@ public: case SSCRATCH: sscratch = value; break; case SATP: satp.raw = value; break; + + #ifdef RVF + case FCSR: fcsr.raw = value & 0x7F; break; + case FRM: fcsr.frm = value; break; + case FFLAGS: fcsr.flags = value; break; + #endif + default: ilegalInstruction(); return true; break; } return false; @@ -671,6 +732,13 @@ public: virtual void step() { stepCounter++; livenessStep = 0; + + while(fpuCompletionTockens != 0 && !fpuCompletion.empty()){ + FpuCompletion completion = fpuCompletion.front(); fpuCompletion.pop(); + fcsr.flags |= completion.flags; + fpuCompletionTockens -= 1; + } + #define rd32 ((i >> 7) & 0x1F) #define iBits(lo, len) ((i >> lo) & ((1 << len)-1)) #define iBitsSigned(lo, len) int32_t(i) << (32-lo-len) >> (32-len) @@ -683,6 +751,7 @@ public: #define i32_sb_imm ((iBits(8, 4) << 1) + (iBits(25,6) << 5) + (iBits(7,1) << 11) + (iSign() << 12)) #define i32_csr iBits(20, 12) #define i32_func3 iBits(12, 3) + #define i32_func7 iBits(25, 7) #define i16_addi4spn_imm ((iBits(6, 1) << 2) + (iBits(5, 1) << 3) + (iBits(11, 2) << 4) + (iBits(7, 4) << 6)) #define i16_lw_imm ((iBits(6, 1) << 2) + (iBits(10, 3) << 3) + (iBits(5, 1) << 6)) #define i16_addr2 (iBits(2,3) + 8) @@ -728,6 +797,95 @@ public: if ((i & 0x3) == 0x3) { //32 bit switch (i & 0x7F) { + #ifdef RVF + case 0x43:// RVFD + case 0x47: + case 0x4B: + case 0x4F: + case 0x53: { + u32 format = iBits(25,2); + u32 opcode = iBits(27,5); + bool withCommit = fpuCommitLut[opcode]; + bool withRsp = fpuRspLut[opcode]; + bool withRs1 = fpuRs1Lut[opcode]; + if((i & 0x7F) != 0x53) { // FMADD + withCommit = true; + withRsp = false; + } + #ifdef RVD + if(format > 1) ilegalInstruction(); + #else + if(format > 0) ilegalInstruction(); + #endif + + if(withCommit){ + FpuCommit commit = fpuCommit.front(); fpuCommit.pop(); + fpuCompletionTockens += 1; +// cout << "withRs1 " << withRs1 << " " << opcode << endl; + if(withRs1 && memcmp(&i32_rs1, &commit.value, 4)){ + cout << "FPU commit missmatch DUT=" << hex << commit.value << " REF=" << i32_rs1 << dec << endl; + fail(); + return; + } + } + if(withRsp){ + auto rsp = fpuRsp.front(); fpuRsp.pop(); + fcsr.flags |= rsp.flags; + rfWrite(rd32, (u32)rsp.value); + } + pcWrite(pc + 4); + } break; + case 0x07: { //Fpu load + uint32_t size = 1 << ((i >> 12) & 0x3); + if(size < 4) ilegalInstruction(); + #ifdef RVD + if(size > 8) ilegalInstruction(); + #else + if(format > 4) ilegalInstruction(); + #endif + auto commit = fpuCommit.front(); fpuCommit.pop(); + fpuCompletionTockens += 1; + + + uint64_t data = 0; + uint32_t address = i32_rs1 + i32_i_imm; + if(address & (size-1)){ + trap(0, 4, address); + } else { + if(v2p(address, &pAddr, READ)){ trap(0, 13, address); return; } + if(dRead(pAddr, size, (uint8_t*)&data)){ + trap(0, 5, address); + } else { + if(memcmp(&data, &commit.value, size)){ + cout << "FPU load missmatch DUT=" << hex << commit.value << " REF=" << data << dec << endl; + fail(); + } else { + pcWrite(pc + 4); + } + } + } + } break; + case 0x27: { //Fpu store + uint32_t size = 1 << ((i >> 12) & 0x3); + if(size < 4) ilegalInstruction(); + #ifdef RVD + if(size > 8) ilegalInstruction(); + #else + if(format > 4) ilegalInstruction(); + #endif + + auto rsp = fpuRsp.front(); fpuRsp.pop(); + fcsr.flags |= rsp.flags; + uint32_t address = i32_rs1 + i32_s_imm; + if(address & (size-1)){ + trap(0, 6, address); + } else { + if(v2p(address, &pAddr, WRITE)){ trap(0, 15, address); return; } + dWrite(pAddr, size, (uint8_t*) &rsp.value); + pcWrite(pc + 4); + } + } break; + #endif case 0x37:rfWrite(rd32, i & 0xFFFFF000);pcWrite(pc + 4);break; // LUI case 0x17:rfWrite(rd32, (i & 0xFFFFF000) + pc);pcWrite(pc + 4);break; //AUIPC case 0x6F:rfWrite(rd32, pc + 4);pcWrite(pc + (iBits(21, 10) << 1) + (iBits(20, 1) << 11) + (iBits(12, 8) << 12) + (iSign() << 20));break; //JAL @@ -754,7 +912,7 @@ public: trap(0, 4, address); } else { if(v2p(address, &pAddr, READ)){ trap(0, 13, address); return; } - if(dRead(pAddr, size, &data)){ + if(dRead(pAddr, size, (uint8_t*)&data)){ trap(0, 5, address); } else { switch ((i >> 12) & 0x7) { @@ -774,7 +932,7 @@ public: trap(0, 6, address); } else { if(v2p(address, &pAddr, WRITE)){ trap(0, 15, address); return; } - dWrite(pAddr, size, i32_rs2); + dWrite(pAddr, size, (uint8_t*)&i32_rs2); pcWrite(pc + 4); } }break; @@ -897,7 +1055,7 @@ public: trap(0, 4, address); } else { if(v2p(address, &pAddr, READ)){ trap(0, 13, address); return; } - if(dRead(pAddr, 4, &data)){ + if(dRead(pAddr, 4, (uint8_t*)&data)){ trap(0, 5, address); } else { lrscReserved = true; @@ -919,7 +1077,7 @@ public: bool hit = lrscReserved; #endif if(hit){ - dWrite(pAddr, 4, i32_rs2); + dWrite(pAddr, 4, (uint8_t*)&i32_rs2); } lrscReserved = false; rfWrite(rd32, !hit); @@ -941,7 +1099,7 @@ public: uint32_t pAddr; if(v2p(addr, &pAddr, READ_WRITE)){ trap(0, 15, addr); return; } - if(dRead(pAddr, 4, (uint32_t*)&readValue)){ + if(dRead(pAddr, 4, (uint8_t*)&readValue)){ trap(0, 15, addr); return; return; } @@ -958,7 +1116,7 @@ public: case 0x1C: writeValue = max((unsigned int)src, (unsigned int)readValue); break; default: ilegalInstruction(); return; break; } - dWrite(pAddr, 4, writeValue); + dWrite(pAddr, 4, (uint8_t*)&writeValue); rfWrite(rd32, readValue); pcWrite(pc + 4); #endif @@ -991,7 +1149,7 @@ public: trap(0, 4, address); } else { if(v2p(address, &pAddr, READ)){ trap(0, 13, address); return; } - if(dRead(pAddr, 4, &data)) { + if(dRead(pAddr, 4, (uint8_t*)&data)) { trap(0, 5, address); } else { rfWrite(i16_addr2, data); pcWrite(pc + 2); @@ -1004,7 +1162,7 @@ public: trap(0, 6, address); } else { if(v2p(address, &pAddr, WRITE)){ trap(0, 15, address); return; } - dWrite(pAddr, 4, i16_rf2); + dWrite(pAddr, 4, (uint8_t*)&i16_rf2); pcWrite(pc + 2); } }break; @@ -1040,7 +1198,7 @@ public: trap(0, 4, address); } else { if(v2p(address, &pAddr, READ)){ trap(0, 13, address); return; } - if(dRead(pAddr, 4, &data)){ + if(dRead(pAddr, 4,(uint8_t*) &data)){ trap(0, 5, address); } else { rfWrite(rd32, data); pcWrite(pc + 2); @@ -1070,7 +1228,7 @@ public: trap(0,6, address); } else { if(v2p(address, &pAddr, WRITE)){ trap(0, 15, address); return; } - dWrite(pAddr, 4, regs[iBits(2,5)]); pcWrite(pc + 2); + dWrite(pAddr, 4, (uint8_t*)®s[iBits(2,5)]); pcWrite(pc + 2); } }break; } @@ -1178,8 +1336,8 @@ public: return error; } - virtual bool dRead(int32_t address, int32_t size, uint32_t *data){ - if(size < 1 || size > 4){ + virtual bool dRead(int32_t address, int32_t size, uint8_t *data){ + if(size < 1 || size > 8){ cout << "dRead size=" << size << endl; fail(); } @@ -1195,28 +1353,28 @@ public: } for(int i = 0; i < size; i++){ - ((uint8_t*)data)[i] = t.data42[i]; + data[i] = t.data42[i]; } periphRead.pop(); return t.error; }else { - mem.read(address, size, (uint8_t*)data); + mem.read(address, size, data); } return false; } - virtual void dWrite(int32_t address, int32_t size, uint32_t data){ + virtual void dWrite(int32_t address, int32_t size, uint8_t *data){ if(address & (size-1) != 0) cout << "Ref did a unaligned write" << endl; if(!ws->isPerifRegion(address)){ - mem.write(address, size, (uint8_t*)&data); + mem.write(address, size, data); } if(ws->isDBusCheckedRegion(address)){ MemWrite w; w.address = address; w.size = size; for(int i = 0; i < size; i++){ - w.data42[i] = ((uint8_t*)&data)[i]; + w.data42[i] = data[i]; } periphWritesGolden.push(w); if(periphWritesGolden.size() > 10){ @@ -1566,6 +1724,37 @@ public: } } #endif + + #ifdef RVF + if(riscvRefEnable) { + if(top->VexRiscv->writeBack_FpuPlugin_commit_valid && top->VexRiscv->writeBack_FpuPlugin_commit_ready && top->VexRiscv->writeBack_FpuPlugin_commit_payload_write){ + FpuCommit c; + c.value = top->VexRiscv->writeBack_FpuPlugin_commit_payload_value; + riscvRef.fpuCommit.push(c); + } + + if(top->VexRiscv->FpuPlugin_port_rsp_valid && top->VexRiscv->FpuPlugin_port_rsp_ready && top->VexRiscv->lastStageIsFiring){ + FpuRsp c; + c.value = top->VexRiscv->FpuPlugin_port_rsp_payload_value; + c.flags = (top->VexRiscv->FpuPlugin_port_rsp_payload_NX << 0) | + (top->VexRiscv->FpuPlugin_port_rsp_payload_NV << 4); + riscvRef.fpuRsp.push(c); + } + + if(top->VexRiscv->FpuPlugin_port_completion_valid && top->VexRiscv->FpuPlugin_port_completion_payload_written){ + FpuCompletion c; + c.flags = (top->VexRiscv->FpuPlugin_port_completion_payload_flags_NX << 0) | + (top->VexRiscv->FpuPlugin_port_completion_payload_flags_UF << 1) | + (top->VexRiscv->FpuPlugin_port_completion_payload_flags_OF << 2) | + (top->VexRiscv->FpuPlugin_port_completion_payload_flags_DZ << 3) | + (top->VexRiscv->FpuPlugin_port_completion_payload_flags_NV << 4); + riscvRef.fpuCompletion.push(c); + } + } + #endif + + + if(top->VexRiscv->lastStageIsFiring){ if(riscvRefEnable) { // privilegeCounters[riscvRef.privilege]++; @@ -3871,12 +4060,12 @@ int main(int argc, char **argv, char **env) { #ifdef RVF for(const string &name : riscvTestFloat){ - redo(REDO,RiscvTest(name).bootAt(0x80000188u)->writeWord(0x80000184u, 0x00305073)->run();) + redo(REDO,RiscvTest(name).withRiscvRef()->bootAt(0x80000188u)->writeWord(0x80000184u, 0x00305073)->run();) } #endif #ifdef RVD for(const string &name : riscvTestDouble){ - redo(REDO,RiscvTest(name).bootAt(0x80000188u)->writeWord(0x80000184u, 0x00305073)->run();) + redo(REDO,RiscvTest(name).withRiscvRef()->bootAt(0x80000188u)->writeWord(0x80000184u, 0x00305073)->run();) } #endif //return 0; From b1f4c06d4ec10fddfa3d877b58112b3002eba413 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 22 Feb 2021 19:27:26 +0100 Subject: [PATCH 595/951] fpu fix arbitration/lock bugs add getVexRiscvRegressionArgs --- src/main/scala/vexriscv/Services.scala | 2 +- src/main/scala/vexriscv/TestsWorkspace.scala | 193 ++++++++++-------- src/main/scala/vexriscv/VexRiscv.scala | 13 +- .../demo/smp/VexRiscvSmpCluster.scala | 2 +- src/main/scala/vexriscv/ip/fpu/FpuCore.scala | 18 +- .../scala/vexriscv/ip/fpu/Interface.scala | 9 +- .../scala/vexriscv/plugin/BranchPlugin.scala | 1 - .../scala/vexriscv/plugin/CsrPlugin.scala | 9 +- .../vexriscv/plugin/DBusCachedPlugin.scala | 14 +- .../scala/vexriscv/plugin/FpuPlugin.scala | 28 +-- .../vexriscv/plugin/IBusCachedPlugin.scala | 13 +- .../plugin/MulDivIterativePlugin.scala | 9 +- .../scala/vexriscv/plugin/MulPlugin.scala | 7 +- src/test/cpp/regression/main.cpp | 103 ++++++---- src/test/cpp/regression/makefile | 9 + src/test/scala/vexriscv/ip/fpu/FpuTest.scala | 15 +- 16 files changed, 293 insertions(+), 152 deletions(-) diff --git a/src/main/scala/vexriscv/Services.scala b/src/main/scala/vexriscv/Services.scala index d7453d16..79a30591 100644 --- a/src/main/scala/vexriscv/Services.scala +++ b/src/main/scala/vexriscv/Services.scala @@ -8,7 +8,7 @@ import spinal.lib._ import scala.beans.BeanProperty trait JumpService{ - def createJumpInterface(stage : Stage, priority : Int = 0) : Flow[UInt] + def createJumpInterface(stage : Stage, priority : Int = 0) : Flow[UInt] //High priority win } trait IBusFetcher{ diff --git a/src/main/scala/vexriscv/TestsWorkspace.scala b/src/main/scala/vexriscv/TestsWorkspace.scala index bcda45ff..f4347f44 100644 --- a/src/main/scala/vexriscv/TestsWorkspace.scala +++ b/src/main/scala/vexriscv/TestsWorkspace.scala @@ -25,95 +25,128 @@ import spinal.lib._ import vexriscv.ip._ import spinal.lib.bus.avalon.AvalonMM import spinal.lib.eda.altera.{InterruptReceiverTag, ResetEmitterTag} +import vexriscv.demo.smp.VexRiscvSmpClusterGen import vexriscv.ip.fpu.FpuParameter // make clean all SEED=42 MMU=no STOP_ON_ERROR=yes DBUS_EXCLUSIVE=yes DBUS_INVALIDATE=yes SUPERVISOR=yes REDO=1 DHRYSTONE=yes LRSC=yes AMO=yes LINUX_REGRESSION=yes TRACE=yes TRACE_START=1000000000 FLOW_INFO=ye IBUS_DATA_WIDTH=128 DBUS_DATA_WIDTH=128 -//make clean all SEED=42 MMU=no STOP_ON_ERROR=yes DBUS_EXCLUSIVE=yes DBUS_INVALIDATE=yes SUPERVISOR=yes REDO=1 DHRYSTONE=yes LRSC=yes AMO=yes TRACE=yes TRACE_START=1000000000 FLOW_INFO=ye IBUS_DATA_WIDTH=128 DBUS_DATA_WIDTH=128 LINUX_SOC_SMP=yes VMLINUX=../../../../../buildroot/output/images/Image RAMDISK=../../../../../buildroot/output/images/rootfs.cpio DTB=../../../../../buildroot/output/images/dtb EMULATOR=../../../../../opensbi/build/platform/spinal/vexriscv/sim/smp/firmware/fw_jump.bin +// make clean all IBUS=CACHED IBUS_DATA_WIDTH=64 COMPRESSED=no DBUS=CACHED DBUS_LOAD_DATA_WIDTH=64 DBUS_STORE_DATA_WIDTH=64 LRSC=yes AMO=yes SUPERVISOR=yes DBUS_EXCLUSIVE=yes DBUS_INVALIDATE=yes MUL=yes DIV=yes RVF=yes RVD=yes DEBUG_PLUGIN=no LINUX_SOC_SMP=yes EMULATOR=$IMAGES/fw_jump.bin VMLINUX=$IMAGES/Image DTB=$IMAGES/linux.dtb RAMDISK=$IMAGES/rootfs.cpio TRACE=ye REDO=1 DEBUG=ye WITH_USER_IO=yes SEED=42 object TestsWorkspace { def main(args: Array[String]) { SpinalConfig().generateVerilog { + // make clean all REDO=10 CSR=no MMU=no COREMARK=no RVF=yes RVD=yes REDO=1 DBUS_LOAD_DATA_WIDTH=64 DBUS_STORE_DATA_WIDTH=64 DEBUG=ye TRACE=ye - val config = VexRiscvConfig( - plugins = List( - new IBusCachedPlugin( - prediction = DYNAMIC, - config = InstructionCacheConfig( - cacheSize = 4096, - bytePerLine =32, - wayCount = 1, - addressWidth = 32, - cpuDataWidth = 32, - memDataWidth = 32, - catchIllegalAccess = true, - catchAccessFault = true, - asyncTagMemory = false, - twoCycleRam = true, - twoCycleCache = true - ), - memoryTranslatorPortConfig = MmuPortConfig( - portTlbSize = 4 - ) - ), - new DBusCachedPlugin( - config = new DataCacheConfig( - cacheSize = 4096, - bytePerLine = 32, - wayCount = 1, - addressWidth = 32, - cpuDataWidth = 64, - memDataWidth = 64, - catchAccessError = true, - catchIllegal = true, - catchUnaligned = true - ), - memoryTranslatorPortConfig = MmuPortConfig( - portTlbSize = 6 - ) - ), - new MmuPlugin( - virtualRange = _(31 downto 28) === 0xC, - ioRange = _(31 downto 28) === 0xF - ), - new DecoderSimplePlugin( - catchIllegalInstruction = true - ), - new RegFilePlugin( - regFileReadyKind = plugin.SYNC, - zeroBoot = false - ), - new IntAluPlugin, - new SrcPlugin( - separatedAddSub = false, - executeInsertion = true - ), - new FullBarrelShifterPlugin, - new HazardSimplePlugin( - bypassExecute = true, - bypassMemory = true, - bypassWriteBack = true, - bypassWriteBackBuffer = true, - pessimisticUseSrc = false, - pessimisticWriteRegFile = false, - pessimisticAddressMatch = false - ), - new MulPlugin, - new DivPlugin, - new CsrPlugin(CsrPluginConfig.small(0x80000020l)), - new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))), - new BranchPlugin( - earlyBranch = false, - catchAddressMisaligned = true - ), - new YamlPlugin("cpu0.yaml") - ) - ) - config.plugins += new FpuPlugin( - externalFpu = false, - p = FpuParameter( - withDouble = true - ) +// val config = VexRiscvConfig( +// plugins = List( +// new IBusCachedPlugin( +// prediction = DYNAMIC, +// config = InstructionCacheConfig( +// cacheSize = 4096, +// bytePerLine =32, +// wayCount = 1, +// addressWidth = 32, +// cpuDataWidth = 32, +// memDataWidth = 32, +// catchIllegalAccess = true, +// catchAccessFault = true, +// asyncTagMemory = false, +// twoCycleRam = true, +// twoCycleCache = true +// ), +// memoryTranslatorPortConfig = MmuPortConfig( +// portTlbSize = 4 +// ) +// ), +// new DBusCachedPlugin( +// config = new DataCacheConfig( +// cacheSize = 4096, +// bytePerLine = 32, +// wayCount = 1, +// addressWidth = 32, +// cpuDataWidth = 64, +// memDataWidth = 64, +// catchAccessError = true, +// catchIllegal = true, +// catchUnaligned = true +// ), +// memoryTranslatorPortConfig = MmuPortConfig( +// portTlbSize = 6 +// ) +// ), +// new MmuPlugin( +// virtualRange = _(31 downto 28) === 0xC, +// ioRange = _(31 downto 28) === 0xF +// ), +// new DecoderSimplePlugin( +// catchIllegalInstruction = true +// ), +// new RegFilePlugin( +// regFileReadyKind = plugin.SYNC, +// zeroBoot = false +// ), +// new IntAluPlugin, +// new SrcPlugin( +// separatedAddSub = false, +// executeInsertion = true +// ), +// new FullBarrelShifterPlugin, +// new HazardSimplePlugin( +// bypassExecute = true, +// bypassMemory = true, +// bypassWriteBack = true, +// bypassWriteBackBuffer = true, +// pessimisticUseSrc = false, +// pessimisticWriteRegFile = false, +// pessimisticAddressMatch = false +// ), +// new MulPlugin, +// new DivPlugin, +// new CsrPlugin(CsrPluginConfig.small(0x80000020l)), +// new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))), +// new BranchPlugin( +// earlyBranch = false, +// catchAddressMisaligned = true +// ), +// new YamlPlugin("cpu0.yaml") +// ) +// ) +// config.plugins += new FpuPlugin( +// externalFpu = false, +// p = FpuParameter( +// withDouble = true +// ) +// ) + +// mkdir buildroot-build +// cd buildroot-build/ +// make O=$PWD BR2_EXTERNAL=../buildroot-spinal-saxon -C ../buildroot saxon_regression_defconfig + + // export IMAGES=/media/data/open/SaxonSoc/artyA7SmpUpdate/buildroot-regression/buildroot-build/images + // make clean all IBUS=CACHED IBUS_DATA_WIDTH=64 COMPRESSED=no DBUS=CACHED DBUS_LOAD_DATA_WIDTH=64 DBUS_STORE_DATA_WIDTH=64 LRSC=yes AMO=yes SUPERVISOR=yes DBUS_EXCLUSIVE=yes DBUS_INVALIDATE=yes MUL=yes DIV=yes RVF=yes RVD=yes DEBUG_PLUGIN=no LINUX_SOC_SMP=yes EMULATOR=$IMAGES/fw_jump.bin VMLINUX=$IMAGES/Image DTB=$IMAGES/linux.dtb RAMDISK=$IMAGES/rootfs.cpio TRACE=ye REDO=1 DEBUG=ye WITH_USER_IO=no + // make clean all IBUS=CACHED IBUS_DATA_WIDTH=64 COMPRESSED=no DBUS=CACHED DBUS_LOAD_DATA_WIDTH=64 DBUS_STORE_DATA_WIDTH=64 LRSC=yes AMO=yes SUPERVISOR=yes DBUS_EXCLUSIVE=yes DBUS_INVALIDATE=yes MUL=yes DIV=yes RVF=yes RVD=yes DEBUG_PLUGIN=no LINUX_SOC_SMP=yes EMULATOR=$IMAGES/fw_jump.bin VMLINUX=$IMAGES/Image DTB=$IMAGES/linux.dtb RAMDISK=$IMAGES/rootfs.cpio TRACE=yes REDO=1 DEBUG=ye WITH_USER_IO=no FLOW_INFO=yes TRACE_START=47000000000ll SEED=43 + // make clean all IBUS=CACHED IBUS_DATA_WIDTH=64 COMPRESSED=no DBUS=CACHED DBUS_LOAD_DATA_WIDTH=64 DBUS_STORE_DATA_WIDTH=64 LRSC=yes AMO=yes SUPERVISOR=yes DBUS_EXCLUSIVE=yes DBUS_INVALIDATE=yes MUL=yes DIV=yes RVF=yes RVD=yes DEBUG_PLUGIN=no LINUX_SOC_SMP=yes EMULATOR=$IMAGES/fw_jump.bin VMLINUX=$IMAGES/Image DTB=$IMAGES/linux.dtb RAMDISK=$IMAGES/rootfs.cpio TRACE=yes REDO=1 DEBUG=ye WITH_USER_IO=no FLOW_INFO=yes TRACE_START=47000000000ll SEED=45 + //make clean all IBUS=CACHED IBUS_DATA_WIDTH=64 COMPRESSED=no DBUS=CACHED DBUS_LOAD_DATA_WIDTH=64 DBUS_STORE_DATA_WIDTH=64 LRSC=yes AMO=yes SUPERVISOR=yes DBUS_EXCLUSIVE=yes DBUS_INVALIDATE=yes MUL=yes DIV=yes RVF=yes RVD=yes DEBUG_PLUGIN=no LINUX_SOC_SMP=yes EMULATOR=$IMAGES/fw_jump.bin VMLINUX=$IMAGES/Image DTB=$IMAGES/linux.dtb RAMDISK=$IMAGES/rootfs.cpio TRACE=yes REDO=1 DEBUG=ye WITH_USER_IO=no FLOW_INFO=yes TRACE_START=565000000ll SEED=45 + val config = VexRiscvSmpClusterGen.vexRiscvConfig( + hartId = 0, + ioRange = _ (31 downto 28) === 0xF, + resetVector = 0x80000000l, + iBusWidth = 64, + dBusWidth = 64, + loadStoreWidth = 64, + iCacheSize = 4096*2, + dCacheSize = 4096*2, + iCacheWays = 2, + dCacheWays = 2, + withFloat = true, + withDouble = true, + externalFpu = false ) + + + println("Args :") + println(config.getRegressionArgs().mkString(" ")) + + val toplevel = new VexRiscv(config) // val toplevel = new VexRiscv(configLight) // val toplevel = new VexRiscv(configTest) diff --git a/src/main/scala/vexriscv/VexRiscv.scala b/src/main/scala/vexriscv/VexRiscv.scala index 5f7865cf..77ce1c14 100644 --- a/src/main/scala/vexriscv/VexRiscv.scala +++ b/src/main/scala/vexriscv/VexRiscv.scala @@ -16,7 +16,9 @@ object VexRiscvConfig{ def apply(plugins : Seq[Plugin[VexRiscv]] = ArrayBuffer()) : VexRiscvConfig = apply(true,true,plugins) } - +trait VexRiscvRegressionArg{ + def getVexRiscvRegressionArgs() : Seq[String] +} case class VexRiscvConfig(){ var withMemoryStage = true var withWriteBackStage = true @@ -83,6 +85,15 @@ case class VexRiscvConfig(){ } object SRC1_CTRL extends Stageable(Src1CtrlEnum()) object SRC2_CTRL extends Stageable(Src2CtrlEnum()) + + def getRegressionArgs() : Seq[String] = { + val str = ArrayBuffer[String]() + plugins.foreach{ + case e : VexRiscvRegressionArg => str ++= e.getVexRiscvRegressionArgs() + case _ => + } + str + } } diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index 5b66670a..0e3018ba 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -279,7 +279,7 @@ object VexRiscvSmpClusterGen { ) if(withFloat) config.plugins += new FpuPlugin( - externalFpu = true, + externalFpu = externalFpu, p = FpuParameter(withDouble = withDouble) ) config diff --git a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala index a2410998..21b2ad7f 100644 --- a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala +++ b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala @@ -184,7 +184,8 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val commitLogic = for(source <- 0 until portCount) yield new Area{ val fire = False - val target, hit = Reg(UInt(log2Up(rfLockCount) bits)) init(0) + val target, hit = Reg(UInt(log2Up(rfLockCount+1) bits)) init(0) + val full = target + 1 === hit when(fire){ hit := hit + 1 } @@ -192,7 +193,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ commitFork.commit(source).ready := False when(commitFork.commit(source).valid) { for (lock <- rf.lock) { - when(lock.valid && lock.source === source && lock.id === hit) { + when(lock.valid && lock.source === source && lock.id === hit && !lock.commited) { fire := True lock.commited := True lock.write := commitFork.commit(source).write @@ -233,7 +234,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } val hits = List((useRs1, s0.rs1), (useRs2, s0.rs2), (useRs3, s0.rs3), (useRd, s0.rd)).map{case (use, reg) => use && rf.lock.map(l => l.valid && l.source === s0.source && l.address === reg).orR} - val hazard = hits.orR + val hazard = hits.orR || commitLogic.map(_.full).read(s0.source) when(s0.fire && useRd){ for(i <- 0 until portCount){ when(s0.source === i){ @@ -938,7 +939,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ output.roundMode := input.roundMode output.scrap := norm.scrap output.value := norm.output - output.NV := NV + output.NV := NV //TODO isn't propagated in FMA output.DZ := False decode.mulToAdd.valid := input.valid && input.add @@ -946,7 +947,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ decode.mulToAdd.rs1.mantissa := norm.output.mantissa >> 1 //FMA Precision lost decode.mulToAdd.rs1.exponent := norm.output.exponent decode.mulToAdd.rs1.sign := norm.output.sign - decode.mulToAdd.rs1.special := False //TODO + decode.mulToAdd.rs1.special := norm.output.special decode.mulToAdd.rs2 := input.rs3 decode.mulToAdd.rd := input.rd decode.mulToAdd.lockId := input.lockId @@ -1289,6 +1290,8 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ if(p.withMul) (inputs += mul.result.output) if(p.withShortPipMisc) (inputs += shortPip.rfOutput.pipelined(m2s = true)) val arbitrated = StreamArbiterFactory.lowerFirst.noLock.on(inputs) + val isCommited = rf.lock.map(_.commited).read(arbitrated.lockId) + val commited = arbitrated.haltWhen(!isCommited).toFlow } class RoundFront extends MergeInput{ @@ -1298,7 +1301,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } val roundFront = new Area { - val input = merge.arbitrated.stage() + val input = merge.commited.stage() val output = input.swapPayload(new RoundFront()) output.payload.assignSomeByName(input.payload) @@ -1328,8 +1331,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val roundBack = new Area{ val input = roundFront.output.stage() - val isCommited = rf.lock.map(_.commited).read(input.lockId) - val output = input.haltWhen(!isCommited).toFlow.swapPayload(RoundOutput()) + val output = input.swapPayload(RoundOutput()) import input.payload._ val math = p.internalFloating() diff --git a/src/main/scala/vexriscv/ip/fpu/Interface.scala b/src/main/scala/vexriscv/ip/fpu/Interface.scala index 9e021619..dd0d2f04 100644 --- a/src/main/scala/vexriscv/ip/fpu/Interface.scala +++ b/src/main/scala/vexriscv/ip/fpu/Interface.scala @@ -92,8 +92,15 @@ object FpuFormat extends SpinalEnum{ val FLOAT, DOUBLE = newElement() } -object FpuRoundMode extends SpinalEnum(defaultEncoding = binarySequential){ +object FpuRoundMode extends SpinalEnum(){ val RNE, RTZ, RDN, RUP, RMM = newElement() + defaultEncoding = SpinalEnumEncoding("opt")( + RNE -> 0, + RTZ -> 1, + RDN -> 2, + RUP -> 3, + RMM -> 4 + ) } object FpuRoundModeInstr extends SpinalEnum(){ val RNE, RTZ, RDN, RUP, RMM, DYN = newElement() diff --git a/src/main/scala/vexriscv/plugin/BranchPlugin.scala b/src/main/scala/vexriscv/plugin/BranchPlugin.scala index 9c36cf7d..53ef62d9 100644 --- a/src/main/scala/vexriscv/plugin/BranchPlugin.scala +++ b/src/main/scala/vexriscv/plugin/BranchPlugin.scala @@ -66,7 +66,6 @@ class BranchPlugin(earlyBranch : Boolean, object IS_FENCEI extends Stageable(Bool) var jumpInterface : Flow[UInt] = null - var predictionJumpInterface : Flow[UInt] = null var predictionExceptionPort : Flow[ExceptionCause] = null var branchExceptionPort : Flow[ExceptionCause] = null diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 407d8900..456d6888 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -544,7 +544,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep if(supervisorGen) { - redoInterface = pcManagerService.createJumpInterface(pipeline.execute, -1) + redoInterface = pcManagerService.createJumpInterface(pipeline.execute, 10) } exceptionPendings = Vec(Bool, pipeline.stages.length) @@ -749,12 +749,13 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep satpAccess(CSR.SATP, 31 -> satp.MODE, 22 -> satp.ASID, 0 -> satp.PPN) - if(supervisorGen) { + val satpLogic = supervisorGen generate new Area { redoInterface.valid := False redoInterface.payload := decode.input(PC) - duringWrite(CSR.SATP){ - execute.arbitration.flushNext := True + duringWrite(CSR.SATP) { redoInterface.valid := True + execute.arbitration.flushNext := True + decode.arbitration.haltByOther := True } } } diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index 9c939bff..32cfdb9f 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -33,7 +33,7 @@ class DBusCachedPlugin(val config : DataCacheConfig, dBusCmdSlavePipe : Boolean = false, dBusRspSlavePipe : Boolean = false, relaxedMemoryTranslationRegister : Boolean = false, - csrInfo : Boolean = false) extends Plugin[VexRiscv] with DBusAccessService with DBusEncodingService { + csrInfo : Boolean = false) extends Plugin[VexRiscv] with DBusAccessService with DBusEncodingService with VexRiscvRegressionArg { import config._ assert(!(config.withExternalAmo && !dBusRspSlavePipe)) assert(isPow2(cacheSize)) @@ -52,6 +52,18 @@ class DBusCachedPlugin(val config : DataCacheConfig, dBusAccess } + override def getVexRiscvRegressionArgs(): Seq[String] = { + var args = List[String]() + args :+= "DBUS=CACHED" + args :+= s"DBUS_LOAD_DATA_WIDTH=$memDataWidth" + args :+= s"DBUS_STORE_DATA_WIDTH=$cpuDataWidth" + if(withLrSc) args :+= "LRSC=yes" + if(withAmo) args :+= "AMO=yes" + if(config.withExclusive && config.withInvalidate) args ++= List("DBUS_EXCLUSIVE=yes", "DBUS_INVALIDATE=yes") + args + } + + override def addLoadWordEncoding(key : MaskedLiteral): Unit = { val decoderService = pipeline.service(classOf[DecoderService]) val cfg = pipeline.config diff --git a/src/main/scala/vexriscv/plugin/FpuPlugin.scala b/src/main/scala/vexriscv/plugin/FpuPlugin.scala index c8af1d91..1d657b43 100644 --- a/src/main/scala/vexriscv/plugin/FpuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/FpuPlugin.scala @@ -10,7 +10,7 @@ import vexriscv.ip.fpu._ import scala.collection.mutable.ArrayBuffer class FpuPlugin(externalFpu : Boolean = false, - p : FpuParameter) extends Plugin[VexRiscv]{ + p : FpuParameter) extends Plugin[VexRiscv] with VexRiscvRegressionArg { object FPU_ENABLE extends Stageable(Bool()) object FPU_COMMIT extends Stageable(Bool()) @@ -24,6 +24,13 @@ class FpuPlugin(externalFpu : Boolean = false, var port : FpuPort = null + override def getVexRiscvRegressionArgs(): Seq[String] = { + var args = List[String]() + args :+= "RVF=yes" + if(p.withDouble) args :+= "RVD=yes" + args + } + override def setup(pipeline: VexRiscv): Unit = { import pipeline.config._ @@ -154,7 +161,7 @@ class FpuPlugin(externalFpu : Boolean = false, dBusEncoding.addStoreWordEncoding(FSD) } - exposeEncoding() +// exposeEncoding() } def exposeEncoding(): Unit ={ @@ -171,15 +178,6 @@ class FpuPlugin(externalFpu : Boolean = false, if(s == pipeline.config.RS1_USE) (if(isSet)rs1 += key else rs1N += key) } -// println("COMMIT => ") -// filter(0x53, commits).foreach(println) -// println("COMMITN => ") -// filter(0x53, commitsN).foreach(println) -// println("RSP => ") -// filter(0x53, rsps).foreach(println) -// println("RSPN => ") -// filter(0x53, rspsN).foreach(println) - val commitLut, rspLut, rs1Lut = Array.fill(32)(false) filter(0x53,commits).foreach{m => val idx = (m.value >> 27).toInt @@ -256,11 +254,17 @@ class FpuPlugin(externalFpu : Boolean = false, execute.arbitration.haltByOther setWhen(csrActive && hasPending) // pessimistic val fs = Reg(Bits(2 bits)) init(1) - when(hasPending){ + val sd = fs === 3 + + when(stages.last.arbitration.isFiring && stages.last.input(FPU_ENABLE)){ fs := 3 //DIRTY } + service.rw(CSR.SSTATUS, 13, fs) service.rw(CSR.MSTATUS, 13, fs) + + service.r(CSR.SSTATUS, 31, sd) + service.r(CSR.MSTATUS, 31, sd) } decode plug new Area{ diff --git a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala index e23cec7a..9de1382a 100644 --- a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala @@ -49,15 +49,26 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l, injectorStage = (!config.twoCycleCache && !withoutInjectorStage) || injectorStage, relaxPredictorAddress = relaxPredictorAddress, fetchRedoGen = true, - predictionBuffer = predictionBuffer){ + predictionBuffer = predictionBuffer) with VexRiscvRegressionArg{ import config._ + + assert(isPow2(cacheSize)) assert(!(memoryTranslatorPortConfig != null && config.cacheSize/config.wayCount > 4096), "When the I$ is used with MMU, each way can't be bigger than a page (4096 bytes)") assert(!(withoutInjectorStage && injectorStage)) + + override def getVexRiscvRegressionArgs(): Seq[String] = { + var args = List[String]() + args :+= "IBUS=CACHED" + args :+= s"IBUS_DATA_WIDTH=$memDataWidth" + args :+= s"COMPRESSED=${if(compressedGen) "yes" else "no"}" + args + } + var iBus : InstructionCacheMemBus = null var mmuBus : MemoryTranslatorBus = null var privilegeService : PrivilegeService = null diff --git a/src/main/scala/vexriscv/plugin/MulDivIterativePlugin.scala b/src/main/scala/vexriscv/plugin/MulDivIterativePlugin.scala index da3738d7..fff12efe 100644 --- a/src/main/scala/vexriscv/plugin/MulDivIterativePlugin.scala +++ b/src/main/scala/vexriscv/plugin/MulDivIterativePlugin.scala @@ -19,9 +19,16 @@ class MulDivIterativePlugin(genMul : Boolean = true, mulUnrollFactor : Int = 1, divUnrollFactor : Int = 1, dhrystoneOpt : Boolean = false, - customMul : (UInt, UInt, Stage, VexRiscv) => Area = null) extends Plugin[VexRiscv]{ + customMul : (UInt, UInt, Stage, VexRiscv) => Area = null) extends Plugin[VexRiscv] with VexRiscvRegressionArg { import MulDivIterativePlugin._ + override def getVexRiscvRegressionArgs(): Seq[String] = { + var args = List[String]() + if(genMul) args :+= "MUL=yes" + if(genDiv) args :+= "DIV=yes" + args + } + override def setup(pipeline: VexRiscv): Unit = { import Riscv._ import pipeline.config._ diff --git a/src/main/scala/vexriscv/plugin/MulPlugin.scala b/src/main/scala/vexriscv/plugin/MulPlugin.scala index 31714e82..2a139002 100644 --- a/src/main/scala/vexriscv/plugin/MulPlugin.scala +++ b/src/main/scala/vexriscv/plugin/MulPlugin.scala @@ -5,7 +5,7 @@ import spinal.core._ import spinal.lib.KeepAttribute //Input buffer generaly avoid the FPGA synthesis to duplicate reg inside the DSP cell, which could stress timings quite much. -class MulPlugin(inputBuffer : Boolean = false) extends Plugin[VexRiscv]{ +class MulPlugin(inputBuffer : Boolean = false) extends Plugin[VexRiscv] with VexRiscvRegressionArg { object MUL_LL extends Stageable(UInt(32 bits)) object MUL_LH extends Stageable(SInt(34 bits)) object MUL_HL extends Stageable(SInt(34 bits)) @@ -15,6 +15,11 @@ class MulPlugin(inputBuffer : Boolean = false) extends Plugin[VexRiscv]{ object IS_MUL extends Stageable(Bool) + override def getVexRiscvRegressionArgs(): Seq[String] = { + List("MUL=yes") + } + + override def setup(pipeline: VexRiscv): Unit = { import Riscv._ import pipeline.config._ diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index c6330a79..ac9417b0 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -227,7 +227,8 @@ class success : public std::exception { }; #define SIP 0x144 #define SATP 0x180 - +#define UTIME 0xC01 // rdtime +#define UTIMEH 0xC81 #define SSTATUS_SIE 0x00000002 #define SSTATUS_SPIE 0x00000020 @@ -426,6 +427,7 @@ public: bool lrscReserved; uint32_t lrscReservedAddress; u32 fpuCompletionTockens; + u32 dutRfWriteValue; RiscvGolden() { pc = 0x80000000; @@ -444,6 +446,10 @@ public: status.spp = 1; #ifdef RVF status.fs = 1; + misa |= 1 << 5; + #endif + #ifdef RVD + misa |= 1 << 3; #endif fcsr.flags = 0; fcsr.frm = 0; @@ -515,10 +521,10 @@ public: } void trap(bool interrupt,int32_t cause, bool valueWrite, uint32_t value) { #ifdef FLOW_INFO - cout << "TRAP " << (interrupt ? "interrupt" : "exception") << " cause=" << cause << " PC=0x" << hex << pc << " val=0x" << hex << value << dec << endl; - if(cause == 9){ - cout << hex << " a7=0x" << regs[17] << " a0=0x" << regs[10] << " a1=0x" << regs[11] << " a2=0x" << regs[12] << dec << endl; - } +// cout << "TRAP " << (interrupt ? "interrupt" : "exception") << " cause=" << cause << " PC=0x" << hex << pc << " val=0x" << hex << value << dec << endl; +// if(cause == 9){ +// cout << hex << " a7=0x" << regs[17] << " a0=0x" << regs[10] << " a1=0x" << regs[11] << " a2=0x" << regs[12] << dec << endl; +// } #endif //Check leguality of the interrupt if(interrupt) { @@ -584,7 +590,7 @@ public: virtual bool csrRead(int32_t csr, uint32_t *value){ if(((csr >> 8) & 0x3) > privilege) return true; switch(csr){ - case MSTATUS: *value = status.raw & MSTATUS_READ_MASK; break; + case MSTATUS: *value = (status.raw | (((status.raw & 0x6000) == 0x6000) ? 0x80000000 : 0)) & MSTATUS_READ_MASK; break; case MIP: *value = getIp().raw; break; case MIE: *value = ie.raw; break; case MTVEC: *value = mtvec.raw; break; @@ -597,7 +603,7 @@ public: case MIDELEG: *value = mideleg; break; case MHARTID: *value = 0; break; - case SSTATUS: *value = status.raw & 0xC0133; break; + case SSTATUS: *value = (status.raw | (((status.raw & 0x6000) == 0x6000) ? 0x80000000 : 0)) & (0x800C0133 | STATUS_FS_MASK); break; case SIP: *value = getIp().raw & 0x333; break; case SIE: *value = ie.raw & 0x333; break; case STVEC: *value = stvec.raw; break; @@ -613,6 +619,11 @@ public: case FFLAGS: *value = fcsr.flags; break; #endif + #ifdef UTIME_INPUT + case UTIME: *value = dutRfWriteValue; break; + case UTIMEH: *value = dutRfWriteValue; break; + #endif + default: return true; break; } return false; @@ -627,12 +638,12 @@ public: return value; } - #define maskedWrite(dst, src, mask) dst=(dst & ~mask)|(src & mask); + #define maskedWrite(dst, src, mask) dst=((dst) & ~(mask))|((src) & (mask)); virtual bool csrWrite(int32_t csr, uint32_t value){ if(((csr >> 8) & 0x3) > privilege) return true; switch(csr){ - case MSTATUS: status.raw = value; break; + case MSTATUS: status.raw = value & 0x7FFFFFFF; break; case MIP: ipSoft = value; break; case MIE: ie.raw = value; break; case MTVEC: mtvec.raw = value; break; @@ -644,7 +655,7 @@ public: case MEDELEG: medeleg = value & (~0x8); break; case MIDELEG: mideleg = value; break; - case SSTATUS: maskedWrite(status.raw, value,0xC0133 | STATUS_FS_MASK); break; + case SSTATUS: maskedWrite(status.raw, value, 0xC0133 | STATUS_FS_MASK); break; case SIP: maskedWrite(ipSoft, value,0x333); break; case SIE: maskedWrite(ie.raw, value,0x333); break; case STVEC: stvec.raw = value; break; @@ -652,8 +663,7 @@ public: case STVAL: sbadaddr = value; break; case SEPC: sepc = value; break; case SSCRATCH: sscratch = value; break; - case SATP: satp.raw = value; break; - + case SATP: satp.raw = value; break; #ifdef RVF case FCSR: fcsr.raw = value & 0x7F; break; @@ -739,6 +749,7 @@ public: fpuCompletionTockens -= 1; } + #define rd32 ((i >> 7) & 0x1F) #define iBits(lo, len) ((i >> lo) & ((1 << len)-1)) #define iBitsSigned(lo, len) int32_t(i) << (32-lo-len) >> (32-len) @@ -833,6 +844,7 @@ public: fcsr.flags |= rsp.flags; rfWrite(rd32, (u32)rsp.value); } + status.fs = 3; pcWrite(pc + 4); } break; case 0x07: { //Fpu load @@ -860,6 +872,7 @@ public: cout << "FPU load missmatch DUT=" << hex << commit.value << " REF=" << data << dec << endl; fail(); } else { + status.fs = 3; pcWrite(pc + 4); } } @@ -882,6 +895,7 @@ public: } else { if(v2p(address, &pAddr, WRITE)){ trap(0, 15, address); return; } dWrite(pAddr, size, (uint8_t*) &rsp.value); + status.fs = 3; pcWrite(pc + 4); } } break; @@ -1687,10 +1701,15 @@ public: //if(mTime == mTimeCmp) printf("SIM timer tick\n"); #endif + + #ifdef UTIME_INPUT + top->utime = mTime; + #endif + currentTime = i; #ifdef FLOW_INFO - if(i % 2000000 == 0) cout << "**" << endl << "**" << endl << "**" << endl << "**" << endl << "**" << endl << "PROGRESS TRACE_START=" << i << endl; + if(i % 5000000 == 0) cout << endl << "**" << endl << "**" << endl << "PROGRESS TRACE_START=" << i << endl; #endif @@ -1764,6 +1783,7 @@ public: // cout << "- S " << privilegeCounters[1] << endl; // cout << "- M " << privilegeCounters[3] << endl; // } + riscvRef.dutRfWriteValue = top->VexRiscv->lastStageRegFileWrite_payload_data; riscvRef.step(); bool mIntTimer = false; bool mIntExt = false; @@ -2554,10 +2574,16 @@ public: virtual void onReset(){ top->dBus_cmd_ready = 1; top->dBus_rsp_valid = 0; + #ifdef DBUS_AGGREGATION + top->dBus_rsp_payload_aggregated = 0; + #endif #ifdef DBUS_INVALIDATE top->dBus_inv_valid = 0; top->dBus_ack_ready = 0; top->dBus_sync_valid = 0; + #ifdef DBUS_AGGREGATION + top->dBus_sync_payload_aggregated = 0; + #endif #endif } @@ -3700,7 +3726,7 @@ public: - virtual void dBusAccess(uint32_t addr,bool wr, uint32_t size,uint64_t mask, uint8_t *dataBytes, bool *error) { + virtual void dBusAccess(uint32_t addr,bool wr, uint32_t size, uint8_t *dataBytes, bool *error) { uint32_t *data = (uint32_t*)dataBytes; if(isPerifRegion(addr)) switch(addr){ case 0xF0010000: if(wr && *data != 0) fail(); else *data = 0; break; @@ -3733,9 +3759,9 @@ public: } } break; - default: cout << "Unmapped peripheral access : addr=0x" << hex << addr << " wr=" << wr << " mask=0x" << mask << " data=0x" << data << dec << endl; fail(); break; + default: cout << "Unmapped peripheral access : addr=0x" << hex << addr << " wr=" << wr << " data=0x" << data << dec << endl; fail(); break; } - Workspace::dBusAccess(addr,wr,size,mask,data,error); + Workspace::dBusAccess(addr,wr,size,dataBytes,error); } virtual void onStdout(char c){ @@ -4058,6 +4084,30 @@ int main(int argc, char **argv, char **env) { printf("BOOT\n"); timespec startedAt = timer_start(); + +#ifdef LINUX_SOC_SMP + { + + LinuxSocSmp soc("linuxSmp"); + #ifndef DEBUG_PLUGIN_EXTERNAL + soc.withRiscvRef(); + soc.loadBin(EMULATOR, 0x80000000); + soc.loadBin(VMLINUX, 0x80400000); + soc.loadBin(DTB, 0x80FF0000); + soc.loadBin(RAMDISK, 0x81000000); + #endif + //soc.setIStall(true); + //soc.setDStall(true); + soc.bootAt(0x80000000); + soc.run(0); +// soc.run((496300000l + 2000000) / 2); +// soc.run(438700000l/2); + return -1; + } +#endif + + + #ifdef RVF for(const string &name : riscvTestFloat){ redo(REDO,RiscvTest(name).withRiscvRef()->bootAt(0x80000188u)->writeWord(0x80000184u, 0x00305073)->run();) @@ -4141,27 +4191,6 @@ int main(int argc, char **argv, char **env) { #endif -#ifdef LINUX_SOC_SMP - { - - LinuxSocSmp soc("linuxSmp"); - #ifndef DEBUG_PLUGIN_EXTERNAL - soc.withRiscvRef(); - soc.loadBin(EMULATOR, 0x80000000); - soc.loadBin(VMLINUX, 0xC0000000); - soc.loadBin(DTB, 0xC4000000); - soc.loadBin(RAMDISK, 0xC2000000); - #endif - //soc.setIStall(true); - //soc.setDStall(true); - soc.bootAt(0x80000000); - soc.run(0); -// soc.run((496300000l + 2000000) / 2); -// soc.run(438700000l/2); - return -1; - } -#endif - diff --git a/src/test/cpp/regression/makefile b/src/test/cpp/regression/makefile index 19bee06a..b8759c9f 100644 --- a/src/test/cpp/regression/makefile +++ b/src/test/cpp/regression/makefile @@ -150,6 +150,15 @@ ifneq ($(EXTERNAL_INTERRUPT),no) endif endif +ifneq ($(shell grep utime ${VEXRISCV_FILE} -w),) + ADDCFLAGS += -CFLAGS -DUTIME_INPUT +endif + +ifneq ($(shell grep dBus_rsp_payload_aggregated ${VEXRISCV_FILE} -w),) + ADDCFLAGS += -CFLAGS -DDBUS_AGGREGATION +endif + + ifneq ($(RUN_HEX),no) ADDCFLAGS += -CFLAGS -DRUN_HEX='\"$(RUN_HEX)\"' endif diff --git a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala index 163460d8..a0c97a0a 100644 --- a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala +++ b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala @@ -55,11 +55,11 @@ class FpuTest extends FunSuite{ } def testP(p : FpuParameter){ - val portCount = 4 + val portCount = 1 val config = SimConfig config.allOptimisation -// if(p.withDouble) config.withFstWave + if(p.withDouble) config.withFstWave config.compile(new FpuCore(portCount, p){ for(i <- 0 until portCount) out(Bits(5 bits)).setName(s"flagAcc$i") := io.port(i).completion.flags.asBits setDefinitionName("FpuCore"+ (if(p.withDouble) "Double" else "")) @@ -1286,6 +1286,17 @@ class FpuTest extends FunSuite{ //TODO double <-> simple convertions if(p.withDouble) { + load(0, 1.0) + load(0, 2.0) + load(0, 2.5) + load(0, 0.75) + load(0, -5) + load(0, 0) + load(0, Double.PositiveInfinity) + load(0, Double.NaN) + dut.clockDomain.waitSampling(200) + simSuccess() + for(_ <- 0 until 10000) testSgnjF64() println("f64 sgnj done") From 47673863fb66ddc21e128361ac3a7ca1b66c2594 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 22 Feb 2021 19:27:55 +0100 Subject: [PATCH 596/951] fpu test cleaning --- src/test/scala/vexriscv/ip/fpu/FpuTest.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala index a0c97a0a..dafac842 100644 --- a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala +++ b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala @@ -55,11 +55,11 @@ class FpuTest extends FunSuite{ } def testP(p : FpuParameter){ - val portCount = 1 + val portCount = 4 val config = SimConfig config.allOptimisation - if(p.withDouble) config.withFstWave +// if(p.withDouble) config.withFstWave config.compile(new FpuCore(portCount, p){ for(i <- 0 until portCount) out(Bits(5 bits)).setName(s"flagAcc$i") := io.port(i).completion.flags.asBits setDefinitionName("FpuCore"+ (if(p.withDouble) "Double" else "")) From be81cc1e0e18ade1c1e1a73fb6c2847cbd6f8d46 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 23 Feb 2021 12:23:48 +0100 Subject: [PATCH 597/951] CfuPlugin.response_ok removed --- src/main/scala/vexriscv/plugin/CfuPlugin.scala | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/CfuPlugin.scala b/src/main/scala/vexriscv/plugin/CfuPlugin.scala index 60dd95b0..30428e55 100644 --- a/src/main/scala/vexriscv/plugin/CfuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CfuPlugin.scala @@ -49,13 +49,11 @@ case class CfuCmd( p : CfuBusParameter ) extends Bundle{ } case class CfuRsp(p : CfuBusParameter) extends Bundle{ - val response_ok = Bool() val response_id = UInt(p.CFU_REQ_RESP_ID_W bits) val outputs = Vec(Bits(p.CFU_OUTPUT_DATA_W bits), p.CFU_OUTPUTS) def weakAssignFrom(m : CfuRsp): Unit ={ def s = this - s.response_ok := m.response_ok s.response_id := m.response_id s.outputs := m.outputs } @@ -105,7 +103,6 @@ class CfuPlugin(val stageCount : Int, // assert(p.CFU_FUNCTION_ID_W == 3) var bus : CfuBus = null - var joinException : Flow[ExceptionCause] = null lazy val forkStage = pipeline.execute lazy val joinStage = pipeline.stages(Math.min(pipeline.stages.length - 1, pipeline.indexOf(forkStage) + stageCount)) @@ -121,7 +118,6 @@ class CfuPlugin(val stageCount : Int, import pipeline.config._ bus = master(CfuBus(p)) - joinException = pipeline.service(classOf[ExceptionService]).newExceptionPort(joinStage) val decoderService = pipeline.service(classOf[DecoderService]) decoderService.addDefault(CFU_ENABLE, False) @@ -207,19 +203,11 @@ class CfuPlugin(val stageCount : Int, bus.rsp.combStage() } - joinException.valid := False - joinException.code := 15 - joinException.badAddr := 0 - rsp.ready := False when(input(CFU_IN_FLIGHT)){ arbitration.haltItself setWhen(!rsp.valid) rsp.ready := !arbitration.isStuckByOthers output(REGFILE_WRITE_DATA) := rsp.outputs(0) - - when(arbitration.isValid){ - joinException.valid := !rsp.response_ok - } } } @@ -251,7 +239,6 @@ case class CfuTest() extends Component{ val bus = slave(CfuBus(CfuTest.getCfuParameter())) } io.bus.rsp.arbitrationFrom(io.bus.cmd) - io.bus.rsp.response_ok := True io.bus.rsp.response_id := io.bus.cmd.request_id io.bus.rsp.outputs(0) := ~(io.bus.cmd.inputs(0) & io.bus.cmd.inputs(1)) } @@ -320,7 +307,6 @@ case class CfuDecoder(p : CfuBusParameter, io.input.rsp.payload := io.outputs.map(_.rsp.payload).read(OHToUInt(rspHits)) if(!hasDefault) when(rspNoHit.doIt) { io.input.rsp.valid := True - io.input.rsp.response_ok := False io.input.rsp.response_id := rspNoHit.response_id } for(output <- io.outputs) output.rsp.ready := io.input.rsp.ready From de09ed3fcb3d221bce97afec5267586efb15f011 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 25 Feb 2021 15:28:38 +0100 Subject: [PATCH 598/951] fpu added exact div/sqrt implementations using iterative approaches --- src/main/scala/vexriscv/ip/fpu/FpuCore.scala | 260 +++++++++++++++++- src/main/scala/vexriscv/ip/fpu/FpuDiv.scala | 128 +++++++++ src/main/scala/vexriscv/ip/fpu/FpuSqrt.scala | 116 ++++++++ .../scala/vexriscv/ip/fpu/Interface.scala | 7 +- src/test/scala/vexriscv/ip/fpu/FpuTest.scala | 100 +++---- 5 files changed, 537 insertions(+), 74 deletions(-) create mode 100644 src/main/scala/vexriscv/ip/fpu/FpuDiv.scala create mode 100644 src/main/scala/vexriscv/ip/fpu/FpuSqrt.scala diff --git a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala index 21b2ad7f..daf78774 100644 --- a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala +++ b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala @@ -3,6 +3,7 @@ package vexriscv.ip.fpu import spinal.core._ import spinal.lib._ import spinal.lib.eda.bench.{Bench, Rtl, XilinxStdTargets} +import spinal.lib.math.UnsignedDivider import scala.collection.mutable.ArrayBuffer @@ -24,8 +25,8 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val exponentF32Infinity = exponentOne+127+1 val exponentF64Infinity = exponentOne+1023+1 - val rfLockCount = 5 - val lockIdType = HardType(UInt(log2Up(rfLockCount) bits)) + + val lockIdType = HardType(UInt(log2Up(p.rfLockCount) bits)) def whenDouble(format : FpuFormat.C)(yes : => Unit)(no : => Unit): Unit ={ if(p.withDouble) when(format === FpuFormat.DOUBLE) { yes } otherwise{ no } @@ -106,6 +107,25 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val format = p.withDouble generate FpuFormat() } + case class DivInput() extends Bundle{ + val source = Source() + val rs1, rs2 = p.internalFloating() + val rd = p.rfAddress() + val lockId = lockIdType() + val roundMode = FpuRoundMode() + val format = p.withDouble generate FpuFormat() + } + + + case class SqrtInput() extends Bundle{ + val source = Source() + val rs1 = p.internalFloating() + val rd = p.rfAddress() + val lockId = lockIdType() + val roundMode = FpuRoundMode() + val format = p.withDouble generate FpuFormat() + } + case class AddInput() extends Bundle{ val source = Source() @@ -145,11 +165,11 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val boxed = p.withDouble generate Bool() } val ram = Mem(Entry(), 32*portCount) - val lock = for(i <- 0 until rfLockCount) yield new Area{ + val lock = for(i <- 0 until p.rfLockCount) yield new Area{ val valid = RegInit(False) val source = Reg(Source()) val address = Reg(p.rfAddress) - val id = Reg(UInt(log2Up(rfLockCount) bits)) + val id = Reg(UInt(log2Up(p.rfLockCount+1) bits)) val commited = Reg(Bool) val write = Reg(Bool) } @@ -184,7 +204,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val commitLogic = for(source <- 0 until portCount) yield new Area{ val fire = False - val target, hit = Reg(UInt(log2Up(rfLockCount+1) bits)) init(0) + val target, hit = Reg(UInt(log2Up(p.rfLockCount+1) bits)) init(0) val full = target + 1 === hit when(fire){ hit := hit + 1 @@ -241,7 +261,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ commitLogic(i).target := commitLogic(i).target + 1 } } - for(i <- 0 until rfLockCount){ + for(i <- 0 until p.rfLockCount){ when(rf.lockFreeId(i)){ rf.lock(i).valid := True rf.lock(i).source := s0.source @@ -317,10 +337,31 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ divSqrt.div := input.opcode === p.Opcode.DIV } + val divHit = input.opcode === p.Opcode.DIV + val div = Stream(DivInput()) + if(p.withDiv) { + input.ready setWhen (divHit && div.ready) + div.valid := input.valid && divHit + div.payload.assignSomeByName(input.payload) + } + + val sqrtHit = input.opcode === p.Opcode.SQRT + val sqrt = Stream(SqrtInput()) + if(p.withSqrt) { + input.ready setWhen (sqrtHit && sqrt.ready) + sqrt.valid := input.valid && sqrtHit + sqrt.payload.assignSomeByName(input.payload) + } + + val fmaHit = input.opcode === p.Opcode.FMA val mulHit = input.opcode === p.Opcode.MUL || fmaHit val mul = Stream(new MulInput()) val divSqrtToMul = Stream(new MulInput()) + if(!p.withDivSqrt){ + divSqrtToMul.valid := False + divSqrtToMul.payload.assignDontCare() + } if(p.withMul) { input.ready setWhen (mulHit && mul.ready && !divSqrtToMul.valid) @@ -910,7 +951,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ // val flag = io.port(input.source).completion.flag when(forceNan) { output.setNanQuiet - NV setWhen(input.valid && (infinitynan || input.rs1.isNanSignaling || input.rs2.isNanSignaling)) + NV setWhen(infinitynan || input.rs1.isNanSignaling || input.rs2.isNanSignaling) } elsewhen(forceOverflow) { output.setInfinity } elsewhen(forceZero) { @@ -958,6 +999,145 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } } + + val div = p.withDiv generate new Area{ + val input = decode.div.halfPipe() + val haltIt = True + val output = input.haltWhen(haltIt).swapPayload(new MergeInput()) + + val dividerShift = if(p.withDouble) 0 else 1 + val divider = FpuDiv(p.internalMantissaSize + dividerShift) + divider.io.input.a := input.rs1.mantissa << dividerShift + divider.io.input.b := input.rs2.mantissa << dividerShift + val dividerResult = divider.io.output.result >> dividerShift + val dividerScrap = divider.io.output.remain =/= 0 || divider.io.output.result(0, dividerShift bits) =/= 0 + + val cmdSent = RegInit(False) setWhen(divider.io.input.fire) clearWhen(!haltIt) + divider.io.input.valid := input.valid && !cmdSent + divider.io.output.ready := input.ready + output.payload.assignSomeByName(input.payload) + + val needShift = !dividerResult.msb + val mantissa = needShift ? dividerResult(0, p.internalMantissaSize + 1 bits) | dividerResult(1, p.internalMantissaSize + 1 bits) + val scrap = dividerScrap || !needShift && dividerResult(0) + val exponentOffset = 1 << (p.internalExponentSize + (if(p.withDouble) 0 else 1)) + val exponent = input.rs1.exponent + U(exponentOffset | exponentOne) - input.rs2.exponent - U(needShift) + + output.value.setNormal + output.value.sign := input.rs1.sign ^ input.rs2.sign + output.value.exponent := exponent.resized + output.value.mantissa := mantissa + output.scrap := scrap + if(!p.withDouble) when(exponent.takeHigh(2) === 3){ output.value.exponent(p.internalExponentSize-3, 3 bits) := 7} //Handle overflow + + + + val underflowThreshold = muxDouble[UInt](input.format)(exponentOne + exponentOffset - 1023 - 53) (exponentOne + exponentOffset - 127 - 24) + val underflowExp = muxDouble[UInt](input.format)(exponentOne + exponentOffset - 1023 - 54) (exponentOne + exponentOffset - 127 - 25) + val forceUnderflow = exponent < underflowThreshold + val forceOverflow = input.rs1.isInfinity || input.rs2.isZero + val infinitynan = input.rs1.isZero && input.rs2.isZero + val forceNan = input.rs1.isNan || input.rs2.isNan || infinitynan + val forceZero = input.rs1.isZero + + + + output.NV := False + output.DZ := !forceNan && input.rs2.isZero + + when(exponent(exponent.getWidth-3, 3 bits) === 7) { output.value.exponent(p.internalExponentSize-2, 2 bits) := 3 } + + when(forceNan) { + output.value.setNanQuiet + output.NV setWhen((infinitynan || input.rs1.isNanSignaling || input.rs2.isNanSignaling)) + } elsewhen(forceOverflow) { + output.value.setInfinity + } elsewhen(forceZero) { + output.value.setZero + } elsewhen(forceUnderflow) { + output.value.exponent := underflowExp.resized + } + + + haltIt clearWhen(divider.io.output.valid) + } + + + + val sqrt = p.withSqrt generate new Area{ + val input = decode.sqrt.halfPipe() + val haltIt = True + val output = input.haltWhen(haltIt).swapPayload(new MergeInput()) + + val needShift = !input.rs1.exponent.lsb + val sqrt = FpuSqrt(p.internalMantissaSize) + sqrt.io.input.a := (needShift ? (U"1" @@ input.rs1.mantissa @@ U"0") | (U"01" @@ input.rs1.mantissa)) + + val cmdSent = RegInit(False) setWhen(sqrt.io.input.fire) clearWhen(!haltIt) + sqrt.io.input.valid := input.valid && !cmdSent + sqrt.io.output.ready := input.ready + output.payload.assignSomeByName(input.payload) + + + val scrap = sqrt.io.output.remain =/= 0 + val exponent = RegNext(exponentOne-exponentOne/2 -1 +^ (input.rs1.exponent >> 1) + U(input.rs1.exponent.lsb)) + + output.value.setNormal + output.value.sign := input.rs1.sign + output.value.exponent := exponent + output.value.mantissa := sqrt.io.output.result + output.scrap := scrap + output.NV := False + output.DZ := False + + val negative = !input.rs1.isNan && !input.rs1.isZero && input.rs1.sign + + when(input.rs1.isInfinity){ + output.value.setInfinity + } + when(negative){ + output.value.setNanQuiet + output.NV := True + } + when(input.rs1.isNan){ + output.value.setNanQuiet + output.NV := !input.rs1.isQuiet + } + when(input.rs1.isZero){ + output.value.setZero + } + + +// val underflowThreshold = muxDouble[UInt](input.format)(exponentOne + exponentOffset - 1023 - 53) (exponentOne + exponentOffset - 127 - 24) +// val underflowExp = muxDouble[UInt](input.format)(exponentOne + exponentOffset - 1023 - 54) (exponentOne + exponentOffset - 127 - 25) +// val forceUnderflow = exponent < underflowThreshold +// val forceOverflow = input.rs1.isInfinity// || input.rs2.isInfinity +// val infinitynan = input.rs1.isZero && input.rs2.isZero +// val forceNan = input.rs1.isNan || input.rs2.isNan || infinitynan +// val forceZero = input.rs1.isZero +// +// +// +// output.NV := False +// output.DZ := !forceNan && input.rs2.isZero +// +// when(exponent(exponent.getWidth-3, 3 bits) === 7) { output.value.exponent(p.internalExponentSize-2, 2 bits) := 3 } +// +// when(forceNan) { +// output.value.setNanQuiet +// output.NV setWhen((infinitynan || input.rs1.isNanSignaling || input.rs2.isNanSignaling)) +// } elsewhen(forceOverflow) { +// output.value.setInfinity +// } elsewhen(forceZero) { +// output.value.setZero +// } elsewhen(forceUnderflow) { +// output.value.exponent := underflowExp.resized +// } + + + haltIt clearWhen(sqrt.io.output.valid) + } + val divSqrt = p.withDivSqrt generate new Area { val input = decode.divSqrt.halfPipe() @@ -1263,7 +1443,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ // val flag = io.port(input.source).completion.flag - output.NV := (input.valid && (infinityNan || input.rs1.isNanSignaling || input.rs2.isNanSignaling)) + output.NV := infinityNan || input.rs1.isNanSignaling || input.rs2.isNanSignaling output.DZ := False when(forceNan) { output.value.setNanQuiet @@ -1286,6 +1466,8 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ //TODO maybe load can bypass merge and round. val inputs = ArrayBuffer[Stream[MergeInput]]() inputs += load.s1.output.stage() + if(p.withSqrt) (inputs += sqrt.output) + if(p.withDiv) (inputs += div.output) if(p.withAdd) (inputs += add.result.output) if(p.withMul) (inputs += mul.result.output) if(p.withShortPipMisc) (inputs += shortPip.rfOutput.pipelined(m2s = true)) @@ -1422,7 +1604,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } when(input.valid){ - for(i <- 0 until rfLockCount) when(input.lockId === i){ + for(i <- 0 until p.rfLockCount) when(input.lockId === i){ rf.lock(i).valid := False } } @@ -1516,19 +1698,40 @@ object FpuSynthesisBench extends App{ SpinalVerilog(new Component{ val a = Delay(in UInt(width bits), 3) val sel = Delay(in UInt(log2Up(width) bits),3) -// val result = -// val output = Delay(result, 3) + // val result = + // val output = Delay(result, 3) setDefinitionName(Rotate3.this.getName()) }) } + class Div(width : Int) extends Rtl{ + override def getName(): String = "div_" + width + override def getRtlPath(): String = getName() + ".v" + SpinalVerilog(new UnsignedDivider(width,width, false).setDefinitionName(Div.this.getName())) + } + class Add(width : Int) extends Rtl{ + override def getName(): String = "add_" + width + override def getRtlPath(): String = getName() + ".v" + SpinalVerilog(new Component{ + val a, b = in UInt(width bits) + val result = out(a + b) + setDefinitionName(Add.this.getName()) + }) + } + + class DivSqrtRtl(width : Int) extends Rtl{ + override def getName(): String = "DivSqrt_" + width + override def getRtlPath(): String = getName() + ".v" + SpinalVerilog(new FpuDiv(width).setDefinitionName(DivSqrtRtl.this.getName())) + } val rtls = ArrayBuffer[Rtl]() rtls += new Fpu( "32", portCount = 1, FpuParameter( +// withDivSqrt = false, withDouble = false ) ) @@ -1536,11 +1739,18 @@ object FpuSynthesisBench extends App{ "64", portCount = 1, FpuParameter( +// withDivSqrt = false, withDouble = true ) ) -// rtls += new Shifter(24) +// rtls += new Div(52) +// rtls += new Div(23) +// rtls += new Add(64) +// rtls += new DivSqrtRtl(52) +// rtls += new DivSqrtRtl(23) + + // rtls += new Shifter(24) // rtls += new Shifter(32) // rtls += new Shifter(52) // rtls += new Shifter(64) @@ -1557,4 +1767,28 @@ object FpuSynthesisBench extends App{ Bench(rtls, targets) -} \ No newline at end of file +} + +//Fpu_32 -> +//Artix 7 -> 136 Mhz 1471 LUT 1336 FF +//Artix 7 -> 196 Mhz 1687 LUT 1371 FF +//Fpu_64 -> +//Artix 7 -> 105 Mhz 2822 LUT 2132 FF +//Artix 7 -> 161 Mhz 3114 LUT 2272 FF +// +// +// +//Fpu_32 -> +//Artix 7 -> 128 Mhz 1693 LUT 1481 FF +//Artix 7 -> 203 Mhz 1895 LUT 1481 FF +//Fpu_64 -> +//Artix 7 -> 99 Mhz 3073 LUT 2396 FF +//Artix 7 -> 164 Mhz 3433 LUT 2432 FF + + +//Fpu_32 -> +//Artix 7 -> 112 Mhz 1790 LUT 1666 FF +//Artix 7 -> 158 Mhz 1989 LUT 1701 FF +//Fpu_64 -> +//Artix 7 -> 100 Mhz 3294 LUT 2763 FF +//Artix 7 -> 151 Mhz 3708 LUT 2904 FF \ No newline at end of file diff --git a/src/main/scala/vexriscv/ip/fpu/FpuDiv.scala b/src/main/scala/vexriscv/ip/fpu/FpuDiv.scala new file mode 100644 index 00000000..9912e3fb --- /dev/null +++ b/src/main/scala/vexriscv/ip/fpu/FpuDiv.scala @@ -0,0 +1,128 @@ +package vexriscv.ip.fpu + + +import spinal.core._ +import spinal.lib.math.{UnsignedDividerCmd, UnsignedDividerRsp} +import spinal.lib._ +import spinal.lib.sim.{StreamDriver, StreamMonitor, StreamReadyRandomizer} + +import scala.collection.mutable +import scala.util.Random + +case class FpuDivCmd(mantissaWidth : Int) extends Bundle{ + val a,b = UInt(mantissaWidth bits) +} + +case class FpuDivRsp(mantissaWidth : Int) extends Bundle{ + val result = UInt(mantissaWidth+1 + 2 bits) + val remain = UInt(mantissaWidth+1 bits) +} + +case class FpuDiv(val mantissaWidth : Int) extends Component { + assert(mantissaWidth % 2 == 0) + val io = new Bundle{ + val input = slave Stream(FpuDivCmd(mantissaWidth)) + val output = master Stream(FpuDivRsp(mantissaWidth)) + } + + val iterations = (mantissaWidth+2+2)/2 + val counter = Reg(UInt(log2Up(iterations) bits)) + val busy = RegInit(False) clearWhen(io.output.fire) + val done = RegInit(False) setWhen(busy && counter === iterations-1) clearWhen(io.output.fire) + + val shifter = Reg(UInt(mantissaWidth + 3 bits)) + val result = Reg(UInt(mantissaWidth+1+2 bits)) + + val div1, div3 = Reg(UInt(mantissaWidth+3 bits)) + val div2 = div1 |<< 1 + + val sub1 = shifter -^ div1 + val sub2 = shifter -^ div2 + val sub3 = shifter -^ div3 + + io.output.valid := done + io.output.result := (result << 0).resized + io.output.remain := (shifter >> 2).resized + io.input.ready := !busy + + when(!done){ + counter := counter + 1 + val sel = CombInit(shifter) + result := result |<< 2 + when(!sub1.msb){ + sel := sub1.resized + result(1 downto 0) := 1 + } + when(!sub2.msb){ + sel := sub2.resized + result(1 downto 0) := 2 + } + when(!sub3.msb){ + sel := sub3.resized + result(1 downto 0) := 3 + } + shifter := sel |<< 2 + } + + when(!busy){ + counter := 0 + shifter := (U"1" @@ io.input.a @@ U"").resized + div1 := (U"1" @@ io.input.b).resized + div3 := (U"1" @@ io.input.b) +^ (((U"1" @@ io.input.b)) << 1) + busy := io.input.valid + } +} + + +object FpuDivTester extends App{ + import spinal.core.sim._ + + for(w <- List(16, 20)) { + val config = SimConfig + config.withFstWave + config.compile(new FpuDiv(w)).doSim(seed=2){dut => + dut.clockDomain.forkStimulus(10) + + + val (cmdDriver, cmdQueue) = StreamDriver.queue(dut.io.input, dut.clockDomain) + val rspQueue = mutable.Queue[FpuDivRsp => Unit]() + StreamMonitor(dut.io.output, dut.clockDomain)( rspQueue.dequeue()(_)) + StreamReadyRandomizer(dut.io.output, dut.clockDomain) + + def test(a : Int, b : Int): Unit ={ + cmdQueue +={p => + p.a #= a + p.b #= b + } + rspQueue += {p => + val x = (a | (1 << dut.mantissaWidth)).toLong + val y = (b | (1 << dut.mantissaWidth)).toLong + val result = (x << dut.mantissaWidth+2) / y + val remain = (x << dut.mantissaWidth+2) % y + + assert(p.result.toLong == result, f"$x%x/$y%x=${p.result.toLong}%x instead of $result%x") + assert(p.remain.toLong == remain, f"$x%x %% $y%x=${p.remain.toLong}%x instead of $remain%x") + } + } + + val s = dut.mantissaWidth-16 + val f = (1 << dut.mantissaWidth)-1 + test(0xE000 << s, 0x8000 << s) + test(0xC000 << s, 0x4000 << s) + test(0xC835 << s, 0x4742 << s) + test(0,0) + test(0,f) + test(f,0) + test(f,f) + + for(i <- 0 until 10000){ + test(Random.nextInt(1 << dut.mantissaWidth), Random.nextInt(1 << dut.mantissaWidth)) + } + + waitUntil(rspQueue.isEmpty) + + dut.clockDomain.waitSampling(100) + + } + } +} \ No newline at end of file diff --git a/src/main/scala/vexriscv/ip/fpu/FpuSqrt.scala b/src/main/scala/vexriscv/ip/fpu/FpuSqrt.scala new file mode 100644 index 00000000..0f809059 --- /dev/null +++ b/src/main/scala/vexriscv/ip/fpu/FpuSqrt.scala @@ -0,0 +1,116 @@ +package vexriscv.ip.fpu + +import spinal.core._ +import spinal.lib._ +import spinal.lib.sim.{StreamDriver, StreamMonitor, StreamReadyRandomizer} + +import scala.collection.mutable +import scala.util.Random + +case class FpuSqrtCmd(mantissaWidth : Int) extends Bundle{ + val a = UInt(mantissaWidth+2 bits) +} + +case class FpuSqrtRsp(mantissaWidth : Int) extends Bundle{ + val result = UInt(mantissaWidth+1 bits) + val remain = UInt(mantissaWidth+5 bits) +} + +case class FpuSqrt(val mantissaWidth : Int) extends Component { + val io = new Bundle{ + val input = slave Stream(FpuSqrtCmd(mantissaWidth)) + val output = master Stream(FpuSqrtRsp(mantissaWidth)) + } + + val iterations = mantissaWidth+2 + val counter = Reg(UInt(log2Up(iterations ) bits)) + val busy = RegInit(False) clearWhen(io.output.fire) + val done = RegInit(False) setWhen(busy && counter === iterations-1) clearWhen(io.output.fire) + + val a = Reg(UInt(mantissaWidth+5 bits)) + val x = Reg(UInt(mantissaWidth bits)) + val q = Reg(UInt(mantissaWidth+1 bits)) + val t = a-(q @@ U"01") + + + io.output.valid := done + io.output.result := (q << 0).resized + io.output.remain := a + io.input.ready := !busy + + when(!done){ + counter := counter + 1 + val sel = CombInit(a) + when(!t.msb){ + sel := t.resized + } + q := (q @@ !t.msb).resized + a := (sel @@ x(widthOf(x)-2,2 bits)).resized + x := x |<< 2 + } + + when(!busy){ + q := 0 + a := io.input.a(widthOf(io.input.a)-2,2 bits).resized + x := (io.input.a).resized + counter := 0 + when(io.input.valid){ + busy := True + } + } +} + + +object FpuSqrtTester extends App{ + import spinal.core.sim._ + + for(w <- List(16)) { + val config = SimConfig + config.withFstWave + config.compile(new FpuSqrt(w)).doSim(seed=2){dut => + dut.clockDomain.forkStimulus(10) + + + val (cmdDriver, cmdQueue) = StreamDriver.queue(dut.io.input, dut.clockDomain) + val rspQueue = mutable.Queue[FpuSqrtRsp => Unit]() + StreamMonitor(dut.io.output, dut.clockDomain)( rspQueue.dequeue()(_)) + StreamReadyRandomizer(dut.io.output, dut.clockDomain) + + def test(a : Int): Unit ={ + cmdQueue +={p => + p.a #= a + } + rspQueue += {p => +// val x = (a * (1l << dut.mantissaWidth)).toLong +// val result = Math.sqrt(x).toLong/(1 << dut.mantissaWidth/2) +// val remain = a-x*x + val x = a.toDouble / (1 << dut.mantissaWidth) + val result = (Math.sqrt(x)*(1 << dut.mantissaWidth+1)).toLong + val filtred = result % (1 << dut.mantissaWidth+1) +// val remain = (a-(result*result)).toLong + assert(p.result.toLong == filtred, f"$a%x=${p.result.toLong}%x instead of $filtred%x") +// assert(p.remain.toLong == remain, f"$a%x=${p.remain.toLong}%x instead of $remain%x") + } + } + + val s = dut.mantissaWidth-16 + val f = (1 << dut.mantissaWidth)-1 +// test(121) + test(0x20000) + test(0x18000) +// test(0,0) +// test(0,f) +// test(f,0) +// test(f,f) + + for(i <- 0 until 10000){ + test(Random.nextInt(3 << dut.mantissaWidth) + (1 << dut.mantissaWidth)) + } + + waitUntil(rspQueue.isEmpty) + + dut.clockDomain.waitSampling(100) + + } + } +} \ No newline at end of file diff --git a/src/main/scala/vexriscv/ip/fpu/Interface.scala b/src/main/scala/vexriscv/ip/fpu/Interface.scala index dd0d2f04..e5a02722 100644 --- a/src/main/scala/vexriscv/ip/fpu/Interface.scala +++ b/src/main/scala/vexriscv/ip/fpu/Interface.scala @@ -50,7 +50,7 @@ case class FpuFloat(exponentSize: Int, def isInfinity = special && exponent(1 downto 0) === FpuFloat.INFINITY def isNan = special && exponent(1 downto 0) === FpuFloat.NAN def isQuiet = mantissa.msb - def isNanSignaling = special && exponent(1 downto 0) === FpuFloat.NAN && !isQuiet + def isNanSignaling = special && exponent(1 downto 0) === FpuFloat.NAN && !isQuiet def isCanonical = exponent(FpuFloat.NAN_CANONICAL_BIT) def setNormal = { special := False } @@ -118,10 +118,13 @@ object FpuRoundModeInstr extends SpinalEnum(){ case class FpuParameter( withDouble : Boolean, mulWidthA : Int = 18, mulWidthB : Int = 18, + rfLockCount : Int = 8, sim : Boolean = false, withAdd : Boolean = true, withMul : Boolean = true, - withDivSqrt : Boolean = true, + withDivSqrt : Boolean = false, + withDiv : Boolean = true, + withSqrt : Boolean = true, withShortPipMisc : Boolean = true){ val internalMantissaSize = if(withDouble) 52 else 23 diff --git a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala index dafac842..5b1a8011 100644 --- a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala +++ b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala @@ -55,11 +55,11 @@ class FpuTest extends FunSuite{ } def testP(p : FpuParameter){ - val portCount = 4 + val portCount = 1 val config = SimConfig config.allOptimisation -// if(p.withDouble) config.withFstWave +// config.withFstWave config.compile(new FpuCore(portCount, p){ for(i <- 0 until portCount) out(Bits(5 bits)).setName(s"flagAcc$i") := io.port(i).completion.flags.asBits setDefinitionName("FpuCore"+ (if(p.withDouble) "Double" else "")) @@ -724,58 +724,34 @@ class FpuTest extends FunSuite{ } } - def testSqrtExact(a : Float, ref : Float, flag : Int, rounding : FpuRoundMode.E): Unit ={ - val rs = new RegAllocator() - val rs1, rs2, rs3 = rs.allocate() - val rd = Random.nextInt(32) - load(rs1, a) - - sqrt(rd,rs1, FpuRoundMode.RNE, FpuFormat.FLOAT) - storeFloat(rd){v => - val error = Math.abs(ref-v)/ref - assert(checkFloat(ref, v), f"sqrt($a) = $v, $ref $error $rounding") - } - } - - def testDivExact(a : Float, b : Float, ref : Float, flag : Int, rounding : FpuRoundMode.E): Unit ={ - val rs = new RegAllocator() - val rs1, rs2, rs3 = rs.allocate() - val rd = Random.nextInt(32) - load(rs1, a) - load(rs2, b) - - div(rd,rs1, rs2, FpuRoundMode.RNE, FpuFormat.FLOAT) - storeFloat(rd){v => - val error = Math.abs(ref-v)/ref - assert(checkFloat(ref, v), f"div($a, $b) = $v, $ref $error $rounding") - } - } - def testSqrtF64Exact(a : Double, ref : Double, flag : Int, rounding : FpuRoundMode.E): Unit ={ val rs = new RegAllocator() val rs1, rs2, rs3 = rs.allocate() val rd = Random.nextInt(32) load(rs1, a) - sqrt(rd,rs1, FpuRoundMode.RNE, FpuFormat.DOUBLE) + sqrt(rd,rs1, rounding, FpuFormat.DOUBLE) + store(rd){v => - val error = Math.abs(ref-v)/ref - assert(checkDouble(ref, v), f"sqrt($a) = $v, $ref $error $rounding") + assert(d2b(v) == d2b(ref), f"## sqrt${a} = $v, $ref $rounding, ${d2b(a).toString(16)} ${d2b(ref).toString(16)}") } + + flagMatch(flag, ref, f"## sqrt${a} $ref $rounding") } - def testDivF64Exact(a : Double, b : Double, ref : Double, flag : Int, rounding : FpuRoundMode.E): Unit ={ + def testSqrtExact(a : Float, ref : Float, flag : Int, rounding : FpuRoundMode.E): Unit ={ val rs = new RegAllocator() val rs1, rs2, rs3 = rs.allocate() val rd = Random.nextInt(32) load(rs1, a) - load(rs2, b) - div(rd,rs1, rs2, FpuRoundMode.RNE, FpuFormat.DOUBLE) - store(rd){v => - val error = Math.abs(ref-v)/ref - assert(checkDouble(ref, v), f"div($a, $b) = $v, $ref $error $rounding") + sqrt(rd,rs1, rounding, FpuFormat.FLOAT) + + storeFloat(rd){v => + assert(d2b(v) == d2b(ref), f"## sqrt${a} = $v, $ref $rounding, ${f2b(a).toString()} ${f2b(ref).toString()}") } + + flagMatch(flag, ref, f"## sqrt${a} $ref $rounding") } @@ -1108,8 +1084,7 @@ class FpuTest extends FunSuite{ def testDiv() : Unit = { val rounding = FpuRoundMode.elements.randomPick() val (a,b,r,f) = f32.div(rounding).f32_f32_f32 - testDivExact(a, b, r, f, rounding) - flagClear() + testBinaryOp(div, a, b, r, f, rounding, "div") } def testSqrt() : Unit = { @@ -1132,7 +1107,8 @@ class FpuTest extends FunSuite{ def testDivF64() : Unit = { val rounding = FpuRoundMode.elements.randomPick() val (a,b,r,f) = f64.div(rounding).f64_f64_f64 - testDivF64Exact(a, b, r, f, rounding) + // testDivF64Exact(a, b, r, f, rounding) + testBinaryOpF64(div, a, b, r, f,rounding, "div") flagClear() } @@ -1280,22 +1256,34 @@ class FpuTest extends FunSuite{ var fxxTests = f32Tests if(p.withDouble) fxxTests ++= f64Tests - - + + for(_ <- 0 until 10000) testDiv() + println("f32 div done") + + for(_ <- 0 until 10000) testSqrt() + println("f32 sqrt done") + + + + //TODO test boxing //TODO double <-> simple convertions if(p.withDouble) { - load(0, 1.0) - load(0, 2.0) - load(0, 2.5) - load(0, 0.75) - load(0, -5) - load(0, 0) - load(0, Double.PositiveInfinity) - load(0, Double.NaN) - dut.clockDomain.waitSampling(200) - simSuccess() + testSqrtF64Exact(1.25*1.25, 1.25, 0, FpuRoundMode.RNE) + testSqrtF64Exact(1.5*1.5, 1.5, 0, FpuRoundMode.RNE) + + for(_ <- 0 until 10000) testSqrtF64() + println("f64 sqrt done") + +// testDivF64Exact(1.0, 8.0, 0.125, 0, FpuRoundMode.RNE) +// testDivF64Exact(4.0, 8.0, 0.5, 0, FpuRoundMode.RNE) +// testDivF64Exact(8.0, 8.0, 1.0, 0, FpuRoundMode.RNE) +// testDivF64Exact(1.5, 2.0, 0.75, 0, FpuRoundMode.RNE) +// testDivF64Exact(1.875, 1.5, 1.25, 0, FpuRoundMode.RNE) + + for(_ <- 0 until 10000) testDivF64() + println("f64 div done") for(_ <- 0 until 10000) testSgnjF64() println("f64 sgnj done") @@ -1338,12 +1326,6 @@ class FpuTest extends FunSuite{ println("f64 Cmp done") - for(_ <- 0 until 10000) testDivF64() - println("f64 div done") - - for(_ <- 0 until 10000) testSqrtF64() - println("f64 sqrt done") - for(_ <- 0 until 10000) testClassF64() println("f64 class done") // From de81da36eb11793f86465bc8d37f9dd3a4518490 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 25 Feb 2021 19:39:57 +0100 Subject: [PATCH 599/951] Fpu fix a few div special cases --- src/main/scala/vexriscv/ip/fpu/FpuCore.scala | 127 +++++++++++++++---- src/main/scala/vexriscv/ip/fpu/FpuDiv.scala | 12 ++ src/test/scala/vexriscv/ip/fpu/FpuTest.scala | 19 ++- 3 files changed, 134 insertions(+), 24 deletions(-) diff --git a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala index daf78774..6c73d83d 100644 --- a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala +++ b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala @@ -555,7 +555,8 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ when(isInfinity){recoded.setInfinity} when(isNan){recoded.setNan} - val output = input.haltWhen(busy).swapPayload(new MergeInput()) + val isCommited = rf.lock.map(_.commited).read(input.lockId) + val output = input.haltWhen(busy || !isCommited).swapPayload(new MergeInput()) output.source := input.source output.lockId := input.lockId output.roundMode := input.roundMode @@ -590,6 +591,9 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val rfOutput = Stream(new MergeInput()) + val isCommited = rf.lock.map(_.commited).read(input.lockId) + val output = rfOutput.haltWhen(!isCommited) + val result = p.storeLoadType().assignDontCare() val halt = False @@ -880,6 +884,8 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ case class MulSplit(offsetA : Int, offsetB : Int, widthA : Int, widthB : Int, id : Int){ val offsetC = offsetA+offsetB + val widthC = widthA + widthB + val endC = offsetC+widthC } val splitsUnordered = for(offsetA <- 0 until inWidthA by p.mulWidthA; offsetB <- 0 until inWidthB by p.mulWidthB; @@ -887,7 +893,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ widthB = (inWidthB - offsetB) min p.mulWidthB) yield { MulSplit(offsetA, offsetB, widthA, widthB, -1) } - val splits = splitsUnordered.sortWith(_.offsetC < _.offsetC).zipWithIndex.map(e => e._1.copy(id=e._2)) + val splits = splitsUnordered.sortWith(_.endC < _.endC).zipWithIndex.map(e => e._1.copy(id=e._2)) class MathWithExp extends MulInput{ val exp = UInt(p.internalExponentSize+1 bits) @@ -910,21 +916,39 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ splits.foreach(e => output.muls(e.id) := mulA(e.offsetA, e.widthA bits) * mulB(e.offsetB, e.widthB bits)) } - class MathOutput extends MathWithExp{ + val sumSplitAt = splits.size/2//splits.filter(e => e.endC <= p.internalMantissaSize).size + + class Sum1Output extends MathWithExp{ + val muls2 = Vec(splits.drop(sumSplitAt).map(e => UInt(e.widthA + e.widthB bits))) + val mulC2 = UInt(p.internalMantissaSize*2+2 bits) + } + class Sum2Output extends MathWithExp{ val mulC = UInt(p.internalMantissaSize*2+2 bits) } - val math = new Area { + val sum1 = new Area { val input = mul.output.stage() - val sum = splits.map(e => (input.muls(e.id) << e.offsetC).resize(outWidth)).reduceBalancedTree(_ + _) + val sum = splits.take(sumSplitAt).map(e => (input.muls(e.id) << e.offsetC).resize(outWidth)).reduceBalancedTree(_ + _) - val output = input.swapPayload(new MathOutput()) + val isCommited = rf.lock.map(_.commited).read(input.lockId) + val output = input.haltWhen(!isCommited).swapPayload(new Sum1Output()) + output.payload.assignSomeByName(input.payload) + output.mulC2 := sum.resized + output.muls2 := Vec(input.muls.drop(sumSplitAt)) + } + + val sum2 = new Area { + val input = sum1.output.stage() + val sum = input.mulC2 + splits.drop(sumSplitAt).map(e => (input.muls2(e.id-sumSplitAt) << e.offsetC).resize(outWidth)).reduceBalancedTree(_ + _) + + val isCommited = rf.lock.map(_.commited).read(input.lockId) + val output = input.haltWhen(!isCommited).swapPayload(new Sum2Output()) output.payload.assignSomeByName(input.payload) output.mulC := sum } val norm = new Area{ - val input = math.output.stage() + val input = sum2.output.stage() val (mulHigh, mulLow) = input.mulC.splitAt(p.internalMantissaSize-1) val scrap = mulLow =/= 0 val needShift = mulHigh.msb @@ -1003,7 +1027,8 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val div = p.withDiv generate new Area{ val input = decode.div.halfPipe() val haltIt = True - val output = input.haltWhen(haltIt).swapPayload(new MergeInput()) + val isCommited = RegNext(rf.lock.map(_.commited).read(input.lockId)) + val output = input.haltWhen(haltIt || !isCommited).swapPayload(new MergeInput()) val dividerShift = if(p.withDouble) 0 else 1 val divider = FpuDiv(p.internalMantissaSize + dividerShift) @@ -1020,7 +1045,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val needShift = !dividerResult.msb val mantissa = needShift ? dividerResult(0, p.internalMantissaSize + 1 bits) | dividerResult(1, p.internalMantissaSize + 1 bits) val scrap = dividerScrap || !needShift && dividerResult(0) - val exponentOffset = 1 << (p.internalExponentSize + (if(p.withDouble) 0 else 1)) + val exponentOffset = 1 << (p.internalExponentSize + 1) val exponent = input.rs1.exponent + U(exponentOffset | exponentOne) - input.rs2.exponent - U(needShift) output.value.setNormal @@ -1028,7 +1053,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ output.value.exponent := exponent.resized output.value.mantissa := mantissa output.scrap := scrap - if(!p.withDouble) when(exponent.takeHigh(2) === 3){ output.value.exponent(p.internalExponentSize-3, 3 bits) := 7} //Handle overflow + when(exponent.takeHigh(2) === 3){ output.value.exponent(p.internalExponentSize-3, 3 bits) := 7} //Handle overflow @@ -1036,14 +1061,14 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val underflowExp = muxDouble[UInt](input.format)(exponentOne + exponentOffset - 1023 - 54) (exponentOne + exponentOffset - 127 - 25) val forceUnderflow = exponent < underflowThreshold val forceOverflow = input.rs1.isInfinity || input.rs2.isZero - val infinitynan = input.rs1.isZero && input.rs2.isZero + val infinitynan = input.rs1.isZero && input.rs2.isZero || input.rs1.isInfinity && input.rs2.isInfinity val forceNan = input.rs1.isNan || input.rs2.isNan || infinitynan - val forceZero = input.rs1.isZero + val forceZero = input.rs1.isZero || input.rs2.isInfinity output.NV := False - output.DZ := !forceNan && input.rs2.isZero + output.DZ := !forceNan && !input.rs1.isInfinity && input.rs2.isZero when(exponent(exponent.getWidth-3, 3 bits) === 7) { output.value.exponent(p.internalExponentSize-2, 2 bits) := 3 } @@ -1067,7 +1092,8 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val sqrt = p.withSqrt generate new Area{ val input = decode.sqrt.halfPipe() val haltIt = True - val output = input.haltWhen(haltIt).swapPayload(new MergeInput()) + val isCommited = RegNext(rf.lock.map(_.commited).read(input.lockId)) + val output = input.haltWhen(haltIt || !isCommited).swapPayload(new MergeInput()) val needShift = !input.rs1.exponent.lsb val sqrt = FpuSqrt(p.internalMantissaSize) @@ -1390,7 +1416,8 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val oh = new Area { val input = math.output.stage() - val output = input.swapPayload(new OhOutput) + val isCommited = rf.lock.map(_.commited).read(input.lockId) + val output = input.haltWhen(!isCommited).swapPayload(new OhOutput) output.payload.assignSomeByName(input.payload) import input.payload._ @@ -1447,6 +1474,8 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ output.DZ := False when(forceNan) { output.value.setNanQuiet + } elsewhen (forceInfinity) { + output.value.setInfinity } elsewhen (forceZero) { output.value.setZero when(xyMantissaZero || input.rs1.isZero && input.rs2.isZero) { @@ -1455,8 +1484,6 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ when((input.rs1.sign || input.rs2.sign) && input.roundMode === FpuRoundMode.RDN) { output.value.sign := True } - } elsewhen (forceInfinity) { - output.value.setInfinity } } } @@ -1470,10 +1497,8 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ if(p.withDiv) (inputs += div.output) if(p.withAdd) (inputs += add.result.output) if(p.withMul) (inputs += mul.result.output) - if(p.withShortPipMisc) (inputs += shortPip.rfOutput.pipelined(m2s = true)) - val arbitrated = StreamArbiterFactory.lowerFirst.noLock.on(inputs) - val isCommited = rf.lock.map(_.commited).read(arbitrated.lockId) - val commited = arbitrated.haltWhen(!isCommited).toFlow + if(p.withShortPipMisc) (inputs += shortPip.output.pipelined(m2s = true)) + val arbitrated = StreamArbiterFactory.lowerFirst.noLock.on(inputs).toFlow } class RoundFront extends MergeInput{ @@ -1483,7 +1508,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } val roundFront = new Area { - val input = merge.commited.stage() + val input = merge.arbitrated.stage() val output = input.swapPayload(new RoundFront()) output.payload.assignSomeByName(input.payload) @@ -1791,4 +1816,60 @@ object FpuSynthesisBench extends App{ //Artix 7 -> 158 Mhz 1989 LUT 1701 FF //Fpu_64 -> //Artix 7 -> 100 Mhz 3294 LUT 2763 FF -//Artix 7 -> 151 Mhz 3708 LUT 2904 FF \ No newline at end of file +//Artix 7 -> 151 Mhz 3708 LUT 2904 FF + +//Fpu_32 -> +//Artix 7 -> 139 Mhz 1879 LUT 1713 FF +//Artix 7 -> 206 Mhz 2135 LUT 1723 FF +//Fpu_64 -> +//Artix 7 -> 106 Mhz 3502 LUT 2811 FF +//Artix 7 -> 163 Mhz 3905 LUT 2951 FF + +//Fpu_32 -> +//Artix 7 -> 130 Mhz 1889 LUT 1835 FF +//Artix 7 -> 210 Mhz 2131 LUT 1845 FF +//Fpu_64 -> +//Artix 7 -> 106 Mhz 3322 LUT 3023 FF +//Artix 7 -> 161 Mhz 3675 LUT 3163 FF + + +/* +testfloat -tininessafter -all1 > all1.txt +cat all1.txt | grep "Errors found in" + +testfloat -tininessafter -all2 > all2.txt +cat all2.txt | grep "Errors found in" + + +all1 => +Errors found in f32_to_ui64_rx_minMag: +Errors found in f32_to_i64_rx_minMag: +Errors found in f64_to_ui64_rx_minMag: +Errors found in f64_to_i64_rx_minMag: + +all2 => +Errors found in f32_add, rounding near_even: +Errors found in f32_add, rounding minMag: +Errors found in f32_add, rounding min: +Errors found in f32_add, rounding max: +Errors found in f32_sub, rounding near_even: +Errors found in f32_sub, rounding minMag: +Errors found in f32_sub, rounding min: +Errors found in f32_sub, rounding max: +Errors found in f32_mul, rounding near_even: +Errors found in f32_mul, rounding min: +Errors found in f32_mul, rounding max: +Errors found in f32_div, rounding near_even: +Errors found in f32_div, rounding minMag: +Errors found in f32_div, rounding min: +Errors found in f32_div, rounding max: +Errors found in f64_mul, rounding near_even: +Errors found in f64_mul, rounding min: +Errors found in f64_mul, rounding max: +Errors found in f64_div, rounding near_even: +Errors found in f64_div, rounding minMag: +Errors found in f64_div, rounding min: +Errors found in f64_div, rounding max: + + + */ \ No newline at end of file diff --git a/src/main/scala/vexriscv/ip/fpu/FpuDiv.scala b/src/main/scala/vexriscv/ip/fpu/FpuDiv.scala index 9912e3fb..7c9e713e 100644 --- a/src/main/scala/vexriscv/ip/fpu/FpuDiv.scala +++ b/src/main/scala/vexriscv/ip/fpu/FpuDiv.scala @@ -125,4 +125,16 @@ object FpuDivTester extends App{ } } +} + +object FpuDivTester2 extends App{ + val mantissaWidth = 52 + val a = BigInt(0xfffffff810000l) + val b = BigInt(0x0000000000FF0l) + val x = (a | (1l << mantissaWidth)) + val y = (b | (1l << mantissaWidth)) + val result = (x << mantissaWidth+2) / y + val remain = (x << mantissaWidth+2) % y + println("done") + } \ No newline at end of file diff --git a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala index 5b1a8011..ddc53a80 100644 --- a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala +++ b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala @@ -59,7 +59,7 @@ class FpuTest extends FunSuite{ val config = SimConfig config.allOptimisation -// config.withFstWave + config.withFstWave config.compile(new FpuCore(portCount, p){ for(i <- 0 until portCount) out(Bits(5 bits)).setName(s"flagAcc$i") := io.port(i).completion.flags.asBits setDefinitionName("FpuCore"+ (if(p.withDouble) "Double" else "")) @@ -1257,15 +1257,32 @@ class FpuTest extends FunSuite{ var fxxTests = f32Tests if(p.withDouble) fxxTests ++= f64Tests +// testBinaryOpF64(div, -2.2250738564511294E-308, 4.294967296003891E9, -5.180654E-318, 1, FpuRoundMode.RDN,"div") // ??? wtf + +// testBinaryOp(add,b2f(0x7F800000),b2f(0x1FD << 23),b2f(0x7F800000),0, FpuRoundMode.RNE,"add") + + + for(_ <- 0 until 1000000) testDivF64() + println("f64 div done") + + for(_ <- 0 until 10000) testDiv() println("f32 div done") + for(_ <- 0 until 10000) testAddF32() + for(_ <- 0 until 10000) testSubF32() + + println("Add done") + + for(_ <- 0 until 10000) testSqrt() println("f32 sqrt done") + + //TODO test boxing //TODO double <-> simple convertions if(p.withDouble) { From 81c193af1ff28021a4cb2979f17bce456b5f2be2 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 26 Feb 2021 16:32:42 +0100 Subject: [PATCH 600/951] Improve subnormal/normal rounding --- src/main/scala/vexriscv/ip/fpu/FpuCore.scala | 74 ++++++--- src/test/cpp/fpu/math/fpu_math.c | 23 +++ src/test/java/vexriscv/ip/fpu/FpuMath.java | 3 + src/test/scala/vexriscv/ip/fpu/FpuTest.scala | 166 ++++++++++++------- 4 files changed, 184 insertions(+), 82 deletions(-) diff --git a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala index 6c73d83d..76cbac08 100644 --- a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala +++ b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala @@ -1004,7 +1004,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ output.roundMode := input.roundMode output.scrap := norm.scrap output.value := norm.output - output.NV := NV //TODO isn't propagated in FMA + output.NV := NV output.DZ := False decode.mulToAdd.valid := input.valid && input.add @@ -1019,6 +1019,10 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ decode.mulToAdd.roundMode := input.roundMode if (p.withDouble) decode.mulToAdd.format := input.format + when(NV){ + decode.mulToAdd.rs1.mantissa.msb := False + } + input.ready := (input.add ? decode.mulToAdd.ready | output.ready) || input.divSqrt } } @@ -1558,7 +1562,23 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val ufThreshold = muxDouble[UInt](input.format)(exponentF64Subnormal-52+1)(exponentF32Subnormal-23+1) val ofThreshold = muxDouble[UInt](input.format)(exponentF64Infinity-1)(exponentF32Infinity-1) - when(!math.special && math.exponent <= ufSubnormalThreshold && roundAdjusted.asUInt =/= 0){ //Do not catch exact 1.17549435E-38 underflow, but, who realy care ? + //catch exact 1.17549435E-38 underflow, but, who realy care ? +// val borringCase = input.value.exponent === ufSubnormalThreshold && roundAdjusted.asUInt < U"11" +// when(!math.special && (math.exponent <= ufSubnormalThreshold || borringCase) && roundAdjusted.asUInt =/= 0){ +// uf := True +// } + val threshold = input.roundMode.mux( + FpuRoundMode.RNE -> U"110", + FpuRoundMode.RTZ -> U"110", + FpuRoundMode.RDN -> (input.value.sign ? U"101" | U"111"), + FpuRoundMode.RUP -> (input.value.sign ? U"111" | U"101"), + FpuRoundMode.RMM -> U"110" + ) + val borringRound = (input.value.mantissa(1 downto 0) ## input.scrap) + if(p.withDouble) when(input.format === FpuFormat.FLOAT) { borringRound := (input.value.mantissa(30 downto 29) ## input.value.mantissa(28 downto 0).orR)} + + val borringCase = input.value.exponent === ufSubnormalThreshold && borringRound.asUInt < threshold + when(!math.special && (math.exponent <= ufSubnormalThreshold || borringCase) && roundAdjusted.asUInt =/= 0){ uf := True } when(!math.special && math.exponent > ofThreshold){ @@ -1840,6 +1860,11 @@ cat all1.txt | grep "Errors found in" testfloat -tininessafter -all2 > all2.txt cat all2.txt | grep "Errors found in" +testfloat -tininessafter -f32_mulAdd > fma.txt + +testfloat -tininessafter -all2 -level 2 -checkall > all2.txt + + all1 => Errors found in f32_to_ui64_rx_minMag: @@ -1848,28 +1873,29 @@ Errors found in f64_to_ui64_rx_minMag: Errors found in f64_to_i64_rx_minMag: all2 => -Errors found in f32_add, rounding near_even: -Errors found in f32_add, rounding minMag: -Errors found in f32_add, rounding min: -Errors found in f32_add, rounding max: -Errors found in f32_sub, rounding near_even: -Errors found in f32_sub, rounding minMag: -Errors found in f32_sub, rounding min: -Errors found in f32_sub, rounding max: -Errors found in f32_mul, rounding near_even: -Errors found in f32_mul, rounding min: -Errors found in f32_mul, rounding max: -Errors found in f32_div, rounding near_even: -Errors found in f32_div, rounding minMag: -Errors found in f32_div, rounding min: -Errors found in f32_div, rounding max: -Errors found in f64_mul, rounding near_even: -Errors found in f64_mul, rounding min: -Errors found in f64_mul, rounding max: -Errors found in f64_div, rounding near_even: -Errors found in f64_div, rounding minMag: -Errors found in f64_div, rounding min: -Errors found in f64_div, rounding max: + + +Errors found in f32_mulAdd, rounding min: ++00.7FFFFF +67.000001 -01.000000 + => -01.000000 ...ux expected -01.000000 ....x ++67.000001 +00.7FFFFF -01.000000 + => -01.000000 ...ux expected -01.000000 ....x +-00.7FFFFF -67.000001 -01.000000 + => -01.000000 ...ux expected -01.000000 ....x +-67.000001 -00.7FFFFF -01.000000 + => -01.000000 ...ux expected -01.000000 ....x +Errors found in f32_mulAdd, rounding max: ++00.7FFFFF -67.000001 +01.000000 + => +01.000000 ...ux expected +01.000000 ....x ++67.000001 -00.7FFFFF +01.000000 + => +01.000000 ...ux expected +01.000000 ....x ++66.7FFFFE -01.000001 +01.000000 + => +01.000000 ...ux expected +01.000000 ....x +-00.7FFFFF +67.000001 +01.000000 + => +01.000000 ...ux expected +01.000000 ....x +-67.000001 +00.7FFFFF +01.000000 + => +01.000000 ...ux expected +01.000000 ....x + */ \ No newline at end of file diff --git a/src/test/cpp/fpu/math/fpu_math.c b/src/test/cpp/fpu/math/fpu_math.c index ee0b3c04..da45fe2e 100644 --- a/src/test/cpp/fpu/math/fpu_math.c +++ b/src/test/cpp/fpu/math/fpu_math.c @@ -43,6 +43,10 @@ void applyRounding(int rounding){ #define toF32(v) (*((float32_t*)&v)) #define fromF32(x) (*((float*)&(x.v))) + +#define toF64(v) (*((float64_t*)&v)) +#define fromF64(x) (*((double*)&(x.v))) + JNIEXPORT jfloat API JNICALL Java_vexriscv_ip_fpu_FpuMath_addF32(JNIEnv * env, jobject obj, jfloat a, jfloat b, jint rounding){ applyRounding(rounding); float32_t v = f32_add(toF32(a), toF32(b)); @@ -53,4 +57,23 @@ JNIEXPORT jfloat API JNICALL Java_vexriscv_ip_fpu_FpuMath_mulF32(JNIEnv * env, j applyRounding(rounding); float32_t v = f32_mul(toF32(a), toF32(b)); return fromF32(v); +} +JNIEXPORT jint API JNICALL Java_vexriscv_ip_fpu_FpuMath_mulFlagF32(JNIEnv * env, jobject obj, jfloat a, jfloat b, jint rounding){ + applyRounding(rounding); + softfloat_exceptionFlags = 0; + float32_t v = f32_mul(toF32(a), toF32(b)); + return softfloat_exceptionFlags; +} + + +JNIEXPORT jfloat API JNICALL Java_vexriscv_ip_fpu_FpuMath_d2f(JNIEnv * env, jobject obj, jdouble a, jint rounding){ + applyRounding(rounding); + float32_t v = f64_to_f32(toF64(a)); + return fromF32(v); +} +JNIEXPORT jint API JNICALL Java_vexriscv_ip_fpu_FpuMath_d2fFlag(JNIEnv * env, jobject obj, jdouble a, jint rounding){ + applyRounding(rounding); + softfloat_exceptionFlags = 0; + float32_t v = f64_to_f32(toF64(a)); + return softfloat_exceptionFlags; } \ No newline at end of file diff --git a/src/test/java/vexriscv/ip/fpu/FpuMath.java b/src/test/java/vexriscv/ip/fpu/FpuMath.java index 88da0074..51f95021 100644 --- a/src/test/java/vexriscv/ip/fpu/FpuMath.java +++ b/src/test/java/vexriscv/ip/fpu/FpuMath.java @@ -5,6 +5,9 @@ import java.io.File; public class FpuMath { public native float addF32(float a, float b, int rounding); public native float mulF32(float a, float b, int rounding); + public native int mulFlagF32(float a, float b, int rounding); + public native float d2f(double a, int rounding); + public native int d2fFlag(double a, int rounding); static{ System.load(new File("src/test/cpp/fpu/math/fpu_math.so").getAbsolutePath()); diff --git a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala index ddc53a80..6d4c1fe9 100644 --- a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala +++ b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala @@ -59,7 +59,7 @@ class FpuTest extends FunSuite{ val config = SimConfig config.allOptimisation - config.withFstWave +// config.withFstWave config.compile(new FpuCore(portCount, p){ for(i <- 0 until portCount) out(Bits(5 bits)).setName(s"flagAcc$i") := io.port(i).completion.flags.asBits setDefinitionName("FpuCore"+ (if(p.withDouble) "Double" else "")) @@ -206,18 +206,18 @@ class FpuTest extends FunSuite{ def softAssert(cond : Boolean, msg : String) = if(!cond)println(msg) def flagMatch(ref : Int, value : Float, report : String): Unit ={ - val patch = if(value.abs == 1.17549435E-38f) ref & ~2 else ref - flagMatch(patch, report) + val patch = if(value.abs == 1.17549435E-38f && false) 0x1f & ~2 else 0x1f + flagMatch(ref, report, patch) } def flagMatch(ref : Int, value : Double, report : String): Unit ={ - val patch = if(value.abs == b2d(1 << 52)) ref & ~2 else ref - flagMatch(patch, report) + val patch = if(value.abs == b2d(1 << 52) && false) 0x1f & ~2 else 0x1f + flagMatch(ref, report, patch) } - def flagMatch(ref : Int, report : String): Unit ={ + def flagMatch(ref : Int, report : String, mask : Int = 0x1f): Unit ={ waitUntil(pendingMiaou == 0) - assert(flagAccumulator == ref, s"Flag missmatch dut=$flagAccumulator ref=$ref $report") + assert((flagAccumulator & mask) == (ref & mask), s"Flag missmatch dut=$flagAccumulator ref=$ref $report") flagAccumulator = 0 } def flagClear(): Unit ={ @@ -1257,26 +1257,68 @@ class FpuTest extends FunSuite{ var fxxTests = f32Tests if(p.withDouble) fxxTests ++= f64Tests +//5071920 5225560 +// for(v <- List(-1.17549435082e-38f, 1.17549435082e-38f); +// rounding <- FpuRoundMode.elements) { +// for (i <- 0 until 2048) { +// val b = d2b(v)// 0x0010000000000000l //d2b(1.17549435082e-38) +// val s = (b - (i.toLong << 21)).toLong +// val d = b2d(s) +//// val rounding = FpuRoundMode.RNE +// testCvtF64F32Raw(d, Clib.math.d2f(d, rounding.position), Clib.math.d2fFlag(d, rounding.position), rounding) +// } +// } +// +// +// testCvtF64F32Raw(-1.1754943508051483E-38, -1.17549435E-38f, 1, FpuRoundMode.RNE) +// testCvtF64F32Raw( 1.1754943157898258E-38, 1.17549435E-38f , 3, FpuRoundMode.RMM) +// testCvtF64F32Raw( 1.1754942807573643E-38, 1.17549435E-38f , 3, FpuRoundMode.RMM) +// testCvtF64F32Raw(-1.1754943508051483E-38, -1.17549435E-38f, 1, FpuRoundMode.RMM) + + //-1.1754943508051483E-38 -1.17549435E-38 1 RNE @ 592770 + // 1.1754943157898258E-38 1.17549435E-38 3 RMM @ 2697440 + // 1.1754942807573643E-38 1.17549435E-38 3 RMM +// for(_ <- 0 until 1000000) testCvtF64F32() // 1 did not equal 3 Flag missmatch dut=1 ref=3 testCvtF64F32Raw 1.1754942807573643E-38 1.17549435E-38 RMM +// println("FCVT_D_S done") + // testBinaryOpF64(div, -2.2250738564511294E-308, 4.294967296003891E9, -5.180654E-318, 1, FpuRoundMode.RDN,"div") // ??? wtf // testBinaryOp(add,b2f(0x7F800000),b2f(0x1FD << 23),b2f(0x7F800000),0, FpuRoundMode.RNE,"add") - for(_ <- 0 until 1000000) testDivF64() - println("f64 div done") - - for(_ <- 0 until 10000) testDiv() - println("f32 div done") - - for(_ <- 0 until 10000) testAddF32() - for(_ <- 0 until 10000) testSubF32() - - println("Add done") - - - for(_ <- 0 until 10000) testSqrt() - println("f32 sqrt done") +// testBinaryOp(mul,1.1753509E-38f, 1.0001221f ,1.17549435E-38f,1, FpuRoundMode.RNE,"mul") +// +// for(i <- 0 until 10000000){ +// val rounding = FpuRoundMode.elements.randomPick() +// val (a,b,c,f) = f32.mul(rounding).f32_f32_f32 +// testBinaryOp(mul,a,b,c,f, rounding,"mul") +// } +// +// testBinaryOpF64(mul,2.781342323134002E-309, 7.999999999999999, 2.2250738585072014E-308, 3, FpuRoundMode.RNE,"mul") +//// for(i <- 0 until 10000000){ +//// val rounding = FpuRoundMode.RNE +//// val (a,b,c,f) = f64.mul(rounding).f64_f64_f64 +//// testBinaryOpF64(mul,a,b,c,f, rounding,"mul") +//// } +// for(_ <- 0 until 100000000) testMulF64() +// println("f64 Mul done") +// +// for(_ <- 0 until 10000) testDivF64() +// println("f64 div done") +// +// +// for(_ <- 0 until 10000) testDiv() +// println("f32 div done") +// +// for(_ <- 0 until 10000) testAddF32() +// for(_ <- 0 until 10000) testSubF32() +// +// println("Add done") +// +// +// for(_ <- 0 until 10000) testSqrt() +// println("f32 sqrt done") @@ -1533,8 +1575,8 @@ class FpuTest extends FunSuite{ // DoCmd.doCmd(cmd) // val math = new FpuMath //} -//// cd /media/data/open/SaxonSoc/testFloatBuild/berkeley-softfloat-3/build/Linux-x86_64-GCC -//// make clean && SPECIALIZE_TYPE=RISCV make -j$(nproc) && cp softfloat.a /media/data/open/SaxonSoc/artyA7SmpUpdate/SaxonSoc/ext/VexRiscv/src/test/cpp/fpu/math +// cd /media/data/open/SaxonSoc/testFloatBuild/berkeley-softfloat-3/build/Linux-x86_64-GCC +// make clean && SPECIALIZE_TYPE=RISCV make -j$(nproc) && cp softfloat.a /media/data/open/SaxonSoc/artyA7SmpUpdate/SaxonSoc/ext/VexRiscv/src/test/cpp/fpu/math //object FpuCompileSo extends App{ // //// val b2f = lang.Float.intBitsToFloat(_) @@ -1548,29 +1590,52 @@ class FpuTest extends FunSuite{ //// miaou ffffffff 7fffffe0 7f //// miaou 0 3ffffff0 70 = 0 // +// val b2f = lang.Float.intBitsToFloat(_) +// val b2d = lang.Double.longBitsToDouble(_) +// val f2b = lang.Float.floatToRawIntBits(_) +// val d2bOffset = BigInt("10000000000000000",16) +// def d2b(that : Double) = { +// val l = lang.Double.doubleToRawLongBits(that) +// var a = BigInt(l) +// if(l < 0) { +// a = d2bOffset + a +// } +// a +// } +// val builder =new StringBuilder() +// for(i <- 0 until 256){ +//// builder ++= (Clib.math.mulF32(1.17548538251e-38f, b2f(f2b(1.0f)+i),0)).toString + "\n" +// val b = d2b(1.17549435082e-38) +// val s = (b-(i.toLong << 25)).toLong +// val d = b2d(s) +// builder ++= f"$b $s $d => " +// builder ++= f"${d2b(d)}%x " + (Clib.math.d2fFlag(d,0)).toString + " " + d + " => " + (Clib.math.d2f(d,FpuRoundMode.RMM.position)).toString + "\n" +// } // +// Thread.sleep(400) +// println(builder.toString) // println(Clib.math.mulF32( 1.1753509E-38f, 1.0001221f, FpuRoundMode.RUP.position)) // println(Clib.math.mulF32( 1.1754945E-38f, 0.9999998f, FpuRoundMode.RUP.position)) -//// testBinaryOp(mul, 1.1753509E-38f, 1.0001221f, 1.17549435E-38f ,1, FpuRoundMode.RUP,"mul") -//// testBinaryOp(mul, 1.1754945E-38f, 0.9999998f, 1.17549435E-38f, 3, FpuRoundMode.RUP, "mul") -//// miaou ffffffff 7fffffe0 7f -//// miaou 0 3ffffff0 70 = 0 -//// miaou ffffffff 7fffff7e 7f -//// miaou 1 3fffffbf 3f = 1 -// -//// println(Clib.math.mulF32( 1.1753509E-38f, 1.0001221f, FpuRoundMode.RUP.position)) -//// println(Clib.math.mulF32( 1.469368E-39f, 7.9999995f, FpuRoundMode.RUP.position)) -//// println(Clib.math.mulF32( 1.40129846432e-45f, 7.9999995f, FpuRoundMode.RUP.position)) -//// println(Clib.math.mulF32( 2.93873587706e-39f, 7.9999995f, FpuRoundMode.RUP.position)) -//// println(Clib.math.mulF32( 1f, 7.9999995f, FpuRoundMode.RUP.position)) -// -// -//// println(Clib.math.addF32(1.00000011921f, 4.0f, FpuRoundMode.RNE.position)) -//// println(Clib.math.addF32(1.00000011921f, 4.0f, FpuRoundMode.RTZ.position)) -//// println(Clib.math.addF32(1.00000011921f, 4.0f, FpuRoundMode.RDN.position)) -//// println(Clib.math.addF32(1.00000011921f, 4.0f, FpuRoundMode.RUP.position)) +// testBinaryOp(mul, 1.1753509E-38f, 1.0001221f, 1.17549435E-38f ,1, FpuRoundMode.RUP,"mul") +// testBinaryOp(mul, 1.1754945E-38f, 0.9999998f, 1.17549435E-38f, 3, FpuRoundMode.RUP, "mul") +// miaou ffffffff 7fffffe0 7f +// miaou 0 3ffffff0 70 = 0 +// miaou ffffffff 7fffff7e 7f +// miaou 1 3fffffbf 3f = 1 + +// println(Clib.math.mulF32( 1.1753509E-38f, 1.0001221f, FpuRoundMode.RUP.position)) +// println(Clib.math.mulF32( 1.469368E-39f, 7.9999995f, FpuRoundMode.RUP.position)) +// println(Clib.math.mulF32( 1.40129846432e-45f, 7.9999995f, FpuRoundMode.RUP.position)) +// println(Clib.math.mulF32( 2.93873587706e-39f, 7.9999995f, FpuRoundMode.RUP.position)) +// println(Clib.math.mulF32( 1f, 7.9999995f, FpuRoundMode.RUP.position)) + + +// println(Clib.math.addF32(1.00000011921f, 4.0f, FpuRoundMode.RNE.position)) +// println(Clib.math.addF32(1.00000011921f, 4.0f, FpuRoundMode.RTZ.position)) +// println(Clib.math.addF32(1.00000011921f, 4.0f, FpuRoundMode.RDN.position)) +// println(Clib.math.addF32(1.00000011921f, 4.0f, FpuRoundMode.RUP.position)) //} -// + class ProcessStream(cmd : String){ import sys.process._ @@ -1590,19 +1655,4 @@ class ProcessStream(cmd : String){ buf.dequeue()() } } -// -//object TestSoftFloat extends App{ -// val p = new ProcessStream("testfloat_gen -forever f32_add") -// Thread.sleep(1000) -// println(p.next) -// println(p.next) -// println(p.next) -// println(p.next) -// println(p.next) -// Thread.sleep(1000) -// println(p.next) -// while(true) { -// Thread.sleep(10) -// println(p.next) -// } -//} + From 636d53cf639f00efa1672f5bdf2e2c3974fd08a6 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 2 Mar 2021 16:13:12 +0100 Subject: [PATCH 601/951] fpu now track commits using a counter per pipeline per port --- src/main/scala/vexriscv/ip/fpu/FpuCore.scala | 237 ++++++++++-------- .../scala/vexriscv/ip/fpu/Interface.scala | 4 +- .../scala/vexriscv/plugin/FpuPlugin.scala | 5 +- src/test/scala/vexriscv/ip/fpu/FpuTest.scala | 17 +- 4 files changed, 146 insertions(+), 117 deletions(-) diff --git a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala index 76cbac08..2dba93a0 100644 --- a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala +++ b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala @@ -26,7 +26,6 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val exponentF64Infinity = exponentOne+1023+1 - val lockIdType = HardType(UInt(log2Up(p.rfLockCount) bits)) def whenDouble(format : FpuFormat.C)(yes : => Unit)(no : => Unit): Unit ={ if(p.withDouble) when(format === FpuFormat.DOUBLE) { yes } otherwise{ no } @@ -51,7 +50,6 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ case class RfReadOutput() extends Bundle{ val source = Source() val opcode = p.Opcode() - val lockId = lockIdType() val rs1, rs2, rs3 = p.internalFloating() val rd = p.rfAddress() val arg = p.Arg() @@ -64,7 +62,6 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ case class LoadInput() extends Bundle{ val source = Source() val rd = p.rfAddress() - val lockId = lockIdType() val i2f = Bool() val arg = Bits(2 bits) val roundMode = FpuRoundMode() @@ -75,7 +72,6 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val source = Source() val opcode = p.Opcode() val rs1, rs2 = p.internalFloating() - val lockId = lockIdType() val rd = p.rfAddress() val value = Bits(32 bits) val arg = Bits(2 bits) @@ -88,7 +84,6 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val source = Source() val rs1, rs2, rs3 = p.internalFloating() val rd = p.rfAddress() - val lockId = lockIdType() val add = Bool() val divSqrt = Bool() val msb1, msb2 = Bool() //allow usage of msb bits of mul @@ -101,7 +96,6 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val source = Source() val rs1, rs2 = p.internalFloating() val rd = p.rfAddress() - val lockId = lockIdType() val div = Bool() val roundMode = FpuRoundMode() val format = p.withDouble generate FpuFormat() @@ -111,7 +105,6 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val source = Source() val rs1, rs2 = p.internalFloating() val rd = p.rfAddress() - val lockId = lockIdType() val roundMode = FpuRoundMode() val format = p.withDouble generate FpuFormat() } @@ -121,7 +114,6 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val source = Source() val rs1 = p.internalFloating() val rd = p.rfAddress() - val lockId = lockIdType() val roundMode = FpuRoundMode() val format = p.withDouble generate FpuFormat() } @@ -131,15 +123,14 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val source = Source() val rs1, rs2 = p.internalFloating() val rd = p.rfAddress() - val lockId = lockIdType() val roundMode = FpuRoundMode() val format = p.withDouble generate FpuFormat() + val needCommit = Bool() } class MergeInput() extends Bundle{ val source = Source() - val lockId = lockIdType() val rd = p.rfAddress() val value = p.writeFloating() val scrap = Bool() @@ -151,7 +142,6 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ case class RoundOutput() extends Bundle{ val source = Source() - val lockId = lockIdType() val rd = p.rfAddress() val value = p.internalFloating() val format = p.withDouble generate FpuFormat() @@ -165,16 +155,28 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val boxed = p.withDouble generate Bool() } val ram = Mem(Entry(), 32*portCount) - val lock = for(i <- 0 until p.rfLockCount) yield new Area{ - val valid = RegInit(False) - val source = Reg(Source()) - val address = Reg(p.rfAddress) - val id = Reg(UInt(log2Up(p.rfLockCount+1) bits)) - val commited = Reg(Bool) - val write = Reg(Bool) + + val init = new Area{ + val counter = Reg(UInt(6 bits)) init(0) + val done = CombInit(counter.msb) + when(!done){ + counter := counter + 1 + } + def apply(port : Flow[MemWriteCmd[Bool]]) = { + port.valid := !done + port.address := counter.resized + port.data := False + port + } } - val lockFree = !lock.map(_.valid).andR - val lockFreeId = OHMasking.first(lock.map(!_.valid)) + + val scoreboards = Array.fill(portCount)(new Area{ + val target, hit = Mem(Bool, 32) // XOR + val writes = Mem(Bool, 32) + + val targetWrite = init(target.writePort) + val hitWrite = init(hit.writePort) + }) } // val completion = for(source <- 0 until portCount) yield new Area{ @@ -202,85 +204,97 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } } - val commitLogic = for(source <- 0 until portCount) yield new Area{ - val fire = False - val target, hit = Reg(UInt(log2Up(p.rfLockCount+1) bits)) init(0) - val full = target + 1 === hit - when(fire){ - hit := hit + 1 - } + class Tracker(width : Int) extends Area{ + val counter = Reg(UInt(width bits)) init(0) + val full = counter.andR + val notEmpty = counter.orR + val inc = False + val dec = False + counter := counter + U(inc) - U(dec) + } - commitFork.commit(source).ready := False - when(commitFork.commit(source).valid) { - for (lock <- rf.lock) { - when(lock.valid && lock.source === source && lock.id === hit && !lock.commited) { - fire := True - lock.commited := True - lock.write := commitFork.commit(source).write - commitFork.commit(source).ready := True - } - } + class CommitArea(source : Int) extends Area{ + val add, mul, div, sqrt, short = new Tracker(4) + val input = commitFork.commit(source).haltWhen(List(add, mul, div, sqrt, short).map(_.full).orR).toFlow + + when(input.fire){ + add.inc setWhen(List(FpuOpcode.ADD).map(input.opcode === _).orR) + mul.inc setWhen(List(FpuOpcode.MUL, FpuOpcode.FMA).map(input.opcode === _).orR) + div.inc setWhen(List(FpuOpcode.DIV).map(input.opcode === _).orR) + sqrt.inc setWhen(List(FpuOpcode.SQRT).map(input.opcode === _).orR) + short.inc setWhen(List(FpuOpcode.SGNJ, FpuOpcode.MIN_MAX, FpuOpcode.FCVT_X_X).map(input.opcode === _).orR) + rf.scoreboards(source).writes(input.rd) := input.write } } - val read = new Area{ - val arbiter = StreamArbiterFactory.noLock.roundRobin.build(FpuCmd(p), portCount) - arbiter.io.inputs <> Vec(io.port.map(_.cmd)) + val commitLogic = for(source <- 0 until portCount) yield new CommitArea(source) - val arbiterOutput = Stream(RfReadInput()) - arbiterOutput.arbitrationFrom(arbiter.io.output) - arbiterOutput.source := arbiter.io.chosen - arbiterOutput.payload.assignSomeByName(arbiter.io.output.payload) + def commitConsume(what : CommitArea => Tracker, source : UInt, fire : Bool) : Bool = { + for(i <- 0 until portCount) what(commitLogic(i)).dec setWhen(fire && source === i) + commitLogic.map(what(_).notEmpty).read(source) + } - val s0 = arbiterOutput.pipelined(m2s = true, s2m = true) //TODO may need to remove m2s for store latency + + val scheduler = for(portId <- 0 until portCount; + scoreboard = rf.scoreboards(portId)) yield new Area{ + val input = io.port(portId).cmd.combStage() val useRs1, useRs2, useRs3, useRd = False - switch(s0.opcode){ - is(p.Opcode.LOAD) { useRd := True } - is(p.Opcode.STORE) { useRs1 := True } - is(p.Opcode.ADD) { useRd := True; useRs1 := True; useRs2 := True } - is(p.Opcode.MUL) { useRd := True; useRs1 := True; useRs2 := True } - is(p.Opcode.DIV) { useRd := True; useRs1 := True; useRs2 := True } - is(p.Opcode.SQRT) { useRd := True; useRs1 := True } - is(p.Opcode.FMA) { useRd := True; useRs1 := True; useRs2 := True; useRs3 := True } - is(p.Opcode.I2F) { useRd := True } - is(p.Opcode.F2I) { useRs1 := True } - is(p.Opcode.MIN_MAX) { useRd := True; useRs1 := True; useRs2 := True } - is(p.Opcode.CMP) { useRs1 := True; useRs2 := True } - is(p.Opcode.SGNJ) { useRd := True; useRs1 := True; useRs2 := True } - is(p.Opcode.FMV_X_W) { useRs1 := True } - is(p.Opcode.FMV_W_X) { useRd := True } - is(p.Opcode.FCLASS ) { useRs1 := True } + switch(input.opcode){ + is(p.Opcode.LOAD) { useRd := True } + is(p.Opcode.STORE) { useRs1 := True } + is(p.Opcode.ADD) { useRd := True; useRs1 := True; useRs2 := True } + is(p.Opcode.MUL) { useRd := True; useRs1 := True; useRs2 := True } + is(p.Opcode.DIV) { useRd := True; useRs1 := True; useRs2 := True } + is(p.Opcode.SQRT) { useRd := True; useRs1 := True } + is(p.Opcode.FMA) { useRd := True; useRs1 := True; useRs2 := True; useRs3 := True } + is(p.Opcode.I2F) { useRd := True } + is(p.Opcode.F2I) { useRs1 := True } + is(p.Opcode.MIN_MAX) { useRd := True; useRs1 := True; useRs2 := True } + is(p.Opcode.CMP) { useRs1 := True; useRs2 := True } + is(p.Opcode.SGNJ) { useRd := True; useRs1 := True; useRs2 := True } + is(p.Opcode.FMV_X_W) { useRs1 := True } + is(p.Opcode.FMV_W_X) { useRd := True } + is(p.Opcode.FCLASS ) { useRs1 := True } is(p.Opcode.FCVT_X_X ) { useRd := True; useRs1 := True } } - val hits = List((useRs1, s0.rs1), (useRs2, s0.rs2), (useRs3, s0.rs3), (useRd, s0.rd)).map{case (use, reg) => use && rf.lock.map(l => l.valid && l.source === s0.source && l.address === reg).orR} - val hazard = hits.orR || commitLogic.map(_.full).read(s0.source) - when(s0.fire && useRd){ - for(i <- 0 until portCount){ - when(s0.source === i){ - commitLogic(i).target := commitLogic(i).target + 1 - } - } - for(i <- 0 until p.rfLockCount){ - when(rf.lockFreeId(i)){ - rf.lock(i).valid := True - rf.lock(i).source := s0.source - rf.lock(i).address := s0.rd - rf.lock(i).id := commitLogic.map(_.target).read(s0.source) - rf.lock(i).commited := False - } - } - } + val uses = List(useRs1, useRs2, useRs3, useRd) + val regs = List(input.rs1, input.rs2, input.rs3, input.rd) + val rfHits = regs.map(scoreboard.hit.readAsync(_)) + val rfTargets = regs.map(scoreboard.target.readAsync(_)) + val rfBusy = (rfHits, rfTargets).zipped.map(_ ^ _) - val s1 = s0.haltWhen(hazard || !rf.lockFree).m2sPipe() + val hits = (0 to 3).map(id => uses(id) && rfBusy(id)) + val hazard = hits.orR || !rf.init.done + val output = input.haltWhen(hazard) + when(input.valid && rf.init.done){ + scoreboard.targetWrite.address := input.rd + scoreboard.targetWrite.data := !rfTargets.last + } + when(output.fire && useRd){ + scoreboard.targetWrite.valid := True + } + } + + + val cmdArbiter = new Area{ + val arbiter = StreamArbiterFactory.noLock.roundRobin.build(FpuCmd(p), portCount) + arbiter.io.inputs <> Vec(scheduler.map(_.output)) + + val output = arbiter.io.output.swapPayload(RfReadInput()) + output.source := arbiter.io.chosen + output.payload.assignSomeByName(arbiter.io.output.payload) + } + + val read = new Area{ + val s0 = cmdArbiter.output.pipelined(m2s = true, s2m = true) //TODO may need to remove m2s for store latency + val s1 = s0.m2sPipe() val output = s1.swapPayload(RfReadOutput()) - val s1LockId = RegNextWhen(OHToUInt(rf.lockFreeId), !output.isStall) val rs1Entry = rf.ram.readSync(s0.source @@ s0.rs1,enable = !output.isStall) val rs2Entry = rf.ram.readSync(s0.source @@ s0.rs2,enable = !output.isStall) val rs3Entry = rf.ram.readSync(s0.source @@ s0.rs3,enable = !output.isStall) output.source := s1.source output.opcode := s1.opcode - output.lockId := s1LockId output.arg := s1.arg output.roundMode := s1.roundMode output.rd := s1.rd @@ -397,6 +411,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ add.payload.assignSomeByName(input.payload) add.rs2.sign.allowOverride; add.rs2.sign := input.rs2.sign ^ input.arg(0) + add.needCommit := True } } } @@ -405,7 +420,6 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ case class S0() extends Bundle{ val source = Source() - val lockId = lockIdType() val rd = p.rfAddress() val value = p.storeLoadType() val i2f = Bool() @@ -416,15 +430,15 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val s0 = new Area{ val input = decode.load.pipelined(m2s = true, s2m = true) - val filtred = commitFork.load.map(port => port.takeWhen(port.sync)) + val filtred = commitFork.load.map(port => port.takeWhen(List(FpuOpcode.LOAD, FpuOpcode.FMV_W_X, FpuOpcode.I2F).map(_ === port.opcode).orR)) def feed = filtred(input.source) val hazard = !feed.valid + val output = input.haltWhen(hazard).swapPayload(S0()) filtred.foreach(_.ready := False) feed.ready := input.valid && output.ready output.source := input.source - output.lockId := input.lockId output.rd := input.rd output.value := feed.value output.i2f := input.i2f @@ -555,10 +569,8 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ when(isInfinity){recoded.setInfinity} when(isNan){recoded.setNan} - val isCommited = rf.lock.map(_.commited).read(input.lockId) - val output = input.haltWhen(busy || !isCommited).swapPayload(new MergeInput()) + val output = input.haltWhen(busy).swapPayload(new MergeInput()) output.source := input.source - output.lockId := input.lockId output.roundMode := input.roundMode if(p.withDouble) { output.format := input.format @@ -589,9 +601,10 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val shortPip = new Area{ val input = decode.shortPip.stage() + val toFpuRf = List(FpuOpcode.MIN_MAX, FpuOpcode.SGNJ, FpuOpcode.FCVT_X_X).map(input.opcode === _).orR val rfOutput = Stream(new MergeInput()) - val isCommited = rf.lock.map(_.commited).read(input.lockId) + val isCommited = commitConsume(_.short, input.source, input.fire && toFpuRf) val output = rfOutput.haltWhen(!isCommited) val result = p.storeLoadType().assignDontCare() @@ -809,11 +822,9 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ is(FpuOpcode.FCLASS) { result(31 downto 0) := fclassResult.resized } } - val toFpuRf = List(FpuOpcode.MIN_MAX, FpuOpcode.SGNJ, FpuOpcode.FCVT_X_X).map(input.opcode === _).orR rfOutput.valid := input.valid && toFpuRf && !halt rfOutput.source := input.source - rfOutput.lockId := input.lockId rfOutput.rd := input.rd rfOutput.roundMode := input.roundMode if(p.withDouble) rfOutput.format := input.format @@ -930,8 +941,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val input = mul.output.stage() val sum = splits.take(sumSplitAt).map(e => (input.muls(e.id) << e.offsetC).resize(outWidth)).reduceBalancedTree(_ + _) - val isCommited = rf.lock.map(_.commited).read(input.lockId) - val output = input.haltWhen(!isCommited).swapPayload(new Sum1Output()) + val output = input.swapPayload(new Sum1Output()) output.payload.assignSomeByName(input.payload) output.mulC2 := sum.resized output.muls2 := Vec(input.muls.drop(sumSplitAt)) @@ -941,7 +951,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val input = sum1.output.stage() val sum = input.mulC2 + splits.drop(sumSplitAt).map(e => (input.muls2(e.id-sumSplitAt) << e.offsetC).resize(outWidth)).reduceBalancedTree(_ + _) - val isCommited = rf.lock.map(_.commited).read(input.lockId) + val isCommited = commitConsume(_.mul, input.source, input.fire) val output = input.haltWhen(!isCommited).swapPayload(new Sum2Output()) output.payload.assignSomeByName(input.payload) output.mulC := sum @@ -998,7 +1008,6 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val output = Stream(new MergeInput()) output.valid := input.valid && !input.add && !input.divSqrt output.source := input.source - output.lockId := input.lockId output.rd := input.rd if (p.withDouble) output.format := input.format output.roundMode := input.roundMode @@ -1015,8 +1024,8 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ decode.mulToAdd.rs1.special := norm.output.special decode.mulToAdd.rs2 := input.rs3 decode.mulToAdd.rd := input.rd - decode.mulToAdd.lockId := input.lockId decode.mulToAdd.roundMode := input.roundMode + decode.mulToAdd.needCommit := False if (p.withDouble) decode.mulToAdd.format := input.format when(NV){ @@ -1031,7 +1040,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val div = p.withDiv generate new Area{ val input = decode.div.halfPipe() val haltIt = True - val isCommited = RegNext(rf.lock.map(_.commited).read(input.lockId)) + val isCommited = RegNext(commitConsume(_.div, input.source, input.fire)) val output = input.haltWhen(haltIt || !isCommited).swapPayload(new MergeInput()) val dividerShift = if(p.withDouble) 0 else 1 @@ -1096,7 +1105,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val sqrt = p.withSqrt generate new Area{ val input = decode.sqrt.halfPipe() val haltIt = True - val isCommited = RegNext(rf.lock.map(_.commited).read(input.lockId)) + val isCommited = RegNext(commitConsume(_.sqrt, input.source, input.fire)) val output = input.haltWhen(haltIt || !isCommited).swapPayload(new MergeInput()) val needShift = !input.rs1.exponent.lsb @@ -1170,7 +1179,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val divSqrt = p.withDivSqrt generate new Area { val input = decode.divSqrt.halfPipe() - + assert(false, "Need to implement commit tracking") val aproxWidth = 8 val aproxDepth = 64 val divIterationCount = 3 @@ -1188,7 +1197,6 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ decode.divSqrtToMul.rs2.assignDontCare() decode.divSqrtToMul.rs3.assignDontCare() decode.divSqrtToMul.rd := input.rd - decode.divSqrtToMul.lockId := input.lockId decode.divSqrtToMul.add := False decode.divSqrtToMul.divSqrt := True decode.divSqrtToMul.msb1 := True @@ -1420,8 +1428,8 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val oh = new Area { val input = math.output.stage() - val isCommited = rf.lock.map(_.commited).read(input.lockId) - val output = input.haltWhen(!isCommited).swapPayload(new OhOutput) + val isCommited = commitConsume(_.add, input.source, input.fire && input.needCommit) + val output = input.haltWhen(input.needCommit && !isCommited).swapPayload(new OhOutput) output.payload.assignSomeByName(input.payload) import input.payload._ @@ -1462,7 +1470,6 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ import input.payload._ output.source := input.source - output.lockId := input.lockId output.rd := input.rd output.value.sign := xySign output.value.mantissa := (mantissa >> 2).resized @@ -1620,14 +1627,14 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ nx setWhen(!input.value.special && (roundAdjusted =/= 0)) - val write = rf.lock.map(_.write).read(input.lockId) + val writes = rf.scoreboards.map(_.writes.readAsync(input.rd)) + val write = writes.toList.read(input.source) output.NX := nx & write output.OF := of & write output.UF := uf & write output.NV := input.NV & write output.DZ := input.DZ & write output.source := input.source - output.lockId := input.lockId output.rd := input.rd output.write := write if(p.withDouble) output.format := input.format @@ -1649,8 +1656,11 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } when(input.valid){ - for(i <- 0 until p.rfLockCount) when(input.lockId === i){ - rf.lock(i).valid := False + for(i <- 0 until portCount) { + val port = rf.scoreboards(i).hitWrite + port.valid setWhen(input.source === i) + port.address := input.rd + port.data := !rf.scoreboards(i).hit(input.rd) //TODO improve } } @@ -1852,6 +1862,19 @@ object FpuSynthesisBench extends App{ //Artix 7 -> 106 Mhz 3322 LUT 3023 FF //Artix 7 -> 161 Mhz 3675 LUT 3163 FF +//Fpu_32 -> +//Artix 7 -> 132 Mhz 1891 LUT 1837 FF +//Artix 7 -> 209 Mhz 2132 LUT 1847 FF +//Fpu_64 -> +//Artix 7 -> 105 Mhz 3348 LUT 3024 FF +//Artix 7 -> 162 Mhz 3712 LUT 3165 FF + +//Fpu_32 -> +//Artix 7 -> 128 Mhz 1796 LUT 1727 FF +//Artix 7 -> 208 Mhz 2049 LUT 1727 FF +//Fpu_64 -> +//Artix 7 -> 109 Mhz 3417 LUT 2913 FF +//Artix 7 -> 168 Mhz 3844 LUT 3053 FF /* testfloat -tininessafter -all1 > all1.txt diff --git a/src/main/scala/vexriscv/ip/fpu/Interface.scala b/src/main/scala/vexriscv/ip/fpu/Interface.scala index e5a02722..d56534c0 100644 --- a/src/main/scala/vexriscv/ip/fpu/Interface.scala +++ b/src/main/scala/vexriscv/ip/fpu/Interface.scala @@ -118,7 +118,6 @@ object FpuRoundModeInstr extends SpinalEnum(){ case class FpuParameter( withDouble : Boolean, mulWidthA : Int = 18, mulWidthB : Int = 18, - rfLockCount : Int = 8, sim : Boolean = false, withAdd : Boolean = true, withMul : Boolean = true, @@ -160,8 +159,9 @@ case class FpuCmd(p : FpuParameter) extends Bundle{ } case class FpuCommit(p : FpuParameter) extends Bundle{ + val opcode = FpuOpcode() + val rd = UInt(5 bits) val write = Bool() - val sync = Bool() val value = p.storeLoadType() // IEEE 754 } diff --git a/src/main/scala/vexriscv/plugin/FpuPlugin.scala b/src/main/scala/vexriscv/plugin/FpuPlugin.scala index 1d657b43..a49d4c94 100644 --- a/src/main/scala/vexriscv/plugin/FpuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/FpuPlugin.scala @@ -22,7 +22,7 @@ class FpuPlugin(externalFpu : Boolean = false, object FPU_ARG extends Stageable(Bits(2 bits)) object FPU_FORMAT extends Stageable(FpuFormat()) - var port : FpuPort = null + var port : FpuPort = null //Commit port is already isolated override def getVexRiscvRegressionArgs(): Seq[String] = { var args = List[String]() @@ -331,7 +331,8 @@ class FpuPlugin(externalFpu : Boolean = false, commit.value(31 downto 0) := (input(FPU_COMMIT_LOAD) ? dBusEncoding.loadData()(31 downto 0) | input(RS1)) if(p.withDouble) commit.value(63 downto 32) := dBusEncoding.loadData()(63 downto 32) commit.write := arbitration.isValid && !arbitration.removeIt - commit.sync := input(FPU_COMMIT_SYNC) + commit.opcode := input(FPU_OPCODE) + commit.rd := input(INSTRUCTION)(rdRange).asUInt when(isCommit && !commit.ready){ arbitration.haltByOther := True diff --git a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala index 6d4c1fe9..290e39bb 100644 --- a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala +++ b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala @@ -55,7 +55,7 @@ class FpuTest extends FunSuite{ } def testP(p : FpuParameter){ - val portCount = 1 + val portCount = 4 val config = SimConfig config.allOptimisation @@ -276,8 +276,9 @@ class FpuTest extends FunSuite{ } commitQueue += {cmd => cmd.write #= true + cmd.rd #= rd cmd.value #= value - cmd.sync #= true + cmd.opcode #= cmd.opcode.spinalEnum.LOAD } } @@ -326,7 +327,8 @@ class FpuTest extends FunSuite{ } commitQueue += {cmd => cmd.write #= true - cmd.sync #= false + cmd.rd #= rd + cmd.opcode #= opcode } } @@ -404,7 +406,8 @@ class FpuTest extends FunSuite{ } commitQueue += {cmd => cmd.write #= true - cmd.sync #= true + cmd.rd #= rd + cmd.opcode #= FpuOpcode.I2F cmd.value #= value.toLong & 0xFFFFFFFFl } } @@ -436,7 +439,8 @@ class FpuTest extends FunSuite{ } commitQueue += {cmd => cmd.write #= true - cmd.sync #= true + cmd.rd #= rd + cmd.opcode #= FpuOpcode.FMV_W_X cmd.value #= value.toLong & 0xFFFFFFFFl } } @@ -454,7 +458,8 @@ class FpuTest extends FunSuite{ } commitQueue += {cmd => cmd.write #= true - cmd.sync #= false + cmd.rd #= rd + cmd.opcode #= FpuOpcode.MIN_MAX } } From 4bdab667cccc5b4be33cb1666ecb1a1f5a0e5dad Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 2 Mar 2021 19:39:55 +0100 Subject: [PATCH 602/951] fpu fix cmd / commit race condition --- src/main/scala/vexriscv/TestsWorkspace.scala | 12 ++++--- .../demo/smp/VexRiscvSmpCluster.scala | 4 ++- src/main/scala/vexriscv/ip/fpu/FpuCore.scala | 31 +++++-------------- .../scala/vexriscv/plugin/FpuPlugin.scala | 19 +++++++++--- src/test/cpp/regression/main.cpp | 9 ++++-- 5 files changed, 40 insertions(+), 35 deletions(-) diff --git a/src/main/scala/vexriscv/TestsWorkspace.scala b/src/main/scala/vexriscv/TestsWorkspace.scala index f4347f44..c961f05a 100644 --- a/src/main/scala/vexriscv/TestsWorkspace.scala +++ b/src/main/scala/vexriscv/TestsWorkspace.scala @@ -121,11 +121,12 @@ object TestsWorkspace { // cd buildroot-build/ // make O=$PWD BR2_EXTERNAL=../buildroot-spinal-saxon -C ../buildroot saxon_regression_defconfig + //make clean all IBUS=CACHED IBUS_DATA_WIDTH=64 COMPRESSED=no DBUS=CACHED DBUS_LOAD_DATA_WIDTH=64 DBUS_STORE_DATA_WIDTH=64 LRSC=yes AMO=yes SUPERVISOR=yes DBUS_EXCLUSIVE=yes DBUS_INVALIDATE=yes MUL=yes DIV=yes RVF=yes RVD=yes DEBUG_PLUGIN=no TRACE=yes REDO=1 DEBUG=ye WITH_USER_IO=no FLOW_INFO=no TRACE_START=565000000000ll SEED=45 + + //make clean all IBUS=CACHED IBUS_DATA_WIDTH=64 COMPRESSED=no DBUS=CACHED DBUS_LOAD_DATA_WIDTH=64 DBUS_STORE_DATA_WIDTH=64 LRSC=yes AMO=yes SUPERVISOR=yes DBUS_EXCLUSIVE=yes DBUS_INVALIDATE=yes MUL=yes DIV=yes RVF=yes RVD=yes DEBUG_PLUGIN=no TRACE=yes REDO=100 DEBUG=ye WITH_USER_IO=no FLOW_INFO=no TRACE_START=5600000000000ll SEED=45 STOP_ON_ERROR=ye + // export IMAGES=/media/data/open/SaxonSoc/artyA7SmpUpdate/buildroot-regression/buildroot-build/images - // make clean all IBUS=CACHED IBUS_DATA_WIDTH=64 COMPRESSED=no DBUS=CACHED DBUS_LOAD_DATA_WIDTH=64 DBUS_STORE_DATA_WIDTH=64 LRSC=yes AMO=yes SUPERVISOR=yes DBUS_EXCLUSIVE=yes DBUS_INVALIDATE=yes MUL=yes DIV=yes RVF=yes RVD=yes DEBUG_PLUGIN=no LINUX_SOC_SMP=yes EMULATOR=$IMAGES/fw_jump.bin VMLINUX=$IMAGES/Image DTB=$IMAGES/linux.dtb RAMDISK=$IMAGES/rootfs.cpio TRACE=ye REDO=1 DEBUG=ye WITH_USER_IO=no - // make clean all IBUS=CACHED IBUS_DATA_WIDTH=64 COMPRESSED=no DBUS=CACHED DBUS_LOAD_DATA_WIDTH=64 DBUS_STORE_DATA_WIDTH=64 LRSC=yes AMO=yes SUPERVISOR=yes DBUS_EXCLUSIVE=yes DBUS_INVALIDATE=yes MUL=yes DIV=yes RVF=yes RVD=yes DEBUG_PLUGIN=no LINUX_SOC_SMP=yes EMULATOR=$IMAGES/fw_jump.bin VMLINUX=$IMAGES/Image DTB=$IMAGES/linux.dtb RAMDISK=$IMAGES/rootfs.cpio TRACE=yes REDO=1 DEBUG=ye WITH_USER_IO=no FLOW_INFO=yes TRACE_START=47000000000ll SEED=43 - // make clean all IBUS=CACHED IBUS_DATA_WIDTH=64 COMPRESSED=no DBUS=CACHED DBUS_LOAD_DATA_WIDTH=64 DBUS_STORE_DATA_WIDTH=64 LRSC=yes AMO=yes SUPERVISOR=yes DBUS_EXCLUSIVE=yes DBUS_INVALIDATE=yes MUL=yes DIV=yes RVF=yes RVD=yes DEBUG_PLUGIN=no LINUX_SOC_SMP=yes EMULATOR=$IMAGES/fw_jump.bin VMLINUX=$IMAGES/Image DTB=$IMAGES/linux.dtb RAMDISK=$IMAGES/rootfs.cpio TRACE=yes REDO=1 DEBUG=ye WITH_USER_IO=no FLOW_INFO=yes TRACE_START=47000000000ll SEED=45 - //make clean all IBUS=CACHED IBUS_DATA_WIDTH=64 COMPRESSED=no DBUS=CACHED DBUS_LOAD_DATA_WIDTH=64 DBUS_STORE_DATA_WIDTH=64 LRSC=yes AMO=yes SUPERVISOR=yes DBUS_EXCLUSIVE=yes DBUS_INVALIDATE=yes MUL=yes DIV=yes RVF=yes RVD=yes DEBUG_PLUGIN=no LINUX_SOC_SMP=yes EMULATOR=$IMAGES/fw_jump.bin VMLINUX=$IMAGES/Image DTB=$IMAGES/linux.dtb RAMDISK=$IMAGES/rootfs.cpio TRACE=yes REDO=1 DEBUG=ye WITH_USER_IO=no FLOW_INFO=yes TRACE_START=565000000ll SEED=45 + // make clean all IBUS=CACHED IBUS_DATA_WIDTH=64 COMPRESSED=no DBUS=CACHED DBUS_LOAD_DATA_WIDTH=64 DBUS_STORE_DATA_WIDTH=64 LRSC=yes AMO=yes SUPERVISOR=yes DBUS_EXCLUSIVE=yes DBUS_INVALIDATE=yes MUL=yes DIV=yes RVF=yes RVD=yes DEBUG_PLUGIN=no LINUX_SOC_SMP=yes EMULATOR=$IMAGES/fw_jump.bin VMLINUX=$IMAGES/Image DTB=$IMAGES/linux.dtb RAMDISK=$IMAGES/rootfs.cpio TRACE=yes REDO=1 DEBUG=ye WITH_USER_IO=no FLOW_INFO=no TRACE_START=565000000000ll SEED=45 val config = VexRiscvSmpClusterGen.vexRiscvConfig( hartId = 0, ioRange = _ (31 downto 28) === 0xF, @@ -139,7 +140,8 @@ object TestsWorkspace { dCacheWays = 2, withFloat = true, withDouble = true, - externalFpu = false + externalFpu = false, + simHalt = true ) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index 0e3018ba..177187e0 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -167,7 +167,8 @@ object VexRiscvSmpClusterGen { withSupervisor : Boolean = true, withFloat : Boolean = false, withDouble : Boolean = false, - externalFpu : Boolean = true + externalFpu : Boolean = true, + simHalt : Boolean = false ) = { assert(iCacheSize/iCacheWays <= 4096, "Instruction cache ways can't be bigger than 4096 bytes") assert(dCacheSize/dCacheWays <= 4096, "Data cache ways can't be bigger than 4096 bytes") @@ -280,6 +281,7 @@ object VexRiscvSmpClusterGen { if(withFloat) config.plugins += new FpuPlugin( externalFpu = externalFpu, + simHalt = simHalt, p = FpuParameter(withDouble = withDouble) ) config diff --git a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala index 2dba93a0..5c814210 100644 --- a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala +++ b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala @@ -179,25 +179,10 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ }) } -// val completion = for(source <- 0 until portCount) yield new Area{ -// def port = io.port(source) -// port.completion.flag.NV := False -// port.completion.flag.DZ := False -// port.completion.flag.OF := False -// port.completion.flag.UF := False -// port.completion.flag.NX := False -// -// val increments = ArrayBuffer[Bool]() -// -// afterElaboration{ -// port.completion.count := increments.map(_.asUInt.resize(log2Up(increments.size + 1))).reduceBalancedTree(_ + _) -// } -// } - val commitFork = new Area{ val load, commit = Vec(Stream(FpuCommit(p)), portCount) for(i <- 0 until portCount){ - val fork = new StreamFork(FpuCommit(p), 2) + val fork = new StreamFork(FpuCommit(p), 2, synchronous = true) fork.io.input << io.port(i).commit fork.io.outputs(0) >> load(i) fork.io.outputs(1).pipelined(m2s = true, s2m = true) >> commit(i) //Pipelining here is light, as it only use the flags of the payload @@ -214,8 +199,9 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } class CommitArea(source : Int) extends Area{ + val pending = new Tracker(4) val add, mul, div, sqrt, short = new Tracker(4) - val input = commitFork.commit(source).haltWhen(List(add, mul, div, sqrt, short).map(_.full).orR).toFlow + val input = commitFork.commit(source).haltWhen(List(add, mul, div, sqrt, short).map(_.full).orR || !pending.notEmpty).toFlow when(input.fire){ add.inc setWhen(List(FpuOpcode.ADD).map(input.opcode === _).orR) @@ -224,6 +210,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ sqrt.inc setWhen(List(FpuOpcode.SQRT).map(input.opcode === _).orR) short.inc setWhen(List(FpuOpcode.SGNJ, FpuOpcode.MIN_MAX, FpuOpcode.FCVT_X_X).map(input.opcode === _).orR) rf.scoreboards(source).writes(input.rd) := input.write + pending.dec := True } } @@ -237,7 +224,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val scheduler = for(portId <- 0 until portCount; scoreboard = rf.scoreboards(portId)) yield new Area{ - val input = io.port(portId).cmd.combStage() + val input = io.port(portId).cmd.pipelined(s2m = true) val useRs1, useRs2, useRs3, useRd = False switch(input.opcode){ is(p.Opcode.LOAD) { useRd := True } @@ -265,7 +252,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val rfBusy = (rfHits, rfTargets).zipped.map(_ ^ _) val hits = (0 to 3).map(id => uses(id) && rfBusy(id)) - val hazard = hits.orR || !rf.init.done + val hazard = hits.orR || !rf.init.done || commitLogic(portId).pending.full val output = input.haltWhen(hazard) when(input.valid && rf.init.done){ scoreboard.targetWrite.address := input.rd @@ -273,6 +260,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } when(output.fire && useRd){ scoreboard.targetWrite.valid := True + commitLogic(portId).pending.inc := True } } @@ -287,7 +275,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } val read = new Area{ - val s0 = cmdArbiter.output.pipelined(m2s = true, s2m = true) //TODO may need to remove m2s for store latency + val s0 = cmdArbiter.output.pipelined() //TODO may need to remove m2s for store latency val s1 = s0.m2sPipe() val output = s1.swapPayload(RfReadOutput()) val rs1Entry = rf.ram.readSync(s0.source @@ s0.rs1,enable = !output.isStall) @@ -982,7 +970,6 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ when(exp(exp.getWidth-3, 3 bits) >= 5) { output.exponent(p.internalExponentSize-2, 2 bits) := 3 } -// val flag = io.port(input.source).completion.flag when(forceNan) { output.setNanQuiet NV setWhen(infinitynan || input.rs1.isNanSignaling || input.rs2.isNanSignaling) @@ -1479,8 +1466,6 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ if (p.withDouble) output.format := input.format output.scrap := (mantissa(1) | mantissa(0) | roundingScrap) - -// val flag = io.port(input.source).completion.flag output.NV := infinityNan || input.rs1.isNanSignaling || input.rs2.isNanSignaling output.DZ := False when(forceNan) { diff --git a/src/main/scala/vexriscv/plugin/FpuPlugin.scala b/src/main/scala/vexriscv/plugin/FpuPlugin.scala index a49d4c94..6aa6831e 100644 --- a/src/main/scala/vexriscv/plugin/FpuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/FpuPlugin.scala @@ -10,6 +10,7 @@ import vexriscv.ip.fpu._ import scala.collection.mutable.ArrayBuffer class FpuPlugin(externalFpu : Boolean = false, + simHalt : Boolean = false, p : FpuParameter) extends Plugin[VexRiscv] with VexRiscvRegressionArg { object FPU_ENABLE extends Stageable(Bool()) @@ -222,10 +223,20 @@ class FpuPlugin(externalFpu : Boolean = false, val internal = (!externalFpu).generate (pipeline plug new Area{ val fpu = FpuCore(1, p) - fpu.io.port(0).cmd << port.cmd - fpu.io.port(0).commit << port.commit - fpu.io.port(0).rsp >> port.rsp - fpu.io.port(0).completion <> port.completion + if(simHalt) { + val cmdHalt = in(Bool).setName("fpuCmdHalt").addAttribute(Verilator.public) + val commitHalt = in(Bool).setName("fpuCommitHalt").addAttribute(Verilator.public) + val rspHalt = in(Bool).setName("fpuRspHalt").addAttribute(Verilator.public) + fpu.io.port(0).cmd << port.cmd.haltWhen(cmdHalt) + fpu.io.port(0).commit << port.commit.haltWhen(commitHalt) + fpu.io.port(0).rsp.haltWhen(rspHalt) >> port.rsp + fpu.io.port(0).completion <> port.completion + } else { + fpu.io.port(0).cmd << port.cmd + fpu.io.port(0).commit << port.commit + fpu.io.port(0).rsp >> port.rsp + fpu.io.port(0).completion <> port.completion + } }) diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index ac9417b0..e58aba37 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -1848,6 +1848,11 @@ public: instanceCycles += 1; for(SimElement* simElement : simElements) simElement->postCycle(); + #ifdef RVF + top->fpuCmdHalt = VL_RANDOM_I(1); + top->fpuCommitHalt = VL_RANDOM_I(1); + top->fpuRspHalt = VL_RANDOM_I(1); + #endif @@ -3815,10 +3820,10 @@ string riscvTestMemory[] = { string riscvTestFloat[] = { + "rv32uf-p-fmadd", "rv32uf-p-fadd", "rv32uf-p-fcmp", "rv32uf-p-fcvt_w", - "rv32uf-p-fmadd", "rv32uf-p-ldst", "rv32uf-p-recoding", "rv32uf-p-fclass", @@ -3830,9 +3835,9 @@ string riscvTestFloat[] = { string riscvTestDouble[] = { + "rv32ud-p-fmadd", "rv32ud-p-fadd", "rv32ud-p-fcvt", - "rv32ud-p-fmadd", "rv32ud-p-recoding", "rv32ud-p-fclass", "rv32ud-p-fcvt_w", From caf1bde49b643939cb2c717dbcae450a4f1ca58b Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 4 Mar 2021 10:16:45 +0100 Subject: [PATCH 603/951] Add MuraxAsicBlackBox example --- src/main/scala/vexriscv/demo/Murax.scala | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/main/scala/vexriscv/demo/Murax.scala b/src/main/scala/vexriscv/demo/Murax.scala index a0590ade..b507881d 100644 --- a/src/main/scala/vexriscv/demo/Murax.scala +++ b/src/main/scala/vexriscv/demo/Murax.scala @@ -483,3 +483,13 @@ object Murax_arty{ SpinalVerilog(Murax(MuraxConfig.default(false).copy(coreFrequency = 100 MHz,onChipRamSize = 32 kB, onChipRamHexFile = hex))) } } + + +object MuraxAsicBlackBox{ + def main(args: Array[String]) { + println("Warning this soc do not has any rom to boot on.") + val config = SpinalConfig() + config.addStandardMemBlackboxing(blackboxAll) + config.generateVerilog(Murax(MuraxConfig.default(false).copy(coreFrequency = 100 MHz,onChipRamSize = 32 kB))) + } +} \ No newline at end of file From 0530d22a1de1d6ebda4da4a8a1fd7963491f89ec Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 4 Mar 2021 16:06:18 +0100 Subject: [PATCH 604/951] sync --- src/main/scala/vexriscv/plugin/Plugin.scala | 3 +++ src/test/scala/vexriscv/ip/fpu/FpuTest.scala | 1 - 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/plugin/Plugin.scala b/src/main/scala/vexriscv/plugin/Plugin.scala index 957a12eb..96d2bc68 100644 --- a/src/main/scala/vexriscv/plugin/Plugin.scala +++ b/src/main/scala/vexriscv/plugin/Plugin.scala @@ -10,7 +10,10 @@ trait Plugin[T <: Pipeline] extends Nameable{ var pipeline : T = null.asInstanceOf[T] setName(this.getClass.getSimpleName.replace("$","")) + // Used to setup things with other plugins def setup(pipeline: T) : Unit = {} + + //Used to flush out the required hardware (called after setup) def build(pipeline: T) : Unit implicit class implicitsStage(stage: Stage){ diff --git a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala index 290e39bb..fb5943a1 100644 --- a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala +++ b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala @@ -68,7 +68,6 @@ class FpuTest extends FunSuite{ dut.clockDomain.forkSimSpeedPrinter(5.0) - class TestCase(op : String){ def build(arg : String) = new ProcessStream(s"testfloat_gen $arg -tininessafter -forever -$op"){ def f32_f32_f32 ={ From bdc52097b6a107ea40beb62dfdec1e06cd2c8a58 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 4 Mar 2021 20:15:01 +0100 Subject: [PATCH 605/951] CFU ensure that CFU_IN_FLIGHT do not produce false positive when the pipeline is stuck --- src/main/scala/vexriscv/plugin/CfuPlugin.scala | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/scala/vexriscv/plugin/CfuPlugin.scala b/src/main/scala/vexriscv/plugin/CfuPlugin.scala index 60dd95b0..0fb03b46 100644 --- a/src/main/scala/vexriscv/plugin/CfuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CfuPlugin.scala @@ -223,6 +223,7 @@ class CfuPlugin(val stageCount : Int, } } + pipeline.stages.dropRight(1).foreach(s => s.output(CFU_IN_FLIGHT) clearWhen(s.arbitration.isStuck)) addPrePopTask(() => stages.dropWhile(_ != memory).reverse.dropWhile(_ != joinStage).foreach(s => s.input(CFU_IN_FLIGHT).init(False))) } } From ec507308e7e5fc8ab6265590c98b8c40127296af Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 4 Mar 2021 20:29:33 +0100 Subject: [PATCH 606/951] fix cfu gen error --- src/main/scala/vexriscv/plugin/CfuPlugin.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/plugin/CfuPlugin.scala b/src/main/scala/vexriscv/plugin/CfuPlugin.scala index 0fb03b46..cd81d245 100644 --- a/src/main/scala/vexriscv/plugin/CfuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CfuPlugin.scala @@ -223,7 +223,7 @@ class CfuPlugin(val stageCount : Int, } } - pipeline.stages.dropRight(1).foreach(s => s.output(CFU_IN_FLIGHT) clearWhen(s.arbitration.isStuck)) + pipeline.stages.drop(1).foreach(s => s.output(CFU_IN_FLIGHT) clearWhen(s.arbitration.isStuck)) addPrePopTask(() => stages.dropWhile(_ != memory).reverse.dropWhile(_ != joinStage).foreach(s => s.input(CFU_IN_FLIGHT).init(False))) } } From aee8841438d0b368eab0c68782f43bb2555c9966 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 4 Mar 2021 20:15:01 +0100 Subject: [PATCH 607/951] CFU ensure that CFU_IN_FLIGHT do not produce false positive when the pipeline is stuck --- src/main/scala/vexriscv/plugin/CfuPlugin.scala | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/scala/vexriscv/plugin/CfuPlugin.scala b/src/main/scala/vexriscv/plugin/CfuPlugin.scala index 30428e55..2586e7f8 100644 --- a/src/main/scala/vexriscv/plugin/CfuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CfuPlugin.scala @@ -211,6 +211,7 @@ class CfuPlugin(val stageCount : Int, } } + pipeline.stages.dropRight(1).foreach(s => s.output(CFU_IN_FLIGHT) clearWhen(s.arbitration.isStuck)) addPrePopTask(() => stages.dropWhile(_ != memory).reverse.dropWhile(_ != joinStage).foreach(s => s.input(CFU_IN_FLIGHT).init(False))) } } From fd234bbf9e3820bb9d6e999ba2e77560c5fa3065 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 4 Mar 2021 20:29:33 +0100 Subject: [PATCH 608/951] fix cfu gen error --- src/main/scala/vexriscv/plugin/CfuPlugin.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/plugin/CfuPlugin.scala b/src/main/scala/vexriscv/plugin/CfuPlugin.scala index 2586e7f8..bb2cb568 100644 --- a/src/main/scala/vexriscv/plugin/CfuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CfuPlugin.scala @@ -211,7 +211,7 @@ class CfuPlugin(val stageCount : Int, } } - pipeline.stages.dropRight(1).foreach(s => s.output(CFU_IN_FLIGHT) clearWhen(s.arbitration.isStuck)) + pipeline.stages.drop(1).foreach(s => s.output(CFU_IN_FLIGHT) clearWhen(s.arbitration.isStuck)) addPrePopTask(() => stages.dropWhile(_ != memory).reverse.dropWhile(_ != joinStage).foreach(s => s.input(CFU_IN_FLIGHT).init(False))) } } From e384bfe1451a9b7af287caa0fbd01155f36a07d7 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 5 Mar 2021 22:04:20 +0100 Subject: [PATCH 609/951] fiber update --- .../scala/vexriscv/VexRiscvBmbGenerator.scala | 15 +++++++-------- src/main/scala/vexriscv/demo/smp/Misc.scala | 3 ++- .../vexriscv/demo/smp/VexRiscvSmpCluster.scala | 15 +++++++++++---- .../demo/smp/VexRiscvSmpLitexCluster.scala | 11 +++++++---- 4 files changed, 27 insertions(+), 17 deletions(-) diff --git a/src/main/scala/vexriscv/VexRiscvBmbGenerator.scala b/src/main/scala/vexriscv/VexRiscvBmbGenerator.scala index 15fc7c83..a443a40f 100644 --- a/src/main/scala/vexriscv/VexRiscvBmbGenerator.scala +++ b/src/main/scala/vexriscv/VexRiscvBmbGenerator.scala @@ -7,7 +7,7 @@ import spinal.lib.com.jtag.{Jtag, JtagTapInstructionCtrl} import spinal.lib.generator._ import spinal.lib.slave import vexriscv.plugin._ - +import spinal.core.fiber._ object VexRiscvBmbGenerator{ val DEBUG_NONE = 0 @@ -34,7 +34,7 @@ case class VexRiscvBmbGenerator()(implicit interconnectSmp: BmbInterconnectGener val timerInterrupt = product[Bool] val softwareInterrupt = product[Bool] - def setTimerInterrupt(that: Handle[Bool]) = Dependable(that, timerInterrupt){timerInterrupt := that} + def setTimerInterrupt(that: Handle[Bool]) = Dependable(that, timerInterrupt){timerInterrupt := that} def setSoftwareInterrupt(that: Handle[Bool]) = Dependable(that, softwareInterrupt){softwareInterrupt := that} @@ -45,14 +45,14 @@ case class VexRiscvBmbGenerator()(implicit interconnectSmp: BmbInterconnectGener def enableJtag(debugCd : ClockDomainResetGenerator, resetCd : ClockDomainResetGenerator) : Unit = debugCd{ this.debugClockDomain.merge(debugCd.outputClockDomain) val resetBridge = resetCd.asyncReset(debugReset, ResetSensitivity.HIGH) - debugAskReset.load(null) + debugAskReset.loadNothing() withDebug.load(DEBUG_JTAG) } def enableJtagInstructionCtrl(debugCd : ClockDomainResetGenerator, resetCd : ClockDomainResetGenerator) : Unit = debugCd{ this.debugClockDomain.merge(debugCd.outputClockDomain) val resetBridge = resetCd.asyncReset(debugReset, ResetSensitivity.HIGH) - debugAskReset.load(null) + debugAskReset.loadNothing() withDebug.load(DEBUG_JTAG_CTRL) dependencies += jtagClockDomain } @@ -60,7 +60,7 @@ case class VexRiscvBmbGenerator()(implicit interconnectSmp: BmbInterconnectGener def enableDebugBus(debugCd : ClockDomainResetGenerator, resetCd : ClockDomainResetGenerator) : Unit = debugCd{ this.debugClockDomain.merge(debugCd.outputClockDomain) val resetBridge = resetCd.asyncReset(debugReset, ResetSensitivity.HIGH) - debugAskReset.load(null) + debugAskReset.loadNothing() withDebug.load(DEBUG_BUS) } @@ -69,16 +69,15 @@ case class VexRiscvBmbGenerator()(implicit interconnectSmp: BmbInterconnectGener def enableDebugBmb(debugCd : ClockDomainResetGenerator, resetCd : ClockDomainResetGenerator, mapping : AddressMapping)(implicit debugMaster : BmbImplicitDebugDecoder = null) : Unit = debugCd{ this.debugClockDomain.merge(debugCd.outputClockDomain) val resetBridge = resetCd.asyncReset(debugReset, ResetSensitivity.HIGH) - debugAskReset.load(null) + debugAskReset.loadNothing() withDebug.load(DEBUG_BMB) - val slaveModel = interconnectSmp.addSlave( + val slaveModel = debugCd.outputClockDomain on interconnectSmp.addSlave( accessSource = debugBmbAccessSource, accessCapabilities = debugBmbAccessSource.derivate(DebugExtensionBus.getBmbAccessParameter(_)), accessRequirements = debugBmbAccessRequirements, bus = debugBmb, mapping = mapping ) - slaveModel.onClockDomain(debugCd.outputClockDomain) debugBmb.derivatedFrom(debugBmbAccessRequirements)(Bmb(_)) if(debugMaster != null) interconnectSmp.addConnection(debugMaster.bus, debugBmb) dependencies += debugBmb diff --git a/src/main/scala/vexriscv/demo/smp/Misc.scala b/src/main/scala/vexriscv/demo/smp/Misc.scala index 1306fc17..fba9fd2c 100644 --- a/src/main/scala/vexriscv/demo/smp/Misc.scala +++ b/src/main/scala/vexriscv/demo/smp/Misc.scala @@ -2,6 +2,7 @@ package vexriscv.demo.smp import spinal.core._ +import spinal.core.fiber._ import spinal.lib.bus.bmb._ import spinal.lib.bus.wishbone.{Wishbone, WishboneConfig, WishboneSlaveFactory} import spinal.lib.com.jtag.Jtag @@ -9,7 +10,7 @@ import spinal.lib._ import spinal.lib.bus.bmb.sim.{BmbMemoryMultiPort, BmbMemoryTester} import spinal.lib.bus.misc.{AddressMapping, DefaultMapping, SizeMapping} import spinal.lib.eda.bench.Bench -import spinal.lib.generator.{Generator, Handle} +import spinal.lib.generator._ import spinal.lib.misc.Clint import spinal.lib.sim.{SimData, SparseMemory, StreamDriver, StreamMonitor, StreamReadyRandomizer} import vexriscv.{VexRiscv, VexRiscvConfig} diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index 177187e0..00da4bb4 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -11,7 +11,9 @@ import spinal.lib.bus.wishbone.{Wishbone, WishboneConfig, WishboneToBmb, Wishbon import spinal.lib.com.jtag.{Jtag, JtagInstructionDebuggerGenerator, JtagTapInstructionCtrl} import spinal.lib.com.jtag.sim.JtagTcp import spinal.lib.com.jtag.xilinx.Bscane2BmbMasterGenerator -import spinal.lib.generator.Handle +import spinal.lib.generator._ +import spinal.core.fiber._ +import spinal.idslplugin.PostInitCallback import spinal.lib.misc.plic.PlicMapping import spinal.lib.system.debugger.SystemDebuggerConfig import vexriscv.ip.{DataCacheAck, DataCacheConfig, DataCacheMemBus, InstructionCache, InstructionCacheConfig} @@ -25,7 +27,7 @@ import vexriscv.ip.fpu.FpuParameter case class VexRiscvSmpClusterParameter(cpuConfigs : Seq[VexRiscvConfig], withExclusiveAndInvalidation : Boolean, forcePeripheralWidth : Boolean = true, outOfOrderDecoder : Boolean = true) -class VexRiscvSmpClusterBase(p : VexRiscvSmpClusterParameter) extends Generator{ +class VexRiscvSmpClusterBase(p : VexRiscvSmpClusterParameter) extends Generator with PostInitCallback{ val cpuCount = p.cpuConfigs.size val debugCd = ClockDomainResetGenerator() @@ -36,11 +38,16 @@ class VexRiscvSmpClusterBase(p : VexRiscvSmpClusterParameter) extends Generator{ systemCd.holdDuration.load(63) systemCd.setInput(debugCd) - this.onClockDomain(systemCd.outputClockDomain) + + systemCd.outputClockDomain.push() + override def postInitCallback(): VexRiscvSmpClusterBase.this.type = { + systemCd.outputClockDomain.pop() + this + } implicit val interconnect = BmbInterconnectGenerator() - val debugBridge = JtagInstructionDebuggerGenerator() onClockDomain(debugCd.outputClockDomain) + val debugBridge = debugCd.outputClockDomain on JtagInstructionDebuggerGenerator() debugBridge.jtagClockDomain.load(ClockDomain.external("jtag", withReset = false)) val debugPort = debugBridge.produceIo(debugBridge.logic.jtagBridge.io.ctrl) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala index 4098f9e9..9513f8a1 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala @@ -1,9 +1,11 @@ package vexriscv.demo.smp import spinal.core._ +import spinal.core.fiber._ import spinal.lib.bus.bmb._ import spinal.lib.bus.misc.{AddressMapping, DefaultMapping, SizeMapping} import spinal.lib.bus.wishbone.{WishboneConfig, WishboneToBmbGenerator} +import spinal.lib.generator.GeneratorComponent import spinal.lib.sim.SparseMemory import vexriscv.demo.smp.VexRiscvSmpClusterGen.vexRiscvConfig import vexriscv.plugin.{AesPlugin, DBusCachedPlugin} @@ -126,9 +128,9 @@ object VexRiscvLitexSmpClusterCmdGen extends App { ) def dutGen = { - val toplevel = new VexRiscvLitexSmpCluster( + val toplevel = GeneratorComponent(new VexRiscvLitexSmpCluster( p = parameter - ).toComponent() + )) toplevel } @@ -197,9 +199,10 @@ object VexRiscvLitexSmpClusterOpenSbi extends App{ ) def dutGen = { - val top = new VexRiscvLitexSmpCluster( + import GeneratorComponent.toGenerator + val top = new GeneratorComponent(new VexRiscvLitexSmpCluster( p = parameter - ).toComponent() + )) top.rework{ top.clintWishbone.setAsDirectionLess.allowDirectionLessIo top.peripheral.setAsDirectionLess.allowDirectionLessIo.simPublic() From 75bbb28ef62636dd0d4d3741c6e559a911fc85af Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sat, 6 Mar 2021 19:49:23 +0100 Subject: [PATCH 610/951] readme update verlator version --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index eec2dd02..1902977a 100644 --- a/README.md +++ b/README.md @@ -152,7 +152,7 @@ unsetenv VERILATOR_ROOT # For csh; ignore error if on bash unset VERILATOR_ROOT # For bash cd verilator git pull # Make sure we're up-to-date -git checkout v3.916 +git checkout v4.040 autoconf # Create ./configure script ./configure make From 67d2f72a4bd0ff7c879e944ec8c2fba1b97c599c Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Sun, 7 Mar 2021 20:43:02 +0100 Subject: [PATCH 611/951] fiber sync --- src/main/scala/vexriscv/VexRiscvBmbGenerator.scala | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/main/scala/vexriscv/VexRiscvBmbGenerator.scala b/src/main/scala/vexriscv/VexRiscvBmbGenerator.scala index a443a40f..c9e3ae96 100644 --- a/src/main/scala/vexriscv/VexRiscvBmbGenerator.scala +++ b/src/main/scala/vexriscv/VexRiscvBmbGenerator.scala @@ -43,14 +43,14 @@ case class VexRiscvBmbGenerator()(implicit interconnectSmp: BmbInterconnectGener } def enableJtag(debugCd : ClockDomainResetGenerator, resetCd : ClockDomainResetGenerator) : Unit = debugCd{ - this.debugClockDomain.merge(debugCd.outputClockDomain) + this.debugClockDomain.load(debugCd.outputClockDomain) val resetBridge = resetCd.asyncReset(debugReset, ResetSensitivity.HIGH) debugAskReset.loadNothing() withDebug.load(DEBUG_JTAG) } def enableJtagInstructionCtrl(debugCd : ClockDomainResetGenerator, resetCd : ClockDomainResetGenerator) : Unit = debugCd{ - this.debugClockDomain.merge(debugCd.outputClockDomain) + this.debugClockDomain.load(debugCd.outputClockDomain) val resetBridge = resetCd.asyncReset(debugReset, ResetSensitivity.HIGH) debugAskReset.loadNothing() withDebug.load(DEBUG_JTAG_CTRL) @@ -58,7 +58,7 @@ case class VexRiscvBmbGenerator()(implicit interconnectSmp: BmbInterconnectGener } def enableDebugBus(debugCd : ClockDomainResetGenerator, resetCd : ClockDomainResetGenerator) : Unit = debugCd{ - this.debugClockDomain.merge(debugCd.outputClockDomain) + this.debugClockDomain.load(debugCd.outputClockDomain) val resetBridge = resetCd.asyncReset(debugReset, ResetSensitivity.HIGH) debugAskReset.loadNothing() withDebug.load(DEBUG_BUS) @@ -67,7 +67,7 @@ case class VexRiscvBmbGenerator()(implicit interconnectSmp: BmbInterconnectGener val debugBmbAccessSource = Handle[BmbAccessCapabilities] val debugBmbAccessRequirements = Handle[BmbAccessParameter] def enableDebugBmb(debugCd : ClockDomainResetGenerator, resetCd : ClockDomainResetGenerator, mapping : AddressMapping)(implicit debugMaster : BmbImplicitDebugDecoder = null) : Unit = debugCd{ - this.debugClockDomain.merge(debugCd.outputClockDomain) + this.debugClockDomain.load(debugCd.outputClockDomain) val resetBridge = resetCd.asyncReset(debugReset, ResetSensitivity.HIGH) debugAskReset.loadNothing() withDebug.load(DEBUG_BMB) @@ -132,6 +132,9 @@ case class VexRiscvBmbGenerator()(implicit interconnectSmp: BmbInterconnectGener } } + + logic.soon(debugReset) + val parameterGenerator = new Generator { val iBusParameter, dBusParameter = product[BmbParameter] dependencies += config From 845cfcb9661812404eec59896740963b9f4ba82b Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Wed, 10 Mar 2021 20:35:44 +0100 Subject: [PATCH 612/951] DebugPlugin.fromBscane2 added --- src/main/scala/vexriscv/plugin/DebugPlugin.scala | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/main/scala/vexriscv/plugin/DebugPlugin.scala b/src/main/scala/vexriscv/plugin/DebugPlugin.scala index 0d987e0c..491fc6d0 100644 --- a/src/main/scala/vexriscv/plugin/DebugPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DebugPlugin.scala @@ -7,6 +7,7 @@ import vexriscv._ import vexriscv.ip._ import spinal.core._ import spinal.lib._ +import spinal.lib.blackbox.xilinx.s7.BSCANE2 import spinal.lib.bus.amba3.apb.{Apb3, Apb3Config} import spinal.lib.bus.avalon.{AvalonMM, AvalonMMConfig} import spinal.lib.bus.bmb.{Bmb, BmbAccessCapabilities, BmbAccessParameter, BmbParameter} @@ -149,6 +150,20 @@ case class DebugExtensionBus() extends Bundle with IMasterSlave{ jtagBridge.io.ctrl } + + def fromBscane2(usedId : Int): Unit ={ + val jtagConfig = SystemDebuggerConfig() + + val bscane2 = BSCANE2(usedId) + val jtagClockDomain = ClockDomain(bscane2.TCK) + + val jtagBridge = new JtagBridgeNoTap(jtagConfig, jtagClockDomain) + jtagBridge.io.ctrl << bscane2.toJtagTapInstructionCtrl() + + val debugger = new SystemDebugger(jtagConfig) + debugger.io.remote <> jtagBridge.io.remote + debugger.io.mem <> this.from(debugger.io.mem.c) + } } case class DebugExtensionIo() extends Bundle with IMasterSlave{ From adc37b269cc64f98293a7f7b0b20a947425b1cd3 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Thu, 11 Mar 2021 13:06:50 +0100 Subject: [PATCH 613/951] FpuPlugin.pending is now 6 bits --- src/main/scala/vexriscv/plugin/FpuPlugin.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/plugin/FpuPlugin.scala b/src/main/scala/vexriscv/plugin/FpuPlugin.scala index 6aa6831e..498480d8 100644 --- a/src/main/scala/vexriscv/plugin/FpuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/FpuPlugin.scala @@ -241,7 +241,7 @@ class FpuPlugin(externalFpu : Boolean = false, val csr = pipeline plug new Area{ - val pendings = Reg(UInt(5 bits)) init(0) + val pendings = Reg(UInt(6 bits)) init(0) pendings := pendings + U(port.cmd.fire) - U(port.completion.fire) - U(port.rsp.fire) val hasPending = pendings =/= 0 From ff4e5e4666e71153eab7c62648532bd6ceb505ed Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Thu, 11 Mar 2021 18:02:02 +0100 Subject: [PATCH 614/951] wipe generator --- .../scala/vexriscv/VexRiscvBmbGenerator.scala | 35 ++++------- src/main/scala/vexriscv/demo/Murax.scala | 15 +++-- src/main/scala/vexriscv/demo/smp/Misc.scala | 26 ++++---- .../demo/smp/VexRiscvSmpCluster.scala | 10 +-- .../demo/smp/VexRiscvSmpLitexCluster.scala | 62 ++++++++++--------- 5 files changed, 71 insertions(+), 77 deletions(-) diff --git a/src/main/scala/vexriscv/VexRiscvBmbGenerator.scala b/src/main/scala/vexriscv/VexRiscvBmbGenerator.scala index c9e3ae96..b3d7f0fe 100644 --- a/src/main/scala/vexriscv/VexRiscvBmbGenerator.scala +++ b/src/main/scala/vexriscv/VexRiscvBmbGenerator.scala @@ -17,7 +17,7 @@ object VexRiscvBmbGenerator{ val DEBUG_BMB = 4 } -case class VexRiscvBmbGenerator()(implicit interconnectSmp: BmbInterconnectGenerator = null) extends Generator { +case class VexRiscvBmbGenerator()(implicit interconnectSmp: BmbInterconnectGenerator = null) extends Area { import VexRiscvBmbGenerator._ val config = Handle[VexRiscvConfig] @@ -27,12 +27,12 @@ case class VexRiscvBmbGenerator()(implicit interconnectSmp: BmbInterconnectGener val debugAskReset = Handle[() => Unit] val hardwareBreakpointCount = Handle(0) - val iBus, dBus = product[Bmb] + val iBus, dBus = Handle[Bmb] - val externalInterrupt = product[Bool] - val externalSupervisorInterrupt = product[Bool] - val timerInterrupt = product[Bool] - val softwareInterrupt = product[Bool] + val externalInterrupt = Handle[Bool] + val externalSupervisorInterrupt = Handle[Bool] + val timerInterrupt = Handle[Bool] + val softwareInterrupt = Handle[Bool] def setTimerInterrupt(that: Handle[Bool]) = Dependable(that, timerInterrupt){timerInterrupt := that} def setSoftwareInterrupt(that: Handle[Bool]) = Dependable(that, softwareInterrupt){softwareInterrupt := that} @@ -42,22 +42,21 @@ case class VexRiscvBmbGenerator()(implicit interconnectSmp: BmbInterconnectGener withDebug.load(DEBUG_NONE) } - def enableJtag(debugCd : ClockDomainResetGenerator, resetCd : ClockDomainResetGenerator) : Unit = debugCd{ + def enableJtag(debugCd : ClockDomainResetGenerator, resetCd : ClockDomainResetGenerator) : Unit = debugCd.rework{ this.debugClockDomain.load(debugCd.outputClockDomain) val resetBridge = resetCd.asyncReset(debugReset, ResetSensitivity.HIGH) debugAskReset.loadNothing() withDebug.load(DEBUG_JTAG) } - def enableJtagInstructionCtrl(debugCd : ClockDomainResetGenerator, resetCd : ClockDomainResetGenerator) : Unit = debugCd{ + def enableJtagInstructionCtrl(debugCd : ClockDomainResetGenerator, resetCd : ClockDomainResetGenerator) : Unit = debugCd.rework{ this.debugClockDomain.load(debugCd.outputClockDomain) val resetBridge = resetCd.asyncReset(debugReset, ResetSensitivity.HIGH) debugAskReset.loadNothing() withDebug.load(DEBUG_JTAG_CTRL) - dependencies += jtagClockDomain } - def enableDebugBus(debugCd : ClockDomainResetGenerator, resetCd : ClockDomainResetGenerator) : Unit = debugCd{ + def enableDebugBus(debugCd : ClockDomainResetGenerator, resetCd : ClockDomainResetGenerator) : Unit = debugCd.rework{ this.debugClockDomain.load(debugCd.outputClockDomain) val resetBridge = resetCd.asyncReset(debugReset, ResetSensitivity.HIGH) debugAskReset.loadNothing() @@ -66,7 +65,7 @@ case class VexRiscvBmbGenerator()(implicit interconnectSmp: BmbInterconnectGener val debugBmbAccessSource = Handle[BmbAccessCapabilities] val debugBmbAccessRequirements = Handle[BmbAccessParameter] - def enableDebugBmb(debugCd : ClockDomainResetGenerator, resetCd : ClockDomainResetGenerator, mapping : AddressMapping)(implicit debugMaster : BmbImplicitDebugDecoder = null) : Unit = debugCd{ + def enableDebugBmb(debugCd : ClockDomainResetGenerator, resetCd : ClockDomainResetGenerator, mapping : AddressMapping)(implicit debugMaster : BmbImplicitDebugDecoder = null) : Unit = debugCd.rework{ this.debugClockDomain.load(debugCd.outputClockDomain) val resetBridge = resetCd.asyncReset(debugReset, ResetSensitivity.HIGH) debugAskReset.loadNothing() @@ -80,24 +79,16 @@ case class VexRiscvBmbGenerator()(implicit interconnectSmp: BmbInterconnectGener ) debugBmb.derivatedFrom(debugBmbAccessRequirements)(Bmb(_)) if(debugMaster != null) interconnectSmp.addConnection(debugMaster.bus, debugBmb) - dependencies += debugBmb } - dependencies ++= List(config) - dependencies += Dependable(withDebug) { - if (withDebug.get != DEBUG_NONE) { - dependencies ++= List(debugClockDomain, debugAskReset) - } - } - - val jtag = add task (withDebug.get == DEBUG_JTAG generate slave(Jtag())) + val jtag = Handle(withDebug.get == DEBUG_JTAG generate slave(Jtag())) val jtagInstructionCtrl = withDebug.produce(withDebug.get == DEBUG_JTAG_CTRL generate JtagTapInstructionCtrl()) val debugBus = withDebug.produce(withDebug.get == DEBUG_BUS generate DebugExtensionBus()) val debugBmb = Handle[Bmb] val jtagClockDomain = Handle[ClockDomain] - val logic = add task new Area { + val logic = Handle(new Area { withDebug.get != DEBUG_NONE generate new Area { config.add(new DebugPlugin(debugClockDomain, hardwareBreakpointCount)) } @@ -130,7 +121,7 @@ case class VexRiscvBmbGenerator()(implicit interconnectSmp: BmbInterconnectGener } case _ => } - } + }) logic.soon(debugReset) diff --git a/src/main/scala/vexriscv/demo/Murax.scala b/src/main/scala/vexriscv/demo/Murax.scala index b507881d..82bceb36 100644 --- a/src/main/scala/vexriscv/demo/Murax.scala +++ b/src/main/scala/vexriscv/demo/Murax.scala @@ -485,11 +485,10 @@ object Murax_arty{ } -object MuraxAsicBlackBox{ - def main(args: Array[String]) { - println("Warning this soc do not has any rom to boot on.") - val config = SpinalConfig() - config.addStandardMemBlackboxing(blackboxAll) - config.generateVerilog(Murax(MuraxConfig.default(false).copy(coreFrequency = 100 MHz,onChipRamSize = 32 kB))) - } -} \ No newline at end of file +object MuraxAsicBlackBox extends App{ + println("Warning this soc do not has any rom to boot on.") + val config = SpinalConfig() + config.addStandardMemBlackboxing(blackboxAll) + config.generateVerilog(Murax(MuraxConfig.default())) +} + diff --git a/src/main/scala/vexriscv/demo/smp/Misc.scala b/src/main/scala/vexriscv/demo/smp/Misc.scala index fba9fd2c..58bad634 100644 --- a/src/main/scala/vexriscv/demo/smp/Misc.scala +++ b/src/main/scala/vexriscv/demo/smp/Misc.scala @@ -248,13 +248,13 @@ object BmbToLiteDramTester extends App{ } } -case class BmbToLiteDramGenerator(mapping : AddressMapping)(implicit interconnect : BmbInterconnectGenerator) extends Generator{ - val liteDramParameter = createDependency[LiteDramNativeParameter] - val bmb = produce(logic.io.input) - val dram = produceIo(logic.io.output) +case class BmbToLiteDramGenerator(mapping : AddressMapping)(implicit interconnect : BmbInterconnectGenerator) extends Area{ + val liteDramParameter = Handle[LiteDramNativeParameter] + val bmb = Handle(logic.io.input) + val dram = Handle(logic.io.output.toIo) val accessSource = Handle[BmbAccessCapabilities] - val accessRequirements = createDependency[BmbAccessParameter] + val accessRequirements = Handle[BmbAccessParameter] interconnect.addSlave( accessSource = accessSource, accessCapabilities = accessSource, @@ -262,20 +262,20 @@ case class BmbToLiteDramGenerator(mapping : AddressMapping)(implicit interconnec bus = bmb, mapping = mapping ) - val logic = add task BmbToLiteDram( + val logic = Handle(BmbToLiteDram( bmbParameter = accessRequirements.toBmbParameter(), liteDramParameter = liteDramParameter, wdataFifoSize = 32, rdataFifoSize = 32 - ) + )) } -case class BmbToWishboneGenerator(mapping : AddressMapping)(implicit interconnect : BmbInterconnectGenerator) extends Generator{ - val bmb = produce(logic.io.input) - val wishbone = produce(logic.io.output) +case class BmbToWishboneGenerator(mapping : AddressMapping)(implicit interconnect : BmbInterconnectGenerator) extends Area{ + val bmb = Handle(logic.io.input) + val wishbone = Handle(logic.io.output) val accessSource = Handle[BmbAccessCapabilities] - val accessRequirements = createDependency[BmbAccessParameter] + val accessRequirements = Handle[BmbAccessParameter] interconnect.addSlave( accessSource = accessSource, accessCapabilities = accessSource, @@ -283,7 +283,7 @@ case class BmbToWishboneGenerator(mapping : AddressMapping)(implicit interconnec bus = bmb, mapping = mapping ) - val logic = add task BmbToWishbone( + val logic = Handle(BmbToWishbone( p = accessRequirements.toBmbParameter() - ) + )) } diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index 00da4bb4..fc4926dd 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -27,7 +27,7 @@ import vexriscv.ip.fpu.FpuParameter case class VexRiscvSmpClusterParameter(cpuConfigs : Seq[VexRiscvConfig], withExclusiveAndInvalidation : Boolean, forcePeripheralWidth : Boolean = true, outOfOrderDecoder : Boolean = true) -class VexRiscvSmpClusterBase(p : VexRiscvSmpClusterParameter) extends Generator with PostInitCallback{ +class VexRiscvSmpClusterBase(p : VexRiscvSmpClusterParameter) extends Area with PostInitCallback{ val cpuCount = p.cpuConfigs.size val debugCd = ClockDomainResetGenerator() @@ -50,7 +50,7 @@ class VexRiscvSmpClusterBase(p : VexRiscvSmpClusterParameter) extends Generator val debugBridge = debugCd.outputClockDomain on JtagInstructionDebuggerGenerator() debugBridge.jtagClockDomain.load(ClockDomain.external("jtag", withReset = false)) - val debugPort = debugBridge.produceIo(debugBridge.logic.jtagBridge.io.ctrl) + val debugPort = Handle(debugBridge.logic.jtagBridge.io.ctrl.toIo) val dBusCoherent = BmbBridgeGenerator() val dBusNonCoherent = BmbBridgeGenerator() @@ -87,7 +87,7 @@ class VexRiscvSmpClusterBase(p : VexRiscvSmpClusterParameter) extends Generator class VexRiscvSmpClusterWithPeripherals(p : VexRiscvSmpClusterParameter) extends VexRiscvSmpClusterBase(p) { val peripheralBridge = BmbToWishboneGenerator(DefaultMapping) - val peripheral = peripheralBridge.produceIo(peripheralBridge.logic.io.output) + val peripheral = Handle(peripheralBridge.logic.io.output.toIo) if(p.forcePeripheralWidth) interconnect.slaves(peripheralBridge.bmb).forceAccessSourceDataWidth(32) val plic = BmbPlicGenerator()(interconnect = null) @@ -133,8 +133,8 @@ class VexRiscvSmpClusterWithPeripherals(p : VexRiscvSmpClusterParameter) extends } val clintWishbone = clintWishboneBridge.produceIo(clintWishboneBridge.logic.bridge.io.input) - val interrupts = add task (in Bits(32 bits)) - for(i <- 1 to 31) yield plic.addInterrupt(interrupts.derivate(_.apply(i)), i) + val interrupts = in Bits(32 bits) + for(i <- 1 to 31) yield plic.addInterrupt(interrupts(i), i) for ((core, cpuId) <- cores.zipWithIndex) { core.cpu.setTimerInterrupt(clint.timerInterrupt(cpuId)) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala index 9513f8a1..c0d5309d 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala @@ -43,7 +43,7 @@ class VexRiscvLitexSmpCluster(p : VexRiscvLitexSmpClusterParameter) extends VexR // Coherent DMA interface val dma = p.coherentDma generate new Area { val bridge = WishboneToBmbGenerator() - val wishbone = bridge.produceIo(bridge.logic.io.input) + val wishbone = Handle(bridge.logic.io.input.toIo) val dataWidth = p.cluster.cpuConfigs.head.find(classOf[DBusCachedPlugin]).get.config.memDataWidth bridge.config.load(WishboneConfig( addressWidth = 32 - log2Up(dataWidth / 8), @@ -128,9 +128,12 @@ object VexRiscvLitexSmpClusterCmdGen extends App { ) def dutGen = { - val toplevel = GeneratorComponent(new VexRiscvLitexSmpCluster( - p = parameter - )) + val toplevel = new Component { + val body = new VexRiscvLitexSmpCluster( + p = parameter + ) + body.setName("") + } toplevel } @@ -200,29 +203,30 @@ object VexRiscvLitexSmpClusterOpenSbi extends App{ def dutGen = { import GeneratorComponent.toGenerator - val top = new GeneratorComponent(new VexRiscvLitexSmpCluster( - p = parameter - )) + val top = new Component { + val body = new VexRiscvLitexSmpCluster( + p = parameter + ) + } top.rework{ - top.clintWishbone.setAsDirectionLess.allowDirectionLessIo - top.peripheral.setAsDirectionLess.allowDirectionLessIo.simPublic() + top.body.clintWishbone.setAsDirectionLess.allowDirectionLessIo + top.body.peripheral.setAsDirectionLess.allowDirectionLessIo.simPublic() - val hit = (top.peripheral.ADR <<2 >= 0xF0010000l && top.peripheral.ADR<<2 < 0xF0020000l) - top.clintWishbone.CYC := top.peripheral.CYC && hit - top.clintWishbone.STB := top.peripheral.STB - top.clintWishbone.WE := top.peripheral.WE - top.clintWishbone.ADR := top.peripheral.ADR.resized - top.clintWishbone.DAT_MOSI := top.peripheral.DAT_MOSI - top.peripheral.DAT_MISO := top.clintWishbone.DAT_MISO - top.peripheral.ACK := top.peripheral.CYC && (!hit || top.clintWishbone.ACK) - top.peripheral.ERR := False - -// top.dMemBridge.unburstified.cmd.simPublic() + val hit = (top.body.peripheral.ADR <<2 >= 0xF0010000l && top.body.peripheral.ADR<<2 < 0xF0020000l) + top.body.clintWishbone.CYC := top.body.peripheral.CYC && hit + top.body.clintWishbone.STB := top.body.peripheral.STB + top.body.clintWishbone.WE := top.body.peripheral.WE + top.body.clintWishbone.ADR := top.body.peripheral.ADR.resized + top.body.clintWishbone.DAT_MOSI := top.body.peripheral.DAT_MOSI + top.body.peripheral.DAT_MISO := top.body.clintWishbone.DAT_MISO + top.body.peripheral.ACK := top.body.peripheral.CYC && (!hit || top.body.clintWishbone.ACK) + top.body.peripheral.ERR := False } top } + simConfig.compile(dutGen).doSimUntilVoid(seed = 42){dut => - dut.debugCd.inputClockDomain.get.forkStimulus(10) + dut.body.debugCd.inputClockDomain.get.forkStimulus(10) val ram = SparseMemory() ram.loadBin(0x80000000l, "../opensbi/build/platform/spinal/vexriscv/sim/smp/firmware/fw_jump.bin") @@ -231,16 +235,16 @@ object VexRiscvLitexSmpClusterOpenSbi extends App{ ram.loadBin(0xC2000000l, "../buildroot/output/images/rootfs.cpio") - dut.iBridge.dram.simSlave(ram, dut.debugCd.inputClockDomain) - dut.dBridge.dram.simSlave(ram, dut.debugCd.inputClockDomain/*, dut.dMemBridge.unburstified*/) + dut.body.iBridge.dram.simSlave(ram, dut.body.debugCd.inputClockDomain) + dut.body.dBridge.dram.simSlave(ram, dut.body.debugCd.inputClockDomain/*, dut.body.dMemBridge.unburstified*/) - dut.interrupts.get #= 0 + dut.body.interrupts #= 0 - dut.debugCd.inputClockDomain.get.onFallingEdges{ - if(dut.peripheral.CYC.toBoolean){ - (dut.peripheral.ADR.toLong << 2) match { - case 0xF0000000l => print(dut.peripheral.DAT_MOSI.toLong.toChar) - case 0xF0000004l => dut.peripheral.DAT_MISO #= (if(System.in.available() != 0) System.in.read() else 0xFFFFFFFFl) + dut.body.debugCd.inputClockDomain.get.onFallingEdges{ + if(dut.body.peripheral.CYC.toBoolean){ + (dut.body.peripheral.ADR.toLong << 2) match { + case 0xF0000000l => print(dut.body.peripheral.DAT_MOSI.toLong.toChar) + case 0xF0000004l => dut.body.peripheral.DAT_MISO #= (if(System.in.available() != 0) System.in.read() else 0xFFFFFFFFl) case _ => } } From 341c159d06e6ee234967b898fbb2090da647afe2 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 15 Mar 2021 14:43:22 +0100 Subject: [PATCH 615/951] data cache relax assert into error --- src/main/scala/vexriscv/ip/DataCache.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index 4ba1b42c..8c1ce619 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -1059,7 +1059,7 @@ class DataCache(val p : DataCacheConfig, mmuParameter : MemoryTranslatorBusParam } io.cpu.redo setWhen(io.cpu.writeBack.isValid && (mmuRsp.refilling || consistancyHazard)) - assert(!(io.cpu.writeBack.isValid && !io.cpu.writeBack.haltIt && io.cpu.writeBack.isStuck), "writeBack stuck by another plugin is not allowed") + assert(!(io.cpu.writeBack.isValid && !io.cpu.writeBack.haltIt && io.cpu.writeBack.isStuck), "writeBack stuck by another plugin is not allowed", ERROR) } val loader = new Area{ From 5aa1f2e9966ec3bf629eec074bd7dac8304d6c46 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 15 Mar 2021 17:27:10 +0100 Subject: [PATCH 616/951] fpu improve pipline cycles --- src/main/scala/vexriscv/ip/fpu/FpuCore.scala | 4 ++-- src/main/scala/vexriscv/plugin/FpuPlugin.scala | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala index 5c814210..7af4263f 100644 --- a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala +++ b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala @@ -185,7 +185,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val fork = new StreamFork(FpuCommit(p), 2, synchronous = true) fork.io.input << io.port(i).commit fork.io.outputs(0) >> load(i) - fork.io.outputs(1).pipelined(m2s = true, s2m = true) >> commit(i) //Pipelining here is light, as it only use the flags of the payload + fork.io.outputs(1).pipelined(m2s = false, s2m = true) >> commit(i) //Pipelining here is light, as it only use the flags of the payload } } @@ -417,7 +417,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } val s0 = new Area{ - val input = decode.load.pipelined(m2s = true, s2m = true) + val input = decode.load.pipelined(m2s = true, s2m = true).stage() val filtred = commitFork.load.map(port => port.takeWhen(List(FpuOpcode.LOAD, FpuOpcode.FMV_W_X, FpuOpcode.I2F).map(_ === port.opcode).orR)) def feed = filtred(input.source) val hazard = !feed.valid diff --git a/src/main/scala/vexriscv/plugin/FpuPlugin.scala b/src/main/scala/vexriscv/plugin/FpuPlugin.scala index 498480d8..5a6f1237 100644 --- a/src/main/scala/vexriscv/plugin/FpuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/FpuPlugin.scala @@ -267,7 +267,7 @@ class FpuPlugin(externalFpu : Boolean = false, val fs = Reg(Bits(2 bits)) init(1) val sd = fs === 3 - when(stages.last.arbitration.isFiring && stages.last.input(FPU_ENABLE)){ + when(stages.last.arbitration.isFiring && stages.last.input(FPU_ENABLE) && stages.last.input(FPU_OPCODE) =/= FpuOpcode.STORE){ fs := 3 //DIRTY } @@ -349,7 +349,7 @@ class FpuPlugin(externalFpu : Boolean = false, arbitration.haltByOther := True } - port.commit <-/< commit + port.commit << commit.pipelined(s2m = true, m2s = false) } pipeline.stages.dropRight(1).foreach(s => s.output(FPU_FORKED) clearWhen(s.arbitration.isStuck)) From 0d628b4706588a98479b68e1fdad9e93377ee7c6 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 16 Mar 2021 14:44:31 +0100 Subject: [PATCH 617/951] fpu add doc --- README.md | 60 + assets/fpuDesign.svg | 2491 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 2551 insertions(+) create mode 100644 assets/fpuDesign.svg diff --git a/README.md b/README.md index eec2dd02..914f4128 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,7 @@ - [Adding a new CSR via the plugin system](#adding-a-new-csr-via-the-plugin-system) - [CPU clock and resets](#cpu-clock-and-resets) - [VexRiscv Architecture](#vexriscv-architecture) + * [FPU](#fpu) * [Plugins](#plugins) @@ -668,6 +669,53 @@ via the VexRiscv implementation: If you generate the CPU without any plugin, it will only contain the definition of the 5 pipeline stages and their basic arbitration, but nothing else, and everything else, including the program counter is added into the CPU via plugins. +### FPU + +Features : + +- Support IEEE 754 float and optionaly double +- Implement Subnormal (few cycles lost in case of subnormal load/store) +- Implement exceptions flags +- The FPU can be shared between multiple CPU +- Can be integrated inside or outside the CPU via the FpuPlugin +- Fully pipelined, can produce one result per cycle for most operations (add,sub, mul, fma, load, store), as long there is no inter-dependancies +- Implement multiplication using multiple sub multiplication operations in parallel ("FPGA friendly") +- Division done with radix 4 (2 bits per cycle) +- Square root done with radix 2 (1 bit per cycle) +- Currently only compatible with the DBusCachedPlugin for load and store +- 64 bits Load and store can be done in one cycle via the DBusCachedPlugin (even if VexRiscv is RV32) + +Accuracy, roundings (RNE, RTZ, RDN, RUP, RMM) and compliance: + +- Fully implemented excepted in the cases specified bellow +- In FMA, the result of the multiplication is truncated before the addition (keep mantissa width bits) +- A very special corner case of underflow flag do not follow IEEE 754 (rounding from subnormal to normal number) +- Very specific, but SGNJ instruction will not mutate the value from/to F32/F64 (no NaN-boxing mutation) + + There is a diagram of the FPU design and its CPU integration : + + ![fpuDesign](assets/fpuDesign.svg?raw=true "") + + The FPU can be parametrized with FpuParameter data structure : + + | Parameters | type | description | + | ------ | ----------- | ------ | + | withDouble | Boolean | Enable 64 bits floating point (32 bits always enabled) | + | asyncRegFile | Boolean | Implement the register file using combinatorial reads (instead of syncronous reads) | + | mulWidthA | Boolean | Specify the width of the left operand of multiplication blocks | + | mulWidthB | Boolean | Same than above but the the right operand | + +Synthesis results of the FPU itself, without the CPU integration, on the fast speed grade : + +``` +Fpu 32 bits -> + Artix 7 relaxed -> 135 Mhz 1786 LUT 1778 FF + Artix 7 FMax -> 205 Mhz 2101 LUT 1778 FF +Fpu 64/32 bits -> + Artix 7 relaxed -> 101 Mhz 3336 LUT 3033 FF + Artix 7 FMax -> 165 Mhz 3728 LUT 3175 FF +``` + ### Plugins This chapter describes the currently implemented plugins. @@ -692,6 +740,7 @@ This chapter describes the currently implemented plugins. - [MemoryTranslatorPlugin](#memorytranslatorplugin) - [DebugPlugin](#debugplugin) - [YamlPlugin](#yamlplugin) +- [FpuPlugin](#fpuplugin) #### IBusSimplePlugin @@ -1091,3 +1140,14 @@ The OpenOCD port is here: This plugin offers a service to other plugins to generate a useful Yaml file describing the CPU configuration. It contains, for instance, the sequence of instructions required to flush the data cache (information used by openocd). + +#### FpuPlugin + +Allow the integration of a internal or a external FPU into VexRiscv (See the FPU chapter) + +| Parameters | type | description | +| ------ | ----------- | ------ | +| externalFpu | Boolean | When false the FPU is instanciated in Vex, else the plugin has a `port` interface to which you can connect an external FPU | +| p | FpuParameter | Parameter with which the connected FPU will be created | + + diff --git a/assets/fpuDesign.svg b/assets/fpuDesign.svg new file mode 100644 index 00000000..947ac985 --- /dev/null +++ b/assets/fpuDesign.svg @@ -0,0 +1,2491 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Decode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Execute + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Memory + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Writeback + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + CPU0 + + + + + + FPU + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Fetch + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + rsp + + + + + + + + RF + + + + + + + + D$ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cmd + + + + + + completion + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + RF + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + CPU1,2,n + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Hazard + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + counters + + + + + + CPU1,2,n + + + + + + + + + + + + + + + + + + + + + + + + commit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Join + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + RF + + + + + + + + RF + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + CPU1,2,n + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + counters + + + + + + + + + + + + + + + + + + + + + + + + + + fpuFlags + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + CPU1,2,n + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SQRT + + + + + + DIV + + + + + + ADD + + + + + + MUL + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + FMA + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + LOADI2F + + + + + + STOREF2ICMP + + + + + + MIN MAX SGNJ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 02c572b6f111c03936897e5a96d376acea886564 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 16 Mar 2021 14:45:59 +0100 Subject: [PATCH 618/951] fpu improve FMax and add asyncronus regfile support --- src/main/scala/vexriscv/ip/fpu/FpuCore.scala | 89 ++++++++++++------- .../scala/vexriscv/ip/fpu/Interface.scala | 1 + 2 files changed, 60 insertions(+), 30 deletions(-) diff --git a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala index 7af4263f..72f13690 100644 --- a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala +++ b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala @@ -278,36 +278,38 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val s0 = cmdArbiter.output.pipelined() //TODO may need to remove m2s for store latency val s1 = s0.m2sPipe() val output = s1.swapPayload(RfReadOutput()) - val rs1Entry = rf.ram.readSync(s0.source @@ s0.rs1,enable = !output.isStall) - val rs2Entry = rf.ram.readSync(s0.source @@ s0.rs2,enable = !output.isStall) - val rs3Entry = rf.ram.readSync(s0.source @@ s0.rs3,enable = !output.isStall) + val rs = if(p.asyncRegFile){ + List(s1.rs1, s1.rs2, s1.rs3).map(a => rf.ram.readAsync(s1.source @@ a)) + } else { + List(s0.rs1, s0.rs2, s0.rs3).map(a => rf.ram.readSync(s0.source @@ a, enable = !output.isStall)) + } output.source := s1.source output.opcode := s1.opcode output.arg := s1.arg output.roundMode := s1.roundMode output.rd := s1.rd - output.rs1 := rs1Entry.value - output.rs2 := rs2Entry.value - output.rs3 := rs3Entry.value + output.rs1 := rs(0).value + output.rs2 := rs(1).value + output.rs3 := rs(2).value if(p.withDouble){ - output.rs1Boxed := rs1Entry.boxed - output.rs2Boxed := rs2Entry.boxed + output.rs1Boxed := rs(0).boxed + output.rs2Boxed := rs(1).boxed output.format := s1.format val store = s1.opcode === FpuOpcode.STORE ||s1.opcode === FpuOpcode.FMV_X_W val sgnjBypass = s1.opcode === FpuOpcode.SGNJ && s1.format === FpuFormat.DOUBLE when(!sgnjBypass) { when(store) { //Pass through - output.format := rs1Entry.boxed ? FpuFormat.FLOAT | FpuFormat.DOUBLE - } elsewhen (s1.format === FpuFormat.FLOAT =/= rs1Entry.boxed) { + output.format := rs(0).boxed ? FpuFormat.FLOAT | FpuFormat.DOUBLE + } elsewhen (s1.format === FpuFormat.FLOAT =/= rs(0).boxed) { output.rs1.setNanQuiet output.rs1.sign := False } } - when(s1.format === FpuFormat.FLOAT =/= rs2Entry.boxed) { + when(s1.format === FpuFormat.FLOAT =/= rs(1).boxed) { output.rs2.setNanQuiet output.rs2.sign := False } - when(s1.format === FpuFormat.FLOAT =/= rs3Entry.boxed) { + when(s1.format === FpuFormat.FLOAT =/= rs(2).boxed) { output.rs3.setNanQuiet } } @@ -1003,23 +1005,26 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ output.NV := NV output.DZ := False - decode.mulToAdd.valid := input.valid && input.add - decode.mulToAdd.source := input.source - decode.mulToAdd.rs1.mantissa := norm.output.mantissa >> 1 //FMA Precision lost - decode.mulToAdd.rs1.exponent := norm.output.exponent - decode.mulToAdd.rs1.sign := norm.output.sign - decode.mulToAdd.rs1.special := norm.output.special - decode.mulToAdd.rs2 := input.rs3 - decode.mulToAdd.rd := input.rd - decode.mulToAdd.roundMode := input.roundMode - decode.mulToAdd.needCommit := False - if (p.withDouble) decode.mulToAdd.format := input.format + val mulToAdd = Stream(AddInput()) + decode.mulToAdd << mulToAdd.stage() + + mulToAdd.valid := input.valid && input.add + mulToAdd.source := input.source + mulToAdd.rs1.mantissa := norm.output.mantissa >> 1 //FMA Precision lost + mulToAdd.rs1.exponent := norm.output.exponent + mulToAdd.rs1.sign := norm.output.sign + mulToAdd.rs1.special := norm.output.special + mulToAdd.rs2 := input.rs3 + mulToAdd.rd := input.rd + mulToAdd.roundMode := input.roundMode + mulToAdd.needCommit := False + if (p.withDouble) mulToAdd.format := input.format when(NV){ - decode.mulToAdd.rs1.mantissa.msb := False + mulToAdd.rs1.mantissa.msb := False } - input.ready := (input.add ? decode.mulToAdd.ready | output.ready) || input.divSqrt + input.ready := (input.add ? mulToAdd.ready | output.ready) || input.divSqrt } } @@ -1348,6 +1353,27 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val add = p.withAdd generate new Area{ + + class PreShifterOutput extends AddInput{ + val absRs1Bigger = Bool() + val rs1ExponentBigger = Bool() + } + + val preShifter = new Area{ + val input = decode.add.combStage() + val output = input.swapPayload(new PreShifterOutput) + + val exp21 = input.rs2.exponent -^ input.rs1.exponent + val rs1ExponentBigger = (exp21.msb || input.rs2.isZero) && !input.rs1.isZero + val rs1ExponentEqual = input.rs1.exponent === input.rs2.exponent + val rs1MantissaBigger = input.rs1.mantissa > input.rs2.mantissa + val absRs1Bigger = ((rs1ExponentBigger || rs1ExponentEqual && rs1MantissaBigger) && !input.rs1.isZero || input.rs1.isInfinity) && !input.rs2.isInfinity + + output.payload.assignSomeByName(input.payload) + output.absRs1Bigger := absRs1Bigger + output.rs1ExponentBigger := rs1ExponentBigger + } + class ShifterOutput extends AddInput{ val xSign, ySign = Bool() val xMantissa, yMantissa = UInt(p.internalMantissaSize+3 bits) @@ -1357,19 +1383,22 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } val shifter = new Area { - val input = decode.add.stage() + val input = preShifter.output.stage() val output = input.swapPayload(new ShifterOutput) output.payload.assignSomeByName(input.payload) val exp21 = input.rs2.exponent -^ input.rs1.exponent - val rs1ExponentBigger = (exp21.msb || input.rs2.isZero) && !input.rs1.isZero - val rs1ExponentEqual = input.rs1.exponent === input.rs2.exponent - val rs1MantissaBigger = input.rs1.mantissa > input.rs2.mantissa - val absRs1Bigger = ((rs1ExponentBigger || rs1ExponentEqual && rs1MantissaBigger) && !input.rs1.isZero || input.rs1.isInfinity) && !input.rs2.isInfinity +// val rs1ExponentBigger = (exp21.msb || input.rs2.isZero) && !input.rs1.isZero +// val rs1ExponentEqual = input.rs1.exponent === input.rs2.exponent +// val rs1MantissaBigger = input.rs1.mantissa > input.rs2.mantissa +// val absRs1Bigger = ((rs1ExponentBigger || rs1ExponentEqual && rs1MantissaBigger) && !input.rs1.isZero || input.rs1.isInfinity) && !input.rs2.isInfinity val shiftBy = exp21.asSInt.abs//rs1ExponentBigger ? (0-exp21) | exp21 val shiftOverflow = (shiftBy >= p.internalMantissaSize+3) val passThrough = shiftOverflow || (input.rs1.isZero) || (input.rs2.isZero) + def absRs1Bigger = input.absRs1Bigger + def rs1ExponentBigger = input.rs1ExponentBigger + //Note that rs1ExponentBigger can be replaced by absRs1Bigger bellow to avoid xsigned two complement in math block at expense of combinatorial path val xySign = absRs1Bigger ? input.rs1.sign | input.rs2.sign output.xSign := xySign ^ (rs1ExponentBigger ? input.rs1.sign | input.rs2.sign) diff --git a/src/main/scala/vexriscv/ip/fpu/Interface.scala b/src/main/scala/vexriscv/ip/fpu/Interface.scala index d56534c0..baf0a684 100644 --- a/src/main/scala/vexriscv/ip/fpu/Interface.scala +++ b/src/main/scala/vexriscv/ip/fpu/Interface.scala @@ -116,6 +116,7 @@ object FpuRoundModeInstr extends SpinalEnum(){ case class FpuParameter( withDouble : Boolean, + asyncRegFile : Boolean = false, mulWidthA : Int = 18, mulWidthB : Int = 18, sim : Boolean = false, From e23687c45d28757633775ef554b940c25af980a0 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 16 Mar 2021 14:46:30 +0100 Subject: [PATCH 619/951] Handle ClockDomain improvements --- src/main/scala/vexriscv/VexRiscvBmbGenerator.scala | 7 +++---- src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/main/scala/vexriscv/VexRiscvBmbGenerator.scala b/src/main/scala/vexriscv/VexRiscvBmbGenerator.scala index b3d7f0fe..9bd8d942 100644 --- a/src/main/scala/vexriscv/VexRiscvBmbGenerator.scala +++ b/src/main/scala/vexriscv/VexRiscvBmbGenerator.scala @@ -65,12 +65,12 @@ case class VexRiscvBmbGenerator()(implicit interconnectSmp: BmbInterconnectGener val debugBmbAccessSource = Handle[BmbAccessCapabilities] val debugBmbAccessRequirements = Handle[BmbAccessParameter] - def enableDebugBmb(debugCd : ClockDomainResetGenerator, resetCd : ClockDomainResetGenerator, mapping : AddressMapping)(implicit debugMaster : BmbImplicitDebugDecoder = null) : Unit = debugCd.rework{ - this.debugClockDomain.load(debugCd.outputClockDomain) + def enableDebugBmb(debugCd : Handle[ClockDomain], resetCd : ClockDomainResetGenerator, mapping : AddressMapping)(implicit debugMaster : BmbImplicitDebugDecoder = null) : Unit = debugCd.on{ + this.debugClockDomain.load(debugCd) val resetBridge = resetCd.asyncReset(debugReset, ResetSensitivity.HIGH) debugAskReset.loadNothing() withDebug.load(DEBUG_BMB) - val slaveModel = debugCd.outputClockDomain on interconnectSmp.addSlave( + val slaveModel = debugCd on interconnectSmp.addSlave( accessSource = debugBmbAccessSource, accessCapabilities = debugBmbAccessSource.derivate(DebugExtensionBus.getBmbAccessParameter(_)), accessRequirements = debugBmbAccessRequirements, @@ -81,7 +81,6 @@ case class VexRiscvBmbGenerator()(implicit interconnectSmp: BmbInterconnectGener if(debugMaster != null) interconnectSmp.addConnection(debugMaster.bus, debugBmb) } - val jtag = Handle(withDebug.get == DEBUG_JTAG generate slave(Jtag())) val jtagInstructionCtrl = withDebug.produce(withDebug.get == DEBUG_JTAG_CTRL generate JtagTapInstructionCtrl()) val debugBus = withDebug.produce(withDebug.get == DEBUG_BUS generate DebugExtensionBus()) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index 58ab5eef..8c9df5fa 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -76,7 +76,7 @@ class VexRiscvSmpClusterBase(p : VexRiscvSmpClusterParameter) extends Area with cpu.dBus -> List(dBusCoherent.bmb) ) cpu.enableDebugBmb( - debugCd = debugCd, + debugCd = debugCd.outputClockDomain, resetCd = systemCd, mapping = SizeMapping(cpuId*0x1000, 0x1000) ) From 530554d19ca2c84924594ddfa25614cdde699550 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 16 Mar 2021 14:52:57 +0100 Subject: [PATCH 620/951] fix fpu diagram --- README.md | 2 +- assets/fpuDesign.png | Bin 0 -> 133091 bytes assets/fpuDesign.svg | 2491 ------------------------------------------ 3 files changed, 1 insertion(+), 2492 deletions(-) create mode 100644 assets/fpuDesign.png delete mode 100644 assets/fpuDesign.svg diff --git a/README.md b/README.md index 914f4128..747bffef 100644 --- a/README.md +++ b/README.md @@ -694,7 +694,7 @@ Accuracy, roundings (RNE, RTZ, RDN, RUP, RMM) and compliance: There is a diagram of the FPU design and its CPU integration : - ![fpuDesign](assets/fpuDesign.svg?raw=true "") + ![fpuDesign](assets/fpuDesign.png?raw=true "") The FPU can be parametrized with FpuParameter data structure : diff --git a/assets/fpuDesign.png b/assets/fpuDesign.png new file mode 100644 index 0000000000000000000000000000000000000000..7b5127a0acb3588c2e3ce85e6e47694fcfe5cf1a GIT binary patch literal 133091 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%0A&p>{)pB8QRpzvTc>r^~MJG+3( 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 z z!XKw&!S3^k02JGq32{ZT-^(XhN-|Uk?;$CIKT1JE9l1y%hsqhgWP!)lO}A12W@@$89pwvHH5wobhL+a zqTS%EF9-_@EBKS+2;TVSf0p_}jm`|A*A&b9N(~22qeK}jbh$*$Sp0fy~D>* z)!@mclB4Lks7HWshZ6GQ#6yf(VOtGzwT3B>5Ixu{&=4uVQ0&zu5D+}xp2Mk^zd|Jl zQ;k6~j0$ohUm->d+zypizKP;PsD-3diY79+c@yj&p!D$E_h zcUd3wp=ufCgurNFMN7oG)dik^Y3|(y0z`a9i9H;1^dx-QgbA+9k(e7uaTrCH*i_Zo z3yol`*zA;}BTOep<8(VACMVSIG5cg;Rfx=n0Z$XNWXOSl_>%X^VY>ndb#HI)c)|26 z&L}cMjgcfY0dD);CF0UQATK}ln|_bLW+jVzq_Y3S((<)j7Izi;S)dYjoGsdLQa@R5S;iDhPRyFZ_a7 z+SpLQ{5u@;4<)D$A(z9ZnK6mJS$%#oj`I#Ng7eiS&*{=XJgkjIi?XNxFZai1GX4KT{9V#4 zaB{PnW(b^^0)>WEe)uFGQJDH7O@hV;)g${g_?pZ*tc!gz?T|Suq*hLQFWV3>PR})x z!`Prk!!YQbl(r{9Hdc0oh2~^i`3D3lDy`sG7NY{^)(#dYGe-}0440k8A=Iy!_QptI zR7U9hQ{id@A)P}d>!odCLeZuo43}D^eT!0z*KHn-R{Y!c&p%5=dqWnh$2=TLR4qm} zizyHZEbq6>c8naX|LkWl%e8n^>#{4V6LL0a9U-;w+kj}Y*W{6`WUlk;vmtLvesNCu z?nM7ICgW4 z$vuf8jj#46J)Vh(KU2}HW`5vypxdfng;O1~#jr(L3I<_)agMo*PCNQc!^23(RP44H zKYb)kUnHvg=oRz4_AYP~xm9yNA!7LhIMOV5>p1aOwb|H5%3Gj@8T6l6(wc zlqIn0P>~s)4vC!XA+pBbnbjY$S3xXfw~9sPY9|F&6~1#m1)I47iHGoO>K|V|h_i5z z0ckZdKAB?!<`ogAqadHSV`koFydUBpC)LQTq2~~;p%?WOkX!)QI9-WPAcApBDWmo; znCmQGDlHq>1uPzw3aP65p;B{{=Y7|q^ed(567=hzRj|i8ZhAX%Ba<_K9nDQGKTZ}x zCYxKd+L%u~+*VRC8os8UbGn>gwoWit#=NHIi}5zAEtP3?DlO3cy2;Y&w)mQi!8bHzqx8P_{o-0#BI+M2=AyfW9y0yccyr`70hT*qQ#dxReK zx_=SQ)>WynREj=VXLh;D@MksoG&sbjC>v+%+HdtqvmIXd_mJM~39Ig|wtf7V4zxcV zR~Y5a0?1$ckkeE7tQKl})SSJ#Jn3s9$FWbuc|;Cf)4 zFMh$r%Vu$-|LNT|mX+phMp97up$4hS%!^S8-NB}uFKPwL&7kpyGqL6YD8S!wIdr4u z1vv#mGbeWd=}2c+mpz8>pTVRepFg;Fhtyp8@`=jNi?i(Z?O*O#YRcLa4QwpV$|va3 z;bWmNZI*auzU%d})Krue*+jS^v62x>RKZ)jEc zx>RUd&rU%;JpSOFV_5fy5|c$&z~kUB#N*+bf%tvl@6V?C7{;ksT~oN^3*UufFEh6v zd}ZfGbL=~3CESv^Z55;|y35|`D!)$0VP!%vzLFkA)1`iQ8B2j%P(G`8H)C^m*YSO! zb8)KXZe!>8+ezq=b(+P)yP5TnDv}59M%O>nL4dw(Ut}WiL?qZ-;6%c(LT%Cp&?2aV zL0&;i$mR%*<1!k8`SYp(3Pv3Ls=kI-H1rbbwaE_^*4(8Bzpv(bi@~)v9A&OMX-{sS zd&~-2{x3n;*HpM|Az2*;!Q(@WFxgijz}W?fYJGav`@2)@ixv__@dqmasx$#_#e;`` zegHf2V+bqb=OQ$%>+Z#C#5zt$wv-n@!KbuSh|ZvhJP9b|!XYpUI{h}@!$uB)LNa|k zwu)_GB&P36YHY7kVXFEC5YZWdT_bkU&kgG}A-71D!;gRoFXPM&;hGMgFtu2PTTrgq z*-B)WbNgrLt&_jzd%J3A`yUj&p6&gL;Y!Bq<&n2T&$erUX(tm?y}V4iSTvf4Zt7+( zJwhy9CFa5PRR&)Q?s}HeN8Vljs^VqYL@be*G`ws_bhj93Z6%pM*%0R4(Lu>9pETPq z^H#XiDRGdqwxLF|G-}mFPK@STI-Fbj89|XC(_!ImhHz3 z)BA!3hMK3{XC1Ftkl5|L!tA_o<>^+eNBTX=ySMaX(46`ZHrL8`#fZUcpYB2Vs-2_F zytBr97!kC$2Aw2tuhE)ddkrHQ-{0uyO@M-Q+?dii874}U16!m%>sC6>I|a-dx0A`$ zqU^13jl;W%jn!XgR+WEj^9^fBm3Q(4vrtkp|JBE-Y5Y=oLY?>pg5%E)KhPxF@9W!d z!qGupkbDl*MEL5&8=h~Pr{Y4FR;@)yiS2f)ha_VloC7KQI{f>HSI6iTK)ykm@(-0V zJQ27WxJ~bVD&OAQ88;i+4U0et*mGt0tpxf}K(XkD z6I^&>O$7v_NfF3VW;$4fD_Rr_>-)GeJmZVW_l9G_tqT*21Wnskjs!RX;{uPg{dnPe zbPP2oj9EW@p*P3tK_y|itlSu-5T0NZ1ua$r|CYu zJNk)3=WSEQ7O@CcKDo!;;zx&}1G8)1Ere1=&%05(VCsY~hd;N9%7f!KlD^G^IoFBd z-1Z!zZSe^D5H+N%@iqz6);pAbk((E?kQyX$h|LT(-XK{YI;xs>qT!Ila7 zOJyDxyB&+sqr9xC709^Eyq;Ic@etpZ;y&2SyyCQ%x!5am5+n)jNAL0M3_H+LPU3j>#(TlRId722gQD= z_A%^!rX#sH%f5+IW++U#LiO{syGc=?4gv0D z{@&=uJ<%|O2jzlXGB#?tdZ#huAVYH&1bs7ZWi%0!L6F~Q2pXci4Lq4$BYIr*_l}9x zECk5ijzctGIq=4I+f~ z$;nB~bkfVz~DcXdN4 z^a(XvCz#oJ%aYNu{7$}w4wKA3eCwJmw!UwQ%v&NaUjG<8Su(~m^>%4ARP2(%-9H(( z`{~MSTbdUkSfIBPWOhAnoAU=P<6~~2=J7}lAvBp9`X=N&$9(9cQP?)-(|kxZndW8) zON@N6V``D3UmmW)9;gLhd1}524X}RcS)thy&=m<^h3r! z1qRuosx9*=MZ`z1=aYm9z9-M$8;6$@&j#~Voa6ml%+4YrTO%^ta40r!>5^W}GO?~+ z)ep_Sx9W{PcC2fy6bryq$02a}Jlw**8)FwQ+(~nWf`H;T=@BQu&cAWzXUW+A+jKW# z6t!qD2GwsnjBqWAIdZeaPlZEU71`0&K7Xxwx>E13el-jmjhWj>t!vcat&?JRw@C(< zK^J|sK4s_Ewc=Kc(`EKqCLgECt>-HSrcWJx z&B;{aFr3_-f@uvao|5lP7Vc10TJ?A+!Gm>(t1mr<27?yewn&=jW2Suct~k-=%S+ZhtS21eNS7JMQg$ zQywf}n6MblgmgZmaC|ok!z#vjHrz`B_VtTlDsD z(L)=?LM38;k?vTjy23T=TVX#d@A3XCK7~H+*8`d!J#pp z97@sur~sdI)Ce1Qrf1W~O`Rq-QoOzDoqA)cj5Y4O)Kth!ck)P>SH(1StgU}I`-bM8 zS!*v(m0cel#Z^?9u8rP(S~d^d-#dV6cs|lo%+Jqov>F`If@UN-UUX5HG2=X|z;8m~ z#in;0yIx&M3mHVA{-FB(gs7VDG4!zq4x3K0Q?*!;!mVgsIRb+AMlAgi9 z>htoHePnjtz($kI)B3Ku=d$ZxzAE1yGSgKh-8*Jqs$mW1wNX=O^)^+VyC>abTdlGY zw!^_O{Vms)>>KH~wFGXQX$}qssNd|?6T=z(*j}j;2?{}cy*F>oK2j@vmlH;&b$IueYx@o*NWj#`8s+!+h^t-XH zJF}Xw)IXdU^f%0=C-9iCek%V0tDW}Sr9XTvXz#%2LTPYr5G|#zt3{%1eLAIK@p|(q zs(jOeh){b@y!^?*Kz+So$<%0FF)@-n5oCJ1Xm%gMu$e#MNoOd$g{c|~XZ7H5tPB?15A zkYcYh|JK0b;p56i7s!k#EVD`0@6E`jtq3xAOgU=um~O|0#W0g=8vgCX$oe!F@NB&2 zaIuYP{7Z*Ng)Pi9*YL)6x^|-grv(k{A&^5pe}SY|W@w8Lhk`h(yo< zbl*=PCL;8;*Q# zCs=Ze5DtdV1TbWs{-hYWpZ=~8kE)=X5(4gBD#(BqZyNNO*>j5a_J}aPxx`%)Tq<}_ zIuo(J78k7x-`9LxA54?`ZmRq48{2pX`VX%wlh)W+m#q#BBTNZtg7f*KigwNowIM{* zLwh%W`REz;{L3s<$g3x!KIOGG5N|sLy*$iYJyv3;6`ZamG|c0rUpWoi8P%0{uHM~k zXU{D{f+^Tm#pyJla?{i#bGMD(T4X>mwyf8g&LvDsUh|~`r2v&04LEqkylfgP1qaat z4Oi~RzCyIC#&n-h(p1Im(yCV*dGI@N_J=-(+XXw(jye!dapSP*s;Hc64b&=-A2{7i zCwvl3--YrmS|P%bZ`gU<-nn*>WQYwLcF-eyEK>5a)I`vHS27Kvc$p^DqMMh=gN?%# zG2cKQ9;2(&0wxxofEfKFvO=FFkG+G+bb$;$d4V%_n`ABnh%rVQg|@?RNEXjf&zv*l z+0tN`wpAOGI{a1o@j=`A4|LEYwR0)xlFO{S)p$=Q8~3D%19X%sLffu4O=mweRQ~ zdUh?aLfU!uStaCWxTL;a2sT7-r=JY3w?NE+fA#8>#68~g#gb3nNeoPseHfoS4NR_zSzOFNrNKk$m(-i z$-%eK$wYNFc(dAm9PxBcUTFwYR?=f8`!tawvvXI2GCaz%7Xzz2OePYL?96fN!biWs z!h)fdFre}t(<)*nA7Uk7D^V#!EHn)7qc@Rz?fZz%o+&E>N<7lLj~?)omt?G}KU`LW(&8Zo99m=48T zX&?6JO|Mj>A<91e^PKm=B!qXVP z2!c7HI-sL03{j-cPGfyQh*x|CQPa|=+s_vvY^Jxx4cKu4`AGa6&nNUF0u zaxaBlafp{*Uzf{KHUQL-P<}{ly!&m?NBFCF4oOjh0$~!QXrB!-qB}nnR>y^~r71NZ zpMMOt6@4Vb{8A8JvFW%sSw+eqH#;_)R^qbmzPK!rx;Z?f4EtP0E`+Cs3Q4R2O;}h~1p67!KdJ=2l+21bx$OderzDz)X_Do| z9(N3GuPA&i%=U=V2Vg^6_;uIAEJXiXPT8bMj?j@dK#>!yRD4H5L8ENR$;~BE)C9_# z>{lV|r-4exZjZmP!bYvgNvP5-GTx4=_+iG6nEJ&w&9J8E8?aokvP7wlgxLy9i}We1 zU?VZLjFOjFUJa+^T#XZlaqK(wly%qc3Fi;LEz6!7`*hQ=%iZ|Vuljl0eI}?IM**DD zxQlZYX#vBfi^edFsJCO4e@Z%9H2bM3ElmJet&a+=4`-cfq~8S%7dNz9g2 zJ3I#IYep$rqbai8%5Isrz zgiiMs8A9SHVolgXfs`w*GJxDwK=y+5v&Gq=`_l4X7r#>d z=aPoYpoW7f|Gu&zvK-`=*WY5XmD?lCN&E{ZbhTKJL{Qh*;%9i&%~{0szx8&~C8Gm* z#KWlEuXp;xN%ECxN8(6O+k@-I%KV#>$4vYo@@L%X`qx7s>Z3uQqFW2_hbB@Pk&<}1 z^eFdW2|qcgpj%ew@$7XV_=f1?VWKtS7Ayimav3Oi445Nu88rO~ zvw*H&HiB*WD^EzYpdd)B31F@#hsJ7(;gT`F$A(q`b`TxkcFBWfr6!r@cBzAaU$yh} z^4d4>nhi^T+x0O?=o;q3`J#CqsP4cD4Xi~(lR<57_0H&|rx*_j1HqUC1c(%9H|3+9 zn;~}~U4NEcJ&MqvN{BBNr+sq^&| zP&~s@TpS0a6h7;hsuRk6qS0y+maRB8pV3MPjtC3rwQ%{q>+scXmDlKemA@{uWg(;YDeANTjj-vj*+qXg_a2FxbRqpH+; zti(SA?h>2uTk2k5nB2NJ^BV}?V!J`0p4#v8Qp^g-TK_A3`OK(AK74Frwo=v0$6lkHmsK#C!lB#7S6S)MEvUi@y`8tQrrPq|K*yu@Y`0wD#c3Pky;+9a`ZRYZMiyB-uvLOkrYED>R4O3JJ9H!l2jTVLY2sHJ%}U=na%||G z(6}PP9a!$tc#;3~4FWtt)&I`d8r`|$K-?%=Q|V*HZBJ7{nM1z_d7Yqp`V27?`>#1X zuXi9(L-U7rw7;MMyY6*BuIPxFiY6-WF-p&UUa$ONOw2C#OBwn+z&~fUS+E1E6xE|( zc{25Ue5>ZCs7J7Q2~IrEMjjv+VOGB*oz z&EW{u1xI0B$ONaTilF@`nbIRSPYJ$*cWuRk^Qf&Tz41n zIUtRb3~U%6(=fmfN!D8vf1UQ6@xjmGM8RDLl2Ng*R-SJALoJdUxjmSV;zTqa%X`iIvF>=PY?i?D^ZYb5 zzxHhKyXUy6`2S0*k4zj}vGn#^BgIA@-QE~9kMn=UwMxw^I3uP*zG#o$!0#ZU&Nw7g zz*P0k;e7ya!31amPJ{Sjlnj0P?-jv)jPUt0kC&v6$P9$3+Wa?H@UKC%#w=<^pATr^ zCN_af3j<07ue+E;96%TiEK3F=q%i6IXDY(^wb2Xp*yLA=a-ML;jRKwPYD)wKZ*oHL z&Ydu*{(l?$^Uwfezu{l~A*Wp3_oUVrB`#5sgdXsdvf6k(TPl6FaGh$3CR-~M=4F_5 zw`DXojGDqrrB_78?Aq4HT~%fEsiQ54>K5reG-U?Kr7+Wu>JT=O4vYvfWciX)wZdy>yLlr2K7!uS*$Z z)v0m_D=cc7w{zI~-LvQz?Lc zg3XUfP=Zj0qw6iQ72U3A5wVG?Nf%`RiVWaUku_-kMvYeZUMOcg<8DBjuAC0AONMFfwXgtvbH zt{~MZbtFd1Jw^?yByQP5Ps!h2ph!h#$CD3yI;l`?8yR_C9a0R)WY7l9x4=3~Itf7j z?{@Cr+vwIWbq*XB6gdbjC&>9BWG=X&fmYT3 zYMzR}C;{z16`kA{&^|yfC)}Z=yTQb;ltrN6$WO>p%p}Nr6?)yC*cOmwM_CY~JT>{z zS1Q~Je2PE7z-`KO5ZfNU#5+{tOod!Xyd`=D%h+LMpZM|>2pH8G^d1d_ zCXt(aHJ~u<$dsZi*$-tR-7h-;h1rzM*`~8aLt>)J9W2rL@Lv;AS@E{f(4j59Uu%eX zBh^9w%DRxo^VZC_4Hkh|_LBcmsb0Oq1^6y5*~}(*T*amzKO42R4MEWKB7?X{OX|w! z_OlkdkVxHD3HR8CvISKaJ{#BdD~Hc=_T`va5+pCSXHsiNb^ z#5eb@$CuH(e6DwjEL4ZUA<-NFXft(m1b7Cc-Ow9TM4jwi)rChQ!m|7E{s$F@*9K8R zbz0Ge^T4zY+asX=boeQQC&FQRB!%FGpp~Wd&2XmTa=ZIaku;v^-s2WP5>$m`nZ0M$rBM(@IwOlX~&D1$?SuIE9~|pY8$dY$*KT6?VqpFAhtn{d&en zx!)GylMbKJgEsvi{sG+{bs$zNee4Nc8lRz)HwPv;87CJ*aW38E9SlUo!os?Y(2cw~ zLMdf`Jfd*D-0B5Qv%R3b=tlbS-Qf(fmQp!G!@N0Hsf5wK7+=&tsovuO^dhdC-g?R2 z0B!T+fR9!;;%inj1HxQcbm+N4>LGJydT5mo+g{8FqIKj| z7&tc;DJQlrsuu6PQ~UVr;|J4IzcRSlkKaCWtK=^QA2zRi*qyiAk8=h$#jJe9%zmyo zW<;T_(>mjkcP6_`p1hF-3; zJZLl;=v-*;j4{nmU*O`9qd#GQSZ{m28_`<3GhV~Q1rJQ^s=M#)N{%?A5S#DlN>2!J zT~1s_o=JV0@GAt>P^Q3NOGA*Hv^^$CCx-i@WBTg^BDjo();2b>(|Zjf1eo|p2~ZJL zGWoS(OVaG1&ZK-v)5-`+{*W4N#fzYU%ES=qgJcSjz_;c@IFp8Ur|1jrVAt{v#$+Gb z`1g}EoOg4AvVrZXLz_W3l6kqm+7y<2DRP(+9oF120qjcIK{wzXx@B!J~2amdOZTytlrP(a{s9dPBx(Op*{!Wbwj*Z&O
(W`U- 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 literal 0 HcmV?d00001 diff --git a/assets/fpuDesign.svg b/assets/fpuDesign.svg deleted file mode 100644 index 947ac985..00000000 --- a/assets/fpuDesign.svg +++ /dev/null @@ -1,2491 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Decode - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Execute - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Memory - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Writeback - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CPU0 - - - - - - FPU - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Fetch - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - rsp - - - - - - - - RF - - - - - - - - D$ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - cmd - - - - - - completion - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - RF - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CPU1,2,n - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Hazard - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - counters - - - - - - CPU1,2,n - - - - - - - - - - - - - - - - - - - - - - - - commit - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Join - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - RF - - - - - - - - RF - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CPU1,2,n - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - counters - - - - - - - - - - - - - - - - - - - - - - - - - - fpuFlags - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CPU1,2,n - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SQRT - - - - - - DIV - - - - - - ADD - - - - - - MUL - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FMA - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - LOADI2F - - - - - - STOREF2ICMP - - - - - - MIN MAX SGNJ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file From f6e620196de0ccce369532faaffe68931053fbaa Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 17 Mar 2021 13:19:41 +0100 Subject: [PATCH 621/951] litex add fpu suport --- .../demo/smp/VexRiscvSmpCluster.scala | 6 ++- .../demo/smp/VexRiscvSmpLitexCluster.scala | 40 +++++++++++++++++-- .../vexriscv/plugin/DBusCachedPlugin.scala | 1 + 3 files changed, 43 insertions(+), 4 deletions(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index 8c9df5fa..da373be7 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -25,7 +25,11 @@ import scala.collection.mutable.ArrayBuffer import spinal.lib.generator._ import vexriscv.ip.fpu.FpuParameter -case class VexRiscvSmpClusterParameter(cpuConfigs : Seq[VexRiscvConfig], withExclusiveAndInvalidation : Boolean, forcePeripheralWidth : Boolean = true, outOfOrderDecoder : Boolean = true) +case class VexRiscvSmpClusterParameter(cpuConfigs : Seq[VexRiscvConfig], + withExclusiveAndInvalidation : Boolean, + forcePeripheralWidth : Boolean = true, + outOfOrderDecoder : Boolean = true, + fpu : Boolean = false) class VexRiscvSmpClusterBase(p : VexRiscvSmpClusterParameter) extends Area with PostInitCallback{ val cpuCount = p.cpuConfigs.size diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala index c0d5309d..730ed190 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala @@ -8,7 +8,8 @@ import spinal.lib.bus.wishbone.{WishboneConfig, WishboneToBmbGenerator} import spinal.lib.generator.GeneratorComponent import spinal.lib.sim.SparseMemory import vexriscv.demo.smp.VexRiscvSmpClusterGen.vexRiscvConfig -import vexriscv.plugin.{AesPlugin, DBusCachedPlugin} +import vexriscv.ip.fpu.{FpuCore, FpuParameter} +import vexriscv.plugin.{AesPlugin, DBusCachedPlugin, FpuPlugin} case class VexRiscvLitexSmpClusterParameter( cluster : VexRiscvSmpClusterParameter, @@ -33,6 +34,30 @@ class VexRiscvLitexSmpCluster(p : VexRiscvLitexSmpClusterParameter) extends VexR dBusNonCoherent.bmb -> List(peripheralBridge.bmb) ) + val fpu = p.cluster.fpu generate new Area{ + val logic = Handle{ + new FpuCore( + portCount = cpuCount, + p = FpuParameter( + withDouble = true, + asyncRegFile = false + ) + ) + } + + val connect = Handle{ + for(i <- 0 until cpuCount; + vex = cores(i).cpu.logic.cpu; + port = logic.io.port(i)) { + val plugin = vex.service(classOf[FpuPlugin]) + plugin.port.cmd >> port.cmd + plugin.port.commit >> port.commit + plugin.port.completion := port.completion.stage() + plugin.port.rsp << port.rsp + } + } + } + if(p.cluster.withExclusiveAndInvalidation) interconnect.masters(dBusNonCoherent.bmb).withOutOfOrderDecoder() if(!p.wishboneMemory) { @@ -78,6 +103,7 @@ object VexRiscvLitexSmpClusterCmdGen extends App { var wishboneMemory = false var outOfOrderDecoder = true var aesInstruction = false + var fpu = false var netlistDirectory = "." var netlistName = "VexRiscvLitexSmpCluster" assert(new scopt.OptionParser[Unit]("VexRiscvLitexSmpClusterCmdGen") { @@ -96,6 +122,7 @@ object VexRiscvLitexSmpClusterCmdGen extends App { opt[String]("aes-instruction") action { (v, c) => aesInstruction = v.toBoolean } opt[String]("out-of-order-decoder") action { (v, c) => outOfOrderDecoder = v.toBoolean } opt[String]("wishbone-memory" ) action { (v, c) => wishboneMemory = v.toBoolean } + opt[String]("fpu" ) action { (v, c) => fpu = v.toBoolean } }.parse(args)) val coherency = coherentDma || cpuCount > 1 @@ -112,14 +139,21 @@ object VexRiscvLitexSmpClusterCmdGen extends App { dCacheSize = dCacheSize, iCacheWays = iCacheWays, dCacheWays = dCacheWays, - coherency = coherency + coherency = coherency, + iBusRelax = true, + earlyBranch = true, + withFloat = fpu, + withDouble = fpu, + externalFpu = fpu, + loadStoreWidth = if(fpu) 64 else 32 ) if(aesInstruction) c.add(new AesPlugin) c }}, withExclusiveAndInvalidation = coherency, forcePeripheralWidth = !wishboneMemory, - outOfOrderDecoder = outOfOrderDecoder + outOfOrderDecoder = outOfOrderDecoder, + fpu = fpu ), liteDram = LiteDramNativeParameter(addressWidth = 32, dataWidth = liteDramWidth), liteDramMapping = SizeMapping(0x40000000l, 0x40000000l), diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index 32cfdb9f..4309ea2a 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -116,6 +116,7 @@ class DBusCachedPlugin(val config : DataCacheConfig, override def bypassStore(data: Bits): Unit = { val prefix = s"DBusBypass${bypassStoreList.size}" bypassStoreList += ConditionalContext.isTrue().setName(prefix + "_cond") -> CombInit(data).setName(prefix + "_value") + assert(config.cpuDataWidth >= data.getWidth, "Data cache word width is too small for that") } From 099dea743b1775048b6a56bd66d4ec5dfdb4e389 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 18 Mar 2021 10:54:43 +0100 Subject: [PATCH 622/951] fpu cleanup --- src/main/scala/vexriscv/ip/fpu/FpuCore.scala | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala index 72f13690..3c160b7a 100644 --- a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala +++ b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala @@ -11,7 +11,7 @@ object FpuDivSqrtIterationState extends SpinalEnum{ val IDLE, YY, XYY, Y2_XYY, DIV, _15_XYY2, Y_15_XYY2, Y_15_XYY2_RESULT, SQRT = newElement() } -//TODO cleanup rounding + case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val io = new Bundle { val port = Vec(slave(FpuPort(p)), portCount) @@ -137,7 +137,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val roundMode = FpuRoundMode() val format = p.withDouble generate FpuFormat() val NV = Bool() - val DZ = Bool() //TODO + val DZ = Bool() } case class RoundOutput() extends Bundle{ @@ -275,7 +275,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } val read = new Area{ - val s0 = cmdArbiter.output.pipelined() //TODO may need to remove m2s for store latency + val s0 = cmdArbiter.output.pipelined() val s1 = s0.m2sPipe() val output = s1.swapPayload(RfReadOutput()) val rs = if(p.asyncRegFile){ @@ -513,9 +513,6 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } shift.input := (ohInput.asUInt |<< 1).resized - val subnormalShiftOffset = if(!p.withDouble) U(0) else ((input.format === FpuFormat.DOUBLE) ? U(0) | U(0)) //TODO remove ? - val subnormalExpOffset = if(!p.withDouble) U(0) else ((input.format === FpuFormat.DOUBLE) ? U(0) | U(0)) - when(input.valid && (input.i2f || isSubnormal) && !done){ busy := True when(boot){ @@ -523,7 +520,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ input.value.getDrivingReg(0, 32 bits) := B(input.value.asUInt.twoComplement(True).resize(32 bits)) patched := True } otherwise { - shift.by := OHToUInt(OHMasking.first((ohInput).reversed)) + (input.i2f ? U(0) | subnormalShiftOffset) + shift.by := OHToUInt(OHMasking.first((ohInput).reversed)) boot := False i2fZero := input.value(31 downto 0) === 0 } @@ -535,7 +532,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val expOffset = (UInt(p.internalExponentSize bits)) expOffset := 0 when(isSubnormal){ - expOffset := (shift.by-subnormalExpOffset).resized + expOffset := shift.by.resized } when(!input.isStall){ @@ -1169,6 +1166,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ haltIt clearWhen(sqrt.io.output.valid) } + //divSqrt isn't realy used anymore val divSqrt = p.withDivSqrt generate new Area { val input = decode.divSqrt.halfPipe() assert(false, "Need to implement commit tracking") @@ -1515,7 +1513,6 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val merge = new Area { - //TODO maybe load can bypass merge and round. val inputs = ArrayBuffer[Stream[MergeInput]]() inputs += load.s1.output.stage() if(p.withSqrt) (inputs += sqrt.output) From 6956db2b21da540d889b0ff6e7cff3cea5b5f9b9 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 18 Mar 2021 11:09:26 +0100 Subject: [PATCH 623/951] fpu add schedulerM2sPipe optino --- src/main/scala/vexriscv/ip/fpu/FpuCore.scala | 2 +- src/main/scala/vexriscv/ip/fpu/Interface.scala | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala index 3c160b7a..256adfa9 100644 --- a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala +++ b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala @@ -267,7 +267,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val cmdArbiter = new Area{ val arbiter = StreamArbiterFactory.noLock.roundRobin.build(FpuCmd(p), portCount) - arbiter.io.inputs <> Vec(scheduler.map(_.output)) + arbiter.io.inputs <> Vec(scheduler.map(_.output.pipelined(m2s = p.schedulerM2sPipe))) val output = arbiter.io.output.swapPayload(RfReadInput()) output.source := arbiter.io.chosen diff --git a/src/main/scala/vexriscv/ip/fpu/Interface.scala b/src/main/scala/vexriscv/ip/fpu/Interface.scala index baf0a684..9338c35b 100644 --- a/src/main/scala/vexriscv/ip/fpu/Interface.scala +++ b/src/main/scala/vexriscv/ip/fpu/Interface.scala @@ -119,6 +119,7 @@ case class FpuParameter( withDouble : Boolean, asyncRegFile : Boolean = false, mulWidthA : Int = 18, mulWidthB : Int = 18, + schedulerM2sPipe : Boolean = false, sim : Boolean = false, withAdd : Boolean = true, withMul : Boolean = true, From 80f64f0f9f0e434796f72d583aa1eaaa47d863b9 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 18 Mar 2021 11:10:18 +0100 Subject: [PATCH 624/951] litex better pipelining for better fmax, create one FPU for each 4 cores --- .../demo/smp/VexRiscvSmpLitexCluster.scala | 29 ++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala index 730ed190..16a847ab 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala @@ -34,29 +34,33 @@ class VexRiscvLitexSmpCluster(p : VexRiscvLitexSmpClusterParameter) extends VexR dBusNonCoherent.bmb -> List(peripheralBridge.bmb) ) - val fpu = p.cluster.fpu generate new Area{ + val fpuGroups = (cores.reverse.grouped(4)).toList.reverse + val fpu = p.cluster.fpu generate { for(group <- fpuGroups) yield new Area{ + val extraStage = group.size > 2 + val logic = Handle{ new FpuCore( - portCount = cpuCount, + portCount = group.size, p = FpuParameter( withDouble = true, - asyncRegFile = false + asyncRegFile = false, + schedulerM2sPipe = extraStage ) ) } val connect = Handle{ - for(i <- 0 until cpuCount; - vex = cores(i).cpu.logic.cpu; + for(i <- 0 until group.size; + vex = group(i).cpu.logic.cpu; port = logic.io.port(i)) { val plugin = vex.service(classOf[FpuPlugin]) - plugin.port.cmd >> port.cmd - plugin.port.commit >> port.commit - plugin.port.completion := port.completion.stage() + plugin.port.cmd.pipelined(m2s = false, s2m = false) >> port.cmd + plugin.port.commit.pipelined(m2s = extraStage, s2m = false) >> port.commit + plugin.port.completion := port.completion.m2sPipe() plugin.port.rsp << port.rsp } } - } + }} if(p.cluster.withExclusiveAndInvalidation) interconnect.masters(dBusNonCoherent.bmb).withOutOfOrderDecoder() @@ -81,12 +85,17 @@ class VexRiscvLitexSmpCluster(p : VexRiscvLitexSmpClusterParameter) extends VexR // Interconnect pipelining (FMax) for(core <- cores) { - interconnect.setPipelining(core.cpu.dBus)(cmdValid = true, cmdReady = true, rspValid = true) + interconnect.setPipelining(core.cpu.dBus)(cmdValid = true, cmdReady = true, rspValid = true, invValid = true, ackValid = true, syncValid = true) interconnect.setPipelining(core.cpu.iBus)(cmdHalfRate = true, rspValid = true) interconnect.setPipelining(iArbiter.bmb)(cmdHalfRate = true, rspValid = true) } + interconnect.setPipelining(dBusCoherent.bmb)(cmdValid = true, cmdReady = true) interconnect.setPipelining(dBusNonCoherent.bmb)(cmdValid = true, cmdReady = true, rspValid = true) interconnect.setPipelining(peripheralBridge.bmb)(cmdHalfRate = !p.wishboneMemory, cmdValid = p.wishboneMemory, cmdReady = p.wishboneMemory, rspValid = true) + if(!p.wishboneMemory) { + interconnect.setPipelining(iBridge.bmb)(cmdHalfRate = true) + interconnect.setPipelining(dBridge.bmb)(cmdReady = true) + } } From da458dea7ee290e0fb0b60f25b7abaf4d1ccb110 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 23 Mar 2021 20:00:50 +0100 Subject: [PATCH 625/951] litex cluster add cpuPerFpu option --- .../vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala index 16a847ab..8af6bf1e 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala @@ -16,7 +16,8 @@ case class VexRiscvLitexSmpClusterParameter( cluster : VexRiscvSmpClusterParamet liteDram : LiteDramNativeParameter, liteDramMapping : AddressMapping, coherentDma : Boolean, - wishboneMemory : Boolean) + wishboneMemory : Boolean, + cpuPerFpu : Int) class VexRiscvLitexSmpCluster(p : VexRiscvLitexSmpClusterParameter) extends VexRiscvSmpClusterWithPeripherals(p.cluster) { @@ -34,7 +35,7 @@ class VexRiscvLitexSmpCluster(p : VexRiscvLitexSmpClusterParameter) extends VexR dBusNonCoherent.bmb -> List(peripheralBridge.bmb) ) - val fpuGroups = (cores.reverse.grouped(4)).toList.reverse + val fpuGroups = (cores.reverse.grouped(p.cpuPerFpu)).toList.reverse val fpu = p.cluster.fpu generate { for(group <- fpuGroups) yield new Area{ val extraStage = group.size > 2 @@ -113,6 +114,7 @@ object VexRiscvLitexSmpClusterCmdGen extends App { var outOfOrderDecoder = true var aesInstruction = false var fpu = false + var cpuPerFpu = 4 var netlistDirectory = "." var netlistName = "VexRiscvLitexSmpCluster" assert(new scopt.OptionParser[Unit]("VexRiscvLitexSmpClusterCmdGen") { @@ -132,6 +134,7 @@ object VexRiscvLitexSmpClusterCmdGen extends App { opt[String]("out-of-order-decoder") action { (v, c) => outOfOrderDecoder = v.toBoolean } opt[String]("wishbone-memory" ) action { (v, c) => wishboneMemory = v.toBoolean } opt[String]("fpu" ) action { (v, c) => fpu = v.toBoolean } + opt[String]("cpu-per-fpu") action { (v, c) => cpuPerFpu = v.toInt } }.parse(args)) val coherency = coherentDma || cpuCount > 1 @@ -167,7 +170,8 @@ object VexRiscvLitexSmpClusterCmdGen extends App { liteDram = LiteDramNativeParameter(addressWidth = 32, dataWidth = liteDramWidth), liteDramMapping = SizeMapping(0x40000000l, 0x40000000l), coherentDma = coherentDma, - wishboneMemory = wishboneMemory + wishboneMemory = wishboneMemory, + cpuPerFpu = cpuPerFpu ) def dutGen = { @@ -241,7 +245,8 @@ object VexRiscvLitexSmpClusterOpenSbi extends App{ liteDram = LiteDramNativeParameter(addressWidth = 32, dataWidth = 128), liteDramMapping = SizeMapping(0x80000000l, 0x70000000l), coherentDma = false, - wishboneMemory = false + wishboneMemory = false, + cpuPerFpu = 4 ) def dutGen = { From 8495fe3dde0c0295ff8dba4f58597fed3ea27844 Mon Sep 17 00:00:00 2001 From: Romain Dolbeau Date: Wed, 24 Mar 2021 11:07:09 +0100 Subject: [PATCH 626/951] Attempt at supporting C (ompressed) and F/D (floating-point) together --- src/main/scala/vexriscv/plugin/Misc.scala | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/main/scala/vexriscv/plugin/Misc.scala b/src/main/scala/vexriscv/plugin/Misc.scala index 60c16822..eba87e89 100644 --- a/src/main/scala/vexriscv/plugin/Misc.scala +++ b/src/main/scala/vexriscv/plugin/Misc.scala @@ -32,6 +32,11 @@ object RvcDecompressor{ def lwspImm = B"0000" ## i(3 downto 2) ## i(12) ## i(6 downto 4) ## B"00" def swspImm = B"0000" ## i(8 downto 7) ## i(12 downto 9) ## B"00" + val lfdImm = B"0000" ## i(6 downto 5) ## i(12 downto 10) ## B"000" + def sfdImm = lfdImm + def lfdspImm = B"000" ## i(4 downto 2) ## i(12) ## i(6 downto 5) ## B"000" + def sfdspImm = B"000" ## i(9 downto 7) ## i(12 downto 10) ## B"000" + val x0 = B"00000" val x1 = B"00001" @@ -39,8 +44,12 @@ object RvcDecompressor{ switch(i(1 downto 0) ## i(15 downto 13)){ is(0){ret := addi5spnImm ## B"00010" ## B"000" ## rcl ## B"0010011"} //C.ADDI4SPN -> addi rd0, x2, nzuimm[9:2]. + is(1){ret := lfdImm ## rch ## B"011" ## rcl ## B"0000111" } //C.FLD (w/ D ext) is(2){ret := lwImm ## rch ## B"010" ## rcl ## B"0000011"} //C.LW -> lw rd', offset[6:2](rs1') + is(3){ret := lwImm ## rch ## B"010" ## rcl ## B"0000111" } //C.FLW (w/ F ext) + is(5){ret := sfdImm(11 downto 5) ## rcl ## rch ## B"011" ## sfdImm(4 downto 0) ## B"0100111" } //C.FSD (w/ D ext) is(6){ret := swImm(11 downto 5) ## rcl ## rch ## B"010" ## swImm(4 downto 0) ## B"0100011"} //C.SW -> sw rs2',offset[6:2](rs1') + is(7){ret := swImm(11 downto 5) ## rcl ## rch ## B"010" ## swImm(4 downto 0) ## B"0100111" } //C.FSW (w/ F ext) is(8){ret := addImm ## i(11 downto 7) ## B"000" ## i(11 downto 7) ## B"0010011"} //C.ADDI -> addi rd, rd, nzimm[5:0]. is(9){ret := jalImm(20) ## jalImm(10 downto 1) ## jalImm(11) ## jalImm(19 downto 12) ## x1 ## B"1101111"} //C.JAL -> jalr x1, rs1, 0. is(10){ret := lImm ## B"00000" ## B"000" ## i(11 downto 7) ## B"0010011"} //C.LI -> addi rd, x0, imm[5:0]. @@ -76,7 +85,9 @@ object RvcDecompressor{ is(14){ ret := bImm(12) ## bImm(10 downto 5) ## x0 ## rch ## B"000" ## bImm(4 downto 1) ## bImm(11) ## B"1100011" } is(15){ ret := bImm(12) ## bImm(10 downto 5) ## x0 ## rch ## B"001" ## bImm(4 downto 1) ## bImm(11) ## B"1100011" } is(16){ ret := B"0000000" ## i(6 downto 2) ## i(11 downto 7) ## B"001" ## i(11 downto 7) ## B"0010011" } + is(17){ ret := lfdspImm ## x2 ## B"011" ## i(11 downto 7) ## B"0000111" } // C.FLDSP (w/ D ext) is(18){ ret := lwspImm ## x2 ## B"010" ## i(11 downto 7) ## B"0000011" } + is(19){ ret := lwspImm ## x2 ## B"010" ## i(11 downto 7) ## B"0000111" } // C.FLWSP (w/ F ext) is(20) { val add = B"000_0000" ## i(6 downto 2) ## (i(12) ? i(11 downto 7) | x0) ## B"000" ## i(11 downto 7) ## B"0110011" //add => add rd, rd, rs2 mv => add rd, x0, rs2 val j = B"0000_0000_0000" ## i(11 downto 7) ## B"000" ## (i(12) ? x1 | x0) ## B"1100111" //jr => jalr x0, rs1, 0. jalr => jalr x1, rs1, 0. @@ -84,7 +95,9 @@ object RvcDecompressor{ val addJ = (i(6 downto 2) === 0) ? j | add ret := (i(12 downto 2) === B"100_0000_0000") ? ebreak | addJ } + is(21){ ret := sfdspImm(11 downto 5) ## i(6 downto 2) ## x2 ## B"011" ## sfdspImm(4 downto 0) ## B"0100111" } // C.FSDSP (w/ D ext) is(22){ ret := swspImm(11 downto 5) ## i(6 downto 2) ## x2 ## B"010" ## swspImm(4 downto 0) ## B"0100011" } + is(23){ ret := swspImm(11 downto 5) ## i(6 downto 2) ## x2 ## B"010" ## swspImm(4 downto 0) ## B"0100111" } // C.FSWSP (w/ F ext) } ret From 925edd160eda667d580b36abeda648250cfab233 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 24 Mar 2021 12:00:33 +0100 Subject: [PATCH 627/951] RVC implement RVF RVD Rework RVC_GEN --- src/main/scala/vexriscv/Services.scala | 1 + src/main/scala/vexriscv/VexRiscv.scala | 19 ++++++++++-- .../demo/smp/VexRiscvSmpCluster.scala | 5 ++-- .../scala/vexriscv/plugin/BranchPlugin.scala | 11 ++++--- .../scala/vexriscv/plugin/DebugPlugin.scala | 2 +- src/main/scala/vexriscv/plugin/Fetcher.scala | 11 +++---- .../scala/vexriscv/plugin/FpuPlugin.scala | 2 +- src/main/scala/vexriscv/plugin/Misc.scala | 30 +++++++++---------- .../scala/vexriscv/plugin/SrcPlugin.scala | 2 +- 9 files changed, 49 insertions(+), 34 deletions(-) diff --git a/src/main/scala/vexriscv/Services.scala b/src/main/scala/vexriscv/Services.scala index 79a30591..5da43af1 100644 --- a/src/main/scala/vexriscv/Services.scala +++ b/src/main/scala/vexriscv/Services.scala @@ -16,6 +16,7 @@ trait IBusFetcher{ def incoming() : Bool def pcValid(stage : Stage) : Bool def getInjectionPort() : Stream[Bits] + def withRvc() : Boolean } diff --git a/src/main/scala/vexriscv/VexRiscv.scala b/src/main/scala/vexriscv/VexRiscv.scala index 35e5d6df..2bc647db 100644 --- a/src/main/scala/vexriscv/VexRiscv.scala +++ b/src/main/scala/vexriscv/VexRiscv.scala @@ -37,6 +37,21 @@ case class VexRiscvConfig(){ } } + def withRvc = plugins.find(_.isInstanceOf[IBusFetcher]) match { + case Some(x) => x.asInstanceOf[IBusFetcher].withRvc + case None => false + } + + def withRvf = find(classOf[FpuPlugin]) match { + case Some(x) => true + case None => false + } + + def withRvd = find(classOf[FpuPlugin]) match { + case Some(x) => x.p.withDouble + case None => false + } + //Default Stageables object IS_RVC extends Stageable(Bool) object BYPASSABLE_EXECUTE_STAGE extends Stageable(Bool) @@ -103,7 +118,7 @@ case class VexRiscvConfig(){ -object RVC_GEN extends PipelineThing[Boolean] + class VexRiscv(val config : VexRiscvConfig) extends Component with Pipeline{ type T = VexRiscv import config._ @@ -131,8 +146,6 @@ class VexRiscv(val config : VexRiscvConfig) extends Component with Pipeline{ memory.arbitration.removeIt.noBackendCombMerge } execute.arbitration.flushNext.noBackendCombMerge - - this(RVC_GEN) = false } diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index da373be7..b724c45a 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -181,7 +181,8 @@ object VexRiscvSmpClusterGen { withDouble : Boolean = false, externalFpu : Boolean = true, simHalt : Boolean = false, - regfileRead : RegFileReadKind = plugin.ASYNC + regfileRead : RegFileReadKind = plugin.ASYNC, + rvc : Boolean = false ) = { assert(iCacheSize/iCacheWays <= 4096, "Instruction cache ways can't be bigger than 4096 bytes") assert(dCacheSize/dCacheWays <= 4096, "Data cache ways can't be bigger than 4096 bytes") @@ -197,7 +198,7 @@ object VexRiscvSmpClusterGen { //Uncomment the whole IBusCachedPlugin and comment IBusSimplePlugin if you want cached iBus config new IBusCachedPlugin( resetVector = resetVector, - compressedGen = false, + compressedGen = rvc, prediction = vexriscv.plugin.NONE, historyRamSizeLog2 = 9, relaxPredictorAddress = true, diff --git a/src/main/scala/vexriscv/plugin/BranchPlugin.scala b/src/main/scala/vexriscv/plugin/BranchPlugin.scala index 53ef62d9..eb4c8d03 100644 --- a/src/main/scala/vexriscv/plugin/BranchPlugin.scala +++ b/src/main/scala/vexriscv/plugin/BranchPlugin.scala @@ -57,7 +57,7 @@ class BranchPlugin(earlyBranch : Boolean, decodeBranchSrc2 : Boolean = false) extends Plugin[VexRiscv] with PredictionInterface{ - def catchAddressMisalignedForReal = catchAddressMisaligned && !pipeline(RVC_GEN) + def catchAddressMisalignedForReal = catchAddressMisaligned && !pipeline.config.withRvc lazy val branchStage = if(earlyBranch) pipeline.execute else pipeline.memory object BRANCH_CALC extends Stageable(UInt(32 bits)) @@ -114,7 +114,6 @@ class BranchPlugin(earlyBranch : Boolean, decoderService.addDefault(BRANCH_CTRL, BranchCtrlEnum.INC) - val rvc = pipeline(RVC_GEN) decoderService.add(List( JAL(true) -> (jActions ++ List(BRANCH_CTRL -> BranchCtrlEnum.JAL, ALU_CTRL -> AluCtrlEnum.ADD_SUB)), JALR -> (jActions ++ List(BRANCH_CTRL -> BranchCtrlEnum.JALR, ALU_CTRL -> AluCtrlEnum.ADD_SUB, RS1_USE -> True)), @@ -252,7 +251,7 @@ class BranchPlugin(earlyBranch : Boolean, ) val imm = IMM(input(INSTRUCTION)) - val missAlignedTarget = if(pipeline(RVC_GEN)) False else (input(BRANCH_COND_RESULT) && input(BRANCH_CTRL).mux( + val missAlignedTarget = if(pipeline.config.withRvc) False else (input(BRANCH_COND_RESULT) && input(BRANCH_CTRL).mux( BranchCtrlEnum.JALR -> (imm.i_sext(1) ^ input(RS1)(1)), BranchCtrlEnum.JAL -> imm.j_sext(1), default -> imm.b_sext(1) @@ -271,7 +270,7 @@ class BranchPlugin(earlyBranch : Boolean, branch_src1 := input(PC) branch_src2 := ((input(BRANCH_CTRL) === BranchCtrlEnum.JAL) ? imm.j_sext | imm.b_sext).asUInt when(input(PREDICTION_HAD_BRANCHED)){ //Assume the predictor never predict missaligned stuff, this avoid the need to know if the instruction should branch or not - branch_src2 := (if(pipeline(RVC_GEN)) Mux(input(IS_RVC), B(2), B(4)) else B(4)).asUInt.resized + branch_src2 := (if(pipeline.config.withRvc) Mux(input(IS_RVC), B(2), B(4)) else B(4)).asUInt.resized } } } @@ -344,7 +343,7 @@ class BranchPlugin(earlyBranch : Boolean, val branchAdder = branch_src1 + input(BRANCH_SRC2) insert(BRANCH_CALC) := branchAdder(31 downto 1) @@ U"0" - insert(NEXT_PC) := input(PC) + (if(pipeline(RVC_GEN)) ((input(IS_RVC)) ? U(2) | U(4)) else 4) + insert(NEXT_PC) := input(PC) + (if(pipeline.config.withRvc) ((input(IS_RVC)) ? U(2) | U(4)) else 4) insert(TARGET_MISSMATCH) := decode.input(PC) =/= input(BRANCH_CALC) } @@ -357,7 +356,7 @@ class BranchPlugin(earlyBranch : Boolean, fetchPrediction.rsp.wasRight := ! predictionMissmatch fetchPrediction.rsp.finalPc := input(BRANCH_CALC) fetchPrediction.rsp.sourceLastWord := { - if(pipeline(RVC_GEN)) + if(pipeline.config.withRvc) ((!input(IS_RVC) && input(PC)(1)) ? input(NEXT_PC) | input(PC)) else input(PC) diff --git a/src/main/scala/vexriscv/plugin/DebugPlugin.scala b/src/main/scala/vexriscv/plugin/DebugPlugin.scala index 491fc6d0..c75db107 100644 --- a/src/main/scala/vexriscv/plugin/DebugPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DebugPlugin.scala @@ -304,7 +304,7 @@ class DebugPlugin(var debugClockDomain : ClockDomain, hardwareBreakpointCount : } //Avoid having two C instruction executed in a single step - if(pipeline(RVC_GEN)){ + if(pipeline.config.withRvc){ val cleanStep = RegNext(stepIt && decode.arbitration.isFiring) init(False) execute.arbitration.flushNext setWhen(cleanStep) } diff --git a/src/main/scala/vexriscv/plugin/Fetcher.scala b/src/main/scala/vexriscv/plugin/Fetcher.scala index 1de5021a..0bdecd5c 100644 --- a/src/main/scala/vexriscv/plugin/Fetcher.scala +++ b/src/main/scala/vexriscv/plugin/Fetcher.scala @@ -38,6 +38,9 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, var incomingInstruction : Bool = null override def incoming() = incomingInstruction + + override def withRvc(): Boolean = compressedGen + var injectionPort : Stream[Bits] = null override def getInjectionPort() = { injectionPort = Stream(Bits(32 bits)) @@ -63,8 +66,6 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, incomingInstruction = False if(resetVector == null) externalResetVector = in(UInt(32 bits).setName("externalResetVector")) - pipeline(RVC_GEN) = compressedGen - prediction match { case NONE => case STATIC | DYNAMIC => { @@ -261,7 +262,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, whenFalse = input.rsp.inst(31 downto 16) ## (throw2Bytes ? input.rsp.inst(31 downto 16) | input.rsp.inst(15 downto 0)) ) val isRvc = raw(1 downto 0) =/= 3 - val decompressed = RvcDecompressor(raw(15 downto 0)) + val decompressed = RvcDecompressor(raw(15 downto 0), pipeline.config.withRvf, pipeline.config.withRvd) output.valid := input.valid && !(throw2Bytes && !bufferValid && !isInputHighRvc) output.pc := input.pc output.isRvc := isRvc @@ -467,7 +468,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, val branchContext = branchStage.input(PREDICTION_CONTEXT) val moreJump = decodePrediction.rsp.wasWrong ^ branchContext.line.history.msb - historyWrite.address := branchStage.input(PC)(2, historyRamSizeLog2 bits) + (if(pipeline(RVC_GEN)) + historyWrite.address := branchStage.input(PC)(2, historyRamSizeLog2 bits) + (if(pipeline.config.withRvc) ((!branchStage.input(IS_RVC) && branchStage.input(PC)(1)) ? U(1) | U(0)) else U(0)) @@ -487,7 +488,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, decodePrediction.cmd.hadBranch := decode.input(BRANCH_CTRL) === BranchCtrlEnum.JAL || (decode.input(BRANCH_CTRL) === BranchCtrlEnum.B && conditionalBranchPrediction) - val noPredictionOnMissaligned = (!pipeline(RVC_GEN)) generate new Area{ + val noPredictionOnMissaligned = (!pipeline.config.withRvc) generate new Area{ val missaligned = decode.input(BRANCH_CTRL).mux( BranchCtrlEnum.JAL -> imm.j_sext(1), default -> imm.b_sext(1) diff --git a/src/main/scala/vexriscv/plugin/FpuPlugin.scala b/src/main/scala/vexriscv/plugin/FpuPlugin.scala index 5a6f1237..0bcb1fc7 100644 --- a/src/main/scala/vexriscv/plugin/FpuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/FpuPlugin.scala @@ -11,7 +11,7 @@ import scala.collection.mutable.ArrayBuffer class FpuPlugin(externalFpu : Boolean = false, simHalt : Boolean = false, - p : FpuParameter) extends Plugin[VexRiscv] with VexRiscvRegressionArg { + val p : FpuParameter) extends Plugin[VexRiscv] with VexRiscvRegressionArg { object FPU_ENABLE extends Stageable(Bool()) object FPU_COMMIT extends Stageable(Bool()) diff --git a/src/main/scala/vexriscv/plugin/Misc.scala b/src/main/scala/vexriscv/plugin/Misc.scala index eba87e89..081a06a6 100644 --- a/src/main/scala/vexriscv/plugin/Misc.scala +++ b/src/main/scala/vexriscv/plugin/Misc.scala @@ -7,11 +7,11 @@ object RvcDecompressor{ def main(args: Array[String]): Unit = { SpinalVerilog(new Component{ - out(Delay((apply(Delay(in Bits(16 bits),2))),2)) + out(Delay((apply(Delay(in Bits(16 bits),2), false, false)),2)) }.setDefinitionName("Decompressor")) } - def apply(i : Bits): Bits ={ + def apply(i : Bits, rvf : Boolean, rvd : Boolean): Bits ={ val ret = Bits(32 bits).assignDontCare() val rch = B"01" ## i(9 downto 7) @@ -20,6 +20,8 @@ object RvcDecompressor{ val addi5spnImm = B"00" ## i(10 downto 7) ## i(12 downto 11) ## i(5) ## i(6) ## B"00" val lwImm = B"00000" ## i(5) ## i(12 downto 10) ## i(6) ## B"00" def swImm = lwImm + val ldImm = B"0000" ## i(6 downto 5) ## i(12 downto 10) ## B"000" + def sdImm = ldImm val addImm = B((11 downto 5) -> i(12), (4 downto 0) -> i(6 downto 2)) def lImm = addImm val jalImm = B((9 downto 0) -> i(12)) ## i(8) ## i(10 downto 9) ## i(6) ## i(7) ## i(2) ## i(11) ## i(5 downto 3) ## B"0" @@ -31,11 +33,8 @@ object RvcDecompressor{ def lwspImm = B"0000" ## i(3 downto 2) ## i(12) ## i(6 downto 4) ## B"00" def swspImm = B"0000" ## i(8 downto 7) ## i(12 downto 9) ## B"00" - - val lfdImm = B"0000" ## i(6 downto 5) ## i(12 downto 10) ## B"000" - def sfdImm = lfdImm - def lfdspImm = B"000" ## i(4 downto 2) ## i(12) ## i(6 downto 5) ## B"000" - def sfdspImm = B"000" ## i(9 downto 7) ## i(12 downto 10) ## B"000" + def ldspImm = B"000" ## i(4 downto 2) ## i(12) ## i(6 downto 5) ## B"000" + def sdspImm = B"000" ## i(9 downto 7) ## i(12 downto 10) ## B"000" val x0 = B"00000" @@ -44,12 +43,12 @@ object RvcDecompressor{ switch(i(1 downto 0) ## i(15 downto 13)){ is(0){ret := addi5spnImm ## B"00010" ## B"000" ## rcl ## B"0010011"} //C.ADDI4SPN -> addi rd0, x2, nzuimm[9:2]. - is(1){ret := lfdImm ## rch ## B"011" ## rcl ## B"0000111" } //C.FLD (w/ D ext) + if(rvd) is(1){ret := ldImm ## rch ## B"011" ## rcl ## B"0000111"} // C.FLD is(2){ret := lwImm ## rch ## B"010" ## rcl ## B"0000011"} //C.LW -> lw rd', offset[6:2](rs1') - is(3){ret := lwImm ## rch ## B"010" ## rcl ## B"0000111" } //C.FLW (w/ F ext) - is(5){ret := sfdImm(11 downto 5) ## rcl ## rch ## B"011" ## sfdImm(4 downto 0) ## B"0100111" } //C.FSD (w/ D ext) + if(rvf) is(3){ret := lwImm ## rch ## B"010" ## rcl ## B"0000111"} // C.FLW + if(rvd) is(5){ret := sdImm(11 downto 5) ## rcl ## rch ## B"011" ## sdImm(4 downto 0) ## B"0100111"} // C.FSD is(6){ret := swImm(11 downto 5) ## rcl ## rch ## B"010" ## swImm(4 downto 0) ## B"0100011"} //C.SW -> sw rs2',offset[6:2](rs1') - is(7){ret := swImm(11 downto 5) ## rcl ## rch ## B"010" ## swImm(4 downto 0) ## B"0100111" } //C.FSW (w/ F ext) + if(rvf) is(7){ret := swImm(11 downto 5) ## rcl ## rch ## B"010" ## swImm(4 downto 0) ## B"0100111"} // C.FSW is(8){ret := addImm ## i(11 downto 7) ## B"000" ## i(11 downto 7) ## B"0010011"} //C.ADDI -> addi rd, rd, nzimm[5:0]. is(9){ret := jalImm(20) ## jalImm(10 downto 1) ## jalImm(11) ## jalImm(19 downto 12) ## x1 ## B"1101111"} //C.JAL -> jalr x1, rs1, 0. is(10){ret := lImm ## B"00000" ## B"000" ## i(11 downto 7) ## B"0010011"} //C.LI -> addi rd, x0, imm[5:0]. @@ -85,9 +84,9 @@ object RvcDecompressor{ is(14){ ret := bImm(12) ## bImm(10 downto 5) ## x0 ## rch ## B"000" ## bImm(4 downto 1) ## bImm(11) ## B"1100011" } is(15){ ret := bImm(12) ## bImm(10 downto 5) ## x0 ## rch ## B"001" ## bImm(4 downto 1) ## bImm(11) ## B"1100011" } is(16){ ret := B"0000000" ## i(6 downto 2) ## i(11 downto 7) ## B"001" ## i(11 downto 7) ## B"0010011" } - is(17){ ret := lfdspImm ## x2 ## B"011" ## i(11 downto 7) ## B"0000111" } // C.FLDSP (w/ D ext) + if(rvd) is(17){ret := ldspImm ## x2 ## B"011" ## i(11 downto 7) ## B"0000111" } // C.FLDSP is(18){ ret := lwspImm ## x2 ## B"010" ## i(11 downto 7) ## B"0000011" } - is(19){ ret := lwspImm ## x2 ## B"010" ## i(11 downto 7) ## B"0000111" } // C.FLWSP (w/ F ext) + if(rvf) is(19){ret := lwspImm ## x2 ## B"010" ## i(11 downto 7) ## B"0000111" } // C.FLWSP is(20) { val add = B"000_0000" ## i(6 downto 2) ## (i(12) ? i(11 downto 7) | x0) ## B"000" ## i(11 downto 7) ## B"0110011" //add => add rd, rd, rs2 mv => add rd, x0, rs2 val j = B"0000_0000_0000" ## i(11 downto 7) ## B"000" ## (i(12) ? x1 | x0) ## B"1100111" //jr => jalr x0, rs1, 0. jalr => jalr x1, rs1, 0. @@ -95,9 +94,10 @@ object RvcDecompressor{ val addJ = (i(6 downto 2) === 0) ? j | add ret := (i(12 downto 2) === B"100_0000_0000") ? ebreak | addJ } - is(21){ ret := sfdspImm(11 downto 5) ## i(6 downto 2) ## x2 ## B"011" ## sfdspImm(4 downto 0) ## B"0100111" } // C.FSDSP (w/ D ext) + + if(rvd) is(21){ret := sdspImm(11 downto 5) ## i(6 downto 2) ## x2 ## B"011" ## sdspImm(4 downto 0) ## B"0100111" } // C.FSDSP is(22){ ret := swspImm(11 downto 5) ## i(6 downto 2) ## x2 ## B"010" ## swspImm(4 downto 0) ## B"0100011" } - is(23){ ret := swspImm(11 downto 5) ## i(6 downto 2) ## x2 ## B"010" ## swspImm(4 downto 0) ## B"0100111" } // C.FSWSP (w/ F ext) + if(rvf) is(23){ret := swspImm(11 downto 5) ## i(6 downto 2) ## x2 ## B"010" ## swspImm(4 downto 0) ## B"0100111" } // C.FSwSP } ret diff --git a/src/main/scala/vexriscv/plugin/SrcPlugin.scala b/src/main/scala/vexriscv/plugin/SrcPlugin.scala index eb5ab1f3..d67e7cc3 100644 --- a/src/main/scala/vexriscv/plugin/SrcPlugin.scala +++ b/src/main/scala/vexriscv/plugin/SrcPlugin.scala @@ -29,7 +29,7 @@ class SrcPlugin(separatedAddSub : Boolean = false, executeInsertion : Boolean = val imm = Riscv.IMM(input(INSTRUCTION)) insert(SRC1) := input(SRC1_CTRL).mux( Src1CtrlEnum.RS -> output(RS1), - Src1CtrlEnum.PC_INCREMENT -> (if(pipeline(RVC_GEN)) Mux(input(IS_RVC), B(2), B(4)) else B(4)).resized, + Src1CtrlEnum.PC_INCREMENT -> (if(pipeline.config.withRvc) Mux(input(IS_RVC), B(2), B(4)) else B(4)).resized, Src1CtrlEnum.IMU -> imm.u.resized, Src1CtrlEnum.URS1 -> input(INSTRUCTION)(Riscv.rs1Range).resized ) From 21c91c6b7086552ce870642346562796e43ce338 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 24 Mar 2021 16:21:37 +0100 Subject: [PATCH 628/951] fpu now lift wfi --- src/main/scala/vexriscv/plugin/FpuPlugin.scala | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/scala/vexriscv/plugin/FpuPlugin.scala b/src/main/scala/vexriscv/plugin/FpuPlugin.scala index 0bcb1fc7..0f63ab23 100644 --- a/src/main/scala/vexriscv/plugin/FpuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/FpuPlugin.scala @@ -306,6 +306,10 @@ class FpuPlugin(externalFpu : Boolean = false, insert(FPU_COMMIT_SYNC) := List(FpuOpcode.LOAD, FpuOpcode.FMV_W_X, FpuOpcode.I2F).map(_ === input(FPU_OPCODE)).orR insert(FPU_COMMIT_LOAD) := input(FPU_OPCODE) === FpuOpcode.LOAD + + if(serviceExist(classOf[IWake])) when(forked){ + service(classOf[IWake]).askWake() //Ensure that no WFI followed by a FPU stall the FPU interface for other CPU + } } writeBack plug new Area{ //WARNING IF STAGE CHANGE, update the regression rsp capture filter for the golden model (top->VexRiscv->lastStageIsFiring) From 6f481f51ef2bc9ec15866682087eb982ce865ae9 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 25 Mar 2021 14:13:12 +0100 Subject: [PATCH 629/951] Fetcher.decompressor ensure that the decoded instruction do not mutate when the pipeline is stalled (fix FPU cmd fork for rvc without injector stage) --- src/main/scala/vexriscv/plugin/Fetcher.scala | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/Fetcher.scala b/src/main/scala/vexriscv/plugin/Fetcher.scala index 0bdecd5c..8b276e13 100644 --- a/src/main/scala/vexriscv/plugin/Fetcher.scala +++ b/src/main/scala/vexriscv/plugin/Fetcher.scala @@ -256,10 +256,17 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, val throw2Bytes = throw2BytesReg || input.pc(1) val unaligned = throw2Bytes || bufferValid def aligned = !unaligned + + //Latch and patches are there to ensure that the decoded instruction do not mutate while being halted and unscheduled to ensure FpuPlugin cmd fork from consistancy + val bufferValidLatch = RegNextWhen(bufferValid, input.valid) + val throw2BytesLatch = RegNextWhen(throw2Bytes, input.valid) + val bufferValidPatched = input.valid ? bufferValid | bufferValidLatch + val throw2BytesPatched = input.valid ? throw2Bytes | throw2BytesLatch + val raw = Mux( - sel = bufferValid, + sel = bufferValidPatched, whenTrue = input.rsp.inst(15 downto 0) ## bufferData, - whenFalse = input.rsp.inst(31 downto 16) ## (throw2Bytes ? input.rsp.inst(31 downto 16) | input.rsp.inst(15 downto 0)) + whenFalse = input.rsp.inst(31 downto 16) ## (throw2BytesPatched ? input.rsp.inst(31 downto 16) | input.rsp.inst(15 downto 0)) ) val isRvc = raw(1 downto 0) =/= 3 val decompressed = RvcDecompressor(raw(15 downto 0), pipeline.config.withRvf, pipeline.config.withRvd) From 9462496386b193abc94b505cf8d49ef59aba9124 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 25 Mar 2021 14:14:19 +0100 Subject: [PATCH 630/951] Add rvc support and fix rvc with FPU --- .../scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala index 8af6bf1e..4f0936e8 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala @@ -115,6 +115,7 @@ object VexRiscvLitexSmpClusterCmdGen extends App { var aesInstruction = false var fpu = false var cpuPerFpu = 4 + var rvc = false var netlistDirectory = "." var netlistName = "VexRiscvLitexSmpCluster" assert(new scopt.OptionParser[Unit]("VexRiscvLitexSmpClusterCmdGen") { @@ -135,6 +136,7 @@ object VexRiscvLitexSmpClusterCmdGen extends App { opt[String]("wishbone-memory" ) action { (v, c) => wishboneMemory = v.toBoolean } opt[String]("fpu" ) action { (v, c) => fpu = v.toBoolean } opt[String]("cpu-per-fpu") action { (v, c) => cpuPerFpu = v.toInt } + opt[String]("rvc") action { (v, c) => rvc = v.toBoolean } }.parse(args)) val coherency = coherentDma || cpuCount > 1 @@ -157,7 +159,9 @@ object VexRiscvLitexSmpClusterCmdGen extends App { withFloat = fpu, withDouble = fpu, externalFpu = fpu, - loadStoreWidth = if(fpu) 64 else 32 + loadStoreWidth = if(fpu) 64 else 32, + rvc = rvc, + injectorStage = rvc ) if(aesInstruction) c.add(new AesPlugin) c From a8721b02de8288fa97903d6c98a8c0a0e5d230b8 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 29 Mar 2021 14:55:41 +0200 Subject: [PATCH 631/951] Add AES/FPU doc --- README.md | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 747bffef..1bc4557b 100644 --- a/README.md +++ b/README.md @@ -28,12 +28,13 @@ This repository hosts a RISC-V implementation written in SpinalHDL. Here are some specs : -- RV32I[M][C][A] instruction set (Atomic only inside a single core) +- RV32I[M][A][F[D]][C] instruction set - Pipelined from 2 to 5+ stages ([Fetch*X], Decode, Execute, [Memory], [WriteBack]) - 1.44 DMIPS/Mhz --no-inline when nearly all features are enabled (1.57 DMIPS/Mhz when the divider lookup table is enabled) - Optimized for FPGA, does not use any vendor specific IP block / primitive - AXI4, Avalon, wishbone ready - Optional MUL/DIV extensions +- Optional F32/F64 FPU (require data cache for now) - Optional instruction and data caches - Optional hardware refilled MMU - Optional debug extension allowing Eclipse debugging via a GDB >> openOCD >> JTAG connection @@ -688,7 +689,7 @@ Features : Accuracy, roundings (RNE, RTZ, RDN, RUP, RMM) and compliance: - Fully implemented excepted in the cases specified bellow -- In FMA, the result of the multiplication is truncated before the addition (keep mantissa width bits) +- In FMA, the result of the multiplication is rounded before the addition (keep mantissa width + 2 bits) - A very special corner case of underflow flag do not follow IEEE 754 (rounding from subnormal to normal number) - Very specific, but SGNJ instruction will not mutate the value from/to F32/F64 (no NaN-boxing mutation) @@ -715,7 +716,7 @@ Fpu 64/32 bits -> Artix 7 relaxed -> 101 Mhz 3336 LUT 3033 FF Artix 7 FMax -> 165 Mhz 3728 LUT 3175 FF ``` - + ### Plugins This chapter describes the currently implemented plugins. @@ -1150,4 +1151,13 @@ Allow the integration of a internal or a external FPU into VexRiscv (See the FPU | externalFpu | Boolean | When false the FPU is instanciated in Vex, else the plugin has a `port` interface to which you can connect an external FPU | | p | FpuParameter | Parameter with which the connected FPU will be created | +#### AesPlugin +This plugin allow to accelerate AES encryption/decryption by using an internal ROM to solve SBOX and permutations, allowing in practice to execute one AES round in about 21 cycles. + +For more documentation, check src/main/scala/vexriscv/plugin/AesPlugin.scala, a software C driver can be found here : + +It was also ported on libressl via the following patch : + + +Speed up of 4 was observed in libressl running in linux. \ No newline at end of file From 9ac6625ef34dd1606ced2afddeaf23e4a1942579 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 29 Mar 2021 16:31:18 +0200 Subject: [PATCH 632/951] FpuCore improve FMA rounding --- src/main/scala/vexriscv/ip/fpu/FpuCore.scala | 42 +++++++++++--------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala index 256adfa9..ffe05723 100644 --- a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala +++ b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala @@ -119,9 +119,10 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } + val addExtraBits = 2 case class AddInput() extends Bundle{ val source = Source() - val rs1, rs2 = p.internalFloating() + val rs1, rs2 = FpuFloat(exponentSize = p.internalExponentSize, mantissaSize = p.internalMantissaSize+addExtraBits) val rd = p.rfAddress() val roundMode = FpuRoundMode() val format = p.withDouble generate FpuFormat() @@ -398,10 +399,19 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ mulToAdd.ready := add.ready add.payload := mulToAdd.payload when(!mulToAdd.valid) { - add.payload.assignSomeByName(input.payload) - add.rs2.sign.allowOverride; - add.rs2.sign := input.rs2.sign ^ input.arg(0) + add.source := input.source + add.rd := input.rd + add.roundMode := input.roundMode + if(p.withDouble) add.format := input.format add.needCommit := True + add.rs1.special := input.rs1.special + add.rs2.special := input.rs2.special + add.rs1.exponent := input.rs1.exponent + add.rs2.exponent := input.rs2.exponent + add.rs1.sign := input.rs1.sign + add.rs2.sign := input.rs2.sign ^ input.arg(0) + add.rs1.mantissa := input.rs1.mantissa << addExtraBits + add.rs2.mantissa := input.rs2.mantissa << addExtraBits } } } @@ -1007,11 +1017,12 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ mulToAdd.valid := input.valid && input.add mulToAdd.source := input.source - mulToAdd.rs1.mantissa := norm.output.mantissa >> 1 //FMA Precision lost + mulToAdd.rs1.mantissa := norm.output.mantissa @@ norm.scrap //FMA Precision lost mulToAdd.rs1.exponent := norm.output.exponent mulToAdd.rs1.sign := norm.output.sign mulToAdd.rs1.special := norm.output.special mulToAdd.rs2 := input.rs3 + mulToAdd.rs2.mantissa.removeAssignments() := input.rs3.mantissa << addExtraBits mulToAdd.rd := input.rd mulToAdd.roundMode := input.roundMode mulToAdd.needCommit := False @@ -1374,7 +1385,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ class ShifterOutput extends AddInput{ val xSign, ySign = Bool() - val xMantissa, yMantissa = UInt(p.internalMantissaSize+3 bits) + val xMantissa, yMantissa = UInt(p.internalMantissaSize+1+addExtraBits bits) val xyExponent = UInt(p.internalExponentSize bits) val xySign = Bool() val roundingScrap = Bool() @@ -1386,12 +1397,8 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ output.payload.assignSomeByName(input.payload) val exp21 = input.rs2.exponent -^ input.rs1.exponent -// val rs1ExponentBigger = (exp21.msb || input.rs2.isZero) && !input.rs1.isZero -// val rs1ExponentEqual = input.rs1.exponent === input.rs2.exponent -// val rs1MantissaBigger = input.rs1.mantissa > input.rs2.mantissa -// val absRs1Bigger = ((rs1ExponentBigger || rs1ExponentEqual && rs1MantissaBigger) && !input.rs1.isZero || input.rs1.isInfinity) && !input.rs2.isInfinity val shiftBy = exp21.asSInt.abs//rs1ExponentBigger ? (0-exp21) | exp21 - val shiftOverflow = (shiftBy >= p.internalMantissaSize+3) + val shiftOverflow = (shiftBy >= p.internalMantissaSize+1+addExtraBits) val passThrough = shiftOverflow || (input.rs1.isZero) || (input.rs2.isZero) def absRs1Bigger = input.absRs1Bigger @@ -1401,8 +1408,8 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val xySign = absRs1Bigger ? input.rs1.sign | input.rs2.sign output.xSign := xySign ^ (rs1ExponentBigger ? input.rs1.sign | input.rs2.sign) output.ySign := xySign ^ (rs1ExponentBigger ? input.rs2.sign | input.rs1.sign) - val xMantissa = U"1" @@ (rs1ExponentBigger ? input.rs1.mantissa | input.rs2.mantissa) @@ U"00" - val yMantissaUnshifted = U"1" @@ (rs1ExponentBigger ? input.rs2.mantissa | input.rs1.mantissa) @@ U"00" + val xMantissa = U"1" @@ (rs1ExponentBigger ? input.rs1.mantissa | input.rs2.mantissa) + val yMantissaUnshifted = U"1" @@ (rs1ExponentBigger ? input.rs2.mantissa | input.rs1.mantissa) var yMantissa = CombInit(yMantissaUnshifted) val roundingScrap = False for(i <- log2Up(p.internalMantissaSize) - 1 downto 0){ @@ -1420,7 +1427,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } class MathOutput extends ShifterOutput{ - val xyMantissa = UInt(p.internalMantissaSize+4 bits) + val xyMantissa = UInt(p.internalMantissaSize+1+addExtraBits+1 bits) } val math = new Area { @@ -1436,8 +1443,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ } class OhOutput extends MathOutput{ -// val shiftOh = Vec(Bool, p.internalMantissaSize+4) - val shift = UInt(log2Up(p.internalMantissaSize+4) bits) + val shift = UInt(log2Up(p.internalMantissaSize+1+addExtraBits+1) bits) } val oh = new Area { @@ -1456,7 +1462,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ class NormOutput extends AddInput{ - val mantissa = UInt(p.internalMantissaSize+4 bits) + val mantissa = UInt(p.internalMantissaSize+1+addExtraBits+1 bits) val exponent = UInt(p.internalExponentSize+1 bits) val infinityNan, forceNan, forceZero, forceInfinity = Bool() val xySign, roundingScrap = Bool() @@ -1486,7 +1492,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ output.source := input.source output.rd := input.rd output.value.sign := xySign - output.value.mantissa := (mantissa >> 2).resized + output.value.mantissa := (mantissa >> addExtraBits).resized output.value.exponent := exponent.resized output.value.special := False output.roundMode := input.roundMode From a42c0891196d26594e17c4e9c426bff4c4371b0d Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 31 Mar 2021 19:03:38 +0200 Subject: [PATCH 633/951] IBusSimplePlugin ensure AHB persistance --- src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala index 8f36e4c8..5780ce8a 100644 --- a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala @@ -180,6 +180,7 @@ case class IBusSimpleBus(plugin: IBusSimplePlugin) extends Bundle with IMasterSl //cmdForkPersistence need to bet set def toAhbLite3Master(): AhbLite3Master = { + assert(plugin.cmdForkPersistence) val bus = AhbLite3Master(IBusSimpleBus.getAhbLite3Config()) bus.HADDR := this.cmd.pc bus.HWRITE := False From 73893ce5d98d89a20c4b0dadc026d96538b426be Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 2 Apr 2021 09:20:26 +0200 Subject: [PATCH 634/951] CfuPlugin names fixes --- src/main/scala/vexriscv/plugin/CfuPlugin.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/plugin/CfuPlugin.scala b/src/main/scala/vexriscv/plugin/CfuPlugin.scala index bb2cb568..c96be098 100644 --- a/src/main/scala/vexriscv/plugin/CfuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CfuPlugin.scala @@ -111,7 +111,7 @@ class CfuPlugin(val stageCount : Int, val CFU_ENABLE = new Stageable(Bool()).setCompositeName(this, "CFU_ENABLE") val CFU_IN_FLIGHT = new Stageable(Bool()).setCompositeName(this, "CFU_IN_FLIGHT") val CFU_ENCODING = new Stageable(UInt(log2Up(encodings.size) bits)).setCompositeName(this, "CFU_ENCODING") - val CFU_INPUT_2_KIND = new Stageable(CfuPlugin.Input2Kind()).setCompositeName(this, "CFU_ENCODING") + val CFU_INPUT_2_KIND = new Stageable(CfuPlugin.Input2Kind()).setCompositeName(this, "CFU_INPUT_2_KIND") override def setup(pipeline: VexRiscv): Unit = { import pipeline._ From 66f5c3079b3d369615717d88eb33e899819d9eef Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 2 Apr 2021 09:20:26 +0200 Subject: [PATCH 635/951] CfuPlugin names fixes --- src/main/scala/vexriscv/plugin/CfuPlugin.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/plugin/CfuPlugin.scala b/src/main/scala/vexriscv/plugin/CfuPlugin.scala index cd81d245..d6508132 100644 --- a/src/main/scala/vexriscv/plugin/CfuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CfuPlugin.scala @@ -114,7 +114,7 @@ class CfuPlugin(val stageCount : Int, val CFU_ENABLE = new Stageable(Bool()).setCompositeName(this, "CFU_ENABLE") val CFU_IN_FLIGHT = new Stageable(Bool()).setCompositeName(this, "CFU_IN_FLIGHT") val CFU_ENCODING = new Stageable(UInt(log2Up(encodings.size) bits)).setCompositeName(this, "CFU_ENCODING") - val CFU_INPUT_2_KIND = new Stageable(CfuPlugin.Input2Kind()).setCompositeName(this, "CFU_ENCODING") + val CFU_INPUT_2_KIND = new Stageable(CfuPlugin.Input2Kind()).setCompositeName(this, "CFU_INPUT_2_KIND") override def setup(pipeline: VexRiscv): Unit = { import pipeline._ From 36c896f95b6cd85188ad56b402b5038772692737 Mon Sep 17 00:00:00 2001 From: Tim Callahan Date: Fri, 2 Apr 2021 13:16:53 -0700 Subject: [PATCH 636/951] Update CFU immed field to use sext([31:24]) to match spec. Signed-off-by: Tim Callahan --- src/main/scala/vexriscv/Riscv.scala | 2 ++ src/main/scala/vexriscv/plugin/CfuPlugin.scala | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/Riscv.scala b/src/main/scala/vexriscv/Riscv.scala index 23ab965a..dd9e4bc8 100644 --- a/src/main/scala/vexriscv/Riscv.scala +++ b/src/main/scala/vexriscv/Riscv.scala @@ -16,6 +16,7 @@ object Riscv{ case class IMM(instruction : Bits) extends Area{ // immediates def i = instruction(31 downto 20) + def h = instruction(31 downto 24) def s = instruction(31 downto 25) ## instruction(11 downto 7) def b = instruction(31) ## instruction(7) ## instruction(30 downto 25) ## instruction(11 downto 8) def u = instruction(31 downto 12) ## U"x000" @@ -24,6 +25,7 @@ object Riscv{ // sign-extend immediates def i_sext = B((19 downto 0) -> i(11)) ## i + def h_sext = B((23 downto 0) -> h(7)) ## h def s_sext = B((19 downto 0) -> s(11)) ## s def b_sext = B((18 downto 0) -> b(11)) ## b ## False def j_sext = B((10 downto 0) -> j(19)) ## j ## False diff --git a/src/main/scala/vexriscv/plugin/CfuPlugin.scala b/src/main/scala/vexriscv/plugin/CfuPlugin.scala index d6508132..868ef25e 100644 --- a/src/main/scala/vexriscv/plugin/CfuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CfuPlugin.scala @@ -187,7 +187,7 @@ class CfuPlugin(val stageCount : Int, if(p.CFU_INPUTS >= 1) bus.cmd.inputs(0) := input(RS1) if(p.CFU_INPUTS >= 2) bus.cmd.inputs(1) := input(CFU_INPUT_2_KIND).mux( CfuPlugin.Input2Kind.RS -> input(RS2), - CfuPlugin.Input2Kind.IMM_I -> IMM(input(INSTRUCTION)).i_sext + CfuPlugin.Input2Kind.IMM_I -> IMM(input(INSTRUCTION)).h_sext ) } From bf399cc927ceb158a7fc72b89078164488b50b91 Mon Sep 17 00:00:00 2001 From: Samuel Lindemer Date: Fri, 26 Mar 2021 10:12:03 +0100 Subject: [PATCH 637/951] Initial commit of optimized PMP plugin --- .../scala/vexriscv/plugin/CsrPlugin.scala | 50 ++- .../scala/vexriscv/plugin/PmpPlugin.scala | 367 +++++++++++------- src/test/cpp/raw/pmp/build/pmp.asm | 243 +++++++----- src/test/cpp/raw/pmp/build/pmp.elf | Bin 5480 -> 5680 bytes src/test/cpp/raw/pmp/build/pmp.hex | 68 ++-- src/test/cpp/raw/pmp/build/pmp.map | 24 +- src/test/cpp/raw/pmp/src/crt.S | 89 +++-- 7 files changed, 521 insertions(+), 320 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index c980fa8d..7f4c7744 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -32,6 +32,14 @@ object CsrAccess { object NONE extends CsrAccess } +object CsrPlugin { + object IS_CSR extends Stageable(Bool) + object CSR_WRITE_OPCODE extends Stageable(Bool) + object CSR_READ_OPCODE extends Stageable(Bool) + object IS_PMP_CFG extends Stageable(Bool) + object IS_PMP_ADDR extends Stageable(Bool) +} + case class ExceptionPortInfo(port : Flow[ExceptionCause],stage : Stage, priority : Int) case class CsrPluginConfig( catchIllegalAccess : Boolean, @@ -399,6 +407,7 @@ trait IWake{ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with ExceptionService with PrivilegeService with InterruptionInhibitor with ExceptionInhibitor with IContextSwitching with CsrInterface with IWake{ import config._ import CsrAccess._ + import CsrPlugin._ assert(!(wfiGenAsNop && wfiGenAsWait)) @@ -440,9 +449,6 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep } object ENV_CTRL extends Stageable(EnvCtrlEnum()) - object IS_CSR extends Stageable(Bool) - object CSR_WRITE_OPCODE extends Stageable(Bool) - object CSR_READ_OPCODE extends Stageable(Bool) object PIPELINED_CSR_READ extends Stageable(Bits(32 bits)) var allowInterrupts : Bool = null @@ -1029,9 +1035,13 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep || (input(INSTRUCTION)(14 downto 13) === B"11" && imm.z === 0) ) insert(CSR_READ_OPCODE) := input(INSTRUCTION)(13 downto 7) =/= B"0100000" + + if (pipeline.serviceExist(classOf[PmpPlugin])) { + insert(IS_PMP_CFG) := input(INSTRUCTION)(31 downto 24) === 0x3a + insert(IS_PMP_ADDR) := input(INSTRUCTION)(31 downto 24) === 0x3b + } } - execute plug new Area{ import execute._ //Manage WFI instructions @@ -1103,25 +1113,27 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep True -> Mux(input(INSTRUCTION)(12), readToWriteData & ~writeSrc, readToWriteData | writeSrc) ) - when(arbitration.isValid && input(IS_CSR)) { - if(!pipelineCsrRead) output(REGFILE_WRITE_DATA) := readData - arbitration.haltItself setWhen(blockedBySideEffects) - } - if(pipelineCsrRead){ - insert(PIPELINED_CSR_READ) := readData - when(memory.arbitration.isValid && memory.input(IS_CSR)) { - memory.output(REGFILE_WRITE_DATA) := memory.input(PIPELINED_CSR_READ) + val csrAddress = input(INSTRUCTION)(csrRange) + val pmpAccess = if (pipeline.serviceExist(classOf[PmpPlugin])) { + input(IS_PMP_CFG) | input(IS_PMP_ADDR) + } else False + + when (~pmpAccess) { + when(arbitration.isValid && input(IS_CSR)) { + if(!pipelineCsrRead) output(REGFILE_WRITE_DATA) := readData + arbitration.haltItself setWhen(blockedBySideEffects) } + if(pipelineCsrRead){ + insert(PIPELINED_CSR_READ) := readData + when(memory.arbitration.isValid && memory.input(IS_CSR)) { + memory.output(REGFILE_WRITE_DATA) := memory.input(PIPELINED_CSR_READ) + } + } + }.elsewhen(arbitration.isValid && input(IS_CSR)) { + illegalAccess := False } -// -// Component.current.rework{ -// when(arbitration.isFiring && input(IS_CSR)) { -// memory.input(REGFILE_WRITE_DATA).getDrivingReg := readData -// } -// } //Translation of the csrMapping into real logic - val csrAddress = input(INSTRUCTION)(csrRange) Component.current.afterElaboration{ def doJobs(jobs : ArrayBuffer[Any]): Unit ={ val withWrite = jobs.exists(j => j.isInstanceOf[CsrWrite] || j.isInstanceOf[CsrOnWrite] || j.isInstanceOf[CsrDuringWrite]) diff --git a/src/main/scala/vexriscv/plugin/PmpPlugin.scala b/src/main/scala/vexriscv/plugin/PmpPlugin.scala index e6cb396f..357d5b8c 100644 --- a/src/main/scala/vexriscv/plugin/PmpPlugin.scala +++ b/src/main/scala/vexriscv/plugin/PmpPlugin.scala @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Samuel Lindemer + * Copyright (c) 2021 Samuel Lindemer * * SPDX-License-Identifier: MIT */ @@ -7,9 +7,11 @@ package vexriscv.plugin import vexriscv.{VexRiscv, _} +import vexriscv.plugin.CsrPlugin.{_} +import vexriscv.plugin.MemoryTranslatorPort.{_} import spinal.core._ import spinal.lib._ -import scala.collection.mutable.ArrayBuffer +import spinal.lib.fsm._ /* Each 32-bit pmpcfg# register contains four 8-bit configuration sections. * These section numbers contain flags which apply to regions defined by the @@ -63,104 +65,70 @@ import scala.collection.mutable.ArrayBuffer * register defines a 4-byte wide region. */ -case class PmpRegister(previous : PmpRegister) extends Area { - +trait Pmp { def OFF = 0 def TOR = 1 def NA4 = 2 def NAPOT = 3 - val state = new Area { - val r, w, x = Reg(Bool) - val l = RegInit(False) - val a = Reg(UInt(2 bits)) init(0) - val addr = Reg(UInt(32 bits)) + def xlen = 32 + def rBit = 0 + def wBit = 1 + def xBit = 2 + def aBits = 4 downto 3 + def lBit = 7 +} + +class PmpSetter() extends Component with Pmp { + val io = new Bundle { + val a = in Bits(2 bits) + val addr = in UInt(xlen bits) + val prevHi = in UInt(30 bits) + val boundLo, boundHi = out UInt(30 bits) } - // CSR writes connect to these signals rather than the internal state - // registers. This makes locking and WARL possible. - val csr = new Area { - val r, w, x = Bool - val l = Bool - val a = UInt(2 bits) - val addr = UInt(32 bits) - } + val shifted = io.addr(29 downto 0) + io.boundLo := shifted + io.boundHi := shifted - // Last valid assignment wins; nothing happens if a user-initiated write did - // not occur on this clock cycle. - csr.r := state.r - csr.w := state.w - csr.x := state.x - csr.l := state.l - csr.a := state.a - csr.addr := state.addr - - // Computed PMP region bounds - val region = new Area { - val valid, locked = Bool - val start, end = UInt(32 bits) - } - - when(~state.l) { - state.r := csr.r - state.w := csr.w - state.x := csr.x - state.l := csr.l - state.a := csr.a - state.addr := csr.addr - - if (csr.l == True & csr.a == TOR) { - previous.state.l := True + switch (io.a) { + is (TOR) { + io.boundLo := io.prevHi } - } - - val shifted = state.addr |<< 2 - val mask = state.addr & ~(state.addr + 1) - val masked = (state.addr & ~mask) |<< 2 - - // PMP changes take effect two clock cycles after the initial CSR write (i.e., - // settings propagate from csr -> state -> region). - region.locked := state.l - region.valid := True - - switch(csr.a) { - is(TOR) { - if (previous == null) region.start := 0 - else region.start := previous.region.end - region.end := shifted + is (NA4) { + io.boundHi := shifted + 1 } - is(NA4) { - region.start := shifted - region.end := shifted + 4 - } - is(NAPOT) { - region.start := masked - region.end := masked + ((mask + 1) |<< 3) - } - default { - region.start := 0 - region.end := shifted - region.valid := False + is (NAPOT) { + val mask = io.addr & ~(io.addr + 1) + val boundLo = (io.addr ^ mask)(29 downto 0) + io.boundLo := boundLo + io.boundHi := boundLo + ((mask + 1) |<< 3)(29 downto 0) } } } case class ProtectedMemoryTranslatorPort(bus : MemoryTranslatorBus) -class PmpPlugin(regions : Int, ioRange : UInt => Bool) extends Plugin[VexRiscv] with MemoryTranslator { - - // Each pmpcfg# CSR configures four regions. - assert((regions % 4) == 0) - - val pmps = ArrayBuffer[PmpRegister]() - val portsInfo = ArrayBuffer[ProtectedMemoryTranslatorPort]() +class PmpPlugin(regions : Int, ioRange : UInt => Bool) extends Plugin[VexRiscv] with MemoryTranslator with Pmp { + assert(regions % 4 == 0) + assert(regions <= 16) + var setter : PmpSetter = null + var dPort, iPort : ProtectedMemoryTranslatorPort = null + override def newTranslationPort(priority : Int, args : Any): MemoryTranslatorBus = { val port = ProtectedMemoryTranslatorPort(MemoryTranslatorBus(new MemoryTranslatorBusParameter(0, 0))) - portsInfo += port + priority match { + case PRIORITY_INSTRUCTION => iPort = port + case PRIORITY_DATA => dPort = port + } port.bus } + override def setup(pipeline: VexRiscv): Unit = { + setter = new PmpSetter() + } + override def build(pipeline: VexRiscv): Unit = { import pipeline.config._ import pipeline._ @@ -169,78 +137,201 @@ class PmpPlugin(regions : Int, ioRange : UInt => Bool) extends Plugin[VexRiscv] val csrService = pipeline.service(classOf[CsrInterface]) val privilegeService = pipeline.service(classOf[PrivilegeService]) - val core = pipeline plug new Area { + val pmpaddr = Mem(UInt(xlen bits), regions) + val pmpcfg = Reg(Bits(8 * regions bits)) init(0) + val boundLo, boundHi = Mem(UInt(30 bits), regions) + val cfgRegion = pmpcfg.subdivideIn(8 bits) + val cfgRegister = pmpcfg.subdivideIn(xlen bits) + val lockMask = Reg(Bits(4 bits)) init(B"4'0") - // Instantiate pmpaddr0 ... pmpaddr# CSRs. - for (i <- 0 until regions) { - if (i == 0) { - pmps += PmpRegister(null) - } else { - pmps += PmpRegister(pmps.last) + execute plug new Area { + import execute._ + + val csrAddress = input(INSTRUCTION)(csrRange) + val accessAddr = input(IS_PMP_ADDR) + val accessCfg = input(IS_PMP_CFG) + val pmpWrite = arbitration.isValid && input(IS_CSR) && input(CSR_WRITE_OPCODE) & (accessAddr | accessCfg) + val pmpRead = arbitration.isValid && input(IS_CSR) && input(CSR_READ_OPCODE) & (accessAddr | accessCfg) + val pmpIndex = csrAddress(log2Up(regions) - 1 downto 0).asUInt + val pmpSelect = pmpIndex(log2Up(regions) - 3 downto 0) + + val readAddr = pmpaddr.readAsync(pmpIndex).asBits + val readCfg = cfgRegister(pmpSelect) + val readToWrite = Mux(accessCfg, readCfg, readAddr) + val writeSrc = input(SRC1) + val writeData = input(INSTRUCTION)(13).mux( + False -> writeSrc, + True -> Mux( + input(INSTRUCTION)(12), + readToWrite & ~writeSrc, + readToWrite | writeSrc + ) + ) + + val writer = new Area { + when (accessCfg) { + when (pmpRead) { + output(REGFILE_WRITE_DATA).assignFromBits(readCfg) + } + when (pmpWrite) { + switch(pmpSelect) { + for (i <- 0 until (regions / 4)) { + is(i) { + for (j <- Range(0, xlen, 8)) { + val bitRange = j + xlen * i + lBit downto j + xlen * i + val overwrite = writeData.subdivideIn(8 bits)(j / 8) + val locked = cfgRegister(i).subdivideIn(8 bits)(j / 8)(lBit) + lockMask(j / 8) := locked + when (~locked) { + pmpcfg(bitRange).assignFromBits(overwrite) + if (j != 0 || i != 0) { + when (overwrite(lBit) & overwrite(aBits) === TOR) { + pmpcfg(j + xlen * i - 1) := True + } + } + } + } + } + } + } + } + }.elsewhen (accessAddr) { + when (pmpRead) { + output(REGFILE_WRITE_DATA) := readAddr + } } - csrService.r(0x3b0 + i, pmps(i).state.addr) - csrService.w(0x3b0 + i, pmps(i).csr.addr) + val locked = cfgRegion(pmpIndex)(lBit) + pmpaddr.write(pmpIndex, writeData.asUInt, ~locked & pmpWrite & accessAddr) } - // Instantiate pmpcfg0 ... pmpcfg# CSRs. - for (i <- 0 until (regions / 4)) { - csrService.r(0x3a0 + i, - 31 -> pmps((i * 4) + 3).state.l, 23 -> pmps((i * 4) + 2).state.l, - 15 -> pmps((i * 4) + 1).state.l, 7 -> pmps((i * 4) ).state.l, - 27 -> pmps((i * 4) + 3).state.a, 26 -> pmps((i * 4) + 3).state.x, - 25 -> pmps((i * 4) + 3).state.w, 24 -> pmps((i * 4) + 3).state.r, - 19 -> pmps((i * 4) + 2).state.a, 18 -> pmps((i * 4) + 2).state.x, - 17 -> pmps((i * 4) + 2).state.w, 16 -> pmps((i * 4) + 2).state.r, - 11 -> pmps((i * 4) + 1).state.a, 10 -> pmps((i * 4) + 1).state.x, - 9 -> pmps((i * 4) + 1).state.w, 8 -> pmps((i * 4) + 1).state.r, - 3 -> pmps((i * 4) ).state.a, 2 -> pmps((i * 4) ).state.x, - 1 -> pmps((i * 4) ).state.w, 0 -> pmps((i * 4) ).state.r - ) - csrService.w(0x3a0 + i, - 31 -> pmps((i * 4) + 3).csr.l, 23 -> pmps((i * 4) + 2).csr.l, - 15 -> pmps((i * 4) + 1).csr.l, 7 -> pmps((i * 4) ).csr.l, - 27 -> pmps((i * 4) + 3).csr.a, 26 -> pmps((i * 4) + 3).csr.x, - 25 -> pmps((i * 4) + 3).csr.w, 24 -> pmps((i * 4) + 3).csr.r, - 19 -> pmps((i * 4) + 2).csr.a, 18 -> pmps((i * 4) + 2).csr.x, - 17 -> pmps((i * 4) + 2).csr.w, 16 -> pmps((i * 4) + 2).csr.r, - 11 -> pmps((i * 4) + 1).csr.a, 10 -> pmps((i * 4) + 1).csr.x, - 9 -> pmps((i * 4) + 1).csr.w, 8 -> pmps((i * 4) + 1).csr.r, - 3 -> pmps((i * 4) ).csr.a, 2 -> pmps((i * 4) ).csr.x, - 1 -> pmps((i * 4) ).csr.w, 0 -> pmps((i * 4) ).csr.r - ) - } + val controller = new StateMachine { + val counter = Reg(UInt(log2Up(regions) bits)) init(0) + val enable = RegInit(False) - // Connect memory ports to PMP logic. - val ports = for ((port, portId) <- portsInfo.zipWithIndex) yield new Area { + val stateIdle : State = new State with EntryPoint { + onEntry { + lockMask := B"4'x0" + enable := False + counter := 0 + } + onExit { + enable := True + arbitration.haltItself := True + } + whenIsActive { + when (pmpWrite) { + when (accessCfg) { + goto(stateCfg) + }.elsewhen (accessAddr) { + goto(stateAddr) + } + } + } + } - val address = port.bus.cmd(0).virtualAddress - port.bus.rsp.physicalAddress := address + val stateCfg : State = new State { + onEntry (counter := pmpIndex(log2Up(regions) - 3 downto 0) @@ U"2'00") + whenIsActive { + counter := counter + 1 + when (counter(1 downto 0) === 3) { + goto(stateIdle) + } otherwise { + arbitration.haltItself := True + } + } + } - // Only the first matching PMP region applies. - val hits = pmps.map(pmp => pmp.region.valid & - pmp.region.start <= address & - pmp.region.end > address & - (pmp.region.locked | ~privilegeService.isMachine())) + val stateAddr : State = new State { + onEntry (counter := pmpIndex) + whenIsActive { + counter := counter + 1 + when (counter === (pmpIndex + 1) | counter === 0) { + goto(stateIdle) + } otherwise { + arbitration.haltItself := True + } + } + } - // M-mode has full access by default, others have none. - when(CountOne(hits) === 0) { - port.bus.rsp.allowRead := privilegeService.isMachine() - port.bus.rsp.allowWrite := privilegeService.isMachine() - port.bus.rsp.allowExecute := privilegeService.isMachine() + when (accessCfg) { + setter.io.a := writeData.subdivideIn(8 bits)(counter(1 downto 0))(aBits) + setter.io.addr := pmpaddr(counter) } otherwise { - port.bus.rsp.allowRead := MuxOH(OHMasking.first(hits), pmps.map(_.state.r)) - port.bus.rsp.allowWrite := MuxOH(OHMasking.first(hits), pmps.map(_.state.w)) - port.bus.rsp.allowExecute := MuxOH(OHMasking.first(hits), pmps.map(_.state.x)) + setter.io.a := cfgRegion(counter)(aBits) + when (counter === pmpIndex) { + setter.io.addr := writeData.asUInt + } otherwise { + setter.io.addr := pmpaddr(counter) + } } + + when (counter === 0) { + setter.io.prevHi := 0 + } otherwise { + setter.io.prevHi := boundHi(counter - 1) + } + + when (enable & + ((accessCfg & ~lockMask(counter(1 downto 0))) | + (accessAddr & ~cfgRegion(counter)(lBit)))) { + boundLo(counter) := setter.io.boundLo + boundHi(counter) := setter.io.boundHi + } + } + } - port.bus.rsp.isIoAccess := ioRange(port.bus.rsp.physicalAddress) - port.bus.rsp.isPaging := False - port.bus.rsp.exception := False - port.bus.rsp.refilling := False - port.bus.busy := False + pipeline plug new Area { + def getHits(address : UInt) = { + (0 until regions).map(i => + address >= boundLo(U(i, log2Up(regions) bits)) & + address < boundHi(U(i, log2Up(regions) bits)) & + (cfgRegion(i)(lBit) | ~privilegeService.isMachine()) & + cfgRegion(i)(aBits) =/= 0 + ) + } + val dGuard = new Area { + val address = dPort.bus.cmd(0).virtualAddress + dPort.bus.rsp.physicalAddress := address + dPort.bus.rsp.isIoAccess := ioRange(address) + dPort.bus.rsp.isPaging := False + dPort.bus.rsp.exception := False + dPort.bus.rsp.refilling := False + dPort.bus.rsp.allowExecute := False + dPort.bus.busy := False + + val hits = getHits(address(31 downto 2)) + + when(~hits.orR) { + dPort.bus.rsp.allowRead := privilegeService.isMachine() + dPort.bus.rsp.allowWrite := privilegeService.isMachine() + } otherwise { + val oneHot = OHMasking.first(hits) + dPort.bus.rsp.allowRead := MuxOH(oneHot, cfgRegion.map(cfg => cfg(rBit))) + dPort.bus.rsp.allowWrite := MuxOH(oneHot, cfgRegion.map(cfg => cfg(wBit))) + } + } + + val iGuard = new Area { + val address = iPort.bus.cmd(0).virtualAddress + iPort.bus.rsp.physicalAddress := address + iPort.bus.rsp.isIoAccess := ioRange(address) + iPort.bus.rsp.isPaging := False + iPort.bus.rsp.exception := False + iPort.bus.rsp.refilling := False + iPort.bus.rsp.allowRead := False + iPort.bus.rsp.allowWrite := False + iPort.bus.busy := False + + val hits = getHits(address(31 downto 2)) + + when(~hits.orR) { + iPort.bus.rsp.allowExecute := privilegeService.isMachine() + } otherwise { + val oneHot = OHMasking.first(hits) + iPort.bus.rsp.allowExecute := MuxOH(oneHot, cfgRegion.map(cfg => cfg(xBit))) + } } } } -} - +} \ No newline at end of file diff --git a/src/test/cpp/raw/pmp/build/pmp.asm b/src/test/cpp/raw/pmp/build/pmp.asm index 4508ee60..c1fa1b79 100644 --- a/src/test/cpp/raw/pmp/build/pmp.asm +++ b/src/test/cpp/raw/pmp/build/pmp.asm @@ -17,26 +17,26 @@ Disassembly of section .crt_section: 80000018 : 80000018: 00000e13 li t3,0 8000001c: 00000f17 auipc t5,0x0 -80000020: 27cf0f13 addi t5,t5,636 # 80000298 +80000020: 330f0f13 addi t5,t5,816 # 8000034c 80000024: 800000b7 lui ra,0x80000 80000028: 80008237 lui tp,0x80008 8000002c: deadc137 lui sp,0xdeadc -80000030: eef10113 addi sp,sp,-273 # deadbeef -80000034: 0020a023 sw sp,0(ra) # 80000000 -80000038: 00222023 sw sp,0(tp) # 80008000 +80000030: eef10113 addi sp,sp,-273 # deadbeef +80000034: 0020a023 sw sp,0(ra) # 80000000 +80000038: 00222023 sw sp,0(tp) # 80008000 8000003c: 0000a183 lw gp,0(ra) -80000040: 24311c63 bne sp,gp,80000298 +80000040: 30311663 bne sp,gp,8000034c 80000044: 00022183 lw gp,0(tp) # 0 <_start-0x80000000> -80000048: 24311863 bne sp,gp,80000298 +80000048: 30311263 bne sp,gp,8000034c 8000004c: 071202b7 lui t0,0x7120 80000050: 3a029073 csrw pmpcfg0,t0 80000054: 3a002373 csrr t1,pmpcfg0 -80000058: 24629063 bne t0,t1,80000298 +80000058: 2e629a63 bne t0,t1,8000034c 8000005c: 191f02b7 lui t0,0x191f0 80000060: 30428293 addi t0,t0,772 # 191f0304 <_start-0x66e0fcfc> 80000064: 3a129073 csrw pmpcfg1,t0 -80000068: 000f02b7 lui t0,0xf0 -8000006c: 50628293 addi t0,t0,1286 # f0506 <_start-0x7ff0fafa> +80000068: 000f12b7 lui t0,0xf1 +8000006c: 90a28293 addi t0,t0,-1782 # f090a <_start-0x7ff0f6f6> 80000070: 3a229073 csrw pmpcfg2,t0 80000074: 0f1e22b7 lui t0,0xf1e2 80000078: 90028293 addi t0,t0,-1792 # f1e1900 <_start-0x70e1e700> @@ -44,7 +44,7 @@ Disassembly of section .crt_section: 80000080: 200002b7 lui t0,0x20000 80000084: 3b029073 csrw pmpaddr0,t0 80000088: 3b002373 csrr t1,pmpaddr0 -8000008c: 20629663 bne t0,t1,80000298 +8000008c: 2c629063 bne t0,t1,8000034c 80000090: fff00293 li t0,-1 80000094: 3b129073 csrw pmpaddr1,t0 80000098: 200022b7 lui t0,0x20002 @@ -85,119 +85,166 @@ Disassembly of section .crt_section: 80000124: 0020a023 sw sp,0(ra) 80000128: 00222023 sw sp,0(tp) # 0 <_start-0x80000000> 8000012c: 0000a183 lw gp,0(ra) -80000130: 16311463 bne sp,gp,80000298 +80000130: 20311e63 bne sp,gp,8000034c 80000134: 00000193 li gp,0 80000138: 00022183 lw gp,0(tp) # 0 <_start-0x80000000> -8000013c: 14311e63 bne sp,gp,80000298 +8000013c: 20311863 bne sp,gp,8000034c 80000140 : 80000140: 00100e13 li t3,1 80000144: 00000f17 auipc t5,0x0 -80000148: 154f0f13 addi t5,t5,340 # 80000298 +80000148: 208f0f13 addi t5,t5,520 # 8000034c 8000014c: 079212b7 lui t0,0x7921 80000150: 80828293 addi t0,t0,-2040 # 7920808 <_start-0x786df7f8> 80000154: 3a029073 csrw pmpcfg0,t0 80000158: 3a002373 csrr t1,pmpcfg0 -8000015c: 12629e63 bne t0,t1,80000298 +8000015c: 1e629863 bne t0,t1,8000034c 80000160: 800080b7 lui ra,0x80008 80000164: deadc137 lui sp,0xdeadc -80000168: eef10113 addi sp,sp,-273 # deadbeef -8000016c: 0020a023 sw sp,0(ra) # 80008000 +80000168: eef10113 addi sp,sp,-273 # deadbeef +8000016c: 0020a023 sw sp,0(ra) # 80008000 80000170: 00000f17 auipc t5,0x0 80000174: 010f0f13 addi t5,t5,16 # 80000180 80000178: 0000a183 lw gp,0(ra) -8000017c: 11c0006f j 80000298 +8000017c: 1d00006f j 8000034c 80000180 : 80000180: 00200e13 li t3,2 80000184: 00000f17 auipc t5,0x0 -80000188: 114f0f13 addi t5,t5,276 # 80000298 +80000188: 1c8f0f13 addi t5,t5,456 # 8000034c 8000018c: 071202b7 lui t0,0x7120 80000190: 3a029073 csrw pmpcfg0,t0 80000194: 3a002373 csrr t1,pmpcfg0 -80000198: 3b205073 csrwi pmpaddr2,0 -8000019c: 3b202373 csrr t1,pmpaddr2 -800001a0: 0e030c63 beqz t1,80000298 -800001a4: 0e628a63 beq t0,t1,80000298 -800001a8: 800080b7 lui ra,0x80008 -800001ac: deadc137 lui sp,0xdeadc -800001b0: eef10113 addi sp,sp,-273 # deadbeef -800001b4: 0020a023 sw sp,0(ra) # 80008000 -800001b8: 00000f17 auipc t5,0x0 -800001bc: 010f0f13 addi t5,t5,16 # 800001c8 -800001c0: 0000a183 lw gp,0(ra) -800001c4: 0d40006f j 80000298 +80000198: 1a628a63 beq t0,t1,8000034c +8000019c: 200042b7 lui t0,0x20004 +800001a0: fff28293 addi t0,t0,-1 # 20003fff <_start-0x5fffc001> +800001a4: 3b305073 csrwi pmpaddr3,0 +800001a8: 3b302373 csrr t1,pmpaddr3 +800001ac: 1a031063 bnez t1,8000034c +800001b0: 18628e63 beq t0,t1,8000034c +800001b4: 200022b7 lui t0,0x20002 +800001b8: 3b205073 csrwi pmpaddr2,0 +800001bc: 3b202373 csrr t1,pmpaddr2 +800001c0: 18030663 beqz t1,8000034c +800001c4: 18629463 bne t0,t1,8000034c +800001c8: 800080b7 lui ra,0x80008 +800001cc: deadc137 lui sp,0xdeadc +800001d0: eef10113 addi sp,sp,-273 # deadbeef +800001d4: 0020a023 sw sp,0(ra) # 80008000 +800001d8: 00000f17 auipc t5,0x0 +800001dc: 010f0f13 addi t5,t5,16 # 800001e8 +800001e0: 0000a183 lw gp,0(ra) +800001e4: 1680006f j 8000034c -800001c8 : -800001c8: 00300e13 li t3,3 -800001cc: 00000f17 auipc t5,0x0 -800001d0: 0ccf0f13 addi t5,t5,204 # 80000298 -800001d4: 00000117 auipc sp,0x0 -800001d8: 01010113 addi sp,sp,16 # 800001e4 -800001dc: 34111073 csrw mepc,sp -800001e0: 30200073 mret +800001e8 : +800001e8: 00300e13 li t3,3 +800001ec: 00000f17 auipc t5,0x0 +800001f0: 160f0f13 addi t5,t5,352 # 8000034c +800001f4: 00ff02b7 lui t0,0xff0 +800001f8: 3b32a073 csrs pmpaddr3,t0 +800001fc: 3b302373 csrr t1,pmpaddr3 +80000200: 14629663 bne t0,t1,8000034c +80000204: 0ff00293 li t0,255 +80000208: 3b32a073 csrs pmpaddr3,t0 +8000020c: 3b302373 csrr t1,pmpaddr3 +80000210: 00ff02b7 lui t0,0xff0 +80000214: 0ff28293 addi t0,t0,255 # ff00ff <_start-0x7f00ff01> +80000218: 12629a63 bne t0,t1,8000034c +8000021c: 00ff02b7 lui t0,0xff0 +80000220: 3b32b073 csrc pmpaddr3,t0 +80000224: 3b302373 csrr t1,pmpaddr3 +80000228: 0ff00293 li t0,255 +8000022c: 12629063 bne t0,t1,8000034c +80000230: 00ff02b7 lui t0,0xff0 +80000234: 0ff28293 addi t0,t0,255 # ff00ff <_start-0x7f00ff01> +80000238: 3a02b073 csrc pmpcfg0,t0 +8000023c: 3a002373 csrr t1,pmpcfg0 +80000240: 079202b7 lui t0,0x7920 +80000244: 10629463 bne t0,t1,8000034c +80000248: 00ff02b7 lui t0,0xff0 +8000024c: 70728293 addi t0,t0,1799 # ff0707 <_start-0x7f00f8f9> +80000250: 3a02a073 csrs pmpcfg0,t0 +80000254: 3a002373 csrr t1,pmpcfg0 +80000258: 079202b7 lui t0,0x7920 +8000025c: 70728293 addi t0,t0,1799 # 7920707 <_start-0x786df8f9> +80000260: 0e629663 bne t0,t1,8000034c -800001e4 : -800001e4: 00400e13 li t3,4 -800001e8: 00000f17 auipc t5,0x0 -800001ec: 0b0f0f13 addi t5,t5,176 # 80000298 -800001f0: deadc137 lui sp,0xdeadc -800001f4: eef10113 addi sp,sp,-273 # deadbeef -800001f8: 800080b7 lui ra,0x80008 -800001fc: 0020a023 sw sp,0(ra) # 80008000 -80000200: 00000f17 auipc t5,0x0 -80000204: 010f0f13 addi t5,t5,16 # 80000210 -80000208: 0000a183 lw gp,0(ra) -8000020c: 08c0006f j 80000298 - -80000210 : -80000210: 00500e13 li t3,5 -80000214: deadc137 lui sp,0xdeadc -80000218: eef10113 addi sp,sp,-273 # deadbeef -8000021c: 800000b7 lui ra,0x80000 -80000220: 0020a023 sw sp,0(ra) # 80000000 -80000224: 0000a183 lw gp,0(ra) -80000228: 06311863 bne sp,gp,80000298 - -8000022c : -8000022c: 00600e13 li t3,6 -80000230: 800100b7 lui ra,0x80010 -80000234: 0000a183 lw gp,0(ra) # 80010000 -80000238: 00000f17 auipc t5,0x0 -8000023c: 06cf0f13 addi t5,t5,108 # 800002a4 -80000240: 0030a023 sw gp,0(ra) -80000244: 0540006f j 80000298 - -80000248 : -80000248: 00700e13 li t3,7 -8000024c: 00000f17 auipc t5,0x0 -80000250: 04cf0f13 addi t5,t5,76 # 80000298 -80000254: deadc137 lui sp,0xdeadc -80000258: eef10113 addi sp,sp,-273 # deadbeef -8000025c: 800300b7 lui ra,0x80030 -80000260: ff808093 addi ra,ra,-8 # 8002fff8 -80000264: 00222023 sw sp,0(tp) # 0 <_start-0x80000000> +80000264 : +80000264: 00400e13 li t3,4 80000268: 00000f17 auipc t5,0x0 -8000026c: fa8f0f13 addi t5,t5,-88 # 80000210 -80000270: 00022183 lw gp,0(tp) # 0 <_start-0x80000000> -80000274: 0240006f j 80000298 +8000026c: 0e4f0f13 addi t5,t5,228 # 8000034c +80000270: 00000117 auipc sp,0x0 +80000274: 01010113 addi sp,sp,16 # 80000280 +80000278: 34111073 csrw mepc,sp +8000027c: 30200073 mret -80000278 : -80000278: 00800e13 li t3,8 -8000027c: 800400b7 lui ra,0x80040 -80000280: ff808093 addi ra,ra,-8 # 8003fff8 -80000284: 0000a183 lw gp,0(ra) -80000288: 00000f17 auipc t5,0x0 -8000028c: 01cf0f13 addi t5,t5,28 # 800002a4 -80000290: 0030a023 sw gp,0(ra) -80000294: 0040006f j 80000298 +80000280 : +80000280: 00500e13 li t3,5 +80000284: 00000f17 auipc t5,0x0 +80000288: 0c8f0f13 addi t5,t5,200 # 8000034c +8000028c: deadc137 lui sp,0xdeadc +80000290: eef10113 addi sp,sp,-273 # deadbeef +80000294: 800080b7 lui ra,0x80008 +80000298: 0020a023 sw sp,0(ra) # 80008000 +8000029c: 00000f17 auipc t5,0x0 +800002a0: 010f0f13 addi t5,t5,16 # 800002ac +800002a4: 0000a183 lw gp,0(ra) +800002a8: 0a40006f j 8000034c -80000298 : -80000298: f0100137 lui sp,0xf0100 -8000029c: f2410113 addi sp,sp,-220 # f00fff24 -800002a0: 01c12023 sw t3,0(sp) +800002ac : +800002ac: 00600e13 li t3,6 +800002b0: 00000f17 auipc t5,0x0 +800002b4: 09cf0f13 addi t5,t5,156 # 8000034c +800002b8: deadc137 lui sp,0xdeadc +800002bc: eef10113 addi sp,sp,-273 # deadbeef +800002c0: 800000b7 lui ra,0x80000 +800002c4: 0020a023 sw sp,0(ra) # 80000000 +800002c8: 0000a183 lw gp,0(ra) +800002cc: 08311063 bne sp,gp,8000034c -800002a4 : -800002a4: f0100137 lui sp,0xf0100 -800002a8: f2010113 addi sp,sp,-224 # f00fff20 -800002ac: 00012023 sw zero,0(sp) +800002d0 : +800002d0: 00700e13 li t3,7 +800002d4: 00000f17 auipc t5,0x0 +800002d8: 078f0f13 addi t5,t5,120 # 8000034c +800002dc: 800400b7 lui ra,0x80040 +800002e0: 0000a183 lw gp,0(ra) # 80040000 +800002e4: 00000f17 auipc t5,0x0 +800002e8: 074f0f13 addi t5,t5,116 # 80000358 +800002ec: 0030a023 sw gp,0(ra) +800002f0: 05c0006f j 8000034c + +800002f4 : +800002f4: 00800e13 li t3,8 +800002f8: 00000f17 auipc t5,0x0 +800002fc: 054f0f13 addi t5,t5,84 # 8000034c +80000300: deadc137 lui sp,0xdeadc +80000304: eef10113 addi sp,sp,-273 # deadbeef +80000308: 800300b7 lui ra,0x80030 +8000030c: ff808093 addi ra,ra,-8 # 8002fff8 +80000310: 00222023 sw sp,0(tp) # 0 <_start-0x80000000> +80000314: 00000f17 auipc t5,0x0 +80000318: 010f0f13 addi t5,t5,16 # 80000324 +8000031c: 00022183 lw gp,0(tp) # 0 <_start-0x80000000> +80000320: 02c0006f j 8000034c + +80000324 : +80000324: 00900e13 li t3,9 +80000328: 00000f17 auipc t5,0x0 +8000032c: 024f0f13 addi t5,t5,36 # 8000034c +80000330: 800400b7 lui ra,0x80040 +80000334: ff808093 addi ra,ra,-8 # 8003fff8 +80000338: 0000a183 lw gp,0(ra) +8000033c: 00000f17 auipc t5,0x0 +80000340: 01cf0f13 addi t5,t5,28 # 80000358 +80000344: 0030a023 sw gp,0(ra) +80000348: 0040006f j 8000034c + +8000034c : +8000034c: f0100137 lui sp,0xf0100 +80000350: f2410113 addi sp,sp,-220 # f00fff24 +80000354: 01c12023 sw t3,0(sp) + +80000358 : +80000358: f0100137 lui sp,0xf0100 +8000035c: f2010113 addi sp,sp,-224 # f00fff20 +80000360: 00012023 sw zero,0(sp) diff --git a/src/test/cpp/raw/pmp/build/pmp.elf b/src/test/cpp/raw/pmp/build/pmp.elf index b844a20189743c473a3eeb6c94fa6b6976f7932d..68e30ea6a9ba2d543a6c80014c5854c5ee1aca40 100755 GIT binary patch delta 844 zcmY*XF>ljA6n;K84IpZ}J|}Sl4M&VXLM1q9Q6Ujh)PbQO5+;~XYloo|R<7!VRLk8M z!0n+5F`$$gq_E%>egUwtz)B}n5PNuz<0hQs(|zCj-n)12^Wo+GLdZxnw_7excVvK$ z{C@SDdRJYH0Q}_uzfbReQ0ezCtH;1%W!O0YaPw7r=R5&dui6pOvpghqZb99BBQgNqt0k%Xjv>gAn&LQyrB!^HKGgLSU954#gp1?6pG+Vkds)0jOY*uN z?~Qp8bUk<9QRpS5Il8>16mS$&k|eIpE^%NsRodx0Pm3e$wRwsvYa{CO$<&S5o!F6~ z8(Q@QRlGDU8^M$x^T||OS*vHmWB8b%il1_saUIzgzCVbaP4uc1JA-;cl@JQqp*1Zc zp6J)iIRNNxaCZwNq#@JYTC8o=9~9s-uyG^?6;Z3=3C}Yx7$cL zK+4}<`=s3*p2+~B#hCovo6nN{`0ni4;MiT*-UkRydehsdIRq_lI^)KuN_bB>&vMpI@5~T^M6W$9Gnz@VQ*(FF1abbC2FLh^U5)!5qb} z6<#3L`Tu;6c(%fQ;#U>EOnkM%*NL|(e4Cgo%7ae*?f@W~H}r5-DcHEDHWrI`5r3H> z-nUGia(rlY>!|_I!Pk~^_5;mydfO2?fj+PpbsCS5*T_rzLb~tbPs?d7n*jN}OQX$& F{Q=jbd`tiU diff --git a/src/test/cpp/raw/pmp/build/pmp.hex b/src/test/cpp/raw/pmp/build/pmp.hex index 8197935b..5dc92f6e 100644 --- a/src/test/cpp/raw/pmp/build/pmp.hex +++ b/src/test/cpp/raw/pmp/build/pmp.hex @@ -1,13 +1,13 @@ :0200000480007A :100000009700000093800001739050306F00C00093 :1000100073101F3473002030130E0000170F000000 -:10002000130FCF27B70000803782008037C1ADDEC5 +:10002000130F0F33B70000803782008037C1ADDE79 :100030001301F1EE23A020002320220083A1000061 -:10004000631C31248321020063183124B702120794 -:100050007390023A7323003A63906224B7021F1927 -:10006000938242307390123AB7020F00938262502B +:10004000631631308321020063123130B702120788 +:100050007390023A7323003A639A622EB7021F1913 +:10006000938242307390123AB7120F009382A2909B :100070007390223AB7221E0F938202907390323A05 -:10008000B70200207390023B7323003B639662200B +:10008000B70200207390023B7323003B6390622C05 :100090009302F0FF7390123BB72200207390223B33 :1000A000B74200209382F2FF7390323BB7420020A8 :1000B0009382F2FF7390423BB74200209382F2FF9B @@ -18,29 +18,41 @@ :100100007390C23B930200007390D23B93020000B5 :100110007390E23B930200007390F23B3701C10001 :100120001301E1FE23A020002320220083A1000070 -:10013000631431169301000083210200631E311401 -:10014000130E1000170F0000130F4F15B712920770 -:10015000938282807390023A7323003A639E621204 +:10013000631E3120930100008321020063183120E7 +:10014000130E1000170F0000130F8F20B712920725 +:10015000938282807390023A7323003A6398621EFE :10016000B780008037C1ADDE1301F1EE23A020007F -:10017000170F0000130F0F0183A100006F00C011C3 -:10018000130E2000170F0000130F4F11B7021207B4 -:100190007390023A7323003A7350203B7323203B41 -:1001A000630C030E638A620EB780008037C1ADDE38 -:1001B0001301F1EE23A02000170F0000130F0F0111 -:1001C00083A100006F00400D130E3000170F0000D8 -:1001D000130FCF0C1701000013010101731011342C -:1001E00073002030130E4000170F0000130F0F0B89 -:1001F00037C1ADDE1301F1EEB780008023A02000EF -:10020000170F0000130F0F0183A100006F00C0083B -:10021000130E500037C1ADDE1301F1EEB7000080C0 -:1002200023A0200083A1000063183106130E600094 -:10023000B700018083A10000170F0000130FCF0645 -:1002400023A030006F004005130E7000170F000050 -:10025000130FCF0437C1ADDE1301F1EEB7000380F9 -:10026000938080FF23202200170F0000130F8FFAC6 -:10027000832102006F004002130E8000B70004804B -:10028000938080FF83A10000170F0000130FCF01A0 -:1002900023A030006F004000370110F0130141F23D -:1002A0002320C101370110F0130101F223200100C6 +:10017000170F0000130F0F0183A100006F00001D77 +:10018000130E2000170F0000130F8F1CB702120769 +:100190007390023A7323003A638A621AB7420020CE +:1001A0009382F2FF7350303B7323303B6310031A8A +:1001B000638E6218B72200207350203B7323203BCC +:1001C0006306031863946218B780008037C1ADDE00 +:1001D0001301F1EE23A02000170F0000130F0F01F1 +:1001E00083A100006F008016130E3000170F00006F +:1001F000130F0F16B702FF0073A0323B7323303B7F +:10020000639662149302F00F73A0323B7323303B6A +:10021000B702FF009382F20F639A6212B702FF00E7 +:1002200073B0323B7323303B9302F00F6390621242 +:10023000B702FF009382F20F73B0023A7323003AC1 +:10024000B702920763946210B702FF009382727044 +:1002500073A0023A7323003AB70292079382727036 +:100260006396620E130E4000170F0000130F4F0E1F +:1002700017010000130101017310113473002030C5 +:10028000130E5000170F0000130F8F0C37C1ADDE97 +:100290001301F1EEB780008023A02000170F0000AB +:1002A000130F0F0183A100006F00400A130E6000BE +:1002B000170F0000130FCF0937C1ADDE1301F1EEA8 +:1002C000B700008023A0200083A100006310310844 +:1002D000130E7000170F0000130F8F07B700048074 +:1002E00083A10000170F0000130F4F0723A0300059 +:1002F0006F00C005130E8000170F0000130F4F058D +:1003000037C1ADDE1301F1EEB7000380938080FFAB +:1003100023202200170F0000130F0F01832102007A +:100320006F00C002130E9000170F0000130F4F0252 +:10033000B7000480938080FF83A10000170F0000A6 +:10034000130FCF0123A030006F004000370110F0E1 +:10035000130141F22320C101370110F0130101F212 +:040360002320010055 :040000058000000077 :00000001FF diff --git a/src/test/cpp/raw/pmp/build/pmp.map b/src/test/cpp/raw/pmp/build/pmp.map index 2a018207..f2e88d83 100644 --- a/src/test/cpp/raw/pmp/build/pmp.map +++ b/src/test/cpp/raw/pmp/build/pmp.map @@ -8,28 +8,28 @@ onChipRam 0x0000000080000000 0x0000000000020000 w !xr Linker script and memory map LOAD build/src/crt.o -LOAD /opt/riscv/lib/gcc/riscv64-unknown-elf/10.2.0/libgcc.a +LOAD /opt/riscv/bin/../lib/gcc/riscv64-unknown-elf/8.3.0/rv32i/ilp32/libgcc.a START GROUP -LOAD /opt/riscv/lib/gcc/riscv64-unknown-elf/10.2.0/../../../../riscv64-unknown-elf/lib/libc.a -LOAD /opt/riscv/lib/gcc/riscv64-unknown-elf/10.2.0/../../../../riscv64-unknown-elf/lib/libgloss.a +LOAD /opt/riscv/bin/../lib/gcc/riscv64-unknown-elf/8.3.0/../../../../riscv64-unknown-elf/lib/rv32i/ilp32/libc.a +LOAD /opt/riscv/bin/../lib/gcc/riscv64-unknown-elf/8.3.0/../../../../riscv64-unknown-elf/lib/rv32i/ilp32/libgloss.a END GROUP -LOAD /opt/riscv/lib/gcc/riscv64-unknown-elf/10.2.0/libgcc.a +LOAD /opt/riscv/bin/../lib/gcc/riscv64-unknown-elf/8.3.0/rv32i/ilp32/libgcc.a -.crt_section 0x0000000080000000 0x2b0 +.crt_section 0x0000000080000000 0x364 0x0000000080000000 . = ALIGN (0x4) *crt.o(.text) - .text 0x0000000080000000 0x2b0 build/src/crt.o + .text 0x0000000080000000 0x364 build/src/crt.o 0x0000000080000000 _start 0x0000000080000010 trap OUTPUT(build/pmp.elf elf32-littleriscv) -.data 0x00000000800002b0 0x0 - .data 0x00000000800002b0 0x0 build/src/crt.o +.data 0x0000000080000364 0x0 + .data 0x0000000080000364 0x0 build/src/crt.o -.bss 0x00000000800002b0 0x0 - .bss 0x00000000800002b0 0x0 build/src/crt.o +.bss 0x0000000080000364 0x0 + .bss 0x0000000080000364 0x0 build/src/crt.o .riscv.attributes - 0x0000000000000000 0x1e + 0x0000000000000000 0x1a .riscv.attributes - 0x0000000000000000 0x1e build/src/crt.o + 0x0000000000000000 0x1a build/src/crt.o diff --git a/src/test/cpp/raw/pmp/src/crt.S b/src/test/cpp/raw/pmp/src/crt.S index 76ee02f2..089500ab 100644 --- a/src/test/cpp/raw/pmp/src/crt.S +++ b/src/test/cpp/raw/pmp/src/crt.S @@ -8,15 +8,15 @@ #define TRAP_RA x30 #define PMPCFG0 0x07120000 -#define PMPCFG0_ 0x07920808 // locked +#define PMPCFG0_ 0x07920808 #define PMPCFG1 0x191f0304 -#define PMPCFG2 0x000f0506 +#define PMPCFG2 0x000f090a #define PMPCFG3 0x0f1e1900 -#define PMPADDR0 0x20000000 // OFF -#define PMPADDR1 0xffffffff // OFF +#define PMPADDR0 0x20000000 // OFF (test0) -> TOR (test1) -> OFF (test2) +#define PMPADDR1 0xffffffff // OFF (test0) -> TOR (test1) -> OFF (test2) #define PMPADDR2 0x20002000 // NA4 W -#define PMPADDR3 0x20003fff // OFF RWX +#define PMPADDR3 0x20003fff // OFF RWX -> 0x00000000 OFF RWX (test2) #define PMPADDR4 0x20003fff // OFF X #define PMPADDR5 0x20003fff // OFF RW #define PMPADDR6 0x20001fff // NAPOT RWX @@ -132,10 +132,17 @@ test2: li x5, PMPCFG0 csrw pmpcfg0, x5 // "unlock" region 2 csrr x6, pmpcfg0 + beq x5, x6, fail + li x5, PMPADDR3 + csrwi pmpaddr3, 0x0 + csrr x6, pmpaddr3 + bnez x6, fail + beq x5, x6, fail + li x5, PMPADDR2 csrwi pmpaddr2, 0x0 csrr x6, pmpaddr2 - beqz x6, fail - beq x5, x6, fail + beqz x6, fail + bne x5, x6, fail li x1, 0x80008000 li x2, 0xdeadbeef sw x2, 0x0(x1) // should still be OK (write 0x80008000) @@ -143,54 +150,86 @@ test2: lw x3, 0x0(x1) // should still fault (read 0x80008000) j fail -// jump into user mode +// verify masked CSR read/write operations test3: li TEST_ID, 3 la TRAP_RA, fail - la x2, test4 + li x5, 0x00ff0000 + csrs pmpaddr3, x5 + csrr x6, pmpaddr3 + bne x5, x6, fail + li x5, 0x000000ff + csrs pmpaddr3, x5 + csrr x6, pmpaddr3 + li x5, 0x00ff00ff + bne x5, x6, fail + li x5, 0x00ff0000 + csrc pmpaddr3, x5 + csrr x6, pmpaddr3 + li x5, 0x000000ff + bne x5, x6, fail + li x5, 0x00ff00ff + csrc pmpcfg0, x5 + csrr x6, pmpcfg0 + li x5, 0x07920000 + bne x5, x6, fail + li x5, 0x00ff0707 + csrs pmpcfg0, x5 + csrr x6, pmpcfg0 + li x5, 0x07920707 + bne x5, x6, fail + +// jump into user mode +test4: + li TEST_ID, 4 + la TRAP_RA, fail + la x2, test5 csrw mepc, x2 mret // attempt to read/write region 2 from user mode -test4: - li TEST_ID, 4 +test5: + li TEST_ID, 5 la TRAP_RA, fail li x2, 0xdeadbeef li x1, 0x80008000 sw x2, 0x0(x1) // should be OK (write 0x80008000) - la TRAP_RA, test5 + la TRAP_RA, test6 lw x3, 0x0(x1) // should fault (read 0x80008000) j fail // attempt to read/write other regions from user mode -test5: - li TEST_ID, 5 +test6: + li TEST_ID, 6 + la TRAP_RA, fail li x2, 0xdeadbeef li x1, 0x80000000 sw x2, 0x0(x1) lw x3, 0x0(x1) bne x2, x3, fail // should be OK (read/write 0x80000000) -test6: - li TEST_ID, 6 - li x1, 0x80010000 - lw x3, 0x0(x1) // should be OK (read 0x80010000) - la TRAP_RA, pass - sw x3, 0x0(x1) // should fault (write 0x80010000) - j fail - test7: li TEST_ID, 7 + la TRAP_RA, fail + li x1, 0x80040000 + lw x3, 0x0(x1) // should be OK (read 0x80040000) + la TRAP_RA, pass + sw x3, 0x0(x1) // should fault (write 0x80040000) + j fail + +test8: + li TEST_ID, 8 la TRAP_RA, fail li x2, 0xdeadbeef li x1, 0x8002fff8 sw x2, 0x0(x4) // should be OK (write 0x8002fff8) - la TRAP_RA, test5 + la TRAP_RA, test9 lw x3, 0x0(x4) // should fault (read 0x8002fff8) j fail -test8: - li TEST_ID, 8 +test9: + li TEST_ID, 9 + la TRAP_RA, fail li x1, 0x8003fff8 lw x3, 0x0(x1) // should be OK (read 0x8003fff8) la TRAP_RA, pass From b41db0af93ee80fb7eb2891f450e5d74334c0db4 Mon Sep 17 00:00:00 2001 From: Samuel Lindemer Date: Mon, 12 Apr 2021 09:58:49 +0200 Subject: [PATCH 638/951] Prevent PMP access from U-mode, fix tests --- .../scala/vexriscv/plugin/PmpPlugin.scala | 5 +- src/test/cpp/raw/pmp/build/pmp.asm | 494 ++++++++++-------- src/test/cpp/raw/pmp/build/pmp.elf | Bin 5680 -> 5952 bytes src/test/cpp/raw/pmp/build/pmp.hex | 118 +++-- src/test/cpp/raw/pmp/build/pmp.map | 14 +- src/test/cpp/raw/pmp/src/crt.S | 104 +++- 6 files changed, 417 insertions(+), 318 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/PmpPlugin.scala b/src/main/scala/vexriscv/plugin/PmpPlugin.scala index 357d5b8c..7f120dac 100644 --- a/src/main/scala/vexriscv/plugin/PmpPlugin.scala +++ b/src/main/scala/vexriscv/plugin/PmpPlugin.scala @@ -150,8 +150,9 @@ class PmpPlugin(regions : Int, ioRange : UInt => Bool) extends Plugin[VexRiscv] val csrAddress = input(INSTRUCTION)(csrRange) val accessAddr = input(IS_PMP_ADDR) val accessCfg = input(IS_PMP_CFG) - val pmpWrite = arbitration.isValid && input(IS_CSR) && input(CSR_WRITE_OPCODE) & (accessAddr | accessCfg) - val pmpRead = arbitration.isValid && input(IS_CSR) && input(CSR_READ_OPCODE) & (accessAddr | accessCfg) + val accessAny = (accessAddr | accessCfg) & privilegeService.isMachine() + val pmpWrite = arbitration.isValid && input(IS_CSR) && input(CSR_WRITE_OPCODE) & accessAny + val pmpRead = arbitration.isValid && input(IS_CSR) && input(CSR_READ_OPCODE) & accessAny val pmpIndex = csrAddress(log2Up(regions) - 1 downto 0).asUInt val pmpSelect = pmpIndex(log2Up(regions) - 3 downto 0) diff --git a/src/test/cpp/raw/pmp/build/pmp.asm b/src/test/cpp/raw/pmp/build/pmp.asm index c1fa1b79..ef3f2804 100644 --- a/src/test/cpp/raw/pmp/build/pmp.asm +++ b/src/test/cpp/raw/pmp/build/pmp.asm @@ -5,246 +5,290 @@ build/pmp.elf: file format elf32-littleriscv Disassembly of section .crt_section: 80000000 <_start>: -80000000: 00000097 auipc ra,0x0 -80000004: 01008093 addi ra,ra,16 # 80000010 -80000008: 30509073 csrw mtvec,ra -8000000c: 00c0006f j 80000018 +80000000: 00000493 li s1,0 +80000004: 00000097 auipc ra,0x0 +80000008: 01008093 addi ra,ra,16 # 80000014 +8000000c: 30509073 csrw mtvec,ra +80000010: 0140006f j 80000024 -80000010 : -80000010: 341f1073 csrw mepc,t5 -80000014: 30200073 mret +80000014 : +80000014: 341f1073 csrw mepc,t5 +80000018: 00049463 bnez s1,80000020 +8000001c: 30200073 mret -80000018 : -80000018: 00000e13 li t3,0 -8000001c: 00000f17 auipc t5,0x0 -80000020: 330f0f13 addi t5,t5,816 # 8000034c -80000024: 800000b7 lui ra,0x80000 -80000028: 80008237 lui tp,0x80008 -8000002c: deadc137 lui sp,0xdeadc -80000030: eef10113 addi sp,sp,-273 # deadbeef -80000034: 0020a023 sw sp,0(ra) # 80000000 -80000038: 00222023 sw sp,0(tp) # 80008000 -8000003c: 0000a183 lw gp,0(ra) -80000040: 30311663 bne sp,gp,8000034c -80000044: 00022183 lw gp,0(tp) # 0 <_start-0x80000000> -80000048: 30311263 bne sp,gp,8000034c -8000004c: 071202b7 lui t0,0x7120 -80000050: 3a029073 csrw pmpcfg0,t0 -80000054: 3a002373 csrr t1,pmpcfg0 -80000058: 2e629a63 bne t0,t1,8000034c -8000005c: 191f02b7 lui t0,0x191f0 -80000060: 30428293 addi t0,t0,772 # 191f0304 <_start-0x66e0fcfc> -80000064: 3a129073 csrw pmpcfg1,t0 -80000068: 000f12b7 lui t0,0xf1 -8000006c: 90a28293 addi t0,t0,-1782 # f090a <_start-0x7ff0f6f6> -80000070: 3a229073 csrw pmpcfg2,t0 -80000074: 0f1e22b7 lui t0,0xf1e2 -80000078: 90028293 addi t0,t0,-1792 # f1e1900 <_start-0x70e1e700> -8000007c: 3a329073 csrw pmpcfg3,t0 -80000080: 200002b7 lui t0,0x20000 -80000084: 3b029073 csrw pmpaddr0,t0 -80000088: 3b002373 csrr t1,pmpaddr0 -8000008c: 2c629063 bne t0,t1,8000034c -80000090: fff00293 li t0,-1 -80000094: 3b129073 csrw pmpaddr1,t0 -80000098: 200022b7 lui t0,0x20002 -8000009c: 3b229073 csrw pmpaddr2,t0 -800000a0: 200042b7 lui t0,0x20004 -800000a4: fff28293 addi t0,t0,-1 # 20003fff <_start-0x5fffc001> -800000a8: 3b329073 csrw pmpaddr3,t0 +80000020 : +80000020: 000f0067 jr t5 + +80000024 : +80000024: 00000e13 li t3,0 +80000028: 00000f17 auipc t5,0x0 +8000002c: 3a4f0f13 addi t5,t5,932 # 800003cc +80000030: 800000b7 lui ra,0x80000 +80000034: 80008237 lui tp,0x80008 +80000038: deadc137 lui sp,0xdeadc +8000003c: eef10113 addi sp,sp,-273 # deadbeef +80000040: 0020a023 sw sp,0(ra) # 80000000 +80000044: 00222023 sw sp,0(tp) # 80008000 +80000048: 0000a183 lw gp,0(ra) +8000004c: 38311063 bne sp,gp,800003cc +80000050: 00022183 lw gp,0(tp) # 0 <_start-0x80000000> +80000054: 36311c63 bne sp,gp,800003cc +80000058: 071202b7 lui t0,0x7120 +8000005c: 3a029073 csrw pmpcfg0,t0 +80000060: 3a002373 csrr t1,pmpcfg0 +80000064: 36629463 bne t0,t1,800003cc +80000068: 191f02b7 lui t0,0x191f0 +8000006c: 30428293 addi t0,t0,772 # 191f0304 <_start-0x66e0fcfc> +80000070: 3a129073 csrw pmpcfg1,t0 +80000074: 000f12b7 lui t0,0xf1 +80000078: 90a28293 addi t0,t0,-1782 # f090a <_start-0x7ff0f6f6> +8000007c: 3a229073 csrw pmpcfg2,t0 +80000080: 0f1e22b7 lui t0,0xf1e2 +80000084: 90028293 addi t0,t0,-1792 # f1e1900 <_start-0x70e1e700> +80000088: 3a329073 csrw pmpcfg3,t0 +8000008c: 200002b7 lui t0,0x20000 +80000090: 3b029073 csrw pmpaddr0,t0 +80000094: 3b002373 csrr t1,pmpaddr0 +80000098: 32629a63 bne t0,t1,800003cc +8000009c: fff00293 li t0,-1 +800000a0: 3b129073 csrw pmpaddr1,t0 +800000a4: 200022b7 lui t0,0x20002 +800000a8: 3b229073 csrw pmpaddr2,t0 800000ac: 200042b7 lui t0,0x20004 800000b0: fff28293 addi t0,t0,-1 # 20003fff <_start-0x5fffc001> -800000b4: 3b429073 csrw pmpaddr4,t0 +800000b4: 3b329073 csrw pmpaddr3,t0 800000b8: 200042b7 lui t0,0x20004 800000bc: fff28293 addi t0,t0,-1 # 20003fff <_start-0x5fffc001> -800000c0: 3b529073 csrw pmpaddr5,t0 -800000c4: 200022b7 lui t0,0x20002 -800000c8: fff28293 addi t0,t0,-1 # 20001fff <_start-0x5fffe001> -800000cc: 3b629073 csrw pmpaddr6,t0 -800000d0: 200062b7 lui t0,0x20006 -800000d4: fff28293 addi t0,t0,-1 # 20005fff <_start-0x5fffa001> -800000d8: 3b729073 csrw pmpaddr7,t0 -800000dc: 2000c2b7 lui t0,0x2000c -800000e0: 3b829073 csrw pmpaddr8,t0 -800000e4: 2000d2b7 lui t0,0x2000d -800000e8: 3b929073 csrw pmpaddr9,t0 -800000ec: fff00293 li t0,-1 -800000f0: 3ba29073 csrw pmpaddr10,t0 -800000f4: 00000293 li t0,0 -800000f8: 3bb29073 csrw pmpaddr11,t0 -800000fc: 00000293 li t0,0 -80000100: 3bc29073 csrw pmpaddr12,t0 -80000104: 00000293 li t0,0 -80000108: 3bd29073 csrw pmpaddr13,t0 -8000010c: 00000293 li t0,0 -80000110: 3be29073 csrw pmpaddr14,t0 -80000114: 00000293 li t0,0 -80000118: 3bf29073 csrw pmpaddr15,t0 -8000011c: 00c10137 lui sp,0xc10 -80000120: fee10113 addi sp,sp,-18 # c0ffee <_start-0x7f3f0012> -80000124: 0020a023 sw sp,0(ra) -80000128: 00222023 sw sp,0(tp) # 0 <_start-0x80000000> -8000012c: 0000a183 lw gp,0(ra) -80000130: 20311e63 bne sp,gp,8000034c -80000134: 00000193 li gp,0 -80000138: 00022183 lw gp,0(tp) # 0 <_start-0x80000000> -8000013c: 20311863 bne sp,gp,8000034c +800000c0: 3b429073 csrw pmpaddr4,t0 +800000c4: 200042b7 lui t0,0x20004 +800000c8: fff28293 addi t0,t0,-1 # 20003fff <_start-0x5fffc001> +800000cc: 3b529073 csrw pmpaddr5,t0 +800000d0: 200022b7 lui t0,0x20002 +800000d4: fff28293 addi t0,t0,-1 # 20001fff <_start-0x5fffe001> +800000d8: 3b629073 csrw pmpaddr6,t0 +800000dc: 200062b7 lui t0,0x20006 +800000e0: fff28293 addi t0,t0,-1 # 20005fff <_start-0x5fffa001> +800000e4: 3b729073 csrw pmpaddr7,t0 +800000e8: 200d02b7 lui t0,0x200d0 +800000ec: 3b829073 csrw pmpaddr8,t0 +800000f0: 200e02b7 lui t0,0x200e0 +800000f4: 3b929073 csrw pmpaddr9,t0 +800000f8: fff00293 li t0,-1 +800000fc: 3ba29073 csrw pmpaddr10,t0 +80000100: 00000293 li t0,0 +80000104: 3bb29073 csrw pmpaddr11,t0 +80000108: 00000293 li t0,0 +8000010c: 3bc29073 csrw pmpaddr12,t0 +80000110: 00000293 li t0,0 +80000114: 3bd29073 csrw pmpaddr13,t0 +80000118: 00000293 li t0,0 +8000011c: 3be29073 csrw pmpaddr14,t0 +80000120: 00000293 li t0,0 +80000124: 3bf29073 csrw pmpaddr15,t0 +80000128: 00c10137 lui sp,0xc10 +8000012c: fee10113 addi sp,sp,-18 # c0ffee <_start-0x7f3f0012> +80000130: 0020a023 sw sp,0(ra) +80000134: 00222023 sw sp,0(tp) # 0 <_start-0x80000000> +80000138: 0000a183 lw gp,0(ra) +8000013c: 28311863 bne sp,gp,800003cc +80000140: 00000193 li gp,0 +80000144: 00022183 lw gp,0(tp) # 0 <_start-0x80000000> +80000148: 28311263 bne sp,gp,800003cc -80000140 : -80000140: 00100e13 li t3,1 -80000144: 00000f17 auipc t5,0x0 -80000148: 208f0f13 addi t5,t5,520 # 8000034c -8000014c: 079212b7 lui t0,0x7921 -80000150: 80828293 addi t0,t0,-2040 # 7920808 <_start-0x786df7f8> -80000154: 3a029073 csrw pmpcfg0,t0 -80000158: 3a002373 csrr t1,pmpcfg0 -8000015c: 1e629863 bne t0,t1,8000034c -80000160: 800080b7 lui ra,0x80008 -80000164: deadc137 lui sp,0xdeadc -80000168: eef10113 addi sp,sp,-273 # deadbeef -8000016c: 0020a023 sw sp,0(ra) # 80008000 -80000170: 00000f17 auipc t5,0x0 -80000174: 010f0f13 addi t5,t5,16 # 80000180 -80000178: 0000a183 lw gp,0(ra) -8000017c: 1d00006f j 8000034c +8000014c : +8000014c: 00100e13 li t3,1 +80000150: 00000f17 auipc t5,0x0 +80000154: 27cf0f13 addi t5,t5,636 # 800003cc +80000158: 079212b7 lui t0,0x7921 +8000015c: 80828293 addi t0,t0,-2040 # 7920808 <_start-0x786df7f8> +80000160: 3a029073 csrw pmpcfg0,t0 +80000164: 3a002373 csrr t1,pmpcfg0 +80000168: 26629263 bne t0,t1,800003cc +8000016c: 800080b7 lui ra,0x80008 +80000170: deadc137 lui sp,0xdeadc +80000174: eef10113 addi sp,sp,-273 # deadbeef +80000178: 0020a023 sw sp,0(ra) # 80008000 +8000017c: 00000f17 auipc t5,0x0 +80000180: 010f0f13 addi t5,t5,16 # 8000018c +80000184: 0000a183 lw gp,0(ra) +80000188: 2440006f j 800003cc -80000180 : -80000180: 00200e13 li t3,2 -80000184: 00000f17 auipc t5,0x0 -80000188: 1c8f0f13 addi t5,t5,456 # 8000034c -8000018c: 071202b7 lui t0,0x7120 -80000190: 3a029073 csrw pmpcfg0,t0 -80000194: 3a002373 csrr t1,pmpcfg0 -80000198: 1a628a63 beq t0,t1,8000034c -8000019c: 200042b7 lui t0,0x20004 -800001a0: fff28293 addi t0,t0,-1 # 20003fff <_start-0x5fffc001> -800001a4: 3b305073 csrwi pmpaddr3,0 -800001a8: 3b302373 csrr t1,pmpaddr3 -800001ac: 1a031063 bnez t1,8000034c -800001b0: 18628e63 beq t0,t1,8000034c -800001b4: 200022b7 lui t0,0x20002 -800001b8: 3b205073 csrwi pmpaddr2,0 -800001bc: 3b202373 csrr t1,pmpaddr2 -800001c0: 18030663 beqz t1,8000034c -800001c4: 18629463 bne t0,t1,8000034c -800001c8: 800080b7 lui ra,0x80008 -800001cc: deadc137 lui sp,0xdeadc -800001d0: eef10113 addi sp,sp,-273 # deadbeef -800001d4: 0020a023 sw sp,0(ra) # 80008000 -800001d8: 00000f17 auipc t5,0x0 -800001dc: 010f0f13 addi t5,t5,16 # 800001e8 -800001e0: 0000a183 lw gp,0(ra) -800001e4: 1680006f j 8000034c +8000018c : +8000018c: 00200e13 li t3,2 +80000190: 00000f17 auipc t5,0x0 +80000194: 23cf0f13 addi t5,t5,572 # 800003cc +80000198: 071202b7 lui t0,0x7120 +8000019c: 3a029073 csrw pmpcfg0,t0 +800001a0: 3a002373 csrr t1,pmpcfg0 +800001a4: 22628463 beq t0,t1,800003cc +800001a8: 200042b7 lui t0,0x20004 +800001ac: fff28293 addi t0,t0,-1 # 20003fff <_start-0x5fffc001> +800001b0: 3b305073 csrwi pmpaddr3,0 +800001b4: 3b302373 csrr t1,pmpaddr3 +800001b8: 20031a63 bnez t1,800003cc +800001bc: 20628863 beq t0,t1,800003cc +800001c0: 200022b7 lui t0,0x20002 +800001c4: 3b205073 csrwi pmpaddr2,0 +800001c8: 3b202373 csrr t1,pmpaddr2 +800001cc: 20030063 beqz t1,800003cc +800001d0: 1e629e63 bne t0,t1,800003cc +800001d4: 800080b7 lui ra,0x80008 +800001d8: deadc137 lui sp,0xdeadc +800001dc: eef10113 addi sp,sp,-273 # deadbeef +800001e0: 0020a023 sw sp,0(ra) # 80008000 +800001e4: 00000f17 auipc t5,0x0 +800001e8: 010f0f13 addi t5,t5,16 # 800001f4 +800001ec: 0000a183 lw gp,0(ra) +800001f0: 1dc0006f j 800003cc -800001e8 : -800001e8: 00300e13 li t3,3 -800001ec: 00000f17 auipc t5,0x0 -800001f0: 160f0f13 addi t5,t5,352 # 8000034c -800001f4: 00ff02b7 lui t0,0xff0 -800001f8: 3b32a073 csrs pmpaddr3,t0 -800001fc: 3b302373 csrr t1,pmpaddr3 -80000200: 14629663 bne t0,t1,8000034c -80000204: 0ff00293 li t0,255 -80000208: 3b32a073 csrs pmpaddr3,t0 -8000020c: 3b302373 csrr t1,pmpaddr3 -80000210: 00ff02b7 lui t0,0xff0 -80000214: 0ff28293 addi t0,t0,255 # ff00ff <_start-0x7f00ff01> -80000218: 12629a63 bne t0,t1,8000034c +800001f4 : +800001f4: 00300e13 li t3,3 +800001f8: 00000f17 auipc t5,0x0 +800001fc: 1d4f0f13 addi t5,t5,468 # 800003cc +80000200: 00ff02b7 lui t0,0xff0 +80000204: 3b32a073 csrs pmpaddr3,t0 +80000208: 3b302373 csrr t1,pmpaddr3 +8000020c: 1c629063 bne t0,t1,800003cc +80000210: 0ff00293 li t0,255 +80000214: 3b32a073 csrs pmpaddr3,t0 +80000218: 3b302373 csrr t1,pmpaddr3 8000021c: 00ff02b7 lui t0,0xff0 -80000220: 3b32b073 csrc pmpaddr3,t0 -80000224: 3b302373 csrr t1,pmpaddr3 -80000228: 0ff00293 li t0,255 -8000022c: 12629063 bne t0,t1,8000034c -80000230: 00ff02b7 lui t0,0xff0 -80000234: 0ff28293 addi t0,t0,255 # ff00ff <_start-0x7f00ff01> -80000238: 3a02b073 csrc pmpcfg0,t0 -8000023c: 3a002373 csrr t1,pmpcfg0 -80000240: 079202b7 lui t0,0x7920 -80000244: 10629463 bne t0,t1,8000034c -80000248: 00ff02b7 lui t0,0xff0 -8000024c: 70728293 addi t0,t0,1799 # ff0707 <_start-0x7f00f8f9> -80000250: 3a02a073 csrs pmpcfg0,t0 -80000254: 3a002373 csrr t1,pmpcfg0 -80000258: 079202b7 lui t0,0x7920 -8000025c: 70728293 addi t0,t0,1799 # 7920707 <_start-0x786df8f9> -80000260: 0e629663 bne t0,t1,8000034c +80000220: 0ff28293 addi t0,t0,255 # ff00ff <_start-0x7f00ff01> +80000224: 1a629463 bne t0,t1,800003cc +80000228: 00ff02b7 lui t0,0xff0 +8000022c: 3b32b073 csrc pmpaddr3,t0 +80000230: 3b302373 csrr t1,pmpaddr3 +80000234: 0ff00293 li t0,255 +80000238: 18629a63 bne t0,t1,800003cc +8000023c: 00ff02b7 lui t0,0xff0 +80000240: 0ff28293 addi t0,t0,255 # ff00ff <_start-0x7f00ff01> +80000244: 3a02b073 csrc pmpcfg0,t0 +80000248: 3a002373 csrr t1,pmpcfg0 +8000024c: 079202b7 lui t0,0x7920 +80000250: 16629e63 bne t0,t1,800003cc +80000254: 00ff02b7 lui t0,0xff0 +80000258: 70728293 addi t0,t0,1799 # ff0707 <_start-0x7f00f8f9> +8000025c: 3a02a073 csrs pmpcfg0,t0 +80000260: 3a002373 csrr t1,pmpcfg0 +80000264: 079202b7 lui t0,0x7920 +80000268: 70728293 addi t0,t0,1799 # 7920707 <_start-0x786df8f9> +8000026c: 16629063 bne t0,t1,800003cc -80000264 : -80000264: 00400e13 li t3,4 -80000268: 00000f17 auipc t5,0x0 -8000026c: 0e4f0f13 addi t5,t5,228 # 8000034c -80000270: 00000117 auipc sp,0x0 -80000274: 01010113 addi sp,sp,16 # 80000280 -80000278: 34111073 csrw mepc,sp -8000027c: 30200073 mret +80000270 : +80000270: 00400e13 li t3,4 +80000274: 00000f17 auipc t5,0x0 +80000278: 158f0f13 addi t5,t5,344 # 800003cc +8000027c: 00000117 auipc sp,0x0 +80000280: 01010113 addi sp,sp,16 # 8000028c +80000284: 34111073 csrw mepc,sp +80000288: 30200073 mret -80000280 : -80000280: 00500e13 li t3,5 -80000284: 00000f17 auipc t5,0x0 -80000288: 0c8f0f13 addi t5,t5,200 # 8000034c -8000028c: deadc137 lui sp,0xdeadc -80000290: eef10113 addi sp,sp,-273 # deadbeef -80000294: 800080b7 lui ra,0x80008 -80000298: 0020a023 sw sp,0(ra) # 80008000 -8000029c: 00000f17 auipc t5,0x0 -800002a0: 010f0f13 addi t5,t5,16 # 800002ac -800002a4: 0000a183 lw gp,0(ra) -800002a8: 0a40006f j 8000034c +8000028c : +8000028c: 00500e13 li t3,5 +80000290: 00000f17 auipc t5,0x0 +80000294: 13cf0f13 addi t5,t5,316 # 800003cc +80000298: deadc137 lui sp,0xdeadc +8000029c: eef10113 addi sp,sp,-273 # deadbeef +800002a0: 800080b7 lui ra,0x80008 +800002a4: 0020a023 sw sp,0(ra) # 80008000 +800002a8: 00000f17 auipc t5,0x0 +800002ac: 010f0f13 addi t5,t5,16 # 800002b8 +800002b0: 0000a183 lw gp,0(ra) +800002b4: 1180006f j 800003cc -800002ac : -800002ac: 00600e13 li t3,6 -800002b0: 00000f17 auipc t5,0x0 -800002b4: 09cf0f13 addi t5,t5,156 # 8000034c -800002b8: deadc137 lui sp,0xdeadc -800002bc: eef10113 addi sp,sp,-273 # deadbeef -800002c0: 800000b7 lui ra,0x80000 -800002c4: 0020a023 sw sp,0(ra) # 80000000 -800002c8: 0000a183 lw gp,0(ra) -800002cc: 08311063 bne sp,gp,8000034c +800002b8 : +800002b8: 00600e13 li t3,6 +800002bc: 00000f17 auipc t5,0x0 +800002c0: 110f0f13 addi t5,t5,272 # 800003cc +800002c4: deadc137 lui sp,0xdeadc +800002c8: eef10113 addi sp,sp,-273 # deadbeef +800002cc: 800000b7 lui ra,0x80000 +800002d0: 0020a023 sw sp,0(ra) # 80000000 +800002d4: 0000a183 lw gp,0(ra) +800002d8: 0e311a63 bne sp,gp,800003cc -800002d0 : -800002d0: 00700e13 li t3,7 -800002d4: 00000f17 auipc t5,0x0 -800002d8: 078f0f13 addi t5,t5,120 # 8000034c -800002dc: 800400b7 lui ra,0x80040 -800002e0: 0000a183 lw gp,0(ra) # 80040000 -800002e4: 00000f17 auipc t5,0x0 -800002e8: 074f0f13 addi t5,t5,116 # 80000358 -800002ec: 0030a023 sw gp,0(ra) -800002f0: 05c0006f j 8000034c +800002dc : +800002dc: 00700e13 li t3,7 +800002e0: 00000f17 auipc t5,0x0 +800002e4: 0ecf0f13 addi t5,t5,236 # 800003cc +800002e8: 800400b7 lui ra,0x80040 +800002ec: 0000a183 lw gp,0(ra) # 80040000 +800002f0: 00000f17 auipc t5,0x0 +800002f4: 010f0f13 addi t5,t5,16 # 80000300 +800002f8: 0030a023 sw gp,0(ra) +800002fc: 0d00006f j 800003cc -800002f4 : -800002f4: 00800e13 li t3,8 -800002f8: 00000f17 auipc t5,0x0 -800002fc: 054f0f13 addi t5,t5,84 # 8000034c -80000300: deadc137 lui sp,0xdeadc -80000304: eef10113 addi sp,sp,-273 # deadbeef -80000308: 800300b7 lui ra,0x80030 -8000030c: ff808093 addi ra,ra,-8 # 8002fff8 -80000310: 00222023 sw sp,0(tp) # 0 <_start-0x80000000> -80000314: 00000f17 auipc t5,0x0 -80000318: 010f0f13 addi t5,t5,16 # 80000324 -8000031c: 00022183 lw gp,0(tp) # 0 <_start-0x80000000> -80000320: 02c0006f j 8000034c +80000300 : +80000300: 00800e13 li t3,8 +80000304: 00000f17 auipc t5,0x0 +80000308: 0c8f0f13 addi t5,t5,200 # 800003cc +8000030c: deadc137 lui sp,0xdeadc +80000310: eef10113 addi sp,sp,-273 # deadbeef +80000314: 803400b7 lui ra,0x80340 +80000318: ff808093 addi ra,ra,-8 # 8033fff8 +8000031c: 00222023 sw sp,0(tp) # 0 <_start-0x80000000> +80000320: 00000f17 auipc t5,0x0 +80000324: 010f0f13 addi t5,t5,16 # 80000330 +80000328: 00022183 lw gp,0(tp) # 0 <_start-0x80000000> +8000032c: 0a00006f j 800003cc -80000324 : -80000324: 00900e13 li t3,9 -80000328: 00000f17 auipc t5,0x0 -8000032c: 024f0f13 addi t5,t5,36 # 8000034c -80000330: 800400b7 lui ra,0x80040 -80000334: ff808093 addi ra,ra,-8 # 8003fff8 -80000338: 0000a183 lw gp,0(ra) -8000033c: 00000f17 auipc t5,0x0 -80000340: 01cf0f13 addi t5,t5,28 # 80000358 -80000344: 0030a023 sw gp,0(ra) -80000348: 0040006f j 8000034c +80000330 : +80000330: 00900e13 li t3,9 +80000334: 00000f17 auipc t5,0x0 +80000338: 098f0f13 addi t5,t5,152 # 800003cc +8000033c: 803800b7 lui ra,0x80380 +80000340: ff808093 addi ra,ra,-8 # 8037fff8 +80000344: 0000a183 lw gp,0(ra) +80000348: 00000f17 auipc t5,0x0 +8000034c: 010f0f13 addi t5,t5,16 # 80000358 +80000350: 0030a023 sw gp,0(ra) +80000354: 0780006f j 800003cc -8000034c : -8000034c: f0100137 lui sp,0xf0100 -80000350: f2410113 addi sp,sp,-220 # f00fff24 -80000354: 01c12023 sw t3,0(sp) +80000358 : +80000358: 00a00e13 li t3,10 +8000035c: 00000f17 auipc t5,0x0 +80000360: 014f0f13 addi t5,t5,20 # 80000370 +80000364: 00100493 li s1,1 +80000368: 3a305073 csrwi pmpcfg3,0 +8000036c: 0600006f j 800003cc -80000358 : -80000358: f0100137 lui sp,0xf0100 -8000035c: f2010113 addi sp,sp,-224 # f00fff20 -80000360: 00012023 sw zero,0(sp) +80000370 : +80000370: 00a00e13 li t3,10 +80000374: 0f1e22b7 lui t0,0xf1e2 +80000378: 90028293 addi t0,t0,-1792 # f1e1900 <_start-0x70e1e700> +8000037c: 3a302373 csrr t1,pmpcfg3 +80000380: 04629663 bne t0,t1,800003cc + +80000384 : +80000384: 00b00e13 li t3,11 +80000388: 00000f17 auipc t5,0x0 +8000038c: 044f0f13 addi t5,t5,68 # 800003cc +80000390: 00000493 li s1,0 +80000394: 00000117 auipc sp,0x0 +80000398: 01010113 addi sp,sp,16 # 800003a4 +8000039c: 34111073 csrw mepc,sp +800003a0: 30200073 mret + +800003a4 : +800003a4: 00b00e13 li t3,11 +800003a8: 00000f17 auipc t5,0x0 +800003ac: 014f0f13 addi t5,t5,20 # 800003bc +800003b0: 00100493 li s1,1 +800003b4: 3ba05073 csrwi pmpaddr10,0 +800003b8: 0140006f j 800003cc + +800003bc : +800003bc: 00b00e13 li t3,11 +800003c0: fff00293 li t0,-1 +800003c4: 3ba02373 csrr t1,pmpaddr10 +800003c8: 00628863 beq t0,t1,800003d8 + +800003cc : +800003cc: f0100137 lui sp,0xf0100 +800003d0: f2410113 addi sp,sp,-220 # f00fff24 +800003d4: 01c12023 sw t3,0(sp) + +800003d8 : +800003d8: f0100137 lui sp,0xf0100 +800003dc: f2010113 addi sp,sp,-224 # f00fff20 +800003e0: 00012023 sw zero,0(sp) diff --git a/src/test/cpp/raw/pmp/build/pmp.elf b/src/test/cpp/raw/pmp/build/pmp.elf index 68e30ea6a9ba2d543a6c80014c5854c5ee1aca40..26fc85b43a89acc7708191e30981cd7f5b88847c 100755 GIT binary patch literal 5952 zcmeHLPiP!f9R9t@CZS?yH~UP|#{QY^mYRd4v)i?aJ0NXP4^rsjq4XfcooUpCXqI`? zq98bIb5IaEWU7J(S&LU8co`2KjAudcEVR z-ZyU+_PzJQl@}Rfq?-5$j(AK(jp7|GR@F*I$lwHh#20VB9hm%q*7k?idHyK zI8ZoHI8ZoHI8ZoHI8ZoHI8ZoHI8ZoHIPgDlATAMof@g_CVj}9;+jNPE%ITJOw?u+0 z`*kW4H;ER@M7(^po#6le>HydNm%niK@b~)AqPkV1+n*D8mB!lbGX{Al8W$6zIx8Zh zE$Y>`TSV1%QY}+FxEG12)=p}t%JINJzu8Uslod>rpLuz`koVGcNX(6q`co3!!aKZ{Js~t3*5Yv z&3$Kn5#DheK8ea)OYSvpcJ%tW-d}Pp((_5L!Z~ifs=2w57JE}_rJvqX!{laP*E16; zg_75G>O&iz(@}1Q8F%OLah+BehvA{z*IF;%G4zjdGt&Aa39TvJqjkesZVofuRTh^j zBsz8*_s>XvwCC$~+xyrpadS^=OY(bs)R)nCR%__U?^NEW_HljaU@y=rt32TB@8~N$Is6Ln^&Gwd+|S`H;GG-}fWOG$cY(jj;T_|8=G(U0(!06+frmh#ioiERBWmEjEWakTvc&R#b;G)*xf9< zX>Me=p|MB(t`M{#g03H^iHTOkJ8uSE7di0L{D$t~DL2HX7xcE@q7}8NR=Ppp_uQL! za=FU?)}Dln;hIV1p*%O1XUMvhvd%Ix=)UIfbD|{;kYx?oWX4bVxJi>i$~y80TV_l_ dM{wn)p>Uq)BXGLudU9Xqb@M3F)*@uB`x`f|h-Lr) delta 881 zcmY+Dzi-n(6vvUx1a^=ZkchZ~goIQp z-H@QBhe}m3q&rCIM|h#47ZvtqbeE6Zn9Y4DvEA5Jd)b+ ztK#8_>N3nxm5s}0|LgX`uf$h?iSF+KZ#fNaJB@%SmEe_c#uj#NF^sWBa7;0SH@=z3 zRYQZS&UhFjmIuIl=hLm*{)`}cX=T^fhw*+I7xGUnh|(Cg(s(}|HkP-FC`*!B(S6+E zy)2$^uJiUfy(e62bS5%;CIF1!E9VHZDIIx*D%4t&a&9PplY6N9#c$ZB%5lsp+ z;X^4E_QYrUY~92I;gdj8lJP9ECuM9QhdDlr{5{7tD=QS*6#DQOGAHIOd1{W x)G(yBcxl+^_l+~>LJGj}!A=Y%vULg>f0`rf&ESQJLfJNz5 Date: Mon, 12 Apr 2021 10:14:10 +0200 Subject: [PATCH 639/951] Update README.md --- README.md | 102 +++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 78 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index eec2dd02..79e66c95 100644 --- a/README.md +++ b/README.md @@ -7,9 +7,9 @@ - [CPU generation](#cpu-generation) - [Regression tests](#regression-tests) - [Interactive debug of the simulated CPU via GDB OpenOCD and Verilator](#interactive-debug-of-the-simulated-cpu-via-gdb-openocd-and-verilator) -- [Using Eclipse to run and debug the software](#using-Eclipse-to-run-and-debug-the-software) - * [By using gnu-mcu-eclipse](#by-using-gnu-mcu-eclipse) - * [By using Zylin plugin (old)](#by-using-zylin-plugin-old) +- [Using Eclipse to run and debug the software](#using-eclipse-to-run-and-debug-the-software) + - [By using gnu-mcu-eclipse](#by-using-gnu-mcu-eclipse) + - [By using Zylin plugin (old)](#by-using-zylin-plugin-old) - [Briey SoC](#briey-soc) - [Murax SoC](#murax-soc) - [Running Linux](#running-linux) @@ -19,7 +19,32 @@ - [Adding a new CSR via the plugin system](#adding-a-new-csr-via-the-plugin-system) - [CPU clock and resets](#cpu-clock-and-resets) - [VexRiscv Architecture](#vexriscv-architecture) - * [Plugins](#plugins) + - [Plugins](#plugins) + - [IBusSimplePlugin](#ibussimpleplugin) + - [IBusCachedPlugin](#ibuscachedplugin) + - [DecoderSimplePlugin](#decodersimpleplugin) + - [RegFilePlugin](#regfileplugin) + - [HazardSimplePlugin](#hazardsimpleplugin) + - [SrcPlugin](#srcplugin) + - [IntAluPlugin](#intaluplugin) + - [LightShifterPlugin](#lightshifterplugin) + - [FullBarrelShifterPlugin](#fullbarrelshifterplugin) + - [BranchPlugin](#branchplugin) + - [Prediction NONE](#prediction-none) + - [Prediction STATIC](#prediction-static) + - [Prediction DYNAMIC](#prediction-dynamic) + - [Prediction DYNAMIC_TARGET](#prediction-dynamic_target) + - [DBusSimplePlugin](#dbussimpleplugin) + - [DBusCachedPlugin](#dbuscachedplugin) + - [MulPlugin](#mulplugin) + - [DivPlugin](#divplugin) + - [MulDivIterativePlugin](#muldiviterativeplugin) + - [CsrPlugin](#csrplugin) + - [StaticMemoryTranslatorPlugin](#staticmemorytranslatorplugin) + - [MmuPlugin](#mmuplugin) + - [PmpPlugin](#pmpplugin) + - [DebugPlugin](#debugplugin) + - [YamlPlugin](#yamlplugin) @@ -672,26 +697,51 @@ and everything else, including the program counter is added into the CPU via plu This chapter describes the currently implemented plugins. -- [IBusSimplePlugin](#ibussimpleplugin) -- [IBusCachedPlugin](#ibuscachedplugin) -- [DecoderSimplePlugin](#decodersimpleplugin) -- [RegFilePlugin](#regfileplugin) -- [HazardSimplePlugin](#hazardsimpleplugin) -- [SrcPlugin](#srcplugin) -- [IntAluPlugin](#intaluplugin) -- [LightShifterPlugin](#lightshifterplugin) -- [FullBarrelShifterPlugin](#fullbarrelshifterplugin) -- [BranchPlugin](#branchplugin) -- [DBusSimplePlugin](#dbussimpleplugin) -- [DBusCachedPlugin](#dbuscachedplugin) -- [MulPlugin](#mulplugin) -- [DivPlugin](#divplugin) -- [MulDivIterativePlugin](#muldiviterativeplugin) -- [CsrPlugin](#csrplugin) -- [StaticMemoryTranslatorPlugin](#staticmemorytranslatorplugin) -- [MemoryTranslatorPlugin](#memorytranslatorplugin) -- [DebugPlugin](#debugplugin) -- [YamlPlugin](#yamlplugin) +- [Index](#index) +- [Description](#description) +- [Area usage and maximal frequency](#area-usage-and-maximal-frequency) +- [Dependencies](#dependencies) +- [CPU generation](#cpu-generation) +- [Regression tests](#regression-tests) +- [Interactive debug of the simulated CPU via GDB OpenOCD and Verilator](#interactive-debug-of-the-simulated-cpu-via-gdb-openocd-and-verilator) +- [Using Eclipse to run and debug the software](#using-eclipse-to-run-and-debug-the-software) + - [By using gnu-mcu-eclipse](#by-using-gnu-mcu-eclipse) + - [By using Zylin plugin (old)](#by-using-zylin-plugin-old) +- [Briey SoC](#briey-soc) +- [Murax SoC](#murax-soc) +- [Running Linux](#running-linux) +- [Build the RISC-V GCC](#build-the-risc-v-gcc) +- [CPU parametrization and instantiation example](#cpu-parametrization-and-instantiation-example) +- [Add a custom instruction to the CPU via the plugin system](#add-a-custom-instruction-to-the-cpu-via-the-plugin-system) +- [Adding a new CSR via the plugin system](#adding-a-new-csr-via-the-plugin-system) +- [CPU clock and resets](#cpu-clock-and-resets) +- [VexRiscv Architecture](#vexriscv-architecture) + - [Plugins](#plugins) + - [IBusSimplePlugin](#ibussimpleplugin) + - [IBusCachedPlugin](#ibuscachedplugin) + - [DecoderSimplePlugin](#decodersimpleplugin) + - [RegFilePlugin](#regfileplugin) + - [HazardSimplePlugin](#hazardsimpleplugin) + - [SrcPlugin](#srcplugin) + - [IntAluPlugin](#intaluplugin) + - [LightShifterPlugin](#lightshifterplugin) + - [FullBarrelShifterPlugin](#fullbarrelshifterplugin) + - [BranchPlugin](#branchplugin) + - [Prediction NONE](#prediction-none) + - [Prediction STATIC](#prediction-static) + - [Prediction DYNAMIC](#prediction-dynamic) + - [Prediction DYNAMIC_TARGET](#prediction-dynamic_target) + - [DBusSimplePlugin](#dbussimpleplugin) + - [DBusCachedPlugin](#dbuscachedplugin) + - [MulPlugin](#mulplugin) + - [DivPlugin](#divplugin) + - [MulDivIterativePlugin](#muldiviterativeplugin) + - [CsrPlugin](#csrplugin) + - [StaticMemoryTranslatorPlugin](#staticmemorytranslatorplugin) + - [MmuPlugin](#mmuplugin) + - [PmpPlugin](#pmpplugin) + - [DebugPlugin](#debugplugin) + - [YamlPlugin](#yamlplugin) #### IBusSimplePlugin @@ -1027,6 +1077,10 @@ Static memory translator plugin which allows to specify which range of the memor Hardware refilled MMU implementation. Allows other plugins such as DBusCachedPlugin/IBusCachedPlugin to instanciate memory address translation ports. Each port has a small dedicated fully associative TLB cache which is refilled automaticaly via a dbus access sharing. +#### PmpPlugin + +This is a physical memory protection (PMP) plugin which conforms to the latest RISC-V privilege specification. PMP is configured by writing two special CSRs: `pmpcfg#` and `pmpaddr#`. The former contains the permissions and addressing modes for four protection regions, and the latter contains the encoded start address for a single region. Since the actual region bounds must be computed from the values written to these registers, writing them takes a few CPU cylces: (5 for `pmpcfg#` and 2-3 for `pmpaddr#`). This delay is necessary in order to centralize all of the decoding logic into a single component. Otherwise, it would have to be duplicated for each region, even though the decoding operation happens only when PMP is reprogrammed (e.g., on some context switches). + #### DebugPlugin This plugin implements enough CPU debug features to allow comfortable GDB/Eclipse debugging. To access those debug features, it provides a simple memory bus interface. From 4e41654a84c1a683cd9458ffc1e6b4fde11a6c35 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 12 Apr 2021 18:28:41 +0200 Subject: [PATCH 640/951] remove eclipse plugin --- project/plugins.sbt | 2 -- 1 file changed, 2 deletions(-) diff --git a/project/plugins.sbt b/project/plugins.sbt index 60a54de4..26ac3e58 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,3 +1 @@ -addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "5.2.4") - addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.10") From 79bc09e69aa9b83dd4499b70ae2c4552edf9bcb9 Mon Sep 17 00:00:00 2001 From: Samuel Lindemer Date: Tue, 13 Apr 2021 08:35:07 +0200 Subject: [PATCH 641/951] Decouple PMP and CSR plugins --- .../scala/vexriscv/plugin/CsrPlugin.scala | 40 +++++++------------ .../scala/vexriscv/plugin/PmpPlugin.scala | 12 ++++++ 2 files changed, 27 insertions(+), 25 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 87a3cbb6..98fc1135 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -36,8 +36,6 @@ object CsrPlugin { object IS_CSR extends Stageable(Bool) object CSR_WRITE_OPCODE extends Stageable(Bool) object CSR_READ_OPCODE extends Stageable(Bool) - object IS_PMP_CFG extends Stageable(Bool) - object IS_PMP_ADDR extends Stageable(Bool) } case class ExceptionPortInfo(port : Flow[ExceptionCause],stage : Stage, priority : Int) @@ -350,6 +348,7 @@ case class CsrDuringWrite(doThat :() => Unit) case class CsrDuringRead(doThat :() => Unit) case class CsrDuring(doThat :() => Unit) case class CsrOnRead(doThat : () => Unit) +case class CsrIgnoreIllegal() case class CsrMapping() extends CsrInterface{ val mapping = mutable.LinkedHashMap[Int,ArrayBuffer[Any]]() def addMappingAt(address : Int,that : Any) = mapping.getOrElseUpdate(address,new ArrayBuffer[Any]) += that @@ -362,6 +361,7 @@ case class CsrMapping() extends CsrInterface{ override def during(csrAddress: Int)(body: => Unit): Unit = addMappingAt(csrAddress, CsrDuring(() => body)) override def onRead(csrAddress: Int)(body: => Unit): Unit = addMappingAt(csrAddress, CsrOnRead(() => {body})) override def duringAny(): Bool = ??? + override def ignoreIllegal(csrAddress: Int) : Unit = addMappingAt(csrAddress, CsrIgnoreIllegal()) } @@ -378,6 +378,7 @@ trait CsrInterface{ r(csrAddress,bitOffset,that) w(csrAddress,bitOffset,that) } + def ignoreIllegal(csrAddress : Int) : Unit def r2w(csrAddress : Int, bitOffset : Int,that : Data): Unit @@ -497,6 +498,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep override def duringRead(csrAddress: Int)(body: => Unit): Unit = csrMapping.duringRead(csrAddress)(body) override def during(csrAddress: Int)(body: => Unit): Unit = csrMapping.during(csrAddress)(body) override def duringAny(): Bool = pipeline.execute.arbitration.isValid && pipeline.execute.input(IS_CSR) + override def ignoreIllegal(csrAddress: Int): Unit = csrMapping.ignoreIllegal(csrAddress) override def setup(pipeline: VexRiscv): Unit = { import pipeline.config._ @@ -1049,11 +1051,6 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep || (input(INSTRUCTION)(14 downto 13) === B"11" && imm.z === 0) ) insert(CSR_READ_OPCODE) := input(INSTRUCTION)(13 downto 7) =/= B"0100000" - - if (pipeline.serviceExist(classOf[PmpPlugin])) { - insert(IS_PMP_CFG) := input(INSTRUCTION)(31 downto 24) === 0x3a - insert(IS_PMP_ADDR) := input(INSTRUCTION)(31 downto 24) === 0x3b - } } execute plug new Area{ @@ -1127,32 +1124,25 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep True -> Mux(input(INSTRUCTION)(12), readToWriteData & ~writeSrc, readToWriteData | writeSrc) ) - val csrAddress = input(INSTRUCTION)(csrRange) - val pmpAccess = if (pipeline.serviceExist(classOf[PmpPlugin])) { - input(IS_PMP_CFG) | input(IS_PMP_ADDR) - } else False - - when (~pmpAccess) { - when(arbitration.isValid && input(IS_CSR)) { - if(!pipelineCsrRead) output(REGFILE_WRITE_DATA) := readData - arbitration.haltItself setWhen(blockedBySideEffects) + when(arbitration.isValid && input(IS_CSR)) { + if(!pipelineCsrRead) output(REGFILE_WRITE_DATA) := readData + arbitration.haltItself setWhen(blockedBySideEffects) + } + if(pipelineCsrRead){ + insert(PIPELINED_CSR_READ) := readData + when(memory.arbitration.isValid && memory.input(IS_CSR)) { + memory.output(REGFILE_WRITE_DATA) := memory.input(PIPELINED_CSR_READ) } - if(pipelineCsrRead){ - insert(PIPELINED_CSR_READ) := readData - when(memory.arbitration.isValid && memory.input(IS_CSR)) { - memory.output(REGFILE_WRITE_DATA) := memory.input(PIPELINED_CSR_READ) - } - } - }.elsewhen(arbitration.isValid && input(IS_CSR)) { - illegalAccess := False } //Translation of the csrMapping into real logic + val csrAddress = input(INSTRUCTION)(csrRange) Component.current.afterElaboration{ def doJobs(jobs : ArrayBuffer[Any]): Unit ={ val withWrite = jobs.exists(j => j.isInstanceOf[CsrWrite] || j.isInstanceOf[CsrOnWrite] || j.isInstanceOf[CsrDuringWrite]) val withRead = jobs.exists(j => j.isInstanceOf[CsrRead] || j.isInstanceOf[CsrOnRead]) - if(withRead && withWrite) { + val ignoreIllegal = jobs.exists(j => j.isInstanceOf[CsrIgnoreIllegal]) + if(withRead && withWrite | ignoreIllegal) { illegalAccess := False } else { if (withWrite) illegalAccess.clearWhen(input(CSR_WRITE_OPCODE)) diff --git a/src/main/scala/vexriscv/plugin/PmpPlugin.scala b/src/main/scala/vexriscv/plugin/PmpPlugin.scala index 7f120dac..1f494532 100644 --- a/src/main/scala/vexriscv/plugin/PmpPlugin.scala +++ b/src/main/scala/vexriscv/plugin/PmpPlugin.scala @@ -137,6 +137,9 @@ class PmpPlugin(regions : Int, ioRange : UInt => Bool) extends Plugin[VexRiscv] val csrService = pipeline.service(classOf[CsrInterface]) val privilegeService = pipeline.service(classOf[PrivilegeService]) + for (i <- 0x3a0 to 0x3a3) csrService.ignoreIllegal(i) + for (i <- 0x3b0 to 0x3bf) csrService.ignoreIllegal(i) + val pmpaddr = Mem(UInt(xlen bits), regions) val pmpcfg = Reg(Bits(8 * regions bits)) init(0) val boundLo, boundHi = Mem(UInt(30 bits), regions) @@ -144,6 +147,15 @@ class PmpPlugin(regions : Int, ioRange : UInt => Bool) extends Plugin[VexRiscv] val cfgRegister = pmpcfg.subdivideIn(xlen bits) val lockMask = Reg(Bits(4 bits)) init(B"4'0") + object IS_PMP_CFG extends Stageable(Bool) + object IS_PMP_ADDR extends Stageable(Bool) + + decode plug new Area { + import decode._ + insert(IS_PMP_CFG) := input(INSTRUCTION)(31 downto 24) === 0x3a + insert(IS_PMP_ADDR) := input(INSTRUCTION)(31 downto 24) === 0x3b + } + execute plug new Area { import execute._ From bfe65da1ebd8b87421a1b8ce4fe4e640b599916f Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 20 Apr 2021 23:23:18 +0200 Subject: [PATCH 642/951] implement #176 DebugPlugin.allowEBreak is now disabled until the debug bus is used. --- src/main/scala/vexriscv/plugin/DebugPlugin.scala | 5 +++-- src/test/cpp/regression/main.cpp | 5 ++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/DebugPlugin.scala b/src/main/scala/vexriscv/plugin/DebugPlugin.scala index c75db107..45e9a973 100644 --- a/src/main/scala/vexriscv/plugin/DebugPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DebugPlugin.scala @@ -226,6 +226,9 @@ class DebugPlugin(var debugClockDomain : ClockDomain, hardwareBreakpointCount : val isPipBusy = RegNext(stages.map(_.arbitration.isValid).orR || iBusFetcher.incoming()) val godmode = RegInit(False) setWhen(haltIt && !isPipBusy) val haltedByBreak = RegInit(False) + val allowEBreak = RegInit(False) setWhen(io.bus.cmd.valid) +// val allowEBreak = if(!pipeline.serviceExist(classOf[PrivilegeService])) True else pipeline.service(classOf[PrivilegeService]).isMachine() + val hardwareBreakpoints = Vec(Reg(new Bundle{ val valid = Bool() @@ -277,8 +280,6 @@ class DebugPlugin(var debugClockDomain : ClockDomain, hardwareBreakpointCount : } } - val allowEBreak = if(!pipeline.serviceExist(classOf[PrivilegeService])) True else pipeline.service(classOf[PrivilegeService]).isMachine() - decode.insert(DO_EBREAK) := !haltIt && (decode.input(IS_EBREAK) || hardwareBreakpoints.map(hb => hb.valid && hb.pc === (decode.input(PC) >> 1)).foldLeft(False)(_ || _)) && allowEBreak when(execute.arbitration.isValid && execute.input(DO_EBREAK)){ execute.arbitration.haltByOther := True diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index e58aba37..48120d2a 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -2824,13 +2824,16 @@ public: socklen_t addr_size; char buffer[1024]; uint32_t timeSpacer = 0; - bool taskValid = false; + bool taskValid; DebugPluginTask task; DebugPlugin(Workspace* ws){ this->ws = ws; this->top = ws->top; + taskValid = true; //true as a Workaround to enable the ebreak + task.wr = false; + task.address = 0; #ifdef DEBUG_PLUGIN_EXTERNAL ws->mTimeCmp = ~0; From 32e4ea406f52759557c29a494a9681ecc1ae07b9 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 22 Apr 2021 13:59:33 +0200 Subject: [PATCH 643/951] update #176 when DebugPlugin ebreak are enabled it disable CsrPlugin ebreak. Also, DebugPlugin ebreak can be disabled via the debug bus. --- src/main/scala/vexriscv/Services.scala | 1 + src/main/scala/vexriscv/plugin/CsrPlugin.scala | 7 ++++++- src/main/scala/vexriscv/plugin/DebugPlugin.scala | 14 ++++++++++---- src/test/cpp/regression/main.cpp | 11 +++++++---- 4 files changed, 24 insertions(+), 9 deletions(-) diff --git a/src/main/scala/vexriscv/Services.scala b/src/main/scala/vexriscv/Services.scala index 5da43af1..59a81621 100644 --- a/src/main/scala/vexriscv/Services.scala +++ b/src/main/scala/vexriscv/Services.scala @@ -56,6 +56,7 @@ trait InterruptionInhibitor{ trait ExceptionInhibitor{ def inhibateException() : Unit + def inhibateEbreakException() : Unit } diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 456d6888..71f3c8a5 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -32,6 +32,8 @@ object CsrAccess { object NONE extends CsrAccess } + + case class ExceptionPortInfo(port : Flow[ExceptionCause],stage : Stage, priority : Int) case class CsrPluginConfig( catchIllegalAccess : Boolean, @@ -457,6 +459,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep var allowInterrupts : Bool = null var allowException : Bool = null + var allowEbreakException : Bool = null val csrMapping = new CsrMapping() @@ -565,6 +568,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep allowInterrupts = True allowException = True + allowEbreakException = True for (i <- interruptSpecs) i.cond = i.cond.pull() @@ -577,6 +581,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep def inhibateInterrupts() : Unit = allowInterrupts := False def inhibateException() : Unit = allowException := False + def inhibateEbreakException() : Unit = allowEbreakException := False override def isUser() : Bool = privilege === 0 override def isSupervisor(): Bool = privilege === 1 @@ -1097,7 +1102,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep } - if(ebreakGen) when(arbitration.isValid && input(ENV_CTRL) === EnvCtrlEnum.EBREAK){ + if(ebreakGen) when(arbitration.isValid && input(ENV_CTRL) === EnvCtrlEnum.EBREAK && allowEbreakException){ selfException.valid := True selfException.code := 3 } diff --git a/src/main/scala/vexriscv/plugin/DebugPlugin.scala b/src/main/scala/vexriscv/plugin/DebugPlugin.scala index 45e9a973..cc302c93 100644 --- a/src/main/scala/vexriscv/plugin/DebugPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DebugPlugin.scala @@ -176,8 +176,6 @@ case class DebugExtensionIo() extends Bundle with IMasterSlave{ } } - - class DebugPlugin(var debugClockDomain : ClockDomain, hardwareBreakpointCount : Int = 0) extends Plugin[VexRiscv] { var io : DebugExtensionIo = null @@ -226,9 +224,10 @@ class DebugPlugin(var debugClockDomain : ClockDomain, hardwareBreakpointCount : val isPipBusy = RegNext(stages.map(_.arbitration.isValid).orR || iBusFetcher.incoming()) val godmode = RegInit(False) setWhen(haltIt && !isPipBusy) val haltedByBreak = RegInit(False) - val allowEBreak = RegInit(False) setWhen(io.bus.cmd.valid) -// val allowEBreak = if(!pipeline.serviceExist(classOf[PrivilegeService])) True else pipeline.service(classOf[PrivilegeService]).isMachine() + val debugUsed = RegInit(False) setWhen(io.bus.cmd.valid) addAttribute(Verilator.public) + val disableEbreak = RegInit(False) + val allowEBreak = debugUsed && !disableEbreak val hardwareBreakpoints = Vec(Reg(new Bundle{ val valid = Bool() @@ -262,6 +261,7 @@ class DebugPlugin(var debugClockDomain : ClockDomain, hardwareBreakpointCount : haltIt setWhen (io.bus.cmd.data(17)) clearWhen (io.bus.cmd.data(25)) haltedByBreak clearWhen (io.bus.cmd.data(25)) godmode clearWhen(io.bus.cmd.data(25)) + disableEbreak setWhen (io.bus.cmd.data(18)) clearWhen (io.bus.cmd.data(26)) } } is(0x1) { @@ -329,6 +329,12 @@ class DebugPlugin(var debugClockDomain : ClockDomain, hardwareBreakpointCount : } if(pipeline.things.contains(DEBUG_BYPASS_CACHE)) pipeline(DEBUG_BYPASS_CACHE) := True } + when(!allowEBreak) { + pipeline.plugins.foreach { + case p: ExceptionInhibitor => p.inhibateEbreakException() + case _ => + } + } val wakeService = serviceElse(classOf[IWake], null) if(wakeService != null) when(haltIt){ diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 48120d2a..c8ad579d 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -1673,6 +1673,7 @@ public: } #endif + bool failed = false; try { // run simulation for 100 clock periods @@ -2824,16 +2825,13 @@ public: socklen_t addr_size; char buffer[1024]; uint32_t timeSpacer = 0; - bool taskValid; + bool taskValid = false; DebugPluginTask task; DebugPlugin(Workspace* ws){ this->ws = ws; this->top = ws->top; - taskValid = true; //true as a Workaround to enable the ebreak - task.wr = false; - task.address = 0; #ifdef DEBUG_PLUGIN_EXTERNAL ws->mTimeCmp = ~0; @@ -3499,6 +3497,11 @@ public: if(clientSuccess) pass(); if(clientFail) fail(); } + + virtual void postReset(){ + Workspace::postReset(); + top->VexRiscv->DebugPlugin_debugUsed = 1; + } }; #endif From 0a0998fcea10c34a45be8f3a10c2c6d5d017b262 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 22 Apr 2021 14:02:46 +0200 Subject: [PATCH 644/951] #176 fix typo --- src/main/scala/vexriscv/plugin/DebugPlugin.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/plugin/DebugPlugin.scala b/src/main/scala/vexriscv/plugin/DebugPlugin.scala index cc302c93..b7f621c3 100644 --- a/src/main/scala/vexriscv/plugin/DebugPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DebugPlugin.scala @@ -329,7 +329,7 @@ class DebugPlugin(var debugClockDomain : ClockDomain, hardwareBreakpointCount : } if(pipeline.things.contains(DEBUG_BYPASS_CACHE)) pipeline(DEBUG_BYPASS_CACHE) := True } - when(!allowEBreak) { + when(allowEBreak) { pipeline.plugins.foreach { case p: ExceptionInhibitor => p.inhibateEbreakException() case _ => From 45e67ccf56c24ce168d456c3a188c543f822a469 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 26 Apr 2021 11:10:55 +0200 Subject: [PATCH 645/951] sync --- .gitignore | 1 + .../vexriscv/TestIndividualFeatures.scala | 32 ++++++++++++++++++- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 239d9b71..641c9266 100644 --- a/.gitignore +++ b/.gitignore @@ -46,6 +46,7 @@ obj_dir *.tcl *.o *.bin +explor simWorkspace/ tmp/ diff --git a/src/test/scala/vexriscv/TestIndividualFeatures.scala b/src/test/scala/vexriscv/TestIndividualFeatures.scala index 6167f712..8141448c 100644 --- a/src/test/scala/vexriscv/TestIndividualFeatures.scala +++ b/src/test/scala/vexriscv/TestIndividualFeatures.scala @@ -2,10 +2,10 @@ package vexriscv import java.io.{File, OutputStream} import java.util.concurrent.{ForkJoinPool, TimeUnit} - import org.apache.commons.io.FileUtils import org.scalatest.{BeforeAndAfterAll, FunSuite, ParallelTestExecution, Tag, Transformer} import spinal.core._ +import spinal.lib.DoCmd import vexriscv.demo._ import vexriscv.ip.{DataCacheConfig, InstructionCacheConfig} import vexriscv.plugin._ @@ -840,3 +840,33 @@ class TestIndividualFeatures extends MultithreadedFunSuite(sys.env.getOrElse("VE println(s"Duration=${(time/60).toInt}mn clocks=${(clockCounter*1e-6).toLong}M clockPerSecond=${clockPerSecond}K") } } + + +object TestIndividualExplore extends App{ + val seeds = mutable.HashSet[Int]() + val futures = mutable.ArrayBuffer[Future[Unit]]() + implicit val ec = ExecutionContext.fromExecutorService( + new ForkJoinPool(24, ForkJoinPool.defaultForkJoinWorkerThreadFactory, null, true) + ) + for(i <- 0 until 1000){ + val seed = Random.nextInt(1000000) + 1 + futures += Future { + if (!seeds.contains(seed)) { +// val cmd = s"make run REGRESSION_PATH=../../src/test/cpp/regression VEXRISCV_FILE=VexRiscv.v WITH_USER_IO=no REDO=1 TRACE=yes TRACE_START=100000000000ll FLOW_INFO=no STOP_ON_ERROR=no DHRYSTONE=yes COREMARK=mo THREAD_COUNT=1 IBUS=CACHED IBUS_DATA_WIDTH=128 COMPRESSED=yes DBUS=SIMPLE LRSC=yes MUL=yes DIV=yes FREERTOS=0 ZEPHYR=0 LINUX_REGRESSION=no SUPERVISOR=yes CONCURRENT_OS_EXECUTIONS=yes MMU=yes PMP=no SEED=$seed" + val cmd = s"make run REGRESSION_PATH=../../src/test/cpp/regression VEXRISCV_FILE=VexRiscv.v WITH_USER_IO=no REDO=10 TRACE=yes TRACE_START=100000000000ll FLOW_INFO=no STOP_ON_ERROR=no DHRYSTONE=yes COREMARK=yes THREAD_COUNT=1 IBUS=CACHED IBUS_DATA_WIDTH=128 COMPRESSED=yes DBUS=SIMPLE LRSC=yes MUL=yes DIV=yes FREERTOS=0 ZEPHYR=2 LINUX_REGRESSION=yes SUPERVISOR=yes CONCURRENT_OS_EXECUTIONS=yes MMU=yes PMP=no SEED=$seed" + val workspace = s"explor/seed_$seed" + FileUtils.copyDirectory(new File("simWorkspace/ref"), new File(workspace)) + val str = DoCmd.doCmdWithLog(cmd, workspace) + if(!str.contains("REGRESSION SUCCESS")){ + println(s"seed $seed FAILED with\n\n$str") + sys.exit(1) + } + FileUtils.deleteDirectory(new File(workspace)) + println(s"seed $seed PASSED") + } + } + } + + futures.foreach(Await.result(_, Duration.Inf)) + +} \ No newline at end of file From f10f9246dd82063d1f9d29fab880047d7cc38393 Mon Sep 17 00:00:00 2001 From: Pradeep2004 <78598837+Pradeep2004@users.noreply.github.com> Date: Fri, 30 Apr 2021 17:45:16 +0200 Subject: [PATCH 646/951] Create Readme Debugging Murax SoC without JTAG adapter --- Readme | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 Readme diff --git a/Readme b/Readme new file mode 100644 index 00000000..4fa52650 --- /dev/null +++ b/Readme @@ -0,0 +1,74 @@ +1. INTRODUCTION + +The traditional way of debugging an SoC which is programmed inside a FPGA was by using a JTAG Adapter which comes with an FTDI Chip. In recent times, modern FPGA’s come with an integrated FTDI chip which makes debugging easy with only a USB cable. + +In this document, I am going to guide you through the steps in an experiment which I conducted along with my supervisor to debug an SoC named MURAX without using an external JTAG adapter on ARTY A7 FPGA. + +2. Generation of Bscane2 within Murax SoC in Linux + +The BSCANE2 allows access between the internal FPGA logic and the JTAG Boundary Scan logic controller. This allows for communication between the internal running design and the dedicated JTAG pins of the FPGA. + +2.1 Steps to create Bscane2 + +• After cloning all the files from https://github.com/SpinalHDL/VexRiscv, go to this path : src/main/scala/vexriscv/demo and find the Murax.scala file. + +• Comment out these lines to remove the toplevel jtag I/O pins: + Line 165, Line 395 to 397, Line 410 to 403 + +• In the Murax.scala file, delete line number 253 and add the following lines : + val jtagCtrl = JtagTapInstructionCtrl() + val tap = jtagCtrl.fromXilinxBscane2(userId = 2) + jtagCtrl <> plugin.io.bus.fromJtagInstructionCtrl(ClockDomain(tap.TCK)) + +• Add the following import statement at the beginning in Murax.scala : +import spinal.lib.com.jtag.JtagTapInstructionCtrl + +• Then to generate the SoC with a demo program already in ram, run: +sbt "runMain vexriscv.demo.MuraxWithRamInit" + +• A verilog file will be generated with the name Murax.v and four .bin files will be generated inside VexRiscv folder which can be used to program the FPGA. Inside the Murax.v file, we can see that the Bscane2 ports will be instantiated, confirming that the Bscane2 has been created within the Murax SoC to debug it. +  +3. Programming Arty A7 FPGA + +There are many applications to program a FPGA. I am using Xilinx Vivado 2020 Application to program the FPGA. + +3.1 Steps involved to program the FPGA + +• Create a new project and choose the board which are using and choose the constraint file. + +• As, I mentioned in the previous section a verilog file and four .bin files will be generated in the Vexriscv folder. Copy these files and paste them inside your vivado project in this path : project_name.srcs\sources_1\imports\Downloads + +• Create a toplevel file by instantiating Murax I/O ports in it to blink the LED’s on the FPGA. (Note : The program to blink the LED’s is already present in Murax.v file). The toplevel file and constraint file, if required can be found here : https://github.com/SpinalHDL/VexRiscv/tree/master/scripts/Murax/arty_a7 , but make sure all the jtag ports of Murax are commented or deleted in the toplevel file. + +• Next, click Generate Bitstream and program the FPGA with the bit file. You can see the LED’s blink and Murax SoC has been programmed into the FPGA. + +4. Debugging via OpenOCD GDB in Linux + +• In a new terminal in Linux, after cloning and setting up openocd with the steps provided in this link : https://github.com/SpinalHDL/openocd_riscv , run the below command to establish a openocd connection with Jtag of FPGA. +• To run openocd : +Use the below command : +src/openocd -c "set CPU0_YAML ..VexRiscv/cpu0.yaml" -f tcl/interface/usb_connect.cfg -f tcl/interface/soc_init.cfg + +• You basically have to provide 2 files. +usb_connect.cfg => interface configuration +soc_init.cfg => take over the control of the CPU + +• For usb_connect.cfg +you can take it from https://github.com/SpinalHDL/SaxonSoc/blob/dev-0.3/bsp/digilent/ArtyA7SmpLinux/openocd/usb_connect.cfg (without modifications i would say) + + +• For soc_init.cfg +https://github.com/SpinalHDL/SaxonSoc/blob/dev-0.3/bsp/digilent/ArtyA7SmpLinux/openocd/soc_init.cfg +You can take it but you need to : set cpu_count to 1 and remove Line 22 to 35. + +• Then, after openocd is running, in new terminal, follow the below commands in VexriscvSocSoftware folder ( https://github.com/SpinalHDL/VexRiscvSocSoftware ). + +• Go to the path VexRiscvSocSoftware/projects/murax/demo/build and then give the below commands : + + riscv64-unknown-elf-gdb demo.elf + target remote localhost:3333 + monitor reset halt + load + continue + +• After giving the monitor reset halt command you can see that the LED’s stop blinking and when the continue command is given the LED’s start continuing from the point where they stopped. From ff2b7c64a493764745b700ef23f7087ce1e5530d Mon Sep 17 00:00:00 2001 From: Pradeep2004 <78598837+Pradeep2004@users.noreply.github.com> Date: Fri, 30 Apr 2021 17:46:16 +0200 Subject: [PATCH 647/951] Debugging Murax SoC without JTAG Adapter --- Readme | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Readme b/Readme index 4fa52650..08fc96bd 100644 --- a/Readme +++ b/Readme @@ -51,7 +51,7 @@ src/openocd -c "set CPU0_YAML ..VexRiscv/cpu0.yaml" -f tcl/interface/usb_connect • You basically have to provide 2 files. usb_connect.cfg => interface configuration -soc_init.cfg => take over the control of the CPU +soc_init.cfg => take over the control of the CPU. • For usb_connect.cfg you can take it from https://github.com/SpinalHDL/SaxonSoc/blob/dev-0.3/bsp/digilent/ArtyA7SmpLinux/openocd/usb_connect.cfg (without modifications i would say) From d15f358b44fe11e405e91f0846f109d61156fcc7 Mon Sep 17 00:00:00 2001 From: Pradeep2004 <78598837+Pradeep2004@users.noreply.github.com> Date: Fri, 30 Apr 2021 22:35:41 +0200 Subject: [PATCH 648/951] Update Readme --- Readme | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Readme b/Readme index 08fc96bd..b4b223a6 100644 --- a/Readme +++ b/Readme @@ -12,8 +12,14 @@ The BSCANE2 allows access between the internal FPGA logic and the JTAG Boundary • After cloning all the files from https://github.com/SpinalHDL/VexRiscv, go to this path : src/main/scala/vexriscv/demo and find the Murax.scala file. -• Comment out these lines to remove the toplevel jtag I/O pins: - Line 165, Line 395 to 397, Line 410 to 403 +• Comment out the following lines to remove the toplevel jtag I/O pins in Murax.scala file + val jtag = slave(Jtag()) + val jtagClkBuffer = SB_GB() + jtagClkBuffer.USER_SIGNAL_TO_GLOBAL_BUFFER <> io.jtag_tck + jtagClkBuffer.GLOBAL_BUFFER_OUTPUT <> murax.io.jtag.tck + murax.io.jtag.tdi <> io.jtag_tdi + murax.io.jtag.tdo <> io.jtag_tdo + murax.io.jtag.tms <> io.jtag_tms • In the Murax.scala file, delete line number 253 and add the following lines : val jtagCtrl = JtagTapInstructionCtrl() From 334df7010cfdc6359155e1658addb5ce0c9e1da9 Mon Sep 17 00:00:00 2001 From: Pradeep2004 <78598837+Pradeep2004@users.noreply.github.com> Date: Fri, 30 Apr 2021 22:37:26 +0200 Subject: [PATCH 649/951] debugging Murax SoC without Jtag Adapter --- Readme | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Readme b/Readme index b4b223a6..6ebb3066 100644 --- a/Readme +++ b/Readme @@ -67,7 +67,7 @@ you can take it from https://github.com/SpinalHDL/SaxonSoc/blob/dev-0.3/bsp/digi https://github.com/SpinalHDL/SaxonSoc/blob/dev-0.3/bsp/digilent/ArtyA7SmpLinux/openocd/soc_init.cfg You can take it but you need to : set cpu_count to 1 and remove Line 22 to 35. -• Then, after openocd is running, in new terminal, follow the below commands in VexriscvSocSoftware folder ( https://github.com/SpinalHDL/VexRiscvSocSoftware ). +• Then, after openocd is running, in new terminal, follow the below commands in VexriscvSocSoftware folder ( https://github.com/SpinalHDL/VexRiscvSocSoftware ) • Go to the path VexRiscvSocSoftware/projects/murax/demo/build and then give the below commands : From fb8694aa8d722670403f6eebe392c147c4eedec2 Mon Sep 17 00:00:00 2001 From: Pradeep2004 <78598837+Pradeep2004@users.noreply.github.com> Date: Fri, 30 Apr 2021 22:43:37 +0200 Subject: [PATCH 650/951] Create nativeJtag --- doc/nativeJtag | 1 + 1 file changed, 1 insertion(+) create mode 100644 doc/nativeJtag diff --git a/doc/nativeJtag b/doc/nativeJtag new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/doc/nativeJtag @@ -0,0 +1 @@ + From d72e9fad3f41995fa54ba2677df8b7181fa4ddaa Mon Sep 17 00:00:00 2001 From: Pradeep2004 <78598837+Pradeep2004@users.noreply.github.com> Date: Fri, 30 Apr 2021 22:44:22 +0200 Subject: [PATCH 651/951] Delete nativeJtag --- doc/nativeJtag | 1 - 1 file changed, 1 deletion(-) delete mode 100644 doc/nativeJtag diff --git a/doc/nativeJtag b/doc/nativeJtag deleted file mode 100644 index 8b137891..00000000 --- a/doc/nativeJtag +++ /dev/null @@ -1 +0,0 @@ - From d4ab5e971b99a7919701b31f887e4b8e76e77f15 Mon Sep 17 00:00:00 2001 From: Pradeep2004 <78598837+Pradeep2004@users.noreply.github.com> Date: Fri, 30 Apr 2021 22:55:18 +0200 Subject: [PATCH 652/951] Debugging Murax SoC without using Jtag Adapter --- doc/nativeJtag/Readme | 1 + 1 file changed, 1 insertion(+) create mode 100644 doc/nativeJtag/Readme diff --git a/doc/nativeJtag/Readme b/doc/nativeJtag/Readme new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/doc/nativeJtag/Readme @@ -0,0 +1 @@ + From 6ca917b5cc5d2fd594253ea1497d8c08ee5e0490 Mon Sep 17 00:00:00 2001 From: Pradeep2004 <78598837+Pradeep2004@users.noreply.github.com> Date: Fri, 30 Apr 2021 22:56:47 +0200 Subject: [PATCH 653/951] Debugging Murax SoC without using Jtag Adapter --- doc/nativeJtag/Readme | 79 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/doc/nativeJtag/Readme b/doc/nativeJtag/Readme index 8b137891..6ebb3066 100644 --- a/doc/nativeJtag/Readme +++ b/doc/nativeJtag/Readme @@ -1 +1,80 @@ +1. INTRODUCTION +The traditional way of debugging an SoC which is programmed inside a FPGA was by using a JTAG Adapter which comes with an FTDI Chip. In recent times, modern FPGA’s come with an integrated FTDI chip which makes debugging easy with only a USB cable. + +In this document, I am going to guide you through the steps in an experiment which I conducted along with my supervisor to debug an SoC named MURAX without using an external JTAG adapter on ARTY A7 FPGA. + +2. Generation of Bscane2 within Murax SoC in Linux + +The BSCANE2 allows access between the internal FPGA logic and the JTAG Boundary Scan logic controller. This allows for communication between the internal running design and the dedicated JTAG pins of the FPGA. + +2.1 Steps to create Bscane2 + +• After cloning all the files from https://github.com/SpinalHDL/VexRiscv, go to this path : src/main/scala/vexriscv/demo and find the Murax.scala file. + +• Comment out the following lines to remove the toplevel jtag I/O pins in Murax.scala file + val jtag = slave(Jtag()) + val jtagClkBuffer = SB_GB() + jtagClkBuffer.USER_SIGNAL_TO_GLOBAL_BUFFER <> io.jtag_tck + jtagClkBuffer.GLOBAL_BUFFER_OUTPUT <> murax.io.jtag.tck + murax.io.jtag.tdi <> io.jtag_tdi + murax.io.jtag.tdo <> io.jtag_tdo + murax.io.jtag.tms <> io.jtag_tms + +• In the Murax.scala file, delete line number 253 and add the following lines : + val jtagCtrl = JtagTapInstructionCtrl() + val tap = jtagCtrl.fromXilinxBscane2(userId = 2) + jtagCtrl <> plugin.io.bus.fromJtagInstructionCtrl(ClockDomain(tap.TCK)) + +• Add the following import statement at the beginning in Murax.scala : +import spinal.lib.com.jtag.JtagTapInstructionCtrl + +• Then to generate the SoC with a demo program already in ram, run: +sbt "runMain vexriscv.demo.MuraxWithRamInit" + +• A verilog file will be generated with the name Murax.v and four .bin files will be generated inside VexRiscv folder which can be used to program the FPGA. Inside the Murax.v file, we can see that the Bscane2 ports will be instantiated, confirming that the Bscane2 has been created within the Murax SoC to debug it. +  +3. Programming Arty A7 FPGA + +There are many applications to program a FPGA. I am using Xilinx Vivado 2020 Application to program the FPGA. + +3.1 Steps involved to program the FPGA + +• Create a new project and choose the board which are using and choose the constraint file. + +• As, I mentioned in the previous section a verilog file and four .bin files will be generated in the Vexriscv folder. Copy these files and paste them inside your vivado project in this path : project_name.srcs\sources_1\imports\Downloads + +• Create a toplevel file by instantiating Murax I/O ports in it to blink the LED’s on the FPGA. (Note : The program to blink the LED’s is already present in Murax.v file). The toplevel file and constraint file, if required can be found here : https://github.com/SpinalHDL/VexRiscv/tree/master/scripts/Murax/arty_a7 , but make sure all the jtag ports of Murax are commented or deleted in the toplevel file. + +• Next, click Generate Bitstream and program the FPGA with the bit file. You can see the LED’s blink and Murax SoC has been programmed into the FPGA. + +4. Debugging via OpenOCD GDB in Linux + +• In a new terminal in Linux, after cloning and setting up openocd with the steps provided in this link : https://github.com/SpinalHDL/openocd_riscv , run the below command to establish a openocd connection with Jtag of FPGA. +• To run openocd : +Use the below command : +src/openocd -c "set CPU0_YAML ..VexRiscv/cpu0.yaml" -f tcl/interface/usb_connect.cfg -f tcl/interface/soc_init.cfg + +• You basically have to provide 2 files. +usb_connect.cfg => interface configuration +soc_init.cfg => take over the control of the CPU. + +• For usb_connect.cfg +you can take it from https://github.com/SpinalHDL/SaxonSoc/blob/dev-0.3/bsp/digilent/ArtyA7SmpLinux/openocd/usb_connect.cfg (without modifications i would say) + + +• For soc_init.cfg +https://github.com/SpinalHDL/SaxonSoc/blob/dev-0.3/bsp/digilent/ArtyA7SmpLinux/openocd/soc_init.cfg +You can take it but you need to : set cpu_count to 1 and remove Line 22 to 35. + +• Then, after openocd is running, in new terminal, follow the below commands in VexriscvSocSoftware folder ( https://github.com/SpinalHDL/VexRiscvSocSoftware ) + +• Go to the path VexRiscvSocSoftware/projects/murax/demo/build and then give the below commands : + + riscv64-unknown-elf-gdb demo.elf + target remote localhost:3333 + monitor reset halt + load + continue + +• After giving the monitor reset halt command you can see that the LED’s stop blinking and when the continue command is given the LED’s start continuing from the point where they stopped. From 2a5bf9e993ba0c7089ae41c240589cd2c939d7e2 Mon Sep 17 00:00:00 2001 From: Pradeep2004 <78598837+Pradeep2004@users.noreply.github.com> Date: Fri, 30 Apr 2021 22:57:59 +0200 Subject: [PATCH 654/951] Delete Readme --- Readme | 80 ---------------------------------------------------------- 1 file changed, 80 deletions(-) delete mode 100644 Readme diff --git a/Readme b/Readme deleted file mode 100644 index 6ebb3066..00000000 --- a/Readme +++ /dev/null @@ -1,80 +0,0 @@ -1. INTRODUCTION - -The traditional way of debugging an SoC which is programmed inside a FPGA was by using a JTAG Adapter which comes with an FTDI Chip. In recent times, modern FPGA’s come with an integrated FTDI chip which makes debugging easy with only a USB cable. - -In this document, I am going to guide you through the steps in an experiment which I conducted along with my supervisor to debug an SoC named MURAX without using an external JTAG adapter on ARTY A7 FPGA. - -2. Generation of Bscane2 within Murax SoC in Linux - -The BSCANE2 allows access between the internal FPGA logic and the JTAG Boundary Scan logic controller. This allows for communication between the internal running design and the dedicated JTAG pins of the FPGA. - -2.1 Steps to create Bscane2 - -• After cloning all the files from https://github.com/SpinalHDL/VexRiscv, go to this path : src/main/scala/vexriscv/demo and find the Murax.scala file. - -• Comment out the following lines to remove the toplevel jtag I/O pins in Murax.scala file - val jtag = slave(Jtag()) - val jtagClkBuffer = SB_GB() - jtagClkBuffer.USER_SIGNAL_TO_GLOBAL_BUFFER <> io.jtag_tck - jtagClkBuffer.GLOBAL_BUFFER_OUTPUT <> murax.io.jtag.tck - murax.io.jtag.tdi <> io.jtag_tdi - murax.io.jtag.tdo <> io.jtag_tdo - murax.io.jtag.tms <> io.jtag_tms - -• In the Murax.scala file, delete line number 253 and add the following lines : - val jtagCtrl = JtagTapInstructionCtrl() - val tap = jtagCtrl.fromXilinxBscane2(userId = 2) - jtagCtrl <> plugin.io.bus.fromJtagInstructionCtrl(ClockDomain(tap.TCK)) - -• Add the following import statement at the beginning in Murax.scala : -import spinal.lib.com.jtag.JtagTapInstructionCtrl - -• Then to generate the SoC with a demo program already in ram, run: -sbt "runMain vexriscv.demo.MuraxWithRamInit" - -• A verilog file will be generated with the name Murax.v and four .bin files will be generated inside VexRiscv folder which can be used to program the FPGA. Inside the Murax.v file, we can see that the Bscane2 ports will be instantiated, confirming that the Bscane2 has been created within the Murax SoC to debug it. -  -3. Programming Arty A7 FPGA - -There are many applications to program a FPGA. I am using Xilinx Vivado 2020 Application to program the FPGA. - -3.1 Steps involved to program the FPGA - -• Create a new project and choose the board which are using and choose the constraint file. - -• As, I mentioned in the previous section a verilog file and four .bin files will be generated in the Vexriscv folder. Copy these files and paste them inside your vivado project in this path : project_name.srcs\sources_1\imports\Downloads - -• Create a toplevel file by instantiating Murax I/O ports in it to blink the LED’s on the FPGA. (Note : The program to blink the LED’s is already present in Murax.v file). The toplevel file and constraint file, if required can be found here : https://github.com/SpinalHDL/VexRiscv/tree/master/scripts/Murax/arty_a7 , but make sure all the jtag ports of Murax are commented or deleted in the toplevel file. - -• Next, click Generate Bitstream and program the FPGA with the bit file. You can see the LED’s blink and Murax SoC has been programmed into the FPGA. - -4. Debugging via OpenOCD GDB in Linux - -• In a new terminal in Linux, after cloning and setting up openocd with the steps provided in this link : https://github.com/SpinalHDL/openocd_riscv , run the below command to establish a openocd connection with Jtag of FPGA. -• To run openocd : -Use the below command : -src/openocd -c "set CPU0_YAML ..VexRiscv/cpu0.yaml" -f tcl/interface/usb_connect.cfg -f tcl/interface/soc_init.cfg - -• You basically have to provide 2 files. -usb_connect.cfg => interface configuration -soc_init.cfg => take over the control of the CPU. - -• For usb_connect.cfg -you can take it from https://github.com/SpinalHDL/SaxonSoc/blob/dev-0.3/bsp/digilent/ArtyA7SmpLinux/openocd/usb_connect.cfg (without modifications i would say) - - -• For soc_init.cfg -https://github.com/SpinalHDL/SaxonSoc/blob/dev-0.3/bsp/digilent/ArtyA7SmpLinux/openocd/soc_init.cfg -You can take it but you need to : set cpu_count to 1 and remove Line 22 to 35. - -• Then, after openocd is running, in new terminal, follow the below commands in VexriscvSocSoftware folder ( https://github.com/SpinalHDL/VexRiscvSocSoftware ) - -• Go to the path VexRiscvSocSoftware/projects/murax/demo/build and then give the below commands : - - riscv64-unknown-elf-gdb demo.elf - target remote localhost:3333 - monitor reset halt - load - continue - -• After giving the monitor reset halt command you can see that the LED’s stop blinking and when the continue command is given the LED’s start continuing from the point where they stopped. From d194867b19ff9758cca4d99e8535244c27bf3719 Mon Sep 17 00:00:00 2001 From: Pradeep2004 <78598837+Pradeep2004@users.noreply.github.com> Date: Fri, 30 Apr 2021 23:14:50 +0200 Subject: [PATCH 655/951] Create usb_connect.cfg --- doc/nativeJtag/usb_connect.cfg | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 doc/nativeJtag/usb_connect.cfg diff --git a/doc/nativeJtag/usb_connect.cfg b/doc/nativeJtag/usb_connect.cfg new file mode 100644 index 00000000..09b75dfd --- /dev/null +++ b/doc/nativeJtag/usb_connect.cfg @@ -0,0 +1,32 @@ +if [info exists env(SPINAL_SIM)] { + set SPINAL_SIM $::env(SPINAL_SIM) +} else { + set SPINAL_SIM no +} + + + +if {$SPINAL_SIM == "yes"} { + interface jtag_tcp + set _CHIPNAME fpga_spinal + set TAP_NAME $_CHIPNAME.bridge + set _CPUTAPID 0x10001fff + jtag newtap $_CHIPNAME bridge -expected-id $_CPUTAPID -irlen 4 -ircapture 0x1 -irmask 0xF + reset_config none + adapter_khz 50000 +} else { + interface ftdi + ftdi_device_desc "Digilent USB Device" + ftdi_vid_pid 0x0403 0x6010 + ftdi_channel 0 + ftdi_layout_init 0x00e8 0x60eb + ftdi_tdo_sample_edge falling + + reset_config none + adapter_khz 50000 + + source [find cpld/xilinx-xc7.cfg] + source [find cpld/jtagspi.cfg] + + set TAP_NAME xc7.tap +} From 1470069dbd664ba711e2768bb714aac6430b81df Mon Sep 17 00:00:00 2001 From: Pradeep2004 <78598837+Pradeep2004@users.noreply.github.com> Date: Fri, 30 Apr 2021 23:15:58 +0200 Subject: [PATCH 656/951] Create soc_init.cfg --- doc/nativeJtag/soc_init.cfg | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 doc/nativeJtag/soc_init.cfg diff --git a/doc/nativeJtag/soc_init.cfg b/doc/nativeJtag/soc_init.cfg new file mode 100644 index 00000000..92d67cfe --- /dev/null +++ b/doc/nativeJtag/soc_init.cfg @@ -0,0 +1,20 @@ +set cpu_count 1 + + +for {set i 0} {$i < $cpu_count} {incr i} { + target create saxon.cpu$i vexriscv -endian little -chain-position $TAP_NAME -coreid $i -dbgbase [expr $i*0x1000+0x10B80000] + vexriscv readWaitCycles 40 + vexriscv cpuConfigFile $CPU0_YAML + if {$SPINAL_SIM != "yes"} { + vexriscv jtagMapping 3 3 0 1 2 2 + } +} + +for {set i 0} {$i < $cpu_count} {incr i} { + targets saxon.cpu$i + poll_period 50 + init + soft_reset_halt +} + +puts " done" From a34d6ffb83e3cd3d52e4591ae801e85d37ab95b0 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 3 May 2021 10:59:21 +0200 Subject: [PATCH 657/951] update doc/nativeJtag/usb_connect.cfg --- doc/nativeJtag/usb_connect.cfg | 40 ++++++++++------------------------ 1 file changed, 11 insertions(+), 29 deletions(-) diff --git a/doc/nativeJtag/usb_connect.cfg b/doc/nativeJtag/usb_connect.cfg index 09b75dfd..e9da2fc2 100644 --- a/doc/nativeJtag/usb_connect.cfg +++ b/doc/nativeJtag/usb_connect.cfg @@ -1,32 +1,14 @@ -if [info exists env(SPINAL_SIM)] { - set SPINAL_SIM $::env(SPINAL_SIM) -} else { - set SPINAL_SIM no -} +interface ftdi +ftdi_device_desc "Digilent USB Device" +ftdi_vid_pid 0x0403 0x6010 +ftdi_channel 0 +ftdi_layout_init 0x00e8 0x60eb +ftdi_tdo_sample_edge falling +reset_config none +adapter_khz 50000 +source [find cpld/xilinx-xc7.cfg] +source [find cpld/jtagspi.cfg] -if {$SPINAL_SIM == "yes"} { - interface jtag_tcp - set _CHIPNAME fpga_spinal - set TAP_NAME $_CHIPNAME.bridge - set _CPUTAPID 0x10001fff - jtag newtap $_CHIPNAME bridge -expected-id $_CPUTAPID -irlen 4 -ircapture 0x1 -irmask 0xF - reset_config none - adapter_khz 50000 -} else { - interface ftdi - ftdi_device_desc "Digilent USB Device" - ftdi_vid_pid 0x0403 0x6010 - ftdi_channel 0 - ftdi_layout_init 0x00e8 0x60eb - ftdi_tdo_sample_edge falling - - reset_config none - adapter_khz 50000 - - source [find cpld/xilinx-xc7.cfg] - source [find cpld/jtagspi.cfg] - - set TAP_NAME xc7.tap -} +set TAP_NAME xc7.tap From f1d7c294ee5210033cadb21cb3fea26ebda4fdec Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 3 May 2021 10:59:32 +0200 Subject: [PATCH 658/951] Update usb_connect.cfg --- doc/nativeJtag/usb_connect.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/nativeJtag/usb_connect.cfg b/doc/nativeJtag/usb_connect.cfg index e9da2fc2..313b9194 100644 --- a/doc/nativeJtag/usb_connect.cfg +++ b/doc/nativeJtag/usb_connect.cfg @@ -6,7 +6,7 @@ ftdi_layout_init 0x00e8 0x60eb ftdi_tdo_sample_edge falling reset_config none -adapter_khz 50000 +adapter_khz 5000 source [find cpld/xilinx-xc7.cfg] source [find cpld/jtagspi.cfg] From b1fd24665e7bb724d289c823630ee5fa409063dc Mon Sep 17 00:00:00 2001 From: Pradeep2004 <78598837+Pradeep2004@users.noreply.github.com> Date: Mon, 3 May 2021 17:34:50 +0200 Subject: [PATCH 659/951] Update Readme --- doc/nativeJtag/Readme | 148 +++++++++++++++++++++++++++++------------- 1 file changed, 103 insertions(+), 45 deletions(-) diff --git a/doc/nativeJtag/Readme b/doc/nativeJtag/Readme index 6ebb3066..5ef5a6b3 100644 --- a/doc/nativeJtag/Readme +++ b/doc/nativeJtag/Readme @@ -1,6 +1,6 @@ 1. INTRODUCTION -The traditional way of debugging an SoC which is programmed inside a FPGA was by using a JTAG Adapter which comes with an FTDI Chip. In recent times, modern FPGA’s come with an integrated FTDI chip which makes debugging easy with only a USB cable. +In recent times, modern FPGA’s come with an integrated FTDI chip which makes debugging easy with only a USB cable, thereby reducing an unnecessary extra hardware (JTAG Adapter). In this document, I am going to guide you through the steps in an experiment which I conducted along with my supervisor to debug an SoC named MURAX without using an external JTAG adapter on ARTY A7 FPGA. @@ -8,73 +8,131 @@ In this document, I am going to guide you through the steps in an experiment whi The BSCANE2 allows access between the internal FPGA logic and the JTAG Boundary Scan logic controller. This allows for communication between the internal running design and the dedicated JTAG pins of the FPGA. -2.1 Steps to create Bscane2 +Steps to create Bscane2 -• After cloning all the files from https://github.com/SpinalHDL/VexRiscv, go to this path : src/main/scala/vexriscv/demo and find the Murax.scala file. +• After cloning all the files from https://github.com/SpinalHDL/VexRiscv, go to this path : src/main/scala/vexriscv/demo and find the Murax.scala file. -• Comment out the following lines to remove the toplevel jtag I/O pins in Murax.scala file - val jtag = slave(Jtag()) - val jtagClkBuffer = SB_GB() - jtagClkBuffer.USER_SIGNAL_TO_GLOBAL_BUFFER <> io.jtag_tck - jtagClkBuffer.GLOBAL_BUFFER_OUTPUT <> murax.io.jtag.tck - murax.io.jtag.tdi <> io.jtag_tdi - murax.io.jtag.tdo <> io.jtag_tdo - murax.io.jtag.tms <> io.jtag_tms +• Comment out the following lines to remove the toplevel jtag I/O pins in Murax.scala + val jtag = slave(Jtag()) + val jtagClkBuffer = SB_GB() + jtagClkBuffer.USER_SIGNAL_TO_GLOBAL_BUFFER <> io.jtag_tck + jtagClkBuffer.GLOBAL_BUFFER_OUTPUT <> murax.io.jtag.tck + murax.io.jtag.tdi <> io.jtag_tdi + murax.io.jtag.tdo <> io.jtag_tdo + murax.io.jtag.tms <> io.jtag_tms -• In the Murax.scala file, delete line number 253 and add the following lines : - val jtagCtrl = JtagTapInstructionCtrl() - val tap = jtagCtrl.fromXilinxBscane2(userId = 2) - jtagCtrl <> plugin.io.bus.fromJtagInstructionCtrl(ClockDomain(tap.TCK)) +• In the Murax.scala file, delete the below line: + io.jtag <> plugin.io.bus.fromJtag() + +And add the following lines : + val jtagCtrl = JtagTapInstructionCtrl() + val tap = jtagCtrl.fromXilinxBscane2(userId = 2) + jtagCtrl <> plugin.io.bus.fromJtagInstructionCtrl(ClockDomain(tap.TCK)) -• Add the following import statement at the beginning in Murax.scala : -import spinal.lib.com.jtag.JtagTapInstructionCtrl +By deleting the line (io.jtag <> plugin.io.bus.fromJtag() ) and adding the above lines, the Murax SoC’s Jtag ports are removed and a Bscane2 bridge will be created inside the Murax SoC itself, thereby avoiding to add the Bscane2 IP while programming the FPGA. -• Then to generate the SoC with a demo program already in ram, run: -sbt "runMain vexriscv.demo.MuraxWithRamInit" +• Add the following import statement at the beginning in Murax.scala : + import spinal.lib.com.jtag.JtagTapInstructionCtrl + +• Then to generate the SoC with a demo program already in ram, run: + sbt "runMain vexriscv.demo.MuraxWithRamInit" + +• A verilog file will be generated with the name Murax.v and four .bin files will be generated inside VexRiscv folder which can be used to program the FPGA. Inside the Murax.v file, we can see that the Bscane2 ports will be instantiated, confirming that the Bscane2 has been created within the Murax SoC to debug it. -• A verilog file will be generated with the name Murax.v and four .bin files will be generated inside VexRiscv folder which can be used to program the FPGA. Inside the Murax.v file, we can see that the Bscane2 ports will be instantiated, confirming that the Bscane2 has been created within the Murax SoC to debug it. -  3. Programming Arty A7 FPGA -There are many applications to program a FPGA. I am using Xilinx Vivado 2020 Application to program the FPGA. +There are many applications to program a FPGA. I am using Xilinx Vivado 2020 Application to program the FPGA, which is an open source application and is readily available in Xilinx website and free of cost to download. -3.1 Steps involved to program the FPGA +Steps involved to program the FPGA -• Create a new project and choose the board which are using and choose the constraint file. +• Create a new project and choose the board which are using and choose the constraint file. -• As, I mentioned in the previous section a verilog file and four .bin files will be generated in the Vexriscv folder. Copy these files and paste them inside your vivado project in this path : project_name.srcs\sources_1\imports\Downloads +• As, I mentioned in the previous section a verilog file and four .bin files will be generated in the Vexriscv folder. Copy these files and paste them inside your vivado project in this path : project_name.srcs\sources_1\imports\Downloads -• Create a toplevel file by instantiating Murax I/O ports in it to blink the LED’s on the FPGA. (Note : The program to blink the LED’s is already present in Murax.v file). The toplevel file and constraint file, if required can be found here : https://github.com/SpinalHDL/VexRiscv/tree/master/scripts/Murax/arty_a7 , but make sure all the jtag ports of Murax are commented or deleted in the toplevel file. +• Create a toplevel file by instantiating Murax I/O ports in it to blink the LED’s on the FPGA. (Note : The program to blink the LED’s is already present in Murax.v file). The toplevel file and constraint file, if required can be found in this path :VexRiscv/scripts/Murax/arty_a7 , but make sure all the jtag ports of Murax are commented or deleted in the toplevel file. -• Next, click Generate Bitstream and program the FPGA with the bit file. You can see the LED’s blink and Murax SoC has been programmed into the FPGA. +• The lines to remove from toplevel file are : + reg tesic_tck,tesic_tms,tesic_tdi; + wire tesic_tdo; + reg soc_tck,soc_tms,soc_tdi; + wire soc_tdo; + + always @(*) begin + {soc_tck, soc_tms, soc_tdi } = {tck,tms,tdi}; + tdo = soc_tdo; + end + + .io_jtag_tck(soc_tck), + .io_jtag_tdi(soc_tdi), + .io_jtag_tdo(soc_tdo), + .io_jtag_tms(soc_tms), + +• Next, click Generate Bitstream and program the FPGA with the bit file. You can see the LED’s blink and Murax SoC has been programmed into the FPGA. 4. Debugging via OpenOCD GDB in Linux -• In a new terminal in Linux, after cloning and setting up openocd with the steps provided in this link : https://github.com/SpinalHDL/openocd_riscv , run the below command to establish a openocd connection with Jtag of FPGA. -• To run openocd : -Use the below command : -src/openocd -c "set CPU0_YAML ..VexRiscv/cpu0.yaml" -f tcl/interface/usb_connect.cfg -f tcl/interface/soc_init.cfg +• In a new terminal in Linux, after cloning and setting up openocd with the steps provided in this link : https://github.com/SpinalHDL/openocd_riscv , run the below command to establish a openocd connection with JTAG of FPGA. -• You basically have to provide 2 files. +• You basically have to provide 2 files. usb_connect.cfg => interface configuration -soc_init.cfg => take over the control of the CPU. +soc_init.cfg => take over the control of the CPU -• For usb_connect.cfg -you can take it from https://github.com/SpinalHDL/SaxonSoc/blob/dev-0.3/bsp/digilent/ArtyA7SmpLinux/openocd/usb_connect.cfg (without modifications i would say) +• For usb_connect.cfg +you can take it from https://github.com/SpinalHDL/SaxonSoc/blob/dev-0.3/bsp/digilent/ArtyA7SmpLinux/openocd/usb_connect.cfg (without modifications I would say, but make sure to check the entire path in your system for the files +xilinx-xc7.cfg and jtagspi.cfg) and write it as below, remove the word “find” and the square brackets. +source ../openocd_riscv/tcl/cpld/xilinx-xc7.cfg +source .. /openocd_riscv/tcl/cpld/jtagspi.cfg - -• For soc_init.cfg +• For soc_init.cfg https://github.com/SpinalHDL/SaxonSoc/blob/dev-0.3/bsp/digilent/ArtyA7SmpLinux/openocd/soc_init.cfg -You can take it but you need to : set cpu_count to 1 and remove Line 22 to 35. +You can take it but you need to : set cpu_count to 1 and remove Line 22 to 35 as shown below : +set cpu_count 1 -• Then, after openocd is running, in new terminal, follow the below commands in VexriscvSocSoftware folder ( https://github.com/SpinalHDL/VexRiscvSocSoftware ) +for {set i 0} {$i < $cpu_count} {incr i} { + target create saxon.cpu$i vexriscv -endian little -chain-position $TAP_NAME -coreid $i -dbgbase [expr $i*0x1000+0x10B80000] + vexriscv readWaitCycles 40 + vexriscv cpuConfigFile $CPU0_YAML + if {$SPINAL_SIM != "yes"} { + vexriscv jtagMapping 3 3 0 1 2 2 + } +} -• Go to the path VexRiscvSocSoftware/projects/murax/demo/build and then give the below commands : +for {set i 0} {$i < $cpu_count} {incr i} { + targets saxon.cpu$i + poll_period 50 + init + soft_reset_halt +} + +puts done + +• To run openocd : +Use the below command : +src/openocd -c "set CPU0_YAML ../VexRiscv/cpu0.yaml" -f tcl/interface/usb_connect.cfg -f tcl/interface/soc_init.cfg + +• Prequisites to have before executing the next steps can be found here : +https://github.com/riscv/riscv-gnu-toolchain + +• Then, after openocd is running, in new terminal, follow the below commands in VexriscvSocSoftware folder ( https://github.com/SpinalHDL/VexRiscvSocSoftware ). + +• Go to the path VexRiscvSocSoftware/projects/murax/demo/build and then give the below commands : + +riscv64-unknown-elf-gdb demo.elf +- This command will initiate the already written demo program to blink the LED’s on the FPGA. + +target remote localhost:3333 +- This command will connect the GDB server + +load +- This command will load the program into the FPGA - riscv64-unknown-elf-gdb demo.elf - target remote localhost:3333 monitor reset halt - load - continue +- This command will halt the blinking of LED’s -• After giving the monitor reset halt command you can see that the LED’s stop blinking and when the continue command is given the LED’s start continuing from the point where they stopped. + continue +- This command will continue the blinking of LED’s from the point it stopped. + + +By, + Pradeep Krishnamurthy - Research Assistant, Offis e.V + Frank Poppen - Senior Research Engineer, Offis e.V From e78c0546a0aaf61cbf6183b1a2f92def219c4323 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 4 May 2021 21:09:42 +0200 Subject: [PATCH 660/951] fix #178 --- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 71f3c8a5..c2d795c1 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -956,9 +956,9 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep targetPrivilege := exceptionPortCtrl.exceptionTargetPrivilege } - val trapCause = CombInit(interrupt.code) + val trapCause = CombInit(interrupt.code.resize(trapCodeWidth)) if(exceptionPortCtrl != null) when( hadException){ - trapCause := exceptionPortCtrl.exceptionContext.code + trapCause := exceptionPortCtrl.exceptionContext.code.resized } val xtvec = Xtvec().assignDontCare() From ac1a6715d77824f7e925560cdc34c34a245daf44 Mon Sep 17 00:00:00 2001 From: Frank Poppen Date: Thu, 6 May 2021 08:44:05 +0200 Subject: [PATCH 661/951] Improves the documentation for nativeJtag about Murax with BSCANE2 and OpenOCD. --- doc/nativeJtag/README.md | 181 +++++++++++++++++++++++++++++ doc/nativeJtag/Readme | 138 ---------------------- doc/nativeJtag/Readme.pdf | Bin 0 -> 566276 bytes doc/nativeJtag/cpld/jtagspi.cfg | 37 ++++++ doc/nativeJtag/cpld/xilinx-xc7.cfg | 65 +++++++++++ doc/nativeJtag/soc_init.cfg | 6 + doc/nativeJtag/usb_connect.cfg | 4 +- 7 files changed, 291 insertions(+), 140 deletions(-) create mode 100644 doc/nativeJtag/README.md delete mode 100644 doc/nativeJtag/Readme create mode 100644 doc/nativeJtag/Readme.pdf create mode 100644 doc/nativeJtag/cpld/jtagspi.cfg create mode 100644 doc/nativeJtag/cpld/xilinx-xc7.cfg diff --git a/doc/nativeJtag/README.md b/doc/nativeJtag/README.md new file mode 100644 index 00000000..876f65e7 --- /dev/null +++ b/doc/nativeJtag/README.md @@ -0,0 +1,181 @@ +# AcceleoIssueWithInvalids +https://www.eclipse.org/forums/index.php/t/1091946/ + + +# DELETE THIS AFTER + + + + +# Implementing VexRiscv Based Murax SoC on Arty A7 Artix-7 PCB from Digilent and Enabling JTAG Connection through Xilinx’s BSCANE2 Debug IP + +**By**
+**Pradeep Krishnamurthy – Student Research Assistant, OFFIS e.V.**
+**Frank Poppen – Senior Research Engineer, OFFIS e.V.**
+ +**www.offis.de** + +Acknowledgement +This work was supported in part by the German Federal Ministry of Education and Research (BMBF) within the project +SATiSFy under contract no. 16KIS0821K, and within the project Scale4Edge under contract no. 16ME0127. + +## 1. Introduction +Up-to-date FPGA evaluation boards, like the Digilent Arty A7 mounting a Xilinx Artix-7 FPGA, come with an integrated +FTDI chip which makes programming and debugging quite easy. In our work, we synthesized the VexRiscv based Murax +processor to an Artix-7 FPGA and at first lead out the JTAG relevant signals of the Riscv core to the board’s Pmod +Header to connect to a dedicated Olimex JTAG Adapter through a second USB cable. As it turns out, this extra effort +on hardware can be minimized by use of some Xilinx Debug IP named BSCANE2. Collecting the required information on how +to do this was tedious. So we came to the decision to document our path to success with this short report. We expect +that the reader is familiar with the README.md to be found at https://github.com/SpinalHDL/VexRiscv and that the +reader is capable of generating the Murax SoC as it is described there. + +## 2. SpinalHDL - Generation of Murax SoC with BSCANE2 +The BSCANE2 allows access between the internal FPGA logic and the JTAG Boundary Scan logic controller. This allows +for communication between the internally running design and the dedicated JTAG pins of the FPGA. + +### Steps to enable Bscane2 + +After cloning all files from https://github.com/SpinalHDL/VexRiscv, go to the path: `src/main/scala/vexriscv/demo` +and find the `Murax.scala` file. +* Comment out the following lines to remove the toplevel jtag I/O pins in `Murax.scala`. Be aware that line numbers +as given could move with future changes to the file: +``` +[164] val jtag = slave(Jtag()) +… +[392] val jtagClkBuffer = SB_GB() +[393] jtagClkBuffer.USER_SIGNAL_TO_GLOBAL_BUFFER <> io.jtag_tck +[394] jtagClkBuffer.GLOBAL_BUFFER_OUTPUT <> murax.io.jtag.tck +… +[398] murax.io.jtag.tdi <> io.jtag_tdi +[399] murax.io.jtag.tdo <> io.jtag_tdo +[400] murax.io.jtag.tms <> io.jtag_tms +``` +* In the `Murax.scala` file, delete the line: +``` +[253] io.jtag <> plugin.io.bus.fromJtag() +``` +* And add the lines: +``` +[254] val jtagCtrl = JtagTapInstructionCtrl() +[255] val tap = jtagCtrl.fromXilinxBscane2(userId = 2) +[256] jtagCtrl <> plugin.io.bus.fromJtagInstructionCtrl(ClockDomain(tap.TCK)) +``` +Changing the above lines, removes the Murax SoC’s JTAG ports as pins of the FPGA and inserts the BSCANE2 Xilinx +Debug IP to which the JTAG signals are now connected. +* Add the following import statement at the beginning of `Murax.scala`: +``` +import spinal.lib.com.jtag.JtagTapInstructionCtrl +``` +With these changes in place, you generate the SoC with a demo program already in ram by use of: +``` +sbt "runMain vexriscv.demo.MuraxWithRamInit" +``` +A Verilog file is generated with the name `Murax.v` next to four `.bin` files inside the `VexRiscv` folder. These +files are the input to the Xilinx FPGA synthesis. Inside the `Murax.v` file, we can see that the BSCANE2 ports are +instantiated, confirming that the BSCANE2 has successfully been instantiated within the Murax SoC as a debug brige +to JTAG. + +## 3. Xilinx Vivado - Programming Arty A7 FPGA +There are many applications to program a FPGA. In our work we referred to the freely available Xilinx Vivado 2020 +application to synthesize and program the FPGA. Vivado is readily available at Xilinx website and free of cost to +download. This document assumes that the reader is able to setup and execute FPGA synthesis projects. The +following is not a step by step tutorial, but gives general guiding information. + +### Programming the FPGA + +* Create a new project and choose the board. In our case it is the Arty A7-35 (`xc7a35ticsg324-1L`). +* Copy the mentioned files (.v and .bin) of the previous section from the Vexriscv folder into the Vivado project +in e.g. the path: `project_name.srcs\sources_1\imports\Downloads` +* Create a toplevel file by instantiating Murax I/O ports in it to blink the LED’s on the Digilent board. (Note: The program to blink the LED’s is already present in the four `.bin` files with the `Murax.v` file). The toplevel file and constraint `arty_a7.xdc` file, if required, can be found and reused from the path: `VexRiscv/scripts/Murax/arty_a7`, but you need to make sure that all the JTAG ports of Murax are commented or deleted in the toplevel file. Remember: we removed them in Section 2 and connected them internally to the BSCANE2 debug bridge. +* Be aware that line numbers as given could move with future changes to the file. The lines to remove from toplevel file are: +``` +[43] reg tesic_tck,tesic_tms,tesic_tdi; +[44] wire tesic_tdo; +[45] reg soc_tck,soc_tms,soc_tdi; +[46] wire soc_tdo; +[47] +[48] always @(*) begin +[49] {soc_tck, soc_tms, soc_tdi } = {tck,tms,tdi}; +[50] tdo = soc_tdo; +[51] end +… +[56] .io_jtag_tck(soc_tck), +[57] .io_jtag_tdi(soc_tdi), +[58] .io_jtag_tdo(soc_tdo), +[59] .io_jtag_tms(soc_tms), +``` +* Also remove any JTAG port to pin assignments from any constraint file. +* Next, click Generate Bitstream and program the FPGA with the bit file. You can see the LED’s blink and Murax SoC has been programmed into the FPGA. + +### 4. Debugging - Using OpenOCD and GDB +* Clone and setup openocd with the steps as provided by https://github.com/SpinalHDL/openocd_riscv +* You basically have to provide two files for OpenOCD to connect successfully through the FPGA into the Murax SoC inside it: +1. `usb_connect.cfg` (interface configuration) +2. `soc_init.cfg` (take over the control of the CPU) +* `usb_connect.cfg` +You can take it from … https://github.com/SpinalHDL/SaxonSoc/blob/dev-0.3/bsp/digilent/ArtyA7SmpLinux/openocd/usb_connect.cfg … without modifications as we would say, but make sure to check the entire path in your system for the files `xilinx-xc7.cfg` and `jtagspi.cfg`. If required, adapt the find and path for the lines: +``` +[29] source [find cpld/xilinx-xc7.cfg] +[30] source [find cpld/jtagspi.cfg] +``` +* `soc_init.cfg` +https://github.com/SpinalHDL/SaxonSoc/blob/dev-0.3/bsp/digilent/ArtyA7SmpLinux/openocd/soc_init.cfg +You can take it but you need to: `set cpu_count to 1` and remove lines 22 to 35 as shown in the result below: +``` +set cpu_count 1 + +for {set i 0} {$i < $cpu_count} {incr i} { + target create saxon.cpu$i vexriscv -endian little -chain-position $TAP_NAME -coreid $i -dbgbase [expr $i*0x1000+0x10B80000] + vexriscv readWaitCycles 40 + vexriscv cpuConfigFile $CPU0_YAML + if {$SPINAL_SIM != "yes"} { + vexriscv jtagMapping 3 3 0 1 2 2 + } +} + +for {set i 0} {$i < $cpu_count} {incr i} { + targets saxon.cpu$i + poll_period 50 + init + soft_reset_halt +} + +puts " done" +``` +* Run openocd: +``` +openocd -c "set CPU0_YAML ../VexRiscv/cpu0.yaml" \ +-f tcl/interface/usb_connect.cfg \ +-f tcl/interface/soc_init.cfg +``` +On success you should be able to see something like +``` +Open On-Chip Debugger 0.10.0+dev-01231-gf8c1c8ad-dirty (2021-05-03-10:57) +Licensed under GNU GPL v2 +For bug reports, read + http://openocd.org/doc/doxygen/bugs.html +../../cpu0.yaml +Info : auto-selecting first available session transport "jtag". To override use 'transport select '. +xc7.tap +Info : set servers polling period to 50ms +Info : clock speed 5000 kHz +Info : JTAG tap: xc7.tap tap/device found: 0x0362d093 (mfg: 0x049 (Xilinx), part: 0x362d, ver: 0x0) +Info : starting gdb server for saxon.cpu0 on 3333 +Info : Listening on port 3333 for gdb connections +requesting target halt and executing a soft reset + done +Info : Listening on port 6666 for tcl connections +Info : Listening on port 4444 for telnet connections +``` +* Information on setting up a riscv compiler and debugger toolchain are to be found at: +https://github.com/riscv/riscv-gnu-toolchain +* With openocd running you can now connect a debugger to `port 3333`. +* A demonstration software to compile and debug with the Murax SoC can be found at https://github.com/SpinalHDL/VexRiscvSocSoftware in the path `VexRiscvSocSoftware/projects/murax/demo`. With a `make` you create the `.elf` in the `build` directory from which you then give the command: +``` +riscv64-unknown-elf-gdb demo.elf +``` +* The riscv debugger is started with the `demo.elf` program and is ready to be connected to the CPU. Do so by issuing the following command in its window: + * `target remote localhost:3333` This command will connect the GDB server to OpenOCD + * `load` This command will load the program into the FPGA. Whenever you decide to make changes to the demo software and recompiled it, you need to upload the resulting new executable to the CPU in this way. + * `monitor reset halt` This command resets the Murax CPU and halts it to receive further commands. + * `continue` From here on you should be able to execute a regular debug session with your VexRiscv based Murax SoC on the FPGA. diff --git a/doc/nativeJtag/Readme b/doc/nativeJtag/Readme deleted file mode 100644 index 5ef5a6b3..00000000 --- a/doc/nativeJtag/Readme +++ /dev/null @@ -1,138 +0,0 @@ -1. INTRODUCTION - -In recent times, modern FPGA’s come with an integrated FTDI chip which makes debugging easy with only a USB cable, thereby reducing an unnecessary extra hardware (JTAG Adapter). - -In this document, I am going to guide you through the steps in an experiment which I conducted along with my supervisor to debug an SoC named MURAX without using an external JTAG adapter on ARTY A7 FPGA. - -2. Generation of Bscane2 within Murax SoC in Linux - -The BSCANE2 allows access between the internal FPGA logic and the JTAG Boundary Scan logic controller. This allows for communication between the internal running design and the dedicated JTAG pins of the FPGA. - -Steps to create Bscane2 - -• After cloning all the files from https://github.com/SpinalHDL/VexRiscv, go to this path : src/main/scala/vexriscv/demo and find the Murax.scala file. - -• Comment out the following lines to remove the toplevel jtag I/O pins in Murax.scala - val jtag = slave(Jtag()) - val jtagClkBuffer = SB_GB() - jtagClkBuffer.USER_SIGNAL_TO_GLOBAL_BUFFER <> io.jtag_tck - jtagClkBuffer.GLOBAL_BUFFER_OUTPUT <> murax.io.jtag.tck - murax.io.jtag.tdi <> io.jtag_tdi - murax.io.jtag.tdo <> io.jtag_tdo - murax.io.jtag.tms <> io.jtag_tms - -• In the Murax.scala file, delete the below line: - io.jtag <> plugin.io.bus.fromJtag() - -And add the following lines : - val jtagCtrl = JtagTapInstructionCtrl() - val tap = jtagCtrl.fromXilinxBscane2(userId = 2) - jtagCtrl <> plugin.io.bus.fromJtagInstructionCtrl(ClockDomain(tap.TCK)) - -By deleting the line (io.jtag <> plugin.io.bus.fromJtag() ) and adding the above lines, the Murax SoC’s Jtag ports are removed and a Bscane2 bridge will be created inside the Murax SoC itself, thereby avoiding to add the Bscane2 IP while programming the FPGA. - -• Add the following import statement at the beginning in Murax.scala : - import spinal.lib.com.jtag.JtagTapInstructionCtrl - -• Then to generate the SoC with a demo program already in ram, run: - sbt "runMain vexriscv.demo.MuraxWithRamInit" - -• A verilog file will be generated with the name Murax.v and four .bin files will be generated inside VexRiscv folder which can be used to program the FPGA. Inside the Murax.v file, we can see that the Bscane2 ports will be instantiated, confirming that the Bscane2 has been created within the Murax SoC to debug it. - -3. Programming Arty A7 FPGA - -There are many applications to program a FPGA. I am using Xilinx Vivado 2020 Application to program the FPGA, which is an open source application and is readily available in Xilinx website and free of cost to download. - -Steps involved to program the FPGA - -• Create a new project and choose the board which are using and choose the constraint file. - -• As, I mentioned in the previous section a verilog file and four .bin files will be generated in the Vexriscv folder. Copy these files and paste them inside your vivado project in this path : project_name.srcs\sources_1\imports\Downloads - -• Create a toplevel file by instantiating Murax I/O ports in it to blink the LED’s on the FPGA. (Note : The program to blink the LED’s is already present in Murax.v file). The toplevel file and constraint file, if required can be found in this path :VexRiscv/scripts/Murax/arty_a7 , but make sure all the jtag ports of Murax are commented or deleted in the toplevel file. - -• The lines to remove from toplevel file are : - reg tesic_tck,tesic_tms,tesic_tdi; - wire tesic_tdo; - reg soc_tck,soc_tms,soc_tdi; - wire soc_tdo; - - always @(*) begin - {soc_tck, soc_tms, soc_tdi } = {tck,tms,tdi}; - tdo = soc_tdo; - end - - .io_jtag_tck(soc_tck), - .io_jtag_tdi(soc_tdi), - .io_jtag_tdo(soc_tdo), - .io_jtag_tms(soc_tms), - -• Next, click Generate Bitstream and program the FPGA with the bit file. You can see the LED’s blink and Murax SoC has been programmed into the FPGA. - -4. Debugging via OpenOCD GDB in Linux - -• In a new terminal in Linux, after cloning and setting up openocd with the steps provided in this link : https://github.com/SpinalHDL/openocd_riscv , run the below command to establish a openocd connection with JTAG of FPGA. - -• You basically have to provide 2 files. -usb_connect.cfg => interface configuration -soc_init.cfg => take over the control of the CPU - -• For usb_connect.cfg -you can take it from https://github.com/SpinalHDL/SaxonSoc/blob/dev-0.3/bsp/digilent/ArtyA7SmpLinux/openocd/usb_connect.cfg (without modifications I would say, but make sure to check the entire path in your system for the files -xilinx-xc7.cfg and jtagspi.cfg) and write it as below, remove the word “find” and the square brackets. -source ../openocd_riscv/tcl/cpld/xilinx-xc7.cfg -source .. /openocd_riscv/tcl/cpld/jtagspi.cfg - -• For soc_init.cfg -https://github.com/SpinalHDL/SaxonSoc/blob/dev-0.3/bsp/digilent/ArtyA7SmpLinux/openocd/soc_init.cfg -You can take it but you need to : set cpu_count to 1 and remove Line 22 to 35 as shown below : -set cpu_count 1 - -for {set i 0} {$i < $cpu_count} {incr i} { - target create saxon.cpu$i vexriscv -endian little -chain-position $TAP_NAME -coreid $i -dbgbase [expr $i*0x1000+0x10B80000] - vexriscv readWaitCycles 40 - vexriscv cpuConfigFile $CPU0_YAML - if {$SPINAL_SIM != "yes"} { - vexriscv jtagMapping 3 3 0 1 2 2 - } -} - -for {set i 0} {$i < $cpu_count} {incr i} { - targets saxon.cpu$i - poll_period 50 - init - soft_reset_halt -} - -puts done - -• To run openocd : -Use the below command : -src/openocd -c "set CPU0_YAML ../VexRiscv/cpu0.yaml" -f tcl/interface/usb_connect.cfg -f tcl/interface/soc_init.cfg - -• Prequisites to have before executing the next steps can be found here : -https://github.com/riscv/riscv-gnu-toolchain - -• Then, after openocd is running, in new terminal, follow the below commands in VexriscvSocSoftware folder ( https://github.com/SpinalHDL/VexRiscvSocSoftware ). - -• Go to the path VexRiscvSocSoftware/projects/murax/demo/build and then give the below commands : - -riscv64-unknown-elf-gdb demo.elf -- This command will initiate the already written demo program to blink the LED’s on the FPGA. - -target remote localhost:3333 -- This command will connect the GDB server - -load -- This command will load the program into the FPGA - - monitor reset halt -- This command will halt the blinking of LED’s - - continue -- This command will continue the blinking of LED’s from the point it stopped. - - -By, - Pradeep Krishnamurthy - Research Assistant, Offis e.V - Frank Poppen - Senior Research Engineer, Offis e.V diff --git a/doc/nativeJtag/Readme.pdf b/doc/nativeJtag/Readme.pdf new file mode 100644 index 0000000000000000000000000000000000000000..b62e0008de53bf2254697932a419bd44ceef995f GIT binary patch literal 566276 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⪚zUXyGvf&=@F2hYU_xO+ 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�uW9$+3IP~58$&qo* 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
@CK1N74Th1n# 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 literal 0 HcmV?d00001 diff --git a/doc/nativeJtag/cpld/jtagspi.cfg b/doc/nativeJtag/cpld/jtagspi.cfg new file mode 100644 index 00000000..e720c395 --- /dev/null +++ b/doc/nativeJtag/cpld/jtagspi.cfg @@ -0,0 +1,37 @@ +set _USER1 0x02 + +if { [info exists JTAGSPI_IR] } { + set _JTAGSPI_IR $JTAGSPI_IR +} else { + set _JTAGSPI_IR $_USER1 +} + +if { [info exists TARGETNAME] } { + set _TARGETNAME $TARGETNAME +} else { + set _TARGETNAME $_CHIPNAME.proxy +} + +if { [info exists FLASHNAME] } { + set _FLASHNAME $FLASHNAME +} else { + set _FLASHNAME $_CHIPNAME.spi +} + +target create $_TARGETNAME testee -chain-position $_CHIPNAME.tap +flash bank $_FLASHNAME jtagspi 0 0 0 0 $_TARGETNAME $_JTAGSPI_IR + +proc jtagspi_init {chain_id proxy_bit} { + # load proxy bitstream $proxy_bit and probe spi flash + global _FLASHNAME + pld load $chain_id $proxy_bit + reset halt + flash probe $_FLASHNAME +} + +proc jtagspi_program {bin addr} { + # write and verify binary file $bin at offset $addr + global _FLASHNAME + flash write_image erase $bin $addr + flash verify_bank $_FLASHNAME $bin $addr +} diff --git a/doc/nativeJtag/cpld/xilinx-xc7.cfg b/doc/nativeJtag/cpld/xilinx-xc7.cfg new file mode 100644 index 00000000..4c0502c5 --- /dev/null +++ b/doc/nativeJtag/cpld/xilinx-xc7.cfg @@ -0,0 +1,65 @@ +# xilinx series 7 (artix, kintex, virtex) +# http://www.xilinx.com/support/documentation/user_guides/ug470_7Series_Config.pdf + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME xc7 +} + +# the 4 top bits (28:31) are the die stepping/revisions. ignore it. +jtag newtap $_CHIPNAME tap -irlen 6 -ignore-version \ + -expected-id 0x03622093 \ + -expected-id 0x03620093 \ + -expected-id 0x037C4093 \ + -expected-id 0x0362F093 \ + -expected-id 0x037C8093 \ + -expected-id 0x037C7093 \ + -expected-id 0x037C3093 \ + -expected-id 0x0362E093 \ + -expected-id 0x037C2093 \ + -expected-id 0x0362D093 \ + -expected-id 0x0362C093 \ + -expected-id 0x03632093 \ + -expected-id 0x03631093 \ + -expected-id 0x03636093 \ + -expected-id 0x03647093 \ + -expected-id 0x0364C093 \ + -expected-id 0x03651093 \ + -expected-id 0x03747093 \ + -expected-id 0x03656093 \ + -expected-id 0x03752093 \ + -expected-id 0x03751093 \ + -expected-id 0x03671093 \ + -expected-id 0x036B3093 \ + -expected-id 0x036B7093 \ + -expected-id 0x036BB093 \ + -expected-id 0x036BF093 \ + -expected-id 0x03667093 \ + -expected-id 0x03682093 \ + -expected-id 0x03687093 \ + -expected-id 0x03692093 \ + -expected-id 0x03691093 \ + -expected-id 0x03696093 \ + -expected-id 0x036D5093 \ + -expected-id 0x036D9093 \ + -expected-id 0x036DB093 + +pld device virtex2 $_CHIPNAME.tap 1 + +set XC7_JSHUTDOWN 0x0d +set XC7_JPROGRAM 0x0b +set XC7_JSTART 0x0c +set XC7_BYPASS 0x3f + +proc xc7_program {tap} { + global XC7_JSHUTDOWN XC7_JPROGRAM XC7_JSTART XC7_BYPASS + irscan $tap $XC7_JSHUTDOWN + irscan $tap $XC7_JPROGRAM + runtest 60000 + #JSTART prevents this from working... + #irscan $tap $XC7_JSTART + runtest 2000 + irscan $tap $XC7_BYPASS + runtest 2000 +} diff --git a/doc/nativeJtag/soc_init.cfg b/doc/nativeJtag/soc_init.cfg index 92d67cfe..47fc5fb1 100644 --- a/doc/nativeJtag/soc_init.cfg +++ b/doc/nativeJtag/soc_init.cfg @@ -1,3 +1,9 @@ +if [info exists env(SPINAL_SIM)] { + set SPINAL_SIM $::env(SPINAL_SIM) +} else { + set SPINAL_SIM no +} + set cpu_count 1 diff --git a/doc/nativeJtag/usb_connect.cfg b/doc/nativeJtag/usb_connect.cfg index 313b9194..02d62fdf 100644 --- a/doc/nativeJtag/usb_connect.cfg +++ b/doc/nativeJtag/usb_connect.cfg @@ -1,4 +1,4 @@ -interface ftdi +adapter driver ftdi ftdi_device_desc "Digilent USB Device" ftdi_vid_pid 0x0403 0x6010 ftdi_channel 0 @@ -6,7 +6,7 @@ ftdi_layout_init 0x00e8 0x60eb ftdi_tdo_sample_edge falling reset_config none -adapter_khz 5000 +adapter speed 5000 source [find cpld/xilinx-xc7.cfg] source [find cpld/jtagspi.cfg] From 47110a97a397a7b12911b5bdbcde17de06ce13cd Mon Sep 17 00:00:00 2001 From: Frank Poppen Date: Thu, 6 May 2021 08:49:11 +0200 Subject: [PATCH 662/951] Updates two missed issues with nativeJtag documentation from previous commit. --- doc/nativeJtag/README.md | 9 --------- doc/nativeJtag/{Readme.pdf => README.pdf} | Bin 2 files changed, 9 deletions(-) rename doc/nativeJtag/{Readme.pdf => README.pdf} (100%) diff --git a/doc/nativeJtag/README.md b/doc/nativeJtag/README.md index 876f65e7..062dfe1d 100644 --- a/doc/nativeJtag/README.md +++ b/doc/nativeJtag/README.md @@ -1,12 +1,3 @@ -# AcceleoIssueWithInvalids -https://www.eclipse.org/forums/index.php/t/1091946/ - - -# DELETE THIS AFTER - - - - # Implementing VexRiscv Based Murax SoC on Arty A7 Artix-7 PCB from Digilent and Enabling JTAG Connection through Xilinx’s BSCANE2 Debug IP **By**
diff --git a/doc/nativeJtag/Readme.pdf b/doc/nativeJtag/README.pdf similarity index 100% rename from doc/nativeJtag/Readme.pdf rename to doc/nativeJtag/README.pdf From 5a7c71259d5593eb53aa211e016dfaf4ee8807d1 Mon Sep 17 00:00:00 2001 From: Frank Poppen Date: Thu, 6 May 2021 17:31:40 +0200 Subject: [PATCH 663/951] Removes PDF and xilinx-xc7.cfg and jtagspi.cfg. Enhances README.md to find in OpenOCD. --- doc/nativeJtag/README.md | 2 +- doc/nativeJtag/README.pdf | Bin 566276 -> 0 bytes doc/nativeJtag/cpld/jtagspi.cfg | 37 ---------------- doc/nativeJtag/cpld/xilinx-xc7.cfg | 65 ----------------------------- 4 files changed, 1 insertion(+), 103 deletions(-) delete mode 100644 doc/nativeJtag/README.pdf delete mode 100644 doc/nativeJtag/cpld/jtagspi.cfg delete mode 100644 doc/nativeJtag/cpld/xilinx-xc7.cfg diff --git a/doc/nativeJtag/README.md b/doc/nativeJtag/README.md index 062dfe1d..550d8be8 100644 --- a/doc/nativeJtag/README.md +++ b/doc/nativeJtag/README.md @@ -104,7 +104,7 @@ in e.g. the path: `project_name.srcs\sources_1\imports\Downloads` 1. `usb_connect.cfg` (interface configuration) 2. `soc_init.cfg` (take over the control of the CPU) * `usb_connect.cfg` -You can take it from … https://github.com/SpinalHDL/SaxonSoc/blob/dev-0.3/bsp/digilent/ArtyA7SmpLinux/openocd/usb_connect.cfg … without modifications as we would say, but make sure to check the entire path in your system for the files `xilinx-xc7.cfg` and `jtagspi.cfg`. If required, adapt the find and path for the lines: +You can take it from ... https://github.com/SpinalHDL/SaxonSoc/blob/dev-0.3/bsp/digilent/ArtyA7SmpLinux/openocd/usb_connect.cfg ... without modifications as we would say. Be aware that it includes the two files `xilinx-xc7.cfg` and `jtagspi.cfg` which are part of the OpenOCD project ... https://github.com/riscv/riscv-openocd/tree/riscv/tcl/cpld , but make sure to check the path for the files. If required, adapt the find and path for the lines: ``` [29] source [find cpld/xilinx-xc7.cfg] [30] source [find cpld/jtagspi.cfg] diff --git a/doc/nativeJtag/README.pdf b/doc/nativeJtag/README.pdf deleted file mode 100644 index b62e0008de53bf2254697932a419bd44ceef995f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 566276 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⪚zUXyGvf&=@F2hYU_xO+ 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�uW9$+3IP~58$&qo* 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
@CK1N74Th1n# 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 diff --git a/doc/nativeJtag/cpld/jtagspi.cfg b/doc/nativeJtag/cpld/jtagspi.cfg deleted file mode 100644 index e720c395..00000000 --- a/doc/nativeJtag/cpld/jtagspi.cfg +++ /dev/null @@ -1,37 +0,0 @@ -set _USER1 0x02 - -if { [info exists JTAGSPI_IR] } { - set _JTAGSPI_IR $JTAGSPI_IR -} else { - set _JTAGSPI_IR $_USER1 -} - -if { [info exists TARGETNAME] } { - set _TARGETNAME $TARGETNAME -} else { - set _TARGETNAME $_CHIPNAME.proxy -} - -if { [info exists FLASHNAME] } { - set _FLASHNAME $FLASHNAME -} else { - set _FLASHNAME $_CHIPNAME.spi -} - -target create $_TARGETNAME testee -chain-position $_CHIPNAME.tap -flash bank $_FLASHNAME jtagspi 0 0 0 0 $_TARGETNAME $_JTAGSPI_IR - -proc jtagspi_init {chain_id proxy_bit} { - # load proxy bitstream $proxy_bit and probe spi flash - global _FLASHNAME - pld load $chain_id $proxy_bit - reset halt - flash probe $_FLASHNAME -} - -proc jtagspi_program {bin addr} { - # write and verify binary file $bin at offset $addr - global _FLASHNAME - flash write_image erase $bin $addr - flash verify_bank $_FLASHNAME $bin $addr -} diff --git a/doc/nativeJtag/cpld/xilinx-xc7.cfg b/doc/nativeJtag/cpld/xilinx-xc7.cfg deleted file mode 100644 index 4c0502c5..00000000 --- a/doc/nativeJtag/cpld/xilinx-xc7.cfg +++ /dev/null @@ -1,65 +0,0 @@ -# xilinx series 7 (artix, kintex, virtex) -# http://www.xilinx.com/support/documentation/user_guides/ug470_7Series_Config.pdf - -if { [info exists CHIPNAME] } { - set _CHIPNAME $CHIPNAME -} else { - set _CHIPNAME xc7 -} - -# the 4 top bits (28:31) are the die stepping/revisions. ignore it. -jtag newtap $_CHIPNAME tap -irlen 6 -ignore-version \ - -expected-id 0x03622093 \ - -expected-id 0x03620093 \ - -expected-id 0x037C4093 \ - -expected-id 0x0362F093 \ - -expected-id 0x037C8093 \ - -expected-id 0x037C7093 \ - -expected-id 0x037C3093 \ - -expected-id 0x0362E093 \ - -expected-id 0x037C2093 \ - -expected-id 0x0362D093 \ - -expected-id 0x0362C093 \ - -expected-id 0x03632093 \ - -expected-id 0x03631093 \ - -expected-id 0x03636093 \ - -expected-id 0x03647093 \ - -expected-id 0x0364C093 \ - -expected-id 0x03651093 \ - -expected-id 0x03747093 \ - -expected-id 0x03656093 \ - -expected-id 0x03752093 \ - -expected-id 0x03751093 \ - -expected-id 0x03671093 \ - -expected-id 0x036B3093 \ - -expected-id 0x036B7093 \ - -expected-id 0x036BB093 \ - -expected-id 0x036BF093 \ - -expected-id 0x03667093 \ - -expected-id 0x03682093 \ - -expected-id 0x03687093 \ - -expected-id 0x03692093 \ - -expected-id 0x03691093 \ - -expected-id 0x03696093 \ - -expected-id 0x036D5093 \ - -expected-id 0x036D9093 \ - -expected-id 0x036DB093 - -pld device virtex2 $_CHIPNAME.tap 1 - -set XC7_JSHUTDOWN 0x0d -set XC7_JPROGRAM 0x0b -set XC7_JSTART 0x0c -set XC7_BYPASS 0x3f - -proc xc7_program {tap} { - global XC7_JSHUTDOWN XC7_JPROGRAM XC7_JSTART XC7_BYPASS - irscan $tap $XC7_JSHUTDOWN - irscan $tap $XC7_JPROGRAM - runtest 60000 - #JSTART prevents this from working... - #irscan $tap $XC7_JSTART - runtest 2000 - irscan $tap $XC7_BYPASS - runtest 2000 -} From 1bd33a369ef859c741f1dbc44c6262841036081b Mon Sep 17 00:00:00 2001 From: Romain Dolbeau Date: Sat, 8 May 2021 07:37:55 -0400 Subject: [PATCH 664/951] Make the [ID]TLB size configurable from Litex --- src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala | 8 +++++--- .../scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala | 8 +++++++- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index b724c45a..91e75f3f 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -182,7 +182,9 @@ object VexRiscvSmpClusterGen { externalFpu : Boolean = true, simHalt : Boolean = false, regfileRead : RegFileReadKind = plugin.ASYNC, - rvc : Boolean = false + rvc : Boolean = false, + iTlbSize : Int = 4, + dTlbSize : Int = 4 ) = { assert(iCacheSize/iCacheWays <= 4096, "Instruction cache ways can't be bigger than 4096 bytes") assert(dCacheSize/dCacheWays <= 4096, "Data cache ways can't be bigger than 4096 bytes") @@ -219,7 +221,7 @@ object VexRiscvSmpClusterGen { reducedBankWidth = true ), memoryTranslatorPortConfig = MmuPortConfig( - portTlbSize = 4, + portTlbSize = iTlbSize, latency = 1, earlyRequireMmuLockup = true, earlyCacheHits = true @@ -247,7 +249,7 @@ object VexRiscvSmpClusterGen { withWriteAggregation = dBusWidth > 32 ), memoryTranslatorPortConfig = MmuPortConfig( - portTlbSize = 4, + portTlbSize = dTlbSize, latency = 1, earlyRequireMmuLockup = true, earlyCacheHits = true diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala index 4f0936e8..7a20b300 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala @@ -118,6 +118,8 @@ object VexRiscvLitexSmpClusterCmdGen extends App { var rvc = false var netlistDirectory = "." var netlistName = "VexRiscvLitexSmpCluster" + var iTlbSize = 4 + var dTlbSize = 4 assert(new scopt.OptionParser[Unit]("VexRiscvLitexSmpClusterCmdGen") { help("help").text("prints this usage text") opt[Unit]("coherent-dma") action { (v, c) => coherentDma = true } @@ -137,6 +139,8 @@ object VexRiscvLitexSmpClusterCmdGen extends App { opt[String]("fpu" ) action { (v, c) => fpu = v.toBoolean } opt[String]("cpu-per-fpu") action { (v, c) => cpuPerFpu = v.toInt } opt[String]("rvc") action { (v, c) => rvc = v.toBoolean } + opt[String]("itlb-size") action { (v, c) => iTlbSize = v.toInt } + opt[String]("dtlb-size") action { (v, c) => dTlbSize = v.toInt } }.parse(args)) val coherency = coherentDma || cpuCount > 1 @@ -161,7 +165,9 @@ object VexRiscvLitexSmpClusterCmdGen extends App { externalFpu = fpu, loadStoreWidth = if(fpu) 64 else 32, rvc = rvc, - injectorStage = rvc + injectorStage = rvc, + iTlbSize = iTlbSize, + dTlbSize = dTlbSize ) if(aesInstruction) c.add(new AesPlugin) c From fe739b907a6a2dc046b707e9f6dba2db959b8362 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 10 May 2021 10:47:09 +0200 Subject: [PATCH 665/951] Bench DecoderPlugin --- .../scala/vexriscv/demo/SynthesisBench.scala | 70 +++++++++++++++++++ .../demo/smp/VexRiscvSmpCluster.scala | 6 +- .../vexriscv/plugin/DecoderSimplePlugin.scala | 11 ++- .../scala/vexriscv/plugin/FpuPlugin.scala | 2 +- 4 files changed, 85 insertions(+), 4 deletions(-) diff --git a/src/main/scala/vexriscv/demo/SynthesisBench.scala b/src/main/scala/vexriscv/demo/SynthesisBench.scala index e021e194..6a044eae 100644 --- a/src/main/scala/vexriscv/demo/SynthesisBench.scala +++ b/src/main/scala/vexriscv/demo/SynthesisBench.scala @@ -6,6 +6,7 @@ import spinal.lib.eda.bench._ import spinal.lib.eda.icestorm.IcestormStdTargets import spinal.lib.eda.xilinx.VivadoFlow import spinal.lib.io.InOutWrapper +import vexriscv.demo.smp.VexRiscvSmpClusterGen import vexriscv.plugin.CsrAccess.{READ_ONLY, READ_WRITE, WRITE_ONLY} import vexriscv.{VexRiscv, VexRiscvConfig, plugin} import vexriscv.plugin.{BranchPlugin, CsrPlugin, CsrPluginConfig, DBusSimplePlugin, DecoderSimplePlugin, FullBarrelShifterPlugin, HazardSimplePlugin, IBusSimplePlugin, IntAluPlugin, LightShifterPlugin, NONE, RegFilePlugin, SrcPlugin, YamlPlugin} @@ -200,9 +201,78 @@ object VexRiscvSynthesisBench { SpinalConfig(inlineRom = true).generateVerilog(wrap(new VexRiscv(LinuxGen.configFull(false, true, withSmp = true))).setDefinitionName(getRtlPath().split("\\.").head)) } + val linuxFpuSmp = new Rtl { + override def getName(): String = "VexRiscv linux Fpu SMP" + override def getRtlPath(): String = "VexRiscvLinuxFpuSmp.v" + SpinalConfig(inlineRom = true).generateVerilog(wrap(new VexRiscv( + VexRiscvSmpClusterGen.vexRiscvConfig( + hartId = 0, + ioRange = _ (31 downto 28) === 0xF, + resetVector = 0x80000000l, + iBusWidth = 64, + dBusWidth = 64, + loadStoreWidth = 64, + iCacheSize = 4096*2, + dCacheSize = 4096*2, + iCacheWays = 2, + dCacheWays = 2, + withFloat = true, + withDouble = true, + externalFpu = false, + simHalt = true + ))).setDefinitionName(getRtlPath().split("\\.").head)) + } + + val linuxFpuSmpNoDecoder = new Rtl { + override def getName(): String = "VexRiscv linux Fpu SMP without decoder" + override def getRtlPath(): String = "VexRiscvLinuxFpuSmpNoDecoder.v" + SpinalConfig(inlineRom = true).generateVerilog(wrap(new VexRiscv( + VexRiscvSmpClusterGen.vexRiscvConfig( + hartId = 0, + ioRange = _ (31 downto 28) === 0xF, + resetVector = 0x80000000l, + iBusWidth = 64, + dBusWidth = 64, + loadStoreWidth = 64, + iCacheSize = 4096*2, + dCacheSize = 4096*2, + iCacheWays = 2, + dCacheWays = 2, + withFloat = true, + withDouble = true, + externalFpu = false, + simHalt = true, + decoderIsolationBench = true + ))).setDefinitionName(getRtlPath().split("\\.").head)) + } + + val linuxFpuSmpStupidDecoder = new Rtl { + override def getName(): String = "VexRiscv linux Fpu SMP stupid decoder" + override def getRtlPath(): String = "VexRiscvLinuxFpuSmpStupidDecoder.v" + SpinalConfig(inlineRom = true).generateVerilog(wrap(new VexRiscv( + VexRiscvSmpClusterGen.vexRiscvConfig( + hartId = 0, + ioRange = _ (31 downto 28) === 0xF, + resetVector = 0x80000000l, + iBusWidth = 64, + dBusWidth = 64, + loadStoreWidth = 64, + iCacheSize = 4096*2, + dCacheSize = 4096*2, + iCacheWays = 2, + dCacheWays = 2, + withFloat = true, + withDouble = true, + externalFpu = false, + simHalt = true, + decoderStupid = true + ))).setDefinitionName(getRtlPath().split("\\.").head)) + } + val rtls = List( +// linuxFpuSmp, linuxFpuSmpNoDecoder, linuxFpuSmpStupidDecoder twoStage, twoStageBarell, twoStageMulDiv, twoStageAll, threeStage, threeStageBarell, threeStageMulDiv, threeStageAll, smallestNoCsr, smallest, smallAndProductive, smallAndProductiveWithICache, fullNoMmuNoCache, noCacheNoMmuMaxPerf, fullNoMmuMaxPerf, fullNoMmu, full, linuxBalanced, linuxBalancedSmp diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index b724c45a..c2bd3b49 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -181,6 +181,8 @@ object VexRiscvSmpClusterGen { withDouble : Boolean = false, externalFpu : Boolean = true, simHalt : Boolean = false, + decoderIsolationBench : Boolean = false, + decoderStupid : Boolean = false, regfileRead : RegFileReadKind = plugin.ASYNC, rvc : Boolean = false ) = { @@ -254,7 +256,9 @@ object VexRiscvSmpClusterGen { ) ), new DecoderSimplePlugin( - catchIllegalInstruction = true + catchIllegalInstruction = true, + decoderIsolationBench = decoderIsolationBench, + stupidDecoder = decoderStupid ), new RegFilePlugin( regFileReadyKind = regfileRead, diff --git a/src/main/scala/vexriscv/plugin/DecoderSimplePlugin.scala b/src/main/scala/vexriscv/plugin/DecoderSimplePlugin.scala index e2ab1117..71e38948 100644 --- a/src/main/scala/vexriscv/plugin/DecoderSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/DecoderSimplePlugin.scala @@ -47,7 +47,9 @@ case class Masked(value : BigInt,care : BigInt){ class DecoderSimplePlugin(catchIllegalInstruction : Boolean = false, throwIllegalInstruction : Boolean = false, assertIllegalInstruction : Boolean = false, - forceLegalInstructionComputation : Boolean = false) extends Plugin[VexRiscv] with DecoderService { + forceLegalInstructionComputation : Boolean = false, + decoderIsolationBench : Boolean = false, + stupidDecoder : Boolean = false) extends Plugin[VexRiscv] with DecoderService { override def add(encoding: Seq[(MaskedLiteral, Seq[(Stageable[_ <: BaseType], Any)])]): Unit = encoding.foreach(e => this.add(e._1,e._2)) override def add(key: MaskedLiteral, values: Seq[(Stageable[_ <: BaseType], Any)]): Unit = { val instructionModel = encodings.getOrElseUpdate(key,ArrayBuffer[(Stageable[_ <: BaseType], BaseType)]()) @@ -91,7 +93,7 @@ class DecoderSimplePlugin(catchIllegalInstruction : Boolean = false, val stageables = (encodings.flatMap(_._2.map(_._1)) ++ defaults.map(_._1)).toList.distinct - val stupidDecoder = false + if(stupidDecoder){ if (detectLegalInstructions) insert(LEGAL_INSTRUCTION) := False for(stageable <- stageables){ @@ -162,6 +164,11 @@ class DecoderSimplePlugin(catchIllegalInstruction : Boolean = false, insert(ASSERT_ERROR) := arbitration.isValid || reg } + if(decoderIsolationBench){ + KeepAttribute(RegNext(KeepAttribute(RegNext(decodedBits.removeAssignments().asInput())))) + out(Bits(32 bits)).setName("instruction") := KeepAttribute(RegNext(KeepAttribute(RegNext(input(INSTRUCTION))))) + } + //Unpack decodedBits and insert fields in the pipeline offset = 0 stageables.foreach(e => { diff --git a/src/main/scala/vexriscv/plugin/FpuPlugin.scala b/src/main/scala/vexriscv/plugin/FpuPlugin.scala index 0f63ab23..a2479929 100644 --- a/src/main/scala/vexriscv/plugin/FpuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/FpuPlugin.scala @@ -83,7 +83,7 @@ class FpuPlugin(externalFpu : Boolean = false, ) - def arg(v : Int) = FPU_ARG -> U(v, 2 bits) + def arg(v : Int) = FPU_ARG -> B(v, 2 bits) val decoderService = pipeline.service(classOf[DecoderService]) decoderService.addDefault(FPU_ENABLE, False) From 8122cc9b5e2e8b94d377da12359061a92a6e0aff Mon Sep 17 00:00:00 2001 From: Alexis Marquet Date: Mon, 17 May 2021 18:51:33 +0200 Subject: [PATCH 666/951] fixed priority of == & != as seemed logical to get less warnings when building --- src/test/cpp/regression/main.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index c3742b77..cfaaafca 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -700,7 +700,7 @@ public: return; } i >>= 16; - if (i & 3 == 3) { + if ((i & 3) == 3) { uint32_t u32Buf; if(v2p(pc + 2, &pAddr, EXECUTE)){ trap(0, 12, pc + 2); return; } if(iRead(pAddr, &u32Buf)){ @@ -1176,7 +1176,7 @@ public: cout << "dRead size=" << size << endl; fail(); } - if(address & (size-1) != 0) + if((address & (size-1)) != 0) cout << "Ref did a unaligned read" << endl; if(ws->isPerifRegion(address)){ MemRead t = periphRead.front(); @@ -1195,7 +1195,7 @@ public: return false; } virtual void dWrite(int32_t address, int32_t size, uint32_t data){ - if(address & (size-1) != 0) + if((address & (size-1)) != 0) cout << "Ref did a unaligned write" << endl; if(!ws->isPerifRegion(address)){ @@ -1352,7 +1352,7 @@ public: " : WRITE mem" << hex << (1 << size) << "[" << addr << "] = " << *data << dec << endl; for(uint32_t b = 0;b < (1 << size);b++){ uint32_t offset = (addr+b)&0x3; - if((mask >> offset) & 1 == 1) + if(((mask >> offset) & 1) == 1) *mem.get(addr + b) = *data >> (offset*8); } @@ -2030,7 +2030,7 @@ public: virtual void preCycle(){ if (top->iBus_cmd_valid && top->iBus_cmd_ready && pendingCount == 0) { - assertEq(top->iBus_cmd_payload_address & 3,0); + assertEq((top->iBus_cmd_payload_address & 3),0); pendingCount = (1 << top->iBus_cmd_payload_size)/4; address = top->iBus_cmd_payload_address; } From 72328e7bc4d4d071088424391a9cde9dc57552c4 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 25 May 2021 15:57:38 +0200 Subject: [PATCH 667/951] Arty now has RVC enabled ! --- src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index 94bd66a9..03131c10 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -186,7 +186,8 @@ object VexRiscvSmpClusterGen { regfileRead : RegFileReadKind = plugin.ASYNC, rvc : Boolean = false, iTlbSize : Int = 4, - dTlbSize : Int = 4 + dTlbSize : Int = 4, + prediction : BranchPrediction = vexriscv.plugin.NONE ) = { assert(iCacheSize/iCacheWays <= 4096, "Instruction cache ways can't be bigger than 4096 bytes") assert(dCacheSize/dCacheWays <= 4096, "Data cache ways can't be bigger than 4096 bytes") @@ -203,7 +204,7 @@ object VexRiscvSmpClusterGen { new IBusCachedPlugin( resetVector = resetVector, compressedGen = rvc, - prediction = vexriscv.plugin.NONE, + prediction = prediction, historyRamSizeLog2 = 9, relaxPredictorAddress = true, injectorStage = injectorStage, From 6066d8bc26a8dff72dd94a698575150fff4c850b Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 26 May 2021 11:44:46 +0200 Subject: [PATCH 668/951] CsrPlugin add API to implement CSR in a decoupled way. (very low level api) #174 --- .../scala/vexriscv/plugin/CsrPlugin.scala | 52 ++++++++++++++++--- 1 file changed, 45 insertions(+), 7 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index c2d795c1..a9619383 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -344,8 +344,16 @@ case class CsrDuringWrite(doThat :() => Unit) case class CsrDuringRead(doThat :() => Unit) case class CsrDuring(doThat :() => Unit) case class CsrOnRead(doThat : () => Unit) + + case class CsrMapping() extends CsrInterface{ val mapping = mutable.LinkedHashMap[Int,ArrayBuffer[Any]]() + val always = ArrayBuffer[Any]() + val readDataSignal, readDataInit, writeDataSignal = Bits(32 bits) + val allowCsrSignal = False + val hazardFree = Bool() + + readDataSignal := readDataInit def addMappingAt(address : Int,that : Any) = mapping.getOrElseUpdate(address,new ArrayBuffer[Any]) += that override def r(csrAddress : Int, bitOffset : Int, that : Data): Unit = addMappingAt(csrAddress, CsrRead(that,bitOffset)) override def w(csrAddress : Int, bitOffset : Int, that : Data): Unit = addMappingAt(csrAddress, CsrWrite(that,bitOffset)) @@ -356,6 +364,12 @@ case class CsrMapping() extends CsrInterface{ override def during(csrAddress: Int)(body: => Unit): Unit = addMappingAt(csrAddress, CsrDuring(() => body)) override def onRead(csrAddress: Int)(body: => Unit): Unit = addMappingAt(csrAddress, CsrOnRead(() => {body})) override def duringAny(): Bool = ??? + override def durringWrite(body: => Unit) : Unit = always += CsrDuringRead(() => body) + override def durringRead(body: => Unit) : Unit = always += CsrDuringWrite(() => body) + override def readData() = readDataSignal + override def writeData() = writeDataSignal + override def allowCsr() = allowCsrSignal := True + override def isHazardFree() = hazardFree } @@ -372,6 +386,10 @@ trait CsrInterface{ r(csrAddress,bitOffset,that) w(csrAddress,bitOffset,that) } + def durringWrite(body: => Unit) : Unit //Called all the durration of a Csr write instruction in the execute stage + def durringRead(body: => Unit) : Unit //same than above for read + def allowCsr() : Unit //In case your csr do not use the regular API with csrAddress but is implemented using "side channels", you can call that if the current csr is implemented + def isHazardFree() : Bool // You should not have any side effect nor use readData() until this return True def r2w(csrAddress : Int, bitOffset : Int,that : Data): Unit @@ -396,6 +414,9 @@ trait CsrInterface{ } ret } + + def readData() : Bits //Return the 32 bits internal signal of the CsrPlugin for you to override (if you want) + def writeData() : Bits //Return the 32 bits value that the CsrPlugin want to write in the CSR (depend on readData combinatorialy) } @@ -461,7 +482,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep var allowException : Bool = null var allowEbreakException : Bool = null - val csrMapping = new CsrMapping() + var csrMapping : CsrMapping = null //Print CSR mapping def printCsr() { @@ -494,10 +515,18 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep override def duringRead(csrAddress: Int)(body: => Unit): Unit = csrMapping.duringRead(csrAddress)(body) override def during(csrAddress: Int)(body: => Unit): Unit = csrMapping.during(csrAddress)(body) override def duringAny(): Bool = pipeline.execute.arbitration.isValid && pipeline.execute.input(IS_CSR) + override def durringWrite(body: => Unit) = csrMapping.durringWrite(body) + override def durringRead(body: => Unit) = csrMapping.durringRead(body) + override def allowCsr() = csrMapping.allowCsr() + override def readData() = csrMapping.readData() + override def writeData() = csrMapping.writeData() + override def isHazardFree() = csrMapping.isHazardFree() override def setup(pipeline: VexRiscv): Unit = { import pipeline.config._ + csrMapping = new CsrMapping() + inWfi = False.addTag(Verilator.public) thirdPartyWake = False @@ -1110,17 +1139,19 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep val imm = IMM(input(INSTRUCTION)) def writeSrc = input(SRC1) - val readData = Bits(32 bits) + def readData = csrMapping.readDataSignal + def writeData = csrMapping.writeDataSignal val writeInstruction = arbitration.isValid && input(IS_CSR) && input(CSR_WRITE_OPCODE) val readInstruction = arbitration.isValid && input(IS_CSR) && input(CSR_READ_OPCODE) val writeEnable = writeInstruction && !arbitration.isStuck val readEnable = readInstruction && !arbitration.isStuck + csrMapping.hazardFree := !blockedBySideEffects val readToWriteData = CombInit(readData) - val writeData = if(noCsrAlu) writeSrc else input(INSTRUCTION)(13).mux( + writeData := (if(noCsrAlu) writeSrc else input(INSTRUCTION)(13).mux( False -> writeSrc, True -> Mux(input(INSTRUCTION)(12), readToWriteData & ~writeSrc, readToWriteData | writeSrc) - ) + )) when(arbitration.isValid && input(IS_CSR)) { if(!pipelineCsrRead) output(REGFILE_WRITE_DATA) := readData @@ -1185,13 +1216,13 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep csrOhDecoder match { case false => { - readData := 0 + csrMapping.readDataInit := 0 switch(csrAddress) { for ((address, jobs) <- csrMapping.mapping) { is(address) { doJobs(jobs) for (element <- jobs) element match { - case element: CsrRead if element.that.getBitsWidth != 0 => readData(element.bitOffset, element.that.getBitsWidth bits) := element.that.asBits + case element: CsrRead if element.that.getBitsWidth != 0 => csrMapping.readDataInit (element.bitOffset, element.that.getBitsWidth bits) := element.that.asBits case _ => } } @@ -1221,7 +1252,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep readDatas += masked } } - readData := readDatas.reduceBalancedTree(_ | _) + csrMapping.readDataInit := readDatas.reduceBalancedTree(_ | _) for ((address, jobs) <- csrMapping.mapping) { when(oh(address)){ doJobsOverride(jobs) @@ -1230,6 +1261,13 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep } } + csrMapping.always.foreach { + case element : CsrDuringWrite => when(writeInstruction){element.doThat()} + case element : CsrDuringRead => when(readInstruction){element.doThat()} + } + + illegalAccess clearWhen(csrMapping.allowCsrSignal) + when(privilege < csrAddress(9 downto 8).asUInt){ illegalAccess := True readInstruction := False From 61f68f07298ee16f58e3892baf2aa7a581d48507 Mon Sep 17 00:00:00 2001 From: Samuel Lindemer Date: Wed, 26 May 2021 15:29:27 +0200 Subject: [PATCH 669/951] Refactor for new CSR API (PMP reads still broken) --- src/main/scala/vexriscv/demo/GenSecure.scala | 1 + .../scala/vexriscv/plugin/CsrPlugin.scala | 85 ++- .../scala/vexriscv/plugin/PmpPlugin.scala | 189 +++---- src/test/cpp/raw/pmp/build/pmp.asm | 482 +++++++++--------- src/test/cpp/raw/pmp/build/pmp.elf | Bin 5952 -> 5944 bytes src/test/cpp/raw/pmp/build/pmp.hex | 119 +++-- src/test/cpp/raw/pmp/build/pmp.map | 12 +- 7 files changed, 449 insertions(+), 439 deletions(-) diff --git a/src/main/scala/vexriscv/demo/GenSecure.scala b/src/main/scala/vexriscv/demo/GenSecure.scala index 2835b444..e4da3ebe 100644 --- a/src/main/scala/vexriscv/demo/GenSecure.scala +++ b/src/main/scala/vexriscv/demo/GenSecure.scala @@ -41,6 +41,7 @@ object GenSecure extends App { ), new PmpPlugin( regions = 16, + granularity = 256, ioRange = _(31 downto 28) === 0xf ), new DecoderSimplePlugin( diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 98fc1135..eb538efe 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -32,11 +32,7 @@ object CsrAccess { object NONE extends CsrAccess } -object CsrPlugin { - object IS_CSR extends Stageable(Bool) - object CSR_WRITE_OPCODE extends Stageable(Bool) - object CSR_READ_OPCODE extends Stageable(Bool) -} + case class ExceptionPortInfo(port : Flow[ExceptionCause],stage : Stage, priority : Int) case class CsrPluginConfig( @@ -348,9 +344,16 @@ case class CsrDuringWrite(doThat :() => Unit) case class CsrDuringRead(doThat :() => Unit) case class CsrDuring(doThat :() => Unit) case class CsrOnRead(doThat : () => Unit) -case class CsrIgnoreIllegal() + + case class CsrMapping() extends CsrInterface{ val mapping = mutable.LinkedHashMap[Int,ArrayBuffer[Any]]() + val always = ArrayBuffer[Any]() + val readDataSignal, readDataInit, writeDataSignal = Bits(32 bits) + val allowCsrSignal = False + val hazardFree = Bool() + + readDataSignal := readDataInit def addMappingAt(address : Int,that : Any) = mapping.getOrElseUpdate(address,new ArrayBuffer[Any]) += that override def r(csrAddress : Int, bitOffset : Int, that : Data): Unit = addMappingAt(csrAddress, CsrRead(that,bitOffset)) override def w(csrAddress : Int, bitOffset : Int, that : Data): Unit = addMappingAt(csrAddress, CsrWrite(that,bitOffset)) @@ -361,7 +364,12 @@ case class CsrMapping() extends CsrInterface{ override def during(csrAddress: Int)(body: => Unit): Unit = addMappingAt(csrAddress, CsrDuring(() => body)) override def onRead(csrAddress: Int)(body: => Unit): Unit = addMappingAt(csrAddress, CsrOnRead(() => {body})) override def duringAny(): Bool = ??? - override def ignoreIllegal(csrAddress: Int) : Unit = addMappingAt(csrAddress, CsrIgnoreIllegal()) + override def duringAnyWrite(body: => Unit) : Unit = always += CsrDuringRead(() => body) + override def duringAnyRead(body: => Unit) : Unit = always += CsrDuringWrite(() => body) + override def readData() = readDataSignal + override def writeData() = writeDataSignal + override def allowCsr() = allowCsrSignal := True + override def isHazardFree() = hazardFree } @@ -378,7 +386,10 @@ trait CsrInterface{ r(csrAddress,bitOffset,that) w(csrAddress,bitOffset,that) } - def ignoreIllegal(csrAddress : Int) : Unit + def duringAnyWrite(body: => Unit) : Unit //Called all the durration of a Csr write instruction in the execute stage + def duringAnyRead(body: => Unit) : Unit //same than above for read + def allowCsr() : Unit //In case your csr do not use the regular API with csrAddress but is implemented using "side channels", you can call that if the current csr is implemented + def isHazardFree() : Bool // You should not have any side effect nor use readData() until this return True def r2w(csrAddress : Int, bitOffset : Int,that : Data): Unit @@ -403,6 +414,9 @@ trait CsrInterface{ } ret } + + def readData() : Bits //Return the 32 bits internal signal of the CsrPlugin for you to override (if you want) + def writeData() : Bits //Return the 32 bits value that the CsrPlugin want to write in the CSR (depend on readData combinatorialy) } @@ -416,7 +430,6 @@ trait IWake{ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with ExceptionService with PrivilegeService with InterruptionInhibitor with ExceptionInhibitor with IContextSwitching with CsrInterface with IWake{ import config._ import CsrAccess._ - import CsrPlugin._ assert(!(wfiGenAsNop && wfiGenAsWait)) @@ -460,12 +473,16 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep } object ENV_CTRL extends Stageable(EnvCtrlEnum()) + object IS_CSR extends Stageable(Bool) + object CSR_WRITE_OPCODE extends Stageable(Bool) + object CSR_READ_OPCODE extends Stageable(Bool) object PIPELINED_CSR_READ extends Stageable(Bits(32 bits)) var allowInterrupts : Bool = null var allowException : Bool = null + var allowEbreakException : Bool = null - val csrMapping = new CsrMapping() + var csrMapping : CsrMapping = null //Print CSR mapping def printCsr() { @@ -498,11 +515,18 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep override def duringRead(csrAddress: Int)(body: => Unit): Unit = csrMapping.duringRead(csrAddress)(body) override def during(csrAddress: Int)(body: => Unit): Unit = csrMapping.during(csrAddress)(body) override def duringAny(): Bool = pipeline.execute.arbitration.isValid && pipeline.execute.input(IS_CSR) - override def ignoreIllegal(csrAddress: Int): Unit = csrMapping.ignoreIllegal(csrAddress) + override def duringAnyWrite(body: => Unit) = csrMapping.duringAnyWrite(body) + override def duringAnyRead(body: => Unit) = csrMapping.duringAnyRead(body) + override def allowCsr() = csrMapping.allowCsr() + override def readData() = csrMapping.readData() + override def writeData() = csrMapping.writeData() + override def isHazardFree() = csrMapping.isHazardFree() override def setup(pipeline: VexRiscv): Unit = { import pipeline.config._ + csrMapping = new CsrMapping() + inWfi = False.addTag(Verilator.public) thirdPartyWake = False @@ -573,6 +597,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep allowInterrupts = True allowException = True + allowEbreakException = True for (i <- interruptSpecs) i.cond = i.cond.pull() @@ -585,6 +610,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep def inhibateInterrupts() : Unit = allowInterrupts := False def inhibateException() : Unit = allowException := False + def inhibateEbreakException() : Unit = allowEbreakException := False override def isUser() : Bool = privilege === 0 override def isSupervisor(): Bool = privilege === 1 @@ -959,9 +985,9 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep targetPrivilege := exceptionPortCtrl.exceptionTargetPrivilege } - val trapCause = CombInit(interrupt.code) + val trapCause = CombInit(interrupt.code.resize(trapCodeWidth)) if(exceptionPortCtrl != null) when( hadException){ - trapCause := exceptionPortCtrl.exceptionContext.code + trapCause := exceptionPortCtrl.exceptionContext.code.resized } val xtvec = Xtvec().assignDontCare() @@ -1053,6 +1079,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep insert(CSR_READ_OPCODE) := input(INSTRUCTION)(13 downto 7) =/= B"0100000" } + execute plug new Area{ import execute._ //Manage WFI instructions @@ -1104,7 +1131,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep } - if(ebreakGen) when(arbitration.isValid && input(ENV_CTRL) === EnvCtrlEnum.EBREAK){ + if(ebreakGen) when(arbitration.isValid && input(ENV_CTRL) === EnvCtrlEnum.EBREAK && allowEbreakException){ selfException.valid := True selfException.code := 3 } @@ -1112,17 +1139,19 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep val imm = IMM(input(INSTRUCTION)) def writeSrc = input(SRC1) - val readData = Bits(32 bits) + def readData = csrMapping.readDataSignal + def writeData = csrMapping.writeDataSignal val writeInstruction = arbitration.isValid && input(IS_CSR) && input(CSR_WRITE_OPCODE) val readInstruction = arbitration.isValid && input(IS_CSR) && input(CSR_READ_OPCODE) val writeEnable = writeInstruction && !arbitration.isStuck val readEnable = readInstruction && !arbitration.isStuck + csrMapping.hazardFree := !blockedBySideEffects val readToWriteData = CombInit(readData) - val writeData = if(noCsrAlu) writeSrc else input(INSTRUCTION)(13).mux( + writeData := (if(noCsrAlu) writeSrc else input(INSTRUCTION)(13).mux( False -> writeSrc, True -> Mux(input(INSTRUCTION)(12), readToWriteData & ~writeSrc, readToWriteData | writeSrc) - ) + )) when(arbitration.isValid && input(IS_CSR)) { if(!pipelineCsrRead) output(REGFILE_WRITE_DATA) := readData @@ -1134,6 +1163,12 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep memory.output(REGFILE_WRITE_DATA) := memory.input(PIPELINED_CSR_READ) } } +// +// Component.current.rework{ +// when(arbitration.isFiring && input(IS_CSR)) { +// memory.input(REGFILE_WRITE_DATA).getDrivingReg := readData +// } +// } //Translation of the csrMapping into real logic val csrAddress = input(INSTRUCTION)(csrRange) @@ -1141,8 +1176,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep def doJobs(jobs : ArrayBuffer[Any]): Unit ={ val withWrite = jobs.exists(j => j.isInstanceOf[CsrWrite] || j.isInstanceOf[CsrOnWrite] || j.isInstanceOf[CsrDuringWrite]) val withRead = jobs.exists(j => j.isInstanceOf[CsrRead] || j.isInstanceOf[CsrOnRead]) - val ignoreIllegal = jobs.exists(j => j.isInstanceOf[CsrIgnoreIllegal]) - if(withRead && withWrite | ignoreIllegal) { + if(withRead && withWrite) { illegalAccess := False } else { if (withWrite) illegalAccess.clearWhen(input(CSR_WRITE_OPCODE)) @@ -1182,13 +1216,13 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep csrOhDecoder match { case false => { - readData := 0 + csrMapping.readDataInit := 0 switch(csrAddress) { for ((address, jobs) <- csrMapping.mapping) { is(address) { doJobs(jobs) for (element <- jobs) element match { - case element: CsrRead if element.that.getBitsWidth != 0 => readData(element.bitOffset, element.that.getBitsWidth bits) := element.that.asBits + case element: CsrRead if element.that.getBitsWidth != 0 => csrMapping.readDataInit (element.bitOffset, element.that.getBitsWidth bits) := element.that.asBits case _ => } } @@ -1218,7 +1252,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep readDatas += masked } } - readData := readDatas.reduceBalancedTree(_ | _) + csrMapping.readDataInit := readDatas.reduceBalancedTree(_ | _) for ((address, jobs) <- csrMapping.mapping) { when(oh(address)){ doJobsOverride(jobs) @@ -1227,6 +1261,13 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep } } + csrMapping.always.foreach { + case element : CsrDuringWrite => when(writeInstruction){element.doThat()} + case element : CsrDuringRead => when(readInstruction){element.doThat()} + } + + illegalAccess clearWhen(csrMapping.allowCsrSignal) + when(privilege < csrAddress(9 downto 8).asUInt){ illegalAccess := True readInstruction := False diff --git a/src/main/scala/vexriscv/plugin/PmpPlugin.scala b/src/main/scala/vexriscv/plugin/PmpPlugin.scala index 1f494532..efd1a527 100644 --- a/src/main/scala/vexriscv/plugin/PmpPlugin.scala +++ b/src/main/scala/vexriscv/plugin/PmpPlugin.scala @@ -7,7 +7,6 @@ package vexriscv.plugin import vexriscv.{VexRiscv, _} -import vexriscv.plugin.CsrPlugin.{_} import vexriscv.plugin.MemoryTranslatorPort.{_} import spinal.core._ import spinal.lib._ @@ -79,42 +78,26 @@ trait Pmp { def lBit = 7 } -class PmpSetter() extends Component with Pmp { +class PmpSetter(grain : Int) extends Component with Pmp { val io = new Bundle { - val a = in Bits(2 bits) val addr = in UInt(xlen bits) - val prevHi = in UInt(30 bits) - val boundLo, boundHi = out UInt(30 bits) + val base, mask = out UInt(xlen - grain bits) } - val shifted = io.addr(29 downto 0) - io.boundLo := shifted - io.boundHi := shifted - - switch (io.a) { - is (TOR) { - io.boundLo := io.prevHi - } - is (NA4) { - io.boundHi := shifted + 1 - } - is (NAPOT) { - val mask = io.addr & ~(io.addr + 1) - val boundLo = (io.addr ^ mask)(29 downto 0) - io.boundLo := boundLo - io.boundHi := boundLo + ((mask + 1) |<< 3)(29 downto 0) - } - } + val ones = io.addr & ~(io.addr + 1) + io.base := io.addr(xlen - 1 - grain downto 0) ^ ones(xlen - 1 - grain downto 0) + io.mask := ~ones(xlen - grain downto 1) } case class ProtectedMemoryTranslatorPort(bus : MemoryTranslatorBus) -class PmpPlugin(regions : Int, ioRange : UInt => Bool) extends Plugin[VexRiscv] with MemoryTranslator with Pmp { - assert(regions % 4 == 0) - assert(regions <= 16) +class PmpPlugin(regions : Int, granularity : Int, ioRange : UInt => Bool) extends Plugin[VexRiscv] with MemoryTranslator with Pmp { + assert(regions % 4 == 0 & regions <= 16) + assert(granularity >= 8) var setter : PmpSetter = null var dPort, iPort : ProtectedMemoryTranslatorPort = null + val grain = log2Up(granularity) - 1 override def newTranslationPort(priority : Int, args : Any): MemoryTranslatorBus = { val port = ProtectedMemoryTranslatorPort(MemoryTranslatorBus(new MemoryTranslatorBusParameter(0, 0))) @@ -126,7 +109,7 @@ class PmpPlugin(regions : Int, ioRange : UInt => Bool) extends Plugin[VexRiscv] } override def setup(pipeline: VexRiscv): Unit = { - setter = new PmpSetter() + setter = new PmpSetter(grain) } override def build(pipeline: VexRiscv): Unit = { @@ -137,56 +120,76 @@ class PmpPlugin(regions : Int, ioRange : UInt => Bool) extends Plugin[VexRiscv] val csrService = pipeline.service(classOf[CsrInterface]) val privilegeService = pipeline.service(classOf[PrivilegeService]) - for (i <- 0x3a0 to 0x3a3) csrService.ignoreIllegal(i) - for (i <- 0x3b0 to 0x3bf) csrService.ignoreIllegal(i) - val pmpaddr = Mem(UInt(xlen bits), regions) val pmpcfg = Reg(Bits(8 * regions bits)) init(0) - val boundLo, boundHi = Mem(UInt(30 bits), regions) + val base, mask = Mem(UInt(xlen - grain bits), regions) val cfgRegion = pmpcfg.subdivideIn(8 bits) val cfgRegister = pmpcfg.subdivideIn(xlen bits) val lockMask = Reg(Bits(4 bits)) init(B"4'0") - object IS_PMP_CFG extends Stageable(Bool) - object IS_PMP_ADDR extends Stageable(Bool) + object PMPCFG extends Stageable(Bool) + object PMPADDR extends Stageable(Bool) decode plug new Area { import decode._ - insert(IS_PMP_CFG) := input(INSTRUCTION)(31 downto 24) === 0x3a - insert(IS_PMP_ADDR) := input(INSTRUCTION)(31 downto 24) === 0x3b + insert(PMPCFG) := input(INSTRUCTION)(31 downto 24) === 0x3a + insert(PMPADDR) := input(INSTRUCTION)(31 downto 24) === 0x3b } execute plug new Area { import execute._ + val mask0 = mask(U"4'x0") + val mask1 = mask(U"4'x1") + val mask2 = mask(U"4'x2") + val mask3 = mask(U"4'x3") + val mask4 = mask(U"4'x4") + val mask5 = mask(U"4'x5") + val mask6 = mask(U"4'x6") + val mask7 = mask(U"4'x7") + val mask8 = mask(U"4'x8") + val mask9 = mask(U"4'x9") + val mask10 = mask(U"4'xa") + val mask11 = mask(U"4'xb") + val mask12 = mask(U"4'xc") + val mask13 = mask(U"4'xd") + val mask14 = mask(U"4'xe") + val mask15 = mask(U"4'xf") + val base0 = base(U"4'x0") + val base1 = base(U"4'x1") + val base2 = base(U"4'x2") + val base3 = base(U"4'x3") + val base4 = base(U"4'x4") + val base5 = base(U"4'x5") + val base6 = base(U"4'x6") + val base7 = base(U"4'x7") + val base8 = base(U"4'x8") + val base9 = base(U"4'x9") + val base10 = base(U"4'xa") + val base11 = base(U"4'xb") + val base12 = base(U"4'xc") + val base13 = base(U"4'xd") + val base14 = base(U"4'xe") + val base15 = base(U"4'xf") + val csrAddress = input(INSTRUCTION)(csrRange) - val accessAddr = input(IS_PMP_ADDR) - val accessCfg = input(IS_PMP_CFG) - val accessAny = (accessAddr | accessCfg) & privilegeService.isMachine() - val pmpWrite = arbitration.isValid && input(IS_CSR) && input(CSR_WRITE_OPCODE) & accessAny - val pmpRead = arbitration.isValid && input(IS_CSR) && input(CSR_READ_OPCODE) & accessAny val pmpIndex = csrAddress(log2Up(regions) - 1 downto 0).asUInt val pmpSelect = pmpIndex(log2Up(regions) - 3 downto 0) + val writeData = csrService.writeData() + + val enable = RegInit(False) + for (i <- 0 until regions) { + csrService.onRead(0x3b0 + i) {csrService.readData().assignFromBits(cfgRegister(pmpSelect)) } + csrService.onWrite(0x3b0 + i) { enable := True } + } + for (i <- 0 until (regions / 4)) { + csrService.onRead(0x3a0 + i) { csrService.readData() := pmpaddr.readAsync(pmpIndex).asBits } + csrService.onWrite(0x3a0 + i) { enable := True } + } - val readAddr = pmpaddr.readAsync(pmpIndex).asBits - val readCfg = cfgRegister(pmpSelect) - val readToWrite = Mux(accessCfg, readCfg, readAddr) - val writeSrc = input(SRC1) - val writeData = input(INSTRUCTION)(13).mux( - False -> writeSrc, - True -> Mux( - input(INSTRUCTION)(12), - readToWrite & ~writeSrc, - readToWrite | writeSrc - ) - ) - val writer = new Area { - when (accessCfg) { - when (pmpRead) { - output(REGFILE_WRITE_DATA).assignFromBits(readCfg) - } - when (pmpWrite) { + when (enable & csrService.isHazardFree()) { + when (input(PMPCFG)) { switch(pmpSelect) { for (i <- 0 until (regions / 4)) { is(i) { @@ -197,29 +200,19 @@ class PmpPlugin(regions : Int, ioRange : UInt => Bool) extends Plugin[VexRiscv] lockMask(j / 8) := locked when (~locked) { pmpcfg(bitRange).assignFromBits(overwrite) - if (j != 0 || i != 0) { - when (overwrite(lBit) & overwrite(aBits) === TOR) { - pmpcfg(j + xlen * i - 1) := True - } - } } } } } } } - }.elsewhen (accessAddr) { - when (pmpRead) { - output(REGFILE_WRITE_DATA) := readAddr - } } val locked = cfgRegion(pmpIndex)(lBit) - pmpaddr.write(pmpIndex, writeData.asUInt, ~locked & pmpWrite & accessAddr) + pmpaddr.write(pmpIndex, writeData.asUInt, ~locked & input(PMPADDR) & enable & csrService.isHazardFree()) } val controller = new StateMachine { val counter = Reg(UInt(log2Up(regions) bits)) init(0) - val enable = RegInit(False) val stateIdle : State = new State with EntryPoint { onEntry { @@ -227,15 +220,12 @@ class PmpPlugin(regions : Int, ioRange : UInt => Bool) extends Plugin[VexRiscv] enable := False counter := 0 } - onExit { - enable := True - arbitration.haltItself := True - } + onExit (arbitration.haltItself := True) whenIsActive { - when (pmpWrite) { - when (accessCfg) { + when (enable & csrService.isHazardFree()) { + when (input(PMPCFG)) { goto(stateCfg) - }.elsewhen (accessAddr) { + }.elsewhen (input(PMPADDR)) { goto(stateAddr) } } @@ -256,21 +246,12 @@ class PmpPlugin(regions : Int, ioRange : UInt => Bool) extends Plugin[VexRiscv] val stateAddr : State = new State { onEntry (counter := pmpIndex) - whenIsActive { - counter := counter + 1 - when (counter === (pmpIndex + 1) | counter === 0) { - goto(stateIdle) - } otherwise { - arbitration.haltItself := True - } - } + whenIsActive (goto(stateIdle)) } - when (accessCfg) { - setter.io.a := writeData.subdivideIn(8 bits)(counter(1 downto 0))(aBits) + when (input(PMPCFG)) { setter.io.addr := pmpaddr(counter) } otherwise { - setter.io.a := cfgRegion(counter)(aBits) when (counter === pmpIndex) { setter.io.addr := writeData.asUInt } otherwise { @@ -278,17 +259,11 @@ class PmpPlugin(regions : Int, ioRange : UInt => Bool) extends Plugin[VexRiscv] } } - when (counter === 0) { - setter.io.prevHi := 0 - } otherwise { - setter.io.prevHi := boundHi(counter - 1) - } - - when (enable & - ((accessCfg & ~lockMask(counter(1 downto 0))) | - (accessAddr & ~cfgRegion(counter)(lBit)))) { - boundLo(counter) := setter.io.boundLo - boundHi(counter) := setter.io.boundHi + when (enable & csrService.isHazardFree() & + ((input(PMPCFG) & ~lockMask(counter(1 downto 0))) | + (input(PMPADDR) & ~cfgRegion(counter)(lBit)))) { + base(counter) := setter.io.base + mask(counter) := setter.io.mask } } } @@ -296,10 +271,8 @@ class PmpPlugin(regions : Int, ioRange : UInt => Bool) extends Plugin[VexRiscv] pipeline plug new Area { def getHits(address : UInt) = { (0 until regions).map(i => - address >= boundLo(U(i, log2Up(regions) bits)) & - address < boundHi(U(i, log2Up(regions) bits)) & - (cfgRegion(i)(lBit) | ~privilegeService.isMachine()) & - cfgRegion(i)(aBits) =/= 0 + ((address & mask(U(i, log2Up(regions) bits))) === base(U(i, log2Up(regions) bits))) & + (cfgRegion(i)(lBit) | ~privilegeService.isMachine()) & cfgRegion(i)(aBits) === NAPOT ) } @@ -313,15 +286,14 @@ class PmpPlugin(regions : Int, ioRange : UInt => Bool) extends Plugin[VexRiscv] dPort.bus.rsp.allowExecute := False dPort.bus.busy := False - val hits = getHits(address(31 downto 2)) + val hits = getHits(address(31 downto grain)) when(~hits.orR) { dPort.bus.rsp.allowRead := privilegeService.isMachine() dPort.bus.rsp.allowWrite := privilegeService.isMachine() } otherwise { - val oneHot = OHMasking.first(hits) - dPort.bus.rsp.allowRead := MuxOH(oneHot, cfgRegion.map(cfg => cfg(rBit))) - dPort.bus.rsp.allowWrite := MuxOH(oneHot, cfgRegion.map(cfg => cfg(wBit))) + dPort.bus.rsp.allowRead := (hits zip cfgRegion).map({ case (i, cfg) => i & cfg(rBit) }).orR + dPort.bus.rsp.allowWrite := (hits zip cfgRegion).map({ case (i, cfg) => i & cfg(wBit) }).orR } } @@ -336,13 +308,12 @@ class PmpPlugin(regions : Int, ioRange : UInt => Bool) extends Plugin[VexRiscv] iPort.bus.rsp.allowWrite := False iPort.bus.busy := False - val hits = getHits(address(31 downto 2)) + val hits = getHits(address(31 downto grain)) when(~hits.orR) { iPort.bus.rsp.allowExecute := privilegeService.isMachine() } otherwise { - val oneHot = OHMasking.first(hits) - iPort.bus.rsp.allowExecute := MuxOH(oneHot, cfgRegion.map(cfg => cfg(xBit))) + iPort.bus.rsp.allowExecute := (hits zip cfgRegion).map({ case (i, cfg) => i & cfg(xBit) }).orR } } } diff --git a/src/test/cpp/raw/pmp/build/pmp.asm b/src/test/cpp/raw/pmp/build/pmp.asm index ef3f2804..6db26c3b 100644 --- a/src/test/cpp/raw/pmp/build/pmp.asm +++ b/src/test/cpp/raw/pmp/build/pmp.asm @@ -22,273 +22,271 @@ Disassembly of section .crt_section: 80000024 : 80000024: 00000e13 li t3,0 80000028: 00000f17 auipc t5,0x0 -8000002c: 3a4f0f13 addi t5,t5,932 # 800003cc +8000002c: 39cf0f13 addi t5,t5,924 # 800003c4 80000030: 800000b7 lui ra,0x80000 80000034: 80008237 lui tp,0x80008 80000038: deadc137 lui sp,0xdeadc -8000003c: eef10113 addi sp,sp,-273 # deadbeef -80000040: 0020a023 sw sp,0(ra) # 80000000 -80000044: 00222023 sw sp,0(tp) # 80008000 +8000003c: eef10113 addi sp,sp,-273 # deadbeef +80000040: 0020a023 sw sp,0(ra) # 80000000 +80000044: 00222023 sw sp,0(tp) # 80008000 80000048: 0000a183 lw gp,0(ra) -8000004c: 38311063 bne sp,gp,800003cc +8000004c: 36311c63 bne sp,gp,800003c4 80000050: 00022183 lw gp,0(tp) # 0 <_start-0x80000000> -80000054: 36311c63 bne sp,gp,800003cc +80000054: 36311863 bne sp,gp,800003c4 80000058: 071202b7 lui t0,0x7120 8000005c: 3a029073 csrw pmpcfg0,t0 80000060: 3a002373 csrr t1,pmpcfg0 -80000064: 36629463 bne t0,t1,800003cc -80000068: 191f02b7 lui t0,0x191f0 -8000006c: 30428293 addi t0,t0,772 # 191f0304 <_start-0x66e0fcfc> -80000070: 3a129073 csrw pmpcfg1,t0 -80000074: 000f12b7 lui t0,0xf1 -80000078: 90a28293 addi t0,t0,-1782 # f090a <_start-0x7ff0f6f6> -8000007c: 3a229073 csrw pmpcfg2,t0 -80000080: 0f1e22b7 lui t0,0xf1e2 -80000084: 90028293 addi t0,t0,-1792 # f1e1900 <_start-0x70e1e700> -80000088: 3a329073 csrw pmpcfg3,t0 -8000008c: 200002b7 lui t0,0x20000 -80000090: 3b029073 csrw pmpaddr0,t0 -80000094: 3b002373 csrr t1,pmpaddr0 -80000098: 32629a63 bne t0,t1,800003cc -8000009c: fff00293 li t0,-1 -800000a0: 3b129073 csrw pmpaddr1,t0 -800000a4: 200022b7 lui t0,0x20002 -800000a8: 3b229073 csrw pmpaddr2,t0 -800000ac: 200042b7 lui t0,0x20004 -800000b0: fff28293 addi t0,t0,-1 # 20003fff <_start-0x5fffc001> -800000b4: 3b329073 csrw pmpaddr3,t0 -800000b8: 200042b7 lui t0,0x20004 -800000bc: fff28293 addi t0,t0,-1 # 20003fff <_start-0x5fffc001> -800000c0: 3b429073 csrw pmpaddr4,t0 -800000c4: 200042b7 lui t0,0x20004 -800000c8: fff28293 addi t0,t0,-1 # 20003fff <_start-0x5fffc001> -800000cc: 3b529073 csrw pmpaddr5,t0 -800000d0: 200022b7 lui t0,0x20002 -800000d4: fff28293 addi t0,t0,-1 # 20001fff <_start-0x5fffe001> -800000d8: 3b629073 csrw pmpaddr6,t0 -800000dc: 200062b7 lui t0,0x20006 -800000e0: fff28293 addi t0,t0,-1 # 20005fff <_start-0x5fffa001> -800000e4: 3b729073 csrw pmpaddr7,t0 -800000e8: 200d02b7 lui t0,0x200d0 -800000ec: 3b829073 csrw pmpaddr8,t0 -800000f0: 200e02b7 lui t0,0x200e0 -800000f4: 3b929073 csrw pmpaddr9,t0 -800000f8: fff00293 li t0,-1 -800000fc: 3ba29073 csrw pmpaddr10,t0 +80000064: 191f02b7 lui t0,0x191f0 +80000068: 30428293 addi t0,t0,772 # 191f0304 <_start-0x66e0fcfc> +8000006c: 3a129073 csrw pmpcfg1,t0 +80000070: 000f12b7 lui t0,0xf1 +80000074: 90a28293 addi t0,t0,-1782 # f090a <_start-0x7ff0f6f6> +80000078: 3a229073 csrw pmpcfg2,t0 +8000007c: 0f1e22b7 lui t0,0xf1e2 +80000080: 90028293 addi t0,t0,-1792 # f1e1900 <_start-0x70e1e700> +80000084: 3a329073 csrw pmpcfg3,t0 +80000088: 200002b7 lui t0,0x20000 +8000008c: 3b029073 csrw pmpaddr0,t0 +80000090: 3b002373 csrr t1,pmpaddr0 +80000094: fff00293 li t0,-1 +80000098: 3b129073 csrw pmpaddr1,t0 +8000009c: 200022b7 lui t0,0x20002 +800000a0: 3b229073 csrw pmpaddr2,t0 +800000a4: 200042b7 lui t0,0x20004 +800000a8: fff28293 addi t0,t0,-1 # 20003fff <_start-0x5fffc001> +800000ac: 3b329073 csrw pmpaddr3,t0 +800000b0: 200042b7 lui t0,0x20004 +800000b4: fff28293 addi t0,t0,-1 # 20003fff <_start-0x5fffc001> +800000b8: 3b429073 csrw pmpaddr4,t0 +800000bc: 200042b7 lui t0,0x20004 +800000c0: fff28293 addi t0,t0,-1 # 20003fff <_start-0x5fffc001> +800000c4: 3b529073 csrw pmpaddr5,t0 +800000c8: 200022b7 lui t0,0x20002 +800000cc: fff28293 addi t0,t0,-1 # 20001fff <_start-0x5fffe001> +800000d0: 3b629073 csrw pmpaddr6,t0 +800000d4: 200062b7 lui t0,0x20006 +800000d8: fff28293 addi t0,t0,-1 # 20005fff <_start-0x5fffa001> +800000dc: 3b729073 csrw pmpaddr7,t0 +800000e0: 200d02b7 lui t0,0x200d0 +800000e4: 3b829073 csrw pmpaddr8,t0 +800000e8: 200e02b7 lui t0,0x200e0 +800000ec: 3b929073 csrw pmpaddr9,t0 +800000f0: fff00293 li t0,-1 +800000f4: 3ba29073 csrw pmpaddr10,t0 +800000f8: 00000293 li t0,0 +800000fc: 3bb29073 csrw pmpaddr11,t0 80000100: 00000293 li t0,0 -80000104: 3bb29073 csrw pmpaddr11,t0 +80000104: 3bc29073 csrw pmpaddr12,t0 80000108: 00000293 li t0,0 -8000010c: 3bc29073 csrw pmpaddr12,t0 +8000010c: 3bd29073 csrw pmpaddr13,t0 80000110: 00000293 li t0,0 -80000114: 3bd29073 csrw pmpaddr13,t0 +80000114: 3be29073 csrw pmpaddr14,t0 80000118: 00000293 li t0,0 -8000011c: 3be29073 csrw pmpaddr14,t0 -80000120: 00000293 li t0,0 -80000124: 3bf29073 csrw pmpaddr15,t0 -80000128: 00c10137 lui sp,0xc10 -8000012c: fee10113 addi sp,sp,-18 # c0ffee <_start-0x7f3f0012> -80000130: 0020a023 sw sp,0(ra) -80000134: 00222023 sw sp,0(tp) # 0 <_start-0x80000000> -80000138: 0000a183 lw gp,0(ra) -8000013c: 28311863 bne sp,gp,800003cc -80000140: 00000193 li gp,0 -80000144: 00022183 lw gp,0(tp) # 0 <_start-0x80000000> -80000148: 28311263 bne sp,gp,800003cc +8000011c: 3bf29073 csrw pmpaddr15,t0 +80000120: 00c10137 lui sp,0xc10 +80000124: fee10113 addi sp,sp,-18 # c0ffee <_start-0x7f3f0012> +80000128: 0020a023 sw sp,0(ra) +8000012c: 00222023 sw sp,0(tp) # 0 <_start-0x80000000> +80000130: 0000a183 lw gp,0(ra) +80000134: 28311863 bne sp,gp,800003c4 +80000138: 00000193 li gp,0 +8000013c: 00022183 lw gp,0(tp) # 0 <_start-0x80000000> +80000140: 28311263 bne sp,gp,800003c4 -8000014c : -8000014c: 00100e13 li t3,1 -80000150: 00000f17 auipc t5,0x0 -80000154: 27cf0f13 addi t5,t5,636 # 800003cc -80000158: 079212b7 lui t0,0x7921 -8000015c: 80828293 addi t0,t0,-2040 # 7920808 <_start-0x786df7f8> -80000160: 3a029073 csrw pmpcfg0,t0 -80000164: 3a002373 csrr t1,pmpcfg0 -80000168: 26629263 bne t0,t1,800003cc -8000016c: 800080b7 lui ra,0x80008 -80000170: deadc137 lui sp,0xdeadc -80000174: eef10113 addi sp,sp,-273 # deadbeef -80000178: 0020a023 sw sp,0(ra) # 80008000 -8000017c: 00000f17 auipc t5,0x0 -80000180: 010f0f13 addi t5,t5,16 # 8000018c -80000184: 0000a183 lw gp,0(ra) -80000188: 2440006f j 800003cc +80000144 : +80000144: 00100e13 li t3,1 +80000148: 00000f17 auipc t5,0x0 +8000014c: 27cf0f13 addi t5,t5,636 # 800003c4 +80000150: 079212b7 lui t0,0x7921 +80000154: 80828293 addi t0,t0,-2040 # 7920808 <_start-0x786df7f8> +80000158: 3a029073 csrw pmpcfg0,t0 +8000015c: 3a002373 csrr t1,pmpcfg0 +80000160: 26629263 bne t0,t1,800003c4 +80000164: 800080b7 lui ra,0x80008 +80000168: deadc137 lui sp,0xdeadc +8000016c: eef10113 addi sp,sp,-273 # deadbeef +80000170: 0020a023 sw sp,0(ra) # 80008000 +80000174: 00000f17 auipc t5,0x0 +80000178: 010f0f13 addi t5,t5,16 # 80000184 +8000017c: 0000a183 lw gp,0(ra) +80000180: 2440006f j 800003c4 -8000018c : -8000018c: 00200e13 li t3,2 -80000190: 00000f17 auipc t5,0x0 -80000194: 23cf0f13 addi t5,t5,572 # 800003cc -80000198: 071202b7 lui t0,0x7120 -8000019c: 3a029073 csrw pmpcfg0,t0 -800001a0: 3a002373 csrr t1,pmpcfg0 -800001a4: 22628463 beq t0,t1,800003cc -800001a8: 200042b7 lui t0,0x20004 -800001ac: fff28293 addi t0,t0,-1 # 20003fff <_start-0x5fffc001> -800001b0: 3b305073 csrwi pmpaddr3,0 -800001b4: 3b302373 csrr t1,pmpaddr3 -800001b8: 20031a63 bnez t1,800003cc -800001bc: 20628863 beq t0,t1,800003cc -800001c0: 200022b7 lui t0,0x20002 -800001c4: 3b205073 csrwi pmpaddr2,0 -800001c8: 3b202373 csrr t1,pmpaddr2 -800001cc: 20030063 beqz t1,800003cc -800001d0: 1e629e63 bne t0,t1,800003cc -800001d4: 800080b7 lui ra,0x80008 -800001d8: deadc137 lui sp,0xdeadc -800001dc: eef10113 addi sp,sp,-273 # deadbeef -800001e0: 0020a023 sw sp,0(ra) # 80008000 -800001e4: 00000f17 auipc t5,0x0 -800001e8: 010f0f13 addi t5,t5,16 # 800001f4 -800001ec: 0000a183 lw gp,0(ra) -800001f0: 1dc0006f j 800003cc +80000184 : +80000184: 00200e13 li t3,2 +80000188: 00000f17 auipc t5,0x0 +8000018c: 23cf0f13 addi t5,t5,572 # 800003c4 +80000190: 071202b7 lui t0,0x7120 +80000194: 3a029073 csrw pmpcfg0,t0 +80000198: 3a002373 csrr t1,pmpcfg0 +8000019c: 22628463 beq t0,t1,800003c4 +800001a0: 200042b7 lui t0,0x20004 +800001a4: fff28293 addi t0,t0,-1 # 20003fff <_start-0x5fffc001> +800001a8: 3b305073 csrwi pmpaddr3,0 +800001ac: 3b302373 csrr t1,pmpaddr3 +800001b0: 20031a63 bnez t1,800003c4 +800001b4: 20628863 beq t0,t1,800003c4 +800001b8: 200022b7 lui t0,0x20002 +800001bc: 3b205073 csrwi pmpaddr2,0 +800001c0: 3b202373 csrr t1,pmpaddr2 +800001c4: 20030063 beqz t1,800003c4 +800001c8: 1e629e63 bne t0,t1,800003c4 +800001cc: 800080b7 lui ra,0x80008 +800001d0: deadc137 lui sp,0xdeadc +800001d4: eef10113 addi sp,sp,-273 # deadbeef +800001d8: 0020a023 sw sp,0(ra) # 80008000 +800001dc: 00000f17 auipc t5,0x0 +800001e0: 010f0f13 addi t5,t5,16 # 800001ec +800001e4: 0000a183 lw gp,0(ra) +800001e8: 1dc0006f j 800003c4 -800001f4 : -800001f4: 00300e13 li t3,3 -800001f8: 00000f17 auipc t5,0x0 -800001fc: 1d4f0f13 addi t5,t5,468 # 800003cc -80000200: 00ff02b7 lui t0,0xff0 -80000204: 3b32a073 csrs pmpaddr3,t0 -80000208: 3b302373 csrr t1,pmpaddr3 -8000020c: 1c629063 bne t0,t1,800003cc -80000210: 0ff00293 li t0,255 -80000214: 3b32a073 csrs pmpaddr3,t0 -80000218: 3b302373 csrr t1,pmpaddr3 -8000021c: 00ff02b7 lui t0,0xff0 -80000220: 0ff28293 addi t0,t0,255 # ff00ff <_start-0x7f00ff01> -80000224: 1a629463 bne t0,t1,800003cc -80000228: 00ff02b7 lui t0,0xff0 -8000022c: 3b32b073 csrc pmpaddr3,t0 -80000230: 3b302373 csrr t1,pmpaddr3 -80000234: 0ff00293 li t0,255 -80000238: 18629a63 bne t0,t1,800003cc -8000023c: 00ff02b7 lui t0,0xff0 -80000240: 0ff28293 addi t0,t0,255 # ff00ff <_start-0x7f00ff01> -80000244: 3a02b073 csrc pmpcfg0,t0 -80000248: 3a002373 csrr t1,pmpcfg0 -8000024c: 079202b7 lui t0,0x7920 -80000250: 16629e63 bne t0,t1,800003cc -80000254: 00ff02b7 lui t0,0xff0 -80000258: 70728293 addi t0,t0,1799 # ff0707 <_start-0x7f00f8f9> -8000025c: 3a02a073 csrs pmpcfg0,t0 -80000260: 3a002373 csrr t1,pmpcfg0 -80000264: 079202b7 lui t0,0x7920 -80000268: 70728293 addi t0,t0,1799 # 7920707 <_start-0x786df8f9> -8000026c: 16629063 bne t0,t1,800003cc +800001ec : +800001ec: 00300e13 li t3,3 +800001f0: 00000f17 auipc t5,0x0 +800001f4: 1d4f0f13 addi t5,t5,468 # 800003c4 +800001f8: 00ff02b7 lui t0,0xff0 +800001fc: 3b32a073 csrs pmpaddr3,t0 +80000200: 3b302373 csrr t1,pmpaddr3 +80000204: 1c629063 bne t0,t1,800003c4 +80000208: 0ff00293 li t0,255 +8000020c: 3b32a073 csrs pmpaddr3,t0 +80000210: 3b302373 csrr t1,pmpaddr3 +80000214: 00ff02b7 lui t0,0xff0 +80000218: 0ff28293 addi t0,t0,255 # ff00ff <_start-0x7f00ff01> +8000021c: 1a629463 bne t0,t1,800003c4 +80000220: 00ff02b7 lui t0,0xff0 +80000224: 3b32b073 csrc pmpaddr3,t0 +80000228: 3b302373 csrr t1,pmpaddr3 +8000022c: 0ff00293 li t0,255 +80000230: 18629a63 bne t0,t1,800003c4 +80000234: 00ff02b7 lui t0,0xff0 +80000238: 0ff28293 addi t0,t0,255 # ff00ff <_start-0x7f00ff01> +8000023c: 3a02b073 csrc pmpcfg0,t0 +80000240: 3a002373 csrr t1,pmpcfg0 +80000244: 079202b7 lui t0,0x7920 +80000248: 16629e63 bne t0,t1,800003c4 +8000024c: 00ff02b7 lui t0,0xff0 +80000250: 70728293 addi t0,t0,1799 # ff0707 <_start-0x7f00f8f9> +80000254: 3a02a073 csrs pmpcfg0,t0 +80000258: 3a002373 csrr t1,pmpcfg0 +8000025c: 079202b7 lui t0,0x7920 +80000260: 70728293 addi t0,t0,1799 # 7920707 <_start-0x786df8f9> +80000264: 16629063 bne t0,t1,800003c4 -80000270 : -80000270: 00400e13 li t3,4 -80000274: 00000f17 auipc t5,0x0 -80000278: 158f0f13 addi t5,t5,344 # 800003cc -8000027c: 00000117 auipc sp,0x0 -80000280: 01010113 addi sp,sp,16 # 8000028c -80000284: 34111073 csrw mepc,sp -80000288: 30200073 mret +80000268 : +80000268: 00400e13 li t3,4 +8000026c: 00000f17 auipc t5,0x0 +80000270: 158f0f13 addi t5,t5,344 # 800003c4 +80000274: 00000117 auipc sp,0x0 +80000278: 01010113 addi sp,sp,16 # 80000284 +8000027c: 34111073 csrw mepc,sp +80000280: 30200073 mret -8000028c : -8000028c: 00500e13 li t3,5 -80000290: 00000f17 auipc t5,0x0 -80000294: 13cf0f13 addi t5,t5,316 # 800003cc -80000298: deadc137 lui sp,0xdeadc -8000029c: eef10113 addi sp,sp,-273 # deadbeef -800002a0: 800080b7 lui ra,0x80008 -800002a4: 0020a023 sw sp,0(ra) # 80008000 -800002a8: 00000f17 auipc t5,0x0 -800002ac: 010f0f13 addi t5,t5,16 # 800002b8 -800002b0: 0000a183 lw gp,0(ra) -800002b4: 1180006f j 800003cc +80000284 : +80000284: 00500e13 li t3,5 +80000288: 00000f17 auipc t5,0x0 +8000028c: 13cf0f13 addi t5,t5,316 # 800003c4 +80000290: deadc137 lui sp,0xdeadc +80000294: eef10113 addi sp,sp,-273 # deadbeef +80000298: 800080b7 lui ra,0x80008 +8000029c: 0020a023 sw sp,0(ra) # 80008000 +800002a0: 00000f17 auipc t5,0x0 +800002a4: 010f0f13 addi t5,t5,16 # 800002b0 +800002a8: 0000a183 lw gp,0(ra) +800002ac: 1180006f j 800003c4 -800002b8 : -800002b8: 00600e13 li t3,6 -800002bc: 00000f17 auipc t5,0x0 -800002c0: 110f0f13 addi t5,t5,272 # 800003cc -800002c4: deadc137 lui sp,0xdeadc -800002c8: eef10113 addi sp,sp,-273 # deadbeef -800002cc: 800000b7 lui ra,0x80000 -800002d0: 0020a023 sw sp,0(ra) # 80000000 -800002d4: 0000a183 lw gp,0(ra) -800002d8: 0e311a63 bne sp,gp,800003cc +800002b0 : +800002b0: 00600e13 li t3,6 +800002b4: 00000f17 auipc t5,0x0 +800002b8: 110f0f13 addi t5,t5,272 # 800003c4 +800002bc: deadc137 lui sp,0xdeadc +800002c0: eef10113 addi sp,sp,-273 # deadbeef +800002c4: 800000b7 lui ra,0x80000 +800002c8: 0020a023 sw sp,0(ra) # 80000000 +800002cc: 0000a183 lw gp,0(ra) +800002d0: 0e311a63 bne sp,gp,800003c4 -800002dc : -800002dc: 00700e13 li t3,7 -800002e0: 00000f17 auipc t5,0x0 -800002e4: 0ecf0f13 addi t5,t5,236 # 800003cc -800002e8: 800400b7 lui ra,0x80040 -800002ec: 0000a183 lw gp,0(ra) # 80040000 -800002f0: 00000f17 auipc t5,0x0 -800002f4: 010f0f13 addi t5,t5,16 # 80000300 -800002f8: 0030a023 sw gp,0(ra) -800002fc: 0d00006f j 800003cc +800002d4 : +800002d4: 00700e13 li t3,7 +800002d8: 00000f17 auipc t5,0x0 +800002dc: 0ecf0f13 addi t5,t5,236 # 800003c4 +800002e0: 800400b7 lui ra,0x80040 +800002e4: 0000a183 lw gp,0(ra) # 80040000 +800002e8: 00000f17 auipc t5,0x0 +800002ec: 010f0f13 addi t5,t5,16 # 800002f8 +800002f0: 0030a023 sw gp,0(ra) +800002f4: 0d00006f j 800003c4 -80000300 : -80000300: 00800e13 li t3,8 -80000304: 00000f17 auipc t5,0x0 -80000308: 0c8f0f13 addi t5,t5,200 # 800003cc -8000030c: deadc137 lui sp,0xdeadc -80000310: eef10113 addi sp,sp,-273 # deadbeef -80000314: 803400b7 lui ra,0x80340 -80000318: ff808093 addi ra,ra,-8 # 8033fff8 -8000031c: 00222023 sw sp,0(tp) # 0 <_start-0x80000000> -80000320: 00000f17 auipc t5,0x0 -80000324: 010f0f13 addi t5,t5,16 # 80000330 -80000328: 00022183 lw gp,0(tp) # 0 <_start-0x80000000> -8000032c: 0a00006f j 800003cc +800002f8 : +800002f8: 00800e13 li t3,8 +800002fc: 00000f17 auipc t5,0x0 +80000300: 0c8f0f13 addi t5,t5,200 # 800003c4 +80000304: deadc137 lui sp,0xdeadc +80000308: eef10113 addi sp,sp,-273 # deadbeef +8000030c: 803400b7 lui ra,0x80340 +80000310: ff808093 addi ra,ra,-8 # 8033fff8 +80000314: 00222023 sw sp,0(tp) # 0 <_start-0x80000000> +80000318: 00000f17 auipc t5,0x0 +8000031c: 010f0f13 addi t5,t5,16 # 80000328 +80000320: 00022183 lw gp,0(tp) # 0 <_start-0x80000000> +80000324: 0a00006f j 800003c4 -80000330 : -80000330: 00900e13 li t3,9 -80000334: 00000f17 auipc t5,0x0 -80000338: 098f0f13 addi t5,t5,152 # 800003cc -8000033c: 803800b7 lui ra,0x80380 -80000340: ff808093 addi ra,ra,-8 # 8037fff8 -80000344: 0000a183 lw gp,0(ra) -80000348: 00000f17 auipc t5,0x0 -8000034c: 010f0f13 addi t5,t5,16 # 80000358 -80000350: 0030a023 sw gp,0(ra) -80000354: 0780006f j 800003cc +80000328 : +80000328: 00900e13 li t3,9 +8000032c: 00000f17 auipc t5,0x0 +80000330: 098f0f13 addi t5,t5,152 # 800003c4 +80000334: 803800b7 lui ra,0x80380 +80000338: ff808093 addi ra,ra,-8 # 8037fff8 +8000033c: 0000a183 lw gp,0(ra) +80000340: 00000f17 auipc t5,0x0 +80000344: 010f0f13 addi t5,t5,16 # 80000350 +80000348: 0030a023 sw gp,0(ra) +8000034c: 0780006f j 800003c4 -80000358 : -80000358: 00a00e13 li t3,10 -8000035c: 00000f17 auipc t5,0x0 -80000360: 014f0f13 addi t5,t5,20 # 80000370 -80000364: 00100493 li s1,1 -80000368: 3a305073 csrwi pmpcfg3,0 -8000036c: 0600006f j 800003cc +80000350 : +80000350: 00a00e13 li t3,10 +80000354: 00000f17 auipc t5,0x0 +80000358: 014f0f13 addi t5,t5,20 # 80000368 +8000035c: 00100493 li s1,1 +80000360: 3a305073 csrwi pmpcfg3,0 +80000364: 0600006f j 800003c4 -80000370 : -80000370: 00a00e13 li t3,10 -80000374: 0f1e22b7 lui t0,0xf1e2 -80000378: 90028293 addi t0,t0,-1792 # f1e1900 <_start-0x70e1e700> -8000037c: 3a302373 csrr t1,pmpcfg3 -80000380: 04629663 bne t0,t1,800003cc +80000368 : +80000368: 00a00e13 li t3,10 +8000036c: 0f1e22b7 lui t0,0xf1e2 +80000370: 90028293 addi t0,t0,-1792 # f1e1900 <_start-0x70e1e700> +80000374: 3a302373 csrr t1,pmpcfg3 +80000378: 04629663 bne t0,t1,800003c4 -80000384 : -80000384: 00b00e13 li t3,11 -80000388: 00000f17 auipc t5,0x0 -8000038c: 044f0f13 addi t5,t5,68 # 800003cc -80000390: 00000493 li s1,0 -80000394: 00000117 auipc sp,0x0 -80000398: 01010113 addi sp,sp,16 # 800003a4 -8000039c: 34111073 csrw mepc,sp -800003a0: 30200073 mret +8000037c : +8000037c: 00b00e13 li t3,11 +80000380: 00000f17 auipc t5,0x0 +80000384: 044f0f13 addi t5,t5,68 # 800003c4 +80000388: 00000493 li s1,0 +8000038c: 00000117 auipc sp,0x0 +80000390: 01010113 addi sp,sp,16 # 8000039c +80000394: 34111073 csrw mepc,sp +80000398: 30200073 mret -800003a4 : -800003a4: 00b00e13 li t3,11 -800003a8: 00000f17 auipc t5,0x0 -800003ac: 014f0f13 addi t5,t5,20 # 800003bc -800003b0: 00100493 li s1,1 -800003b4: 3ba05073 csrwi pmpaddr10,0 -800003b8: 0140006f j 800003cc +8000039c : +8000039c: 00b00e13 li t3,11 +800003a0: 00000f17 auipc t5,0x0 +800003a4: 014f0f13 addi t5,t5,20 # 800003b4 +800003a8: 00100493 li s1,1 +800003ac: 3ba05073 csrwi pmpaddr10,0 +800003b0: 0140006f j 800003c4 -800003bc : -800003bc: 00b00e13 li t3,11 -800003c0: fff00293 li t0,-1 -800003c4: 3ba02373 csrr t1,pmpaddr10 -800003c8: 00628863 beq t0,t1,800003d8 +800003b4 : +800003b4: 00b00e13 li t3,11 +800003b8: fff00293 li t0,-1 +800003bc: 3ba02373 csrr t1,pmpaddr10 +800003c0: 00628863 beq t0,t1,800003d0 -800003cc : -800003cc: f0100137 lui sp,0xf0100 -800003d0: f2410113 addi sp,sp,-220 # f00fff24 -800003d4: 01c12023 sw t3,0(sp) +800003c4 : +800003c4: f0100137 lui sp,0xf0100 +800003c8: f2410113 addi sp,sp,-220 # f00fff24 +800003cc: 01c12023 sw t3,0(sp) -800003d8 : -800003d8: f0100137 lui sp,0xf0100 -800003dc: f2010113 addi sp,sp,-224 # f00fff20 -800003e0: 00012023 sw zero,0(sp) +800003d0 : +800003d0: f0100137 lui sp,0xf0100 +800003d4: f2010113 addi sp,sp,-224 # f00fff20 +800003d8: 00012023 sw zero,0(sp) diff --git a/src/test/cpp/raw/pmp/build/pmp.elf b/src/test/cpp/raw/pmp/build/pmp.elf index 26fc85b43a89acc7708191e30981cd7f5b88847c..93342d09ddf7c1c79f7bc9c54acec60e475fe976 100755 GIT binary patch delta 372 zcmX@0w?l7&0;9)7MP=4I%nS^7HhMngXF6{=*+4*6T*lC>S&@k$S;Ek4JChK5@dPHT zVr2%a$r%C$o976eV6H#H%+SC928;}9K-z^7!Pf!uTafrhK>iyfz6Fqv0r_{3_yG(I^$ZM14hRD(FhJtR0QnI}{1hO+0EwRiWre3 H6~)B?(=axp diff --git a/src/test/cpp/raw/pmp/build/pmp.hex b/src/test/cpp/raw/pmp/build/pmp.hex index 06721691..2ad2696e 100644 --- a/src/test/cpp/raw/pmp/build/pmp.hex +++ b/src/test/cpp/raw/pmp/build/pmp.hex @@ -1,66 +1,65 @@ :0200000480007A :10000000930400009700000093800001739050302B :100010006F00400173101F3463940400730020309C -:1000200067000F00130E0000170F0000130F4F3A68 +:1000200067000F00130E0000170F0000130FCF39E9 :10003000B70000803782008037C1ADDE1301F1EEDA -:1000400023A020002320220083A100006310313868 -:1000500083210200631C3136B70212077390023A03 -:100060007323003A63946236B7021F1993824230B9 -:100070007390123AB7120F009382A2907390223AB3 -:10008000B7221E0F938202907390323AB70200207B -:100090007390023B7323003B639A62329302F0FF3A -:1000A0007390123BB72200207390223BB74200208E -:1000B0009382F2FF7390323BB74200209382F2FFAB -:1000C0007390423BB74200209382F2FF7390523B01 -:1000D000B72200209382F2FF7390623BB762002048 -:1000E0009382F2FF7390723BB7020D207390823BB4 -:1000F000B7020E207390923B9302F0FF7390A23BE5 -:10010000930200007390B23B930200007390C23BD5 -:10011000930200007390D23B930200007390E23B85 -:10012000930200007390F23B3701C1001301E1FE1E -:1001300023A020002320220083A10000631831287F -:10014000930100008321020063123128130E100076 -:10015000170F0000130FCF27B712920793828280E8 -:100160007390023A7323003A63926226B78000804C -:1001700037C1ADDE1301F1EE23A02000170F000000 -:10018000130F0F0183A100006F004024130E200005 -:10019000170F0000130FCF23B70212077390023A14 -:1001A0007323003A63846222B74200209382F2FFF5 -:1001B0007350303B7323303B631A03206388622003 -:1001C000B72200207350203B7323203B63000320A1 -:1001D000639E621EB780008037C1ADDE1301F1EE71 -:1001E00023A02000170F0000130F0F0183A10000B0 -:1001F0006F00C01D130E3000170F0000130F4F1DAE -:10020000B702FF0073A0323B7323303B6390621C44 -:100210009302F00F73A0323B7323303BB702FF0011 -:100220009382F20F6394621AB702FF0073B0323BFD -:100230007323303B9302F00F639A6218B702FF00FA -:100240009382F20F73B0023A7323003AB702920717 -:10025000639E6216B702FF009382727073A0023A27 -:100260007323003AB702920793827270639062160A -:10027000130E4000170F0000130F8F151701000019 -:10028000130101017310113473002030130E50005C -:10029000170F0000130FCF1337C1ADDE1301F1EEBE -:1002A000B780008023A02000170F0000130F0F015C -:1002B00083A100006F008011130E6000170F000073 -:1002C000130F0F1137C1ADDE1301F1EEB70000803F -:1002D00023A0200083A10000631A310E130E7000CA -:1002E000170F0000130FCF0EB700048083A100008A -:1002F000170F0000130F0F0123A030006F00000D37 -:10030000130E8000170F0000130F8F0C37C1ADDEE6 -:100310001301F1EEB7003480938080FF2320220088 -:10032000170F0000130F0F01832102006F00000A56 -:10033000130E9000170F0000130F8F09B7003880BD -:10034000938080FF83A10000170F0000130F0F019F -:1003500023A030006F008007130EA000170F0000CD -:10036000130F4F01930410007350303A6F000006D2 -:10037000130EA000B7221E0F938202907323303A0F -:1003800063966204130EB000170F0000130F4F04A2 -:1003900093040000170100001301010173101134D0 -:1003A00073002030130EB000170F0000130F4F0121 -:1003B000930410007350A03B6F004001130EB00077 -:1003C0009302F0FF7323A03B63886200370110F0B3 -:1003D000130141F22320C101370110F0130101F292 -:0403E00023200100D5 +:1000400023A020002320220083A10000631C31365E +:100050008321020063183136B70212077390023A07 +:100060007323003AB7021F19938242307390123AF9 +:10007000B7120F009382A2907390223AB7221E0FFC +:10008000938202907390323AB70200207390023B41 +:100090007323003B9302F0FF7390123BB7220020C2 +:1000A0007390223BB74200209382F2FF7390323B61 +:1000B000B74200209382F2FF7390423BB742002088 +:1000C0009382F2FF7390523BB72200209382F2FF9B +:1000D0007390623BB76200209382F2FF7390723B91 +:1000E000B7020D207390823BB7020E207390923BB3 +:1000F0009302F0FF7390A23B930200007390B23B17 +:10010000930200007390C23B930200007390D23BB5 +:10011000930200007390E23B930200007390F23B65 +:100120003701C1001301E1FE23A02000232022009B +:1001300083A100006318312893010000832102008D +:1001400063123128130E1000170F0000130FCF2772 +:10015000B7129207938282807390023A7323003A17 +:1001600063926226B780008037C1ADDE1301F1EEE5 +:1001700023A02000170F0000130F0F0183A1000020 +:100180006F004024130E2000170F0000130FCF2321 +:10019000B70212077390023A7323003A6384622213 +:1001A000B74200209382F2FF7350303B7323303B01 +:1001B000631A032063886220B72200207350203B1B +:1001C0007323203B63000320639E621EB780008080 +:1001D00037C1ADDE1301F1EE23A02000170F0000A0 +:1001E000130F0F0183A100006F00C01D130E30001C +:1001F000170F0000130F4F1DB702FF0073A0323B13 +:100200007323303B6390621C9302F00F73A0323B68 +:100210007323303BB702FF009382F20F6394621A9C +:10022000B702FF0073B0323B7323303B9302F00FF1 +:10023000639A6218B702FF009382F20F73B0023A1A +:100240007323003AB7029207639E6216B702FF005B +:100250009382727073A0023A7323003AB702920736 +:100260009382727063906216130E4000170F0000A5 +:10027000130F8F15170100001301010173101134C2 +:1002800073002030130E5000170F0000130FCF1310 +:1002900037C1ADDE1301F1EEB780008023A020004E +:1002A000170F0000130F0F0183A100006F008011D2 +:1002B000130E6000170F0000130F0F1137C1ADDED2 +:1002C0001301F1EEB700008023A0200083A10000FD +:1002D000631A310E130E7000170F0000130FCF0EAC +:1002E000B700048083A10000170F0000130F0F0157 +:1002F00023A030006F00000D130E8000170F0000C8 +:10030000130F8F0C37C1ADDE1301F1EEB70034804F +:10031000938080FF23202200170F0000130F0F018E +:10032000832102006F00000A130E9000170F0000D7 +:10033000130F8F09B7003880938080FF83A10000DE +:10034000170F0000130F0F0123A030006F0080076C +:10035000130EA000170F0000130F4F01930410009D +:100360007350303A6F000006130EA000B7221E0F24 +:10037000938202907323303A63966204130EB000A6 +:10038000170F0000130F4F04930400001701000023 +:10039000130101017310113473002030130EB000EB +:1003A000170F0000130F4F01930410007350A03B70 +:1003B0006F004001130EB0009302F0FF7323A03BC7 +:1003C00063886200370110F0130141F22320C1015C +:0C03D000370110F0130101F2232001009E :040000058000000077 :00000001FF diff --git a/src/test/cpp/raw/pmp/build/pmp.map b/src/test/cpp/raw/pmp/build/pmp.map index 0e76f884..fd0c6b0a 100644 --- a/src/test/cpp/raw/pmp/build/pmp.map +++ b/src/test/cpp/raw/pmp/build/pmp.map @@ -15,19 +15,19 @@ LOAD /opt/riscv/bin/../lib/gcc/riscv64-unknown-elf/8.3.0/../../../../riscv64-unk END GROUP LOAD /opt/riscv/bin/../lib/gcc/riscv64-unknown-elf/8.3.0/rv32i/ilp32/libgcc.a -.crt_section 0x0000000080000000 0x3e4 +.crt_section 0x0000000080000000 0x3dc 0x0000000080000000 . = ALIGN (0x4) *crt.o(.text) - .text 0x0000000080000000 0x3e4 build/src/crt.o + .text 0x0000000080000000 0x3dc build/src/crt.o 0x0000000080000000 _start 0x0000000080000014 trap OUTPUT(build/pmp.elf elf32-littleriscv) -.data 0x00000000800003e4 0x0 - .data 0x00000000800003e4 0x0 build/src/crt.o +.data 0x00000000800003dc 0x0 + .data 0x00000000800003dc 0x0 build/src/crt.o -.bss 0x00000000800003e4 0x0 - .bss 0x00000000800003e4 0x0 build/src/crt.o +.bss 0x00000000800003dc 0x0 + .bss 0x00000000800003dc 0x0 build/src/crt.o .riscv.attributes 0x0000000000000000 0x1a From a5f66623b7d4515c794e2c3dcf79ecfd091d6def Mon Sep 17 00:00:00 2001 From: Samuel Lindemer Date: Wed, 26 May 2021 16:34:51 +0200 Subject: [PATCH 670/951] Add an "allow" property to individual CSRs --- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 11 +++++------ src/main/scala/vexriscv/plugin/PmpPlugin.scala | 15 +++++++++------ 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index eb538efe..ab8fcb2d 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -344,13 +344,13 @@ case class CsrDuringWrite(doThat :() => Unit) case class CsrDuringRead(doThat :() => Unit) case class CsrDuring(doThat :() => Unit) case class CsrOnRead(doThat : () => Unit) +case class CsrAllow() case class CsrMapping() extends CsrInterface{ val mapping = mutable.LinkedHashMap[Int,ArrayBuffer[Any]]() val always = ArrayBuffer[Any]() val readDataSignal, readDataInit, writeDataSignal = Bits(32 bits) - val allowCsrSignal = False val hazardFree = Bool() readDataSignal := readDataInit @@ -368,7 +368,7 @@ case class CsrMapping() extends CsrInterface{ override def duringAnyRead(body: => Unit) : Unit = always += CsrDuringWrite(() => body) override def readData() = readDataSignal override def writeData() = writeDataSignal - override def allowCsr() = allowCsrSignal := True + override def allow(csrAddress: Int): Unit = addMappingAt(csrAddress, CsrAllow()) override def isHazardFree() = hazardFree } @@ -386,9 +386,9 @@ trait CsrInterface{ r(csrAddress,bitOffset,that) w(csrAddress,bitOffset,that) } + def allow(csrAddress: Int): Unit def duringAnyWrite(body: => Unit) : Unit //Called all the durration of a Csr write instruction in the execute stage def duringAnyRead(body: => Unit) : Unit //same than above for read - def allowCsr() : Unit //In case your csr do not use the regular API with csrAddress but is implemented using "side channels", you can call that if the current csr is implemented def isHazardFree() : Bool // You should not have any side effect nor use readData() until this return True def r2w(csrAddress : Int, bitOffset : Int,that : Data): Unit @@ -517,7 +517,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep override def duringAny(): Bool = pipeline.execute.arbitration.isValid && pipeline.execute.input(IS_CSR) override def duringAnyWrite(body: => Unit) = csrMapping.duringAnyWrite(body) override def duringAnyRead(body: => Unit) = csrMapping.duringAnyRead(body) - override def allowCsr() = csrMapping.allowCsr() + override def allow(csrAddress: Int): Unit = csrMapping.allow(csrAddress) override def readData() = csrMapping.readData() override def writeData() = csrMapping.writeData() override def isHazardFree() = csrMapping.isHazardFree() @@ -1181,6 +1181,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep } else { if (withWrite) illegalAccess.clearWhen(input(CSR_WRITE_OPCODE)) if (withRead) illegalAccess.clearWhen(input(CSR_READ_OPCODE)) + if (jobs.exists(j => j.isInstanceOf[CsrAllow])) illegalAccess := False } @@ -1266,8 +1267,6 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep case element : CsrDuringRead => when(readInstruction){element.doThat()} } - illegalAccess clearWhen(csrMapping.allowCsrSignal) - when(privilege < csrAddress(9 downto 8).asUInt){ illegalAccess := True readInstruction := False diff --git a/src/main/scala/vexriscv/plugin/PmpPlugin.scala b/src/main/scala/vexriscv/plugin/PmpPlugin.scala index efd1a527..1e974a22 100644 --- a/src/main/scala/vexriscv/plugin/PmpPlugin.scala +++ b/src/main/scala/vexriscv/plugin/PmpPlugin.scala @@ -178,13 +178,16 @@ class PmpPlugin(regions : Int, granularity : Int, ioRange : UInt => Bool) extend val writeData = csrService.writeData() val enable = RegInit(False) - for (i <- 0 until regions) { - csrService.onRead(0x3b0 + i) {csrService.readData().assignFromBits(cfgRegister(pmpSelect)) } - csrService.onWrite(0x3b0 + i) { enable := True } + for (i <- 0 until regions) csrService.allow(0x3b0 + i) + for (i <- 0 until (regions / 4)) csrService.allow(0x3a0 + i) + + csrService.duringAnyRead { + when (input(PMPCFG)) { csrService.readData().assignFromBits(cfgRegister(pmpSelect)) } + when (input(PMPADDR)) { csrService.readData() := pmpaddr.readAsync(pmpIndex).asBits } } - for (i <- 0 until (regions / 4)) { - csrService.onRead(0x3a0 + i) { csrService.readData() := pmpaddr.readAsync(pmpIndex).asBits } - csrService.onWrite(0x3a0 + i) { enable := True } + + csrService.duringAnyWrite { + when (input(PMPCFG) | input(PMPADDR)) { enable := True } } val writer = new Area { From 4b0763b43d87e7e7ec8bfa6a9cb79280f92e11db Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 27 May 2021 10:40:55 +0200 Subject: [PATCH 671/951] CsrPlugin.csrMapping now give names to inner signals --- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index a9619383..413c6c4f 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -346,7 +346,7 @@ case class CsrDuring(doThat :() => Unit) case class CsrOnRead(doThat : () => Unit) -case class CsrMapping() extends CsrInterface{ +case class CsrMapping() extends Area with CsrInterface { val mapping = mutable.LinkedHashMap[Int,ArrayBuffer[Any]]() val always = ArrayBuffer[Any]() val readDataSignal, readDataInit, writeDataSignal = Bits(32 bits) From 6471014131daaf90743fb4f838ed1bff88d1789d Mon Sep 17 00:00:00 2001 From: Samuel Lindemer Date: Thu, 27 May 2021 14:34:51 +0200 Subject: [PATCH 672/951] Simplify pmpcfg encoding --- .../scala/vexriscv/plugin/CsrPlugin.scala | 2 + .../scala/vexriscv/plugin/PmpPlugin.scala | 144 ++++++++++-------- 2 files changed, 86 insertions(+), 60 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index ab8fcb2d..471ffe3e 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -1147,6 +1147,8 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep val readEnable = readInstruction && !arbitration.isStuck csrMapping.hazardFree := !blockedBySideEffects + val READDATASIGNAL = csrMapping.readDataSignal + val readToWriteData = CombInit(readData) writeData := (if(noCsrAlu) writeSrc else input(INSTRUCTION)(13).mux( False -> writeSrc, diff --git a/src/main/scala/vexriscv/plugin/PmpPlugin.scala b/src/main/scala/vexriscv/plugin/PmpPlugin.scala index 1e974a22..e10a92a9 100644 --- a/src/main/scala/vexriscv/plugin/PmpPlugin.scala +++ b/src/main/scala/vexriscv/plugin/PmpPlugin.scala @@ -11,6 +11,7 @@ import vexriscv.plugin.MemoryTranslatorPort.{_} import spinal.core._ import spinal.lib._ import spinal.lib.fsm._ +import javax.net.ssl.TrustManager /* Each 32-bit pmpcfg# register contains four 8-bit configuration sections. * These section numbers contain flags which apply to regions defined by the @@ -121,20 +122,17 @@ class PmpPlugin(regions : Int, granularity : Int, ioRange : UInt => Bool) extend val privilegeService = pipeline.service(classOf[PrivilegeService]) val pmpaddr = Mem(UInt(xlen bits), regions) - val pmpcfg = Reg(Bits(8 * regions bits)) init(0) - val base, mask = Mem(UInt(xlen - grain bits), regions) - val cfgRegion = pmpcfg.subdivideIn(8 bits) - val cfgRegister = pmpcfg.subdivideIn(xlen bits) - val lockMask = Reg(Bits(4 bits)) init(B"4'0") + val pmpcfg = Vector.fill(regions)(Reg(Bits(8 bits)) init(0)) + val base, mask = Vector.fill(regions)(Reg(UInt(xlen - grain bits))) - object PMPCFG extends Stageable(Bool) - object PMPADDR extends Stageable(Bool) + // object PMPCFG extends Stageable(Bool) + // object PMPADDR extends Stageable(Bool) - decode plug new Area { - import decode._ - insert(PMPCFG) := input(INSTRUCTION)(31 downto 24) === 0x3a - insert(PMPADDR) := input(INSTRUCTION)(31 downto 24) === 0x3b - } + // decode plug new Area { + // import decode._ + // insert(PMPCFG) := input(INSTRUCTION)(31 downto 24) === 0x3a + // insert(PMPADDR) := input(INSTRUCTION)(31 downto 24) === 0x3b + // } execute plug new Area { import execute._ @@ -171,64 +169,91 @@ class PmpPlugin(regions : Int, granularity : Int, ioRange : UInt => Bool) extend val base13 = base(U"4'xd") val base14 = base(U"4'xe") val base15 = base(U"4'xf") + val pmpcfg0 = pmpcfg(0) + val pmpcfg1 = pmpcfg(1) + val pmpcfg2 = pmpcfg(2) + val pmpcfg3 = pmpcfg(3) + val pmpcfg4 = pmpcfg(4) + val pmpcfg5 = pmpcfg(5) + val pmpcfg6 = pmpcfg(6) + val pmpcfg7 = pmpcfg(7) + val pmpcfg8 = pmpcfg(8) + val pmpcfg9 = pmpcfg(9) + val pmpcfg10 = pmpcfg(10) + val pmpcfg11 = pmpcfg(11) + val pmpcfg12 = pmpcfg(12) + val pmpcfg13 = pmpcfg(13) + val pmpcfg14 = pmpcfg(14) + val pmpcfg15 = pmpcfg(15) val csrAddress = input(INSTRUCTION)(csrRange) val pmpIndex = csrAddress(log2Up(regions) - 1 downto 0).asUInt + val pmpIndexReg = Reg(UInt(log2Up(regions) bits)) val pmpSelect = pmpIndex(log2Up(regions) - 3 downto 0) - val writeData = csrService.writeData() - - val enable = RegInit(False) - for (i <- 0 until regions) csrService.allow(0x3b0 + i) - for (i <- 0 until (regions / 4)) csrService.allow(0x3a0 + i) + val pmpSelectReg = Reg(UInt(log2Up(regions) - 2 bits)) + val pmpAccessCfg = RegInit(False) + val pmpAccessAddr = RegInit(False) + val writeData = Reg(Bits(xlen bits)) + val pending = RegInit(False) + val hazardFree = csrService.isHazardFree() - csrService.duringAnyRead { - when (input(PMPCFG)) { csrService.readData().assignFromBits(cfgRegister(pmpSelect)) } - when (input(PMPADDR)) { csrService.readData() := pmpaddr.readAsync(pmpIndex).asBits } + def reconfigure() = { + pending := True + writeData := csrService.writeData() + pmpIndexReg := pmpIndex + pmpSelectReg := pmpSelect + pmpAccessCfg := input(INSTRUCTION)(31 downto 24) === 0x3a + pmpAccessAddr := input(INSTRUCTION)(31 downto 24) === 0x3b } - csrService.duringAnyWrite { - when (input(PMPCFG) | input(PMPADDR)) { enable := True } + for (i <- 0 until regions) { + csrService.onRead(0x3b0 + i) { + csrService.readData() := pmpaddr.readAsync(pmpIndex).asBits + } + csrService.onWrite(0x3b0 + i) { reconfigure() } + } + for (i <- 0 until (regions / 4)) { + csrService.onRead(0x3a0 + i) { + csrService.readData() := pmpcfg(i * 4 + 3) ## pmpcfg(i * 4 + 2) ## pmpcfg(i * 4 + 1) ## pmpcfg(i * 4) + } + csrService.onWrite(0x3a0 + i) { reconfigure() } } val writer = new Area { - when (enable & csrService.isHazardFree()) { - when (input(PMPCFG)) { - switch(pmpSelect) { - for (i <- 0 until (regions / 4)) { - is(i) { - for (j <- Range(0, xlen, 8)) { - val bitRange = j + xlen * i + lBit downto j + xlen * i - val overwrite = writeData.subdivideIn(8 bits)(j / 8) - val locked = cfgRegister(i).subdivideIn(8 bits)(j / 8)(lBit) - lockMask(j / 8) := locked - when (~locked) { - pmpcfg(bitRange).assignFromBits(overwrite) - } - } - } + when (pending) { + arbitration.haltItself := True + when (hazardFree & pmpAccessCfg) { + val overwrite = writeData.subdivideIn(8 bits) + for (i <- 0 until 4) { + when (~pmpcfg(pmpSelectReg @@ U(i, 2 bits))(lBit)) { + pmpcfg(pmpSelectReg @@ U(i, 2 bits)).assignFromBits(overwrite(i)) } } } } - val locked = cfgRegion(pmpIndex)(lBit) - pmpaddr.write(pmpIndex, writeData.asUInt, ~locked & input(PMPADDR) & enable & csrService.isHazardFree()) + val locked = pmpcfg(pmpIndex)(lBit) + pmpaddr.write(pmpIndex, writeData.asUInt, ~locked & pmpAccessAddr & pending & hazardFree) } val controller = new StateMachine { + val enable = RegInit(False) val counter = Reg(UInt(log2Up(regions) bits)) init(0) val stateIdle : State = new State with EntryPoint { onEntry { - lockMask := B"4'x0" enable := False counter := 0 } - onExit (arbitration.haltItself := True) + onExit { + enable := True + pending := False + arbitration.haltItself := True + } whenIsActive { - when (enable & csrService.isHazardFree()) { - when (input(PMPCFG)) { + when (pending & hazardFree) { + when (pmpAccessCfg) { goto(stateCfg) - }.elsewhen (input(PMPADDR)) { + }.elsewhen (pmpAccessAddr) { goto(stateAddr) } } @@ -236,7 +261,7 @@ class PmpPlugin(regions : Int, granularity : Int, ioRange : UInt => Bool) extend } val stateCfg : State = new State { - onEntry (counter := pmpIndex(log2Up(regions) - 3 downto 0) @@ U"2'00") + onEntry (counter := pmpSelectReg @@ U(0, 2 bits)) whenIsActive { counter := counter + 1 when (counter(1 downto 0) === 3) { @@ -248,23 +273,17 @@ class PmpPlugin(regions : Int, granularity : Int, ioRange : UInt => Bool) extend } val stateAddr : State = new State { - onEntry (counter := pmpIndex) + onEntry (counter := pmpIndexReg) whenIsActive (goto(stateIdle)) } - when (input(PMPCFG)) { - setter.io.addr := pmpaddr(counter) + when (pmpAccessAddr) { + setter.io.addr := writeData.asUInt } otherwise { - when (counter === pmpIndex) { - setter.io.addr := writeData.asUInt - } otherwise { - setter.io.addr := pmpaddr(counter) - } + setter.io.addr := pmpaddr.readAsync(counter) } - when (enable & csrService.isHazardFree() & - ((input(PMPCFG) & ~lockMask(counter(1 downto 0))) | - (input(PMPADDR) & ~cfgRegion(counter)(lBit)))) { + when (enable & ~pmpcfg(counter)(lBit)) { base(counter) := setter.io.base mask(counter) := setter.io.mask } @@ -272,13 +291,18 @@ class PmpPlugin(regions : Int, granularity : Int, ioRange : UInt => Bool) extend } pipeline plug new Area { + def getHits(address : UInt) = { (0 until regions).map(i => ((address & mask(U(i, log2Up(regions) bits))) === base(U(i, log2Up(regions) bits))) & - (cfgRegion(i)(lBit) | ~privilegeService.isMachine()) & cfgRegion(i)(aBits) === NAPOT + (pmpcfg(i)(lBit) | ~privilegeService.isMachine()) & pmpcfg(i)(aBits) === NAPOT ) } + def getPermission(hits : IndexedSeq[Bool], bit : Int) = { + (hits zip pmpcfg).map({ case (i, cfg) => i & cfg(bit) }).orR + } + val dGuard = new Area { val address = dPort.bus.cmd(0).virtualAddress dPort.bus.rsp.physicalAddress := address @@ -295,8 +319,8 @@ class PmpPlugin(regions : Int, granularity : Int, ioRange : UInt => Bool) extend dPort.bus.rsp.allowRead := privilegeService.isMachine() dPort.bus.rsp.allowWrite := privilegeService.isMachine() } otherwise { - dPort.bus.rsp.allowRead := (hits zip cfgRegion).map({ case (i, cfg) => i & cfg(rBit) }).orR - dPort.bus.rsp.allowWrite := (hits zip cfgRegion).map({ case (i, cfg) => i & cfg(wBit) }).orR + dPort.bus.rsp.allowRead := getPermission(hits, rBit) + dPort.bus.rsp.allowWrite := getPermission(hits, wBit) } } @@ -316,7 +340,7 @@ class PmpPlugin(regions : Int, granularity : Int, ioRange : UInt => Bool) extend when(~hits.orR) { iPort.bus.rsp.allowExecute := privilegeService.isMachine() } otherwise { - iPort.bus.rsp.allowExecute := (hits zip cfgRegion).map({ case (i, cfg) => i & cfg(xBit) }).orR + iPort.bus.rsp.allowExecute := getPermission(hits, xBit) } } } From 4a2dc0ff5f69894bd6daae67ea1385e5674fa5cd Mon Sep 17 00:00:00 2001 From: Samuel Lindemer Date: Thu, 27 May 2021 15:50:45 +0200 Subject: [PATCH 673/951] Fix granularity control --- .../scala/vexriscv/plugin/CsrPlugin.scala | 25 ++++++----- .../scala/vexriscv/plugin/PmpPlugin.scala | 19 ++++---- src/test/cpp/raw/pmp/src/crt.S | 43 +++++++++---------- 3 files changed, 42 insertions(+), 45 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 471ffe3e..f8d944a8 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -344,13 +344,13 @@ case class CsrDuringWrite(doThat :() => Unit) case class CsrDuringRead(doThat :() => Unit) case class CsrDuring(doThat :() => Unit) case class CsrOnRead(doThat : () => Unit) -case class CsrAllow() -case class CsrMapping() extends CsrInterface{ +case class CsrMapping() extends Area with CsrInterface { val mapping = mutable.LinkedHashMap[Int,ArrayBuffer[Any]]() val always = ArrayBuffer[Any]() val readDataSignal, readDataInit, writeDataSignal = Bits(32 bits) + val allowCsrSignal = False val hazardFree = Bool() readDataSignal := readDataInit @@ -364,11 +364,11 @@ case class CsrMapping() extends CsrInterface{ override def during(csrAddress: Int)(body: => Unit): Unit = addMappingAt(csrAddress, CsrDuring(() => body)) override def onRead(csrAddress: Int)(body: => Unit): Unit = addMappingAt(csrAddress, CsrOnRead(() => {body})) override def duringAny(): Bool = ??? - override def duringAnyWrite(body: => Unit) : Unit = always += CsrDuringRead(() => body) - override def duringAnyRead(body: => Unit) : Unit = always += CsrDuringWrite(() => body) + override def duringAnyRead(body: => Unit) : Unit = always += CsrDuringRead(() => body) + override def duringAnyWrite(body: => Unit) : Unit = always += CsrDuringWrite(() => body) override def readData() = readDataSignal override def writeData() = writeDataSignal - override def allow(csrAddress: Int): Unit = addMappingAt(csrAddress, CsrAllow()) + override def allowCsr() = allowCsrSignal := True override def isHazardFree() = hazardFree } @@ -386,9 +386,9 @@ trait CsrInterface{ r(csrAddress,bitOffset,that) w(csrAddress,bitOffset,that) } - def allow(csrAddress: Int): Unit - def duringAnyWrite(body: => Unit) : Unit //Called all the durration of a Csr write instruction in the execute stage - def duringAnyRead(body: => Unit) : Unit //same than above for read + def duringAnyRead(body: => Unit) : Unit //Called all the durration of a Csr write instruction in the execute stage + def duringAnyWrite(body: => Unit) : Unit //same than above for read + def allowCsr() : Unit //In case your csr do not use the regular API with csrAddress but is implemented using "side channels", you can call that if the current csr is implemented def isHazardFree() : Bool // You should not have any side effect nor use readData() until this return True def r2w(csrAddress : Int, bitOffset : Int,that : Data): Unit @@ -515,9 +515,9 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep override def duringRead(csrAddress: Int)(body: => Unit): Unit = csrMapping.duringRead(csrAddress)(body) override def during(csrAddress: Int)(body: => Unit): Unit = csrMapping.during(csrAddress)(body) override def duringAny(): Bool = pipeline.execute.arbitration.isValid && pipeline.execute.input(IS_CSR) - override def duringAnyWrite(body: => Unit) = csrMapping.duringAnyWrite(body) override def duringAnyRead(body: => Unit) = csrMapping.duringAnyRead(body) - override def allow(csrAddress: Int): Unit = csrMapping.allow(csrAddress) + override def duringAnyWrite(body: => Unit) = csrMapping.duringAnyWrite(body) + override def allowCsr() = csrMapping.allowCsr() override def readData() = csrMapping.readData() override def writeData() = csrMapping.writeData() override def isHazardFree() = csrMapping.isHazardFree() @@ -1147,8 +1147,6 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep val readEnable = readInstruction && !arbitration.isStuck csrMapping.hazardFree := !blockedBySideEffects - val READDATASIGNAL = csrMapping.readDataSignal - val readToWriteData = CombInit(readData) writeData := (if(noCsrAlu) writeSrc else input(INSTRUCTION)(13).mux( False -> writeSrc, @@ -1183,7 +1181,6 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep } else { if (withWrite) illegalAccess.clearWhen(input(CSR_WRITE_OPCODE)) if (withRead) illegalAccess.clearWhen(input(CSR_READ_OPCODE)) - if (jobs.exists(j => j.isInstanceOf[CsrAllow])) illegalAccess := False } @@ -1269,6 +1266,8 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep case element : CsrDuringRead => when(readInstruction){element.doThat()} } + illegalAccess clearWhen(csrMapping.allowCsrSignal) + when(privilege < csrAddress(9 downto 8).asUInt){ illegalAccess := True readInstruction := False diff --git a/src/main/scala/vexriscv/plugin/PmpPlugin.scala b/src/main/scala/vexriscv/plugin/PmpPlugin.scala index e10a92a9..e6c94ea5 100644 --- a/src/main/scala/vexriscv/plugin/PmpPlugin.scala +++ b/src/main/scala/vexriscv/plugin/PmpPlugin.scala @@ -11,7 +11,6 @@ import vexriscv.plugin.MemoryTranslatorPort.{_} import spinal.core._ import spinal.lib._ import spinal.lib.fsm._ -import javax.net.ssl.TrustManager /* Each 32-bit pmpcfg# register contains four 8-bit configuration sections. * These section numbers contain flags which apply to regions defined by the @@ -79,15 +78,15 @@ trait Pmp { def lBit = 7 } -class PmpSetter(grain : Int) extends Component with Pmp { +class PmpSetter(cutoff : Int) extends Component with Pmp { val io = new Bundle { val addr = in UInt(xlen bits) - val base, mask = out UInt(xlen - grain bits) + val base, mask = out UInt(xlen - cutoff bits) } val ones = io.addr & ~(io.addr + 1) - io.base := io.addr(xlen - 1 - grain downto 0) ^ ones(xlen - 1 - grain downto 0) - io.mask := ~ones(xlen - grain downto 1) + io.base := io.addr(xlen - 3 downto cutoff - 2) ^ ones(xlen - 3 downto cutoff - 2) + io.mask := ~ones(xlen - 2 downto cutoff - 1) } case class ProtectedMemoryTranslatorPort(bus : MemoryTranslatorBus) @@ -98,7 +97,7 @@ class PmpPlugin(regions : Int, granularity : Int, ioRange : UInt => Bool) extend var setter : PmpSetter = null var dPort, iPort : ProtectedMemoryTranslatorPort = null - val grain = log2Up(granularity) - 1 + val cutoff = log2Up(granularity) - 1 override def newTranslationPort(priority : Int, args : Any): MemoryTranslatorBus = { val port = ProtectedMemoryTranslatorPort(MemoryTranslatorBus(new MemoryTranslatorBusParameter(0, 0))) @@ -110,7 +109,7 @@ class PmpPlugin(regions : Int, granularity : Int, ioRange : UInt => Bool) extend } override def setup(pipeline: VexRiscv): Unit = { - setter = new PmpSetter(grain) + setter = new PmpSetter(cutoff) } override def build(pipeline: VexRiscv): Unit = { @@ -123,7 +122,7 @@ class PmpPlugin(regions : Int, granularity : Int, ioRange : UInt => Bool) extend val pmpaddr = Mem(UInt(xlen bits), regions) val pmpcfg = Vector.fill(regions)(Reg(Bits(8 bits)) init(0)) - val base, mask = Vector.fill(regions)(Reg(UInt(xlen - grain bits))) + val base, mask = Vector.fill(regions)(Reg(UInt(xlen - cutoff bits))) // object PMPCFG extends Stageable(Bool) // object PMPADDR extends Stageable(Bool) @@ -313,7 +312,7 @@ class PmpPlugin(regions : Int, granularity : Int, ioRange : UInt => Bool) extend dPort.bus.rsp.allowExecute := False dPort.bus.busy := False - val hits = getHits(address(31 downto grain)) + val hits = getHits(address(31 downto cutoff)) when(~hits.orR) { dPort.bus.rsp.allowRead := privilegeService.isMachine() @@ -335,7 +334,7 @@ class PmpPlugin(regions : Int, granularity : Int, ioRange : UInt => Bool) extend iPort.bus.rsp.allowWrite := False iPort.bus.busy := False - val hits = getHits(address(31 downto grain)) + val hits = getHits(address(31 downto cutoff)) when(~hits.orR) { iPort.bus.rsp.allowExecute := privilegeService.isMachine() diff --git a/src/test/cpp/raw/pmp/src/crt.S b/src/test/cpp/raw/pmp/src/crt.S index a03e76c5..3dd75ff2 100644 --- a/src/test/cpp/raw/pmp/src/crt.S +++ b/src/test/cpp/raw/pmp/src/crt.S @@ -8,15 +8,15 @@ #define TRAP_RETURN x30 #define TRAP_EXIT x9 -#define PMPCFG0 0x07120000 -#define PMPCFG0_ 0x07920808 +#define PMPCFG0 0x071a0000 +#define PMPCFG0_ 0x079a0808 #define PMPCFG1 0x191f0304 #define PMPCFG2 0x000f090a -#define PMPCFG3 0x0f1e1900 +#define PMPCFG3 0x1c1e1900 #define PMPADDR0 0x20000000 // OFF (test0) -> TOR (test1) -> OFF (test2) #define PMPADDR1 0xffffffff // OFF (test0) -> TOR (test1) -> OFF (test2) -#define PMPADDR2 0x20002000 // NA4 W +#define PMPADDR2 0x20200000 // NAPOT W #define PMPADDR3 0x20003fff // OFF RWX -> 0x00000000 OFF RWX (test2) #define PMPADDR4 0x20003fff // OFF X #define PMPADDR5 0x20003fff // OFF RW @@ -29,7 +29,7 @@ #define PMPADDR12 0x00000000 // OFF #define PMPADDR13 0x00000000 // NAPOT R #define PMPADDR14 0x00000000 // NAPOT WX -#define PMPADDR15 0x00000000 // TOR RWX +#define PMPADDR15 0x000001ff // NAPOT X .global _start _start: @@ -71,6 +71,8 @@ test0: csrw pmpcfg1, x5 li x5, PMPCFG2 csrw pmpcfg2, x5 + csrr x6, pmpcfg2 + bne x5, x6, fail li x5, PMPCFG3 csrw pmpcfg3, x5 li x5, PMPADDR0 @@ -125,11 +127,11 @@ test1: csrw pmpcfg0, x5 // lock region 2 csrr x6, pmpcfg0 bne x5, x6, fail - li x1, 0x80008000 + li x1, 0x80800000 li x2, 0xdeadbeef - sw x2, 0x0(x1) // should be OK (write 0x80008000) + sw x2, 0x0(x1) // should be OK (write 0x80800000) la TRAP_RETURN, test2 - lw x3, 0x0(x1) // should fault (read 0x80008000) + lw x3, 0x0(x1) // should fault (read 0x80800000) j fail // "unlock" region 2, attempt read/write from machine mode @@ -140,21 +142,17 @@ test2: csrw pmpcfg0, x5 // "unlock" region 2 csrr x6, pmpcfg0 beq x5, x6, fail - li x5, PMPADDR3 csrwi pmpaddr3, 0x0 csrr x6, pmpaddr3 - bnez x6, fail - beq x5, x6, fail - li x5, PMPADDR2 + bnez x6, fail csrwi pmpaddr2, 0x0 csrr x6, pmpaddr2 - beqz x6, fail - bne x5, x6, fail - li x1, 0x80008000 + beqz x6, fail + li x1, 0x80800000 li x2, 0xdeadbeef - sw x2, 0x0(x1) // should still be OK (write 0x80008000) + sw x2, 0x0(x1) // should still be OK (write 0x80800000) la TRAP_RETURN, test3 - lw x3, 0x0(x1) // should still fault (read 0x80008000) + lw x3, 0x0(x1) // should still fault (read 0x80800000) j fail // verify masked CSR read/write operations @@ -178,12 +176,12 @@ test3: li x5, 0x00ff00ff csrc pmpcfg0, x5 csrr x6, pmpcfg0 - li x5, 0x07920000 + li x5, 0x079a0000 bne x5, x6, fail li x5, 0x00ff0707 csrs pmpcfg0, x5 csrr x6, pmpcfg0 - li x5, 0x07920707 + li x5, 0x079a0707 bne x5, x6, fail // jump into user mode @@ -192,6 +190,7 @@ test4: la TRAP_RETURN, fail la x2, test5 csrw mepc, x2 + # j pass mret // attempt to read/write region 2 from user mode @@ -199,10 +198,10 @@ test5: li TEST_ID, 5 la TRAP_RETURN, fail li x2, 0xdeadbeef - li x1, 0x80008000 - sw x2, 0x0(x1) // should be OK (write 0x80008000) + li x1, 0x80800000 + sw x2, 0x0(x1) // should be OK (write 0x80800000) la TRAP_RETURN, test6 - lw x3, 0x0(x1) // should fault (read 0x80008000) + lw x3, 0x0(x1) // should fault (read 0x80800000) j fail // attempt to read/write other regions from user mode From 4490254d3d7b7c84a61596bf8f73864829342abe Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 28 May 2021 13:35:52 +0200 Subject: [PATCH 674/951] Csr/Mmu ensure implement that SFENCE_VMA flush the next instructions SAT flush reworked a bit too --- .../scala/vexriscv/plugin/CsrPlugin.scala | 19 +++++++++++++++++-- .../scala/vexriscv/plugin/MmuPlugin.scala | 19 +++++++++---------- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 413c6c4f..badb18fb 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -474,6 +474,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep object ENV_CTRL extends Stageable(EnvCtrlEnum()) object IS_CSR extends Stageable(Bool) + object IS_SFENCE_VMA extends Stageable(Bool) object CSR_WRITE_OPCODE extends Stageable(Bool) object CSR_READ_OPCODE extends Stageable(Bool) object PIPELINED_CSR_READ extends Stageable(Bits(32 bits)) @@ -606,6 +607,11 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep if(withExternalMhartid) externalMhartId = in UInt(mhartidWidth bits) if(utimeAccess != CsrAccess.NONE) utime = in UInt(64 bits) setName("utime") + + if(supervisorGen) { + decoderService.addDefault(IS_SFENCE_VMA, False) + decoderService.add(SFENCE_VMA, List(IS_SFENCE_VMA -> True)) + } } def inhibateInterrupts() : Unit = allowInterrupts := False @@ -783,10 +789,15 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep satpAccess(CSR.SATP, 31 -> satp.MODE, 22 -> satp.ASID, 0 -> satp.PPN) - val satpLogic = supervisorGen generate new Area { + val rescheduleLogic = supervisorGen generate new Area { redoInterface.valid := False redoInterface.payload := decode.input(PC) - duringWrite(CSR.SATP) { + + val rescheduleNext = False + when(execute.arbitration.isValid && execute.input(IS_SFENCE_VMA)) { rescheduleNext := True } + duringWrite(CSR.SATP) { rescheduleNext := True } + + when(rescheduleNext){ redoInterface.valid := True execute.arbitration.flushNext := True decode.arbitration.haltByOther := True @@ -1155,8 +1166,12 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep when(arbitration.isValid && input(IS_CSR)) { if(!pipelineCsrRead) output(REGFILE_WRITE_DATA) := readData + } + + when(arbitration.isValid && (input(IS_CSR) || (if(supervisorGen) input(IS_SFENCE_VMA) else False))) { arbitration.haltItself setWhen(blockedBySideEffects) } + if(pipelineCsrRead){ insert(PIPELINED_CSR_READ) := readData when(memory.arbitration.isValid && memory.input(IS_CSR)) { diff --git a/src/main/scala/vexriscv/plugin/MmuPlugin.scala b/src/main/scala/vexriscv/plugin/MmuPlugin.scala index 3f6635e8..093f59ad 100644 --- a/src/main/scala/vexriscv/plugin/MmuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/MmuPlugin.scala @@ -53,13 +53,13 @@ class MmuPlugin(ioRange : UInt => Bool, port.bus } - object IS_SFENCE_VMA extends Stageable(Bool) + object IS_SFENCE_VMA2 extends Stageable(Bool) override def setup(pipeline: VexRiscv): Unit = { import Riscv._ import pipeline.config._ val decoderService = pipeline.service(classOf[DecoderService]) - decoderService.addDefault(IS_SFENCE_VMA, False) - decoderService.add(SFENCE_VMA, List(IS_SFENCE_VMA -> True)) + decoderService.addDefault(IS_SFENCE_VMA2, False) + decoderService.add(SFENCE_VMA, List(IS_SFENCE_VMA2 -> True)) dBusAccess = pipeline.service(classOf[DBusAccessService]).newDBusAccess() @@ -296,18 +296,17 @@ class MmuPlugin(ioRange : UInt => Bool, } } - val fenceStage = stages.last + val fenceStage = execute + + //Both SFENCE_VMA and SATP reschedule the next instruction in the CsrPlugin itself with one extra cycle to ensure side effect propagation. fenceStage plug new Area{ import fenceStage._ - when(arbitration.isValid && input(IS_SFENCE_VMA)){ - for(port <- core.ports; line <- port.cache) line.valid := False //Assume that the instruction already fetched into the pipeline are ok + when(arbitration.isValid && arbitration.isFiring && input(IS_SFENCE_VMA2)){ + for(port <- core.ports; line <- port.cache) line.valid := False } - csrService.duringWrite(CSR.SATP){ + csrService.onWrite(CSR.SATP){ for(port <- core.ports; line <- port.cache) line.valid := False - core.ports.filter(_.handle.args.earlyRequireMmuLockup).foreach{p => - p.dirty := True - } } } } From 24a534acffd4dd5f1758485311437c265c049f67 Mon Sep 17 00:00:00 2001 From: Samuel Lindemer Date: Fri, 28 May 2021 13:54:55 +0200 Subject: [PATCH 675/951] All tests passing on new PMP plugin --- src/main/scala/vexriscv/demo/GenSecure.scala | 2 +- .../scala/vexriscv/plugin/CsrPlugin.scala | 8 + .../scala/vexriscv/plugin/PmpPlugin.scala | 159 +++--- src/test/cpp/raw/pmp/build/pmp.asm | 457 ++++++++---------- src/test/cpp/raw/pmp/build/pmp.elf | Bin 5944 -> 5804 bytes src/test/cpp/raw/pmp/build/pmp.hex | 112 ++--- src/test/cpp/raw/pmp/build/pmp.map | 12 +- src/test/cpp/raw/pmp/src/crt.S | 89 ++-- .../vexriscv/TestIndividualFeatures.scala | 1 + 9 files changed, 379 insertions(+), 461 deletions(-) diff --git a/src/main/scala/vexriscv/demo/GenSecure.scala b/src/main/scala/vexriscv/demo/GenSecure.scala index e4da3ebe..8b2cd556 100644 --- a/src/main/scala/vexriscv/demo/GenSecure.scala +++ b/src/main/scala/vexriscv/demo/GenSecure.scala @@ -41,7 +41,7 @@ object GenSecure extends App { ), new PmpPlugin( regions = 16, - granularity = 256, + granularity = 32, ioRange = _(31 downto 28) === 0xf ), new DecoderSimplePlugin( diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index f8d944a8..9d16dd5b 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -366,6 +366,8 @@ case class CsrMapping() extends Area with CsrInterface { override def duringAny(): Bool = ??? override def duringAnyRead(body: => Unit) : Unit = always += CsrDuringRead(() => body) override def duringAnyWrite(body: => Unit) : Unit = always += CsrDuringWrite(() => body) + override def onAnyRead(body: => Unit) : Unit = always += CsrOnRead(() => body) + override def onAnyWrite(body: => Unit) : Unit = always += CsrOnWrite(() => body) override def readData() = readDataSignal override def writeData() = writeDataSignal override def allowCsr() = allowCsrSignal := True @@ -388,6 +390,8 @@ trait CsrInterface{ } def duringAnyRead(body: => Unit) : Unit //Called all the durration of a Csr write instruction in the execute stage def duringAnyWrite(body: => Unit) : Unit //same than above for read + def onAnyRead(body: => Unit) : Unit + def onAnyWrite(body: => Unit) : Unit def allowCsr() : Unit //In case your csr do not use the regular API with csrAddress but is implemented using "side channels", you can call that if the current csr is implemented def isHazardFree() : Bool // You should not have any side effect nor use readData() until this return True @@ -517,6 +521,8 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep override def duringAny(): Bool = pipeline.execute.arbitration.isValid && pipeline.execute.input(IS_CSR) override def duringAnyRead(body: => Unit) = csrMapping.duringAnyRead(body) override def duringAnyWrite(body: => Unit) = csrMapping.duringAnyWrite(body) + override def onAnyRead(body: => Unit) = csrMapping.onAnyRead(body) + override def onAnyWrite(body: => Unit) = csrMapping.onAnyWrite(body) override def allowCsr() = csrMapping.allowCsr() override def readData() = csrMapping.readData() override def writeData() = csrMapping.writeData() @@ -1264,6 +1270,8 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep csrMapping.always.foreach { case element : CsrDuringWrite => when(writeInstruction){element.doThat()} case element : CsrDuringRead => when(readInstruction){element.doThat()} + case element : CsrOnWrite => when(writeEnable){element.doThat()} + case element : CsrOnRead => when(readEnable){element.doThat()} } illegalAccess clearWhen(csrMapping.allowCsrSignal) diff --git a/src/main/scala/vexriscv/plugin/PmpPlugin.scala b/src/main/scala/vexriscv/plugin/PmpPlugin.scala index e6c94ea5..f9d47eea 100644 --- a/src/main/scala/vexriscv/plugin/PmpPlugin.scala +++ b/src/main/scala/vexriscv/plugin/PmpPlugin.scala @@ -62,6 +62,10 @@ import spinal.lib.fsm._ * * NA4: This is essentially an edge case of NAPOT where the entire pmpaddr# * register defines a 4-byte wide region. + * + * N.B. THIS IMPLEMENTATION ONLY SUPPORTS NAPOT ADDRESSING. REGIONS ARE NOT + * ORDERED BY PRIORITY. A PERMISSION IS GRANTED TO AN ACCESS IF ANY MATCHING + * PMP REGION HAS THAT PERMISSION ENABLED. */ trait Pmp { @@ -124,114 +128,74 @@ class PmpPlugin(regions : Int, granularity : Int, ioRange : UInt => Bool) extend val pmpcfg = Vector.fill(regions)(Reg(Bits(8 bits)) init(0)) val base, mask = Vector.fill(regions)(Reg(UInt(xlen - cutoff bits))) - // object PMPCFG extends Stageable(Bool) - // object PMPADDR extends Stageable(Bool) - - // decode plug new Area { - // import decode._ - // insert(PMPCFG) := input(INSTRUCTION)(31 downto 24) === 0x3a - // insert(PMPADDR) := input(INSTRUCTION)(31 downto 24) === 0x3b - // } + def machineMode : Bool = privilegeService.isMachine() execute plug new Area { import execute._ - val mask0 = mask(U"4'x0") - val mask1 = mask(U"4'x1") - val mask2 = mask(U"4'x2") - val mask3 = mask(U"4'x3") - val mask4 = mask(U"4'x4") - val mask5 = mask(U"4'x5") - val mask6 = mask(U"4'x6") - val mask7 = mask(U"4'x7") - val mask8 = mask(U"4'x8") - val mask9 = mask(U"4'x9") - val mask10 = mask(U"4'xa") - val mask11 = mask(U"4'xb") - val mask12 = mask(U"4'xc") - val mask13 = mask(U"4'xd") - val mask14 = mask(U"4'xe") - val mask15 = mask(U"4'xf") - val base0 = base(U"4'x0") - val base1 = base(U"4'x1") - val base2 = base(U"4'x2") - val base3 = base(U"4'x3") - val base4 = base(U"4'x4") - val base5 = base(U"4'x5") - val base6 = base(U"4'x6") - val base7 = base(U"4'x7") - val base8 = base(U"4'x8") - val base9 = base(U"4'x9") - val base10 = base(U"4'xa") - val base11 = base(U"4'xb") - val base12 = base(U"4'xc") - val base13 = base(U"4'xd") - val base14 = base(U"4'xe") - val base15 = base(U"4'xf") - val pmpcfg0 = pmpcfg(0) - val pmpcfg1 = pmpcfg(1) - val pmpcfg2 = pmpcfg(2) - val pmpcfg3 = pmpcfg(3) - val pmpcfg4 = pmpcfg(4) - val pmpcfg5 = pmpcfg(5) - val pmpcfg6 = pmpcfg(6) - val pmpcfg7 = pmpcfg(7) - val pmpcfg8 = pmpcfg(8) - val pmpcfg9 = pmpcfg(9) - val pmpcfg10 = pmpcfg(10) - val pmpcfg11 = pmpcfg(11) - val pmpcfg12 = pmpcfg(12) - val pmpcfg13 = pmpcfg(13) - val pmpcfg14 = pmpcfg(14) - val pmpcfg15 = pmpcfg(15) - - val csrAddress = input(INSTRUCTION)(csrRange) - val pmpIndex = csrAddress(log2Up(regions) - 1 downto 0).asUInt - val pmpIndexReg = Reg(UInt(log2Up(regions) bits)) - val pmpSelect = pmpIndex(log2Up(regions) - 3 downto 0) - val pmpSelectReg = Reg(UInt(log2Up(regions) - 2 bits)) - val pmpAccessCfg = RegInit(False) - val pmpAccessAddr = RegInit(False) - val writeData = Reg(Bits(xlen bits)) val pending = RegInit(False) val hazardFree = csrService.isHazardFree() - - def reconfigure() = { - pending := True - writeData := csrService.writeData() - pmpIndexReg := pmpIndex - pmpSelectReg := pmpSelect - pmpAccessCfg := input(INSTRUCTION)(31 downto 24) === 0x3a - pmpAccessAddr := input(INSTRUCTION)(31 downto 24) === 0x3b + + val csrAddress = input(INSTRUCTION)(csrRange) + val pmpNcfg = csrAddress(log2Up(regions) - 1 downto 0).asUInt + val pmpcfgN = pmpNcfg(log2Up(regions) - 3 downto 0) + val pmpcfgCsr = input(INSTRUCTION)(31 downto 24) === 0x3a + val pmpaddrCsr = input(INSTRUCTION)(31 downto 24) === 0x3b + + val pmpNcfg_ = Reg(UInt(log2Up(regions) bits)) + val pmpcfgN_ = Reg(UInt(log2Up(regions) - 2 bits)) + val pmpcfgCsr_ = RegInit(False) + val pmpaddrCsr_ = RegInit(False) + val writeData_ = Reg(Bits(xlen bits)) + + csrService.duringAnyRead { + when (machineMode) { + when (pmpcfgCsr) { + csrService.allowCsr() + csrService.readData() := + pmpcfg(pmpcfgN @@ U(3, 2 bits)) ## + pmpcfg(pmpcfgN @@ U(2, 2 bits)) ## + pmpcfg(pmpcfgN @@ U(1, 2 bits)) ## + pmpcfg(pmpcfgN @@ U(0, 2 bits)) + } + when (pmpaddrCsr) { + csrService.allowCsr() + csrService.readData() := pmpaddr.readAsync(pmpNcfg).asBits + } + } } - for (i <- 0 until regions) { - csrService.onRead(0x3b0 + i) { - csrService.readData() := pmpaddr.readAsync(pmpIndex).asBits + csrService.duringAnyWrite { + when ((pmpcfgCsr | pmpaddrCsr) & machineMode) { + csrService.allowCsr() } - csrService.onWrite(0x3b0 + i) { reconfigure() } } - for (i <- 0 until (regions / 4)) { - csrService.onRead(0x3a0 + i) { - csrService.readData() := pmpcfg(i * 4 + 3) ## pmpcfg(i * 4 + 2) ## pmpcfg(i * 4 + 1) ## pmpcfg(i * 4) + + csrService.onAnyWrite { + when ((pmpcfgCsr | pmpaddrCsr) & machineMode) { + pending := True + writeData_ := csrService.writeData() + pmpNcfg_ := pmpNcfg + pmpcfgN_ := pmpcfgN + pmpaddrCsr_ := pmpcfgCsr + pmpcfgCsr_ := pmpaddrCsr } - csrService.onWrite(0x3a0 + i) { reconfigure() } } val writer = new Area { when (pending) { arbitration.haltItself := True - when (hazardFree & pmpAccessCfg) { - val overwrite = writeData.subdivideIn(8 bits) + when (hazardFree & pmpaddrCsr_) { + val overwrite = writeData_.subdivideIn(8 bits) for (i <- 0 until 4) { - when (~pmpcfg(pmpSelectReg @@ U(i, 2 bits))(lBit)) { - pmpcfg(pmpSelectReg @@ U(i, 2 bits)).assignFromBits(overwrite(i)) + when (~pmpcfg(pmpcfgN_ @@ U(i, 2 bits))(lBit)) { + pmpcfg(pmpcfgN_ @@ U(i, 2 bits)).assignFromBits(overwrite(i)) } } } } - val locked = pmpcfg(pmpIndex)(lBit) - pmpaddr.write(pmpIndex, writeData.asUInt, ~locked & pmpAccessAddr & pending & hazardFree) + val locked = pmpcfg(pmpNcfg_)(lBit) + pmpaddr.write(pmpNcfg_, writeData_.asUInt, ~locked & pmpcfgCsr_ & pending & hazardFree) } val controller = new StateMachine { @@ -250,9 +214,9 @@ class PmpPlugin(regions : Int, granularity : Int, ioRange : UInt => Bool) extend } whenIsActive { when (pending & hazardFree) { - when (pmpAccessCfg) { + when (pmpaddrCsr_) { goto(stateCfg) - }.elsewhen (pmpAccessAddr) { + }.elsewhen (pmpcfgCsr_) { goto(stateAddr) } } @@ -260,7 +224,7 @@ class PmpPlugin(regions : Int, granularity : Int, ioRange : UInt => Bool) extend } val stateCfg : State = new State { - onEntry (counter := pmpSelectReg @@ U(0, 2 bits)) + onEntry (counter := pmpcfgN_ @@ U(0, 2 bits)) whenIsActive { counter := counter + 1 when (counter(1 downto 0) === 3) { @@ -272,12 +236,12 @@ class PmpPlugin(regions : Int, granularity : Int, ioRange : UInt => Bool) extend } val stateAddr : State = new State { - onEntry (counter := pmpIndexReg) + onEntry (counter := pmpNcfg_) whenIsActive (goto(stateIdle)) } - when (pmpAccessAddr) { - setter.io.addr := writeData.asUInt + when (pmpcfgCsr_) { + setter.io.addr := writeData_.asUInt } otherwise { setter.io.addr := pmpaddr.readAsync(counter) } @@ -290,11 +254,10 @@ class PmpPlugin(regions : Int, granularity : Int, ioRange : UInt => Bool) extend } pipeline plug new Area { - def getHits(address : UInt) = { (0 until regions).map(i => ((address & mask(U(i, log2Up(regions) bits))) === base(U(i, log2Up(regions) bits))) & - (pmpcfg(i)(lBit) | ~privilegeService.isMachine()) & pmpcfg(i)(aBits) === NAPOT + (pmpcfg(i)(lBit) | ~machineMode) & (pmpcfg(i)(aBits) === NAPOT) ) } @@ -315,8 +278,8 @@ class PmpPlugin(regions : Int, granularity : Int, ioRange : UInt => Bool) extend val hits = getHits(address(31 downto cutoff)) when(~hits.orR) { - dPort.bus.rsp.allowRead := privilegeService.isMachine() - dPort.bus.rsp.allowWrite := privilegeService.isMachine() + dPort.bus.rsp.allowRead := machineMode + dPort.bus.rsp.allowWrite := machineMode } otherwise { dPort.bus.rsp.allowRead := getPermission(hits, rBit) dPort.bus.rsp.allowWrite := getPermission(hits, wBit) @@ -337,7 +300,7 @@ class PmpPlugin(regions : Int, granularity : Int, ioRange : UInt => Bool) extend val hits = getHits(address(31 downto cutoff)) when(~hits.orR) { - iPort.bus.rsp.allowExecute := privilegeService.isMachine() + iPort.bus.rsp.allowExecute := machineMode } otherwise { iPort.bus.rsp.allowExecute := getPermission(hits, xBit) } diff --git a/src/test/cpp/raw/pmp/build/pmp.asm b/src/test/cpp/raw/pmp/build/pmp.asm index 6db26c3b..34ddcbf2 100644 --- a/src/test/cpp/raw/pmp/build/pmp.asm +++ b/src/test/cpp/raw/pmp/build/pmp.asm @@ -22,271 +22,244 @@ Disassembly of section .crt_section: 80000024 : 80000024: 00000e13 li t3,0 80000028: 00000f17 auipc t5,0x0 -8000002c: 39cf0f13 addi t5,t5,924 # 800003c4 +8000002c: 340f0f13 addi t5,t5,832 # 80000368 80000030: 800000b7 lui ra,0x80000 80000034: 80008237 lui tp,0x80008 80000038: deadc137 lui sp,0xdeadc -8000003c: eef10113 addi sp,sp,-273 # deadbeef -80000040: 0020a023 sw sp,0(ra) # 80000000 -80000044: 00222023 sw sp,0(tp) # 80008000 +8000003c: eef10113 addi sp,sp,-273 # deadbeef +80000040: 0020a023 sw sp,0(ra) # 80000000 +80000044: 00222023 sw sp,0(tp) # 80008000 80000048: 0000a183 lw gp,0(ra) -8000004c: 36311c63 bne sp,gp,800003c4 +8000004c: 30311e63 bne sp,gp,80000368 80000050: 00022183 lw gp,0(tp) # 0 <_start-0x80000000> -80000054: 36311863 bne sp,gp,800003c4 -80000058: 071202b7 lui t0,0x7120 +80000054: 30311a63 bne sp,gp,80000368 +80000058: 071a02b7 lui t0,0x71a0 8000005c: 3a029073 csrw pmpcfg0,t0 80000060: 3a002373 csrr t1,pmpcfg0 -80000064: 191f02b7 lui t0,0x191f0 -80000068: 30428293 addi t0,t0,772 # 191f0304 <_start-0x66e0fcfc> -8000006c: 3a129073 csrw pmpcfg1,t0 -80000070: 000f12b7 lui t0,0xf1 -80000074: 90a28293 addi t0,t0,-1782 # f090a <_start-0x7ff0f6f6> -80000078: 3a229073 csrw pmpcfg2,t0 -8000007c: 0f1e22b7 lui t0,0xf1e2 -80000080: 90028293 addi t0,t0,-1792 # f1e1900 <_start-0x70e1e700> -80000084: 3a329073 csrw pmpcfg3,t0 -80000088: 200002b7 lui t0,0x20000 -8000008c: 3b029073 csrw pmpaddr0,t0 -80000090: 3b002373 csrr t1,pmpaddr0 -80000094: fff00293 li t0,-1 -80000098: 3b129073 csrw pmpaddr1,t0 -8000009c: 200022b7 lui t0,0x20002 -800000a0: 3b229073 csrw pmpaddr2,t0 -800000a4: 200042b7 lui t0,0x20004 -800000a8: fff28293 addi t0,t0,-1 # 20003fff <_start-0x5fffc001> -800000ac: 3b329073 csrw pmpaddr3,t0 -800000b0: 200042b7 lui t0,0x20004 -800000b4: fff28293 addi t0,t0,-1 # 20003fff <_start-0x5fffc001> -800000b8: 3b429073 csrw pmpaddr4,t0 -800000bc: 200042b7 lui t0,0x20004 -800000c0: fff28293 addi t0,t0,-1 # 20003fff <_start-0x5fffc001> -800000c4: 3b529073 csrw pmpaddr5,t0 -800000c8: 200022b7 lui t0,0x20002 -800000cc: fff28293 addi t0,t0,-1 # 20001fff <_start-0x5fffe001> -800000d0: 3b629073 csrw pmpaddr6,t0 -800000d4: 200062b7 lui t0,0x20006 -800000d8: fff28293 addi t0,t0,-1 # 20005fff <_start-0x5fffa001> -800000dc: 3b729073 csrw pmpaddr7,t0 -800000e0: 200d02b7 lui t0,0x200d0 -800000e4: 3b829073 csrw pmpaddr8,t0 -800000e8: 200e02b7 lui t0,0x200e0 -800000ec: 3b929073 csrw pmpaddr9,t0 -800000f0: fff00293 li t0,-1 -800000f4: 3ba29073 csrw pmpaddr10,t0 -800000f8: 00000293 li t0,0 -800000fc: 3bb29073 csrw pmpaddr11,t0 -80000100: 00000293 li t0,0 -80000104: 3bc29073 csrw pmpaddr12,t0 +80000064: 30629263 bne t0,t1,80000368 +80000068: 1a1902b7 lui t0,0x1a190 +8000006c: 30428293 addi t0,t0,772 # 1a190304 <_start-0x65e6fcfc> +80000070: 3a129073 csrw pmpcfg1,t0 +80000074: 000f12b7 lui t0,0xf1 +80000078: 90a28293 addi t0,t0,-1782 # f090a <_start-0x7ff0f6f6> +8000007c: 3a229073 csrw pmpcfg2,t0 +80000080: 3a202373 csrr t1,pmpcfg2 +80000084: 2e629263 bne t0,t1,80000368 +80000088: 1c1e22b7 lui t0,0x1c1e2 +8000008c: 90028293 addi t0,t0,-1792 # 1c1e1900 <_start-0x63e1e700> +80000090: 3a329073 csrw pmpcfg3,t0 +80000094: 200002b7 lui t0,0x20000 +80000098: 3b029073 csrw pmpaddr0,t0 +8000009c: 3b002373 csrr t1,pmpaddr0 +800000a0: 2c629463 bne t0,t1,80000368 +800000a4: fff00293 li t0,-1 +800000a8: 3b129073 csrw pmpaddr1,t0 +800000ac: 202002b7 lui t0,0x20200 +800000b0: 3b229073 csrw pmpaddr2,t0 +800000b4: 200042b7 lui t0,0x20004 +800000b8: fff28293 addi t0,t0,-1 # 20003fff <_start-0x5fffc001> +800000bc: 3b329073 csrw pmpaddr3,t0 +800000c0: 200042b7 lui t0,0x20004 +800000c4: fff28293 addi t0,t0,-1 # 20003fff <_start-0x5fffc001> +800000c8: 3b429073 csrw pmpaddr4,t0 +800000cc: 200042b7 lui t0,0x20004 +800000d0: fff28293 addi t0,t0,-1 # 20003fff <_start-0x5fffc001> +800000d4: 3b529073 csrw pmpaddr5,t0 +800000d8: 230002b7 lui t0,0x23000 +800000dc: fff28293 addi t0,t0,-1 # 22ffffff <_start-0x5d000001> +800000e0: 3b629073 csrw pmpaddr6,t0 +800000e4: 220402b7 lui t0,0x22040 +800000e8: fff28293 addi t0,t0,-1 # 2203ffff <_start-0x5dfc0001> +800000ec: 3b729073 csrw pmpaddr7,t0 +800000f0: 200d02b7 lui t0,0x200d0 +800000f4: 3b829073 csrw pmpaddr8,t0 +800000f8: 200e02b7 lui t0,0x200e0 +800000fc: 3b929073 csrw pmpaddr9,t0 +80000100: fff00293 li t0,-1 +80000104: 3ba29073 csrw pmpaddr10,t0 80000108: 00000293 li t0,0 -8000010c: 3bd29073 csrw pmpaddr13,t0 +8000010c: 3bb29073 csrw pmpaddr11,t0 80000110: 00000293 li t0,0 -80000114: 3be29073 csrw pmpaddr14,t0 +80000114: 3bc29073 csrw pmpaddr12,t0 80000118: 00000293 li t0,0 -8000011c: 3bf29073 csrw pmpaddr15,t0 -80000120: 00c10137 lui sp,0xc10 -80000124: fee10113 addi sp,sp,-18 # c0ffee <_start-0x7f3f0012> -80000128: 0020a023 sw sp,0(ra) -8000012c: 00222023 sw sp,0(tp) # 0 <_start-0x80000000> -80000130: 0000a183 lw gp,0(ra) -80000134: 28311863 bne sp,gp,800003c4 -80000138: 00000193 li gp,0 -8000013c: 00022183 lw gp,0(tp) # 0 <_start-0x80000000> -80000140: 28311263 bne sp,gp,800003c4 +8000011c: 3bd29073 csrw pmpaddr13,t0 +80000120: 00000293 li t0,0 +80000124: 3be29073 csrw pmpaddr14,t0 +80000128: fff00293 li t0,-1 +8000012c: 3bf29073 csrw pmpaddr15,t0 +80000130: 00c10137 lui sp,0xc10 +80000134: fee10113 addi sp,sp,-18 # c0ffee <_start-0x7f3f0012> +80000138: 0020a023 sw sp,0(ra) +8000013c: 00222023 sw sp,0(tp) # 0 <_start-0x80000000> +80000140: 0000a183 lw gp,0(ra) +80000144: 22311263 bne sp,gp,80000368 +80000148: 00000193 li gp,0 +8000014c: 00022183 lw gp,0(tp) # 0 <_start-0x80000000> +80000150: 20311c63 bne sp,gp,80000368 -80000144 : -80000144: 00100e13 li t3,1 -80000148: 00000f17 auipc t5,0x0 -8000014c: 27cf0f13 addi t5,t5,636 # 800003c4 -80000150: 079212b7 lui t0,0x7921 -80000154: 80828293 addi t0,t0,-2040 # 7920808 <_start-0x786df7f8> -80000158: 3a029073 csrw pmpcfg0,t0 -8000015c: 3a002373 csrr t1,pmpcfg0 -80000160: 26629263 bne t0,t1,800003c4 -80000164: 800080b7 lui ra,0x80008 -80000168: deadc137 lui sp,0xdeadc -8000016c: eef10113 addi sp,sp,-273 # deadbeef -80000170: 0020a023 sw sp,0(ra) # 80008000 -80000174: 00000f17 auipc t5,0x0 -80000178: 010f0f13 addi t5,t5,16 # 80000184 -8000017c: 0000a183 lw gp,0(ra) -80000180: 2440006f j 800003c4 +80000154 : +80000154: 00100e13 li t3,1 +80000158: 00000f17 auipc t5,0x0 +8000015c: 210f0f13 addi t5,t5,528 # 80000368 +80000160: 079a12b7 lui t0,0x79a1 +80000164: 80828293 addi t0,t0,-2040 # 79a0808 <_start-0x7865f7f8> +80000168: 3a029073 csrw pmpcfg0,t0 +8000016c: 3a002373 csrr t1,pmpcfg0 +80000170: 1e629c63 bne t0,t1,80000368 +80000174: 808000b7 lui ra,0x80800 +80000178: deadc137 lui sp,0xdeadc +8000017c: eef10113 addi sp,sp,-273 # deadbeef +80000180: 0020a023 sw sp,0(ra) # 80800000 +80000184: 00000f17 auipc t5,0x0 +80000188: 010f0f13 addi t5,t5,16 # 80000194 +8000018c: 0000a183 lw gp,0(ra) +80000190: 1d80006f j 80000368 -80000184 : -80000184: 00200e13 li t3,2 -80000188: 00000f17 auipc t5,0x0 -8000018c: 23cf0f13 addi t5,t5,572 # 800003c4 -80000190: 071202b7 lui t0,0x7120 -80000194: 3a029073 csrw pmpcfg0,t0 -80000198: 3a002373 csrr t1,pmpcfg0 -8000019c: 22628463 beq t0,t1,800003c4 -800001a0: 200042b7 lui t0,0x20004 -800001a4: fff28293 addi t0,t0,-1 # 20003fff <_start-0x5fffc001> -800001a8: 3b305073 csrwi pmpaddr3,0 -800001ac: 3b302373 csrr t1,pmpaddr3 -800001b0: 20031a63 bnez t1,800003c4 -800001b4: 20628863 beq t0,t1,800003c4 -800001b8: 200022b7 lui t0,0x20002 +80000194 : +80000194: 00200e13 li t3,2 +80000198: 00000f17 auipc t5,0x0 +8000019c: 1d0f0f13 addi t5,t5,464 # 80000368 +800001a0: 071a02b7 lui t0,0x71a0 +800001a4: 3a029073 csrw pmpcfg0,t0 +800001a8: 3a002373 csrr t1,pmpcfg0 +800001ac: 1a628e63 beq t0,t1,80000368 +800001b0: 3b305073 csrwi pmpaddr3,0 +800001b4: 3b302373 csrr t1,pmpaddr3 +800001b8: 1a031863 bnez t1,80000368 800001bc: 3b205073 csrwi pmpaddr2,0 800001c0: 3b202373 csrr t1,pmpaddr2 -800001c4: 20030063 beqz t1,800003c4 -800001c8: 1e629e63 bne t0,t1,800003c4 -800001cc: 800080b7 lui ra,0x80008 -800001d0: deadc137 lui sp,0xdeadc -800001d4: eef10113 addi sp,sp,-273 # deadbeef -800001d8: 0020a023 sw sp,0(ra) # 80008000 -800001dc: 00000f17 auipc t5,0x0 -800001e0: 010f0f13 addi t5,t5,16 # 800001ec -800001e4: 0000a183 lw gp,0(ra) -800001e8: 1dc0006f j 800003c4 +800001c4: 1a030263 beqz t1,80000368 +800001c8: 808000b7 lui ra,0x80800 +800001cc: deadc137 lui sp,0xdeadc +800001d0: eef10113 addi sp,sp,-273 # deadbeef +800001d4: 0020a023 sw sp,0(ra) # 80800000 +800001d8: 00000f17 auipc t5,0x0 +800001dc: 010f0f13 addi t5,t5,16 # 800001e8 +800001e0: 0000a183 lw gp,0(ra) +800001e4: 1840006f j 80000368 -800001ec : -800001ec: 00300e13 li t3,3 -800001f0: 00000f17 auipc t5,0x0 -800001f4: 1d4f0f13 addi t5,t5,468 # 800003c4 -800001f8: 00ff02b7 lui t0,0xff0 -800001fc: 3b32a073 csrs pmpaddr3,t0 -80000200: 3b302373 csrr t1,pmpaddr3 -80000204: 1c629063 bne t0,t1,800003c4 -80000208: 0ff00293 li t0,255 -8000020c: 3b32a073 csrs pmpaddr3,t0 -80000210: 3b302373 csrr t1,pmpaddr3 -80000214: 00ff02b7 lui t0,0xff0 -80000218: 0ff28293 addi t0,t0,255 # ff00ff <_start-0x7f00ff01> -8000021c: 1a629463 bne t0,t1,800003c4 -80000220: 00ff02b7 lui t0,0xff0 -80000224: 3b32b073 csrc pmpaddr3,t0 -80000228: 3b302373 csrr t1,pmpaddr3 -8000022c: 0ff00293 li t0,255 -80000230: 18629a63 bne t0,t1,800003c4 -80000234: 00ff02b7 lui t0,0xff0 -80000238: 0ff28293 addi t0,t0,255 # ff00ff <_start-0x7f00ff01> -8000023c: 3a02b073 csrc pmpcfg0,t0 -80000240: 3a002373 csrr t1,pmpcfg0 -80000244: 079202b7 lui t0,0x7920 -80000248: 16629e63 bne t0,t1,800003c4 -8000024c: 00ff02b7 lui t0,0xff0 -80000250: 70728293 addi t0,t0,1799 # ff0707 <_start-0x7f00f8f9> -80000254: 3a02a073 csrs pmpcfg0,t0 -80000258: 3a002373 csrr t1,pmpcfg0 -8000025c: 079202b7 lui t0,0x7920 -80000260: 70728293 addi t0,t0,1799 # 7920707 <_start-0x786df8f9> -80000264: 16629063 bne t0,t1,800003c4 +800001e8 : +800001e8: 00300e13 li t3,3 +800001ec: 00000f17 auipc t5,0x0 +800001f0: 17cf0f13 addi t5,t5,380 # 80000368 +800001f4: 00ff02b7 lui t0,0xff0 +800001f8: 3b32a073 csrs pmpaddr3,t0 +800001fc: 3b302373 csrr t1,pmpaddr3 +80000200: 16629463 bne t0,t1,80000368 +80000204: 0ff00293 li t0,255 +80000208: 3b32a073 csrs pmpaddr3,t0 +8000020c: 3b302373 csrr t1,pmpaddr3 +80000210: 00ff02b7 lui t0,0xff0 +80000214: 0ff28293 addi t0,t0,255 # ff00ff <_start-0x7f00ff01> +80000218: 14629863 bne t0,t1,80000368 +8000021c: 00ff02b7 lui t0,0xff0 +80000220: 3b32b073 csrc pmpaddr3,t0 +80000224: 3b302373 csrr t1,pmpaddr3 +80000228: 0ff00293 li t0,255 +8000022c: 12629e63 bne t0,t1,80000368 +80000230: 00ff02b7 lui t0,0xff0 +80000234: 0ff28293 addi t0,t0,255 # ff00ff <_start-0x7f00ff01> +80000238: 3a02b073 csrc pmpcfg0,t0 +8000023c: 3a002373 csrr t1,pmpcfg0 +80000240: 079a02b7 lui t0,0x79a0 +80000244: 12629263 bne t0,t1,80000368 +80000248: 00ff02b7 lui t0,0xff0 +8000024c: 70728293 addi t0,t0,1799 # ff0707 <_start-0x7f00f8f9> +80000250: 3a02a073 csrs pmpcfg0,t0 +80000254: 3a002373 csrr t1,pmpcfg0 +80000258: 079a02b7 lui t0,0x79a0 +8000025c: 70728293 addi t0,t0,1799 # 79a0707 <_start-0x7865f8f9> +80000260: 10629463 bne t0,t1,80000368 -80000268 : -80000268: 00400e13 li t3,4 -8000026c: 00000f17 auipc t5,0x0 -80000270: 158f0f13 addi t5,t5,344 # 800003c4 -80000274: 00000117 auipc sp,0x0 -80000278: 01010113 addi sp,sp,16 # 80000284 -8000027c: 34111073 csrw mepc,sp -80000280: 30200073 mret +80000264 : +80000264: 00400e13 li t3,4 +80000268: 00000f17 auipc t5,0x0 +8000026c: 100f0f13 addi t5,t5,256 # 80000368 +80000270: 00000117 auipc sp,0x0 +80000274: 01010113 addi sp,sp,16 # 80000280 +80000278: 34111073 csrw mepc,sp +8000027c: 30200073 mret -80000284 : -80000284: 00500e13 li t3,5 -80000288: 00000f17 auipc t5,0x0 -8000028c: 13cf0f13 addi t5,t5,316 # 800003c4 -80000290: deadc137 lui sp,0xdeadc -80000294: eef10113 addi sp,sp,-273 # deadbeef -80000298: 800080b7 lui ra,0x80008 -8000029c: 0020a023 sw sp,0(ra) # 80008000 -800002a0: 00000f17 auipc t5,0x0 -800002a4: 010f0f13 addi t5,t5,16 # 800002b0 -800002a8: 0000a183 lw gp,0(ra) -800002ac: 1180006f j 800003c4 +80000280 : +80000280: 00500e13 li t3,5 +80000284: 00000f17 auipc t5,0x0 +80000288: 0e4f0f13 addi t5,t5,228 # 80000368 +8000028c: deadc137 lui sp,0xdeadc +80000290: eef10113 addi sp,sp,-273 # deadbeef +80000294: 808000b7 lui ra,0x80800 +80000298: 0020a023 sw sp,0(ra) # 80800000 +8000029c: 00000f17 auipc t5,0x0 +800002a0: 010f0f13 addi t5,t5,16 # 800002ac +800002a4: 0000a183 lw gp,0(ra) +800002a8: 0c00006f j 80000368 -800002b0 : -800002b0: 00600e13 li t3,6 -800002b4: 00000f17 auipc t5,0x0 -800002b8: 110f0f13 addi t5,t5,272 # 800003c4 -800002bc: deadc137 lui sp,0xdeadc -800002c0: eef10113 addi sp,sp,-273 # deadbeef -800002c4: 800000b7 lui ra,0x80000 -800002c8: 0020a023 sw sp,0(ra) # 80000000 -800002cc: 0000a183 lw gp,0(ra) -800002d0: 0e311a63 bne sp,gp,800003c4 +800002ac : +800002ac: 00600e13 li t3,6 +800002b0: 00000f17 auipc t5,0x0 +800002b4: 0b8f0f13 addi t5,t5,184 # 80000368 +800002b8: deadc137 lui sp,0xdeadc +800002bc: eef10113 addi sp,sp,-273 # deadbeef +800002c0: 880000b7 lui ra,0x88000 +800002c4: 0020a023 sw sp,0(ra) # 88000000 +800002c8: 0000a183 lw gp,0(ra) -800002d4 : -800002d4: 00700e13 li t3,7 -800002d8: 00000f17 auipc t5,0x0 -800002dc: 0ecf0f13 addi t5,t5,236 # 800003c4 -800002e0: 800400b7 lui ra,0x80040 -800002e4: 0000a183 lw gp,0(ra) # 80040000 -800002e8: 00000f17 auipc t5,0x0 -800002ec: 010f0f13 addi t5,t5,16 # 800002f8 -800002f0: 0030a023 sw gp,0(ra) -800002f4: 0d00006f j 800003c4 +800002cc : +800002cc: 00700e13 li t3,7 +800002d0: 00000f17 auipc t5,0x0 +800002d4: 098f0f13 addi t5,t5,152 # 80000368 +800002d8: 890000b7 lui ra,0x89000 +800002dc: ff008093 addi ra,ra,-16 # 88fffff0 +800002e0: 0000a183 lw gp,0(ra) +800002e4: 00000f17 auipc t5,0x0 +800002e8: 010f0f13 addi t5,t5,16 # 800002f4 +800002ec: 0030a023 sw gp,0(ra) +800002f0: 0780006f j 80000368 -800002f8 : -800002f8: 00800e13 li t3,8 -800002fc: 00000f17 auipc t5,0x0 -80000300: 0c8f0f13 addi t5,t5,200 # 800003c4 -80000304: deadc137 lui sp,0xdeadc -80000308: eef10113 addi sp,sp,-273 # deadbeef -8000030c: 803400b7 lui ra,0x80340 -80000310: ff808093 addi ra,ra,-8 # 8033fff8 -80000314: 00222023 sw sp,0(tp) # 0 <_start-0x80000000> -80000318: 00000f17 auipc t5,0x0 -8000031c: 010f0f13 addi t5,t5,16 # 80000328 -80000320: 00022183 lw gp,0(tp) # 0 <_start-0x80000000> -80000324: 0a00006f j 800003c4 +800002f4 : +800002f4: 00800e13 li t3,8 +800002f8: 00000f17 auipc t5,0x0 +800002fc: 014f0f13 addi t5,t5,20 # 8000030c +80000300: 00100493 li s1,1 +80000304: 3a305073 csrwi pmpcfg3,0 +80000308: 0600006f j 80000368 -80000328 : -80000328: 00900e13 li t3,9 -8000032c: 00000f17 auipc t5,0x0 -80000330: 098f0f13 addi t5,t5,152 # 800003c4 -80000334: 803800b7 lui ra,0x80380 -80000338: ff808093 addi ra,ra,-8 # 8037fff8 -8000033c: 0000a183 lw gp,0(ra) -80000340: 00000f17 auipc t5,0x0 -80000344: 010f0f13 addi t5,t5,16 # 80000350 -80000348: 0030a023 sw gp,0(ra) -8000034c: 0780006f j 800003c4 +8000030c : +8000030c: 00800e13 li t3,8 +80000310: 1c1e22b7 lui t0,0x1c1e2 +80000314: 90028293 addi t0,t0,-1792 # 1c1e1900 <_start-0x63e1e700> +80000318: 3a302373 csrr t1,pmpcfg3 +8000031c: 04629663 bne t0,t1,80000368 -80000350 : -80000350: 00a00e13 li t3,10 -80000354: 00000f17 auipc t5,0x0 -80000358: 014f0f13 addi t5,t5,20 # 80000368 -8000035c: 00100493 li s1,1 -80000360: 3a305073 csrwi pmpcfg3,0 -80000364: 0600006f j 800003c4 +80000320 : +80000320: 00900e13 li t3,9 +80000324: 00000f17 auipc t5,0x0 +80000328: 044f0f13 addi t5,t5,68 # 80000368 +8000032c: 00000493 li s1,0 +80000330: 00000117 auipc sp,0x0 +80000334: 01010113 addi sp,sp,16 # 80000340 +80000338: 34111073 csrw mepc,sp +8000033c: 30200073 mret -80000368 : -80000368: 00a00e13 li t3,10 -8000036c: 0f1e22b7 lui t0,0xf1e2 -80000370: 90028293 addi t0,t0,-1792 # f1e1900 <_start-0x70e1e700> -80000374: 3a302373 csrr t1,pmpcfg3 -80000378: 04629663 bne t0,t1,800003c4 +80000340 : +80000340: 00900e13 li t3,9 +80000344: 00000f17 auipc t5,0x0 +80000348: 014f0f13 addi t5,t5,20 # 80000358 +8000034c: 00100493 li s1,1 +80000350: 3ba05073 csrwi pmpaddr10,0 +80000354: 0140006f j 80000368 -8000037c : -8000037c: 00b00e13 li t3,11 -80000380: 00000f17 auipc t5,0x0 -80000384: 044f0f13 addi t5,t5,68 # 800003c4 -80000388: 00000493 li s1,0 -8000038c: 00000117 auipc sp,0x0 -80000390: 01010113 addi sp,sp,16 # 8000039c -80000394: 34111073 csrw mepc,sp -80000398: 30200073 mret +80000358 : +80000358: 00900e13 li t3,9 +8000035c: fff00293 li t0,-1 +80000360: 3ba02373 csrr t1,pmpaddr10 +80000364: 00628863 beq t0,t1,80000374 -8000039c : -8000039c: 00b00e13 li t3,11 -800003a0: 00000f17 auipc t5,0x0 -800003a4: 014f0f13 addi t5,t5,20 # 800003b4 -800003a8: 00100493 li s1,1 -800003ac: 3ba05073 csrwi pmpaddr10,0 -800003b0: 0140006f j 800003c4 +80000368 : +80000368: f0100137 lui sp,0xf0100 +8000036c: f2410113 addi sp,sp,-220 # f00fff24 +80000370: 01c12023 sw t3,0(sp) -800003b4 : -800003b4: 00b00e13 li t3,11 -800003b8: fff00293 li t0,-1 -800003bc: 3ba02373 csrr t1,pmpaddr10 -800003c0: 00628863 beq t0,t1,800003d0 - -800003c4 : -800003c4: f0100137 lui sp,0xf0100 -800003c8: f2410113 addi sp,sp,-220 # f00fff24 -800003cc: 01c12023 sw t3,0(sp) - -800003d0 : -800003d0: f0100137 lui sp,0xf0100 -800003d4: f2010113 addi sp,sp,-224 # f00fff20 -800003d8: 00012023 sw zero,0(sp) +80000374 : +80000374: f0100137 lui sp,0xf0100 +80000378: f2010113 addi sp,sp,-224 # f00fff20 +8000037c: 00012023 sw zero,0(sp) diff --git a/src/test/cpp/raw/pmp/build/pmp.elf b/src/test/cpp/raw/pmp/build/pmp.elf index 93342d09ddf7c1c79f7bc9c54acec60e475fe976..c28d2cd523bee38e7cdf0e83e5a0a9c9325ecb76 100755 GIT binary patch delta 959 zcmY+BPiPZC6vp37QiE7`H<|ovn$&F;6r`3-DA*)mL-C>)0}6VQx@*CM(9j7YUNUSI z^rEX1L`tzy@E}yEr}f~)yU?o_y$PN~#gka#+s&p~-(hxs-}`3Xo44=gcTTxFeV=(; zE>DOUfOvcEt4h@cX=~Ax{;gvutuVRrgXVNav-? z-7@BNKR@r4XNpp2Y1QsobCUiTpt0dmU2bb9RSJf5exYQc6fet9+A=z1F*#LDRmze8 z1Z9gAohcgRQ~;)`vtDX5Ast5?w6SH)cp&6na=Io;OwmWq(tpi9vSqZ(5j*Pu<-}m|+rnE=-!ydo`DPZ91OW}lx(KqoTkzk4#6(usR z0nV?E1rGUo@M9h7;ymm2Q!CCCS9aMk;>vB7!_{N2x;J7VAP54-@q3Akc@DW3;VSaC z2rnXEr(^#aWD()B$U6}}kNh#hEr2fkjtH00Fd1p+DzYBoRpe%bZz5lbFh}l0_%!7%X`wbFp|0I;*_1Xa%3zkZK{xKbc!{Et?@i-pd-ezRsRFy2Sui2teGw bPkzo$PyEGe@5=qGkrx?&x?eC1v<2}GaMsbY literal 5944 zcmeHLPiP!f82{evCZWa5Z1&kCjr}v-Ep-nio!PEQx&zXNDk4G`51xd$^BS9l*evs= zr9#1Bn}eP@WU7LQti20Cgt;2=u87AX=vkzVm!6E@doyqMg`#-$Fc0SYzTfZt=6myg z`zDb2;FULCC4_()2K)&*idsm%Hk-|~z(&3SlQ5CZS0o={j2@K$#5EzPj2Bfg3I_@Y z3I_@Y3I_@Y3I_@Y3I_@Y3I_@Y3I_@Y{wEG3Wq?odS&|3{k2}s5TqeA7y2T!pfrIVb z01K!IFlPZ!>xWAz{=dIGz-#ZTUnqI(6F<(C5Q3pA3RNi~U(@Ue4FPe{2rDqxjK@ zS7ut`j8U_r_D|Kh5_=JzANDGmq2@b^n;B{GObV^=lP$O=HT$ZcnL;@dyy{aQI_Nn} zQ!~oB`_GO0w4x-64#as@dhr{h{wOtLr9YCwiqt*ZH=3g6FxOopNx1^NOY;3BIJh0Oq0+7>AfLJUN)bxwGhdCLu6~g{|Q;h`%q5 z=g%R&O2+s+;%yB#5&y2?6~r6HSpTxnYxpYST@AmE_-74w5I@!MTZkLl^Sq6?qv7j_ zH#EG7_^yUS#Gh;UF5+)Ayp8xr4S$3fM8Y|401#+HmP$+#rrvWzP-UXsyux_S1q?B>{2m_fhGIjr%p z8-#LUfJOfPdtukd90pn5P!&Gq8eeB&Z|f#3%0so-4a1=4-@+#syZmqC1(XrICNp^? zz88yc$7+=GqJbIdzTzKIfCU9GiymT#jDN~U<0INEdzIs0ep;{ T8mgZ-*Sc;Ro3xb(v(o(y?t_O3 diff --git a/src/test/cpp/raw/pmp/build/pmp.hex b/src/test/cpp/raw/pmp/build/pmp.hex index 2ad2696e..805692b5 100644 --- a/src/test/cpp/raw/pmp/build/pmp.hex +++ b/src/test/cpp/raw/pmp/build/pmp.hex @@ -1,65 +1,59 @@ :0200000480007A :10000000930400009700000093800001739050302B :100010006F00400173101F3463940400730020309C -:1000200067000F00130E0000170F0000130FCF39E9 +:1000200067000F00130E0000170F0000130F0F34AE :10003000B70000803782008037C1ADDE1301F1EEDA -:1000400023A020002320220083A10000631C31365E -:100050008321020063183136B70212077390023A07 -:100060007323003AB7021F19938242307390123AF9 -:10007000B7120F009382A2907390223AB7221E0FFC -:10008000938202907390323AB70200207390023B41 -:100090007323003B9302F0FF7390123BB7220020C2 -:1000A0007390223BB74200209382F2FF7390323B61 -:1000B000B74200209382F2FF7390423BB742002088 -:1000C0009382F2FF7390523BB72200209382F2FF9B -:1000D0007390623BB76200209382F2FF7390723B91 -:1000E000B7020D207390823BB7020E207390923BB3 -:1000F0009302F0FF7390A23B930200007390B23B17 -:10010000930200007390C23B930200007390D23BB5 -:10011000930200007390E23B930200007390F23B65 -:100120003701C1001301E1FE23A02000232022009B -:1001300083A100006318312893010000832102008D -:1001400063123128130E1000170F0000130FCF2772 -:10015000B7129207938282807390023A7323003A17 -:1001600063926226B780008037C1ADDE1301F1EEE5 -:1001700023A02000170F0000130F0F0183A1000020 -:100180006F004024130E2000170F0000130FCF2321 -:10019000B70212077390023A7323003A6384622213 -:1001A000B74200209382F2FF7350303B7323303B01 -:1001B000631A032063886220B72200207350203B1B -:1001C0007323203B63000320639E621EB780008080 -:1001D00037C1ADDE1301F1EE23A02000170F0000A0 -:1001E000130F0F0183A100006F00C01D130E30001C -:1001F000170F0000130F4F1DB702FF0073A0323B13 -:100200007323303B6390621C9302F00F73A0323B68 -:100210007323303BB702FF009382F20F6394621A9C -:10022000B702FF0073B0323B7323303B9302F00FF1 -:10023000639A6218B702FF009382F20F73B0023A1A -:100240007323003AB7029207639E6216B702FF005B -:100250009382727073A0023A7323003AB702920736 -:100260009382727063906216130E4000170F0000A5 -:10027000130F8F15170100001301010173101134C2 -:1002800073002030130E5000170F0000130FCF1310 -:1002900037C1ADDE1301F1EEB780008023A020004E -:1002A000170F0000130F0F0183A100006F008011D2 -:1002B000130E6000170F0000130F0F1137C1ADDED2 -:1002C0001301F1EEB700008023A0200083A10000FD -:1002D000631A310E130E7000170F0000130FCF0EAC -:1002E000B700048083A10000170F0000130F0F0157 -:1002F00023A030006F00000D130E8000170F0000C8 -:10030000130F8F0C37C1ADDE1301F1EEB70034804F -:10031000938080FF23202200170F0000130F0F018E -:10032000832102006F00000A130E9000170F0000D7 -:10033000130F8F09B7003880938080FF83A10000DE -:10034000170F0000130F0F0123A030006F0080076C -:10035000130EA000170F0000130F4F01930410009D -:100360007350303A6F000006130EA000B7221E0F24 -:10037000938202907323303A63966204130EB000A6 -:10038000170F0000130F4F04930400001701000023 -:10039000130101017310113473002030130EB000EB -:1003A000170F0000130F4F01930410007350A03B70 -:1003B0006F004001130EB0009302F0FF7323A03BC7 -:1003C00063886200370110F0130141F22320C1015C -:0C03D000370110F0130101F2232001009E +:1000400023A020002320220083A10000631E313062 +:1000500083210200631A3130B7021A077390023A03 +:100060007323003A63926230B702191A93824230C6 +:100070007390123AB7120F009382A2907390223AB3 +:100080007323203A6392622EB7221E1C9382029041 +:100090007390323AB70200207390023B7323003B07 +:1000A0006394622C9302F0FF7390123BB7022020FE +:1000B0007390223BB74200209382F2FF7390323B51 +:1000C000B74200209382F2FF7390423BB742002078 +:1000D0009382F2FF7390523BB70200239382F2FFA8 +:1000E0007390623BB70204229382F2FF7390723BDB +:1000F000B7020D207390823BB7020E207390923BA3 +:100100009302F0FF7390A23B930200007390B23B06 +:10011000930200007390C23B930200007390D23BA5 +:10012000930200007390E23B9302F0FF7390F23B66 +:100130003701C1001301E1FE23A02000232022008B +:1001400083A1000063123122930100008321020089 +:10015000631C3120130E1000170F0000130F0F2126 +:10016000B7129A07938282807390023A7323003AFF +:10017000639C621EB700808037C1ADDE1301F1EED3 +:1001800023A02000170F0000130F0F0183A1000010 +:100190006F00801D130E2000170F0000130F0F1D9E +:1001A000B7021A077390023A7323003A638E621AF9 +:1001B0007350303B7323303B6318031A7350203B5A +:1001C0007323203B6302031AB700808037C1ADDE82 +:1001D0001301F1EE23A02000170F0000130F0F01F1 +:1001E00083A100006F004018130E3000170F0000AD +:1001F000130FCF17B702FF0073A0323B7323303BBE +:10020000639462169302F00F73A0323B7323303B6A +:10021000B702FF009382F20F63986214B702FF00E7 +:1002200073B0323B7323303B9302F00F639E621234 +:10023000B702FF009382F20F73B0023A7323003AC1 +:10024000B7029A0763926212B702FF00938272703C +:1002500073A0023A7323003AB7029A07938272702E +:1002600063946210130E4000170F0000130F0F105D +:1002700017010000130101017310113473002030C5 +:10028000130E5000170F0000130F4F0E37C1ADDED5 +:100290001301F1EEB700808023A02000170F0000AB +:1002A000130F0F0183A100006F00000C130E6000FC +:1002B000170F0000130F8F0B37C1ADDE1301F1EEE6 +:1002C000B700008823A0200083A10000130E700057 +:1002D000170F0000130F8F09B7000089938000FFEC +:1002E00083A10000170F0000130F0F0123A030009F +:1002F0006F008007130E8000170F0000130F4F01CF +:10030000930410007350303A6F000006130E800003 +:10031000B7221E1C938202907323303A63966204C4 +:10032000130E9000170F0000130F4F0493040000EA +:100330001701000013010101731011347300203004 +:10034000130E9000170F0000130F4F0193041000BD +:100350007350A03B6F004001130E90009302F0FF1A +:100360007323A03B63886200370110F0130141F250 +:100370002320C101370110F0130101F223200100F5 :040000058000000077 :00000001FF diff --git a/src/test/cpp/raw/pmp/build/pmp.map b/src/test/cpp/raw/pmp/build/pmp.map index fd0c6b0a..0a074b1c 100644 --- a/src/test/cpp/raw/pmp/build/pmp.map +++ b/src/test/cpp/raw/pmp/build/pmp.map @@ -15,19 +15,19 @@ LOAD /opt/riscv/bin/../lib/gcc/riscv64-unknown-elf/8.3.0/../../../../riscv64-unk END GROUP LOAD /opt/riscv/bin/../lib/gcc/riscv64-unknown-elf/8.3.0/rv32i/ilp32/libgcc.a -.crt_section 0x0000000080000000 0x3dc +.crt_section 0x0000000080000000 0x380 0x0000000080000000 . = ALIGN (0x4) *crt.o(.text) - .text 0x0000000080000000 0x3dc build/src/crt.o + .text 0x0000000080000000 0x380 build/src/crt.o 0x0000000080000000 _start 0x0000000080000014 trap OUTPUT(build/pmp.elf elf32-littleriscv) -.data 0x00000000800003dc 0x0 - .data 0x00000000800003dc 0x0 build/src/crt.o +.data 0x0000000080000380 0x0 + .data 0x0000000080000380 0x0 build/src/crt.o -.bss 0x00000000800003dc 0x0 - .bss 0x00000000800003dc 0x0 build/src/crt.o +.bss 0x0000000080000380 0x0 + .bss 0x0000000080000380 0x0 build/src/crt.o .riscv.attributes 0x0000000000000000 0x1a diff --git a/src/test/cpp/raw/pmp/src/crt.S b/src/test/cpp/raw/pmp/src/crt.S index 3dd75ff2..5c74beb1 100644 --- a/src/test/cpp/raw/pmp/src/crt.S +++ b/src/test/cpp/raw/pmp/src/crt.S @@ -10,7 +10,7 @@ #define PMPCFG0 0x071a0000 #define PMPCFG0_ 0x079a0808 -#define PMPCFG1 0x191f0304 +#define PMPCFG1 0x1a190304 #define PMPCFG2 0x000f090a #define PMPCFG3 0x1c1e1900 @@ -20,8 +20,8 @@ #define PMPADDR3 0x20003fff // OFF RWX -> 0x00000000 OFF RWX (test2) #define PMPADDR4 0x20003fff // OFF X #define PMPADDR5 0x20003fff // OFF RW -#define PMPADDR6 0x20001fff // NAPOT RWX -#define PMPADDR7 0x20005fff // NAPOT R +#define PMPADDR6 0x22ffffff // NAPOT R +#define PMPADDR7 0x2203ffff // NAPOT W #define PMPADDR8 0x200d0000 // TOR W #define PMPADDR9 0x200e0000 // TOR R #define PMPADDR10 0xffffffff // TOR RWX @@ -29,7 +29,7 @@ #define PMPADDR12 0x00000000 // OFF #define PMPADDR13 0x00000000 // NAPOT R #define PMPADDR14 0x00000000 // NAPOT WX -#define PMPADDR15 0x000001ff // NAPOT X +#define PMPADDR15 0xffffffff // NAPOT X .global _start _start: @@ -129,9 +129,9 @@ test1: bne x5, x6, fail li x1, 0x80800000 li x2, 0xdeadbeef - sw x2, 0x0(x1) // should be OK (write 0x80800000) + sw x2, 0x0(x1) // should be OK (write region 2) la TRAP_RETURN, test2 - lw x3, 0x0(x1) // should fault (read 0x80800000) + lw x3, 0x0(x1) // should fault (read region 2) j fail // "unlock" region 2, attempt read/write from machine mode @@ -150,9 +150,9 @@ test2: beqz x6, fail li x1, 0x80800000 li x2, 0xdeadbeef - sw x2, 0x0(x1) // should still be OK (write 0x80800000) + sw x2, 0x0(x1) // should still be OK (write region 2) la TRAP_RETURN, test3 - lw x3, 0x0(x1) // should still fault (read 0x80800000) + lw x3, 0x0(x1) // should still fault (read region 2) j fail // verify masked CSR read/write operations @@ -184,99 +184,78 @@ test3: li x5, 0x079a0707 bne x5, x6, fail -// jump into user mode +// jump into U-mode test4: li TEST_ID, 4 la TRAP_RETURN, fail la x2, test5 csrw mepc, x2 - # j pass mret -// attempt to read/write region 2 from user mode +// attempt to read/write the locked region from U-mode test5: li TEST_ID, 5 la TRAP_RETURN, fail li x2, 0xdeadbeef li x1, 0x80800000 - sw x2, 0x0(x1) // should be OK (write 0x80800000) + sw x2, 0x0(x1) // should be OK (write region 2) la TRAP_RETURN, test6 - lw x3, 0x0(x1) // should fault (read 0x80800000) + lw x3, 0x0(x1) // should fault (read region 2) j fail -// attempt to read/write other regions from user mode +// attempt to read/write overlapping regions from U-mode test6: li TEST_ID, 6 - la TRAP_RETURN, fail + la TRAP_RETURN, fail li x2, 0xdeadbeef - li x1, 0x80000000 - sw x2, 0x0(x1) - lw x3, 0x0(x1) - bne x2, x3, fail // should be OK (read/write 0x80000000) + li x1, 0x88000000 + sw x2, 0x0(x1) // should be OK (write region 6/7) + lw x3, 0x0(x1) // should be OK (write region 6/7) test7: li TEST_ID, 7 la TRAP_RETURN, fail - li x1, 0x80040000 - lw x3, 0x0(x1) // should be OK (read 0x80040000) - la TRAP_RETURN, test8 - sw x3, 0x0(x1) // should fault (write 0x80040000) - j fail - -test8: - li TEST_ID, 8 - la TRAP_RETURN, fail - li x2, 0xdeadbeef - li x1, 0x8033fff8 - sw x2, 0x0(x4) // should be OK (write region 8) - la TRAP_RETURN, test9 - lw x3, 0x0(x4) // should fault (read region 8) - j fail - -test9: - li TEST_ID, 9 - la TRAP_RETURN, fail - li x1, 0x8037fff8 - lw x3, 0x0(x1) // should be OK (read region 9) - la TRAP_RETURN, test10a - sw x3, 0x0(x1) // should fault (write region 9) + li x1, 0x88fffff0 + lw x3, 0x0(x1) // should be OK (read region 6) + la TRAP_RETURN, test8a + sw x3, 0x0(x1) // should fault (write region 6) j fail // attempt to write a pmpcfg# register from U-mode -test10a: - li TEST_ID, 10 - la TRAP_RETURN, test10b +test8a: + li TEST_ID, 8 + la TRAP_RETURN, test8b li TRAP_EXIT, 0x1 csrwi pmpcfg3, 0x0 j fail // check the result from M-mode -test10b: - li TEST_ID, 10 +test8b: + li TEST_ID, 8 li x5, PMPCFG3 csrr x6, pmpcfg3 bne x5, x6, fail // jump back into U-mode -test11a: - li TEST_ID, 11 +test9a: + li TEST_ID, 9 la TRAP_RETURN, fail li TRAP_EXIT, 0x0 - la x2, test11b + la x2, test9b csrw mepc, x2 mret // attempt to write a pmpaddr# register from U-mode -test11b: - li TEST_ID, 11 - la TRAP_RETURN, test11c +test9b: + li TEST_ID, 9 + la TRAP_RETURN, test9c li TRAP_EXIT, 0x1 csrwi pmpaddr10, 0x0 j fail // check the result from M-mode -test11c: - li TEST_ID, 11 +test9c: + li TEST_ID, 9 li x5, PMPADDR10 csrr x6, pmpaddr10 beq x5, x6, pass diff --git a/src/test/scala/vexriscv/TestIndividualFeatures.scala b/src/test/scala/vexriscv/TestIndividualFeatures.scala index 6167f712..77a47389 100644 --- a/src/test/scala/vexriscv/TestIndividualFeatures.scala +++ b/src/test/scala/vexriscv/TestIndividualFeatures.scala @@ -520,6 +520,7 @@ class MmuPmpDimension extends VexRiscvDimension("DBus") { override def applyOn(config: VexRiscvConfig): Unit = { config.plugins += new PmpPlugin( regions = 16, + granularity = 32, ioRange = _ (31 downto 28) === 0xF ) } From 243d0ec664671444d9c6f32a23f8c98aa950a689 Mon Sep 17 00:00:00 2001 From: Samuel Lindemer Date: Fri, 28 May 2021 13:59:59 +0200 Subject: [PATCH 676/951] Clarify PMP section in README --- README.md | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 62dde967..895f3c2f 100644 --- a/README.md +++ b/README.md @@ -19,8 +19,35 @@ - [Adding a new CSR via the plugin system](#adding-a-new-csr-via-the-plugin-system) - [CPU clock and resets](#cpu-clock-and-resets) - [VexRiscv Architecture](#vexriscv-architecture) - * [FPU](#fpu) - * [Plugins](#plugins) + - [FPU](#fpu) + - [Plugins](#plugins) + - [IBusSimplePlugin](#ibussimpleplugin) + - [IBusCachedPlugin](#ibuscachedplugin) + - [DecoderSimplePlugin](#decodersimpleplugin) + - [RegFilePlugin](#regfileplugin) + - [HazardSimplePlugin](#hazardsimpleplugin) + - [SrcPlugin](#srcplugin) + - [IntAluPlugin](#intaluplugin) + - [LightShifterPlugin](#lightshifterplugin) + - [FullBarrelShifterPlugin](#fullbarrelshifterplugin) + - [BranchPlugin](#branchplugin) + - [Prediction NONE](#prediction-none) + - [Prediction STATIC](#prediction-static) + - [Prediction DYNAMIC](#prediction-dynamic) + - [Prediction DYNAMIC_TARGET](#prediction-dynamic_target) + - [DBusSimplePlugin](#dbussimpleplugin) + - [DBusCachedPlugin](#dbuscachedplugin) + - [MulPlugin](#mulplugin) + - [DivPlugin](#divplugin) + - [MulDivIterativePlugin](#muldiviterativeplugin) + - [CsrPlugin](#csrplugin) + - [StaticMemoryTranslatorPlugin](#staticmemorytranslatorplugin) + - [MmuPlugin](#mmuplugin) + - [PmpPlugin](#pmpplugin) + - [DebugPlugin](#debugplugin) + - [YamlPlugin](#yamlplugin) + - [FpuPlugin](#fpuplugin) + - [AesPlugin](#aesplugin) @@ -1079,7 +1106,7 @@ fully associative TLB cache which is refilled automaticaly via a dbus access sha #### PmpPlugin -This is a physical memory protection (PMP) plugin which conforms to the latest RISC-V privilege specification. PMP is configured by writing two special CSRs: `pmpcfg#` and `pmpaddr#`. The former contains the permissions and addressing modes for four protection regions, and the latter contains the encoded start address for a single region. Since the actual region bounds must be computed from the values written to these registers, writing them takes a few CPU cylces: (5 for `pmpcfg#` and 2-3 for `pmpaddr#`). This delay is necessary in order to centralize all of the decoding logic into a single component. Otherwise, it would have to be duplicated for each region, even though the decoding operation happens only when PMP is reprogrammed (e.g., on some context switches). +This is a physical memory protection (PMP) plugin which conforms to the latest RISC-V privilege specification. PMP is configured by writing two special CSRs: `pmpcfg#` and `pmpaddr#`. The former contains the permissions and addressing modes for four protection regions, and the latter contains the encoded start address for a single region. Since the actual region bounds must be computed from the values written to these registers, writing them takes a few CPU cylces. This delay is necessary in order to centralize all of the decoding logic into a single component. Otherwise, it would have to be duplicated for each region, even though the decoding operation happens only when PMP is reprogrammed (e.g., on some context switches). #### DebugPlugin From 3a4ab7ad517b483d25652e08b0c532e78084d4ed Mon Sep 17 00:00:00 2001 From: Samuel Lindemer Date: Fri, 28 May 2021 16:17:19 +0200 Subject: [PATCH 677/951] Un-pend PMP CSR writes on pipeline flushes --- src/main/scala/vexriscv/plugin/PmpPlugin.scala | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/scala/vexriscv/plugin/PmpPlugin.scala b/src/main/scala/vexriscv/plugin/PmpPlugin.scala index f9d47eea..34d323da 100644 --- a/src/main/scala/vexriscv/plugin/PmpPlugin.scala +++ b/src/main/scala/vexriscv/plugin/PmpPlugin.scala @@ -182,6 +182,10 @@ class PmpPlugin(regions : Int, granularity : Int, ioRange : UInt => Bool) extend } } + when (arbitration.isFlushed) { + pending := False + } + val writer = new Area { when (pending) { arbitration.haltItself := True From 0272d6697158629f42f911e6095d18692e899fa7 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 28 May 2021 16:20:43 +0200 Subject: [PATCH 678/951] Fix CsrPlugin.redoInterface priority --- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index badb18fb..db30cdda 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -577,7 +577,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep if(supervisorGen) { - redoInterface = pcManagerService.createJumpInterface(pipeline.execute, 10) + redoInterface = pcManagerService.createJumpInterface(pipeline.execute, -20) //Should lose against dynamic_target branch prediction correction } exceptionPendings = Vec(Bool, pipeline.stages.length) From 6cde5f9315bf2b887986dd17359035b4a9c14db9 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 2 Jun 2021 10:27:46 +0200 Subject: [PATCH 679/951] Better doc about iorange --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 1bc4557b..739ca084 100644 --- a/README.md +++ b/README.md @@ -1072,6 +1072,11 @@ stage before jumping to mtvec. Static memory translator plugin which allows to specify which range of the memory addresses is I/O mapped and shouldn't be cached. +| Parameters | type | description | +| ------ | ----------- | ------ | +| ioRange | UInt => Bool | Function reference which eat an address and return true if the address should be uncached. ex : ioRange= _(31 downto 28) === 0xF => all 0xFXXXXXXX will be uncached| + + #### MmuPlugin Hardware refilled MMU implementation. Allows other plugins such as DBusCachedPlugin/IBusCachedPlugin to instanciate memory address translation ports. Each port has a small dedicated From 2a4ca0b249e7e72464bf88fe05c4a52f8bb5bdc3 Mon Sep 17 00:00:00 2001 From: Samuel Lindemer Date: Wed, 2 Jun 2021 16:01:30 +0200 Subject: [PATCH 680/951] PMP CSR writes occur in execute stage --- .../scala/vexriscv/plugin/PmpPlugin.scala | 27 +++++++------------ 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/PmpPlugin.scala b/src/main/scala/vexriscv/plugin/PmpPlugin.scala index 34d323da..36626b15 100644 --- a/src/main/scala/vexriscv/plugin/PmpPlugin.scala +++ b/src/main/scala/vexriscv/plugin/PmpPlugin.scala @@ -133,7 +133,7 @@ class PmpPlugin(regions : Int, granularity : Int, ioRange : UInt => Bool) extend execute plug new Area { import execute._ - val pending = RegInit(False) + val pending = RegInit(False) clearWhen(!arbitration.isStuck) val hazardFree = csrService.isHazardFree() val csrAddress = input(INSTRUCTION)(csrRange) @@ -168,24 +168,17 @@ class PmpPlugin(regions : Int, granularity : Int, ioRange : UInt => Bool) extend csrService.duringAnyWrite { when ((pmpcfgCsr | pmpaddrCsr) & machineMode) { csrService.allowCsr() + when (!pending) { + pending := True + writeData_ := csrService.writeData() + pmpNcfg_ := pmpNcfg + pmpcfgN_ := pmpcfgN + pmpaddrCsr_ := pmpcfgCsr + pmpcfgCsr_ := pmpaddrCsr + } } } - csrService.onAnyWrite { - when ((pmpcfgCsr | pmpaddrCsr) & machineMode) { - pending := True - writeData_ := csrService.writeData() - pmpNcfg_ := pmpNcfg - pmpcfgN_ := pmpcfgN - pmpaddrCsr_ := pmpcfgCsr - pmpcfgCsr_ := pmpaddrCsr - } - } - - when (arbitration.isFlushed) { - pending := False - } - val writer = new Area { when (pending) { arbitration.haltItself := True @@ -208,12 +201,12 @@ class PmpPlugin(regions : Int, granularity : Int, ioRange : UInt => Bool) extend val stateIdle : State = new State with EntryPoint { onEntry { + pending := False enable := False counter := 0 } onExit { enable := True - pending := False arbitration.haltItself := True } whenIsActive { From 342b06128f5a147f2b7d3784dd3a59f0ca11abe2 Mon Sep 17 00:00:00 2001 From: Samuel Lindemer Date: Wed, 2 Jun 2021 16:39:52 +0200 Subject: [PATCH 681/951] Combine all the PMP logic into one FSM --- .../scala/vexriscv/plugin/PmpPlugin.scala | 61 ++++++++++--------- 1 file changed, 31 insertions(+), 30 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/PmpPlugin.scala b/src/main/scala/vexriscv/plugin/PmpPlugin.scala index 36626b15..1cebfe70 100644 --- a/src/main/scala/vexriscv/plugin/PmpPlugin.scala +++ b/src/main/scala/vexriscv/plugin/PmpPlugin.scala @@ -160,7 +160,7 @@ class PmpPlugin(regions : Int, granularity : Int, ioRange : UInt => Bool) extend } when (pmpaddrCsr) { csrService.allowCsr() - csrService.readData() := pmpaddr.readAsync(pmpNcfg).asBits + csrService.readData() := pmpaddr(pmpNcfg).asBits } } } @@ -173,28 +173,12 @@ class PmpPlugin(regions : Int, granularity : Int, ioRange : UInt => Bool) extend writeData_ := csrService.writeData() pmpNcfg_ := pmpNcfg pmpcfgN_ := pmpcfgN - pmpaddrCsr_ := pmpcfgCsr - pmpcfgCsr_ := pmpaddrCsr + pmpcfgCsr_ := pmpcfgCsr + pmpaddrCsr_ := pmpaddrCsr } } } - val writer = new Area { - when (pending) { - arbitration.haltItself := True - when (hazardFree & pmpaddrCsr_) { - val overwrite = writeData_.subdivideIn(8 bits) - for (i <- 0 until 4) { - when (~pmpcfg(pmpcfgN_ @@ U(i, 2 bits))(lBit)) { - pmpcfg(pmpcfgN_ @@ U(i, 2 bits)).assignFromBits(overwrite(i)) - } - } - } - } - val locked = pmpcfg(pmpNcfg_)(lBit) - pmpaddr.write(pmpNcfg_, writeData_.asUInt, ~locked & pmpcfgCsr_ & pending & hazardFree) - } - val controller = new StateMachine { val enable = RegInit(False) val counter = Reg(UInt(log2Up(regions) bits)) init(0) @@ -205,21 +189,38 @@ class PmpPlugin(regions : Int, granularity : Int, ioRange : UInt => Bool) extend enable := False counter := 0 } - onExit { - enable := True - arbitration.haltItself := True - } whenIsActive { - when (pending & hazardFree) { - when (pmpaddrCsr_) { - goto(stateCfg) - }.elsewhen (pmpcfgCsr_) { - goto(stateAddr) + when (pending) { + arbitration.haltItself := True + when (hazardFree) { + goto(stateWrite) } } } } + val stateWrite : State = new State { + onExit (enable := True) + whenIsActive { + arbitration.haltItself := True + when (pmpcfgCsr_) { + val overwrite = writeData_.subdivideIn(8 bits) + for (i <- 0 until 4) { + when (~pmpcfg(pmpcfgN_ @@ U(i, 2 bits))(lBit)) { + pmpcfg(pmpcfgN_ @@ U(i, 2 bits)).assignFromBits(overwrite(i)) + } + } + goto(stateCfg) + } + when (pmpaddrCsr_) { + when (~pmpcfg(pmpNcfg_)(lBit)) { + pmpaddr(pmpNcfg_) := writeData_.asUInt + } + goto(stateAddr) + } + } + } + val stateCfg : State = new State { onEntry (counter := pmpcfgN_ @@ U(0, 2 bits)) whenIsActive { @@ -237,10 +238,10 @@ class PmpPlugin(regions : Int, granularity : Int, ioRange : UInt => Bool) extend whenIsActive (goto(stateIdle)) } - when (pmpcfgCsr_) { + when (pmpaddrCsr_) { setter.io.addr := writeData_.asUInt } otherwise { - setter.io.addr := pmpaddr.readAsync(counter) + setter.io.addr := pmpaddr(counter) } when (enable & ~pmpcfg(counter)(lBit)) { From 156a84e76fc8e04fab3257ce0351a6c05c215c67 Mon Sep 17 00:00:00 2001 From: Samuel Lindemer Date: Thu, 3 Jun 2021 13:12:55 +0200 Subject: [PATCH 682/951] Fix PMP FSM halting logic --- .../scala/vexriscv/plugin/PmpPlugin.scala | 49 +++++++++---------- 1 file changed, 23 insertions(+), 26 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/PmpPlugin.scala b/src/main/scala/vexriscv/plugin/PmpPlugin.scala index 1cebfe70..7c1330b9 100644 --- a/src/main/scala/vexriscv/plugin/PmpPlugin.scala +++ b/src/main/scala/vexriscv/plugin/PmpPlugin.scala @@ -133,7 +133,8 @@ class PmpPlugin(regions : Int, granularity : Int, ioRange : UInt => Bool) extend execute plug new Area { import execute._ - val pending = RegInit(False) clearWhen(!arbitration.isStuck) + val fsmPending = RegInit(False) clearWhen(!arbitration.isStuck) + val fsmComplete = False val hazardFree = csrService.isHazardFree() val csrAddress = input(INSTRUCTION)(csrRange) @@ -168,8 +169,9 @@ class PmpPlugin(regions : Int, granularity : Int, ioRange : UInt => Bool) extend csrService.duringAnyWrite { when ((pmpcfgCsr | pmpaddrCsr) & machineMode) { csrService.allowCsr() - when (!pending) { - pending := True + arbitration.haltItself := !fsmComplete + when (!fsmPending) { + fsmPending := True writeData_ := csrService.writeData() pmpNcfg_ := pmpNcfg pmpcfgN_ := pmpcfgN @@ -179,30 +181,26 @@ class PmpPlugin(regions : Int, granularity : Int, ioRange : UInt => Bool) extend } } - val controller = new StateMachine { - val enable = RegInit(False) - val counter = Reg(UInt(log2Up(regions) bits)) init(0) + val fsm = new StateMachine { + val fsmEnable = RegInit(False) + val fsmCounter = Reg(UInt(log2Up(regions) bits)) init(0) val stateIdle : State = new State with EntryPoint { onEntry { - pending := False - enable := False - counter := 0 + fsmPending := False + fsmEnable := False + fsmComplete := True + fsmCounter := 0 } whenIsActive { - when (pending) { - arbitration.haltItself := True - when (hazardFree) { - goto(stateWrite) - } + when (fsmPending & hazardFree) { + goto(stateWrite) } } } val stateWrite : State = new State { - onExit (enable := True) whenIsActive { - arbitration.haltItself := True when (pmpcfgCsr_) { val overwrite = writeData_.subdivideIn(8 bits) for (i <- 0 until 4) { @@ -219,34 +217,33 @@ class PmpPlugin(regions : Int, granularity : Int, ioRange : UInt => Bool) extend goto(stateAddr) } } + onExit (fsmEnable := True) } val stateCfg : State = new State { - onEntry (counter := pmpcfgN_ @@ U(0, 2 bits)) + onEntry (fsmCounter := pmpcfgN_ @@ U(0, 2 bits)) whenIsActive { - counter := counter + 1 - when (counter(1 downto 0) === 3) { + fsmCounter := fsmCounter + 1 + when (fsmCounter(1 downto 0) === 3) { goto(stateIdle) - } otherwise { - arbitration.haltItself := True } } } val stateAddr : State = new State { - onEntry (counter := pmpNcfg_) + onEntry (fsmCounter := pmpNcfg_) whenIsActive (goto(stateIdle)) } when (pmpaddrCsr_) { setter.io.addr := writeData_.asUInt } otherwise { - setter.io.addr := pmpaddr(counter) + setter.io.addr := pmpaddr(fsmCounter) } - when (enable & ~pmpcfg(counter)(lBit)) { - base(counter) := setter.io.base - mask(counter) := setter.io.mask + when (fsmEnable & ~pmpcfg(fsmCounter)(lBit)) { + base(fsmCounter) := setter.io.base + mask(fsmCounter) := setter.io.mask } } } From 646911a37367cafc58f0e07a2d561ce395f26b13 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 7 Jun 2021 17:30:47 +0200 Subject: [PATCH 683/951] Fix pmp write when there is hazard due to the register file. --- .../scala/vexriscv/plugin/PmpPlugin.scala | 44 ++++++++++--------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/PmpPlugin.scala b/src/main/scala/vexriscv/plugin/PmpPlugin.scala index 7c1330b9..10848910 100644 --- a/src/main/scala/vexriscv/plugin/PmpPlugin.scala +++ b/src/main/scala/vexriscv/plugin/PmpPlugin.scala @@ -124,9 +124,11 @@ class PmpPlugin(regions : Int, granularity : Int, ioRange : UInt => Bool) extend val csrService = pipeline.service(classOf[CsrInterface]) val privilegeService = pipeline.service(classOf[PrivilegeService]) - val pmpaddr = Mem(UInt(xlen bits), regions) - val pmpcfg = Vector.fill(regions)(Reg(Bits(8 bits)) init(0)) - val base, mask = Vector.fill(regions)(Reg(UInt(xlen - cutoff bits))) + val state = pipeline plug new Area { + val pmpaddr = Mem(UInt(xlen bits), regions) + val pmpcfg = Vector.fill(regions)(Reg(Bits(8 bits)) init (0)) + val base, mask = Vector.fill(regions)(Reg(UInt(xlen - cutoff bits))) + } def machineMode : Bool = privilegeService.isMachine() @@ -154,14 +156,14 @@ class PmpPlugin(regions : Int, granularity : Int, ioRange : UInt => Bool) extend when (pmpcfgCsr) { csrService.allowCsr() csrService.readData() := - pmpcfg(pmpcfgN @@ U(3, 2 bits)) ## - pmpcfg(pmpcfgN @@ U(2, 2 bits)) ## - pmpcfg(pmpcfgN @@ U(1, 2 bits)) ## - pmpcfg(pmpcfgN @@ U(0, 2 bits)) + state.pmpcfg(pmpcfgN @@ U(3, 2 bits)) ## + state.pmpcfg(pmpcfgN @@ U(2, 2 bits)) ## + state.pmpcfg(pmpcfgN @@ U(1, 2 bits)) ## + state.pmpcfg(pmpcfgN @@ U(0, 2 bits)) } when (pmpaddrCsr) { csrService.allowCsr() - csrService.readData() := pmpaddr(pmpNcfg).asBits + csrService.readData() := state.pmpaddr(pmpNcfg).asBits } } } @@ -170,7 +172,7 @@ class PmpPlugin(regions : Int, granularity : Int, ioRange : UInt => Bool) extend when ((pmpcfgCsr | pmpaddrCsr) & machineMode) { csrService.allowCsr() arbitration.haltItself := !fsmComplete - when (!fsmPending) { + when (!fsmPending && hazardFree) { fsmPending := True writeData_ := csrService.writeData() pmpNcfg_ := pmpNcfg @@ -193,7 +195,7 @@ class PmpPlugin(regions : Int, granularity : Int, ioRange : UInt => Bool) extend fsmCounter := 0 } whenIsActive { - when (fsmPending & hazardFree) { + when (fsmPending) { goto(stateWrite) } } @@ -204,15 +206,15 @@ class PmpPlugin(regions : Int, granularity : Int, ioRange : UInt => Bool) extend when (pmpcfgCsr_) { val overwrite = writeData_.subdivideIn(8 bits) for (i <- 0 until 4) { - when (~pmpcfg(pmpcfgN_ @@ U(i, 2 bits))(lBit)) { - pmpcfg(pmpcfgN_ @@ U(i, 2 bits)).assignFromBits(overwrite(i)) + when (~state.pmpcfg(pmpcfgN_ @@ U(i, 2 bits))(lBit)) { + state.pmpcfg(pmpcfgN_ @@ U(i, 2 bits)).assignFromBits(overwrite(i)) } } goto(stateCfg) } when (pmpaddrCsr_) { - when (~pmpcfg(pmpNcfg_)(lBit)) { - pmpaddr(pmpNcfg_) := writeData_.asUInt + when (~state.pmpcfg(pmpNcfg_)(lBit)) { + state.pmpaddr(pmpNcfg_) := writeData_.asUInt } goto(stateAddr) } @@ -238,12 +240,12 @@ class PmpPlugin(regions : Int, granularity : Int, ioRange : UInt => Bool) extend when (pmpaddrCsr_) { setter.io.addr := writeData_.asUInt } otherwise { - setter.io.addr := pmpaddr(fsmCounter) + setter.io.addr := state.pmpaddr(fsmCounter) } - when (fsmEnable & ~pmpcfg(fsmCounter)(lBit)) { - base(fsmCounter) := setter.io.base - mask(fsmCounter) := setter.io.mask + when (fsmEnable & ~state.pmpcfg(fsmCounter)(lBit)) { + state.base(fsmCounter) := setter.io.base + state.mask(fsmCounter) := setter.io.mask } } } @@ -251,13 +253,13 @@ class PmpPlugin(regions : Int, granularity : Int, ioRange : UInt => Bool) extend pipeline plug new Area { def getHits(address : UInt) = { (0 until regions).map(i => - ((address & mask(U(i, log2Up(regions) bits))) === base(U(i, log2Up(regions) bits))) & - (pmpcfg(i)(lBit) | ~machineMode) & (pmpcfg(i)(aBits) === NAPOT) + ((address & state.mask(U(i, log2Up(regions) bits))) === state.base(U(i, log2Up(regions) bits))) & + (state.pmpcfg(i)(lBit) | ~machineMode) & (state.pmpcfg(i)(aBits) === NAPOT) ) } def getPermission(hits : IndexedSeq[Bool], bit : Int) = { - (hits zip pmpcfg).map({ case (i, cfg) => i & cfg(bit) }).orR + (hits zip state.pmpcfg).map({ case (i, cfg) => i & cfg(bit) }).orR } val dGuard = new Area { From e1e1be5797ae83e3b73c40030c2d9eb639184bf0 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 8 Jun 2021 12:19:08 +0200 Subject: [PATCH 684/951] exception code can now be bigger than 4 bits --- src/main/scala/vexriscv/Services.scala | 13 +++++++++--- .../scala/vexriscv/plugin/CsrPlugin.scala | 21 +++++++++++-------- .../plugin/HaltOnExceptionPlugin.scala | 6 +++--- 3 files changed, 25 insertions(+), 15 deletions(-) diff --git a/src/main/scala/vexriscv/Services.scala b/src/main/scala/vexriscv/Services.scala index 59a81621..64ce5ae2 100644 --- a/src/main/scala/vexriscv/Services.scala +++ b/src/main/scala/vexriscv/Services.scala @@ -26,13 +26,20 @@ trait DecoderService{ def addDefault(key : Stageable[_ <: BaseType], value : Any) } -case class ExceptionCause() extends Bundle{ - val code = UInt(4 bits) +case class ExceptionCause(codeWidth : Int) extends Bundle{ + val code = UInt(codeWidth bits) val badAddr = UInt(32 bits) + + def resizeCode(width : Int): ExceptionCause ={ + val ret = ExceptionCause(width) + ret.badAddr := badAddr + ret.code := code.resized + ret + } } trait ExceptionService{ - def newExceptionPort(stage : Stage, priority : Int = 0) : Flow[ExceptionCause] + def newExceptionPort(stage : Stage, priority : Int = 0, codeWidth : Int = 4) : Flow[ExceptionCause] def isExceptionPending(stage : Stage) : Bool } diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index ea60f641..60d1b34f 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -34,7 +34,7 @@ object CsrAccess { -case class ExceptionPortInfo(port : Flow[ExceptionCause],stage : Stage, priority : Int) +case class ExceptionPortInfo(port : Flow[ExceptionCause],stage : Stage, priority : Int, codeWidth : Int) case class CsrPluginConfig( catchIllegalAccess : Boolean, mvendorid : BigInt, @@ -441,9 +441,9 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep //Mannage ExceptionService calls val exceptionPortsInfos = ArrayBuffer[ExceptionPortInfo]() - override def newExceptionPort(stage : Stage, priority : Int = 0) = { - val interface = Flow(ExceptionCause()) - exceptionPortsInfos += ExceptionPortInfo(interface,stage,priority) + override def newExceptionPort(stage : Stage, priority : Int = 0, codeWidth : Int = 4) = { + val interface = Flow(ExceptionCause(codeWidth)) + exceptionPortsInfos += ExceptionPortInfo(interface,stage,priority,codeWidth) interface } @@ -847,10 +847,11 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep //Aggregate all exception port and remove required instructions val exceptionPortCtrl = exceptionPortsInfos.nonEmpty generate new Area{ + val codeWidth = exceptionPortsInfos.map(_.codeWidth).max val firstStageIndexWithExceptionPort = exceptionPortsInfos.map(i => indexOf(i.stage)).min val exceptionValids = Vec(stages.map(s => Bool().setPartialName(s.getName()))) val exceptionValidsRegs = Vec(stages.map(s => Reg(Bool).init(False).setPartialName(s.getName()))).allowUnsetRegToAvoidLatch - val exceptionContext = Reg(ExceptionCause()) + val exceptionContext = Reg(ExceptionCause(codeWidth)) val exceptionTargetPrivilegeUncapped = U"11" switch(exceptionContext.code){ @@ -876,17 +877,19 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep val groupedByStage = exceptionPortsInfos.map(_.stage).distinct.map(s => { val stagePortsInfos = exceptionPortsInfos.filter(_.stage == s).sortWith(_.priority > _.priority) val stagePort = stagePortsInfos.length match{ - case 1 => stagePortsInfos.head.port + case 1 => { + stagePortsInfos.head.port.translateWith(stagePortsInfos.head.port.payload.resizeCode(codeWidth)) + } case _ => { - val groupedPort = Flow(ExceptionCause()) + val groupedPort = Flow(ExceptionCause(codeWidth)) val valids = stagePortsInfos.map(_.port.valid) - val codes = stagePortsInfos.map(_.port.payload) + val codes = stagePortsInfos.map(_.port.payload.resizeCode(codeWidth)) groupedPort.valid := valids.orR groupedPort.payload := MuxOH(OHMasking.first(stagePortsInfos.map(_.port.valid).asBits), codes) groupedPort } } - ExceptionPortInfo(stagePort,s,0) + ExceptionPortInfo(stagePort,s,0, codeWidth) }) val sortedByStage = groupedByStage.sortWith((a, b) => pipeline.indexOf(a.stage) < pipeline.indexOf(b.stage)) diff --git a/src/main/scala/vexriscv/plugin/HaltOnExceptionPlugin.scala b/src/main/scala/vexriscv/plugin/HaltOnExceptionPlugin.scala index 6e39948a..b1042236 100644 --- a/src/main/scala/vexriscv/plugin/HaltOnExceptionPlugin.scala +++ b/src/main/scala/vexriscv/plugin/HaltOnExceptionPlugin.scala @@ -16,9 +16,9 @@ class HaltOnExceptionPlugin() extends Plugin[VexRiscv] with ExceptionService { //Mannage ExceptionService calls val exceptionPortsInfos = ArrayBuffer[ExceptionPortInfo]() def exceptionCodeWidth = 4 - override def newExceptionPort(stage : Stage, priority : Int = 0) = { - val interface = Flow(ExceptionCause()) - exceptionPortsInfos += ExceptionPortInfo(interface,stage,priority) + override def newExceptionPort(stage : Stage, priority : Int = 0, codeWidth : Int = 4) = { + val interface = Flow(ExceptionCause(4)) + exceptionPortsInfos += ExceptionPortInfo(interface,stage,priority, codeWidth) interface } override def isExceptionPending(stage : Stage): Bool = False From 0e89ebecedce18dd44030ebfb6c954553ee6f7bf Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 9 Jun 2021 11:26:58 +0200 Subject: [PATCH 685/951] Improve FPU rs1 timings --- src/main/scala/vexriscv/ip/fpu/FpuCore.scala | 5 +- .../scala/vexriscv/plugin/FpuPlugin.scala | 53 +------------------ 2 files changed, 5 insertions(+), 53 deletions(-) diff --git a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala index ffe05723..657b2fb4 100644 --- a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala +++ b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala @@ -229,7 +229,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val useRs1, useRs2, useRs3, useRd = False switch(input.opcode){ is(p.Opcode.LOAD) { useRd := True } - is(p.Opcode.STORE) { useRs1 := True } + is(p.Opcode.STORE) { useRs2 := True } is(p.Opcode.ADD) { useRd := True; useRs1 := True; useRs2 := True } is(p.Opcode.MUL) { useRd := True; useRs1 := True; useRs2 := True } is(p.Opcode.DIV) { useRd := True; useRs1 := True; useRs2 := True } @@ -255,6 +255,9 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val hits = (0 to 3).map(id => uses(id) && rfBusy(id)) val hazard = hits.orR || !rf.init.done || commitLogic(portId).pending.full val output = input.haltWhen(hazard) + when(input.opcode === p.Opcode.STORE){ + output.rs1 := input.rs2 //Datapath optimisation to unify rs source in the store pipeline + } when(input.valid && rf.init.done){ scoreboard.targetWrite.address := input.rd scoreboard.targetWrite.data := !rfTargets.last diff --git a/src/main/scala/vexriscv/plugin/FpuPlugin.scala b/src/main/scala/vexriscv/plugin/FpuPlugin.scala index a2479929..3e664f51 100644 --- a/src/main/scala/vexriscv/plugin/FpuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/FpuPlugin.scala @@ -165,57 +165,6 @@ class FpuPlugin(externalFpu : Boolean = false, // exposeEncoding() } - def exposeEncoding(): Unit ={ - val d = pipeline.service(classOf[DecoderSimplePlugin]) - val commits, rsps, rs1, commitsN, rspsN, rs1N = ArrayBuffer[MaskedLiteral]() - def filter(encoding : Int, list : ArrayBuffer[MaskedLiteral]) = list.filter(e => (e.value & 0x7F) == encoding) - def filterNotLs(list : ArrayBuffer[MaskedLiteral]) = list.filter(e => !List(0x7, 0x27).contains(e.value & 0x7F)) - - for((key, t) <- d.encodings; if(t.map(_._1).contains(FPU_ENABLE)); - (s, v) <- t){ - def isSet = v.head.source.asInstanceOf[Literal].getValue == 1 - if(s == FPU_COMMIT) (if(isSet)commits += key else commitsN += key) - if(s == FPU_RSP) (if(isSet)rsps += key else rspsN += key) - if(s == pipeline.config.RS1_USE) (if(isSet)rs1 += key else rs1N += key) - } - - val commitLut, rspLut, rs1Lut = Array.fill(32)(false) - filter(0x53,commits).foreach{m => - val idx = (m.value >> 27).toInt - commitLut(idx) = true - } - filter(0x53,commitsN).foreach{m => - val idx = (m.value >> 27).toInt - assert(!commitLut(idx)) - } - println("COMMIT => ") - println(commitLut.mkString(",")) - - - filter(0x53,rsps).foreach{m => - val idx = (m.value >> 27).toInt - rspLut(idx) = true - } - filter(0x53,rspsN).foreach{m => - val idx = (m.value >> 27).toInt - assert(!rspLut(idx)) - } - println("RSP => ") - println(rspLut.mkString(",")) - - filter(0x53,rs1).foreach{m => - val idx = (m.value >> 27).toInt - rs1Lut(idx) = true - } - filter(0x53,rs1N).foreach{m => - val idx = (m.value >> 27).toInt - assert(!rs1Lut(idx)) - } - println("rs1 => ") - println(rs1Lut.mkString(",")) - - } - override def build(pipeline: VexRiscv): Unit = { import pipeline._ import pipeline.config._ @@ -295,7 +244,7 @@ class FpuPlugin(externalFpu : Boolean = false, port.cmd.valid := arbitration.isValid && input(FPU_ENABLE) && !forked && !hazard port.cmd.opcode := input(FPU_OPCODE) port.cmd.arg := input(FPU_ARG) - port.cmd.rs1 := ((input(FPU_OPCODE) === FpuOpcode.STORE) ? input(INSTRUCTION)(rs2Range).asUInt | input(INSTRUCTION)(rs1Range).asUInt) + port.cmd.rs1 := input(INSTRUCTION)(rs1Range).asUInt port.cmd.rs2 := input(INSTRUCTION)(rs2Range).asUInt port.cmd.rs3 := input(INSTRUCTION)(rs3Range).asUInt port.cmd.rd := input(INSTRUCTION)(rdRange).asUInt From 1ee45eeb0a03acc29fc98918836deab453464f26 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 9 Jun 2021 11:27:18 +0200 Subject: [PATCH 686/951] More named signals --- src/main/scala/vexriscv/plugin/Misc.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/plugin/Misc.scala b/src/main/scala/vexriscv/plugin/Misc.scala index 081a06a6..979d246d 100644 --- a/src/main/scala/vexriscv/plugin/Misc.scala +++ b/src/main/scala/vexriscv/plugin/Misc.scala @@ -136,7 +136,7 @@ object StreamForkVex{ object StreamVexPimper{ implicit class StreamFlushPimper[T <: Data](pimped : Stream[T]){ def m2sPipeWithFlush(flush : Bool, discardInput : Boolean = true, collapsBubble : Boolean = true, flushInput : Bool = null): Stream[T] = { - val ret = cloneOf(pimped) + val ret = cloneOf(pimped).setCompositeName(pimped, "m2sPipe", true) val rValid = RegInit(False) val rData = Reg(pimped.payloadType) From 1497001ebd4728c1801b887eb181cd86b1dcf39b Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 9 Jun 2021 13:37:31 +0200 Subject: [PATCH 687/951] Update FpuTest with the new rs1/rs2 store mapping --- src/test/scala/vexriscv/ip/fpu/FpuTest.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala index fb5943a1..280a5fe5 100644 --- a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala +++ b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala @@ -293,8 +293,8 @@ class FpuTest extends FunSuite{ def storeRaw(rs : Int, format : FpuFormat.E)(body : FpuRsp => Unit): Unit ={ cmdAdd {cmd => cmd.opcode #= cmd.opcode.spinalEnum.STORE - cmd.rs1 #= rs - cmd.rs2.randomize() + cmd.rs1.randomize() + cmd.rs2 #= rs cmd.rs3.randomize() cmd.rd.randomize() cmd.arg.randomize() From 1017b316b8a7e404a6ac3d8c46f3e5afeed9d9ea Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 15 Jun 2021 15:59:09 +0200 Subject: [PATCH 688/951] version++ --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index 51bd3fec..e4cf8d6d 100644 --- a/build.sbt +++ b/build.sbt @@ -1,4 +1,4 @@ -val spinalVersion = "1.4.4" +val spinalVersion = "1.5.1" lazy val root = (project in file(".")). settings( From cdd8a7e94a55992ade6635c18de6144fe82e2170 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 23 Jun 2021 09:04:35 +0200 Subject: [PATCH 689/951] add github action --- .github/workflows/scala.yml | 59 +++++++++++++++++++++++++++++++++++ tools.sh | 62 +++++++++++++++++++++++++++++++++++++ 2 files changed, 121 insertions(+) create mode 100644 .github/workflows/scala.yml create mode 100644 tools.sh diff --git a/.github/workflows/scala.yml b/.github/workflows/scala.yml new file mode 100644 index 00000000..06d1ae41 --- /dev/null +++ b/.github/workflows/scala.yml @@ -0,0 +1,59 @@ +name: Scala CI + +on: [push, pull_request] + +jobs: + build: + runs-on: ubuntu-latest + timeout-minutes: 90 + + steps: + - uses: actions/checkout@v2 + with: + submodules: 'recursive' + + - name: Set up JDK 11 + uses: actions/setup-java@v2 + with: + java-version: '11' + distribution: 'adopt' + + - name: Cache pip + uses: actions/cache@v2 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-v2 + restore-keys: | + ${{ runner.os }}-pip- + + - name: Cache SBT + uses: actions/cache@v2 + with: + path: | + ~/.ivy2/cache + ~/.sbt + key: ${{ runner.os }}-sbt-${{ hashFiles('**/build.sbt') }} + + - name: Cache tools + id: tools + uses: actions/cache@v2 + with: + path: | + ~/tools + key: ${{ runner.os }}-tools_v2 + + - name: Setup env + run: echo "$HOME/tools/bin" >> $GITHUB_PATH + + - name: Install cached tools + if: steps.tools.outputs.cache-hit != 'true' + run: source tools.sh && (cd ~/ && install_verilator) + + - name: Install uncached tools + run: (cd .. && git clone https://github.com/SpinalHDL/SpinalHDL.git -b dev) + + - name: Compile tests + run: sbt "+test:compile" + + - name: Run tests + run: sbt "+test" diff --git a/tools.sh b/tools.sh new file mode 100644 index 00000000..ebe05921 --- /dev/null +++ b/tools.sh @@ -0,0 +1,62 @@ +#!/bin/sh + +install_verilator(){ + sudo apt install -y git make autoconf g++ flex libfl-dev bison # First time prerequisites + git clone http://git.veripool.org/git/verilator # Only first time + unset VERILATOR_ROOT # For bash + cd verilator + git pull # Make sure we're up-to-date + git checkout v4.040 + autoconf # Create ./configure script + ./configure --prefix ~/tools + make -j$(nproc) + make install + cd .. +} + +install_ghdl(){ + sudo apt install -y gnat-9 libgnat-9 zlib1g-dev libboost-dev + git clone https://github.com/ghdl/ghdl ghdl-build && cd ghdl-build + git reset --hard "0316f95368837dc163173e7ca52f37ecd8d3591d" + mkdir build + cd build + ../configure --prefix=~/tools + make -j$(nproc) + make install + cd .. +} + +install_iverilog(){ + sudo apt install -y gperf readline-common bison flex libfl-dev + curl -fsSL https://github.com/steveicarus/iverilog/archive/v10_3.tar.gz | tar -xvz + cd iverilog-10_3 + autoconf + ./configure --prefix ~/tools + make -j$(nproc) + make install + cd .. +} + +install_cocotb(){ + pip3 install --user cocotb + sudo apt install -y git make gcc g++ swig python3-dev +} + +purge_cocotb(){ + # Force cocotb to compile VPI to avoid race condition when tests are start in parallel + cd tester/src/test/python/spinal/Dummy + make TOPLEVEL_LANG=verilog + make TOPLEVEL_LANG=vhdl + cd ../../../../../.. +} + +install_packages(){ + sudo apt install -y gnat-9 libgnat-9 zlib1g-dev libboost-dev +} + +install_tools(){ + install_verilator + install_ghdl + install_iverilog + install_cocotb +} \ No newline at end of file From df7ac05db988b3c3bbbf80b782d5b1f2a2c1a0c9 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 23 Jun 2021 11:48:38 +0200 Subject: [PATCH 690/951] Update 2.13 compatibility --- build.sbt | 4 ++-- src/main/scala/vexriscv/demo/Briey.scala | 8 ++++---- src/main/scala/vexriscv/demo/Murax.scala | 4 ++-- src/main/scala/vexriscv/demo/MuraxUtiles.scala | 2 +- src/test/scala/vexriscv/DhrystoneBench.scala | 4 ++-- .../scala/vexriscv/TestIndividualFeatures.scala | 14 ++++++++------ src/test/scala/vexriscv/ip/fpu/FpuTest.scala | 5 +++-- 7 files changed, 22 insertions(+), 19 deletions(-) diff --git a/build.sbt b/build.sbt index e4cf8d6d..0b0f3026 100644 --- a/build.sbt +++ b/build.sbt @@ -10,8 +10,8 @@ lazy val root = (project in file(".")). scalacOptions += s"-Xplugin:${new File(baseDirectory.value + s"/../SpinalHDL/idslplugin/target/scala-2.11/spinalhdl-idsl-plugin_2.11-$spinalVersion.jar")}", scalacOptions += s"-Xplugin-require:idsl-plugin", libraryDependencies ++= Seq( - "org.scalatest" % "scalatest_2.11" % "2.2.1", - "org.yaml" % "snakeyaml" % "1.8" + "org.scalatest" %% "scalatest" % "3.2.5", + "org.yaml" % "snakeyaml" % "1.8" ), name := "VexRiscv" ).dependsOn(spinalHdlIdslPlugin, spinalHdlSim,spinalHdlCore,spinalHdlLib) diff --git a/src/main/scala/vexriscv/demo/Briey.scala b/src/main/scala/vexriscv/demo/Briey.scala index dd794a67..76c688d9 100644 --- a/src/main/scala/vexriscv/demo/Briey.scala +++ b/src/main/scala/vexriscv/demo/Briey.scala @@ -174,9 +174,9 @@ class Briey(config: BrieyConfig) extends Component{ val io = new Bundle{ //Clocks / reset - val asyncReset = in Bool - val axiClk = in Bool - val vgaClk = in Bool + val asyncReset = in Bool() + val axiClk = in Bool() + val vgaClk = in Bool() //Main components IO val jtag = slave(Jtag()) @@ -188,7 +188,7 @@ class Briey(config: BrieyConfig) extends Component{ val uart = master(Uart()) val vga = master(Vga(vgaRgbConfig)) val timerExternal = in(PinsecTimerCtrlExternal()) - val coreInterrupt = in Bool + val coreInterrupt = in Bool() } val resetCtrlClockDomain = ClockDomain( diff --git a/src/main/scala/vexriscv/demo/Murax.scala b/src/main/scala/vexriscv/demo/Murax.scala index 82bceb36..05c8e00e 100644 --- a/src/main/scala/vexriscv/demo/Murax.scala +++ b/src/main/scala/vexriscv/demo/Murax.scala @@ -157,8 +157,8 @@ case class Murax(config : MuraxConfig) extends Component{ val io = new Bundle { //Clocks / reset - val asyncReset = in Bool - val mainClk = in Bool + val asyncReset = in Bool() + val mainClk = in Bool() //Main components IO val jtag = slave(Jtag()) diff --git a/src/main/scala/vexriscv/demo/MuraxUtiles.scala b/src/main/scala/vexriscv/demo/MuraxUtiles.scala index 1e221570..22bc438f 100644 --- a/src/main/scala/vexriscv/demo/MuraxUtiles.scala +++ b/src/main/scala/vexriscv/demo/MuraxUtiles.scala @@ -142,7 +142,7 @@ class MuraxApb3Timer extends Component{ addressWidth = 8, dataWidth = 32 )) - val interrupt = out Bool + val interrupt = out Bool() } val prescaler = Prescaler(16) diff --git a/src/test/scala/vexriscv/DhrystoneBench.scala b/src/test/scala/vexriscv/DhrystoneBench.scala index a98377c5..48d1b674 100644 --- a/src/test/scala/vexriscv/DhrystoneBench.scala +++ b/src/test/scala/vexriscv/DhrystoneBench.scala @@ -2,13 +2,13 @@ package vexriscv import java.io.File -import org.scalatest.FunSuite +import org.scalatest.funsuite.AnyFunSuite import spinal.core.SpinalVerilog import vexriscv.demo._ import scala.sys.process._ -class DhrystoneBench extends FunSuite { +class DhrystoneBench extends AnyFunSuite { def doCmd(cmd: String): String = { val stdOut = new StringBuilder() class Logger extends ProcessLogger { diff --git a/src/test/scala/vexriscv/TestIndividualFeatures.scala b/src/test/scala/vexriscv/TestIndividualFeatures.scala index 71c66978..bd5acb0a 100644 --- a/src/test/scala/vexriscv/TestIndividualFeatures.scala +++ b/src/test/scala/vexriscv/TestIndividualFeatures.scala @@ -3,7 +3,9 @@ package vexriscv import java.io.{File, OutputStream} import java.util.concurrent.{ForkJoinPool, TimeUnit} import org.apache.commons.io.FileUtils -import org.scalatest.{BeforeAndAfterAll, FunSuite, ParallelTestExecution, Tag, Transformer} +import org.scalatest.{BeforeAndAfterAll, ParallelTestExecution, Tag, Transformer} +import org.scalatest.funsuite.AnyFunSuite + import spinal.core._ import spinal.lib.DoCmd import vexriscv.demo._ @@ -617,7 +619,7 @@ object PlayFuture extends App{ Thread.sleep(8000) } -class MultithreadedFunSuite(threadCount : Int) extends FunSuite { +class MultithreadedFunSuite(threadCount : Int) extends AnyFunSuite { val finalThreadCount = if(threadCount > 0) threadCount else { new oshi.SystemInfo().getHardware.getProcessor.getLogicalProcessorCount } @@ -650,7 +652,7 @@ class MultithreadedFunSuite(threadCount : Int) extends FunSuite { } } - override protected def test(testName: String, testTags: Tag*)(testFun: => Unit) { + def testMp(testName: String, testTags: Tag*)(testFun: => Unit) { val job = new Job(testFun) super.test(testName, testTags :_*)(job.join()) } @@ -662,7 +664,7 @@ class MultithreadedFunSuite(threadCount : Int) extends FunSuite { class FunTestPara extends MultithreadedFunSuite(3){ def createTest(name : String): Unit ={ - test(name){ + testMp(name){ for(i <- 0 to 4) { println(s"$name $i") Thread.sleep(500) @@ -745,7 +747,7 @@ class TestIndividualFeatures extends MultithreadedFunSuite(sys.env.getOrElse("VE stdOut.toString() } - test(prefix + name) { + testMp(prefix + name) { println("START TEST " + prefix + name) //Cleanup @@ -787,7 +789,7 @@ class TestIndividualFeatures extends MultithreadedFunSuite(sys.env.getOrElse("VE val rand = new Random(seed) - test("Info"){ + testMp("Info"){ println(s"MAIN_SEED=$seed") } println(s"Seed=$seed") diff --git a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala index 280a5fe5..11182acc 100644 --- a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala +++ b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala @@ -5,7 +5,7 @@ import java.lang import java.util.Scanner import org.apache.commons.io.FileUtils -import org.scalatest.FunSuite +import org.scalatest.funsuite.AnyFunSuite import spinal.core.SpinalEnumElement import spinal.core.sim._ import spinal.core._ @@ -18,9 +18,10 @@ import scala.collection.mutable import scala.collection.mutable.ArrayBuffer import scala.sys.process.ProcessLogger import scala.util.Random +import org.scalatest.funsuite.AnyFunSuite //TODO Warning DataCache write aggregation will disable itself -class FpuTest extends FunSuite{ +class FpuTest extends AnyFunSuite{ val b2f = lang.Float.intBitsToFloat(_) val b2d = lang.Double.longBitsToDouble(_) From 3702ea03c0a4cae0e9a18e129932edbb32bea765 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 23 Jun 2021 11:48:53 +0200 Subject: [PATCH 691/951] Fix github actions --- .github/workflows/scala.yml | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/.github/workflows/scala.yml b/.github/workflows/scala.yml index 06d1ae41..3c203f50 100644 --- a/.github/workflows/scala.yml +++ b/.github/workflows/scala.yml @@ -55,5 +55,15 @@ jobs: - name: Compile tests run: sbt "+test:compile" - - name: Run tests - run: sbt "+test" + - name: Test Dhrystones + run: make regression_dhrystone -C scripts/regression + + - name: Test Baremetal + run: make regression_random_baremetal -C scripts/regression + + - name: Test Machine OS + run: make regression_random_machine_os -C scripts/regression + + - name: Test Linux + run: make regression_random_linux -C scripts/regression + From 551e76d244912f694f01c2be5d569c1e6c4e3cd9 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 2 Jul 2021 19:04:30 +0200 Subject: [PATCH 692/951] VexRiscvSmpCluster add a few options --- .../demo/smp/VexRiscvSmpCluster.scala | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index b724c45a..55b2c8d5 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -188,6 +188,31 @@ object VexRiscvSmpClusterGen { assert(dCacheSize/dCacheWays <= 4096, "Data cache ways can't be bigger than 4096 bytes") assert(!(withDouble && !withFloat)) + val csrConfig = if(withSupervisor){ + CsrPluginConfig.openSbi(mhartid = hartId, misa = Riscv.misaToInt(s"ima${if(withFloat) "f" else ""}${if(withDouble) "d" else ""}s")).copy(utimeAccess = CsrAccess.READ_ONLY) + } else { + CsrPluginConfig( + catchIllegalAccess = true, + mvendorid = null, + marchid = null, + mimpid = null, + mhartid = 0, + misaExtensionsInit = 0, + misaAccess = CsrAccess.NONE, + mtvecAccess = CsrAccess.READ_WRITE, + mtvecInit = null, + mepcAccess = CsrAccess.READ_WRITE, + mscratchGen = false, + mcauseAccess = CsrAccess.READ_ONLY, + mbadaddrAccess = CsrAccess.READ_ONLY, + mcycleAccess = CsrAccess.NONE, + minstretAccess = CsrAccess.NONE, + ecallGen = true, + wfiGenAsWait = false, + wfiGenAsNop = true, + ucycleAccess = CsrAccess.NONE + ) + } val config = VexRiscvConfig( plugins = List( if(withMmu)new MmuPlugin( @@ -283,7 +308,7 @@ object VexRiscvSmpClusterGen { mulUnrollFactor = 32, divUnrollFactor = 1 ), - new CsrPlugin(CsrPluginConfig.openSbi(mhartid = hartId, misa = Riscv.misaToInt(s"ima${if(withFloat) "f" else ""}${if(withDouble) "d" else ""}s")).copy(utimeAccess = CsrAccess.READ_ONLY)), + new CsrPlugin(csrConfig), new BranchPlugin( earlyBranch = earlyBranch, catchAddressMisaligned = true, From c79357d1b2ae687c01152bd5034c7ef51ac3f430 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 5 Jul 2021 12:38:54 +0200 Subject: [PATCH 693/951] VexRiscvSmpClusterGen no support atomic less configs --- src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index d17e4fb6..cb89da9e 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -167,6 +167,7 @@ object VexRiscvSmpClusterGen { dBusWidth : Int = 64, loadStoreWidth : Int = 32, coherency : Boolean = true, + atomic : Boolean = true, iCacheSize : Int = 8192, dCacheSize : Int = 8192, iCacheWays : Int = 2, @@ -270,9 +271,9 @@ object VexRiscvSmpClusterGen { catchAccessError = true, catchIllegal = true, catchUnaligned = true, - withLrSc = true, - withAmo = true, - withExclusive = coherency, + withLrSc = atomic, + withAmo = atomic, + withExclusive = atomic, withInvalidate = coherency, withWriteAggregation = dBusWidth > 32 ), From 28a75afe7aaab08aac34fb20a3e0f11947cd24d4 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 5 Jul 2021 14:17:48 +0200 Subject: [PATCH 694/951] reduce regression time --- .github/workflows/scala.yml | 2 +- scripts/regression/regression.mk | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/scala.yml b/.github/workflows/scala.yml index 3c203f50..2d4547fa 100644 --- a/.github/workflows/scala.yml +++ b/.github/workflows/scala.yml @@ -5,7 +5,7 @@ on: [push, pull_request] jobs: build: runs-on: ubuntu-latest - timeout-minutes: 90 + timeout-minutes: 120 steps: - uses: actions/checkout@v2 diff --git a/scripts/regression/regression.mk b/scripts/regression/regression.mk index 8e3fba8f..89e760d6 100644 --- a/scripts/regression/regression.mk +++ b/scripts/regression/regression.mk @@ -11,7 +11,7 @@ regression_random: regression_random_linux: cd ../.. - export VEXRISCV_REGRESSION_CONFIG_COUNT=3 + export VEXRISCV_REGRESSION_CONFIG_COUNT=2 export VEXRISCV_REGRESSION_CONFIG_LINUX_RATE=1.0 export VEXRISCV_REGRESSION_CONFIG_SECURE_RATE=0.0 export VEXRISCV_REGRESSION_FREERTOS_COUNT=1 @@ -22,7 +22,7 @@ regression_random_linux: regression_random_machine_os: cd ../.. - export VEXRISCV_REGRESSION_CONFIG_COUNT=15 + export VEXRISCV_REGRESSION_CONFIG_COUNT=10 export VEXRISCV_REGRESSION_CONFIG_LINUX_RATE=0.0 export VEXRISCV_REGRESSION_CONFIG_MACHINE_OS_RATE=1.0 export VEXRISCV_REGRESSION_CONFIG_SECURE_RATE=0.0 @@ -33,7 +33,7 @@ regression_random_machine_os: regression_random_baremetal: cd ../.. - export VEXRISCV_REGRESSION_CONFIG_COUNT=40 + export VEXRISCV_REGRESSION_CONFIG_COUNT=30 export VEXRISCV_REGRESSION_CONFIG_LINUX_RATE=0.0 export VEXRISCV_REGRESSION_CONFIG_MACHINE_OS_RATE=0.0 export VEXRISCV_REGRESSION_CONFIG_SECURE_RATE=0.0 From 9bc7dce857e7f6032a039d48d8eb0f8b28ea4e59 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 8 Jul 2021 09:47:54 +0200 Subject: [PATCH 695/951] Update README.md --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 4fdeec28..1add93b8 100644 --- a/README.md +++ b/README.md @@ -169,8 +169,9 @@ sudo update-alternatives --config java sudo update-alternatives --config javac # Install SBT - https://www.scala-sbt.org/ -echo "deb https://dl.bintray.com/sbt/debian /" | sudo tee -a /etc/apt/sources.list.d/sbt.list -sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 2EE0EA64E40A89B84B2DF73499E82A75642AC823 +echo "deb https://repo.scala-sbt.org/scalasbt/debian all main" | sudo tee /etc/apt/sources.list.d/sbt.list +echo "deb https://repo.scala-sbt.org/scalasbt/debian /" | sudo tee /etc/apt/sources.list.d/sbt_old.list +curl -sL "https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x2EE0EA64E40A89B84B2DF73499E82A75642AC823" | sudo apt-key add sudo apt-get update sudo apt-get install sbt @@ -1196,4 +1197,4 @@ For more documentation, check src/main/scala/vexriscv/plugin/AesPlugin.scala, a It was also ported on libressl via the following patch : -Speed up of 4 was observed in libressl running in linux. \ No newline at end of file +Speed up of 4 was observed in libressl running in linux. From a4c86130cc4fec7d86052ab9deab90b29c307a1d Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 8 Jul 2021 09:47:54 +0200 Subject: [PATCH 696/951] Update README.md --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 78159c7c..b61d6823 100644 --- a/README.md +++ b/README.md @@ -169,8 +169,9 @@ sudo update-alternatives --config java sudo update-alternatives --config javac # Install SBT - https://www.scala-sbt.org/ -echo "deb https://dl.bintray.com/sbt/debian /" | sudo tee -a /etc/apt/sources.list.d/sbt.list -sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 2EE0EA64E40A89B84B2DF73499E82A75642AC823 +echo "deb https://repo.scala-sbt.org/scalasbt/debian all main" | sudo tee /etc/apt/sources.list.d/sbt.list +echo "deb https://repo.scala-sbt.org/scalasbt/debian /" | sudo tee /etc/apt/sources.list.d/sbt_old.list +curl -sL "https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x2EE0EA64E40A89B84B2DF73499E82A75642AC823" | sudo apt-key add sudo apt-get update sudo apt-get install sbt @@ -1196,4 +1197,4 @@ For more documentation, check src/main/scala/vexriscv/plugin/AesPlugin.scala, a It was also ported on libressl via the following patch : -Speed up of 4 was observed in libressl running in linux. \ No newline at end of file +Speed up of 4 was observed in libressl running in linux. From 91b3e79485d7d35758c16c97e300dab265d81e56 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sun, 11 Jul 2021 21:55:13 +0200 Subject: [PATCH 697/951] SpinalHDL version++ --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index 0b0f3026..293a83f3 100644 --- a/build.sbt +++ b/build.sbt @@ -1,4 +1,4 @@ -val spinalVersion = "1.5.1" +val spinalVersion = "1.6.1" lazy val root = (project in file(".")). settings( From 0cdad37fffdc42e5fe1b23db674f25d223d8526c Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sun, 11 Jul 2021 21:55:33 +0200 Subject: [PATCH 698/951] VexRiscvSmpClusterGen now implement ebreak --- src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index cb89da9e..5aacc2b7 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -214,6 +214,7 @@ object VexRiscvSmpClusterGen { mcycleAccess = CsrAccess.NONE, minstretAccess = CsrAccess.NONE, ecallGen = true, + ebreakGen = true, wfiGenAsWait = false, wfiGenAsNop = true, ucycleAccess = CsrAccess.NONE From 66bcd7fca7f7902f5a4fd586f3578543cd04d1ca Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 20 Jul 2021 10:14:54 +0200 Subject: [PATCH 699/951] readme: add the tom link about JTAG and GDB --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 1add93b8..8cb14bd2 100644 --- a/README.md +++ b/README.md @@ -300,6 +300,7 @@ To create a new debug configuration: You can use the Eclipse + Zylin embedded CDT plugin to do it (http://opensource.zylin.com/embeddedcdt.html). Tested with Helios Service Release 2 (http://www.Eclipse.org/downloads/download.php?file=/technology/epp/downloads/release/helios/SR2/Eclipse-cpp-helios-SR2-linux-gtk-x86_64.tar.gz) and the corresponding zylin plugin. To following commands will download Eclipse and install the plugin. + ```sh wget http://www.eclipse.org/downloads/download.php?file=/technology/epp/downloads/release/helios/SR2/eclipse-cpp-helios-SR2-linux-gtk-x86_64.tar.gz tar -xvzf download.php?file=%2Ftechnology%2Fepp%2Fdownloads%2Frelease%2Fhelios%2FSR2%2Feclipse-cpp-helios-SR2-linux-gtk-x86_64.tar.gz @@ -311,6 +312,10 @@ See https://drive.google.com/drive/folders/1NseNHH05B6lmIXqQFVwK8xRjWE4ydeG-?usp Note that sometimes Eclipse needs to be restarted in order to be able to place new breakpoints. +If you want to get more information about how all this JTAG / GDB stuff work, you can find great blog about it here : + + + ## Briey SoC As a demonstration, a SoC named Briey is implemented in `src/main/scala/vexriscv/demo/Briey.scala`. This SoC is very similar to the [Pinsec SoC](https://spinalhdl.github.io/SpinalDoc-RTD/SpinalHDL/Legacy/pinsec/hardware_toplevel.html#): From 3028c19389ae5a6589c561db5c65ab573a6af913 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 20 Jul 2021 11:20:53 +0200 Subject: [PATCH 700/951] Fix #191 (data cache toAxi bridge) --- src/main/scala/vexriscv/ip/DataCache.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index 8c1ce619..72de3436 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -287,7 +287,7 @@ case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave axi.sharedCmd.write := cmdStage.wr axi.sharedCmd.prot := "010" axi.sharedCmd.cache := "1111" - axi.sharedCmd.size := cmd.size.max(log2Up(p.memDataBytes)) + axi.sharedCmd.size := log2Up(p.memDataBytes) axi.sharedCmd.addr := cmdStage.address axi.sharedCmd.len := cmd.beatCountMinusOne.resized From f3f9b79f9a0486a5afa9b7a101a14b84a2c2cb9c Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 21 Jul 2021 18:34:57 +0200 Subject: [PATCH 701/951] VexRiscvSmpCluster earlyShifterInjection added --- src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index 5aacc2b7..ddda92f4 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -175,6 +175,7 @@ object VexRiscvSmpClusterGen { iBusRelax : Boolean = false, injectorStage : Boolean = false, earlyBranch : Boolean = false, + earlyShifterInjection : Boolean = true, dBusCmdMasterPipe : Boolean = false, withMmu : Boolean = true, withSupervisor : Boolean = true, @@ -299,7 +300,7 @@ object VexRiscvSmpClusterGen { new SrcPlugin( separatedAddSub = false ), - new FullBarrelShifterPlugin(earlyInjection = true), + new FullBarrelShifterPlugin(earlyInjection = earlyShifterInjection), // new LightShifterPlugin, new HazardSimplePlugin( bypassExecute = true, From c242744d02b052a7883aa618fe6ce9dca5f7fa68 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 26 Jul 2021 14:45:54 +0200 Subject: [PATCH 702/951] CfuPlugin now only fork when the rest of the pipeline is hazard free --- src/main/scala/vexriscv/Stage.scala | 14 +++++++------- src/main/scala/vexriscv/plugin/CfuPlugin.scala | 6 +++++- .../vexriscv/plugin/DBusCachedPlugin.scala | 18 +++++++++++------- .../vexriscv/plugin/DBusSimplePlugin.scala | 8 +++++--- 4 files changed, 28 insertions(+), 18 deletions(-) diff --git a/src/main/scala/vexriscv/Stage.scala b/src/main/scala/vexriscv/Stage.scala index 5f3365ac..d4099d6c 100644 --- a/src/main/scala/vexriscv/Stage.scala +++ b/src/main/scala/vexriscv/Stage.scala @@ -14,13 +14,13 @@ class Stageable[T <: Data](_dataType : => T) extends HardType[T](_dataType) with class Stage() extends Area{ def outsideCondScope[T](that : => T) : T = { - val body = Component.current.dslBody - body.push() - val swapContext = body.swap() - val ret = that - body.pop() - swapContext.appendBack() - ret + val body = Component.current.dslBody // Get the head of the current component symboles tree (AST in other words) + body.push() // Now all access to the SpinalHDL API will be append to it (instead of the current context) + val swapContext = body.swap() // Empty the symbole tree (but keep a reference to the old content) + val ret = that // Execute the block of code (will be added to the recently empty body) + body.pop() // Restore the original context in which this function was called + swapContext.appendBack() // append the original symboles tree to the modified body + ret // return the value returned by that } def input[T <: Data](key : Stageable[T]) : T = { diff --git a/src/main/scala/vexriscv/plugin/CfuPlugin.scala b/src/main/scala/vexriscv/plugin/CfuPlugin.scala index c96be098..6817e9df 100644 --- a/src/main/scala/vexriscv/plugin/CfuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CfuPlugin.scala @@ -166,7 +166,11 @@ class CfuPlugin(val stageCount : Int, forkStage plug new Area{ import forkStage._ - val schedule = arbitration.isValid && input(CFU_ENABLE) + val hazard = stages.dropWhile(_ != forkStage).tail.map(s => s.arbitration.isValid && s.input(HAS_SIDE_EFFECT)).orR + val scheduleWish = arbitration.isValid && input(CFU_ENABLE) + val schedule = scheduleWish && !hazard + arbitration.haltItself setWhen(scheduleWish && hazard) + val hold = RegInit(False) setWhen(schedule) clearWhen(bus.cmd.ready) val fired = RegInit(False) setWhen(bus.cmd.fire) clearWhen(!arbitration.isStuckByOthers) insert(CFU_IN_FLIGHT) := schedule || hold || fired diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index 4309ea2a..99786e7f 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -81,8 +81,9 @@ class DBusCachedPlugin(val config : DataCacheConfig, // REGFILE_WRITE_VALID -> True, // BYPASSABLE_EXECUTE_STAGE -> False, // BYPASSABLE_MEMORY_STAGE -> False, - MEMORY_WR -> False - ) ++ (if(catchSomething) List(HAS_SIDE_EFFECT -> True) else Nil) + MEMORY_WR -> False, + HAS_SIDE_EFFECT -> True + ) ) if(withLrSc) decoderService.add(key, Seq(MEMORY_LRSC -> False)) @@ -103,8 +104,9 @@ class DBusCachedPlugin(val config : DataCacheConfig, IntAluPlugin.ALU_CTRL -> IntAluPlugin.AluCtrlEnum.ADD_SUB, SRC2_CTRL -> Src2CtrlEnum.IMS, // RS2_USE -> True, - MEMORY_WR -> True - ) ++ (if(catchSomething) List(HAS_SIDE_EFFECT -> True) else Nil) + MEMORY_WR -> True, + HAS_SIDE_EFFECT -> True + ) ) if(withLrSc) decoderService.add(key, Seq(MEMORY_LRSC -> False)) @@ -156,13 +158,15 @@ class DBusCachedPlugin(val config : DataCacheConfig, REGFILE_WRITE_VALID -> True, BYPASSABLE_EXECUTE_STAGE -> False, BYPASSABLE_MEMORY_STAGE -> False, - MEMORY_WR -> False - ) ++ (if(catchSomething) List(HAS_SIDE_EFFECT -> True) else Nil) + MEMORY_WR -> False, + HAS_SIDE_EFFECT -> True + ) val storeActions = stdActions ++ List( SRC2_CTRL -> Src2CtrlEnum.IMS, RS2_USE -> True, - MEMORY_WR -> True + MEMORY_WR -> True, + HAS_SIDE_EFFECT -> True ) decoderService.addDefault(MEMORY_ENABLE, False) diff --git a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala index 1fe09ed0..ac22dc42 100644 --- a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala @@ -327,13 +327,15 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, REGFILE_WRITE_VALID -> True, BYPASSABLE_EXECUTE_STAGE -> False, BYPASSABLE_MEMORY_STAGE -> Bool(earlyInjection), - MEMORY_STORE -> False - ) ++ (if(catchAccessFault || catchAddressMisaligned) List(HAS_SIDE_EFFECT -> True) else Nil) + MEMORY_STORE -> False, + HAS_SIDE_EFFECT -> True + ) val storeActions = stdActions ++ List( SRC2_CTRL -> Src2CtrlEnum.IMS, RS2_USE -> True, - MEMORY_STORE -> True + MEMORY_STORE -> True, + HAS_SIDE_EFFECT -> True ) decoderService.addDefault(MEMORY_ENABLE, False) From b717f228d6e7ef771aee6302ac500ac9c31c8987 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 26 Jul 2021 15:17:06 +0200 Subject: [PATCH 703/951] VfuPlugin wip --- .../demo/GenSmallAndProductiveVfu.scala | 64 +++++++++ .../scala/vexriscv/plugin/VfuPlugin.scala | 135 ++++++++++++++++++ 2 files changed, 199 insertions(+) create mode 100644 src/main/scala/vexriscv/demo/GenSmallAndProductiveVfu.scala create mode 100644 src/main/scala/vexriscv/plugin/VfuPlugin.scala diff --git a/src/main/scala/vexriscv/demo/GenSmallAndProductiveVfu.scala b/src/main/scala/vexriscv/demo/GenSmallAndProductiveVfu.scala new file mode 100644 index 00000000..81ca61bf --- /dev/null +++ b/src/main/scala/vexriscv/demo/GenSmallAndProductiveVfu.scala @@ -0,0 +1,64 @@ +package vexriscv.demo + +import spinal.core._ +import vexriscv.plugin._ +import vexriscv.{VexRiscv, VexRiscvConfig, plugin} + +/** + * Created by spinalvm on 15.06.17. + */ +object GenSmallAndProductiveVfu extends App{ + def cpu() = new VexRiscv( + config = VexRiscvConfig( + plugins = List( + new IBusSimplePlugin( + resetVector = 0x80000000l, + cmdForkOnSecondStage = false, + cmdForkPersistence = false, + prediction = NONE, + catchAccessFault = false, + compressedGen = false + ), + new DBusSimplePlugin( + catchAddressMisaligned = false, + catchAccessFault = false + ), + new CsrPlugin(CsrPluginConfig.smallest), + new DecoderSimplePlugin( + catchIllegalInstruction = false + ), + new RegFilePlugin( + regFileReadyKind = plugin.SYNC, + zeroBoot = false + ), + new IntAluPlugin, + new SrcPlugin( + separatedAddSub = false, + executeInsertion = true + ), + new LightShifterPlugin, + new HazardSimplePlugin( + bypassExecute = true, + bypassMemory = true, + bypassWriteBack = true, + bypassWriteBackBuffer = true, + pessimisticUseSrc = false, + pessimisticWriteRegFile = false, + pessimisticAddressMatch = false + ), + new BranchPlugin( + earlyBranch = false, + catchAddressMisaligned = false + ), + new VfuPlugin( + stageCount = 2, + allowZeroLatency = false, + parameter = VfuParameter() + ), + new YamlPlugin("cpu0.yaml") + ) + ) + ) + + SpinalVerilog(cpu()) +} diff --git a/src/main/scala/vexriscv/plugin/VfuPlugin.scala b/src/main/scala/vexriscv/plugin/VfuPlugin.scala new file mode 100644 index 00000000..27527273 --- /dev/null +++ b/src/main/scala/vexriscv/plugin/VfuPlugin.scala @@ -0,0 +1,135 @@ +package vexriscv.plugin + +import vexriscv.{DecoderService, ExceptionCause, ExceptionService, Stage, Stageable, VexRiscv} +import spinal.core._ +import spinal.lib._ +import spinal.lib.bus.bmb.WeakConnector +import spinal.lib.bus.misc.{AddressMapping, DefaultMapping} +import vexriscv.Riscv.IMM + + +object VfuPlugin{ + val ROUND_MODE_WIDTH = 3 + +} + + +case class VfuParameter() //Empty for now + +case class VfuCmd( p : VfuParameter ) extends Bundle{ + val instruction = Bits(32 bits) + val inputs = Vec(Bits(32 bits), 2) + val rounding = Bits(VfuPlugin.ROUND_MODE_WIDTH bits) +} + +case class VfuRsp(p : VfuParameter) extends Bundle{ + val output = Bits(32 bits) +} + +case class VfuBus(p : VfuParameter) extends Bundle with IMasterSlave{ + val cmd = Stream(VfuCmd(p)) + val rsp = Stream(VfuRsp(p)) + + def <<(m : VfuBus) : Unit = { + val s = this + s.cmd << m.cmd + m.rsp << s.rsp + } + + override def asMaster(): Unit = { + master(cmd) + slave(rsp) + } +} + + + +class VfuPlugin(val stageCount : Int, + val allowZeroLatency : Boolean, + val parameter : VfuParameter) extends Plugin[VexRiscv]{ + def p = parameter + + var bus : VfuBus = null + + lazy val forkStage = pipeline.execute + lazy val joinStage = pipeline.stages(Math.min(pipeline.stages.length - 1, pipeline.indexOf(forkStage) + stageCount)) + + + object VFU_ENABLE extends Stageable(Bool()) + object VFU_IN_FLIGHT extends Stageable(Bool()) + + override def setup(pipeline: VexRiscv): Unit = { + import pipeline._ + import pipeline.config._ + + bus = master(VfuBus(p)) + + val decoderService = pipeline.service(classOf[DecoderService]) + decoderService.addDefault(VFU_ENABLE, False) + + decoderService.add( + key = M"-------------------------0001011", + values = List( + REGFILE_WRITE_VALID -> True, //If you want to write something back into the integer register file + BYPASSABLE_EXECUTE_STAGE -> Bool(stageCount == 0), + BYPASSABLE_MEMORY_STAGE -> Bool(stageCount <= 1), + RS1_USE -> True, + RS2_USE -> True + ) + ) + } + + override def build(pipeline: VexRiscv): Unit = { + import pipeline._ + import pipeline.config._ + + val csr = pipeline plug new Area{ + val factory = pipeline.service(classOf[CsrInterface]) + val rounding = Reg(Bits(VfuPlugin.ROUND_MODE_WIDTH bits)) + + factory.rw(csrAddress = 0xBC0, bitOffset = 0, that = rounding) + } + + + forkStage plug new Area{ + import forkStage._ + val hazard = stages.dropWhile(_ != forkStage).tail.map(s => s.arbitration.isValid && s.input(HAS_SIDE_EFFECT)).orR + val scheduleWish = arbitration.isValid && input(VFU_ENABLE) + val schedule = scheduleWish && !hazard + arbitration.haltItself setWhen(scheduleWish && hazard) + + val hold = RegInit(False) setWhen(schedule) clearWhen(bus.cmd.ready) + val fired = RegInit(False) setWhen(bus.cmd.fire) clearWhen(!arbitration.isStuckByOthers) + insert(VFU_IN_FLIGHT) := schedule || hold || fired + + bus.cmd.valid := (schedule || hold) && !fired + arbitration.haltItself setWhen(bus.cmd.valid && !bus.cmd.ready) + + bus.cmd.instruction := input(INSTRUCTION) + bus.cmd.inputs(0) := input(RS1) + bus.cmd.inputs(1) := input(RS2) + bus.cmd.rounding := csr.rounding + } + + joinStage plug new Area{ + import joinStage._ + + val rsp = if(forkStage != joinStage && allowZeroLatency) { + bus.rsp.s2mPipe() + } else { + bus.rsp.combStage() + } + + rsp.ready := False + when(input(VFU_IN_FLIGHT) && input(REGFILE_WRITE_VALID)){ + arbitration.haltItself setWhen(!bus.rsp.valid) + rsp.ready := !arbitration.isStuckByOthers + output(REGFILE_WRITE_DATA) := bus.rsp.output + } + } + + pipeline.stages.drop(1).foreach(s => s.output(VFU_IN_FLIGHT) clearWhen(s.arbitration.isStuck)) + addPrePopTask(() => stages.dropWhile(_ != memory).reverse.dropWhile(_ != joinStage).foreach(s => s.input(VFU_IN_FLIGHT).init(False))) + } +} + From ba8f5f966aca56231935e07c8caa04f40c9846c0 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 26 Jul 2021 15:27:20 +0200 Subject: [PATCH 704/951] Vfu typo --- src/main/scala/vexriscv/plugin/VfuPlugin.scala | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/scala/vexriscv/plugin/VfuPlugin.scala b/src/main/scala/vexriscv/plugin/VfuPlugin.scala index 27527273..c3048273 100644 --- a/src/main/scala/vexriscv/plugin/VfuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/VfuPlugin.scala @@ -70,6 +70,7 @@ class VfuPlugin(val stageCount : Int, decoderService.add( key = M"-------------------------0001011", values = List( + VFU_ENABLE -> True, REGFILE_WRITE_VALID -> True, //If you want to write something back into the integer register file BYPASSABLE_EXECUTE_STAGE -> Bool(stageCount == 0), BYPASSABLE_MEMORY_STAGE -> Bool(stageCount <= 1), From 671bd309530b8510fd21579abf906638f0698d8f Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 28 Jul 2021 13:44:04 +0200 Subject: [PATCH 705/951] Update Bmb invalidate/sync parameters --- src/main/scala/vexriscv/ip/DataCache.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index 72de3436..c15805b1 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -100,11 +100,11 @@ case class DataCacheConfig(cacheSize : Int, contextWidth = (if(!withWriteResponse) 1 else 0) + aggregationWidth, alignment = BmbParameter.BurstAlignement.LENGTH, canExclusive = withExclusive, - withCachedRead = true + withCachedRead = true, + canInvalidate = withInvalidate, + canSync = withInvalidate )), BmbInvalidationParameter( - canInvalidate = withInvalidate, - canSync = withInvalidate, invalidateLength = log2Up(this.bytePerLine), invalidateAlignment = BmbParameter.BurstAlignement.LENGTH ) From 805bd560776c638c78c30c73833d5efbaea2d8f2 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 30 Jul 2021 16:51:07 +0200 Subject: [PATCH 706/951] Fix VexRiscvBmbGenerator.hardwareBreakpointCount default value --- src/main/scala/vexriscv/VexRiscvBmbGenerator.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/VexRiscvBmbGenerator.scala b/src/main/scala/vexriscv/VexRiscvBmbGenerator.scala index 9bd8d942..723ea7de 100644 --- a/src/main/scala/vexriscv/VexRiscvBmbGenerator.scala +++ b/src/main/scala/vexriscv/VexRiscvBmbGenerator.scala @@ -25,7 +25,7 @@ case class VexRiscvBmbGenerator()(implicit interconnectSmp: BmbInterconnectGener val debugClockDomain = Handle[ClockDomain] val debugReset = Handle[Bool] val debugAskReset = Handle[() => Unit] - val hardwareBreakpointCount = Handle(0) + val hardwareBreakpointCount = Handle.sync(0) val iBus, dBus = Handle[Bmb] From 3deeab42fd511892bd53a324a8246af6704f3f30 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 10 Aug 2021 12:14:39 +0200 Subject: [PATCH 707/951] VexRiscvSmpCluster config fix --- src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index ddda92f4..0623c771 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -275,7 +275,7 @@ object VexRiscvSmpClusterGen { catchUnaligned = true, withLrSc = atomic, withAmo = atomic, - withExclusive = atomic, + withExclusive = coherency, withInvalidate = coherency, withWriteAggregation = dBusWidth > 32 ), From 5c7e4a0294c785b58b424e49b4696855143370cb Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 24 Aug 2021 23:24:22 +0200 Subject: [PATCH 708/951] #170 wishbone example now set dBusCmdMasterPipe --- src/main/scala/vexriscv/demo/VexRiscvCachedWishboneForSim.scala | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/scala/vexriscv/demo/VexRiscvCachedWishboneForSim.scala b/src/main/scala/vexriscv/demo/VexRiscvCachedWishboneForSim.scala index 2a834287..88cad3d0 100644 --- a/src/main/scala/vexriscv/demo/VexRiscvCachedWishboneForSim.scala +++ b/src/main/scala/vexriscv/demo/VexRiscvCachedWishboneForSim.scala @@ -64,6 +64,7 @@ object VexRiscvCachedWishboneForSim{ catchIllegal = true, catchUnaligned = true ), + dBusCmdMasterPipe = true, //required for wishbone memoryTranslatorPortConfig = null // memoryTranslatorPortConfig = MemoryTranslatorPortConfig( // portTlbSize = 6 From bc561c30eb4d1ea46b9264e46fd14addf6e60879 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 1 Sep 2021 11:27:12 +0200 Subject: [PATCH 709/951] Add PmpPluginOld (support TOR) --- .../scala/vexriscv/plugin/PmpPluginOld.scala | 244 ++++++++++++++++++ 1 file changed, 244 insertions(+) create mode 100644 src/main/scala/vexriscv/plugin/PmpPluginOld.scala diff --git a/src/main/scala/vexriscv/plugin/PmpPluginOld.scala b/src/main/scala/vexriscv/plugin/PmpPluginOld.scala new file mode 100644 index 00000000..0426902b --- /dev/null +++ b/src/main/scala/vexriscv/plugin/PmpPluginOld.scala @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2020 Samuel Lindemer + * + * SPDX-License-Identifier: MIT + */ + +package vexriscv.plugin + +import vexriscv.{VexRiscv, _} +import spinal.core._ +import spinal.lib._ +import scala.collection.mutable.ArrayBuffer + +/* Each 32-bit pmpcfg# register contains four 8-bit configuration sections. + * These section numbers contain flags which apply to regions defined by the + * corresponding pmpaddr# register. + * + * 3 2 1 + * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | pmp3cfg | pmp2cfg | pmp1cfg | pmp0cfg | pmpcfg0 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | pmp7cfg | pmp6cfg | pmp5cfg | pmp4cfg | pmpcfg2 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * 7 6 5 4 3 2 1 0 + * +-------+-------+-------+-------+-------+-------+-------+-------+ + * | L | 0 | A | X | W | R | pmp#cfg + * +-------+-------+-------+-------+-------+-------+-------+-------+ + * + * L: locks configuration until system reset (including M-mode) + * 0: hardwired to zero + * A: 0 = OFF (null region / disabled) + * 1 = TOR (top of range) + * 2 = NA4 (naturally aligned four-byte region) + * 3 = NAPOT (naturally aligned power-of-two region, > 7 bytes) + * X: execute + * W: write + * R: read + * + * TOR: Each 32-bit pmpaddr# register defines the upper bound of the pmp region + * right-shifted by two bits. The lower bound of the region is the previous + * pmpaddr# register. In the case of pmpaddr0, the lower bound is address 0x0. + * + * 3 2 1 + * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | address[33:2] | pmpaddr# + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * NAPOT: Each 32-bit pmpaddr# register defines the region address and the size + * of the pmp region. The number of concurrent 1s begging at the LSB indicates + * the size of the region as a power of two (e.g. 0x...0 = 8-byte, 0x...1 = + * 16-byte, 0x...11 = 32-byte, etc.). + * + * 3 2 1 + * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | address[33:2] |0|1|1|1|1| pmpaddr# + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * NA4: This is essentially an edge case of NAPOT where the entire pmpaddr# + * register defines a 4-byte wide region. + */ + +case class PmpRegister(previous : PmpRegister) extends Area { + + def OFF = 0 + def TOR = 1 + def NA4 = 2 + def NAPOT = 3 + + val state = new Area { + val r, w, x = Reg(Bool) + val l = RegInit(False) + val a = Reg(UInt(2 bits)) init(0) + val addr = Reg(UInt(32 bits)) + } + + // CSR writes connect to these signals rather than the internal state + // registers. This makes locking and WARL possible. + val csr = new Area { + val r, w, x = Bool + val l = Bool + val a = UInt(2 bits) + val addr = UInt(32 bits) + } + + // Last valid assignment wins; nothing happens if a user-initiated write did + // not occur on this clock cycle. + csr.r := state.r + csr.w := state.w + csr.x := state.x + csr.l := state.l + csr.a := state.a + csr.addr := state.addr + + // Computed PMP region bounds + val region = new Area { + val valid, locked = Bool + val start, end = UInt(32 bits) + } + + when(~state.l) { + state.r := csr.r + state.w := csr.w + state.x := csr.x + state.l := csr.l + state.a := csr.a + state.addr := csr.addr + + if (csr.l == True & csr.a == TOR) { + previous.state.l := True + } + } + + val shifted = state.addr |<< 2 + val mask = state.addr & ~(state.addr + 1) + val masked = (state.addr & ~mask) |<< 2 + + // PMP changes take effect two clock cycles after the initial CSR write (i.e., + // settings propagate from csr -> state -> region). + region.locked := state.l + region.valid := True + + switch(csr.a) { + is(TOR) { + if (previous == null) region.start := 0 + else region.start := previous.region.end + region.end := shifted + } + is(NA4) { + region.start := shifted + region.end := shifted + 4 + } + is(NAPOT) { + region.start := masked + region.end := masked + ((mask + 1) |<< 3) + } + default { + region.start := 0 + region.end := shifted + region.valid := False + } + } +} + + +class PmpPluginOld(regions : Int, ioRange : UInt => Bool) extends Plugin[VexRiscv] with MemoryTranslator { + + // Each pmpcfg# CSR configures four regions. + assert((regions % 4) == 0) + + val pmps = ArrayBuffer[PmpRegister]() + val portsInfo = ArrayBuffer[ProtectedMemoryTranslatorPort]() + + override def newTranslationPort(priority : Int, args : Any): MemoryTranslatorBus = { + val port = ProtectedMemoryTranslatorPort(MemoryTranslatorBus(new MemoryTranslatorBusParameter(0, 0))) + portsInfo += port + port.bus + } + + override def build(pipeline: VexRiscv): Unit = { + import pipeline.config._ + import pipeline._ + import Riscv._ + + val csrService = pipeline.service(classOf[CsrInterface]) + val privilegeService = pipeline.service(classOf[PrivilegeService]) + + val core = pipeline plug new Area { + + // Instantiate pmpaddr0 ... pmpaddr# CSRs. + for (i <- 0 until regions) { + if (i == 0) { + pmps += PmpRegister(null) + } else { + pmps += PmpRegister(pmps.last) + } + csrService.r(0x3b0 + i, pmps(i).state.addr) + csrService.w(0x3b0 + i, pmps(i).csr.addr) + } + + // Instantiate pmpcfg0 ... pmpcfg# CSRs. + for (i <- 0 until (regions / 4)) { + csrService.r(0x3a0 + i, + 31 -> pmps((i * 4) + 3).state.l, 23 -> pmps((i * 4) + 2).state.l, + 15 -> pmps((i * 4) + 1).state.l, 7 -> pmps((i * 4) ).state.l, + 27 -> pmps((i * 4) + 3).state.a, 26 -> pmps((i * 4) + 3).state.x, + 25 -> pmps((i * 4) + 3).state.w, 24 -> pmps((i * 4) + 3).state.r, + 19 -> pmps((i * 4) + 2).state.a, 18 -> pmps((i * 4) + 2).state.x, + 17 -> pmps((i * 4) + 2).state.w, 16 -> pmps((i * 4) + 2).state.r, + 11 -> pmps((i * 4) + 1).state.a, 10 -> pmps((i * 4) + 1).state.x, + 9 -> pmps((i * 4) + 1).state.w, 8 -> pmps((i * 4) + 1).state.r, + 3 -> pmps((i * 4) ).state.a, 2 -> pmps((i * 4) ).state.x, + 1 -> pmps((i * 4) ).state.w, 0 -> pmps((i * 4) ).state.r + ) + csrService.w(0x3a0 + i, + 31 -> pmps((i * 4) + 3).csr.l, 23 -> pmps((i * 4) + 2).csr.l, + 15 -> pmps((i * 4) + 1).csr.l, 7 -> pmps((i * 4) ).csr.l, + 27 -> pmps((i * 4) + 3).csr.a, 26 -> pmps((i * 4) + 3).csr.x, + 25 -> pmps((i * 4) + 3).csr.w, 24 -> pmps((i * 4) + 3).csr.r, + 19 -> pmps((i * 4) + 2).csr.a, 18 -> pmps((i * 4) + 2).csr.x, + 17 -> pmps((i * 4) + 2).csr.w, 16 -> pmps((i * 4) + 2).csr.r, + 11 -> pmps((i * 4) + 1).csr.a, 10 -> pmps((i * 4) + 1).csr.x, + 9 -> pmps((i * 4) + 1).csr.w, 8 -> pmps((i * 4) + 1).csr.r, + 3 -> pmps((i * 4) ).csr.a, 2 -> pmps((i * 4) ).csr.x, + 1 -> pmps((i * 4) ).csr.w, 0 -> pmps((i * 4) ).csr.r + ) + } + + // Connect memory ports to PMP logic. + val ports = for ((port, portId) <- portsInfo.zipWithIndex) yield new Area { + + val address = port.bus.cmd(0).virtualAddress + port.bus.rsp.physicalAddress := address + + // Only the first matching PMP region applies. + val hits = pmps.map(pmp => pmp.region.valid & + pmp.region.start <= address & + pmp.region.end > address & + (pmp.region.locked | ~privilegeService.isMachine())) + + // M-mode has full access by default, others have none. + when(CountOne(hits) === 0) { + port.bus.rsp.allowRead := privilegeService.isMachine() + port.bus.rsp.allowWrite := privilegeService.isMachine() + port.bus.rsp.allowExecute := privilegeService.isMachine() + } otherwise { + port.bus.rsp.allowRead := MuxOH(OHMasking.first(hits), pmps.map(_.state.r)) + port.bus.rsp.allowWrite := MuxOH(OHMasking.first(hits), pmps.map(_.state.w)) + port.bus.rsp.allowExecute := MuxOH(OHMasking.first(hits), pmps.map(_.state.x)) + } + + port.bus.rsp.isIoAccess := ioRange(port.bus.rsp.physicalAddress) + port.bus.rsp.isPaging := False + port.bus.rsp.exception := False + port.bus.rsp.refilling := False + port.bus.busy := False + + } + } + } +} From cc9f3e753a2e1b7554e10bf43635f0d2b8afed82 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 2 Sep 2021 14:14:42 +0200 Subject: [PATCH 710/951] Fix d$ toAxi bridge --- src/main/scala/vexriscv/ip/DataCache.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index 72de3436..f4b6b77a 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -268,7 +268,7 @@ case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave } def toAxi4Shared(stageCmd : Boolean = false, pendingWritesMax : Int = 7): Axi4Shared = { - val axi = Axi4Shared(p.getAxi4SharedConfig()) + val axi = Axi4Shared(p.getAxi4SharedConfig()).setName("dbus_axi") val cmdPreFork = if (stageCmd) cmd.stage.stage().s2mPipe() else cmd @@ -289,7 +289,7 @@ case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave axi.sharedCmd.cache := "1111" axi.sharedCmd.size := log2Up(p.memDataBytes) axi.sharedCmd.addr := cmdStage.address - axi.sharedCmd.len := cmd.beatCountMinusOne.resized + axi.sharedCmd.len := cmdStage.beatCountMinusOne.resized axi.writeData.arbitrationFrom(dataStage) axi.writeData.data := dataStage.data From 68e704f3092be640aa92c876cf78702a83167f94 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 2 Sep 2021 15:42:33 +0200 Subject: [PATCH 711/951] restore avalon d$ tests --- src/test/cpp/regression/main.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 82cc4d3c..4d9f2b85 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -2747,8 +2747,10 @@ public: virtual void preCycle(){ if ((top->dBusAvalon_read || top->dBusAvalon_write) && top->dBusAvalon_waitRequestn) { if(top->dBusAvalon_write){ + uint32_t size = __builtin_popcount(top->dBusAvalon_byteEnable); + uint32_t offset = ffs(top->dBusAvalon_byteEnable)-1; bool error_next = false; - ws->dBusAccess(top->dBusAvalon_address + beatCounter * 4,1,2,top->dBusAvalon_byteEnable,&top->dBusAvalon_writeData,&error_next); + ws->dBusAccess(top->dBusAvalon_address + beatCounter * 4 + offset,1,size,((uint8_t*)&top->dBusAvalon_writeData)+offset,&error_next); beatCounter++; if(beatCounter == top->dBusAvalon_burstCount){ beatCounter = 0; @@ -2756,7 +2758,7 @@ public: } else { for(int beat = 0;beat < top->dBusAvalon_burstCount;beat++){ DBusCachedAvalonTask rsp; - ws->dBusAccess(top->dBusAvalon_address + beat * 4,0,2,0,&rsp.data,&rsp.error); + ws->dBusAccess(top->dBusAvalon_address + beat * 4 ,0,4,((uint8_t*)&rsp.data),&rsp.error); rsps.push(rsp); } } From 42bb1ab5910c2b43b28dd1e7bcb312ad2f4f4159 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 15 Sep 2021 11:36:51 +0200 Subject: [PATCH 712/951] d$ / i$ toWishbone bridges can now be bigger than 32 bits https://github.com/m-labs/VexRiscv-verilog/pull/12 --- src/main/scala/vexriscv/ip/DataCache.scala | 11 ++++++----- src/main/scala/vexriscv/ip/InstructionCache.scala | 10 +++++----- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index e7bd1992..ccf4803b 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -77,9 +77,9 @@ case class DataCacheConfig(cacheSize : Int, ) def getWishboneConfig() = WishboneConfig( - addressWidth = 30, - dataWidth = 32, - selWidth = 4, + addressWidth = 32-log2Up(memDataWidth/8), + dataWidth = memDataWidth, + selWidth = memDataBytes, useSTALL = false, useLOCK = false, useERR = true, @@ -329,11 +329,12 @@ case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave val wishboneConfig = p.getWishboneConfig() val bus = Wishbone(wishboneConfig) val counter = Reg(UInt(log2Up(p.burstSize) bits)) init(0) + val addressShift = log2Up(p.memDataWidth/8) val cmdBridge = Stream (DataCacheMemCmd(p)) val isBurst = cmdBridge.isBurst cmdBridge.valid := cmd.valid - cmdBridge.address := (isBurst ? (cmd.address(31 downto widthOf(counter) + 2) @@ counter @@ U"00") | (cmd.address(31 downto 2) @@ U"00")) + cmdBridge.address := (isBurst ? (cmd.address(31 downto widthOf(counter) + addressShift) @@ counter @@ U(0, addressShift bits)) | (cmd.address(31 downto 2) @@ U(0, addressShift bits))) cmdBridge.wr := cmd.wr cmdBridge.mask := cmd.mask cmdBridge.data := cmd.data @@ -353,7 +354,7 @@ case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave bus.ADR := cmdBridge.address >> 2 bus.CTI := Mux(isBurst, cmdBridge.last ? B"111" | B"010", B"000") bus.BTE := B"00" - bus.SEL := cmdBridge.wr ? cmdBridge.mask | B"1111" + bus.SEL := cmdBridge.wr ? cmdBridge.mask | B((1 << p.memDataBytes)-1) bus.WE := cmdBridge.wr bus.DAT_MOSI := cmdBridge.data diff --git a/src/main/scala/vexriscv/ip/InstructionCache.scala b/src/main/scala/vexriscv/ip/InstructionCache.scala index ae8a80df..e09712cb 100644 --- a/src/main/scala/vexriscv/ip/InstructionCache.scala +++ b/src/main/scala/vexriscv/ip/InstructionCache.scala @@ -56,9 +56,9 @@ case class InstructionCacheConfig( cacheSize : Int, ) def getWishboneConfig() = WishboneConfig( - addressWidth = 30, - dataWidth = 32, - selWidth = 4, + addressWidth = 32-log2Up(memDataWidth/8), + dataWidth = memDataWidth, + selWidth = memDataWidth/8, useSTALL = false, useLOCK = false, useERR = true, @@ -228,10 +228,10 @@ case class InstructionCacheMemBus(p : InstructionCacheConfig) extends Bundle wit val pending = counter =/= 0 val lastCycle = counter === counter.maxValue - bus.ADR := (cmd.address >> widthOf(counter) + 2) @@ counter + bus.ADR := (cmd.address >> widthOf(counter) + log2Up(p.memDataWidth/8)) @@ counter bus.CTI := lastCycle ? B"111" | B"010" bus.BTE := "00" - bus.SEL := "1111" + bus.SEL.setAll() bus.WE := False bus.DAT_MOSI.assignDontCare() bus.CYC := False From c1481ae244870078bbed1d550defe73be9250fa3 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 16 Sep 2021 19:08:41 +0200 Subject: [PATCH 713/951] update ScopeProperty usages --- src/main/scala/vexriscv/Stage.scala | 4 +- src/main/scala/vexriscv/demo/Briey.scala | 88 ++++++++++--------- .../demo/smp/VexRiscvSmpCluster.scala | 4 +- 3 files changed, 50 insertions(+), 46 deletions(-) diff --git a/src/main/scala/vexriscv/Stage.scala b/src/main/scala/vexriscv/Stage.scala index d4099d6c..fe20d19d 100644 --- a/src/main/scala/vexriscv/Stage.scala +++ b/src/main/scala/vexriscv/Stage.scala @@ -15,10 +15,10 @@ class Stageable[T <: Data](_dataType : => T) extends HardType[T](_dataType) with class Stage() extends Area{ def outsideCondScope[T](that : => T) : T = { val body = Component.current.dslBody // Get the head of the current component symboles tree (AST in other words) - body.push() // Now all access to the SpinalHDL API will be append to it (instead of the current context) + val ctx = body.push() // Now all access to the SpinalHDL API will be append to it (instead of the current context) val swapContext = body.swap() // Empty the symbole tree (but keep a reference to the old content) val ret = that // Execute the block of code (will be added to the recently empty body) - body.pop() // Restore the original context in which this function was called + ctx.restore() // Restore the original context in which this function was called swapContext.appendBack() // append the original symboles tree to the modified body ret // return the value returned by that } diff --git a/src/main/scala/vexriscv/demo/Briey.scala b/src/main/scala/vexriscv/demo/Briey.scala index 76c688d9..40da56a8 100644 --- a/src/main/scala/vexriscv/demo/Briey.scala +++ b/src/main/scala/vexriscv/demo/Briey.scala @@ -51,52 +51,56 @@ object BrieyConfig{ ), cpuPlugins = ArrayBuffer( new PcManagerSimplePlugin(0x80000000l, false), - // new IBusSimplePlugin( - // interfaceKeepData = false, - // catchAccessFault = true - // ), - new IBusCachedPlugin( + new IBusSimplePlugin( resetVector = 0x80000000l, - prediction = STATIC, - config = InstructionCacheConfig( - cacheSize = 4096, - bytePerLine =32, - wayCount = 1, - addressWidth = 32, - cpuDataWidth = 32, - memDataWidth = 32, - catchIllegalAccess = true, - catchAccessFault = true, - asyncTagMemory = false, - twoCycleRam = true, - twoCycleCache = true - ) + cmdForkOnSecondStage = false, + cmdForkPersistence = true, + catchAccessFault = true, + compressedGen = true + ), +// new IBusCachedPlugin( +// resetVector = 0x80000000l, +// prediction = STATIC, +// compressedGen = true, +// config = InstructionCacheConfig( +// cacheSize = 4096, +// bytePerLine =32, +// wayCount = 1, +// addressWidth = 32, +// cpuDataWidth = 32, +// memDataWidth = 32, +// catchIllegalAccess = true, +// catchAccessFault = true, +// asyncTagMemory = false, +// twoCycleRam = true, +// twoCycleCache = true +// ) // askMemoryTranslation = true, // memoryTranslatorPortConfig = MemoryTranslatorPortConfig( // portTlbSize = 4 // ) - ), - // new DBusSimplePlugin( - // catchAddressMisaligned = true, - // catchAccessFault = true - // ), - new DBusCachedPlugin( - config = new DataCacheConfig( - cacheSize = 4096, - bytePerLine = 32, - wayCount = 1, - addressWidth = 32, - cpuDataWidth = 32, - memDataWidth = 32, - catchAccessError = true, - catchIllegal = true, - catchUnaligned = true - ), - memoryTranslatorPortConfig = null - // memoryTranslatorPortConfig = MemoryTranslatorPortConfig( - // portTlbSize = 6 - // ) - ), +// ), + new DBusSimplePlugin( + catchAddressMisaligned = true, + catchAccessFault = true + ), +// new DBusCachedPlugin( +// config = new DataCacheConfig( +// cacheSize = 4096, +// bytePerLine = 32, +// wayCount = 1, +// addressWidth = 32, +// cpuDataWidth = 32, +// memDataWidth = 32, +// catchAccessError = true, +// catchIllegal = true, +// catchUnaligned = true +// ), +// memoryTranslatorPortConfig = null +// // memoryTranslatorPortConfig = MemoryTranslatorPortConfig( +// // portTlbSize = 6 +// // ) +// ), new StaticMemoryTranslatorPlugin( ioRange = _(31 downto 28) === 0xF ), @@ -104,7 +108,7 @@ object BrieyConfig{ catchIllegalInstruction = true ), new RegFilePlugin( - regFileReadyKind = plugin.SYNC, + regFileReadyKind = plugin.ASYNC, zeroBoot = false ), new IntAluPlugin, diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index 0623c771..cb0d94bf 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -43,9 +43,9 @@ class VexRiscvSmpClusterBase(p : VexRiscvSmpClusterParameter) extends Area with systemCd.setInput(debugCd) - systemCd.outputClockDomain.push() + val ctx = systemCd.outputClockDomain.push() override def postInitCallback(): VexRiscvSmpClusterBase.this.type = { - systemCd.outputClockDomain.pop() + ctx.restore() this } From 65cda9517681f0a2714a05a0cdaf87bfe97a3f68 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 17 Sep 2021 09:43:30 +0200 Subject: [PATCH 714/951] Fix wishbone bridges with datawidth > 32 --- src/main/scala/vexriscv/ip/DataCache.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index ccf4803b..c5e2487d 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -334,7 +334,7 @@ case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave val cmdBridge = Stream (DataCacheMemCmd(p)) val isBurst = cmdBridge.isBurst cmdBridge.valid := cmd.valid - cmdBridge.address := (isBurst ? (cmd.address(31 downto widthOf(counter) + addressShift) @@ counter @@ U(0, addressShift bits)) | (cmd.address(31 downto 2) @@ U(0, addressShift bits))) + cmdBridge.address := (isBurst ? (cmd.address(31 downto widthOf(counter) + addressShift) @@ counter @@ U(0, addressShift bits)) | (cmd.address(31 downto addressShift) @@ U(0, addressShift bits))) cmdBridge.wr := cmd.wr cmdBridge.mask := cmd.mask cmdBridge.data := cmd.data @@ -351,7 +351,7 @@ case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave } - bus.ADR := cmdBridge.address >> 2 + bus.ADR := cmdBridge.address >> addressShift bus.CTI := Mux(isBurst, cmdBridge.last ? B"111" | B"010", B"000") bus.BTE := B"00" bus.SEL := cmdBridge.wr ? cmdBridge.mask | B((1 << p.memDataBytes)-1) From b807254759e78050dafb9c01b7a83137ec5cd1d0 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 22 Sep 2021 12:57:27 +0200 Subject: [PATCH 715/951] Briey and Murax verilators now use FST instead of VCD --- src/test/cpp/briey/main.cpp | 1 - src/test/cpp/briey/makefile | 2 +- src/test/cpp/briey/makefile~ | 38 --------------------------------- src/test/cpp/common/framework.h | 7 +++--- src/test/cpp/murax/makefile | 2 +- 5 files changed, 6 insertions(+), 44 deletions(-) delete mode 100644 src/test/cpp/briey/makefile~ diff --git a/src/test/cpp/briey/main.cpp b/src/test/cpp/briey/main.cpp index 0ee7c456..d2b372c5 100644 --- a/src/test/cpp/briey/main.cpp +++ b/src/test/cpp/briey/main.cpp @@ -6,7 +6,6 @@ #include "VBriey_RiscvCore.h" #endif #include "verilated.h" -#include "verilated_vcd_c.h" #include #include #include diff --git a/src/test/cpp/briey/makefile b/src/test/cpp/briey/makefile index 12d4c972..e0a024b0 100644 --- a/src/test/cpp/briey/makefile +++ b/src/test/cpp/briey/makefile @@ -13,7 +13,7 @@ ADDCFLAGS += -LDFLAGS -lSDL2 ifeq ($(TRACE),yes) VERILATOR_ARGS += --trace - ADDCFLAGS += -CFLAGS -DTRACE + ADDCFLAGS += -CFLAGS -DTRACE --trace-fst endif ifeq ($(DEBUG),yes) ADDCFLAGS += -CFLAGS "-g3 -O0" diff --git a/src/test/cpp/briey/makefile~ b/src/test/cpp/briey/makefile~ deleted file mode 100644 index b8345fd1..00000000 --- a/src/test/cpp/briey/makefile~ +++ /dev/null @@ -1,38 +0,0 @@ -DEBUG?=no -TRACE?=no -PRINT_PERF?=no -TRACE_START=0 -ADDCFLAGS += -CFLAGS -pthread - -ifeq ($(TRACE),yes) - VERILATOR_ARGS += --trace - ADDCFLAGS += -CFLAGS -DTRACE -endif -ifeq ($(DEBUG),yes) - ADDCFLAGS += -CFLAGS "-g3 -O0" -endif -ifneq ($(DEBUG),yes) - ADDCFLAGS += -CFLAGS "-O3" -endif -ifeq ($(PRINT_PERF),yes) - ADDCFLAGS += -CFLAGS -DPRINT_PERF -endif - -ADDCFLAGS += -CFLAGS -DTRACE_START=${TRACE_START} - - - -all: clean compile - -run: compile - ./obj_dir/VBriey - -verilate: - verilator -cc ../../../../Briey.v -CFLAGS -std=c++11 ${ADDCFLAGS} --gdbbt ${VERILATOR_ARGS} -Wno-WIDTH --x-assign unique --exe main.cpp - -compile: verilate - make -j -C obj_dir/ -f VBriey.mk VBriey - -clean: - rm -rf obj_dir - diff --git a/src/test/cpp/common/framework.h b/src/test/cpp/common/framework.h index 562d467f..42c1f34a 100644 --- a/src/test/cpp/common/framework.h +++ b/src/test/cpp/common/framework.h @@ -11,6 +11,7 @@ #include #include #include +#include "verilated_fst_c.h" using namespace std; @@ -140,7 +141,7 @@ public: string name; uint64_t time = 0; #ifdef TRACE - VerilatedVcdC* tfp; + VerilatedFstC* tfp; #endif ofstream logTraces; @@ -184,9 +185,9 @@ public: // init trace dump #ifdef TRACE Verilated::traceEverOn(true); - tfp = new VerilatedVcdC; + tfp = new VerilatedFstC; top->trace(tfp, 99); - tfp->open((string(name)+ ".vcd").c_str()); + tfp->open((string(name)+ ".fst").c_str()); #endif struct timespec start_time,tick_time; diff --git a/src/test/cpp/murax/makefile b/src/test/cpp/murax/makefile index 71a5cd67..7c946ae7 100644 --- a/src/test/cpp/murax/makefile +++ b/src/test/cpp/murax/makefile @@ -7,7 +7,7 @@ ADDCFLAGS += -CFLAGS -pthread -LDFLAGS -pthread ifeq ($(TRACE),yes) VERILATOR_ARGS += --trace - ADDCFLAGS += -CFLAGS -DTRACE + ADDCFLAGS += -CFLAGS -DTRACE --trace-fst endif ifeq ($(DEBUG),yes) ADDCFLAGS += -CFLAGS "-g3 -O0" From 5f5f4afbf2594cf95d9c1e0c71880dea83828a34 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 22 Sep 2021 15:01:08 +0200 Subject: [PATCH 716/951] Briey revert RVC unwanted addition --- src/main/scala/vexriscv/demo/Briey.scala | 90 +++++++++++------------- 1 file changed, 43 insertions(+), 47 deletions(-) diff --git a/src/main/scala/vexriscv/demo/Briey.scala b/src/main/scala/vexriscv/demo/Briey.scala index 40da56a8..709cb239 100644 --- a/src/main/scala/vexriscv/demo/Briey.scala +++ b/src/main/scala/vexriscv/demo/Briey.scala @@ -51,56 +51,52 @@ object BrieyConfig{ ), cpuPlugins = ArrayBuffer( new PcManagerSimplePlugin(0x80000000l, false), - new IBusSimplePlugin( + // new IBusSimplePlugin( + // interfaceKeepData = false, + // catchAccessFault = true + // ), + new IBusCachedPlugin( resetVector = 0x80000000l, - cmdForkOnSecondStage = false, - cmdForkPersistence = true, - catchAccessFault = true, - compressedGen = true - ), -// new IBusCachedPlugin( -// resetVector = 0x80000000l, -// prediction = STATIC, -// compressedGen = true, -// config = InstructionCacheConfig( -// cacheSize = 4096, -// bytePerLine =32, -// wayCount = 1, -// addressWidth = 32, -// cpuDataWidth = 32, -// memDataWidth = 32, -// catchIllegalAccess = true, -// catchAccessFault = true, -// asyncTagMemory = false, -// twoCycleRam = true, -// twoCycleCache = true -// ) + prediction = STATIC, + config = InstructionCacheConfig( + cacheSize = 4096, + bytePerLine =32, + wayCount = 1, + addressWidth = 32, + cpuDataWidth = 32, + memDataWidth = 32, + catchIllegalAccess = true, + catchAccessFault = true, + asyncTagMemory = false, + twoCycleRam = true, + twoCycleCache = true + ) // askMemoryTranslation = true, // memoryTranslatorPortConfig = MemoryTranslatorPortConfig( // portTlbSize = 4 // ) -// ), - new DBusSimplePlugin( - catchAddressMisaligned = true, - catchAccessFault = true - ), -// new DBusCachedPlugin( -// config = new DataCacheConfig( -// cacheSize = 4096, -// bytePerLine = 32, -// wayCount = 1, -// addressWidth = 32, -// cpuDataWidth = 32, -// memDataWidth = 32, -// catchAccessError = true, -// catchIllegal = true, -// catchUnaligned = true -// ), -// memoryTranslatorPortConfig = null -// // memoryTranslatorPortConfig = MemoryTranslatorPortConfig( -// // portTlbSize = 6 -// // ) -// ), + ), + // new DBusSimplePlugin( + // catchAddressMisaligned = true, + // catchAccessFault = true + // ), + new DBusCachedPlugin( + config = new DataCacheConfig( + cacheSize = 4096, + bytePerLine = 32, + wayCount = 1, + addressWidth = 32, + cpuDataWidth = 32, + memDataWidth = 32, + catchAccessError = true, + catchIllegal = true, + catchUnaligned = true + ), + memoryTranslatorPortConfig = null + // memoryTranslatorPortConfig = MemoryTranslatorPortConfig( + // portTlbSize = 6 + // ) + ), new StaticMemoryTranslatorPlugin( ioRange = _(31 downto 28) === 0xF ), @@ -108,7 +104,7 @@ object BrieyConfig{ catchIllegalInstruction = true ), new RegFilePlugin( - regFileReadyKind = plugin.ASYNC, + regFileReadyKind = plugin.SYNC, zeroBoot = false ), new IntAluPlugin, @@ -204,7 +200,7 @@ class Briey(config: BrieyConfig) extends Component{ val resetCtrl = new ClockingArea(resetCtrlClockDomain) { val systemResetUnbuffered = False -// val coreResetUnbuffered = False + // val coreResetUnbuffered = False //Implement an counter to keep the reset axiResetOrder high 64 cycles // Also this counter will automaticly do a reset when the system boot. From 8c0fbcadacb7070b4268ac97cbc6c4b3eab83146 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sat, 25 Sep 2021 13:18:55 +0200 Subject: [PATCH 717/951] Add BrieySim (SpinalSim) --- src/main/scala/vexriscv/demo/Briey.scala | 45 +++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/demo/Briey.scala b/src/main/scala/vexriscv/demo/Briey.scala index 709cb239..78d160cb 100644 --- a/src/main/scala/vexriscv/demo/Briey.scala +++ b/src/main/scala/vexriscv/demo/Briey.scala @@ -9,12 +9,15 @@ import spinal.lib._ import spinal.lib.bus.amba3.apb._ import spinal.lib.bus.amba4.axi._ import spinal.lib.com.jtag.Jtag +import spinal.lib.com.jtag.sim.JtagTcp +import spinal.lib.com.uart.sim.{UartDecoder, UartEncoder} import spinal.lib.com.uart.{Apb3UartCtrl, Uart, UartCtrlGenerics, UartCtrlMemoryMappedConfig} import spinal.lib.graphic.RgbConfig import spinal.lib.graphic.vga.{Axi4VgaCtrl, Axi4VgaCtrlGenerics, Vga} import spinal.lib.io.TriStateArray import spinal.lib.memory.sdram.SdramGeneration.SDR import spinal.lib.memory.sdram._ +import spinal.lib.memory.sdram.sdr.sim.SdramModel import spinal.lib.memory.sdram.sdr.{Axi4SharedSdramCtrl, IS42x320D, SdramInterface, SdramTimings} import spinal.lib.misc.HexTools import spinal.lib.soc.pinsec.{PinsecTimerCtrl, PinsecTimerCtrlExternal} @@ -160,7 +163,7 @@ object BrieyConfig{ -class Briey(config: BrieyConfig) extends Component{ +class Briey(val config: BrieyConfig) extends Component{ //Legacy constructor def this(axiFrequency: HertzNumber) { @@ -270,6 +273,7 @@ class Briey(config: BrieyConfig) extends Component{ val uartCtrl = Apb3UartCtrl(uartCtrlConfig) + uartCtrl.io.apb.addAttribute(Verilator.public) val vgaCtrlConfig = Axi4VgaCtrlGenerics( @@ -443,3 +447,42 @@ object BrieyDe0Nano{ }) } } + + + +import spinal.core.sim._ +object BrieySim { + def main(args: Array[String]): Unit = { + val simSlowDown = false + SimConfig.allOptimisation.compile(new Briey(BrieyConfig.default)).doSimUntilVoid{dut => + val mainClkPeriod = (1e12/dut.config.axiFrequency.toDouble).toLong + val jtagClkPeriod = mainClkPeriod*4 + val uartBaudRate = 115200 + val uartBaudPeriod = (1e12/uartBaudRate).toLong + + val clockDomain = ClockDomain(dut.io.axiClk, dut.io.asyncReset) + clockDomain.forkStimulus(mainClkPeriod) + + val tcpJtag = JtagTcp( + jtag = dut.io.jtag, + jtagClkPeriod = jtagClkPeriod + ) + + val uartTx = UartDecoder( + uartPin = dut.io.uart.txd, + baudPeriod = uartBaudPeriod + ) + + val uartRx = UartEncoder( + uartPin = dut.io.uart.rxd, + baudPeriod = uartBaudPeriod + ) + + val sdram = SdramModel( + dut.io.sdram, + dut.config.sdramLayout, + clockDomain + ) + } + } +} From 35754a070963a216a6673e454f0db4565ba8d993 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sat, 25 Sep 2021 13:28:37 +0200 Subject: [PATCH 718/951] Fix BrieySim (SpinalSim) --- src/main/scala/vexriscv/demo/Briey.scala | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/scala/vexriscv/demo/Briey.scala b/src/main/scala/vexriscv/demo/Briey.scala index 78d160cb..701af7bb 100644 --- a/src/main/scala/vexriscv/demo/Briey.scala +++ b/src/main/scala/vexriscv/demo/Briey.scala @@ -483,6 +483,8 @@ object BrieySim { dut.config.sdramLayout, clockDomain ) + + dut.io.coreInterrupt #= false } } } From 97a3c1955b05078390ee13e47e1cd65556597b65 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 8 Oct 2021 13:19:01 +0200 Subject: [PATCH 719/951] VexRiscvSmpCluster add d$ i$ less arg --- .../demo/smp/VexRiscvSmpCluster.scala | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index cb0d94bf..b247adfa 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -189,7 +189,9 @@ object VexRiscvSmpClusterGen { rvc : Boolean = false, iTlbSize : Int = 4, dTlbSize : Int = 4, - prediction : BranchPrediction = vexriscv.plugin.NONE + prediction : BranchPrediction = vexriscv.plugin.NONE, + withDataCache : Boolean = true, + withInstructionCache : Boolean = true ) = { assert(iCacheSize/iCacheWays <= 4096, "Instruction cache ways can't be bigger than 4096 bytes") assert(dCacheSize/dCacheWays <= 4096, "Data cache ways can't be bigger than 4096 bytes") @@ -229,7 +231,7 @@ object VexRiscvSmpClusterGen { ioRange = ioRange ), //Uncomment the whole IBusCachedPlugin and comment IBusSimplePlugin if you want cached iBus config - new IBusCachedPlugin( + if(withInstructionCache) new IBusCachedPlugin( resetVector = resetVector, compressedGen = rvc, prediction = prediction, @@ -257,8 +259,16 @@ object VexRiscvSmpClusterGen { earlyRequireMmuLockup = true, earlyCacheHits = true ) + ) else new IBusSimplePlugin( + resetVector = resetVector, + cmdForkOnSecondStage = false, + cmdForkPersistence = false, + prediction = NONE, + catchAccessFault = false, + compressedGen = rvc, + busLatencyMin = 2 ), - new DBusCachedPlugin( + if(withDataCache) new DBusCachedPlugin( dBusCmdMasterPipe = dBusCmdMasterPipe || dBusWidth == 32, dBusCmdSlavePipe = true, dBusRspSlavePipe = true, @@ -285,6 +295,10 @@ object VexRiscvSmpClusterGen { earlyRequireMmuLockup = true, earlyCacheHits = true ) + ) else new DBusSimplePlugin( + catchAddressMisaligned = false, + catchAccessFault = false, + earlyInjection = false ), new DecoderSimplePlugin( catchIllegalInstruction = true, From c3c3a94c5db5cb516bd6376d220c75ce1777a2d4 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 13 Oct 2021 16:26:16 +0200 Subject: [PATCH 720/951] IBusSimplePlugin can now use a Vec based buffer --- src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala | 3 ++- src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index b247adfa..54941d42 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -266,7 +266,8 @@ object VexRiscvSmpClusterGen { prediction = NONE, catchAccessFault = false, compressedGen = rvc, - busLatencyMin = 2 + busLatencyMin = 2, + vecRspBuffer = true ), if(withDataCache) new DBusCachedPlugin( dBusCmdMasterPipe = dBusCmdMasterPipe || dBusWidth == 32, diff --git a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala index 5780ce8a..1bb02bf2 100644 --- a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala @@ -236,7 +236,8 @@ class IBusSimplePlugin( resetVector : BigInt, val memoryTranslatorPortConfig : Any = null, relaxPredictorAddress : Boolean = true, predictionBuffer : Boolean = true, - bigEndian : Boolean = false + bigEndian : Boolean = false, + vecRspBuffer : Boolean = false ) extends IBusFetcherImpl( resetVector = resetVector, keepPcPlus4 = keepPcPlus4, @@ -351,7 +352,7 @@ class IBusSimplePlugin( resetVector : BigInt, //Manage flush for iBus transactions in flight val rspBuffer = new Area { val output = Stream(IBusSimpleRsp()) - val c = StreamFifoLowLatency(IBusSimpleRsp(), busLatencyMin + (if(cmdForkOnSecondStage && cmdForkPersistence) 1 else 0)) + val c = new StreamFifoLowLatency(IBusSimpleRsp(), busLatencyMin + (if(cmdForkOnSecondStage && cmdForkPersistence) 1 else 0), useVec = vecRspBuffer) val discardCounter = Reg(UInt(log2Up(pendingMax + 1) bits)) init (0) discardCounter := discardCounter - (c.io.pop.valid && discardCounter =/= 0).asUInt when(iBusRsp.flush) { From df03c99ab2a851c612d945afcc7165a8898b282c Mon Sep 17 00:00:00 2001 From: occheung Date: Tue, 19 Oct 2021 11:39:25 +0800 Subject: [PATCH 721/951] pmp_setter: fix mask generation --- src/main/scala/vexriscv/plugin/PmpPlugin.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/plugin/PmpPlugin.scala b/src/main/scala/vexriscv/plugin/PmpPlugin.scala index 10848910..54029d6d 100644 --- a/src/main/scala/vexriscv/plugin/PmpPlugin.scala +++ b/src/main/scala/vexriscv/plugin/PmpPlugin.scala @@ -90,7 +90,7 @@ class PmpSetter(cutoff : Int) extends Component with Pmp { val ones = io.addr & ~(io.addr + 1) io.base := io.addr(xlen - 3 downto cutoff - 2) ^ ones(xlen - 3 downto cutoff - 2) - io.mask := ~ones(xlen - 2 downto cutoff - 1) + io.mask := ~(ones(xlen - 4 downto cutoff - 2) @@ U"1") } case class ProtectedMemoryTranslatorPort(bus : MemoryTranslatorBus) From a3807660e37074215001a598a41bc84734438a58 Mon Sep 17 00:00:00 2001 From: occheung Date: Tue, 19 Oct 2021 11:40:39 +0800 Subject: [PATCH 722/951] pmp perm: revert to mux for priority --- src/main/scala/vexriscv/plugin/PmpPlugin.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/plugin/PmpPlugin.scala b/src/main/scala/vexriscv/plugin/PmpPlugin.scala index 54029d6d..35951e54 100644 --- a/src/main/scala/vexriscv/plugin/PmpPlugin.scala +++ b/src/main/scala/vexriscv/plugin/PmpPlugin.scala @@ -259,7 +259,7 @@ class PmpPlugin(regions : Int, granularity : Int, ioRange : UInt => Bool) extend } def getPermission(hits : IndexedSeq[Bool], bit : Int) = { - (hits zip state.pmpcfg).map({ case (i, cfg) => i & cfg(bit) }).orR + MuxOH(OHMasking.first(hits), state.pmpcfg.map(_(bit))) } val dGuard = new Area { From acf14385d8031d0acf449812f2074d4274240741 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 22 Oct 2021 17:24:51 +0200 Subject: [PATCH 723/951] #213 disable pmp test with region overlapping --- src/test/cpp/raw/pmp/build/pmp.asm | 181 ++++++++++++++--------------- src/test/cpp/raw/pmp/build/pmp.elf | Bin 5804 -> 5776 bytes src/test/cpp/raw/pmp/build/pmp.hex | 69 ++++++----- src/test/cpp/raw/pmp/build/pmp.map | 20 ++-- src/test/cpp/raw/pmp/src/crt.S | 10 +- 5 files changed, 136 insertions(+), 144 deletions(-) diff --git a/src/test/cpp/raw/pmp/build/pmp.asm b/src/test/cpp/raw/pmp/build/pmp.asm index 34ddcbf2..f8a30e2b 100644 --- a/src/test/cpp/raw/pmp/build/pmp.asm +++ b/src/test/cpp/raw/pmp/build/pmp.asm @@ -22,21 +22,21 @@ Disassembly of section .crt_section: 80000024 : 80000024: 00000e13 li t3,0 80000028: 00000f17 auipc t5,0x0 -8000002c: 340f0f13 addi t5,t5,832 # 80000368 +8000002c: 324f0f13 addi t5,t5,804 # 8000034c 80000030: 800000b7 lui ra,0x80000 80000034: 80008237 lui tp,0x80008 80000038: deadc137 lui sp,0xdeadc -8000003c: eef10113 addi sp,sp,-273 # deadbeef -80000040: 0020a023 sw sp,0(ra) # 80000000 -80000044: 00222023 sw sp,0(tp) # 80008000 +8000003c: eef10113 addi sp,sp,-273 # deadbeef +80000040: 0020a023 sw sp,0(ra) # 80000000 +80000044: 00222023 sw sp,0(tp) # 80008000 80000048: 0000a183 lw gp,0(ra) -8000004c: 30311e63 bne sp,gp,80000368 +8000004c: 30311063 bne sp,gp,8000034c 80000050: 00022183 lw gp,0(tp) # 0 <_start-0x80000000> -80000054: 30311a63 bne sp,gp,80000368 +80000054: 2e311c63 bne sp,gp,8000034c 80000058: 071a02b7 lui t0,0x71a0 8000005c: 3a029073 csrw pmpcfg0,t0 80000060: 3a002373 csrr t1,pmpcfg0 -80000064: 30629263 bne t0,t1,80000368 +80000064: 2e629463 bne t0,t1,8000034c 80000068: 1a1902b7 lui t0,0x1a190 8000006c: 30428293 addi t0,t0,772 # 1a190304 <_start-0x65e6fcfc> 80000070: 3a129073 csrw pmpcfg1,t0 @@ -44,14 +44,14 @@ Disassembly of section .crt_section: 80000078: 90a28293 addi t0,t0,-1782 # f090a <_start-0x7ff0f6f6> 8000007c: 3a229073 csrw pmpcfg2,t0 80000080: 3a202373 csrr t1,pmpcfg2 -80000084: 2e629263 bne t0,t1,80000368 +80000084: 2c629463 bne t0,t1,8000034c 80000088: 1c1e22b7 lui t0,0x1c1e2 8000008c: 90028293 addi t0,t0,-1792 # 1c1e1900 <_start-0x63e1e700> 80000090: 3a329073 csrw pmpcfg3,t0 80000094: 200002b7 lui t0,0x20000 80000098: 3b029073 csrw pmpaddr0,t0 8000009c: 3b002373 csrr t1,pmpaddr0 -800000a0: 2c629463 bne t0,t1,80000368 +800000a0: 2a629663 bne t0,t1,8000034c 800000a4: fff00293 li t0,-1 800000a8: 3b129073 csrw pmpaddr1,t0 800000ac: 202002b7 lui t0,0x20200 @@ -92,89 +92,89 @@ Disassembly of section .crt_section: 80000138: 0020a023 sw sp,0(ra) 8000013c: 00222023 sw sp,0(tp) # 0 <_start-0x80000000> 80000140: 0000a183 lw gp,0(ra) -80000144: 22311263 bne sp,gp,80000368 +80000144: 20311463 bne sp,gp,8000034c 80000148: 00000193 li gp,0 8000014c: 00022183 lw gp,0(tp) # 0 <_start-0x80000000> -80000150: 20311c63 bne sp,gp,80000368 +80000150: 1e311e63 bne sp,gp,8000034c 80000154 : 80000154: 00100e13 li t3,1 80000158: 00000f17 auipc t5,0x0 -8000015c: 210f0f13 addi t5,t5,528 # 80000368 +8000015c: 1f4f0f13 addi t5,t5,500 # 8000034c 80000160: 079a12b7 lui t0,0x79a1 80000164: 80828293 addi t0,t0,-2040 # 79a0808 <_start-0x7865f7f8> 80000168: 3a029073 csrw pmpcfg0,t0 8000016c: 3a002373 csrr t1,pmpcfg0 -80000170: 1e629c63 bne t0,t1,80000368 +80000170: 1c629e63 bne t0,t1,8000034c 80000174: 808000b7 lui ra,0x80800 80000178: deadc137 lui sp,0xdeadc -8000017c: eef10113 addi sp,sp,-273 # deadbeef -80000180: 0020a023 sw sp,0(ra) # 80800000 +8000017c: eef10113 addi sp,sp,-273 # deadbeef +80000180: 0020a023 sw sp,0(ra) # 80800000 80000184: 00000f17 auipc t5,0x0 80000188: 010f0f13 addi t5,t5,16 # 80000194 8000018c: 0000a183 lw gp,0(ra) -80000190: 1d80006f j 80000368 +80000190: 1bc0006f j 8000034c 80000194 : 80000194: 00200e13 li t3,2 80000198: 00000f17 auipc t5,0x0 -8000019c: 1d0f0f13 addi t5,t5,464 # 80000368 +8000019c: 1b4f0f13 addi t5,t5,436 # 8000034c 800001a0: 071a02b7 lui t0,0x71a0 800001a4: 3a029073 csrw pmpcfg0,t0 800001a8: 3a002373 csrr t1,pmpcfg0 -800001ac: 1a628e63 beq t0,t1,80000368 +800001ac: 1a628063 beq t0,t1,8000034c 800001b0: 3b305073 csrwi pmpaddr3,0 800001b4: 3b302373 csrr t1,pmpaddr3 -800001b8: 1a031863 bnez t1,80000368 +800001b8: 18031a63 bnez t1,8000034c 800001bc: 3b205073 csrwi pmpaddr2,0 800001c0: 3b202373 csrr t1,pmpaddr2 -800001c4: 1a030263 beqz t1,80000368 +800001c4: 18030463 beqz t1,8000034c 800001c8: 808000b7 lui ra,0x80800 800001cc: deadc137 lui sp,0xdeadc -800001d0: eef10113 addi sp,sp,-273 # deadbeef -800001d4: 0020a023 sw sp,0(ra) # 80800000 +800001d0: eef10113 addi sp,sp,-273 # deadbeef +800001d4: 0020a023 sw sp,0(ra) # 80800000 800001d8: 00000f17 auipc t5,0x0 800001dc: 010f0f13 addi t5,t5,16 # 800001e8 800001e0: 0000a183 lw gp,0(ra) -800001e4: 1840006f j 80000368 +800001e4: 1680006f j 8000034c 800001e8 : 800001e8: 00300e13 li t3,3 800001ec: 00000f17 auipc t5,0x0 -800001f0: 17cf0f13 addi t5,t5,380 # 80000368 +800001f0: 160f0f13 addi t5,t5,352 # 8000034c 800001f4: 00ff02b7 lui t0,0xff0 800001f8: 3b32a073 csrs pmpaddr3,t0 800001fc: 3b302373 csrr t1,pmpaddr3 -80000200: 16629463 bne t0,t1,80000368 +80000200: 14629663 bne t0,t1,8000034c 80000204: 0ff00293 li t0,255 80000208: 3b32a073 csrs pmpaddr3,t0 8000020c: 3b302373 csrr t1,pmpaddr3 80000210: 00ff02b7 lui t0,0xff0 80000214: 0ff28293 addi t0,t0,255 # ff00ff <_start-0x7f00ff01> -80000218: 14629863 bne t0,t1,80000368 +80000218: 12629a63 bne t0,t1,8000034c 8000021c: 00ff02b7 lui t0,0xff0 80000220: 3b32b073 csrc pmpaddr3,t0 80000224: 3b302373 csrr t1,pmpaddr3 80000228: 0ff00293 li t0,255 -8000022c: 12629e63 bne t0,t1,80000368 +8000022c: 12629063 bne t0,t1,8000034c 80000230: 00ff02b7 lui t0,0xff0 80000234: 0ff28293 addi t0,t0,255 # ff00ff <_start-0x7f00ff01> 80000238: 3a02b073 csrc pmpcfg0,t0 8000023c: 3a002373 csrr t1,pmpcfg0 80000240: 079a02b7 lui t0,0x79a0 -80000244: 12629263 bne t0,t1,80000368 +80000244: 10629463 bne t0,t1,8000034c 80000248: 00ff02b7 lui t0,0xff0 8000024c: 70728293 addi t0,t0,1799 # ff0707 <_start-0x7f00f8f9> 80000250: 3a02a073 csrs pmpcfg0,t0 80000254: 3a002373 csrr t1,pmpcfg0 80000258: 079a02b7 lui t0,0x79a0 8000025c: 70728293 addi t0,t0,1799 # 79a0707 <_start-0x7865f8f9> -80000260: 10629463 bne t0,t1,80000368 +80000260: 0e629663 bne t0,t1,8000034c 80000264 : 80000264: 00400e13 li t3,4 80000268: 00000f17 auipc t5,0x0 -8000026c: 100f0f13 addi t5,t5,256 # 80000368 +8000026c: 0e4f0f13 addi t5,t5,228 # 8000034c 80000270: 00000117 auipc sp,0x0 80000274: 01010113 addi sp,sp,16 # 80000280 80000278: 34111073 csrw mepc,sp @@ -183,83 +183,76 @@ Disassembly of section .crt_section: 80000280 : 80000280: 00500e13 li t3,5 80000284: 00000f17 auipc t5,0x0 -80000288: 0e4f0f13 addi t5,t5,228 # 80000368 +80000288: 0c8f0f13 addi t5,t5,200 # 8000034c 8000028c: deadc137 lui sp,0xdeadc -80000290: eef10113 addi sp,sp,-273 # deadbeef +80000290: eef10113 addi sp,sp,-273 # deadbeef 80000294: 808000b7 lui ra,0x80800 -80000298: 0020a023 sw sp,0(ra) # 80800000 +80000298: 0020a023 sw sp,0(ra) # 80800000 8000029c: 00000f17 auipc t5,0x0 800002a0: 010f0f13 addi t5,t5,16 # 800002ac 800002a4: 0000a183 lw gp,0(ra) -800002a8: 0c00006f j 80000368 +800002a8: 0a40006f j 8000034c 800002ac : 800002ac: 00600e13 li t3,6 -800002b0: 00000f17 auipc t5,0x0 -800002b4: 0b8f0f13 addi t5,t5,184 # 80000368 -800002b8: deadc137 lui sp,0xdeadc -800002bc: eef10113 addi sp,sp,-273 # deadbeef -800002c0: 880000b7 lui ra,0x88000 -800002c4: 0020a023 sw sp,0(ra) # 88000000 -800002c8: 0000a183 lw gp,0(ra) -800002cc : -800002cc: 00700e13 li t3,7 -800002d0: 00000f17 auipc t5,0x0 -800002d4: 098f0f13 addi t5,t5,152 # 80000368 -800002d8: 890000b7 lui ra,0x89000 -800002dc: ff008093 addi ra,ra,-16 # 88fffff0 -800002e0: 0000a183 lw gp,0(ra) -800002e4: 00000f17 auipc t5,0x0 -800002e8: 010f0f13 addi t5,t5,16 # 800002f4 -800002ec: 0030a023 sw gp,0(ra) -800002f0: 0780006f j 80000368 +800002b0 : +800002b0: 00700e13 li t3,7 +800002b4: 00000f17 auipc t5,0x0 +800002b8: 098f0f13 addi t5,t5,152 # 8000034c +800002bc: 890000b7 lui ra,0x89000 +800002c0: ff008093 addi ra,ra,-16 # 88fffff0 +800002c4: 0000a183 lw gp,0(ra) +800002c8: 00000f17 auipc t5,0x0 +800002cc: 010f0f13 addi t5,t5,16 # 800002d8 +800002d0: 0030a023 sw gp,0(ra) +800002d4: 0780006f j 8000034c -800002f4 : -800002f4: 00800e13 li t3,8 -800002f8: 00000f17 auipc t5,0x0 -800002fc: 014f0f13 addi t5,t5,20 # 8000030c -80000300: 00100493 li s1,1 -80000304: 3a305073 csrwi pmpcfg3,0 -80000308: 0600006f j 80000368 +800002d8 : +800002d8: 00800e13 li t3,8 +800002dc: 00000f17 auipc t5,0x0 +800002e0: 014f0f13 addi t5,t5,20 # 800002f0 +800002e4: 00100493 li s1,1 +800002e8: 3a305073 csrwi pmpcfg3,0 +800002ec: 0600006f j 8000034c -8000030c : -8000030c: 00800e13 li t3,8 -80000310: 1c1e22b7 lui t0,0x1c1e2 -80000314: 90028293 addi t0,t0,-1792 # 1c1e1900 <_start-0x63e1e700> -80000318: 3a302373 csrr t1,pmpcfg3 -8000031c: 04629663 bne t0,t1,80000368 +800002f0 : +800002f0: 00800e13 li t3,8 +800002f4: 1c1e22b7 lui t0,0x1c1e2 +800002f8: 90028293 addi t0,t0,-1792 # 1c1e1900 <_start-0x63e1e700> +800002fc: 3a302373 csrr t1,pmpcfg3 +80000300: 04629663 bne t0,t1,8000034c -80000320 : -80000320: 00900e13 li t3,9 -80000324: 00000f17 auipc t5,0x0 -80000328: 044f0f13 addi t5,t5,68 # 80000368 -8000032c: 00000493 li s1,0 -80000330: 00000117 auipc sp,0x0 -80000334: 01010113 addi sp,sp,16 # 80000340 -80000338: 34111073 csrw mepc,sp -8000033c: 30200073 mret +80000304 : +80000304: 00900e13 li t3,9 +80000308: 00000f17 auipc t5,0x0 +8000030c: 044f0f13 addi t5,t5,68 # 8000034c +80000310: 00000493 li s1,0 +80000314: 00000117 auipc sp,0x0 +80000318: 01010113 addi sp,sp,16 # 80000324 +8000031c: 34111073 csrw mepc,sp +80000320: 30200073 mret -80000340 : -80000340: 00900e13 li t3,9 -80000344: 00000f17 auipc t5,0x0 -80000348: 014f0f13 addi t5,t5,20 # 80000358 -8000034c: 00100493 li s1,1 -80000350: 3ba05073 csrwi pmpaddr10,0 -80000354: 0140006f j 80000368 +80000324 : +80000324: 00900e13 li t3,9 +80000328: 00000f17 auipc t5,0x0 +8000032c: 014f0f13 addi t5,t5,20 # 8000033c +80000330: 00100493 li s1,1 +80000334: 3ba05073 csrwi pmpaddr10,0 +80000338: 0140006f j 8000034c -80000358 : -80000358: 00900e13 li t3,9 -8000035c: fff00293 li t0,-1 -80000360: 3ba02373 csrr t1,pmpaddr10 -80000364: 00628863 beq t0,t1,80000374 +8000033c : +8000033c: 00900e13 li t3,9 +80000340: fff00293 li t0,-1 +80000344: 3ba02373 csrr t1,pmpaddr10 +80000348: 00628863 beq t0,t1,80000358 -80000368 : -80000368: f0100137 lui sp,0xf0100 -8000036c: f2410113 addi sp,sp,-220 # f00fff24 -80000370: 01c12023 sw t3,0(sp) +8000034c : +8000034c: f0100137 lui sp,0xf0100 +80000350: f2410113 addi sp,sp,-220 # f00fff24 +80000354: 01c12023 sw t3,0(sp) -80000374 : -80000374: f0100137 lui sp,0xf0100 -80000378: f2010113 addi sp,sp,-224 # f00fff20 -8000037c: 00012023 sw zero,0(sp) +80000358 : +80000358: f0100137 lui sp,0xf0100 +8000035c: f2010113 addi sp,sp,-224 # f00fff20 +80000360: 00012023 sw zero,0(sp) diff --git a/src/test/cpp/raw/pmp/build/pmp.elf b/src/test/cpp/raw/pmp/build/pmp.elf index c28d2cd523bee38e7cdf0e83e5a0a9c9325ecb76..f6c3c6984fdd02dd8f0dff4989811e35aacfbd11 100755 GIT binary patch delta 493 zcmY+9ze~eF6oBupEd`MzCTUvIHchQiP+QZ24v9k-K|yFYokWug4vMAs4}`i3MqcUA zK`J;pR61mJ6r9`~UEGVClU`b@@rHNzao_uOU-C+xjtAHILaZ4Sz^B;sliB5t8_N&KLV}=ycrQx;J(Po))x?$F#)hGcEnEwQH-iVXzj4<*1Pq zZRqT+TTV2R3R1USMdFN~R9^AP7ovmeRPWg`kTE~w;14<R6t!4wPT~$n&*D19yMX2Mqai^qnjDN8 z?0yaL9^-L{4;V)yfBrG!r4XMo-V8Biygz!8ix@ZIGf`kMs}!*dTP(i8nNo~369}1* GSEO$Z>U2N= delta 535 zcmY+By-UMD6u{qIkq(w5CjBC|Y1$4&v^6ajp~#<+ z(t@L+QY4Fun}gtApj%f_aTN6ROY0ln-H-QsclS6ud6BeLa(5h!PgpJh>t?yjQ+|PI zLU>w9Yqcl^Lr!ZBmEERIb7mZJMqSrfNeD;kddi6@Ay%cfX=ic{1r?n Date: Thu, 11 Nov 2021 12:12:23 +0100 Subject: [PATCH 724/951] Update DebugPlugin.scala Add readback of the hardware breakpoint values. A new parameter is added to the plugin to switch readback on and off. --- src/main/scala/vexriscv/plugin/DebugPlugin.scala | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/plugin/DebugPlugin.scala b/src/main/scala/vexriscv/plugin/DebugPlugin.scala index b7f621c3..cc7ca33d 100644 --- a/src/main/scala/vexriscv/plugin/DebugPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DebugPlugin.scala @@ -176,7 +176,7 @@ case class DebugExtensionIo() extends Bundle with IMasterSlave{ } } -class DebugPlugin(var debugClockDomain : ClockDomain, hardwareBreakpointCount : Int = 0) extends Plugin[VexRiscv] { +class DebugPlugin(var debugClockDomain : ClockDomain, hardwareBreakpointCount : Int = 0, BreakpointReadback : Boolean = false) extends Plugin[VexRiscv] { var io : DebugExtensionIo = null val injectionAsks = ArrayBuffer[(Stage, Bool)]() @@ -248,6 +248,17 @@ class DebugPlugin(var debugClockDomain : ClockDomain, hardwareBreakpointCount : io.bus.rsp.data(3) := haltedByBreak io.bus.rsp.data(4) := stepIt } + if (BreakpointReadback) { + switch(RegNext(io.bus.cmd.address(7 downto 2))) { + for(i <- 0 until hardwareBreakpointCount){ + is(0x10 + i){ + io.bus.rsp.data(31 downto 1) := hardwareBreakpoints(i).pc.asBits + io.bus.rsp.data(0) := hardwareBreakpoints(i).valid + } + } + } + } + injectionPort.valid := False injectionPort.payload := io.bus.cmd.data From 0539dd7110edca07bf981e99ed939f977d9aee1a Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 8 Dec 2021 23:45:05 +0100 Subject: [PATCH 725/951] SpinalHDL 1.6.2 --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index 293a83f3..9bec9476 100644 --- a/build.sbt +++ b/build.sbt @@ -1,4 +1,4 @@ -val spinalVersion = "1.6.1" +val spinalVersion = "1.6.2" lazy val root = (project in file(".")). settings( From 53a333034092159a6d726acfb5e1c2d0443f7f04 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sat, 18 Dec 2021 09:10:43 +0100 Subject: [PATCH 726/951] Update build.properties --- project/build.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/build.properties b/project/build.properties index 72f90289..0b2e09c5 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=1.2.7 +sbt.version=1.4.7 From a34079884093901842f20917b9a41638213f3eb9 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sat, 18 Dec 2021 09:11:08 +0100 Subject: [PATCH 727/951] Update build.properties --- project/build.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/build.properties b/project/build.properties index 72f90289..0b2e09c5 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=1.2.7 +sbt.version=1.4.7 From 4824827b7ed6331acfda1c2b0dd8c9fb7361cb96 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 20 Dec 2021 09:38:02 +0100 Subject: [PATCH 728/951] Enable scala 2.13 compatibility --- .../scala/spinal/lib/eda/icestorm/IcestormFlow.scala | 2 ++ src/main/scala/vexriscv/VexRiscv.scala | 9 +++++---- src/main/scala/vexriscv/demo/Briey.scala | 2 +- src/main/scala/vexriscv/demo/Murax.scala | 5 +++-- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/main/scala/spinal/lib/eda/icestorm/IcestormFlow.scala b/src/main/scala/spinal/lib/eda/icestorm/IcestormFlow.scala index b6ab7b52..6ef8d086 100644 --- a/src/main/scala/spinal/lib/eda/icestorm/IcestormFlow.scala +++ b/src/main/scala/spinal/lib/eda/icestorm/IcestormFlow.scala @@ -13,6 +13,8 @@ import spinal.lib.eda.bench.Report import scala.sys.process._ +import scala.collection.Seq + object IcestormFlow { def doCmd(cmd : Seq[String], path : String): String ={ println(cmd) diff --git a/src/main/scala/vexriscv/VexRiscv.scala b/src/main/scala/vexriscv/VexRiscv.scala index 2bc647db..d3feda3f 100644 --- a/src/main/scala/vexriscv/VexRiscv.scala +++ b/src/main/scala/vexriscv/VexRiscv.scala @@ -4,6 +4,7 @@ import vexriscv.plugin._ import spinal.core._ import scala.collection.mutable.ArrayBuffer +import scala.collection.Seq object VexRiscvConfig{ def apply(withMemoryStage : Boolean, withWriteBackStage : Boolean, plugins : Seq[Plugin[VexRiscv]]): VexRiscvConfig = { @@ -135,10 +136,10 @@ class VexRiscv(val config : VexRiscvConfig) extends Component with Pipeline{ plugins ++= config.plugins //regression usage - val lastStageInstruction = CombInit(stages.last.input(config.INSTRUCTION)) keep() addAttribute (Verilator.public) - val lastStagePc = CombInit(stages.last.input(config.PC)) keep() addAttribute (Verilator.public) - val lastStageIsValid = CombInit(stages.last.arbitration.isValid) keep() addAttribute (Verilator.public) - val lastStageIsFiring = CombInit(stages.last.arbitration.isFiring) keep() addAttribute (Verilator.public) + val lastStageInstruction = CombInit(stages.last.input(config.INSTRUCTION)).keep().addAttribute (Verilator.public) + val lastStagePc = CombInit(stages.last.input(config.PC)).keep().addAttribute(Verilator.public) + val lastStageIsValid = CombInit(stages.last.arbitration.isValid).keep().addAttribute(Verilator.public) + val lastStageIsFiring = CombInit(stages.last.arbitration.isFiring).keep().addAttribute(Verilator.public) //Verilator perf decode.arbitration.removeIt.noBackendCombMerge diff --git a/src/main/scala/vexriscv/demo/Briey.scala b/src/main/scala/vexriscv/demo/Briey.scala index 701af7bb..32e6d62e 100644 --- a/src/main/scala/vexriscv/demo/Briey.scala +++ b/src/main/scala/vexriscv/demo/Briey.scala @@ -24,7 +24,7 @@ import spinal.lib.soc.pinsec.{PinsecTimerCtrl, PinsecTimerCtrlExternal} import spinal.lib.system.debugger.{JtagAxi4SharedDebugger, JtagBridge, SystemDebugger, SystemDebuggerConfig} import scala.collection.mutable.ArrayBuffer - +import scala.collection.Seq case class BrieyConfig(axiFrequency : HertzNumber, onChipRamSize : BigInt, diff --git a/src/main/scala/vexriscv/demo/Murax.scala b/src/main/scala/vexriscv/demo/Murax.scala index 05c8e00e..7c679a12 100644 --- a/src/main/scala/vexriscv/demo/Murax.scala +++ b/src/main/scala/vexriscv/demo/Murax.scala @@ -16,6 +16,7 @@ import vexriscv.{VexRiscv, VexRiscvConfig, plugin} import spinal.lib.com.spi.ddr._ import spinal.lib.bus.simple._ import scala.collection.mutable.ArrayBuffer +import scala.collection.Seq /** * Created by PIC32F_USER on 28/07/2017. @@ -313,13 +314,13 @@ case class Murax(config : MuraxConfig) extends Component{ //******** Memory mappings ********* val apbDecoder = Apb3Decoder( master = apbBridge.io.apb, - slaves = apbMapping + slaves = apbMapping.toSeq ) val mainBusDecoder = new Area { val logic = new MuraxPipelinedMemoryBusDecoder( master = mainBusArbiter.io.masterBus, - specification = mainBusMapping, + specification = mainBusMapping.toSeq, pipelineMaster = pipelineMainBus ) } From 34e5cafb75142842dd8db7ed64d7d161ddbfd4ef Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 20 Dec 2021 09:38:02 +0100 Subject: [PATCH 729/951] Enable scala 2.13 compatibility --- .../scala/spinal/lib/eda/icestorm/IcestormFlow.scala | 2 ++ src/main/scala/vexriscv/VexRiscv.scala | 9 +++++---- src/main/scala/vexriscv/demo/Briey.scala | 2 +- src/main/scala/vexriscv/demo/Murax.scala | 5 +++-- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/main/scala/spinal/lib/eda/icestorm/IcestormFlow.scala b/src/main/scala/spinal/lib/eda/icestorm/IcestormFlow.scala index b6ab7b52..6ef8d086 100644 --- a/src/main/scala/spinal/lib/eda/icestorm/IcestormFlow.scala +++ b/src/main/scala/spinal/lib/eda/icestorm/IcestormFlow.scala @@ -13,6 +13,8 @@ import spinal.lib.eda.bench.Report import scala.sys.process._ +import scala.collection.Seq + object IcestormFlow { def doCmd(cmd : Seq[String], path : String): String ={ println(cmd) diff --git a/src/main/scala/vexriscv/VexRiscv.scala b/src/main/scala/vexriscv/VexRiscv.scala index 2bc647db..d3feda3f 100644 --- a/src/main/scala/vexriscv/VexRiscv.scala +++ b/src/main/scala/vexriscv/VexRiscv.scala @@ -4,6 +4,7 @@ import vexriscv.plugin._ import spinal.core._ import scala.collection.mutable.ArrayBuffer +import scala.collection.Seq object VexRiscvConfig{ def apply(withMemoryStage : Boolean, withWriteBackStage : Boolean, plugins : Seq[Plugin[VexRiscv]]): VexRiscvConfig = { @@ -135,10 +136,10 @@ class VexRiscv(val config : VexRiscvConfig) extends Component with Pipeline{ plugins ++= config.plugins //regression usage - val lastStageInstruction = CombInit(stages.last.input(config.INSTRUCTION)) keep() addAttribute (Verilator.public) - val lastStagePc = CombInit(stages.last.input(config.PC)) keep() addAttribute (Verilator.public) - val lastStageIsValid = CombInit(stages.last.arbitration.isValid) keep() addAttribute (Verilator.public) - val lastStageIsFiring = CombInit(stages.last.arbitration.isFiring) keep() addAttribute (Verilator.public) + val lastStageInstruction = CombInit(stages.last.input(config.INSTRUCTION)).keep().addAttribute (Verilator.public) + val lastStagePc = CombInit(stages.last.input(config.PC)).keep().addAttribute(Verilator.public) + val lastStageIsValid = CombInit(stages.last.arbitration.isValid).keep().addAttribute(Verilator.public) + val lastStageIsFiring = CombInit(stages.last.arbitration.isFiring).keep().addAttribute(Verilator.public) //Verilator perf decode.arbitration.removeIt.noBackendCombMerge diff --git a/src/main/scala/vexriscv/demo/Briey.scala b/src/main/scala/vexriscv/demo/Briey.scala index 701af7bb..32e6d62e 100644 --- a/src/main/scala/vexriscv/demo/Briey.scala +++ b/src/main/scala/vexriscv/demo/Briey.scala @@ -24,7 +24,7 @@ import spinal.lib.soc.pinsec.{PinsecTimerCtrl, PinsecTimerCtrlExternal} import spinal.lib.system.debugger.{JtagAxi4SharedDebugger, JtagBridge, SystemDebugger, SystemDebuggerConfig} import scala.collection.mutable.ArrayBuffer - +import scala.collection.Seq case class BrieyConfig(axiFrequency : HertzNumber, onChipRamSize : BigInt, diff --git a/src/main/scala/vexriscv/demo/Murax.scala b/src/main/scala/vexriscv/demo/Murax.scala index 05c8e00e..7c679a12 100644 --- a/src/main/scala/vexriscv/demo/Murax.scala +++ b/src/main/scala/vexriscv/demo/Murax.scala @@ -16,6 +16,7 @@ import vexriscv.{VexRiscv, VexRiscvConfig, plugin} import spinal.lib.com.spi.ddr._ import spinal.lib.bus.simple._ import scala.collection.mutable.ArrayBuffer +import scala.collection.Seq /** * Created by PIC32F_USER on 28/07/2017. @@ -313,13 +314,13 @@ case class Murax(config : MuraxConfig) extends Component{ //******** Memory mappings ********* val apbDecoder = Apb3Decoder( master = apbBridge.io.apb, - slaves = apbMapping + slaves = apbMapping.toSeq ) val mainBusDecoder = new Area { val logic = new MuraxPipelinedMemoryBusDecoder( master = mainBusArbiter.io.masterBus, - specification = mainBusMapping, + specification = mainBusMapping.toSeq, pipelineMaster = pipelineMainBus ) } From fe6c391fe434b36733b7819471060d0d459207f4 Mon Sep 17 00:00:00 2001 From: Oscar Shiang Date: Tue, 4 Jan 2022 16:31:23 +0800 Subject: [PATCH 730/951] Fix typo in Linux.scala Correct "machime" to "machine". --- src/main/scala/vexriscv/demo/Linux.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/demo/Linux.scala b/src/main/scala/vexriscv/demo/Linux.scala index 0010fa3a..8508a676 100644 --- a/src/main/scala/vexriscv/demo/Linux.scala +++ b/src/main/scala/vexriscv/demo/Linux.scala @@ -42,13 +42,13 @@ sbt "runMain vexriscv.demo.LinuxGen -r" cd src/test/cpp/regression make clean run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD DHRYSTONE=yes SUPERVISOR=yes MMU=yes CSR=yes DEBUG_PLUGIN=no COMPRESSED=no MUL=yes DIV=yes LRSC=yes AMO=yes REDO=10 TRACE=no COREMARK=yes LINUX_REGRESSION=yes -Run linux in simulation (Require the machime mode emulator compiled in SIM mode) => +Run linux in simulation (Require the machine mode emulator compiled in SIM mode) => sbt "runMain vexriscv.demo.LinuxGen" cd src/test/cpp/regression export BUILDROOT=/home/miaou/pro/riscv/buildrootSpinal make clean run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD SUPERVISOR=yes CSR=yes DEBUG_PLUGIN=no COMPRESSED=no LRSC=yes AMO=yes REDO=0 DHRYSTONE=no LINUX_SOC=yes EMULATOR=../../../main/c/emulator/build/emulator.bin VMLINUX=$BUILDROOT/output/images/Image DTB=$BUILDROOT/board/spinal/vexriscv_sim/rv32.dtb RAMDISK=$BUILDROOT/output/images/rootfs.cpio WITH_USER_IO=yes TRACE=no FLOW_INFO=no -Run linux with QEMU (Require the machime mode emulator compiled in QEMU mode) +Run linux with QEMU (Require the machine mode emulator compiled in QEMU mode) export BUILDROOT=/home/miaou/pro/riscv/buildrootSpinal qemu-system-riscv32 -nographic -machine virt -m 1536M -device loader,file=src/main/c/emulator/build/emulator.bin,addr=0x80000000,cpu-num=0 -device loader,file=$BUILDROOT/board/spinal/vexriscv_sim/rv32.dtb,addr=0xC3000000 -device loader,file=$BUILDROOT/output/images/Image,addr=0xC0000000 -device loader,file=$BUILDROOT/output/images/rootfs.cpio,addr=0xc2000000 From f46ad43f393cd345ca0f81ed716eaddcb7d76e4b Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 10 Jan 2022 13:39:41 +0100 Subject: [PATCH 731/951] DataCache.withInternalLrSc reserved clearing fix --- src/main/scala/vexriscv/ip/DataCache.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index c5e2487d..43bb9198 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -864,8 +864,8 @@ class DataCache(val p : DataCacheConfig, mmuParameter : MemoryTranslatorBusParam val lrSc = withInternalLrSc generate new Area{ val reserved = RegInit(False) - when(io.cpu.writeBack.isValid && !io.cpu.writeBack.isStuck && request.isLrsc){ - reserved := !request.wr + when(io.cpu.writeBack.isValid && !io.cpu.writeBack.isStuck && request.wr){ + reserved := False } } @@ -1167,4 +1167,4 @@ class DataCache(val p : DataCacheConfig, mmuParameter : MemoryTranslatorBusParam s1.invalidations := RegNextWhen((input.valid && input.enable && input.address(lineRange) === s0.input.address(lineRange)) ? wayHits | 0, s0.input.ready) } } -} \ No newline at end of file +} From da53de360f2ee9ca64375c2773b9cc2cb1fe8b28 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 10 Jan 2022 14:21:20 +0100 Subject: [PATCH 732/951] Fix lrsc from last commit --- src/main/scala/vexriscv/ip/DataCache.scala | 5 +++-- src/test/cpp/regression/main.cpp | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index 43bb9198..02d3e9a0 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -864,8 +864,9 @@ class DataCache(val p : DataCacheConfig, mmuParameter : MemoryTranslatorBusParam val lrSc = withInternalLrSc generate new Area{ val reserved = RegInit(False) - when(io.cpu.writeBack.isValid && !io.cpu.writeBack.isStuck && request.wr){ - reserved := False + when(io.cpu.writeBack.isValid && !io.cpu.writeBack.isStuck){ + reserved setWhen(request.isLrsc) + reserved clearWhen(request.wr) } } diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 82cc4d3c..b5df2ef8 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -898,6 +898,7 @@ public: status.fs = 3; pcWrite(pc + 4); } + lrscReserved = false; } break; #endif case 0x37:rfWrite(rd32, i & 0xFFFFF000);pcWrite(pc + 4);break; // LUI @@ -949,6 +950,7 @@ public: dWrite(pAddr, size, (uint8_t*)&i32_rs2); pcWrite(pc + 4); } + lrscReserved = false; }break; case 0x13: //ALUi switch ((i >> 12) & 0x7) { @@ -1107,9 +1109,7 @@ public: int32_t src = i32_rs2; int32_t readValue; - #ifdef DBUS_EXCLUSIVE lrscReserved = false; - #endif uint32_t pAddr; if(v2p(addr, &pAddr, READ_WRITE)){ trap(0, 15, addr); return; } From 6e77f320871e04663ea4c553a8e24cc55a925239 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 10 Jan 2022 16:08:38 +0100 Subject: [PATCH 733/951] sim golden model lrsc reservation sync --- src/test/cpp/regression/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index b5df2ef8..1b316e95 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -897,8 +897,8 @@ public: dWrite(pAddr, size, (uint8_t*) &rsp.value); status.fs = 3; pcWrite(pc + 4); + lrscReserved = false; } - lrscReserved = false; } break; #endif case 0x37:rfWrite(rd32, i & 0xFFFFF000);pcWrite(pc + 4);break; // LUI @@ -949,8 +949,8 @@ public: if(v2p(address, &pAddr, WRITE)){ trap(0, 15, address); return; } dWrite(pAddr, size, (uint8_t*)&i32_rs2); pcWrite(pc + 4); + lrscReserved = false; } - lrscReserved = false; }break; case 0x13: //ALUi switch ((i >> 12) & 0x7) { From b8e904e43f8284768c8b663f76a3385390330b7f Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 10 Jan 2022 19:55:28 +0100 Subject: [PATCH 734/951] syncronize golden model with dut for lrsc reservation --- src/main/scala/vexriscv/ip/DataCache.scala | 5 +++-- src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala | 1 + src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala | 5 +++-- src/test/cpp/regression/main.cpp | 7 +++++-- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index 02d3e9a0..b3cf4dc1 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -175,6 +175,7 @@ case class FenceFlags() extends Bundle { case class DataCacheCpuWriteBack(p : DataCacheConfig) extends Bundle with IMasterSlave{ val isValid = Bool() val isStuck = Bool() + val isFiring = Bool() val isUser = Bool() val haltIt = Bool() val isWrite = Bool() @@ -187,7 +188,7 @@ case class DataCacheCpuWriteBack(p : DataCacheConfig) extends Bundle with IMaste val exclusiveOk = Bool() override def asMaster(): Unit = { - out(isValid,isStuck,isUser, address, fence, storeData) + out(isValid,isStuck,isUser, address, fence, storeData, isFiring) in(haltIt, data, mmuException, unalignedAccess, accessError, isWrite, keepMemRspData, exclusiveOk) } } @@ -864,7 +865,7 @@ class DataCache(val p : DataCacheConfig, mmuParameter : MemoryTranslatorBusParam val lrSc = withInternalLrSc generate new Area{ val reserved = RegInit(False) - when(io.cpu.writeBack.isValid && !io.cpu.writeBack.isStuck){ + when(io.cpu.writeBack.isValid && io.cpu.writeBack.isFiring){ reserved setWhen(request.isLrsc) reserved clearWhen(request.wr) } diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index 99786e7f..3fb64988 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -395,6 +395,7 @@ class DBusCachedPlugin(val config : DataCacheConfig, import managementStage._ cache.io.cpu.writeBack.isValid := arbitration.isValid && input(MEMORY_ENABLE) cache.io.cpu.writeBack.isStuck := arbitration.isStuck + cache.io.cpu.writeBack.isFiring := arbitration.isFiring cache.io.cpu.writeBack.isUser := (if(privilegeService != null) privilegeService.isUser() else False) cache.io.cpu.writeBack.address := U(input(REGFILE_WRITE_DATA)) cache.io.cpu.writeBack.storeData.subdivideIn(32 bits).foreach(_ := input(MEMORY_STORE_DATA_RF)) diff --git a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala index ac22dc42..d96d3120 100644 --- a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala @@ -462,8 +462,9 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, val atomic = withLrSc generate new Area{ val reserved = RegInit(False) insert(ATOMIC_HIT) := reserved - when(arbitration.isFiring && input(MEMORY_ENABLE) && input(MEMORY_ATOMIC) && (if(mmuBus != null) !input(MMU_FAULT) else True) && !skipCmd){ - reserved := !input(MEMORY_STORE) + when(arbitration.isFiring && input(MEMORY_ENABLE) && (if(mmuBus != null) !input(MMU_FAULT) else True) && !skipCmd){ + reserved setWhen(input(MEMORY_ATOMIC)) + reserved clearWhen(input(MEMORY_STORE)) } when(input(MEMORY_STORE) && input(MEMORY_ATOMIC) && !input(ATOMIC_HIT)){ skipCmd := True diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 1b316e95..0178001b 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -949,7 +949,7 @@ public: if(v2p(address, &pAddr, WRITE)){ trap(0, 15, address); return; } dWrite(pAddr, size, (uint8_t*)&i32_rs2); pcWrite(pc + 4); - lrscReserved = false; + lrscReserved = false; } }break; case 0x13: //ALUi @@ -1111,6 +1111,7 @@ public: lrscReserved = false; + uint32_t pAddr; if(v2p(addr, &pAddr, READ_WRITE)){ trap(0, 15, addr); return; } if(dRead(pAddr, 4, (uint8_t*)&readValue)){ @@ -1178,6 +1179,7 @@ public: if(v2p(address, &pAddr, WRITE)){ trap(0, 15, address); return; } dWrite(pAddr, 4, (uint8_t*)&i16_rf2); pcWrite(pc + 2); + lrscReserved = false; } }break; case 8: rfWrite(rd32, regs[rd32] + i16_imm); pcWrite(pc + 2); break; @@ -1243,6 +1245,7 @@ public: } else { if(v2p(address, &pAddr, WRITE)){ trap(0, 15, address); return; } dWrite(pAddr, 4, (uint8_t*)®s[iBits(2,5)]); pcWrite(pc + 2); + lrscReserved = false; } }break; } @@ -2610,7 +2613,6 @@ public: bool hit = reservationValid && reservationAddress == top->dBus_cmd_payload_address; rsp.exclusive = hit; cancel = !hit; - reservationValid = false; } if(!cancel) { for(int idx = 0;idx < 1;idx++){ @@ -2621,6 +2623,7 @@ public: } } + reservationValid = false; rsp.last = true; rsp.error = error; rsps.push(rsp); From 9c34a1fd2e2bf4bb313bed8169bc4bcb3bb1b6fc Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 14 Jan 2022 09:59:22 +0100 Subject: [PATCH 735/951] updated related to JtagInstructionWrapper.ignoreWidth --- src/main/scala/vexriscv/VexRiscvBmbGenerator.scala | 2 +- src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala | 3 ++- .../scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala | 6 ++++-- src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala | 4 ++-- src/main/scala/vexriscv/plugin/DebugPlugin.scala | 8 ++++---- 5 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/main/scala/vexriscv/VexRiscvBmbGenerator.scala b/src/main/scala/vexriscv/VexRiscvBmbGenerator.scala index 723ea7de..3ff33340 100644 --- a/src/main/scala/vexriscv/VexRiscvBmbGenerator.scala +++ b/src/main/scala/vexriscv/VexRiscvBmbGenerator.scala @@ -113,7 +113,7 @@ case class VexRiscvBmbGenerator()(implicit interconnectSmp: BmbInterconnectGener withDebug.get match { case DEBUG_JTAG => jtag <> plugin.io.bus.fromJtag() - case DEBUG_JTAG_CTRL => jtagInstructionCtrl <> plugin.io.bus.fromJtagInstructionCtrl(jtagClockDomain) + case DEBUG_JTAG_CTRL => jtagInstructionCtrl <> plugin.io.bus.fromJtagInstructionCtrl(jtagClockDomain, 0) case DEBUG_BUS => debugBus <> plugin.io.bus case DEBUG_BMB => debugBmb >> plugin.io.bus.fromBmb() } diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index 54941d42..743d2c27 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -26,6 +26,7 @@ import spinal.lib.generator._ import vexriscv.ip.fpu.FpuParameter case class VexRiscvSmpClusterParameter(cpuConfigs : Seq[VexRiscvConfig], + jtagHeaderIgnoreWidth : Int, withExclusiveAndInvalidation : Boolean, forcePeripheralWidth : Boolean = true, outOfOrderDecoder : Boolean = true, @@ -51,7 +52,7 @@ class VexRiscvSmpClusterBase(p : VexRiscvSmpClusterParameter) extends Area with implicit val interconnect = BmbInterconnectGenerator() - val debugBridge = debugCd.outputClockDomain on JtagInstructionDebuggerGenerator() + val debugBridge = debugCd.outputClockDomain on JtagInstructionDebuggerGenerator(p.jtagHeaderIgnoreWidth) debugBridge.jtagClockDomain.load(ClockDomain.external("jtag", withReset = false)) val debugPort = Handle(debugBridge.logic.jtagBridge.io.ctrl.toIo) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala index 7a20b300..4cd4917a 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala @@ -175,7 +175,8 @@ object VexRiscvLitexSmpClusterCmdGen extends App { withExclusiveAndInvalidation = coherency, forcePeripheralWidth = !wishboneMemory, outOfOrderDecoder = outOfOrderDecoder, - fpu = fpu + fpu = fpu, + jtagHeaderIgnoreWidth = 0 ), liteDram = LiteDramNativeParameter(addressWidth = 32, dataWidth = liteDramWidth), liteDramMapping = SizeMapping(0x40000000l, 0x40000000l), @@ -250,7 +251,8 @@ object VexRiscvLitexSmpClusterOpenSbi extends App{ resetVector = 0x80000000l ) }, - withExclusiveAndInvalidation = true + withExclusiveAndInvalidation = true, + jtagHeaderIgnoreWidth = 0 ), liteDram = LiteDramNativeParameter(addressWidth = 32, dataWidth = 128), liteDramMapping = SizeMapping(0x80000000l, 0x70000000l), diff --git a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala index d96d3120..094de174 100644 --- a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala @@ -567,8 +567,8 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, } } - if(!earlyInjection && !emitCmdInMemoryStage && config.withWriteBackStage) - assert(!(arbitration.isValid && input(MEMORY_ENABLE) && !input(MEMORY_STORE) && arbitration.isStuck),"DBusSimplePlugin doesn't allow writeback stage stall when read happend") +// if(!earlyInjection && !emitCmdInMemoryStage && config.withWriteBackStage) +// assert(!(arbitration.isValid && input(MEMORY_ENABLE) && !input(MEMORY_STORE) && arbitration.isStuck),"DBusSimplePlugin doesn't allow writeback stage stall when read happend") //formal insert(FORMAL_MEM_RDATA) := input(MEMORY_READ_DATA) diff --git a/src/main/scala/vexriscv/plugin/DebugPlugin.scala b/src/main/scala/vexriscv/plugin/DebugPlugin.scala index cc7ca33d..87d4f569 100644 --- a/src/main/scala/vexriscv/plugin/DebugPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DebugPlugin.scala @@ -137,13 +137,13 @@ case class DebugExtensionBus() extends Bundle with IMasterSlave{ jtagBridge.io.jtag } - def fromJtagInstructionCtrl(jtagClockDomain : ClockDomain): JtagTapInstructionCtrl ={ + def fromJtagInstructionCtrl(jtagClockDomain : ClockDomain, jtagHeaderIgnoreWidth : Int): JtagTapInstructionCtrl ={ val jtagConfig = SystemDebuggerConfig( memAddressWidth = 32, memDataWidth = 32, remoteCmdWidth = 1 ) - val jtagBridge = new JtagBridgeNoTap(jtagConfig, jtagClockDomain) + val jtagBridge = new JtagBridgeNoTap(jtagConfig, jtagClockDomain, jtagHeaderIgnoreWidth) val debugger = new SystemDebugger(jtagConfig) debugger.io.remote <> jtagBridge.io.remote debugger.io.mem <> this.from(jtagConfig) @@ -151,13 +151,13 @@ case class DebugExtensionBus() extends Bundle with IMasterSlave{ jtagBridge.io.ctrl } - def fromBscane2(usedId : Int): Unit ={ + def fromBscane2(usedId : Int, jtagHeaderIgnoreWidth : Int): Unit ={ val jtagConfig = SystemDebuggerConfig() val bscane2 = BSCANE2(usedId) val jtagClockDomain = ClockDomain(bscane2.TCK) - val jtagBridge = new JtagBridgeNoTap(jtagConfig, jtagClockDomain) + val jtagBridge = new JtagBridgeNoTap(jtagConfig, jtagClockDomain, jtagHeaderIgnoreWidth) jtagBridge.io.ctrl << bscane2.toJtagTapInstructionCtrl() val debugger = new SystemDebugger(jtagConfig) From 57dd80a5667af6e06f8f7886abefd16d70749d9f Mon Sep 17 00:00:00 2001 From: Daniel Schultz Date: Wed, 26 Jan 2022 08:59:03 +0100 Subject: [PATCH 736/951] plugin: CsrPlugin: Init cycle and instret registers Both counters are initialized with "randBoot()". This is fine for FPGA designs because the registers can be loaded with default values but ASIC designs require to load the value during a reset. Since both counters require to start at 0 (read-only CSR registers), change both registers from "randBoot()" to "init(0)". Error: reg [63:0] CsrPlugin_mcycle = 64'b0000000...00000000000; | Warning : Ignoring unsynthesizable construct. [VLOGPT-37] Signed-off-by: Daniel Schultz --- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 60d1b34f..bd48928c 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -689,8 +689,8 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep val exceptionCode = Reg(UInt(trapCodeWidth bits)) } val mtval = Reg(UInt(xlen bits)) - val mcycle = Reg(UInt(64 bits)) randBoot() - val minstret = Reg(UInt(64 bits)) randBoot() + val mcycle = Reg(UInt(64 bits)) init(0) + val minstret = Reg(UInt(64 bits)) init(0) val medeleg = supervisorGen generate new Area { From 8b2f107d46200793202679ec10be412bd15ca47a Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 4 Feb 2022 15:10:57 +0100 Subject: [PATCH 737/951] verilator++ --- README.md | 2 +- src/test/cpp/regression/main.cpp | 124 ++++++++++++++++--------------- 2 files changed, 64 insertions(+), 62 deletions(-) diff --git a/README.md b/README.md index 8f2eb813..1a8864be 100644 --- a/README.md +++ b/README.md @@ -182,7 +182,7 @@ unsetenv VERILATOR_ROOT # For csh; ignore error if on bash unset VERILATOR_ROOT # For bash cd verilator git pull # Make sure we're up-to-date -git checkout v4.040 +git checkout v4.216 autoconf # Create ./configure script ./configure make diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 0178001b..3981b873 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -20,6 +20,8 @@ #include #include "encoding.h" +#define VL_RANDOM_I_WIDTH(w) (VL_RANDOM_I() & (1l << w)-1l) + using namespace std; struct timespec timer_get(){ @@ -1440,7 +1442,7 @@ public: } Workspace(string name){ vcdName = name; - //seed = VL_RANDOM_I(32)^VL_RANDOM_I(32)^0x1093472; + //seed = VL_RANDOM_I_WIDTH(32)^VL_RANDOM_I_WIDTH(32)^0x1093472; //srand48(seed); // setIStall(false); // setDStall(false); @@ -1853,9 +1855,9 @@ public: for(SimElement* simElement : simElements) simElement->postCycle(); #ifdef RVF - top->fpuCmdHalt = VL_RANDOM_I(1); - top->fpuCommitHalt = VL_RANDOM_I(1); - top->fpuRspHalt = VL_RANDOM_I(1); + top->fpuCmdHalt = VL_RANDOM_I_WIDTH(1); + top->fpuCommitHalt = VL_RANDOM_I_WIDTH(1); + top->fpuRspHalt = VL_RANDOM_I_WIDTH(1); #endif @@ -2052,7 +2054,7 @@ public: //TODO doesn't catch when instruction removed ? virtual void postCycle(){ top->iBus_rsp_valid = 0; - if(rPtr != wPtr && (!ws->iStall || VL_RANDOM_I(7) < 100)){ + if(rPtr != wPtr && (!ws->iStall || VL_RANDOM_I_WIDTH(7) < 100)){ uint32_t inst_next; bool error_next; ws->iBusAccess(pendings[rPtr], &inst_next,&error_next); @@ -2061,10 +2063,10 @@ public: top->iBus_rsp_valid = 1; top->iBus_rsp_payload_error = error_next; } else { - top->iBus_rsp_payload_inst = VL_RANDOM_I(32); - top->iBus_rsp_payload_error = VL_RANDOM_I(1); + top->iBus_rsp_payload_inst = VL_RANDOM_I_WIDTH(32); + top->iBus_rsp_payload_error = VL_RANDOM_I_WIDTH(1); } - if(ws->iStall) top->iBus_cmd_ready = VL_RANDOM_I(7) < 100; + if(ws->iStall) top->iBus_cmd_ready = VL_RANDOM_I_WIDTH(7) < 100; } }; #endif @@ -2139,18 +2141,18 @@ public: } //TODO doesn't catch when instruction removed ? virtual void postCycle(){ - if(!rsps.empty() && (!ws->iStall || VL_RANDOM_I(7) < 100)){ + if(!rsps.empty() && (!ws->iStall || VL_RANDOM_I_WIDTH(7) < 100)){ IBusSimpleAvalonRsp rsp = rsps.front(); rsps.pop(); top->iBusAvalon_readDataValid = 1; top->iBusAvalon_readData = rsp.data; top->iBusAvalon_response = rsp.error ? 3 : 0; } else { top->iBusAvalon_readDataValid = 0; - top->iBusAvalon_readData = VL_RANDOM_I(32); - top->iBusAvalon_response = VL_RANDOM_I(2); + top->iBusAvalon_readData = VL_RANDOM_I_WIDTH(32); + top->iBusAvalon_response = VL_RANDOM_I_WIDTH(2); } if(ws->iStall) - top->iBusAvalon_waitRequestn = VL_RANDOM_I(7) < 100; + top->iBusAvalon_waitRequestn = VL_RANDOM_I_WIDTH(7) < 100; } }; #endif @@ -2187,15 +2189,15 @@ public: virtual void postCycle(){ if(ws->iStall) - top->iBusAhbLite3_HREADY = (!ws->iStall || VL_RANDOM_I(7) < 100); + top->iBusAhbLite3_HREADY = (!ws->iStall || VL_RANDOM_I_WIDTH(7) < 100); if(pending && top->iBusAhbLite3_HREADY){ top->iBusAhbLite3_HRDATA = iBusAhbLite3_HRDATA; top->iBusAhbLite3_HRESP = iBusAhbLite3_HRESP; pending = false; } else { - top->iBusAhbLite3_HRDATA = VL_RANDOM_I(32); - top->iBusAhbLite3_HRESP = VL_RANDOM_I(1); + top->iBusAhbLite3_HRDATA = VL_RANDOM_I_WIDTH(32); + top->iBusAhbLite3_HRESP = VL_RANDOM_I_WIDTH(1); } } }; @@ -2233,7 +2235,7 @@ public: virtual void postCycle(){ bool error; top->iBus_rsp_valid = 0; - if(pendingCount != 0 && (!ws->iStall || VL_RANDOM_I(7) < 100)){ + if(pendingCount != 0 && (!ws->iStall || VL_RANDOM_I_WIDTH(7) < 100)){ #ifdef IBUS_TC if((address & 0x70000000) == 0){ printf("IBUS_CACHED access out of range\n"); @@ -2251,7 +2253,7 @@ public: address = address + IBUS_DATA_WIDTH/8; top->iBus_rsp_valid = 1; } - if(ws->iStall) top->iBus_cmd_ready = VL_RANDOM_I(7) < 100 && pendingCount == 0; + if(ws->iStall) top->iBus_cmd_ready = VL_RANDOM_I_WIDTH(7) < 100 && pendingCount == 0; } }; #endif @@ -2266,7 +2268,7 @@ struct IBusCachedAvalonTask{ class IBusCachedAvalon : public SimElement{ public: - uint32_t inst_next = VL_RANDOM_I(32); + uint32_t inst_next = VL_RANDOM_I_WIDTH(32); bool error_next = false; queue tasks; @@ -2296,7 +2298,7 @@ public: virtual void postCycle(){ bool error; top->iBusAvalon_readDataValid = 0; - if(!tasks.empty() && (!ws->iStall || VL_RANDOM_I(7) < 100)){ + if(!tasks.empty() && (!ws->iStall || VL_RANDOM_I_WIDTH(7) < 100)){ uint32_t &address = tasks.front().address; uint32_t &pendingCount = tasks.front().pendingCount; bool error; @@ -2309,7 +2311,7 @@ public: tasks.pop(); } if(ws->iStall) - top->iBusAvalon_waitRequestn = VL_RANDOM_I(7) < 100; + top->iBusAvalon_waitRequestn = VL_RANDOM_I_WIDTH(7) < 100; } }; #endif @@ -2341,9 +2343,9 @@ public: virtual void postCycle(){ if(ws->iStall) - top->iBusWishbone_ACK = VL_RANDOM_I(7) < 100; + top->iBusWishbone_ACK = VL_RANDOM_I_WIDTH(7) < 100; - top->iBusWishbone_DAT_MISO = VL_RANDOM_I(32); + top->iBusWishbone_DAT_MISO = VL_RANDOM_I_WIDTH(32); if (top->iBusWishbone_CYC && top->iBusWishbone_STB && top->iBusWishbone_ACK) { if(top->iBusWishbone_WE){ @@ -2361,7 +2363,7 @@ public: #ifdef DBUS_SIMPLE class DBusSimple : public SimElement{ public: - uint32_t data_next = VL_RANDOM_I(32); + uint32_t data_next = VL_RANDOM_I_WIDTH(32); bool error_next = false; bool pending = false; @@ -2387,16 +2389,16 @@ public: virtual void postCycle(){ top->dBus_rsp_ready = 0; - if(pending && (!ws->dStall || VL_RANDOM_I(7) < 100)){ + if(pending && (!ws->dStall || VL_RANDOM_I_WIDTH(7) < 100)){ pending = false; top->dBus_rsp_ready = 1; top->dBus_rsp_data = data_next; top->dBus_rsp_error = error_next; } else{ - top->dBus_rsp_data = VL_RANDOM_I(32); + top->dBus_rsp_data = VL_RANDOM_I_WIDTH(32); } - if(ws->dStall) top->dBus_cmd_ready = VL_RANDOM_I(7) < 100 && !pending; + if(ws->dStall) top->dBus_cmd_ready = VL_RANDOM_I_WIDTH(7) < 100 && !pending; } }; #endif @@ -2438,18 +2440,18 @@ public: } //TODO doesn't catch when instruction removed ? virtual void postCycle(){ - if(!rsps.empty() && (!ws->iStall || VL_RANDOM_I(7) < 100)){ + if(!rsps.empty() && (!ws->iStall || VL_RANDOM_I_WIDTH(7) < 100)){ DBusSimpleAvalonRsp rsp = rsps.front(); rsps.pop(); top->dBusAvalon_readDataValid = 1; top->dBusAvalon_readData = rsp.data; top->dBusAvalon_response = rsp.error ? 3 : 0; } else { top->dBusAvalon_readDataValid = 0; - top->dBusAvalon_readData = VL_RANDOM_I(32); - top->dBusAvalon_response = VL_RANDOM_I(2); + top->dBusAvalon_readData = VL_RANDOM_I_WIDTH(32); + top->dBusAvalon_response = VL_RANDOM_I_WIDTH(2); } if(ws->iStall) - top->dBusAvalon_waitRequestn = VL_RANDOM_I(7) < 100; + top->dBusAvalon_waitRequestn = VL_RANDOM_I_WIDTH(7) < 100; } }; #endif @@ -2492,10 +2494,10 @@ public: virtual void postCycle(){ if(ws->iStall) - top->dBusAhbLite3_HREADY = (!ws->iStall || VL_RANDOM_I(7) < 100); + top->dBusAhbLite3_HREADY = (!ws->iStall || VL_RANDOM_I_WIDTH(7) < 100); - top->dBusAhbLite3_HRDATA = VL_RANDOM_I(32); - top->dBusAhbLite3_HRESP = VL_RANDOM_I(1); + top->dBusAhbLite3_HRDATA = VL_RANDOM_I_WIDTH(32); + top->dBusAhbLite3_HRESP = VL_RANDOM_I_WIDTH(1); if(top->dBusAhbLite3_HREADY && dBusAhbLite3_HTRANS == 2 && !dBusAhbLite3_HWRITE){ @@ -2534,8 +2536,8 @@ public: virtual void postCycle(){ if(ws->iStall) - top->dBusWishbone_ACK = VL_RANDOM_I(7) < 100; - top->dBusWishbone_DAT_MISO = VL_RANDOM_I(32); + top->dBusWishbone_ACK = VL_RANDOM_I_WIDTH(7) < 100; + top->dBusWishbone_DAT_MISO = VL_RANDOM_I_WIDTH(32); if (top->dBusWishbone_CYC && top->dBusWishbone_STB && top->dBusWishbone_ACK) { if(top->dBusWishbone_WE){ bool dummy; @@ -2638,7 +2640,7 @@ public: ws->dBusAccess(top->dBus_cmd_payload_address,0,1 << top->dBus_cmd_payload_size,buffer, &error); for(int beat = 0;beat <= beatCount;beat++){ for(int i = 0;i < DBUS_LOAD_DATA_WIDTH/8;i++){ - rsp.data[i] = (address >= startAt && address < endAt) ? buffer[address-top->dBus_cmd_payload_address] : VL_RANDOM_I(8); + rsp.data[i] = (address >= startAt && address < endAt) ? buffer[address-top->dBus_cmd_payload_address] : VL_RANDOM_I_WIDTH(8); address += 1; } rsp.last = beat == beatCount; @@ -2655,8 +2657,8 @@ public: #ifdef DBUS_INVALIDATE if(ws->allowInvalidate){ - if(VL_RANDOM_I(7) < 10){ - invalidationHint.push(top->dBus_cmd_payload_address + VL_RANDOM_I(5)); + if(VL_RANDOM_I_WIDTH(7) < 10){ + invalidationHint.push(top->dBus_cmd_payload_address + VL_RANDOM_I_WIDTH(5)); } } #endif @@ -2671,7 +2673,7 @@ public: virtual void postCycle(){ - if(!rsps.empty() && (!ws->dStall || VL_RANDOM_I(7) < 100)){ + if(!rsps.empty() && (!ws->dStall || VL_RANDOM_I_WIDTH(7) < 100)){ DBusCachedTask rsp = rsps.front(); rsps.pop(); top->dBus_rsp_valid = 1; @@ -2686,33 +2688,33 @@ public: } else{ top->dBus_rsp_valid = 0; for(int idx = 0;idx < DBUS_LOAD_DATA_WIDTH/32;idx++){ - ((uint32_t*)&top->dBus_rsp_payload_data)[idx] = VL_RANDOM_I(32); + ((uint32_t*)&top->dBus_rsp_payload_data)[idx] = VL_RANDOM_I_WIDTH(32); } - top->dBus_rsp_payload_error = VL_RANDOM_I(1); - top->dBus_rsp_payload_last = VL_RANDOM_I(1); + top->dBus_rsp_payload_error = VL_RANDOM_I_WIDTH(1); + top->dBus_rsp_payload_last = VL_RANDOM_I_WIDTH(1); #ifdef DBUS_EXCLUSIVE - top->dBus_rsp_payload_exclusive = VL_RANDOM_I(1); + top->dBus_rsp_payload_exclusive = VL_RANDOM_I_WIDTH(1); #endif } - top->dBus_cmd_ready = (ws->dStall ? VL_RANDOM_I(7) < 100 : 1); + top->dBus_cmd_ready = (ws->dStall ? VL_RANDOM_I_WIDTH(7) < 100 : 1); #ifdef DBUS_INVALIDATE if(ws->allowInvalidate){ if(top->dBus_inv_ready) top->dBus_inv_valid = 0; - if(top->dBus_inv_valid == 0 && VL_RANDOM_I(7) < 5){ + if(top->dBus_inv_valid == 0 && VL_RANDOM_I_WIDTH(7) < 5){ top->dBus_inv_valid = 1; - top->dBus_inv_payload_fragment_enable = VL_RANDOM_I(7) < 100; + top->dBus_inv_payload_fragment_enable = VL_RANDOM_I_WIDTH(7) < 100; if(!invalidationHint.empty()){ top->dBus_inv_payload_fragment_address = invalidationHint.front(); invalidationHint.pop(); } else { - top->dBus_inv_payload_fragment_address = VL_RANDOM_I(32); + top->dBus_inv_payload_fragment_address = VL_RANDOM_I_WIDTH(32); } } } - top->dBus_ack_ready = (ws->dStall ? VL_RANDOM_I(7) < 100 : 1); + top->dBus_ack_ready = (ws->dStall ? VL_RANDOM_I_WIDTH(7) < 100 : 1); if(top->dBus_sync_ready) top->dBus_sync_valid = 0; - if(top->dBus_sync_valid == 0 && pendingSync != 0 && (ws->dStall ? VL_RANDOM_I(7) < 80 : 1) ){ + if(top->dBus_sync_valid == 0 && pendingSync != 0 && (ws->dStall ? VL_RANDOM_I_WIDTH(7) < 80 : 1) ){ top->dBus_sync_valid = 1; } #endif @@ -2767,7 +2769,7 @@ public: } virtual void postCycle(){ - if(!rsps.empty() && (!ws->dStall || VL_RANDOM_I(7) < 100)){ + if(!rsps.empty() && (!ws->dStall || VL_RANDOM_I_WIDTH(7) < 100)){ DBusCachedAvalonTask rsp = rsps.front(); rsps.pop(); top->dBusAvalon_response = rsp.error ? 3 : 0; @@ -2775,11 +2777,11 @@ public: top->dBusAvalon_readDataValid = 1; } else{ top->dBusAvalon_readDataValid = 0; - top->dBusAvalon_readData = VL_RANDOM_I(32); - top->dBusAvalon_response = VL_RANDOM_I(2); //TODO + top->dBusAvalon_readData = VL_RANDOM_I_WIDTH(32); + top->dBusAvalon_response = VL_RANDOM_I_WIDTH(2); //TODO } - top->dBusAvalon_waitRequestn = (ws->dStall ? VL_RANDOM_I(7) < 100 : 1); + top->dBusAvalon_waitRequestn = (ws->dStall ? VL_RANDOM_I_WIDTH(7) < 100 : 1); } }; #endif @@ -3008,9 +3010,9 @@ public: top->debug_bus_cmd_payload_data = task.data; }else { top->debug_bus_cmd_valid = 0; - top->debug_bus_cmd_payload_wr = VL_RANDOM_I(1); - top->debug_bus_cmd_payload_address = VL_RANDOM_I(8); - top->debug_bus_cmd_payload_data = VL_RANDOM_I(32); + top->debug_bus_cmd_payload_wr = VL_RANDOM_I_WIDTH(1); + top->debug_bus_cmd_payload_address = VL_RANDOM_I_WIDTH(8); + top->debug_bus_cmd_payload_data = VL_RANDOM_I_WIDTH(32); } } }; @@ -3059,8 +3061,8 @@ public: }else { top->debugBusAvalon_write = 0; top->debugBusAvalon_read = 0; - top->debugBusAvalon_address = VL_RANDOM_I(8); - top->debugBusAvalon_writeData = VL_RANDOM_I(32); + top->debugBusAvalon_address = VL_RANDOM_I_WIDTH(8); + top->debugBusAvalon_writeData = VL_RANDOM_I_WIDTH(32); } } }; @@ -3373,7 +3375,7 @@ public: uint32_t readCmd(uint32_t size, uint32_t address){ - accessCmd(false, 2, address, VL_RANDOM_I(32)); + accessCmd(false, 2, address, VL_RANDOM_I_WIDTH(32)); int error; if((error = recv(clientSocket, buffer, 4, 0)) != 4){ printf("Should read 4 bytes, had %d", error); @@ -4434,7 +4436,7 @@ int main(int argc, char **argv, char **env) { } while(tasks.size() > FREERTOS_COUNT){ - tasks.erase(tasks.begin() + (VL_RANDOM_I(32)%tasks.size())); + tasks.erase(tasks.begin() + (VL_RANDOM_I_WIDTH(32)%tasks.size())); } @@ -4465,7 +4467,7 @@ int main(int argc, char **argv, char **env) { } while(tasks.size() > ZEPHYR_COUNT){ - tasks.erase(tasks.begin() + (VL_RANDOM_I(32)%tasks.size())); + tasks.erase(tasks.begin() + (VL_RANDOM_I_WIDTH(32)%tasks.size())); } From 378c0f87233c3808932eb9a2eeda1929c2d599be Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 4 Feb 2022 16:20:43 +0100 Subject: [PATCH 738/951] verilator++ --- .github/workflows/scala.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scala.yml b/.github/workflows/scala.yml index 2d4547fa..859c1370 100644 --- a/.github/workflows/scala.yml +++ b/.github/workflows/scala.yml @@ -40,7 +40,7 @@ jobs: with: path: | ~/tools - key: ${{ runner.os }}-tools_v2 + key: ${{ runner.os }}-tools_v3 - name: Setup env run: echo "$HOME/tools/bin" >> $GITHUB_PATH From 4dd650736f4ecb0d59bfc4353954b802048b4029 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 4 Feb 2022 16:36:11 +0100 Subject: [PATCH 739/951] verilator++ --- .github/workflows/scala.yml | 2 +- tools.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/scala.yml b/.github/workflows/scala.yml index 859c1370..9d2d2aa2 100644 --- a/.github/workflows/scala.yml +++ b/.github/workflows/scala.yml @@ -40,7 +40,7 @@ jobs: with: path: | ~/tools - key: ${{ runner.os }}-tools_v3 + key: ${{ runner.os }}-tools_v4 - name: Setup env run: echo "$HOME/tools/bin" >> $GITHUB_PATH diff --git a/tools.sh b/tools.sh index ebe05921..7ee6a59b 100644 --- a/tools.sh +++ b/tools.sh @@ -6,7 +6,7 @@ install_verilator(){ unset VERILATOR_ROOT # For bash cd verilator git pull # Make sure we're up-to-date - git checkout v4.040 + git checkout v4.216 autoconf # Create ./configure script ./configure --prefix ~/tools make -j$(nproc) From 62c07670af07f89e9254ba089a121cee81530b0b Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sat, 5 Feb 2022 11:31:04 +0100 Subject: [PATCH 740/951] version++ --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index 9bec9476..19e9c35d 100644 --- a/build.sbt +++ b/build.sbt @@ -1,4 +1,4 @@ -val spinalVersion = "1.6.2" +val spinalVersion = "1.6.3" lazy val root = (project in file(".")). settings( From 807aa98d37f3f213630ada44df6115ffee3c6345 Mon Sep 17 00:00:00 2001 From: Daniel Schultz Date: Thu, 10 Feb 2022 19:55:08 +0100 Subject: [PATCH 741/951] plugin: DBusSimplePlugin: Remove assert This assert triggered sometimes at the beginning of a simulation. Since it's not really needed anymore, we can remove it. Signed-off-by: Daniel Schultz --- src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala index 094de174..372cfcc5 100644 --- a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala @@ -518,9 +518,6 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, } } - - - if(rspStage != execute) assert(!(dBus.rsp.ready && input(MEMORY_ENABLE) && arbitration.isValid && arbitration.isStuck),"DBusSimplePlugin doesn't allow memory stage stall when read happend") } //Reformat read responses, REGFILE_WRITE_DATA overriding From e4fde184d906d3a5f9b40c2bb51a6756e7a8d324 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 16 Feb 2022 14:12:00 +0100 Subject: [PATCH 742/951] SpinalHDL 1.6.5 --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index 19e9c35d..11dee635 100644 --- a/build.sbt +++ b/build.sbt @@ -1,4 +1,4 @@ -val spinalVersion = "1.6.3" +val spinalVersion = "1.6.5" lazy val root = (project in file(".")). settings( From 5b45ddab1b203362aaf47194f018c7e0fd218600 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 16 Feb 2022 14:26:58 +0100 Subject: [PATCH 743/951] SpinalHDL 1.6.4 --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index fe2d43dd..9db37899 100644 --- a/build.sbt +++ b/build.sbt @@ -1,4 +1,4 @@ -val spinalVersion = "1.6.2" +val spinalVersion = "1.6.4" lazy val root = (project in file(".")). settings( From e558b795821621d99e8280aa6b877b73182aec33 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 22 Feb 2022 16:15:14 +0100 Subject: [PATCH 744/951] Fix Briey simulation floating rxd blocking the uart #238 --- src/test/cpp/briey/main.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/test/cpp/briey/main.cpp b/src/test/cpp/briey/main.cpp index d2b372c5..c0e165a2 100644 --- a/src/test/cpp/briey/main.cpp +++ b/src/test/cpp/briey/main.cpp @@ -382,6 +382,8 @@ public: timeProcesses.push_back(asyncReset); timeProcesses.push_back(jtag); timeProcesses.push_back(uartRx); + top->io_uart_rxd = 1; + SdramConfig *sdramConfig = new SdramConfig( 2, //byteCount From e1620c68b2bfcff7ad1bc8ce665cf4ce29452141 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 22 Feb 2022 16:15:14 +0100 Subject: [PATCH 745/951] Fix Briey simulation floating rxd blocking the uart #238 --- src/test/cpp/briey/main.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/test/cpp/briey/main.cpp b/src/test/cpp/briey/main.cpp index d2b372c5..c0e165a2 100644 --- a/src/test/cpp/briey/main.cpp +++ b/src/test/cpp/briey/main.cpp @@ -382,6 +382,8 @@ public: timeProcesses.push_back(asyncReset); timeProcesses.push_back(jtag); timeProcesses.push_back(uartRx); + top->io_uart_rxd = 1; + SdramConfig *sdramConfig = new SdramConfig( 2, //byteCount From 51b8865b66617d09d1363941cbf1c783418c8600 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 18 Mar 2022 12:36:05 +0100 Subject: [PATCH 746/951] Fix VexRiscvSmpClusterGen linux less mhartid --- src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index 743d2c27..a0ad2c74 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -206,7 +206,7 @@ object VexRiscvSmpClusterGen { mvendorid = null, marchid = null, mimpid = null, - mhartid = 0, + mhartid = hartId, misaExtensionsInit = 0, misaAccess = CsrAccess.NONE, mtvecAccess = CsrAccess.READ_WRITE, From 9149c420657c7a50f66df4edafc1e6db25c4f478 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 23 Mar 2022 18:53:43 +0100 Subject: [PATCH 747/951] DecoderPlugin now implement forceIllegal API --- src/main/scala/vexriscv/Services.scala | 1 + src/main/scala/vexriscv/plugin/DecoderSimplePlugin.scala | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/main/scala/vexriscv/Services.scala b/src/main/scala/vexriscv/Services.scala index 64ce5ae2..8a291d64 100644 --- a/src/main/scala/vexriscv/Services.scala +++ b/src/main/scala/vexriscv/Services.scala @@ -24,6 +24,7 @@ trait DecoderService{ def add(key : MaskedLiteral,values : Seq[(Stageable[_ <: BaseType],Any)]) def add(encoding :Seq[(MaskedLiteral,Seq[(Stageable[_ <: BaseType],Any)])]) def addDefault(key : Stageable[_ <: BaseType], value : Any) + def forceIllegal() : Unit } case class ExceptionCause(codeWidth : Int) extends Bundle{ diff --git a/src/main/scala/vexriscv/plugin/DecoderSimplePlugin.scala b/src/main/scala/vexriscv/plugin/DecoderSimplePlugin.scala index 71e38948..a2ab111e 100644 --- a/src/main/scala/vexriscv/plugin/DecoderSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/DecoderSimplePlugin.scala @@ -71,6 +71,8 @@ class DecoderSimplePlugin(catchIllegalInstruction : Boolean = false, } } + def forceIllegal() : Unit = if(catchIllegalInstruction) pipeline.decode.input(pipeline.config.LEGAL_INSTRUCTION) := False + val defaults = mutable.LinkedHashMap[Stageable[_ <: BaseType], BaseType]() val encodings = mutable.LinkedHashMap[MaskedLiteral,ArrayBuffer[(Stageable[_ <: BaseType], BaseType)]]() var decodeExceptionPort : Flow[ExceptionCause] = null From b2e61caf9e62d8febe59eaf654856edec73e5412 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 23 Mar 2022 18:54:07 +0100 Subject: [PATCH 748/951] CfuPlugin now implement upstream spec --- .../demo/GenSmallAndProductiveCfu.scala | 3 +- .../scala/vexriscv/plugin/CfuPlugin.scala | 47 +++++++++++++++---- 2 files changed, 40 insertions(+), 10 deletions(-) diff --git a/src/main/scala/vexriscv/demo/GenSmallAndProductiveCfu.scala b/src/main/scala/vexriscv/demo/GenSmallAndProductiveCfu.scala index a571bccd..507b3439 100644 --- a/src/main/scala/vexriscv/demo/GenSmallAndProductiveCfu.scala +++ b/src/main/scala/vexriscv/demo/GenSmallAndProductiveCfu.scala @@ -53,7 +53,6 @@ object GenSmallAndProductiveCfu extends App{ new CfuPlugin( stageCount = 1, allowZeroLatency = true, - cfuIndexWidth = 4, encodings = List( CfuPluginEncoding ( instruction = M"-------------------------0001011", @@ -64,7 +63,7 @@ object GenSmallAndProductiveCfu extends App{ busParameter = CfuBusParameter( CFU_VERSION = 0, CFU_INTERFACE_ID_W = 0, - CFU_FUNCTION_ID_W = 7, + CFU_FUNCTION_ID_W = 3, CFU_REORDER_ID_W = 0, CFU_REQ_RESP_ID_W = 0, CFU_INPUTS = 2, diff --git a/src/main/scala/vexriscv/plugin/CfuPlugin.scala b/src/main/scala/vexriscv/plugin/CfuPlugin.scala index b8e98cbb..de6daa14 100644 --- a/src/main/scala/vexriscv/plugin/CfuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CfuPlugin.scala @@ -23,6 +23,7 @@ case class CfuPluginParameter( case class CfuBusParameter(CFU_VERSION : Int = 0, CFU_INTERFACE_ID_W : Int = 0, CFU_FUNCTION_ID_W : Int, + CFU_CFU_ID_W : Int = 0, CFU_REORDER_ID_W : Int = 0, CFU_REQ_RESP_ID_W : Int = 0, CFU_STATE_INDEX_NUM : Int = 0, @@ -31,7 +32,9 @@ case class CfuBusParameter(CFU_VERSION : Int = 0, CFU_OUTPUTS : Int, CFU_OUTPUT_DATA_W : Int, CFU_FLOW_REQ_READY_ALWAYS : Boolean, - CFU_FLOW_RESP_READY_ALWAYS : Boolean) + CFU_FLOW_RESP_READY_ALWAYS : Boolean, + CFU_WITH_STATUS : Boolean = false, + CFU_RAW_INSN_W : Int = 0) case class CfuCmd( p : CfuBusParameter ) extends Bundle{ val function_id = UInt(p.CFU_FUNCTION_ID_W bits) @@ -39,6 +42,8 @@ case class CfuCmd( p : CfuBusParameter ) extends Bundle{ val request_id = UInt(p.CFU_REQ_RESP_ID_W bits) val inputs = Vec(Bits(p.CFU_INPUT_DATA_W bits), p.CFU_INPUTS) val state_index = UInt(log2Up(p.CFU_STATE_INDEX_NUM) bits) + val cfu_index = UInt(p.CFU_CFU_ID_W bits) + val raw_insn = Bits(p.CFU_RAW_INSN_W bits) def weakAssignFrom(m : CfuCmd): Unit ={ def s = this WeakConnector(m, s, m.function_id, s.function_id, defaultValue = null, allowUpSize = false, allowDownSize = true , allowDrop = true) @@ -51,6 +56,7 @@ case class CfuCmd( p : CfuBusParameter ) extends Bundle{ case class CfuRsp(p : CfuBusParameter) extends Bundle{ val response_id = UInt(p.CFU_REQ_RESP_ID_W bits) val outputs = Vec(Bits(p.CFU_OUTPUT_DATA_W bits), p.CFU_OUTPUTS) + val status = p.CFU_WITH_STATUS generate Bits(3 bits) def weakAssignFrom(m : CfuRsp): Unit ={ def s = this @@ -95,7 +101,7 @@ class CfuPlugin(val stageCount : Int, val busParameter : CfuBusParameter, val encodings : List[CfuPluginEncoding] = null, val stateAndIndexCsrOffset : Int = 0xBC0, - val cfuIndexWidth : Int = 0) extends Plugin[VexRiscv]{ + val statusCsrOffset : Int = 0x801) extends Plugin[VexRiscv]{ def p = busParameter assert(p.CFU_INPUTS <= 2) @@ -151,18 +157,33 @@ class CfuPlugin(val stageCount : Int, import pipeline.config._ val csr = pipeline plug new Area{ + val factory = pipeline.service(classOf[CsrInterface]) + val en = Reg(Bool()) init(False) + factory.rw(stateAndIndexCsrOffset, 31, en) + val stateId = Reg(UInt(log2Up(p.CFU_STATE_INDEX_NUM) bits)) init(0) if(p.CFU_STATE_INDEX_NUM > 1) { assert(stateAndIndexCsrOffset != -1, "CfuPlugin stateCsrIndex need to be set in the parameters") - pipeline.service(classOf[CsrInterface]).rw(stateAndIndexCsrOffset, 16, stateId) + factory.rw(stateAndIndexCsrOffset, 16, stateId) } - bus.cmd.state_index := stateId - val cfuIndex = Reg(UInt(cfuIndexWidth bits)) init(0) - if(cfuIndexWidth != 0){ - pipeline.service(classOf[CsrInterface]).rw(stateAndIndexCsrOffset, 0, cfuIndex) + + val cfuIndex = Reg(UInt(p.CFU_CFU_ID_W bits)) init(0) + if(p.CFU_CFU_ID_W != 0){ + factory.rw(stateAndIndexCsrOffset, 0, cfuIndex) + } + val status = p.CFU_WITH_STATUS generate new Area{ + val CU, OP, FI, OF, SI, CI = RegInit(False) + val flags = List(CU, OP, FI, OF, SI, CI).reverse + factory.rw(statusCsrOffset, flags.zipWithIndex.map(_.swap) :_*) + factory.duringWrite(statusCsrOffset){ + decode.arbitration.haltByOther := True //Handle CSRW to decode + } } } + when(decode.input(CFU_ENABLE) && !csr.en){ + pipeline.service(classOf[DecoderService]).forceIllegal() + } forkStage plug new Area{ import forkStage._ @@ -181,9 +202,12 @@ class CfuPlugin(val stageCount : Int, // bus.cmd.function_id := U(input(INSTRUCTION)(14 downto 12)).resized val functionIdFromInstructinoWidth = encodings.map(_.functionIdWidth).max val functionsIds = encodings.map(e => U(Cat(e.functionId.map(r => input(INSTRUCTION)(r))), functionIdFromInstructinoWidth bits)) - bus.cmd.function_id := csr.cfuIndex @@ functionsIds.read(input(CFU_ENCODING)) + bus.cmd.cfu_index := csr.cfuIndex + bus.cmd.state_index := csr.stateId + bus.cmd.function_id := functionsIds.read(input(CFU_ENCODING)) bus.cmd.reorder_id := 0 bus.cmd.request_id := 0 + bus.cmd.raw_insn := input(INSTRUCTION).resized if(p.CFU_INPUTS >= 1) bus.cmd.inputs(0) := input(RS1) if(p.CFU_INPUTS >= 2) bus.cmd.inputs(1) := input(CFU_INPUT_2_KIND).mux( CfuPlugin.Input2Kind.RS -> input(RS2), @@ -212,6 +236,13 @@ class CfuPlugin(val stageCount : Int, arbitration.haltItself setWhen(!rsp.valid) rsp.ready := !arbitration.isStuckByOthers output(REGFILE_WRITE_DATA) := rsp.outputs(0) + if(p.CFU_WITH_STATUS) when(arbitration.isFiring){ + switch(rsp.status) { + for (i <- 1 to 6) is(i) { + csr.status.flags(i-1) := True + } + } + } } } From 5dc91a8be484e5f9acd70e11ac6d042cc04759ea Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 23 Mar 2022 18:54:18 +0100 Subject: [PATCH 749/951] Add MuraxCfu --- src/main/scala/vexriscv/demo/Murax.scala | 48 ++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/src/main/scala/vexriscv/demo/Murax.scala b/src/main/scala/vexriscv/demo/Murax.scala index 7c679a12..95a35b54 100644 --- a/src/main/scala/vexriscv/demo/Murax.scala +++ b/src/main/scala/vexriscv/demo/Murax.scala @@ -335,6 +335,54 @@ object Murax{ } } +object MuraxCfu{ + def main(args: Array[String]) { + SpinalVerilog{ + val config = MuraxConfig.default + config.cpuPlugins += new CfuPlugin( + stageCount = 1, + allowZeroLatency = true, + encodings = List( + CfuPluginEncoding ( + instruction = M"-------------------------0001011", + functionId = List(14 downto 12), + input2Kind = CfuPlugin.Input2Kind.RS + ) + ), + busParameter = CfuBusParameter( + CFU_VERSION = 0, + CFU_INTERFACE_ID_W = 0, + CFU_FUNCTION_ID_W = 3, + CFU_REORDER_ID_W = 0, + CFU_REQ_RESP_ID_W = 0, + CFU_INPUTS = 2, + CFU_INPUT_DATA_W = 32, + CFU_OUTPUTS = 1, + CFU_OUTPUT_DATA_W = 32, + CFU_FLOW_REQ_READY_ALWAYS = false, + CFU_FLOW_RESP_READY_ALWAYS = false, + CFU_WITH_STATUS = true, + CFU_RAW_INSN_W = 32, + CFU_CFU_ID_W = 4, + CFU_STATE_INDEX_NUM = 5 + ) + ) + + val toplevel = Murax(config) + + toplevel.rework { + for (plugin <- toplevel.system.cpu.plugins) plugin match { + case plugin: CfuPlugin => plugin.bus.toIo().setName("miaou") + case _ => + } + } + + toplevel + } + } +} + + object Murax_iCE40_hx8k_breakout_board_xip{ case class SB_GB() extends BlackBox{ From 4bddb091aef6fb527e9843449a6f3b44d66042ef Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 23 Mar 2022 18:58:18 +0100 Subject: [PATCH 750/951] Update CFU example --- .../scala/vexriscv/demo/GenSmallAndProductiveCfu.scala | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/demo/GenSmallAndProductiveCfu.scala b/src/main/scala/vexriscv/demo/GenSmallAndProductiveCfu.scala index 507b3439..d28e3184 100644 --- a/src/main/scala/vexriscv/demo/GenSmallAndProductiveCfu.scala +++ b/src/main/scala/vexriscv/demo/GenSmallAndProductiveCfu.scala @@ -70,9 +70,12 @@ object GenSmallAndProductiveCfu extends App{ CFU_INPUT_DATA_W = 32, CFU_OUTPUTS = 1, CFU_OUTPUT_DATA_W = 32, - CFU_STATE_INDEX_NUM = 5, CFU_FLOW_REQ_READY_ALWAYS = false, - CFU_FLOW_RESP_READY_ALWAYS = false + CFU_FLOW_RESP_READY_ALWAYS = false, + CFU_WITH_STATUS = true, + CFU_RAW_INSN_W = 32, + CFU_CFU_ID_W = 4, + CFU_STATE_INDEX_NUM = 5 ) ), new YamlPlugin("cpu0.yaml") From ccff48f872a7948335accff10f406f8b2eb4d200 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 30 Mar 2022 16:17:57 +0200 Subject: [PATCH 751/951] deprecated Data.keep --- src/main/scala/vexriscv/VexRiscv.scala | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/scala/vexriscv/VexRiscv.scala b/src/main/scala/vexriscv/VexRiscv.scala index d3feda3f..ed7e37e7 100644 --- a/src/main/scala/vexriscv/VexRiscv.scala +++ b/src/main/scala/vexriscv/VexRiscv.scala @@ -136,10 +136,10 @@ class VexRiscv(val config : VexRiscvConfig) extends Component with Pipeline{ plugins ++= config.plugins //regression usage - val lastStageInstruction = CombInit(stages.last.input(config.INSTRUCTION)).keep().addAttribute (Verilator.public) - val lastStagePc = CombInit(stages.last.input(config.PC)).keep().addAttribute(Verilator.public) - val lastStageIsValid = CombInit(stages.last.arbitration.isValid).keep().addAttribute(Verilator.public) - val lastStageIsFiring = CombInit(stages.last.arbitration.isFiring).keep().addAttribute(Verilator.public) + val lastStageInstruction = CombInit(stages.last.input(config.INSTRUCTION)).dontSimplifyIt().addAttribute (Verilator.public) + val lastStagePc = CombInit(stages.last.input(config.PC)).dontSimplifyIt().addAttribute(Verilator.public) + val lastStageIsValid = CombInit(stages.last.arbitration.isValid).dontSimplifyIt().addAttribute(Verilator.public) + val lastStageIsFiring = CombInit(stages.last.arbitration.isFiring).dontSimplifyIt().addAttribute(Verilator.public) //Verilator perf decode.arbitration.removeIt.noBackendCombMerge From 2d2017465e4923b91e4e7752e1ca5e890eebb2b6 Mon Sep 17 00:00:00 2001 From: Andreas Wallner Date: Sat, 2 Apr 2022 18:22:10 +0200 Subject: [PATCH 752/951] Fix reset vector of GenCustomSimdAdd With the old reset vector half of the tests fail since they expect the CPU to start at 0x80000000. (e.g. I-IO, I-NOP, I-LUI, etc.) --- src/main/scala/vexriscv/demo/GenCustomSimdAdd.scala | 2 +- src/test/cpp/custom/simd_add/src/ld | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/main/scala/vexriscv/demo/GenCustomSimdAdd.scala b/src/main/scala/vexriscv/demo/GenCustomSimdAdd.scala index 8b137f5e..8d9d6bec 100644 --- a/src/main/scala/vexriscv/demo/GenCustomSimdAdd.scala +++ b/src/main/scala/vexriscv/demo/GenCustomSimdAdd.scala @@ -13,7 +13,7 @@ object GenCustomSimdAdd extends App{ plugins = List( new SimdAddPlugin, new IBusSimplePlugin( - resetVector = 0x00000000l, + resetVector = 0x80000000l, cmdForkOnSecondStage = false, cmdForkPersistence = false, prediction = NONE, diff --git a/src/test/cpp/custom/simd_add/src/ld b/src/test/cpp/custom/simd_add/src/ld index 8d955235..3a4f1128 100644 --- a/src/test/cpp/custom/simd_add/src/ld +++ b/src/test/cpp/custom/simd_add/src/ld @@ -1,13 +1,11 @@ OUTPUT_ARCH( "riscv" ) MEMORY { - onChipRam (W!RX)/*(RX)*/ : ORIGIN = 0x00000000, LENGTH = 8K + onChipRam (W!RX)/*(RX)*/ : ORIGIN = 0x80000000, LENGTH = 8K } SECTIONS { - . = 0x000; - .crt_section : { . = ALIGN(4); From 32a5206541701278fdefcb00704269788ea23a92 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Mon, 4 Apr 2022 16:37:43 +0200 Subject: [PATCH 753/951] Update to latest risc-v-formal --- src/main/scala/vexriscv/plugin/FormalPlugin.scala | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/scala/vexriscv/plugin/FormalPlugin.scala b/src/main/scala/vexriscv/plugin/FormalPlugin.scala index a02218da..2d70ebd8 100644 --- a/src/main/scala/vexriscv/plugin/FormalPlugin.scala +++ b/src/main/scala/vexriscv/plugin/FormalPlugin.scala @@ -35,6 +35,8 @@ case class RvfiPort() extends Bundle with IMasterSlave { val trap = Bool val halt = Bool val intr = Bool + val mode = Bits(2 bits) + val ixl = Bits(2 bits) val rs1 = RvfiPortRsRead() val rs2 = RvfiPortRsRead() val rd = RvfiPortRsWrite() @@ -91,6 +93,8 @@ class FormalPlugin extends Plugin[VexRiscv]{ rvfi.trap := False rvfi.halt := False rvfi.intr := False + rvfi.mode := 3 + rvfi.ixl := 1 // rvfi.rs1.addr := output(INSTRUCTION)(rs1Range).asUInt // rvfi.rs2.addr := output(INSTRUCTION)(rs2Range).asUInt // rvfi.rs1.rdata := output(RS1) From db3403359372289bd2387e1f92baa31abde5a952 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 8 Apr 2022 11:09:07 +0200 Subject: [PATCH 754/951] #240 Code generation now warn against cpu generation without illegal instruction catch and ebreak being disabled, as it may make crash some software, ex : rust --- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 4 ++++ src/main/scala/vexriscv/plugin/DecoderSimplePlugin.scala | 3 +++ 2 files changed, 7 insertions(+) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index bd48928c..5ba15233 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -532,6 +532,10 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep override def setup(pipeline: VexRiscv): Unit = { import pipeline.config._ + if(!config.ebreakGen) { + SpinalWarning("This VexRiscv configuration is set without software ebreak instruction support. Some software may rely on it (ex: Rust). (This isn't related to JTAG ebreak)") + } + csrMapping = new CsrMapping() inWfi = False.addTag(Verilator.public) diff --git a/src/main/scala/vexriscv/plugin/DecoderSimplePlugin.scala b/src/main/scala/vexriscv/plugin/DecoderSimplePlugin.scala index a2ab111e..a525b771 100644 --- a/src/main/scala/vexriscv/plugin/DecoderSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/DecoderSimplePlugin.scala @@ -79,6 +79,9 @@ class DecoderSimplePlugin(catchIllegalInstruction : Boolean = false, override def setup(pipeline: VexRiscv): Unit = { + if(!catchIllegalInstruction) { + SpinalWarning("This VexRiscv configuration is set without illegal instruction catch support. Some software may rely on it (ex: Rust)") + } if(catchIllegalInstruction) { val exceptionService = pipeline.plugins.filter(_.isInstanceOf[ExceptionService]).head.asInstanceOf[ExceptionService] decodeExceptionPort = exceptionService.newExceptionPort(pipeline.decode).setName("decodeExceptionPort") From 53d52692de38633a6b3b58dd1e297d206ad0bd08 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 8 Apr 2022 11:09:48 +0200 Subject: [PATCH 755/951] #240 Code generation now warn against cpu generation without illegal instruction catch and ebreak being disabled, as it may make crash some software, ex : rust --- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 4 ++++ src/main/scala/vexriscv/plugin/DecoderSimplePlugin.scala | 3 +++ 2 files changed, 7 insertions(+) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index bd48928c..5ba15233 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -532,6 +532,10 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep override def setup(pipeline: VexRiscv): Unit = { import pipeline.config._ + if(!config.ebreakGen) { + SpinalWarning("This VexRiscv configuration is set without software ebreak instruction support. Some software may rely on it (ex: Rust). (This isn't related to JTAG ebreak)") + } + csrMapping = new CsrMapping() inWfi = False.addTag(Verilator.public) diff --git a/src/main/scala/vexriscv/plugin/DecoderSimplePlugin.scala b/src/main/scala/vexriscv/plugin/DecoderSimplePlugin.scala index 71e38948..8a458ff3 100644 --- a/src/main/scala/vexriscv/plugin/DecoderSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/DecoderSimplePlugin.scala @@ -77,6 +77,9 @@ class DecoderSimplePlugin(catchIllegalInstruction : Boolean = false, override def setup(pipeline: VexRiscv): Unit = { + if(!catchIllegalInstruction) { + SpinalWarning("This VexRiscv configuration is set without illegal instruction catch support. Some software may rely on it (ex: Rust)") + } if(catchIllegalInstruction) { val exceptionService = pipeline.plugins.filter(_.isInstanceOf[ExceptionService]).head.asInstanceOf[ExceptionService] decodeExceptionPort = exceptionService.newExceptionPort(pipeline.decode).setName("decodeExceptionPort") From 3b8270b82bfbdba29e98498e483847253888b2fc Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 11 Apr 2022 11:59:41 +0200 Subject: [PATCH 756/951] #241 Fix Murax/Briey TB timeouts --- src/test/cpp/briey/main.cpp | 2 -- src/test/cpp/common/framework.h | 7 +++++-- src/test/cpp/murax/main.cpp | 4 +--- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/test/cpp/briey/main.cpp b/src/test/cpp/briey/main.cpp index c0e165a2..bebe8800 100644 --- a/src/test/cpp/briey/main.cpp +++ b/src/test/cpp/briey/main.cpp @@ -466,8 +466,6 @@ int main(int argc, char **argv, char **env) { uint64_t duration = timer_end(startedAt); cout << endl << "****************************************************************" << endl; - cout << "Had simulate " << workspaceCycles << " clock cycles in " << duration*1e-9 << " s (" << workspaceCycles / (duration*1e-9) << " Khz)" << endl; - cout << "****************************************************************" << endl << endl; exit(0); diff --git a/src/test/cpp/common/framework.h b/src/test/cpp/common/framework.h index 42c1f34a..ed419adc 100644 --- a/src/test/cpp/common/framework.h +++ b/src/test/cpp/common/framework.h @@ -127,7 +127,6 @@ public: class success : public std::exception { }; -static uint32_t workspaceCycles = 0; template class Workspace{ public: @@ -180,7 +179,7 @@ public: #endif } - Workspace* run(uint32_t timeout = 5000){ + Workspace* run(double timeout = 1e6){ // init trace dump #ifdef TRACE @@ -205,6 +204,10 @@ public: if(p->wakeEnable && p->wakeDelay < delay) delay = p->wakeDelay; + if(time*timeToSec > timeout){ + printf("Simulation timeout triggered (%f)\n", time*timeToSec); + fail(); + } if(delay == ~0l){ fail(); } diff --git a/src/test/cpp/murax/main.cpp b/src/test/cpp/murax/main.cpp index 9738e847..735875fb 100644 --- a/src/test/cpp/murax/main.cpp +++ b/src/test/cpp/murax/main.cpp @@ -54,12 +54,10 @@ int main(int argc, char **argv, char **env) { printf("BOOT\n"); timespec startedAt = timer_start(); - MuraxWorkspace().run(100e6); + MuraxWorkspace().run(1e9); uint64_t duration = timer_end(startedAt); cout << endl << "****************************************************************" << endl; - cout << "Had simulate " << workspaceCycles << " clock cycles in " << duration*1e-9 << " s (" << workspaceCycles / (duration*1e-9) << " Khz)" << endl; - cout << "****************************************************************" << endl << endl; exit(0); From ea7a18c7f40179e71c8389873811a1cf120b8259 Mon Sep 17 00:00:00 2001 From: Daniel Schultz Date: Wed, 20 Apr 2022 11:16:19 +0200 Subject: [PATCH 757/951] plugin: caches: Fix "Can't resolve the literal value of" Both registers were initialized with unsigned integers without a value. This triggered: [error] Exception in thread "main" spinal.core.SpinalExit: [error] Can't resolve the literal value of (..._rspCounter : UInt[32 bits]) Signed-off-by: Daniel Schultz --- src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala | 2 +- src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index 3fb64988..381f2e0f 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -295,7 +295,7 @@ class DBusCachedPlugin(val config : DataCacheConfig, pipeline plug new Area{ //Memory bandwidth counter - val rspCounter = RegInit(UInt(32 bits)) init(0) + val rspCounter = Reg(UInt(32 bits)) init(0) when(dBus.rsp.valid){ rspCounter := rspCounter + 1 } diff --git a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala index 9de1382a..035c5dcf 100644 --- a/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusCachedPlugin.scala @@ -141,7 +141,7 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l, iBus.cmd.address.allowOverride := cache.io.mem.cmd.address //Memory bandwidth counter - val rspCounter = RegInit(UInt(32 bits)) init(0) + val rspCounter = Reg(UInt(32 bits)) init(0) when(iBus.rsp.valid){ rspCounter := rspCounter + 1 } From bd74833900d6b0e01c1478b3da91878281487dd5 Mon Sep 17 00:00:00 2001 From: Sallar Ahmadi-Pour Date: Mon, 25 Apr 2022 12:21:41 +0200 Subject: [PATCH 758/951] add murax peripheral extension tutorial --- doc/gcdPeripheral/README.md | 592 ++++++++++++++++++ .../murax-gcd-diagrams-gcd-controlpath.png | Bin 0 -> 68613 bytes .../img/murax-gcd-diagrams-gcd-datapath.png | Bin 0 -> 56769 bytes .../img/murax-gcd-diagrams-gcd-dp+cp.png | Bin 0 -> 27013 bytes .../img/murax-gcd-diagrams-gcd.png | Bin 0 -> 15632 bytes .../img/murax-gcd-diagrams.drawio | 1 + doc/gcdPeripheral/img/simulationWave.PNG | Bin 0 -> 48129 bytes .../src/main/c/murax/gcd_world/makefile | 134 ++++ .../murax/gcd_world/project/build.properties | 1 + .../src/main/c/murax/gcd_world/src/crt.S | 98 +++ .../src/main/c/murax/gcd_world/src/gcd.h | 13 + .../src/main/c/murax/gcd_world/src/gpio.h | 15 + .../main/c/murax/gcd_world/src/interrupt.h | 17 + .../src/main/c/murax/gcd_world/src/linker.ld | 110 ++++ .../src/main/c/murax/gcd_world/src/main.c | 62 ++ .../src/main/c/murax/gcd_world/src/main.h | 78 +++ .../src/main/c/murax/gcd_world/src/murax.h | 20 + .../main/c/murax/gcd_world/src/prescaler.h | 16 + .../src/main/c/murax/gcd_world/src/timer.h | 20 + .../src/main/c/murax/gcd_world/src/uart.h | 42 ++ .../src/main/scala/vexriscv/demo/Murax.scala | 559 +++++++++++++++++ .../vexriscv/periph/gcd/Apb3GCDCtrl.scala | 39 ++ .../scala/vexriscv/periph/gcd/GCDCtrl.scala | 68 ++ .../scala/vexriscv/periph/gcd/GCDData.scala | 54 ++ .../scala/vexriscv/periph/gcd/GCDTop.scala | 46 ++ .../scala/vexriscv/periph/gcd/GCDTopSim.scala | 52 ++ 26 files changed, 2037 insertions(+) create mode 100644 doc/gcdPeripheral/README.md create mode 100644 doc/gcdPeripheral/img/murax-gcd-diagrams-gcd-controlpath.png create mode 100644 doc/gcdPeripheral/img/murax-gcd-diagrams-gcd-datapath.png create mode 100644 doc/gcdPeripheral/img/murax-gcd-diagrams-gcd-dp+cp.png create mode 100644 doc/gcdPeripheral/img/murax-gcd-diagrams-gcd.png create mode 100644 doc/gcdPeripheral/img/murax-gcd-diagrams.drawio create mode 100644 doc/gcdPeripheral/img/simulationWave.PNG create mode 100644 doc/gcdPeripheral/src/main/c/murax/gcd_world/makefile create mode 100644 doc/gcdPeripheral/src/main/c/murax/gcd_world/project/build.properties create mode 100644 doc/gcdPeripheral/src/main/c/murax/gcd_world/src/crt.S create mode 100644 doc/gcdPeripheral/src/main/c/murax/gcd_world/src/gcd.h create mode 100644 doc/gcdPeripheral/src/main/c/murax/gcd_world/src/gpio.h create mode 100644 doc/gcdPeripheral/src/main/c/murax/gcd_world/src/interrupt.h create mode 100644 doc/gcdPeripheral/src/main/c/murax/gcd_world/src/linker.ld create mode 100644 doc/gcdPeripheral/src/main/c/murax/gcd_world/src/main.c create mode 100644 doc/gcdPeripheral/src/main/c/murax/gcd_world/src/main.h create mode 100644 doc/gcdPeripheral/src/main/c/murax/gcd_world/src/murax.h create mode 100644 doc/gcdPeripheral/src/main/c/murax/gcd_world/src/prescaler.h create mode 100644 doc/gcdPeripheral/src/main/c/murax/gcd_world/src/timer.h create mode 100644 doc/gcdPeripheral/src/main/c/murax/gcd_world/src/uart.h create mode 100644 doc/gcdPeripheral/src/main/scala/vexriscv/demo/Murax.scala create mode 100644 doc/gcdPeripheral/src/main/scala/vexriscv/periph/gcd/Apb3GCDCtrl.scala create mode 100644 doc/gcdPeripheral/src/main/scala/vexriscv/periph/gcd/GCDCtrl.scala create mode 100644 doc/gcdPeripheral/src/main/scala/vexriscv/periph/gcd/GCDData.scala create mode 100644 doc/gcdPeripheral/src/main/scala/vexriscv/periph/gcd/GCDTop.scala create mode 100644 doc/gcdPeripheral/src/main/scala/vexriscv/periph/gcd/GCDTopSim.scala diff --git a/doc/gcdPeripheral/README.md b/doc/gcdPeripheral/README.md new file mode 100644 index 00000000..210fbbaf --- /dev/null +++ b/doc/gcdPeripheral/README.md @@ -0,0 +1,592 @@ +# Tutorial on Implementing a Peripheral for the VexRiscv Based Murax SoC +**By** + +**Sallar Ahmadi-Pour - Researcher, University of Bremen, Group of Computer Architecture** + +[http://www.informatik.uni-bremen.de/agra/projects/risc-v/](http://www.informatik.uni-bremen.de/agra/projects/risc-v/) + +[http://www.informatik.uni-bremen.de/agra/](http://www.informatik.uni-bremen.de/agra/) + + +## 1. Introduction +Traditional hardware design often requires using languages like VHDL and Verilog and tooling that don't catch errors that can be caught with static analysis of the design. Additionally, information developers receive from the tools is scarce and often lead inexperienced developers on an odyssey. Currently emerging tools (Verilator, Yosys, etc.) for hardware design and languages for hardware description (SpinalHDL, Amaranth, etc.) tackle these and other existing issues. + +Projects like SpinalHDL and the thereon based highly configurable VexRiscv processor experience a rise in popularity and usage amongst academic and commercial users. The increased popularity also requires an increase in educational resources. Due to the specific popularity in the academic environment it only seems natural that researchers document their approaches and insights (not only in peer reviewed publications in a journal). This will allow the next generation of hardware designers to extend and explore big projects like VexRiscv. + +## 2. Our Goal for this Tutorial +Murax SoC is a VexRiscv configuration that is a very lightweight RISC-V platform. +It features a basic set of peripherals (UART, GPIO, Prescalers and Timers) around a pipelined memory bus and Apb3 peripheral bus. +The Murax SoC features enough to more than a toy system and being small and thus offering space for extension. + +For the choice of possible algorithms, that we want to describe in hardware rather than software, the algorithm for calculating the Greatest Common Divisor (GCD) is a good example to start off. There are many digital design resources available on designing a GCD module. + +We will add the hardware peripheral module to the Murax on the Apb3 bus with memory mapped registers to control the module and transfer the data around for the calculation. +In this way we transfer the resources the software to the hardware implementation. +The aspects we will shed some light upon will be + +a) How do we implement an algorithm that we know from the software domain in a hardware implementation suited for FPGAs? + +b) How do we prepare and integrate a new peripheral into the Murax domain and map its control and data ports via memory mapped registers? + +c) How do we extend the software to use the peripheral easily in our baremetal code? + +For a) we will start off the pseudocode of the GCD and work our way to a hardware implementation in SpinalHDL. +We will evaluate that design in a SpinalHDL testbench with Verilator as the simulation backend and drive the testbench with randomly generated values which we compare to a software implementation of the same algorithm. +For b) we will look into the features of SpinalHDL and the structure of the Murax SoC to get an idea where and how to integrate our peripheral. +Before adding the peripheral into the Murax we also need to decide on the details of memory mapping our control and data ports to memory mapped registers (i.e, addresses, write/read/clear modes, etc.). + +At the end there is a small list of possible extensions from which anyone can continue with their own additions. + +## 3. GCD HW Implementation +Let us start the HW implementation by looking at some kind of specification. + +```c +// Pseudocode of the Euclids algorithm for calculating the GCD +inputs: [a, b] +outputs: [ready, a] +ready := False +while(!ready): + if(a > b): + a := a - b + else if(b > a): + b := b - a + else: + ready := True +``` + +The pseudocode shows the GCD algorithm we want to implement in hardware. +Implementing algorithms in hardware in the Register Transfer Level (RTL) style will require you to separate the control path (so if, else, while, for) and the data path (moving, calculating and comparing data). +Inevitably results from data and comparisons affect the control flow and the control flow affects the data flow. +Thus the two paths need to communicate the shared information. +But let us start at defining the interface of our module that will calculate the GCD. + +![GCD Top Diagram](./img/murax-gcd-diagrams-gcd.png) + +Our pseudocode already defines some in- and outputs that can aid us in defining the interface for our module. +At this point we don't want to think about which bus we connect our module to (APB, AXI, Wishbone, etc.). +We take care about that part later. +We simply know we have our input integers A and B, a signal to indicate the start of the calculation, the result and a signal indicating the completion of the calculation. +We choose 32 bit integers and use a valid-ready mechanism (we add a valid signal to kick of the calculation). +The interface features the values A, B and result as the data signals, valid and ready are control signals. +Signals for reset and clock are omitted for readability (unless explicitly used these are handled by SpinalHDL internally anyways). + +From this top level perspective we can describe the behavior as follows: Once we apply a set of operands A and B and then apply the valid signal the module calculates the GCD for a variable amount of clock cycles. +We know the result is ready and can be read once the ready signal is asserted. +Inside the GCD module we will have two other modules: the data path GCDData and the control path GCDCtrl. +We notice again, the data signals (opA, opB and result) belong to our data path and the control signals (valid and ready) belong to our control path. + +![GCD top level block diagram](./img/murax-gcd-diagrams-gcd-dp+cp.png) + +The data path will consist of some basic RTL blocks like multiplexers, a subtraction, comparators and registers. +The elements are connected and arranged such that they represent the dataflow of the algorithm. +Parts of the data path are enabled by the control path. +The control path will be represented by a Finite State Machine (FSM), which orchestrates the data paths calculation of the result. + +![GCD data path](./img/murax-gcd-diagrams-gcd-datapath.png) + +The diagram of the data path shows the processing elements for our algorithm in hardware, with their control input and outputs respectively. +From this we can already see what the interface towards the control path looks like. +The control path needs to know the results of the comparisons. +Vice versa the data path gets controlled through selecting the subtract operands (or more precisely their order), the register enables and an initiation signal for a defined start state. +In the data path, the D-Flipflops (DFF) hold the values A and B that are used for the calculation and they change value throughout the computation. +A subtraction which is set up for a computation such that `r = x - y` with x being the "left" and y being the "right" operand. +The left and right operands are multiplexed from our control path inputs. +Two comparators compute the greater than (cmpAgtB) and less than (cmpAltB) operation. +The result, the GCD of A and B, will be available in the A register after the calculation is done. +Completion of the calculation is signaled by the control path. + +![GCD control path](./img/murax-gcd-diagrams-gcd-controlpath.png) + +In the diagram of the control path we see the same interface (with inverse directions — this information will be helpful later in SpinalHDL). +The interface of the control path are the top level valid signal, the ready signal indicating the finished computation, the results of the two comparisons `A > B` (*cmpAgtB*) and `B > A` (*cmpAltB*). +Initially the FSM is in an idle state, waiting for the valid signal to be asserted, on exit of this state, the init signal is set to 1 to clock in the values of A and B into their respective registers. +Similar to the pseudocode the FSM loops for the calculation and based on the comparators of the data path and orchestrates the data path to calculate either `a := a - b` or `b := b - a`. +If both if the comparators outputs are 0, the end of the calculation is reached. +Within the `calcDone` state the `ready` signal is set to 1. +With the entry of the `idle` state the module becomes ready to calculate another GCD. +The control path drives all the outputs based on the state in the state machine (Moore FSM). +The guards on the transitions show the condition with which the respective transition occurs. +These block diagrams, digital logic and the FSM can be quickly implemented in SpinalHDL, things like the `DataControlIF` that interconnect between the data path and control path can be quickly created and connected in SpinalHDL as well. + +## 4. SpinalHDL implementation +First we can take a look at the interface between the data and control path. + +```scala +// in GCDTop.scala +case class GCDDataControl() extends Bundle with IMasterSlave{ + val cmpAgtB = Bool + val cmpAltB = Bool + val loadA = Bool + val loadB = Bool + val init = Bool + val selL = Bool + val selR = Bool + + override def asMaster(): Unit = { + out(loadA, loadB, selL, selR, init) + in(cmpAgtB, cmpAltB) + } +} +``` + +We can define a Bundle that implements the `IMasterSlave` Interface (see the [Bundle documentation](https://spinalhdl.github.io/SpinalDoc-RTD/master/SpinalHDL/Data%20types/bundle.html?highlight=master%20slave#master-slave)), which allows us to use a operator (`<>`) to interconnect modules and their signals without explicitly describing each wire and connection (other than inside the Bundle from above). +In the Bundle we can define the signals with their types. +We override the `asMaster()` Method (line 10 to 13) from the `IMasterSlave` interface. +In the `asMaster()` Method we define the signal direction from the point of view of the control path. +Thus `cmpAgtB` and `cmpAltB` are inputs and `loadA`, `loadB`, `selL`, `selR`, `init` are outputs. +SpinalHDL will infer the directions for the data path side when we will use the `<>`-Operator. +With that our top level module will look very tidy: + +```scala +// in GCDTop.scala +class GCDTop() extends Component { + val io = new Bundle { + val valid = in Bool() + val ready = out Bool() + val a = in(UInt(32 bits)) + val b = in(UInt(32 bits)) + val res = out(UInt(32 bits)) + } + val gcdCtr = new GCDCtrl() + gcdCtr.io.valid := io.valid + io.ready := gcdCtr.io.ready + val gcdDat = new GCDData() + gcdDat.io.a := io.a + gcdDat.io.b := io.b + io.res := gcdDat.io.res + gcdCtr.io.dataCtrl <> gcdDat.io.dataCtrl +} +``` + +Lines 2 to 8 define the input/output Bundle inline, lines 9 and 12 instantiate the control and data path. All other lines are interconnecting the IO signals. Note in line 16 we interconnect the control and data path by using the `<>`-Operator as they use the shared interface description from earlier as a input (called `dataCtrl` in the design). We will see this in the respective modules input/output bundles. + +Our data path in SpinalHDL looks like this: + +```scala +// in GCDData.scala +class GCDData() extends Component { + val io = new Bundle { + val a = in(UInt(32 bits)) + val b = in(UInt(32 bits)) + val res = out(UInt(32 bits)) + val dataCtrl = slave(GCDDataControl()) + } + //registers + val regA = Reg(UInt(32 bits)) init(0) + val regB = Reg(UInt(32 bits)) init(0) + // compare + val xGTy = regA > regB + val xLTy = regA < regB + // mux + val chX = io.dataCtrl.selL ? regB | regA + val chY = io.dataCtrl.selR ? regB | regA + // subtract + val subXY = chX - chY + // load logic + when(io.dataCtrl.init){ + regA := io.a + regB := io.b + } + when(io.dataCtrl.loadA){ + regA := subXY + } + when(io.dataCtrl.loadB){ + regB := subXY + } + io.dataCtrl.cmpAgtB := xGTy + io.dataCtrl.cmpAltB := xLTy + io.res := regA +} +``` + +Lines 2 to 7 show the Bundle for the IO signals. Note the signal in line 6 (`dataCtrl`), we use the defined Bundle from earlier and give it the direction `slave()` instead `in()` or `out()`. +This tells SpinalHDL to infer the directions of the Bundle signals according to the `asMaster()` method (in that case the inverse directions). +We will see this again in the control path. +The rest of the module (or components, thats how SpinalHDL modules are called) consists of defining signals, registers, and behavior. +Registers can be defined through a `Reg()` components that takes a type and optionally a reset value (via `init()`). +We can write to the register in our `when()` Blocks which could be interpreted as the enable signals for the registers. +(* Side note: technically we describe a multiplexing onto each register as we have multiple cases of enables and different data sources, but we can abstract from that in SpinalHDL a bit and keep it in the back of our minds*). + +Now for the control path of our GCD module: +```scala +// in GCDCtrl.scala +class GCDCtrl() extends Component { + val io = new Bundle { + val valid = in Bool() + val ready = out Bool() + val dataCtrl = master(GCDDataControl()) + } + val fsm = new StateMachine{ + io.dataCtrl.loadA := False + io.dataCtrl.loadB := False + io.dataCtrl.init := False + io.dataCtrl.selL := False + io.dataCtrl.selR := False + io.ready := False + val idle : State = new State with EntryPoint{ + whenIsActive{ + when(io.valid){ + io.dataCtrl.init := True + goto(calculate) + } + } + } + val calculate : State = new State{ + whenIsActive{ + when(io.dataCtrl.cmpAgtB){ + goto(calcA) + }.elsewhen(io.dataCtrl.cmpAltB){ + goto(calcB) + }.elsewhen(!io.dataCtrl.cmpAgtB & !io.dataCtrl.cmpAgtB){ + goto(calcDone) + } + } + } + val calcA : State = new State{ + whenIsActive{ + io.dataCtrl.selR := True + io.dataCtrl.loadA := True + goto(calculate) + } + } + val calcB : State = new State{ + whenIsActive{ + io.dataCtrl.selL := True + io.dataCtrl.loadB := True + goto(calculate) + } + } + val calcDone : State = new State{ + whenIsActive{ + io.ready := True + goto(idle) + } + } + } +} +``` + +The lines 2 to 6 show the input/output signals again, and this time the `dataCtrl` signal, at line 5, shows the direction as `master()`. +This will apply the directions that we set in the first code snipped. +SpinalHDL offers a library to build FSMs and since this module is only that, our control path is descriptive. +We set default values for outputs (lines 8 to 13) and apply the according value in the respective state. + +The API for FSMs in SpinalHDL offers much more than we use here. +In each state we can describe actions for `onEntry`, `onExit`, `whenIsNext` and for `whenIsActive` phases (see the [State Machine documentation](https://spinalhdl.github.io/SpinalDoc-RTD/master/SpinalHDL/Libraries/fsm.html)). +The `onEntry` phase refers to the cycle before entering the state, `onExit` will be executed if the next cycle will be in a different state, and `whenIsNext` will be executed if the state machine will be in that state in the next cycle. +That resembles the capabilities of FSM we have in UML/SysML or in StateCharts. +There is also the possibility to nest FSMs hierarchically or have delay states for a certain amount of cycles. +Describing these things in classic HDL is a lot of boilerplate that SpinalHDL can generate for us instead. + +But with these modules we can already run some first simulations, testing our design for functionality. +And as traditional HDLs go we need a testbench for this. +This applies to SpinalHDL as well. +The default way for [simulation in SpinalHDL](https://spinalhdl.github.io/SpinalDoc-RTD/master/SpinalHDL/Simulation/index.html) is by writing a testbench with SpinalHDL and Scala and then getting it simulated through Verilator. +Verilator compiles our HDL (generated from SpinalHDL) to a C++ simulation model, our testbench interacts with that and thus we can have a fast simulation at hand. +Lets jump straight into the simulation testbench and see how SpinalHDL aids our work here: + +```scala +// in GCDTopSim.scala +object GCDTopSim { + def main(args: Array[String]) { + SimConfig.doSim(new GCDTop()){dut => + def gcd(a: Long,b: Long): Long = { + if(b==0) a else gcd(b, a%b) + } + def RndNextUInt32(): Long = { + ThreadLocalRandom.current().nextLong(Math.pow(2, 32).toLong - 1) + } + var a = 0L + var b = 0L + var model = 0L + dut.io.a #= 0 + dut.io.b #= 0 + dut.io.valid #= false + + dut.clockDomain.forkStimulus(period = 10) + dut.clockDomain.waitRisingEdge() + + for(idx <- 0 to 50000){ + a = RndNextUInt32() + b = RndNextUInt32() + model = gcd(a,b) + dut.io.a #= a + dut.io.b #= b + dut.io.valid #= true + dut.clockDomain.waitRisingEdge() + dut.io.valid #= false + waitUntil(dut.io.ready.toBoolean) + assert( + assertion = (dut.io.res.toBigInt == model), + message = "test " + idx + " failed. Expected " + model + ", retrieved: " + dut.io.res.toBigInt + ) + waitUntil(!dut.io.ready.toBoolean) + } + } + } +} +``` + +In line 3 we basically setup our Design Under Test (DUT), and we could setup some other simulations options like generating the VCD wavetrace. +We want to generate some arbitrary amount of testcases and compare the results against a (different) implementation of the GCD algorithm in software. +Doing this for enough random cases can give confidence in the design, tho it will not always cover edge cases and other aspects that are covered by a constrained random approach, white box testing or formal methods to verify our design. +Lines 4 to 6 are our (recursive) software implementation. +Lines 7 to 9 generate a random number in the range of a UInt32 — we have to do this by hand because of the nature of Java, Scala and SpinalHDL and how they interact with each other when it comes to numeric values and types. +Lines 10 to 15 setup our input for the DUT and in line 17 and 18 we set up the clock and trigger the first event for our signals to be applied to the inputs. +Lines 20 to 35 describe the application of 50k random integers to our design, and our software model, and then comparing them after we waited for the hardware cycles to pass. +We use the `assert` to output a message to the terminal in case a testcase doesn't match with the software model. +If we add `.withWave` to the line 3 we can obtain a wavetrace (tho its recommended not to run as many testcases, as the dump will be huge otherwise). + +![GCD wave trace](./img/simulationWave.PNG) + +## 5. GCD Murax Integration +Now that we have a standalone module that we want to integrate into the Murax SoC. + +Since the Murax is using the APB bus for the peripherals, our module needs to map the IO signals into the memory mapped space of the APB bus. + +```scala +// in Apb3GCDCtrl.scala +object Apb3GCDCtrl { + def getApb3Config = Apb3Config( + addressWidth = 5, + dataWidth = 32, + selWidth = 1, + useSlaveError = false + ) +} + +class Apb3GCDCtrl(apb3Config : Apb3Config) extends Component { + val io = new Bundle { + val apb = slave(Apb3(Apb3GCDCtrl.getApb3Config)) + } + val gcdCtrl = new GCDTop() + val apbCtrl = Apb3SlaveFactory(io.apb) + apbCtrl.driveAndRead(gcdCtrl.io.a, address=0) + apbCtrl.driveAndRead(gcdCtrl.io.b, address=4) + val resSyncBuf = RegNextWhen(gcdCtrl.io.res, gcdCtrl.io.ready) + apbCtrl.read(resSyncBuf, address=8) + apbCtrl.onRead(8)(resSyncBuf := 0) + apbCtrl.onRead(8)(rdySyncBuf := False) + val rdySyncBuf = RegNextWhen(gcdCtrl.io.ready, gcdCtrl.io.ready) + apbCtrl.read(rdySyncBuf, address=12) + gcdCtrl.io.valid := apbCtrl.setOnSet(RegNext(False) init(False), address=16, 0) +} +``` + +Looking at the other peripherals in the Murax, we get an idea how to implement our own Apb3 Mapping (this is also part of the SpinalHDL Workshop). + +The components uses the APB3 Bus as a slave peripheral. +In line 14 we create a instance of our GCD module, in line 15 we create a [APB3 Slave Factory](https://spinalhdl.github.io/SpinalDoc-RTD/master/SpinalHDL/Libraries/bus_slave_factory.html) (for our APB bus connection of the component). +This factory offers us to add memory mapped registers very easily that create all the logic needed to interconnect with our module properly. +A register which can be read and written to can be seen in line 16 and 17 (`driveAndRead()`). +We pass the signal we want to be buffered through that register and an address. +Our result is [buffered with a `RegNextWhen`](https://spinalhdl.github.io/SpinalDoc-RTD/master/SpinalHDL/Sequential%20logic/registers.html#instantiation) (which buffers the first argument `gcdCtrl.io.res` based on the enable signal that is the second argument `gcdCtrl.io.ready`). +We need this because our result is visible for the clock cycle that the ready signal is asserted true by the control path. +We do something similar with the ready signal, and keep it buffered for longer than just one clock cycle (since we don't know when the software will check these registers). +The result and ready registers will be read-only (`read()`) on their respective addresses. +If the result is read (even if ready was not checked) we will flush both registers as if we fetched the result and don't need it anymore. +The valid signal shouldn't be asserted longer than one clock cycle, this is achieved in line 24. +We use a register that sets itself to 0/false whenever its written to. +So if we write a 1/true into it, after one cycle its set to 0/false again. + +| Address | Name | Description | Mode | +|---------|-------|----------------------------------------------|----------------------------------| +| 0 | a | Operand A of the GCD(a,b) | R/W | +| 4 | b | Operand B of the GCD(a,b) | R/W | +| 8 | res | Result of GCD(a,b) | RO, clears res and ready on read | +| 12 | ready | Ready, 1 if result available, 0 otherwise | RO | +| 16 | valid | Valid, write 1 to start calculating GCD(a,b) | WO, clear after write | + + +In this way we implemented this memory mapped register bank with various modes. +Now all thats left is to attach our module to the APB bus of the Murax SoC and write some bare metal firmware to access it. + +We created our modules inside the VexRiscv structure as follows: +``` +src/main/scala/ +├── spinal +└── vexriscv + ├── demo + ├── ip + ├── periph <--- we add this directory with subdir + │ └── gcd + │ ├── Apb3GCDCtrl.scala + │ ├── GCDCtrl.scala + │ ├── GCDData.scala + │ ├── GCDTop.scala + │ └── GCDTopSim.scala + ├── plugin + └── test + +``` + +To integrate our `Apb3GCDCtrl` peripheral into the Murax we need to modify the Murax SoC (`src/main/scala/vexriscv/demo/Murax.scala`) directly. +Deep in the source there will be a comment designating the start of the APB peripherals (`//******** APB peripherals *********`). +There we are going to add our peripheral and designate some memory mapped space to it. + +This step is straightforward as we can add the peripheral similarly to the existing ones. +After the code for the timer `MuraxApb3Timer` module we add our GCD peripheral: + +```scala +val gcd = new Apb3GCDCtrl( + apb3Config = Apb3Config( + addressWidth = 20, + dataWidth = 32 + ) +) +apbMapping += gcd.io.apb -> (0x30000, 1 kB) +``` + +And thats it! + +The Murax SoC now supports our own GCD peripheral. +All thats left now is to use the peripheral in a piece of software. + +## 6. Software Driver Integration + +We start off the software part with the existing `hello_world` example and copy it into a new directory `gcd_world`. + +Since we support a new peripheral in hardware we also need to support it from the software (its supported but we are making it more usable for the developer). +We add a new file in the `gcd_world/src` directory called `gcd.h`. + +```c +// in gcd.h +#ifndef GCD_H_ +#define GCD_H_ + +typedef struct +{ + volatile uint32_t A; + volatile uint32_t B; + volatile uint32_t RES; + volatile uint32_t READY; + volatile uint32_t VALID; +} Gcd_Reg; + +#endif /* GCD_H_ */ + +``` + +With that we define the available memory mapped registers starting from the base address of the peripheral. + +We then edit the `murax.h` header file in the same directory: + +```c +#ifndef __MURAX_H__ +#define __MURAX_H__ + +#include "timer.h" +#include "prescaler.h" +#include "interrupt.h" +#include "gpio.h" +#include "uart.h" +#include "gcd.h" + +#define GPIO_A ((Gpio_Reg*)(0xF0000000)) +#define TIMER_PRESCALER ((Prescaler_Reg*)0xF0020000) +#define TIMER_INTERRUPT ((InterruptCtrl_Reg*)0xF0020010) +#define TIMER_A ((Timer_Reg*)0xF0020040) +#define TIMER_B ((Timer_Reg*)0xF0020050) +#define UART ((Uart_Reg*)(0xF0010000)) +#define GCD ((Gcd_Reg*)(0xF0030000)) + + +#endif /* __MURAX_H__ */ +``` + +Our addition is the line `#define GCD ((Gcd_Reg*)(0xF0030000))`. +With that we create a way of accessing the memory mapped registers without directly referring to the peripherals address (`0xF0030000`) or having to calculate offsets for the registers. + +Now we can start writing our software! + +In our `main.c` we add a function to make the peripheral handling a bit more convenient: + +```c +uint32_t gcd(uint32_t a, uint32_t b){ + GCD->A = a; + GCD->B = b; + GCD->VALID = 0x00000001; + uint32_t rdyFlag = 0; + do{ + rdyFlag = GCD->READY; + }while(!rdyFlag); + return GCD->RES; +} +``` + +This function will take the parameters `a` and `b` and applies them to the respective hardware registers `A` and `B` of our peripheral. +Then the `VALID` signal is set (our Apb3 wrapper takes care of setting it back to 0). +All thats left is waiting for the result, which is done by polling the ready flag until its available and then returning our result value `RES`. + +The software contains a little more code for formatting numbers to print them onto the UART device but reading and understanding that is left as an exercise to the reader. + +So how do we execute our software on the Murax now? + +First we compile the software with the make file. For that call `make` inside `src/main/c/murax/gcd_world`. +You should get some minor warnings and a statistics about the memory usage like + +``` +Memory region Used Size Region Size %age Used + RAM: 1752 B 2 KB 85.55% +``` + +Now we can edit the `Murax.scala` one last time before we execute our simulation. +For this scroll down in the `Murax.scala` file until `MuraxWithRamInit`. +In order to load the memory with our new software instead of the `hello_world` example we edit this part. + +```scala +object MuraxWithRamInit { + def main(args: Array[String]) { + SpinalVerilog( + Murax( + MuraxConfig.default.copy( + onChipRamSize = 4 kB, + onChipRamHexFile = "src/main/c/murax/gcd_world/build/gcd_world.hex" + ) + ) + ) + } +} +``` + + + +Then in the root directory we open `sbt` and call `runMain vexriscv.demo.MuraxWithRamInit` or we call `sbt "runMain vexriscv.demo.MuraxWithRamInit"` directly. + +This will call SpinalHDL to generate the modified Murax SoC with our small software example. + +The last thing we need to do is call the simulation. +For that navigate to `src/test/cpp/murax` and call `make clean run`. + +After some time you should see the following output in the terminal: + +``` +... +BOOT +hello gcd world +gcd(1,123913): +1 +gcd(461952,116298): +18 +gcd(461952,1162): +2 +gcd(461952,11623): +1 +``` + +Keep in mind that we are simulating a SoC. There is no shutdown for our simulation so we have to stop it by ourselves by pressing `CTRL+C`! +Otherwise the simulation won't stop. + + + +## 7. Conclusion + +In a tutorial we described how to convert pseudocode for the GCD calculation into SpinalHDL based hardware. Furthermore the hardware was integrated into the VexRiscv based Murax SoC. +To demonstrate the usage an example C project was set up and the hardware peripheral was used from within the software. + +This tutorial covered the translation from RTL into SpinalHDL, writing a small wrapper for the APB3 bus used in the Murax SoC, integrating the peripheral into the Murax SoC with designated memory mapped space and writing software in C for the Murax SoC that uses the hardware peripheral to calculate the GCD and print it out on the UART of the Murax SoC. + +Now there are a few open challanges to approach as an exercise here are two that would follow up naturally to our existing code: + +* The Murax SoC features interrupts, we could stop polling our ready flag and instead trigger an interrupt from the `Apb3GCDCtrl` instead. +* Write the same algorithm in C and compare it with the hardware peripheral. Is it faster, is it smaller (interacting with the peripheral in software still costs instruction in terms of memory) \ No newline at end of file diff --git a/doc/gcdPeripheral/img/murax-gcd-diagrams-gcd-controlpath.png b/doc/gcdPeripheral/img/murax-gcd-diagrams-gcd-controlpath.png new file mode 100644 index 0000000000000000000000000000000000000000..e0b09f6a0ce46e5e618becfb24fc771afffb3dcb GIT binary patch literal 68613 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�W7=6yT}k+0Lo5h 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 literal 0 HcmV?d00001 diff --git a/doc/gcdPeripheral/img/murax-gcd-diagrams-gcd-dp+cp.png b/doc/gcdPeripheral/img/murax-gcd-diagrams-gcd-dp+cp.png new file mode 100644 index 0000000000000000000000000000000000000000..68daa3c8c902513a09ee7a368431aa56868dbe1f GIT binary patch literal 27013 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┽ zrSoOLZXh%0qS4Ekztt-%)@u8DdnjE8w)T}aDU`kQb1x+zN(rE-r z0;UNA5!x*Nwi`{$GLWSl%3gWt`c)}O#2yYWUfgLBJ+V^I6dI_5TO6;iL4WTR+GwR# z?*yJDqIffmNjQp@S62h2Qq7wYiDydorQ>;fK4cvBWinA_lpkOEnN3 z)hX1|lme|9X<(Pz?>3|$a-0_`)9!hjf*Ws^+QYwBW~i?ZBYrP?!_S$JC5I4smisbR zZ=PjYUAWh@!9jerkU9tPnYH5KmdM)?Rz-CDUi8Z!C%!PW_}~#`LKn!Rn(~Kbx#{m` zB}%2KdpUrg$@)^%n8Jmavwv@_8Ca|%frz_#;vhg>X(C>;mE65bi{8p>rScgNIv2b> zklEQsd9LDYtvX)CIiO6mxTF)u=UzQJeCVpexALy(B59oI7w>%_f7oD{0W!(%rW}IO z`&dwQ+HAj&{kmNaFn&IF`=Ll&SOr6uUEWX^OtU2H88e?Dr5~q>TI;O(U|gVP+bk9Q z^z4;x5L6Ck`u}3klL(lc6>L!Eual{E80SgwX(}Y-A8j!XLZnxT6lWxpgl%=ZQl$~m zng9=<*KvPGb53!w7DvlEueSf1v~Z`Or9?D$lXJbWOkL`gHSsM zM)AZOWDL4>{w_rFV0$KwDm3&u8ixv&dwc6X`^^<}aZE^1rqprh4{FNJ*(yMPzypPl z7DWSNJot|T@fBEa!^%=_fV3qP69_n}6RFTfUi)LiYG$#_Tm!WnHR}Q$;zIyv z*KB+6>u=G7Vrxt^l-1!noRRD3mHnF>g4`vIF$6A142F5!?E===7zk>@_%A-z>h7pB04ROX(dka-+S>%6>tx*ymSYgObJ z_mneYT$r+kX^C`=+T9*G#Pd#2H%Al7T4P+=!y*}CidY|T4xVu-@cojAf?C!JKG=d# zCp+;8lnUkf11TYrRyh3S01rj49bGm!%cckNWEM z{~Q%CJj{UgfeoGPFU;Xn3Lom9l@)CWFLS;xR1*!ix=dnBt#CPnQVTA@Sd{rYxbp9U zdb`E`g$f1oXCmX%cX=4N8n`ciCztdQHN1CL#}-#Rkxq2&7?f?EJoanKBTNaVF!DEH zPvP2*(BY4;yswL8KWGYHVDPb*rUO9*D>#w~>mMhq zX`vc2`x>a<7-v$GkrG}xd8E%cMv?$%dt)@%LXDTUBbk&-&T%h zRgk={Z2!pLrXers6q*E+0!f=Mc>aHDGQi#qb=zBErt$-+TR^;fsh_00Lh;c7`5nO+ zeWc#-MoJ3rFYCb4C|M7D1@`m#-#2soJN$V;|57%xU|K1&P+B0yZlCbIgosXlDD3K? zWxM&srR0BGIXHouM^#lnT7tEzx}kp-`+b?Yw83tOvmAr)!_2~dGCM99R4Y*f7%9Y!2PeHkAK?6KW*cmw((nf^Z)Bvu)*DZb}IGv z5BjkBppc&`66x?XwXsPZicEgPbrNT$2V;F{d&vJB-PPT`9TI(0rq+I1&ZY-HuXIdN MR!ye(I@b5U05CA3NdN!< literal 0 HcmV?d00001 diff --git a/doc/gcdPeripheral/img/murax-gcd-diagrams-gcd.png b/doc/gcdPeripheral/img/murax-gcd-diagrams-gcd.png new file mode 100644 index 0000000000000000000000000000000000000000..f557a69094311785d8d3241b43832e7fc812018d GIT binary patch literal 15632 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 ij~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 \ No newline at end of file diff --git a/doc/gcdPeripheral/img/simulationWave.PNG b/doc/gcdPeripheral/img/simulationWave.PNG new file mode 100644 index 0000000000000000000000000000000000000000..93853cbd702b2a66bdc64f825b147929d59ef71d GIT binary patch literal 48129 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 literal 0 HcmV?d00001 diff --git a/doc/gcdPeripheral/src/main/c/murax/gcd_world/makefile b/doc/gcdPeripheral/src/main/c/murax/gcd_world/makefile new file mode 100644 index 00000000..0f4abd87 --- /dev/null +++ b/doc/gcdPeripheral/src/main/c/murax/gcd_world/makefile @@ -0,0 +1,134 @@ +PROJ_NAME=gcd_world +DEBUG=no +BENCH=no +MULDIV=no + +SRCS = $(wildcard src/*.c) \ + $(wildcard src/*.cpp) \ + $(wildcard src/*.S) + +OBJDIR = build + +INC = +LIBS = +LIBSINC = -L$(OBJDIR) +LDSCRIPT = ./src/linker.ld + +#include ../../../resources/gcc.mk +# Set it to yes if you are using the sifive precompiled GCC pack +SIFIVE_GCC_PACK ?= no + +ifeq ($(SIFIVE_GCC_PACK),yes) + RISCV_NAME ?= riscv64-unknown-elf + RISCV_PATH ?= /home/sallar/tools/riscv-64-newlib-dist/ +else + RISCV_NAME ?= riscv32-unknown-elf + ifeq ($(MULDIV),yes) + RISCV_PATH ?= /home/sallar/tools/riscv-32-imac-ilp32-newlib-dist/ + else + RISCV_PATH ?= /home/sallar/tools/rv32i-ilp32-dist/ + endif +endif + +MABI=ilp32 +MARCH := rv32i +ifeq ($(MULDIV),yes) + MARCH := $(MARCH)m +endif +ifeq ($(COMPRESSED),yes) + MARCH := $(MARCH)ac +endif + +CFLAGS += -march=$(MARCH) -mabi=$(MABI) -DNDEBUG +LDFLAGS += -march=$(MARCH) -mabi=$(MABI) + + + +#include ../../../resources/subproject.mk + + +ifeq ($(DEBUG),yes) + CFLAGS += -g3 -O0 +endif + +ifeq ($(DEBUG),no) + CFLAGS += -g -Os +endif + +ifeq ($(BENCH),yes) + CFLAGS += -fno-inline +endif + +ifeq ($(SIFIVE_GCC_PACK),yes) + RISCV_CLIB=$(RISCV_PATH)/$(RISCV_NAME)/lib/$(MARCH)/$(MABI)/ +else + RISCV_CLIB=$(RISCV_PATH)/$(RISCV_NAME)/lib/ +endif + + + + + +RISCV_OBJCOPY = $(RISCV_PATH)/bin/$(RISCV_NAME)-objcopy +RISCV_OBJDUMP = $(RISCV_PATH)/bin/$(RISCV_NAME)-objdump +RISCV_CC=$(RISCV_PATH)/bin/$(RISCV_NAME)-gcc + +CFLAGS += -MD -fstrict-volatile-bitfields -fno-strict-aliasing +LDFLAGS += -nostdlib -lgcc -mcmodel=medany -nostartfiles -ffreestanding -Wl,-Bstatic,-T,$(LDSCRIPT),-Map,$(OBJDIR)/$(PROJ_NAME).map,--print-memory-usage +#LDFLAGS += -lgcc -lc -lg -nostdlib -lgcc -msave-restore --strip-debug, + +OBJS := $(SRCS) +OBJS := $(OBJS:.c=.o) +OBJS := $(OBJS:.cpp=.o) +OBJS := $(OBJS:.S=.o) +OBJS := $(OBJS:..=miaou) +OBJS := $(addprefix $(OBJDIR)/,$(OBJS)) + + +all: $(OBJDIR)/$(PROJ_NAME).elf $(OBJDIR)/$(PROJ_NAME).hex $(OBJDIR)/$(PROJ_NAME).asm $(OBJDIR)/$(PROJ_NAME).v + +$(OBJDIR)/%.elf: $(OBJS) | $(OBJDIR) + $(RISCV_CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) $(LIBSINC) $(LIBS) + +%.hex: %.elf + $(RISCV_OBJCOPY) -O ihex $^ $@ + +%.bin: %.elf + $(RISCV_OBJCOPY) -O binary $^ $@ + +%.v: %.elf + $(RISCV_OBJCOPY) -O verilog $^ $@ + +%.asm: %.elf + $(RISCV_OBJDUMP) -S -d $^ > $@ + +$(OBJDIR)/%.o: %.c + mkdir -p $(dir $@) + $(RISCV_CC) -c $(CFLAGS) $(INC) -o $@ $^ + $(RISCV_CC) -S $(CFLAGS) $(INC) -o $@.disasm $^ + +$(OBJDIR)/%.o: %.cpp + mkdir -p $(dir $@) + $(RISCV_CC) -c $(CFLAGS) $(INC) -o $@ $^ + +$(OBJDIR)/%.o: %.S + mkdir -p $(dir $@) + $(RISCV_CC) -c $(CFLAGS) -o $@ $^ -D__ASSEMBLY__=1 + +$(OBJDIR): + mkdir -p $@ + +.PHONY: clean +clean: + rm -rf $(OBJDIR)/src + rm -f $(OBJDIR)/$(PROJ_NAME).elf + rm -f $(OBJDIR)/$(PROJ_NAME).hex + rm -f $(OBJDIR)/$(PROJ_NAME).map + rm -f $(OBJDIR)/$(PROJ_NAME).v + rm -f $(OBJDIR)/$(PROJ_NAME).asm + find $(OBJDIR) -type f -name '*.o' -print0 | xargs -0 -r rm + find $(OBJDIR) -type f -name '*.d' -print0 | xargs -0 -r rm + +clean-all : clean + +.SECONDARY: $(OBJS) diff --git a/doc/gcdPeripheral/src/main/c/murax/gcd_world/project/build.properties b/doc/gcdPeripheral/src/main/c/murax/gcd_world/project/build.properties new file mode 100644 index 00000000..dbae93bc --- /dev/null +++ b/doc/gcdPeripheral/src/main/c/murax/gcd_world/project/build.properties @@ -0,0 +1 @@ +sbt.version=1.4.9 diff --git a/doc/gcdPeripheral/src/main/c/murax/gcd_world/src/crt.S b/doc/gcdPeripheral/src/main/c/murax/gcd_world/src/crt.S new file mode 100644 index 00000000..62d67b9e --- /dev/null +++ b/doc/gcdPeripheral/src/main/c/murax/gcd_world/src/crt.S @@ -0,0 +1,98 @@ +.global crtStart +.global main +.global irqCallback + + .section .start_jump,"ax",@progbits +crtStart: + //long jump to allow crtInit to be anywhere + //do it always in 12 bytes + lui x2, %hi(crtInit) + addi x2, x2, %lo(crtInit) + jalr x1,x2 + nop + +.section .text + +.global trap_entry +.align 5 +trap_entry: + sw x1, - 1*4(sp) + sw x5, - 2*4(sp) + sw x6, - 3*4(sp) + sw x7, - 4*4(sp) + sw x10, - 5*4(sp) + sw x11, - 6*4(sp) + sw x12, - 7*4(sp) + sw x13, - 8*4(sp) + sw x14, - 9*4(sp) + sw x15, -10*4(sp) + sw x16, -11*4(sp) + sw x17, -12*4(sp) + sw x28, -13*4(sp) + sw x29, -14*4(sp) + sw x30, -15*4(sp) + sw x31, -16*4(sp) + addi sp,sp,-16*4 + call irqCallback + lw x1 , 15*4(sp) + lw x5, 14*4(sp) + lw x6, 13*4(sp) + lw x7, 12*4(sp) + lw x10, 11*4(sp) + lw x11, 10*4(sp) + lw x12, 9*4(sp) + lw x13, 8*4(sp) + lw x14, 7*4(sp) + lw x15, 6*4(sp) + lw x16, 5*4(sp) + lw x17, 4*4(sp) + lw x28, 3*4(sp) + lw x29, 2*4(sp) + lw x30, 1*4(sp) + lw x31, 0*4(sp) + addi sp,sp,16*4 + mret + .text + + +crtInit: + .option push + .option norelax + la gp, __global_pointer$ + .option pop + la sp, _stack_start + +bss_init: + la a0, _bss_start + la a1, _bss_end +bss_loop: + beq a0,a1,bss_done + sw zero,0(a0) + add a0,a0,4 + j bss_loop +bss_done: + +ctors_init: + la a0, _ctors_start + addi sp,sp,-4 +ctors_loop: + la a1, _ctors_end + beq a0,a1,ctors_done + lw a3,0(a0) + add a0,a0,4 + sw a0,0(sp) + jalr a3 + lw a0,0(sp) + j ctors_loop +ctors_done: + addi sp,sp,4 + + + li a0, 0x880 //880 enable timer + external interrupts + csrw mie,a0 + li a0, 0x1808 //1808 enable interrupts + csrw mstatus,a0 + + call main +infinitLoop: + j infinitLoop diff --git a/doc/gcdPeripheral/src/main/c/murax/gcd_world/src/gcd.h b/doc/gcdPeripheral/src/main/c/murax/gcd_world/src/gcd.h new file mode 100644 index 00000000..1d3ccb70 --- /dev/null +++ b/doc/gcdPeripheral/src/main/c/murax/gcd_world/src/gcd.h @@ -0,0 +1,13 @@ +#ifndef GCD_H_ +#define GCD_H_ + +typedef struct +{ + volatile uint32_t A; + volatile uint32_t B; + volatile uint32_t RES; + volatile uint32_t READY; + volatile uint32_t VALID; +} Gcd_Reg; + +#endif /* GCD_H_ */ diff --git a/doc/gcdPeripheral/src/main/c/murax/gcd_world/src/gpio.h b/doc/gcdPeripheral/src/main/c/murax/gcd_world/src/gpio.h new file mode 100644 index 00000000..34348fec --- /dev/null +++ b/doc/gcdPeripheral/src/main/c/murax/gcd_world/src/gpio.h @@ -0,0 +1,15 @@ +#ifndef GPIO_H_ +#define GPIO_H_ + + +typedef struct +{ + volatile uint32_t INPUT; + volatile uint32_t OUTPUT; + volatile uint32_t OUTPUT_ENABLE; +} Gpio_Reg; + + +#endif /* GPIO_H_ */ + + diff --git a/doc/gcdPeripheral/src/main/c/murax/gcd_world/src/interrupt.h b/doc/gcdPeripheral/src/main/c/murax/gcd_world/src/interrupt.h new file mode 100644 index 00000000..23b7d277 --- /dev/null +++ b/doc/gcdPeripheral/src/main/c/murax/gcd_world/src/interrupt.h @@ -0,0 +1,17 @@ +#ifndef INTERRUPTCTRL_H_ +#define INTERRUPTCTRL_H_ + +#include + +typedef struct +{ + volatile uint32_t PENDINGS; + volatile uint32_t MASKS; +} InterruptCtrl_Reg; + +static void interruptCtrl_init(InterruptCtrl_Reg* reg){ + reg->MASKS = 0; + reg->PENDINGS = 0xFFFFFFFF; +} + +#endif /* INTERRUPTCTRL_H_ */ diff --git a/doc/gcdPeripheral/src/main/c/murax/gcd_world/src/linker.ld b/doc/gcdPeripheral/src/main/c/murax/gcd_world/src/linker.ld new file mode 100644 index 00000000..57bc2f7b --- /dev/null +++ b/doc/gcdPeripheral/src/main/c/murax/gcd_world/src/linker.ld @@ -0,0 +1,110 @@ +/* +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. +*/ +OUTPUT_FORMAT("elf32-littleriscv", "elf32-littleriscv", "elf32-littleriscv") +OUTPUT_ARCH(riscv) +ENTRY(crtStart) + +MEMORY { + RAM (rwx): ORIGIN = 0x80000000, LENGTH = 2k +} + +_stack_size = DEFINED(_stack_size) ? _stack_size : 256; +_heap_size = DEFINED(_heap_size) ? _heap_size : 0; + +SECTIONS { + + ._vector ORIGIN(RAM): { + *crt.o(.start_jump); + *crt.o(.text); + } > RAM + + ._user_heap (NOLOAD): + { + . = ALIGN(8); + PROVIDE ( end = . ); + PROVIDE ( _end = . ); + PROVIDE ( _heap_start = .); + . = . + _heap_size; + . = ALIGN(8); + PROVIDE ( _heap_end = .); + } > RAM + +._stack (NOLOAD): + { + . = ALIGN(16); + PROVIDE (_stack_end = .); + . = . + _stack_size; + . = ALIGN(16); + PROVIDE (_stack_start = .); + } > RAM + + .data : + { + *(.rdata) + *(.rodata .rodata.*) + *(.gnu.linkonce.r.*) + *(.data .data.*) + *(.gnu.linkonce.d.*) + . = ALIGN(8); + PROVIDE( __global_pointer$ = . + 0x800 ); + *(.sdata .sdata.*) + *(.gnu.linkonce.s.*) + . = ALIGN(8); + *(.srodata.cst16) + *(.srodata.cst8) + *(.srodata.cst4) + *(.srodata.cst2) + *(.srodata .srodata.*) + } > RAM + + .bss (NOLOAD) : { + . = ALIGN(4); + /* This is used by the startup in order to initialize the .bss secion */ + _bss_start = .; + *(.sbss*) + *(.gnu.linkonce.sb.*) + *(.bss .bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(4); + _bss_end = .; + } > RAM + + + .rodata : + { + *(.rdata) + *(.rodata .rodata.*) + *(.gnu.linkonce.r.*) + } > RAM + + .noinit (NOLOAD) : { + . = ALIGN(4); + *(.noinit .noinit.*) + . = ALIGN(4); + } > RAM + + .memory : { + *(.text); + end = .; + } > RAM + + .ctors : + { + . = ALIGN(4); + _ctors_start = .; + KEEP(*(.init_array*)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + . = ALIGN(4); + _ctors_end = .; + PROVIDE ( END_OF_SW_IMAGE = . ); + } > RAM + +} diff --git a/doc/gcdPeripheral/src/main/c/murax/gcd_world/src/main.c b/doc/gcdPeripheral/src/main/c/murax/gcd_world/src/main.c new file mode 100644 index 00000000..fccbcc2f --- /dev/null +++ b/doc/gcdPeripheral/src/main/c/murax/gcd_world/src/main.c @@ -0,0 +1,62 @@ +//#include "stddefs.h" +#include + +#include "murax.h" + +#include "main.h" + +#define DEBUG 0 + +uint32_t gcd(uint32_t a, uint32_t b){ + GCD->A = a; + GCD->B = b; + GCD->VALID = 0x00000001; + uint32_t rdyFlag = 0; + do{ + rdyFlag = GCD->READY; + }while(!rdyFlag); + return GCD->RES; +} + +void calcPrintGCD(uint32_t a, uint32_t b){ + uint32_t myGCD = 0; + char buf[5] = { 0x00 }; + char aBuf[11] = { 0x00 }; + char bBuf[11] = { 0x00 }; + itoa(a, aBuf, 10); + itoa(b, bBuf, 10); + print("gcd(");print(aBuf);print(",");print(bBuf);println("):"); + myGCD = gcd(a,b); + itoa(myGCD, buf, 10); + println(buf); +} + +void main() { + GPIO_A->OUTPUT_ENABLE = 0x0000000F; + GPIO_A->OUTPUT = 0x00000001; + println("hello gcd world"); + const int nleds = 4; + const int nloops = 2000000; + + GCD->VALID = 0x00000000; + while(GCD->READY); + + calcPrintGCD(1, 123913); + calcPrintGCD(461952, 116298); + calcPrintGCD(461952, 116298); + calcPrintGCD(461952, 116298); + + while(1){ + for(unsigned int i=0;iOUTPUT = 1<OUTPUT = (1<<(nleds-1))>>i; + delay(nloops); + } + } +} + +void irqCallback(){ +} diff --git a/doc/gcdPeripheral/src/main/c/murax/gcd_world/src/main.h b/doc/gcdPeripheral/src/main/c/murax/gcd_world/src/main.h new file mode 100644 index 00000000..31cb9c03 --- /dev/null +++ b/doc/gcdPeripheral/src/main/c/murax/gcd_world/src/main.h @@ -0,0 +1,78 @@ + +//---------------------------- +// integer to ascii (itoa) with util functions +//---------------------------- + +// function to swap two numbers +void swap(char *x, char *y) { + char t = *x; *x = *y; *y = t; +} + +// function to reverse buffer[i..j] +char* reverse(char *buffer, int i, int j) { + while (i < j) + swap(&buffer[i++], &buffer[j--]); + return buffer; +} + +// Iterative function to implement itoa() function in C +char* itoa(int value, char* buffer, int base) { + // invalid input + if (base < 2 || base > 32) + return buffer; + // consider absolute value of number + int n = (value < 0) ? -value : value; + int i = 0; + while (n) { + int r = n % base; + if (r >= 10) + buffer[i++] = 65 + (r - 10); + else + buffer[i++] = 48 + r; + n = n / base; + } + + // if number is 0 + if (i == 0) + buffer[i++] = '0'; + + // If base is 10 and value is negative, the resulting string + // is preceded with a minus sign (-) + // With any other base, value is always considered unsigned + if (value < 0 && base == 10) + buffer[i++] = '-'; + + buffer[i] = '\0'; // null terminate string + + // reverse the string and return it + return reverse(buffer, 0, i - 1); +} + +//---------------------------- +// print, println, dbgprint +//---------------------------- + +void print(const char*str){ + while(*str){ + uart_write(UART,*str); + str++; + } +} +void println(const char*str){ + print(str); + uart_write(UART,'\n'); +} + +void dbgPrintln(const char*str){ + #if DEBUG == 1 + println(str); + #else + void; + #endif +} + +void delay(uint32_t loops){ + for(int i=0;iOUTPUT; + } +} \ No newline at end of file diff --git a/doc/gcdPeripheral/src/main/c/murax/gcd_world/src/murax.h b/doc/gcdPeripheral/src/main/c/murax/gcd_world/src/murax.h new file mode 100644 index 00000000..9d7b7e7a --- /dev/null +++ b/doc/gcdPeripheral/src/main/c/murax/gcd_world/src/murax.h @@ -0,0 +1,20 @@ +#ifndef __MURAX_H__ +#define __MURAX_H__ + +#include "timer.h" +#include "prescaler.h" +#include "interrupt.h" +#include "gpio.h" +#include "uart.h" +#include "gcd.h" + +#define GPIO_A ((Gpio_Reg*)(0xF0000000)) +#define TIMER_PRESCALER ((Prescaler_Reg*)0xF0020000) +#define TIMER_INTERRUPT ((InterruptCtrl_Reg*)0xF0020010) +#define TIMER_A ((Timer_Reg*)0xF0020040) +#define TIMER_B ((Timer_Reg*)0xF0020050) +#define UART ((Uart_Reg*)(0xF0010000)) +#define GCD ((Gcd_Reg*)(0xF0030000)) + + +#endif /* __MURAX_H__ */ diff --git a/doc/gcdPeripheral/src/main/c/murax/gcd_world/src/prescaler.h b/doc/gcdPeripheral/src/main/c/murax/gcd_world/src/prescaler.h new file mode 100644 index 00000000..6bd9694a --- /dev/null +++ b/doc/gcdPeripheral/src/main/c/murax/gcd_world/src/prescaler.h @@ -0,0 +1,16 @@ +#ifndef PRESCALERCTRL_H_ +#define PRESCALERCTRL_H_ + +#include + + +typedef struct +{ + volatile uint32_t LIMIT; +} Prescaler_Reg; + +static void prescaler_init(Prescaler_Reg* reg){ + +} + +#endif /* PRESCALERCTRL_H_ */ diff --git a/doc/gcdPeripheral/src/main/c/murax/gcd_world/src/timer.h b/doc/gcdPeripheral/src/main/c/murax/gcd_world/src/timer.h new file mode 100644 index 00000000..1577535c --- /dev/null +++ b/doc/gcdPeripheral/src/main/c/murax/gcd_world/src/timer.h @@ -0,0 +1,20 @@ +#ifndef TIMERCTRL_H_ +#define TIMERCTRL_H_ + +#include + + +typedef struct +{ + volatile uint32_t CLEARS_TICKS; + volatile uint32_t LIMIT; + volatile uint32_t VALUE; +} Timer_Reg; + +static void timer_init(Timer_Reg *reg){ + reg->CLEARS_TICKS = 0; + reg->VALUE = 0; +} + + +#endif /* TIMERCTRL_H_ */ diff --git a/doc/gcdPeripheral/src/main/c/murax/gcd_world/src/uart.h b/doc/gcdPeripheral/src/main/c/murax/gcd_world/src/uart.h new file mode 100644 index 00000000..c3a30a56 --- /dev/null +++ b/doc/gcdPeripheral/src/main/c/murax/gcd_world/src/uart.h @@ -0,0 +1,42 @@ +#ifndef UART_H_ +#define UART_H_ + + +typedef struct +{ + volatile uint32_t DATA; + volatile uint32_t STATUS; + volatile uint32_t CLOCK_DIVIDER; + volatile uint32_t FRAME_CONFIG; +} Uart_Reg; + +enum UartParity {NONE = 0,EVEN = 1,ODD = 2}; +enum UartStop {ONE = 0,TWO = 1}; + +typedef struct { + uint32_t dataLength; + enum UartParity parity; + enum UartStop stop; + uint32_t clockDivider; +} Uart_Config; + +static uint32_t uart_writeAvailability(Uart_Reg *reg){ + return (reg->STATUS >> 16) & 0xFF; +} +static uint32_t uart_readOccupancy(Uart_Reg *reg){ + return reg->STATUS >> 24; +} + +static void uart_write(Uart_Reg *reg, uint32_t data){ + while(uart_writeAvailability(reg) == 0); + reg->DATA = data; +} + +static void uart_applyConfig(Uart_Reg *reg, Uart_Config *config){ + reg->CLOCK_DIVIDER = config->clockDivider; + reg->FRAME_CONFIG = ((config->dataLength-1) << 0) | (config->parity << 8) | (config->stop << 16); +} + +#endif /* UART_H_ */ + + diff --git a/doc/gcdPeripheral/src/main/scala/vexriscv/demo/Murax.scala b/doc/gcdPeripheral/src/main/scala/vexriscv/demo/Murax.scala new file mode 100644 index 00000000..f3d4f6cd --- /dev/null +++ b/doc/gcdPeripheral/src/main/scala/vexriscv/demo/Murax.scala @@ -0,0 +1,559 @@ +package vexriscv.demo + +import spinal.core._ +import spinal.lib._ +import spinal.lib.bus.amba3.apb._ +import spinal.lib.bus.misc.SizeMapping +import spinal.lib.bus.simple.PipelinedMemoryBus +import spinal.lib.com.jtag.Jtag +import spinal.lib.com.spi.ddr.SpiXdrMaster +import spinal.lib.com.uart._ +import spinal.lib.io.{InOutWrapper, TriStateArray} +import spinal.lib.misc.{InterruptCtrl, Prescaler, Timer} +import spinal.lib.soc.pinsec.{PinsecTimerCtrl, PinsecTimerCtrlExternal} +import vexriscv.plugin._ +import vexriscv.{VexRiscv, VexRiscvConfig, plugin} +import spinal.lib.com.spi.ddr._ +import spinal.lib.bus.simple._ +import scala.collection.mutable.ArrayBuffer +import vexriscv.periph.gcd._ +import vexriscv.periph.tasks.gen._ +import vexriscv.periph.tasks.map._ +import vexriscv.periph.tasks.sort._ +import vexriscv.periph.tasks.max._ +import vexriscv.periph.tasks.sum._ +import vexriscv.periph.tasks.hash._ + +/** Created by PIC32F_USER on 28/07/2017. + * + * Murax is a very light SoC which could work without any external component. + * - ICE40-hx8k + icestorm => 53 Mhz, 2142 LC + * - 0.37 DMIPS/Mhz + * - 8 kB of on-chip ram + * - JTAG debugger (eclipse/GDB/openocd ready) + * - Interrupt support + * - APB bus for peripherals + * - 32 GPIO pin + * - one 16 bits prescaler, two 16 bits timers + * - one UART with tx/rx fifo + */ + +case class MuraxConfig( + coreFrequency: HertzNumber, + onChipRamSize: BigInt, + onChipRamHexFile: String, + pipelineDBus: Boolean, + pipelineMainBus: Boolean, + pipelineApbBridge: Boolean, + gpioWidth: Int, + uartCtrlConfig: UartCtrlMemoryMappedConfig, + xipConfig: SpiXdrMasterCtrl.MemoryMappingParameters, + hardwareBreakpointCount: Int, + cpuPlugins: ArrayBuffer[Plugin[VexRiscv]] +) { + require( + pipelineApbBridge || pipelineMainBus, + "At least pipelineMainBus or pipelineApbBridge should be enable to avoid wipe transactions" + ) + val genXip = xipConfig != null + +} + +object MuraxConfig { + def default: MuraxConfig = default(false, false) + def default(withXip: Boolean = false, bigEndian: Boolean = false) = + MuraxConfig( + coreFrequency = 12 MHz, + onChipRamSize = 8 kB, + onChipRamHexFile = null, + pipelineDBus = true, + pipelineMainBus = false, + pipelineApbBridge = true, + gpioWidth = 32, + xipConfig = ifGen(withXip)( + SpiXdrMasterCtrl.MemoryMappingParameters( + SpiXdrMasterCtrl + .Parameters(8, 12, SpiXdrParameter(2, 2, 1)) + .addFullDuplex(0, 1, false), + cmdFifoDepth = 32, + rspFifoDepth = 32, + xip = SpiXdrMasterCtrl + .XipBusParameters(addressWidth = 24, lengthWidth = 2) + ) + ), + hardwareBreakpointCount = if (withXip) 3 else 0, + cpuPlugins = ArrayBuffer( //DebugPlugin added by the toplevel + new IBusSimplePlugin( + resetVector = if (withXip) 0xf001e000L else 0x80000000L, + cmdForkOnSecondStage = true, + cmdForkPersistence = withXip, //Required by the Xip controller + prediction = NONE, + catchAccessFault = false, + compressedGen = false, + bigEndian = bigEndian + ), + new DBusSimplePlugin( + catchAddressMisaligned = false, + catchAccessFault = false, + earlyInjection = false, + bigEndian = bigEndian + ), + new CsrPlugin( + CsrPluginConfig.smallest(mtvecInit = + if (withXip) 0xe0040020L else 0x80000020L + ) + ), + new DecoderSimplePlugin( + catchIllegalInstruction = false + ), + new RegFilePlugin( + regFileReadyKind = plugin.SYNC, + zeroBoot = false + ), + new IntAluPlugin, + new SrcPlugin( + separatedAddSub = false, + executeInsertion = false + ), + new LightShifterPlugin, + new HazardSimplePlugin( + bypassExecute = false, + bypassMemory = false, + bypassWriteBack = false, + bypassWriteBackBuffer = false, + pessimisticUseSrc = false, + pessimisticWriteRegFile = false, + pessimisticAddressMatch = false + ), + new BranchPlugin( + earlyBranch = false, + catchAddressMisaligned = false + ), + new YamlPlugin("cpu0.yaml") + ), + uartCtrlConfig = UartCtrlMemoryMappedConfig( + uartCtrlConfig = UartCtrlGenerics( + dataWidthMax = 8, + clockDividerWidth = 20, + preSamplingSize = 1, + samplingSize = 3, + postSamplingSize = 1 + ), + initConfig = UartCtrlInitConfig( + baudrate = 115200, + dataLength = 7, //7 => 8 bits + parity = UartParityType.NONE, + stop = UartStopType.ONE + ), + busCanWriteClockDividerConfig = false, + busCanWriteFrameConfig = false, + txFifoDepth = 16, + rxFifoDepth = 16 + ) + ) + + def fast = { + val config = default + + //Replace HazardSimplePlugin to get datapath bypass + config.cpuPlugins( + config.cpuPlugins.indexWhere(_.isInstanceOf[HazardSimplePlugin]) + ) = new HazardSimplePlugin( + bypassExecute = true, + bypassMemory = true, + bypassWriteBack = true, + bypassWriteBackBuffer = true + ) +// config.cpuPlugins(config.cpuPlugins.indexWhere(_.isInstanceOf[LightShifterPlugin])) = new FullBarrelShifterPlugin() + + config + } +} + +case class Murax(config: MuraxConfig) extends Component { + import config._ + + val io = new Bundle { + //Clocks / reset + val asyncReset = in Bool () + val mainClk = in Bool () + + //Main components IO + val jtag = slave(Jtag()) + + //Peripherals IO + val gpioA = master(TriStateArray(gpioWidth bits)) + val uart = master(Uart()) + + val xip = ifGen(genXip)(master(SpiXdrMaster(xipConfig.ctrl.spi))) + } + + val resetCtrlClockDomain = ClockDomain( + clock = io.mainClk, + config = ClockDomainConfig( + resetKind = BOOT + ) + ) + + val resetCtrl = new ClockingArea(resetCtrlClockDomain) { + val mainClkResetUnbuffered = False + + //Implement an counter to keep the reset axiResetOrder high 64 cycles + // Also this counter will automatically do a reset when the system boot. + val systemClkResetCounter = Reg(UInt(6 bits)) init (0) + when(systemClkResetCounter =/= U(systemClkResetCounter.range -> true)) { + systemClkResetCounter := systemClkResetCounter + 1 + mainClkResetUnbuffered := True + } + when(BufferCC(io.asyncReset)) { + systemClkResetCounter := 0 + } + + //Create all reset used later in the design + val mainClkReset = RegNext(mainClkResetUnbuffered) + val systemReset = RegNext(mainClkResetUnbuffered) + } + + val systemClockDomain = ClockDomain( + clock = io.mainClk, + reset = resetCtrl.systemReset, + frequency = FixedFrequency(coreFrequency) + ) + + val debugClockDomain = ClockDomain( + clock = io.mainClk, + reset = resetCtrl.mainClkReset, + frequency = FixedFrequency(coreFrequency) + ) + + val system = new ClockingArea(systemClockDomain) { + val pipelinedMemoryBusConfig = PipelinedMemoryBusConfig( + addressWidth = 32, + dataWidth = 32 + ) + + val bigEndianDBus = config.cpuPlugins.exists(_ match { + case plugin: DBusSimplePlugin => plugin.bigEndian + case _ => false + }) + + //Arbiter of the cpu dBus/iBus to drive the mainBus + //Priority to dBus, !! cmd transactions can change on the fly !! + val mainBusArbiter = + new MuraxMasterArbiter(pipelinedMemoryBusConfig, bigEndianDBus) + + //Instanciate the CPU + val cpu = new VexRiscv( + config = VexRiscvConfig( + plugins = cpuPlugins += new DebugPlugin( + debugClockDomain, + hardwareBreakpointCount + ) + ) + ) + + //Checkout plugins used to instanciate the CPU to connect them to the SoC + val timerInterrupt = False + val externalInterrupt = False + for (plugin <- cpu.plugins) plugin match { + case plugin: IBusSimplePlugin => + mainBusArbiter.io.iBus.cmd <> plugin.iBus.cmd + mainBusArbiter.io.iBus.rsp <> plugin.iBus.rsp + case plugin: DBusSimplePlugin => { + if (!pipelineDBus) + mainBusArbiter.io.dBus <> plugin.dBus + else { + mainBusArbiter.io.dBus.cmd << plugin.dBus.cmd.halfPipe() + mainBusArbiter.io.dBus.rsp <> plugin.dBus.rsp + } + } + case plugin: CsrPlugin => { + plugin.externalInterrupt := externalInterrupt + plugin.timerInterrupt := timerInterrupt + } + case plugin: DebugPlugin => + plugin.debugClockDomain { + resetCtrl.systemReset setWhen (RegNext(plugin.io.resetOut)) + io.jtag <> plugin.io.bus.fromJtag() + } + case _ => + } + + //****** MainBus slaves ******** + val mainBusMapping = ArrayBuffer[(PipelinedMemoryBus, SizeMapping)]() + val ram = new MuraxPipelinedMemoryBusRam( + onChipRamSize = onChipRamSize, + onChipRamHexFile = onChipRamHexFile, + pipelinedMemoryBusConfig = pipelinedMemoryBusConfig, + bigEndian = bigEndianDBus + ) + mainBusMapping += ram.io.bus -> (0x80000000L, onChipRamSize) + + val apbBridge = new PipelinedMemoryBusToApbBridge( + apb3Config = Apb3Config( + addressWidth = 20, + dataWidth = 32 + ), + pipelineBridge = pipelineApbBridge, + pipelinedMemoryBusConfig = pipelinedMemoryBusConfig + ) + mainBusMapping += apbBridge.io.pipelinedMemoryBus -> (0xf0000000L, 1 MB) + + //******** APB peripherals ********* + val apbMapping = ArrayBuffer[(Apb3, SizeMapping)]() + val gpioACtrl = Apb3Gpio(gpioWidth = gpioWidth, withReadSync = true) + io.gpioA <> gpioACtrl.io.gpio + apbMapping += gpioACtrl.io.apb -> (0x00000, 4 kB) + + val uartCtrl = Apb3UartCtrl(uartCtrlConfig) + uartCtrl.io.uart <> io.uart + externalInterrupt setWhen (uartCtrl.io.interrupt) + apbMapping += uartCtrl.io.apb -> (0x10000, 4 kB) + + val timer = new MuraxApb3Timer() + timerInterrupt setWhen (timer.io.interrupt) + apbMapping += timer.io.apb -> (0x20000, 4 kB) + + val gcd = new Apb3GCDCtrl( + apb3Config = Apb3Config( + addressWidth = 20, + dataWidth = 32 + ) + ) + apbMapping += gcd.io.apb -> (0x30000, 1 kB) + + val xip = ifGen(genXip)(new Area { + val ctrl = Apb3SpiXdrMasterCtrl(xipConfig) + ctrl.io.spi <> io.xip + externalInterrupt setWhen (ctrl.io.interrupt) + apbMapping += ctrl.io.apb -> (0x1f000, 4 kB) + + val accessBus = new PipelinedMemoryBus(PipelinedMemoryBusConfig(24, 32)) + mainBusMapping += accessBus -> (0xe0000000L, 16 MB) + + ctrl.io.xip.fromPipelinedMemoryBus() << accessBus + val bootloader = Apb3Rom("src/main/c/murax/xipBootloader/crt.bin") + apbMapping += bootloader.io.apb -> (0x1e000, 4 kB) + }) + + //******** Memory mappings ********* + val apbDecoder = Apb3Decoder( + master = apbBridge.io.apb, + slaves = apbMapping + ) + + val mainBusDecoder = new Area { + val logic = new MuraxPipelinedMemoryBusDecoder( + master = mainBusArbiter.io.masterBus, + specification = mainBusMapping, + pipelineMaster = pipelineMainBus + ) + } + } +} + +object Murax { + def main(args: Array[String]) { + SpinalVerilog(Murax(MuraxConfig.default)) + } +} + +object Murax_iCE40_hx8k_breakout_board_xip { + + case class SB_GB() extends BlackBox { + val USER_SIGNAL_TO_GLOBAL_BUFFER = in Bool () + val GLOBAL_BUFFER_OUTPUT = out Bool () + } + + case class SB_IO_SCLK() extends BlackBox { + addGeneric("PIN_TYPE", B"010000") + val PACKAGE_PIN = out Bool () + val OUTPUT_CLK = in Bool () + val CLOCK_ENABLE = in Bool () + val D_OUT_0 = in Bool () + val D_OUT_1 = in Bool () + setDefinitionName("SB_IO") + } + + case class SB_IO_DATA() extends BlackBox { + addGeneric("PIN_TYPE", B"110000") + val PACKAGE_PIN = inout(Analog(Bool)) + val CLOCK_ENABLE = in Bool () + val INPUT_CLK = in Bool () + val OUTPUT_CLK = in Bool () + val OUTPUT_ENABLE = in Bool () + val D_OUT_0 = in Bool () + val D_OUT_1 = in Bool () + val D_IN_0 = out Bool () + val D_IN_1 = out Bool () + setDefinitionName("SB_IO") + } + + case class Murax_iCE40_hx8k_breakout_board_xip() extends Component { + val io = new Bundle { + val mainClk = in Bool () + val jtag_tck = in Bool () + val jtag_tdi = in Bool () + val jtag_tdo = out Bool () + val jtag_tms = in Bool () + val uart_txd = out Bool () + val uart_rxd = in Bool () + + val mosi = inout(Analog(Bool)) + val miso = inout(Analog(Bool)) + val sclk = out Bool () + val spis = out Bool () + + val led = out Bits (8 bits) + } + val murax = Murax( + MuraxConfig.default(withXip = true).copy(onChipRamSize = 8 kB) + ) + murax.io.asyncReset := False + + val mainClkBuffer = SB_GB() + mainClkBuffer.USER_SIGNAL_TO_GLOBAL_BUFFER <> io.mainClk + mainClkBuffer.GLOBAL_BUFFER_OUTPUT <> murax.io.mainClk + + val jtagClkBuffer = SB_GB() + jtagClkBuffer.USER_SIGNAL_TO_GLOBAL_BUFFER <> io.jtag_tck + jtagClkBuffer.GLOBAL_BUFFER_OUTPUT <> murax.io.jtag.tck + + io.led <> murax.io.gpioA.write(7 downto 0) + + murax.io.jtag.tdi <> io.jtag_tdi + murax.io.jtag.tdo <> io.jtag_tdo + murax.io.jtag.tms <> io.jtag_tms + murax.io.gpioA.read <> 0 + murax.io.uart.txd <> io.uart_txd + murax.io.uart.rxd <> io.uart_rxd + + val xip = new ClockingArea(murax.systemClockDomain) { + RegNext(murax.io.xip.ss.asBool) <> io.spis + + val sclkIo = SB_IO_SCLK() + sclkIo.PACKAGE_PIN <> io.sclk + sclkIo.CLOCK_ENABLE := True + + sclkIo.OUTPUT_CLK := ClockDomain.current.readClockWire + sclkIo.D_OUT_0 <> murax.io.xip.sclk.write(0) + sclkIo.D_OUT_1 <> RegNext(murax.io.xip.sclk.write(1)) + + val datas = + for ((data, pin) <- (murax.io.xip.data, List(io.mosi, io.miso)).zipped) + yield new Area { + val dataIo = SB_IO_DATA() + dataIo.PACKAGE_PIN := pin + dataIo.CLOCK_ENABLE := True + + dataIo.OUTPUT_CLK := ClockDomain.current.readClockWire + dataIo.OUTPUT_ENABLE <> data.writeEnable + dataIo.D_OUT_0 <> data.write(0) + dataIo.D_OUT_1 <> RegNext(data.write(1)) + + dataIo.INPUT_CLK := ClockDomain.current.readClockWire + data.read(0) := dataIo.D_IN_0 + data.read(1) := RegNext(dataIo.D_IN_1) + } + } + + } + + def main(args: Array[String]) { + SpinalVerilog(Murax_iCE40_hx8k_breakout_board_xip()) + } +} + +object MuraxDhrystoneReady { + def main(args: Array[String]) { + SpinalVerilog(Murax(MuraxConfig.fast.copy(onChipRamSize = 256 kB))) + } +} + +object MuraxDhrystoneReadyMulDivStatic { + def main(args: Array[String]) { + SpinalVerilog({ + val config = MuraxConfig.fast.copy(onChipRamSize = 256 kB) + config.cpuPlugins += new MulPlugin + config.cpuPlugins += new DivPlugin + config.cpuPlugins.remove( + config.cpuPlugins.indexWhere(_.isInstanceOf[BranchPlugin]) + ) + config.cpuPlugins += new BranchPlugin( + earlyBranch = false, + catchAddressMisaligned = false + ) + config.cpuPlugins += new IBusSimplePlugin( + resetVector = 0x80000000L, + cmdForkOnSecondStage = true, + cmdForkPersistence = false, + prediction = STATIC, + catchAccessFault = false, + compressedGen = false + ) + config.cpuPlugins.remove( + config.cpuPlugins.indexWhere(_.isInstanceOf[LightShifterPlugin]) + ) + config.cpuPlugins += new FullBarrelShifterPlugin + Murax(config) + }) + } +} + +//Will blink led and echo UART RX to UART TX (in the verilator sim, type some text and press enter to send UART frame to the Murax RX pin) +object MuraxWithRamInit { + def main(args: Array[String]) { + SpinalVerilog( + Murax( + MuraxConfig.default.copy( + onChipRamSize = 4 kB, + onChipRamHexFile = "src/main/c/murax/gcd_world/build/gcd_world.hex" + ) + ) + ) + .printPruned() + } +} + +object MuraxWithRamInitSynth { + def main(args: Array[String]) { + val config = SpinalConfig( + targetDirectory = "synth", + defaultClockDomainFrequency = FixedFrequency(12 MHz) + ) + config + .generateVerilog( + Murax( + MuraxConfig.default.copy( + onChipRamSize = 4 kB, + onChipRamHexFile = "src/main/c/murax/gcd_world/build/gcd_world.hex" + ) + ) + ) + .printPruned() + } +} + +object Murax_arty { + def main(args: Array[String]) { + val hex = "src/main/c/murax/hello_world/build/hello_world.hex" + SpinalVerilog( + Murax( + MuraxConfig + .default(false) + .copy( + coreFrequency = 100 MHz, + onChipRamSize = 32 kB, + onChipRamHexFile = hex + ) + ) + ) + } +} + +object MuraxAsicBlackBox extends App { + println("Warning this soc do not has any rom to boot on.") + val config = SpinalConfig() + config.addStandardMemBlackboxing(blackboxAll) + config.generateVerilog(Murax(MuraxConfig.default())) +} diff --git a/doc/gcdPeripheral/src/main/scala/vexriscv/periph/gcd/Apb3GCDCtrl.scala b/doc/gcdPeripheral/src/main/scala/vexriscv/periph/gcd/Apb3GCDCtrl.scala new file mode 100644 index 00000000..2ec74016 --- /dev/null +++ b/doc/gcdPeripheral/src/main/scala/vexriscv/periph/gcd/Apb3GCDCtrl.scala @@ -0,0 +1,39 @@ +package vexriscv.periph.gcd + +import spinal.core._ +import spinal.lib._ +import spinal.lib.bus.amba3.apb.{Apb3, Apb3Config, Apb3SlaveFactory} +import spinal.lib.eda.altera.QSysify +import spinal.lib.slave + +object Apb3GCDCtrl { + def getApb3Config = Apb3Config( + addressWidth = 5, + dataWidth = 32, + selWidth = 1, + useSlaveError = false + ) +} + +class Apb3GCDCtrl(apb3Config : Apb3Config) extends Component { + val io = new Bundle { + val apb = slave(Apb3(Apb3GCDCtrl.getApb3Config)) + // maybe later + // val interrupt = out Bool + } + val gcdCtrl = new GCDTop() + val apbCtrl = Apb3SlaveFactory(io.apb) + apbCtrl.driveAndRead(gcdCtrl.io.a, address=0) + apbCtrl.driveAndRead(gcdCtrl.io.b, address=4) + // when result of calculation ready, synchronize it into memory mapped register + val resSyncBuf = RegNextWhen(gcdCtrl.io.res, gcdCtrl.io.ready) + apbCtrl.read(resSyncBuf, address=8) + // if result is read, it will be consumed, set ready to 0 + apbCtrl.onRead(8)(resSyncBuf := 0) + apbCtrl.onRead(8)(rdySyncBuf := False) + // synchronize ready signal into memory mapped register + val rdySyncBuf = RegNextWhen(gcdCtrl.io.ready, gcdCtrl.io.ready) + apbCtrl.read(rdySyncBuf, address=12) + // set valid based on memory mapped register but clear/consume it after 1 cycle b): + * a := a - b + * else if(b > a): + * b := b - a + * else: + * done := True + */ + //registers + val regA = Reg(UInt(32 bits)) init(0) + val regB = Reg(UInt(32 bits)) init(0) + // compare + val xGTy = regA > regB + val xLTy = regA < regB + // mux + val chX = io.dataCtrl.selL ? regB | regA + val chY = io.dataCtrl.selR ? regB | regA + // subtract + val subXY = chX - chY + // load logic + when(io.dataCtrl.init){ + regA := io.a + regB := io.b + } + when(io.dataCtrl.loadA){ + regA := subXY + } + when(io.dataCtrl.loadB){ + regB := subXY + } + io.dataCtrl.cmpAgtB := xGTy + io.dataCtrl.cmpAltB := xLTy + io.res := regA +} \ No newline at end of file diff --git a/doc/gcdPeripheral/src/main/scala/vexriscv/periph/gcd/GCDTop.scala b/doc/gcdPeripheral/src/main/scala/vexriscv/periph/gcd/GCDTop.scala new file mode 100644 index 00000000..654e9b8f --- /dev/null +++ b/doc/gcdPeripheral/src/main/scala/vexriscv/periph/gcd/GCDTop.scala @@ -0,0 +1,46 @@ +package vexriscv.periph.gcd + +import spinal.core._ +import spinal.lib._ +import spinal.lib.IMasterSlave + +case class GCDDataControl() extends Bundle with IMasterSlave{ + val cmpAgtB = Bool + val cmpAltB = Bool + val loadA = Bool + val loadB = Bool + val init = Bool + val selL = Bool + val selR = Bool + // define <> semantic + override def asMaster(): Unit = { + // as controller: output, input + out(loadA, loadB, selL, selR, init) + in(cmpAgtB, cmpAltB) + } +} + +//Hardware definition +class GCDTop() extends Component { + val io = new Bundle { + val valid = in Bool() + val ready = out Bool() + val a = in(UInt(32 bits)) + val b = in(UInt(32 bits)) + val res = out(UInt(32 bits)) + } + val gcdCtr = new GCDCtrl() + gcdCtr.io.valid := io.valid + io.ready := gcdCtr.io.ready + val gcdDat = new GCDData() + gcdDat.io.a := io.a + gcdDat.io.b := io.b + io.res := gcdDat.io.res + gcdCtr.io.dataCtrl <> gcdDat.io.dataCtrl +} + +object GCDTopVerilog { + def main(args: Array[String]) { + SpinalVerilog(new GCDTop) + } +} \ No newline at end of file diff --git a/doc/gcdPeripheral/src/main/scala/vexriscv/periph/gcd/GCDTopSim.scala b/doc/gcdPeripheral/src/main/scala/vexriscv/periph/gcd/GCDTopSim.scala new file mode 100644 index 00000000..53ea8dc7 --- /dev/null +++ b/doc/gcdPeripheral/src/main/scala/vexriscv/periph/gcd/GCDTopSim.scala @@ -0,0 +1,52 @@ +package vexriscv.periph.gcd + +import spinal.core._ +import spinal.sim._ +import spinal.core.sim._ + +//import scala.util.Random +import java.util.concurrent.ThreadLocalRandom +object GCDTopSim { + def main(args: Array[String]) { + + SimConfig.withWave.doSim(new GCDTop()){dut => + // SimConfig.doSim(new GCDTop()){dut => + def gcd(a: Long,b: Long): Long = { + if(b==0) a else gcd(b, a%b) + } + def RndNextUInt32(): Long = { + ThreadLocalRandom.current().nextLong(Math.pow(2, 32).toLong - 1) + } + var a = 0L + var b = 0L + var model = 0L + dut.io.a #= 0 + dut.io.b #= 0 + dut.io.valid #= false + + dut.clockDomain.forkStimulus(period = 10) + dut.clockDomain.waitRisingEdge() + + for(idx <- 0 to 500){ + // generate 2 random ints + a = RndNextUInt32() + b = RndNextUInt32() + // calculate the model value (software) + model = gcd(a,b) + // apply stimulus with random ints + dut.io.a #= a + dut.io.b #= b + dut.io.valid #= true + dut.clockDomain.waitRisingEdge() + dut.io.valid #= false + // wait until calculation of hardware is done + waitUntil(dut.io.ready.toBoolean) + assert( + assertion = (dut.io.res.toBigInt == model), + message = "test " + idx + " failed. Expected " + model + ", retrieved: " + dut.io.res.toBigInt + ) + waitUntil(!dut.io.ready.toBoolean) + } + } + } +} From 17007586e899d0301872a079d278ff06b678385d Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 11 Apr 2022 11:59:41 +0200 Subject: [PATCH 759/951] #241 Fix Murax/Briey TB timeouts --- src/test/cpp/briey/main.cpp | 2 -- src/test/cpp/common/framework.h | 7 +++++-- src/test/cpp/murax/main.cpp | 4 +--- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/test/cpp/briey/main.cpp b/src/test/cpp/briey/main.cpp index c0e165a2..bebe8800 100644 --- a/src/test/cpp/briey/main.cpp +++ b/src/test/cpp/briey/main.cpp @@ -466,8 +466,6 @@ int main(int argc, char **argv, char **env) { uint64_t duration = timer_end(startedAt); cout << endl << "****************************************************************" << endl; - cout << "Had simulate " << workspaceCycles << " clock cycles in " << duration*1e-9 << " s (" << workspaceCycles / (duration*1e-9) << " Khz)" << endl; - cout << "****************************************************************" << endl << endl; exit(0); diff --git a/src/test/cpp/common/framework.h b/src/test/cpp/common/framework.h index 42c1f34a..ed419adc 100644 --- a/src/test/cpp/common/framework.h +++ b/src/test/cpp/common/framework.h @@ -127,7 +127,6 @@ public: class success : public std::exception { }; -static uint32_t workspaceCycles = 0; template class Workspace{ public: @@ -180,7 +179,7 @@ public: #endif } - Workspace* run(uint32_t timeout = 5000){ + Workspace* run(double timeout = 1e6){ // init trace dump #ifdef TRACE @@ -205,6 +204,10 @@ public: if(p->wakeEnable && p->wakeDelay < delay) delay = p->wakeDelay; + if(time*timeToSec > timeout){ + printf("Simulation timeout triggered (%f)\n", time*timeToSec); + fail(); + } if(delay == ~0l){ fail(); } diff --git a/src/test/cpp/murax/main.cpp b/src/test/cpp/murax/main.cpp index 9738e847..735875fb 100644 --- a/src/test/cpp/murax/main.cpp +++ b/src/test/cpp/murax/main.cpp @@ -54,12 +54,10 @@ int main(int argc, char **argv, char **env) { printf("BOOT\n"); timespec startedAt = timer_start(); - MuraxWorkspace().run(100e6); + MuraxWorkspace().run(1e9); uint64_t duration = timer_end(startedAt); cout << endl << "****************************************************************" << endl; - cout << "Had simulate " << workspaceCycles << " clock cycles in " << duration*1e-9 << " s (" << workspaceCycles / (duration*1e-9) << " Khz)" << endl; - cout << "****************************************************************" << endl << endl; exit(0); From 9772e6775dde1f2b62f1ceb3525034d5e6782142 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 27 Apr 2022 16:12:56 +0200 Subject: [PATCH 760/951] readme now document FPU / openocd limitations --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 1a8864be..70e63ae9 100644 --- a/README.md +++ b/README.md @@ -750,6 +750,12 @@ Fpu 64/32 bits -> Artix 7 FMax -> 165 Mhz 3728 LUT 3175 FF ``` +Note that if you want to debug FPU code via the openocd_riscv.vexriscv target, you need to use the GDB from : + +https://static.dev.sifive.com/dev-tools/riscv64-unknown-elf-gcc-20171231-x86_64-linux-centos6.tar.gz + +More recent versions of gdb will not detect the FPU. Also, the openocd_riscv.vexriscv can't read CSR/FPU registers, so to have visibility on the floating points values, you need to compile your code in -O0, which will force values to be stored in memory (and so, be visible) + ### Plugins This chapter describes the currently implemented plugins. From 9506b0b8f1965782600170a63bcacc52a4016487 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 29 Apr 2022 14:16:41 +0200 Subject: [PATCH 761/951] SpianlHDL 1.7.0 --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index 11dee635..6e587044 100644 --- a/build.sbt +++ b/build.sbt @@ -1,4 +1,4 @@ -val spinalVersion = "1.6.5" +val spinalVersion = "1.7.0" lazy val root = (project in file(".")). settings( From 27772a65dd5fad0eafb41694bba2112be3e22803 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 29 Apr 2022 15:22:34 +0200 Subject: [PATCH 762/951] SpinalHDL 1.7.1 --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index 6e587044..65171f05 100644 --- a/build.sbt +++ b/build.sbt @@ -1,4 +1,4 @@ -val spinalVersion = "1.7.0" +val spinalVersion = "1.7.1" lazy val root = (project in file(".")). settings( From 6326736401c2fb6d7b5db7ad907aa1ea9dc1083f Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 4 May 2022 00:03:54 +0200 Subject: [PATCH 763/951] Update build.sbt --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index 65171f05..8800b6ae 100644 --- a/build.sbt +++ b/build.sbt @@ -1,4 +1,4 @@ -val spinalVersion = "1.7.1" +val spinalVersion = "1.7.1-SNAPSHOT" lazy val root = (project in file(".")). settings( From e0eb00573c524fd3b35b13c1c07775ef0b7e0f26 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 9 May 2022 11:33:15 +0200 Subject: [PATCH 764/951] SpinalHDL 1.7.0a --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index 61464884..0206cffb 100644 --- a/build.sbt +++ b/build.sbt @@ -1,4 +1,4 @@ -val spinalVersion = "1.7.0" +val spinalVersion = "1.7.0a" lazy val root = (project in file(".")). settings( From 4fff62d3feeb05edcea46e66b25de0ecf3f274fa Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 11 May 2022 14:10:11 +0200 Subject: [PATCH 765/951] Fix RVC step by step triggering next instruction branch predictor --- src/main/scala/vexriscv/Services.scala | 1 + src/main/scala/vexriscv/plugin/DebugPlugin.scala | 4 ++++ src/main/scala/vexriscv/plugin/Fetcher.scala | 6 ++++++ 3 files changed, 11 insertions(+) diff --git a/src/main/scala/vexriscv/Services.scala b/src/main/scala/vexriscv/Services.scala index 8a291d64..140c69bc 100644 --- a/src/main/scala/vexriscv/Services.scala +++ b/src/main/scala/vexriscv/Services.scala @@ -17,6 +17,7 @@ trait IBusFetcher{ def pcValid(stage : Stage) : Bool def getInjectionPort() : Stream[Bits] def withRvc() : Boolean + def forceNoDecode() : Unit } diff --git a/src/main/scala/vexriscv/plugin/DebugPlugin.scala b/src/main/scala/vexriscv/plugin/DebugPlugin.scala index 87d4f569..a0b4619d 100644 --- a/src/main/scala/vexriscv/plugin/DebugPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DebugPlugin.scala @@ -319,6 +319,10 @@ class DebugPlugin(var debugClockDomain : ClockDomain, hardwareBreakpointCount : if(pipeline.config.withRvc){ val cleanStep = RegNext(stepIt && decode.arbitration.isFiring) init(False) execute.arbitration.flushNext setWhen(cleanStep) + when(cleanStep){ + execute.arbitration.flushNext := True + iBusFetcher.forceNoDecode() + } } io.resetOut := RegNext(resetIt) diff --git a/src/main/scala/vexriscv/plugin/Fetcher.scala b/src/main/scala/vexriscv/plugin/Fetcher.scala index 8b276e13..fdfde8b6 100644 --- a/src/main/scala/vexriscv/plugin/Fetcher.scala +++ b/src/main/scala/vexriscv/plugin/Fetcher.scala @@ -33,6 +33,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, // assert(!(cmdToRspStageCount == 1 && !injectorStage)) assert(!(compressedGen && !decodePcGen)) var fetcherHalt : Bool = null + var forceNoDecodeCond : Bool = null var pcValids : Vec[Bool] = null def pcValid(stage : Stage) = pcValids(pipeline.indexOf(stage)) var incomingInstruction : Bool = null @@ -50,6 +51,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, var predictionJumpInterface : Flow[UInt] = null override def haltIt(): Unit = fetcherHalt := True + override def forceNoDecode(): Unit = forceNoDecodeCond := True case class JumpInfo(interface : Flow[UInt], stage: Stage, priority : Int) val jumpInfos = ArrayBuffer[JumpInfo]() override def createJumpInterface(stage: Stage, priority : Int = 0): Flow[UInt] = { @@ -63,6 +65,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, // var decodeExceptionPort : Flow[ExceptionCause] = null override def setup(pipeline: VexRiscv): Unit = { fetcherHalt = False + forceNoDecodeCond = False incomingInstruction = False if(resetVector == null) externalResetVector = in(UInt(32 bits).setName("externalResetVector")) @@ -408,6 +411,9 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, }) } + Component.current.addPrePopTask(() => { + decode.arbitration.isValid clearWhen(forceNoDecodeCond) + }) //Formal verification signals generation, miss prediction stuff ? val formal = new Area { From 8df2dcbd408825db62c9960bc4fce9813d2bcb41 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 11 May 2022 14:10:11 +0200 Subject: [PATCH 766/951] Fix RVC step by step triggering next instruction branch predictor --- src/main/scala/vexriscv/Services.scala | 1 + src/main/scala/vexriscv/plugin/DebugPlugin.scala | 4 ++++ src/main/scala/vexriscv/plugin/Fetcher.scala | 6 ++++++ 3 files changed, 11 insertions(+) diff --git a/src/main/scala/vexriscv/Services.scala b/src/main/scala/vexriscv/Services.scala index 8a291d64..140c69bc 100644 --- a/src/main/scala/vexriscv/Services.scala +++ b/src/main/scala/vexriscv/Services.scala @@ -17,6 +17,7 @@ trait IBusFetcher{ def pcValid(stage : Stage) : Bool def getInjectionPort() : Stream[Bits] def withRvc() : Boolean + def forceNoDecode() : Unit } diff --git a/src/main/scala/vexriscv/plugin/DebugPlugin.scala b/src/main/scala/vexriscv/plugin/DebugPlugin.scala index 87d4f569..a0b4619d 100644 --- a/src/main/scala/vexriscv/plugin/DebugPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DebugPlugin.scala @@ -319,6 +319,10 @@ class DebugPlugin(var debugClockDomain : ClockDomain, hardwareBreakpointCount : if(pipeline.config.withRvc){ val cleanStep = RegNext(stepIt && decode.arbitration.isFiring) init(False) execute.arbitration.flushNext setWhen(cleanStep) + when(cleanStep){ + execute.arbitration.flushNext := True + iBusFetcher.forceNoDecode() + } } io.resetOut := RegNext(resetIt) diff --git a/src/main/scala/vexriscv/plugin/Fetcher.scala b/src/main/scala/vexriscv/plugin/Fetcher.scala index 8b276e13..fdfde8b6 100644 --- a/src/main/scala/vexriscv/plugin/Fetcher.scala +++ b/src/main/scala/vexriscv/plugin/Fetcher.scala @@ -33,6 +33,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, // assert(!(cmdToRspStageCount == 1 && !injectorStage)) assert(!(compressedGen && !decodePcGen)) var fetcherHalt : Bool = null + var forceNoDecodeCond : Bool = null var pcValids : Vec[Bool] = null def pcValid(stage : Stage) = pcValids(pipeline.indexOf(stage)) var incomingInstruction : Bool = null @@ -50,6 +51,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, var predictionJumpInterface : Flow[UInt] = null override def haltIt(): Unit = fetcherHalt := True + override def forceNoDecode(): Unit = forceNoDecodeCond := True case class JumpInfo(interface : Flow[UInt], stage: Stage, priority : Int) val jumpInfos = ArrayBuffer[JumpInfo]() override def createJumpInterface(stage: Stage, priority : Int = 0): Flow[UInt] = { @@ -63,6 +65,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, // var decodeExceptionPort : Flow[ExceptionCause] = null override def setup(pipeline: VexRiscv): Unit = { fetcherHalt = False + forceNoDecodeCond = False incomingInstruction = False if(resetVector == null) externalResetVector = in(UInt(32 bits).setName("externalResetVector")) @@ -408,6 +411,9 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, }) } + Component.current.addPrePopTask(() => { + decode.arbitration.isValid clearWhen(forceNoDecodeCond) + }) //Formal verification signals generation, miss prediction stuff ? val formal = new Area { From 78f0a7f13e05d8c5d84603105fd1c31a7d24677e Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 16 May 2022 10:36:21 +0200 Subject: [PATCH 767/951] Fix CfuPlugin/VfuPlugin fork duplication https://github.com/google/CFU-Playground/issues/582 --- src/main/scala/vexriscv/plugin/CfuPlugin.scala | 2 +- src/main/scala/vexriscv/plugin/VfuPlugin.scala | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/CfuPlugin.scala b/src/main/scala/vexriscv/plugin/CfuPlugin.scala index de6daa14..9a93f6c0 100644 --- a/src/main/scala/vexriscv/plugin/CfuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CfuPlugin.scala @@ -193,7 +193,7 @@ class CfuPlugin(val stageCount : Int, arbitration.haltItself setWhen(scheduleWish && hazard) val hold = RegInit(False) setWhen(schedule) clearWhen(bus.cmd.ready) - val fired = RegInit(False) setWhen(bus.cmd.fire) clearWhen(!arbitration.isStuckByOthers) + val fired = RegInit(False) setWhen(bus.cmd.fire) clearWhen(!arbitration.isStuck) insert(CFU_IN_FLIGHT) := schedule || hold || fired bus.cmd.valid := (schedule || hold) && !fired diff --git a/src/main/scala/vexriscv/plugin/VfuPlugin.scala b/src/main/scala/vexriscv/plugin/VfuPlugin.scala index c3048273..a2c09304 100644 --- a/src/main/scala/vexriscv/plugin/VfuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/VfuPlugin.scala @@ -100,7 +100,7 @@ class VfuPlugin(val stageCount : Int, arbitration.haltItself setWhen(scheduleWish && hazard) val hold = RegInit(False) setWhen(schedule) clearWhen(bus.cmd.ready) - val fired = RegInit(False) setWhen(bus.cmd.fire) clearWhen(!arbitration.isStuckByOthers) + val fired = RegInit(False) setWhen(bus.cmd.fire) clearWhen(!arbitration.isStuck) insert(VFU_IN_FLIGHT) := schedule || hold || fired bus.cmd.valid := (schedule || hold) && !fired From 9c768be7af39072d3f2f7cca5c4ae2974ad8d86f Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 16 May 2022 10:36:21 +0200 Subject: [PATCH 768/951] Fix CfuPlugin/VfuPlugin fork duplication https://github.com/google/CFU-Playground/issues/582 --- src/main/scala/vexriscv/plugin/CfuPlugin.scala | 2 +- src/main/scala/vexriscv/plugin/VfuPlugin.scala | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/CfuPlugin.scala b/src/main/scala/vexriscv/plugin/CfuPlugin.scala index de6daa14..9a93f6c0 100644 --- a/src/main/scala/vexriscv/plugin/CfuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CfuPlugin.scala @@ -193,7 +193,7 @@ class CfuPlugin(val stageCount : Int, arbitration.haltItself setWhen(scheduleWish && hazard) val hold = RegInit(False) setWhen(schedule) clearWhen(bus.cmd.ready) - val fired = RegInit(False) setWhen(bus.cmd.fire) clearWhen(!arbitration.isStuckByOthers) + val fired = RegInit(False) setWhen(bus.cmd.fire) clearWhen(!arbitration.isStuck) insert(CFU_IN_FLIGHT) := schedule || hold || fired bus.cmd.valid := (schedule || hold) && !fired diff --git a/src/main/scala/vexriscv/plugin/VfuPlugin.scala b/src/main/scala/vexriscv/plugin/VfuPlugin.scala index c3048273..a2c09304 100644 --- a/src/main/scala/vexriscv/plugin/VfuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/VfuPlugin.scala @@ -100,7 +100,7 @@ class VfuPlugin(val stageCount : Int, arbitration.haltItself setWhen(scheduleWish && hazard) val hold = RegInit(False) setWhen(schedule) clearWhen(bus.cmd.ready) - val fired = RegInit(False) setWhen(bus.cmd.fire) clearWhen(!arbitration.isStuckByOthers) + val fired = RegInit(False) setWhen(bus.cmd.fire) clearWhen(!arbitration.isStuck) insert(VFU_IN_FLIGHT) := schedule || hold || fired bus.cmd.valid := (schedule || hold) && !fired From 8d0f7781de05817b2a60e06c7ef4a35b70e3153d Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 17 May 2022 15:27:31 +0200 Subject: [PATCH 769/951] Fix DYNAMIC_TARGET from triggering fetch missprediction while in debug mode #254 --- src/main/scala/vexriscv/plugin/BranchPlugin.scala | 7 +++++++ src/main/scala/vexriscv/plugin/DebugPlugin.scala | 4 ++++ 2 files changed, 11 insertions(+) diff --git a/src/main/scala/vexriscv/plugin/BranchPlugin.scala b/src/main/scala/vexriscv/plugin/BranchPlugin.scala index eb4c8d03..24d42fa0 100644 --- a/src/main/scala/vexriscv/plugin/BranchPlugin.scala +++ b/src/main/scala/vexriscv/plugin/BranchPlugin.scala @@ -46,6 +46,7 @@ case class FetchPredictionBus(stage : Stage) extends Bundle { trait PredictionInterface{ def askFetchPrediction() : FetchPredictionBus def askDecodePrediction() : DecodePredictionBus + def inDebugNoFetch() : Unit } @@ -68,6 +69,7 @@ class BranchPlugin(earlyBranch : Boolean, var jumpInterface : Flow[UInt] = null var predictionExceptionPort : Flow[ExceptionCause] = null var branchExceptionPort : Flow[ExceptionCause] = null + var inDebugNoFetchFlag : Bool = null var decodePrediction : DecodePredictionBus = null @@ -84,6 +86,9 @@ class BranchPlugin(earlyBranch : Boolean, decodePrediction } + + override def inDebugNoFetch(): Unit = inDebugNoFetchFlag := True + def hasHazardOnBranch = if(earlyBranch) pipeline.service(classOf[HazardService]).hazardOnExecuteRS else False override def setup(pipeline: VexRiscv): Unit = { @@ -147,6 +152,7 @@ class BranchPlugin(earlyBranch : Boolean, val exceptionService = pipeline.service(classOf[ExceptionService]) branchExceptionPort = exceptionService.newExceptionPort(branchStage) } + inDebugNoFetchFlag = False.setCompositeName(this, "inDebugNoFetchFlag") } override def build(pipeline: VexRiscv): Unit = { @@ -353,6 +359,7 @@ class BranchPlugin(earlyBranch : Boolean, import branchStage._ val predictionMissmatch = fetchPrediction.cmd.hadBranch =/= input(BRANCH_DO) || (input(BRANCH_DO) && input(TARGET_MISSMATCH)) + when(inDebugNoFetchFlag) { predictionMissmatch := input(BRANCH_DO)} fetchPrediction.rsp.wasRight := ! predictionMissmatch fetchPrediction.rsp.finalPc := input(BRANCH_CALC) fetchPrediction.rsp.sourceLastWord := { diff --git a/src/main/scala/vexriscv/plugin/DebugPlugin.scala b/src/main/scala/vexriscv/plugin/DebugPlugin.scala index a0b4619d..01c2acd6 100644 --- a/src/main/scala/vexriscv/plugin/DebugPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DebugPlugin.scala @@ -342,6 +342,10 @@ class DebugPlugin(var debugClockDomain : ClockDomain, hardwareBreakpointCount : case p : PrivilegeService => p.forceMachine() case _ => } + pipeline.plugins.foreach{ + case p : PredictionInterface => p.inDebugNoFetch() + case _ => + } if(pipeline.things.contains(DEBUG_BYPASS_CACHE)) pipeline(DEBUG_BYPASS_CACHE) := True } when(allowEBreak) { From a553d3b4767af75a75862d77e2c6d5be4fcae0de Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 17 May 2022 15:27:31 +0200 Subject: [PATCH 770/951] Fix DYNAMIC_TARGET from triggering fetch missprediction while in debug mode #254 --- src/main/scala/vexriscv/plugin/BranchPlugin.scala | 7 +++++++ src/main/scala/vexriscv/plugin/DebugPlugin.scala | 4 ++++ 2 files changed, 11 insertions(+) diff --git a/src/main/scala/vexriscv/plugin/BranchPlugin.scala b/src/main/scala/vexriscv/plugin/BranchPlugin.scala index eb4c8d03..24d42fa0 100644 --- a/src/main/scala/vexriscv/plugin/BranchPlugin.scala +++ b/src/main/scala/vexriscv/plugin/BranchPlugin.scala @@ -46,6 +46,7 @@ case class FetchPredictionBus(stage : Stage) extends Bundle { trait PredictionInterface{ def askFetchPrediction() : FetchPredictionBus def askDecodePrediction() : DecodePredictionBus + def inDebugNoFetch() : Unit } @@ -68,6 +69,7 @@ class BranchPlugin(earlyBranch : Boolean, var jumpInterface : Flow[UInt] = null var predictionExceptionPort : Flow[ExceptionCause] = null var branchExceptionPort : Flow[ExceptionCause] = null + var inDebugNoFetchFlag : Bool = null var decodePrediction : DecodePredictionBus = null @@ -84,6 +86,9 @@ class BranchPlugin(earlyBranch : Boolean, decodePrediction } + + override def inDebugNoFetch(): Unit = inDebugNoFetchFlag := True + def hasHazardOnBranch = if(earlyBranch) pipeline.service(classOf[HazardService]).hazardOnExecuteRS else False override def setup(pipeline: VexRiscv): Unit = { @@ -147,6 +152,7 @@ class BranchPlugin(earlyBranch : Boolean, val exceptionService = pipeline.service(classOf[ExceptionService]) branchExceptionPort = exceptionService.newExceptionPort(branchStage) } + inDebugNoFetchFlag = False.setCompositeName(this, "inDebugNoFetchFlag") } override def build(pipeline: VexRiscv): Unit = { @@ -353,6 +359,7 @@ class BranchPlugin(earlyBranch : Boolean, import branchStage._ val predictionMissmatch = fetchPrediction.cmd.hadBranch =/= input(BRANCH_DO) || (input(BRANCH_DO) && input(TARGET_MISSMATCH)) + when(inDebugNoFetchFlag) { predictionMissmatch := input(BRANCH_DO)} fetchPrediction.rsp.wasRight := ! predictionMissmatch fetchPrediction.rsp.finalPc := input(BRANCH_CALC) fetchPrediction.rsp.sourceLastWord := { diff --git a/src/main/scala/vexriscv/plugin/DebugPlugin.scala b/src/main/scala/vexriscv/plugin/DebugPlugin.scala index a0b4619d..01c2acd6 100644 --- a/src/main/scala/vexriscv/plugin/DebugPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DebugPlugin.scala @@ -342,6 +342,10 @@ class DebugPlugin(var debugClockDomain : ClockDomain, hardwareBreakpointCount : case p : PrivilegeService => p.forceMachine() case _ => } + pipeline.plugins.foreach{ + case p : PredictionInterface => p.inDebugNoFetch() + case _ => + } if(pipeline.things.contains(DEBUG_BYPASS_CACHE)) pipeline(DEBUG_BYPASS_CACHE) := True } when(allowEBreak) { From b39557e226ee430783e009981d312b38587f266e Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 17 May 2022 20:44:02 +0200 Subject: [PATCH 771/951] Fix DYNAMIC_TARGET / debug plugin interation corrupting the recoded next pc durring step by step #254 --- src/main/scala/vexriscv/plugin/Fetcher.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/plugin/Fetcher.scala b/src/main/scala/vexriscv/plugin/Fetcher.scala index fdfde8b6..14450a10 100644 --- a/src/main/scala/vexriscv/plugin/Fetcher.scala +++ b/src/main/scala/vexriscv/plugin/Fetcher.scala @@ -186,7 +186,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, val predictionPcLoad = ifGen(prediction == DYNAMIC_TARGET) (Flow(UInt(32 bits))) if(prediction == DYNAMIC_TARGET) { - when(predictionPcLoad.valid) { + when(predictionPcLoad.valid && !forceNoDecodeCond) { pcReg := predictionPcLoad.payload } } From 0872852387842bc21c6c1284e866c9640f793d76 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 17 May 2022 20:44:02 +0200 Subject: [PATCH 772/951] Fix DYNAMIC_TARGET / debug plugin interation corrupting the recoded next pc durring step by step #254 --- src/main/scala/vexriscv/plugin/Fetcher.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/plugin/Fetcher.scala b/src/main/scala/vexriscv/plugin/Fetcher.scala index fdfde8b6..14450a10 100644 --- a/src/main/scala/vexriscv/plugin/Fetcher.scala +++ b/src/main/scala/vexriscv/plugin/Fetcher.scala @@ -186,7 +186,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, val predictionPcLoad = ifGen(prediction == DYNAMIC_TARGET) (Flow(UInt(32 bits))) if(prediction == DYNAMIC_TARGET) { - when(predictionPcLoad.valid) { + when(predictionPcLoad.valid && !forceNoDecodeCond) { pcReg := predictionPcLoad.payload } } From 48cf4120f2e5e44224ca25fc783be96c338767cd Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 23 May 2022 15:49:32 +0200 Subject: [PATCH 773/951] Add VexRiscvSmpCluster forceMisa/forceMscratch --- .../scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index a0ad2c74..ec2aa50c 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -192,7 +192,9 @@ object VexRiscvSmpClusterGen { dTlbSize : Int = 4, prediction : BranchPrediction = vexriscv.plugin.NONE, withDataCache : Boolean = true, - withInstructionCache : Boolean = true + withInstructionCache : Boolean = true, + forceMisa : Boolean = false, + forceMscratch : Boolean = false ) = { assert(iCacheSize/iCacheWays <= 4096, "Instruction cache ways can't be bigger than 4096 bytes") assert(dCacheSize/dCacheWays <= 4096, "Data cache ways can't be bigger than 4096 bytes") @@ -207,12 +209,12 @@ object VexRiscvSmpClusterGen { marchid = null, mimpid = null, mhartid = hartId, - misaExtensionsInit = 0, - misaAccess = CsrAccess.NONE, + misaExtensionsInit = Riscv.misaToInt(s"ima${if(withFloat) "f" else ""}${if(withDouble) "d" else ""}s"), + misaAccess = if(forceMisa) CsrAccess.WRITE_ONLY else CsrAccess.NONE, mtvecAccess = CsrAccess.READ_WRITE, mtvecInit = null, mepcAccess = CsrAccess.READ_WRITE, - mscratchGen = false, + mscratchGen = forceMscratch, mcauseAccess = CsrAccess.READ_ONLY, mbadaddrAccess = CsrAccess.READ_ONLY, mcycleAccess = CsrAccess.NONE, From 209fc719e8a0921ea3fcacc8566b6c6ff887e772 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 24 May 2022 10:19:35 +0200 Subject: [PATCH 774/951] VexRiscvBmbGenerator export more info --- .../scala/vexriscv/VexRiscvBmbGenerator.scala | 29 ++++++++++++++++--- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/src/main/scala/vexriscv/VexRiscvBmbGenerator.scala b/src/main/scala/vexriscv/VexRiscvBmbGenerator.scala index 3ff33340..a30b7513 100644 --- a/src/main/scala/vexriscv/VexRiscvBmbGenerator.scala +++ b/src/main/scala/vexriscv/VexRiscvBmbGenerator.scala @@ -1,11 +1,11 @@ package vexriscv import spinal.core._ -import spinal.lib.bus.bmb.{Bmb, BmbAccessCapabilities, BmbAccessParameter, BmbImplicitDebugDecoder, BmbInvalidationParameter, BmbParameter, BmbInterconnectGenerator} +import spinal.lib.bus.bmb.{Bmb, BmbAccessCapabilities, BmbAccessParameter, BmbImplicitDebugDecoder, BmbInterconnectGenerator, BmbInvalidationParameter, BmbParameter} import spinal.lib.bus.misc.AddressMapping import spinal.lib.com.jtag.{Jtag, JtagTapInstructionCtrl} import spinal.lib.generator._ -import spinal.lib.slave +import spinal.lib.{sexport, slave} import vexriscv.plugin._ import spinal.core.fiber._ @@ -93,12 +93,33 @@ case class VexRiscvBmbGenerator()(implicit interconnectSmp: BmbInterconnectGener } val cpu = new VexRiscv(config) + def doExport(value : => Any, postfix : String) = { + sexport(Handle(value).setCompositeName(VexRiscvBmbGenerator.this, postfix)) + } + + doExport(cpu.plugins.exists(_.isInstanceOf[CfuPlugin]), "cfu") + doExport(cpu.plugins.exists(_.isInstanceOf[FpuPlugin]), "fpu") for (plugin <- cpu.plugins) plugin match { case plugin: IBusSimplePlugin => iBus.load(plugin.iBus.toBmb()) case plugin: DBusSimplePlugin => dBus.load(plugin.dBus.toBmb()) - case plugin: IBusCachedPlugin => iBus.load(plugin.iBus.toBmb()) - case plugin: DBusCachedPlugin => dBus.load(plugin.dBus.toBmb()) + case plugin: IBusCachedPlugin => { + iBus.load(plugin.iBus.toBmb()) + doExport(plugin.config.wayCount, "icacheWays") + doExport(plugin.config.cacheSize, "icacheSize") + } + case plugin: DBusCachedPlugin => { + dBus.load(plugin.dBus.toBmb()) + doExport(plugin.config.wayCount, "dcacheWays") + doExport(plugin.config.cacheSize, "dcacheSize") + } + case plugin: MmuPlugin => { + doExport(true, "mmu") + } + case plugin: StaticMemoryTranslatorPlugin => { + doExport(false, "mmu") + } case plugin: CsrPlugin => { + doExport(plugin.config.supervisorGen, "supervisor") externalInterrupt load plugin.externalInterrupt timerInterrupt load plugin.timerInterrupt softwareInterrupt load plugin.softwareInterrupt From 4c4913c703833f2a1a58cd8e52653bf847b011f3 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 24 May 2022 11:14:34 +0200 Subject: [PATCH 775/951] Fix MPP to only retain legal values --- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 5ba15233..febf1e23 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -713,11 +713,20 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep misaAccess(CSR.MISA, xlen-2 -> misa.base , 0 -> misa.extensions) //Machine CSR - READ_WRITE(CSR.MSTATUS,11 -> mstatus.MPP, 7 -> mstatus.MPIE, 3 -> mstatus.MIE) + READ_WRITE(CSR.MSTATUS, 7 -> mstatus.MPIE, 3 -> mstatus.MIE) READ_ONLY(CSR.MIP, 11 -> mip.MEIP, 7 -> mip.MTIP) READ_WRITE(CSR.MIP, 3 -> mip.MSIP) READ_WRITE(CSR.MIE, 11 -> mie.MEIE, 7 -> mie.MTIE, 3 -> mie.MSIE) + r(CSR.MSTATUS, 11 -> mstatus.MPP) + onWrite(CSR.MSTATUS){ + switch(writeData()(12 downto 11)){ + is(3){ mstatus.MPP := 3 } + if(supervisorGen) is(1){ mstatus.MPP := 1 } + if(userGen) is(0){ mstatus.MPP := 0 } + } + } + mtvecAccess(CSR.MTVEC, 2 -> mtvec.base, 0 -> mtvec.mode) mepcAccess(CSR.MEPC, mepc) if(mscratchGen) READ_WRITE(CSR.MSCRATCH, mscratch) From e6dfcac0be3c49141431e8b842bee7a7a7487ba0 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 24 May 2022 12:13:37 +0200 Subject: [PATCH 776/951] Add D$ single line flush support --- README.md | 2 ++ src/main/scala/vexriscv/ip/DataCache.scala | 14 +++++++++++++- .../scala/vexriscv/plugin/DBusCachedPlugin.scala | 5 ++++- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1a8864be..a02c52b3 100644 --- a/README.md +++ b/README.md @@ -1038,6 +1038,8 @@ There is at least one cycle latency between a cmd and the corresponding rsp. The Multi way cache implementation with writh-through and allocate on read strategy. (Documentation is WIP) +You can invalidate the whole cache via the 0x500F instruction, and you can invalidate a address range of one line via the instruction 0x500F | RS1 << 15 where RS1 should not be X0. + #### MulPlugin Implements the multiplication instruction from the RISC-V M extension. Its implementation was done in a FPGA friendly way by using 4 17*17 bit multiplications. diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index b3cf4dc1..2b70400f 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -40,6 +40,7 @@ case class DataCacheConfig(cacheSize : Int, assert(isPow2(pendingMax)) assert(rfDataWidth <= memDataWidth) + def lineCount = cacheSize/bytePerLine/wayCount def sizeMax = log2Up(bytePerLine) def sizeWidth = log2Up(sizeMax + 1) val aggregationWidth = if(withWriteAggregation) log2Up(memDataBytes+1) else 0 @@ -193,13 +194,18 @@ case class DataCacheCpuWriteBack(p : DataCacheConfig) extends Bundle with IMaste } } +case class DataCacheFlush(lineCount : Int) extends Bundle{ + val singleLine = Bool() + val lineId = UInt(log2Up(lineCount) bits) +} + case class DataCacheCpuBus(p : DataCacheConfig, mmu : MemoryTranslatorBusParameter) extends Bundle with IMasterSlave{ val execute = DataCacheCpuExecute(p) val memory = DataCacheCpuMemory(p, mmu) val writeBack = DataCacheCpuWriteBack(p) val redo = Bool() - val flush = Event + val flush = Stream(DataCacheFlush(p.lineCount)) override def asMaster(): Unit = { master(execute) @@ -849,6 +855,9 @@ class DataCache(val p : DataCacheConfig, mmuParameter : MemoryTranslatorBusParam io.cpu.execute.haltIt := True when(!hold) { counter := counter + 1 + when(io.cpu.flush.singleLine){ + counter.msb := True + } } } @@ -860,6 +869,9 @@ class DataCache(val p : DataCacheConfig, mmuParameter : MemoryTranslatorBusParam when(start){ waitDone := True counter := 0 + when(io.cpu.flush.singleLine){ + counter := U"0" @@ io.cpu.flush.lineId + } } } diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index 381f2e0f..80d44097 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -228,7 +228,8 @@ class DBusCachedPlugin(val config : DataCacheConfig, decoderService.addDefault(MEMORY_MANAGMENT, False) decoderService.add(MANAGEMENT, List( - MEMORY_MANAGMENT -> True + MEMORY_MANAGMENT -> True, + RS1_USE -> True )) withWriteResponse match { @@ -343,6 +344,8 @@ class DBusCachedPlugin(val config : DataCacheConfig, } cache.io.cpu.flush.valid := arbitration.isValid && input(MEMORY_MANAGMENT) + cache.io.cpu.flush.singleLine := input(INSTRUCTION)(Riscv.rs1Range) =/= 0 + cache.io.cpu.flush.lineId := U(input(RS1) >> log2Up(bytePerLine)).resized cache.io.cpu.execute.args.totalyConsistent := input(MEMORY_FORCE_CONSTISTENCY) arbitration.haltItself setWhen(cache.io.cpu.flush.isStall || cache.io.cpu.execute.haltIt) From 771eaf431e75d535ae3d14c4ee3541fbcd092d70 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 24 May 2022 12:15:57 +0200 Subject: [PATCH 777/951] Better cache invalidation doc --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a02c52b3..760c63c4 100644 --- a/README.md +++ b/README.md @@ -1038,7 +1038,7 @@ There is at least one cycle latency between a cmd and the corresponding rsp. The Multi way cache implementation with writh-through and allocate on read strategy. (Documentation is WIP) -You can invalidate the whole cache via the 0x500F instruction, and you can invalidate a address range of one line via the instruction 0x500F | RS1 << 15 where RS1 should not be X0. +You can invalidate the whole cache via the 0x500F instruction, and you can invalidate a address range (single line size) via the instruction 0x500F | RS1 << 15 where RS1 should not be X0 and point to one byte of the desired address to invalidate. #### MulPlugin From 0f6d0f022c6bd9872c912a97c97a556e5966c961 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 24 May 2022 12:37:31 +0200 Subject: [PATCH 778/951] VexRiscvBmbGenerator now also report bytesPerLine --- src/main/scala/vexriscv/VexRiscvBmbGenerator.scala | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/scala/vexriscv/VexRiscvBmbGenerator.scala b/src/main/scala/vexriscv/VexRiscvBmbGenerator.scala index a30b7513..9b08f680 100644 --- a/src/main/scala/vexriscv/VexRiscvBmbGenerator.scala +++ b/src/main/scala/vexriscv/VexRiscvBmbGenerator.scala @@ -106,11 +106,13 @@ case class VexRiscvBmbGenerator()(implicit interconnectSmp: BmbInterconnectGener iBus.load(plugin.iBus.toBmb()) doExport(plugin.config.wayCount, "icacheWays") doExport(plugin.config.cacheSize, "icacheSize") + doExport(plugin.config.bytePerLine, "bytesPerLine") } case plugin: DBusCachedPlugin => { dBus.load(plugin.dBus.toBmb()) doExport(plugin.config.wayCount, "dcacheWays") doExport(plugin.config.cacheSize, "dcacheSize") + doExport(plugin.config.bytePerLine, "bytesPerLine") } case plugin: MmuPlugin => { doExport(true, "mmu") From 8ab9a9b12e5d8881e3a895b31b6a57d076192df0 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 1 Jun 2022 09:53:41 +0200 Subject: [PATCH 779/951] fix VexRiscvRegressionData url --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index ab5c2daa..4205bb2e 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "src/test/resources/VexRiscvRegressionData"] path = src/test/resources/VexRiscvRegressionData - url = ../VexRiscvRegressionData.git + url = https://github.com/SpinalHDL/VexRiscvRegressionData.git From 1ce4c6e4932ac1de3153749e1e8e7159892ff8a5 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 1 Jun 2022 09:53:41 +0200 Subject: [PATCH 780/951] fix VexRiscvRegressionData url --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index ab5c2daa..4205bb2e 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "src/test/resources/VexRiscvRegressionData"] path = src/test/resources/VexRiscvRegressionData - url = ../VexRiscvRegressionData.git + url = https://github.com/SpinalHDL/VexRiscvRegressionData.git From 1303c0ca7c42db16f7bf65ba17b82caf2e284bc4 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 9 Jun 2022 17:57:24 +0200 Subject: [PATCH 781/951] CfuPlugin.withEnable added --- src/main/scala/vexriscv/plugin/CfuPlugin.scala | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/CfuPlugin.scala b/src/main/scala/vexriscv/plugin/CfuPlugin.scala index 9a93f6c0..d343640d 100644 --- a/src/main/scala/vexriscv/plugin/CfuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CfuPlugin.scala @@ -101,7 +101,8 @@ class CfuPlugin(val stageCount : Int, val busParameter : CfuBusParameter, val encodings : List[CfuPluginEncoding] = null, val stateAndIndexCsrOffset : Int = 0xBC0, - val statusCsrOffset : Int = 0x801) extends Plugin[VexRiscv]{ + val statusCsrOffset : Int = 0x801, + val withEnable : Boolean = true) extends Plugin[VexRiscv]{ def p = busParameter assert(p.CFU_INPUTS <= 2) @@ -158,8 +159,8 @@ class CfuPlugin(val stageCount : Int, val csr = pipeline plug new Area{ val factory = pipeline.service(classOf[CsrInterface]) - val en = Reg(Bool()) init(False) - factory.rw(stateAndIndexCsrOffset, 31, en) + val en = withEnable generate (Reg(Bool()) init(False)) + if(withEnable) factory.rw(stateAndIndexCsrOffset, 31, en) val stateId = Reg(UInt(log2Up(p.CFU_STATE_INDEX_NUM) bits)) init(0) if(p.CFU_STATE_INDEX_NUM > 1) { @@ -181,7 +182,7 @@ class CfuPlugin(val stageCount : Int, } } - when(decode.input(CFU_ENABLE) && !csr.en){ + if(withEnable) when(decode.input(CFU_ENABLE) && !csr.en){ pipeline.service(classOf[DecoderService]).forceIllegal() } From b1252f47de08982e39b346d28ef0fc6d46e85dfa Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 13 Jun 2022 16:34:49 +0200 Subject: [PATCH 782/951] csr opensbi now enable ebreak --- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index febf1e23..7731a41f 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -113,7 +113,7 @@ object CsrPluginConfig{ xtvecModeGen = false, noCsrAlu = false, wfiGenAsNop = false, - ebreakGen = false, //TODO + ebreakGen = true, userGen = true, supervisorGen = true, sscratchGen = true, From a650000f0b2008e40a3039a365e79075c5442e9e Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 11 Jul 2022 12:02:59 +0200 Subject: [PATCH 783/951] SpinalHDL 1.7.2 --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index 8800b6ae..e1f842db 100644 --- a/build.sbt +++ b/build.sbt @@ -1,4 +1,4 @@ -val spinalVersion = "1.7.1-SNAPSHOT" +val spinalVersion = "1.7.2-SNAPSHOT" lazy val root = (project in file(".")). settings( From 54412bde30af4d27625e8fe77b8e93dcabde5cc7 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 21 Jul 2022 09:10:23 +0200 Subject: [PATCH 784/951] getDrivingReg() update --- src/main/scala/vexriscv/Stage.scala | 2 +- src/main/scala/vexriscv/ip/fpu/FpuCore.scala | 4 ++-- src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala | 6 +++--- src/main/scala/vexriscv/plugin/Fetcher.scala | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/scala/vexriscv/Stage.scala b/src/main/scala/vexriscv/Stage.scala index fe20d19d..5275622f 100644 --- a/src/main/scala/vexriscv/Stage.scala +++ b/src/main/scala/vexriscv/Stage.scala @@ -75,5 +75,5 @@ class Stage() extends Area{ dontSample.getOrElseUpdate(s, ArrayBuffer[Bool]()) += cond } def inputInit[T <: BaseType](stageable : Stageable[T],initValue : T) = - Component.current.addPrePopTask(() => inputsDefault(stageable.asInstanceOf[Stageable[Data]]).asInstanceOf[T].getDrivingReg.init(initValue)) + Component.current.addPrePopTask(() => inputsDefault(stageable.asInstanceOf[Stageable[Data]]).asInstanceOf[T].getDrivingReg().init(initValue)) } \ No newline at end of file diff --git a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala index 657b2fb4..a9e9959d 100644 --- a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala +++ b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala @@ -530,7 +530,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ busy := True when(boot){ when(input.i2f && !patched && input.value(31) && input.arg(0)){ - input.value.getDrivingReg(0, 32 bits) := B(input.value.asUInt.twoComplement(True).resize(32 bits)) + input.value.getDrivingReg()(0, 32 bits) := B(input.value.asUInt.twoComplement(True).resize(32 bits)) patched := True } otherwise { shift.by := OHToUInt(OHMasking.first((ohInput).reversed)) @@ -1318,7 +1318,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ is(_15_XYY2){ when(mulBuffer.valid) { state := Y_15_XYY2 - mulBuffer.payload.getDrivingReg := (U"11" << mulWidth-2) - (mulBuffer.payload) + mulBuffer.payload.getDrivingReg() := (U"11" << mulWidth-2) - (mulBuffer.payload) } } is(Y_15_XYY2){ diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index 80d44097..50b953e6 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -371,7 +371,7 @@ class DBusCachedPlugin(val config : DataCacheConfig, insert(MEMORY_VIRTUAL_ADDRESS) := cache.io.cpu.execute.address memory.input(MEMORY_VIRTUAL_ADDRESS) if(writeBack != null) addPrePopTask( () => - KeepAttribute(memory.input(MEMORY_VIRTUAL_ADDRESS).getDrivingReg) + KeepAttribute(memory.input(MEMORY_VIRTUAL_ADDRESS).getDrivingReg()) ) } } @@ -528,14 +528,14 @@ class DBusCachedPlugin(val config : DataCacheConfig, dBusAccess.rsp.error := cache.io.cpu.writeBack.unalignedAccess || cache.io.cpu.writeBack.accessError dBusAccess.rsp.redo := cache.io.cpu.redo component.addPrePopTask{() => - managementStage.input(IS_DBUS_SHARING).getDrivingReg clearWhen(dBusAccess.rsp.fire) + managementStage.input(IS_DBUS_SHARING).getDrivingReg() clearWhen(dBusAccess.rsp.fire) when(forceDatapath){ execute.output(REGFILE_WRITE_DATA) := dBusAccess.cmd.address.asBits } if(mmuAndBufferStage != execute) mmuAndBufferStage.input(IS_DBUS_SHARING) init(False) managementStage.input(IS_DBUS_SHARING) init(False) when(dBusAccess.rsp.valid){ - managementStage.input(IS_DBUS_SHARING).getDrivingReg := False + managementStage.input(IS_DBUS_SHARING).getDrivingReg() := False } } } diff --git a/src/main/scala/vexriscv/plugin/Fetcher.scala b/src/main/scala/vexriscv/plugin/Fetcher.scala index 14450a10..f793084e 100644 --- a/src/main/scala/vexriscv/plugin/Fetcher.scala +++ b/src/main/scala/vexriscv/plugin/Fetcher.scala @@ -390,7 +390,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, //Check if the decode instruction is driven by a register val instructionDriver = try { - decode.input(INSTRUCTION).getDrivingReg + decode.input(INSTRUCTION).getDrivingReg() } catch { case _: Throwable => null } From e3e21994b429aaacc5e246c4e84a349a6e174379 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 22 Jul 2022 09:33:12 +0200 Subject: [PATCH 785/951] use SpinalHDL "dev" --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index e1f842db..ec565e2c 100644 --- a/build.sbt +++ b/build.sbt @@ -1,4 +1,4 @@ -val spinalVersion = "1.7.2-SNAPSHOT" +val spinalVersion = "dev" lazy val root = (project in file(".")). settings( From fda7da00c21fedd5911d8b5ae65800d3a83f4b29 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 6 Sep 2022 11:18:48 +0200 Subject: [PATCH 786/951] add litex --wishbone-force-32b --- .../scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala index 4cd4917a..f8e9dcb9 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala @@ -120,6 +120,7 @@ object VexRiscvLitexSmpClusterCmdGen extends App { var netlistName = "VexRiscvLitexSmpCluster" var iTlbSize = 4 var dTlbSize = 4 + var wishboneForce32b = false assert(new scopt.OptionParser[Unit]("VexRiscvLitexSmpClusterCmdGen") { help("help").text("prints this usage text") opt[Unit]("coherent-dma") action { (v, c) => coherentDma = true } @@ -136,6 +137,7 @@ object VexRiscvLitexSmpClusterCmdGen extends App { opt[String]("aes-instruction") action { (v, c) => aesInstruction = v.toBoolean } opt[String]("out-of-order-decoder") action { (v, c) => outOfOrderDecoder = v.toBoolean } opt[String]("wishbone-memory" ) action { (v, c) => wishboneMemory = v.toBoolean } + opt[String]("wishbone-force-32b" ) action { (v, c) => wishboneForce32b = v.toBoolean } opt[String]("fpu" ) action { (v, c) => fpu = v.toBoolean } opt[String]("cpu-per-fpu") action { (v, c) => cpuPerFpu = v.toInt } opt[String]("rvc") action { (v, c) => rvc = v.toBoolean } @@ -173,7 +175,7 @@ object VexRiscvLitexSmpClusterCmdGen extends App { c }}, withExclusiveAndInvalidation = coherency, - forcePeripheralWidth = !wishboneMemory, + forcePeripheralWidth = !wishboneMemory || wishboneForce32b, outOfOrderDecoder = outOfOrderDecoder, fpu = fpu, jtagHeaderIgnoreWidth = 0 From 7b9891829a3498c0178eaca660ab95cfc8f93390 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 26 Sep 2022 11:39:58 +0200 Subject: [PATCH 787/951] More bus doc #266 --- README.md | 104 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) diff --git a/README.md b/README.md index 410d7f98..bcff2391 100644 --- a/README.md +++ b/README.md @@ -868,6 +868,41 @@ Simple and light multi-way instruction cache. Note: If you enable the twoCycleRam option and if wayCount is bigger than one, then the register file plugin should be configured to read the regFile in an asynchronous manner. +The memory bus is defined as : + +```scala +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(p.memDataWidth bit) + val error = Bool +} + +case class InstructionCacheMemBus(p : InstructionCacheConfig) extends Bundle with IMasterSlave{ + val cmd = Stream (InstructionCacheMemCmd(p)) + val rsp = Flow (InstructionCacheMemRsp(p)) + + override def asMaster(): Unit = { + master(cmd) + slave(rsp) + } +} +``` + +The address is in byte and aligned to the bytePerLine config, the size will always be equal to log2(bytePerLine). + +Note that the cmd stream transaction need to be consumed before starting to send back some rsp transactions (1 cycle minimal latency) + +Some documentation about Stream here : + +https://spinalhdl.github.io/SpinalDoc-RTD/master/SpinalHDL/Libraries/stream.html?highlight=stream + +Flow are the same as Stream but without ready signal. + + #### DecoderSimplePlugin This plugin provides instruction decoding capabilities to other plugins. @@ -1046,6 +1081,75 @@ Multi way cache implementation with writh-through and allocate on read strategy. You can invalidate the whole cache via the 0x500F instruction, and you can invalidate a address range (single line size) via the instruction 0x500F | RS1 << 15 where RS1 should not be X0 and point to one byte of the desired address to invalidate. + +The memory bus is defined as : + +```scala +case class DataCacheMemCmd(p : DataCacheConfig) extends Bundle{ + val wr = Bool + val uncached = Bool + val address = UInt(p.addressWidth bit) + val data = Bits(p.cpuDataWidth bits) + val mask = Bits(p.cpuDataWidth/8 bits) + val size = UInt(p.sizeWidth bits) //... 1 => 2 bytes ... 2 => 4 bytes ... + val exclusive = p.withExclusive generate Bool() + val last = Bool +} +case class DataCacheMemRsp(p : DataCacheConfig) extends Bundle{ + val aggregated = UInt(p.aggregationWidth bits) + val last = Bool() + val data = Bits(p.memDataWidth bit) + val error = Bool + val exclusive = p.withExclusive generate Bool() +} +case class DataCacheInv(p : DataCacheConfig) extends Bundle{ + val enable = Bool() + val address = UInt(p.addressWidth bit) +} +case class DataCacheAck(p : DataCacheConfig) extends Bundle{ + val hit = Bool() +} + +case class DataCacheSync(p : DataCacheConfig) extends Bundle{ + val aggregated = UInt(p.aggregationWidth bits) +} + +case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave{ + val cmd = Stream (DataCacheMemCmd(p)) + val rsp = Flow (DataCacheMemRsp(p)) + + val inv = p.withInvalidate generate Stream(Fragment(DataCacheInv(p))) + val ack = p.withInvalidate generate Stream(Fragment(DataCacheAck(p))) + val sync = p.withInvalidate generate Stream(DataCacheSync(p)) + + override def asMaster(): Unit = { + master(cmd) + slave(rsp) + + if(p.withInvalidate) { + slave(inv) + master(ack) + slave(sync) + } + } +} +``` + +If you don't use memory coherency you can ignore the inv/ack/sync streams, also write cmd should not generate any rsp transaction. + +As the cache is write through, there is no write burst but only individual write transactions. + +The address is in byte and aligned to the bytePerLine config, the size will is encoded as log2(number of bytes in the burst). +last should be set only on the last transaction of a burst. + +Note that the cmd stream transaction need to be consumed before starting to send back some rsp transactions (1 cycle minimal latency) + +Some documentation about Stream here : + +https://spinalhdl.github.io/SpinalDoc-RTD/master/SpinalHDL/Libraries/stream.html?highlight=stream + +Flow are the same as Stream but without ready signal. + #### MulPlugin Implements the multiplication instruction from the RISC-V M extension. Its implementation was done in a FPGA friendly way by using 4 17*17 bit multiplications. From 959e48a353b6ec7b6a0e40f0bce4e28bb686adce Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 6 Oct 2022 11:13:57 +0200 Subject: [PATCH 788/951] Fpu now set csr status fs on FPU csr write --- src/main/scala/vexriscv/plugin/FpuPlugin.scala | 3 +++ src/test/cpp/regression/main.cpp | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/FpuPlugin.scala b/src/main/scala/vexriscv/plugin/FpuPlugin.scala index 3e664f51..b3373e35 100644 --- a/src/main/scala/vexriscv/plugin/FpuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/FpuPlugin.scala @@ -219,6 +219,9 @@ class FpuPlugin(externalFpu : Boolean = false, when(stages.last.arbitration.isFiring && stages.last.input(FPU_ENABLE) && stages.last.input(FPU_OPCODE) =/= FpuOpcode.STORE){ fs := 3 //DIRTY } + when(List(CSR.FRM, CSR.FCSR, CSR.FFLAGS).map(id => service.isWriting(id)).orR){ + fs := 3 + } service.rw(CSR.SSTATUS, 13, fs) service.rw(CSR.MSTATUS, 13, fs) diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 3d61c9a8..e5866fa4 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -668,9 +668,9 @@ public: case SATP: satp.raw = value; break; #ifdef RVF - case FCSR: fcsr.raw = value & 0x7F; break; - case FRM: fcsr.frm = value; break; - case FFLAGS: fcsr.flags = value; break; + case FCSR: fcsr.raw = value & 0x7F; status.fs = 3; break; + case FRM: fcsr.frm = value; status.fs = 3; break; + case FFLAGS: fcsr.flags = value; status.fs = 3; break; #endif default: ilegalInstruction(); return true; break; From 4cd3f6529672a4f7d753aba865f2f3b7d75ff475 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 19 Oct 2022 12:36:45 +0200 Subject: [PATCH 789/951] Add official RISC-V debug support (WIP, but can already load / step / run code via openocd telnet) --- README.md | 38 ++ src/main/scala/vexriscv/Riscv.scala | 8 + src/main/scala/vexriscv/TestsWorkspace.scala | 19 +- .../demo/smp/VexRiscvSmpCluster.scala | 8 +- .../scala/vexriscv/plugin/CsrPlugin.scala | 355 ++++++++++++++++-- .../scala/vexriscv/plugin/DebugPlugin.scala | 1 - .../vexriscv/plugin/EmbeddedRiscvJtag.scala | 86 +++++ src/test/cpp/regression/jtag.h | 188 ++++++++++ src/test/cpp/regression/main.cpp | 27 +- src/test/cpp/regression/makefile | 7 + 10 files changed, 691 insertions(+), 46 deletions(-) create mode 100644 src/main/scala/vexriscv/plugin/EmbeddedRiscvJtag.scala create mode 100644 src/test/cpp/regression/jtag.h diff --git a/README.md b/README.md index 760c63c4..6208319f 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,7 @@ - [MmuPlugin](#mmuplugin) - [PmpPlugin](#pmpplugin) - [DebugPlugin](#debugplugin) + - [EmbeddedRiscvJtag](#embeddedRiscvJtag) - [YamlPlugin](#yamlplugin) - [FpuPlugin](#fpuplugin) - [AesPlugin](#aesplugin) @@ -773,6 +774,7 @@ This chapter describes the currently implemented plugins. - [StaticMemoryTranslatorPlugin](#staticmemorytranslatorplugin) - [MemoryTranslatorPlugin](#memorytranslatorplugin) - [DebugPlugin](#debugplugin) +- [EmbeddedRiscvJtag](#embeddedRiscvJtag) - [YamlPlugin](#yamlplugin) - [FpuPlugin](#fpuplugin) @@ -1180,6 +1182,42 @@ Write Address 0x04 -> The OpenOCD port is here: +#### EmbeddedRiscvJtag + +VexRiscv also support the official RISC-V debug specification (Thanks Efinix for the funding !). + +To enable it, you need to add the EmbeddedRiscvJtag to the plugin list : + +```scala +new EmbeddedRiscvJtag( + p = DebugTransportModuleParameter( + addressWidth = 7, + version = 1, + idle = 7 + ), + withTunneling = false, + withTap = true +) +``` + +And turn on the withPrivilegedDebug option in the CsrPlugin config. + +Here is an example of openocd tcl script to connect : + +```tcl +# ADD HERE YOUR JTAG ADAPTER SETTINGS + +set _CHIPNAME riscv +jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x10002FFF + +set _TARGETNAME $_CHIPNAME.cpu + +target create $_TARGETNAME.0 riscv -chain-position $_TARGETNAME + +init +halt +``` + #### YamlPlugin This plugin offers a service to other plugins to generate a useful Yaml file describing the CPU configuration. It contains, for instance, the sequence of instructions required diff --git a/src/main/scala/vexriscv/Riscv.scala b/src/main/scala/vexriscv/Riscv.scala index 9e45e7a8..f0197bcf 100644 --- a/src/main/scala/vexriscv/Riscv.scala +++ b/src/main/scala/vexriscv/Riscv.scala @@ -238,5 +238,13 @@ object Riscv{ val FFLAGS = 0x1 val FRM = 0x2 val FCSR = 0x3 + + val DCSR = 0x7B0 + val DPC = 0x7B1 + val TSELECT = 0x7A0 + val TDATA1 = 0x7A1 + val TDATA2 = 0x7A2 + val TINFO = 0x7a4 + val TCONTROL = 0x7A5 } } diff --git a/src/main/scala/vexriscv/TestsWorkspace.scala b/src/main/scala/vexriscv/TestsWorkspace.scala index c961f05a..f102d81b 100644 --- a/src/main/scala/vexriscv/TestsWorkspace.scala +++ b/src/main/scala/vexriscv/TestsWorkspace.scala @@ -24,6 +24,7 @@ import spinal.core._ import spinal.lib._ import vexriscv.ip._ import spinal.lib.bus.avalon.AvalonMM +import spinal.lib.cpu.riscv.debug.DebugTransportModuleParameter import spinal.lib.eda.altera.{InterruptReceiverTag, ResetEmitterTag} import vexriscv.demo.smp.VexRiscvSmpClusterGen import vexriscv.ip.fpu.FpuParameter @@ -141,14 +142,28 @@ object TestsWorkspace { withFloat = true, withDouble = true, externalFpu = false, - simHalt = true + simHalt = true, + privilegedDebug = true ) + config.plugins += new EmbeddedRiscvJtag( + p = DebugTransportModuleParameter( + addressWidth = 7, + version = 1, + idle = 7 + ), + withTunneling = false, + withTap = true + ) + +// l.foreach{ +// case p : EmbeddedRiscvJtag => p.debugCd.load(ClockDomain.current.copy(reset = Bool().setName("debug_reset"))) +// case _ => +// } println("Args :") println(config.getRegressionArgs().mkString(" ")) - val toplevel = new VexRiscv(config) // val toplevel = new VexRiscv(configLight) // val toplevel = new VexRiscv(configTest) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index ec2aa50c..dfc26b50 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -194,14 +194,15 @@ object VexRiscvSmpClusterGen { withDataCache : Boolean = true, withInstructionCache : Boolean = true, forceMisa : Boolean = false, - forceMscratch : Boolean = false + forceMscratch : Boolean = false, + privilegedDebug : Boolean = false ) = { assert(iCacheSize/iCacheWays <= 4096, "Instruction cache ways can't be bigger than 4096 bytes") assert(dCacheSize/dCacheWays <= 4096, "Data cache ways can't be bigger than 4096 bytes") assert(!(withDouble && !withFloat)) val csrConfig = if(withSupervisor){ - CsrPluginConfig.openSbi(mhartid = hartId, misa = Riscv.misaToInt(s"ima${if(withFloat) "f" else ""}${if(withDouble) "d" else ""}s")).copy(utimeAccess = CsrAccess.READ_ONLY) + CsrPluginConfig.openSbi(mhartid = hartId, misa = Riscv.misaToInt(s"ima${if(withFloat) "f" else ""}${if(withDouble) "d" else ""}s")).copy(utimeAccess = CsrAccess.READ_ONLY, withPrivilegedDebug = privilegedDebug) } else { CsrPluginConfig( catchIllegalAccess = true, @@ -223,7 +224,8 @@ object VexRiscvSmpClusterGen { ebreakGen = true, wfiGenAsWait = false, wfiGenAsNop = true, - ucycleAccess = CsrAccess.NONE + ucycleAccess = CsrAccess.NONE, + withPrivilegedDebug = privilegedDebug ) } val config = VexRiscvConfig( diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 7731a41f..edff425d 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -9,6 +9,8 @@ import vexriscv.plugin.IntAluPlugin.{ALU_BITWISE_CTRL, ALU_CTRL, AluBitwiseCtrlE import scala.collection.mutable.ArrayBuffer import scala.collection.mutable import spinal.core.sim._ +import spinal.lib.cpu.riscv.debug._ +import spinal.lib.fsm.{State, StateMachine} /** * Created by spinalvm on 21.03.17. @@ -78,7 +80,9 @@ case class CsrPluginConfig( pipelinedInterrupt : Boolean = true, csrOhDecoder : Boolean = true, deterministicInteruptionEntry : Boolean = false, //Only used for simulatation purposes - wfiOutput : Boolean = false + wfiOutput : Boolean = false, + withPrivilegedDebug : Boolean = false, //For the official RISC-V debug spec implementation + debugTriggers : Int = 2 ){ assert(!ucycleAccess.canWrite) def privilegeGen = userGen || supervisorGen @@ -465,6 +469,10 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep var externalMhartId : UInt = null var utime : UInt = null + var debugBus : DebugHartBus = null + var debugMode : Bool = null + var injectionPort : Stream[Bits] = null + override def askWake(): Unit = thirdPartyWake := True override def isContextSwitching = contextSwitching @@ -622,6 +630,11 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep decoderService.addDefault(IS_SFENCE_VMA, False) decoderService.add(SFENCE_VMA, List(IS_SFENCE_VMA -> True)) } + + + injectionPort = withPrivilegedDebug generate pipeline.service(classOf[IBusFetcher]).getInjectionPort() + debugMode = withPrivilegedDebug generate Bool().setName("debugMode") + debugBus = withPrivilegedDebug generate slave(DebugHartBus()).setName("debugBus") } def inhibateInterrupts() : Unit = allowInterrupts := False @@ -657,11 +670,244 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep val base = UInt(xlen-2 bits) } + val trapEvent = False + val privilegeReg = privilegeGen generate RegInit(U"11") privilege := (if(privilegeGen) privilegeReg else U"11") when(forceMachineWire) { privilege := 3 } + val debug = withPrivilegedDebug generate pipeline plug new Area{ + val iBusFetcher = service(classOf[IBusFetcher]) + def bus = debugBus + + + val running = RegInit(True) + debugMode := !running + + + when(!running) { + iBusFetcher.haltIt() + } + + bus.resume.rsp.valid := False + + bus.running := running + bus.halted := !running + bus.unavailable := RegNext(ClockDomain.current.isResetActive) + val enterHalt = running.getAheadValue().fall(False) + + val doHalt = RegInit(False) setWhen(bus.haltReq && bus.running && !debugMode) clearWhen(enterHalt) + val forceResume = False + val doResume = forceResume || bus.resume.isPending(1) + + // Pipeline execution timeout used to trigger some redo + val timeout = Timeout(3) + when(pipeline.stages.map(_.arbitration.isValid).orR){ + timeout.clear() + } + + val inject = new Area{ + val cmd = bus.dmToHart.translateWith(bus.dmToHart.data).takeWhen(bus.dmToHart.op === DebugDmToHartOp.EXECUTE) + injectionPort << cmd.toStream.stage + + + val pending = RegInit(False) setWhen(cmd.valid) clearWhen(bus.exception || bus.commit || bus.ebreak || bus.redo) + when(cmd.valid){ timeout.clear() } + bus.redo := pending && timeout.state + } + val dataCsrr = new Area{ + bus.hartToDm.valid := isWriting(DebugModule.CSR_DATA) + bus.hartToDm.address := 0 + bus.hartToDm.data := execute.input(SRC1) + } + + val dataCsrw = new Area{ + val value = Reg(Bits(32 bits)) + + val fromDm = new Area{ + when(bus.dmToHart.valid && bus.dmToHart.op === DebugDmToHartOp.DATA){ + value := bus.dmToHart.data + } + } + + val toHart = new Area{ + r(DebugModule.CSR_DATA, value) + } + } + + val dpc = Reg(UInt(32 bits)) + val dcsr = new Area{ + rw(CSR.DPC, dpc) + val prv = RegInit(U"11") + val step = RegInit(False) //TODO + val nmip = False + val mprven = False + val cause = RegInit(U"000") + val stoptime = False + val stopcount = False + val stepie = RegInit(False) //TODO + val ebreaku = userGen generate RegInit(False) + val ebreaks = supervisorGen generate RegInit(False) + val ebreakm = RegInit(False) + val xdebugver = U(4, 4 bits) + + val stepLogic = new StateMachine{ + val IDLE, SINGLE, WAIT, DELAY = new State() + setEntry(IDLE) + + val isCause = RegInit(False) + + IDLE whenIsActive{ + when(step && bus.resume.rsp.valid){ + goto(SINGLE) + } + } + SINGLE whenIsActive{ + when(iBusFetcher.incoming()) { + iBusFetcher.haltIt() + when(decode.arbitration.isValid) { + goto(WAIT) + } + } + } + + WAIT whenIsActive{ + iBusFetcher.haltIt() + when(pipeline.lastStageIsFiring || trapEvent){ //TODO + doHalt := True + isCause := True + goto(DELAY) + } + //re resume the execution in case of timeout (ex cache miss) + when(timeout.state){ + forceResume := True + goto(DELAY) + } + } + DELAY whenIsActive{ + iBusFetcher.haltIt() + goto(IDLE) + } + + always{ + when(enterHalt){ + goto(IDLE) + } + } + build() + } + + + r(CSR.DCSR, 3 -> nmip, 6 -> cause, 28 -> xdebugver, 4 -> mprven, 9 -> stoptime, 10 -> stopcount) + rw(CSR.DCSR, 0 -> prv, 2 -> step, 11 -> stepie, 15 -> ebreakm) + if(supervisorGen) rw(CSR.DCSR, 13 -> ebreaks) + if(userGen) rw(CSR.DCSR, 12 -> ebreaku) + + + when(debugMode) { + pipeline.plugins.foreach{ + case p : PredictionInterface => p.inDebugNoFetch() + case _ => + } + if(pipeline.things.contains(DEBUG_BYPASS_CACHE)) pipeline(DEBUG_BYPASS_CACHE) := True + } + + val wakeService = serviceElse(classOf[IWake], null) + if(wakeService != null) when(debugMode || step){ + wakeService.askWake() + } + } + + //Very limited subset of the trigger spec + val trigger = (debugTriggers > 0) generate new Area { + val tselect = new Area{ + val index = Reg(UInt(log2Up(debugTriggers) bits)) + rw(CSR.TSELECT, index) + + val outOfRange = if(isPow2(debugTriggers)) False else index < debugTriggers + } + + val tinfo = new Area{ + r(CSR.TINFO, 0 -> tselect.outOfRange, 2 -> !tselect.outOfRange) + } + + val decodeBreak = new Area { + val enabled = False + val timeout = Timeout(3).clearWhen(!enabled || stages.tail.map(_.arbitration.isValid).orR) + when(enabled) { + decode.arbitration.haltByOther := True + when(timeout.state) { + dpc := decode.input(PC) + running := False + dcsr.cause := 2 + dcsr.prv := privilege + privilegeReg := 3 + } + } + } + + val slots = for(slotId <- 0 until debugTriggers) yield new Area { + val selected = tselect.index === slotId + def csrw(csrId : Int, thats : (Int, Data)*): Unit ={ + onWrite(csrId){ + when(selected) { + for((offset, data) <- thats){ + data.assignFromBits(writeData()(offset, widthOf(data) bits)) + } + } + } + } + def csrr(csrId : Int, read : Bits, thats : (Int, Data)*): Unit ={ + when(selected) { + for((offset, data) <- thats){ + read(offset, widthOf(data) bits) := data.asBits + } + } + } + def csrrw(csrId : Int, read : Bits, thats : (Int, Data)*) : Unit = { + csrw(csrId, thats :_*) + csrr(csrId, read, thats :_*) + } + + val tdata1 = new Area{ + val read = B(0, 32 bits) + val tpe = Reg(UInt(4 bits)) init(2) + val dmode = Reg(Bool()) init(False) + + val execute = RegInit(False) + val m, s, u = RegInit(False) + val action = RegInit(U"0000") + val privilegeHit = !debugMode && privilege.mux( + 0 -> u, + 1 -> s, + 3 -> m, + default -> False + ) + + csrrw(CSR.TDATA1, read, 2 -> execute , 3 -> u, 4-> s, 6 -> m, 32 - 4 -> tpe, 32 - 5 -> dmode, 12 -> action) + + + //TODO action sizelo timing select sizehi maskmax + } + + val tdata2 = new Area{ + val value = Reg(PC) + csrw(CSR.TDATA2, 0 -> value) + + val execute = new Area{ + val enabled = !debugMode && tdata1.action === 1 && tdata1.execute && tdata1.privilegeHit + val hit = enabled && value === decode.input(PC) + decodeBreak.enabled.setWhen(hit) + } + } + } + + r(CSR.TDATA1, 0 -> slots.map(_.tdata1.read).read(tselect.index)) + } + } + + val machineCsr = pipeline plug new Area{ //Define CSR registers // Status => MXR, SUM, TVM, TW, TSE ? @@ -973,6 +1219,8 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep } code.addTag(Verilator.public) + + if(withPrivilegedDebug) valid setWhen(debug.doHalt) } @@ -1012,6 +1260,11 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep val hadException = RegNext(exception) init(False) addTag(Verilator.public) pipelineLiberator.done.clearWhen(hadException) + if(withPrivilegedDebug) { + debugBus.commit := debugMode && pipeline.stages.last.arbitration.isFiring + debugBus.exception := debugMode && hadException + debugBus.ebreak := False + } val targetPrivilege = CombInit(interrupt.targetPrivilege) if(exceptionPortCtrl != null) when(hadException) { @@ -1019,8 +1272,17 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep } val trapCause = CombInit(interrupt.code.resize(trapCodeWidth)) + val trapCauseEbreakDebug = False if(exceptionPortCtrl != null) when( hadException){ trapCause := exceptionPortCtrl.exceptionContext.code.resized + if(withPrivilegedDebug) { + when(exceptionPortCtrl.exceptionContext.code === 3){ + trapCauseEbreakDebug setWhen(debugMode) + trapCauseEbreakDebug setWhen(privilege === 3 && debug.dcsr.ebreakm) + if (userGen) trapCauseEbreakDebug setWhen (privilege === 0 && debug.dcsr.ebreaku) + if (supervisorGen) trapCauseEbreakDebug setWhen (privilege === 1 && debug.dcsr.ebreaks) + } + } } val xtvec = Xtvec().assignDontCare() @@ -1029,38 +1291,61 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep is(3){ xtvec := machineCsr.mtvec } } + val trapEnterDebug = False + if(withPrivilegedDebug) trapEnterDebug setWhen(debug.doHalt || trapCauseEbreakDebug || !hadException && debug.doHalt) when(hadException || interruptJump){ + trapEvent := True fetcher.haltIt() //Avoid having the fetch confused by the incomming privilege switch jumpInterface.valid := True jumpInterface.payload := (if(!xtvecModeGen) xtvec.base @@ U"00" else (xtvec.mode === 0 || hadException) ? (xtvec.base @@ U"00") | ((xtvec.base + trapCause) @@ U"00") ) lastStage.arbitration.flushNext := True - if(privilegeGen) privilegeReg := targetPrivilege + when(!trapEnterDebug){ + if(privilegeGen) privilegeReg := targetPrivilege + switch(targetPrivilege){ + if(supervisorGen) is(1) { + sstatus.SIE := False + sstatus.SPIE := sstatus.SIE + sstatus.SPP := privilege(0 downto 0) + scause.interrupt := !hadException + scause.exceptionCode := trapCause + sepc := mepcCaptureStage.input(PC) + if (exceptionPortCtrl != null) when(hadException){ + stval := exceptionPortCtrl.exceptionContext.badAddr + } + } - switch(targetPrivilege){ - if(supervisorGen) is(1) { - sstatus.SIE := False - sstatus.SPIE := sstatus.SIE - sstatus.SPP := privilege(0 downto 0) - scause.interrupt := !hadException - scause.exceptionCode := trapCause - sepc := mepcCaptureStage.input(PC) - if (exceptionPortCtrl != null) when(hadException){ - stval := exceptionPortCtrl.exceptionContext.badAddr + is(3){ + mstatus.MIE := False + mstatus.MPIE := mstatus.MIE + mstatus.MPP := privilege + mcause.interrupt := !hadException + mcause.exceptionCode := trapCause + mepc := mepcCaptureStage.input(PC) + if(exceptionPortCtrl != null) when(hadException){ + mtval := exceptionPortCtrl.exceptionContext.badAddr + } } } - - is(3){ - mstatus.MIE := False - mstatus.MPIE := mstatus.MIE - mstatus.MPP := privilege - mcause.interrupt := !hadException - mcause.exceptionCode := trapCause - mepc := mepcCaptureStage.input(PC) - if(exceptionPortCtrl != null) when(hadException){ - mtval := exceptionPortCtrl.exceptionContext.badAddr + } otherwise { + if(withPrivilegedDebug) { + debug.running := False + when(!debugMode) { + debug.dpc := mepcCaptureStage.input(PC) + debug.dcsr.cause := 3 + when(debug.dcsr.step) { + debug.dcsr.cause := 4 + } + when(trapCauseEbreakDebug) { + debug.dcsr.cause := 1 + } + debug.dcsr.prv := privilege + } otherwise { + debugBus.exception := !trapCauseEbreakDebug //TODO mask interrupt while in debug mode + debugBus.ebreak := trapCauseEbreakDebug } + privilegeReg := 3 } } } @@ -1097,9 +1382,21 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep } } - contextSwitching := jumpInterface.valid + // Debug resume + if(withPrivilegedDebug) { + when(debug.doResume) { + jumpInterface.valid := True + jumpInterface.payload := debug.dpc + + privilegeReg := debug.dcsr.prv + debug.running := True + debug.bus.resume.rsp.valid := True + } + } + + //CSR read/write instructions management decode plug new Area{ import decode._ @@ -1200,12 +1497,6 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep memory.output(REGFILE_WRITE_DATA) := memory.input(PIPELINED_CSR_READ) } } -// -// Component.current.rework{ -// when(arbitration.isFiring && input(IS_CSR)) { -// memory.input(REGFILE_WRITE_DATA).getDrivingReg := readData -// } -// } //Translation of the csrMapping into real logic val csrAddress = input(INSTRUCTION)(csrRange) @@ -1307,11 +1598,15 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep illegalAccess clearWhen(csrMapping.allowCsrSignal) - when(privilege < csrAddress(9 downto 8).asUInt){ + val forceFail = False + forceFail setWhen(privilege < csrAddress(9 downto 8).asUInt) + if(withPrivilegedDebug) forceFail setWhen(!debugMode && csrAddress >> 4 === 0x7B) + when(forceFail){ illegalAccess := True readInstruction := False writeInstruction := False } + illegalAccess clearWhen(!arbitration.isValid || !input(IS_CSR)) } } diff --git a/src/main/scala/vexriscv/plugin/DebugPlugin.scala b/src/main/scala/vexriscv/plugin/DebugPlugin.scala index 01c2acd6..4d0cbac1 100644 --- a/src/main/scala/vexriscv/plugin/DebugPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DebugPlugin.scala @@ -179,7 +179,6 @@ case class DebugExtensionIo() extends Bundle with IMasterSlave{ class DebugPlugin(var debugClockDomain : ClockDomain, hardwareBreakpointCount : Int = 0, BreakpointReadback : Boolean = false) extends Plugin[VexRiscv] { var io : DebugExtensionIo = null - val injectionAsks = ArrayBuffer[(Stage, Bool)]() var injectionPort : Stream[Bits] = null diff --git a/src/main/scala/vexriscv/plugin/EmbeddedRiscvJtag.scala b/src/main/scala/vexriscv/plugin/EmbeddedRiscvJtag.scala new file mode 100644 index 00000000..21eb3d99 --- /dev/null +++ b/src/main/scala/vexriscv/plugin/EmbeddedRiscvJtag.scala @@ -0,0 +1,86 @@ +/** + * Thanks Efinix for funding the official RISC-V debug implementation on VexRiscv ! + */ + + +package vexriscv.plugin + +import spinal.core._ +import spinal.lib._ +import spinal.lib.com.jtag._ +import spinal.lib.cpu.riscv.debug._ +import vexriscv._ + + +class EmbeddedRiscvJtag(var p : DebugTransportModuleParameter, + var withTap : Boolean = true, + var withTunneling : Boolean = false + ) extends Plugin[VexRiscv] with VexRiscvRegressionArg{ + + + override def getVexRiscvRegressionArgs() = List("DEBUG_PLUGIN=RISCV") + + var jtag : Jtag = null + var jtagInstruction : JtagTapInstructionCtrl = null + var ndmreset : Bool = null + +// val debugCd = Handle[ClockDomain].setName("debugCd") +// val noTapCd = Handle[ClockDomain].setName("jtagCd") + + override def setup(pipeline: VexRiscv): Unit = { + jtag = withTap generate slave(Jtag()).setName("jtag") + jtagInstruction = !withTap generate slave(JtagTapInstructionCtrl()).setName("jtagInstruction") + ndmreset = Bool().setName("ndmreset") + } + + override def build(pipeline: VexRiscv): Unit = { + val XLEN = 32 + val dm = DebugModule( + DebugModuleParameter( + version = p.version + 1, + harts = 1, + progBufSize = 2, + datacount = XLEN/32, + xlens = List(XLEN) + ) + ) + + ndmreset := dm.io.ndmreset + + val dmiDirect = if(withTap && !withTunneling) new Area { + val logic = DebugTransportModuleJtagTap( + p.copy(addressWidth = 7), + debugCd = ClockDomain.current + ) + dm.io.ctrl <> logic.io.bus + logic.io.jtag <> jtag + } + val dmiTunneled = if(withTap && withTunneling) new Area { + val logic = DebugTransportModuleJtagTapWithTunnel( + p.copy(addressWidth = 7), + debugCd = ClockDomain.current + ) + dm.io.ctrl <> logic.io.bus + logic.io.jtag <> jtag + } + + val privBus = pipeline.service(classOf[CsrPlugin]).debugBus.setAsDirectionLess() + privBus <> dm.io.harts(0) + privBus.dmToHart.removeAssignments() <-< dm.io.harts(0).dmToHart + } +} + +/* +make IBUS=CACHED IBUS_DATA_WIDTH=64 COMPRESSED=no DBUS=CACHED DBUS_LOAD_DATA_WIDTH=64 DBUS_STORE_DATA_WIDTH=64 LRSC=yes AMO=yes DBUS_EXCLUSIVE=yes DBUS_INVALIDATE=yes MUL=yes DIV=yes RVF=yes RVD=yes RISCV_JTAG=yes REDO=1 WITH_RISCV_REF=no DEBUG_PLUGIN_EXTERNAL=yes DEBUG_PLUGIN=no +src/openocd -f ../VexRiscvOoo/src/main/tcl/openocd/naxriscv_sim.tcl -c "sleep 5000" -c "reg pc 0x80000000" -c "exit" -d3 + +mdw 0x1000 16 +mww 0x1000 0x12345678 +mdw 0x1000 16 + +load_image /media/data/open/VexRiscv/src/test/resources/hex/dhrystoneO3.hex 0 ihex +mdw 0x80000000 16 +reg pc 0x80000000 +bp 0x80000114 4 +resume +*/ diff --git a/src/test/cpp/regression/jtag.h b/src/test/cpp/regression/jtag.h new file mode 100644 index 00000000..8dabe93f --- /dev/null +++ b/src/test/cpp/regression/jtag.h @@ -0,0 +1,188 @@ + +#include +#include +#include +#include +#include +#include +#include +#include + +/** Returns true on success, or false if there was an error */ +bool SetSocketBlockingEnabled(int fd, bool blocking) +{ + if (fd < 0) return false; + +#ifdef WIN32 + unsigned long mode = blocking ? 0 : 1; + return (ioctlsocket(fd, FIONBIO, &mode) == 0) ? true : false; +#else + int flags = fcntl(fd, F_GETFL, 0); + if (flags < 0) return false; + flags = blocking ? (flags&~O_NONBLOCK) : (flags|O_NONBLOCK); + return (fcntl(fd, F_SETFL, flags) == 0) ? true : false; +#endif +} + +class Jtag : public SimElement{ +public: + CData *tms, *tdi, *tdo, *tck; + enum State {reset}; + uint32_t state; + + int serverSocket, clientHandle; + struct sockaddr_in serverAddr; + struct sockaddr_storage serverStorage; + socklen_t addr_size; + uint64_t tooglePeriod; +// char buffer[1024]; + + uint32_t timer; + Jtag(CData *tms, CData *tdi, CData *tdo, CData* tck,uint64_t period){ + this->tms = tms; + this->tdi = tdi; + this->tdo = tdo; + this->tck = tck; + this->tooglePeriod = period-1; + *tms = 0; + *tdi = 0; + *tdo = 0; + *tck = 0; + state = 0; + timer = 0; + + + //---- Create the socket. The three arguments are: ----// + // 1) Internet domain 2) Stream socket 3) Default protocol (TCP in this case) // + serverSocket = socket(PF_INET, SOCK_STREAM, 0); + assert(serverSocket != -1); + int flag = 1; + setsockopt( serverSocket, /* socket affected */ + IPPROTO_TCP, /* set option at TCP level */ + TCP_NODELAY, /* name of option */ + (char *) &flag, /* the cast is historical + cruft */ + sizeof(int)); /* length of option value */ + + /*int a = 0xFFF; + if (setsockopt(serverSocket, SOL_SOCKET, SO_RCVBUF, &a, sizeof(int)) == -1) { + fprintf(stderr, "Error setting socket opts: %s\n", strerror(errno)); + } + a = 0xFFFFFF; + if (setsockopt(serverSocket, SOL_SOCKET, SO_SNDBUF, &a, sizeof(int)) == -1) { + fprintf(stderr, "Error setting socket opts: %s\n", strerror(errno)); + }*/ + + SetSocketBlockingEnabled(serverSocket,0); + + + //---- Configure settings of the server address struct ----// + // Address family = Internet // + serverAddr.sin_family = AF_INET; + serverAddr.sin_port = htons(7894); + serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); + memset(serverAddr.sin_zero, '\0', sizeof serverAddr.sin_zero); + + //---- Bind the address struct to the socket ----// + bind(serverSocket, (struct sockaddr *) &serverAddr, sizeof(serverAddr)); + + //---- Listen on the socket, with 5 max connection requests queued ----// + listen(serverSocket,1); + + //---- Accept call creates a new socket for the incoming connection ----// + addr_size = sizeof serverStorage; + clientHandle = -1; + + } + void connectionReset(){ + printf("CONNECTION RESET\n"); + shutdown(clientHandle,SHUT_RDWR); + clientHandle = -1; + } + + + virtual ~Jtag(){ + if(clientHandle != -1) { + shutdown(clientHandle,SHUT_RDWR); + usleep(100); + } + if(serverSocket != -1) { + close(serverSocket); + usleep(100); + } + } + + uint32_t selfSleep = 0; + uint32_t checkNewConnectionsTimer = 0; + uint8_t rxBuffer[100]; + int32_t rxBufferSize = 0; + int32_t rxBufferRemaining = 0; + +// virtual void onReset(){} +// virtual void postReset(){} +// virtual void preCycle(){} +// virtual void postCycle(){} + virtual void postCycle(){ + if(timer != 0){ + timer -= 1; + return; + } + checkNewConnectionsTimer++; + if(checkNewConnectionsTimer == 5000){ + checkNewConnectionsTimer = 0; + int newclientHandle = accept(serverSocket, (struct sockaddr *) &serverStorage, &addr_size); + if(newclientHandle != -1){ + if(clientHandle != -1){ + connectionReset(); + } + clientHandle = newclientHandle; + printf("CONNECTED\n"); + } + else{ + if(clientHandle == -1) + selfSleep = 1000; + } + } + if(selfSleep) + selfSleep--; + else{ + if(clientHandle != -1){ + uint8_t buffer; + int n; + + if(rxBufferRemaining == 0){ + if(ioctl(clientHandle,FIONREAD,&n) != 0) + connectionReset(); + else if(n >= 1){ + rxBufferSize = read(clientHandle,&rxBuffer,100); + if(rxBufferSize < 0){ + connectionReset(); + }else { + rxBufferRemaining = rxBufferSize; + } + }else { + selfSleep = 30; + } + } + + if(rxBufferRemaining != 0){ + uint8_t buffer = rxBuffer[rxBufferSize - (rxBufferRemaining--)]; + *tms = (buffer & 1) != 0; + *tdi = (buffer & 2) != 0; + *tck = (buffer & 8) != 0; + if(buffer & 4){ + buffer = (*tdo != 0); + //printf("TDO=%d\n",buffer); + if(-1 == send(clientHandle,&buffer,1,0)) + connectionReset(); + }else { + + // printf("\n"); + } + } + } + } + timer = tooglePeriod; + } + +}; \ No newline at end of file diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index e5866fa4..adf7b5b7 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -3071,6 +3071,8 @@ public: #endif +#include "jtag.h" + void Workspace::fillSimELements(){ #ifdef IBUS_SIMPLE simElements.push_back(new IBusSimple(this)); @@ -3121,6 +3123,9 @@ void Workspace::fillSimELements(){ #ifdef DEBUG_PLUGIN_AVALON simElements.push_back(new DebugPluginAvalon(this)); #endif + #ifdef RISCV_JTAG + simElements.push_back(new Jtag(&top->jtag_tms, &top->jtag_tdi, &top->jtag_tdo, &top->jtag_tck, 4)); + #endif } mutex Workspace::staticMutex; @@ -4126,16 +4131,7 @@ int main(int argc, char **argv, char **env) { - #ifdef RVF - for(const string &name : riscvTestFloat){ - redo(REDO,RiscvTest(name).withRiscvRef()->bootAt(0x80000188u)->writeWord(0x80000184u, 0x00305073)->run();) - } - #endif - #ifdef RVD - for(const string &name : riscvTestDouble){ - redo(REDO,RiscvTest(name).withRiscvRef()->bootAt(0x80000188u)->writeWord(0x80000184u, 0x00305073)->run();) - } - #endif + //return 0; //#ifdef LITEX @@ -4365,6 +4361,17 @@ int main(int argc, char **argv, char **env) { redo(REDO,WorkspaceRegression("amo").withRiscvRef()->loadHex(string(REGRESSION_PATH) + "../raw/amo/build/amo.hex")->bootAt(0x00000000u)->run(10e3);); #endif + #ifdef RVF + for(const string &name : riscvTestFloat){ + redo(REDO,RiscvTest(name).withRiscvRef()->bootAt(0x80000188u)->writeWord(0x80000184u, 0x00305073)->run();) + } + #endif + #ifdef RVD + for(const string &name : riscvTestDouble){ + redo(REDO,RiscvTest(name).withRiscvRef()->bootAt(0x80000188u)->writeWord(0x80000184u, 0x00305073)->run();) + } + #endif + #ifdef DHRYSTONE Dhrystone("dhrystoneO3_Stall","dhrystoneO3",true,true).run(1.5e6); #if defined(COMPRESSED) diff --git a/src/test/cpp/regression/makefile b/src/test/cpp/regression/makefile index b8759c9f..13bfbb36 100644 --- a/src/test/cpp/regression/makefile +++ b/src/test/cpp/regression/makefile @@ -30,6 +30,7 @@ AMO?=no NO_STALL?=no DEBUG_PLUGIN?=STD DEBUG_PLUGIN_EXTERNAL?=no +RISCV_JTAG?=no RUN_HEX=no WITH_RISCV_REF=yes CUSTOM_SIMD_ADD?=no @@ -302,6 +303,12 @@ ifeq ($(DEBUG_PLUGIN_EXTERNAL),yes) ADDCFLAGS += -CFLAGS -DDEBUG_PLUGIN_EXTERNAL endif + +ifeq ($(RISCV_JTAG),yes) + ADDCFLAGS += -CFLAGS -DRISCV_JTAG +endif + + ifeq ($(REF),yes) ADDCFLAGS += -CFLAGS -DREF endif From 0313f84419ab8acd260355449297dfaacf977c5f Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 20 Oct 2022 10:36:30 +0200 Subject: [PATCH 790/951] Fix RISCV debug step --- .../scala/vexriscv/plugin/CsrPlugin.scala | 53 +++++++++---------- .../vexriscv/plugin/EmbeddedRiscvJtag.scala | 11 ++++ 2 files changed, 35 insertions(+), 29 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index edff425d..24590619 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -88,6 +88,7 @@ case class CsrPluginConfig( def privilegeGen = userGen || supervisorGen def noException = this.copy(ecallGen = false, ebreakGen = false, catchIllegalAccess = false) def noExceptionButEcall = this.copy(ecallGen = true, ebreakGen = false, catchIllegalAccess = false) + def withEbreak = ebreakGen || withPrivilegedDebug } object CsrPluginConfig{ @@ -481,7 +482,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep val NONE, XRET = newElement() val WFI = if(wfiGenAsWait) newElement() else null val ECALL = if(ecallGen) newElement() else null - val EBREAK = if(ebreakGen) newElement() else null + val EBREAK = if(withEbreak) newElement() else null } object ENV_CTRL extends Stageable(EnvCtrlEnum()) @@ -540,7 +541,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep override def setup(pipeline: VexRiscv): Unit = { import pipeline.config._ - if(!config.ebreakGen) { + if(!config.withEbreak) { SpinalWarning("This VexRiscv configuration is set without software ebreak instruction support. Some software may rely on it (ex: Rust). (This isn't related to JTAG ebreak)") } @@ -586,7 +587,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep if(wfiGenAsWait) decoderService.add(WFI, defaultEnv ++ List(ENV_CTRL -> EnvCtrlEnum.WFI)) if(wfiGenAsNop) decoderService.add(WFI, Nil) if(ecallGen) decoderService.add(ECALL, defaultEnv ++ List(ENV_CTRL -> EnvCtrlEnum.ECALL, HAS_SIDE_EFFECT -> True)) - if(ebreakGen) decoderService.add(EBREAK, defaultEnv ++ List(ENV_CTRL -> EnvCtrlEnum.EBREAK, HAS_SIDE_EFFECT -> True)) + if(withEbreak) decoderService.add(EBREAK, defaultEnv ++ List(ENV_CTRL -> EnvCtrlEnum.EBREAK, HAS_SIDE_EFFECT -> True)) val pcManagerService = pipeline.service(classOf[JumpService]) jumpInterface = pcManagerService.createJumpInterface(pipeline.stages.last) @@ -611,7 +612,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep privilege = UInt(2 bits).setName("CsrPlugin_privilege") forceMachineWire = False - if(catchIllegalAccess || ecallGen || ebreakGen) + if(catchIllegalAccess || ecallGen || withEbreak) selfException = newExceptionPort(pipeline.execute) allowInterrupts = True @@ -677,7 +678,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep when(forceMachineWire) { privilege := 3 } - val debug = withPrivilegedDebug generate pipeline plug new Area{ + val debug = withPrivilegedDebug generate pipeline.plug(new Area{ val iBusFetcher = service(classOf[IBusFetcher]) def bus = debugBus @@ -702,7 +703,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep val doResume = forceResume || bus.resume.isPending(1) // Pipeline execution timeout used to trigger some redo - val timeout = Timeout(3) + val timeout = Timeout(7) when(pipeline.stages.map(_.arbitration.isValid).orR){ timeout.clear() } @@ -753,42 +754,32 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep val xdebugver = U(4, 4 bits) val stepLogic = new StateMachine{ - val IDLE, SINGLE, WAIT, DELAY = new State() + val IDLE, SINGLE, WAIT = new State() setEntry(IDLE) - val isCause = RegInit(False) - IDLE whenIsActive{ when(step && bus.resume.rsp.valid){ goto(SINGLE) } } SINGLE whenIsActive{ - when(iBusFetcher.incoming()) { - iBusFetcher.haltIt() - when(decode.arbitration.isValid) { - goto(WAIT) - } + when(decode.arbitration.isFiring) { + goto(WAIT) } } WAIT whenIsActive{ - iBusFetcher.haltIt() - when(pipeline.lastStageIsFiring || trapEvent){ //TODO - doHalt := True - isCause := True - goto(DELAY) - } + decode.arbitration.haltByOther setWhen(decode.arbitration.isValid) //re resume the execution in case of timeout (ex cache miss) - when(timeout.state){ + when(!doHalt && timeout.state){ forceResume := True - goto(DELAY) + goto(SINGLE) + } otherwise { + when(stages.last.arbitration.isFiring) { + doHalt := True + } } } - DELAY whenIsActive{ - iBusFetcher.haltIt() - goto(IDLE) - } always{ when(enterHalt){ @@ -905,7 +896,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep r(CSR.TDATA1, 0 -> slots.map(_.tdata1.read).read(tselect.index)) } - } + }) val machineCsr = pipeline plug new Area{ @@ -1220,7 +1211,10 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep code.addTag(Verilator.public) - if(withPrivilegedDebug) valid setWhen(debug.doHalt) + if(withPrivilegedDebug) { + valid clearWhen(!debug.dcsr.stepie) + valid setWhen(debug.doHalt) + } } @@ -1389,6 +1383,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep when(debug.doResume) { jumpInterface.valid := True jumpInterface.payload := debug.dpc + lastStage.arbitration.flushIt := True privilegeReg := debug.dcsr.prv debug.running := True @@ -1461,7 +1456,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep } - if(ebreakGen) when(arbitration.isValid && input(ENV_CTRL) === EnvCtrlEnum.EBREAK && allowEbreakException){ + if(withEbreak) when(arbitration.isValid && input(ENV_CTRL) === EnvCtrlEnum.EBREAK && allowEbreakException){ selfException.valid := True selfException.code := 3 } diff --git a/src/main/scala/vexriscv/plugin/EmbeddedRiscvJtag.scala b/src/main/scala/vexriscv/plugin/EmbeddedRiscvJtag.scala index 21eb3d99..f7937556 100644 --- a/src/main/scala/vexriscv/plugin/EmbeddedRiscvJtag.scala +++ b/src/main/scala/vexriscv/plugin/EmbeddedRiscvJtag.scala @@ -83,4 +83,15 @@ mdw 0x80000000 16 reg pc 0x80000000 bp 0x80000114 4 resume + + +mdw 0x1000 16 +mww 0x1000 0x12345678 +mdw 0x1000 16 + +#load_image /media/data/open/VexRiscv/src/test/resources/hex/dhrystoneO3.hex 0 ihex +mww 0x80000000 0x13 +mww 0x80000004 0x13 +reg pc 0x80000000 +step; reg pc */ From 95c656ceef2f6a9ff12d3131698da2b1949fc0b8 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 21 Oct 2022 12:28:17 +0200 Subject: [PATCH 791/951] riscv debug multiple harts --- .../scala/vexriscv/VexRiscvBmbGenerator.scala | 19 +++++++++++++++++-- .../scala/vexriscv/plugin/CsrPlugin.scala | 2 +- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/main/scala/vexriscv/VexRiscvBmbGenerator.scala b/src/main/scala/vexriscv/VexRiscvBmbGenerator.scala index 9b08f680..aa4aada2 100644 --- a/src/main/scala/vexriscv/VexRiscvBmbGenerator.scala +++ b/src/main/scala/vexriscv/VexRiscvBmbGenerator.scala @@ -8,6 +8,7 @@ import spinal.lib.generator._ import spinal.lib.{sexport, slave} import vexriscv.plugin._ import spinal.core.fiber._ +import spinal.lib.cpu.riscv.debug.DebugHartBus object VexRiscvBmbGenerator{ val DEBUG_NONE = 0 @@ -15,6 +16,7 @@ object VexRiscvBmbGenerator{ val DEBUG_JTAG_CTRL = 2 val DEBUG_BUS = 3 val DEBUG_BMB = 4 + val DEBUG_RISCV = 5 } case class VexRiscvBmbGenerator()(implicit interconnectSmp: BmbInterconnectGenerator = null) extends Area { @@ -63,6 +65,12 @@ case class VexRiscvBmbGenerator()(implicit interconnectSmp: BmbInterconnectGener withDebug.load(DEBUG_BUS) } + def enableRiscvDebug(debugCd : Handle[ClockDomain], resetCd : ClockDomainResetGenerator) : Unit = debugCd.on{ + this.debugClockDomain.load(debugCd) + debugAskReset.loadNothing() + withDebug.load(DEBUG_RISCV) + } + val debugBmbAccessSource = Handle[BmbAccessCapabilities] val debugBmbAccessRequirements = Handle[BmbAccessParameter] def enableDebugBmb(debugCd : Handle[ClockDomain], resetCd : ClockDomainResetGenerator, mapping : AddressMapping)(implicit debugMaster : BmbImplicitDebugDecoder = null) : Unit = debugCd.on{ @@ -85,11 +93,14 @@ case class VexRiscvBmbGenerator()(implicit interconnectSmp: BmbInterconnectGener val jtagInstructionCtrl = withDebug.produce(withDebug.get == DEBUG_JTAG_CTRL generate JtagTapInstructionCtrl()) val debugBus = withDebug.produce(withDebug.get == DEBUG_BUS generate DebugExtensionBus()) val debugBmb = Handle[Bmb] + val debugRiscv = withDebug.produce(withDebug.get == DEBUG_RISCV generate DebugHartBus()) val jtagClockDomain = Handle[ClockDomain] val logic = Handle(new Area { - withDebug.get != DEBUG_NONE generate new Area { - config.add(new DebugPlugin(debugClockDomain, hardwareBreakpointCount)) + withDebug.get match { + case DEBUG_NONE => + case DEBUG_RISCV => + case _ => config.add(new DebugPlugin(debugClockDomain, hardwareBreakpointCount)) } val cpu = new VexRiscv(config) @@ -126,6 +137,10 @@ case class VexRiscvBmbGenerator()(implicit interconnectSmp: BmbInterconnectGener timerInterrupt load plugin.timerInterrupt softwareInterrupt load plugin.softwareInterrupt if (plugin.config.supervisorGen) externalSupervisorInterrupt load plugin.externalInterruptS + withDebug.get match { + case DEBUG_RISCV => debugRiscv <> plugin.debugBus + case _ => + } } case plugin: DebugPlugin => plugin.debugClockDomain { if(debugAskReset.get != null) when(RegNext(plugin.io.resetOut)) { diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 24590619..78a5bd90 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -805,7 +805,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep } val wakeService = serviceElse(classOf[IWake], null) - if(wakeService != null) when(debugMode || step){ + if(wakeService != null) when(debugMode || step || bus.haltReq){ wakeService.askWake() } } From 662943522fc1d5eaccb95cb1c4027e368fbb3f57 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 21 Oct 2022 17:21:13 +0200 Subject: [PATCH 792/951] Fix privileged debug trigger decode break logic --- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 78a5bd90..2b6fb80d 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -829,6 +829,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep when(enabled) { decode.arbitration.haltByOther := True when(timeout.state) { + decode.arbitration.flushIt := True dpc := decode.input(PC) running := False dcsr.cause := 2 From 486d17d245594dc778001f24f5307ea2a00a9e1f Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 21 Oct 2022 18:58:13 +0200 Subject: [PATCH 793/951] CsrOpensbi now add rvc to misa --- src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index dfc26b50..084d5235 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -201,8 +201,9 @@ object VexRiscvSmpClusterGen { assert(dCacheSize/dCacheWays <= 4096, "Data cache ways can't be bigger than 4096 bytes") assert(!(withDouble && !withFloat)) + val misa = Riscv.misaToInt(s"ima${if(withFloat) "f" else ""}${if(withDouble) "d" else ""}${if(rvc) "c" else ""}${if(withSupervisor) "s" else ""}") val csrConfig = if(withSupervisor){ - CsrPluginConfig.openSbi(mhartid = hartId, misa = Riscv.misaToInt(s"ima${if(withFloat) "f" else ""}${if(withDouble) "d" else ""}s")).copy(utimeAccess = CsrAccess.READ_ONLY, withPrivilegedDebug = privilegedDebug) + CsrPluginConfig.openSbi(mhartid = hartId, misa = misa).copy(utimeAccess = CsrAccess.READ_ONLY, withPrivilegedDebug = privilegedDebug) } else { CsrPluginConfig( catchIllegalAccess = true, @@ -210,7 +211,7 @@ object VexRiscvSmpClusterGen { marchid = null, mimpid = null, mhartid = hartId, - misaExtensionsInit = Riscv.misaToInt(s"ima${if(withFloat) "f" else ""}${if(withDouble) "d" else ""}s"), + misaExtensionsInit = misa, misaAccess = if(forceMisa) CsrAccess.WRITE_ONLY else CsrAccess.NONE, mtvecAccess = CsrAccess.READ_WRITE, mtvecInit = null, From 17d52ce58f65a194c09220a06c11081661364fcc Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 21 Oct 2022 18:58:40 +0200 Subject: [PATCH 794/951] privileged debug now access data cache with caching enable --- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 2b6fb80d..ee3fe671 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -801,7 +801,6 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep case p : PredictionInterface => p.inDebugNoFetch() case _ => } - if(pipeline.things.contains(DEBUG_BYPASS_CACHE)) pipeline(DEBUG_BYPASS_CACHE) := True } val wakeService = serviceElse(classOf[IWake], null) @@ -864,7 +863,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep val tdata1 = new Area{ val read = B(0, 32 bits) - val tpe = Reg(UInt(4 bits)) init(2) + val tpe = U(2, 4 bits) val dmode = Reg(Bool()) init(False) val execute = RegInit(False) @@ -877,8 +876,8 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep default -> False ) - csrrw(CSR.TDATA1, read, 2 -> execute , 3 -> u, 4-> s, 6 -> m, 32 - 4 -> tpe, 32 - 5 -> dmode, 12 -> action) - + csrrw(CSR.TDATA1, read, 2 -> execute , 3 -> u, 4-> s, 6 -> m, 32 - 5 -> dmode, 12 -> action) + csrr(CSR.TDATA1, read, 32 - 4 -> tpe) //TODO action sizelo timing select sizehi maskmax } From 0979f8ba805d23be7989ffff44cb2a383f7fb61d Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 24 Oct 2022 10:24:32 +0200 Subject: [PATCH 795/951] Add whitebox example --- src/main/scala/vexriscv/demo/WhiteboxPlugin.scala | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 src/main/scala/vexriscv/demo/WhiteboxPlugin.scala diff --git a/src/main/scala/vexriscv/demo/WhiteboxPlugin.scala b/src/main/scala/vexriscv/demo/WhiteboxPlugin.scala new file mode 100644 index 00000000..68520aba --- /dev/null +++ b/src/main/scala/vexriscv/demo/WhiteboxPlugin.scala @@ -0,0 +1,14 @@ +package vexriscv.demo + +import spinal.core._ +import vexriscv.plugin.Plugin +import vexriscv.{DecoderService, Stageable, VexRiscv} + +class WhiteboxPlugin extends Plugin[VexRiscv]{ + override def build(pipeline: VexRiscv): Unit = { + Component.current.afterElaboration { + def export(name : String): Unit = out(Component.current.reflectBaseType(name)) + export("IBusCachedPlugin_fetchPc_pc") + } + } +} From 220af95043c39dc84b83fc1b305ae9206789b961 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 24 Oct 2022 10:35:59 +0200 Subject: [PATCH 796/951] Add VexRiscvAxi4Linux (untested, but generate a netlist) --- .../vexriscv/demo/VexRiscvAxi4Linux.scala | 157 ++++++++++++++++++ 1 file changed, 157 insertions(+) create mode 100644 src/main/scala/vexriscv/demo/VexRiscvAxi4Linux.scala diff --git a/src/main/scala/vexriscv/demo/VexRiscvAxi4Linux.scala b/src/main/scala/vexriscv/demo/VexRiscvAxi4Linux.scala new file mode 100644 index 00000000..ff2ff118 --- /dev/null +++ b/src/main/scala/vexriscv/demo/VexRiscvAxi4Linux.scala @@ -0,0 +1,157 @@ +package vexriscv.demo + +import spinal.core._ +import spinal.lib._ +import spinal.lib.bus.amba4.axi.Axi4ReadOnly +import spinal.lib.com.jtag.Jtag +import spinal.lib.eda.altera.{InterruptReceiverTag, ResetEmitterTag} +import vexriscv.ip.{DataCacheConfig, InstructionCacheConfig} +import vexriscv.plugin._ +import vexriscv.{Riscv, VexRiscv, VexRiscvConfig, plugin} + + +object VexRiscvAxi4Linux{ + def main(args: Array[String]) { + val report = SpinalVerilog{ + + //CPU configuration + val cpuConfig = VexRiscvConfig( + plugins = List( + new PcManagerSimplePlugin(0x00000000l, false), + new IBusCachedPlugin( + prediction = STATIC, + config = InstructionCacheConfig( + cacheSize = 4096, + bytePerLine = 64, + wayCount = 1, + addressWidth = 32, + cpuDataWidth = 32, + memDataWidth = 32, + catchIllegalAccess = true, + catchAccessFault = true, + asyncTagMemory = false, + twoCycleRam = true, + twoCycleCache = true + ), + memoryTranslatorPortConfig = MmuPortConfig( + portTlbSize = 4, + latency = 1, + earlyRequireMmuLockup = true, + earlyCacheHits = true + ) + ), + new DBusCachedPlugin( + config = new DataCacheConfig( + cacheSize = 4096, + bytePerLine = 64, + wayCount = 1, + addressWidth = 32, + cpuDataWidth = 32, + memDataWidth = 32, + catchAccessError = true, + catchIllegal = true, + catchUnaligned = true, + withLrSc = true, + withAmo = true + ), + memoryTranslatorPortConfig = MmuPortConfig( + portTlbSize = 4, + latency = 1, + earlyRequireMmuLockup = true, + earlyCacheHits = true + ) + ), + new MmuPlugin( + ioRange = _(31 downto 28) === 0xF + ), + new DecoderSimplePlugin( + catchIllegalInstruction = true + ), + new RegFilePlugin( + regFileReadyKind = plugin.SYNC, + zeroBoot = false + ), + new IntAluPlugin, + new SrcPlugin( + separatedAddSub = false, + executeInsertion = true + ), + new FullBarrelShifterPlugin, + new MulPlugin, + new DivPlugin, + new HazardSimplePlugin( + bypassExecute = true, + bypassMemory = true, + bypassWriteBack = true, + bypassWriteBackBuffer = true, + pessimisticUseSrc = false, + pessimisticWriteRegFile = false, + pessimisticAddressMatch = false + ), + new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))), + new BranchPlugin( + earlyBranch = false, + catchAddressMisaligned = true + ), + new CsrPlugin(CsrPluginConfig.openSbi(mhartid = 0, misa = Riscv.misaToInt(s"ima")).copy(utimeAccess = CsrAccess.READ_ONLY)), + new YamlPlugin("cpu0.yaml") + ) + ) + + //CPU instanciation + val cpu = new VexRiscv(cpuConfig) + + //CPU modifications to be an Avalon one + cpu.setDefinitionName("VexRiscvAxi4") + cpu.rework { + var iBus : Axi4ReadOnly = null + for (plugin <- cpuConfig.plugins) plugin match { + case plugin: IBusSimplePlugin => { + plugin.iBus.setAsDirectionLess() //Unset IO properties of iBus + iBus = master(plugin.iBus.toAxi4ReadOnly().toFullConfig()) + .setName("iBusAxi") + .addTag(ClockDomainTag(ClockDomain.current)) //Specify a clock domain to the iBus (used by QSysify) + } + case plugin: IBusCachedPlugin => { + plugin.iBus.setAsDirectionLess() //Unset IO properties of iBus + iBus = master(plugin.iBus.toAxi4ReadOnly().toFullConfig()) + .setName("iBusAxi") + .addTag(ClockDomainTag(ClockDomain.current)) //Specify a clock domain to the iBus (used by QSysify) + } + case plugin: DBusSimplePlugin => { + plugin.dBus.setAsDirectionLess() + master(plugin.dBus.toAxi4Shared().toAxi4().toFullConfig()) + .setName("dBusAxi") + .addTag(ClockDomainTag(ClockDomain.current)) + } + case plugin: DBusCachedPlugin => { + plugin.dBus.setAsDirectionLess() + master(plugin.dBus.toAxi4Shared().toAxi4().toFullConfig()) + .setName("dBusAxi") + .addTag(ClockDomainTag(ClockDomain.current)) + } + case plugin: DebugPlugin => plugin.debugClockDomain { + plugin.io.bus.setAsDirectionLess() + val jtag = slave(new Jtag()) + .setName("jtag") + jtag <> plugin.io.bus.fromJtag() + plugin.io.resetOut + .addTag(ResetEmitterTag(plugin.debugClockDomain)) + .parent = null //Avoid the io bundle to be interpreted as a QSys conduit + } + case _ => + } + for (plugin <- cpuConfig.plugins) plugin match { + case plugin: CsrPlugin => { + plugin.externalInterrupt + .addTag(InterruptReceiverTag(iBus, ClockDomain.current)) + plugin.timerInterrupt + .addTag(InterruptReceiverTag(iBus, ClockDomain.current)) + } + case _ => + } + } + cpu + } + } +} From 63dd787bcebbdf63883a846b657765ab805102cf Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 26 Oct 2022 10:15:21 +0200 Subject: [PATCH 797/951] VexRiscvAxi4Linux now integrate Plic and Clint --- ...scala => VexRiscvAxi4LinuxPlicClint.scala} | 64 +++++++++++-------- 1 file changed, 37 insertions(+), 27 deletions(-) rename src/main/scala/vexriscv/demo/{VexRiscvAxi4Linux.scala => VexRiscvAxi4LinuxPlicClint.scala} (71%) diff --git a/src/main/scala/vexriscv/demo/VexRiscvAxi4Linux.scala b/src/main/scala/vexriscv/demo/VexRiscvAxi4LinuxPlicClint.scala similarity index 71% rename from src/main/scala/vexriscv/demo/VexRiscvAxi4Linux.scala rename to src/main/scala/vexriscv/demo/VexRiscvAxi4LinuxPlicClint.scala index ff2ff118..837a4cb5 100644 --- a/src/main/scala/vexriscv/demo/VexRiscvAxi4Linux.scala +++ b/src/main/scala/vexriscv/demo/VexRiscvAxi4LinuxPlicClint.scala @@ -2,15 +2,18 @@ package vexriscv.demo import spinal.core._ import spinal.lib._ -import spinal.lib.bus.amba4.axi.Axi4ReadOnly +import spinal.lib.bus.amba4.axi.{Axi4ReadOnly, Axi4SpecRenamer} +import spinal.lib.bus.amba4.axilite.AxiLite4SpecRenamer import spinal.lib.com.jtag.Jtag import spinal.lib.eda.altera.{InterruptReceiverTag, ResetEmitterTag} +import spinal.lib.misc.AxiLite4Clint +import spinal.lib.misc.plic.AxiLite4Plic import vexriscv.ip.{DataCacheConfig, InstructionCacheConfig} import vexriscv.plugin._ import vexriscv.{Riscv, VexRiscv, VexRiscvConfig, plugin} -object VexRiscvAxi4Linux{ +object VexRiscvAxi4LinuxPlicClint{ def main(args: Array[String]) { val report = SpinalVerilog{ @@ -99,36 +102,42 @@ object VexRiscvAxi4Linux{ ) //CPU instanciation - val cpu = new VexRiscv(cpuConfig) + val cpu = new VexRiscv(cpuConfig){ + val clintCtrl = new AxiLite4Clint(1, bufferTime = false) + val plicCtrl = new AxiLite4Plic( + sourceCount = 31, + targetCount = 2 + ) + + val clint = clintCtrl.io.bus.toIo() + val plic = plicCtrl.io.bus.toIo() + val plicInterrupts = in Bits(32 bits) + plicCtrl.io.sources := plicInterrupts >> 1 + + AxiLite4SpecRenamer(clint) + AxiLite4SpecRenamer(plic) + } //CPU modifications to be an Avalon one - cpu.setDefinitionName("VexRiscvAxi4") + cpu.setDefinitionName("VexRiscvAxi4LinuxPlicClint") cpu.rework { - var iBus : Axi4ReadOnly = null for (plugin <- cpuConfig.plugins) plugin match { - case plugin: IBusSimplePlugin => { - plugin.iBus.setAsDirectionLess() //Unset IO properties of iBus - iBus = master(plugin.iBus.toAxi4ReadOnly().toFullConfig()) - .setName("iBusAxi") - .addTag(ClockDomainTag(ClockDomain.current)) //Specify a clock domain to the iBus (used by QSysify) - } case plugin: IBusCachedPlugin => { plugin.iBus.setAsDirectionLess() //Unset IO properties of iBus - iBus = master(plugin.iBus.toAxi4ReadOnly().toFullConfig()) - .setName("iBusAxi") - .addTag(ClockDomainTag(ClockDomain.current)) //Specify a clock domain to the iBus (used by QSysify) - } - case plugin: DBusSimplePlugin => { - plugin.dBus.setAsDirectionLess() - master(plugin.dBus.toAxi4Shared().toAxi4().toFullConfig()) - .setName("dBusAxi") - .addTag(ClockDomainTag(ClockDomain.current)) + Axi4SpecRenamer( + master(plugin.iBus.toAxi4ReadOnly().toFullConfig()) + .setName("iBusAxi") + .addTag(ClockDomainTag(ClockDomain.current)) //Specify a clock domain to the iBus (used by QSysify) + ) } case plugin: DBusCachedPlugin => { plugin.dBus.setAsDirectionLess() - master(plugin.dBus.toAxi4Shared().toAxi4().toFullConfig()) - .setName("dBusAxi") - .addTag(ClockDomainTag(ClockDomain.current)) + + Axi4SpecRenamer( + master(plugin.dBus.toAxi4Shared().toAxi4().toFullConfig()) + .setName("dBusAxi") + .addTag(ClockDomainTag(ClockDomain.current)) + ) } case plugin: DebugPlugin => plugin.debugClockDomain { plugin.io.bus.setAsDirectionLess() @@ -143,10 +152,11 @@ object VexRiscvAxi4Linux{ } for (plugin <- cpuConfig.plugins) plugin match { case plugin: CsrPlugin => { - plugin.externalInterrupt - .addTag(InterruptReceiverTag(iBus, ClockDomain.current)) - plugin.timerInterrupt - .addTag(InterruptReceiverTag(iBus, ClockDomain.current)) + plugin.timerInterrupt setAsDirectionLess() := cpu.clintCtrl.io.timerInterrupt(0) + plugin.softwareInterrupt setAsDirectionLess() := cpu.clintCtrl.io.softwareInterrupt(0) + plugin.externalInterrupt setAsDirectionLess() := cpu.plicCtrl.io.targets(0) + plugin.externalInterruptS setAsDirectionLess() := cpu.plicCtrl.io.targets(1) + plugin.utime setAsDirectionLess() := cpu.clintCtrl.io.time } case _ => } From 0e531515ac6ee1763e1e2ffffb8ff7062decfe68 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 26 Oct 2022 10:25:50 +0200 Subject: [PATCH 798/951] cleaning --- src/main/scala/vexriscv/demo/VexRiscvAxi4LinuxPlicClint.scala | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main/scala/vexriscv/demo/VexRiscvAxi4LinuxPlicClint.scala b/src/main/scala/vexriscv/demo/VexRiscvAxi4LinuxPlicClint.scala index 837a4cb5..6cf81e42 100644 --- a/src/main/scala/vexriscv/demo/VexRiscvAxi4LinuxPlicClint.scala +++ b/src/main/scala/vexriscv/demo/VexRiscvAxi4LinuxPlicClint.scala @@ -132,7 +132,6 @@ object VexRiscvAxi4LinuxPlicClint{ } case plugin: DBusCachedPlugin => { plugin.dBus.setAsDirectionLess() - Axi4SpecRenamer( master(plugin.dBus.toAxi4Shared().toAxi4().toFullConfig()) .setName("dBusAxi") @@ -148,9 +147,6 @@ object VexRiscvAxi4LinuxPlicClint{ .addTag(ResetEmitterTag(plugin.debugClockDomain)) .parent = null //Avoid the io bundle to be interpreted as a QSys conduit } - case _ => - } - for (plugin <- cpuConfig.plugins) plugin match { case plugin: CsrPlugin => { plugin.timerInterrupt setAsDirectionLess() := cpu.clintCtrl.io.timerInterrupt(0) plugin.softwareInterrupt setAsDirectionLess() := cpu.clintCtrl.io.softwareInterrupt(0) From 7fd55c78514e2bb70f63da13ea94a1873d02d549 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 26 Oct 2022 10:47:23 +0200 Subject: [PATCH 799/951] Add VexRiscvAxi4LinuxPlicClint diagram drawio --- doc/diagram | 1 + src/main/scala/vexriscv/demo/VexRiscvAxi4LinuxPlicClint.scala | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 doc/diagram diff --git a/doc/diagram b/doc/diagram new file mode 100644 index 00000000..6f1c0b9c --- /dev/null +++ b/doc/diagram @@ -0,0 +1 @@ +7VxtV6s4EP41/aiH99KPSvWuu3WPR929ez9GSEv2UtINwbb3128CAQppC9am1VqPR8mQTMMzzyQzYbRnetPFNwJm4T0OYNQztGDRM4c9w3Asl/3kgqUQaGYumBAU5CK9EjyhX1AINSFNUQCTWkeKcUTRrC70cRxDn9ZkgBA8r3cb46j+qTMwgZLgyQeRLP2OAhrmUtfWKvlvEE3C4pN1TdyZgqKzECQhCPB8RWTe9EyPYEzzq+nCgxHHrsAlH3e74W45MQJj2mXAMHwxk/tnL70xvNtbPe6nf/y6EFpeQZSKB+4ZTsT0XSczEPNZ06WAwvkv5VO9HuOYXiSZoa5YB92YLaqb7GrCf99C6oeFKjanXFt+T8BRKjYITuMA8mnq7PY8RBQ+zYDP784ZqZgspNNI3OYfL2ji8mlSgn+WpuEdApCEpTLeeACUQhJnEjbfcgavkFC42IimXtqIcRviKaRkybqIAaYlzCp4bZuiPa9Y4ghRuEKQgg1A8HJSaq5Mxy6E9d5gSVOy5N9w8YgS//VqgawRitPFQ4R8L0LsAZsWYDjQEkwPR5gweYxjyAFHUdQQgQhNOJ4RHPNhHEjEXOZKiKcoCLhmziEfxZNR1m1oVZJHAQgXYTZ8HGWeEbKBkGm4nmE2ywwh+5p9M8w87dLu2WyuHmvrVZt98+6Eejhm0wcoMx8ECZ3DhE+OYAooeMmeVCv4I55c3wMRDLdOBGsgE0F31zDBVMUES2LCXc+wtnid1u51ewDK0ts9xjikx9gSTsMPidMaQq3DyVWFk6NojxhCn0ULX2qTcI68SfQVmfJmAf2Ufi1brnHLg9rSVWTLezjFfHpfx5SOcWRTDhSZ8jth5ngB/s8vZU37yNYs9u+NMQSLVkM8wTGIRhjPBD7/QkqXAk6QUlzHmmFBlv/w8SzsFc0fQl3WGC5qrWXRWiC6Moy1fhQa2XU1iDfKMXFwxTPnXhnvM8kt4iBk9/Ong4GUODcsxhDAKfHhNqjyfhSQCaRtIYjMAAIjQNFrfR7r7CmGPuAs+SkjLWNwadcXdatBivwJxLjV5LqpypJUOQ1V+UNKqjKKlc/0DtbpZ9Z1ZJ3TkXV9Jawz3Q1B4Vs5JynqH5hxxplxHRnX78g49zCMG+yJcY52YMaZZ8Z1ZJzbkXGDgzDOaQZbOzOueWqmmnFt50HvYlyNbxX9Whinr/CtYt/RGdc1lrPOu+pWxjkKGXehXWr6oE473TgG8bJPeIAEMbwgOd6Oa5933K1s7Ktg437WpP3ng1oD7F3XkOYRvqRItdVUHSjd3/91ykdJVoeDQfOQR0mGyqOksvG28KO4/mjhx+CoK77k8vrOa8fg0tEH1dd2tYpXkgKIva8k3tPjKa8kxmBDALCyklgHXUnk+pCH0Z3Xsryof9vdBGrdkntYoOTyCW909+fzh0Nq3cvkwyJlq9icWtKGnVKR3fLtPW5ORtfkWM2Rs7Q5NXPazpuT0aJI9XakMjn+RAeA+09Ym0VHzWqizgnrpuqlQzFEScJ6Zohk2J0DXElRc4NSzRBVhTND+JJOTjmolSoTjx2BmCrS4zVp7naXPZpLWmbDk+zBpWvuuLPb7boUO6YppyjBdZpIJuZIj8ALjOqGK4rSfYY6P1HeXJZOIHPllZLwerX5cJuziD8zEYN7JbVXjb2Fqhtdi20RfU0EN+9khe7WR+DxOIFqDKbi5djndT/bZC7jauVXQ+GuntiiVrVTylXy6HSccsO7yE/tlO6Xdkqj34wumfc4u3mifDYl61LtfvKbnFmE/DvuTSSlp+KHG+qe9u+HF1bDfuoc0VJakPm2o6wPXjqiqLx3f69kjlsSYqk403jzkt7Gh4ShQIsefgSSBPmFWHTTj7kzSHGV845sqd+uSzUp5GOM35+vvp3GhmBtOAf/mIEZa1Z/xp93r/4XgnnzPw== \ No newline at end of file diff --git a/src/main/scala/vexriscv/demo/VexRiscvAxi4LinuxPlicClint.scala b/src/main/scala/vexriscv/demo/VexRiscvAxi4LinuxPlicClint.scala index 6cf81e42..a8ab02a4 100644 --- a/src/main/scala/vexriscv/demo/VexRiscvAxi4LinuxPlicClint.scala +++ b/src/main/scala/vexriscv/demo/VexRiscvAxi4LinuxPlicClint.scala @@ -12,7 +12,7 @@ import vexriscv.ip.{DataCacheConfig, InstructionCacheConfig} import vexriscv.plugin._ import vexriscv.{Riscv, VexRiscv, VexRiscvConfig, plugin} - +//make clean run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD DHRYSTONE=yes SUPERVISOR=yes MMU=no CSR=yes CSR_SKIP_TEST=yes COMPRESSED=no MUL=yes DIV=yes LRSC=yes AMO=yes REDO=0 TRACE=no COREMARK=no LINUX_REGRESSION=yes object VexRiscvAxi4LinuxPlicClint{ def main(args: Array[String]) { val report = SpinalVerilog{ @@ -161,3 +161,4 @@ object VexRiscvAxi4LinuxPlicClint{ } } } + From ab7b2cff3b993692627dbb5423e54b487407502e Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 26 Oct 2022 10:48:21 +0200 Subject: [PATCH 800/951] fix diagram name --- doc/{diagram => diagram.drawio} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename doc/{diagram => diagram.drawio} (100%) diff --git a/doc/diagram b/doc/diagram.drawio similarity index 100% rename from doc/diagram rename to doc/diagram.drawio From a6c29766da07ae9bd7756876fd3fdf4619fa1b58 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 26 Oct 2022 15:48:26 +0200 Subject: [PATCH 801/951] CsrPlugin now force privilegeGen when withPrivilegedDebug is enabled --- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index ee3fe671..54d805f4 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -85,7 +85,7 @@ case class CsrPluginConfig( debugTriggers : Int = 2 ){ assert(!ucycleAccess.canWrite) - def privilegeGen = userGen || supervisorGen + def privilegeGen = userGen || supervisorGen || withPrivilegedDebug def noException = this.copy(ecallGen = false, ebreakGen = false, catchIllegalAccess = false) def noExceptionButEcall = this.copy(ecallGen = true, ebreakGen = false, catchIllegalAccess = false) def withEbreak = ebreakGen || withPrivilegedDebug From 9f6186cd9a6221ce8c139a604652cc5d21452e2c Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 27 Oct 2022 14:55:40 +0200 Subject: [PATCH 802/951] Add GenFullWithRiscvPrivilegedDebugJtag demo --- .../GenFullWithRiscvPrivilegedDebugJtag.scala | 101 ++++++++++++++++++ .../vexriscv/plugin/EmbeddedRiscvJtag.scala | 2 +- 2 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 src/main/scala/vexriscv/demo/GenFullWithRiscvPrivilegedDebugJtag.scala diff --git a/src/main/scala/vexriscv/demo/GenFullWithRiscvPrivilegedDebugJtag.scala b/src/main/scala/vexriscv/demo/GenFullWithRiscvPrivilegedDebugJtag.scala new file mode 100644 index 00000000..e6496b11 --- /dev/null +++ b/src/main/scala/vexriscv/demo/GenFullWithRiscvPrivilegedDebugJtag.scala @@ -0,0 +1,101 @@ +package vexriscv.demo + +import spinal.core._ +import spinal.lib.cpu.riscv.debug.DebugTransportModuleParameter +import vexriscv.ip.{DataCacheConfig, InstructionCacheConfig} +import vexriscv.plugin._ +import vexriscv.{VexRiscv, VexRiscvConfig, plugin} + +/** + * Created by spinalvm on 15.06.17. + */ +object GenFullWithRiscvPrivilegedDebugJtag extends App{ + def config = VexRiscvConfig( + plugins = List( + new IBusCachedPlugin( + prediction = DYNAMIC, + config = InstructionCacheConfig( + cacheSize = 4096, + bytePerLine =32, + wayCount = 1, + addressWidth = 32, + cpuDataWidth = 32, + memDataWidth = 32, + catchIllegalAccess = true, + catchAccessFault = true, + asyncTagMemory = false, + twoCycleRam = true, + twoCycleCache = true + ), + memoryTranslatorPortConfig = MmuPortConfig( + portTlbSize = 4 + ) + ), + new DBusCachedPlugin( + config = new DataCacheConfig( + cacheSize = 4096, + bytePerLine = 32, + wayCount = 1, + addressWidth = 32, + cpuDataWidth = 32, + memDataWidth = 32, + catchAccessError = true, + catchIllegal = true, + catchUnaligned = true + ), + memoryTranslatorPortConfig = MmuPortConfig( + portTlbSize = 6 + ) + ), + new MmuPlugin( + virtualRange = _(31 downto 28) === 0xC, + ioRange = _(31 downto 28) === 0xF + ), + new DecoderSimplePlugin( + catchIllegalInstruction = true + ), + new RegFilePlugin( + regFileReadyKind = plugin.SYNC, + zeroBoot = false + ), + new IntAluPlugin, + new SrcPlugin( + separatedAddSub = false, + executeInsertion = true + ), + new FullBarrelShifterPlugin, + new HazardSimplePlugin( + bypassExecute = true, + bypassMemory = true, + bypassWriteBack = true, + bypassWriteBackBuffer = true, + pessimisticUseSrc = false, + pessimisticWriteRegFile = false, + pessimisticAddressMatch = false + ), + new MulPlugin, + new DivPlugin, + new CsrPlugin(CsrPluginConfig.small(0x80000020l).copy(withPrivilegedDebug = true)), //withPrivilegedDebug is required + new EmbeddedRiscvJtag( + DebugTransportModuleParameter( + addressWidth = 7, + version = 1, + idle = 7 + ), + withTap = true, + withTunneling = false + ), + new BranchPlugin( + earlyBranch = false, + catchAddressMisaligned = true + ), + new YamlPlugin("cpu0.yaml") + ) + ) + + def cpu() = new VexRiscv( + config + ) + + SpinalVerilog(cpu()) +} diff --git a/src/main/scala/vexriscv/plugin/EmbeddedRiscvJtag.scala b/src/main/scala/vexriscv/plugin/EmbeddedRiscvJtag.scala index f7937556..c75c4d1e 100644 --- a/src/main/scala/vexriscv/plugin/EmbeddedRiscvJtag.scala +++ b/src/main/scala/vexriscv/plugin/EmbeddedRiscvJtag.scala @@ -30,7 +30,7 @@ class EmbeddedRiscvJtag(var p : DebugTransportModuleParameter, override def setup(pipeline: VexRiscv): Unit = { jtag = withTap generate slave(Jtag()).setName("jtag") jtagInstruction = !withTap generate slave(JtagTapInstructionCtrl()).setName("jtagInstruction") - ndmreset = Bool().setName("ndmreset") + ndmreset = out(Bool()).setName("ndmreset") } override def build(pipeline: VexRiscv): Unit = { From 5d0deb20b3549a9301c19cd5187b1e0854238f9f Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 27 Oct 2022 15:20:55 +0200 Subject: [PATCH 803/951] Fix regression compilation --- src/test/cpp/regression/jtag.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/cpp/regression/jtag.h b/src/test/cpp/regression/jtag.h index 8dabe93f..014b51a9 100644 --- a/src/test/cpp/regression/jtag.h +++ b/src/test/cpp/regression/jtag.h @@ -9,7 +9,7 @@ #include /** Returns true on success, or false if there was an error */ -bool SetSocketBlockingEnabled(int fd, bool blocking) +bool SetSocketBlockingEnabledRegression(int fd, bool blocking) { if (fd < 0) return false; @@ -73,7 +73,7 @@ public: fprintf(stderr, "Error setting socket opts: %s\n", strerror(errno)); }*/ - SetSocketBlockingEnabled(serverSocket,0); + SetSocketBlockingEnabledRegression(serverSocket,0); //---- Configure settings of the server address struct ----// From d70794f25206d721dc07f97f1ea22c800648c4ea Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 27 Oct 2022 15:38:34 +0200 Subject: [PATCH 804/951] fix regression --- src/test/scala/vexriscv/TestIndividualFeatures.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/scala/vexriscv/TestIndividualFeatures.scala b/src/test/scala/vexriscv/TestIndividualFeatures.scala index bd5acb0a..281570b7 100644 --- a/src/test/scala/vexriscv/TestIndividualFeatures.scala +++ b/src/test/scala/vexriscv/TestIndividualFeatures.scala @@ -770,7 +770,7 @@ class TestIndividualFeatures extends MultithreadedFunSuite(sys.env.getOrElse("VE } //Setup test - val files = List("main.cpp", "encoding.h" ,"makefile", "dhrystoneO3.logRef", "dhrystoneO3C.logRef","dhrystoneO3MC.logRef","dhrystoneO3M.logRef") + val files = List("main.cpp", "jtag.h", "encoding.h" ,"makefile", "dhrystoneO3.logRef", "dhrystoneO3C.logRef","dhrystoneO3MC.logRef","dhrystoneO3M.logRef") files.foreach(f => FileUtils.copyFileToDirectory(new File(s"src/test/cpp/regression/$f"), new File(project))) //Test RTL From f71234786ff12b8e20e56c41501e614b4a403de8 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 27 Oct 2022 15:44:50 +0200 Subject: [PATCH 805/951] Remove rv64 opcode (shift and lwu) Thanks Milan --- src/main/scala/vexriscv/Riscv.scala | 7 +++---- src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala | 6 +++--- src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala | 4 ++-- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/main/scala/vexriscv/Riscv.scala b/src/main/scala/vexriscv/Riscv.scala index f0197bcf..cb129a97 100644 --- a/src/main/scala/vexriscv/Riscv.scala +++ b/src/main/scala/vexriscv/Riscv.scala @@ -45,12 +45,12 @@ object Riscv{ def AND = M"0000000----------111-----0110011" def ADDI = M"-----------------000-----0010011" - def SLLI = M"000000-----------001-----0010011" + def SLLI = M"0000000----------001-----0010011" def SLTI = M"-----------------010-----0010011" def SLTIU = M"-----------------011-----0010011" def XORI = M"-----------------100-----0010011" - def SRLI = M"000000-----------101-----0010011" - def SRAI = M"010000-----------101-----0010011" + def SRLI = M"0000000----------101-----0010011" + def SRAI = M"0100000----------101-----0010011" def ORI = M"-----------------110-----0010011" def ANDI = M"-----------------111-----0010011" @@ -59,7 +59,6 @@ object Riscv{ def LW = M"-----------------010-----0000011" def LBU = M"-----------------100-----0000011" def LHU = M"-----------------101-----0000011" - def LWU = M"-----------------110-----0000011" def SB = M"-----------------000-----0100011" def SH = M"-----------------001-----0100011" def SW = M"-----------------010-----0100011" diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index 50b953e6..3a1a8a97 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -171,12 +171,12 @@ class DBusCachedPlugin(val config : DataCacheConfig, decoderService.addDefault(MEMORY_ENABLE, False) decoderService.add( - List(LB, LH, LW, LBU, LHU, LWU).map(_ -> loadActions) ++ + List(LB, LH, LW, LBU, LHU).map(_ -> loadActions) ++ List(SB, SH, SW).map(_ -> storeActions) ) if(withLrSc){ - List(LB, LH, LW, LBU, LHU, LWU, SB, SH, SW).foreach(e => + List(LB, LH, LW, LBU, LHU, SB, SH, SW).foreach(e => decoderService.add(e, Seq(MEMORY_LRSC -> False)) ) decoderService.add( @@ -199,7 +199,7 @@ class DBusCachedPlugin(val config : DataCacheConfig, } if(withAmo){ - List(LB, LH, LW, LBU, LHU, LWU, SB, SH, SW).foreach(e => + List(LB, LH, LW, LBU, LHU, SB, SH, SW).foreach(e => decoderService.add(e, Seq(MEMORY_AMO -> False)) ) val amoActions = storeActions.filter(_._1 != SRC2_CTRL) ++ Seq( diff --git a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala index 372cfcc5..dbf66090 100644 --- a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala @@ -340,13 +340,13 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, decoderService.addDefault(MEMORY_ENABLE, False) decoderService.add( - (if(onlyLoadWords) List(LW) else List(LB, LH, LW, LBU, LHU, LWU)).map(_ -> loadActions) ++ + (if(onlyLoadWords) List(LW) else List(LB, LH, LW, LBU, LHU)).map(_ -> loadActions) ++ List(SB, SH, SW).map(_ -> storeActions) ) if(withLrSc){ - List(LB, LH, LW, LBU, LHU, LWU, SB, SH, SW).foreach(e => + List(LB, LH, LW, LBU, LHU, SB, SH, SW).foreach(e => decoderService.add(e, Seq(MEMORY_ATOMIC -> False)) ) decoderService.add( From 0bfaf06a4ace279f9369f60ad00ec990b8c76ea3 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 10 Nov 2022 13:43:14 +0100 Subject: [PATCH 806/951] main.cpp add VEXRISCV_JTAG=yes --- src/test/cpp/regression/main.cpp | 29 +++++++++++++++++++++++++++++ src/test/cpp/regression/makefile | 4 ++++ 2 files changed, 33 insertions(+) diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index adf7b5b7..0c3fdd3f 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -3073,6 +3073,31 @@ public: #include "jtag.h" +#ifdef VEXRISCV_JTAG +class VexRiscvJtag : public SimElement{ +public: + Workspace *ws; + VVexRiscv* top; + + VexRiscvJtag(Workspace* ws){ + this->ws = ws; + this->top = ws->top; + } + + virtual void onReset(){ + top->debugReset = 1; + } + + virtual void preCycle(){ + + } + + virtual void postCycle(){ + top->debugReset = 0; + } +}; +#endif + void Workspace::fillSimELements(){ #ifdef IBUS_SIMPLE simElements.push_back(new IBusSimple(this)); @@ -3126,6 +3151,10 @@ void Workspace::fillSimELements(){ #ifdef RISCV_JTAG simElements.push_back(new Jtag(&top->jtag_tms, &top->jtag_tdi, &top->jtag_tdo, &top->jtag_tck, 4)); #endif + #ifdef VEXRISCV_JTAG + simElements.push_back(new Jtag(&top->jtag_tms, &top->jtag_tdi, &top->jtag_tdo, &top->jtag_tck, 4)); + simElements.push_back(new VexRiscvJtag(this)); + #endif } mutex Workspace::staticMutex; diff --git a/src/test/cpp/regression/makefile b/src/test/cpp/regression/makefile index 13bfbb36..e02f3b86 100644 --- a/src/test/cpp/regression/makefile +++ b/src/test/cpp/regression/makefile @@ -308,6 +308,10 @@ ifeq ($(RISCV_JTAG),yes) ADDCFLAGS += -CFLAGS -DRISCV_JTAG endif +ifeq ($(VEXRISCV_JTAG),yes) + ADDCFLAGS += -CFLAGS -DVEXRISCV_JTAG +endif + ifeq ($(REF),yes) ADDCFLAGS += -CFLAGS -DREF From 2504f9b9b971ed987ef271f308f8f3b789d5e9e3 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 10 Nov 2022 15:49:03 +0100 Subject: [PATCH 807/951] RISC-V debug havereset implemented --- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 54d805f4..4d7d708e 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -696,6 +696,10 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep bus.running := running bus.halted := !running bus.unavailable := RegNext(ClockDomain.current.isResetActive) + + val reseting = RegNext(False) init(True) + bus.haveReset := RegInit(False) setWhen(reseting) clearWhen(bus.ackReset) + val enterHalt = running.getAheadValue().fall(False) val doHalt = RegInit(False) setWhen(bus.haltReq && bus.running && !debugMode) clearWhen(enterHalt) From fe68b8494e1065fa0ca24e2ba64da861a8c63723 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 11 Nov 2022 14:05:38 +0100 Subject: [PATCH 808/951] Fix a few RISC-V official debug support : - Disable interrupts in debug mode - Ensure traps do not change CSR in debug mode - step will also consider trapEvent --- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 4d7d708e..36737fb0 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -696,6 +696,9 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep bus.running := running bus.halted := !running bus.unavailable := RegNext(ClockDomain.current.isResetActive) + when(debugMode){ + inhibateInterrupts() + } val reseting = RegNext(False) init(True) bus.haveReset := RegInit(False) setWhen(reseting) clearWhen(bus.ackReset) @@ -767,6 +770,10 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep } } SINGLE whenIsActive{ + when(trapEvent){ + doHalt := True + goto(WAIT) + } when(decode.arbitration.isFiring) { goto(WAIT) } @@ -1290,7 +1297,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep } val trapEnterDebug = False - if(withPrivilegedDebug) trapEnterDebug setWhen(debug.doHalt || trapCauseEbreakDebug || !hadException && debug.doHalt) + if(withPrivilegedDebug) trapEnterDebug setWhen(debug.doHalt || trapCauseEbreakDebug || !hadException && debug.doHalt || !debug.running) when(hadException || interruptJump){ trapEvent := True fetcher.haltIt() //Avoid having the fetch confused by the incomming privilege switch From 5e17ab62d699300b78861465a5a97b743caf888b Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 14 Nov 2022 14:45:11 +0100 Subject: [PATCH 809/951] Fix RISC-V debug hardware breakpoints --- .../scala/vexriscv/VexRiscvBmbGenerator.scala | 5 +++++ src/main/scala/vexriscv/plugin/CsrPlugin.scala | 17 +++++++++++++---- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/main/scala/vexriscv/VexRiscvBmbGenerator.scala b/src/main/scala/vexriscv/VexRiscvBmbGenerator.scala index aa4aada2..2492b1c0 100644 --- a/src/main/scala/vexriscv/VexRiscvBmbGenerator.scala +++ b/src/main/scala/vexriscv/VexRiscvBmbGenerator.scala @@ -103,6 +103,11 @@ case class VexRiscvBmbGenerator()(implicit interconnectSmp: BmbInterconnectGener case _ => config.add(new DebugPlugin(debugClockDomain, hardwareBreakpointCount)) } + for (e <- config.plugins) e match { + case e: CsrPlugin => e.config.debugTriggers = hardwareBreakpointCount + case _ => + } + val cpu = new VexRiscv(config) def doExport(value : => Any, postfix : String) = { sexport(Handle(value).setCompositeName(VexRiscvBmbGenerator.this, postfix)) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 36737fb0..cbe8ce90 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -82,7 +82,7 @@ case class CsrPluginConfig( deterministicInteruptionEntry : Boolean = false, //Only used for simulatation purposes wfiOutput : Boolean = false, withPrivilegedDebug : Boolean = false, //For the official RISC-V debug spec implementation - debugTriggers : Int = 2 + var debugTriggers : Int = 2 ){ assert(!ucycleAccess.canWrite) def privilegeGen = userGen || supervisorGen || withPrivilegedDebug @@ -711,7 +711,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep // Pipeline execution timeout used to trigger some redo val timeout = Timeout(7) - when(pipeline.stages.map(_.arbitration.isValid).orR){ + when(pipeline.stages.tail.map(_.arbitration.isValid).orR){ timeout.clear() } @@ -770,6 +770,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep } } SINGLE whenIsActive{ + timeout.clear() when(trapEvent){ doHalt := True goto(WAIT) @@ -783,7 +784,6 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep decode.arbitration.haltByOther setWhen(decode.arbitration.isValid) //re resume the execution in case of timeout (ex cache miss) when(!doHalt && timeout.state){ - forceResume := True goto(SINGLE) } otherwise { when(stages.last.arbitration.isFiring) { @@ -839,7 +839,9 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep when(enabled) { decode.arbitration.haltByOther := True when(timeout.state) { - decode.arbitration.flushIt := True + trapEvent := True + decode.arbitration.flushNext := True + decode.arbitration.removeIt := True dpc := decode.input(PC) running := False dcsr.cause := 2 @@ -906,6 +908,8 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep } r(CSR.TDATA1, 0 -> slots.map(_.tdata1.read).read(tselect.index)) + + decodeBreak.enabled clearWhen(!decode.arbitration.isValid) } }) @@ -1616,6 +1620,11 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep illegalAccess clearWhen(!arbitration.isValid || !input(IS_CSR)) } } + +// Component.toplevel.rework{ +// out(CombInit(debug.running.pull())).setName("debug0") +// out(CombInit(pipeline.decode.arbitration.isFiring.pull())).setName("debug1") +// } } } } From 36c3346e51a6d9b19acb12e0aaab4632f8822ff4 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 17 Nov 2022 11:03:42 +0100 Subject: [PATCH 810/951] ensure rvc 0 is detected as a illegal instruction --- src/main/scala/vexriscv/plugin/Misc.scala | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/plugin/Misc.scala b/src/main/scala/vexriscv/plugin/Misc.scala index 979d246d..73d90e69 100644 --- a/src/main/scala/vexriscv/plugin/Misc.scala +++ b/src/main/scala/vexriscv/plugin/Misc.scala @@ -42,7 +42,10 @@ object RvcDecompressor{ val x2 = B"00010" switch(i(1 downto 0) ## i(15 downto 13)){ - is(0){ret := addi5spnImm ## B"00010" ## B"000" ## rcl ## B"0010011"} //C.ADDI4SPN -> addi rd0, x2, nzuimm[9:2]. + is(0){ + ret := addi5spnImm ## B"00010" ## B"000" ## rcl ## B"0010011" + when(i(12 downto 2) === 0) { ret := 0 } //Ensure 0 => illegal + } //C.ADDI4SPN -> addi rd0, x2, nzuimm[9:2]. if(rvd) is(1){ret := ldImm ## rch ## B"011" ## rcl ## B"0000111"} // C.FLD is(2){ret := lwImm ## rch ## B"010" ## rcl ## B"0000011"} //C.LW -> lw rd', offset[6:2](rs1') if(rvf) is(3){ret := lwImm ## rch ## B"010" ## rcl ## B"0000111"} // C.FLW From 663174bc7319666648d2238ff8a1f9d6e45bf418 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 17 Nov 2022 13:58:25 +0100 Subject: [PATCH 811/951] Privileged debug now implement stoptime stopcount --- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index cbe8ce90..6d05e698 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -469,6 +469,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep var inWfi : Bool = null var externalMhartId : UInt = null var utime : UInt = null + var stoptime : Bool = null var debugBus : DebugHartBus = null var debugMode : Bool = null @@ -752,8 +753,8 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep val nmip = False val mprven = False val cause = RegInit(U"000") - val stoptime = False - val stopcount = False + val stoptime = RegInit(False) + val stopcount = RegInit(False) val stepie = RegInit(False) //TODO val ebreaku = userGen generate RegInit(False) val ebreaks = supervisorGen generate RegInit(False) @@ -801,8 +802,8 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep } - r(CSR.DCSR, 3 -> nmip, 6 -> cause, 28 -> xdebugver, 4 -> mprven, 9 -> stoptime, 10 -> stopcount) - rw(CSR.DCSR, 0 -> prv, 2 -> step, 11 -> stepie, 15 -> ebreakm) + r(CSR.DCSR, 3 -> nmip, 6 -> cause, 28 -> xdebugver, 4 -> mprven) + rw(CSR.DCSR, 0 -> prv, 2 -> step, 9 -> stoptime, 10 -> stopcount, 11 -> stepie, 15 -> ebreakm) if(supervisorGen) rw(CSR.DCSR, 13 -> ebreaks) if(userGen) rw(CSR.DCSR, 12 -> ebreaku) @@ -819,6 +820,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep wakeService.askWake() } } + stoptime = out(debugMode && dcsr.stoptime).setName("stoptime") //Very limited subset of the trigger spec val trigger = (debugTriggers > 0) generate new Area { @@ -1088,7 +1090,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep val stagesFromExecute = pipeline.stages.dropWhile(_ != execute) //Manage counters - mcycle := mcycle + 1 + mcycle := mcycle + (if(withPrivilegedDebug) U(!debugMode || !debug.dcsr.stopcount) else U(1)) when(lastStage.arbitration.isFiring) { minstret := minstret + 1 } From e19e59b55ce85aba1a32c53f1b67d7b41cedfa02 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 17 Nov 2022 15:03:47 +0100 Subject: [PATCH 812/951] Clear mprv on xretAwayFromMachine --- .../scala/vexriscv/demo/SynthesisBench.scala | 156 +++++++++--------- .../scala/vexriscv/plugin/CsrPlugin.scala | 14 +- .../scala/vexriscv/plugin/MmuPlugin.scala | 3 +- 3 files changed, 95 insertions(+), 78 deletions(-) diff --git a/src/main/scala/vexriscv/demo/SynthesisBench.scala b/src/main/scala/vexriscv/demo/SynthesisBench.scala index 6a044eae..7a1ff357 100644 --- a/src/main/scala/vexriscv/demo/SynthesisBench.scala +++ b/src/main/scala/vexriscv/demo/SynthesisBench.scala @@ -2,6 +2,8 @@ package vexriscv.demo import spinal.core._ import spinal.lib._ +import spinal.lib.com.jtag.Jtag +import spinal.lib.cpu.riscv.debug.DebugTransportModuleParameter import spinal.lib.eda.bench._ import spinal.lib.eda.icestorm.IcestormStdTargets import spinal.lib.eda.xilinx.VivadoFlow @@ -9,7 +11,7 @@ import spinal.lib.io.InOutWrapper import vexriscv.demo.smp.VexRiscvSmpClusterGen import vexriscv.plugin.CsrAccess.{READ_ONLY, READ_WRITE, WRITE_ONLY} import vexriscv.{VexRiscv, VexRiscvConfig, plugin} -import vexriscv.plugin.{BranchPlugin, CsrPlugin, CsrPluginConfig, DBusSimplePlugin, DecoderSimplePlugin, FullBarrelShifterPlugin, HazardSimplePlugin, IBusSimplePlugin, IntAluPlugin, LightShifterPlugin, NONE, RegFilePlugin, SrcPlugin, YamlPlugin} +import vexriscv.plugin.{BranchPlugin, CsrPlugin, CsrPluginConfig, DBusSimplePlugin, DebugPlugin, DecoderSimplePlugin, EmbeddedRiscvJtag, FullBarrelShifterPlugin, HazardSimplePlugin, IBusSimplePlugin, IntAluPlugin, LightShifterPlugin, NONE, Plugin, RegFilePlugin, SrcPlugin, YamlPlugin} import scala.collection.mutable.ArrayBuffer import scala.util.Random @@ -409,88 +411,94 @@ object VexRiscvCustomSynthesisBench { def main(args: Array[String]) { - def gen(csr : CsrPlugin) = new VexRiscv( - config = VexRiscvConfig( - plugins = List( - new IBusSimplePlugin( - resetVector = 0x80000000l, - cmdForkOnSecondStage = false, - cmdForkPersistence = false, - prediction = NONE, - catchAccessFault = false, - compressedGen = false - ), - new DBusSimplePlugin( - catchAddressMisaligned = false, - catchAccessFault = false - ), - new DecoderSimplePlugin( - catchIllegalInstruction = false - ), - new RegFilePlugin( - regFileReadyKind = plugin.SYNC, - zeroBoot = false - ), - new IntAluPlugin, - new SrcPlugin( - separatedAddSub = false, - executeInsertion = true - ), - csr, - new FullBarrelShifterPlugin(), - new HazardSimplePlugin( - bypassExecute = true, - bypassMemory = true, - bypassWriteBack = true, - bypassWriteBackBuffer = true, - pessimisticUseSrc = false, - pessimisticWriteRegFile = false, - pessimisticAddressMatch = false - ), - new BranchPlugin( - earlyBranch = false, - catchAddressMisaligned = false - ), - new YamlPlugin("cpu0.yaml") + def gen(csr : CsrPlugin, p : Plugin[VexRiscv]) = { + val cpu = new VexRiscv( + config = VexRiscvConfig( + plugins = List( + p, + new IBusSimplePlugin( + resetVector = 0x80000000l, + cmdForkOnSecondStage = false, + cmdForkPersistence = false, + prediction = NONE, + catchAccessFault = false, + compressedGen = false + ), + new DBusSimplePlugin( + catchAddressMisaligned = false, + catchAccessFault = false + ), + new DecoderSimplePlugin( + catchIllegalInstruction = false + ), + new RegFilePlugin( + regFileReadyKind = plugin.SYNC, + zeroBoot = false + ), + new IntAluPlugin, + new SrcPlugin( + separatedAddSub = false, + executeInsertion = true + ), + csr, + new FullBarrelShifterPlugin(), + new HazardSimplePlugin( + bypassExecute = true, + bypassMemory = true, + bypassWriteBack = true, + bypassWriteBackBuffer = true, + pessimisticUseSrc = false, + pessimisticWriteRegFile = false, + pessimisticAddressMatch = false + ), + new BranchPlugin( + earlyBranch = false, + catchAddressMisaligned = false + ), + new YamlPlugin("cpu0.yaml") + ) ) ) - ) - - - val fixedMtvec = new Rtl { - override def getName(): String = "Fixed MTVEC" - override def getRtlPath(): String = "fixedMtvec.v" - SpinalVerilog(gen(new CsrPlugin(CsrPluginConfig.smallest(0x80000000l))).setDefinitionName(getRtlPath().split("\\.").head)) - } - - val writeOnlyMtvec = new Rtl { - override def getName(): String = "write only MTVEC" - override def getRtlPath(): String = "woMtvec.v" - SpinalVerilog(gen(new CsrPlugin(CsrPluginConfig.smallest(null).copy(mtvecAccess = WRITE_ONLY))).setDefinitionName(getRtlPath().split("\\.").head)) - } - - val readWriteMtvec = new Rtl { - override def getName(): String = "read write MTVEC" - override def getRtlPath(): String = "wrMtvec.v" - SpinalVerilog(gen(new CsrPlugin(CsrPluginConfig.smallest(null).copy(mtvecAccess = READ_WRITE))).setDefinitionName(getRtlPath().split("\\.").head)) - } - - val fixedMtvecRoCounter = new Rtl { - override def getName(): String = "Fixed MTVEC, read only mcycle/minstret" - override def getRtlPath(): String = "fixedMtvecRoCounter.v" - SpinalVerilog(gen(new CsrPlugin(CsrPluginConfig.smallest(0x80000000l).copy(mcycleAccess = READ_ONLY, minstretAccess = READ_ONLY))).setDefinitionName(getRtlPath().split("\\.").head)) + cpu.rework { + for (plugin <- cpu.config.plugins) plugin match { + case plugin: DebugPlugin => plugin.debugClockDomain { + plugin.io.bus.setAsDirectionLess() + val jtag = slave(new Jtag()) + .setName("jtag") + jtag <> plugin.io.bus.fromJtag() + } + case _ => + } + } + cpu } - val rwMtvecRoCounter = new Rtl { - override def getName(): String = "read write MTVEC, read only mcycle/minstret" - override def getRtlPath(): String = "readWriteMtvecRoCounter.v" - SpinalVerilog(gen(new CsrPlugin(CsrPluginConfig.smallest(null).copy(mtvecAccess = READ_WRITE, mcycleAccess = READ_ONLY, minstretAccess = READ_ONLY))).setDefinitionName(getRtlPath().split("\\.").head)) + val riscvDebug = new Rtl { + override def getName(): String = "riscvDebug" + override def getRtlPath(): String = "riscvDebug.v" + SpinalVerilog(gen(new CsrPlugin(CsrPluginConfig.smallest(0x80000000l).copy(withPrivilegedDebug = true)), new EmbeddedRiscvJtag( + p = DebugTransportModuleParameter( + addressWidth = 7, + version = 1, + idle = 7 + ), + withTunneling = false, + withTap = true + )).setDefinitionName(getRtlPath().split("\\.").head)) + } + + val vexDebug = new Rtl { + override def getName(): String = "vexDebug" + override def getRtlPath(): String = "vexDebug.v" + SpinalVerilog(gen(new CsrPlugin(CsrPluginConfig.smallest(0x80000000l)), + new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))) + ).setDefinitionName(getRtlPath().split("\\.").head)) } // val rtls = List(twoStage, twoStageBarell, twoStageMulDiv, twoStageAll, smallestNoCsr, smallest, smallAndProductive, smallAndProductiveWithICache, fullNoMmuNoCache, noCacheNoMmuMaxPerf, fullNoMmuMaxPerf, fullNoMmu, full, linuxBalanced, linuxBalancedSmp) - val rtls = List(fixedMtvec, writeOnlyMtvec, readWriteMtvec,fixedMtvecRoCounter, rwMtvecRoCounter) + val rtls = List(riscvDebug, vexDebug) // val rtls = List(smallest) val targets = XilinxStdTargets() ++ AlteraStdTargets() ++ IcestormStdTargets().take(1) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 6d05e698..40f6a6ec 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -470,6 +470,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep var externalMhartId : UInt = null var utime : UInt = null var stoptime : Bool = null + var xretAwayFromMachine : Bool = null var debugBus : DebugHartBus = null var debugMode : Bool = null @@ -633,6 +634,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep decoderService.add(SFENCE_VMA, List(IS_SFENCE_VMA -> True)) } + xretAwayFromMachine = False injectionPort = withPrivilegedDebug generate pipeline.service(classOf[IBusFetcher]).getInjectionPort() debugMode = withPrivilegedDebug generate Bool().setName("debugMode") @@ -751,7 +753,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep val prv = RegInit(U"11") val step = RegInit(False) //TODO val nmip = False - val mprven = False + val mprven = True val cause = RegInit(U"000") val stoptime = RegInit(False) val stopcount = RegInit(False) @@ -1380,14 +1382,20 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep mstatus.MIE := mstatus.MPIE mstatus.MPIE := True jumpInterface.payload := mepc - if(privilegeGen) privilegeReg := mstatus.MPP + if(privilegeGen) { + privilegeReg := mstatus.MPP + xretAwayFromMachine setWhen(mstatus.MPP < 3) + } } if(supervisorGen) is(1){ sstatus.SPP := U"0" sstatus.SIE := sstatus.SPIE sstatus.SPIE := True jumpInterface.payload := sepc - if(privilegeGen) privilegeReg := U"0" @@ sstatus.SPP + if(privilegeGen) { + privilegeReg := U"0" @@ sstatus.SPP + xretAwayFromMachine := True + } } } } diff --git a/src/main/scala/vexriscv/plugin/MmuPlugin.scala b/src/main/scala/vexriscv/plugin/MmuPlugin.scala index 093f59ad..c984b035 100644 --- a/src/main/scala/vexriscv/plugin/MmuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/MmuPlugin.scala @@ -69,7 +69,7 @@ class MmuPlugin(ioRange : UInt => Bool, import pipeline._ import pipeline.config._ import Riscv._ - val csrService = pipeline.service(classOf[CsrInterface]) + val csrService = pipeline.service(classOf[CsrPlugin]) //Sorted by priority val sortedPortsInfo = portsInfo.sortBy(_.priority) @@ -89,6 +89,7 @@ class MmuPlugin(ioRange : UInt => Bool, val csr = pipeline plug new Area{ val status = new Area{ val sum, mxr, mprv = RegInit(False) + mprv clearWhen(csrService.xretAwayFromMachine) } val satp = new Area { val mode = RegInit(False) From 4ae7386904424c7f42b29a20a4f8f5df22d1fa82 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 18 Nov 2022 17:38:50 +0100 Subject: [PATCH 813/951] Merge pull request #276 from LYWalker/master Add ability to debug over Intel Virtual JTAG --- README.md | 2 + doc/vjtag/README.md | 106 ++++++++++++++++++ .../scala/vexriscv/plugin/DebugPlugin.scala | 16 ++- 3 files changed, 123 insertions(+), 1 deletion(-) create mode 100644 doc/vjtag/README.md diff --git a/README.md b/README.md index 6208319f..034c734e 100644 --- a/README.md +++ b/README.md @@ -346,11 +346,13 @@ To connect OpenOCD (https://github.com/SpinalHDL/openocd_riscv) to the simulatio ```sh src/openocd -f tcl/interface/jtag_tcp.cfg -c "set BRIEY_CPU0_YAML /home/spinalvm/Spinal/VexRiscv/cpu0.yaml" -f tcl/target/briey.cfg ``` +To connect OpenOCD to Altera FPGAs (Intel VJTAG) see here: https://github.com/SpinalHDL/VexRiscv/tree/master/doc/vjtag You can find multiple software examples and demos here: You can find some FPGA projects which instantiate the Briey SoC here (DE1-SoC, DE0-Nano): https://drive.google.com/drive/folders/0B-CqLXDTaMbKZGdJZlZ5THAxRTQ?usp=sharing + Here are some measurements of Briey SoC timings and area: ``` diff --git a/doc/vjtag/README.md b/doc/vjtag/README.md new file mode 100644 index 00000000..fc25589a --- /dev/null +++ b/doc/vjtag/README.md @@ -0,0 +1,106 @@ +# Intel VJTAG +*By Levi Walker (@LYWalker)* + +Intel VJTAG allows JTAG communication with the FPGA fabric of Altera devices through the standard USB cable using the onboard USB-Blaster. This avoids the needs to breakout the JTAG signals to the GPIO and use a dedicated external debugger. + +## How to use VJTAG with Briey +In Briey.scala remove the following lines (note: line numbers may differ, depending on edits): + +``` +[185] val jtag = slave(Jtag()) +... +[466] val tcpJtag = JtagTcp( +[467] jtag = dut.io.jtag, +[468] jtagClkPeriod = jtagClkPeriod +[469] ) +``` + +Then VJAG can be added in two ways. + +### Method 1 +Replace the following line in Briey.scala: + +``` +[311] io.jtag <> plugin.io.bus.fromJtag() +``` +with +``` +[311] plugin.io.bus.fromVJtag() +``` + +### Method 2 +Replace the following line in Briey.scala: + +``` +[311] io.jtag <> plugin.io.bus.fromJtag() +``` +with +``` +[311] val tap = new sld_virtual_jtag(2) +[312] val jtagCtrl = tap.toJtagTapInstructionCtrl() +[313] jtagCtrl <> plugin.io.bus.fromJtagInstructionCtrl(ClockDomain(tap.io.tck),0) +``` +And add +``` +import spinal.lib.blackbox.altera.sld_virtual_jtag +``` +to the imports at the top of the file. + +This uses the existing JtagInstructionCtrl architecture and communicates using DR headers. + +## Using OpenOCD + +First, clone and setup openocd with the steps as provided by https://github.com/SpinalHDL/openocd_riscv + +Then in tcl/target/Briey.cfg set `_USE_VJTAG` to 1: +``` +[3] set _USE_VJTAG 1 +``` + +Then if you used Method 1 above uncomment line 25: +``` +[25] vexriscv jtagMapping 0 1 0 0 0 0 +``` +If you used Method 2 uncomment line 27: +``` +[27] vexriscv jtagMapping 0 0 0 1 2 2 +``` + +If the board uses USB-Blaster2 then run OpenOCD in shell using: +``` +openocd -c "set CPU0_YAML ../VexRiscv/cpu0.yaml" \ +-f tcl/interface/altera-usb-blaster2.cfg \ +-f tcl/interface/soc_init.cfg +``` +Note: you may need to edit `tcl/interface/altera-usb-blaster2.cfg` with your quartus path. + +If using an older board using USB-Blaster run using: +``` +openocd -c "set CPU0_YAML ../VexRiscv/cpu0.yaml" -f tcl/interface/altera-usb-blaster.cfg -f tcl/interface/Briey.cfg +``` + +On success it should look something like: +``` +Open On-Chip Debugger 0.11.0+dev-02588-gb10abb4b1 (2022-11-07-13:38) +Licensed under GNU GPL v2 +For bug reports, read + http://openocd.org/doc/doxygen/bugs.html +../../Verilog/cpu0.yaml +Info : only one transport option; autoselect 'jtag' +DEPRECATED! use 'adapter speed' not 'adapter_khz' +DEPRECATED! use 'adapter srst delay' not 'adapter_nsrst_delay' +Info : set servers polling period to 50ms +Info : usb blaster interface using libftdi +Info : This adapter doesn't support configurable speed +Info : JTAG tap: fpgasoc.fpga.tap tap/device found: 0x020f20dd (mfg: 0x06e (Altera), part: 0x20f2, ver: 0x0) +[fpga_spinal.cpu0] Target successfully examined. +Info : starting gdb server for fpga_spinal.cpu0 on 3333 +Info : Listening on port 3333 for gdb connections +requesting target halt and executing a soft reset +Info : Listening on port 6666 for tcl connections +Info : Listening on port 4444 for telnet connections +``` + +From this point on attach a gdb connection and debug the board as usual. + +*NOTE: You may need to add your boards FPGA ID to line [21] of Briey.cfg, simply append it to the other expected ids using: `-expected-id `. The IDs for the DE1-SoC and DE0 have already been added.* \ No newline at end of file diff --git a/src/main/scala/vexriscv/plugin/DebugPlugin.scala b/src/main/scala/vexriscv/plugin/DebugPlugin.scala index 4d0cbac1..d62c4de4 100644 --- a/src/main/scala/vexriscv/plugin/DebugPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DebugPlugin.scala @@ -1,7 +1,7 @@ package vexriscv.plugin import spinal.lib.com.jtag.{Jtag, JtagTapInstructionCtrl} -import spinal.lib.system.debugger.{JtagBridge, JtagBridgeNoTap, SystemDebugger, SystemDebuggerConfig, SystemDebuggerMemBus} +import spinal.lib.system.debugger.{JtagBridge, JtagBridgeNoTap, VJtagBridge, SystemDebugger, SystemDebuggerConfig, SystemDebuggerMemBus} import vexriscv.plugin.IntAluPlugin.{ALU_CTRL, AluCtrlEnum} import vexriscv._ import vexriscv.ip._ @@ -164,6 +164,20 @@ case class DebugExtensionBus() extends Bundle with IMasterSlave{ debugger.io.remote <> jtagBridge.io.remote debugger.io.mem <> this.from(debugger.io.mem.c) } + + def fromVJtag() : Unit = { + val jtagConfig = SystemDebuggerConfig( + memAddressWidth = 32, + memDataWidth = 32, + remoteCmdWidth = 1 + ) + + val jtagBridge = new VJtagBridge(jtagConfig) + + val debugger = new SystemDebugger(jtagConfig) + debugger.io.remote <> jtagBridge.io.remote + debugger.io.mem <> this.from(debugger.io.mem.c) + } } case class DebugExtensionIo() extends Bundle with IMasterSlave{ From 5a8cdee884a9866b29a17be3eafe423a16e83634 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 21 Nov 2022 11:55:05 +0100 Subject: [PATCH 814/951] Fix CsrPlugin dcsr.stepie --- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 40f6a6ec..25165987 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -1231,7 +1231,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep code.addTag(Verilator.public) if(withPrivilegedDebug) { - valid clearWhen(!debug.dcsr.stepie) + valid clearWhen(debug.dcsr.step && !debug.dcsr.stepie) valid setWhen(debug.doHalt) } } From 572ca3fcfa10e1f57ccf4f380711241e0533721e Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 21 Nov 2022 14:01:28 +0100 Subject: [PATCH 815/951] Privileged debug fake maskmax to 31 --- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 25165987..0598d8bd 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -895,6 +895,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep csrrw(CSR.TDATA1, read, 2 -> execute , 3 -> u, 4-> s, 6 -> m, 32 - 5 -> dmode, 12 -> action) csrr(CSR.TDATA1, read, 32 - 4 -> tpe) + csrr(CSR.TDATA1, read, 20 -> B"011111") //TODO action sizelo timing select sizehi maskmax } @@ -1631,10 +1632,14 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep } } -// Component.toplevel.rework{ -// out(CombInit(debug.running.pull())).setName("debug0") -// out(CombInit(pipeline.decode.arbitration.isFiring.pull())).setName("debug1") -// } + val csrs = (0x7A0 to 0x7A5) + val miaouRead = csrs.map(v => isReading(v)).orR + val miaouWrite = csrs.map(v => isWriting(v)).orR + + Component.toplevel.rework{ + out(CombInit(miaouRead.pull())).setName("debug0") + out(CombInit(miaouWrite.pull())).setName("debug1") + } } } } From a25ae96d33a4fe4066756666ca711fbe8433d5a7 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 21 Nov 2022 14:02:35 +0100 Subject: [PATCH 816/951] comment debug code --- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 0598d8bd..928fe07a 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -1632,14 +1632,14 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep } } - val csrs = (0x7A0 to 0x7A5) - val miaouRead = csrs.map(v => isReading(v)).orR - val miaouWrite = csrs.map(v => isWriting(v)).orR - - Component.toplevel.rework{ - out(CombInit(miaouRead.pull())).setName("debug0") - out(CombInit(miaouWrite.pull())).setName("debug1") - } +// val csrs = (0x7A0 to 0x7A5) +// val miaouRead = csrs.map(v => isReading(v)).orR +// val miaouWrite = csrs.map(v => isWriting(v)).orR +// +// Component.toplevel.rework{ +// out(CombInit(miaouRead.pull())).setName("debug0") +// out(CombInit(miaouWrite.pull())).setName("debug1") +// } } } } From eafeb5fe493e5cdf9523f565a17be090724ec6c4 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 28 Nov 2022 11:04:02 +0100 Subject: [PATCH 817/951] Add EmbeddedRiscvJtag.debugCd --- src/main/scala/vexriscv/TestsWorkspace.scala | 1 + .../demo/GenFullWithRiscvPrivilegedDebugJtag.scala | 1 + src/main/scala/vexriscv/demo/SynthesisBench.scala | 1 + src/main/scala/vexriscv/plugin/EmbeddedRiscvJtag.scala | 8 +++++--- src/test/cpp/regression/main.cpp | 1 + 5 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/main/scala/vexriscv/TestsWorkspace.scala b/src/main/scala/vexriscv/TestsWorkspace.scala index f102d81b..32645db1 100644 --- a/src/main/scala/vexriscv/TestsWorkspace.scala +++ b/src/main/scala/vexriscv/TestsWorkspace.scala @@ -152,6 +152,7 @@ object TestsWorkspace { version = 1, idle = 7 ), + debugCd = ClockDomain.current.copy(reset = Bool().setName("debugReset")), withTunneling = false, withTap = true ) diff --git a/src/main/scala/vexriscv/demo/GenFullWithRiscvPrivilegedDebugJtag.scala b/src/main/scala/vexriscv/demo/GenFullWithRiscvPrivilegedDebugJtag.scala index e6496b11..7dd17dda 100644 --- a/src/main/scala/vexriscv/demo/GenFullWithRiscvPrivilegedDebugJtag.scala +++ b/src/main/scala/vexriscv/demo/GenFullWithRiscvPrivilegedDebugJtag.scala @@ -82,6 +82,7 @@ object GenFullWithRiscvPrivilegedDebugJtag extends App{ version = 1, idle = 7 ), + debugCd = ClockDomain.current.copy(reset = Bool().setName("debugReset")), withTap = true, withTunneling = false ), diff --git a/src/main/scala/vexriscv/demo/SynthesisBench.scala b/src/main/scala/vexriscv/demo/SynthesisBench.scala index 7a1ff357..d0188194 100644 --- a/src/main/scala/vexriscv/demo/SynthesisBench.scala +++ b/src/main/scala/vexriscv/demo/SynthesisBench.scala @@ -483,6 +483,7 @@ object VexRiscvCustomSynthesisBench { version = 1, idle = 7 ), + debugCd = ClockDomain.current.copy(reset = Bool().setName("debugReset")), withTunneling = false, withTap = true )).setDefinitionName(getRtlPath().split("\\.").head)) diff --git a/src/main/scala/vexriscv/plugin/EmbeddedRiscvJtag.scala b/src/main/scala/vexriscv/plugin/EmbeddedRiscvJtag.scala index c75c4d1e..3366e726 100644 --- a/src/main/scala/vexriscv/plugin/EmbeddedRiscvJtag.scala +++ b/src/main/scala/vexriscv/plugin/EmbeddedRiscvJtag.scala @@ -13,6 +13,7 @@ import vexriscv._ class EmbeddedRiscvJtag(var p : DebugTransportModuleParameter, + var debugCd : ClockDomain = null, var withTap : Boolean = true, var withTunneling : Boolean = false ) extends Plugin[VexRiscv] with VexRiscvRegressionArg{ @@ -24,16 +25,17 @@ class EmbeddedRiscvJtag(var p : DebugTransportModuleParameter, var jtagInstruction : JtagTapInstructionCtrl = null var ndmreset : Bool = null -// val debugCd = Handle[ClockDomain].setName("debugCd") -// val noTapCd = Handle[ClockDomain].setName("jtagCd") + + def setDebugCd(cd : ClockDomain) : this.type = {debugCd = cd; this} override def setup(pipeline: VexRiscv): Unit = { jtag = withTap generate slave(Jtag()).setName("jtag") jtagInstruction = !withTap generate slave(JtagTapInstructionCtrl()).setName("jtagInstruction") ndmreset = out(Bool()).setName("ndmreset") + assert(debugCd != null, "You need to set the debugCd of the VexRiscv EmbeddedRiscvJtag.") } - override def build(pipeline: VexRiscv): Unit = { + override def build(pipeline: VexRiscv): Unit = debugCd{ val XLEN = 32 val dm = DebugModule( DebugModuleParameter( diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 0c3fdd3f..67dff411 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -3150,6 +3150,7 @@ void Workspace::fillSimELements(){ #endif #ifdef RISCV_JTAG simElements.push_back(new Jtag(&top->jtag_tms, &top->jtag_tdi, &top->jtag_tdo, &top->jtag_tck, 4)); + simElements.push_back(new VexRiscvJtag(this)); #endif #ifdef VEXRISCV_JTAG simElements.push_back(new Jtag(&top->jtag_tms, &top->jtag_tdi, &top->jtag_tdo, &top->jtag_tck, 4)); From fb084327dafb28aacdeaf368caa61042c25ad075 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 28 Nov 2022 16:30:47 +0100 Subject: [PATCH 818/951] Add VexRiscvBmbGenerator CsrPlugin withPrivilegedDebug assert --- src/main/scala/vexriscv/VexRiscvBmbGenerator.scala | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/VexRiscvBmbGenerator.scala b/src/main/scala/vexriscv/VexRiscvBmbGenerator.scala index 2492b1c0..7468c85c 100644 --- a/src/main/scala/vexriscv/VexRiscvBmbGenerator.scala +++ b/src/main/scala/vexriscv/VexRiscvBmbGenerator.scala @@ -143,7 +143,10 @@ case class VexRiscvBmbGenerator()(implicit interconnectSmp: BmbInterconnectGener softwareInterrupt load plugin.softwareInterrupt if (plugin.config.supervisorGen) externalSupervisorInterrupt load plugin.externalInterruptS withDebug.get match { - case DEBUG_RISCV => debugRiscv <> plugin.debugBus + case DEBUG_RISCV => { + assert(plugin.debugBus != null, "You need to enable CsrPluginConfig.withPrivilegedDebug") + debugRiscv <> plugin.debugBus + } case _ => } } From 773f268f37975cc857a5922906c0895a3d85355b Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 1 Dec 2022 12:04:13 +0100 Subject: [PATCH 819/951] Fix FPU test syntax --- src/test/scala/vexriscv/ip/fpu/FpuTest.scala | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala index 11182acc..fbcec746 100644 --- a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala +++ b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala @@ -265,7 +265,7 @@ class FpuTest extends AnyFunSuite{ def loadRaw(rd : Int, value : BigInt, format : FpuFormat.E): Unit ={ cmdAdd {cmd => - cmd.opcode #= cmd.opcode.spinalEnum.LOAD + cmd.opcode #= cmd.p.Opcode.LOAD cmd.rs1.randomize() cmd.rs2.randomize() cmd.rs3.randomize() @@ -278,7 +278,7 @@ class FpuTest extends AnyFunSuite{ cmd.write #= true cmd.rd #= rd cmd.value #= value - cmd.opcode #= cmd.opcode.spinalEnum.LOAD + cmd.opcode #= cmd.p.Opcode.LOAD } } @@ -293,7 +293,7 @@ class FpuTest extends AnyFunSuite{ def storeRaw(rs : Int, format : FpuFormat.E)(body : FpuRsp => Unit): Unit ={ cmdAdd {cmd => - cmd.opcode #= cmd.opcode.spinalEnum.STORE + cmd.opcode #= cmd.p.Opcode.STORE cmd.rs1.randomize() cmd.rs2 #= rs cmd.rs3.randomize() @@ -395,7 +395,7 @@ class FpuTest extends AnyFunSuite{ def i2f(rd : Int, value : Int, signed : Boolean, rounding : FpuRoundMode.E, format : FpuFormat.E): Unit ={ cmdAdd {cmd => - cmd.opcode #= cmd.opcode.spinalEnum.I2F + cmd.opcode #= cmd.p.Opcode.I2F cmd.rs1.randomize() cmd.rs2.randomize() cmd.rs3.randomize() @@ -414,7 +414,7 @@ class FpuTest extends AnyFunSuite{ def fmv_x_w(rs1 : Int)(body : Float => Unit): Unit ={ cmdAdd {cmd => - cmd.opcode #= cmd.opcode.spinalEnum.FMV_X_W + cmd.opcode #= cmd.p.Opcode.FMV_X_W cmd.rs1 #= rs1 cmd.rs2.randomize() cmd.rs3.randomize() @@ -428,7 +428,7 @@ class FpuTest extends AnyFunSuite{ def fmv_w_x(rd : Int, value : Int): Unit ={ cmdAdd {cmd => - cmd.opcode #= cmd.opcode.spinalEnum.FMV_W_X + cmd.opcode #= cmd.p.Opcode.FMV_W_X cmd.rs1.randomize() cmd.rs2.randomize() cmd.rs3.randomize() @@ -447,7 +447,7 @@ class FpuTest extends AnyFunSuite{ def minMax(rd : Int, rs1 : Int, rs2 : Int, arg : Int, format : FpuFormat.E): Unit ={ cmdAdd {cmd => - cmd.opcode #= cmd.opcode.spinalEnum.MIN_MAX + cmd.opcode #= cmd.p.Opcode.MIN_MAX cmd.rs1 #= rs1 cmd.rs2 #= rs2 cmd.rs3.randomize() From b86047901ae55a3ea0dc892acf1e72c2f0012118 Mon Sep 17 00:00:00 2001 From: buncram Date: Mon, 19 Dec 2022 19:03:33 +0800 Subject: [PATCH 820/951] add flag to expose SATP externally --- .../scala/vexriscv/plugin/MmuPlugin.scala | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/MmuPlugin.scala b/src/main/scala/vexriscv/plugin/MmuPlugin.scala index c984b035..73efaf04 100644 --- a/src/main/scala/vexriscv/plugin/MmuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/MmuPlugin.scala @@ -41,7 +41,9 @@ case class MmuPortConfig(portTlbSize : Int, latency : Int = 0, earlyRequireMmuLo class MmuPlugin(ioRange : UInt => Bool, virtualRange : UInt => Bool = address => True, // allowUserIo : Boolean = false, - enableMmuInMachineMode : Boolean = false) extends Plugin[VexRiscv] with MemoryTranslator { + enableMmuInMachineMode : Boolean = false, + exportSatp: Boolean = false + ) extends Plugin[VexRiscv] with MemoryTranslator { var dBusAccess : DBusAccess = null val portsInfo = ArrayBuffer[MmuPort]() @@ -91,10 +93,18 @@ class MmuPlugin(ioRange : UInt => Bool, val sum, mxr, mprv = RegInit(False) mprv clearWhen(csrService.xretAwayFromMachine) } - val satp = new Area { - val mode = RegInit(False) - val asid = Reg(Bits(9 bits)) - val ppn = Reg(UInt(20 bits)) + val satp = if(exportSatp) { + new Area { + val mode = out(RegInit(False)) + val asid = out(Reg(Bits(9 bits))) + val ppn = out(Reg(UInt(20 bits))) + } + } else { + new Area { + val mode = RegInit(False) + val asid = Reg(Bits(9 bits)) + val ppn = Reg(UInt(20 bits)) + } } for(offset <- List(CSR.MSTATUS, CSR.SSTATUS)) csrService.rw(offset, 19 -> status.mxr, 18 -> status.sum, 17 -> status.mprv) From bf3521f86a424736168fec1741e4a187fc758cad Mon Sep 17 00:00:00 2001 From: bunnie Date: Tue, 20 Dec 2022 19:25:47 +0800 Subject: [PATCH 821/951] Expand SATP register to 22 bits per spec Vex only implements a 32-bit PA which does not take advantage of the potetnial 32-bit space in Sv32 mode. Very reasonably, Vex simply discards the top two unused bits. However, the spec does require that the register occupy all 22 bits and it is possible for the OS to use the extra bits up top for some bookkeeping purpose. This commit proposes to expand the register to occupy the full 22 bits in case an OS is written to utilize the full width of the register as written in the spec. --- src/main/scala/vexriscv/plugin/MmuPlugin.scala | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/MmuPlugin.scala b/src/main/scala/vexriscv/plugin/MmuPlugin.scala index c984b035..c17a3879 100644 --- a/src/main/scala/vexriscv/plugin/MmuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/MmuPlugin.scala @@ -94,7 +94,8 @@ class MmuPlugin(ioRange : UInt => Bool, val satp = new Area { val mode = RegInit(False) val asid = Reg(Bits(9 bits)) - val ppn = Reg(UInt(20 bits)) + // Bottom 20 bits are used in implementation, but top 2 bits are still stored for OS use. + val ppn = Reg(UInt(22 bits)) } for(offset <- List(CSR.MSTATUS, CSR.SSTATUS)) csrService.rw(offset, 19 -> status.mxr, 18 -> status.sum, 17 -> status.mprv) @@ -233,7 +234,8 @@ class MmuPlugin(ioRange : UInt => Bool, } is(State.L1_CMD){ dBusAccess.cmd.valid := True - dBusAccess.cmd.address := csr.satp.ppn @@ vpn(1) @@ U"00" + // RV spec allows for 34-bit phys address in Sv32 mode; we only implement 32 bits and ignore the top 2 bits of satp. + dBusAccess.cmd.address := csr.satp.ppn(19 downto 0) @@ vpn(1) @@ U"00" when(dBusAccess.cmd.ready){ state := State.L1_RSP } From df52fab7d1422c4ddeb964dbb96445150bf3b0b4 Mon Sep 17 00:00:00 2001 From: chiangkd Date: Sat, 24 Dec 2022 20:41:57 +0800 Subject: [PATCH 822/951] Fix incorrect comment --- src/test/cpp/custom/atomic/src/crt.S | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/cpp/custom/atomic/src/crt.S b/src/test/cpp/custom/atomic/src/crt.S index 1462dd25..ef5cb411 100644 --- a/src/test/cpp/custom/atomic/src/crt.S +++ b/src/test/cpp/custom/atomic/src/crt.S @@ -15,7 +15,7 @@ trap_entry: csrr x29, mstatus and x29, x29, 0x080 beqz x29, notExternalInterrupt - li x29, 0x1800 //000 disable interrupts + li x29, 0x1800 //1800 disable interrupts csrw mstatus,x29 mret @@ -227,7 +227,7 @@ test7: sw a3, 0(a0) li x29, 0x800 //800 external interrupts csrw mie,x29 - li x29, 0x1808 //008 enable interrupts + li x29, 0x1808 //1808 enable interrupts lr.w a5, (a0) csrw mstatus,x29 //Enable external interrupt (will jump instantly due to testbench setup) nop From 6650d0549da23197a99f0c18334af85a02a10f49 Mon Sep 17 00:00:00 2001 From: chiangkd Date: Thu, 12 Jan 2023 20:51:58 +0800 Subject: [PATCH 823/951] Fix invalid hyperlink --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5a25ca3f..28bace2e 100644 --- a/README.md +++ b/README.md @@ -319,7 +319,7 @@ If you want to get more information about how all this JTAG / GDB stuff work, yo ## Briey SoC As a demonstration, a SoC named Briey is implemented in `src/main/scala/vexriscv/demo/Briey.scala`. This SoC is very similar to -the [Pinsec SoC](https://spinalhdl.github.io/SpinalDoc-RTD/SpinalHDL/Legacy/pinsec/hardware_toplevel.html#): +the [Pinsec SoC](https://spinalhdl.github.io/SpinalDoc-RTD/v1.3.1/SpinalHDL/Legacy/pinsec/hardware_toplevel.html): ![Briey SoC](assets/brieySoc.png?raw=true "") From 2297f8aea0133f3304bdc6493bdb157d66fce63d Mon Sep 17 00:00:00 2001 From: buncram Date: Mon, 16 Jan 2023 02:16:25 +0800 Subject: [PATCH 824/951] also need to expose privilege state turns out SATP is not enough to figure out what code you're running, because the kernel code is mapped into all userspace's virtual memory areas. You also need the privilege state to be exported. This creates an option to export those bits. --- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 928fe07a..c2ab72a6 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -82,6 +82,7 @@ case class CsrPluginConfig( deterministicInteruptionEntry : Boolean = false, //Only used for simulatation purposes wfiOutput : Boolean = false, withPrivilegedDebug : Boolean = false, //For the official RISC-V debug spec implementation + exportPrivilege : Boolean = false, var debugTriggers : Int = 2 ){ assert(!ucycleAccess.canWrite) @@ -612,6 +613,9 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep contextSwitching = Bool().setName("contextSwitching") privilege = UInt(2 bits).setName("CsrPlugin_privilege") + if (exportPrivilege) { + val export_priv = out(privilege) + } forceMachineWire = False if(catchIllegalAccess || ecallGen || withEbreak) From ed5babaaab9daac276806c0ca0ba98e5c8c5df62 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 16 Jan 2023 12:39:55 +0100 Subject: [PATCH 825/951] shorter syntax on privilege export --- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index c2ab72a6..8eeb8983 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -613,9 +613,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep contextSwitching = Bool().setName("contextSwitching") privilege = UInt(2 bits).setName("CsrPlugin_privilege") - if (exportPrivilege) { - val export_priv = out(privilege) - } + if (exportPrivilege) out(privilege) forceMachineWire = False if(catchIllegalAccess || ecallGen || withEbreak) From 0aa6e0573d6f69bacbe6006ea801944e19175b88 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 16 Jan 2023 12:43:01 +0100 Subject: [PATCH 826/951] shorter satp export --- src/main/scala/vexriscv/plugin/MmuPlugin.scala | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/MmuPlugin.scala b/src/main/scala/vexriscv/plugin/MmuPlugin.scala index 423b1ce3..f8bd88fc 100644 --- a/src/main/scala/vexriscv/plugin/MmuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/MmuPlugin.scala @@ -93,18 +93,12 @@ class MmuPlugin(ioRange : UInt => Bool, val sum, mxr, mprv = RegInit(False) mprv clearWhen(csrService.xretAwayFromMachine) } - val satp = if(exportSatp) { - new Area { - val mode = out(RegInit(False)) - val asid = out(Reg(Bits(9 bits))) - // Bottom 20 bits are used in implementation, but top 2 bits are still stored for OS use. - val ppn = out(Reg(UInt(22 bits))) - } - } else { - new Area { - val mode = RegInit(False) - val asid = Reg(Bits(9 bits)) - val ppn = Reg(UInt(22 bits)) + val satp = new Area { + val mode = RegInit(False) + val asid = Reg(Bits(9 bits)) + val ppn = Reg(UInt(22 bits)) // Bottom 20 bits are used in implementation, but top 2 bits are still stored for OS use. + if(exportSatp) { + out(mode, asid, ppn) } } From aea2e90d1ed2bbf00d1f1d3ea8dfe2fd1f3a19fb Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 16 Jan 2023 17:58:23 +0100 Subject: [PATCH 827/951] Upgrade to SBT 1.6.0 --- project/build.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/build.properties b/project/build.properties index 0b2e09c5..1e70b0c1 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=1.4.7 +sbt.version=1.6.0 From 7d3a862183f45a4c15bed13fd269c93d01304cdd Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 16 Jan 2023 18:10:51 +0100 Subject: [PATCH 828/951] Fix Litex cluster scopt update --- src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala index f8e9dcb9..3454577b 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala @@ -143,7 +143,7 @@ object VexRiscvLitexSmpClusterCmdGen extends App { opt[String]("rvc") action { (v, c) => rvc = v.toBoolean } opt[String]("itlb-size") action { (v, c) => iTlbSize = v.toInt } opt[String]("dtlb-size") action { (v, c) => dTlbSize = v.toInt } - }.parse(args)) + }.parse(args, Unit).nonEmpty) val coherency = coherentDma || cpuCount > 1 def parameter = VexRiscvLitexSmpClusterParameter( From 2bc6e70f03edcacd875a4ec93714dc023ae136d3 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 18 Jan 2023 15:19:33 +0100 Subject: [PATCH 829/951] Fix RVC decompressor don't care #296 --- src/main/scala/vexriscv/plugin/Misc.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/plugin/Misc.scala b/src/main/scala/vexriscv/plugin/Misc.scala index 73d90e69..ce9370f0 100644 --- a/src/main/scala/vexriscv/plugin/Misc.scala +++ b/src/main/scala/vexriscv/plugin/Misc.scala @@ -12,7 +12,7 @@ object RvcDecompressor{ } def apply(i : Bits, rvf : Boolean, rvd : Boolean): Bits ={ - val ret = Bits(32 bits).assignDontCare() + val ret = B(0, 32 bits) val rch = B"01" ## i(9 downto 7) val rcl = B"01" ## i(4 downto 2) From e83bc5312ec54254fd929c561db4ddfcd6dbe746 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 18 Jan 2023 15:19:33 +0100 Subject: [PATCH 830/951] Fix RVC decompressor don't care #296 --- src/main/scala/vexriscv/plugin/Misc.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/plugin/Misc.scala b/src/main/scala/vexriscv/plugin/Misc.scala index 73d90e69..ce9370f0 100644 --- a/src/main/scala/vexriscv/plugin/Misc.scala +++ b/src/main/scala/vexriscv/plugin/Misc.scala @@ -12,7 +12,7 @@ object RvcDecompressor{ } def apply(i : Bits, rvf : Boolean, rvd : Boolean): Bits ={ - val ret = Bits(32 bits).assignDontCare() + val ret = B(0, 32 bits) val rch = B"01" ## i(9 downto 7) val rcl = B"01" ## i(4 downto 2) From fc9a9d25ed6c5e02b7811fb11a278bfa04cc408e Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 6 Feb 2023 11:43:49 +0100 Subject: [PATCH 831/951] sync --- src/main/scala/vexriscv/TestsWorkspace.scala | 1 + src/main/scala/vexriscv/demo/Linux.scala | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/src/main/scala/vexriscv/TestsWorkspace.scala b/src/main/scala/vexriscv/TestsWorkspace.scala index 32645db1..39389214 100644 --- a/src/main/scala/vexriscv/TestsWorkspace.scala +++ b/src/main/scala/vexriscv/TestsWorkspace.scala @@ -128,6 +128,7 @@ object TestsWorkspace { // export IMAGES=/media/data/open/SaxonSoc/artyA7SmpUpdate/buildroot-regression/buildroot-build/images // make clean all IBUS=CACHED IBUS_DATA_WIDTH=64 COMPRESSED=no DBUS=CACHED DBUS_LOAD_DATA_WIDTH=64 DBUS_STORE_DATA_WIDTH=64 LRSC=yes AMO=yes SUPERVISOR=yes DBUS_EXCLUSIVE=yes DBUS_INVALIDATE=yes MUL=yes DIV=yes RVF=yes RVD=yes DEBUG_PLUGIN=no LINUX_SOC_SMP=yes EMULATOR=$IMAGES/fw_jump.bin VMLINUX=$IMAGES/Image DTB=$IMAGES/linux.dtb RAMDISK=$IMAGES/rootfs.cpio TRACE=yes REDO=1 DEBUG=ye WITH_USER_IO=no FLOW_INFO=no TRACE_START=565000000000ll SEED=45 + // make clean all IBUS=CACHED IBUS_DATA_WIDTH=64 COMPRESSED=no DBUS=CACHED DBUS_LOAD_DATA_WIDTH=64 DBUS_STORE_DATA_WIDTH=64 LRSC=yes AMO=yes SUPERVISOR=yes DBUS_EXCLUSIVE=yes DBUS_INVALIDATE=yes MUL=yes DIV=yes RVF=yes RVD=yes DEBUG_PLUGIN=no RUN_HEX=/media/data/open/VexRiscv/src/test/cpp/raw/play/build/play.hex TRACE=yes val config = VexRiscvSmpClusterGen.vexRiscvConfig( hartId = 0, ioRange = _ (31 downto 28) === 0xF, diff --git a/src/main/scala/vexriscv/demo/Linux.scala b/src/main/scala/vexriscv/demo/Linux.scala index 8508a676..2cdc8f3a 100644 --- a/src/main/scala/vexriscv/demo/Linux.scala +++ b/src/main/scala/vexriscv/demo/Linux.scala @@ -130,6 +130,18 @@ cd .. make clean run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD DHRYSTONE=yes SUPERVISOR=yes MMU=yes CSR=yes COMPRESSED=no MUL=yes DIV=yes LRSC=yes AMO=yes REDO=10 TRACE=no COREMARK=yes LINUX_REGRESSION=yes RUN_HEX=~/pro/riscv/zephyr/samples/synchronization/build/zephyr/zephyr.hex + +All in one way to run : +export ARCH_LINUX=rv32ima +export VMLINUX=../../resources/VexRiscvRegressionData/sim/linux/${ARCH_LINUX}/Image +export DTB=../../resources/VexRiscvRegressionData/sim/linux/${ARCH_LINUX}/rv32.dtb +export RAMDISK=../../resources/VexRiscvRegressionData/sim/linux/${ARCH_LINUX}/rootfs.cpio +export EMULATOR=../../resources/VexRiscvRegressionData/sim/linux/emulator/emulator.bin + +make clean run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD SUPERVISOR=yes CSR=yes DEBUG_PLUGIN=STD COMPRESSED=no LRSC=yes AMO=yes REDO=0 DHRYSTONE=no LINUX_SOC=yes WITH_USER_IO=yes TRACE=no FLOW_INFO=no + + + */ From 9acc5ddc1c444aa2da9100b1edc99eb5c1dc6b98 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 6 Feb 2023 11:44:44 +0100 Subject: [PATCH 832/951] Fix FPU access trap on fs = 0 #297 --- src/main/scala/vexriscv/plugin/FpuPlugin.scala | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/plugin/FpuPlugin.scala b/src/main/scala/vexriscv/plugin/FpuPlugin.scala index b3373e35..894d426a 100644 --- a/src/main/scala/vexriscv/plugin/FpuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/FpuPlugin.scala @@ -233,10 +233,15 @@ class FpuPlugin(externalFpu : Boolean = false, decode plug new Area{ import decode._ + val trap = decode.input(FPU_ENABLE) && csr.fs === 0 && !stagesFromExecute.map(_.arbitration.isValid).orR + when(trap){ + pipeline.service(classOf[DecoderService]).forceIllegal() + } + //Maybe it might be better to not fork before fire to avoid RF stall on commits val forked = Reg(Bool) setWhen(port.cmd.fire) clearWhen(!arbitration.isStuck) init(False) - val hazard = csr.pendings.msb || csr.csrActive + val hazard = csr.pendings.msb || csr.csrActive || csr.fs === 0 arbitration.haltItself setWhen(arbitration.isValid && input(FPU_ENABLE) && hazard) arbitration.haltItself setWhen(port.cmd.isStall) From cbc89093b38db993ac1dd2f3f14de7eaf24e59be Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 7 Feb 2023 10:18:08 +0100 Subject: [PATCH 833/951] fpu csr access on fs===0 now also trap --- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 6 +++++- src/main/scala/vexriscv/plugin/FpuPlugin.scala | 8 ++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 928fe07a..d936edc5 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -357,6 +357,7 @@ case class CsrMapping() extends Area with CsrInterface { val readDataSignal, readDataInit, writeDataSignal = Bits(32 bits) val allowCsrSignal = False val hazardFree = Bool() + val doForceFailCsr = False readDataSignal := readDataInit def addMappingAt(address : Int,that : Any) = mapping.getOrElseUpdate(address,new ArrayBuffer[Any]) += that @@ -377,6 +378,7 @@ case class CsrMapping() extends Area with CsrInterface { override def writeData() = writeDataSignal override def allowCsr() = allowCsrSignal := True override def isHazardFree() = hazardFree + override def forceFailCsr() = doForceFailCsr := True } @@ -399,6 +401,7 @@ trait CsrInterface{ def onAnyWrite(body: => Unit) : Unit def allowCsr() : Unit //In case your csr do not use the regular API with csrAddress but is implemented using "side channels", you can call that if the current csr is implemented def isHazardFree() : Bool // You should not have any side effect nor use readData() until this return True + def forceFailCsr() : Unit def r2w(csrAddress : Int, bitOffset : Int,that : Data): Unit @@ -539,6 +542,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep override def readData() = csrMapping.readData() override def writeData() = csrMapping.writeData() override def isHazardFree() = csrMapping.isHazardFree() + override def forceFailCsr() = csrMapping.forceFailCsr() override def setup(pipeline: VexRiscv): Unit = { import pipeline.config._ @@ -1619,7 +1623,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep illegalAccess clearWhen(csrMapping.allowCsrSignal) - val forceFail = False + val forceFail = CombInit(csrMapping.doForceFailCsr) forceFail setWhen(privilege < csrAddress(9 downto 8).asUInt) if(withPrivilegedDebug) forceFail setWhen(!debugMode && csrAddress >> 4 === 0x7B) when(forceFail){ diff --git a/src/main/scala/vexriscv/plugin/FpuPlugin.scala b/src/main/scala/vexriscv/plugin/FpuPlugin.scala index 894d426a..8ea478eb 100644 --- a/src/main/scala/vexriscv/plugin/FpuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/FpuPlugin.scala @@ -228,6 +228,14 @@ class FpuPlugin(externalFpu : Boolean = false, service.r(CSR.SSTATUS, 31, sd) service.r(CSR.MSTATUS, 31, sd) + + when(fs === 0) { + for (csr <- List(CSR.FRM, CSR.FCSR, CSR.FFLAGS)) { + service.during(csr) { + service.forceFailCsr() + } + } + } } decode plug new Area{ From 692f604dd5ee738cef453377a6be1daa0ac5f668 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 8 Feb 2023 11:28:21 +0100 Subject: [PATCH 834/951] Fix VexRiscvSmpClusterGen without linux debug minimal features --- src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index 084d5235..bf805e8c 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -207,12 +207,12 @@ object VexRiscvSmpClusterGen { } else { CsrPluginConfig( catchIllegalAccess = true, - mvendorid = null, - marchid = null, - mimpid = null, + mvendorid = 0, + marchid = 0, + mimpid = 0, mhartid = hartId, misaExtensionsInit = misa, - misaAccess = if(forceMisa) CsrAccess.WRITE_ONLY else CsrAccess.NONE, + misaAccess = if(forceMisa) CsrAccess.READ_ONLY else CsrAccess.NONE, mtvecAccess = CsrAccess.READ_WRITE, mtvecInit = null, mepcAccess = CsrAccess.READ_WRITE, From 3ae51cdeb84e3d3686f3ff4d2b3739276166cdd6 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 8 Feb 2023 14:44:04 +0100 Subject: [PATCH 835/951] Fix fpu csr access on fs===0 now also trap --- src/main/scala/vexriscv/plugin/FpuPlugin.scala | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/FpuPlugin.scala b/src/main/scala/vexriscv/plugin/FpuPlugin.scala index 8ea478eb..69897539 100644 --- a/src/main/scala/vexriscv/plugin/FpuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/FpuPlugin.scala @@ -229,13 +229,15 @@ class FpuPlugin(externalFpu : Boolean = false, service.r(CSR.SSTATUS, 31, sd) service.r(CSR.MSTATUS, 31, sd) - when(fs === 0) { - for (csr <- List(CSR.FRM, CSR.FCSR, CSR.FFLAGS)) { - service.during(csr) { - service.forceFailCsr() - } + val accessFpuCsr = False + for (csr <- List(CSR.FRM, CSR.FCSR, CSR.FFLAGS)) { + service.during(csr) { + accessFpuCsr := True } } + when(accessFpuCsr && fs === 0) { + service.forceFailCsr() + } } decode plug new Area{ From 33e820bdf994cf0b99abb0439b82e2c69496a9e4 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 8 Feb 2023 15:16:53 +0100 Subject: [PATCH 836/951] FPU now implement a less pessismitic dirty logic --- src/main/scala/vexriscv/ip/fpu/Interface.scala | 1 + src/main/scala/vexriscv/plugin/FpuPlugin.scala | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/ip/fpu/Interface.scala b/src/main/scala/vexriscv/ip/fpu/Interface.scala index 9338c35b..58cc017e 100644 --- a/src/main/scala/vexriscv/ip/fpu/Interface.scala +++ b/src/main/scala/vexriscv/ip/fpu/Interface.scala @@ -144,6 +144,7 @@ case class FpuParameter( withDouble : Boolean, case class FpuFlags() extends Bundle{ val NX, UF, OF, DZ, NV = Bool() + def any = List(NX, UF, OF, DZ, NV).orR } case class FpuCompletion() extends Bundle{ diff --git a/src/main/scala/vexriscv/plugin/FpuPlugin.scala b/src/main/scala/vexriscv/plugin/FpuPlugin.scala index 69897539..8df6fa81 100644 --- a/src/main/scala/vexriscv/plugin/FpuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/FpuPlugin.scala @@ -216,8 +216,8 @@ class FpuPlugin(externalFpu : Boolean = false, val fs = Reg(Bits(2 bits)) init(1) val sd = fs === 3 - when(stages.last.arbitration.isFiring && stages.last.input(FPU_ENABLE) && stages.last.input(FPU_OPCODE) =/= FpuOpcode.STORE){ - fs := 3 //DIRTY + when(port.completion.fire && (port.completion.written || port.completion.flags.any)){ + fs := 3 } when(List(CSR.FRM, CSR.FCSR, CSR.FFLAGS).map(id => service.isWriting(id)).orR){ fs := 3 @@ -298,6 +298,9 @@ class FpuPlugin(externalFpu : Boolean = false, when(!arbitration.isStuck && !arbitration.isRemoved){ csr.flags.NV setWhen(port.rsp.NV) csr.flags.NX setWhen(port.rsp.NX) + when(port.rsp.NV || port.rsp.NX){ + csr.fs := 3 + } } } when(!port.rsp.valid){ From d078297496b58b061a899a555effab7cc6069743 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sun, 19 Feb 2023 09:48:59 +0100 Subject: [PATCH 837/951] fix too early --- README.md | 36 ------------------------------------ 1 file changed, 36 deletions(-) diff --git a/README.md b/README.md index 034c734e..63ed33e6 100644 --- a/README.md +++ b/README.md @@ -1184,42 +1184,6 @@ Write Address 0x04 -> The OpenOCD port is here: -#### EmbeddedRiscvJtag - -VexRiscv also support the official RISC-V debug specification (Thanks Efinix for the funding !). - -To enable it, you need to add the EmbeddedRiscvJtag to the plugin list : - -```scala -new EmbeddedRiscvJtag( - p = DebugTransportModuleParameter( - addressWidth = 7, - version = 1, - idle = 7 - ), - withTunneling = false, - withTap = true -) -``` - -And turn on the withPrivilegedDebug option in the CsrPlugin config. - -Here is an example of openocd tcl script to connect : - -```tcl -# ADD HERE YOUR JTAG ADAPTER SETTINGS - -set _CHIPNAME riscv -jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x10002FFF - -set _TARGETNAME $_CHIPNAME.cpu - -target create $_TARGETNAME.0 riscv -chain-position $_TARGETNAME - -init -halt -``` - #### YamlPlugin This plugin offers a service to other plugins to generate a useful Yaml file describing the CPU configuration. It contains, for instance, the sequence of instructions required From c57da3c7dc71872251dae877c4fe5de7739d0366 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sun, 19 Feb 2023 09:50:41 +0100 Subject: [PATCH 838/951] fix too early --- README.md | 36 ------------------------------------ 1 file changed, 36 deletions(-) diff --git a/README.md b/README.md index 28bace2e..c7578c6f 100644 --- a/README.md +++ b/README.md @@ -1294,42 +1294,6 @@ Write Address 0x04 -> The OpenOCD port is here: -#### EmbeddedRiscvJtag - -VexRiscv also support the official RISC-V debug specification (Thanks Efinix for the funding !). - -To enable it, you need to add the EmbeddedRiscvJtag to the plugin list : - -```scala -new EmbeddedRiscvJtag( - p = DebugTransportModuleParameter( - addressWidth = 7, - version = 1, - idle = 7 - ), - withTunneling = false, - withTap = true -) -``` - -And turn on the withPrivilegedDebug option in the CsrPlugin config. - -Here is an example of openocd tcl script to connect : - -```tcl -# ADD HERE YOUR JTAG ADAPTER SETTINGS - -set _CHIPNAME riscv -jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x10002FFF - -set _TARGETNAME $_CHIPNAME.cpu - -target create $_TARGETNAME.0 riscv -chain-position $_TARGETNAME - -init -halt -``` - #### YamlPlugin This plugin offers a service to other plugins to generate a useful Yaml file describing the CPU configuration. It contains, for instance, the sequence of instructions required From 15a665af53d351e627ffd3c06630860b6e65a1f7 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sun, 19 Feb 2023 09:51:18 +0100 Subject: [PATCH 839/951] fix too early --- .../GenFullWithRiscvPrivilegedDebugJtag.scala | 102 ------------------ .../scala/vexriscv/demo/SynthesisBench.scala | 19 +--- 2 files changed, 2 insertions(+), 119 deletions(-) delete mode 100644 src/main/scala/vexriscv/demo/GenFullWithRiscvPrivilegedDebugJtag.scala diff --git a/src/main/scala/vexriscv/demo/GenFullWithRiscvPrivilegedDebugJtag.scala b/src/main/scala/vexriscv/demo/GenFullWithRiscvPrivilegedDebugJtag.scala deleted file mode 100644 index 7dd17dda..00000000 --- a/src/main/scala/vexriscv/demo/GenFullWithRiscvPrivilegedDebugJtag.scala +++ /dev/null @@ -1,102 +0,0 @@ -package vexriscv.demo - -import spinal.core._ -import spinal.lib.cpu.riscv.debug.DebugTransportModuleParameter -import vexriscv.ip.{DataCacheConfig, InstructionCacheConfig} -import vexriscv.plugin._ -import vexriscv.{VexRiscv, VexRiscvConfig, plugin} - -/** - * Created by spinalvm on 15.06.17. - */ -object GenFullWithRiscvPrivilegedDebugJtag extends App{ - def config = VexRiscvConfig( - plugins = List( - new IBusCachedPlugin( - prediction = DYNAMIC, - config = InstructionCacheConfig( - cacheSize = 4096, - bytePerLine =32, - wayCount = 1, - addressWidth = 32, - cpuDataWidth = 32, - memDataWidth = 32, - catchIllegalAccess = true, - catchAccessFault = true, - asyncTagMemory = false, - twoCycleRam = true, - twoCycleCache = true - ), - memoryTranslatorPortConfig = MmuPortConfig( - portTlbSize = 4 - ) - ), - new DBusCachedPlugin( - config = new DataCacheConfig( - cacheSize = 4096, - bytePerLine = 32, - wayCount = 1, - addressWidth = 32, - cpuDataWidth = 32, - memDataWidth = 32, - catchAccessError = true, - catchIllegal = true, - catchUnaligned = true - ), - memoryTranslatorPortConfig = MmuPortConfig( - portTlbSize = 6 - ) - ), - new MmuPlugin( - virtualRange = _(31 downto 28) === 0xC, - ioRange = _(31 downto 28) === 0xF - ), - new DecoderSimplePlugin( - catchIllegalInstruction = true - ), - new RegFilePlugin( - regFileReadyKind = plugin.SYNC, - zeroBoot = false - ), - new IntAluPlugin, - new SrcPlugin( - separatedAddSub = false, - executeInsertion = true - ), - new FullBarrelShifterPlugin, - new HazardSimplePlugin( - bypassExecute = true, - bypassMemory = true, - bypassWriteBack = true, - bypassWriteBackBuffer = true, - pessimisticUseSrc = false, - pessimisticWriteRegFile = false, - pessimisticAddressMatch = false - ), - new MulPlugin, - new DivPlugin, - new CsrPlugin(CsrPluginConfig.small(0x80000020l).copy(withPrivilegedDebug = true)), //withPrivilegedDebug is required - new EmbeddedRiscvJtag( - DebugTransportModuleParameter( - addressWidth = 7, - version = 1, - idle = 7 - ), - debugCd = ClockDomain.current.copy(reset = Bool().setName("debugReset")), - withTap = true, - withTunneling = false - ), - new BranchPlugin( - earlyBranch = false, - catchAddressMisaligned = true - ), - new YamlPlugin("cpu0.yaml") - ) - ) - - def cpu() = new VexRiscv( - config - ) - - SpinalVerilog(cpu()) -} diff --git a/src/main/scala/vexriscv/demo/SynthesisBench.scala b/src/main/scala/vexriscv/demo/SynthesisBench.scala index d0188194..d13645a1 100644 --- a/src/main/scala/vexriscv/demo/SynthesisBench.scala +++ b/src/main/scala/vexriscv/demo/SynthesisBench.scala @@ -473,22 +473,7 @@ object VexRiscvCustomSynthesisBench { cpu } - - val riscvDebug = new Rtl { - override def getName(): String = "riscvDebug" - override def getRtlPath(): String = "riscvDebug.v" - SpinalVerilog(gen(new CsrPlugin(CsrPluginConfig.smallest(0x80000000l).copy(withPrivilegedDebug = true)), new EmbeddedRiscvJtag( - p = DebugTransportModuleParameter( - addressWidth = 7, - version = 1, - idle = 7 - ), - debugCd = ClockDomain.current.copy(reset = Bool().setName("debugReset")), - withTunneling = false, - withTap = true - )).setDefinitionName(getRtlPath().split("\\.").head)) - } - + val vexDebug = new Rtl { override def getName(): String = "vexDebug" override def getRtlPath(): String = "vexDebug.v" @@ -499,7 +484,7 @@ object VexRiscvCustomSynthesisBench { // val rtls = List(twoStage, twoStageBarell, twoStageMulDiv, twoStageAll, smallestNoCsr, smallest, smallAndProductive, smallAndProductiveWithICache, fullNoMmuNoCache, noCacheNoMmuMaxPerf, fullNoMmuMaxPerf, fullNoMmu, full, linuxBalanced, linuxBalancedSmp) - val rtls = List(riscvDebug, vexDebug) + val rtls = List(vexDebug) // val rtls = List(smallest) val targets = XilinxStdTargets() ++ AlteraStdTargets() ++ IcestormStdTargets().take(1) From 366f09a14a4f908efead42b2097043d95fe783de Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sun, 19 Feb 2023 09:51:18 +0100 Subject: [PATCH 840/951] fix too early --- .../GenFullWithRiscvPrivilegedDebugJtag.scala | 102 ------------------ .../scala/vexriscv/demo/SynthesisBench.scala | 19 +--- 2 files changed, 2 insertions(+), 119 deletions(-) delete mode 100644 src/main/scala/vexriscv/demo/GenFullWithRiscvPrivilegedDebugJtag.scala diff --git a/src/main/scala/vexriscv/demo/GenFullWithRiscvPrivilegedDebugJtag.scala b/src/main/scala/vexriscv/demo/GenFullWithRiscvPrivilegedDebugJtag.scala deleted file mode 100644 index 7dd17dda..00000000 --- a/src/main/scala/vexriscv/demo/GenFullWithRiscvPrivilegedDebugJtag.scala +++ /dev/null @@ -1,102 +0,0 @@ -package vexriscv.demo - -import spinal.core._ -import spinal.lib.cpu.riscv.debug.DebugTransportModuleParameter -import vexriscv.ip.{DataCacheConfig, InstructionCacheConfig} -import vexriscv.plugin._ -import vexriscv.{VexRiscv, VexRiscvConfig, plugin} - -/** - * Created by spinalvm on 15.06.17. - */ -object GenFullWithRiscvPrivilegedDebugJtag extends App{ - def config = VexRiscvConfig( - plugins = List( - new IBusCachedPlugin( - prediction = DYNAMIC, - config = InstructionCacheConfig( - cacheSize = 4096, - bytePerLine =32, - wayCount = 1, - addressWidth = 32, - cpuDataWidth = 32, - memDataWidth = 32, - catchIllegalAccess = true, - catchAccessFault = true, - asyncTagMemory = false, - twoCycleRam = true, - twoCycleCache = true - ), - memoryTranslatorPortConfig = MmuPortConfig( - portTlbSize = 4 - ) - ), - new DBusCachedPlugin( - config = new DataCacheConfig( - cacheSize = 4096, - bytePerLine = 32, - wayCount = 1, - addressWidth = 32, - cpuDataWidth = 32, - memDataWidth = 32, - catchAccessError = true, - catchIllegal = true, - catchUnaligned = true - ), - memoryTranslatorPortConfig = MmuPortConfig( - portTlbSize = 6 - ) - ), - new MmuPlugin( - virtualRange = _(31 downto 28) === 0xC, - ioRange = _(31 downto 28) === 0xF - ), - new DecoderSimplePlugin( - catchIllegalInstruction = true - ), - new RegFilePlugin( - regFileReadyKind = plugin.SYNC, - zeroBoot = false - ), - new IntAluPlugin, - new SrcPlugin( - separatedAddSub = false, - executeInsertion = true - ), - new FullBarrelShifterPlugin, - new HazardSimplePlugin( - bypassExecute = true, - bypassMemory = true, - bypassWriteBack = true, - bypassWriteBackBuffer = true, - pessimisticUseSrc = false, - pessimisticWriteRegFile = false, - pessimisticAddressMatch = false - ), - new MulPlugin, - new DivPlugin, - new CsrPlugin(CsrPluginConfig.small(0x80000020l).copy(withPrivilegedDebug = true)), //withPrivilegedDebug is required - new EmbeddedRiscvJtag( - DebugTransportModuleParameter( - addressWidth = 7, - version = 1, - idle = 7 - ), - debugCd = ClockDomain.current.copy(reset = Bool().setName("debugReset")), - withTap = true, - withTunneling = false - ), - new BranchPlugin( - earlyBranch = false, - catchAddressMisaligned = true - ), - new YamlPlugin("cpu0.yaml") - ) - ) - - def cpu() = new VexRiscv( - config - ) - - SpinalVerilog(cpu()) -} diff --git a/src/main/scala/vexriscv/demo/SynthesisBench.scala b/src/main/scala/vexriscv/demo/SynthesisBench.scala index d0188194..d13645a1 100644 --- a/src/main/scala/vexriscv/demo/SynthesisBench.scala +++ b/src/main/scala/vexriscv/demo/SynthesisBench.scala @@ -473,22 +473,7 @@ object VexRiscvCustomSynthesisBench { cpu } - - val riscvDebug = new Rtl { - override def getName(): String = "riscvDebug" - override def getRtlPath(): String = "riscvDebug.v" - SpinalVerilog(gen(new CsrPlugin(CsrPluginConfig.smallest(0x80000000l).copy(withPrivilegedDebug = true)), new EmbeddedRiscvJtag( - p = DebugTransportModuleParameter( - addressWidth = 7, - version = 1, - idle = 7 - ), - debugCd = ClockDomain.current.copy(reset = Bool().setName("debugReset")), - withTunneling = false, - withTap = true - )).setDefinitionName(getRtlPath().split("\\.").head)) - } - + val vexDebug = new Rtl { override def getName(): String = "vexDebug" override def getRtlPath(): String = "vexDebug.v" @@ -499,7 +484,7 @@ object VexRiscvCustomSynthesisBench { // val rtls = List(twoStage, twoStageBarell, twoStageMulDiv, twoStageAll, smallestNoCsr, smallest, smallAndProductive, smallAndProductiveWithICache, fullNoMmuNoCache, noCacheNoMmuMaxPerf, fullNoMmuMaxPerf, fullNoMmu, full, linuxBalanced, linuxBalancedSmp) - val rtls = List(riscvDebug, vexDebug) + val rtls = List(vexDebug) // val rtls = List(smallest) val targets = XilinxStdTargets() ++ AlteraStdTargets() ++ IcestormStdTargets().take(1) From 220b599c9a820444941225c05cfa36b3b84e2bea Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 22 Feb 2023 13:15:57 +0100 Subject: [PATCH 841/951] Fix d$ invalidation when the mmu is enabled --- src/main/scala/vexriscv/ip/DataCache.scala | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index 2b70400f..b4b04f70 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -1063,16 +1063,18 @@ class DataCache(val p : DataCacheConfig, mmuParameter : MemoryTranslatorBusParam } //remove side effects on exceptions - when(consistancyHazard || mmuRsp.refilling || io.cpu.writeBack.accessError || io.cpu.writeBack.mmuException || io.cpu.writeBack.unalignedAccess){ - io.mem.cmd.valid := False - tagsWriteCmd.valid := False - dataWriteCmd.valid := False - loaderValid := False - io.cpu.writeBack.haltIt := False - if(withInternalLrSc) lrSc.reserved := lrSc.reserved - if(withExternalAmo) amo.external.state := LR_CMD + when(io.cpu.writeBack.isValid) { + when(consistancyHazard || mmuRsp.refilling || io.cpu.writeBack.accessError || io.cpu.writeBack.mmuException || io.cpu.writeBack.unalignedAccess) { + io.mem.cmd.valid := False + tagsWriteCmd.valid := False + dataWriteCmd.valid := False + loaderValid := False + io.cpu.writeBack.haltIt := False + if (withInternalLrSc) lrSc.reserved := lrSc.reserved + if (withExternalAmo) amo.external.state := LR_CMD + } + io.cpu.redo setWhen((mmuRsp.refilling || consistancyHazard)) } - io.cpu.redo setWhen(io.cpu.writeBack.isValid && (mmuRsp.refilling || consistancyHazard)) assert(!(io.cpu.writeBack.isValid && !io.cpu.writeBack.haltIt && io.cpu.writeBack.isStuck), "writeBack stuck by another plugin is not allowed", ERROR) } From 9605b663bf39460ee7a3862dfc569512f4a66f79 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 22 Feb 2023 15:26:14 +0100 Subject: [PATCH 842/951] D$ now support thightly coupled ram. Add IBusDBusCachedTightlyCoupledRam plugin --- .../vexriscv/plugin/DBusCachedPlugin.scala | 121 +++++++++++++++++- .../vexriscv/plugin/IBusCachedPlugin.scala | 8 +- 2 files changed, 127 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index 3a1a8a97..3c8f9c52 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 035c5dcf..1bb15dc0 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 From 344b2d4edaa52670c874e24015bacf990514c705 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 23 Feb 2023 11:59:13 +0100 Subject: [PATCH 843/951] TestIndividual supervisor missing CSR=yes --- src/test/resources/asm/mmu.asm | 13463 ++++++++++++++++ .../vexriscv/TestIndividualFeatures.scala | 2 +- 2 files changed, 13464 insertions(+), 1 deletion(-) create mode 100644 src/test/resources/asm/mmu.asm diff --git a/src/test/resources/asm/mmu.asm b/src/test/resources/asm/mmu.asm new file mode 100644 index 00000000..e9dc2424 --- /dev/null +++ b/src/test/resources/asm/mmu.asm @@ -0,0 +1,13463 @@ + +build/mmu.elf: file format elf32-littleriscv + + +Disassembly of section .crt_section: + +80000000 <_start>: +80000000: 00000e93 li t4,0 +80000004: 00000097 auipc ra,0x0 +80000008: 4ec08093 addi ra,ra,1260 # 800004f0 +8000000c: 30509073 csrw mtvec,ra + +80000010 : +80000010: 00100e13 li t3,1 +80000014: 00007097 auipc ra,0x7 +80000018: fec08093 addi ra,ra,-20 # 80007000 +8000001c: 27262137 lui sp,0x27262 +80000020: 52410113 addi sp,sp,1316 # 27262524 <_start-0x58d9dadc> +80000024: 0040a083 lw ra,4(ra) +80000028: 48209c63 bne ra,sp,800004c0 + +8000002c : +8000002c: 00200e13 li t3,2 +80000030: 00000097 auipc ra,0x0 +80000034: 02008093 addi ra,ra,32 # 80000050 +80000038: 34109073 csrw mepc,ra +8000003c: 000020b7 lui ra,0x2 +80000040: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800> +80000044: 30009073 csrw mstatus,ra +80000048: 30200073 mret +8000004c: 4740006f j 800004c0 + +80000050 : +80000050: 00300e13 li t3,3 +80000054: 000010b7 lui ra,0x1 +80000058: 80008093 addi ra,ra,-2048 # 800 <_start-0x7ffff800> +8000005c: 30009073 csrw mstatus,ra +80000060: 00000097 auipc ra,0x0 +80000064: 01408093 addi ra,ra,20 # 80000074 +80000068: 34109073 csrw mepc,ra +8000006c: 30200073 mret +80000070: 4500006f j 800004c0 + +80000074 : +80000074: 00400e13 li t3,4 +80000078: 00008097 auipc ra,0x8 +8000007c: f8808093 addi ra,ra,-120 # 80008000 +80000080: 37363137 lui sp,0x37363 +80000084: 53410113 addi sp,sp,1332 # 37363534 <_start-0x48c9cacc> +80000088: 0040a083 lw ra,4(ra) +8000008c: 42209a63 bne ra,sp,800004c0 + +80000090 : +80000090: 00500e13 li t3,5 +80000094: 00001097 auipc ra,0x1 +80000098: 76c08093 addi ra,ra,1900 # 80001800 +8000009c: 00002117 auipc sp,0x2 +800000a0: f6410113 addi sp,sp,-156 # 80002000 +800000a4: 00215113 srli sp,sp,0x2 +800000a8: 00116113 ori sp,sp,1 +800000ac: 0020a023 sw sp,0(ra) +800000b0: 00002097 auipc ra,0x2 +800000b4: f5008093 addi ra,ra,-176 # 80002000 +800000b8: 80000137 lui sp,0x80000 +800000bc: 00215113 srli sp,sp,0x2 +800000c0: 0cf16113 ori sp,sp,207 +800000c4: 0020a023 sw sp,0(ra) +800000c8: 00500e13 li t3,5 +800000cc: 00002097 auipc ra,0x2 +800000d0: 83408093 addi ra,ra,-1996 # 80001900 +800000d4: 00003117 auipc sp,0x3 +800000d8: f2c10113 addi sp,sp,-212 # 80003000 +800000dc: 00215113 srli sp,sp,0x2 +800000e0: 00116113 ori sp,sp,1 +800000e4: 0020a023 sw sp,0(ra) +800000e8: 00003097 auipc ra,0x3 +800000ec: f4008093 addi ra,ra,-192 # 80003028 +800000f0: 00009117 auipc sp,0x9 +800000f4: f1010113 addi sp,sp,-240 # 80009000 +800000f8: 00215113 srli sp,sp,0x2 +800000fc: 0df16113 ori sp,sp,223 +80000100: 0020a023 sw sp,0(ra) +80000104: 00003097 auipc ra,0x3 +80000108: f3c08093 addi ra,ra,-196 # 80003040 +8000010c: 0000a117 auipc sp,0xa +80000110: ef410113 addi sp,sp,-268 # 8000a000 +80000114: 00215113 srli sp,sp,0x2 +80000118: 0d316113 ori sp,sp,211 +8000011c: 0020a023 sw sp,0(ra) +80000120: 00003097 auipc ra,0x3 +80000124: f2408093 addi ra,ra,-220 # 80003044 +80000128: 0000a117 auipc sp,0xa +8000012c: ed810113 addi sp,sp,-296 # 8000a000 +80000130: 00215113 srli sp,sp,0x2 +80000134: 0d716113 ori sp,sp,215 +80000138: 0020a023 sw sp,0(ra) +8000013c: 00003097 auipc ra,0x3 +80000140: f0c08093 addi ra,ra,-244 # 80003048 +80000144: 0000a117 auipc sp,0xa +80000148: ebc10113 addi sp,sp,-324 # 8000a000 +8000014c: 00215113 srli sp,sp,0x2 +80000150: 0d916113 ori sp,sp,217 +80000154: 0020a023 sw sp,0(ra) +80000158: 00003097 auipc ra,0x3 +8000015c: ef408093 addi ra,ra,-268 # 8000304c +80000160: 0000a117 auipc sp,0xa +80000164: ea010113 addi sp,sp,-352 # 8000a000 +80000168: 00215113 srli sp,sp,0x2 +8000016c: 0db16113 ori sp,sp,219 +80000170: 0020a023 sw sp,0(ra) +80000174: 00003097 auipc ra,0x3 +80000178: edc08093 addi ra,ra,-292 # 80003050 +8000017c: 0000a117 auipc sp,0xa +80000180: e8410113 addi sp,sp,-380 # 8000a000 +80000184: 00215113 srli sp,sp,0x2 +80000188: 0cf16113 ori sp,sp,207 +8000018c: 0020a023 sw sp,0(ra) +80000190: 00500e13 li t3,5 +80000194: 00002097 auipc ra,0x2 +80000198: 86c08093 addi ra,ra,-1940 # 80001a00 +8000019c: 00000117 auipc sp,0x0 +800001a0: e6410113 addi sp,sp,-412 # 80000000 <_start> +800001a4: 00215113 srli sp,sp,0x2 +800001a8: 0df16113 ori sp,sp,223 +800001ac: 0020a023 sw sp,0(ra) +800001b0: 00500e13 li t3,5 +800001b4: 00002097 auipc ra,0x2 +800001b8: 94c08093 addi ra,ra,-1716 # 80001b00 +800001bc: 0000a023 sw zero,0(ra) +800001c0: 000400b7 lui ra,0x40 +800001c4: 1000a073 csrs sstatus,ra +800001c8: 00001097 auipc ra,0x1 +800001cc: e3808093 addi ra,ra,-456 # 80001000 +800001d0: 00c0d093 srli ra,ra,0xc +800001d4: 80000137 lui sp,0x80000 +800001d8: 0020e0b3 or ra,ra,sp +800001dc: 12000073 sfence.vma +800001e0: 18009073 csrw satp,ra +800001e4: 0000100f fence.i + +800001e8 : +800001e8: 00600e13 li t3,6 +800001ec: 9000a0b7 lui ra,0x9000a +800001f0: 00808093 addi ra,ra,8 # 9000a008 +800001f4: 4b4a5137 lui sp,0x4b4a5 +800001f8: 94810113 addi sp,sp,-1720 # 4b4a4948 <_start-0x34b5b6b8> +800001fc: 0000a083 lw ra,0(ra) +80000200: 2c209063 bne ra,sp,800004c0 + +80000204 : +80000204: 00700e13 li t3,7 +80000208: 9000a0b7 lui ra,0x9000a +8000020c: 36008093 addi ra,ra,864 # 9000a360 +80000210: aaee0137 lui sp,0xaaee0 +80000214: 00110113 addi sp,sp,1 # aaee0001 +80000218: 0020a023 sw sp,0(ra) +8000021c: 0000a083 lw ra,0(ra) +80000220: 2a209063 bne ra,sp,800004c0 + +80000224 : +80000224: 00800e13 li t3,8 +80000228: 2000c097 auipc ra,0x2000c +8000022c: ddc08093 addi ra,ra,-548 # a000c004 +80000230: 77767137 lui sp,0x77767 +80000234: 57410113 addi sp,sp,1396 # 77767574 <_start-0x8898a8c> +80000238: 0000a083 lw ra,0(ra) +8000023c: 28209263 bne ra,sp,800004c0 + +80000240 : +80000240: 00900e13 li t3,9 +80000244: a000a0b7 lui ra,0xa000a +80000248: 36008093 addi ra,ra,864 # a000a360 +8000024c: aaee0137 lui sp,0xaaee0 +80000250: 00210113 addi sp,sp,2 # aaee0002 +80000254: 0020a023 sw sp,0(ra) +80000258: 0000a083 lw ra,0(ra) +8000025c: 26209263 bne ra,sp,800004c0 + +80000260 : +80000260: 00a00e13 li t3,10 +80000264: 18005073 csrwi satp,0 +80000268: 00009097 auipc ra,0x9 +8000026c: 0f808093 addi ra,ra,248 # 80009360 +80000270: aaee0137 lui sp,0xaaee0 +80000274: 00110113 addi sp,sp,1 # aaee0001 +80000278: 0000a083 lw ra,0(ra) +8000027c: 24209263 bne ra,sp,800004c0 + +80000280 : +80000280: 00b00e13 li t3,11 +80000284: 0000a097 auipc ra,0xa +80000288: 0dc08093 addi ra,ra,220 # 8000a360 +8000028c: aaee0137 lui sp,0xaaee0 +80000290: 00210113 addi sp,sp,2 # aaee0002 +80000294: 0000a083 lw ra,0(ra) +80000298: 22209463 bne ra,sp,800004c0 +8000029c: 00001097 auipc ra,0x1 +800002a0: d6408093 addi ra,ra,-668 # 80001000 +800002a4: 00c0d093 srli ra,ra,0xc +800002a8: 80000137 lui sp,0x80000 +800002ac: 0020e0b3 or ra,ra,sp +800002b0: 18009073 csrw satp,ra + +800002b4 : +800002b4: 00c00e13 li t3,12 +800002b8: 00100e93 li t4,1 +800002bc: 00000f17 auipc t5,0x0 +800002c0: 010f0f13 addi t5,t5,16 # 800002cc +800002c4: 00000073 ecall +800002c8: 1f80006f j 800004c0 + +800002cc : +800002cc: 00d00e13 li t3,13 +800002d0: 00000f17 auipc t5,0x0 +800002d4: 014f0f13 addi t5,t5,20 # 800002e4 +800002d8: b00000b7 lui ra,0xb0000 +800002dc: 0080a083 lw ra,8(ra) # b0000008 +800002e0: 1e00006f j 800004c0 + +800002e4 : +800002e4: 00e00e13 li t3,14 +800002e8: 00000f17 auipc t5,0x0 +800002ec: 014f0f13 addi t5,t5,20 # 800002fc +800002f0: b00000b7 lui ra,0xb0000 +800002f4: 0010a423 sw ra,8(ra) # b0000008 +800002f8: 1c80006f j 800004c0 + +800002fc : +800002fc: 00f00e13 li t3,15 +80000300: 00000f17 auipc t5,0x0 +80000304: 014f0f13 addi t5,t5,20 # 80000314 +80000308: b00000b7 lui ra,0xb0000 +8000030c: 00008067 ret +80000310: 1b00006f j 800004c0 + +80000314 : +80000314: 01000e13 li t3,16 +80000318: 00000e93 li t4,0 +8000031c: 900100b7 lui ra,0x90010 +80000320: 00808093 addi ra,ra,8 # 90010008 +80000324: 5b5a6137 lui sp,0x5b5a6 +80000328: 95810113 addi sp,sp,-1704 # 5b5a5958 <_start-0x24a5a6a8> +8000032c: 0000a083 lw ra,0(ra) +80000330: 18209863 bne ra,sp,800004c0 +80000334: 900110b7 lui ra,0x90011 +80000338: 00808093 addi ra,ra,8 # 90011008 +8000033c: 5b5a6137 lui sp,0x5b5a6 +80000340: 95810113 addi sp,sp,-1704 # 5b5a5958 <_start-0x24a5a6a8> +80000344: 0000a083 lw ra,0(ra) +80000348: 16209c63 bne ra,sp,800004c0 +8000034c: 900130b7 lui ra,0x90013 +80000350: 00808093 addi ra,ra,8 # 90013008 +80000354: 5b5a6137 lui sp,0x5b5a6 +80000358: 95810113 addi sp,sp,-1704 # 5b5a5958 <_start-0x24a5a6a8> +8000035c: 0000a083 lw ra,0(ra) +80000360: 16209063 bne ra,sp,800004c0 + +80000364 : +80000364: 01100e13 li t3,17 +80000368: 900110b7 lui ra,0x90011 +8000036c: 36008093 addi ra,ra,864 # 90011360 +80000370: aaee0137 lui sp,0xaaee0 +80000374: 00310113 addi sp,sp,3 # aaee0003 +80000378: 0020a023 sw sp,0(ra) +8000037c: 0000a083 lw ra,0(ra) +80000380: 14209063 bne ra,sp,800004c0 + +80000384 : +80000384: 01200e13 li t3,18 +80000388: 00100e93 li t4,1 +8000038c: 00000f17 auipc t5,0x0 +80000390: 018f0f13 addi t5,t5,24 # 800003a4 +80000394: 90012137 lui sp,0x90012 +80000398: 01010113 addi sp,sp,16 # 90012010 +8000039c: 00010067 jr sp +800003a0: 1200006f j 800004c0 + +800003a4 : +800003a4: 01300e13 li t3,19 +800003a8: 00100e93 li t4,1 +800003ac: 00000f17 auipc t5,0x0 +800003b0: 018f0f13 addi t5,t5,24 # 800003c4 +800003b4: 900120b7 lui ra,0x90012 +800003b8: 01008093 addi ra,ra,16 # 90012010 +800003bc: 0000a083 lw ra,0(ra) +800003c0: 1000006f j 800004c0 + +800003c4 : +800003c4: 00000f17 auipc t5,0x0 +800003c8: 018f0f13 addi t5,t5,24 # 800003dc +800003cc: 900130b7 lui ra,0x90013 +800003d0: 01008093 addi ra,ra,16 # 90013010 +800003d4: 0010a023 sw ra,0(ra) +800003d8: 0e80006f j 800004c0 + +800003dc : +800003dc: 00000f17 auipc t5,0x0 +800003e0: 018f0f13 addi t5,t5,24 # 800003f4 +800003e4: 900110b7 lui ra,0x90011 +800003e8: 01008093 addi ra,ra,16 # 90011010 +800003ec: 00008067 ret +800003f0: 0d00006f j 800004c0 + +800003f4 : +800003f4: 01500e13 li t3,21 +800003f8: 00000e93 li t4,0 +800003fc: 000800b7 lui ra,0x80 +80000400: 1000a073 csrs sstatus,ra +80000404: 900120b7 lui ra,0x90012 +80000408: 00808093 addi ra,ra,8 # 90012008 +8000040c: 5b5a6137 lui sp,0x5b5a6 +80000410: 95810113 addi sp,sp,-1704 # 5b5a5958 <_start-0x24a5a6a8> +80000414: 0000a083 lw ra,0(ra) +80000418: 0a209463 bne ra,sp,800004c0 +8000041c: 000800b7 lui ra,0x80 +80000420: 1000b073 csrc sstatus,ra + +80000424 : +80000424: 00000e93 li t4,0 +80000428: 01400e13 li t3,20 +8000042c: 900140b7 lui ra,0x90014 +80000430: 38008093 addi ra,ra,896 # 90014380 +80000434: aaee0137 lui sp,0xaaee0 +80000438: 00510113 addi sp,sp,5 # aaee0005 +8000043c: 0020a023 sw sp,0(ra) +80000440: 0000a083 lw ra,0(ra) +80000444: 06209e63 bne ra,sp,800004c0 +80000448: 000400b7 lui ra,0x40 +8000044c: 1000b073 csrc sstatus,ra +80000450: 00100e93 li t4,1 +80000454: 00000f17 auipc t5,0x0 +80000458: 018f0f13 addi t5,t5,24 # 8000046c +8000045c: 900110b7 lui ra,0x90011 +80000460: 64808093 addi ra,ra,1608 # 90011648 +80000464: 0010a023 sw ra,0(ra) +80000468: 0580006f j 800004c0 + +8000046c : +8000046c: 03200e13 li t3,50 +80000470: 00000e93 li t4,0 +80000474: 000400b7 lui ra,0x40 +80000478: 1000a073 csrs sstatus,ra +8000047c: 18002573 csrr a0,satp +80000480: 18001073 csrw satp,zero +80000484: 00002097 auipc ra,0x2 +80000488: bb008093 addi ra,ra,-1104 # 80002034 +8000048c: 8000d137 lui sp,0x8000d +80000490: 00215113 srli sp,sp,0x2 +80000494: 05f16113 ori sp,sp,95 +80000498: 0020a023 sw sp,0(ra) +8000049c: 18051073 csrw satp,a0 +800004a0: 10000093 li ra,256 +800004a4: 1000b073 csrc sstatus,ra +800004a8: 0000d097 auipc ra,0xd +800004ac: b5808093 addi ra,ra,-1192 # 8000d000 +800004b0: 14109073 csrw sepc,ra +800004b4: 12000073 sfence.vma +800004b8: 10200073 sret +800004bc: 0040006f j 800004c0 + +800004c0 : +800004c0: 00000e93 li t4,0 +800004c4: 00000073 ecall + +800004c8 : +800004c8: f0100137 lui sp,0xf0100 +800004cc: f2410113 addi sp,sp,-220 # f00fff24 +800004d0: 01c12023 sw t3,0(sp) + +800004d4 : +800004d4: 00200e93 li t4,2 +800004d8: 00000073 ecall + +800004dc : +800004dc: f0100137 lui sp,0xf0100 +800004e0: f2010113 addi sp,sp,-224 # f00fff20 +800004e4: 00012023 sw zero,0(sp) +800004e8: 00000013 nop +800004ec: 00000013 nop + +800004f0 : +800004f0: fc0e88e3 beqz t4,800004c0 +800004f4: 342020f3 csrr ra,mcause +800004f8: 341020f3 csrr ra,mepc +800004fc: 300020f3 csrr ra,mstatus +80000500: 343020f3 csrr ra,mtval +80000504: 00200093 li ra,2 +80000508: fc1e86e3 beq t4,ra,800004d4 +8000050c: 341f1073 csrw mepc,t5 +80000510: 30200073 mret +80000514: 00000013 nop +80000518: 00000013 nop +8000051c: 00000013 nop +80000520: 00000013 nop +80000524: 00000013 nop +80000528: 00000013 nop +8000052c: 00000013 nop +80000530: 00000013 nop +80000534: 00000013 nop +80000538: 00000013 nop +8000053c: 00000013 nop +80000540: 00000013 nop +80000544: 00000013 nop +80000548: 00000013 nop +8000054c: 00000013 nop +80000550: 00000013 nop +80000554: 00000013 nop +80000558: 00000013 nop +8000055c: 00000013 nop +80000560: 00000013 nop +80000564: 00000013 nop +80000568: 00000013 nop +8000056c: 00000013 nop +80000570: 00000013 nop +80000574: 00000013 nop +80000578: 00000013 nop +8000057c: 00000013 nop +80000580: 00000013 nop +80000584: 00000013 nop +80000588: 00000013 nop +8000058c: 00000013 nop +80000590: 00000013 nop +80000594: 00000013 nop +80000598: 00000013 nop +8000059c: 00000013 nop +800005a0: 00000013 nop +800005a4: 00000013 nop +800005a8: 00000013 nop +800005ac: 00000013 nop +800005b0: 00000013 nop +800005b4: 00000013 nop +800005b8: 00000013 nop +800005bc: 00000013 nop +800005c0: 00000013 nop +800005c4: 00000013 nop +800005c8: 00000013 nop +800005cc: 00000013 nop +800005d0: 00000013 nop +800005d4: 00000013 nop +800005d8: 00000013 nop +800005dc: 00000013 nop +800005e0: 00000013 nop +800005e4: 00000013 nop +800005e8: 00000013 nop +800005ec: 00000013 nop +800005f0: 00000013 nop +800005f4: 00000013 nop +800005f8: 00000013 nop +800005fc: 00000013 nop +80000600: 00000013 nop +80000604: 00000013 nop +80000608: 00000013 nop +8000060c: 00000013 nop +80000610: 00000013 nop +80000614: 00000013 nop +80000618: 00000013 nop +8000061c: 00000013 nop +80000620: 00000013 nop +80000624: 00000013 nop +80000628: 00000013 nop +8000062c: 00000013 nop +80000630: 00000013 nop +80000634: 00000013 nop +80000638: 00000013 nop +8000063c: 00000013 nop +80000640: 00000013 nop +80000644: 00000013 nop +80000648: 00000013 nop +8000064c: 00000013 nop +80000650: 00000013 nop +80000654: 00000013 nop +80000658: 00000013 nop +8000065c: 00000013 nop +80000660: 00000013 nop +80000664: 00000013 nop +80000668: 00000013 nop +8000066c: 00000013 nop +80000670: 00000013 nop +80000674: 00000013 nop +80000678: 00000013 nop +8000067c: 00000013 nop +80000680: 00000013 nop +80000684: 00000013 nop +80000688: 00000013 nop +8000068c: 00000013 nop +80000690: 00000013 nop +80000694: 00000013 nop +80000698: 00000013 nop +8000069c: 00000013 nop +800006a0: 00000013 nop +800006a4: 00000013 nop +800006a8: 00000013 nop +800006ac: 00000013 nop +800006b0: 00000013 nop +800006b4: 00000013 nop +800006b8: 00000013 nop +800006bc: 00000013 nop +800006c0: 00000013 nop +800006c4: 00000013 nop +800006c8: 00000013 nop +800006cc: 00000013 nop +800006d0: 00000013 nop +800006d4: 00000013 nop +800006d8: 00000013 nop +800006dc: 00000013 nop +800006e0: 00000013 nop +800006e4: 00000013 nop +800006e8: 00000013 nop +800006ec: 00000013 nop +800006f0: 00000013 nop +800006f4: 00000013 nop +800006f8: 00000013 nop +800006fc: 00000013 nop +80000700: 00000013 nop +80000704: 00000013 nop +80000708: 00000013 nop +8000070c: 00000013 nop +80000710: 00000013 nop +80000714: 00000013 nop +80000718: 00000013 nop +8000071c: 00000013 nop +80000720: 00000013 nop +80000724: 00000013 nop +80000728: 00000013 nop +8000072c: 00000013 nop +80000730: 00000013 nop +80000734: 00000013 nop +80000738: 00000013 nop +8000073c: 00000013 nop +80000740: 00000013 nop +80000744: 00000013 nop +80000748: 00000013 nop +8000074c: 00000013 nop +80000750: 00000013 nop +80000754: 00000013 nop +80000758: 00000013 nop +8000075c: 00000013 nop +80000760: 00000013 nop +80000764: 00000013 nop +80000768: 00000013 nop +8000076c: 00000013 nop +80000770: 00000013 nop +80000774: 00000013 nop +80000778: 00000013 nop +8000077c: 00000013 nop +80000780: 00000013 nop +80000784: 00000013 nop +80000788: 00000013 nop +8000078c: 00000013 nop +80000790: 00000013 nop +80000794: 00000013 nop +80000798: 00000013 nop +8000079c: 00000013 nop +800007a0: 00000013 nop +800007a4: 00000013 nop +800007a8: 00000013 nop +800007ac: 00000013 nop +800007b0: 00000013 nop +800007b4: 00000013 nop +800007b8: 00000013 nop +800007bc: 00000013 nop +800007c0: 00000013 nop +800007c4: 00000013 nop +800007c8: 00000013 nop +800007cc: 00000013 nop +800007d0: 00000013 nop +800007d4: 00000013 nop +800007d8: 00000013 nop +800007dc: 00000013 nop +800007e0: 00000013 nop +800007e4: 00000013 nop +800007e8: 00000013 nop +800007ec: 00000013 nop +800007f0: 00000013 nop +800007f4: 00000013 nop +800007f8: 00000013 nop +800007fc: 00000013 nop +80000800: 00000013 nop +80000804: 00000013 nop +80000808: 00000013 nop +8000080c: 00000013 nop +80000810: 00000013 nop +80000814: 00000013 nop +80000818: 00000013 nop +8000081c: 00000013 nop +80000820: 00000013 nop +80000824: 00000013 nop +80000828: 00000013 nop +8000082c: 00000013 nop +80000830: 00000013 nop +80000834: 00000013 nop +80000838: 00000013 nop +8000083c: 00000013 nop +80000840: 00000013 nop +80000844: 00000013 nop +80000848: 00000013 nop +8000084c: 00000013 nop +80000850: 00000013 nop +80000854: 00000013 nop +80000858: 00000013 nop +8000085c: 00000013 nop +80000860: 00000013 nop +80000864: 00000013 nop +80000868: 00000013 nop +8000086c: 00000013 nop +80000870: 00000013 nop +80000874: 00000013 nop +80000878: 00000013 nop +8000087c: 00000013 nop +80000880: 00000013 nop +80000884: 00000013 nop +80000888: 00000013 nop +8000088c: 00000013 nop +80000890: 00000013 nop +80000894: 00000013 nop +80000898: 00000013 nop +8000089c: 00000013 nop +800008a0: 00000013 nop +800008a4: 00000013 nop +800008a8: 00000013 nop +800008ac: 00000013 nop +800008b0: 00000013 nop +800008b4: 00000013 nop +800008b8: 00000013 nop +800008bc: 00000013 nop +800008c0: 00000013 nop +800008c4: 00000013 nop +800008c8: 00000013 nop +800008cc: 00000013 nop +800008d0: 00000013 nop +800008d4: 00000013 nop +800008d8: 00000013 nop +800008dc: 00000013 nop +800008e0: 00000013 nop +800008e4: 00000013 nop +800008e8: 00000013 nop +800008ec: 00000013 nop +800008f0: 00000013 nop +800008f4: 00000013 nop +800008f8: 00000013 nop +800008fc: 00000013 nop +80000900: 00000013 nop +80000904: 00000013 nop +80000908: 00000013 nop +8000090c: 00000013 nop +80000910: 00000013 nop +80000914: 00000013 nop +80000918: 00000013 nop +8000091c: 00000013 nop +80000920: 00000013 nop +80000924: 00000013 nop +80000928: 00000013 nop +8000092c: 00000013 nop +80000930: 00000013 nop +80000934: 00000013 nop +80000938: 00000013 nop +8000093c: 00000013 nop +80000940: 00000013 nop +80000944: 00000013 nop +80000948: 00000013 nop +8000094c: 00000013 nop +80000950: 00000013 nop +80000954: 00000013 nop +80000958: 00000013 nop +8000095c: 00000013 nop +80000960: 00000013 nop +80000964: 00000013 nop +80000968: 00000013 nop +8000096c: 00000013 nop +80000970: 00000013 nop +80000974: 00000013 nop +80000978: 00000013 nop +8000097c: 00000013 nop +80000980: 00000013 nop +80000984: 00000013 nop +80000988: 00000013 nop +8000098c: 00000013 nop +80000990: 00000013 nop +80000994: 00000013 nop +80000998: 00000013 nop +8000099c: 00000013 nop +800009a0: 00000013 nop +800009a4: 00000013 nop +800009a8: 00000013 nop +800009ac: 00000013 nop +800009b0: 00000013 nop +800009b4: 00000013 nop +800009b8: 00000013 nop +800009bc: 00000013 nop +800009c0: 00000013 nop +800009c4: 00000013 nop +800009c8: 00000013 nop +800009cc: 00000013 nop +800009d0: 00000013 nop +800009d4: 00000013 nop +800009d8: 00000013 nop +800009dc: 00000013 nop +800009e0: 00000013 nop +800009e4: 00000013 nop +800009e8: 00000013 nop +800009ec: 00000013 nop +800009f0: 00000013 nop +800009f4: 00000013 nop +800009f8: 00000013 nop +800009fc: 00000013 nop +80000a00: 00000013 nop +80000a04: 00000013 nop +80000a08: 00000013 nop +80000a0c: 00000013 nop +80000a10: 00000013 nop +80000a14: 00000013 nop +80000a18: 00000013 nop +80000a1c: 00000013 nop +80000a20: 00000013 nop +80000a24: 00000013 nop +80000a28: 00000013 nop +80000a2c: 00000013 nop +80000a30: 00000013 nop +80000a34: 00000013 nop +80000a38: 00000013 nop +80000a3c: 00000013 nop +80000a40: 00000013 nop +80000a44: 00000013 nop +80000a48: 00000013 nop +80000a4c: 00000013 nop +80000a50: 00000013 nop +80000a54: 00000013 nop +80000a58: 00000013 nop +80000a5c: 00000013 nop +80000a60: 00000013 nop +80000a64: 00000013 nop +80000a68: 00000013 nop +80000a6c: 00000013 nop +80000a70: 00000013 nop +80000a74: 00000013 nop +80000a78: 00000013 nop +80000a7c: 00000013 nop +80000a80: 00000013 nop +80000a84: 00000013 nop +80000a88: 00000013 nop +80000a8c: 00000013 nop +80000a90: 00000013 nop +80000a94: 00000013 nop +80000a98: 00000013 nop +80000a9c: 00000013 nop +80000aa0: 00000013 nop +80000aa4: 00000013 nop +80000aa8: 00000013 nop +80000aac: 00000013 nop +80000ab0: 00000013 nop +80000ab4: 00000013 nop +80000ab8: 00000013 nop +80000abc: 00000013 nop +80000ac0: 00000013 nop +80000ac4: 00000013 nop +80000ac8: 00000013 nop +80000acc: 00000013 nop +80000ad0: 00000013 nop +80000ad4: 00000013 nop +80000ad8: 00000013 nop +80000adc: 00000013 nop +80000ae0: 00000013 nop +80000ae4: 00000013 nop +80000ae8: 00000013 nop +80000aec: 00000013 nop +80000af0: 00000013 nop +80000af4: 00000013 nop +80000af8: 00000013 nop +80000afc: 00000013 nop +80000b00: 00000013 nop +80000b04: 00000013 nop +80000b08: 00000013 nop +80000b0c: 00000013 nop +80000b10: 00000013 nop +80000b14: 00000013 nop +80000b18: 00000013 nop +80000b1c: 00000013 nop +80000b20: 00000013 nop +80000b24: 00000013 nop +80000b28: 00000013 nop +80000b2c: 00000013 nop +80000b30: 00000013 nop +80000b34: 00000013 nop +80000b38: 00000013 nop +80000b3c: 00000013 nop +80000b40: 00000013 nop +80000b44: 00000013 nop +80000b48: 00000013 nop +80000b4c: 00000013 nop +80000b50: 00000013 nop +80000b54: 00000013 nop +80000b58: 00000013 nop +80000b5c: 00000013 nop +80000b60: 00000013 nop +80000b64: 00000013 nop +80000b68: 00000013 nop +80000b6c: 00000013 nop +80000b70: 00000013 nop +80000b74: 00000013 nop +80000b78: 00000013 nop +80000b7c: 00000013 nop +80000b80: 00000013 nop +80000b84: 00000013 nop +80000b88: 00000013 nop +80000b8c: 00000013 nop +80000b90: 00000013 nop +80000b94: 00000013 nop +80000b98: 00000013 nop +80000b9c: 00000013 nop +80000ba0: 00000013 nop +80000ba4: 00000013 nop +80000ba8: 00000013 nop +80000bac: 00000013 nop +80000bb0: 00000013 nop +80000bb4: 00000013 nop +80000bb8: 00000013 nop +80000bbc: 00000013 nop +80000bc0: 00000013 nop +80000bc4: 00000013 nop +80000bc8: 00000013 nop +80000bcc: 00000013 nop +80000bd0: 00000013 nop +80000bd4: 00000013 nop +80000bd8: 00000013 nop +80000bdc: 00000013 nop +80000be0: 00000013 nop +80000be4: 00000013 nop +80000be8: 00000013 nop +80000bec: 00000013 nop +80000bf0: 00000013 nop +80000bf4: 00000013 nop +80000bf8: 00000013 nop +80000bfc: 00000013 nop +80000c00: 00000013 nop +80000c04: 00000013 nop +80000c08: 00000013 nop +80000c0c: 00000013 nop +80000c10: 00000013 nop +80000c14: 00000013 nop +80000c18: 00000013 nop +80000c1c: 00000013 nop +80000c20: 00000013 nop +80000c24: 00000013 nop +80000c28: 00000013 nop +80000c2c: 00000013 nop +80000c30: 00000013 nop +80000c34: 00000013 nop +80000c38: 00000013 nop +80000c3c: 00000013 nop +80000c40: 00000013 nop +80000c44: 00000013 nop +80000c48: 00000013 nop +80000c4c: 00000013 nop +80000c50: 00000013 nop +80000c54: 00000013 nop +80000c58: 00000013 nop +80000c5c: 00000013 nop +80000c60: 00000013 nop +80000c64: 00000013 nop +80000c68: 00000013 nop +80000c6c: 00000013 nop +80000c70: 00000013 nop +80000c74: 00000013 nop +80000c78: 00000013 nop +80000c7c: 00000013 nop +80000c80: 00000013 nop +80000c84: 00000013 nop +80000c88: 00000013 nop +80000c8c: 00000013 nop +80000c90: 00000013 nop +80000c94: 00000013 nop +80000c98: 00000013 nop +80000c9c: 00000013 nop +80000ca0: 00000013 nop +80000ca4: 00000013 nop +80000ca8: 00000013 nop +80000cac: 00000013 nop +80000cb0: 00000013 nop +80000cb4: 00000013 nop +80000cb8: 00000013 nop +80000cbc: 00000013 nop +80000cc0: 00000013 nop +80000cc4: 00000013 nop +80000cc8: 00000013 nop +80000ccc: 00000013 nop +80000cd0: 00000013 nop +80000cd4: 00000013 nop +80000cd8: 00000013 nop +80000cdc: 00000013 nop +80000ce0: 00000013 nop +80000ce4: 00000013 nop +80000ce8: 00000013 nop +80000cec: 00000013 nop +80000cf0: 00000013 nop +80000cf4: 00000013 nop +80000cf8: 00000013 nop +80000cfc: 00000013 nop +80000d00: 00000013 nop +80000d04: 00000013 nop +80000d08: 00000013 nop +80000d0c: 00000013 nop +80000d10: 00000013 nop +80000d14: 00000013 nop +80000d18: 00000013 nop +80000d1c: 00000013 nop +80000d20: 00000013 nop +80000d24: 00000013 nop +80000d28: 00000013 nop +80000d2c: 00000013 nop +80000d30: 00000013 nop +80000d34: 00000013 nop +80000d38: 00000013 nop +80000d3c: 00000013 nop +80000d40: 00000013 nop +80000d44: 00000013 nop +80000d48: 00000013 nop +80000d4c: 00000013 nop +80000d50: 00000013 nop +80000d54: 00000013 nop +80000d58: 00000013 nop +80000d5c: 00000013 nop +80000d60: 00000013 nop +80000d64: 00000013 nop +80000d68: 00000013 nop +80000d6c: 00000013 nop +80000d70: 00000013 nop +80000d74: 00000013 nop +80000d78: 00000013 nop +80000d7c: 00000013 nop +80000d80: 00000013 nop +80000d84: 00000013 nop +80000d88: 00000013 nop +80000d8c: 00000013 nop +80000d90: 00000013 nop +80000d94: 00000013 nop +80000d98: 00000013 nop +80000d9c: 00000013 nop +80000da0: 00000013 nop +80000da4: 00000013 nop +80000da8: 00000013 nop +80000dac: 00000013 nop +80000db0: 00000013 nop +80000db4: 00000013 nop +80000db8: 00000013 nop +80000dbc: 00000013 nop +80000dc0: 00000013 nop +80000dc4: 00000013 nop +80000dc8: 00000013 nop +80000dcc: 00000013 nop +80000dd0: 00000013 nop +80000dd4: 00000013 nop +80000dd8: 00000013 nop +80000ddc: 00000013 nop +80000de0: 00000013 nop +80000de4: 00000013 nop +80000de8: 00000013 nop +80000dec: 00000013 nop +80000df0: 00000013 nop +80000df4: 00000013 nop +80000df8: 00000013 nop +80000dfc: 00000013 nop +80000e00: 00000013 nop +80000e04: 00000013 nop +80000e08: 00000013 nop +80000e0c: 00000013 nop +80000e10: 00000013 nop +80000e14: 00000013 nop +80000e18: 00000013 nop +80000e1c: 00000013 nop +80000e20: 00000013 nop +80000e24: 00000013 nop +80000e28: 00000013 nop +80000e2c: 00000013 nop +80000e30: 00000013 nop +80000e34: 00000013 nop +80000e38: 00000013 nop +80000e3c: 00000013 nop +80000e40: 00000013 nop +80000e44: 00000013 nop +80000e48: 00000013 nop +80000e4c: 00000013 nop +80000e50: 00000013 nop +80000e54: 00000013 nop +80000e58: 00000013 nop +80000e5c: 00000013 nop +80000e60: 00000013 nop +80000e64: 00000013 nop +80000e68: 00000013 nop +80000e6c: 00000013 nop +80000e70: 00000013 nop +80000e74: 00000013 nop +80000e78: 00000013 nop +80000e7c: 00000013 nop +80000e80: 00000013 nop +80000e84: 00000013 nop +80000e88: 00000013 nop +80000e8c: 00000013 nop +80000e90: 00000013 nop +80000e94: 00000013 nop +80000e98: 00000013 nop +80000e9c: 00000013 nop +80000ea0: 00000013 nop +80000ea4: 00000013 nop +80000ea8: 00000013 nop +80000eac: 00000013 nop +80000eb0: 00000013 nop +80000eb4: 00000013 nop +80000eb8: 00000013 nop +80000ebc: 00000013 nop +80000ec0: 00000013 nop +80000ec4: 00000013 nop +80000ec8: 00000013 nop +80000ecc: 00000013 nop +80000ed0: 00000013 nop +80000ed4: 00000013 nop +80000ed8: 00000013 nop +80000edc: 00000013 nop +80000ee0: 00000013 nop +80000ee4: 00000013 nop +80000ee8: 00000013 nop +80000eec: 00000013 nop +80000ef0: 00000013 nop +80000ef4: 00000013 nop +80000ef8: 00000013 nop +80000efc: 00000013 nop +80000f00: 00000013 nop +80000f04: 00000013 nop +80000f08: 00000013 nop +80000f0c: 00000013 nop +80000f10: 00000013 nop +80000f14: 00000013 nop +80000f18: 00000013 nop +80000f1c: 00000013 nop +80000f20: 00000013 nop +80000f24: 00000013 nop +80000f28: 00000013 nop +80000f2c: 00000013 nop +80000f30: 00000013 nop +80000f34: 00000013 nop +80000f38: 00000013 nop +80000f3c: 00000013 nop +80000f40: 00000013 nop +80000f44: 00000013 nop +80000f48: 00000013 nop +80000f4c: 00000013 nop +80000f50: 00000013 nop +80000f54: 00000013 nop +80000f58: 00000013 nop +80000f5c: 00000013 nop +80000f60: 00000013 nop +80000f64: 00000013 nop +80000f68: 00000013 nop +80000f6c: 00000013 nop +80000f70: 00000013 nop +80000f74: 00000013 nop +80000f78: 00000013 nop +80000f7c: 00000013 nop +80000f80: 00000013 nop +80000f84: 00000013 nop +80000f88: 00000013 nop +80000f8c: 00000013 nop +80000f90: 00000013 nop +80000f94: 00000013 nop +80000f98: 00000013 nop +80000f9c: 00000013 nop +80000fa0: 00000013 nop +80000fa4: 00000013 nop +80000fa8: 00000013 nop +80000fac: 00000013 nop +80000fb0: 00000013 nop +80000fb4: 00000013 nop +80000fb8: 00000013 nop +80000fbc: 00000013 nop +80000fc0: 00000013 nop +80000fc4: 00000013 nop +80000fc8: 00000013 nop +80000fcc: 00000013 nop +80000fd0: 00000013 nop +80000fd4: 00000013 nop +80000fd8: 00000013 nop +80000fdc: 00000013 nop +80000fe0: 00000013 nop +80000fe4: 00000013 nop +80000fe8: 00000013 nop +80000fec: 00000013 nop +80000ff0: 00000013 nop +80000ff4: 00000013 nop +80000ff8: 00000013 nop +80000ffc: 00000013 nop + +80001000 : +80001000: 00000000 .word 0x00000000 +80001004: 00000013 nop +80001008: 00000013 nop +8000100c: 00000013 nop +80001010: 00000013 nop +80001014: 00000013 nop +80001018: 00000013 nop +8000101c: 00000013 nop +80001020: 00000013 nop +80001024: 00000013 nop +80001028: 00000013 nop +8000102c: 00000013 nop +80001030: 00000013 nop +80001034: 00000013 nop +80001038: 00000013 nop +8000103c: 00000013 nop +80001040: 00000013 nop +80001044: 00000013 nop +80001048: 00000013 nop +8000104c: 00000013 nop +80001050: 00000013 nop +80001054: 00000013 nop +80001058: 00000013 nop +8000105c: 00000013 nop +80001060: 00000013 nop +80001064: 00000013 nop +80001068: 00000013 nop +8000106c: 00000013 nop +80001070: 00000013 nop +80001074: 00000013 nop +80001078: 00000013 nop +8000107c: 00000013 nop +80001080: 00000013 nop +80001084: 00000013 nop +80001088: 00000013 nop +8000108c: 00000013 nop +80001090: 00000013 nop +80001094: 00000013 nop +80001098: 00000013 nop +8000109c: 00000013 nop +800010a0: 00000013 nop +800010a4: 00000013 nop +800010a8: 00000013 nop +800010ac: 00000013 nop +800010b0: 00000013 nop +800010b4: 00000013 nop +800010b8: 00000013 nop +800010bc: 00000013 nop +800010c0: 00000013 nop +800010c4: 00000013 nop +800010c8: 00000013 nop +800010cc: 00000013 nop +800010d0: 00000013 nop +800010d4: 00000013 nop +800010d8: 00000013 nop +800010dc: 00000013 nop +800010e0: 00000013 nop +800010e4: 00000013 nop +800010e8: 00000013 nop +800010ec: 00000013 nop +800010f0: 00000013 nop +800010f4: 00000013 nop +800010f8: 00000013 nop +800010fc: 00000013 nop +80001100: 00000013 nop +80001104: 00000013 nop +80001108: 00000013 nop +8000110c: 00000013 nop +80001110: 00000013 nop +80001114: 00000013 nop +80001118: 00000013 nop +8000111c: 00000013 nop +80001120: 00000013 nop +80001124: 00000013 nop +80001128: 00000013 nop +8000112c: 00000013 nop +80001130: 00000013 nop +80001134: 00000013 nop +80001138: 00000013 nop +8000113c: 00000013 nop +80001140: 00000013 nop +80001144: 00000013 nop +80001148: 00000013 nop +8000114c: 00000013 nop +80001150: 00000013 nop +80001154: 00000013 nop +80001158: 00000013 nop +8000115c: 00000013 nop +80001160: 00000013 nop +80001164: 00000013 nop +80001168: 00000013 nop +8000116c: 00000013 nop +80001170: 00000013 nop +80001174: 00000013 nop +80001178: 00000013 nop +8000117c: 00000013 nop +80001180: 00000013 nop +80001184: 00000013 nop +80001188: 00000013 nop +8000118c: 00000013 nop +80001190: 00000013 nop +80001194: 00000013 nop +80001198: 00000013 nop +8000119c: 00000013 nop +800011a0: 00000013 nop +800011a4: 00000013 nop +800011a8: 00000013 nop +800011ac: 00000013 nop +800011b0: 00000013 nop +800011b4: 00000013 nop +800011b8: 00000013 nop +800011bc: 00000013 nop +800011c0: 00000013 nop +800011c4: 00000013 nop +800011c8: 00000013 nop +800011cc: 00000013 nop +800011d0: 00000013 nop +800011d4: 00000013 nop +800011d8: 00000013 nop +800011dc: 00000013 nop +800011e0: 00000013 nop +800011e4: 00000013 nop +800011e8: 00000013 nop +800011ec: 00000013 nop +800011f0: 00000013 nop +800011f4: 00000013 nop +800011f8: 00000013 nop +800011fc: 00000013 nop +80001200: 00000013 nop +80001204: 00000013 nop +80001208: 00000013 nop +8000120c: 00000013 nop +80001210: 00000013 nop +80001214: 00000013 nop +80001218: 00000013 nop +8000121c: 00000013 nop +80001220: 00000013 nop +80001224: 00000013 nop +80001228: 00000013 nop +8000122c: 00000013 nop +80001230: 00000013 nop +80001234: 00000013 nop +80001238: 00000013 nop +8000123c: 00000013 nop +80001240: 00000013 nop +80001244: 00000013 nop +80001248: 00000013 nop +8000124c: 00000013 nop +80001250: 00000013 nop +80001254: 00000013 nop +80001258: 00000013 nop +8000125c: 00000013 nop +80001260: 00000013 nop +80001264: 00000013 nop +80001268: 00000013 nop +8000126c: 00000013 nop +80001270: 00000013 nop +80001274: 00000013 nop +80001278: 00000013 nop +8000127c: 00000013 nop +80001280: 00000013 nop +80001284: 00000013 nop +80001288: 00000013 nop +8000128c: 00000013 nop +80001290: 00000013 nop +80001294: 00000013 nop +80001298: 00000013 nop +8000129c: 00000013 nop +800012a0: 00000013 nop +800012a4: 00000013 nop +800012a8: 00000013 nop +800012ac: 00000013 nop +800012b0: 00000013 nop +800012b4: 00000013 nop +800012b8: 00000013 nop +800012bc: 00000013 nop +800012c0: 00000013 nop +800012c4: 00000013 nop +800012c8: 00000013 nop +800012cc: 00000013 nop +800012d0: 00000013 nop +800012d4: 00000013 nop +800012d8: 00000013 nop +800012dc: 00000013 nop +800012e0: 00000013 nop +800012e4: 00000013 nop +800012e8: 00000013 nop +800012ec: 00000013 nop +800012f0: 00000013 nop +800012f4: 00000013 nop +800012f8: 00000013 nop +800012fc: 00000013 nop +80001300: 00000013 nop +80001304: 00000013 nop +80001308: 00000013 nop +8000130c: 00000013 nop +80001310: 00000013 nop +80001314: 00000013 nop +80001318: 00000013 nop +8000131c: 00000013 nop +80001320: 00000013 nop +80001324: 00000013 nop +80001328: 00000013 nop +8000132c: 00000013 nop +80001330: 00000013 nop +80001334: 00000013 nop +80001338: 00000013 nop +8000133c: 00000013 nop +80001340: 00000013 nop +80001344: 00000013 nop +80001348: 00000013 nop +8000134c: 00000013 nop +80001350: 00000013 nop +80001354: 00000013 nop +80001358: 00000013 nop +8000135c: 00000013 nop +80001360: 00000013 nop +80001364: 00000013 nop +80001368: 00000013 nop +8000136c: 00000013 nop +80001370: 00000013 nop +80001374: 00000013 nop +80001378: 00000013 nop +8000137c: 00000013 nop +80001380: 00000013 nop +80001384: 00000013 nop +80001388: 00000013 nop +8000138c: 00000013 nop +80001390: 00000013 nop +80001394: 00000013 nop +80001398: 00000013 nop +8000139c: 00000013 nop +800013a0: 00000013 nop +800013a4: 00000013 nop +800013a8: 00000013 nop +800013ac: 00000013 nop +800013b0: 00000013 nop +800013b4: 00000013 nop +800013b8: 00000013 nop +800013bc: 00000013 nop +800013c0: 00000013 nop +800013c4: 00000013 nop +800013c8: 00000013 nop +800013cc: 00000013 nop +800013d0: 00000013 nop +800013d4: 00000013 nop +800013d8: 00000013 nop +800013dc: 00000013 nop +800013e0: 00000013 nop +800013e4: 00000013 nop +800013e8: 00000013 nop +800013ec: 00000013 nop +800013f0: 00000013 nop +800013f4: 00000013 nop +800013f8: 00000013 nop +800013fc: 00000013 nop +80001400: 00000013 nop +80001404: 00000013 nop +80001408: 00000013 nop +8000140c: 00000013 nop +80001410: 00000013 nop +80001414: 00000013 nop +80001418: 00000013 nop +8000141c: 00000013 nop +80001420: 00000013 nop +80001424: 00000013 nop +80001428: 00000013 nop +8000142c: 00000013 nop +80001430: 00000013 nop +80001434: 00000013 nop +80001438: 00000013 nop +8000143c: 00000013 nop +80001440: 00000013 nop +80001444: 00000013 nop +80001448: 00000013 nop +8000144c: 00000013 nop +80001450: 00000013 nop +80001454: 00000013 nop +80001458: 00000013 nop +8000145c: 00000013 nop +80001460: 00000013 nop +80001464: 00000013 nop +80001468: 00000013 nop +8000146c: 00000013 nop +80001470: 00000013 nop +80001474: 00000013 nop +80001478: 00000013 nop +8000147c: 00000013 nop +80001480: 00000013 nop +80001484: 00000013 nop +80001488: 00000013 nop +8000148c: 00000013 nop +80001490: 00000013 nop +80001494: 00000013 nop +80001498: 00000013 nop +8000149c: 00000013 nop +800014a0: 00000013 nop +800014a4: 00000013 nop +800014a8: 00000013 nop +800014ac: 00000013 nop +800014b0: 00000013 nop +800014b4: 00000013 nop +800014b8: 00000013 nop +800014bc: 00000013 nop +800014c0: 00000013 nop +800014c4: 00000013 nop +800014c8: 00000013 nop +800014cc: 00000013 nop +800014d0: 00000013 nop +800014d4: 00000013 nop +800014d8: 00000013 nop +800014dc: 00000013 nop +800014e0: 00000013 nop +800014e4: 00000013 nop +800014e8: 00000013 nop +800014ec: 00000013 nop +800014f0: 00000013 nop +800014f4: 00000013 nop +800014f8: 00000013 nop +800014fc: 00000013 nop +80001500: 00000013 nop +80001504: 00000013 nop +80001508: 00000013 nop +8000150c: 00000013 nop +80001510: 00000013 nop +80001514: 00000013 nop +80001518: 00000013 nop +8000151c: 00000013 nop +80001520: 00000013 nop +80001524: 00000013 nop +80001528: 00000013 nop +8000152c: 00000013 nop +80001530: 00000013 nop +80001534: 00000013 nop +80001538: 00000013 nop +8000153c: 00000013 nop +80001540: 00000013 nop +80001544: 00000013 nop +80001548: 00000013 nop +8000154c: 00000013 nop +80001550: 00000013 nop +80001554: 00000013 nop +80001558: 00000013 nop +8000155c: 00000013 nop +80001560: 00000013 nop +80001564: 00000013 nop +80001568: 00000013 nop +8000156c: 00000013 nop +80001570: 00000013 nop +80001574: 00000013 nop +80001578: 00000013 nop +8000157c: 00000013 nop +80001580: 00000013 nop +80001584: 00000013 nop +80001588: 00000013 nop +8000158c: 00000013 nop +80001590: 00000013 nop +80001594: 00000013 nop +80001598: 00000013 nop +8000159c: 00000013 nop +800015a0: 00000013 nop +800015a4: 00000013 nop +800015a8: 00000013 nop +800015ac: 00000013 nop +800015b0: 00000013 nop +800015b4: 00000013 nop +800015b8: 00000013 nop +800015bc: 00000013 nop +800015c0: 00000013 nop +800015c4: 00000013 nop +800015c8: 00000013 nop +800015cc: 00000013 nop +800015d0: 00000013 nop +800015d4: 00000013 nop +800015d8: 00000013 nop +800015dc: 00000013 nop +800015e0: 00000013 nop +800015e4: 00000013 nop +800015e8: 00000013 nop +800015ec: 00000013 nop +800015f0: 00000013 nop +800015f4: 00000013 nop +800015f8: 00000013 nop +800015fc: 00000013 nop +80001600: 00000013 nop +80001604: 00000013 nop +80001608: 00000013 nop +8000160c: 00000013 nop +80001610: 00000013 nop +80001614: 00000013 nop +80001618: 00000013 nop +8000161c: 00000013 nop +80001620: 00000013 nop +80001624: 00000013 nop +80001628: 00000013 nop +8000162c: 00000013 nop +80001630: 00000013 nop +80001634: 00000013 nop +80001638: 00000013 nop +8000163c: 00000013 nop +80001640: 00000013 nop +80001644: 00000013 nop +80001648: 00000013 nop +8000164c: 00000013 nop +80001650: 00000013 nop +80001654: 00000013 nop +80001658: 00000013 nop +8000165c: 00000013 nop +80001660: 00000013 nop +80001664: 00000013 nop +80001668: 00000013 nop +8000166c: 00000013 nop +80001670: 00000013 nop +80001674: 00000013 nop +80001678: 00000013 nop +8000167c: 00000013 nop +80001680: 00000013 nop +80001684: 00000013 nop +80001688: 00000013 nop +8000168c: 00000013 nop +80001690: 00000013 nop +80001694: 00000013 nop +80001698: 00000013 nop +8000169c: 00000013 nop +800016a0: 00000013 nop +800016a4: 00000013 nop +800016a8: 00000013 nop +800016ac: 00000013 nop +800016b0: 00000013 nop +800016b4: 00000013 nop +800016b8: 00000013 nop +800016bc: 00000013 nop +800016c0: 00000013 nop +800016c4: 00000013 nop +800016c8: 00000013 nop +800016cc: 00000013 nop +800016d0: 00000013 nop +800016d4: 00000013 nop +800016d8: 00000013 nop +800016dc: 00000013 nop +800016e0: 00000013 nop +800016e4: 00000013 nop +800016e8: 00000013 nop +800016ec: 00000013 nop +800016f0: 00000013 nop +800016f4: 00000013 nop +800016f8: 00000013 nop +800016fc: 00000013 nop +80001700: 00000013 nop +80001704: 00000013 nop +80001708: 00000013 nop +8000170c: 00000013 nop +80001710: 00000013 nop +80001714: 00000013 nop +80001718: 00000013 nop +8000171c: 00000013 nop +80001720: 00000013 nop +80001724: 00000013 nop +80001728: 00000013 nop +8000172c: 00000013 nop +80001730: 00000013 nop +80001734: 00000013 nop +80001738: 00000013 nop +8000173c: 00000013 nop +80001740: 00000013 nop +80001744: 00000013 nop +80001748: 00000013 nop +8000174c: 00000013 nop +80001750: 00000013 nop +80001754: 00000013 nop +80001758: 00000013 nop +8000175c: 00000013 nop +80001760: 00000013 nop +80001764: 00000013 nop +80001768: 00000013 nop +8000176c: 00000013 nop +80001770: 00000013 nop +80001774: 00000013 nop +80001778: 00000013 nop +8000177c: 00000013 nop +80001780: 00000013 nop +80001784: 00000013 nop +80001788: 00000013 nop +8000178c: 00000013 nop +80001790: 00000013 nop +80001794: 00000013 nop +80001798: 00000013 nop +8000179c: 00000013 nop +800017a0: 00000013 nop +800017a4: 00000013 nop +800017a8: 00000013 nop +800017ac: 00000013 nop +800017b0: 00000013 nop +800017b4: 00000013 nop +800017b8: 00000013 nop +800017bc: 00000013 nop +800017c0: 00000013 nop +800017c4: 00000013 nop +800017c8: 00000013 nop +800017cc: 00000013 nop +800017d0: 00000013 nop +800017d4: 00000013 nop +800017d8: 00000013 nop +800017dc: 00000013 nop +800017e0: 00000013 nop +800017e4: 00000013 nop +800017e8: 00000013 nop +800017ec: 00000013 nop +800017f0: 00000013 nop +800017f4: 00000013 nop +800017f8: 00000013 nop +800017fc: 00000013 nop +80001800: 00000013 nop +80001804: 00000013 nop +80001808: 00000013 nop +8000180c: 00000013 nop +80001810: 00000013 nop +80001814: 00000013 nop +80001818: 00000013 nop +8000181c: 00000013 nop +80001820: 00000013 nop +80001824: 00000013 nop +80001828: 00000013 nop +8000182c: 00000013 nop +80001830: 00000013 nop +80001834: 00000013 nop +80001838: 00000013 nop +8000183c: 00000013 nop +80001840: 00000013 nop +80001844: 00000013 nop +80001848: 00000013 nop +8000184c: 00000013 nop +80001850: 00000013 nop +80001854: 00000013 nop +80001858: 00000013 nop +8000185c: 00000013 nop +80001860: 00000013 nop +80001864: 00000013 nop +80001868: 00000013 nop +8000186c: 00000013 nop +80001870: 00000013 nop +80001874: 00000013 nop +80001878: 00000013 nop +8000187c: 00000013 nop +80001880: 00000013 nop +80001884: 00000013 nop +80001888: 00000013 nop +8000188c: 00000013 nop +80001890: 00000013 nop +80001894: 00000013 nop +80001898: 00000013 nop +8000189c: 00000013 nop +800018a0: 00000013 nop +800018a4: 00000013 nop +800018a8: 00000013 nop +800018ac: 00000013 nop +800018b0: 00000013 nop +800018b4: 00000013 nop +800018b8: 00000013 nop +800018bc: 00000013 nop +800018c0: 00000013 nop +800018c4: 00000013 nop +800018c8: 00000013 nop +800018cc: 00000013 nop +800018d0: 00000013 nop +800018d4: 00000013 nop +800018d8: 00000013 nop +800018dc: 00000013 nop +800018e0: 00000013 nop +800018e4: 00000013 nop +800018e8: 00000013 nop +800018ec: 00000013 nop +800018f0: 00000013 nop +800018f4: 00000013 nop +800018f8: 00000013 nop +800018fc: 00000013 nop +80001900: 00000013 nop +80001904: 00000013 nop +80001908: 00000013 nop +8000190c: 00000013 nop +80001910: 00000013 nop +80001914: 00000013 nop +80001918: 00000013 nop +8000191c: 00000013 nop +80001920: 00000013 nop +80001924: 00000013 nop +80001928: 00000013 nop +8000192c: 00000013 nop +80001930: 00000013 nop +80001934: 00000013 nop +80001938: 00000013 nop +8000193c: 00000013 nop +80001940: 00000013 nop +80001944: 00000013 nop +80001948: 00000013 nop +8000194c: 00000013 nop +80001950: 00000013 nop +80001954: 00000013 nop +80001958: 00000013 nop +8000195c: 00000013 nop +80001960: 00000013 nop +80001964: 00000013 nop +80001968: 00000013 nop +8000196c: 00000013 nop +80001970: 00000013 nop +80001974: 00000013 nop +80001978: 00000013 nop +8000197c: 00000013 nop +80001980: 00000013 nop +80001984: 00000013 nop +80001988: 00000013 nop +8000198c: 00000013 nop +80001990: 00000013 nop +80001994: 00000013 nop +80001998: 00000013 nop +8000199c: 00000013 nop +800019a0: 00000013 nop +800019a4: 00000013 nop +800019a8: 00000013 nop +800019ac: 00000013 nop +800019b0: 00000013 nop +800019b4: 00000013 nop +800019b8: 00000013 nop +800019bc: 00000013 nop +800019c0: 00000013 nop +800019c4: 00000013 nop +800019c8: 00000013 nop +800019cc: 00000013 nop +800019d0: 00000013 nop +800019d4: 00000013 nop +800019d8: 00000013 nop +800019dc: 00000013 nop +800019e0: 00000013 nop +800019e4: 00000013 nop +800019e8: 00000013 nop +800019ec: 00000013 nop +800019f0: 00000013 nop +800019f4: 00000013 nop +800019f8: 00000013 nop +800019fc: 00000013 nop +80001a00: 00000013 nop +80001a04: 00000013 nop +80001a08: 00000013 nop +80001a0c: 00000013 nop +80001a10: 00000013 nop +80001a14: 00000013 nop +80001a18: 00000013 nop +80001a1c: 00000013 nop +80001a20: 00000013 nop +80001a24: 00000013 nop +80001a28: 00000013 nop +80001a2c: 00000013 nop +80001a30: 00000013 nop +80001a34: 00000013 nop +80001a38: 00000013 nop +80001a3c: 00000013 nop +80001a40: 00000013 nop +80001a44: 00000013 nop +80001a48: 00000013 nop +80001a4c: 00000013 nop +80001a50: 00000013 nop +80001a54: 00000013 nop +80001a58: 00000013 nop +80001a5c: 00000013 nop +80001a60: 00000013 nop +80001a64: 00000013 nop +80001a68: 00000013 nop +80001a6c: 00000013 nop +80001a70: 00000013 nop +80001a74: 00000013 nop +80001a78: 00000013 nop +80001a7c: 00000013 nop +80001a80: 00000013 nop +80001a84: 00000013 nop +80001a88: 00000013 nop +80001a8c: 00000013 nop +80001a90: 00000013 nop +80001a94: 00000013 nop +80001a98: 00000013 nop +80001a9c: 00000013 nop +80001aa0: 00000013 nop +80001aa4: 00000013 nop +80001aa8: 00000013 nop +80001aac: 00000013 nop +80001ab0: 00000013 nop +80001ab4: 00000013 nop +80001ab8: 00000013 nop +80001abc: 00000013 nop +80001ac0: 00000013 nop +80001ac4: 00000013 nop +80001ac8: 00000013 nop +80001acc: 00000013 nop +80001ad0: 00000013 nop +80001ad4: 00000013 nop +80001ad8: 00000013 nop +80001adc: 00000013 nop +80001ae0: 00000013 nop +80001ae4: 00000013 nop +80001ae8: 00000013 nop +80001aec: 00000013 nop +80001af0: 00000013 nop +80001af4: 00000013 nop +80001af8: 00000013 nop +80001afc: 00000013 nop +80001b00: 00000013 nop +80001b04: 00000013 nop +80001b08: 00000013 nop +80001b0c: 00000013 nop +80001b10: 00000013 nop +80001b14: 00000013 nop +80001b18: 00000013 nop +80001b1c: 00000013 nop +80001b20: 00000013 nop +80001b24: 00000013 nop +80001b28: 00000013 nop +80001b2c: 00000013 nop +80001b30: 00000013 nop +80001b34: 00000013 nop +80001b38: 00000013 nop +80001b3c: 00000013 nop +80001b40: 00000013 nop +80001b44: 00000013 nop +80001b48: 00000013 nop +80001b4c: 00000013 nop +80001b50: 00000013 nop +80001b54: 00000013 nop +80001b58: 00000013 nop +80001b5c: 00000013 nop +80001b60: 00000013 nop +80001b64: 00000013 nop +80001b68: 00000013 nop +80001b6c: 00000013 nop +80001b70: 00000013 nop +80001b74: 00000013 nop +80001b78: 00000013 nop +80001b7c: 00000013 nop +80001b80: 00000013 nop +80001b84: 00000013 nop +80001b88: 00000013 nop +80001b8c: 00000013 nop +80001b90: 00000013 nop +80001b94: 00000013 nop +80001b98: 00000013 nop +80001b9c: 00000013 nop +80001ba0: 00000013 nop +80001ba4: 00000013 nop +80001ba8: 00000013 nop +80001bac: 00000013 nop +80001bb0: 00000013 nop +80001bb4: 00000013 nop +80001bb8: 00000013 nop +80001bbc: 00000013 nop +80001bc0: 00000013 nop +80001bc4: 00000013 nop +80001bc8: 00000013 nop +80001bcc: 00000013 nop +80001bd0: 00000013 nop +80001bd4: 00000013 nop +80001bd8: 00000013 nop +80001bdc: 00000013 nop +80001be0: 00000013 nop +80001be4: 00000013 nop +80001be8: 00000013 nop +80001bec: 00000013 nop +80001bf0: 00000013 nop +80001bf4: 00000013 nop +80001bf8: 00000013 nop +80001bfc: 00000013 nop +80001c00: 00000013 nop +80001c04: 00000013 nop +80001c08: 00000013 nop +80001c0c: 00000013 nop +80001c10: 00000013 nop +80001c14: 00000013 nop +80001c18: 00000013 nop +80001c1c: 00000013 nop +80001c20: 00000013 nop +80001c24: 00000013 nop +80001c28: 00000013 nop +80001c2c: 00000013 nop +80001c30: 00000013 nop +80001c34: 00000013 nop +80001c38: 00000013 nop +80001c3c: 00000013 nop +80001c40: 00000013 nop +80001c44: 00000013 nop +80001c48: 00000013 nop +80001c4c: 00000013 nop +80001c50: 00000013 nop +80001c54: 00000013 nop +80001c58: 00000013 nop +80001c5c: 00000013 nop +80001c60: 00000013 nop +80001c64: 00000013 nop +80001c68: 00000013 nop +80001c6c: 00000013 nop +80001c70: 00000013 nop +80001c74: 00000013 nop +80001c78: 00000013 nop +80001c7c: 00000013 nop +80001c80: 00000013 nop +80001c84: 00000013 nop +80001c88: 00000013 nop +80001c8c: 00000013 nop +80001c90: 00000013 nop +80001c94: 00000013 nop +80001c98: 00000013 nop +80001c9c: 00000013 nop +80001ca0: 00000013 nop +80001ca4: 00000013 nop +80001ca8: 00000013 nop +80001cac: 00000013 nop +80001cb0: 00000013 nop +80001cb4: 00000013 nop +80001cb8: 00000013 nop +80001cbc: 00000013 nop +80001cc0: 00000013 nop +80001cc4: 00000013 nop +80001cc8: 00000013 nop +80001ccc: 00000013 nop +80001cd0: 00000013 nop +80001cd4: 00000013 nop +80001cd8: 00000013 nop +80001cdc: 00000013 nop +80001ce0: 00000013 nop +80001ce4: 00000013 nop +80001ce8: 00000013 nop +80001cec: 00000013 nop +80001cf0: 00000013 nop +80001cf4: 00000013 nop +80001cf8: 00000013 nop +80001cfc: 00000013 nop +80001d00: 00000013 nop +80001d04: 00000013 nop +80001d08: 00000013 nop +80001d0c: 00000013 nop +80001d10: 00000013 nop +80001d14: 00000013 nop +80001d18: 00000013 nop +80001d1c: 00000013 nop +80001d20: 00000013 nop +80001d24: 00000013 nop +80001d28: 00000013 nop +80001d2c: 00000013 nop +80001d30: 00000013 nop +80001d34: 00000013 nop +80001d38: 00000013 nop +80001d3c: 00000013 nop +80001d40: 00000013 nop +80001d44: 00000013 nop +80001d48: 00000013 nop +80001d4c: 00000013 nop +80001d50: 00000013 nop +80001d54: 00000013 nop +80001d58: 00000013 nop +80001d5c: 00000013 nop +80001d60: 00000013 nop +80001d64: 00000013 nop +80001d68: 00000013 nop +80001d6c: 00000013 nop +80001d70: 00000013 nop +80001d74: 00000013 nop +80001d78: 00000013 nop +80001d7c: 00000013 nop +80001d80: 00000013 nop +80001d84: 00000013 nop +80001d88: 00000013 nop +80001d8c: 00000013 nop +80001d90: 00000013 nop +80001d94: 00000013 nop +80001d98: 00000013 nop +80001d9c: 00000013 nop +80001da0: 00000013 nop +80001da4: 00000013 nop +80001da8: 00000013 nop +80001dac: 00000013 nop +80001db0: 00000013 nop +80001db4: 00000013 nop +80001db8: 00000013 nop +80001dbc: 00000013 nop +80001dc0: 00000013 nop +80001dc4: 00000013 nop +80001dc8: 00000013 nop +80001dcc: 00000013 nop +80001dd0: 00000013 nop +80001dd4: 00000013 nop +80001dd8: 00000013 nop +80001ddc: 00000013 nop +80001de0: 00000013 nop +80001de4: 00000013 nop +80001de8: 00000013 nop +80001dec: 00000013 nop +80001df0: 00000013 nop +80001df4: 00000013 nop +80001df8: 00000013 nop +80001dfc: 00000013 nop +80001e00: 00000013 nop +80001e04: 00000013 nop +80001e08: 00000013 nop +80001e0c: 00000013 nop +80001e10: 00000013 nop +80001e14: 00000013 nop +80001e18: 00000013 nop +80001e1c: 00000013 nop +80001e20: 00000013 nop +80001e24: 00000013 nop +80001e28: 00000013 nop +80001e2c: 00000013 nop +80001e30: 00000013 nop +80001e34: 00000013 nop +80001e38: 00000013 nop +80001e3c: 00000013 nop +80001e40: 00000013 nop +80001e44: 00000013 nop +80001e48: 00000013 nop +80001e4c: 00000013 nop +80001e50: 00000013 nop +80001e54: 00000013 nop +80001e58: 00000013 nop +80001e5c: 00000013 nop +80001e60: 00000013 nop +80001e64: 00000013 nop +80001e68: 00000013 nop +80001e6c: 00000013 nop +80001e70: 00000013 nop +80001e74: 00000013 nop +80001e78: 00000013 nop +80001e7c: 00000013 nop +80001e80: 00000013 nop +80001e84: 00000013 nop +80001e88: 00000013 nop +80001e8c: 00000013 nop +80001e90: 00000013 nop +80001e94: 00000013 nop +80001e98: 00000013 nop +80001e9c: 00000013 nop +80001ea0: 00000013 nop +80001ea4: 00000013 nop +80001ea8: 00000013 nop +80001eac: 00000013 nop +80001eb0: 00000013 nop +80001eb4: 00000013 nop +80001eb8: 00000013 nop +80001ebc: 00000013 nop +80001ec0: 00000013 nop +80001ec4: 00000013 nop +80001ec8: 00000013 nop +80001ecc: 00000013 nop +80001ed0: 00000013 nop +80001ed4: 00000013 nop +80001ed8: 00000013 nop +80001edc: 00000013 nop +80001ee0: 00000013 nop +80001ee4: 00000013 nop +80001ee8: 00000013 nop +80001eec: 00000013 nop +80001ef0: 00000013 nop +80001ef4: 00000013 nop +80001ef8: 00000013 nop +80001efc: 00000013 nop +80001f00: 00000013 nop +80001f04: 00000013 nop +80001f08: 00000013 nop +80001f0c: 00000013 nop +80001f10: 00000013 nop +80001f14: 00000013 nop +80001f18: 00000013 nop +80001f1c: 00000013 nop +80001f20: 00000013 nop +80001f24: 00000013 nop +80001f28: 00000013 nop +80001f2c: 00000013 nop +80001f30: 00000013 nop +80001f34: 00000013 nop +80001f38: 00000013 nop +80001f3c: 00000013 nop +80001f40: 00000013 nop +80001f44: 00000013 nop +80001f48: 00000013 nop +80001f4c: 00000013 nop +80001f50: 00000013 nop +80001f54: 00000013 nop +80001f58: 00000013 nop +80001f5c: 00000013 nop +80001f60: 00000013 nop +80001f64: 00000013 nop +80001f68: 00000013 nop +80001f6c: 00000013 nop +80001f70: 00000013 nop +80001f74: 00000013 nop +80001f78: 00000013 nop +80001f7c: 00000013 nop +80001f80: 00000013 nop +80001f84: 00000013 nop +80001f88: 00000013 nop +80001f8c: 00000013 nop +80001f90: 00000013 nop +80001f94: 00000013 nop +80001f98: 00000013 nop +80001f9c: 00000013 nop +80001fa0: 00000013 nop +80001fa4: 00000013 nop +80001fa8: 00000013 nop +80001fac: 00000013 nop +80001fb0: 00000013 nop +80001fb4: 00000013 nop +80001fb8: 00000013 nop +80001fbc: 00000013 nop +80001fc0: 00000013 nop +80001fc4: 00000013 nop +80001fc8: 00000013 nop +80001fcc: 00000013 nop +80001fd0: 00000013 nop +80001fd4: 00000013 nop +80001fd8: 00000013 nop +80001fdc: 00000013 nop +80001fe0: 00000013 nop +80001fe4: 00000013 nop +80001fe8: 00000013 nop +80001fec: 00000013 nop +80001ff0: 00000013 nop +80001ff4: 00000013 nop +80001ff8: 00000013 nop +80001ffc: 00000013 nop + +80002000 : +80002000: 00000000 .word 0x00000000 +80002004: 00000013 nop +80002008: 00000013 nop +8000200c: 00000013 nop +80002010: 00000013 nop +80002014: 00000013 nop +80002018: 00000013 nop +8000201c: 00000013 nop +80002020: 00000013 nop +80002024: 00000013 nop +80002028: 00000013 nop +8000202c: 00000013 nop +80002030: 00000013 nop +80002034: 00000013 nop +80002038: 00000013 nop +8000203c: 00000013 nop +80002040: 00000013 nop +80002044: 00000013 nop +80002048: 00000013 nop +8000204c: 00000013 nop +80002050: 00000013 nop +80002054: 00000013 nop +80002058: 00000013 nop +8000205c: 00000013 nop +80002060: 00000013 nop +80002064: 00000013 nop +80002068: 00000013 nop +8000206c: 00000013 nop +80002070: 00000013 nop +80002074: 00000013 nop +80002078: 00000013 nop +8000207c: 00000013 nop +80002080: 00000013 nop +80002084: 00000013 nop +80002088: 00000013 nop +8000208c: 00000013 nop +80002090: 00000013 nop +80002094: 00000013 nop +80002098: 00000013 nop +8000209c: 00000013 nop +800020a0: 00000013 nop +800020a4: 00000013 nop +800020a8: 00000013 nop +800020ac: 00000013 nop +800020b0: 00000013 nop +800020b4: 00000013 nop +800020b8: 00000013 nop +800020bc: 00000013 nop +800020c0: 00000013 nop +800020c4: 00000013 nop +800020c8: 00000013 nop +800020cc: 00000013 nop +800020d0: 00000013 nop +800020d4: 00000013 nop +800020d8: 00000013 nop +800020dc: 00000013 nop +800020e0: 00000013 nop +800020e4: 00000013 nop +800020e8: 00000013 nop +800020ec: 00000013 nop +800020f0: 00000013 nop +800020f4: 00000013 nop +800020f8: 00000013 nop +800020fc: 00000013 nop +80002100: 00000013 nop +80002104: 00000013 nop +80002108: 00000013 nop +8000210c: 00000013 nop +80002110: 00000013 nop +80002114: 00000013 nop +80002118: 00000013 nop +8000211c: 00000013 nop +80002120: 00000013 nop +80002124: 00000013 nop +80002128: 00000013 nop +8000212c: 00000013 nop +80002130: 00000013 nop +80002134: 00000013 nop +80002138: 00000013 nop +8000213c: 00000013 nop +80002140: 00000013 nop +80002144: 00000013 nop +80002148: 00000013 nop +8000214c: 00000013 nop +80002150: 00000013 nop +80002154: 00000013 nop +80002158: 00000013 nop +8000215c: 00000013 nop +80002160: 00000013 nop +80002164: 00000013 nop +80002168: 00000013 nop +8000216c: 00000013 nop +80002170: 00000013 nop +80002174: 00000013 nop +80002178: 00000013 nop +8000217c: 00000013 nop +80002180: 00000013 nop +80002184: 00000013 nop +80002188: 00000013 nop +8000218c: 00000013 nop +80002190: 00000013 nop +80002194: 00000013 nop +80002198: 00000013 nop +8000219c: 00000013 nop +800021a0: 00000013 nop +800021a4: 00000013 nop +800021a8: 00000013 nop +800021ac: 00000013 nop +800021b0: 00000013 nop +800021b4: 00000013 nop +800021b8: 00000013 nop +800021bc: 00000013 nop +800021c0: 00000013 nop +800021c4: 00000013 nop +800021c8: 00000013 nop +800021cc: 00000013 nop +800021d0: 00000013 nop +800021d4: 00000013 nop +800021d8: 00000013 nop +800021dc: 00000013 nop +800021e0: 00000013 nop +800021e4: 00000013 nop +800021e8: 00000013 nop +800021ec: 00000013 nop +800021f0: 00000013 nop +800021f4: 00000013 nop +800021f8: 00000013 nop +800021fc: 00000013 nop +80002200: 00000013 nop +80002204: 00000013 nop +80002208: 00000013 nop +8000220c: 00000013 nop +80002210: 00000013 nop +80002214: 00000013 nop +80002218: 00000013 nop +8000221c: 00000013 nop +80002220: 00000013 nop +80002224: 00000013 nop +80002228: 00000013 nop +8000222c: 00000013 nop +80002230: 00000013 nop +80002234: 00000013 nop +80002238: 00000013 nop +8000223c: 00000013 nop +80002240: 00000013 nop +80002244: 00000013 nop +80002248: 00000013 nop +8000224c: 00000013 nop +80002250: 00000013 nop +80002254: 00000013 nop +80002258: 00000013 nop +8000225c: 00000013 nop +80002260: 00000013 nop +80002264: 00000013 nop +80002268: 00000013 nop +8000226c: 00000013 nop +80002270: 00000013 nop +80002274: 00000013 nop +80002278: 00000013 nop +8000227c: 00000013 nop +80002280: 00000013 nop +80002284: 00000013 nop +80002288: 00000013 nop +8000228c: 00000013 nop +80002290: 00000013 nop +80002294: 00000013 nop +80002298: 00000013 nop +8000229c: 00000013 nop +800022a0: 00000013 nop +800022a4: 00000013 nop +800022a8: 00000013 nop +800022ac: 00000013 nop +800022b0: 00000013 nop +800022b4: 00000013 nop +800022b8: 00000013 nop +800022bc: 00000013 nop +800022c0: 00000013 nop +800022c4: 00000013 nop +800022c8: 00000013 nop +800022cc: 00000013 nop +800022d0: 00000013 nop +800022d4: 00000013 nop +800022d8: 00000013 nop +800022dc: 00000013 nop +800022e0: 00000013 nop +800022e4: 00000013 nop +800022e8: 00000013 nop +800022ec: 00000013 nop +800022f0: 00000013 nop +800022f4: 00000013 nop +800022f8: 00000013 nop +800022fc: 00000013 nop +80002300: 00000013 nop +80002304: 00000013 nop +80002308: 00000013 nop +8000230c: 00000013 nop +80002310: 00000013 nop +80002314: 00000013 nop +80002318: 00000013 nop +8000231c: 00000013 nop +80002320: 00000013 nop +80002324: 00000013 nop +80002328: 00000013 nop +8000232c: 00000013 nop +80002330: 00000013 nop +80002334: 00000013 nop +80002338: 00000013 nop +8000233c: 00000013 nop +80002340: 00000013 nop +80002344: 00000013 nop +80002348: 00000013 nop +8000234c: 00000013 nop +80002350: 00000013 nop +80002354: 00000013 nop +80002358: 00000013 nop +8000235c: 00000013 nop +80002360: 00000013 nop +80002364: 00000013 nop +80002368: 00000013 nop +8000236c: 00000013 nop +80002370: 00000013 nop +80002374: 00000013 nop +80002378: 00000013 nop +8000237c: 00000013 nop +80002380: 00000013 nop +80002384: 00000013 nop +80002388: 00000013 nop +8000238c: 00000013 nop +80002390: 00000013 nop +80002394: 00000013 nop +80002398: 00000013 nop +8000239c: 00000013 nop +800023a0: 00000013 nop +800023a4: 00000013 nop +800023a8: 00000013 nop +800023ac: 00000013 nop +800023b0: 00000013 nop +800023b4: 00000013 nop +800023b8: 00000013 nop +800023bc: 00000013 nop +800023c0: 00000013 nop +800023c4: 00000013 nop +800023c8: 00000013 nop +800023cc: 00000013 nop +800023d0: 00000013 nop +800023d4: 00000013 nop +800023d8: 00000013 nop +800023dc: 00000013 nop +800023e0: 00000013 nop +800023e4: 00000013 nop +800023e8: 00000013 nop +800023ec: 00000013 nop +800023f0: 00000013 nop +800023f4: 00000013 nop +800023f8: 00000013 nop +800023fc: 00000013 nop +80002400: 00000013 nop +80002404: 00000013 nop +80002408: 00000013 nop +8000240c: 00000013 nop +80002410: 00000013 nop +80002414: 00000013 nop +80002418: 00000013 nop +8000241c: 00000013 nop +80002420: 00000013 nop +80002424: 00000013 nop +80002428: 00000013 nop +8000242c: 00000013 nop +80002430: 00000013 nop +80002434: 00000013 nop +80002438: 00000013 nop +8000243c: 00000013 nop +80002440: 00000013 nop +80002444: 00000013 nop +80002448: 00000013 nop +8000244c: 00000013 nop +80002450: 00000013 nop +80002454: 00000013 nop +80002458: 00000013 nop +8000245c: 00000013 nop +80002460: 00000013 nop +80002464: 00000013 nop +80002468: 00000013 nop +8000246c: 00000013 nop +80002470: 00000013 nop +80002474: 00000013 nop +80002478: 00000013 nop +8000247c: 00000013 nop +80002480: 00000013 nop +80002484: 00000013 nop +80002488: 00000013 nop +8000248c: 00000013 nop +80002490: 00000013 nop +80002494: 00000013 nop +80002498: 00000013 nop +8000249c: 00000013 nop +800024a0: 00000013 nop +800024a4: 00000013 nop +800024a8: 00000013 nop +800024ac: 00000013 nop +800024b0: 00000013 nop +800024b4: 00000013 nop +800024b8: 00000013 nop +800024bc: 00000013 nop +800024c0: 00000013 nop +800024c4: 00000013 nop +800024c8: 00000013 nop +800024cc: 00000013 nop +800024d0: 00000013 nop +800024d4: 00000013 nop +800024d8: 00000013 nop +800024dc: 00000013 nop +800024e0: 00000013 nop +800024e4: 00000013 nop +800024e8: 00000013 nop +800024ec: 00000013 nop +800024f0: 00000013 nop +800024f4: 00000013 nop +800024f8: 00000013 nop +800024fc: 00000013 nop +80002500: 00000013 nop +80002504: 00000013 nop +80002508: 00000013 nop +8000250c: 00000013 nop +80002510: 00000013 nop +80002514: 00000013 nop +80002518: 00000013 nop +8000251c: 00000013 nop +80002520: 00000013 nop +80002524: 00000013 nop +80002528: 00000013 nop +8000252c: 00000013 nop +80002530: 00000013 nop +80002534: 00000013 nop +80002538: 00000013 nop +8000253c: 00000013 nop +80002540: 00000013 nop +80002544: 00000013 nop +80002548: 00000013 nop +8000254c: 00000013 nop +80002550: 00000013 nop +80002554: 00000013 nop +80002558: 00000013 nop +8000255c: 00000013 nop +80002560: 00000013 nop +80002564: 00000013 nop +80002568: 00000013 nop +8000256c: 00000013 nop +80002570: 00000013 nop +80002574: 00000013 nop +80002578: 00000013 nop +8000257c: 00000013 nop +80002580: 00000013 nop +80002584: 00000013 nop +80002588: 00000013 nop +8000258c: 00000013 nop +80002590: 00000013 nop +80002594: 00000013 nop +80002598: 00000013 nop +8000259c: 00000013 nop +800025a0: 00000013 nop +800025a4: 00000013 nop +800025a8: 00000013 nop +800025ac: 00000013 nop +800025b0: 00000013 nop +800025b4: 00000013 nop +800025b8: 00000013 nop +800025bc: 00000013 nop +800025c0: 00000013 nop +800025c4: 00000013 nop +800025c8: 00000013 nop +800025cc: 00000013 nop +800025d0: 00000013 nop +800025d4: 00000013 nop +800025d8: 00000013 nop +800025dc: 00000013 nop +800025e0: 00000013 nop +800025e4: 00000013 nop +800025e8: 00000013 nop +800025ec: 00000013 nop +800025f0: 00000013 nop +800025f4: 00000013 nop +800025f8: 00000013 nop +800025fc: 00000013 nop +80002600: 00000013 nop +80002604: 00000013 nop +80002608: 00000013 nop +8000260c: 00000013 nop +80002610: 00000013 nop +80002614: 00000013 nop +80002618: 00000013 nop +8000261c: 00000013 nop +80002620: 00000013 nop +80002624: 00000013 nop +80002628: 00000013 nop +8000262c: 00000013 nop +80002630: 00000013 nop +80002634: 00000013 nop +80002638: 00000013 nop +8000263c: 00000013 nop +80002640: 00000013 nop +80002644: 00000013 nop +80002648: 00000013 nop +8000264c: 00000013 nop +80002650: 00000013 nop +80002654: 00000013 nop +80002658: 00000013 nop +8000265c: 00000013 nop +80002660: 00000013 nop +80002664: 00000013 nop +80002668: 00000013 nop +8000266c: 00000013 nop +80002670: 00000013 nop +80002674: 00000013 nop +80002678: 00000013 nop +8000267c: 00000013 nop +80002680: 00000013 nop +80002684: 00000013 nop +80002688: 00000013 nop +8000268c: 00000013 nop +80002690: 00000013 nop +80002694: 00000013 nop +80002698: 00000013 nop +8000269c: 00000013 nop +800026a0: 00000013 nop +800026a4: 00000013 nop +800026a8: 00000013 nop +800026ac: 00000013 nop +800026b0: 00000013 nop +800026b4: 00000013 nop +800026b8: 00000013 nop +800026bc: 00000013 nop +800026c0: 00000013 nop +800026c4: 00000013 nop +800026c8: 00000013 nop +800026cc: 00000013 nop +800026d0: 00000013 nop +800026d4: 00000013 nop +800026d8: 00000013 nop +800026dc: 00000013 nop +800026e0: 00000013 nop +800026e4: 00000013 nop +800026e8: 00000013 nop +800026ec: 00000013 nop +800026f0: 00000013 nop +800026f4: 00000013 nop +800026f8: 00000013 nop +800026fc: 00000013 nop +80002700: 00000013 nop +80002704: 00000013 nop +80002708: 00000013 nop +8000270c: 00000013 nop +80002710: 00000013 nop +80002714: 00000013 nop +80002718: 00000013 nop +8000271c: 00000013 nop +80002720: 00000013 nop +80002724: 00000013 nop +80002728: 00000013 nop +8000272c: 00000013 nop +80002730: 00000013 nop +80002734: 00000013 nop +80002738: 00000013 nop +8000273c: 00000013 nop +80002740: 00000013 nop +80002744: 00000013 nop +80002748: 00000013 nop +8000274c: 00000013 nop +80002750: 00000013 nop +80002754: 00000013 nop +80002758: 00000013 nop +8000275c: 00000013 nop +80002760: 00000013 nop +80002764: 00000013 nop +80002768: 00000013 nop +8000276c: 00000013 nop +80002770: 00000013 nop +80002774: 00000013 nop +80002778: 00000013 nop +8000277c: 00000013 nop +80002780: 00000013 nop +80002784: 00000013 nop +80002788: 00000013 nop +8000278c: 00000013 nop +80002790: 00000013 nop +80002794: 00000013 nop +80002798: 00000013 nop +8000279c: 00000013 nop +800027a0: 00000013 nop +800027a4: 00000013 nop +800027a8: 00000013 nop +800027ac: 00000013 nop +800027b0: 00000013 nop +800027b4: 00000013 nop +800027b8: 00000013 nop +800027bc: 00000013 nop +800027c0: 00000013 nop +800027c4: 00000013 nop +800027c8: 00000013 nop +800027cc: 00000013 nop +800027d0: 00000013 nop +800027d4: 00000013 nop +800027d8: 00000013 nop +800027dc: 00000013 nop +800027e0: 00000013 nop +800027e4: 00000013 nop +800027e8: 00000013 nop +800027ec: 00000013 nop +800027f0: 00000013 nop +800027f4: 00000013 nop +800027f8: 00000013 nop +800027fc: 00000013 nop +80002800: 00000013 nop +80002804: 00000013 nop +80002808: 00000013 nop +8000280c: 00000013 nop +80002810: 00000013 nop +80002814: 00000013 nop +80002818: 00000013 nop +8000281c: 00000013 nop +80002820: 00000013 nop +80002824: 00000013 nop +80002828: 00000013 nop +8000282c: 00000013 nop +80002830: 00000013 nop +80002834: 00000013 nop +80002838: 00000013 nop +8000283c: 00000013 nop +80002840: 00000013 nop +80002844: 00000013 nop +80002848: 00000013 nop +8000284c: 00000013 nop +80002850: 00000013 nop +80002854: 00000013 nop +80002858: 00000013 nop +8000285c: 00000013 nop +80002860: 00000013 nop +80002864: 00000013 nop +80002868: 00000013 nop +8000286c: 00000013 nop +80002870: 00000013 nop +80002874: 00000013 nop +80002878: 00000013 nop +8000287c: 00000013 nop +80002880: 00000013 nop +80002884: 00000013 nop +80002888: 00000013 nop +8000288c: 00000013 nop +80002890: 00000013 nop +80002894: 00000013 nop +80002898: 00000013 nop +8000289c: 00000013 nop +800028a0: 00000013 nop +800028a4: 00000013 nop +800028a8: 00000013 nop +800028ac: 00000013 nop +800028b0: 00000013 nop +800028b4: 00000013 nop +800028b8: 00000013 nop +800028bc: 00000013 nop +800028c0: 00000013 nop +800028c4: 00000013 nop +800028c8: 00000013 nop +800028cc: 00000013 nop +800028d0: 00000013 nop +800028d4: 00000013 nop +800028d8: 00000013 nop +800028dc: 00000013 nop +800028e0: 00000013 nop +800028e4: 00000013 nop +800028e8: 00000013 nop +800028ec: 00000013 nop +800028f0: 00000013 nop +800028f4: 00000013 nop +800028f8: 00000013 nop +800028fc: 00000013 nop +80002900: 00000013 nop +80002904: 00000013 nop +80002908: 00000013 nop +8000290c: 00000013 nop +80002910: 00000013 nop +80002914: 00000013 nop +80002918: 00000013 nop +8000291c: 00000013 nop +80002920: 00000013 nop +80002924: 00000013 nop +80002928: 00000013 nop +8000292c: 00000013 nop +80002930: 00000013 nop +80002934: 00000013 nop +80002938: 00000013 nop +8000293c: 00000013 nop +80002940: 00000013 nop +80002944: 00000013 nop +80002948: 00000013 nop +8000294c: 00000013 nop +80002950: 00000013 nop +80002954: 00000013 nop +80002958: 00000013 nop +8000295c: 00000013 nop +80002960: 00000013 nop +80002964: 00000013 nop +80002968: 00000013 nop +8000296c: 00000013 nop +80002970: 00000013 nop +80002974: 00000013 nop +80002978: 00000013 nop +8000297c: 00000013 nop +80002980: 00000013 nop +80002984: 00000013 nop +80002988: 00000013 nop +8000298c: 00000013 nop +80002990: 00000013 nop +80002994: 00000013 nop +80002998: 00000013 nop +8000299c: 00000013 nop +800029a0: 00000013 nop +800029a4: 00000013 nop +800029a8: 00000013 nop +800029ac: 00000013 nop +800029b0: 00000013 nop +800029b4: 00000013 nop +800029b8: 00000013 nop +800029bc: 00000013 nop +800029c0: 00000013 nop +800029c4: 00000013 nop +800029c8: 00000013 nop +800029cc: 00000013 nop +800029d0: 00000013 nop +800029d4: 00000013 nop +800029d8: 00000013 nop +800029dc: 00000013 nop +800029e0: 00000013 nop +800029e4: 00000013 nop +800029e8: 00000013 nop +800029ec: 00000013 nop +800029f0: 00000013 nop +800029f4: 00000013 nop +800029f8: 00000013 nop +800029fc: 00000013 nop +80002a00: 00000013 nop +80002a04: 00000013 nop +80002a08: 00000013 nop +80002a0c: 00000013 nop +80002a10: 00000013 nop +80002a14: 00000013 nop +80002a18: 00000013 nop +80002a1c: 00000013 nop +80002a20: 00000013 nop +80002a24: 00000013 nop +80002a28: 00000013 nop +80002a2c: 00000013 nop +80002a30: 00000013 nop +80002a34: 00000013 nop +80002a38: 00000013 nop +80002a3c: 00000013 nop +80002a40: 00000013 nop +80002a44: 00000013 nop +80002a48: 00000013 nop +80002a4c: 00000013 nop +80002a50: 00000013 nop +80002a54: 00000013 nop +80002a58: 00000013 nop +80002a5c: 00000013 nop +80002a60: 00000013 nop +80002a64: 00000013 nop +80002a68: 00000013 nop +80002a6c: 00000013 nop +80002a70: 00000013 nop +80002a74: 00000013 nop +80002a78: 00000013 nop +80002a7c: 00000013 nop +80002a80: 00000013 nop +80002a84: 00000013 nop +80002a88: 00000013 nop +80002a8c: 00000013 nop +80002a90: 00000013 nop +80002a94: 00000013 nop +80002a98: 00000013 nop +80002a9c: 00000013 nop +80002aa0: 00000013 nop +80002aa4: 00000013 nop +80002aa8: 00000013 nop +80002aac: 00000013 nop +80002ab0: 00000013 nop +80002ab4: 00000013 nop +80002ab8: 00000013 nop +80002abc: 00000013 nop +80002ac0: 00000013 nop +80002ac4: 00000013 nop +80002ac8: 00000013 nop +80002acc: 00000013 nop +80002ad0: 00000013 nop +80002ad4: 00000013 nop +80002ad8: 00000013 nop +80002adc: 00000013 nop +80002ae0: 00000013 nop +80002ae4: 00000013 nop +80002ae8: 00000013 nop +80002aec: 00000013 nop +80002af0: 00000013 nop +80002af4: 00000013 nop +80002af8: 00000013 nop +80002afc: 00000013 nop +80002b00: 00000013 nop +80002b04: 00000013 nop +80002b08: 00000013 nop +80002b0c: 00000013 nop +80002b10: 00000013 nop +80002b14: 00000013 nop +80002b18: 00000013 nop +80002b1c: 00000013 nop +80002b20: 00000013 nop +80002b24: 00000013 nop +80002b28: 00000013 nop +80002b2c: 00000013 nop +80002b30: 00000013 nop +80002b34: 00000013 nop +80002b38: 00000013 nop +80002b3c: 00000013 nop +80002b40: 00000013 nop +80002b44: 00000013 nop +80002b48: 00000013 nop +80002b4c: 00000013 nop +80002b50: 00000013 nop +80002b54: 00000013 nop +80002b58: 00000013 nop +80002b5c: 00000013 nop +80002b60: 00000013 nop +80002b64: 00000013 nop +80002b68: 00000013 nop +80002b6c: 00000013 nop +80002b70: 00000013 nop +80002b74: 00000013 nop +80002b78: 00000013 nop +80002b7c: 00000013 nop +80002b80: 00000013 nop +80002b84: 00000013 nop +80002b88: 00000013 nop +80002b8c: 00000013 nop +80002b90: 00000013 nop +80002b94: 00000013 nop +80002b98: 00000013 nop +80002b9c: 00000013 nop +80002ba0: 00000013 nop +80002ba4: 00000013 nop +80002ba8: 00000013 nop +80002bac: 00000013 nop +80002bb0: 00000013 nop +80002bb4: 00000013 nop +80002bb8: 00000013 nop +80002bbc: 00000013 nop +80002bc0: 00000013 nop +80002bc4: 00000013 nop +80002bc8: 00000013 nop +80002bcc: 00000013 nop +80002bd0: 00000013 nop +80002bd4: 00000013 nop +80002bd8: 00000013 nop +80002bdc: 00000013 nop +80002be0: 00000013 nop +80002be4: 00000013 nop +80002be8: 00000013 nop +80002bec: 00000013 nop +80002bf0: 00000013 nop +80002bf4: 00000013 nop +80002bf8: 00000013 nop +80002bfc: 00000013 nop +80002c00: 00000013 nop +80002c04: 00000013 nop +80002c08: 00000013 nop +80002c0c: 00000013 nop +80002c10: 00000013 nop +80002c14: 00000013 nop +80002c18: 00000013 nop +80002c1c: 00000013 nop +80002c20: 00000013 nop +80002c24: 00000013 nop +80002c28: 00000013 nop +80002c2c: 00000013 nop +80002c30: 00000013 nop +80002c34: 00000013 nop +80002c38: 00000013 nop +80002c3c: 00000013 nop +80002c40: 00000013 nop +80002c44: 00000013 nop +80002c48: 00000013 nop +80002c4c: 00000013 nop +80002c50: 00000013 nop +80002c54: 00000013 nop +80002c58: 00000013 nop +80002c5c: 00000013 nop +80002c60: 00000013 nop +80002c64: 00000013 nop +80002c68: 00000013 nop +80002c6c: 00000013 nop +80002c70: 00000013 nop +80002c74: 00000013 nop +80002c78: 00000013 nop +80002c7c: 00000013 nop +80002c80: 00000013 nop +80002c84: 00000013 nop +80002c88: 00000013 nop +80002c8c: 00000013 nop +80002c90: 00000013 nop +80002c94: 00000013 nop +80002c98: 00000013 nop +80002c9c: 00000013 nop +80002ca0: 00000013 nop +80002ca4: 00000013 nop +80002ca8: 00000013 nop +80002cac: 00000013 nop +80002cb0: 00000013 nop +80002cb4: 00000013 nop +80002cb8: 00000013 nop +80002cbc: 00000013 nop +80002cc0: 00000013 nop +80002cc4: 00000013 nop +80002cc8: 00000013 nop +80002ccc: 00000013 nop +80002cd0: 00000013 nop +80002cd4: 00000013 nop +80002cd8: 00000013 nop +80002cdc: 00000013 nop +80002ce0: 00000013 nop +80002ce4: 00000013 nop +80002ce8: 00000013 nop +80002cec: 00000013 nop +80002cf0: 00000013 nop +80002cf4: 00000013 nop +80002cf8: 00000013 nop +80002cfc: 00000013 nop +80002d00: 00000013 nop +80002d04: 00000013 nop +80002d08: 00000013 nop +80002d0c: 00000013 nop +80002d10: 00000013 nop +80002d14: 00000013 nop +80002d18: 00000013 nop +80002d1c: 00000013 nop +80002d20: 00000013 nop +80002d24: 00000013 nop +80002d28: 00000013 nop +80002d2c: 00000013 nop +80002d30: 00000013 nop +80002d34: 00000013 nop +80002d38: 00000013 nop +80002d3c: 00000013 nop +80002d40: 00000013 nop +80002d44: 00000013 nop +80002d48: 00000013 nop +80002d4c: 00000013 nop +80002d50: 00000013 nop +80002d54: 00000013 nop +80002d58: 00000013 nop +80002d5c: 00000013 nop +80002d60: 00000013 nop +80002d64: 00000013 nop +80002d68: 00000013 nop +80002d6c: 00000013 nop +80002d70: 00000013 nop +80002d74: 00000013 nop +80002d78: 00000013 nop +80002d7c: 00000013 nop +80002d80: 00000013 nop +80002d84: 00000013 nop +80002d88: 00000013 nop +80002d8c: 00000013 nop +80002d90: 00000013 nop +80002d94: 00000013 nop +80002d98: 00000013 nop +80002d9c: 00000013 nop +80002da0: 00000013 nop +80002da4: 00000013 nop +80002da8: 00000013 nop +80002dac: 00000013 nop +80002db0: 00000013 nop +80002db4: 00000013 nop +80002db8: 00000013 nop +80002dbc: 00000013 nop +80002dc0: 00000013 nop +80002dc4: 00000013 nop +80002dc8: 00000013 nop +80002dcc: 00000013 nop +80002dd0: 00000013 nop +80002dd4: 00000013 nop +80002dd8: 00000013 nop +80002ddc: 00000013 nop +80002de0: 00000013 nop +80002de4: 00000013 nop +80002de8: 00000013 nop +80002dec: 00000013 nop +80002df0: 00000013 nop +80002df4: 00000013 nop +80002df8: 00000013 nop +80002dfc: 00000013 nop +80002e00: 00000013 nop +80002e04: 00000013 nop +80002e08: 00000013 nop +80002e0c: 00000013 nop +80002e10: 00000013 nop +80002e14: 00000013 nop +80002e18: 00000013 nop +80002e1c: 00000013 nop +80002e20: 00000013 nop +80002e24: 00000013 nop +80002e28: 00000013 nop +80002e2c: 00000013 nop +80002e30: 00000013 nop +80002e34: 00000013 nop +80002e38: 00000013 nop +80002e3c: 00000013 nop +80002e40: 00000013 nop +80002e44: 00000013 nop +80002e48: 00000013 nop +80002e4c: 00000013 nop +80002e50: 00000013 nop +80002e54: 00000013 nop +80002e58: 00000013 nop +80002e5c: 00000013 nop +80002e60: 00000013 nop +80002e64: 00000013 nop +80002e68: 00000013 nop +80002e6c: 00000013 nop +80002e70: 00000013 nop +80002e74: 00000013 nop +80002e78: 00000013 nop +80002e7c: 00000013 nop +80002e80: 00000013 nop +80002e84: 00000013 nop +80002e88: 00000013 nop +80002e8c: 00000013 nop +80002e90: 00000013 nop +80002e94: 00000013 nop +80002e98: 00000013 nop +80002e9c: 00000013 nop +80002ea0: 00000013 nop +80002ea4: 00000013 nop +80002ea8: 00000013 nop +80002eac: 00000013 nop +80002eb0: 00000013 nop +80002eb4: 00000013 nop +80002eb8: 00000013 nop +80002ebc: 00000013 nop +80002ec0: 00000013 nop +80002ec4: 00000013 nop +80002ec8: 00000013 nop +80002ecc: 00000013 nop +80002ed0: 00000013 nop +80002ed4: 00000013 nop +80002ed8: 00000013 nop +80002edc: 00000013 nop +80002ee0: 00000013 nop +80002ee4: 00000013 nop +80002ee8: 00000013 nop +80002eec: 00000013 nop +80002ef0: 00000013 nop +80002ef4: 00000013 nop +80002ef8: 00000013 nop +80002efc: 00000013 nop +80002f00: 00000013 nop +80002f04: 00000013 nop +80002f08: 00000013 nop +80002f0c: 00000013 nop +80002f10: 00000013 nop +80002f14: 00000013 nop +80002f18: 00000013 nop +80002f1c: 00000013 nop +80002f20: 00000013 nop +80002f24: 00000013 nop +80002f28: 00000013 nop +80002f2c: 00000013 nop +80002f30: 00000013 nop +80002f34: 00000013 nop +80002f38: 00000013 nop +80002f3c: 00000013 nop +80002f40: 00000013 nop +80002f44: 00000013 nop +80002f48: 00000013 nop +80002f4c: 00000013 nop +80002f50: 00000013 nop +80002f54: 00000013 nop +80002f58: 00000013 nop +80002f5c: 00000013 nop +80002f60: 00000013 nop +80002f64: 00000013 nop +80002f68: 00000013 nop +80002f6c: 00000013 nop +80002f70: 00000013 nop +80002f74: 00000013 nop +80002f78: 00000013 nop +80002f7c: 00000013 nop +80002f80: 00000013 nop +80002f84: 00000013 nop +80002f88: 00000013 nop +80002f8c: 00000013 nop +80002f90: 00000013 nop +80002f94: 00000013 nop +80002f98: 00000013 nop +80002f9c: 00000013 nop +80002fa0: 00000013 nop +80002fa4: 00000013 nop +80002fa8: 00000013 nop +80002fac: 00000013 nop +80002fb0: 00000013 nop +80002fb4: 00000013 nop +80002fb8: 00000013 nop +80002fbc: 00000013 nop +80002fc0: 00000013 nop +80002fc4: 00000013 nop +80002fc8: 00000013 nop +80002fcc: 00000013 nop +80002fd0: 00000013 nop +80002fd4: 00000013 nop +80002fd8: 00000013 nop +80002fdc: 00000013 nop +80002fe0: 00000013 nop +80002fe4: 00000013 nop +80002fe8: 00000013 nop +80002fec: 00000013 nop +80002ff0: 00000013 nop +80002ff4: 00000013 nop +80002ff8: 00000013 nop +80002ffc: 00000013 nop + +80003000 : +80003000: 00000000 .word 0x00000000 +80003004: 00000013 nop +80003008: 00000013 nop +8000300c: 00000013 nop +80003010: 00000013 nop +80003014: 00000013 nop +80003018: 00000013 nop +8000301c: 00000013 nop +80003020: 00000013 nop +80003024: 00000013 nop +80003028: 00000013 nop +8000302c: 00000013 nop +80003030: 00000013 nop +80003034: 00000013 nop +80003038: 00000013 nop +8000303c: 00000013 nop +80003040: 00000013 nop +80003044: 00000013 nop +80003048: 00000013 nop +8000304c: 00000013 nop +80003050: 00000013 nop +80003054: 00000013 nop +80003058: 00000013 nop +8000305c: 00000013 nop +80003060: 00000013 nop +80003064: 00000013 nop +80003068: 00000013 nop +8000306c: 00000013 nop +80003070: 00000013 nop +80003074: 00000013 nop +80003078: 00000013 nop +8000307c: 00000013 nop +80003080: 00000013 nop +80003084: 00000013 nop +80003088: 00000013 nop +8000308c: 00000013 nop +80003090: 00000013 nop +80003094: 00000013 nop +80003098: 00000013 nop +8000309c: 00000013 nop +800030a0: 00000013 nop +800030a4: 00000013 nop +800030a8: 00000013 nop +800030ac: 00000013 nop +800030b0: 00000013 nop +800030b4: 00000013 nop +800030b8: 00000013 nop +800030bc: 00000013 nop +800030c0: 00000013 nop +800030c4: 00000013 nop +800030c8: 00000013 nop +800030cc: 00000013 nop +800030d0: 00000013 nop +800030d4: 00000013 nop +800030d8: 00000013 nop +800030dc: 00000013 nop +800030e0: 00000013 nop +800030e4: 00000013 nop +800030e8: 00000013 nop +800030ec: 00000013 nop +800030f0: 00000013 nop +800030f4: 00000013 nop +800030f8: 00000013 nop +800030fc: 00000013 nop +80003100: 00000013 nop +80003104: 00000013 nop +80003108: 00000013 nop +8000310c: 00000013 nop +80003110: 00000013 nop +80003114: 00000013 nop +80003118: 00000013 nop +8000311c: 00000013 nop +80003120: 00000013 nop +80003124: 00000013 nop +80003128: 00000013 nop +8000312c: 00000013 nop +80003130: 00000013 nop +80003134: 00000013 nop +80003138: 00000013 nop +8000313c: 00000013 nop +80003140: 00000013 nop +80003144: 00000013 nop +80003148: 00000013 nop +8000314c: 00000013 nop +80003150: 00000013 nop +80003154: 00000013 nop +80003158: 00000013 nop +8000315c: 00000013 nop +80003160: 00000013 nop +80003164: 00000013 nop +80003168: 00000013 nop +8000316c: 00000013 nop +80003170: 00000013 nop +80003174: 00000013 nop +80003178: 00000013 nop +8000317c: 00000013 nop +80003180: 00000013 nop +80003184: 00000013 nop +80003188: 00000013 nop +8000318c: 00000013 nop +80003190: 00000013 nop +80003194: 00000013 nop +80003198: 00000013 nop +8000319c: 00000013 nop +800031a0: 00000013 nop +800031a4: 00000013 nop +800031a8: 00000013 nop +800031ac: 00000013 nop +800031b0: 00000013 nop +800031b4: 00000013 nop +800031b8: 00000013 nop +800031bc: 00000013 nop +800031c0: 00000013 nop +800031c4: 00000013 nop +800031c8: 00000013 nop +800031cc: 00000013 nop +800031d0: 00000013 nop +800031d4: 00000013 nop +800031d8: 00000013 nop +800031dc: 00000013 nop +800031e0: 00000013 nop +800031e4: 00000013 nop +800031e8: 00000013 nop +800031ec: 00000013 nop +800031f0: 00000013 nop +800031f4: 00000013 nop +800031f8: 00000013 nop +800031fc: 00000013 nop +80003200: 00000013 nop +80003204: 00000013 nop +80003208: 00000013 nop +8000320c: 00000013 nop +80003210: 00000013 nop +80003214: 00000013 nop +80003218: 00000013 nop +8000321c: 00000013 nop +80003220: 00000013 nop +80003224: 00000013 nop +80003228: 00000013 nop +8000322c: 00000013 nop +80003230: 00000013 nop +80003234: 00000013 nop +80003238: 00000013 nop +8000323c: 00000013 nop +80003240: 00000013 nop +80003244: 00000013 nop +80003248: 00000013 nop +8000324c: 00000013 nop +80003250: 00000013 nop +80003254: 00000013 nop +80003258: 00000013 nop +8000325c: 00000013 nop +80003260: 00000013 nop +80003264: 00000013 nop +80003268: 00000013 nop +8000326c: 00000013 nop +80003270: 00000013 nop +80003274: 00000013 nop +80003278: 00000013 nop +8000327c: 00000013 nop +80003280: 00000013 nop +80003284: 00000013 nop +80003288: 00000013 nop +8000328c: 00000013 nop +80003290: 00000013 nop +80003294: 00000013 nop +80003298: 00000013 nop +8000329c: 00000013 nop +800032a0: 00000013 nop +800032a4: 00000013 nop +800032a8: 00000013 nop +800032ac: 00000013 nop +800032b0: 00000013 nop +800032b4: 00000013 nop +800032b8: 00000013 nop +800032bc: 00000013 nop +800032c0: 00000013 nop +800032c4: 00000013 nop +800032c8: 00000013 nop +800032cc: 00000013 nop +800032d0: 00000013 nop +800032d4: 00000013 nop +800032d8: 00000013 nop +800032dc: 00000013 nop +800032e0: 00000013 nop +800032e4: 00000013 nop +800032e8: 00000013 nop +800032ec: 00000013 nop +800032f0: 00000013 nop +800032f4: 00000013 nop +800032f8: 00000013 nop +800032fc: 00000013 nop +80003300: 00000013 nop +80003304: 00000013 nop +80003308: 00000013 nop +8000330c: 00000013 nop +80003310: 00000013 nop +80003314: 00000013 nop +80003318: 00000013 nop +8000331c: 00000013 nop +80003320: 00000013 nop +80003324: 00000013 nop +80003328: 00000013 nop +8000332c: 00000013 nop +80003330: 00000013 nop +80003334: 00000013 nop +80003338: 00000013 nop +8000333c: 00000013 nop +80003340: 00000013 nop +80003344: 00000013 nop +80003348: 00000013 nop +8000334c: 00000013 nop +80003350: 00000013 nop +80003354: 00000013 nop +80003358: 00000013 nop +8000335c: 00000013 nop +80003360: 00000013 nop +80003364: 00000013 nop +80003368: 00000013 nop +8000336c: 00000013 nop +80003370: 00000013 nop +80003374: 00000013 nop +80003378: 00000013 nop +8000337c: 00000013 nop +80003380: 00000013 nop +80003384: 00000013 nop +80003388: 00000013 nop +8000338c: 00000013 nop +80003390: 00000013 nop +80003394: 00000013 nop +80003398: 00000013 nop +8000339c: 00000013 nop +800033a0: 00000013 nop +800033a4: 00000013 nop +800033a8: 00000013 nop +800033ac: 00000013 nop +800033b0: 00000013 nop +800033b4: 00000013 nop +800033b8: 00000013 nop +800033bc: 00000013 nop +800033c0: 00000013 nop +800033c4: 00000013 nop +800033c8: 00000013 nop +800033cc: 00000013 nop +800033d0: 00000013 nop +800033d4: 00000013 nop +800033d8: 00000013 nop +800033dc: 00000013 nop +800033e0: 00000013 nop +800033e4: 00000013 nop +800033e8: 00000013 nop +800033ec: 00000013 nop +800033f0: 00000013 nop +800033f4: 00000013 nop +800033f8: 00000013 nop +800033fc: 00000013 nop +80003400: 00000013 nop +80003404: 00000013 nop +80003408: 00000013 nop +8000340c: 00000013 nop +80003410: 00000013 nop +80003414: 00000013 nop +80003418: 00000013 nop +8000341c: 00000013 nop +80003420: 00000013 nop +80003424: 00000013 nop +80003428: 00000013 nop +8000342c: 00000013 nop +80003430: 00000013 nop +80003434: 00000013 nop +80003438: 00000013 nop +8000343c: 00000013 nop +80003440: 00000013 nop +80003444: 00000013 nop +80003448: 00000013 nop +8000344c: 00000013 nop +80003450: 00000013 nop +80003454: 00000013 nop +80003458: 00000013 nop +8000345c: 00000013 nop +80003460: 00000013 nop +80003464: 00000013 nop +80003468: 00000013 nop +8000346c: 00000013 nop +80003470: 00000013 nop +80003474: 00000013 nop +80003478: 00000013 nop +8000347c: 00000013 nop +80003480: 00000013 nop +80003484: 00000013 nop +80003488: 00000013 nop +8000348c: 00000013 nop +80003490: 00000013 nop +80003494: 00000013 nop +80003498: 00000013 nop +8000349c: 00000013 nop +800034a0: 00000013 nop +800034a4: 00000013 nop +800034a8: 00000013 nop +800034ac: 00000013 nop +800034b0: 00000013 nop +800034b4: 00000013 nop +800034b8: 00000013 nop +800034bc: 00000013 nop +800034c0: 00000013 nop +800034c4: 00000013 nop +800034c8: 00000013 nop +800034cc: 00000013 nop +800034d0: 00000013 nop +800034d4: 00000013 nop +800034d8: 00000013 nop +800034dc: 00000013 nop +800034e0: 00000013 nop +800034e4: 00000013 nop +800034e8: 00000013 nop +800034ec: 00000013 nop +800034f0: 00000013 nop +800034f4: 00000013 nop +800034f8: 00000013 nop +800034fc: 00000013 nop +80003500: 00000013 nop +80003504: 00000013 nop +80003508: 00000013 nop +8000350c: 00000013 nop +80003510: 00000013 nop +80003514: 00000013 nop +80003518: 00000013 nop +8000351c: 00000013 nop +80003520: 00000013 nop +80003524: 00000013 nop +80003528: 00000013 nop +8000352c: 00000013 nop +80003530: 00000013 nop +80003534: 00000013 nop +80003538: 00000013 nop +8000353c: 00000013 nop +80003540: 00000013 nop +80003544: 00000013 nop +80003548: 00000013 nop +8000354c: 00000013 nop +80003550: 00000013 nop +80003554: 00000013 nop +80003558: 00000013 nop +8000355c: 00000013 nop +80003560: 00000013 nop +80003564: 00000013 nop +80003568: 00000013 nop +8000356c: 00000013 nop +80003570: 00000013 nop +80003574: 00000013 nop +80003578: 00000013 nop +8000357c: 00000013 nop +80003580: 00000013 nop +80003584: 00000013 nop +80003588: 00000013 nop +8000358c: 00000013 nop +80003590: 00000013 nop +80003594: 00000013 nop +80003598: 00000013 nop +8000359c: 00000013 nop +800035a0: 00000013 nop +800035a4: 00000013 nop +800035a8: 00000013 nop +800035ac: 00000013 nop +800035b0: 00000013 nop +800035b4: 00000013 nop +800035b8: 00000013 nop +800035bc: 00000013 nop +800035c0: 00000013 nop +800035c4: 00000013 nop +800035c8: 00000013 nop +800035cc: 00000013 nop +800035d0: 00000013 nop +800035d4: 00000013 nop +800035d8: 00000013 nop +800035dc: 00000013 nop +800035e0: 00000013 nop +800035e4: 00000013 nop +800035e8: 00000013 nop +800035ec: 00000013 nop +800035f0: 00000013 nop +800035f4: 00000013 nop +800035f8: 00000013 nop +800035fc: 00000013 nop +80003600: 00000013 nop +80003604: 00000013 nop +80003608: 00000013 nop +8000360c: 00000013 nop +80003610: 00000013 nop +80003614: 00000013 nop +80003618: 00000013 nop +8000361c: 00000013 nop +80003620: 00000013 nop +80003624: 00000013 nop +80003628: 00000013 nop +8000362c: 00000013 nop +80003630: 00000013 nop +80003634: 00000013 nop +80003638: 00000013 nop +8000363c: 00000013 nop +80003640: 00000013 nop +80003644: 00000013 nop +80003648: 00000013 nop +8000364c: 00000013 nop +80003650: 00000013 nop +80003654: 00000013 nop +80003658: 00000013 nop +8000365c: 00000013 nop +80003660: 00000013 nop +80003664: 00000013 nop +80003668: 00000013 nop +8000366c: 00000013 nop +80003670: 00000013 nop +80003674: 00000013 nop +80003678: 00000013 nop +8000367c: 00000013 nop +80003680: 00000013 nop +80003684: 00000013 nop +80003688: 00000013 nop +8000368c: 00000013 nop +80003690: 00000013 nop +80003694: 00000013 nop +80003698: 00000013 nop +8000369c: 00000013 nop +800036a0: 00000013 nop +800036a4: 00000013 nop +800036a8: 00000013 nop +800036ac: 00000013 nop +800036b0: 00000013 nop +800036b4: 00000013 nop +800036b8: 00000013 nop +800036bc: 00000013 nop +800036c0: 00000013 nop +800036c4: 00000013 nop +800036c8: 00000013 nop +800036cc: 00000013 nop +800036d0: 00000013 nop +800036d4: 00000013 nop +800036d8: 00000013 nop +800036dc: 00000013 nop +800036e0: 00000013 nop +800036e4: 00000013 nop +800036e8: 00000013 nop +800036ec: 00000013 nop +800036f0: 00000013 nop +800036f4: 00000013 nop +800036f8: 00000013 nop +800036fc: 00000013 nop +80003700: 00000013 nop +80003704: 00000013 nop +80003708: 00000013 nop +8000370c: 00000013 nop +80003710: 00000013 nop +80003714: 00000013 nop +80003718: 00000013 nop +8000371c: 00000013 nop +80003720: 00000013 nop +80003724: 00000013 nop +80003728: 00000013 nop +8000372c: 00000013 nop +80003730: 00000013 nop +80003734: 00000013 nop +80003738: 00000013 nop +8000373c: 00000013 nop +80003740: 00000013 nop +80003744: 00000013 nop +80003748: 00000013 nop +8000374c: 00000013 nop +80003750: 00000013 nop +80003754: 00000013 nop +80003758: 00000013 nop +8000375c: 00000013 nop +80003760: 00000013 nop +80003764: 00000013 nop +80003768: 00000013 nop +8000376c: 00000013 nop +80003770: 00000013 nop +80003774: 00000013 nop +80003778: 00000013 nop +8000377c: 00000013 nop +80003780: 00000013 nop +80003784: 00000013 nop +80003788: 00000013 nop +8000378c: 00000013 nop +80003790: 00000013 nop +80003794: 00000013 nop +80003798: 00000013 nop +8000379c: 00000013 nop +800037a0: 00000013 nop +800037a4: 00000013 nop +800037a8: 00000013 nop +800037ac: 00000013 nop +800037b0: 00000013 nop +800037b4: 00000013 nop +800037b8: 00000013 nop +800037bc: 00000013 nop +800037c0: 00000013 nop +800037c4: 00000013 nop +800037c8: 00000013 nop +800037cc: 00000013 nop +800037d0: 00000013 nop +800037d4: 00000013 nop +800037d8: 00000013 nop +800037dc: 00000013 nop +800037e0: 00000013 nop +800037e4: 00000013 nop +800037e8: 00000013 nop +800037ec: 00000013 nop +800037f0: 00000013 nop +800037f4: 00000013 nop +800037f8: 00000013 nop +800037fc: 00000013 nop +80003800: 00000013 nop +80003804: 00000013 nop +80003808: 00000013 nop +8000380c: 00000013 nop +80003810: 00000013 nop +80003814: 00000013 nop +80003818: 00000013 nop +8000381c: 00000013 nop +80003820: 00000013 nop +80003824: 00000013 nop +80003828: 00000013 nop +8000382c: 00000013 nop +80003830: 00000013 nop +80003834: 00000013 nop +80003838: 00000013 nop +8000383c: 00000013 nop +80003840: 00000013 nop +80003844: 00000013 nop +80003848: 00000013 nop +8000384c: 00000013 nop +80003850: 00000013 nop +80003854: 00000013 nop +80003858: 00000013 nop +8000385c: 00000013 nop +80003860: 00000013 nop +80003864: 00000013 nop +80003868: 00000013 nop +8000386c: 00000013 nop +80003870: 00000013 nop +80003874: 00000013 nop +80003878: 00000013 nop +8000387c: 00000013 nop +80003880: 00000013 nop +80003884: 00000013 nop +80003888: 00000013 nop +8000388c: 00000013 nop +80003890: 00000013 nop +80003894: 00000013 nop +80003898: 00000013 nop +8000389c: 00000013 nop +800038a0: 00000013 nop +800038a4: 00000013 nop +800038a8: 00000013 nop +800038ac: 00000013 nop +800038b0: 00000013 nop +800038b4: 00000013 nop +800038b8: 00000013 nop +800038bc: 00000013 nop +800038c0: 00000013 nop +800038c4: 00000013 nop +800038c8: 00000013 nop +800038cc: 00000013 nop +800038d0: 00000013 nop +800038d4: 00000013 nop +800038d8: 00000013 nop +800038dc: 00000013 nop +800038e0: 00000013 nop +800038e4: 00000013 nop +800038e8: 00000013 nop +800038ec: 00000013 nop +800038f0: 00000013 nop +800038f4: 00000013 nop +800038f8: 00000013 nop +800038fc: 00000013 nop +80003900: 00000013 nop +80003904: 00000013 nop +80003908: 00000013 nop +8000390c: 00000013 nop +80003910: 00000013 nop +80003914: 00000013 nop +80003918: 00000013 nop +8000391c: 00000013 nop +80003920: 00000013 nop +80003924: 00000013 nop +80003928: 00000013 nop +8000392c: 00000013 nop +80003930: 00000013 nop +80003934: 00000013 nop +80003938: 00000013 nop +8000393c: 00000013 nop +80003940: 00000013 nop +80003944: 00000013 nop +80003948: 00000013 nop +8000394c: 00000013 nop +80003950: 00000013 nop +80003954: 00000013 nop +80003958: 00000013 nop +8000395c: 00000013 nop +80003960: 00000013 nop +80003964: 00000013 nop +80003968: 00000013 nop +8000396c: 00000013 nop +80003970: 00000013 nop +80003974: 00000013 nop +80003978: 00000013 nop +8000397c: 00000013 nop +80003980: 00000013 nop +80003984: 00000013 nop +80003988: 00000013 nop +8000398c: 00000013 nop +80003990: 00000013 nop +80003994: 00000013 nop +80003998: 00000013 nop +8000399c: 00000013 nop +800039a0: 00000013 nop +800039a4: 00000013 nop +800039a8: 00000013 nop +800039ac: 00000013 nop +800039b0: 00000013 nop +800039b4: 00000013 nop +800039b8: 00000013 nop +800039bc: 00000013 nop +800039c0: 00000013 nop +800039c4: 00000013 nop +800039c8: 00000013 nop +800039cc: 00000013 nop +800039d0: 00000013 nop +800039d4: 00000013 nop +800039d8: 00000013 nop +800039dc: 00000013 nop +800039e0: 00000013 nop +800039e4: 00000013 nop +800039e8: 00000013 nop +800039ec: 00000013 nop +800039f0: 00000013 nop +800039f4: 00000013 nop +800039f8: 00000013 nop +800039fc: 00000013 nop +80003a00: 00000013 nop +80003a04: 00000013 nop +80003a08: 00000013 nop +80003a0c: 00000013 nop +80003a10: 00000013 nop +80003a14: 00000013 nop +80003a18: 00000013 nop +80003a1c: 00000013 nop +80003a20: 00000013 nop +80003a24: 00000013 nop +80003a28: 00000013 nop +80003a2c: 00000013 nop +80003a30: 00000013 nop +80003a34: 00000013 nop +80003a38: 00000013 nop +80003a3c: 00000013 nop +80003a40: 00000013 nop +80003a44: 00000013 nop +80003a48: 00000013 nop +80003a4c: 00000013 nop +80003a50: 00000013 nop +80003a54: 00000013 nop +80003a58: 00000013 nop +80003a5c: 00000013 nop +80003a60: 00000013 nop +80003a64: 00000013 nop +80003a68: 00000013 nop +80003a6c: 00000013 nop +80003a70: 00000013 nop +80003a74: 00000013 nop +80003a78: 00000013 nop +80003a7c: 00000013 nop +80003a80: 00000013 nop +80003a84: 00000013 nop +80003a88: 00000013 nop +80003a8c: 00000013 nop +80003a90: 00000013 nop +80003a94: 00000013 nop +80003a98: 00000013 nop +80003a9c: 00000013 nop +80003aa0: 00000013 nop +80003aa4: 00000013 nop +80003aa8: 00000013 nop +80003aac: 00000013 nop +80003ab0: 00000013 nop +80003ab4: 00000013 nop +80003ab8: 00000013 nop +80003abc: 00000013 nop +80003ac0: 00000013 nop +80003ac4: 00000013 nop +80003ac8: 00000013 nop +80003acc: 00000013 nop +80003ad0: 00000013 nop +80003ad4: 00000013 nop +80003ad8: 00000013 nop +80003adc: 00000013 nop +80003ae0: 00000013 nop +80003ae4: 00000013 nop +80003ae8: 00000013 nop +80003aec: 00000013 nop +80003af0: 00000013 nop +80003af4: 00000013 nop +80003af8: 00000013 nop +80003afc: 00000013 nop +80003b00: 00000013 nop +80003b04: 00000013 nop +80003b08: 00000013 nop +80003b0c: 00000013 nop +80003b10: 00000013 nop +80003b14: 00000013 nop +80003b18: 00000013 nop +80003b1c: 00000013 nop +80003b20: 00000013 nop +80003b24: 00000013 nop +80003b28: 00000013 nop +80003b2c: 00000013 nop +80003b30: 00000013 nop +80003b34: 00000013 nop +80003b38: 00000013 nop +80003b3c: 00000013 nop +80003b40: 00000013 nop +80003b44: 00000013 nop +80003b48: 00000013 nop +80003b4c: 00000013 nop +80003b50: 00000013 nop +80003b54: 00000013 nop +80003b58: 00000013 nop +80003b5c: 00000013 nop +80003b60: 00000013 nop +80003b64: 00000013 nop +80003b68: 00000013 nop +80003b6c: 00000013 nop +80003b70: 00000013 nop +80003b74: 00000013 nop +80003b78: 00000013 nop +80003b7c: 00000013 nop +80003b80: 00000013 nop +80003b84: 00000013 nop +80003b88: 00000013 nop +80003b8c: 00000013 nop +80003b90: 00000013 nop +80003b94: 00000013 nop +80003b98: 00000013 nop +80003b9c: 00000013 nop +80003ba0: 00000013 nop +80003ba4: 00000013 nop +80003ba8: 00000013 nop +80003bac: 00000013 nop +80003bb0: 00000013 nop +80003bb4: 00000013 nop +80003bb8: 00000013 nop +80003bbc: 00000013 nop +80003bc0: 00000013 nop +80003bc4: 00000013 nop +80003bc8: 00000013 nop +80003bcc: 00000013 nop +80003bd0: 00000013 nop +80003bd4: 00000013 nop +80003bd8: 00000013 nop +80003bdc: 00000013 nop +80003be0: 00000013 nop +80003be4: 00000013 nop +80003be8: 00000013 nop +80003bec: 00000013 nop +80003bf0: 00000013 nop +80003bf4: 00000013 nop +80003bf8: 00000013 nop +80003bfc: 00000013 nop +80003c00: 00000013 nop +80003c04: 00000013 nop +80003c08: 00000013 nop +80003c0c: 00000013 nop +80003c10: 00000013 nop +80003c14: 00000013 nop +80003c18: 00000013 nop +80003c1c: 00000013 nop +80003c20: 00000013 nop +80003c24: 00000013 nop +80003c28: 00000013 nop +80003c2c: 00000013 nop +80003c30: 00000013 nop +80003c34: 00000013 nop +80003c38: 00000013 nop +80003c3c: 00000013 nop +80003c40: 00000013 nop +80003c44: 00000013 nop +80003c48: 00000013 nop +80003c4c: 00000013 nop +80003c50: 00000013 nop +80003c54: 00000013 nop +80003c58: 00000013 nop +80003c5c: 00000013 nop +80003c60: 00000013 nop +80003c64: 00000013 nop +80003c68: 00000013 nop +80003c6c: 00000013 nop +80003c70: 00000013 nop +80003c74: 00000013 nop +80003c78: 00000013 nop +80003c7c: 00000013 nop +80003c80: 00000013 nop +80003c84: 00000013 nop +80003c88: 00000013 nop +80003c8c: 00000013 nop +80003c90: 00000013 nop +80003c94: 00000013 nop +80003c98: 00000013 nop +80003c9c: 00000013 nop +80003ca0: 00000013 nop +80003ca4: 00000013 nop +80003ca8: 00000013 nop +80003cac: 00000013 nop +80003cb0: 00000013 nop +80003cb4: 00000013 nop +80003cb8: 00000013 nop +80003cbc: 00000013 nop +80003cc0: 00000013 nop +80003cc4: 00000013 nop +80003cc8: 00000013 nop +80003ccc: 00000013 nop +80003cd0: 00000013 nop +80003cd4: 00000013 nop +80003cd8: 00000013 nop +80003cdc: 00000013 nop +80003ce0: 00000013 nop +80003ce4: 00000013 nop +80003ce8: 00000013 nop +80003cec: 00000013 nop +80003cf0: 00000013 nop +80003cf4: 00000013 nop +80003cf8: 00000013 nop +80003cfc: 00000013 nop +80003d00: 00000013 nop +80003d04: 00000013 nop +80003d08: 00000013 nop +80003d0c: 00000013 nop +80003d10: 00000013 nop +80003d14: 00000013 nop +80003d18: 00000013 nop +80003d1c: 00000013 nop +80003d20: 00000013 nop +80003d24: 00000013 nop +80003d28: 00000013 nop +80003d2c: 00000013 nop +80003d30: 00000013 nop +80003d34: 00000013 nop +80003d38: 00000013 nop +80003d3c: 00000013 nop +80003d40: 00000013 nop +80003d44: 00000013 nop +80003d48: 00000013 nop +80003d4c: 00000013 nop +80003d50: 00000013 nop +80003d54: 00000013 nop +80003d58: 00000013 nop +80003d5c: 00000013 nop +80003d60: 00000013 nop +80003d64: 00000013 nop +80003d68: 00000013 nop +80003d6c: 00000013 nop +80003d70: 00000013 nop +80003d74: 00000013 nop +80003d78: 00000013 nop +80003d7c: 00000013 nop +80003d80: 00000013 nop +80003d84: 00000013 nop +80003d88: 00000013 nop +80003d8c: 00000013 nop +80003d90: 00000013 nop +80003d94: 00000013 nop +80003d98: 00000013 nop +80003d9c: 00000013 nop +80003da0: 00000013 nop +80003da4: 00000013 nop +80003da8: 00000013 nop +80003dac: 00000013 nop +80003db0: 00000013 nop +80003db4: 00000013 nop +80003db8: 00000013 nop +80003dbc: 00000013 nop +80003dc0: 00000013 nop +80003dc4: 00000013 nop +80003dc8: 00000013 nop +80003dcc: 00000013 nop +80003dd0: 00000013 nop +80003dd4: 00000013 nop +80003dd8: 00000013 nop +80003ddc: 00000013 nop +80003de0: 00000013 nop +80003de4: 00000013 nop +80003de8: 00000013 nop +80003dec: 00000013 nop +80003df0: 00000013 nop +80003df4: 00000013 nop +80003df8: 00000013 nop +80003dfc: 00000013 nop +80003e00: 00000013 nop +80003e04: 00000013 nop +80003e08: 00000013 nop +80003e0c: 00000013 nop +80003e10: 00000013 nop +80003e14: 00000013 nop +80003e18: 00000013 nop +80003e1c: 00000013 nop +80003e20: 00000013 nop +80003e24: 00000013 nop +80003e28: 00000013 nop +80003e2c: 00000013 nop +80003e30: 00000013 nop +80003e34: 00000013 nop +80003e38: 00000013 nop +80003e3c: 00000013 nop +80003e40: 00000013 nop +80003e44: 00000013 nop +80003e48: 00000013 nop +80003e4c: 00000013 nop +80003e50: 00000013 nop +80003e54: 00000013 nop +80003e58: 00000013 nop +80003e5c: 00000013 nop +80003e60: 00000013 nop +80003e64: 00000013 nop +80003e68: 00000013 nop +80003e6c: 00000013 nop +80003e70: 00000013 nop +80003e74: 00000013 nop +80003e78: 00000013 nop +80003e7c: 00000013 nop +80003e80: 00000013 nop +80003e84: 00000013 nop +80003e88: 00000013 nop +80003e8c: 00000013 nop +80003e90: 00000013 nop +80003e94: 00000013 nop +80003e98: 00000013 nop +80003e9c: 00000013 nop +80003ea0: 00000013 nop +80003ea4: 00000013 nop +80003ea8: 00000013 nop +80003eac: 00000013 nop +80003eb0: 00000013 nop +80003eb4: 00000013 nop +80003eb8: 00000013 nop +80003ebc: 00000013 nop +80003ec0: 00000013 nop +80003ec4: 00000013 nop +80003ec8: 00000013 nop +80003ecc: 00000013 nop +80003ed0: 00000013 nop +80003ed4: 00000013 nop +80003ed8: 00000013 nop +80003edc: 00000013 nop +80003ee0: 00000013 nop +80003ee4: 00000013 nop +80003ee8: 00000013 nop +80003eec: 00000013 nop +80003ef0: 00000013 nop +80003ef4: 00000013 nop +80003ef8: 00000013 nop +80003efc: 00000013 nop +80003f00: 00000013 nop +80003f04: 00000013 nop +80003f08: 00000013 nop +80003f0c: 00000013 nop +80003f10: 00000013 nop +80003f14: 00000013 nop +80003f18: 00000013 nop +80003f1c: 00000013 nop +80003f20: 00000013 nop +80003f24: 00000013 nop +80003f28: 00000013 nop +80003f2c: 00000013 nop +80003f30: 00000013 nop +80003f34: 00000013 nop +80003f38: 00000013 nop +80003f3c: 00000013 nop +80003f40: 00000013 nop +80003f44: 00000013 nop +80003f48: 00000013 nop +80003f4c: 00000013 nop +80003f50: 00000013 nop +80003f54: 00000013 nop +80003f58: 00000013 nop +80003f5c: 00000013 nop +80003f60: 00000013 nop +80003f64: 00000013 nop +80003f68: 00000013 nop +80003f6c: 00000013 nop +80003f70: 00000013 nop +80003f74: 00000013 nop +80003f78: 00000013 nop +80003f7c: 00000013 nop +80003f80: 00000013 nop +80003f84: 00000013 nop +80003f88: 00000013 nop +80003f8c: 00000013 nop +80003f90: 00000013 nop +80003f94: 00000013 nop +80003f98: 00000013 nop +80003f9c: 00000013 nop +80003fa0: 00000013 nop +80003fa4: 00000013 nop +80003fa8: 00000013 nop +80003fac: 00000013 nop +80003fb0: 00000013 nop +80003fb4: 00000013 nop +80003fb8: 00000013 nop +80003fbc: 00000013 nop +80003fc0: 00000013 nop +80003fc4: 00000013 nop +80003fc8: 00000013 nop +80003fcc: 00000013 nop +80003fd0: 00000013 nop +80003fd4: 00000013 nop +80003fd8: 00000013 nop +80003fdc: 00000013 nop +80003fe0: 00000013 nop +80003fe4: 00000013 nop +80003fe8: 00000013 nop +80003fec: 00000013 nop +80003ff0: 00000013 nop +80003ff4: 00000013 nop +80003ff8: 00000013 nop +80003ffc: 00000013 nop + +80004000 : +80004000: 00000000 .word 0x00000000 +80004004: 00000013 nop +80004008: 00000013 nop +8000400c: 00000013 nop +80004010: 00000013 nop +80004014: 00000013 nop +80004018: 00000013 nop +8000401c: 00000013 nop +80004020: 00000013 nop +80004024: 00000013 nop +80004028: 00000013 nop +8000402c: 00000013 nop +80004030: 00000013 nop +80004034: 00000013 nop +80004038: 00000013 nop +8000403c: 00000013 nop +80004040: 00000013 nop +80004044: 00000013 nop +80004048: 00000013 nop +8000404c: 00000013 nop +80004050: 00000013 nop +80004054: 00000013 nop +80004058: 00000013 nop +8000405c: 00000013 nop +80004060: 00000013 nop +80004064: 00000013 nop +80004068: 00000013 nop +8000406c: 00000013 nop +80004070: 00000013 nop +80004074: 00000013 nop +80004078: 00000013 nop +8000407c: 00000013 nop +80004080: 00000013 nop +80004084: 00000013 nop +80004088: 00000013 nop +8000408c: 00000013 nop +80004090: 00000013 nop +80004094: 00000013 nop +80004098: 00000013 nop +8000409c: 00000013 nop +800040a0: 00000013 nop +800040a4: 00000013 nop +800040a8: 00000013 nop +800040ac: 00000013 nop +800040b0: 00000013 nop +800040b4: 00000013 nop +800040b8: 00000013 nop +800040bc: 00000013 nop +800040c0: 00000013 nop +800040c4: 00000013 nop +800040c8: 00000013 nop +800040cc: 00000013 nop +800040d0: 00000013 nop +800040d4: 00000013 nop +800040d8: 00000013 nop +800040dc: 00000013 nop +800040e0: 00000013 nop +800040e4: 00000013 nop +800040e8: 00000013 nop +800040ec: 00000013 nop +800040f0: 00000013 nop +800040f4: 00000013 nop +800040f8: 00000013 nop +800040fc: 00000013 nop +80004100: 00000013 nop +80004104: 00000013 nop +80004108: 00000013 nop +8000410c: 00000013 nop +80004110: 00000013 nop +80004114: 00000013 nop +80004118: 00000013 nop +8000411c: 00000013 nop +80004120: 00000013 nop +80004124: 00000013 nop +80004128: 00000013 nop +8000412c: 00000013 nop +80004130: 00000013 nop +80004134: 00000013 nop +80004138: 00000013 nop +8000413c: 00000013 nop +80004140: 00000013 nop +80004144: 00000013 nop +80004148: 00000013 nop +8000414c: 00000013 nop +80004150: 00000013 nop +80004154: 00000013 nop +80004158: 00000013 nop +8000415c: 00000013 nop +80004160: 00000013 nop +80004164: 00000013 nop +80004168: 00000013 nop +8000416c: 00000013 nop +80004170: 00000013 nop +80004174: 00000013 nop +80004178: 00000013 nop +8000417c: 00000013 nop +80004180: 00000013 nop +80004184: 00000013 nop +80004188: 00000013 nop +8000418c: 00000013 nop +80004190: 00000013 nop +80004194: 00000013 nop +80004198: 00000013 nop +8000419c: 00000013 nop +800041a0: 00000013 nop +800041a4: 00000013 nop +800041a8: 00000013 nop +800041ac: 00000013 nop +800041b0: 00000013 nop +800041b4: 00000013 nop +800041b8: 00000013 nop +800041bc: 00000013 nop +800041c0: 00000013 nop +800041c4: 00000013 nop +800041c8: 00000013 nop +800041cc: 00000013 nop +800041d0: 00000013 nop +800041d4: 00000013 nop +800041d8: 00000013 nop +800041dc: 00000013 nop +800041e0: 00000013 nop +800041e4: 00000013 nop +800041e8: 00000013 nop +800041ec: 00000013 nop +800041f0: 00000013 nop +800041f4: 00000013 nop +800041f8: 00000013 nop +800041fc: 00000013 nop +80004200: 00000013 nop +80004204: 00000013 nop +80004208: 00000013 nop +8000420c: 00000013 nop +80004210: 00000013 nop +80004214: 00000013 nop +80004218: 00000013 nop +8000421c: 00000013 nop +80004220: 00000013 nop +80004224: 00000013 nop +80004228: 00000013 nop +8000422c: 00000013 nop +80004230: 00000013 nop +80004234: 00000013 nop +80004238: 00000013 nop +8000423c: 00000013 nop +80004240: 00000013 nop +80004244: 00000013 nop +80004248: 00000013 nop +8000424c: 00000013 nop +80004250: 00000013 nop +80004254: 00000013 nop +80004258: 00000013 nop +8000425c: 00000013 nop +80004260: 00000013 nop +80004264: 00000013 nop +80004268: 00000013 nop +8000426c: 00000013 nop +80004270: 00000013 nop +80004274: 00000013 nop +80004278: 00000013 nop +8000427c: 00000013 nop +80004280: 00000013 nop +80004284: 00000013 nop +80004288: 00000013 nop +8000428c: 00000013 nop +80004290: 00000013 nop +80004294: 00000013 nop +80004298: 00000013 nop +8000429c: 00000013 nop +800042a0: 00000013 nop +800042a4: 00000013 nop +800042a8: 00000013 nop +800042ac: 00000013 nop +800042b0: 00000013 nop +800042b4: 00000013 nop +800042b8: 00000013 nop +800042bc: 00000013 nop +800042c0: 00000013 nop +800042c4: 00000013 nop +800042c8: 00000013 nop +800042cc: 00000013 nop +800042d0: 00000013 nop +800042d4: 00000013 nop +800042d8: 00000013 nop +800042dc: 00000013 nop +800042e0: 00000013 nop +800042e4: 00000013 nop +800042e8: 00000013 nop +800042ec: 00000013 nop +800042f0: 00000013 nop +800042f4: 00000013 nop +800042f8: 00000013 nop +800042fc: 00000013 nop +80004300: 00000013 nop +80004304: 00000013 nop +80004308: 00000013 nop +8000430c: 00000013 nop +80004310: 00000013 nop +80004314: 00000013 nop +80004318: 00000013 nop +8000431c: 00000013 nop +80004320: 00000013 nop +80004324: 00000013 nop +80004328: 00000013 nop +8000432c: 00000013 nop +80004330: 00000013 nop +80004334: 00000013 nop +80004338: 00000013 nop +8000433c: 00000013 nop +80004340: 00000013 nop +80004344: 00000013 nop +80004348: 00000013 nop +8000434c: 00000013 nop +80004350: 00000013 nop +80004354: 00000013 nop +80004358: 00000013 nop +8000435c: 00000013 nop +80004360: 00000013 nop +80004364: 00000013 nop +80004368: 00000013 nop +8000436c: 00000013 nop +80004370: 00000013 nop +80004374: 00000013 nop +80004378: 00000013 nop +8000437c: 00000013 nop +80004380: 00000013 nop +80004384: 00000013 nop +80004388: 00000013 nop +8000438c: 00000013 nop +80004390: 00000013 nop +80004394: 00000013 nop +80004398: 00000013 nop +8000439c: 00000013 nop +800043a0: 00000013 nop +800043a4: 00000013 nop +800043a8: 00000013 nop +800043ac: 00000013 nop +800043b0: 00000013 nop +800043b4: 00000013 nop +800043b8: 00000013 nop +800043bc: 00000013 nop +800043c0: 00000013 nop +800043c4: 00000013 nop +800043c8: 00000013 nop +800043cc: 00000013 nop +800043d0: 00000013 nop +800043d4: 00000013 nop +800043d8: 00000013 nop +800043dc: 00000013 nop +800043e0: 00000013 nop +800043e4: 00000013 nop +800043e8: 00000013 nop +800043ec: 00000013 nop +800043f0: 00000013 nop +800043f4: 00000013 nop +800043f8: 00000013 nop +800043fc: 00000013 nop +80004400: 00000013 nop +80004404: 00000013 nop +80004408: 00000013 nop +8000440c: 00000013 nop +80004410: 00000013 nop +80004414: 00000013 nop +80004418: 00000013 nop +8000441c: 00000013 nop +80004420: 00000013 nop +80004424: 00000013 nop +80004428: 00000013 nop +8000442c: 00000013 nop +80004430: 00000013 nop +80004434: 00000013 nop +80004438: 00000013 nop +8000443c: 00000013 nop +80004440: 00000013 nop +80004444: 00000013 nop +80004448: 00000013 nop +8000444c: 00000013 nop +80004450: 00000013 nop +80004454: 00000013 nop +80004458: 00000013 nop +8000445c: 00000013 nop +80004460: 00000013 nop +80004464: 00000013 nop +80004468: 00000013 nop +8000446c: 00000013 nop +80004470: 00000013 nop +80004474: 00000013 nop +80004478: 00000013 nop +8000447c: 00000013 nop +80004480: 00000013 nop +80004484: 00000013 nop +80004488: 00000013 nop +8000448c: 00000013 nop +80004490: 00000013 nop +80004494: 00000013 nop +80004498: 00000013 nop +8000449c: 00000013 nop +800044a0: 00000013 nop +800044a4: 00000013 nop +800044a8: 00000013 nop +800044ac: 00000013 nop +800044b0: 00000013 nop +800044b4: 00000013 nop +800044b8: 00000013 nop +800044bc: 00000013 nop +800044c0: 00000013 nop +800044c4: 00000013 nop +800044c8: 00000013 nop +800044cc: 00000013 nop +800044d0: 00000013 nop +800044d4: 00000013 nop +800044d8: 00000013 nop +800044dc: 00000013 nop +800044e0: 00000013 nop +800044e4: 00000013 nop +800044e8: 00000013 nop +800044ec: 00000013 nop +800044f0: 00000013 nop +800044f4: 00000013 nop +800044f8: 00000013 nop +800044fc: 00000013 nop +80004500: 00000013 nop +80004504: 00000013 nop +80004508: 00000013 nop +8000450c: 00000013 nop +80004510: 00000013 nop +80004514: 00000013 nop +80004518: 00000013 nop +8000451c: 00000013 nop +80004520: 00000013 nop +80004524: 00000013 nop +80004528: 00000013 nop +8000452c: 00000013 nop +80004530: 00000013 nop +80004534: 00000013 nop +80004538: 00000013 nop +8000453c: 00000013 nop +80004540: 00000013 nop +80004544: 00000013 nop +80004548: 00000013 nop +8000454c: 00000013 nop +80004550: 00000013 nop +80004554: 00000013 nop +80004558: 00000013 nop +8000455c: 00000013 nop +80004560: 00000013 nop +80004564: 00000013 nop +80004568: 00000013 nop +8000456c: 00000013 nop +80004570: 00000013 nop +80004574: 00000013 nop +80004578: 00000013 nop +8000457c: 00000013 nop +80004580: 00000013 nop +80004584: 00000013 nop +80004588: 00000013 nop +8000458c: 00000013 nop +80004590: 00000013 nop +80004594: 00000013 nop +80004598: 00000013 nop +8000459c: 00000013 nop +800045a0: 00000013 nop +800045a4: 00000013 nop +800045a8: 00000013 nop +800045ac: 00000013 nop +800045b0: 00000013 nop +800045b4: 00000013 nop +800045b8: 00000013 nop +800045bc: 00000013 nop +800045c0: 00000013 nop +800045c4: 00000013 nop +800045c8: 00000013 nop +800045cc: 00000013 nop +800045d0: 00000013 nop +800045d4: 00000013 nop +800045d8: 00000013 nop +800045dc: 00000013 nop +800045e0: 00000013 nop +800045e4: 00000013 nop +800045e8: 00000013 nop +800045ec: 00000013 nop +800045f0: 00000013 nop +800045f4: 00000013 nop +800045f8: 00000013 nop +800045fc: 00000013 nop +80004600: 00000013 nop +80004604: 00000013 nop +80004608: 00000013 nop +8000460c: 00000013 nop +80004610: 00000013 nop +80004614: 00000013 nop +80004618: 00000013 nop +8000461c: 00000013 nop +80004620: 00000013 nop +80004624: 00000013 nop +80004628: 00000013 nop +8000462c: 00000013 nop +80004630: 00000013 nop +80004634: 00000013 nop +80004638: 00000013 nop +8000463c: 00000013 nop +80004640: 00000013 nop +80004644: 00000013 nop +80004648: 00000013 nop +8000464c: 00000013 nop +80004650: 00000013 nop +80004654: 00000013 nop +80004658: 00000013 nop +8000465c: 00000013 nop +80004660: 00000013 nop +80004664: 00000013 nop +80004668: 00000013 nop +8000466c: 00000013 nop +80004670: 00000013 nop +80004674: 00000013 nop +80004678: 00000013 nop +8000467c: 00000013 nop +80004680: 00000013 nop +80004684: 00000013 nop +80004688: 00000013 nop +8000468c: 00000013 nop +80004690: 00000013 nop +80004694: 00000013 nop +80004698: 00000013 nop +8000469c: 00000013 nop +800046a0: 00000013 nop +800046a4: 00000013 nop +800046a8: 00000013 nop +800046ac: 00000013 nop +800046b0: 00000013 nop +800046b4: 00000013 nop +800046b8: 00000013 nop +800046bc: 00000013 nop +800046c0: 00000013 nop +800046c4: 00000013 nop +800046c8: 00000013 nop +800046cc: 00000013 nop +800046d0: 00000013 nop +800046d4: 00000013 nop +800046d8: 00000013 nop +800046dc: 00000013 nop +800046e0: 00000013 nop +800046e4: 00000013 nop +800046e8: 00000013 nop +800046ec: 00000013 nop +800046f0: 00000013 nop +800046f4: 00000013 nop +800046f8: 00000013 nop +800046fc: 00000013 nop +80004700: 00000013 nop +80004704: 00000013 nop +80004708: 00000013 nop +8000470c: 00000013 nop +80004710: 00000013 nop +80004714: 00000013 nop +80004718: 00000013 nop +8000471c: 00000013 nop +80004720: 00000013 nop +80004724: 00000013 nop +80004728: 00000013 nop +8000472c: 00000013 nop +80004730: 00000013 nop +80004734: 00000013 nop +80004738: 00000013 nop +8000473c: 00000013 nop +80004740: 00000013 nop +80004744: 00000013 nop +80004748: 00000013 nop +8000474c: 00000013 nop +80004750: 00000013 nop +80004754: 00000013 nop +80004758: 00000013 nop +8000475c: 00000013 nop +80004760: 00000013 nop +80004764: 00000013 nop +80004768: 00000013 nop +8000476c: 00000013 nop +80004770: 00000013 nop +80004774: 00000013 nop +80004778: 00000013 nop +8000477c: 00000013 nop +80004780: 00000013 nop +80004784: 00000013 nop +80004788: 00000013 nop +8000478c: 00000013 nop +80004790: 00000013 nop +80004794: 00000013 nop +80004798: 00000013 nop +8000479c: 00000013 nop +800047a0: 00000013 nop +800047a4: 00000013 nop +800047a8: 00000013 nop +800047ac: 00000013 nop +800047b0: 00000013 nop +800047b4: 00000013 nop +800047b8: 00000013 nop +800047bc: 00000013 nop +800047c0: 00000013 nop +800047c4: 00000013 nop +800047c8: 00000013 nop +800047cc: 00000013 nop +800047d0: 00000013 nop +800047d4: 00000013 nop +800047d8: 00000013 nop +800047dc: 00000013 nop +800047e0: 00000013 nop +800047e4: 00000013 nop +800047e8: 00000013 nop +800047ec: 00000013 nop +800047f0: 00000013 nop +800047f4: 00000013 nop +800047f8: 00000013 nop +800047fc: 00000013 nop +80004800: 00000013 nop +80004804: 00000013 nop +80004808: 00000013 nop +8000480c: 00000013 nop +80004810: 00000013 nop +80004814: 00000013 nop +80004818: 00000013 nop +8000481c: 00000013 nop +80004820: 00000013 nop +80004824: 00000013 nop +80004828: 00000013 nop +8000482c: 00000013 nop +80004830: 00000013 nop +80004834: 00000013 nop +80004838: 00000013 nop +8000483c: 00000013 nop +80004840: 00000013 nop +80004844: 00000013 nop +80004848: 00000013 nop +8000484c: 00000013 nop +80004850: 00000013 nop +80004854: 00000013 nop +80004858: 00000013 nop +8000485c: 00000013 nop +80004860: 00000013 nop +80004864: 00000013 nop +80004868: 00000013 nop +8000486c: 00000013 nop +80004870: 00000013 nop +80004874: 00000013 nop +80004878: 00000013 nop +8000487c: 00000013 nop +80004880: 00000013 nop +80004884: 00000013 nop +80004888: 00000013 nop +8000488c: 00000013 nop +80004890: 00000013 nop +80004894: 00000013 nop +80004898: 00000013 nop +8000489c: 00000013 nop +800048a0: 00000013 nop +800048a4: 00000013 nop +800048a8: 00000013 nop +800048ac: 00000013 nop +800048b0: 00000013 nop +800048b4: 00000013 nop +800048b8: 00000013 nop +800048bc: 00000013 nop +800048c0: 00000013 nop +800048c4: 00000013 nop +800048c8: 00000013 nop +800048cc: 00000013 nop +800048d0: 00000013 nop +800048d4: 00000013 nop +800048d8: 00000013 nop +800048dc: 00000013 nop +800048e0: 00000013 nop +800048e4: 00000013 nop +800048e8: 00000013 nop +800048ec: 00000013 nop +800048f0: 00000013 nop +800048f4: 00000013 nop +800048f8: 00000013 nop +800048fc: 00000013 nop +80004900: 00000013 nop +80004904: 00000013 nop +80004908: 00000013 nop +8000490c: 00000013 nop +80004910: 00000013 nop +80004914: 00000013 nop +80004918: 00000013 nop +8000491c: 00000013 nop +80004920: 00000013 nop +80004924: 00000013 nop +80004928: 00000013 nop +8000492c: 00000013 nop +80004930: 00000013 nop +80004934: 00000013 nop +80004938: 00000013 nop +8000493c: 00000013 nop +80004940: 00000013 nop +80004944: 00000013 nop +80004948: 00000013 nop +8000494c: 00000013 nop +80004950: 00000013 nop +80004954: 00000013 nop +80004958: 00000013 nop +8000495c: 00000013 nop +80004960: 00000013 nop +80004964: 00000013 nop +80004968: 00000013 nop +8000496c: 00000013 nop +80004970: 00000013 nop +80004974: 00000013 nop +80004978: 00000013 nop +8000497c: 00000013 nop +80004980: 00000013 nop +80004984: 00000013 nop +80004988: 00000013 nop +8000498c: 00000013 nop +80004990: 00000013 nop +80004994: 00000013 nop +80004998: 00000013 nop +8000499c: 00000013 nop +800049a0: 00000013 nop +800049a4: 00000013 nop +800049a8: 00000013 nop +800049ac: 00000013 nop +800049b0: 00000013 nop +800049b4: 00000013 nop +800049b8: 00000013 nop +800049bc: 00000013 nop +800049c0: 00000013 nop +800049c4: 00000013 nop +800049c8: 00000013 nop +800049cc: 00000013 nop +800049d0: 00000013 nop +800049d4: 00000013 nop +800049d8: 00000013 nop +800049dc: 00000013 nop +800049e0: 00000013 nop +800049e4: 00000013 nop +800049e8: 00000013 nop +800049ec: 00000013 nop +800049f0: 00000013 nop +800049f4: 00000013 nop +800049f8: 00000013 nop +800049fc: 00000013 nop +80004a00: 00000013 nop +80004a04: 00000013 nop +80004a08: 00000013 nop +80004a0c: 00000013 nop +80004a10: 00000013 nop +80004a14: 00000013 nop +80004a18: 00000013 nop +80004a1c: 00000013 nop +80004a20: 00000013 nop +80004a24: 00000013 nop +80004a28: 00000013 nop +80004a2c: 00000013 nop +80004a30: 00000013 nop +80004a34: 00000013 nop +80004a38: 00000013 nop +80004a3c: 00000013 nop +80004a40: 00000013 nop +80004a44: 00000013 nop +80004a48: 00000013 nop +80004a4c: 00000013 nop +80004a50: 00000013 nop +80004a54: 00000013 nop +80004a58: 00000013 nop +80004a5c: 00000013 nop +80004a60: 00000013 nop +80004a64: 00000013 nop +80004a68: 00000013 nop +80004a6c: 00000013 nop +80004a70: 00000013 nop +80004a74: 00000013 nop +80004a78: 00000013 nop +80004a7c: 00000013 nop +80004a80: 00000013 nop +80004a84: 00000013 nop +80004a88: 00000013 nop +80004a8c: 00000013 nop +80004a90: 00000013 nop +80004a94: 00000013 nop +80004a98: 00000013 nop +80004a9c: 00000013 nop +80004aa0: 00000013 nop +80004aa4: 00000013 nop +80004aa8: 00000013 nop +80004aac: 00000013 nop +80004ab0: 00000013 nop +80004ab4: 00000013 nop +80004ab8: 00000013 nop +80004abc: 00000013 nop +80004ac0: 00000013 nop +80004ac4: 00000013 nop +80004ac8: 00000013 nop +80004acc: 00000013 nop +80004ad0: 00000013 nop +80004ad4: 00000013 nop +80004ad8: 00000013 nop +80004adc: 00000013 nop +80004ae0: 00000013 nop +80004ae4: 00000013 nop +80004ae8: 00000013 nop +80004aec: 00000013 nop +80004af0: 00000013 nop +80004af4: 00000013 nop +80004af8: 00000013 nop +80004afc: 00000013 nop +80004b00: 00000013 nop +80004b04: 00000013 nop +80004b08: 00000013 nop +80004b0c: 00000013 nop +80004b10: 00000013 nop +80004b14: 00000013 nop +80004b18: 00000013 nop +80004b1c: 00000013 nop +80004b20: 00000013 nop +80004b24: 00000013 nop +80004b28: 00000013 nop +80004b2c: 00000013 nop +80004b30: 00000013 nop +80004b34: 00000013 nop +80004b38: 00000013 nop +80004b3c: 00000013 nop +80004b40: 00000013 nop +80004b44: 00000013 nop +80004b48: 00000013 nop +80004b4c: 00000013 nop +80004b50: 00000013 nop +80004b54: 00000013 nop +80004b58: 00000013 nop +80004b5c: 00000013 nop +80004b60: 00000013 nop +80004b64: 00000013 nop +80004b68: 00000013 nop +80004b6c: 00000013 nop +80004b70: 00000013 nop +80004b74: 00000013 nop +80004b78: 00000013 nop +80004b7c: 00000013 nop +80004b80: 00000013 nop +80004b84: 00000013 nop +80004b88: 00000013 nop +80004b8c: 00000013 nop +80004b90: 00000013 nop +80004b94: 00000013 nop +80004b98: 00000013 nop +80004b9c: 00000013 nop +80004ba0: 00000013 nop +80004ba4: 00000013 nop +80004ba8: 00000013 nop +80004bac: 00000013 nop +80004bb0: 00000013 nop +80004bb4: 00000013 nop +80004bb8: 00000013 nop +80004bbc: 00000013 nop +80004bc0: 00000013 nop +80004bc4: 00000013 nop +80004bc8: 00000013 nop +80004bcc: 00000013 nop +80004bd0: 00000013 nop +80004bd4: 00000013 nop +80004bd8: 00000013 nop +80004bdc: 00000013 nop +80004be0: 00000013 nop +80004be4: 00000013 nop +80004be8: 00000013 nop +80004bec: 00000013 nop +80004bf0: 00000013 nop +80004bf4: 00000013 nop +80004bf8: 00000013 nop +80004bfc: 00000013 nop +80004c00: 00000013 nop +80004c04: 00000013 nop +80004c08: 00000013 nop +80004c0c: 00000013 nop +80004c10: 00000013 nop +80004c14: 00000013 nop +80004c18: 00000013 nop +80004c1c: 00000013 nop +80004c20: 00000013 nop +80004c24: 00000013 nop +80004c28: 00000013 nop +80004c2c: 00000013 nop +80004c30: 00000013 nop +80004c34: 00000013 nop +80004c38: 00000013 nop +80004c3c: 00000013 nop +80004c40: 00000013 nop +80004c44: 00000013 nop +80004c48: 00000013 nop +80004c4c: 00000013 nop +80004c50: 00000013 nop +80004c54: 00000013 nop +80004c58: 00000013 nop +80004c5c: 00000013 nop +80004c60: 00000013 nop +80004c64: 00000013 nop +80004c68: 00000013 nop +80004c6c: 00000013 nop +80004c70: 00000013 nop +80004c74: 00000013 nop +80004c78: 00000013 nop +80004c7c: 00000013 nop +80004c80: 00000013 nop +80004c84: 00000013 nop +80004c88: 00000013 nop +80004c8c: 00000013 nop +80004c90: 00000013 nop +80004c94: 00000013 nop +80004c98: 00000013 nop +80004c9c: 00000013 nop +80004ca0: 00000013 nop +80004ca4: 00000013 nop +80004ca8: 00000013 nop +80004cac: 00000013 nop +80004cb0: 00000013 nop +80004cb4: 00000013 nop +80004cb8: 00000013 nop +80004cbc: 00000013 nop +80004cc0: 00000013 nop +80004cc4: 00000013 nop +80004cc8: 00000013 nop +80004ccc: 00000013 nop +80004cd0: 00000013 nop +80004cd4: 00000013 nop +80004cd8: 00000013 nop +80004cdc: 00000013 nop +80004ce0: 00000013 nop +80004ce4: 00000013 nop +80004ce8: 00000013 nop +80004cec: 00000013 nop +80004cf0: 00000013 nop +80004cf4: 00000013 nop +80004cf8: 00000013 nop +80004cfc: 00000013 nop +80004d00: 00000013 nop +80004d04: 00000013 nop +80004d08: 00000013 nop +80004d0c: 00000013 nop +80004d10: 00000013 nop +80004d14: 00000013 nop +80004d18: 00000013 nop +80004d1c: 00000013 nop +80004d20: 00000013 nop +80004d24: 00000013 nop +80004d28: 00000013 nop +80004d2c: 00000013 nop +80004d30: 00000013 nop +80004d34: 00000013 nop +80004d38: 00000013 nop +80004d3c: 00000013 nop +80004d40: 00000013 nop +80004d44: 00000013 nop +80004d48: 00000013 nop +80004d4c: 00000013 nop +80004d50: 00000013 nop +80004d54: 00000013 nop +80004d58: 00000013 nop +80004d5c: 00000013 nop +80004d60: 00000013 nop +80004d64: 00000013 nop +80004d68: 00000013 nop +80004d6c: 00000013 nop +80004d70: 00000013 nop +80004d74: 00000013 nop +80004d78: 00000013 nop +80004d7c: 00000013 nop +80004d80: 00000013 nop +80004d84: 00000013 nop +80004d88: 00000013 nop +80004d8c: 00000013 nop +80004d90: 00000013 nop +80004d94: 00000013 nop +80004d98: 00000013 nop +80004d9c: 00000013 nop +80004da0: 00000013 nop +80004da4: 00000013 nop +80004da8: 00000013 nop +80004dac: 00000013 nop +80004db0: 00000013 nop +80004db4: 00000013 nop +80004db8: 00000013 nop +80004dbc: 00000013 nop +80004dc0: 00000013 nop +80004dc4: 00000013 nop +80004dc8: 00000013 nop +80004dcc: 00000013 nop +80004dd0: 00000013 nop +80004dd4: 00000013 nop +80004dd8: 00000013 nop +80004ddc: 00000013 nop +80004de0: 00000013 nop +80004de4: 00000013 nop +80004de8: 00000013 nop +80004dec: 00000013 nop +80004df0: 00000013 nop +80004df4: 00000013 nop +80004df8: 00000013 nop +80004dfc: 00000013 nop +80004e00: 00000013 nop +80004e04: 00000013 nop +80004e08: 00000013 nop +80004e0c: 00000013 nop +80004e10: 00000013 nop +80004e14: 00000013 nop +80004e18: 00000013 nop +80004e1c: 00000013 nop +80004e20: 00000013 nop +80004e24: 00000013 nop +80004e28: 00000013 nop +80004e2c: 00000013 nop +80004e30: 00000013 nop +80004e34: 00000013 nop +80004e38: 00000013 nop +80004e3c: 00000013 nop +80004e40: 00000013 nop +80004e44: 00000013 nop +80004e48: 00000013 nop +80004e4c: 00000013 nop +80004e50: 00000013 nop +80004e54: 00000013 nop +80004e58: 00000013 nop +80004e5c: 00000013 nop +80004e60: 00000013 nop +80004e64: 00000013 nop +80004e68: 00000013 nop +80004e6c: 00000013 nop +80004e70: 00000013 nop +80004e74: 00000013 nop +80004e78: 00000013 nop +80004e7c: 00000013 nop +80004e80: 00000013 nop +80004e84: 00000013 nop +80004e88: 00000013 nop +80004e8c: 00000013 nop +80004e90: 00000013 nop +80004e94: 00000013 nop +80004e98: 00000013 nop +80004e9c: 00000013 nop +80004ea0: 00000013 nop +80004ea4: 00000013 nop +80004ea8: 00000013 nop +80004eac: 00000013 nop +80004eb0: 00000013 nop +80004eb4: 00000013 nop +80004eb8: 00000013 nop +80004ebc: 00000013 nop +80004ec0: 00000013 nop +80004ec4: 00000013 nop +80004ec8: 00000013 nop +80004ecc: 00000013 nop +80004ed0: 00000013 nop +80004ed4: 00000013 nop +80004ed8: 00000013 nop +80004edc: 00000013 nop +80004ee0: 00000013 nop +80004ee4: 00000013 nop +80004ee8: 00000013 nop +80004eec: 00000013 nop +80004ef0: 00000013 nop +80004ef4: 00000013 nop +80004ef8: 00000013 nop +80004efc: 00000013 nop +80004f00: 00000013 nop +80004f04: 00000013 nop +80004f08: 00000013 nop +80004f0c: 00000013 nop +80004f10: 00000013 nop +80004f14: 00000013 nop +80004f18: 00000013 nop +80004f1c: 00000013 nop +80004f20: 00000013 nop +80004f24: 00000013 nop +80004f28: 00000013 nop +80004f2c: 00000013 nop +80004f30: 00000013 nop +80004f34: 00000013 nop +80004f38: 00000013 nop +80004f3c: 00000013 nop +80004f40: 00000013 nop +80004f44: 00000013 nop +80004f48: 00000013 nop +80004f4c: 00000013 nop +80004f50: 00000013 nop +80004f54: 00000013 nop +80004f58: 00000013 nop +80004f5c: 00000013 nop +80004f60: 00000013 nop +80004f64: 00000013 nop +80004f68: 00000013 nop +80004f6c: 00000013 nop +80004f70: 00000013 nop +80004f74: 00000013 nop +80004f78: 00000013 nop +80004f7c: 00000013 nop +80004f80: 00000013 nop +80004f84: 00000013 nop +80004f88: 00000013 nop +80004f8c: 00000013 nop +80004f90: 00000013 nop +80004f94: 00000013 nop +80004f98: 00000013 nop +80004f9c: 00000013 nop +80004fa0: 00000013 nop +80004fa4: 00000013 nop +80004fa8: 00000013 nop +80004fac: 00000013 nop +80004fb0: 00000013 nop +80004fb4: 00000013 nop +80004fb8: 00000013 nop +80004fbc: 00000013 nop +80004fc0: 00000013 nop +80004fc4: 00000013 nop +80004fc8: 00000013 nop +80004fcc: 00000013 nop +80004fd0: 00000013 nop +80004fd4: 00000013 nop +80004fd8: 00000013 nop +80004fdc: 00000013 nop +80004fe0: 00000013 nop +80004fe4: 00000013 nop +80004fe8: 00000013 nop +80004fec: 00000013 nop +80004ff0: 00000013 nop +80004ff4: 00000013 nop +80004ff8: 00000013 nop +80004ffc: 00000013 nop + +80005000 : +80005000: 03020100 .word 0x03020100 +80005004: 07060504 .word 0x07060504 +80005008: 0b0a0908 .word 0x0b0a0908 +8000500c: 0f0e0d0c .word 0x0f0e0d0c +80005010: 00000013 nop +80005014: 00000013 nop +80005018: 00000013 nop +8000501c: 00000013 nop +80005020: 00000013 nop +80005024: 00000013 nop +80005028: 00000013 nop +8000502c: 00000013 nop +80005030: 00000013 nop +80005034: 00000013 nop +80005038: 00000013 nop +8000503c: 00000013 nop +80005040: 00000013 nop +80005044: 00000013 nop +80005048: 00000013 nop +8000504c: 00000013 nop +80005050: 00000013 nop +80005054: 00000013 nop +80005058: 00000013 nop +8000505c: 00000013 nop +80005060: 00000013 nop +80005064: 00000013 nop +80005068: 00000013 nop +8000506c: 00000013 nop +80005070: 00000013 nop +80005074: 00000013 nop +80005078: 00000013 nop +8000507c: 00000013 nop +80005080: 00000013 nop +80005084: 00000013 nop +80005088: 00000013 nop +8000508c: 00000013 nop +80005090: 00000013 nop +80005094: 00000013 nop +80005098: 00000013 nop +8000509c: 00000013 nop +800050a0: 00000013 nop +800050a4: 00000013 nop +800050a8: 00000013 nop +800050ac: 00000013 nop +800050b0: 00000013 nop +800050b4: 00000013 nop +800050b8: 00000013 nop +800050bc: 00000013 nop +800050c0: 00000013 nop +800050c4: 00000013 nop +800050c8: 00000013 nop +800050cc: 00000013 nop +800050d0: 00000013 nop +800050d4: 00000013 nop +800050d8: 00000013 nop +800050dc: 00000013 nop +800050e0: 00000013 nop +800050e4: 00000013 nop +800050e8: 00000013 nop +800050ec: 00000013 nop +800050f0: 00000013 nop +800050f4: 00000013 nop +800050f8: 00000013 nop +800050fc: 00000013 nop +80005100: 00000013 nop +80005104: 00000013 nop +80005108: 00000013 nop +8000510c: 00000013 nop +80005110: 00000013 nop +80005114: 00000013 nop +80005118: 00000013 nop +8000511c: 00000013 nop +80005120: 00000013 nop +80005124: 00000013 nop +80005128: 00000013 nop +8000512c: 00000013 nop +80005130: 00000013 nop +80005134: 00000013 nop +80005138: 00000013 nop +8000513c: 00000013 nop +80005140: 00000013 nop +80005144: 00000013 nop +80005148: 00000013 nop +8000514c: 00000013 nop +80005150: 00000013 nop +80005154: 00000013 nop +80005158: 00000013 nop +8000515c: 00000013 nop +80005160: 00000013 nop +80005164: 00000013 nop +80005168: 00000013 nop +8000516c: 00000013 nop +80005170: 00000013 nop +80005174: 00000013 nop +80005178: 00000013 nop +8000517c: 00000013 nop +80005180: 00000013 nop +80005184: 00000013 nop +80005188: 00000013 nop +8000518c: 00000013 nop +80005190: 00000013 nop +80005194: 00000013 nop +80005198: 00000013 nop +8000519c: 00000013 nop +800051a0: 00000013 nop +800051a4: 00000013 nop +800051a8: 00000013 nop +800051ac: 00000013 nop +800051b0: 00000013 nop +800051b4: 00000013 nop +800051b8: 00000013 nop +800051bc: 00000013 nop +800051c0: 00000013 nop +800051c4: 00000013 nop +800051c8: 00000013 nop +800051cc: 00000013 nop +800051d0: 00000013 nop +800051d4: 00000013 nop +800051d8: 00000013 nop +800051dc: 00000013 nop +800051e0: 00000013 nop +800051e4: 00000013 nop +800051e8: 00000013 nop +800051ec: 00000013 nop +800051f0: 00000013 nop +800051f4: 00000013 nop +800051f8: 00000013 nop +800051fc: 00000013 nop +80005200: 00000013 nop +80005204: 00000013 nop +80005208: 00000013 nop +8000520c: 00000013 nop +80005210: 00000013 nop +80005214: 00000013 nop +80005218: 00000013 nop +8000521c: 00000013 nop +80005220: 00000013 nop +80005224: 00000013 nop +80005228: 00000013 nop +8000522c: 00000013 nop +80005230: 00000013 nop +80005234: 00000013 nop +80005238: 00000013 nop +8000523c: 00000013 nop +80005240: 00000013 nop +80005244: 00000013 nop +80005248: 00000013 nop +8000524c: 00000013 nop +80005250: 00000013 nop +80005254: 00000013 nop +80005258: 00000013 nop +8000525c: 00000013 nop +80005260: 00000013 nop +80005264: 00000013 nop +80005268: 00000013 nop +8000526c: 00000013 nop +80005270: 00000013 nop +80005274: 00000013 nop +80005278: 00000013 nop +8000527c: 00000013 nop +80005280: 00000013 nop +80005284: 00000013 nop +80005288: 00000013 nop +8000528c: 00000013 nop +80005290: 00000013 nop +80005294: 00000013 nop +80005298: 00000013 nop +8000529c: 00000013 nop +800052a0: 00000013 nop +800052a4: 00000013 nop +800052a8: 00000013 nop +800052ac: 00000013 nop +800052b0: 00000013 nop +800052b4: 00000013 nop +800052b8: 00000013 nop +800052bc: 00000013 nop +800052c0: 00000013 nop +800052c4: 00000013 nop +800052c8: 00000013 nop +800052cc: 00000013 nop +800052d0: 00000013 nop +800052d4: 00000013 nop +800052d8: 00000013 nop +800052dc: 00000013 nop +800052e0: 00000013 nop +800052e4: 00000013 nop +800052e8: 00000013 nop +800052ec: 00000013 nop +800052f0: 00000013 nop +800052f4: 00000013 nop +800052f8: 00000013 nop +800052fc: 00000013 nop +80005300: 00000013 nop +80005304: 00000013 nop +80005308: 00000013 nop +8000530c: 00000013 nop +80005310: 00000013 nop +80005314: 00000013 nop +80005318: 00000013 nop +8000531c: 00000013 nop +80005320: 00000013 nop +80005324: 00000013 nop +80005328: 00000013 nop +8000532c: 00000013 nop +80005330: 00000013 nop +80005334: 00000013 nop +80005338: 00000013 nop +8000533c: 00000013 nop +80005340: 00000013 nop +80005344: 00000013 nop +80005348: 00000013 nop +8000534c: 00000013 nop +80005350: 00000013 nop +80005354: 00000013 nop +80005358: 00000013 nop +8000535c: 00000013 nop +80005360: 00000013 nop +80005364: 00000013 nop +80005368: 00000013 nop +8000536c: 00000013 nop +80005370: 00000013 nop +80005374: 00000013 nop +80005378: 00000013 nop +8000537c: 00000013 nop +80005380: 00000013 nop +80005384: 00000013 nop +80005388: 00000013 nop +8000538c: 00000013 nop +80005390: 00000013 nop +80005394: 00000013 nop +80005398: 00000013 nop +8000539c: 00000013 nop +800053a0: 00000013 nop +800053a4: 00000013 nop +800053a8: 00000013 nop +800053ac: 00000013 nop +800053b0: 00000013 nop +800053b4: 00000013 nop +800053b8: 00000013 nop +800053bc: 00000013 nop +800053c0: 00000013 nop +800053c4: 00000013 nop +800053c8: 00000013 nop +800053cc: 00000013 nop +800053d0: 00000013 nop +800053d4: 00000013 nop +800053d8: 00000013 nop +800053dc: 00000013 nop +800053e0: 00000013 nop +800053e4: 00000013 nop +800053e8: 00000013 nop +800053ec: 00000013 nop +800053f0: 00000013 nop +800053f4: 00000013 nop +800053f8: 00000013 nop +800053fc: 00000013 nop +80005400: 00000013 nop +80005404: 00000013 nop +80005408: 00000013 nop +8000540c: 00000013 nop +80005410: 00000013 nop +80005414: 00000013 nop +80005418: 00000013 nop +8000541c: 00000013 nop +80005420: 00000013 nop +80005424: 00000013 nop +80005428: 00000013 nop +8000542c: 00000013 nop +80005430: 00000013 nop +80005434: 00000013 nop +80005438: 00000013 nop +8000543c: 00000013 nop +80005440: 00000013 nop +80005444: 00000013 nop +80005448: 00000013 nop +8000544c: 00000013 nop +80005450: 00000013 nop +80005454: 00000013 nop +80005458: 00000013 nop +8000545c: 00000013 nop +80005460: 00000013 nop +80005464: 00000013 nop +80005468: 00000013 nop +8000546c: 00000013 nop +80005470: 00000013 nop +80005474: 00000013 nop +80005478: 00000013 nop +8000547c: 00000013 nop +80005480: 00000013 nop +80005484: 00000013 nop +80005488: 00000013 nop +8000548c: 00000013 nop +80005490: 00000013 nop +80005494: 00000013 nop +80005498: 00000013 nop +8000549c: 00000013 nop +800054a0: 00000013 nop +800054a4: 00000013 nop +800054a8: 00000013 nop +800054ac: 00000013 nop +800054b0: 00000013 nop +800054b4: 00000013 nop +800054b8: 00000013 nop +800054bc: 00000013 nop +800054c0: 00000013 nop +800054c4: 00000013 nop +800054c8: 00000013 nop +800054cc: 00000013 nop +800054d0: 00000013 nop +800054d4: 00000013 nop +800054d8: 00000013 nop +800054dc: 00000013 nop +800054e0: 00000013 nop +800054e4: 00000013 nop +800054e8: 00000013 nop +800054ec: 00000013 nop +800054f0: 00000013 nop +800054f4: 00000013 nop +800054f8: 00000013 nop +800054fc: 00000013 nop +80005500: 00000013 nop +80005504: 00000013 nop +80005508: 00000013 nop +8000550c: 00000013 nop +80005510: 00000013 nop +80005514: 00000013 nop +80005518: 00000013 nop +8000551c: 00000013 nop +80005520: 00000013 nop +80005524: 00000013 nop +80005528: 00000013 nop +8000552c: 00000013 nop +80005530: 00000013 nop +80005534: 00000013 nop +80005538: 00000013 nop +8000553c: 00000013 nop +80005540: 00000013 nop +80005544: 00000013 nop +80005548: 00000013 nop +8000554c: 00000013 nop +80005550: 00000013 nop +80005554: 00000013 nop +80005558: 00000013 nop +8000555c: 00000013 nop +80005560: 00000013 nop +80005564: 00000013 nop +80005568: 00000013 nop +8000556c: 00000013 nop +80005570: 00000013 nop +80005574: 00000013 nop +80005578: 00000013 nop +8000557c: 00000013 nop +80005580: 00000013 nop +80005584: 00000013 nop +80005588: 00000013 nop +8000558c: 00000013 nop +80005590: 00000013 nop +80005594: 00000013 nop +80005598: 00000013 nop +8000559c: 00000013 nop +800055a0: 00000013 nop +800055a4: 00000013 nop +800055a8: 00000013 nop +800055ac: 00000013 nop +800055b0: 00000013 nop +800055b4: 00000013 nop +800055b8: 00000013 nop +800055bc: 00000013 nop +800055c0: 00000013 nop +800055c4: 00000013 nop +800055c8: 00000013 nop +800055cc: 00000013 nop +800055d0: 00000013 nop +800055d4: 00000013 nop +800055d8: 00000013 nop +800055dc: 00000013 nop +800055e0: 00000013 nop +800055e4: 00000013 nop +800055e8: 00000013 nop +800055ec: 00000013 nop +800055f0: 00000013 nop +800055f4: 00000013 nop +800055f8: 00000013 nop +800055fc: 00000013 nop +80005600: 00000013 nop +80005604: 00000013 nop +80005608: 00000013 nop +8000560c: 00000013 nop +80005610: 00000013 nop +80005614: 00000013 nop +80005618: 00000013 nop +8000561c: 00000013 nop +80005620: 00000013 nop +80005624: 00000013 nop +80005628: 00000013 nop +8000562c: 00000013 nop +80005630: 00000013 nop +80005634: 00000013 nop +80005638: 00000013 nop +8000563c: 00000013 nop +80005640: 00000013 nop +80005644: 00000013 nop +80005648: 00000013 nop +8000564c: 00000013 nop +80005650: 00000013 nop +80005654: 00000013 nop +80005658: 00000013 nop +8000565c: 00000013 nop +80005660: 00000013 nop +80005664: 00000013 nop +80005668: 00000013 nop +8000566c: 00000013 nop +80005670: 00000013 nop +80005674: 00000013 nop +80005678: 00000013 nop +8000567c: 00000013 nop +80005680: 00000013 nop +80005684: 00000013 nop +80005688: 00000013 nop +8000568c: 00000013 nop +80005690: 00000013 nop +80005694: 00000013 nop +80005698: 00000013 nop +8000569c: 00000013 nop +800056a0: 00000013 nop +800056a4: 00000013 nop +800056a8: 00000013 nop +800056ac: 00000013 nop +800056b0: 00000013 nop +800056b4: 00000013 nop +800056b8: 00000013 nop +800056bc: 00000013 nop +800056c0: 00000013 nop +800056c4: 00000013 nop +800056c8: 00000013 nop +800056cc: 00000013 nop +800056d0: 00000013 nop +800056d4: 00000013 nop +800056d8: 00000013 nop +800056dc: 00000013 nop +800056e0: 00000013 nop +800056e4: 00000013 nop +800056e8: 00000013 nop +800056ec: 00000013 nop +800056f0: 00000013 nop +800056f4: 00000013 nop +800056f8: 00000013 nop +800056fc: 00000013 nop +80005700: 00000013 nop +80005704: 00000013 nop +80005708: 00000013 nop +8000570c: 00000013 nop +80005710: 00000013 nop +80005714: 00000013 nop +80005718: 00000013 nop +8000571c: 00000013 nop +80005720: 00000013 nop +80005724: 00000013 nop +80005728: 00000013 nop +8000572c: 00000013 nop +80005730: 00000013 nop +80005734: 00000013 nop +80005738: 00000013 nop +8000573c: 00000013 nop +80005740: 00000013 nop +80005744: 00000013 nop +80005748: 00000013 nop +8000574c: 00000013 nop +80005750: 00000013 nop +80005754: 00000013 nop +80005758: 00000013 nop +8000575c: 00000013 nop +80005760: 00000013 nop +80005764: 00000013 nop +80005768: 00000013 nop +8000576c: 00000013 nop +80005770: 00000013 nop +80005774: 00000013 nop +80005778: 00000013 nop +8000577c: 00000013 nop +80005780: 00000013 nop +80005784: 00000013 nop +80005788: 00000013 nop +8000578c: 00000013 nop +80005790: 00000013 nop +80005794: 00000013 nop +80005798: 00000013 nop +8000579c: 00000013 nop +800057a0: 00000013 nop +800057a4: 00000013 nop +800057a8: 00000013 nop +800057ac: 00000013 nop +800057b0: 00000013 nop +800057b4: 00000013 nop +800057b8: 00000013 nop +800057bc: 00000013 nop +800057c0: 00000013 nop +800057c4: 00000013 nop +800057c8: 00000013 nop +800057cc: 00000013 nop +800057d0: 00000013 nop +800057d4: 00000013 nop +800057d8: 00000013 nop +800057dc: 00000013 nop +800057e0: 00000013 nop +800057e4: 00000013 nop +800057e8: 00000013 nop +800057ec: 00000013 nop +800057f0: 00000013 nop +800057f4: 00000013 nop +800057f8: 00000013 nop +800057fc: 00000013 nop +80005800: 00000013 nop +80005804: 00000013 nop +80005808: 00000013 nop +8000580c: 00000013 nop +80005810: 00000013 nop +80005814: 00000013 nop +80005818: 00000013 nop +8000581c: 00000013 nop +80005820: 00000013 nop +80005824: 00000013 nop +80005828: 00000013 nop +8000582c: 00000013 nop +80005830: 00000013 nop +80005834: 00000013 nop +80005838: 00000013 nop +8000583c: 00000013 nop +80005840: 00000013 nop +80005844: 00000013 nop +80005848: 00000013 nop +8000584c: 00000013 nop +80005850: 00000013 nop +80005854: 00000013 nop +80005858: 00000013 nop +8000585c: 00000013 nop +80005860: 00000013 nop +80005864: 00000013 nop +80005868: 00000013 nop +8000586c: 00000013 nop +80005870: 00000013 nop +80005874: 00000013 nop +80005878: 00000013 nop +8000587c: 00000013 nop +80005880: 00000013 nop +80005884: 00000013 nop +80005888: 00000013 nop +8000588c: 00000013 nop +80005890: 00000013 nop +80005894: 00000013 nop +80005898: 00000013 nop +8000589c: 00000013 nop +800058a0: 00000013 nop +800058a4: 00000013 nop +800058a8: 00000013 nop +800058ac: 00000013 nop +800058b0: 00000013 nop +800058b4: 00000013 nop +800058b8: 00000013 nop +800058bc: 00000013 nop +800058c0: 00000013 nop +800058c4: 00000013 nop +800058c8: 00000013 nop +800058cc: 00000013 nop +800058d0: 00000013 nop +800058d4: 00000013 nop +800058d8: 00000013 nop +800058dc: 00000013 nop +800058e0: 00000013 nop +800058e4: 00000013 nop +800058e8: 00000013 nop +800058ec: 00000013 nop +800058f0: 00000013 nop +800058f4: 00000013 nop +800058f8: 00000013 nop +800058fc: 00000013 nop +80005900: 00000013 nop +80005904: 00000013 nop +80005908: 00000013 nop +8000590c: 00000013 nop +80005910: 00000013 nop +80005914: 00000013 nop +80005918: 00000013 nop +8000591c: 00000013 nop +80005920: 00000013 nop +80005924: 00000013 nop +80005928: 00000013 nop +8000592c: 00000013 nop +80005930: 00000013 nop +80005934: 00000013 nop +80005938: 00000013 nop +8000593c: 00000013 nop +80005940: 00000013 nop +80005944: 00000013 nop +80005948: 00000013 nop +8000594c: 00000013 nop +80005950: 00000013 nop +80005954: 00000013 nop +80005958: 00000013 nop +8000595c: 00000013 nop +80005960: 00000013 nop +80005964: 00000013 nop +80005968: 00000013 nop +8000596c: 00000013 nop +80005970: 00000013 nop +80005974: 00000013 nop +80005978: 00000013 nop +8000597c: 00000013 nop +80005980: 00000013 nop +80005984: 00000013 nop +80005988: 00000013 nop +8000598c: 00000013 nop +80005990: 00000013 nop +80005994: 00000013 nop +80005998: 00000013 nop +8000599c: 00000013 nop +800059a0: 00000013 nop +800059a4: 00000013 nop +800059a8: 00000013 nop +800059ac: 00000013 nop +800059b0: 00000013 nop +800059b4: 00000013 nop +800059b8: 00000013 nop +800059bc: 00000013 nop +800059c0: 00000013 nop +800059c4: 00000013 nop +800059c8: 00000013 nop +800059cc: 00000013 nop +800059d0: 00000013 nop +800059d4: 00000013 nop +800059d8: 00000013 nop +800059dc: 00000013 nop +800059e0: 00000013 nop +800059e4: 00000013 nop +800059e8: 00000013 nop +800059ec: 00000013 nop +800059f0: 00000013 nop +800059f4: 00000013 nop +800059f8: 00000013 nop +800059fc: 00000013 nop +80005a00: 00000013 nop +80005a04: 00000013 nop +80005a08: 00000013 nop +80005a0c: 00000013 nop +80005a10: 00000013 nop +80005a14: 00000013 nop +80005a18: 00000013 nop +80005a1c: 00000013 nop +80005a20: 00000013 nop +80005a24: 00000013 nop +80005a28: 00000013 nop +80005a2c: 00000013 nop +80005a30: 00000013 nop +80005a34: 00000013 nop +80005a38: 00000013 nop +80005a3c: 00000013 nop +80005a40: 00000013 nop +80005a44: 00000013 nop +80005a48: 00000013 nop +80005a4c: 00000013 nop +80005a50: 00000013 nop +80005a54: 00000013 nop +80005a58: 00000013 nop +80005a5c: 00000013 nop +80005a60: 00000013 nop +80005a64: 00000013 nop +80005a68: 00000013 nop +80005a6c: 00000013 nop +80005a70: 00000013 nop +80005a74: 00000013 nop +80005a78: 00000013 nop +80005a7c: 00000013 nop +80005a80: 00000013 nop +80005a84: 00000013 nop +80005a88: 00000013 nop +80005a8c: 00000013 nop +80005a90: 00000013 nop +80005a94: 00000013 nop +80005a98: 00000013 nop +80005a9c: 00000013 nop +80005aa0: 00000013 nop +80005aa4: 00000013 nop +80005aa8: 00000013 nop +80005aac: 00000013 nop +80005ab0: 00000013 nop +80005ab4: 00000013 nop +80005ab8: 00000013 nop +80005abc: 00000013 nop +80005ac0: 00000013 nop +80005ac4: 00000013 nop +80005ac8: 00000013 nop +80005acc: 00000013 nop +80005ad0: 00000013 nop +80005ad4: 00000013 nop +80005ad8: 00000013 nop +80005adc: 00000013 nop +80005ae0: 00000013 nop +80005ae4: 00000013 nop +80005ae8: 00000013 nop +80005aec: 00000013 nop +80005af0: 00000013 nop +80005af4: 00000013 nop +80005af8: 00000013 nop +80005afc: 00000013 nop +80005b00: 00000013 nop +80005b04: 00000013 nop +80005b08: 00000013 nop +80005b0c: 00000013 nop +80005b10: 00000013 nop +80005b14: 00000013 nop +80005b18: 00000013 nop +80005b1c: 00000013 nop +80005b20: 00000013 nop +80005b24: 00000013 nop +80005b28: 00000013 nop +80005b2c: 00000013 nop +80005b30: 00000013 nop +80005b34: 00000013 nop +80005b38: 00000013 nop +80005b3c: 00000013 nop +80005b40: 00000013 nop +80005b44: 00000013 nop +80005b48: 00000013 nop +80005b4c: 00000013 nop +80005b50: 00000013 nop +80005b54: 00000013 nop +80005b58: 00000013 nop +80005b5c: 00000013 nop +80005b60: 00000013 nop +80005b64: 00000013 nop +80005b68: 00000013 nop +80005b6c: 00000013 nop +80005b70: 00000013 nop +80005b74: 00000013 nop +80005b78: 00000013 nop +80005b7c: 00000013 nop +80005b80: 00000013 nop +80005b84: 00000013 nop +80005b88: 00000013 nop +80005b8c: 00000013 nop +80005b90: 00000013 nop +80005b94: 00000013 nop +80005b98: 00000013 nop +80005b9c: 00000013 nop +80005ba0: 00000013 nop +80005ba4: 00000013 nop +80005ba8: 00000013 nop +80005bac: 00000013 nop +80005bb0: 00000013 nop +80005bb4: 00000013 nop +80005bb8: 00000013 nop +80005bbc: 00000013 nop +80005bc0: 00000013 nop +80005bc4: 00000013 nop +80005bc8: 00000013 nop +80005bcc: 00000013 nop +80005bd0: 00000013 nop +80005bd4: 00000013 nop +80005bd8: 00000013 nop +80005bdc: 00000013 nop +80005be0: 00000013 nop +80005be4: 00000013 nop +80005be8: 00000013 nop +80005bec: 00000013 nop +80005bf0: 00000013 nop +80005bf4: 00000013 nop +80005bf8: 00000013 nop +80005bfc: 00000013 nop +80005c00: 00000013 nop +80005c04: 00000013 nop +80005c08: 00000013 nop +80005c0c: 00000013 nop +80005c10: 00000013 nop +80005c14: 00000013 nop +80005c18: 00000013 nop +80005c1c: 00000013 nop +80005c20: 00000013 nop +80005c24: 00000013 nop +80005c28: 00000013 nop +80005c2c: 00000013 nop +80005c30: 00000013 nop +80005c34: 00000013 nop +80005c38: 00000013 nop +80005c3c: 00000013 nop +80005c40: 00000013 nop +80005c44: 00000013 nop +80005c48: 00000013 nop +80005c4c: 00000013 nop +80005c50: 00000013 nop +80005c54: 00000013 nop +80005c58: 00000013 nop +80005c5c: 00000013 nop +80005c60: 00000013 nop +80005c64: 00000013 nop +80005c68: 00000013 nop +80005c6c: 00000013 nop +80005c70: 00000013 nop +80005c74: 00000013 nop +80005c78: 00000013 nop +80005c7c: 00000013 nop +80005c80: 00000013 nop +80005c84: 00000013 nop +80005c88: 00000013 nop +80005c8c: 00000013 nop +80005c90: 00000013 nop +80005c94: 00000013 nop +80005c98: 00000013 nop +80005c9c: 00000013 nop +80005ca0: 00000013 nop +80005ca4: 00000013 nop +80005ca8: 00000013 nop +80005cac: 00000013 nop +80005cb0: 00000013 nop +80005cb4: 00000013 nop +80005cb8: 00000013 nop +80005cbc: 00000013 nop +80005cc0: 00000013 nop +80005cc4: 00000013 nop +80005cc8: 00000013 nop +80005ccc: 00000013 nop +80005cd0: 00000013 nop +80005cd4: 00000013 nop +80005cd8: 00000013 nop +80005cdc: 00000013 nop +80005ce0: 00000013 nop +80005ce4: 00000013 nop +80005ce8: 00000013 nop +80005cec: 00000013 nop +80005cf0: 00000013 nop +80005cf4: 00000013 nop +80005cf8: 00000013 nop +80005cfc: 00000013 nop +80005d00: 00000013 nop +80005d04: 00000013 nop +80005d08: 00000013 nop +80005d0c: 00000013 nop +80005d10: 00000013 nop +80005d14: 00000013 nop +80005d18: 00000013 nop +80005d1c: 00000013 nop +80005d20: 00000013 nop +80005d24: 00000013 nop +80005d28: 00000013 nop +80005d2c: 00000013 nop +80005d30: 00000013 nop +80005d34: 00000013 nop +80005d38: 00000013 nop +80005d3c: 00000013 nop +80005d40: 00000013 nop +80005d44: 00000013 nop +80005d48: 00000013 nop +80005d4c: 00000013 nop +80005d50: 00000013 nop +80005d54: 00000013 nop +80005d58: 00000013 nop +80005d5c: 00000013 nop +80005d60: 00000013 nop +80005d64: 00000013 nop +80005d68: 00000013 nop +80005d6c: 00000013 nop +80005d70: 00000013 nop +80005d74: 00000013 nop +80005d78: 00000013 nop +80005d7c: 00000013 nop +80005d80: 00000013 nop +80005d84: 00000013 nop +80005d88: 00000013 nop +80005d8c: 00000013 nop +80005d90: 00000013 nop +80005d94: 00000013 nop +80005d98: 00000013 nop +80005d9c: 00000013 nop +80005da0: 00000013 nop +80005da4: 00000013 nop +80005da8: 00000013 nop +80005dac: 00000013 nop +80005db0: 00000013 nop +80005db4: 00000013 nop +80005db8: 00000013 nop +80005dbc: 00000013 nop +80005dc0: 00000013 nop +80005dc4: 00000013 nop +80005dc8: 00000013 nop +80005dcc: 00000013 nop +80005dd0: 00000013 nop +80005dd4: 00000013 nop +80005dd8: 00000013 nop +80005ddc: 00000013 nop +80005de0: 00000013 nop +80005de4: 00000013 nop +80005de8: 00000013 nop +80005dec: 00000013 nop +80005df0: 00000013 nop +80005df4: 00000013 nop +80005df8: 00000013 nop +80005dfc: 00000013 nop +80005e00: 00000013 nop +80005e04: 00000013 nop +80005e08: 00000013 nop +80005e0c: 00000013 nop +80005e10: 00000013 nop +80005e14: 00000013 nop +80005e18: 00000013 nop +80005e1c: 00000013 nop +80005e20: 00000013 nop +80005e24: 00000013 nop +80005e28: 00000013 nop +80005e2c: 00000013 nop +80005e30: 00000013 nop +80005e34: 00000013 nop +80005e38: 00000013 nop +80005e3c: 00000013 nop +80005e40: 00000013 nop +80005e44: 00000013 nop +80005e48: 00000013 nop +80005e4c: 00000013 nop +80005e50: 00000013 nop +80005e54: 00000013 nop +80005e58: 00000013 nop +80005e5c: 00000013 nop +80005e60: 00000013 nop +80005e64: 00000013 nop +80005e68: 00000013 nop +80005e6c: 00000013 nop +80005e70: 00000013 nop +80005e74: 00000013 nop +80005e78: 00000013 nop +80005e7c: 00000013 nop +80005e80: 00000013 nop +80005e84: 00000013 nop +80005e88: 00000013 nop +80005e8c: 00000013 nop +80005e90: 00000013 nop +80005e94: 00000013 nop +80005e98: 00000013 nop +80005e9c: 00000013 nop +80005ea0: 00000013 nop +80005ea4: 00000013 nop +80005ea8: 00000013 nop +80005eac: 00000013 nop +80005eb0: 00000013 nop +80005eb4: 00000013 nop +80005eb8: 00000013 nop +80005ebc: 00000013 nop +80005ec0: 00000013 nop +80005ec4: 00000013 nop +80005ec8: 00000013 nop +80005ecc: 00000013 nop +80005ed0: 00000013 nop +80005ed4: 00000013 nop +80005ed8: 00000013 nop +80005edc: 00000013 nop +80005ee0: 00000013 nop +80005ee4: 00000013 nop +80005ee8: 00000013 nop +80005eec: 00000013 nop +80005ef0: 00000013 nop +80005ef4: 00000013 nop +80005ef8: 00000013 nop +80005efc: 00000013 nop +80005f00: 00000013 nop +80005f04: 00000013 nop +80005f08: 00000013 nop +80005f0c: 00000013 nop +80005f10: 00000013 nop +80005f14: 00000013 nop +80005f18: 00000013 nop +80005f1c: 00000013 nop +80005f20: 00000013 nop +80005f24: 00000013 nop +80005f28: 00000013 nop +80005f2c: 00000013 nop +80005f30: 00000013 nop +80005f34: 00000013 nop +80005f38: 00000013 nop +80005f3c: 00000013 nop +80005f40: 00000013 nop +80005f44: 00000013 nop +80005f48: 00000013 nop +80005f4c: 00000013 nop +80005f50: 00000013 nop +80005f54: 00000013 nop +80005f58: 00000013 nop +80005f5c: 00000013 nop +80005f60: 00000013 nop +80005f64: 00000013 nop +80005f68: 00000013 nop +80005f6c: 00000013 nop +80005f70: 00000013 nop +80005f74: 00000013 nop +80005f78: 00000013 nop +80005f7c: 00000013 nop +80005f80: 00000013 nop +80005f84: 00000013 nop +80005f88: 00000013 nop +80005f8c: 00000013 nop +80005f90: 00000013 nop +80005f94: 00000013 nop +80005f98: 00000013 nop +80005f9c: 00000013 nop +80005fa0: 00000013 nop +80005fa4: 00000013 nop +80005fa8: 00000013 nop +80005fac: 00000013 nop +80005fb0: 00000013 nop +80005fb4: 00000013 nop +80005fb8: 00000013 nop +80005fbc: 00000013 nop +80005fc0: 00000013 nop +80005fc4: 00000013 nop +80005fc8: 00000013 nop +80005fcc: 00000013 nop +80005fd0: 00000013 nop +80005fd4: 00000013 nop +80005fd8: 00000013 nop +80005fdc: 00000013 nop +80005fe0: 00000013 nop +80005fe4: 00000013 nop +80005fe8: 00000013 nop +80005fec: 00000013 nop +80005ff0: 00000013 nop +80005ff4: 00000013 nop +80005ff8: 00000013 nop +80005ffc: 00000013 nop + +80006000 : +80006000: 13121110 .word 0x13121110 +80006004: 17161514 .word 0x17161514 +80006008: 1b1a1918 .word 0x1b1a1918 +8000600c: 1f1e1d1c .word 0x1f1e1d1c +80006010: 00000013 nop +80006014: 00000013 nop +80006018: 00000013 nop +8000601c: 00000013 nop +80006020: 00000013 nop +80006024: 00000013 nop +80006028: 00000013 nop +8000602c: 00000013 nop +80006030: 00000013 nop +80006034: 00000013 nop +80006038: 00000013 nop +8000603c: 00000013 nop +80006040: 00000013 nop +80006044: 00000013 nop +80006048: 00000013 nop +8000604c: 00000013 nop +80006050: 00000013 nop +80006054: 00000013 nop +80006058: 00000013 nop +8000605c: 00000013 nop +80006060: 00000013 nop +80006064: 00000013 nop +80006068: 00000013 nop +8000606c: 00000013 nop +80006070: 00000013 nop +80006074: 00000013 nop +80006078: 00000013 nop +8000607c: 00000013 nop +80006080: 00000013 nop +80006084: 00000013 nop +80006088: 00000013 nop +8000608c: 00000013 nop +80006090: 00000013 nop +80006094: 00000013 nop +80006098: 00000013 nop +8000609c: 00000013 nop +800060a0: 00000013 nop +800060a4: 00000013 nop +800060a8: 00000013 nop +800060ac: 00000013 nop +800060b0: 00000013 nop +800060b4: 00000013 nop +800060b8: 00000013 nop +800060bc: 00000013 nop +800060c0: 00000013 nop +800060c4: 00000013 nop +800060c8: 00000013 nop +800060cc: 00000013 nop +800060d0: 00000013 nop +800060d4: 00000013 nop +800060d8: 00000013 nop +800060dc: 00000013 nop +800060e0: 00000013 nop +800060e4: 00000013 nop +800060e8: 00000013 nop +800060ec: 00000013 nop +800060f0: 00000013 nop +800060f4: 00000013 nop +800060f8: 00000013 nop +800060fc: 00000013 nop +80006100: 00000013 nop +80006104: 00000013 nop +80006108: 00000013 nop +8000610c: 00000013 nop +80006110: 00000013 nop +80006114: 00000013 nop +80006118: 00000013 nop +8000611c: 00000013 nop +80006120: 00000013 nop +80006124: 00000013 nop +80006128: 00000013 nop +8000612c: 00000013 nop +80006130: 00000013 nop +80006134: 00000013 nop +80006138: 00000013 nop +8000613c: 00000013 nop +80006140: 00000013 nop +80006144: 00000013 nop +80006148: 00000013 nop +8000614c: 00000013 nop +80006150: 00000013 nop +80006154: 00000013 nop +80006158: 00000013 nop +8000615c: 00000013 nop +80006160: 00000013 nop +80006164: 00000013 nop +80006168: 00000013 nop +8000616c: 00000013 nop +80006170: 00000013 nop +80006174: 00000013 nop +80006178: 00000013 nop +8000617c: 00000013 nop +80006180: 00000013 nop +80006184: 00000013 nop +80006188: 00000013 nop +8000618c: 00000013 nop +80006190: 00000013 nop +80006194: 00000013 nop +80006198: 00000013 nop +8000619c: 00000013 nop +800061a0: 00000013 nop +800061a4: 00000013 nop +800061a8: 00000013 nop +800061ac: 00000013 nop +800061b0: 00000013 nop +800061b4: 00000013 nop +800061b8: 00000013 nop +800061bc: 00000013 nop +800061c0: 00000013 nop +800061c4: 00000013 nop +800061c8: 00000013 nop +800061cc: 00000013 nop +800061d0: 00000013 nop +800061d4: 00000013 nop +800061d8: 00000013 nop +800061dc: 00000013 nop +800061e0: 00000013 nop +800061e4: 00000013 nop +800061e8: 00000013 nop +800061ec: 00000013 nop +800061f0: 00000013 nop +800061f4: 00000013 nop +800061f8: 00000013 nop +800061fc: 00000013 nop +80006200: 00000013 nop +80006204: 00000013 nop +80006208: 00000013 nop +8000620c: 00000013 nop +80006210: 00000013 nop +80006214: 00000013 nop +80006218: 00000013 nop +8000621c: 00000013 nop +80006220: 00000013 nop +80006224: 00000013 nop +80006228: 00000013 nop +8000622c: 00000013 nop +80006230: 00000013 nop +80006234: 00000013 nop +80006238: 00000013 nop +8000623c: 00000013 nop +80006240: 00000013 nop +80006244: 00000013 nop +80006248: 00000013 nop +8000624c: 00000013 nop +80006250: 00000013 nop +80006254: 00000013 nop +80006258: 00000013 nop +8000625c: 00000013 nop +80006260: 00000013 nop +80006264: 00000013 nop +80006268: 00000013 nop +8000626c: 00000013 nop +80006270: 00000013 nop +80006274: 00000013 nop +80006278: 00000013 nop +8000627c: 00000013 nop +80006280: 00000013 nop +80006284: 00000013 nop +80006288: 00000013 nop +8000628c: 00000013 nop +80006290: 00000013 nop +80006294: 00000013 nop +80006298: 00000013 nop +8000629c: 00000013 nop +800062a0: 00000013 nop +800062a4: 00000013 nop +800062a8: 00000013 nop +800062ac: 00000013 nop +800062b0: 00000013 nop +800062b4: 00000013 nop +800062b8: 00000013 nop +800062bc: 00000013 nop +800062c0: 00000013 nop +800062c4: 00000013 nop +800062c8: 00000013 nop +800062cc: 00000013 nop +800062d0: 00000013 nop +800062d4: 00000013 nop +800062d8: 00000013 nop +800062dc: 00000013 nop +800062e0: 00000013 nop +800062e4: 00000013 nop +800062e8: 00000013 nop +800062ec: 00000013 nop +800062f0: 00000013 nop +800062f4: 00000013 nop +800062f8: 00000013 nop +800062fc: 00000013 nop +80006300: 00000013 nop +80006304: 00000013 nop +80006308: 00000013 nop +8000630c: 00000013 nop +80006310: 00000013 nop +80006314: 00000013 nop +80006318: 00000013 nop +8000631c: 00000013 nop +80006320: 00000013 nop +80006324: 00000013 nop +80006328: 00000013 nop +8000632c: 00000013 nop +80006330: 00000013 nop +80006334: 00000013 nop +80006338: 00000013 nop +8000633c: 00000013 nop +80006340: 00000013 nop +80006344: 00000013 nop +80006348: 00000013 nop +8000634c: 00000013 nop +80006350: 00000013 nop +80006354: 00000013 nop +80006358: 00000013 nop +8000635c: 00000013 nop +80006360: 00000013 nop +80006364: 00000013 nop +80006368: 00000013 nop +8000636c: 00000013 nop +80006370: 00000013 nop +80006374: 00000013 nop +80006378: 00000013 nop +8000637c: 00000013 nop +80006380: 00000013 nop +80006384: 00000013 nop +80006388: 00000013 nop +8000638c: 00000013 nop +80006390: 00000013 nop +80006394: 00000013 nop +80006398: 00000013 nop +8000639c: 00000013 nop +800063a0: 00000013 nop +800063a4: 00000013 nop +800063a8: 00000013 nop +800063ac: 00000013 nop +800063b0: 00000013 nop +800063b4: 00000013 nop +800063b8: 00000013 nop +800063bc: 00000013 nop +800063c0: 00000013 nop +800063c4: 00000013 nop +800063c8: 00000013 nop +800063cc: 00000013 nop +800063d0: 00000013 nop +800063d4: 00000013 nop +800063d8: 00000013 nop +800063dc: 00000013 nop +800063e0: 00000013 nop +800063e4: 00000013 nop +800063e8: 00000013 nop +800063ec: 00000013 nop +800063f0: 00000013 nop +800063f4: 00000013 nop +800063f8: 00000013 nop +800063fc: 00000013 nop +80006400: 00000013 nop +80006404: 00000013 nop +80006408: 00000013 nop +8000640c: 00000013 nop +80006410: 00000013 nop +80006414: 00000013 nop +80006418: 00000013 nop +8000641c: 00000013 nop +80006420: 00000013 nop +80006424: 00000013 nop +80006428: 00000013 nop +8000642c: 00000013 nop +80006430: 00000013 nop +80006434: 00000013 nop +80006438: 00000013 nop +8000643c: 00000013 nop +80006440: 00000013 nop +80006444: 00000013 nop +80006448: 00000013 nop +8000644c: 00000013 nop +80006450: 00000013 nop +80006454: 00000013 nop +80006458: 00000013 nop +8000645c: 00000013 nop +80006460: 00000013 nop +80006464: 00000013 nop +80006468: 00000013 nop +8000646c: 00000013 nop +80006470: 00000013 nop +80006474: 00000013 nop +80006478: 00000013 nop +8000647c: 00000013 nop +80006480: 00000013 nop +80006484: 00000013 nop +80006488: 00000013 nop +8000648c: 00000013 nop +80006490: 00000013 nop +80006494: 00000013 nop +80006498: 00000013 nop +8000649c: 00000013 nop +800064a0: 00000013 nop +800064a4: 00000013 nop +800064a8: 00000013 nop +800064ac: 00000013 nop +800064b0: 00000013 nop +800064b4: 00000013 nop +800064b8: 00000013 nop +800064bc: 00000013 nop +800064c0: 00000013 nop +800064c4: 00000013 nop +800064c8: 00000013 nop +800064cc: 00000013 nop +800064d0: 00000013 nop +800064d4: 00000013 nop +800064d8: 00000013 nop +800064dc: 00000013 nop +800064e0: 00000013 nop +800064e4: 00000013 nop +800064e8: 00000013 nop +800064ec: 00000013 nop +800064f0: 00000013 nop +800064f4: 00000013 nop +800064f8: 00000013 nop +800064fc: 00000013 nop +80006500: 00000013 nop +80006504: 00000013 nop +80006508: 00000013 nop +8000650c: 00000013 nop +80006510: 00000013 nop +80006514: 00000013 nop +80006518: 00000013 nop +8000651c: 00000013 nop +80006520: 00000013 nop +80006524: 00000013 nop +80006528: 00000013 nop +8000652c: 00000013 nop +80006530: 00000013 nop +80006534: 00000013 nop +80006538: 00000013 nop +8000653c: 00000013 nop +80006540: 00000013 nop +80006544: 00000013 nop +80006548: 00000013 nop +8000654c: 00000013 nop +80006550: 00000013 nop +80006554: 00000013 nop +80006558: 00000013 nop +8000655c: 00000013 nop +80006560: 00000013 nop +80006564: 00000013 nop +80006568: 00000013 nop +8000656c: 00000013 nop +80006570: 00000013 nop +80006574: 00000013 nop +80006578: 00000013 nop +8000657c: 00000013 nop +80006580: 00000013 nop +80006584: 00000013 nop +80006588: 00000013 nop +8000658c: 00000013 nop +80006590: 00000013 nop +80006594: 00000013 nop +80006598: 00000013 nop +8000659c: 00000013 nop +800065a0: 00000013 nop +800065a4: 00000013 nop +800065a8: 00000013 nop +800065ac: 00000013 nop +800065b0: 00000013 nop +800065b4: 00000013 nop +800065b8: 00000013 nop +800065bc: 00000013 nop +800065c0: 00000013 nop +800065c4: 00000013 nop +800065c8: 00000013 nop +800065cc: 00000013 nop +800065d0: 00000013 nop +800065d4: 00000013 nop +800065d8: 00000013 nop +800065dc: 00000013 nop +800065e0: 00000013 nop +800065e4: 00000013 nop +800065e8: 00000013 nop +800065ec: 00000013 nop +800065f0: 00000013 nop +800065f4: 00000013 nop +800065f8: 00000013 nop +800065fc: 00000013 nop +80006600: 00000013 nop +80006604: 00000013 nop +80006608: 00000013 nop +8000660c: 00000013 nop +80006610: 00000013 nop +80006614: 00000013 nop +80006618: 00000013 nop +8000661c: 00000013 nop +80006620: 00000013 nop +80006624: 00000013 nop +80006628: 00000013 nop +8000662c: 00000013 nop +80006630: 00000013 nop +80006634: 00000013 nop +80006638: 00000013 nop +8000663c: 00000013 nop +80006640: 00000013 nop +80006644: 00000013 nop +80006648: 00000013 nop +8000664c: 00000013 nop +80006650: 00000013 nop +80006654: 00000013 nop +80006658: 00000013 nop +8000665c: 00000013 nop +80006660: 00000013 nop +80006664: 00000013 nop +80006668: 00000013 nop +8000666c: 00000013 nop +80006670: 00000013 nop +80006674: 00000013 nop +80006678: 00000013 nop +8000667c: 00000013 nop +80006680: 00000013 nop +80006684: 00000013 nop +80006688: 00000013 nop +8000668c: 00000013 nop +80006690: 00000013 nop +80006694: 00000013 nop +80006698: 00000013 nop +8000669c: 00000013 nop +800066a0: 00000013 nop +800066a4: 00000013 nop +800066a8: 00000013 nop +800066ac: 00000013 nop +800066b0: 00000013 nop +800066b4: 00000013 nop +800066b8: 00000013 nop +800066bc: 00000013 nop +800066c0: 00000013 nop +800066c4: 00000013 nop +800066c8: 00000013 nop +800066cc: 00000013 nop +800066d0: 00000013 nop +800066d4: 00000013 nop +800066d8: 00000013 nop +800066dc: 00000013 nop +800066e0: 00000013 nop +800066e4: 00000013 nop +800066e8: 00000013 nop +800066ec: 00000013 nop +800066f0: 00000013 nop +800066f4: 00000013 nop +800066f8: 00000013 nop +800066fc: 00000013 nop +80006700: 00000013 nop +80006704: 00000013 nop +80006708: 00000013 nop +8000670c: 00000013 nop +80006710: 00000013 nop +80006714: 00000013 nop +80006718: 00000013 nop +8000671c: 00000013 nop +80006720: 00000013 nop +80006724: 00000013 nop +80006728: 00000013 nop +8000672c: 00000013 nop +80006730: 00000013 nop +80006734: 00000013 nop +80006738: 00000013 nop +8000673c: 00000013 nop +80006740: 00000013 nop +80006744: 00000013 nop +80006748: 00000013 nop +8000674c: 00000013 nop +80006750: 00000013 nop +80006754: 00000013 nop +80006758: 00000013 nop +8000675c: 00000013 nop +80006760: 00000013 nop +80006764: 00000013 nop +80006768: 00000013 nop +8000676c: 00000013 nop +80006770: 00000013 nop +80006774: 00000013 nop +80006778: 00000013 nop +8000677c: 00000013 nop +80006780: 00000013 nop +80006784: 00000013 nop +80006788: 00000013 nop +8000678c: 00000013 nop +80006790: 00000013 nop +80006794: 00000013 nop +80006798: 00000013 nop +8000679c: 00000013 nop +800067a0: 00000013 nop +800067a4: 00000013 nop +800067a8: 00000013 nop +800067ac: 00000013 nop +800067b0: 00000013 nop +800067b4: 00000013 nop +800067b8: 00000013 nop +800067bc: 00000013 nop +800067c0: 00000013 nop +800067c4: 00000013 nop +800067c8: 00000013 nop +800067cc: 00000013 nop +800067d0: 00000013 nop +800067d4: 00000013 nop +800067d8: 00000013 nop +800067dc: 00000013 nop +800067e0: 00000013 nop +800067e4: 00000013 nop +800067e8: 00000013 nop +800067ec: 00000013 nop +800067f0: 00000013 nop +800067f4: 00000013 nop +800067f8: 00000013 nop +800067fc: 00000013 nop +80006800: 00000013 nop +80006804: 00000013 nop +80006808: 00000013 nop +8000680c: 00000013 nop +80006810: 00000013 nop +80006814: 00000013 nop +80006818: 00000013 nop +8000681c: 00000013 nop +80006820: 00000013 nop +80006824: 00000013 nop +80006828: 00000013 nop +8000682c: 00000013 nop +80006830: 00000013 nop +80006834: 00000013 nop +80006838: 00000013 nop +8000683c: 00000013 nop +80006840: 00000013 nop +80006844: 00000013 nop +80006848: 00000013 nop +8000684c: 00000013 nop +80006850: 00000013 nop +80006854: 00000013 nop +80006858: 00000013 nop +8000685c: 00000013 nop +80006860: 00000013 nop +80006864: 00000013 nop +80006868: 00000013 nop +8000686c: 00000013 nop +80006870: 00000013 nop +80006874: 00000013 nop +80006878: 00000013 nop +8000687c: 00000013 nop +80006880: 00000013 nop +80006884: 00000013 nop +80006888: 00000013 nop +8000688c: 00000013 nop +80006890: 00000013 nop +80006894: 00000013 nop +80006898: 00000013 nop +8000689c: 00000013 nop +800068a0: 00000013 nop +800068a4: 00000013 nop +800068a8: 00000013 nop +800068ac: 00000013 nop +800068b0: 00000013 nop +800068b4: 00000013 nop +800068b8: 00000013 nop +800068bc: 00000013 nop +800068c0: 00000013 nop +800068c4: 00000013 nop +800068c8: 00000013 nop +800068cc: 00000013 nop +800068d0: 00000013 nop +800068d4: 00000013 nop +800068d8: 00000013 nop +800068dc: 00000013 nop +800068e0: 00000013 nop +800068e4: 00000013 nop +800068e8: 00000013 nop +800068ec: 00000013 nop +800068f0: 00000013 nop +800068f4: 00000013 nop +800068f8: 00000013 nop +800068fc: 00000013 nop +80006900: 00000013 nop +80006904: 00000013 nop +80006908: 00000013 nop +8000690c: 00000013 nop +80006910: 00000013 nop +80006914: 00000013 nop +80006918: 00000013 nop +8000691c: 00000013 nop +80006920: 00000013 nop +80006924: 00000013 nop +80006928: 00000013 nop +8000692c: 00000013 nop +80006930: 00000013 nop +80006934: 00000013 nop +80006938: 00000013 nop +8000693c: 00000013 nop +80006940: 00000013 nop +80006944: 00000013 nop +80006948: 00000013 nop +8000694c: 00000013 nop +80006950: 00000013 nop +80006954: 00000013 nop +80006958: 00000013 nop +8000695c: 00000013 nop +80006960: 00000013 nop +80006964: 00000013 nop +80006968: 00000013 nop +8000696c: 00000013 nop +80006970: 00000013 nop +80006974: 00000013 nop +80006978: 00000013 nop +8000697c: 00000013 nop +80006980: 00000013 nop +80006984: 00000013 nop +80006988: 00000013 nop +8000698c: 00000013 nop +80006990: 00000013 nop +80006994: 00000013 nop +80006998: 00000013 nop +8000699c: 00000013 nop +800069a0: 00000013 nop +800069a4: 00000013 nop +800069a8: 00000013 nop +800069ac: 00000013 nop +800069b0: 00000013 nop +800069b4: 00000013 nop +800069b8: 00000013 nop +800069bc: 00000013 nop +800069c0: 00000013 nop +800069c4: 00000013 nop +800069c8: 00000013 nop +800069cc: 00000013 nop +800069d0: 00000013 nop +800069d4: 00000013 nop +800069d8: 00000013 nop +800069dc: 00000013 nop +800069e0: 00000013 nop +800069e4: 00000013 nop +800069e8: 00000013 nop +800069ec: 00000013 nop +800069f0: 00000013 nop +800069f4: 00000013 nop +800069f8: 00000013 nop +800069fc: 00000013 nop +80006a00: 00000013 nop +80006a04: 00000013 nop +80006a08: 00000013 nop +80006a0c: 00000013 nop +80006a10: 00000013 nop +80006a14: 00000013 nop +80006a18: 00000013 nop +80006a1c: 00000013 nop +80006a20: 00000013 nop +80006a24: 00000013 nop +80006a28: 00000013 nop +80006a2c: 00000013 nop +80006a30: 00000013 nop +80006a34: 00000013 nop +80006a38: 00000013 nop +80006a3c: 00000013 nop +80006a40: 00000013 nop +80006a44: 00000013 nop +80006a48: 00000013 nop +80006a4c: 00000013 nop +80006a50: 00000013 nop +80006a54: 00000013 nop +80006a58: 00000013 nop +80006a5c: 00000013 nop +80006a60: 00000013 nop +80006a64: 00000013 nop +80006a68: 00000013 nop +80006a6c: 00000013 nop +80006a70: 00000013 nop +80006a74: 00000013 nop +80006a78: 00000013 nop +80006a7c: 00000013 nop +80006a80: 00000013 nop +80006a84: 00000013 nop +80006a88: 00000013 nop +80006a8c: 00000013 nop +80006a90: 00000013 nop +80006a94: 00000013 nop +80006a98: 00000013 nop +80006a9c: 00000013 nop +80006aa0: 00000013 nop +80006aa4: 00000013 nop +80006aa8: 00000013 nop +80006aac: 00000013 nop +80006ab0: 00000013 nop +80006ab4: 00000013 nop +80006ab8: 00000013 nop +80006abc: 00000013 nop +80006ac0: 00000013 nop +80006ac4: 00000013 nop +80006ac8: 00000013 nop +80006acc: 00000013 nop +80006ad0: 00000013 nop +80006ad4: 00000013 nop +80006ad8: 00000013 nop +80006adc: 00000013 nop +80006ae0: 00000013 nop +80006ae4: 00000013 nop +80006ae8: 00000013 nop +80006aec: 00000013 nop +80006af0: 00000013 nop +80006af4: 00000013 nop +80006af8: 00000013 nop +80006afc: 00000013 nop +80006b00: 00000013 nop +80006b04: 00000013 nop +80006b08: 00000013 nop +80006b0c: 00000013 nop +80006b10: 00000013 nop +80006b14: 00000013 nop +80006b18: 00000013 nop +80006b1c: 00000013 nop +80006b20: 00000013 nop +80006b24: 00000013 nop +80006b28: 00000013 nop +80006b2c: 00000013 nop +80006b30: 00000013 nop +80006b34: 00000013 nop +80006b38: 00000013 nop +80006b3c: 00000013 nop +80006b40: 00000013 nop +80006b44: 00000013 nop +80006b48: 00000013 nop +80006b4c: 00000013 nop +80006b50: 00000013 nop +80006b54: 00000013 nop +80006b58: 00000013 nop +80006b5c: 00000013 nop +80006b60: 00000013 nop +80006b64: 00000013 nop +80006b68: 00000013 nop +80006b6c: 00000013 nop +80006b70: 00000013 nop +80006b74: 00000013 nop +80006b78: 00000013 nop +80006b7c: 00000013 nop +80006b80: 00000013 nop +80006b84: 00000013 nop +80006b88: 00000013 nop +80006b8c: 00000013 nop +80006b90: 00000013 nop +80006b94: 00000013 nop +80006b98: 00000013 nop +80006b9c: 00000013 nop +80006ba0: 00000013 nop +80006ba4: 00000013 nop +80006ba8: 00000013 nop +80006bac: 00000013 nop +80006bb0: 00000013 nop +80006bb4: 00000013 nop +80006bb8: 00000013 nop +80006bbc: 00000013 nop +80006bc0: 00000013 nop +80006bc4: 00000013 nop +80006bc8: 00000013 nop +80006bcc: 00000013 nop +80006bd0: 00000013 nop +80006bd4: 00000013 nop +80006bd8: 00000013 nop +80006bdc: 00000013 nop +80006be0: 00000013 nop +80006be4: 00000013 nop +80006be8: 00000013 nop +80006bec: 00000013 nop +80006bf0: 00000013 nop +80006bf4: 00000013 nop +80006bf8: 00000013 nop +80006bfc: 00000013 nop +80006c00: 00000013 nop +80006c04: 00000013 nop +80006c08: 00000013 nop +80006c0c: 00000013 nop +80006c10: 00000013 nop +80006c14: 00000013 nop +80006c18: 00000013 nop +80006c1c: 00000013 nop +80006c20: 00000013 nop +80006c24: 00000013 nop +80006c28: 00000013 nop +80006c2c: 00000013 nop +80006c30: 00000013 nop +80006c34: 00000013 nop +80006c38: 00000013 nop +80006c3c: 00000013 nop +80006c40: 00000013 nop +80006c44: 00000013 nop +80006c48: 00000013 nop +80006c4c: 00000013 nop +80006c50: 00000013 nop +80006c54: 00000013 nop +80006c58: 00000013 nop +80006c5c: 00000013 nop +80006c60: 00000013 nop +80006c64: 00000013 nop +80006c68: 00000013 nop +80006c6c: 00000013 nop +80006c70: 00000013 nop +80006c74: 00000013 nop +80006c78: 00000013 nop +80006c7c: 00000013 nop +80006c80: 00000013 nop +80006c84: 00000013 nop +80006c88: 00000013 nop +80006c8c: 00000013 nop +80006c90: 00000013 nop +80006c94: 00000013 nop +80006c98: 00000013 nop +80006c9c: 00000013 nop +80006ca0: 00000013 nop +80006ca4: 00000013 nop +80006ca8: 00000013 nop +80006cac: 00000013 nop +80006cb0: 00000013 nop +80006cb4: 00000013 nop +80006cb8: 00000013 nop +80006cbc: 00000013 nop +80006cc0: 00000013 nop +80006cc4: 00000013 nop +80006cc8: 00000013 nop +80006ccc: 00000013 nop +80006cd0: 00000013 nop +80006cd4: 00000013 nop +80006cd8: 00000013 nop +80006cdc: 00000013 nop +80006ce0: 00000013 nop +80006ce4: 00000013 nop +80006ce8: 00000013 nop +80006cec: 00000013 nop +80006cf0: 00000013 nop +80006cf4: 00000013 nop +80006cf8: 00000013 nop +80006cfc: 00000013 nop +80006d00: 00000013 nop +80006d04: 00000013 nop +80006d08: 00000013 nop +80006d0c: 00000013 nop +80006d10: 00000013 nop +80006d14: 00000013 nop +80006d18: 00000013 nop +80006d1c: 00000013 nop +80006d20: 00000013 nop +80006d24: 00000013 nop +80006d28: 00000013 nop +80006d2c: 00000013 nop +80006d30: 00000013 nop +80006d34: 00000013 nop +80006d38: 00000013 nop +80006d3c: 00000013 nop +80006d40: 00000013 nop +80006d44: 00000013 nop +80006d48: 00000013 nop +80006d4c: 00000013 nop +80006d50: 00000013 nop +80006d54: 00000013 nop +80006d58: 00000013 nop +80006d5c: 00000013 nop +80006d60: 00000013 nop +80006d64: 00000013 nop +80006d68: 00000013 nop +80006d6c: 00000013 nop +80006d70: 00000013 nop +80006d74: 00000013 nop +80006d78: 00000013 nop +80006d7c: 00000013 nop +80006d80: 00000013 nop +80006d84: 00000013 nop +80006d88: 00000013 nop +80006d8c: 00000013 nop +80006d90: 00000013 nop +80006d94: 00000013 nop +80006d98: 00000013 nop +80006d9c: 00000013 nop +80006da0: 00000013 nop +80006da4: 00000013 nop +80006da8: 00000013 nop +80006dac: 00000013 nop +80006db0: 00000013 nop +80006db4: 00000013 nop +80006db8: 00000013 nop +80006dbc: 00000013 nop +80006dc0: 00000013 nop +80006dc4: 00000013 nop +80006dc8: 00000013 nop +80006dcc: 00000013 nop +80006dd0: 00000013 nop +80006dd4: 00000013 nop +80006dd8: 00000013 nop +80006ddc: 00000013 nop +80006de0: 00000013 nop +80006de4: 00000013 nop +80006de8: 00000013 nop +80006dec: 00000013 nop +80006df0: 00000013 nop +80006df4: 00000013 nop +80006df8: 00000013 nop +80006dfc: 00000013 nop +80006e00: 00000013 nop +80006e04: 00000013 nop +80006e08: 00000013 nop +80006e0c: 00000013 nop +80006e10: 00000013 nop +80006e14: 00000013 nop +80006e18: 00000013 nop +80006e1c: 00000013 nop +80006e20: 00000013 nop +80006e24: 00000013 nop +80006e28: 00000013 nop +80006e2c: 00000013 nop +80006e30: 00000013 nop +80006e34: 00000013 nop +80006e38: 00000013 nop +80006e3c: 00000013 nop +80006e40: 00000013 nop +80006e44: 00000013 nop +80006e48: 00000013 nop +80006e4c: 00000013 nop +80006e50: 00000013 nop +80006e54: 00000013 nop +80006e58: 00000013 nop +80006e5c: 00000013 nop +80006e60: 00000013 nop +80006e64: 00000013 nop +80006e68: 00000013 nop +80006e6c: 00000013 nop +80006e70: 00000013 nop +80006e74: 00000013 nop +80006e78: 00000013 nop +80006e7c: 00000013 nop +80006e80: 00000013 nop +80006e84: 00000013 nop +80006e88: 00000013 nop +80006e8c: 00000013 nop +80006e90: 00000013 nop +80006e94: 00000013 nop +80006e98: 00000013 nop +80006e9c: 00000013 nop +80006ea0: 00000013 nop +80006ea4: 00000013 nop +80006ea8: 00000013 nop +80006eac: 00000013 nop +80006eb0: 00000013 nop +80006eb4: 00000013 nop +80006eb8: 00000013 nop +80006ebc: 00000013 nop +80006ec0: 00000013 nop +80006ec4: 00000013 nop +80006ec8: 00000013 nop +80006ecc: 00000013 nop +80006ed0: 00000013 nop +80006ed4: 00000013 nop +80006ed8: 00000013 nop +80006edc: 00000013 nop +80006ee0: 00000013 nop +80006ee4: 00000013 nop +80006ee8: 00000013 nop +80006eec: 00000013 nop +80006ef0: 00000013 nop +80006ef4: 00000013 nop +80006ef8: 00000013 nop +80006efc: 00000013 nop +80006f00: 00000013 nop +80006f04: 00000013 nop +80006f08: 00000013 nop +80006f0c: 00000013 nop +80006f10: 00000013 nop +80006f14: 00000013 nop +80006f18: 00000013 nop +80006f1c: 00000013 nop +80006f20: 00000013 nop +80006f24: 00000013 nop +80006f28: 00000013 nop +80006f2c: 00000013 nop +80006f30: 00000013 nop +80006f34: 00000013 nop +80006f38: 00000013 nop +80006f3c: 00000013 nop +80006f40: 00000013 nop +80006f44: 00000013 nop +80006f48: 00000013 nop +80006f4c: 00000013 nop +80006f50: 00000013 nop +80006f54: 00000013 nop +80006f58: 00000013 nop +80006f5c: 00000013 nop +80006f60: 00000013 nop +80006f64: 00000013 nop +80006f68: 00000013 nop +80006f6c: 00000013 nop +80006f70: 00000013 nop +80006f74: 00000013 nop +80006f78: 00000013 nop +80006f7c: 00000013 nop +80006f80: 00000013 nop +80006f84: 00000013 nop +80006f88: 00000013 nop +80006f8c: 00000013 nop +80006f90: 00000013 nop +80006f94: 00000013 nop +80006f98: 00000013 nop +80006f9c: 00000013 nop +80006fa0: 00000013 nop +80006fa4: 00000013 nop +80006fa8: 00000013 nop +80006fac: 00000013 nop +80006fb0: 00000013 nop +80006fb4: 00000013 nop +80006fb8: 00000013 nop +80006fbc: 00000013 nop +80006fc0: 00000013 nop +80006fc4: 00000013 nop +80006fc8: 00000013 nop +80006fcc: 00000013 nop +80006fd0: 00000013 nop +80006fd4: 00000013 nop +80006fd8: 00000013 nop +80006fdc: 00000013 nop +80006fe0: 00000013 nop +80006fe4: 00000013 nop +80006fe8: 00000013 nop +80006fec: 00000013 nop +80006ff0: 00000013 nop +80006ff4: 00000013 nop +80006ff8: 00000013 nop +80006ffc: 00000013 nop + +80007000 : +80007000: 23222120 .word 0x23222120 +80007004: 27262524 .word 0x27262524 +80007008: 2b2a2928 .word 0x2b2a2928 +8000700c: 2f2e2d2c .word 0x2f2e2d2c +80007010: 00000013 nop +80007014: 00000013 nop +80007018: 00000013 nop +8000701c: 00000013 nop +80007020: 00000013 nop +80007024: 00000013 nop +80007028: 00000013 nop +8000702c: 00000013 nop +80007030: 00000013 nop +80007034: 00000013 nop +80007038: 00000013 nop +8000703c: 00000013 nop +80007040: 00000013 nop +80007044: 00000013 nop +80007048: 00000013 nop +8000704c: 00000013 nop +80007050: 00000013 nop +80007054: 00000013 nop +80007058: 00000013 nop +8000705c: 00000013 nop +80007060: 00000013 nop +80007064: 00000013 nop +80007068: 00000013 nop +8000706c: 00000013 nop +80007070: 00000013 nop +80007074: 00000013 nop +80007078: 00000013 nop +8000707c: 00000013 nop +80007080: 00000013 nop +80007084: 00000013 nop +80007088: 00000013 nop +8000708c: 00000013 nop +80007090: 00000013 nop +80007094: 00000013 nop +80007098: 00000013 nop +8000709c: 00000013 nop +800070a0: 00000013 nop +800070a4: 00000013 nop +800070a8: 00000013 nop +800070ac: 00000013 nop +800070b0: 00000013 nop +800070b4: 00000013 nop +800070b8: 00000013 nop +800070bc: 00000013 nop +800070c0: 00000013 nop +800070c4: 00000013 nop +800070c8: 00000013 nop +800070cc: 00000013 nop +800070d0: 00000013 nop +800070d4: 00000013 nop +800070d8: 00000013 nop +800070dc: 00000013 nop +800070e0: 00000013 nop +800070e4: 00000013 nop +800070e8: 00000013 nop +800070ec: 00000013 nop +800070f0: 00000013 nop +800070f4: 00000013 nop +800070f8: 00000013 nop +800070fc: 00000013 nop +80007100: 00000013 nop +80007104: 00000013 nop +80007108: 00000013 nop +8000710c: 00000013 nop +80007110: 00000013 nop +80007114: 00000013 nop +80007118: 00000013 nop +8000711c: 00000013 nop +80007120: 00000013 nop +80007124: 00000013 nop +80007128: 00000013 nop +8000712c: 00000013 nop +80007130: 00000013 nop +80007134: 00000013 nop +80007138: 00000013 nop +8000713c: 00000013 nop +80007140: 00000013 nop +80007144: 00000013 nop +80007148: 00000013 nop +8000714c: 00000013 nop +80007150: 00000013 nop +80007154: 00000013 nop +80007158: 00000013 nop +8000715c: 00000013 nop +80007160: 00000013 nop +80007164: 00000013 nop +80007168: 00000013 nop +8000716c: 00000013 nop +80007170: 00000013 nop +80007174: 00000013 nop +80007178: 00000013 nop +8000717c: 00000013 nop +80007180: 00000013 nop +80007184: 00000013 nop +80007188: 00000013 nop +8000718c: 00000013 nop +80007190: 00000013 nop +80007194: 00000013 nop +80007198: 00000013 nop +8000719c: 00000013 nop +800071a0: 00000013 nop +800071a4: 00000013 nop +800071a8: 00000013 nop +800071ac: 00000013 nop +800071b0: 00000013 nop +800071b4: 00000013 nop +800071b8: 00000013 nop +800071bc: 00000013 nop +800071c0: 00000013 nop +800071c4: 00000013 nop +800071c8: 00000013 nop +800071cc: 00000013 nop +800071d0: 00000013 nop +800071d4: 00000013 nop +800071d8: 00000013 nop +800071dc: 00000013 nop +800071e0: 00000013 nop +800071e4: 00000013 nop +800071e8: 00000013 nop +800071ec: 00000013 nop +800071f0: 00000013 nop +800071f4: 00000013 nop +800071f8: 00000013 nop +800071fc: 00000013 nop +80007200: 00000013 nop +80007204: 00000013 nop +80007208: 00000013 nop +8000720c: 00000013 nop +80007210: 00000013 nop +80007214: 00000013 nop +80007218: 00000013 nop +8000721c: 00000013 nop +80007220: 00000013 nop +80007224: 00000013 nop +80007228: 00000013 nop +8000722c: 00000013 nop +80007230: 00000013 nop +80007234: 00000013 nop +80007238: 00000013 nop +8000723c: 00000013 nop +80007240: 00000013 nop +80007244: 00000013 nop +80007248: 00000013 nop +8000724c: 00000013 nop +80007250: 00000013 nop +80007254: 00000013 nop +80007258: 00000013 nop +8000725c: 00000013 nop +80007260: 00000013 nop +80007264: 00000013 nop +80007268: 00000013 nop +8000726c: 00000013 nop +80007270: 00000013 nop +80007274: 00000013 nop +80007278: 00000013 nop +8000727c: 00000013 nop +80007280: 00000013 nop +80007284: 00000013 nop +80007288: 00000013 nop +8000728c: 00000013 nop +80007290: 00000013 nop +80007294: 00000013 nop +80007298: 00000013 nop +8000729c: 00000013 nop +800072a0: 00000013 nop +800072a4: 00000013 nop +800072a8: 00000013 nop +800072ac: 00000013 nop +800072b0: 00000013 nop +800072b4: 00000013 nop +800072b8: 00000013 nop +800072bc: 00000013 nop +800072c0: 00000013 nop +800072c4: 00000013 nop +800072c8: 00000013 nop +800072cc: 00000013 nop +800072d0: 00000013 nop +800072d4: 00000013 nop +800072d8: 00000013 nop +800072dc: 00000013 nop +800072e0: 00000013 nop +800072e4: 00000013 nop +800072e8: 00000013 nop +800072ec: 00000013 nop +800072f0: 00000013 nop +800072f4: 00000013 nop +800072f8: 00000013 nop +800072fc: 00000013 nop +80007300: 00000013 nop +80007304: 00000013 nop +80007308: 00000013 nop +8000730c: 00000013 nop +80007310: 00000013 nop +80007314: 00000013 nop +80007318: 00000013 nop +8000731c: 00000013 nop +80007320: 00000013 nop +80007324: 00000013 nop +80007328: 00000013 nop +8000732c: 00000013 nop +80007330: 00000013 nop +80007334: 00000013 nop +80007338: 00000013 nop +8000733c: 00000013 nop +80007340: 00000013 nop +80007344: 00000013 nop +80007348: 00000013 nop +8000734c: 00000013 nop +80007350: 00000013 nop +80007354: 00000013 nop +80007358: 00000013 nop +8000735c: 00000013 nop +80007360: 00000013 nop +80007364: 00000013 nop +80007368: 00000013 nop +8000736c: 00000013 nop +80007370: 00000013 nop +80007374: 00000013 nop +80007378: 00000013 nop +8000737c: 00000013 nop +80007380: 00000013 nop +80007384: 00000013 nop +80007388: 00000013 nop +8000738c: 00000013 nop +80007390: 00000013 nop +80007394: 00000013 nop +80007398: 00000013 nop +8000739c: 00000013 nop +800073a0: 00000013 nop +800073a4: 00000013 nop +800073a8: 00000013 nop +800073ac: 00000013 nop +800073b0: 00000013 nop +800073b4: 00000013 nop +800073b8: 00000013 nop +800073bc: 00000013 nop +800073c0: 00000013 nop +800073c4: 00000013 nop +800073c8: 00000013 nop +800073cc: 00000013 nop +800073d0: 00000013 nop +800073d4: 00000013 nop +800073d8: 00000013 nop +800073dc: 00000013 nop +800073e0: 00000013 nop +800073e4: 00000013 nop +800073e8: 00000013 nop +800073ec: 00000013 nop +800073f0: 00000013 nop +800073f4: 00000013 nop +800073f8: 00000013 nop +800073fc: 00000013 nop +80007400: 00000013 nop +80007404: 00000013 nop +80007408: 00000013 nop +8000740c: 00000013 nop +80007410: 00000013 nop +80007414: 00000013 nop +80007418: 00000013 nop +8000741c: 00000013 nop +80007420: 00000013 nop +80007424: 00000013 nop +80007428: 00000013 nop +8000742c: 00000013 nop +80007430: 00000013 nop +80007434: 00000013 nop +80007438: 00000013 nop +8000743c: 00000013 nop +80007440: 00000013 nop +80007444: 00000013 nop +80007448: 00000013 nop +8000744c: 00000013 nop +80007450: 00000013 nop +80007454: 00000013 nop +80007458: 00000013 nop +8000745c: 00000013 nop +80007460: 00000013 nop +80007464: 00000013 nop +80007468: 00000013 nop +8000746c: 00000013 nop +80007470: 00000013 nop +80007474: 00000013 nop +80007478: 00000013 nop +8000747c: 00000013 nop +80007480: 00000013 nop +80007484: 00000013 nop +80007488: 00000013 nop +8000748c: 00000013 nop +80007490: 00000013 nop +80007494: 00000013 nop +80007498: 00000013 nop +8000749c: 00000013 nop +800074a0: 00000013 nop +800074a4: 00000013 nop +800074a8: 00000013 nop +800074ac: 00000013 nop +800074b0: 00000013 nop +800074b4: 00000013 nop +800074b8: 00000013 nop +800074bc: 00000013 nop +800074c0: 00000013 nop +800074c4: 00000013 nop +800074c8: 00000013 nop +800074cc: 00000013 nop +800074d0: 00000013 nop +800074d4: 00000013 nop +800074d8: 00000013 nop +800074dc: 00000013 nop +800074e0: 00000013 nop +800074e4: 00000013 nop +800074e8: 00000013 nop +800074ec: 00000013 nop +800074f0: 00000013 nop +800074f4: 00000013 nop +800074f8: 00000013 nop +800074fc: 00000013 nop +80007500: 00000013 nop +80007504: 00000013 nop +80007508: 00000013 nop +8000750c: 00000013 nop +80007510: 00000013 nop +80007514: 00000013 nop +80007518: 00000013 nop +8000751c: 00000013 nop +80007520: 00000013 nop +80007524: 00000013 nop +80007528: 00000013 nop +8000752c: 00000013 nop +80007530: 00000013 nop +80007534: 00000013 nop +80007538: 00000013 nop +8000753c: 00000013 nop +80007540: 00000013 nop +80007544: 00000013 nop +80007548: 00000013 nop +8000754c: 00000013 nop +80007550: 00000013 nop +80007554: 00000013 nop +80007558: 00000013 nop +8000755c: 00000013 nop +80007560: 00000013 nop +80007564: 00000013 nop +80007568: 00000013 nop +8000756c: 00000013 nop +80007570: 00000013 nop +80007574: 00000013 nop +80007578: 00000013 nop +8000757c: 00000013 nop +80007580: 00000013 nop +80007584: 00000013 nop +80007588: 00000013 nop +8000758c: 00000013 nop +80007590: 00000013 nop +80007594: 00000013 nop +80007598: 00000013 nop +8000759c: 00000013 nop +800075a0: 00000013 nop +800075a4: 00000013 nop +800075a8: 00000013 nop +800075ac: 00000013 nop +800075b0: 00000013 nop +800075b4: 00000013 nop +800075b8: 00000013 nop +800075bc: 00000013 nop +800075c0: 00000013 nop +800075c4: 00000013 nop +800075c8: 00000013 nop +800075cc: 00000013 nop +800075d0: 00000013 nop +800075d4: 00000013 nop +800075d8: 00000013 nop +800075dc: 00000013 nop +800075e0: 00000013 nop +800075e4: 00000013 nop +800075e8: 00000013 nop +800075ec: 00000013 nop +800075f0: 00000013 nop +800075f4: 00000013 nop +800075f8: 00000013 nop +800075fc: 00000013 nop +80007600: 00000013 nop +80007604: 00000013 nop +80007608: 00000013 nop +8000760c: 00000013 nop +80007610: 00000013 nop +80007614: 00000013 nop +80007618: 00000013 nop +8000761c: 00000013 nop +80007620: 00000013 nop +80007624: 00000013 nop +80007628: 00000013 nop +8000762c: 00000013 nop +80007630: 00000013 nop +80007634: 00000013 nop +80007638: 00000013 nop +8000763c: 00000013 nop +80007640: 00000013 nop +80007644: 00000013 nop +80007648: 00000013 nop +8000764c: 00000013 nop +80007650: 00000013 nop +80007654: 00000013 nop +80007658: 00000013 nop +8000765c: 00000013 nop +80007660: 00000013 nop +80007664: 00000013 nop +80007668: 00000013 nop +8000766c: 00000013 nop +80007670: 00000013 nop +80007674: 00000013 nop +80007678: 00000013 nop +8000767c: 00000013 nop +80007680: 00000013 nop +80007684: 00000013 nop +80007688: 00000013 nop +8000768c: 00000013 nop +80007690: 00000013 nop +80007694: 00000013 nop +80007698: 00000013 nop +8000769c: 00000013 nop +800076a0: 00000013 nop +800076a4: 00000013 nop +800076a8: 00000013 nop +800076ac: 00000013 nop +800076b0: 00000013 nop +800076b4: 00000013 nop +800076b8: 00000013 nop +800076bc: 00000013 nop +800076c0: 00000013 nop +800076c4: 00000013 nop +800076c8: 00000013 nop +800076cc: 00000013 nop +800076d0: 00000013 nop +800076d4: 00000013 nop +800076d8: 00000013 nop +800076dc: 00000013 nop +800076e0: 00000013 nop +800076e4: 00000013 nop +800076e8: 00000013 nop +800076ec: 00000013 nop +800076f0: 00000013 nop +800076f4: 00000013 nop +800076f8: 00000013 nop +800076fc: 00000013 nop +80007700: 00000013 nop +80007704: 00000013 nop +80007708: 00000013 nop +8000770c: 00000013 nop +80007710: 00000013 nop +80007714: 00000013 nop +80007718: 00000013 nop +8000771c: 00000013 nop +80007720: 00000013 nop +80007724: 00000013 nop +80007728: 00000013 nop +8000772c: 00000013 nop +80007730: 00000013 nop +80007734: 00000013 nop +80007738: 00000013 nop +8000773c: 00000013 nop +80007740: 00000013 nop +80007744: 00000013 nop +80007748: 00000013 nop +8000774c: 00000013 nop +80007750: 00000013 nop +80007754: 00000013 nop +80007758: 00000013 nop +8000775c: 00000013 nop +80007760: 00000013 nop +80007764: 00000013 nop +80007768: 00000013 nop +8000776c: 00000013 nop +80007770: 00000013 nop +80007774: 00000013 nop +80007778: 00000013 nop +8000777c: 00000013 nop +80007780: 00000013 nop +80007784: 00000013 nop +80007788: 00000013 nop +8000778c: 00000013 nop +80007790: 00000013 nop +80007794: 00000013 nop +80007798: 00000013 nop +8000779c: 00000013 nop +800077a0: 00000013 nop +800077a4: 00000013 nop +800077a8: 00000013 nop +800077ac: 00000013 nop +800077b0: 00000013 nop +800077b4: 00000013 nop +800077b8: 00000013 nop +800077bc: 00000013 nop +800077c0: 00000013 nop +800077c4: 00000013 nop +800077c8: 00000013 nop +800077cc: 00000013 nop +800077d0: 00000013 nop +800077d4: 00000013 nop +800077d8: 00000013 nop +800077dc: 00000013 nop +800077e0: 00000013 nop +800077e4: 00000013 nop +800077e8: 00000013 nop +800077ec: 00000013 nop +800077f0: 00000013 nop +800077f4: 00000013 nop +800077f8: 00000013 nop +800077fc: 00000013 nop +80007800: 00000013 nop +80007804: 00000013 nop +80007808: 00000013 nop +8000780c: 00000013 nop +80007810: 00000013 nop +80007814: 00000013 nop +80007818: 00000013 nop +8000781c: 00000013 nop +80007820: 00000013 nop +80007824: 00000013 nop +80007828: 00000013 nop +8000782c: 00000013 nop +80007830: 00000013 nop +80007834: 00000013 nop +80007838: 00000013 nop +8000783c: 00000013 nop +80007840: 00000013 nop +80007844: 00000013 nop +80007848: 00000013 nop +8000784c: 00000013 nop +80007850: 00000013 nop +80007854: 00000013 nop +80007858: 00000013 nop +8000785c: 00000013 nop +80007860: 00000013 nop +80007864: 00000013 nop +80007868: 00000013 nop +8000786c: 00000013 nop +80007870: 00000013 nop +80007874: 00000013 nop +80007878: 00000013 nop +8000787c: 00000013 nop +80007880: 00000013 nop +80007884: 00000013 nop +80007888: 00000013 nop +8000788c: 00000013 nop +80007890: 00000013 nop +80007894: 00000013 nop +80007898: 00000013 nop +8000789c: 00000013 nop +800078a0: 00000013 nop +800078a4: 00000013 nop +800078a8: 00000013 nop +800078ac: 00000013 nop +800078b0: 00000013 nop +800078b4: 00000013 nop +800078b8: 00000013 nop +800078bc: 00000013 nop +800078c0: 00000013 nop +800078c4: 00000013 nop +800078c8: 00000013 nop +800078cc: 00000013 nop +800078d0: 00000013 nop +800078d4: 00000013 nop +800078d8: 00000013 nop +800078dc: 00000013 nop +800078e0: 00000013 nop +800078e4: 00000013 nop +800078e8: 00000013 nop +800078ec: 00000013 nop +800078f0: 00000013 nop +800078f4: 00000013 nop +800078f8: 00000013 nop +800078fc: 00000013 nop +80007900: 00000013 nop +80007904: 00000013 nop +80007908: 00000013 nop +8000790c: 00000013 nop +80007910: 00000013 nop +80007914: 00000013 nop +80007918: 00000013 nop +8000791c: 00000013 nop +80007920: 00000013 nop +80007924: 00000013 nop +80007928: 00000013 nop +8000792c: 00000013 nop +80007930: 00000013 nop +80007934: 00000013 nop +80007938: 00000013 nop +8000793c: 00000013 nop +80007940: 00000013 nop +80007944: 00000013 nop +80007948: 00000013 nop +8000794c: 00000013 nop +80007950: 00000013 nop +80007954: 00000013 nop +80007958: 00000013 nop +8000795c: 00000013 nop +80007960: 00000013 nop +80007964: 00000013 nop +80007968: 00000013 nop +8000796c: 00000013 nop +80007970: 00000013 nop +80007974: 00000013 nop +80007978: 00000013 nop +8000797c: 00000013 nop +80007980: 00000013 nop +80007984: 00000013 nop +80007988: 00000013 nop +8000798c: 00000013 nop +80007990: 00000013 nop +80007994: 00000013 nop +80007998: 00000013 nop +8000799c: 00000013 nop +800079a0: 00000013 nop +800079a4: 00000013 nop +800079a8: 00000013 nop +800079ac: 00000013 nop +800079b0: 00000013 nop +800079b4: 00000013 nop +800079b8: 00000013 nop +800079bc: 00000013 nop +800079c0: 00000013 nop +800079c4: 00000013 nop +800079c8: 00000013 nop +800079cc: 00000013 nop +800079d0: 00000013 nop +800079d4: 00000013 nop +800079d8: 00000013 nop +800079dc: 00000013 nop +800079e0: 00000013 nop +800079e4: 00000013 nop +800079e8: 00000013 nop +800079ec: 00000013 nop +800079f0: 00000013 nop +800079f4: 00000013 nop +800079f8: 00000013 nop +800079fc: 00000013 nop +80007a00: 00000013 nop +80007a04: 00000013 nop +80007a08: 00000013 nop +80007a0c: 00000013 nop +80007a10: 00000013 nop +80007a14: 00000013 nop +80007a18: 00000013 nop +80007a1c: 00000013 nop +80007a20: 00000013 nop +80007a24: 00000013 nop +80007a28: 00000013 nop +80007a2c: 00000013 nop +80007a30: 00000013 nop +80007a34: 00000013 nop +80007a38: 00000013 nop +80007a3c: 00000013 nop +80007a40: 00000013 nop +80007a44: 00000013 nop +80007a48: 00000013 nop +80007a4c: 00000013 nop +80007a50: 00000013 nop +80007a54: 00000013 nop +80007a58: 00000013 nop +80007a5c: 00000013 nop +80007a60: 00000013 nop +80007a64: 00000013 nop +80007a68: 00000013 nop +80007a6c: 00000013 nop +80007a70: 00000013 nop +80007a74: 00000013 nop +80007a78: 00000013 nop +80007a7c: 00000013 nop +80007a80: 00000013 nop +80007a84: 00000013 nop +80007a88: 00000013 nop +80007a8c: 00000013 nop +80007a90: 00000013 nop +80007a94: 00000013 nop +80007a98: 00000013 nop +80007a9c: 00000013 nop +80007aa0: 00000013 nop +80007aa4: 00000013 nop +80007aa8: 00000013 nop +80007aac: 00000013 nop +80007ab0: 00000013 nop +80007ab4: 00000013 nop +80007ab8: 00000013 nop +80007abc: 00000013 nop +80007ac0: 00000013 nop +80007ac4: 00000013 nop +80007ac8: 00000013 nop +80007acc: 00000013 nop +80007ad0: 00000013 nop +80007ad4: 00000013 nop +80007ad8: 00000013 nop +80007adc: 00000013 nop +80007ae0: 00000013 nop +80007ae4: 00000013 nop +80007ae8: 00000013 nop +80007aec: 00000013 nop +80007af0: 00000013 nop +80007af4: 00000013 nop +80007af8: 00000013 nop +80007afc: 00000013 nop +80007b00: 00000013 nop +80007b04: 00000013 nop +80007b08: 00000013 nop +80007b0c: 00000013 nop +80007b10: 00000013 nop +80007b14: 00000013 nop +80007b18: 00000013 nop +80007b1c: 00000013 nop +80007b20: 00000013 nop +80007b24: 00000013 nop +80007b28: 00000013 nop +80007b2c: 00000013 nop +80007b30: 00000013 nop +80007b34: 00000013 nop +80007b38: 00000013 nop +80007b3c: 00000013 nop +80007b40: 00000013 nop +80007b44: 00000013 nop +80007b48: 00000013 nop +80007b4c: 00000013 nop +80007b50: 00000013 nop +80007b54: 00000013 nop +80007b58: 00000013 nop +80007b5c: 00000013 nop +80007b60: 00000013 nop +80007b64: 00000013 nop +80007b68: 00000013 nop +80007b6c: 00000013 nop +80007b70: 00000013 nop +80007b74: 00000013 nop +80007b78: 00000013 nop +80007b7c: 00000013 nop +80007b80: 00000013 nop +80007b84: 00000013 nop +80007b88: 00000013 nop +80007b8c: 00000013 nop +80007b90: 00000013 nop +80007b94: 00000013 nop +80007b98: 00000013 nop +80007b9c: 00000013 nop +80007ba0: 00000013 nop +80007ba4: 00000013 nop +80007ba8: 00000013 nop +80007bac: 00000013 nop +80007bb0: 00000013 nop +80007bb4: 00000013 nop +80007bb8: 00000013 nop +80007bbc: 00000013 nop +80007bc0: 00000013 nop +80007bc4: 00000013 nop +80007bc8: 00000013 nop +80007bcc: 00000013 nop +80007bd0: 00000013 nop +80007bd4: 00000013 nop +80007bd8: 00000013 nop +80007bdc: 00000013 nop +80007be0: 00000013 nop +80007be4: 00000013 nop +80007be8: 00000013 nop +80007bec: 00000013 nop +80007bf0: 00000013 nop +80007bf4: 00000013 nop +80007bf8: 00000013 nop +80007bfc: 00000013 nop +80007c00: 00000013 nop +80007c04: 00000013 nop +80007c08: 00000013 nop +80007c0c: 00000013 nop +80007c10: 00000013 nop +80007c14: 00000013 nop +80007c18: 00000013 nop +80007c1c: 00000013 nop +80007c20: 00000013 nop +80007c24: 00000013 nop +80007c28: 00000013 nop +80007c2c: 00000013 nop +80007c30: 00000013 nop +80007c34: 00000013 nop +80007c38: 00000013 nop +80007c3c: 00000013 nop +80007c40: 00000013 nop +80007c44: 00000013 nop +80007c48: 00000013 nop +80007c4c: 00000013 nop +80007c50: 00000013 nop +80007c54: 00000013 nop +80007c58: 00000013 nop +80007c5c: 00000013 nop +80007c60: 00000013 nop +80007c64: 00000013 nop +80007c68: 00000013 nop +80007c6c: 00000013 nop +80007c70: 00000013 nop +80007c74: 00000013 nop +80007c78: 00000013 nop +80007c7c: 00000013 nop +80007c80: 00000013 nop +80007c84: 00000013 nop +80007c88: 00000013 nop +80007c8c: 00000013 nop +80007c90: 00000013 nop +80007c94: 00000013 nop +80007c98: 00000013 nop +80007c9c: 00000013 nop +80007ca0: 00000013 nop +80007ca4: 00000013 nop +80007ca8: 00000013 nop +80007cac: 00000013 nop +80007cb0: 00000013 nop +80007cb4: 00000013 nop +80007cb8: 00000013 nop +80007cbc: 00000013 nop +80007cc0: 00000013 nop +80007cc4: 00000013 nop +80007cc8: 00000013 nop +80007ccc: 00000013 nop +80007cd0: 00000013 nop +80007cd4: 00000013 nop +80007cd8: 00000013 nop +80007cdc: 00000013 nop +80007ce0: 00000013 nop +80007ce4: 00000013 nop +80007ce8: 00000013 nop +80007cec: 00000013 nop +80007cf0: 00000013 nop +80007cf4: 00000013 nop +80007cf8: 00000013 nop +80007cfc: 00000013 nop +80007d00: 00000013 nop +80007d04: 00000013 nop +80007d08: 00000013 nop +80007d0c: 00000013 nop +80007d10: 00000013 nop +80007d14: 00000013 nop +80007d18: 00000013 nop +80007d1c: 00000013 nop +80007d20: 00000013 nop +80007d24: 00000013 nop +80007d28: 00000013 nop +80007d2c: 00000013 nop +80007d30: 00000013 nop +80007d34: 00000013 nop +80007d38: 00000013 nop +80007d3c: 00000013 nop +80007d40: 00000013 nop +80007d44: 00000013 nop +80007d48: 00000013 nop +80007d4c: 00000013 nop +80007d50: 00000013 nop +80007d54: 00000013 nop +80007d58: 00000013 nop +80007d5c: 00000013 nop +80007d60: 00000013 nop +80007d64: 00000013 nop +80007d68: 00000013 nop +80007d6c: 00000013 nop +80007d70: 00000013 nop +80007d74: 00000013 nop +80007d78: 00000013 nop +80007d7c: 00000013 nop +80007d80: 00000013 nop +80007d84: 00000013 nop +80007d88: 00000013 nop +80007d8c: 00000013 nop +80007d90: 00000013 nop +80007d94: 00000013 nop +80007d98: 00000013 nop +80007d9c: 00000013 nop +80007da0: 00000013 nop +80007da4: 00000013 nop +80007da8: 00000013 nop +80007dac: 00000013 nop +80007db0: 00000013 nop +80007db4: 00000013 nop +80007db8: 00000013 nop +80007dbc: 00000013 nop +80007dc0: 00000013 nop +80007dc4: 00000013 nop +80007dc8: 00000013 nop +80007dcc: 00000013 nop +80007dd0: 00000013 nop +80007dd4: 00000013 nop +80007dd8: 00000013 nop +80007ddc: 00000013 nop +80007de0: 00000013 nop +80007de4: 00000013 nop +80007de8: 00000013 nop +80007dec: 00000013 nop +80007df0: 00000013 nop +80007df4: 00000013 nop +80007df8: 00000013 nop +80007dfc: 00000013 nop +80007e00: 00000013 nop +80007e04: 00000013 nop +80007e08: 00000013 nop +80007e0c: 00000013 nop +80007e10: 00000013 nop +80007e14: 00000013 nop +80007e18: 00000013 nop +80007e1c: 00000013 nop +80007e20: 00000013 nop +80007e24: 00000013 nop +80007e28: 00000013 nop +80007e2c: 00000013 nop +80007e30: 00000013 nop +80007e34: 00000013 nop +80007e38: 00000013 nop +80007e3c: 00000013 nop +80007e40: 00000013 nop +80007e44: 00000013 nop +80007e48: 00000013 nop +80007e4c: 00000013 nop +80007e50: 00000013 nop +80007e54: 00000013 nop +80007e58: 00000013 nop +80007e5c: 00000013 nop +80007e60: 00000013 nop +80007e64: 00000013 nop +80007e68: 00000013 nop +80007e6c: 00000013 nop +80007e70: 00000013 nop +80007e74: 00000013 nop +80007e78: 00000013 nop +80007e7c: 00000013 nop +80007e80: 00000013 nop +80007e84: 00000013 nop +80007e88: 00000013 nop +80007e8c: 00000013 nop +80007e90: 00000013 nop +80007e94: 00000013 nop +80007e98: 00000013 nop +80007e9c: 00000013 nop +80007ea0: 00000013 nop +80007ea4: 00000013 nop +80007ea8: 00000013 nop +80007eac: 00000013 nop +80007eb0: 00000013 nop +80007eb4: 00000013 nop +80007eb8: 00000013 nop +80007ebc: 00000013 nop +80007ec0: 00000013 nop +80007ec4: 00000013 nop +80007ec8: 00000013 nop +80007ecc: 00000013 nop +80007ed0: 00000013 nop +80007ed4: 00000013 nop +80007ed8: 00000013 nop +80007edc: 00000013 nop +80007ee0: 00000013 nop +80007ee4: 00000013 nop +80007ee8: 00000013 nop +80007eec: 00000013 nop +80007ef0: 00000013 nop +80007ef4: 00000013 nop +80007ef8: 00000013 nop +80007efc: 00000013 nop +80007f00: 00000013 nop +80007f04: 00000013 nop +80007f08: 00000013 nop +80007f0c: 00000013 nop +80007f10: 00000013 nop +80007f14: 00000013 nop +80007f18: 00000013 nop +80007f1c: 00000013 nop +80007f20: 00000013 nop +80007f24: 00000013 nop +80007f28: 00000013 nop +80007f2c: 00000013 nop +80007f30: 00000013 nop +80007f34: 00000013 nop +80007f38: 00000013 nop +80007f3c: 00000013 nop +80007f40: 00000013 nop +80007f44: 00000013 nop +80007f48: 00000013 nop +80007f4c: 00000013 nop +80007f50: 00000013 nop +80007f54: 00000013 nop +80007f58: 00000013 nop +80007f5c: 00000013 nop +80007f60: 00000013 nop +80007f64: 00000013 nop +80007f68: 00000013 nop +80007f6c: 00000013 nop +80007f70: 00000013 nop +80007f74: 00000013 nop +80007f78: 00000013 nop +80007f7c: 00000013 nop +80007f80: 00000013 nop +80007f84: 00000013 nop +80007f88: 00000013 nop +80007f8c: 00000013 nop +80007f90: 00000013 nop +80007f94: 00000013 nop +80007f98: 00000013 nop +80007f9c: 00000013 nop +80007fa0: 00000013 nop +80007fa4: 00000013 nop +80007fa8: 00000013 nop +80007fac: 00000013 nop +80007fb0: 00000013 nop +80007fb4: 00000013 nop +80007fb8: 00000013 nop +80007fbc: 00000013 nop +80007fc0: 00000013 nop +80007fc4: 00000013 nop +80007fc8: 00000013 nop +80007fcc: 00000013 nop +80007fd0: 00000013 nop +80007fd4: 00000013 nop +80007fd8: 00000013 nop +80007fdc: 00000013 nop +80007fe0: 00000013 nop +80007fe4: 00000013 nop +80007fe8: 00000013 nop +80007fec: 00000013 nop +80007ff0: 00000013 nop +80007ff4: 00000013 nop +80007ff8: 00000013 nop +80007ffc: 00000013 nop + +80008000 : +80008000: 33323130 .word 0x33323130 +80008004: 37363534 .word 0x37363534 +80008008: 3b3a3938 .word 0x3b3a3938 +8000800c: 3f3e3d3c .word 0x3f3e3d3c +80008010: 00000013 nop +80008014: 00000013 nop +80008018: 00000013 nop +8000801c: 00000013 nop +80008020: 00000013 nop +80008024: 00000013 nop +80008028: 00000013 nop +8000802c: 00000013 nop +80008030: 00000013 nop +80008034: 00000013 nop +80008038: 00000013 nop +8000803c: 00000013 nop +80008040: 00000013 nop +80008044: 00000013 nop +80008048: 00000013 nop +8000804c: 00000013 nop +80008050: 00000013 nop +80008054: 00000013 nop +80008058: 00000013 nop +8000805c: 00000013 nop +80008060: 00000013 nop +80008064: 00000013 nop +80008068: 00000013 nop +8000806c: 00000013 nop +80008070: 00000013 nop +80008074: 00000013 nop +80008078: 00000013 nop +8000807c: 00000013 nop +80008080: 00000013 nop +80008084: 00000013 nop +80008088: 00000013 nop +8000808c: 00000013 nop +80008090: 00000013 nop +80008094: 00000013 nop +80008098: 00000013 nop +8000809c: 00000013 nop +800080a0: 00000013 nop +800080a4: 00000013 nop +800080a8: 00000013 nop +800080ac: 00000013 nop +800080b0: 00000013 nop +800080b4: 00000013 nop +800080b8: 00000013 nop +800080bc: 00000013 nop +800080c0: 00000013 nop +800080c4: 00000013 nop +800080c8: 00000013 nop +800080cc: 00000013 nop +800080d0: 00000013 nop +800080d4: 00000013 nop +800080d8: 00000013 nop +800080dc: 00000013 nop +800080e0: 00000013 nop +800080e4: 00000013 nop +800080e8: 00000013 nop +800080ec: 00000013 nop +800080f0: 00000013 nop +800080f4: 00000013 nop +800080f8: 00000013 nop +800080fc: 00000013 nop +80008100: 00000013 nop +80008104: 00000013 nop +80008108: 00000013 nop +8000810c: 00000013 nop +80008110: 00000013 nop +80008114: 00000013 nop +80008118: 00000013 nop +8000811c: 00000013 nop +80008120: 00000013 nop +80008124: 00000013 nop +80008128: 00000013 nop +8000812c: 00000013 nop +80008130: 00000013 nop +80008134: 00000013 nop +80008138: 00000013 nop +8000813c: 00000013 nop +80008140: 00000013 nop +80008144: 00000013 nop +80008148: 00000013 nop +8000814c: 00000013 nop +80008150: 00000013 nop +80008154: 00000013 nop +80008158: 00000013 nop +8000815c: 00000013 nop +80008160: 00000013 nop +80008164: 00000013 nop +80008168: 00000013 nop +8000816c: 00000013 nop +80008170: 00000013 nop +80008174: 00000013 nop +80008178: 00000013 nop +8000817c: 00000013 nop +80008180: 00000013 nop +80008184: 00000013 nop +80008188: 00000013 nop +8000818c: 00000013 nop +80008190: 00000013 nop +80008194: 00000013 nop +80008198: 00000013 nop +8000819c: 00000013 nop +800081a0: 00000013 nop +800081a4: 00000013 nop +800081a8: 00000013 nop +800081ac: 00000013 nop +800081b0: 00000013 nop +800081b4: 00000013 nop +800081b8: 00000013 nop +800081bc: 00000013 nop +800081c0: 00000013 nop +800081c4: 00000013 nop +800081c8: 00000013 nop +800081cc: 00000013 nop +800081d0: 00000013 nop +800081d4: 00000013 nop +800081d8: 00000013 nop +800081dc: 00000013 nop +800081e0: 00000013 nop +800081e4: 00000013 nop +800081e8: 00000013 nop +800081ec: 00000013 nop +800081f0: 00000013 nop +800081f4: 00000013 nop +800081f8: 00000013 nop +800081fc: 00000013 nop +80008200: 00000013 nop +80008204: 00000013 nop +80008208: 00000013 nop +8000820c: 00000013 nop +80008210: 00000013 nop +80008214: 00000013 nop +80008218: 00000013 nop +8000821c: 00000013 nop +80008220: 00000013 nop +80008224: 00000013 nop +80008228: 00000013 nop +8000822c: 00000013 nop +80008230: 00000013 nop +80008234: 00000013 nop +80008238: 00000013 nop +8000823c: 00000013 nop +80008240: 00000013 nop +80008244: 00000013 nop +80008248: 00000013 nop +8000824c: 00000013 nop +80008250: 00000013 nop +80008254: 00000013 nop +80008258: 00000013 nop +8000825c: 00000013 nop +80008260: 00000013 nop +80008264: 00000013 nop +80008268: 00000013 nop +8000826c: 00000013 nop +80008270: 00000013 nop +80008274: 00000013 nop +80008278: 00000013 nop +8000827c: 00000013 nop +80008280: 00000013 nop +80008284: 00000013 nop +80008288: 00000013 nop +8000828c: 00000013 nop +80008290: 00000013 nop +80008294: 00000013 nop +80008298: 00000013 nop +8000829c: 00000013 nop +800082a0: 00000013 nop +800082a4: 00000013 nop +800082a8: 00000013 nop +800082ac: 00000013 nop +800082b0: 00000013 nop +800082b4: 00000013 nop +800082b8: 00000013 nop +800082bc: 00000013 nop +800082c0: 00000013 nop +800082c4: 00000013 nop +800082c8: 00000013 nop +800082cc: 00000013 nop +800082d0: 00000013 nop +800082d4: 00000013 nop +800082d8: 00000013 nop +800082dc: 00000013 nop +800082e0: 00000013 nop +800082e4: 00000013 nop +800082e8: 00000013 nop +800082ec: 00000013 nop +800082f0: 00000013 nop +800082f4: 00000013 nop +800082f8: 00000013 nop +800082fc: 00000013 nop +80008300: 00000013 nop +80008304: 00000013 nop +80008308: 00000013 nop +8000830c: 00000013 nop +80008310: 00000013 nop +80008314: 00000013 nop +80008318: 00000013 nop +8000831c: 00000013 nop +80008320: 00000013 nop +80008324: 00000013 nop +80008328: 00000013 nop +8000832c: 00000013 nop +80008330: 00000013 nop +80008334: 00000013 nop +80008338: 00000013 nop +8000833c: 00000013 nop +80008340: 00000013 nop +80008344: 00000013 nop +80008348: 00000013 nop +8000834c: 00000013 nop +80008350: 00000013 nop +80008354: 00000013 nop +80008358: 00000013 nop +8000835c: 00000013 nop +80008360: 00000013 nop +80008364: 00000013 nop +80008368: 00000013 nop +8000836c: 00000013 nop +80008370: 00000013 nop +80008374: 00000013 nop +80008378: 00000013 nop +8000837c: 00000013 nop +80008380: 00000013 nop +80008384: 00000013 nop +80008388: 00000013 nop +8000838c: 00000013 nop +80008390: 00000013 nop +80008394: 00000013 nop +80008398: 00000013 nop +8000839c: 00000013 nop +800083a0: 00000013 nop +800083a4: 00000013 nop +800083a8: 00000013 nop +800083ac: 00000013 nop +800083b0: 00000013 nop +800083b4: 00000013 nop +800083b8: 00000013 nop +800083bc: 00000013 nop +800083c0: 00000013 nop +800083c4: 00000013 nop +800083c8: 00000013 nop +800083cc: 00000013 nop +800083d0: 00000013 nop +800083d4: 00000013 nop +800083d8: 00000013 nop +800083dc: 00000013 nop +800083e0: 00000013 nop +800083e4: 00000013 nop +800083e8: 00000013 nop +800083ec: 00000013 nop +800083f0: 00000013 nop +800083f4: 00000013 nop +800083f8: 00000013 nop +800083fc: 00000013 nop +80008400: 00000013 nop +80008404: 00000013 nop +80008408: 00000013 nop +8000840c: 00000013 nop +80008410: 00000013 nop +80008414: 00000013 nop +80008418: 00000013 nop +8000841c: 00000013 nop +80008420: 00000013 nop +80008424: 00000013 nop +80008428: 00000013 nop +8000842c: 00000013 nop +80008430: 00000013 nop +80008434: 00000013 nop +80008438: 00000013 nop +8000843c: 00000013 nop +80008440: 00000013 nop +80008444: 00000013 nop +80008448: 00000013 nop +8000844c: 00000013 nop +80008450: 00000013 nop +80008454: 00000013 nop +80008458: 00000013 nop +8000845c: 00000013 nop +80008460: 00000013 nop +80008464: 00000013 nop +80008468: 00000013 nop +8000846c: 00000013 nop +80008470: 00000013 nop +80008474: 00000013 nop +80008478: 00000013 nop +8000847c: 00000013 nop +80008480: 00000013 nop +80008484: 00000013 nop +80008488: 00000013 nop +8000848c: 00000013 nop +80008490: 00000013 nop +80008494: 00000013 nop +80008498: 00000013 nop +8000849c: 00000013 nop +800084a0: 00000013 nop +800084a4: 00000013 nop +800084a8: 00000013 nop +800084ac: 00000013 nop +800084b0: 00000013 nop +800084b4: 00000013 nop +800084b8: 00000013 nop +800084bc: 00000013 nop +800084c0: 00000013 nop +800084c4: 00000013 nop +800084c8: 00000013 nop +800084cc: 00000013 nop +800084d0: 00000013 nop +800084d4: 00000013 nop +800084d8: 00000013 nop +800084dc: 00000013 nop +800084e0: 00000013 nop +800084e4: 00000013 nop +800084e8: 00000013 nop +800084ec: 00000013 nop +800084f0: 00000013 nop +800084f4: 00000013 nop +800084f8: 00000013 nop +800084fc: 00000013 nop +80008500: 00000013 nop +80008504: 00000013 nop +80008508: 00000013 nop +8000850c: 00000013 nop +80008510: 00000013 nop +80008514: 00000013 nop +80008518: 00000013 nop +8000851c: 00000013 nop +80008520: 00000013 nop +80008524: 00000013 nop +80008528: 00000013 nop +8000852c: 00000013 nop +80008530: 00000013 nop +80008534: 00000013 nop +80008538: 00000013 nop +8000853c: 00000013 nop +80008540: 00000013 nop +80008544: 00000013 nop +80008548: 00000013 nop +8000854c: 00000013 nop +80008550: 00000013 nop +80008554: 00000013 nop +80008558: 00000013 nop +8000855c: 00000013 nop +80008560: 00000013 nop +80008564: 00000013 nop +80008568: 00000013 nop +8000856c: 00000013 nop +80008570: 00000013 nop +80008574: 00000013 nop +80008578: 00000013 nop +8000857c: 00000013 nop +80008580: 00000013 nop +80008584: 00000013 nop +80008588: 00000013 nop +8000858c: 00000013 nop +80008590: 00000013 nop +80008594: 00000013 nop +80008598: 00000013 nop +8000859c: 00000013 nop +800085a0: 00000013 nop +800085a4: 00000013 nop +800085a8: 00000013 nop +800085ac: 00000013 nop +800085b0: 00000013 nop +800085b4: 00000013 nop +800085b8: 00000013 nop +800085bc: 00000013 nop +800085c0: 00000013 nop +800085c4: 00000013 nop +800085c8: 00000013 nop +800085cc: 00000013 nop +800085d0: 00000013 nop +800085d4: 00000013 nop +800085d8: 00000013 nop +800085dc: 00000013 nop +800085e0: 00000013 nop +800085e4: 00000013 nop +800085e8: 00000013 nop +800085ec: 00000013 nop +800085f0: 00000013 nop +800085f4: 00000013 nop +800085f8: 00000013 nop +800085fc: 00000013 nop +80008600: 00000013 nop +80008604: 00000013 nop +80008608: 00000013 nop +8000860c: 00000013 nop +80008610: 00000013 nop +80008614: 00000013 nop +80008618: 00000013 nop +8000861c: 00000013 nop +80008620: 00000013 nop +80008624: 00000013 nop +80008628: 00000013 nop +8000862c: 00000013 nop +80008630: 00000013 nop +80008634: 00000013 nop +80008638: 00000013 nop +8000863c: 00000013 nop +80008640: 00000013 nop +80008644: 00000013 nop +80008648: 00000013 nop +8000864c: 00000013 nop +80008650: 00000013 nop +80008654: 00000013 nop +80008658: 00000013 nop +8000865c: 00000013 nop +80008660: 00000013 nop +80008664: 00000013 nop +80008668: 00000013 nop +8000866c: 00000013 nop +80008670: 00000013 nop +80008674: 00000013 nop +80008678: 00000013 nop +8000867c: 00000013 nop +80008680: 00000013 nop +80008684: 00000013 nop +80008688: 00000013 nop +8000868c: 00000013 nop +80008690: 00000013 nop +80008694: 00000013 nop +80008698: 00000013 nop +8000869c: 00000013 nop +800086a0: 00000013 nop +800086a4: 00000013 nop +800086a8: 00000013 nop +800086ac: 00000013 nop +800086b0: 00000013 nop +800086b4: 00000013 nop +800086b8: 00000013 nop +800086bc: 00000013 nop +800086c0: 00000013 nop +800086c4: 00000013 nop +800086c8: 00000013 nop +800086cc: 00000013 nop +800086d0: 00000013 nop +800086d4: 00000013 nop +800086d8: 00000013 nop +800086dc: 00000013 nop +800086e0: 00000013 nop +800086e4: 00000013 nop +800086e8: 00000013 nop +800086ec: 00000013 nop +800086f0: 00000013 nop +800086f4: 00000013 nop +800086f8: 00000013 nop +800086fc: 00000013 nop +80008700: 00000013 nop +80008704: 00000013 nop +80008708: 00000013 nop +8000870c: 00000013 nop +80008710: 00000013 nop +80008714: 00000013 nop +80008718: 00000013 nop +8000871c: 00000013 nop +80008720: 00000013 nop +80008724: 00000013 nop +80008728: 00000013 nop +8000872c: 00000013 nop +80008730: 00000013 nop +80008734: 00000013 nop +80008738: 00000013 nop +8000873c: 00000013 nop +80008740: 00000013 nop +80008744: 00000013 nop +80008748: 00000013 nop +8000874c: 00000013 nop +80008750: 00000013 nop +80008754: 00000013 nop +80008758: 00000013 nop +8000875c: 00000013 nop +80008760: 00000013 nop +80008764: 00000013 nop +80008768: 00000013 nop +8000876c: 00000013 nop +80008770: 00000013 nop +80008774: 00000013 nop +80008778: 00000013 nop +8000877c: 00000013 nop +80008780: 00000013 nop +80008784: 00000013 nop +80008788: 00000013 nop +8000878c: 00000013 nop +80008790: 00000013 nop +80008794: 00000013 nop +80008798: 00000013 nop +8000879c: 00000013 nop +800087a0: 00000013 nop +800087a4: 00000013 nop +800087a8: 00000013 nop +800087ac: 00000013 nop +800087b0: 00000013 nop +800087b4: 00000013 nop +800087b8: 00000013 nop +800087bc: 00000013 nop +800087c0: 00000013 nop +800087c4: 00000013 nop +800087c8: 00000013 nop +800087cc: 00000013 nop +800087d0: 00000013 nop +800087d4: 00000013 nop +800087d8: 00000013 nop +800087dc: 00000013 nop +800087e0: 00000013 nop +800087e4: 00000013 nop +800087e8: 00000013 nop +800087ec: 00000013 nop +800087f0: 00000013 nop +800087f4: 00000013 nop +800087f8: 00000013 nop +800087fc: 00000013 nop +80008800: 00000013 nop +80008804: 00000013 nop +80008808: 00000013 nop +8000880c: 00000013 nop +80008810: 00000013 nop +80008814: 00000013 nop +80008818: 00000013 nop +8000881c: 00000013 nop +80008820: 00000013 nop +80008824: 00000013 nop +80008828: 00000013 nop +8000882c: 00000013 nop +80008830: 00000013 nop +80008834: 00000013 nop +80008838: 00000013 nop +8000883c: 00000013 nop +80008840: 00000013 nop +80008844: 00000013 nop +80008848: 00000013 nop +8000884c: 00000013 nop +80008850: 00000013 nop +80008854: 00000013 nop +80008858: 00000013 nop +8000885c: 00000013 nop +80008860: 00000013 nop +80008864: 00000013 nop +80008868: 00000013 nop +8000886c: 00000013 nop +80008870: 00000013 nop +80008874: 00000013 nop +80008878: 00000013 nop +8000887c: 00000013 nop +80008880: 00000013 nop +80008884: 00000013 nop +80008888: 00000013 nop +8000888c: 00000013 nop +80008890: 00000013 nop +80008894: 00000013 nop +80008898: 00000013 nop +8000889c: 00000013 nop +800088a0: 00000013 nop +800088a4: 00000013 nop +800088a8: 00000013 nop +800088ac: 00000013 nop +800088b0: 00000013 nop +800088b4: 00000013 nop +800088b8: 00000013 nop +800088bc: 00000013 nop +800088c0: 00000013 nop +800088c4: 00000013 nop +800088c8: 00000013 nop +800088cc: 00000013 nop +800088d0: 00000013 nop +800088d4: 00000013 nop +800088d8: 00000013 nop +800088dc: 00000013 nop +800088e0: 00000013 nop +800088e4: 00000013 nop +800088e8: 00000013 nop +800088ec: 00000013 nop +800088f0: 00000013 nop +800088f4: 00000013 nop +800088f8: 00000013 nop +800088fc: 00000013 nop +80008900: 00000013 nop +80008904: 00000013 nop +80008908: 00000013 nop +8000890c: 00000013 nop +80008910: 00000013 nop +80008914: 00000013 nop +80008918: 00000013 nop +8000891c: 00000013 nop +80008920: 00000013 nop +80008924: 00000013 nop +80008928: 00000013 nop +8000892c: 00000013 nop +80008930: 00000013 nop +80008934: 00000013 nop +80008938: 00000013 nop +8000893c: 00000013 nop +80008940: 00000013 nop +80008944: 00000013 nop +80008948: 00000013 nop +8000894c: 00000013 nop +80008950: 00000013 nop +80008954: 00000013 nop +80008958: 00000013 nop +8000895c: 00000013 nop +80008960: 00000013 nop +80008964: 00000013 nop +80008968: 00000013 nop +8000896c: 00000013 nop +80008970: 00000013 nop +80008974: 00000013 nop +80008978: 00000013 nop +8000897c: 00000013 nop +80008980: 00000013 nop +80008984: 00000013 nop +80008988: 00000013 nop +8000898c: 00000013 nop +80008990: 00000013 nop +80008994: 00000013 nop +80008998: 00000013 nop +8000899c: 00000013 nop +800089a0: 00000013 nop +800089a4: 00000013 nop +800089a8: 00000013 nop +800089ac: 00000013 nop +800089b0: 00000013 nop +800089b4: 00000013 nop +800089b8: 00000013 nop +800089bc: 00000013 nop +800089c0: 00000013 nop +800089c4: 00000013 nop +800089c8: 00000013 nop +800089cc: 00000013 nop +800089d0: 00000013 nop +800089d4: 00000013 nop +800089d8: 00000013 nop +800089dc: 00000013 nop +800089e0: 00000013 nop +800089e4: 00000013 nop +800089e8: 00000013 nop +800089ec: 00000013 nop +800089f0: 00000013 nop +800089f4: 00000013 nop +800089f8: 00000013 nop +800089fc: 00000013 nop +80008a00: 00000013 nop +80008a04: 00000013 nop +80008a08: 00000013 nop +80008a0c: 00000013 nop +80008a10: 00000013 nop +80008a14: 00000013 nop +80008a18: 00000013 nop +80008a1c: 00000013 nop +80008a20: 00000013 nop +80008a24: 00000013 nop +80008a28: 00000013 nop +80008a2c: 00000013 nop +80008a30: 00000013 nop +80008a34: 00000013 nop +80008a38: 00000013 nop +80008a3c: 00000013 nop +80008a40: 00000013 nop +80008a44: 00000013 nop +80008a48: 00000013 nop +80008a4c: 00000013 nop +80008a50: 00000013 nop +80008a54: 00000013 nop +80008a58: 00000013 nop +80008a5c: 00000013 nop +80008a60: 00000013 nop +80008a64: 00000013 nop +80008a68: 00000013 nop +80008a6c: 00000013 nop +80008a70: 00000013 nop +80008a74: 00000013 nop +80008a78: 00000013 nop +80008a7c: 00000013 nop +80008a80: 00000013 nop +80008a84: 00000013 nop +80008a88: 00000013 nop +80008a8c: 00000013 nop +80008a90: 00000013 nop +80008a94: 00000013 nop +80008a98: 00000013 nop +80008a9c: 00000013 nop +80008aa0: 00000013 nop +80008aa4: 00000013 nop +80008aa8: 00000013 nop +80008aac: 00000013 nop +80008ab0: 00000013 nop +80008ab4: 00000013 nop +80008ab8: 00000013 nop +80008abc: 00000013 nop +80008ac0: 00000013 nop +80008ac4: 00000013 nop +80008ac8: 00000013 nop +80008acc: 00000013 nop +80008ad0: 00000013 nop +80008ad4: 00000013 nop +80008ad8: 00000013 nop +80008adc: 00000013 nop +80008ae0: 00000013 nop +80008ae4: 00000013 nop +80008ae8: 00000013 nop +80008aec: 00000013 nop +80008af0: 00000013 nop +80008af4: 00000013 nop +80008af8: 00000013 nop +80008afc: 00000013 nop +80008b00: 00000013 nop +80008b04: 00000013 nop +80008b08: 00000013 nop +80008b0c: 00000013 nop +80008b10: 00000013 nop +80008b14: 00000013 nop +80008b18: 00000013 nop +80008b1c: 00000013 nop +80008b20: 00000013 nop +80008b24: 00000013 nop +80008b28: 00000013 nop +80008b2c: 00000013 nop +80008b30: 00000013 nop +80008b34: 00000013 nop +80008b38: 00000013 nop +80008b3c: 00000013 nop +80008b40: 00000013 nop +80008b44: 00000013 nop +80008b48: 00000013 nop +80008b4c: 00000013 nop +80008b50: 00000013 nop +80008b54: 00000013 nop +80008b58: 00000013 nop +80008b5c: 00000013 nop +80008b60: 00000013 nop +80008b64: 00000013 nop +80008b68: 00000013 nop +80008b6c: 00000013 nop +80008b70: 00000013 nop +80008b74: 00000013 nop +80008b78: 00000013 nop +80008b7c: 00000013 nop +80008b80: 00000013 nop +80008b84: 00000013 nop +80008b88: 00000013 nop +80008b8c: 00000013 nop +80008b90: 00000013 nop +80008b94: 00000013 nop +80008b98: 00000013 nop +80008b9c: 00000013 nop +80008ba0: 00000013 nop +80008ba4: 00000013 nop +80008ba8: 00000013 nop +80008bac: 00000013 nop +80008bb0: 00000013 nop +80008bb4: 00000013 nop +80008bb8: 00000013 nop +80008bbc: 00000013 nop +80008bc0: 00000013 nop +80008bc4: 00000013 nop +80008bc8: 00000013 nop +80008bcc: 00000013 nop +80008bd0: 00000013 nop +80008bd4: 00000013 nop +80008bd8: 00000013 nop +80008bdc: 00000013 nop +80008be0: 00000013 nop +80008be4: 00000013 nop +80008be8: 00000013 nop +80008bec: 00000013 nop +80008bf0: 00000013 nop +80008bf4: 00000013 nop +80008bf8: 00000013 nop +80008bfc: 00000013 nop +80008c00: 00000013 nop +80008c04: 00000013 nop +80008c08: 00000013 nop +80008c0c: 00000013 nop +80008c10: 00000013 nop +80008c14: 00000013 nop +80008c18: 00000013 nop +80008c1c: 00000013 nop +80008c20: 00000013 nop +80008c24: 00000013 nop +80008c28: 00000013 nop +80008c2c: 00000013 nop +80008c30: 00000013 nop +80008c34: 00000013 nop +80008c38: 00000013 nop +80008c3c: 00000013 nop +80008c40: 00000013 nop +80008c44: 00000013 nop +80008c48: 00000013 nop +80008c4c: 00000013 nop +80008c50: 00000013 nop +80008c54: 00000013 nop +80008c58: 00000013 nop +80008c5c: 00000013 nop +80008c60: 00000013 nop +80008c64: 00000013 nop +80008c68: 00000013 nop +80008c6c: 00000013 nop +80008c70: 00000013 nop +80008c74: 00000013 nop +80008c78: 00000013 nop +80008c7c: 00000013 nop +80008c80: 00000013 nop +80008c84: 00000013 nop +80008c88: 00000013 nop +80008c8c: 00000013 nop +80008c90: 00000013 nop +80008c94: 00000013 nop +80008c98: 00000013 nop +80008c9c: 00000013 nop +80008ca0: 00000013 nop +80008ca4: 00000013 nop +80008ca8: 00000013 nop +80008cac: 00000013 nop +80008cb0: 00000013 nop +80008cb4: 00000013 nop +80008cb8: 00000013 nop +80008cbc: 00000013 nop +80008cc0: 00000013 nop +80008cc4: 00000013 nop +80008cc8: 00000013 nop +80008ccc: 00000013 nop +80008cd0: 00000013 nop +80008cd4: 00000013 nop +80008cd8: 00000013 nop +80008cdc: 00000013 nop +80008ce0: 00000013 nop +80008ce4: 00000013 nop +80008ce8: 00000013 nop +80008cec: 00000013 nop +80008cf0: 00000013 nop +80008cf4: 00000013 nop +80008cf8: 00000013 nop +80008cfc: 00000013 nop +80008d00: 00000013 nop +80008d04: 00000013 nop +80008d08: 00000013 nop +80008d0c: 00000013 nop +80008d10: 00000013 nop +80008d14: 00000013 nop +80008d18: 00000013 nop +80008d1c: 00000013 nop +80008d20: 00000013 nop +80008d24: 00000013 nop +80008d28: 00000013 nop +80008d2c: 00000013 nop +80008d30: 00000013 nop +80008d34: 00000013 nop +80008d38: 00000013 nop +80008d3c: 00000013 nop +80008d40: 00000013 nop +80008d44: 00000013 nop +80008d48: 00000013 nop +80008d4c: 00000013 nop +80008d50: 00000013 nop +80008d54: 00000013 nop +80008d58: 00000013 nop +80008d5c: 00000013 nop +80008d60: 00000013 nop +80008d64: 00000013 nop +80008d68: 00000013 nop +80008d6c: 00000013 nop +80008d70: 00000013 nop +80008d74: 00000013 nop +80008d78: 00000013 nop +80008d7c: 00000013 nop +80008d80: 00000013 nop +80008d84: 00000013 nop +80008d88: 00000013 nop +80008d8c: 00000013 nop +80008d90: 00000013 nop +80008d94: 00000013 nop +80008d98: 00000013 nop +80008d9c: 00000013 nop +80008da0: 00000013 nop +80008da4: 00000013 nop +80008da8: 00000013 nop +80008dac: 00000013 nop +80008db0: 00000013 nop +80008db4: 00000013 nop +80008db8: 00000013 nop +80008dbc: 00000013 nop +80008dc0: 00000013 nop +80008dc4: 00000013 nop +80008dc8: 00000013 nop +80008dcc: 00000013 nop +80008dd0: 00000013 nop +80008dd4: 00000013 nop +80008dd8: 00000013 nop +80008ddc: 00000013 nop +80008de0: 00000013 nop +80008de4: 00000013 nop +80008de8: 00000013 nop +80008dec: 00000013 nop +80008df0: 00000013 nop +80008df4: 00000013 nop +80008df8: 00000013 nop +80008dfc: 00000013 nop +80008e00: 00000013 nop +80008e04: 00000013 nop +80008e08: 00000013 nop +80008e0c: 00000013 nop +80008e10: 00000013 nop +80008e14: 00000013 nop +80008e18: 00000013 nop +80008e1c: 00000013 nop +80008e20: 00000013 nop +80008e24: 00000013 nop +80008e28: 00000013 nop +80008e2c: 00000013 nop +80008e30: 00000013 nop +80008e34: 00000013 nop +80008e38: 00000013 nop +80008e3c: 00000013 nop +80008e40: 00000013 nop +80008e44: 00000013 nop +80008e48: 00000013 nop +80008e4c: 00000013 nop +80008e50: 00000013 nop +80008e54: 00000013 nop +80008e58: 00000013 nop +80008e5c: 00000013 nop +80008e60: 00000013 nop +80008e64: 00000013 nop +80008e68: 00000013 nop +80008e6c: 00000013 nop +80008e70: 00000013 nop +80008e74: 00000013 nop +80008e78: 00000013 nop +80008e7c: 00000013 nop +80008e80: 00000013 nop +80008e84: 00000013 nop +80008e88: 00000013 nop +80008e8c: 00000013 nop +80008e90: 00000013 nop +80008e94: 00000013 nop +80008e98: 00000013 nop +80008e9c: 00000013 nop +80008ea0: 00000013 nop +80008ea4: 00000013 nop +80008ea8: 00000013 nop +80008eac: 00000013 nop +80008eb0: 00000013 nop +80008eb4: 00000013 nop +80008eb8: 00000013 nop +80008ebc: 00000013 nop +80008ec0: 00000013 nop +80008ec4: 00000013 nop +80008ec8: 00000013 nop +80008ecc: 00000013 nop +80008ed0: 00000013 nop +80008ed4: 00000013 nop +80008ed8: 00000013 nop +80008edc: 00000013 nop +80008ee0: 00000013 nop +80008ee4: 00000013 nop +80008ee8: 00000013 nop +80008eec: 00000013 nop +80008ef0: 00000013 nop +80008ef4: 00000013 nop +80008ef8: 00000013 nop +80008efc: 00000013 nop +80008f00: 00000013 nop +80008f04: 00000013 nop +80008f08: 00000013 nop +80008f0c: 00000013 nop +80008f10: 00000013 nop +80008f14: 00000013 nop +80008f18: 00000013 nop +80008f1c: 00000013 nop +80008f20: 00000013 nop +80008f24: 00000013 nop +80008f28: 00000013 nop +80008f2c: 00000013 nop +80008f30: 00000013 nop +80008f34: 00000013 nop +80008f38: 00000013 nop +80008f3c: 00000013 nop +80008f40: 00000013 nop +80008f44: 00000013 nop +80008f48: 00000013 nop +80008f4c: 00000013 nop +80008f50: 00000013 nop +80008f54: 00000013 nop +80008f58: 00000013 nop +80008f5c: 00000013 nop +80008f60: 00000013 nop +80008f64: 00000013 nop +80008f68: 00000013 nop +80008f6c: 00000013 nop +80008f70: 00000013 nop +80008f74: 00000013 nop +80008f78: 00000013 nop +80008f7c: 00000013 nop +80008f80: 00000013 nop +80008f84: 00000013 nop +80008f88: 00000013 nop +80008f8c: 00000013 nop +80008f90: 00000013 nop +80008f94: 00000013 nop +80008f98: 00000013 nop +80008f9c: 00000013 nop +80008fa0: 00000013 nop +80008fa4: 00000013 nop +80008fa8: 00000013 nop +80008fac: 00000013 nop +80008fb0: 00000013 nop +80008fb4: 00000013 nop +80008fb8: 00000013 nop +80008fbc: 00000013 nop +80008fc0: 00000013 nop +80008fc4: 00000013 nop +80008fc8: 00000013 nop +80008fcc: 00000013 nop +80008fd0: 00000013 nop +80008fd4: 00000013 nop +80008fd8: 00000013 nop +80008fdc: 00000013 nop +80008fe0: 00000013 nop +80008fe4: 00000013 nop +80008fe8: 00000013 nop +80008fec: 00000013 nop +80008ff0: 00000013 nop +80008ff4: 00000013 nop +80008ff8: 00000013 nop +80008ffc: 00000013 nop + +80009000 : +80009000: 43424140 .word 0x43424140 +80009004: 47464544 .word 0x47464544 +80009008: 4b4a4948 .word 0x4b4a4948 +8000900c: 4f4e4d4c .word 0x4f4e4d4c +80009010: 00000013 nop +80009014: 00000013 nop +80009018: 00000013 nop +8000901c: 00000013 nop +80009020: 00000013 nop +80009024: 00000013 nop +80009028: 00000013 nop +8000902c: 00000013 nop +80009030: 00000013 nop +80009034: 00000013 nop +80009038: 00000013 nop +8000903c: 00000013 nop +80009040: 00000013 nop +80009044: 00000013 nop +80009048: 00000013 nop +8000904c: 00000013 nop +80009050: 00000013 nop +80009054: 00000013 nop +80009058: 00000013 nop +8000905c: 00000013 nop +80009060: 00000013 nop +80009064: 00000013 nop +80009068: 00000013 nop +8000906c: 00000013 nop +80009070: 00000013 nop +80009074: 00000013 nop +80009078: 00000013 nop +8000907c: 00000013 nop +80009080: 00000013 nop +80009084: 00000013 nop +80009088: 00000013 nop +8000908c: 00000013 nop +80009090: 00000013 nop +80009094: 00000013 nop +80009098: 00000013 nop +8000909c: 00000013 nop +800090a0: 00000013 nop +800090a4: 00000013 nop +800090a8: 00000013 nop +800090ac: 00000013 nop +800090b0: 00000013 nop +800090b4: 00000013 nop +800090b8: 00000013 nop +800090bc: 00000013 nop +800090c0: 00000013 nop +800090c4: 00000013 nop +800090c8: 00000013 nop +800090cc: 00000013 nop +800090d0: 00000013 nop +800090d4: 00000013 nop +800090d8: 00000013 nop +800090dc: 00000013 nop +800090e0: 00000013 nop +800090e4: 00000013 nop +800090e8: 00000013 nop +800090ec: 00000013 nop +800090f0: 00000013 nop +800090f4: 00000013 nop +800090f8: 00000013 nop +800090fc: 00000013 nop +80009100: 00000013 nop +80009104: 00000013 nop +80009108: 00000013 nop +8000910c: 00000013 nop +80009110: 00000013 nop +80009114: 00000013 nop +80009118: 00000013 nop +8000911c: 00000013 nop +80009120: 00000013 nop +80009124: 00000013 nop +80009128: 00000013 nop +8000912c: 00000013 nop +80009130: 00000013 nop +80009134: 00000013 nop +80009138: 00000013 nop +8000913c: 00000013 nop +80009140: 00000013 nop +80009144: 00000013 nop +80009148: 00000013 nop +8000914c: 00000013 nop +80009150: 00000013 nop +80009154: 00000013 nop +80009158: 00000013 nop +8000915c: 00000013 nop +80009160: 00000013 nop +80009164: 00000013 nop +80009168: 00000013 nop +8000916c: 00000013 nop +80009170: 00000013 nop +80009174: 00000013 nop +80009178: 00000013 nop +8000917c: 00000013 nop +80009180: 00000013 nop +80009184: 00000013 nop +80009188: 00000013 nop +8000918c: 00000013 nop +80009190: 00000013 nop +80009194: 00000013 nop +80009198: 00000013 nop +8000919c: 00000013 nop +800091a0: 00000013 nop +800091a4: 00000013 nop +800091a8: 00000013 nop +800091ac: 00000013 nop +800091b0: 00000013 nop +800091b4: 00000013 nop +800091b8: 00000013 nop +800091bc: 00000013 nop +800091c0: 00000013 nop +800091c4: 00000013 nop +800091c8: 00000013 nop +800091cc: 00000013 nop +800091d0: 00000013 nop +800091d4: 00000013 nop +800091d8: 00000013 nop +800091dc: 00000013 nop +800091e0: 00000013 nop +800091e4: 00000013 nop +800091e8: 00000013 nop +800091ec: 00000013 nop +800091f0: 00000013 nop +800091f4: 00000013 nop +800091f8: 00000013 nop +800091fc: 00000013 nop +80009200: 00000013 nop +80009204: 00000013 nop +80009208: 00000013 nop +8000920c: 00000013 nop +80009210: 00000013 nop +80009214: 00000013 nop +80009218: 00000013 nop +8000921c: 00000013 nop +80009220: 00000013 nop +80009224: 00000013 nop +80009228: 00000013 nop +8000922c: 00000013 nop +80009230: 00000013 nop +80009234: 00000013 nop +80009238: 00000013 nop +8000923c: 00000013 nop +80009240: 00000013 nop +80009244: 00000013 nop +80009248: 00000013 nop +8000924c: 00000013 nop +80009250: 00000013 nop +80009254: 00000013 nop +80009258: 00000013 nop +8000925c: 00000013 nop +80009260: 00000013 nop +80009264: 00000013 nop +80009268: 00000013 nop +8000926c: 00000013 nop +80009270: 00000013 nop +80009274: 00000013 nop +80009278: 00000013 nop +8000927c: 00000013 nop +80009280: 00000013 nop +80009284: 00000013 nop +80009288: 00000013 nop +8000928c: 00000013 nop +80009290: 00000013 nop +80009294: 00000013 nop +80009298: 00000013 nop +8000929c: 00000013 nop +800092a0: 00000013 nop +800092a4: 00000013 nop +800092a8: 00000013 nop +800092ac: 00000013 nop +800092b0: 00000013 nop +800092b4: 00000013 nop +800092b8: 00000013 nop +800092bc: 00000013 nop +800092c0: 00000013 nop +800092c4: 00000013 nop +800092c8: 00000013 nop +800092cc: 00000013 nop +800092d0: 00000013 nop +800092d4: 00000013 nop +800092d8: 00000013 nop +800092dc: 00000013 nop +800092e0: 00000013 nop +800092e4: 00000013 nop +800092e8: 00000013 nop +800092ec: 00000013 nop +800092f0: 00000013 nop +800092f4: 00000013 nop +800092f8: 00000013 nop +800092fc: 00000013 nop +80009300: 00000013 nop +80009304: 00000013 nop +80009308: 00000013 nop +8000930c: 00000013 nop +80009310: 00000013 nop +80009314: 00000013 nop +80009318: 00000013 nop +8000931c: 00000013 nop +80009320: 00000013 nop +80009324: 00000013 nop +80009328: 00000013 nop +8000932c: 00000013 nop +80009330: 00000013 nop +80009334: 00000013 nop +80009338: 00000013 nop +8000933c: 00000013 nop +80009340: 00000013 nop +80009344: 00000013 nop +80009348: 00000013 nop +8000934c: 00000013 nop +80009350: 00000013 nop +80009354: 00000013 nop +80009358: 00000013 nop +8000935c: 00000013 nop +80009360: 00000013 nop +80009364: 00000013 nop +80009368: 00000013 nop +8000936c: 00000013 nop +80009370: 00000013 nop +80009374: 00000013 nop +80009378: 00000013 nop +8000937c: 00000013 nop +80009380: 00000013 nop +80009384: 00000013 nop +80009388: 00000013 nop +8000938c: 00000013 nop +80009390: 00000013 nop +80009394: 00000013 nop +80009398: 00000013 nop +8000939c: 00000013 nop +800093a0: 00000013 nop +800093a4: 00000013 nop +800093a8: 00000013 nop +800093ac: 00000013 nop +800093b0: 00000013 nop +800093b4: 00000013 nop +800093b8: 00000013 nop +800093bc: 00000013 nop +800093c0: 00000013 nop +800093c4: 00000013 nop +800093c8: 00000013 nop +800093cc: 00000013 nop +800093d0: 00000013 nop +800093d4: 00000013 nop +800093d8: 00000013 nop +800093dc: 00000013 nop +800093e0: 00000013 nop +800093e4: 00000013 nop +800093e8: 00000013 nop +800093ec: 00000013 nop +800093f0: 00000013 nop +800093f4: 00000013 nop +800093f8: 00000013 nop +800093fc: 00000013 nop +80009400: 00000013 nop +80009404: 00000013 nop +80009408: 00000013 nop +8000940c: 00000013 nop +80009410: 00000013 nop +80009414: 00000013 nop +80009418: 00000013 nop +8000941c: 00000013 nop +80009420: 00000013 nop +80009424: 00000013 nop +80009428: 00000013 nop +8000942c: 00000013 nop +80009430: 00000013 nop +80009434: 00000013 nop +80009438: 00000013 nop +8000943c: 00000013 nop +80009440: 00000013 nop +80009444: 00000013 nop +80009448: 00000013 nop +8000944c: 00000013 nop +80009450: 00000013 nop +80009454: 00000013 nop +80009458: 00000013 nop +8000945c: 00000013 nop +80009460: 00000013 nop +80009464: 00000013 nop +80009468: 00000013 nop +8000946c: 00000013 nop +80009470: 00000013 nop +80009474: 00000013 nop +80009478: 00000013 nop +8000947c: 00000013 nop +80009480: 00000013 nop +80009484: 00000013 nop +80009488: 00000013 nop +8000948c: 00000013 nop +80009490: 00000013 nop +80009494: 00000013 nop +80009498: 00000013 nop +8000949c: 00000013 nop +800094a0: 00000013 nop +800094a4: 00000013 nop +800094a8: 00000013 nop +800094ac: 00000013 nop +800094b0: 00000013 nop +800094b4: 00000013 nop +800094b8: 00000013 nop +800094bc: 00000013 nop +800094c0: 00000013 nop +800094c4: 00000013 nop +800094c8: 00000013 nop +800094cc: 00000013 nop +800094d0: 00000013 nop +800094d4: 00000013 nop +800094d8: 00000013 nop +800094dc: 00000013 nop +800094e0: 00000013 nop +800094e4: 00000013 nop +800094e8: 00000013 nop +800094ec: 00000013 nop +800094f0: 00000013 nop +800094f4: 00000013 nop +800094f8: 00000013 nop +800094fc: 00000013 nop +80009500: 00000013 nop +80009504: 00000013 nop +80009508: 00000013 nop +8000950c: 00000013 nop +80009510: 00000013 nop +80009514: 00000013 nop +80009518: 00000013 nop +8000951c: 00000013 nop +80009520: 00000013 nop +80009524: 00000013 nop +80009528: 00000013 nop +8000952c: 00000013 nop +80009530: 00000013 nop +80009534: 00000013 nop +80009538: 00000013 nop +8000953c: 00000013 nop +80009540: 00000013 nop +80009544: 00000013 nop +80009548: 00000013 nop +8000954c: 00000013 nop +80009550: 00000013 nop +80009554: 00000013 nop +80009558: 00000013 nop +8000955c: 00000013 nop +80009560: 00000013 nop +80009564: 00000013 nop +80009568: 00000013 nop +8000956c: 00000013 nop +80009570: 00000013 nop +80009574: 00000013 nop +80009578: 00000013 nop +8000957c: 00000013 nop +80009580: 00000013 nop +80009584: 00000013 nop +80009588: 00000013 nop +8000958c: 00000013 nop +80009590: 00000013 nop +80009594: 00000013 nop +80009598: 00000013 nop +8000959c: 00000013 nop +800095a0: 00000013 nop +800095a4: 00000013 nop +800095a8: 00000013 nop +800095ac: 00000013 nop +800095b0: 00000013 nop +800095b4: 00000013 nop +800095b8: 00000013 nop +800095bc: 00000013 nop +800095c0: 00000013 nop +800095c4: 00000013 nop +800095c8: 00000013 nop +800095cc: 00000013 nop +800095d0: 00000013 nop +800095d4: 00000013 nop +800095d8: 00000013 nop +800095dc: 00000013 nop +800095e0: 00000013 nop +800095e4: 00000013 nop +800095e8: 00000013 nop +800095ec: 00000013 nop +800095f0: 00000013 nop +800095f4: 00000013 nop +800095f8: 00000013 nop +800095fc: 00000013 nop +80009600: 00000013 nop +80009604: 00000013 nop +80009608: 00000013 nop +8000960c: 00000013 nop +80009610: 00000013 nop +80009614: 00000013 nop +80009618: 00000013 nop +8000961c: 00000013 nop +80009620: 00000013 nop +80009624: 00000013 nop +80009628: 00000013 nop +8000962c: 00000013 nop +80009630: 00000013 nop +80009634: 00000013 nop +80009638: 00000013 nop +8000963c: 00000013 nop +80009640: 00000013 nop +80009644: 00000013 nop +80009648: 00000013 nop +8000964c: 00000013 nop +80009650: 00000013 nop +80009654: 00000013 nop +80009658: 00000013 nop +8000965c: 00000013 nop +80009660: 00000013 nop +80009664: 00000013 nop +80009668: 00000013 nop +8000966c: 00000013 nop +80009670: 00000013 nop +80009674: 00000013 nop +80009678: 00000013 nop +8000967c: 00000013 nop +80009680: 00000013 nop +80009684: 00000013 nop +80009688: 00000013 nop +8000968c: 00000013 nop +80009690: 00000013 nop +80009694: 00000013 nop +80009698: 00000013 nop +8000969c: 00000013 nop +800096a0: 00000013 nop +800096a4: 00000013 nop +800096a8: 00000013 nop +800096ac: 00000013 nop +800096b0: 00000013 nop +800096b4: 00000013 nop +800096b8: 00000013 nop +800096bc: 00000013 nop +800096c0: 00000013 nop +800096c4: 00000013 nop +800096c8: 00000013 nop +800096cc: 00000013 nop +800096d0: 00000013 nop +800096d4: 00000013 nop +800096d8: 00000013 nop +800096dc: 00000013 nop +800096e0: 00000013 nop +800096e4: 00000013 nop +800096e8: 00000013 nop +800096ec: 00000013 nop +800096f0: 00000013 nop +800096f4: 00000013 nop +800096f8: 00000013 nop +800096fc: 00000013 nop +80009700: 00000013 nop +80009704: 00000013 nop +80009708: 00000013 nop +8000970c: 00000013 nop +80009710: 00000013 nop +80009714: 00000013 nop +80009718: 00000013 nop +8000971c: 00000013 nop +80009720: 00000013 nop +80009724: 00000013 nop +80009728: 00000013 nop +8000972c: 00000013 nop +80009730: 00000013 nop +80009734: 00000013 nop +80009738: 00000013 nop +8000973c: 00000013 nop +80009740: 00000013 nop +80009744: 00000013 nop +80009748: 00000013 nop +8000974c: 00000013 nop +80009750: 00000013 nop +80009754: 00000013 nop +80009758: 00000013 nop +8000975c: 00000013 nop +80009760: 00000013 nop +80009764: 00000013 nop +80009768: 00000013 nop +8000976c: 00000013 nop +80009770: 00000013 nop +80009774: 00000013 nop +80009778: 00000013 nop +8000977c: 00000013 nop +80009780: 00000013 nop +80009784: 00000013 nop +80009788: 00000013 nop +8000978c: 00000013 nop +80009790: 00000013 nop +80009794: 00000013 nop +80009798: 00000013 nop +8000979c: 00000013 nop +800097a0: 00000013 nop +800097a4: 00000013 nop +800097a8: 00000013 nop +800097ac: 00000013 nop +800097b0: 00000013 nop +800097b4: 00000013 nop +800097b8: 00000013 nop +800097bc: 00000013 nop +800097c0: 00000013 nop +800097c4: 00000013 nop +800097c8: 00000013 nop +800097cc: 00000013 nop +800097d0: 00000013 nop +800097d4: 00000013 nop +800097d8: 00000013 nop +800097dc: 00000013 nop +800097e0: 00000013 nop +800097e4: 00000013 nop +800097e8: 00000013 nop +800097ec: 00000013 nop +800097f0: 00000013 nop +800097f4: 00000013 nop +800097f8: 00000013 nop +800097fc: 00000013 nop +80009800: 00000013 nop +80009804: 00000013 nop +80009808: 00000013 nop +8000980c: 00000013 nop +80009810: 00000013 nop +80009814: 00000013 nop +80009818: 00000013 nop +8000981c: 00000013 nop +80009820: 00000013 nop +80009824: 00000013 nop +80009828: 00000013 nop +8000982c: 00000013 nop +80009830: 00000013 nop +80009834: 00000013 nop +80009838: 00000013 nop +8000983c: 00000013 nop +80009840: 00000013 nop +80009844: 00000013 nop +80009848: 00000013 nop +8000984c: 00000013 nop +80009850: 00000013 nop +80009854: 00000013 nop +80009858: 00000013 nop +8000985c: 00000013 nop +80009860: 00000013 nop +80009864: 00000013 nop +80009868: 00000013 nop +8000986c: 00000013 nop +80009870: 00000013 nop +80009874: 00000013 nop +80009878: 00000013 nop +8000987c: 00000013 nop +80009880: 00000013 nop +80009884: 00000013 nop +80009888: 00000013 nop +8000988c: 00000013 nop +80009890: 00000013 nop +80009894: 00000013 nop +80009898: 00000013 nop +8000989c: 00000013 nop +800098a0: 00000013 nop +800098a4: 00000013 nop +800098a8: 00000013 nop +800098ac: 00000013 nop +800098b0: 00000013 nop +800098b4: 00000013 nop +800098b8: 00000013 nop +800098bc: 00000013 nop +800098c0: 00000013 nop +800098c4: 00000013 nop +800098c8: 00000013 nop +800098cc: 00000013 nop +800098d0: 00000013 nop +800098d4: 00000013 nop +800098d8: 00000013 nop +800098dc: 00000013 nop +800098e0: 00000013 nop +800098e4: 00000013 nop +800098e8: 00000013 nop +800098ec: 00000013 nop +800098f0: 00000013 nop +800098f4: 00000013 nop +800098f8: 00000013 nop +800098fc: 00000013 nop +80009900: 00000013 nop +80009904: 00000013 nop +80009908: 00000013 nop +8000990c: 00000013 nop +80009910: 00000013 nop +80009914: 00000013 nop +80009918: 00000013 nop +8000991c: 00000013 nop +80009920: 00000013 nop +80009924: 00000013 nop +80009928: 00000013 nop +8000992c: 00000013 nop +80009930: 00000013 nop +80009934: 00000013 nop +80009938: 00000013 nop +8000993c: 00000013 nop +80009940: 00000013 nop +80009944: 00000013 nop +80009948: 00000013 nop +8000994c: 00000013 nop +80009950: 00000013 nop +80009954: 00000013 nop +80009958: 00000013 nop +8000995c: 00000013 nop +80009960: 00000013 nop +80009964: 00000013 nop +80009968: 00000013 nop +8000996c: 00000013 nop +80009970: 00000013 nop +80009974: 00000013 nop +80009978: 00000013 nop +8000997c: 00000013 nop +80009980: 00000013 nop +80009984: 00000013 nop +80009988: 00000013 nop +8000998c: 00000013 nop +80009990: 00000013 nop +80009994: 00000013 nop +80009998: 00000013 nop +8000999c: 00000013 nop +800099a0: 00000013 nop +800099a4: 00000013 nop +800099a8: 00000013 nop +800099ac: 00000013 nop +800099b0: 00000013 nop +800099b4: 00000013 nop +800099b8: 00000013 nop +800099bc: 00000013 nop +800099c0: 00000013 nop +800099c4: 00000013 nop +800099c8: 00000013 nop +800099cc: 00000013 nop +800099d0: 00000013 nop +800099d4: 00000013 nop +800099d8: 00000013 nop +800099dc: 00000013 nop +800099e0: 00000013 nop +800099e4: 00000013 nop +800099e8: 00000013 nop +800099ec: 00000013 nop +800099f0: 00000013 nop +800099f4: 00000013 nop +800099f8: 00000013 nop +800099fc: 00000013 nop +80009a00: 00000013 nop +80009a04: 00000013 nop +80009a08: 00000013 nop +80009a0c: 00000013 nop +80009a10: 00000013 nop +80009a14: 00000013 nop +80009a18: 00000013 nop +80009a1c: 00000013 nop +80009a20: 00000013 nop +80009a24: 00000013 nop +80009a28: 00000013 nop +80009a2c: 00000013 nop +80009a30: 00000013 nop +80009a34: 00000013 nop +80009a38: 00000013 nop +80009a3c: 00000013 nop +80009a40: 00000013 nop +80009a44: 00000013 nop +80009a48: 00000013 nop +80009a4c: 00000013 nop +80009a50: 00000013 nop +80009a54: 00000013 nop +80009a58: 00000013 nop +80009a5c: 00000013 nop +80009a60: 00000013 nop +80009a64: 00000013 nop +80009a68: 00000013 nop +80009a6c: 00000013 nop +80009a70: 00000013 nop +80009a74: 00000013 nop +80009a78: 00000013 nop +80009a7c: 00000013 nop +80009a80: 00000013 nop +80009a84: 00000013 nop +80009a88: 00000013 nop +80009a8c: 00000013 nop +80009a90: 00000013 nop +80009a94: 00000013 nop +80009a98: 00000013 nop +80009a9c: 00000013 nop +80009aa0: 00000013 nop +80009aa4: 00000013 nop +80009aa8: 00000013 nop +80009aac: 00000013 nop +80009ab0: 00000013 nop +80009ab4: 00000013 nop +80009ab8: 00000013 nop +80009abc: 00000013 nop +80009ac0: 00000013 nop +80009ac4: 00000013 nop +80009ac8: 00000013 nop +80009acc: 00000013 nop +80009ad0: 00000013 nop +80009ad4: 00000013 nop +80009ad8: 00000013 nop +80009adc: 00000013 nop +80009ae0: 00000013 nop +80009ae4: 00000013 nop +80009ae8: 00000013 nop +80009aec: 00000013 nop +80009af0: 00000013 nop +80009af4: 00000013 nop +80009af8: 00000013 nop +80009afc: 00000013 nop +80009b00: 00000013 nop +80009b04: 00000013 nop +80009b08: 00000013 nop +80009b0c: 00000013 nop +80009b10: 00000013 nop +80009b14: 00000013 nop +80009b18: 00000013 nop +80009b1c: 00000013 nop +80009b20: 00000013 nop +80009b24: 00000013 nop +80009b28: 00000013 nop +80009b2c: 00000013 nop +80009b30: 00000013 nop +80009b34: 00000013 nop +80009b38: 00000013 nop +80009b3c: 00000013 nop +80009b40: 00000013 nop +80009b44: 00000013 nop +80009b48: 00000013 nop +80009b4c: 00000013 nop +80009b50: 00000013 nop +80009b54: 00000013 nop +80009b58: 00000013 nop +80009b5c: 00000013 nop +80009b60: 00000013 nop +80009b64: 00000013 nop +80009b68: 00000013 nop +80009b6c: 00000013 nop +80009b70: 00000013 nop +80009b74: 00000013 nop +80009b78: 00000013 nop +80009b7c: 00000013 nop +80009b80: 00000013 nop +80009b84: 00000013 nop +80009b88: 00000013 nop +80009b8c: 00000013 nop +80009b90: 00000013 nop +80009b94: 00000013 nop +80009b98: 00000013 nop +80009b9c: 00000013 nop +80009ba0: 00000013 nop +80009ba4: 00000013 nop +80009ba8: 00000013 nop +80009bac: 00000013 nop +80009bb0: 00000013 nop +80009bb4: 00000013 nop +80009bb8: 00000013 nop +80009bbc: 00000013 nop +80009bc0: 00000013 nop +80009bc4: 00000013 nop +80009bc8: 00000013 nop +80009bcc: 00000013 nop +80009bd0: 00000013 nop +80009bd4: 00000013 nop +80009bd8: 00000013 nop +80009bdc: 00000013 nop +80009be0: 00000013 nop +80009be4: 00000013 nop +80009be8: 00000013 nop +80009bec: 00000013 nop +80009bf0: 00000013 nop +80009bf4: 00000013 nop +80009bf8: 00000013 nop +80009bfc: 00000013 nop +80009c00: 00000013 nop +80009c04: 00000013 nop +80009c08: 00000013 nop +80009c0c: 00000013 nop +80009c10: 00000013 nop +80009c14: 00000013 nop +80009c18: 00000013 nop +80009c1c: 00000013 nop +80009c20: 00000013 nop +80009c24: 00000013 nop +80009c28: 00000013 nop +80009c2c: 00000013 nop +80009c30: 00000013 nop +80009c34: 00000013 nop +80009c38: 00000013 nop +80009c3c: 00000013 nop +80009c40: 00000013 nop +80009c44: 00000013 nop +80009c48: 00000013 nop +80009c4c: 00000013 nop +80009c50: 00000013 nop +80009c54: 00000013 nop +80009c58: 00000013 nop +80009c5c: 00000013 nop +80009c60: 00000013 nop +80009c64: 00000013 nop +80009c68: 00000013 nop +80009c6c: 00000013 nop +80009c70: 00000013 nop +80009c74: 00000013 nop +80009c78: 00000013 nop +80009c7c: 00000013 nop +80009c80: 00000013 nop +80009c84: 00000013 nop +80009c88: 00000013 nop +80009c8c: 00000013 nop +80009c90: 00000013 nop +80009c94: 00000013 nop +80009c98: 00000013 nop +80009c9c: 00000013 nop +80009ca0: 00000013 nop +80009ca4: 00000013 nop +80009ca8: 00000013 nop +80009cac: 00000013 nop +80009cb0: 00000013 nop +80009cb4: 00000013 nop +80009cb8: 00000013 nop +80009cbc: 00000013 nop +80009cc0: 00000013 nop +80009cc4: 00000013 nop +80009cc8: 00000013 nop +80009ccc: 00000013 nop +80009cd0: 00000013 nop +80009cd4: 00000013 nop +80009cd8: 00000013 nop +80009cdc: 00000013 nop +80009ce0: 00000013 nop +80009ce4: 00000013 nop +80009ce8: 00000013 nop +80009cec: 00000013 nop +80009cf0: 00000013 nop +80009cf4: 00000013 nop +80009cf8: 00000013 nop +80009cfc: 00000013 nop +80009d00: 00000013 nop +80009d04: 00000013 nop +80009d08: 00000013 nop +80009d0c: 00000013 nop +80009d10: 00000013 nop +80009d14: 00000013 nop +80009d18: 00000013 nop +80009d1c: 00000013 nop +80009d20: 00000013 nop +80009d24: 00000013 nop +80009d28: 00000013 nop +80009d2c: 00000013 nop +80009d30: 00000013 nop +80009d34: 00000013 nop +80009d38: 00000013 nop +80009d3c: 00000013 nop +80009d40: 00000013 nop +80009d44: 00000013 nop +80009d48: 00000013 nop +80009d4c: 00000013 nop +80009d50: 00000013 nop +80009d54: 00000013 nop +80009d58: 00000013 nop +80009d5c: 00000013 nop +80009d60: 00000013 nop +80009d64: 00000013 nop +80009d68: 00000013 nop +80009d6c: 00000013 nop +80009d70: 00000013 nop +80009d74: 00000013 nop +80009d78: 00000013 nop +80009d7c: 00000013 nop +80009d80: 00000013 nop +80009d84: 00000013 nop +80009d88: 00000013 nop +80009d8c: 00000013 nop +80009d90: 00000013 nop +80009d94: 00000013 nop +80009d98: 00000013 nop +80009d9c: 00000013 nop +80009da0: 00000013 nop +80009da4: 00000013 nop +80009da8: 00000013 nop +80009dac: 00000013 nop +80009db0: 00000013 nop +80009db4: 00000013 nop +80009db8: 00000013 nop +80009dbc: 00000013 nop +80009dc0: 00000013 nop +80009dc4: 00000013 nop +80009dc8: 00000013 nop +80009dcc: 00000013 nop +80009dd0: 00000013 nop +80009dd4: 00000013 nop +80009dd8: 00000013 nop +80009ddc: 00000013 nop +80009de0: 00000013 nop +80009de4: 00000013 nop +80009de8: 00000013 nop +80009dec: 00000013 nop +80009df0: 00000013 nop +80009df4: 00000013 nop +80009df8: 00000013 nop +80009dfc: 00000013 nop +80009e00: 00000013 nop +80009e04: 00000013 nop +80009e08: 00000013 nop +80009e0c: 00000013 nop +80009e10: 00000013 nop +80009e14: 00000013 nop +80009e18: 00000013 nop +80009e1c: 00000013 nop +80009e20: 00000013 nop +80009e24: 00000013 nop +80009e28: 00000013 nop +80009e2c: 00000013 nop +80009e30: 00000013 nop +80009e34: 00000013 nop +80009e38: 00000013 nop +80009e3c: 00000013 nop +80009e40: 00000013 nop +80009e44: 00000013 nop +80009e48: 00000013 nop +80009e4c: 00000013 nop +80009e50: 00000013 nop +80009e54: 00000013 nop +80009e58: 00000013 nop +80009e5c: 00000013 nop +80009e60: 00000013 nop +80009e64: 00000013 nop +80009e68: 00000013 nop +80009e6c: 00000013 nop +80009e70: 00000013 nop +80009e74: 00000013 nop +80009e78: 00000013 nop +80009e7c: 00000013 nop +80009e80: 00000013 nop +80009e84: 00000013 nop +80009e88: 00000013 nop +80009e8c: 00000013 nop +80009e90: 00000013 nop +80009e94: 00000013 nop +80009e98: 00000013 nop +80009e9c: 00000013 nop +80009ea0: 00000013 nop +80009ea4: 00000013 nop +80009ea8: 00000013 nop +80009eac: 00000013 nop +80009eb0: 00000013 nop +80009eb4: 00000013 nop +80009eb8: 00000013 nop +80009ebc: 00000013 nop +80009ec0: 00000013 nop +80009ec4: 00000013 nop +80009ec8: 00000013 nop +80009ecc: 00000013 nop +80009ed0: 00000013 nop +80009ed4: 00000013 nop +80009ed8: 00000013 nop +80009edc: 00000013 nop +80009ee0: 00000013 nop +80009ee4: 00000013 nop +80009ee8: 00000013 nop +80009eec: 00000013 nop +80009ef0: 00000013 nop +80009ef4: 00000013 nop +80009ef8: 00000013 nop +80009efc: 00000013 nop +80009f00: 00000013 nop +80009f04: 00000013 nop +80009f08: 00000013 nop +80009f0c: 00000013 nop +80009f10: 00000013 nop +80009f14: 00000013 nop +80009f18: 00000013 nop +80009f1c: 00000013 nop +80009f20: 00000013 nop +80009f24: 00000013 nop +80009f28: 00000013 nop +80009f2c: 00000013 nop +80009f30: 00000013 nop +80009f34: 00000013 nop +80009f38: 00000013 nop +80009f3c: 00000013 nop +80009f40: 00000013 nop +80009f44: 00000013 nop +80009f48: 00000013 nop +80009f4c: 00000013 nop +80009f50: 00000013 nop +80009f54: 00000013 nop +80009f58: 00000013 nop +80009f5c: 00000013 nop +80009f60: 00000013 nop +80009f64: 00000013 nop +80009f68: 00000013 nop +80009f6c: 00000013 nop +80009f70: 00000013 nop +80009f74: 00000013 nop +80009f78: 00000013 nop +80009f7c: 00000013 nop +80009f80: 00000013 nop +80009f84: 00000013 nop +80009f88: 00000013 nop +80009f8c: 00000013 nop +80009f90: 00000013 nop +80009f94: 00000013 nop +80009f98: 00000013 nop +80009f9c: 00000013 nop +80009fa0: 00000013 nop +80009fa4: 00000013 nop +80009fa8: 00000013 nop +80009fac: 00000013 nop +80009fb0: 00000013 nop +80009fb4: 00000013 nop +80009fb8: 00000013 nop +80009fbc: 00000013 nop +80009fc0: 00000013 nop +80009fc4: 00000013 nop +80009fc8: 00000013 nop +80009fcc: 00000013 nop +80009fd0: 00000013 nop +80009fd4: 00000013 nop +80009fd8: 00000013 nop +80009fdc: 00000013 nop +80009fe0: 00000013 nop +80009fe4: 00000013 nop +80009fe8: 00000013 nop +80009fec: 00000013 nop +80009ff0: 00000013 nop +80009ff4: 00000013 nop +80009ff8: 00000013 nop +80009ffc: 00000013 nop + +8000a000 : +8000a000: 53525150 .word 0x53525150 +8000a004: 57565554 .word 0x57565554 +8000a008: 5b5a5958 .word 0x5b5a5958 +8000a00c: 5f5e5d5c .word 0x5f5e5d5c +8000a010: 00008067 ret +8000a014: 00000013 nop +8000a018: 00000013 nop +8000a01c: 00000013 nop +8000a020: 00000013 nop +8000a024: 00000013 nop +8000a028: 00000013 nop +8000a02c: 00000013 nop +8000a030: 00000013 nop +8000a034: 00000013 nop +8000a038: 00000013 nop +8000a03c: 00000013 nop +8000a040: 00000013 nop +8000a044: 00000013 nop +8000a048: 00000013 nop +8000a04c: 00000013 nop +8000a050: 00000013 nop +8000a054: 00000013 nop +8000a058: 00000013 nop +8000a05c: 00000013 nop +8000a060: 00000013 nop +8000a064: 00000013 nop +8000a068: 00000013 nop +8000a06c: 00000013 nop +8000a070: 00000013 nop +8000a074: 00000013 nop +8000a078: 00000013 nop +8000a07c: 00000013 nop +8000a080: 00000013 nop +8000a084: 00000013 nop +8000a088: 00000013 nop +8000a08c: 00000013 nop +8000a090: 00000013 nop +8000a094: 00000013 nop +8000a098: 00000013 nop +8000a09c: 00000013 nop +8000a0a0: 00000013 nop +8000a0a4: 00000013 nop +8000a0a8: 00000013 nop +8000a0ac: 00000013 nop +8000a0b0: 00000013 nop +8000a0b4: 00000013 nop +8000a0b8: 00000013 nop +8000a0bc: 00000013 nop +8000a0c0: 00000013 nop +8000a0c4: 00000013 nop +8000a0c8: 00000013 nop +8000a0cc: 00000013 nop +8000a0d0: 00000013 nop +8000a0d4: 00000013 nop +8000a0d8: 00000013 nop +8000a0dc: 00000013 nop +8000a0e0: 00000013 nop +8000a0e4: 00000013 nop +8000a0e8: 00000013 nop +8000a0ec: 00000013 nop +8000a0f0: 00000013 nop +8000a0f4: 00000013 nop +8000a0f8: 00000013 nop +8000a0fc: 00000013 nop +8000a100: 00000013 nop +8000a104: 00000013 nop +8000a108: 00000013 nop +8000a10c: 00000013 nop +8000a110: 00000013 nop +8000a114: 00000013 nop +8000a118: 00000013 nop +8000a11c: 00000013 nop +8000a120: 00000013 nop +8000a124: 00000013 nop +8000a128: 00000013 nop +8000a12c: 00000013 nop +8000a130: 00000013 nop +8000a134: 00000013 nop +8000a138: 00000013 nop +8000a13c: 00000013 nop +8000a140: 00000013 nop +8000a144: 00000013 nop +8000a148: 00000013 nop +8000a14c: 00000013 nop +8000a150: 00000013 nop +8000a154: 00000013 nop +8000a158: 00000013 nop +8000a15c: 00000013 nop +8000a160: 00000013 nop +8000a164: 00000013 nop +8000a168: 00000013 nop +8000a16c: 00000013 nop +8000a170: 00000013 nop +8000a174: 00000013 nop +8000a178: 00000013 nop +8000a17c: 00000013 nop +8000a180: 00000013 nop +8000a184: 00000013 nop +8000a188: 00000013 nop +8000a18c: 00000013 nop +8000a190: 00000013 nop +8000a194: 00000013 nop +8000a198: 00000013 nop +8000a19c: 00000013 nop +8000a1a0: 00000013 nop +8000a1a4: 00000013 nop +8000a1a8: 00000013 nop +8000a1ac: 00000013 nop +8000a1b0: 00000013 nop +8000a1b4: 00000013 nop +8000a1b8: 00000013 nop +8000a1bc: 00000013 nop +8000a1c0: 00000013 nop +8000a1c4: 00000013 nop +8000a1c8: 00000013 nop +8000a1cc: 00000013 nop +8000a1d0: 00000013 nop +8000a1d4: 00000013 nop +8000a1d8: 00000013 nop +8000a1dc: 00000013 nop +8000a1e0: 00000013 nop +8000a1e4: 00000013 nop +8000a1e8: 00000013 nop +8000a1ec: 00000013 nop +8000a1f0: 00000013 nop +8000a1f4: 00000013 nop +8000a1f8: 00000013 nop +8000a1fc: 00000013 nop +8000a200: 00000013 nop +8000a204: 00000013 nop +8000a208: 00000013 nop +8000a20c: 00000013 nop +8000a210: 00000013 nop +8000a214: 00000013 nop +8000a218: 00000013 nop +8000a21c: 00000013 nop +8000a220: 00000013 nop +8000a224: 00000013 nop +8000a228: 00000013 nop +8000a22c: 00000013 nop +8000a230: 00000013 nop +8000a234: 00000013 nop +8000a238: 00000013 nop +8000a23c: 00000013 nop +8000a240: 00000013 nop +8000a244: 00000013 nop +8000a248: 00000013 nop +8000a24c: 00000013 nop +8000a250: 00000013 nop +8000a254: 00000013 nop +8000a258: 00000013 nop +8000a25c: 00000013 nop +8000a260: 00000013 nop +8000a264: 00000013 nop +8000a268: 00000013 nop +8000a26c: 00000013 nop +8000a270: 00000013 nop +8000a274: 00000013 nop +8000a278: 00000013 nop +8000a27c: 00000013 nop +8000a280: 00000013 nop +8000a284: 00000013 nop +8000a288: 00000013 nop +8000a28c: 00000013 nop +8000a290: 00000013 nop +8000a294: 00000013 nop +8000a298: 00000013 nop +8000a29c: 00000013 nop +8000a2a0: 00000013 nop +8000a2a4: 00000013 nop +8000a2a8: 00000013 nop +8000a2ac: 00000013 nop +8000a2b0: 00000013 nop +8000a2b4: 00000013 nop +8000a2b8: 00000013 nop +8000a2bc: 00000013 nop +8000a2c0: 00000013 nop +8000a2c4: 00000013 nop +8000a2c8: 00000013 nop +8000a2cc: 00000013 nop +8000a2d0: 00000013 nop +8000a2d4: 00000013 nop +8000a2d8: 00000013 nop +8000a2dc: 00000013 nop +8000a2e0: 00000013 nop +8000a2e4: 00000013 nop +8000a2e8: 00000013 nop +8000a2ec: 00000013 nop +8000a2f0: 00000013 nop +8000a2f4: 00000013 nop +8000a2f8: 00000013 nop +8000a2fc: 00000013 nop +8000a300: 00000013 nop +8000a304: 00000013 nop +8000a308: 00000013 nop +8000a30c: 00000013 nop +8000a310: 00000013 nop +8000a314: 00000013 nop +8000a318: 00000013 nop +8000a31c: 00000013 nop +8000a320: 00000013 nop +8000a324: 00000013 nop +8000a328: 00000013 nop +8000a32c: 00000013 nop +8000a330: 00000013 nop +8000a334: 00000013 nop +8000a338: 00000013 nop +8000a33c: 00000013 nop +8000a340: 00000013 nop +8000a344: 00000013 nop +8000a348: 00000013 nop +8000a34c: 00000013 nop +8000a350: 00000013 nop +8000a354: 00000013 nop +8000a358: 00000013 nop +8000a35c: 00000013 nop +8000a360: 00000013 nop +8000a364: 00000013 nop +8000a368: 00000013 nop +8000a36c: 00000013 nop +8000a370: 00000013 nop +8000a374: 00000013 nop +8000a378: 00000013 nop +8000a37c: 00000013 nop +8000a380: 00000013 nop +8000a384: 00000013 nop +8000a388: 00000013 nop +8000a38c: 00000013 nop +8000a390: 00000013 nop +8000a394: 00000013 nop +8000a398: 00000013 nop +8000a39c: 00000013 nop +8000a3a0: 00000013 nop +8000a3a4: 00000013 nop +8000a3a8: 00000013 nop +8000a3ac: 00000013 nop +8000a3b0: 00000013 nop +8000a3b4: 00000013 nop +8000a3b8: 00000013 nop +8000a3bc: 00000013 nop +8000a3c0: 00000013 nop +8000a3c4: 00000013 nop +8000a3c8: 00000013 nop +8000a3cc: 00000013 nop +8000a3d0: 00000013 nop +8000a3d4: 00000013 nop +8000a3d8: 00000013 nop +8000a3dc: 00000013 nop +8000a3e0: 00000013 nop +8000a3e4: 00000013 nop +8000a3e8: 00000013 nop +8000a3ec: 00000013 nop +8000a3f0: 00000013 nop +8000a3f4: 00000013 nop +8000a3f8: 00000013 nop +8000a3fc: 00000013 nop +8000a400: 00000013 nop +8000a404: 00000013 nop +8000a408: 00000013 nop +8000a40c: 00000013 nop +8000a410: 00000013 nop +8000a414: 00000013 nop +8000a418: 00000013 nop +8000a41c: 00000013 nop +8000a420: 00000013 nop +8000a424: 00000013 nop +8000a428: 00000013 nop +8000a42c: 00000013 nop +8000a430: 00000013 nop +8000a434: 00000013 nop +8000a438: 00000013 nop +8000a43c: 00000013 nop +8000a440: 00000013 nop +8000a444: 00000013 nop +8000a448: 00000013 nop +8000a44c: 00000013 nop +8000a450: 00000013 nop +8000a454: 00000013 nop +8000a458: 00000013 nop +8000a45c: 00000013 nop +8000a460: 00000013 nop +8000a464: 00000013 nop +8000a468: 00000013 nop +8000a46c: 00000013 nop +8000a470: 00000013 nop +8000a474: 00000013 nop +8000a478: 00000013 nop +8000a47c: 00000013 nop +8000a480: 00000013 nop +8000a484: 00000013 nop +8000a488: 00000013 nop +8000a48c: 00000013 nop +8000a490: 00000013 nop +8000a494: 00000013 nop +8000a498: 00000013 nop +8000a49c: 00000013 nop +8000a4a0: 00000013 nop +8000a4a4: 00000013 nop +8000a4a8: 00000013 nop +8000a4ac: 00000013 nop +8000a4b0: 00000013 nop +8000a4b4: 00000013 nop +8000a4b8: 00000013 nop +8000a4bc: 00000013 nop +8000a4c0: 00000013 nop +8000a4c4: 00000013 nop +8000a4c8: 00000013 nop +8000a4cc: 00000013 nop +8000a4d0: 00000013 nop +8000a4d4: 00000013 nop +8000a4d8: 00000013 nop +8000a4dc: 00000013 nop +8000a4e0: 00000013 nop +8000a4e4: 00000013 nop +8000a4e8: 00000013 nop +8000a4ec: 00000013 nop +8000a4f0: 00000013 nop +8000a4f4: 00000013 nop +8000a4f8: 00000013 nop +8000a4fc: 00000013 nop +8000a500: 00000013 nop +8000a504: 00000013 nop +8000a508: 00000013 nop +8000a50c: 00000013 nop +8000a510: 00000013 nop +8000a514: 00000013 nop +8000a518: 00000013 nop +8000a51c: 00000013 nop +8000a520: 00000013 nop +8000a524: 00000013 nop +8000a528: 00000013 nop +8000a52c: 00000013 nop +8000a530: 00000013 nop +8000a534: 00000013 nop +8000a538: 00000013 nop +8000a53c: 00000013 nop +8000a540: 00000013 nop +8000a544: 00000013 nop +8000a548: 00000013 nop +8000a54c: 00000013 nop +8000a550: 00000013 nop +8000a554: 00000013 nop +8000a558: 00000013 nop +8000a55c: 00000013 nop +8000a560: 00000013 nop +8000a564: 00000013 nop +8000a568: 00000013 nop +8000a56c: 00000013 nop +8000a570: 00000013 nop +8000a574: 00000013 nop +8000a578: 00000013 nop +8000a57c: 00000013 nop +8000a580: 00000013 nop +8000a584: 00000013 nop +8000a588: 00000013 nop +8000a58c: 00000013 nop +8000a590: 00000013 nop +8000a594: 00000013 nop +8000a598: 00000013 nop +8000a59c: 00000013 nop +8000a5a0: 00000013 nop +8000a5a4: 00000013 nop +8000a5a8: 00000013 nop +8000a5ac: 00000013 nop +8000a5b0: 00000013 nop +8000a5b4: 00000013 nop +8000a5b8: 00000013 nop +8000a5bc: 00000013 nop +8000a5c0: 00000013 nop +8000a5c4: 00000013 nop +8000a5c8: 00000013 nop +8000a5cc: 00000013 nop +8000a5d0: 00000013 nop +8000a5d4: 00000013 nop +8000a5d8: 00000013 nop +8000a5dc: 00000013 nop +8000a5e0: 00000013 nop +8000a5e4: 00000013 nop +8000a5e8: 00000013 nop +8000a5ec: 00000013 nop +8000a5f0: 00000013 nop +8000a5f4: 00000013 nop +8000a5f8: 00000013 nop +8000a5fc: 00000013 nop +8000a600: 00000013 nop +8000a604: 00000013 nop +8000a608: 00000013 nop +8000a60c: 00000013 nop +8000a610: 00000013 nop +8000a614: 00000013 nop +8000a618: 00000013 nop +8000a61c: 00000013 nop +8000a620: 00000013 nop +8000a624: 00000013 nop +8000a628: 00000013 nop +8000a62c: 00000013 nop +8000a630: 00000013 nop +8000a634: 00000013 nop +8000a638: 00000013 nop +8000a63c: 00000013 nop +8000a640: 00000013 nop +8000a644: 00000013 nop +8000a648: 00000013 nop +8000a64c: 00000013 nop +8000a650: 00000013 nop +8000a654: 00000013 nop +8000a658: 00000013 nop +8000a65c: 00000013 nop +8000a660: 00000013 nop +8000a664: 00000013 nop +8000a668: 00000013 nop +8000a66c: 00000013 nop +8000a670: 00000013 nop +8000a674: 00000013 nop +8000a678: 00000013 nop +8000a67c: 00000013 nop +8000a680: 00000013 nop +8000a684: 00000013 nop +8000a688: 00000013 nop +8000a68c: 00000013 nop +8000a690: 00000013 nop +8000a694: 00000013 nop +8000a698: 00000013 nop +8000a69c: 00000013 nop +8000a6a0: 00000013 nop +8000a6a4: 00000013 nop +8000a6a8: 00000013 nop +8000a6ac: 00000013 nop +8000a6b0: 00000013 nop +8000a6b4: 00000013 nop +8000a6b8: 00000013 nop +8000a6bc: 00000013 nop +8000a6c0: 00000013 nop +8000a6c4: 00000013 nop +8000a6c8: 00000013 nop +8000a6cc: 00000013 nop +8000a6d0: 00000013 nop +8000a6d4: 00000013 nop +8000a6d8: 00000013 nop +8000a6dc: 00000013 nop +8000a6e0: 00000013 nop +8000a6e4: 00000013 nop +8000a6e8: 00000013 nop +8000a6ec: 00000013 nop +8000a6f0: 00000013 nop +8000a6f4: 00000013 nop +8000a6f8: 00000013 nop +8000a6fc: 00000013 nop +8000a700: 00000013 nop +8000a704: 00000013 nop +8000a708: 00000013 nop +8000a70c: 00000013 nop +8000a710: 00000013 nop +8000a714: 00000013 nop +8000a718: 00000013 nop +8000a71c: 00000013 nop +8000a720: 00000013 nop +8000a724: 00000013 nop +8000a728: 00000013 nop +8000a72c: 00000013 nop +8000a730: 00000013 nop +8000a734: 00000013 nop +8000a738: 00000013 nop +8000a73c: 00000013 nop +8000a740: 00000013 nop +8000a744: 00000013 nop +8000a748: 00000013 nop +8000a74c: 00000013 nop +8000a750: 00000013 nop +8000a754: 00000013 nop +8000a758: 00000013 nop +8000a75c: 00000013 nop +8000a760: 00000013 nop +8000a764: 00000013 nop +8000a768: 00000013 nop +8000a76c: 00000013 nop +8000a770: 00000013 nop +8000a774: 00000013 nop +8000a778: 00000013 nop +8000a77c: 00000013 nop +8000a780: 00000013 nop +8000a784: 00000013 nop +8000a788: 00000013 nop +8000a78c: 00000013 nop +8000a790: 00000013 nop +8000a794: 00000013 nop +8000a798: 00000013 nop +8000a79c: 00000013 nop +8000a7a0: 00000013 nop +8000a7a4: 00000013 nop +8000a7a8: 00000013 nop +8000a7ac: 00000013 nop +8000a7b0: 00000013 nop +8000a7b4: 00000013 nop +8000a7b8: 00000013 nop +8000a7bc: 00000013 nop +8000a7c0: 00000013 nop +8000a7c4: 00000013 nop +8000a7c8: 00000013 nop +8000a7cc: 00000013 nop +8000a7d0: 00000013 nop +8000a7d4: 00000013 nop +8000a7d8: 00000013 nop +8000a7dc: 00000013 nop +8000a7e0: 00000013 nop +8000a7e4: 00000013 nop +8000a7e8: 00000013 nop +8000a7ec: 00000013 nop +8000a7f0: 00000013 nop +8000a7f4: 00000013 nop +8000a7f8: 00000013 nop +8000a7fc: 00000013 nop +8000a800: 00000013 nop +8000a804: 00000013 nop +8000a808: 00000013 nop +8000a80c: 00000013 nop +8000a810: 00000013 nop +8000a814: 00000013 nop +8000a818: 00000013 nop +8000a81c: 00000013 nop +8000a820: 00000013 nop +8000a824: 00000013 nop +8000a828: 00000013 nop +8000a82c: 00000013 nop +8000a830: 00000013 nop +8000a834: 00000013 nop +8000a838: 00000013 nop +8000a83c: 00000013 nop +8000a840: 00000013 nop +8000a844: 00000013 nop +8000a848: 00000013 nop +8000a84c: 00000013 nop +8000a850: 00000013 nop +8000a854: 00000013 nop +8000a858: 00000013 nop +8000a85c: 00000013 nop +8000a860: 00000013 nop +8000a864: 00000013 nop +8000a868: 00000013 nop +8000a86c: 00000013 nop +8000a870: 00000013 nop +8000a874: 00000013 nop +8000a878: 00000013 nop +8000a87c: 00000013 nop +8000a880: 00000013 nop +8000a884: 00000013 nop +8000a888: 00000013 nop +8000a88c: 00000013 nop +8000a890: 00000013 nop +8000a894: 00000013 nop +8000a898: 00000013 nop +8000a89c: 00000013 nop +8000a8a0: 00000013 nop +8000a8a4: 00000013 nop +8000a8a8: 00000013 nop +8000a8ac: 00000013 nop +8000a8b0: 00000013 nop +8000a8b4: 00000013 nop +8000a8b8: 00000013 nop +8000a8bc: 00000013 nop +8000a8c0: 00000013 nop +8000a8c4: 00000013 nop +8000a8c8: 00000013 nop +8000a8cc: 00000013 nop +8000a8d0: 00000013 nop +8000a8d4: 00000013 nop +8000a8d8: 00000013 nop +8000a8dc: 00000013 nop +8000a8e0: 00000013 nop +8000a8e4: 00000013 nop +8000a8e8: 00000013 nop +8000a8ec: 00000013 nop +8000a8f0: 00000013 nop +8000a8f4: 00000013 nop +8000a8f8: 00000013 nop +8000a8fc: 00000013 nop +8000a900: 00000013 nop +8000a904: 00000013 nop +8000a908: 00000013 nop +8000a90c: 00000013 nop +8000a910: 00000013 nop +8000a914: 00000013 nop +8000a918: 00000013 nop +8000a91c: 00000013 nop +8000a920: 00000013 nop +8000a924: 00000013 nop +8000a928: 00000013 nop +8000a92c: 00000013 nop +8000a930: 00000013 nop +8000a934: 00000013 nop +8000a938: 00000013 nop +8000a93c: 00000013 nop +8000a940: 00000013 nop +8000a944: 00000013 nop +8000a948: 00000013 nop +8000a94c: 00000013 nop +8000a950: 00000013 nop +8000a954: 00000013 nop +8000a958: 00000013 nop +8000a95c: 00000013 nop +8000a960: 00000013 nop +8000a964: 00000013 nop +8000a968: 00000013 nop +8000a96c: 00000013 nop +8000a970: 00000013 nop +8000a974: 00000013 nop +8000a978: 00000013 nop +8000a97c: 00000013 nop +8000a980: 00000013 nop +8000a984: 00000013 nop +8000a988: 00000013 nop +8000a98c: 00000013 nop +8000a990: 00000013 nop +8000a994: 00000013 nop +8000a998: 00000013 nop +8000a99c: 00000013 nop +8000a9a0: 00000013 nop +8000a9a4: 00000013 nop +8000a9a8: 00000013 nop +8000a9ac: 00000013 nop +8000a9b0: 00000013 nop +8000a9b4: 00000013 nop +8000a9b8: 00000013 nop +8000a9bc: 00000013 nop +8000a9c0: 00000013 nop +8000a9c4: 00000013 nop +8000a9c8: 00000013 nop +8000a9cc: 00000013 nop +8000a9d0: 00000013 nop +8000a9d4: 00000013 nop +8000a9d8: 00000013 nop +8000a9dc: 00000013 nop +8000a9e0: 00000013 nop +8000a9e4: 00000013 nop +8000a9e8: 00000013 nop +8000a9ec: 00000013 nop +8000a9f0: 00000013 nop +8000a9f4: 00000013 nop +8000a9f8: 00000013 nop +8000a9fc: 00000013 nop +8000aa00: 00000013 nop +8000aa04: 00000013 nop +8000aa08: 00000013 nop +8000aa0c: 00000013 nop +8000aa10: 00000013 nop +8000aa14: 00000013 nop +8000aa18: 00000013 nop +8000aa1c: 00000013 nop +8000aa20: 00000013 nop +8000aa24: 00000013 nop +8000aa28: 00000013 nop +8000aa2c: 00000013 nop +8000aa30: 00000013 nop +8000aa34: 00000013 nop +8000aa38: 00000013 nop +8000aa3c: 00000013 nop +8000aa40: 00000013 nop +8000aa44: 00000013 nop +8000aa48: 00000013 nop +8000aa4c: 00000013 nop +8000aa50: 00000013 nop +8000aa54: 00000013 nop +8000aa58: 00000013 nop +8000aa5c: 00000013 nop +8000aa60: 00000013 nop +8000aa64: 00000013 nop +8000aa68: 00000013 nop +8000aa6c: 00000013 nop +8000aa70: 00000013 nop +8000aa74: 00000013 nop +8000aa78: 00000013 nop +8000aa7c: 00000013 nop +8000aa80: 00000013 nop +8000aa84: 00000013 nop +8000aa88: 00000013 nop +8000aa8c: 00000013 nop +8000aa90: 00000013 nop +8000aa94: 00000013 nop +8000aa98: 00000013 nop +8000aa9c: 00000013 nop +8000aaa0: 00000013 nop +8000aaa4: 00000013 nop +8000aaa8: 00000013 nop +8000aaac: 00000013 nop +8000aab0: 00000013 nop +8000aab4: 00000013 nop +8000aab8: 00000013 nop +8000aabc: 00000013 nop +8000aac0: 00000013 nop +8000aac4: 00000013 nop +8000aac8: 00000013 nop +8000aacc: 00000013 nop +8000aad0: 00000013 nop +8000aad4: 00000013 nop +8000aad8: 00000013 nop +8000aadc: 00000013 nop +8000aae0: 00000013 nop +8000aae4: 00000013 nop +8000aae8: 00000013 nop +8000aaec: 00000013 nop +8000aaf0: 00000013 nop +8000aaf4: 00000013 nop +8000aaf8: 00000013 nop +8000aafc: 00000013 nop +8000ab00: 00000013 nop +8000ab04: 00000013 nop +8000ab08: 00000013 nop +8000ab0c: 00000013 nop +8000ab10: 00000013 nop +8000ab14: 00000013 nop +8000ab18: 00000013 nop +8000ab1c: 00000013 nop +8000ab20: 00000013 nop +8000ab24: 00000013 nop +8000ab28: 00000013 nop +8000ab2c: 00000013 nop +8000ab30: 00000013 nop +8000ab34: 00000013 nop +8000ab38: 00000013 nop +8000ab3c: 00000013 nop +8000ab40: 00000013 nop +8000ab44: 00000013 nop +8000ab48: 00000013 nop +8000ab4c: 00000013 nop +8000ab50: 00000013 nop +8000ab54: 00000013 nop +8000ab58: 00000013 nop +8000ab5c: 00000013 nop +8000ab60: 00000013 nop +8000ab64: 00000013 nop +8000ab68: 00000013 nop +8000ab6c: 00000013 nop +8000ab70: 00000013 nop +8000ab74: 00000013 nop +8000ab78: 00000013 nop +8000ab7c: 00000013 nop +8000ab80: 00000013 nop +8000ab84: 00000013 nop +8000ab88: 00000013 nop +8000ab8c: 00000013 nop +8000ab90: 00000013 nop +8000ab94: 00000013 nop +8000ab98: 00000013 nop +8000ab9c: 00000013 nop +8000aba0: 00000013 nop +8000aba4: 00000013 nop +8000aba8: 00000013 nop +8000abac: 00000013 nop +8000abb0: 00000013 nop +8000abb4: 00000013 nop +8000abb8: 00000013 nop +8000abbc: 00000013 nop +8000abc0: 00000013 nop +8000abc4: 00000013 nop +8000abc8: 00000013 nop +8000abcc: 00000013 nop +8000abd0: 00000013 nop +8000abd4: 00000013 nop +8000abd8: 00000013 nop +8000abdc: 00000013 nop +8000abe0: 00000013 nop +8000abe4: 00000013 nop +8000abe8: 00000013 nop +8000abec: 00000013 nop +8000abf0: 00000013 nop +8000abf4: 00000013 nop +8000abf8: 00000013 nop +8000abfc: 00000013 nop +8000ac00: 00000013 nop +8000ac04: 00000013 nop +8000ac08: 00000013 nop +8000ac0c: 00000013 nop +8000ac10: 00000013 nop +8000ac14: 00000013 nop +8000ac18: 00000013 nop +8000ac1c: 00000013 nop +8000ac20: 00000013 nop +8000ac24: 00000013 nop +8000ac28: 00000013 nop +8000ac2c: 00000013 nop +8000ac30: 00000013 nop +8000ac34: 00000013 nop +8000ac38: 00000013 nop +8000ac3c: 00000013 nop +8000ac40: 00000013 nop +8000ac44: 00000013 nop +8000ac48: 00000013 nop +8000ac4c: 00000013 nop +8000ac50: 00000013 nop +8000ac54: 00000013 nop +8000ac58: 00000013 nop +8000ac5c: 00000013 nop +8000ac60: 00000013 nop +8000ac64: 00000013 nop +8000ac68: 00000013 nop +8000ac6c: 00000013 nop +8000ac70: 00000013 nop +8000ac74: 00000013 nop +8000ac78: 00000013 nop +8000ac7c: 00000013 nop +8000ac80: 00000013 nop +8000ac84: 00000013 nop +8000ac88: 00000013 nop +8000ac8c: 00000013 nop +8000ac90: 00000013 nop +8000ac94: 00000013 nop +8000ac98: 00000013 nop +8000ac9c: 00000013 nop +8000aca0: 00000013 nop +8000aca4: 00000013 nop +8000aca8: 00000013 nop +8000acac: 00000013 nop +8000acb0: 00000013 nop +8000acb4: 00000013 nop +8000acb8: 00000013 nop +8000acbc: 00000013 nop +8000acc0: 00000013 nop +8000acc4: 00000013 nop +8000acc8: 00000013 nop +8000accc: 00000013 nop +8000acd0: 00000013 nop +8000acd4: 00000013 nop +8000acd8: 00000013 nop +8000acdc: 00000013 nop +8000ace0: 00000013 nop +8000ace4: 00000013 nop +8000ace8: 00000013 nop +8000acec: 00000013 nop +8000acf0: 00000013 nop +8000acf4: 00000013 nop +8000acf8: 00000013 nop +8000acfc: 00000013 nop +8000ad00: 00000013 nop +8000ad04: 00000013 nop +8000ad08: 00000013 nop +8000ad0c: 00000013 nop +8000ad10: 00000013 nop +8000ad14: 00000013 nop +8000ad18: 00000013 nop +8000ad1c: 00000013 nop +8000ad20: 00000013 nop +8000ad24: 00000013 nop +8000ad28: 00000013 nop +8000ad2c: 00000013 nop +8000ad30: 00000013 nop +8000ad34: 00000013 nop +8000ad38: 00000013 nop +8000ad3c: 00000013 nop +8000ad40: 00000013 nop +8000ad44: 00000013 nop +8000ad48: 00000013 nop +8000ad4c: 00000013 nop +8000ad50: 00000013 nop +8000ad54: 00000013 nop +8000ad58: 00000013 nop +8000ad5c: 00000013 nop +8000ad60: 00000013 nop +8000ad64: 00000013 nop +8000ad68: 00000013 nop +8000ad6c: 00000013 nop +8000ad70: 00000013 nop +8000ad74: 00000013 nop +8000ad78: 00000013 nop +8000ad7c: 00000013 nop +8000ad80: 00000013 nop +8000ad84: 00000013 nop +8000ad88: 00000013 nop +8000ad8c: 00000013 nop +8000ad90: 00000013 nop +8000ad94: 00000013 nop +8000ad98: 00000013 nop +8000ad9c: 00000013 nop +8000ada0: 00000013 nop +8000ada4: 00000013 nop +8000ada8: 00000013 nop +8000adac: 00000013 nop +8000adb0: 00000013 nop +8000adb4: 00000013 nop +8000adb8: 00000013 nop +8000adbc: 00000013 nop +8000adc0: 00000013 nop +8000adc4: 00000013 nop +8000adc8: 00000013 nop +8000adcc: 00000013 nop +8000add0: 00000013 nop +8000add4: 00000013 nop +8000add8: 00000013 nop +8000addc: 00000013 nop +8000ade0: 00000013 nop +8000ade4: 00000013 nop +8000ade8: 00000013 nop +8000adec: 00000013 nop +8000adf0: 00000013 nop +8000adf4: 00000013 nop +8000adf8: 00000013 nop +8000adfc: 00000013 nop +8000ae00: 00000013 nop +8000ae04: 00000013 nop +8000ae08: 00000013 nop +8000ae0c: 00000013 nop +8000ae10: 00000013 nop +8000ae14: 00000013 nop +8000ae18: 00000013 nop +8000ae1c: 00000013 nop +8000ae20: 00000013 nop +8000ae24: 00000013 nop +8000ae28: 00000013 nop +8000ae2c: 00000013 nop +8000ae30: 00000013 nop +8000ae34: 00000013 nop +8000ae38: 00000013 nop +8000ae3c: 00000013 nop +8000ae40: 00000013 nop +8000ae44: 00000013 nop +8000ae48: 00000013 nop +8000ae4c: 00000013 nop +8000ae50: 00000013 nop +8000ae54: 00000013 nop +8000ae58: 00000013 nop +8000ae5c: 00000013 nop +8000ae60: 00000013 nop +8000ae64: 00000013 nop +8000ae68: 00000013 nop +8000ae6c: 00000013 nop +8000ae70: 00000013 nop +8000ae74: 00000013 nop +8000ae78: 00000013 nop +8000ae7c: 00000013 nop +8000ae80: 00000013 nop +8000ae84: 00000013 nop +8000ae88: 00000013 nop +8000ae8c: 00000013 nop +8000ae90: 00000013 nop +8000ae94: 00000013 nop +8000ae98: 00000013 nop +8000ae9c: 00000013 nop +8000aea0: 00000013 nop +8000aea4: 00000013 nop +8000aea8: 00000013 nop +8000aeac: 00000013 nop +8000aeb0: 00000013 nop +8000aeb4: 00000013 nop +8000aeb8: 00000013 nop +8000aebc: 00000013 nop +8000aec0: 00000013 nop +8000aec4: 00000013 nop +8000aec8: 00000013 nop +8000aecc: 00000013 nop +8000aed0: 00000013 nop +8000aed4: 00000013 nop +8000aed8: 00000013 nop +8000aedc: 00000013 nop +8000aee0: 00000013 nop +8000aee4: 00000013 nop +8000aee8: 00000013 nop +8000aeec: 00000013 nop +8000aef0: 00000013 nop +8000aef4: 00000013 nop +8000aef8: 00000013 nop +8000aefc: 00000013 nop +8000af00: 00000013 nop +8000af04: 00000013 nop +8000af08: 00000013 nop +8000af0c: 00000013 nop +8000af10: 00000013 nop +8000af14: 00000013 nop +8000af18: 00000013 nop +8000af1c: 00000013 nop +8000af20: 00000013 nop +8000af24: 00000013 nop +8000af28: 00000013 nop +8000af2c: 00000013 nop +8000af30: 00000013 nop +8000af34: 00000013 nop +8000af38: 00000013 nop +8000af3c: 00000013 nop +8000af40: 00000013 nop +8000af44: 00000013 nop +8000af48: 00000013 nop +8000af4c: 00000013 nop +8000af50: 00000013 nop +8000af54: 00000013 nop +8000af58: 00000013 nop +8000af5c: 00000013 nop +8000af60: 00000013 nop +8000af64: 00000013 nop +8000af68: 00000013 nop +8000af6c: 00000013 nop +8000af70: 00000013 nop +8000af74: 00000013 nop +8000af78: 00000013 nop +8000af7c: 00000013 nop +8000af80: 00000013 nop +8000af84: 00000013 nop +8000af88: 00000013 nop +8000af8c: 00000013 nop +8000af90: 00000013 nop +8000af94: 00000013 nop +8000af98: 00000013 nop +8000af9c: 00000013 nop +8000afa0: 00000013 nop +8000afa4: 00000013 nop +8000afa8: 00000013 nop +8000afac: 00000013 nop +8000afb0: 00000013 nop +8000afb4: 00000013 nop +8000afb8: 00000013 nop +8000afbc: 00000013 nop +8000afc0: 00000013 nop +8000afc4: 00000013 nop +8000afc8: 00000013 nop +8000afcc: 00000013 nop +8000afd0: 00000013 nop +8000afd4: 00000013 nop +8000afd8: 00000013 nop +8000afdc: 00000013 nop +8000afe0: 00000013 nop +8000afe4: 00000013 nop +8000afe8: 00000013 nop +8000afec: 00000013 nop +8000aff0: 00000013 nop +8000aff4: 00000013 nop +8000aff8: 00000013 nop +8000affc: 00000013 nop + +8000b000 : +8000b000: 63626160 .word 0x63626160 +8000b004: 67666564 .word 0x67666564 +8000b008: 6b6a6968 .word 0x6b6a6968 +8000b00c: 6f6e6d6c .word 0x6f6e6d6c +8000b010: 00000013 nop +8000b014: 00000013 nop +8000b018: 00000013 nop +8000b01c: 00000013 nop +8000b020: 00000013 nop +8000b024: 00000013 nop +8000b028: 00000013 nop +8000b02c: 00000013 nop +8000b030: 00000013 nop +8000b034: 00000013 nop +8000b038: 00000013 nop +8000b03c: 00000013 nop +8000b040: 00000013 nop +8000b044: 00000013 nop +8000b048: 00000013 nop +8000b04c: 00000013 nop +8000b050: 00000013 nop +8000b054: 00000013 nop +8000b058: 00000013 nop +8000b05c: 00000013 nop +8000b060: 00000013 nop +8000b064: 00000013 nop +8000b068: 00000013 nop +8000b06c: 00000013 nop +8000b070: 00000013 nop +8000b074: 00000013 nop +8000b078: 00000013 nop +8000b07c: 00000013 nop +8000b080: 00000013 nop +8000b084: 00000013 nop +8000b088: 00000013 nop +8000b08c: 00000013 nop +8000b090: 00000013 nop +8000b094: 00000013 nop +8000b098: 00000013 nop +8000b09c: 00000013 nop +8000b0a0: 00000013 nop +8000b0a4: 00000013 nop +8000b0a8: 00000013 nop +8000b0ac: 00000013 nop +8000b0b0: 00000013 nop +8000b0b4: 00000013 nop +8000b0b8: 00000013 nop +8000b0bc: 00000013 nop +8000b0c0: 00000013 nop +8000b0c4: 00000013 nop +8000b0c8: 00000013 nop +8000b0cc: 00000013 nop +8000b0d0: 00000013 nop +8000b0d4: 00000013 nop +8000b0d8: 00000013 nop +8000b0dc: 00000013 nop +8000b0e0: 00000013 nop +8000b0e4: 00000013 nop +8000b0e8: 00000013 nop +8000b0ec: 00000013 nop +8000b0f0: 00000013 nop +8000b0f4: 00000013 nop +8000b0f8: 00000013 nop +8000b0fc: 00000013 nop +8000b100: 00000013 nop +8000b104: 00000013 nop +8000b108: 00000013 nop +8000b10c: 00000013 nop +8000b110: 00000013 nop +8000b114: 00000013 nop +8000b118: 00000013 nop +8000b11c: 00000013 nop +8000b120: 00000013 nop +8000b124: 00000013 nop +8000b128: 00000013 nop +8000b12c: 00000013 nop +8000b130: 00000013 nop +8000b134: 00000013 nop +8000b138: 00000013 nop +8000b13c: 00000013 nop +8000b140: 00000013 nop +8000b144: 00000013 nop +8000b148: 00000013 nop +8000b14c: 00000013 nop +8000b150: 00000013 nop +8000b154: 00000013 nop +8000b158: 00000013 nop +8000b15c: 00000013 nop +8000b160: 00000013 nop +8000b164: 00000013 nop +8000b168: 00000013 nop +8000b16c: 00000013 nop +8000b170: 00000013 nop +8000b174: 00000013 nop +8000b178: 00000013 nop +8000b17c: 00000013 nop +8000b180: 00000013 nop +8000b184: 00000013 nop +8000b188: 00000013 nop +8000b18c: 00000013 nop +8000b190: 00000013 nop +8000b194: 00000013 nop +8000b198: 00000013 nop +8000b19c: 00000013 nop +8000b1a0: 00000013 nop +8000b1a4: 00000013 nop +8000b1a8: 00000013 nop +8000b1ac: 00000013 nop +8000b1b0: 00000013 nop +8000b1b4: 00000013 nop +8000b1b8: 00000013 nop +8000b1bc: 00000013 nop +8000b1c0: 00000013 nop +8000b1c4: 00000013 nop +8000b1c8: 00000013 nop +8000b1cc: 00000013 nop +8000b1d0: 00000013 nop +8000b1d4: 00000013 nop +8000b1d8: 00000013 nop +8000b1dc: 00000013 nop +8000b1e0: 00000013 nop +8000b1e4: 00000013 nop +8000b1e8: 00000013 nop +8000b1ec: 00000013 nop +8000b1f0: 00000013 nop +8000b1f4: 00000013 nop +8000b1f8: 00000013 nop +8000b1fc: 00000013 nop +8000b200: 00000013 nop +8000b204: 00000013 nop +8000b208: 00000013 nop +8000b20c: 00000013 nop +8000b210: 00000013 nop +8000b214: 00000013 nop +8000b218: 00000013 nop +8000b21c: 00000013 nop +8000b220: 00000013 nop +8000b224: 00000013 nop +8000b228: 00000013 nop +8000b22c: 00000013 nop +8000b230: 00000013 nop +8000b234: 00000013 nop +8000b238: 00000013 nop +8000b23c: 00000013 nop +8000b240: 00000013 nop +8000b244: 00000013 nop +8000b248: 00000013 nop +8000b24c: 00000013 nop +8000b250: 00000013 nop +8000b254: 00000013 nop +8000b258: 00000013 nop +8000b25c: 00000013 nop +8000b260: 00000013 nop +8000b264: 00000013 nop +8000b268: 00000013 nop +8000b26c: 00000013 nop +8000b270: 00000013 nop +8000b274: 00000013 nop +8000b278: 00000013 nop +8000b27c: 00000013 nop +8000b280: 00000013 nop +8000b284: 00000013 nop +8000b288: 00000013 nop +8000b28c: 00000013 nop +8000b290: 00000013 nop +8000b294: 00000013 nop +8000b298: 00000013 nop +8000b29c: 00000013 nop +8000b2a0: 00000013 nop +8000b2a4: 00000013 nop +8000b2a8: 00000013 nop +8000b2ac: 00000013 nop +8000b2b0: 00000013 nop +8000b2b4: 00000013 nop +8000b2b8: 00000013 nop +8000b2bc: 00000013 nop +8000b2c0: 00000013 nop +8000b2c4: 00000013 nop +8000b2c8: 00000013 nop +8000b2cc: 00000013 nop +8000b2d0: 00000013 nop +8000b2d4: 00000013 nop +8000b2d8: 00000013 nop +8000b2dc: 00000013 nop +8000b2e0: 00000013 nop +8000b2e4: 00000013 nop +8000b2e8: 00000013 nop +8000b2ec: 00000013 nop +8000b2f0: 00000013 nop +8000b2f4: 00000013 nop +8000b2f8: 00000013 nop +8000b2fc: 00000013 nop +8000b300: 00000013 nop +8000b304: 00000013 nop +8000b308: 00000013 nop +8000b30c: 00000013 nop +8000b310: 00000013 nop +8000b314: 00000013 nop +8000b318: 00000013 nop +8000b31c: 00000013 nop +8000b320: 00000013 nop +8000b324: 00000013 nop +8000b328: 00000013 nop +8000b32c: 00000013 nop +8000b330: 00000013 nop +8000b334: 00000013 nop +8000b338: 00000013 nop +8000b33c: 00000013 nop +8000b340: 00000013 nop +8000b344: 00000013 nop +8000b348: 00000013 nop +8000b34c: 00000013 nop +8000b350: 00000013 nop +8000b354: 00000013 nop +8000b358: 00000013 nop +8000b35c: 00000013 nop +8000b360: 00000013 nop +8000b364: 00000013 nop +8000b368: 00000013 nop +8000b36c: 00000013 nop +8000b370: 00000013 nop +8000b374: 00000013 nop +8000b378: 00000013 nop +8000b37c: 00000013 nop +8000b380: 00000013 nop +8000b384: 00000013 nop +8000b388: 00000013 nop +8000b38c: 00000013 nop +8000b390: 00000013 nop +8000b394: 00000013 nop +8000b398: 00000013 nop +8000b39c: 00000013 nop +8000b3a0: 00000013 nop +8000b3a4: 00000013 nop +8000b3a8: 00000013 nop +8000b3ac: 00000013 nop +8000b3b0: 00000013 nop +8000b3b4: 00000013 nop +8000b3b8: 00000013 nop +8000b3bc: 00000013 nop +8000b3c0: 00000013 nop +8000b3c4: 00000013 nop +8000b3c8: 00000013 nop +8000b3cc: 00000013 nop +8000b3d0: 00000013 nop +8000b3d4: 00000013 nop +8000b3d8: 00000013 nop +8000b3dc: 00000013 nop +8000b3e0: 00000013 nop +8000b3e4: 00000013 nop +8000b3e8: 00000013 nop +8000b3ec: 00000013 nop +8000b3f0: 00000013 nop +8000b3f4: 00000013 nop +8000b3f8: 00000013 nop +8000b3fc: 00000013 nop +8000b400: 00000013 nop +8000b404: 00000013 nop +8000b408: 00000013 nop +8000b40c: 00000013 nop +8000b410: 00000013 nop +8000b414: 00000013 nop +8000b418: 00000013 nop +8000b41c: 00000013 nop +8000b420: 00000013 nop +8000b424: 00000013 nop +8000b428: 00000013 nop +8000b42c: 00000013 nop +8000b430: 00000013 nop +8000b434: 00000013 nop +8000b438: 00000013 nop +8000b43c: 00000013 nop +8000b440: 00000013 nop +8000b444: 00000013 nop +8000b448: 00000013 nop +8000b44c: 00000013 nop +8000b450: 00000013 nop +8000b454: 00000013 nop +8000b458: 00000013 nop +8000b45c: 00000013 nop +8000b460: 00000013 nop +8000b464: 00000013 nop +8000b468: 00000013 nop +8000b46c: 00000013 nop +8000b470: 00000013 nop +8000b474: 00000013 nop +8000b478: 00000013 nop +8000b47c: 00000013 nop +8000b480: 00000013 nop +8000b484: 00000013 nop +8000b488: 00000013 nop +8000b48c: 00000013 nop +8000b490: 00000013 nop +8000b494: 00000013 nop +8000b498: 00000013 nop +8000b49c: 00000013 nop +8000b4a0: 00000013 nop +8000b4a4: 00000013 nop +8000b4a8: 00000013 nop +8000b4ac: 00000013 nop +8000b4b0: 00000013 nop +8000b4b4: 00000013 nop +8000b4b8: 00000013 nop +8000b4bc: 00000013 nop +8000b4c0: 00000013 nop +8000b4c4: 00000013 nop +8000b4c8: 00000013 nop +8000b4cc: 00000013 nop +8000b4d0: 00000013 nop +8000b4d4: 00000013 nop +8000b4d8: 00000013 nop +8000b4dc: 00000013 nop +8000b4e0: 00000013 nop +8000b4e4: 00000013 nop +8000b4e8: 00000013 nop +8000b4ec: 00000013 nop +8000b4f0: 00000013 nop +8000b4f4: 00000013 nop +8000b4f8: 00000013 nop +8000b4fc: 00000013 nop +8000b500: 00000013 nop +8000b504: 00000013 nop +8000b508: 00000013 nop +8000b50c: 00000013 nop +8000b510: 00000013 nop +8000b514: 00000013 nop +8000b518: 00000013 nop +8000b51c: 00000013 nop +8000b520: 00000013 nop +8000b524: 00000013 nop +8000b528: 00000013 nop +8000b52c: 00000013 nop +8000b530: 00000013 nop +8000b534: 00000013 nop +8000b538: 00000013 nop +8000b53c: 00000013 nop +8000b540: 00000013 nop +8000b544: 00000013 nop +8000b548: 00000013 nop +8000b54c: 00000013 nop +8000b550: 00000013 nop +8000b554: 00000013 nop +8000b558: 00000013 nop +8000b55c: 00000013 nop +8000b560: 00000013 nop +8000b564: 00000013 nop +8000b568: 00000013 nop +8000b56c: 00000013 nop +8000b570: 00000013 nop +8000b574: 00000013 nop +8000b578: 00000013 nop +8000b57c: 00000013 nop +8000b580: 00000013 nop +8000b584: 00000013 nop +8000b588: 00000013 nop +8000b58c: 00000013 nop +8000b590: 00000013 nop +8000b594: 00000013 nop +8000b598: 00000013 nop +8000b59c: 00000013 nop +8000b5a0: 00000013 nop +8000b5a4: 00000013 nop +8000b5a8: 00000013 nop +8000b5ac: 00000013 nop +8000b5b0: 00000013 nop +8000b5b4: 00000013 nop +8000b5b8: 00000013 nop +8000b5bc: 00000013 nop +8000b5c0: 00000013 nop +8000b5c4: 00000013 nop +8000b5c8: 00000013 nop +8000b5cc: 00000013 nop +8000b5d0: 00000013 nop +8000b5d4: 00000013 nop +8000b5d8: 00000013 nop +8000b5dc: 00000013 nop +8000b5e0: 00000013 nop +8000b5e4: 00000013 nop +8000b5e8: 00000013 nop +8000b5ec: 00000013 nop +8000b5f0: 00000013 nop +8000b5f4: 00000013 nop +8000b5f8: 00000013 nop +8000b5fc: 00000013 nop +8000b600: 00000013 nop +8000b604: 00000013 nop +8000b608: 00000013 nop +8000b60c: 00000013 nop +8000b610: 00000013 nop +8000b614: 00000013 nop +8000b618: 00000013 nop +8000b61c: 00000013 nop +8000b620: 00000013 nop +8000b624: 00000013 nop +8000b628: 00000013 nop +8000b62c: 00000013 nop +8000b630: 00000013 nop +8000b634: 00000013 nop +8000b638: 00000013 nop +8000b63c: 00000013 nop +8000b640: 00000013 nop +8000b644: 00000013 nop +8000b648: 00000013 nop +8000b64c: 00000013 nop +8000b650: 00000013 nop +8000b654: 00000013 nop +8000b658: 00000013 nop +8000b65c: 00000013 nop +8000b660: 00000013 nop +8000b664: 00000013 nop +8000b668: 00000013 nop +8000b66c: 00000013 nop +8000b670: 00000013 nop +8000b674: 00000013 nop +8000b678: 00000013 nop +8000b67c: 00000013 nop +8000b680: 00000013 nop +8000b684: 00000013 nop +8000b688: 00000013 nop +8000b68c: 00000013 nop +8000b690: 00000013 nop +8000b694: 00000013 nop +8000b698: 00000013 nop +8000b69c: 00000013 nop +8000b6a0: 00000013 nop +8000b6a4: 00000013 nop +8000b6a8: 00000013 nop +8000b6ac: 00000013 nop +8000b6b0: 00000013 nop +8000b6b4: 00000013 nop +8000b6b8: 00000013 nop +8000b6bc: 00000013 nop +8000b6c0: 00000013 nop +8000b6c4: 00000013 nop +8000b6c8: 00000013 nop +8000b6cc: 00000013 nop +8000b6d0: 00000013 nop +8000b6d4: 00000013 nop +8000b6d8: 00000013 nop +8000b6dc: 00000013 nop +8000b6e0: 00000013 nop +8000b6e4: 00000013 nop +8000b6e8: 00000013 nop +8000b6ec: 00000013 nop +8000b6f0: 00000013 nop +8000b6f4: 00000013 nop +8000b6f8: 00000013 nop +8000b6fc: 00000013 nop +8000b700: 00000013 nop +8000b704: 00000013 nop +8000b708: 00000013 nop +8000b70c: 00000013 nop +8000b710: 00000013 nop +8000b714: 00000013 nop +8000b718: 00000013 nop +8000b71c: 00000013 nop +8000b720: 00000013 nop +8000b724: 00000013 nop +8000b728: 00000013 nop +8000b72c: 00000013 nop +8000b730: 00000013 nop +8000b734: 00000013 nop +8000b738: 00000013 nop +8000b73c: 00000013 nop +8000b740: 00000013 nop +8000b744: 00000013 nop +8000b748: 00000013 nop +8000b74c: 00000013 nop +8000b750: 00000013 nop +8000b754: 00000013 nop +8000b758: 00000013 nop +8000b75c: 00000013 nop +8000b760: 00000013 nop +8000b764: 00000013 nop +8000b768: 00000013 nop +8000b76c: 00000013 nop +8000b770: 00000013 nop +8000b774: 00000013 nop +8000b778: 00000013 nop +8000b77c: 00000013 nop +8000b780: 00000013 nop +8000b784: 00000013 nop +8000b788: 00000013 nop +8000b78c: 00000013 nop +8000b790: 00000013 nop +8000b794: 00000013 nop +8000b798: 00000013 nop +8000b79c: 00000013 nop +8000b7a0: 00000013 nop +8000b7a4: 00000013 nop +8000b7a8: 00000013 nop +8000b7ac: 00000013 nop +8000b7b0: 00000013 nop +8000b7b4: 00000013 nop +8000b7b8: 00000013 nop +8000b7bc: 00000013 nop +8000b7c0: 00000013 nop +8000b7c4: 00000013 nop +8000b7c8: 00000013 nop +8000b7cc: 00000013 nop +8000b7d0: 00000013 nop +8000b7d4: 00000013 nop +8000b7d8: 00000013 nop +8000b7dc: 00000013 nop +8000b7e0: 00000013 nop +8000b7e4: 00000013 nop +8000b7e8: 00000013 nop +8000b7ec: 00000013 nop +8000b7f0: 00000013 nop +8000b7f4: 00000013 nop +8000b7f8: 00000013 nop +8000b7fc: 00000013 nop +8000b800: 00000013 nop +8000b804: 00000013 nop +8000b808: 00000013 nop +8000b80c: 00000013 nop +8000b810: 00000013 nop +8000b814: 00000013 nop +8000b818: 00000013 nop +8000b81c: 00000013 nop +8000b820: 00000013 nop +8000b824: 00000013 nop +8000b828: 00000013 nop +8000b82c: 00000013 nop +8000b830: 00000013 nop +8000b834: 00000013 nop +8000b838: 00000013 nop +8000b83c: 00000013 nop +8000b840: 00000013 nop +8000b844: 00000013 nop +8000b848: 00000013 nop +8000b84c: 00000013 nop +8000b850: 00000013 nop +8000b854: 00000013 nop +8000b858: 00000013 nop +8000b85c: 00000013 nop +8000b860: 00000013 nop +8000b864: 00000013 nop +8000b868: 00000013 nop +8000b86c: 00000013 nop +8000b870: 00000013 nop +8000b874: 00000013 nop +8000b878: 00000013 nop +8000b87c: 00000013 nop +8000b880: 00000013 nop +8000b884: 00000013 nop +8000b888: 00000013 nop +8000b88c: 00000013 nop +8000b890: 00000013 nop +8000b894: 00000013 nop +8000b898: 00000013 nop +8000b89c: 00000013 nop +8000b8a0: 00000013 nop +8000b8a4: 00000013 nop +8000b8a8: 00000013 nop +8000b8ac: 00000013 nop +8000b8b0: 00000013 nop +8000b8b4: 00000013 nop +8000b8b8: 00000013 nop +8000b8bc: 00000013 nop +8000b8c0: 00000013 nop +8000b8c4: 00000013 nop +8000b8c8: 00000013 nop +8000b8cc: 00000013 nop +8000b8d0: 00000013 nop +8000b8d4: 00000013 nop +8000b8d8: 00000013 nop +8000b8dc: 00000013 nop +8000b8e0: 00000013 nop +8000b8e4: 00000013 nop +8000b8e8: 00000013 nop +8000b8ec: 00000013 nop +8000b8f0: 00000013 nop +8000b8f4: 00000013 nop +8000b8f8: 00000013 nop +8000b8fc: 00000013 nop +8000b900: 00000013 nop +8000b904: 00000013 nop +8000b908: 00000013 nop +8000b90c: 00000013 nop +8000b910: 00000013 nop +8000b914: 00000013 nop +8000b918: 00000013 nop +8000b91c: 00000013 nop +8000b920: 00000013 nop +8000b924: 00000013 nop +8000b928: 00000013 nop +8000b92c: 00000013 nop +8000b930: 00000013 nop +8000b934: 00000013 nop +8000b938: 00000013 nop +8000b93c: 00000013 nop +8000b940: 00000013 nop +8000b944: 00000013 nop +8000b948: 00000013 nop +8000b94c: 00000013 nop +8000b950: 00000013 nop +8000b954: 00000013 nop +8000b958: 00000013 nop +8000b95c: 00000013 nop +8000b960: 00000013 nop +8000b964: 00000013 nop +8000b968: 00000013 nop +8000b96c: 00000013 nop +8000b970: 00000013 nop +8000b974: 00000013 nop +8000b978: 00000013 nop +8000b97c: 00000013 nop +8000b980: 00000013 nop +8000b984: 00000013 nop +8000b988: 00000013 nop +8000b98c: 00000013 nop +8000b990: 00000013 nop +8000b994: 00000013 nop +8000b998: 00000013 nop +8000b99c: 00000013 nop +8000b9a0: 00000013 nop +8000b9a4: 00000013 nop +8000b9a8: 00000013 nop +8000b9ac: 00000013 nop +8000b9b0: 00000013 nop +8000b9b4: 00000013 nop +8000b9b8: 00000013 nop +8000b9bc: 00000013 nop +8000b9c0: 00000013 nop +8000b9c4: 00000013 nop +8000b9c8: 00000013 nop +8000b9cc: 00000013 nop +8000b9d0: 00000013 nop +8000b9d4: 00000013 nop +8000b9d8: 00000013 nop +8000b9dc: 00000013 nop +8000b9e0: 00000013 nop +8000b9e4: 00000013 nop +8000b9e8: 00000013 nop +8000b9ec: 00000013 nop +8000b9f0: 00000013 nop +8000b9f4: 00000013 nop +8000b9f8: 00000013 nop +8000b9fc: 00000013 nop +8000ba00: 00000013 nop +8000ba04: 00000013 nop +8000ba08: 00000013 nop +8000ba0c: 00000013 nop +8000ba10: 00000013 nop +8000ba14: 00000013 nop +8000ba18: 00000013 nop +8000ba1c: 00000013 nop +8000ba20: 00000013 nop +8000ba24: 00000013 nop +8000ba28: 00000013 nop +8000ba2c: 00000013 nop +8000ba30: 00000013 nop +8000ba34: 00000013 nop +8000ba38: 00000013 nop +8000ba3c: 00000013 nop +8000ba40: 00000013 nop +8000ba44: 00000013 nop +8000ba48: 00000013 nop +8000ba4c: 00000013 nop +8000ba50: 00000013 nop +8000ba54: 00000013 nop +8000ba58: 00000013 nop +8000ba5c: 00000013 nop +8000ba60: 00000013 nop +8000ba64: 00000013 nop +8000ba68: 00000013 nop +8000ba6c: 00000013 nop +8000ba70: 00000013 nop +8000ba74: 00000013 nop +8000ba78: 00000013 nop +8000ba7c: 00000013 nop +8000ba80: 00000013 nop +8000ba84: 00000013 nop +8000ba88: 00000013 nop +8000ba8c: 00000013 nop +8000ba90: 00000013 nop +8000ba94: 00000013 nop +8000ba98: 00000013 nop +8000ba9c: 00000013 nop +8000baa0: 00000013 nop +8000baa4: 00000013 nop +8000baa8: 00000013 nop +8000baac: 00000013 nop +8000bab0: 00000013 nop +8000bab4: 00000013 nop +8000bab8: 00000013 nop +8000babc: 00000013 nop +8000bac0: 00000013 nop +8000bac4: 00000013 nop +8000bac8: 00000013 nop +8000bacc: 00000013 nop +8000bad0: 00000013 nop +8000bad4: 00000013 nop +8000bad8: 00000013 nop +8000badc: 00000013 nop +8000bae0: 00000013 nop +8000bae4: 00000013 nop +8000bae8: 00000013 nop +8000baec: 00000013 nop +8000baf0: 00000013 nop +8000baf4: 00000013 nop +8000baf8: 00000013 nop +8000bafc: 00000013 nop +8000bb00: 00000013 nop +8000bb04: 00000013 nop +8000bb08: 00000013 nop +8000bb0c: 00000013 nop +8000bb10: 00000013 nop +8000bb14: 00000013 nop +8000bb18: 00000013 nop +8000bb1c: 00000013 nop +8000bb20: 00000013 nop +8000bb24: 00000013 nop +8000bb28: 00000013 nop +8000bb2c: 00000013 nop +8000bb30: 00000013 nop +8000bb34: 00000013 nop +8000bb38: 00000013 nop +8000bb3c: 00000013 nop +8000bb40: 00000013 nop +8000bb44: 00000013 nop +8000bb48: 00000013 nop +8000bb4c: 00000013 nop +8000bb50: 00000013 nop +8000bb54: 00000013 nop +8000bb58: 00000013 nop +8000bb5c: 00000013 nop +8000bb60: 00000013 nop +8000bb64: 00000013 nop +8000bb68: 00000013 nop +8000bb6c: 00000013 nop +8000bb70: 00000013 nop +8000bb74: 00000013 nop +8000bb78: 00000013 nop +8000bb7c: 00000013 nop +8000bb80: 00000013 nop +8000bb84: 00000013 nop +8000bb88: 00000013 nop +8000bb8c: 00000013 nop +8000bb90: 00000013 nop +8000bb94: 00000013 nop +8000bb98: 00000013 nop +8000bb9c: 00000013 nop +8000bba0: 00000013 nop +8000bba4: 00000013 nop +8000bba8: 00000013 nop +8000bbac: 00000013 nop +8000bbb0: 00000013 nop +8000bbb4: 00000013 nop +8000bbb8: 00000013 nop +8000bbbc: 00000013 nop +8000bbc0: 00000013 nop +8000bbc4: 00000013 nop +8000bbc8: 00000013 nop +8000bbcc: 00000013 nop +8000bbd0: 00000013 nop +8000bbd4: 00000013 nop +8000bbd8: 00000013 nop +8000bbdc: 00000013 nop +8000bbe0: 00000013 nop +8000bbe4: 00000013 nop +8000bbe8: 00000013 nop +8000bbec: 00000013 nop +8000bbf0: 00000013 nop +8000bbf4: 00000013 nop +8000bbf8: 00000013 nop +8000bbfc: 00000013 nop +8000bc00: 00000013 nop +8000bc04: 00000013 nop +8000bc08: 00000013 nop +8000bc0c: 00000013 nop +8000bc10: 00000013 nop +8000bc14: 00000013 nop +8000bc18: 00000013 nop +8000bc1c: 00000013 nop +8000bc20: 00000013 nop +8000bc24: 00000013 nop +8000bc28: 00000013 nop +8000bc2c: 00000013 nop +8000bc30: 00000013 nop +8000bc34: 00000013 nop +8000bc38: 00000013 nop +8000bc3c: 00000013 nop +8000bc40: 00000013 nop +8000bc44: 00000013 nop +8000bc48: 00000013 nop +8000bc4c: 00000013 nop +8000bc50: 00000013 nop +8000bc54: 00000013 nop +8000bc58: 00000013 nop +8000bc5c: 00000013 nop +8000bc60: 00000013 nop +8000bc64: 00000013 nop +8000bc68: 00000013 nop +8000bc6c: 00000013 nop +8000bc70: 00000013 nop +8000bc74: 00000013 nop +8000bc78: 00000013 nop +8000bc7c: 00000013 nop +8000bc80: 00000013 nop +8000bc84: 00000013 nop +8000bc88: 00000013 nop +8000bc8c: 00000013 nop +8000bc90: 00000013 nop +8000bc94: 00000013 nop +8000bc98: 00000013 nop +8000bc9c: 00000013 nop +8000bca0: 00000013 nop +8000bca4: 00000013 nop +8000bca8: 00000013 nop +8000bcac: 00000013 nop +8000bcb0: 00000013 nop +8000bcb4: 00000013 nop +8000bcb8: 00000013 nop +8000bcbc: 00000013 nop +8000bcc0: 00000013 nop +8000bcc4: 00000013 nop +8000bcc8: 00000013 nop +8000bccc: 00000013 nop +8000bcd0: 00000013 nop +8000bcd4: 00000013 nop +8000bcd8: 00000013 nop +8000bcdc: 00000013 nop +8000bce0: 00000013 nop +8000bce4: 00000013 nop +8000bce8: 00000013 nop +8000bcec: 00000013 nop +8000bcf0: 00000013 nop +8000bcf4: 00000013 nop +8000bcf8: 00000013 nop +8000bcfc: 00000013 nop +8000bd00: 00000013 nop +8000bd04: 00000013 nop +8000bd08: 00000013 nop +8000bd0c: 00000013 nop +8000bd10: 00000013 nop +8000bd14: 00000013 nop +8000bd18: 00000013 nop +8000bd1c: 00000013 nop +8000bd20: 00000013 nop +8000bd24: 00000013 nop +8000bd28: 00000013 nop +8000bd2c: 00000013 nop +8000bd30: 00000013 nop +8000bd34: 00000013 nop +8000bd38: 00000013 nop +8000bd3c: 00000013 nop +8000bd40: 00000013 nop +8000bd44: 00000013 nop +8000bd48: 00000013 nop +8000bd4c: 00000013 nop +8000bd50: 00000013 nop +8000bd54: 00000013 nop +8000bd58: 00000013 nop +8000bd5c: 00000013 nop +8000bd60: 00000013 nop +8000bd64: 00000013 nop +8000bd68: 00000013 nop +8000bd6c: 00000013 nop +8000bd70: 00000013 nop +8000bd74: 00000013 nop +8000bd78: 00000013 nop +8000bd7c: 00000013 nop +8000bd80: 00000013 nop +8000bd84: 00000013 nop +8000bd88: 00000013 nop +8000bd8c: 00000013 nop +8000bd90: 00000013 nop +8000bd94: 00000013 nop +8000bd98: 00000013 nop +8000bd9c: 00000013 nop +8000bda0: 00000013 nop +8000bda4: 00000013 nop +8000bda8: 00000013 nop +8000bdac: 00000013 nop +8000bdb0: 00000013 nop +8000bdb4: 00000013 nop +8000bdb8: 00000013 nop +8000bdbc: 00000013 nop +8000bdc0: 00000013 nop +8000bdc4: 00000013 nop +8000bdc8: 00000013 nop +8000bdcc: 00000013 nop +8000bdd0: 00000013 nop +8000bdd4: 00000013 nop +8000bdd8: 00000013 nop +8000bddc: 00000013 nop +8000bde0: 00000013 nop +8000bde4: 00000013 nop +8000bde8: 00000013 nop +8000bdec: 00000013 nop +8000bdf0: 00000013 nop +8000bdf4: 00000013 nop +8000bdf8: 00000013 nop +8000bdfc: 00000013 nop +8000be00: 00000013 nop +8000be04: 00000013 nop +8000be08: 00000013 nop +8000be0c: 00000013 nop +8000be10: 00000013 nop +8000be14: 00000013 nop +8000be18: 00000013 nop +8000be1c: 00000013 nop +8000be20: 00000013 nop +8000be24: 00000013 nop +8000be28: 00000013 nop +8000be2c: 00000013 nop +8000be30: 00000013 nop +8000be34: 00000013 nop +8000be38: 00000013 nop +8000be3c: 00000013 nop +8000be40: 00000013 nop +8000be44: 00000013 nop +8000be48: 00000013 nop +8000be4c: 00000013 nop +8000be50: 00000013 nop +8000be54: 00000013 nop +8000be58: 00000013 nop +8000be5c: 00000013 nop +8000be60: 00000013 nop +8000be64: 00000013 nop +8000be68: 00000013 nop +8000be6c: 00000013 nop +8000be70: 00000013 nop +8000be74: 00000013 nop +8000be78: 00000013 nop +8000be7c: 00000013 nop +8000be80: 00000013 nop +8000be84: 00000013 nop +8000be88: 00000013 nop +8000be8c: 00000013 nop +8000be90: 00000013 nop +8000be94: 00000013 nop +8000be98: 00000013 nop +8000be9c: 00000013 nop +8000bea0: 00000013 nop +8000bea4: 00000013 nop +8000bea8: 00000013 nop +8000beac: 00000013 nop +8000beb0: 00000013 nop +8000beb4: 00000013 nop +8000beb8: 00000013 nop +8000bebc: 00000013 nop +8000bec0: 00000013 nop +8000bec4: 00000013 nop +8000bec8: 00000013 nop +8000becc: 00000013 nop +8000bed0: 00000013 nop +8000bed4: 00000013 nop +8000bed8: 00000013 nop +8000bedc: 00000013 nop +8000bee0: 00000013 nop +8000bee4: 00000013 nop +8000bee8: 00000013 nop +8000beec: 00000013 nop +8000bef0: 00000013 nop +8000bef4: 00000013 nop +8000bef8: 00000013 nop +8000befc: 00000013 nop +8000bf00: 00000013 nop +8000bf04: 00000013 nop +8000bf08: 00000013 nop +8000bf0c: 00000013 nop +8000bf10: 00000013 nop +8000bf14: 00000013 nop +8000bf18: 00000013 nop +8000bf1c: 00000013 nop +8000bf20: 00000013 nop +8000bf24: 00000013 nop +8000bf28: 00000013 nop +8000bf2c: 00000013 nop +8000bf30: 00000013 nop +8000bf34: 00000013 nop +8000bf38: 00000013 nop +8000bf3c: 00000013 nop +8000bf40: 00000013 nop +8000bf44: 00000013 nop +8000bf48: 00000013 nop +8000bf4c: 00000013 nop +8000bf50: 00000013 nop +8000bf54: 00000013 nop +8000bf58: 00000013 nop +8000bf5c: 00000013 nop +8000bf60: 00000013 nop +8000bf64: 00000013 nop +8000bf68: 00000013 nop +8000bf6c: 00000013 nop +8000bf70: 00000013 nop +8000bf74: 00000013 nop +8000bf78: 00000013 nop +8000bf7c: 00000013 nop +8000bf80: 00000013 nop +8000bf84: 00000013 nop +8000bf88: 00000013 nop +8000bf8c: 00000013 nop +8000bf90: 00000013 nop +8000bf94: 00000013 nop +8000bf98: 00000013 nop +8000bf9c: 00000013 nop +8000bfa0: 00000013 nop +8000bfa4: 00000013 nop +8000bfa8: 00000013 nop +8000bfac: 00000013 nop +8000bfb0: 00000013 nop +8000bfb4: 00000013 nop +8000bfb8: 00000013 nop +8000bfbc: 00000013 nop +8000bfc0: 00000013 nop +8000bfc4: 00000013 nop +8000bfc8: 00000013 nop +8000bfcc: 00000013 nop +8000bfd0: 00000013 nop +8000bfd4: 00000013 nop +8000bfd8: 00000013 nop +8000bfdc: 00000013 nop +8000bfe0: 00000013 nop +8000bfe4: 00000013 nop +8000bfe8: 00000013 nop +8000bfec: 00000013 nop +8000bff0: 00000013 nop +8000bff4: 00000013 nop +8000bff8: 00000013 nop +8000bffc: 00000013 nop + +8000c000 : +8000c000: 73727170 .word 0x73727170 +8000c004: 77767574 .word 0x77767574 +8000c008: 7b7a7978 .word 0x7b7a7978 +8000c00c: 7f7e7d7c .word 0x7f7e7d7c +8000c010: 00000013 nop +8000c014: 00000013 nop +8000c018: 00000013 nop +8000c01c: 00000013 nop +8000c020: 00000013 nop +8000c024: 00000013 nop +8000c028: 00000013 nop +8000c02c: 00000013 nop +8000c030: 00000013 nop +8000c034: 00000013 nop +8000c038: 00000013 nop +8000c03c: 00000013 nop +8000c040: 00000013 nop +8000c044: 00000013 nop +8000c048: 00000013 nop +8000c04c: 00000013 nop +8000c050: 00000013 nop +8000c054: 00000013 nop +8000c058: 00000013 nop +8000c05c: 00000013 nop +8000c060: 00000013 nop +8000c064: 00000013 nop +8000c068: 00000013 nop +8000c06c: 00000013 nop +8000c070: 00000013 nop +8000c074: 00000013 nop +8000c078: 00000013 nop +8000c07c: 00000013 nop +8000c080: 00000013 nop +8000c084: 00000013 nop +8000c088: 00000013 nop +8000c08c: 00000013 nop +8000c090: 00000013 nop +8000c094: 00000013 nop +8000c098: 00000013 nop +8000c09c: 00000013 nop +8000c0a0: 00000013 nop +8000c0a4: 00000013 nop +8000c0a8: 00000013 nop +8000c0ac: 00000013 nop +8000c0b0: 00000013 nop +8000c0b4: 00000013 nop +8000c0b8: 00000013 nop +8000c0bc: 00000013 nop +8000c0c0: 00000013 nop +8000c0c4: 00000013 nop +8000c0c8: 00000013 nop +8000c0cc: 00000013 nop +8000c0d0: 00000013 nop +8000c0d4: 00000013 nop +8000c0d8: 00000013 nop +8000c0dc: 00000013 nop +8000c0e0: 00000013 nop +8000c0e4: 00000013 nop +8000c0e8: 00000013 nop +8000c0ec: 00000013 nop +8000c0f0: 00000013 nop +8000c0f4: 00000013 nop +8000c0f8: 00000013 nop +8000c0fc: 00000013 nop +8000c100: 00000013 nop +8000c104: 00000013 nop +8000c108: 00000013 nop +8000c10c: 00000013 nop +8000c110: 00000013 nop +8000c114: 00000013 nop +8000c118: 00000013 nop +8000c11c: 00000013 nop +8000c120: 00000013 nop +8000c124: 00000013 nop +8000c128: 00000013 nop +8000c12c: 00000013 nop +8000c130: 00000013 nop +8000c134: 00000013 nop +8000c138: 00000013 nop +8000c13c: 00000013 nop +8000c140: 00000013 nop +8000c144: 00000013 nop +8000c148: 00000013 nop +8000c14c: 00000013 nop +8000c150: 00000013 nop +8000c154: 00000013 nop +8000c158: 00000013 nop +8000c15c: 00000013 nop +8000c160: 00000013 nop +8000c164: 00000013 nop +8000c168: 00000013 nop +8000c16c: 00000013 nop +8000c170: 00000013 nop +8000c174: 00000013 nop +8000c178: 00000013 nop +8000c17c: 00000013 nop +8000c180: 00000013 nop +8000c184: 00000013 nop +8000c188: 00000013 nop +8000c18c: 00000013 nop +8000c190: 00000013 nop +8000c194: 00000013 nop +8000c198: 00000013 nop +8000c19c: 00000013 nop +8000c1a0: 00000013 nop +8000c1a4: 00000013 nop +8000c1a8: 00000013 nop +8000c1ac: 00000013 nop +8000c1b0: 00000013 nop +8000c1b4: 00000013 nop +8000c1b8: 00000013 nop +8000c1bc: 00000013 nop +8000c1c0: 00000013 nop +8000c1c4: 00000013 nop +8000c1c8: 00000013 nop +8000c1cc: 00000013 nop +8000c1d0: 00000013 nop +8000c1d4: 00000013 nop +8000c1d8: 00000013 nop +8000c1dc: 00000013 nop +8000c1e0: 00000013 nop +8000c1e4: 00000013 nop +8000c1e8: 00000013 nop +8000c1ec: 00000013 nop +8000c1f0: 00000013 nop +8000c1f4: 00000013 nop +8000c1f8: 00000013 nop +8000c1fc: 00000013 nop +8000c200: 00000013 nop +8000c204: 00000013 nop +8000c208: 00000013 nop +8000c20c: 00000013 nop +8000c210: 00000013 nop +8000c214: 00000013 nop +8000c218: 00000013 nop +8000c21c: 00000013 nop +8000c220: 00000013 nop +8000c224: 00000013 nop +8000c228: 00000013 nop +8000c22c: 00000013 nop +8000c230: 00000013 nop +8000c234: 00000013 nop +8000c238: 00000013 nop +8000c23c: 00000013 nop +8000c240: 00000013 nop +8000c244: 00000013 nop +8000c248: 00000013 nop +8000c24c: 00000013 nop +8000c250: 00000013 nop +8000c254: 00000013 nop +8000c258: 00000013 nop +8000c25c: 00000013 nop +8000c260: 00000013 nop +8000c264: 00000013 nop +8000c268: 00000013 nop +8000c26c: 00000013 nop +8000c270: 00000013 nop +8000c274: 00000013 nop +8000c278: 00000013 nop +8000c27c: 00000013 nop +8000c280: 00000013 nop +8000c284: 00000013 nop +8000c288: 00000013 nop +8000c28c: 00000013 nop +8000c290: 00000013 nop +8000c294: 00000013 nop +8000c298: 00000013 nop +8000c29c: 00000013 nop +8000c2a0: 00000013 nop +8000c2a4: 00000013 nop +8000c2a8: 00000013 nop +8000c2ac: 00000013 nop +8000c2b0: 00000013 nop +8000c2b4: 00000013 nop +8000c2b8: 00000013 nop +8000c2bc: 00000013 nop +8000c2c0: 00000013 nop +8000c2c4: 00000013 nop +8000c2c8: 00000013 nop +8000c2cc: 00000013 nop +8000c2d0: 00000013 nop +8000c2d4: 00000013 nop +8000c2d8: 00000013 nop +8000c2dc: 00000013 nop +8000c2e0: 00000013 nop +8000c2e4: 00000013 nop +8000c2e8: 00000013 nop +8000c2ec: 00000013 nop +8000c2f0: 00000013 nop +8000c2f4: 00000013 nop +8000c2f8: 00000013 nop +8000c2fc: 00000013 nop +8000c300: 00000013 nop +8000c304: 00000013 nop +8000c308: 00000013 nop +8000c30c: 00000013 nop +8000c310: 00000013 nop +8000c314: 00000013 nop +8000c318: 00000013 nop +8000c31c: 00000013 nop +8000c320: 00000013 nop +8000c324: 00000013 nop +8000c328: 00000013 nop +8000c32c: 00000013 nop +8000c330: 00000013 nop +8000c334: 00000013 nop +8000c338: 00000013 nop +8000c33c: 00000013 nop +8000c340: 00000013 nop +8000c344: 00000013 nop +8000c348: 00000013 nop +8000c34c: 00000013 nop +8000c350: 00000013 nop +8000c354: 00000013 nop +8000c358: 00000013 nop +8000c35c: 00000013 nop +8000c360: 00000013 nop +8000c364: 00000013 nop +8000c368: 00000013 nop +8000c36c: 00000013 nop +8000c370: 00000013 nop +8000c374: 00000013 nop +8000c378: 00000013 nop +8000c37c: 00000013 nop +8000c380: 00000013 nop +8000c384: 00000013 nop +8000c388: 00000013 nop +8000c38c: 00000013 nop +8000c390: 00000013 nop +8000c394: 00000013 nop +8000c398: 00000013 nop +8000c39c: 00000013 nop +8000c3a0: 00000013 nop +8000c3a4: 00000013 nop +8000c3a8: 00000013 nop +8000c3ac: 00000013 nop +8000c3b0: 00000013 nop +8000c3b4: 00000013 nop +8000c3b8: 00000013 nop +8000c3bc: 00000013 nop +8000c3c0: 00000013 nop +8000c3c4: 00000013 nop +8000c3c8: 00000013 nop +8000c3cc: 00000013 nop +8000c3d0: 00000013 nop +8000c3d4: 00000013 nop +8000c3d8: 00000013 nop +8000c3dc: 00000013 nop +8000c3e0: 00000013 nop +8000c3e4: 00000013 nop +8000c3e8: 00000013 nop +8000c3ec: 00000013 nop +8000c3f0: 00000013 nop +8000c3f4: 00000013 nop +8000c3f8: 00000013 nop +8000c3fc: 00000013 nop +8000c400: 00000013 nop +8000c404: 00000013 nop +8000c408: 00000013 nop +8000c40c: 00000013 nop +8000c410: 00000013 nop +8000c414: 00000013 nop +8000c418: 00000013 nop +8000c41c: 00000013 nop +8000c420: 00000013 nop +8000c424: 00000013 nop +8000c428: 00000013 nop +8000c42c: 00000013 nop +8000c430: 00000013 nop +8000c434: 00000013 nop +8000c438: 00000013 nop +8000c43c: 00000013 nop +8000c440: 00000013 nop +8000c444: 00000013 nop +8000c448: 00000013 nop +8000c44c: 00000013 nop +8000c450: 00000013 nop +8000c454: 00000013 nop +8000c458: 00000013 nop +8000c45c: 00000013 nop +8000c460: 00000013 nop +8000c464: 00000013 nop +8000c468: 00000013 nop +8000c46c: 00000013 nop +8000c470: 00000013 nop +8000c474: 00000013 nop +8000c478: 00000013 nop +8000c47c: 00000013 nop +8000c480: 00000013 nop +8000c484: 00000013 nop +8000c488: 00000013 nop +8000c48c: 00000013 nop +8000c490: 00000013 nop +8000c494: 00000013 nop +8000c498: 00000013 nop +8000c49c: 00000013 nop +8000c4a0: 00000013 nop +8000c4a4: 00000013 nop +8000c4a8: 00000013 nop +8000c4ac: 00000013 nop +8000c4b0: 00000013 nop +8000c4b4: 00000013 nop +8000c4b8: 00000013 nop +8000c4bc: 00000013 nop +8000c4c0: 00000013 nop +8000c4c4: 00000013 nop +8000c4c8: 00000013 nop +8000c4cc: 00000013 nop +8000c4d0: 00000013 nop +8000c4d4: 00000013 nop +8000c4d8: 00000013 nop +8000c4dc: 00000013 nop +8000c4e0: 00000013 nop +8000c4e4: 00000013 nop +8000c4e8: 00000013 nop +8000c4ec: 00000013 nop +8000c4f0: 00000013 nop +8000c4f4: 00000013 nop +8000c4f8: 00000013 nop +8000c4fc: 00000013 nop +8000c500: 00000013 nop +8000c504: 00000013 nop +8000c508: 00000013 nop +8000c50c: 00000013 nop +8000c510: 00000013 nop +8000c514: 00000013 nop +8000c518: 00000013 nop +8000c51c: 00000013 nop +8000c520: 00000013 nop +8000c524: 00000013 nop +8000c528: 00000013 nop +8000c52c: 00000013 nop +8000c530: 00000013 nop +8000c534: 00000013 nop +8000c538: 00000013 nop +8000c53c: 00000013 nop +8000c540: 00000013 nop +8000c544: 00000013 nop +8000c548: 00000013 nop +8000c54c: 00000013 nop +8000c550: 00000013 nop +8000c554: 00000013 nop +8000c558: 00000013 nop +8000c55c: 00000013 nop +8000c560: 00000013 nop +8000c564: 00000013 nop +8000c568: 00000013 nop +8000c56c: 00000013 nop +8000c570: 00000013 nop +8000c574: 00000013 nop +8000c578: 00000013 nop +8000c57c: 00000013 nop +8000c580: 00000013 nop +8000c584: 00000013 nop +8000c588: 00000013 nop +8000c58c: 00000013 nop +8000c590: 00000013 nop +8000c594: 00000013 nop +8000c598: 00000013 nop +8000c59c: 00000013 nop +8000c5a0: 00000013 nop +8000c5a4: 00000013 nop +8000c5a8: 00000013 nop +8000c5ac: 00000013 nop +8000c5b0: 00000013 nop +8000c5b4: 00000013 nop +8000c5b8: 00000013 nop +8000c5bc: 00000013 nop +8000c5c0: 00000013 nop +8000c5c4: 00000013 nop +8000c5c8: 00000013 nop +8000c5cc: 00000013 nop +8000c5d0: 00000013 nop +8000c5d4: 00000013 nop +8000c5d8: 00000013 nop +8000c5dc: 00000013 nop +8000c5e0: 00000013 nop +8000c5e4: 00000013 nop +8000c5e8: 00000013 nop +8000c5ec: 00000013 nop +8000c5f0: 00000013 nop +8000c5f4: 00000013 nop +8000c5f8: 00000013 nop +8000c5fc: 00000013 nop +8000c600: 00000013 nop +8000c604: 00000013 nop +8000c608: 00000013 nop +8000c60c: 00000013 nop +8000c610: 00000013 nop +8000c614: 00000013 nop +8000c618: 00000013 nop +8000c61c: 00000013 nop +8000c620: 00000013 nop +8000c624: 00000013 nop +8000c628: 00000013 nop +8000c62c: 00000013 nop +8000c630: 00000013 nop +8000c634: 00000013 nop +8000c638: 00000013 nop +8000c63c: 00000013 nop +8000c640: 00000013 nop +8000c644: 00000013 nop +8000c648: 00000013 nop +8000c64c: 00000013 nop +8000c650: 00000013 nop +8000c654: 00000013 nop +8000c658: 00000013 nop +8000c65c: 00000013 nop +8000c660: 00000013 nop +8000c664: 00000013 nop +8000c668: 00000013 nop +8000c66c: 00000013 nop +8000c670: 00000013 nop +8000c674: 00000013 nop +8000c678: 00000013 nop +8000c67c: 00000013 nop +8000c680: 00000013 nop +8000c684: 00000013 nop +8000c688: 00000013 nop +8000c68c: 00000013 nop +8000c690: 00000013 nop +8000c694: 00000013 nop +8000c698: 00000013 nop +8000c69c: 00000013 nop +8000c6a0: 00000013 nop +8000c6a4: 00000013 nop +8000c6a8: 00000013 nop +8000c6ac: 00000013 nop +8000c6b0: 00000013 nop +8000c6b4: 00000013 nop +8000c6b8: 00000013 nop +8000c6bc: 00000013 nop +8000c6c0: 00000013 nop +8000c6c4: 00000013 nop +8000c6c8: 00000013 nop +8000c6cc: 00000013 nop +8000c6d0: 00000013 nop +8000c6d4: 00000013 nop +8000c6d8: 00000013 nop +8000c6dc: 00000013 nop +8000c6e0: 00000013 nop +8000c6e4: 00000013 nop +8000c6e8: 00000013 nop +8000c6ec: 00000013 nop +8000c6f0: 00000013 nop +8000c6f4: 00000013 nop +8000c6f8: 00000013 nop +8000c6fc: 00000013 nop +8000c700: 00000013 nop +8000c704: 00000013 nop +8000c708: 00000013 nop +8000c70c: 00000013 nop +8000c710: 00000013 nop +8000c714: 00000013 nop +8000c718: 00000013 nop +8000c71c: 00000013 nop +8000c720: 00000013 nop +8000c724: 00000013 nop +8000c728: 00000013 nop +8000c72c: 00000013 nop +8000c730: 00000013 nop +8000c734: 00000013 nop +8000c738: 00000013 nop +8000c73c: 00000013 nop +8000c740: 00000013 nop +8000c744: 00000013 nop +8000c748: 00000013 nop +8000c74c: 00000013 nop +8000c750: 00000013 nop +8000c754: 00000013 nop +8000c758: 00000013 nop +8000c75c: 00000013 nop +8000c760: 00000013 nop +8000c764: 00000013 nop +8000c768: 00000013 nop +8000c76c: 00000013 nop +8000c770: 00000013 nop +8000c774: 00000013 nop +8000c778: 00000013 nop +8000c77c: 00000013 nop +8000c780: 00000013 nop +8000c784: 00000013 nop +8000c788: 00000013 nop +8000c78c: 00000013 nop +8000c790: 00000013 nop +8000c794: 00000013 nop +8000c798: 00000013 nop +8000c79c: 00000013 nop +8000c7a0: 00000013 nop +8000c7a4: 00000013 nop +8000c7a8: 00000013 nop +8000c7ac: 00000013 nop +8000c7b0: 00000013 nop +8000c7b4: 00000013 nop +8000c7b8: 00000013 nop +8000c7bc: 00000013 nop +8000c7c0: 00000013 nop +8000c7c4: 00000013 nop +8000c7c8: 00000013 nop +8000c7cc: 00000013 nop +8000c7d0: 00000013 nop +8000c7d4: 00000013 nop +8000c7d8: 00000013 nop +8000c7dc: 00000013 nop +8000c7e0: 00000013 nop +8000c7e4: 00000013 nop +8000c7e8: 00000013 nop +8000c7ec: 00000013 nop +8000c7f0: 00000013 nop +8000c7f4: 00000013 nop +8000c7f8: 00000013 nop +8000c7fc: 00000013 nop +8000c800: 00000013 nop +8000c804: 00000013 nop +8000c808: 00000013 nop +8000c80c: 00000013 nop +8000c810: 00000013 nop +8000c814: 00000013 nop +8000c818: 00000013 nop +8000c81c: 00000013 nop +8000c820: 00000013 nop +8000c824: 00000013 nop +8000c828: 00000013 nop +8000c82c: 00000013 nop +8000c830: 00000013 nop +8000c834: 00000013 nop +8000c838: 00000013 nop +8000c83c: 00000013 nop +8000c840: 00000013 nop +8000c844: 00000013 nop +8000c848: 00000013 nop +8000c84c: 00000013 nop +8000c850: 00000013 nop +8000c854: 00000013 nop +8000c858: 00000013 nop +8000c85c: 00000013 nop +8000c860: 00000013 nop +8000c864: 00000013 nop +8000c868: 00000013 nop +8000c86c: 00000013 nop +8000c870: 00000013 nop +8000c874: 00000013 nop +8000c878: 00000013 nop +8000c87c: 00000013 nop +8000c880: 00000013 nop +8000c884: 00000013 nop +8000c888: 00000013 nop +8000c88c: 00000013 nop +8000c890: 00000013 nop +8000c894: 00000013 nop +8000c898: 00000013 nop +8000c89c: 00000013 nop +8000c8a0: 00000013 nop +8000c8a4: 00000013 nop +8000c8a8: 00000013 nop +8000c8ac: 00000013 nop +8000c8b0: 00000013 nop +8000c8b4: 00000013 nop +8000c8b8: 00000013 nop +8000c8bc: 00000013 nop +8000c8c0: 00000013 nop +8000c8c4: 00000013 nop +8000c8c8: 00000013 nop +8000c8cc: 00000013 nop +8000c8d0: 00000013 nop +8000c8d4: 00000013 nop +8000c8d8: 00000013 nop +8000c8dc: 00000013 nop +8000c8e0: 00000013 nop +8000c8e4: 00000013 nop +8000c8e8: 00000013 nop +8000c8ec: 00000013 nop +8000c8f0: 00000013 nop +8000c8f4: 00000013 nop +8000c8f8: 00000013 nop +8000c8fc: 00000013 nop +8000c900: 00000013 nop +8000c904: 00000013 nop +8000c908: 00000013 nop +8000c90c: 00000013 nop +8000c910: 00000013 nop +8000c914: 00000013 nop +8000c918: 00000013 nop +8000c91c: 00000013 nop +8000c920: 00000013 nop +8000c924: 00000013 nop +8000c928: 00000013 nop +8000c92c: 00000013 nop +8000c930: 00000013 nop +8000c934: 00000013 nop +8000c938: 00000013 nop +8000c93c: 00000013 nop +8000c940: 00000013 nop +8000c944: 00000013 nop +8000c948: 00000013 nop +8000c94c: 00000013 nop +8000c950: 00000013 nop +8000c954: 00000013 nop +8000c958: 00000013 nop +8000c95c: 00000013 nop +8000c960: 00000013 nop +8000c964: 00000013 nop +8000c968: 00000013 nop +8000c96c: 00000013 nop +8000c970: 00000013 nop +8000c974: 00000013 nop +8000c978: 00000013 nop +8000c97c: 00000013 nop +8000c980: 00000013 nop +8000c984: 00000013 nop +8000c988: 00000013 nop +8000c98c: 00000013 nop +8000c990: 00000013 nop +8000c994: 00000013 nop +8000c998: 00000013 nop +8000c99c: 00000013 nop +8000c9a0: 00000013 nop +8000c9a4: 00000013 nop +8000c9a8: 00000013 nop +8000c9ac: 00000013 nop +8000c9b0: 00000013 nop +8000c9b4: 00000013 nop +8000c9b8: 00000013 nop +8000c9bc: 00000013 nop +8000c9c0: 00000013 nop +8000c9c4: 00000013 nop +8000c9c8: 00000013 nop +8000c9cc: 00000013 nop +8000c9d0: 00000013 nop +8000c9d4: 00000013 nop +8000c9d8: 00000013 nop +8000c9dc: 00000013 nop +8000c9e0: 00000013 nop +8000c9e4: 00000013 nop +8000c9e8: 00000013 nop +8000c9ec: 00000013 nop +8000c9f0: 00000013 nop +8000c9f4: 00000013 nop +8000c9f8: 00000013 nop +8000c9fc: 00000013 nop +8000ca00: 00000013 nop +8000ca04: 00000013 nop +8000ca08: 00000013 nop +8000ca0c: 00000013 nop +8000ca10: 00000013 nop +8000ca14: 00000013 nop +8000ca18: 00000013 nop +8000ca1c: 00000013 nop +8000ca20: 00000013 nop +8000ca24: 00000013 nop +8000ca28: 00000013 nop +8000ca2c: 00000013 nop +8000ca30: 00000013 nop +8000ca34: 00000013 nop +8000ca38: 00000013 nop +8000ca3c: 00000013 nop +8000ca40: 00000013 nop +8000ca44: 00000013 nop +8000ca48: 00000013 nop +8000ca4c: 00000013 nop +8000ca50: 00000013 nop +8000ca54: 00000013 nop +8000ca58: 00000013 nop +8000ca5c: 00000013 nop +8000ca60: 00000013 nop +8000ca64: 00000013 nop +8000ca68: 00000013 nop +8000ca6c: 00000013 nop +8000ca70: 00000013 nop +8000ca74: 00000013 nop +8000ca78: 00000013 nop +8000ca7c: 00000013 nop +8000ca80: 00000013 nop +8000ca84: 00000013 nop +8000ca88: 00000013 nop +8000ca8c: 00000013 nop +8000ca90: 00000013 nop +8000ca94: 00000013 nop +8000ca98: 00000013 nop +8000ca9c: 00000013 nop +8000caa0: 00000013 nop +8000caa4: 00000013 nop +8000caa8: 00000013 nop +8000caac: 00000013 nop +8000cab0: 00000013 nop +8000cab4: 00000013 nop +8000cab8: 00000013 nop +8000cabc: 00000013 nop +8000cac0: 00000013 nop +8000cac4: 00000013 nop +8000cac8: 00000013 nop +8000cacc: 00000013 nop +8000cad0: 00000013 nop +8000cad4: 00000013 nop +8000cad8: 00000013 nop +8000cadc: 00000013 nop +8000cae0: 00000013 nop +8000cae4: 00000013 nop +8000cae8: 00000013 nop +8000caec: 00000013 nop +8000caf0: 00000013 nop +8000caf4: 00000013 nop +8000caf8: 00000013 nop +8000cafc: 00000013 nop +8000cb00: 00000013 nop +8000cb04: 00000013 nop +8000cb08: 00000013 nop +8000cb0c: 00000013 nop +8000cb10: 00000013 nop +8000cb14: 00000013 nop +8000cb18: 00000013 nop +8000cb1c: 00000013 nop +8000cb20: 00000013 nop +8000cb24: 00000013 nop +8000cb28: 00000013 nop +8000cb2c: 00000013 nop +8000cb30: 00000013 nop +8000cb34: 00000013 nop +8000cb38: 00000013 nop +8000cb3c: 00000013 nop +8000cb40: 00000013 nop +8000cb44: 00000013 nop +8000cb48: 00000013 nop +8000cb4c: 00000013 nop +8000cb50: 00000013 nop +8000cb54: 00000013 nop +8000cb58: 00000013 nop +8000cb5c: 00000013 nop +8000cb60: 00000013 nop +8000cb64: 00000013 nop +8000cb68: 00000013 nop +8000cb6c: 00000013 nop +8000cb70: 00000013 nop +8000cb74: 00000013 nop +8000cb78: 00000013 nop +8000cb7c: 00000013 nop +8000cb80: 00000013 nop +8000cb84: 00000013 nop +8000cb88: 00000013 nop +8000cb8c: 00000013 nop +8000cb90: 00000013 nop +8000cb94: 00000013 nop +8000cb98: 00000013 nop +8000cb9c: 00000013 nop +8000cba0: 00000013 nop +8000cba4: 00000013 nop +8000cba8: 00000013 nop +8000cbac: 00000013 nop +8000cbb0: 00000013 nop +8000cbb4: 00000013 nop +8000cbb8: 00000013 nop +8000cbbc: 00000013 nop +8000cbc0: 00000013 nop +8000cbc4: 00000013 nop +8000cbc8: 00000013 nop +8000cbcc: 00000013 nop +8000cbd0: 00000013 nop +8000cbd4: 00000013 nop +8000cbd8: 00000013 nop +8000cbdc: 00000013 nop +8000cbe0: 00000013 nop +8000cbe4: 00000013 nop +8000cbe8: 00000013 nop +8000cbec: 00000013 nop +8000cbf0: 00000013 nop +8000cbf4: 00000013 nop +8000cbf8: 00000013 nop +8000cbfc: 00000013 nop +8000cc00: 00000013 nop +8000cc04: 00000013 nop +8000cc08: 00000013 nop +8000cc0c: 00000013 nop +8000cc10: 00000013 nop +8000cc14: 00000013 nop +8000cc18: 00000013 nop +8000cc1c: 00000013 nop +8000cc20: 00000013 nop +8000cc24: 00000013 nop +8000cc28: 00000013 nop +8000cc2c: 00000013 nop +8000cc30: 00000013 nop +8000cc34: 00000013 nop +8000cc38: 00000013 nop +8000cc3c: 00000013 nop +8000cc40: 00000013 nop +8000cc44: 00000013 nop +8000cc48: 00000013 nop +8000cc4c: 00000013 nop +8000cc50: 00000013 nop +8000cc54: 00000013 nop +8000cc58: 00000013 nop +8000cc5c: 00000013 nop +8000cc60: 00000013 nop +8000cc64: 00000013 nop +8000cc68: 00000013 nop +8000cc6c: 00000013 nop +8000cc70: 00000013 nop +8000cc74: 00000013 nop +8000cc78: 00000013 nop +8000cc7c: 00000013 nop +8000cc80: 00000013 nop +8000cc84: 00000013 nop +8000cc88: 00000013 nop +8000cc8c: 00000013 nop +8000cc90: 00000013 nop +8000cc94: 00000013 nop +8000cc98: 00000013 nop +8000cc9c: 00000013 nop +8000cca0: 00000013 nop +8000cca4: 00000013 nop +8000cca8: 00000013 nop +8000ccac: 00000013 nop +8000ccb0: 00000013 nop +8000ccb4: 00000013 nop +8000ccb8: 00000013 nop +8000ccbc: 00000013 nop +8000ccc0: 00000013 nop +8000ccc4: 00000013 nop +8000ccc8: 00000013 nop +8000cccc: 00000013 nop +8000ccd0: 00000013 nop +8000ccd4: 00000013 nop +8000ccd8: 00000013 nop +8000ccdc: 00000013 nop +8000cce0: 00000013 nop +8000cce4: 00000013 nop +8000cce8: 00000013 nop +8000ccec: 00000013 nop +8000ccf0: 00000013 nop +8000ccf4: 00000013 nop +8000ccf8: 00000013 nop +8000ccfc: 00000013 nop +8000cd00: 00000013 nop +8000cd04: 00000013 nop +8000cd08: 00000013 nop +8000cd0c: 00000013 nop +8000cd10: 00000013 nop +8000cd14: 00000013 nop +8000cd18: 00000013 nop +8000cd1c: 00000013 nop +8000cd20: 00000013 nop +8000cd24: 00000013 nop +8000cd28: 00000013 nop +8000cd2c: 00000013 nop +8000cd30: 00000013 nop +8000cd34: 00000013 nop +8000cd38: 00000013 nop +8000cd3c: 00000013 nop +8000cd40: 00000013 nop +8000cd44: 00000013 nop +8000cd48: 00000013 nop +8000cd4c: 00000013 nop +8000cd50: 00000013 nop +8000cd54: 00000013 nop +8000cd58: 00000013 nop +8000cd5c: 00000013 nop +8000cd60: 00000013 nop +8000cd64: 00000013 nop +8000cd68: 00000013 nop +8000cd6c: 00000013 nop +8000cd70: 00000013 nop +8000cd74: 00000013 nop +8000cd78: 00000013 nop +8000cd7c: 00000013 nop +8000cd80: 00000013 nop +8000cd84: 00000013 nop +8000cd88: 00000013 nop +8000cd8c: 00000013 nop +8000cd90: 00000013 nop +8000cd94: 00000013 nop +8000cd98: 00000013 nop +8000cd9c: 00000013 nop +8000cda0: 00000013 nop +8000cda4: 00000013 nop +8000cda8: 00000013 nop +8000cdac: 00000013 nop +8000cdb0: 00000013 nop +8000cdb4: 00000013 nop +8000cdb8: 00000013 nop +8000cdbc: 00000013 nop +8000cdc0: 00000013 nop +8000cdc4: 00000013 nop +8000cdc8: 00000013 nop +8000cdcc: 00000013 nop +8000cdd0: 00000013 nop +8000cdd4: 00000013 nop +8000cdd8: 00000013 nop +8000cddc: 00000013 nop +8000cde0: 00000013 nop +8000cde4: 00000013 nop +8000cde8: 00000013 nop +8000cdec: 00000013 nop +8000cdf0: 00000013 nop +8000cdf4: 00000013 nop +8000cdf8: 00000013 nop +8000cdfc: 00000013 nop +8000ce00: 00000013 nop +8000ce04: 00000013 nop +8000ce08: 00000013 nop +8000ce0c: 00000013 nop +8000ce10: 00000013 nop +8000ce14: 00000013 nop +8000ce18: 00000013 nop +8000ce1c: 00000013 nop +8000ce20: 00000013 nop +8000ce24: 00000013 nop +8000ce28: 00000013 nop +8000ce2c: 00000013 nop +8000ce30: 00000013 nop +8000ce34: 00000013 nop +8000ce38: 00000013 nop +8000ce3c: 00000013 nop +8000ce40: 00000013 nop +8000ce44: 00000013 nop +8000ce48: 00000013 nop +8000ce4c: 00000013 nop +8000ce50: 00000013 nop +8000ce54: 00000013 nop +8000ce58: 00000013 nop +8000ce5c: 00000013 nop +8000ce60: 00000013 nop +8000ce64: 00000013 nop +8000ce68: 00000013 nop +8000ce6c: 00000013 nop +8000ce70: 00000013 nop +8000ce74: 00000013 nop +8000ce78: 00000013 nop +8000ce7c: 00000013 nop +8000ce80: 00000013 nop +8000ce84: 00000013 nop +8000ce88: 00000013 nop +8000ce8c: 00000013 nop +8000ce90: 00000013 nop +8000ce94: 00000013 nop +8000ce98: 00000013 nop +8000ce9c: 00000013 nop +8000cea0: 00000013 nop +8000cea4: 00000013 nop +8000cea8: 00000013 nop +8000ceac: 00000013 nop +8000ceb0: 00000013 nop +8000ceb4: 00000013 nop +8000ceb8: 00000013 nop +8000cebc: 00000013 nop +8000cec0: 00000013 nop +8000cec4: 00000013 nop +8000cec8: 00000013 nop +8000cecc: 00000013 nop +8000ced0: 00000013 nop +8000ced4: 00000013 nop +8000ced8: 00000013 nop +8000cedc: 00000013 nop +8000cee0: 00000013 nop +8000cee4: 00000013 nop +8000cee8: 00000013 nop +8000ceec: 00000013 nop +8000cef0: 00000013 nop +8000cef4: 00000013 nop +8000cef8: 00000013 nop +8000cefc: 00000013 nop +8000cf00: 00000013 nop +8000cf04: 00000013 nop +8000cf08: 00000013 nop +8000cf0c: 00000013 nop +8000cf10: 00000013 nop +8000cf14: 00000013 nop +8000cf18: 00000013 nop +8000cf1c: 00000013 nop +8000cf20: 00000013 nop +8000cf24: 00000013 nop +8000cf28: 00000013 nop +8000cf2c: 00000013 nop +8000cf30: 00000013 nop +8000cf34: 00000013 nop +8000cf38: 00000013 nop +8000cf3c: 00000013 nop +8000cf40: 00000013 nop +8000cf44: 00000013 nop +8000cf48: 00000013 nop +8000cf4c: 00000013 nop +8000cf50: 00000013 nop +8000cf54: 00000013 nop +8000cf58: 00000013 nop +8000cf5c: 00000013 nop +8000cf60: 00000013 nop +8000cf64: 00000013 nop +8000cf68: 00000013 nop +8000cf6c: 00000013 nop +8000cf70: 00000013 nop +8000cf74: 00000013 nop +8000cf78: 00000013 nop +8000cf7c: 00000013 nop +8000cf80: 00000013 nop +8000cf84: 00000013 nop +8000cf88: 00000013 nop +8000cf8c: 00000013 nop +8000cf90: 00000013 nop +8000cf94: 00000013 nop +8000cf98: 00000013 nop +8000cf9c: 00000013 nop +8000cfa0: 00000013 nop +8000cfa4: 00000013 nop +8000cfa8: 00000013 nop +8000cfac: 00000013 nop +8000cfb0: 00000013 nop +8000cfb4: 00000013 nop +8000cfb8: 00000013 nop +8000cfbc: 00000013 nop +8000cfc0: 00000013 nop +8000cfc4: 00000013 nop +8000cfc8: 00000013 nop +8000cfcc: 00000013 nop +8000cfd0: 00000013 nop +8000cfd4: 00000013 nop +8000cfd8: 00000013 nop +8000cfdc: 00000013 nop +8000cfe0: 00000013 nop +8000cfe4: 00000013 nop +8000cfe8: 00000013 nop +8000cfec: 00000013 nop +8000cff0: 00000013 nop +8000cff4: 00000013 nop +8000cff8: 00000013 nop +8000cffc: 00000013 nop + +8000d000 : +8000d000: 03300e13 li t3,51 +8000d004: 900110b7 lui ra,0x90011 +8000d008: 00808093 addi ra,ra,8 # 90011008 +8000d00c: 5b5a6137 lui sp,0x5b5a6 +8000d010: 95810113 addi sp,sp,-1704 # 5b5a5958 <_start-0x24a5a6a8> +8000d014: 0000a083 lw ra,0(ra) +8000d018: 00208463 beq ra,sp,8000d020 +8000d01c: ca4f306f j 800004c0 +8000d020: a000a0b7 lui ra,0xa000a +8000d024: 32408093 addi ra,ra,804 # a000a324 +8000d028: aaee0137 lui sp,0xaaee0 +8000d02c: 00810113 addi sp,sp,8 # aaee0008 +8000d030: 0020a023 sw sp,0(ra) +8000d034: 0000a083 lw ra,0(ra) +8000d038: 00208463 beq ra,sp,8000d040 +8000d03c: c84f306f j 800004c0 + +8000d040 : +8000d040: 03400e13 li t3,52 +8000d044: 00000097 auipc ra,0x0 +8000d048: 01808093 addi ra,ra,24 # 8000d05c +8000d04c: 90012137 lui sp,0x90012 +8000d050: 01010113 addi sp,sp,16 # 90012010 +8000d054: 00010067 jr sp +8000d058: c68f306f j 800004c0 + +8000d05c : +8000d05c: 03500e13 li t3,53 +8000d060: 00100e93 li t4,1 +8000d064: 00000f17 auipc t5,0x0 +8000d068: 018f0f13 addi t5,t5,24 # 8000d07c +8000d06c: 900140b7 lui ra,0x90014 +8000d070: 39008093 addi ra,ra,912 # 90014390 +8000d074: 00008067 ret +8000d078: c48f306f j 800004c0 + +8000d07c : +8000d07c: 03600e13 li t3,54 +8000d080: 00100e93 li t4,1 +8000d084: 00000f17 auipc t5,0x0 +8000d088: 018f0f13 addi t5,t5,24 # 8000d09c +8000d08c: 900140b7 lui ra,0x90014 +8000d090: 39408093 addi ra,ra,916 # 90014394 +8000d094: 0000a083 lw ra,0(ra) +8000d098: c28f306f j 800004c0 + +8000d09c : +8000d09c: 03700e13 li t3,55 +8000d0a0: 00100e93 li t4,1 +8000d0a4: 00000f17 auipc t5,0x0 +8000d0a8: 018f0f13 addi t5,t5,24 # 8000d0bc +8000d0ac: 900140b7 lui ra,0x90014 +8000d0b0: 39808093 addi ra,ra,920 # 90014398 +8000d0b4: 0010a023 sw ra,0(ra) +8000d0b8: c08f306f j 800004c0 + +8000d0bc : +8000d0bc: 00200e93 li t4,2 +8000d0c0: 00000073 ecall + ... diff --git a/src/test/scala/vexriscv/TestIndividualFeatures.scala b/src/test/scala/vexriscv/TestIndividualFeatures.scala index 281570b7..fc87ce28 100644 --- a/src/test/scala/vexriscv/TestIndividualFeatures.scala +++ b/src/test/scala/vexriscv/TestIndividualFeatures.scala @@ -554,7 +554,7 @@ class CsrDimension(freertos : String, zephyr : String, linux : String) extends V if(supervisor){ new VexRiscvPosition("Supervisor") with CatchAllPosition{ override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new CsrPlugin(CsrPluginConfig.linuxFull(0x80000020l)) - override def testParam = s"FREERTOS=$freertos ZEPHYR=$zephyr LINUX_REGRESSION=$linux SUPERVISOR=yes" + override def testParam = s"FREERTOS=$freertos ZEPHYR=$zephyr LINUX_REGRESSION=$linux SUPERVISOR=yes CSR=yes" } } else if(pmp){ new VexRiscvPosition("Secure") with CatchAllPosition{ From a40d5f19b27a1cfa45a231637727fba2394c63aa Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 23 Feb 2023 12:00:08 +0100 Subject: [PATCH 844/951] Fix MMU A and D flag handeling --- .../scala/vexriscv/plugin/MmuPlugin.scala | 4 +- src/test/cpp/raw/mmu/src/crt.S | 156 +- src/test/cpp/regression/main.cpp | 18 +- src/test/resources/asm/mmu.asm | 58 +- src/test/resources/hex/mmu.hex | 8284 +++++++---------- 5 files changed, 3612 insertions(+), 4908 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/MmuPlugin.scala b/src/main/scala/vexriscv/plugin/MmuPlugin.scala index c984b035..aea906f6 100644 --- a/src/main/scala/vexriscv/plugin/MmuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/MmuPlugin.scala @@ -281,11 +281,11 @@ class MmuPlugin(ioRange : UInt => Bool, when(port.entryToReplace === lineId){ val superPage = state === State.L1_RSP line.valid := True - line.exception := dBusRsp.exception || (superPage && dBusRsp.pte.PPN0 =/= 0) + line.exception := dBusRsp.exception || (superPage && dBusRsp.pte.PPN0 =/= 0) || !dBusRsp.pte.A line.virtualAddress := vpn line.physicalAddress := Vec(dBusRsp.pte.PPN0, dBusRsp.pte.PPN1(9 downto 0)) line.allowRead := dBusRsp.pte.R - line.allowWrite := dBusRsp.pte.W + line.allowWrite := dBusRsp.pte.W && dBusRsp.pte.D line.allowExecute := dBusRsp.pte.X line.allowUser := dBusRsp.pte.U line.superPage := state === State.L1_RSP diff --git a/src/test/cpp/raw/mmu/src/crt.S b/src/test/cpp/raw/mmu/src/crt.S index 2f85bbe4..d98b7ccc 100644 --- a/src/test/cpp/raw/mmu/src/crt.S +++ b/src/test/cpp/raw/mmu/src/crt.S @@ -53,13 +53,13 @@ test5: //setup MMU la x1, MMU_TABLE_0 + 0x800 la x2, MMU_TABLE_1 srli x2, x2, 2 - ori x2, x2, 0x11 + ori x2, x2, 0x1 sw x2, 0(x1) la x1, MMU_TABLE_1 + 0x000*4 li x2, 0x80000000 srli x2, x2, 2 - ori x2, x2, 0x0F + ori x2, x2, 0x0F | 0xC0 sw x2, 0(x1) @@ -67,50 +67,50 @@ test5: //setup MMU la x1, MMU_TABLE_0 + 0x900 la x2, MMU_TABLE_2 srli x2, x2, 2 - ori x2, x2, 0x11 + ori x2, x2, 0x01 sw x2, 0(x1) la x1, MMU_TABLE_2 + 0x00A*4 la x2, ROM_4 srli x2, x2, 2 - ori x2, x2, 0x1F + ori x2, x2, 0x1F | 0xC0 sw x2, 0(x1) la x1, MMU_TABLE_2 + 0x010*4 // Read Only la x2, ROM_5 srli x2, x2, 2 - ori x2, x2, 0x11 + (0x1 << 1) + ori x2, x2, 0x11 + (0x1 << 1) | 0xC0 sw x2, 0(x1) la x1, MMU_TABLE_2 + 0x011*4 // Read Write la x2, ROM_5 srli x2, x2, 2 - ori x2, x2, 0x11 + (0x3 << 1) + ori x2, x2, 0x11 + (0x3 << 1) | 0xC0 sw x2, 0(x1) la x1, MMU_TABLE_2 + 0x012*4 // Execute only la x2, ROM_5 srli x2, x2, 2 - ori x2, x2, 0x11 + (0x4 << 1) + ori x2, x2, 0x11 + (0x4 << 1) | 0xC0 sw x2, 0(x1) la x1, MMU_TABLE_2 + 0x013*4 //Read Execute la x2, ROM_5 srli x2, x2, 2 - ori x2, x2, 0x11 + (0x5 << 1) + ori x2, x2, 0x11 + (0x5 << 1) | 0xC0 sw x2, 0(x1) la x1, MMU_TABLE_2 + 0x014*4 //no user la x2, ROM_5 srli x2, x2, 2 - ori x2, x2, 0x01 + (0x7 << 1) + ori x2, x2, 0x01 + (0x7 << 1) | 0xC0 sw x2, 0(x1) li TEST_ID, 5 la x1, MMU_TABLE_0 + 0xA00 la x2, ROM_SUPER_0 srli x2, x2, 2 - ori x2, x2, 0x1F + ori x2, x2, 0x1F | 0xC0 sw x2, 0(x1) li TEST_ID, 5 @@ -124,7 +124,9 @@ test5: //setup MMU srli x1, x1, 12 li x2, 0x80000000 or x1, x1, x2 + sfence.vma csrw satp, x1 + fence.i test6: //read through MMU @@ -254,8 +256,8 @@ test17: //Test limited write access test18: //Test limited execute access li TEST_ID, 18 - - la x1, test18_end + li TRAP_OK, 1 + la TRAP_RET, test18_end li x2, 0x90012010 jr x2 j fail @@ -305,7 +307,6 @@ test21: //supervisor accessing not user bne x1, x2, fail - li x1, 1 << 18 //clear SUM csrc sstatus, x1 li TRAP_OK, 1 @@ -320,6 +321,7 @@ test21_pass: + test50: //User mode setup li TEST_ID, 50 li TRAP_OK, 0 @@ -331,10 +333,10 @@ test50: //User mode setup //remap code tlb into userspace csrr x10, satp csrw satp, x0 - la x1, MMU_TABLE_1 + 0x000*4 - li x2, 0x80000000 + la x1, MMU_TABLE_1 + 0x00D*4 //test51 + li x2, 0x8000D000 srli x2, x2, 2 - ori x2, x2, 0x1F + ori x2, x2, 0x1F | 0x40 sw x2, 0(x1) csrw satp, x10 @@ -347,83 +349,32 @@ test50: //User mode setup sret j fail -test51: //user read/write - li TEST_ID, 51 - li x1, 0x90011008 - li x2, 0x5B5A5958 - lw x1, 0(x1) - bne x1, x2, fail - - li x1, 0xA000A324 - li x2, 0xAAEE0008 - sw x2, 0(x1) - lw x1, 0(x1) - bne x1, x2, fail - -test52: //user fetch - li TEST_ID, 52 - la x1, test53 - li x2, 0x90012010 - jr x2 - j fail - -test53: // user fetch page fault - li TEST_ID, 53 - li TRAP_OK, 1 - la TRAP_RET, test54 - li x1, 0x90014390 - jr x1 - j fail - -test54: //user load page fault - li TEST_ID, 54 - li TRAP_OK, 1 - la TRAP_RET, test55 - li x1, 0x90014394 - lw x1, 0(x1) - j fail - -test55: //user store page fault - li TEST_ID, 55 - li TRAP_OK, 1 - la TRAP_RET, test56 - li x1, 0x90014398 - sw x1, 0(x1) - j fail - -test56: - - - - - - - - j pass fail: //TEST_ID => error code li TRAP_OK, 0 + la TRAP_RET, failFence ecall failFence: li x2, 0xF00FFF24 sw TEST_ID, 0(x2) pass: - li TRAP_OK, 2 + li TRAP_OK, 1 + la TRAP_RET, passFence ecall passFence: li x2, 0xF00FFF20 sw x0, 0(x2) - +.align 4 trap: - beq TRAP_OK, x0, failFence + beq TRAP_OK, x0, fail csrr x1, mcause csrr x1, mepc csrr x1, mstatus csrr x1, mbadaddr li x1, 2 - beq TRAP_OK, x1, passFence + beq TRAP_OK, x1, pass csrw mepc, TRAP_RET mret @@ -435,6 +386,7 @@ trap: nop nop + .align 12 MMU_TABLE_0: .word 0 @@ -508,19 +460,53 @@ ROM_7: .word 0x7B7A7978 .word 0x7F7E7D7C -/* -.align 22 -ROM_SUPER_0: -.word 0x83828180 -.word 0x87868584 -.word 0x8B8A8988 -.word 0x8F8E8D8C .align 12 -ROM_SUPER_1: -.word 0x93929190 -.word 0x97969594 -.word 0x9B9A9998 -.word 0x9F9E9D9C*/ +test51: //user read/write + li TEST_ID, 51 + li x1, 0x90011008 + li x2, 0x5B5A5958 + lw x1, 0(x1) + bne x1, x2, fail + li x1, 0xA000A324 + li x2, 0xAAEE0008 + sw x2, 0(x1) + lw x1, 0(x1) + bne x1, x2, fail +test52: //user fetch + li TEST_ID, 52 + la x1, test53 + li x2, 0x90012010 + jr x2 + j fail + +test53: // user fetch page fault + li TEST_ID, 53 + li TRAP_OK, 1 + la TRAP_RET, test54 + li x1, 0x90014390 + jr x1 + j fail + +test54: //user load page fault + li TEST_ID, 54 + li TRAP_OK, 1 + la TRAP_RET, test55 + li x1, 0x90014394 + lw x1, 0(x1) + j fail + +test55: //user store page fault + li TEST_ID, 55 + li TRAP_OK, 1 + la TRAP_RET, test56 + li x1, 0x90014398 + sw x1, 0(x1) + j fail + +test56: + + li TRAP_OK, 2 + ecall diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 67dff411..c482adcc 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -407,7 +407,10 @@ public: uint32_t w : 1; uint32_t x : 1; uint32_t u : 1; - uint32_t _dummy : 5; + uint32_t g : 1; + uint32_t a : 1; + uint32_t d : 1; + uint32_t _dummy : 2; uint32_t ppn : 22; }; struct __attribute__((packed)){ @@ -505,9 +508,9 @@ public: } if(!tlb.u && effectivePrivilege == 0) return true; if( tlb.u && effectivePrivilege == 1 && !status.sum) return true; - if(superPage && tlb.ppn0 != 0) return true; + if(superPage && tlb.ppn0 != 0 || !tlb.a) return true; if(kind == READ || kind == READ_WRITE) if(!tlb.r && !(status.mxr && tlb.x)) return true; - if(kind == WRITE || kind == READ_WRITE) if(!tlb.w) return true; + if(kind == WRITE || kind == READ_WRITE) if(!tlb.w || !tlb.d) return true; if(kind == EXECUTE) if(!tlb.x) return true; *p = (tlb.ppn1 << 22) | (superPage ? v & 0x3FF000 : tlb.ppn0 << 12) | (v & 0xFFF); @@ -628,6 +631,9 @@ public: default: return true; break; } +// if(csr == MSTATUS || csr == SSTATUS){ +// printf("READ %x %x\n", pc, *value); +// } return false; } @@ -644,6 +650,9 @@ public: virtual bool csrWrite(int32_t csr, uint32_t value){ if(((csr >> 8) & 0x3) > privilege) return true; +// if(csr == MSTATUS || csr == SSTATUS){ +// printf("MIAOU %x %x\n", pc, value); +// } switch(csr){ case MSTATUS: status.raw = value & 0x7FFFFFFF; break; case MIP: ipSoft = value; break; @@ -675,6 +684,9 @@ public: default: ilegalInstruction(); return true; break; } +// if(csr == MSTATUS || csr == SSTATUS){ +// printf(" %x %x\n", pc, status.raw); +// } return false; } diff --git a/src/test/resources/asm/mmu.asm b/src/test/resources/asm/mmu.asm index e9dc2424..b39cf209 100644 --- a/src/test/resources/asm/mmu.asm +++ b/src/test/resources/asm/mmu.asm @@ -7,7 +7,7 @@ Disassembly of section .crt_section: 80000000 <_start>: 80000000: 00000e93 li t4,0 80000004: 00000097 auipc ra,0x0 -80000008: 4ec08093 addi ra,ra,1260 # 800004f0 +80000008: 4fc08093 addi ra,ra,1276 # 80000500 8000000c: 30509073 csrw mtvec,ra 80000010 : @@ -360,38 +360,38 @@ Disassembly of section .crt_section: 800004c0 : 800004c0: 00000e93 li t4,0 -800004c4: 00000073 ecall +800004c4: 00000f17 auipc t5,0x0 +800004c8: 00cf0f13 addi t5,t5,12 # 800004d0 +800004cc: 00000073 ecall -800004c8 : -800004c8: f0100137 lui sp,0xf0100 -800004cc: f2410113 addi sp,sp,-220 # f00fff24 -800004d0: 01c12023 sw t3,0(sp) +800004d0 : +800004d0: f0100137 lui sp,0xf0100 +800004d4: f2410113 addi sp,sp,-220 # f00fff24 +800004d8: 01c12023 sw t3,0(sp) -800004d4 : -800004d4: 00200e93 li t4,2 -800004d8: 00000073 ecall +800004dc : +800004dc: 00100e93 li t4,1 +800004e0: 00000f17 auipc t5,0x0 +800004e4: 00cf0f13 addi t5,t5,12 # 800004ec +800004e8: 00000073 ecall -800004dc : -800004dc: f0100137 lui sp,0xf0100 -800004e0: f2010113 addi sp,sp,-224 # f00fff20 -800004e4: 00012023 sw zero,0(sp) -800004e8: 00000013 nop -800004ec: 00000013 nop +800004ec : +800004ec: f0100137 lui sp,0xf0100 +800004f0: f2010113 addi sp,sp,-224 # f00fff20 +800004f4: 00012023 sw zero,0(sp) +800004f8: 00000013 nop +800004fc: 00000013 nop -800004f0 : -800004f0: fc0e88e3 beqz t4,800004c0 -800004f4: 342020f3 csrr ra,mcause -800004f8: 341020f3 csrr ra,mepc -800004fc: 300020f3 csrr ra,mstatus -80000500: 343020f3 csrr ra,mtval -80000504: 00200093 li ra,2 -80000508: fc1e86e3 beq t4,ra,800004d4 -8000050c: 341f1073 csrw mepc,t5 -80000510: 30200073 mret -80000514: 00000013 nop -80000518: 00000013 nop -8000051c: 00000013 nop -80000520: 00000013 nop +80000500 : +80000500: fc0e80e3 beqz t4,800004c0 +80000504: 342020f3 csrr ra,mcause +80000508: 341020f3 csrr ra,mepc +8000050c: 300020f3 csrr ra,mstatus +80000510: 343020f3 csrr ra,mtval +80000514: 00200093 li ra,2 +80000518: fc1e82e3 beq t4,ra,800004dc +8000051c: 341f1073 csrw mepc,t5 +80000520: 30200073 mret 80000524: 00000013 nop 80000528: 00000013 nop 8000052c: 00000013 nop diff --git a/src/test/resources/hex/mmu.hex b/src/test/resources/hex/mmu.hex index 41403fe1..30333a1c 100644 --- a/src/test/resources/hex/mmu.hex +++ b/src/test/resources/hex/mmu.hex @@ -1,4791 +1,3497 @@ :0200000480007A -:100000006F00000413000000130000001300000044 -:100010001300000013000000130000001300000094 -:10002000732E2034732E3034B74E0C00370F01F08E -:10003000930F40000FF00E000FF0EF03730020301D -:10004000130E10001303F0011303F3FF0F700302EC -:10005000E31C03FE130E200037020C00B70201F070 -:10006000130300000F7002000F70530237120C00D0 -:10007000B70201F0130310000F7002000F7053025B -:1000800037220C00B70202F0130320000F700200A9 -:100090000F70530237320C00B70202F01303300026 -:1000A0000F7002000F705302130E30003702001061 -:1000B000B70200C0370300C1B7030020370400C2F5 -:1000C000B70400C3370500C4371611111306161103 -:1000D000B726222293862622373733331307373346 -:1000E0002320C200032E020003AE0200032E0300F1 -:1000F00023A0D31003AE0310032E041003AE04108C -:10010000130E4000032E02002320E30003AE020082 -:10011000032E0200130E5000032E0500130E600084 -:10012000130E700037620C00B70200F01303F001E9 -:100130000F7002000F705302130000001300000044 -:10014000130000001300000013000000370200C677 -:1001500067000200130000001300000013000000FD -:08016000130000001300000071 -:100168001305000067800000130500006780000089 -:1001780013050000678000006FF09FFE1305000064 -:10018800678000001305000067800000B70710F0C3 -:1001980023A0A7F067800000130101FF232481003A -:1001A800232611001304050003450500630A050012 -:1001B80013041400EFF09FFD03450400E31A05FE45 -:1001C8008320C1000324810013010101678000001E -:1001D800130101FF2320210123261100232481007C -:1001E8002322910013090600630E060013840500FC -:1001F800B384C5000345040013041400EFF01FF98D -:10020800E39A84FE8320C1000324810013050900BA -:1002180083244100032901001301010167800000C4 -:100228006780000037150180130101FF1305C527FA -:1002380023261100EF00C0058320C100B70710F086 -:1002480023A007F2130500001301010167800000D5 -:10025800130101FC2324C1022326D1022328E10231 -:10026800232AF102232C0103232E110313860500F0 -:100278008325850093068102232E11002326D100B1 -:10028800EF0040068320C1011301010467800000CC -:10029800130101FC2324C1022326D102232AF102DF -:1002A8002322B1022328E102232C0103232E110368 -:1002B800973701009387078583A7070093064102B4 -:1002C8001306050083A5870013850700232E110058 -:1002D8002326D100EF0000018320C101130101048E -:1002E80067800000130101E32326111C2322911CBF -:1002F8002320211D232E311B2320A11B1389050038 -:1003080093040600138D06002324811C232C411B13 -:10031800232A511B2328611B2326711B2324811B9D -:100328002322911B232EB11993090500EF40104792 -:1003380083270500138507002324F102EF60503757 -:10034800232AA1002328010C232A010C232C010CA9 -:10035800232E010C638A090083A78903639607008B -:1003680013850900EF2080518317C90013972701CF -:1003780063420702B726000003274906B3E7D70000 -:100388002316F900B7E7FFFF9387F7FFB377F70066 -:100398002322F9068357C90093F78700638E07065F -:1003A80083270901638A07068357C9001307A0003A -:1003B80093F7A7016390E7088317E90063CC070662 -:1003C80093060D00138604009305090013850900A0 -:1003D800EF10906F232CA1008320C11C0324811CE3 -:1003E800032581018324411C0329011C8329C11B86 -:1003F800032A811B832A411B032B011B832BC11A50 -:10040800032C811A832C411A032D011A832DC1193B -:100418001301011D67800000930509001385090079 -:10042800EF105076E30205F89307F0FF232CF10054 -:100438006FF09FFA9307C10E2322F10C2326010CBB -:100448002324010C130A0000138B0700232A01023E -:10045800232801022324010023220102232601026A -:10046800232C01001384040013075002834704005F -:10047800638407006392E70CB30A9440638A0A0412 -:100488008327C10C23209B0023225B01B3875701DC -:100498002326F10C8327810C13077000130B8B00A4 -:1004A800938717002324F10C635EF7001306410CB1 -:1004B8009305090013850900EF80101F631A05765C -:1004C800130BC10E83278101B3875701232CF10039 -:1004D80083470400639407006F10505B9307140070 -:1004E8002328F100A303010A930CF0FF232E010037 -:1004F80013040000930B9000130CA0028327010142 -:1005080083CA0700938717002328F10093870AFE00 -:100518001307A0056374F7006F10C02417170100B4 -:10052800130747D693972700B387E70083A70700E9 -:10053800B387E70067800700130414006FF01FF308 -:1005480097170100938707EF232AF1029377040294 -:10055800639407006F104003130D7D00137D8DFF1A -:1005680093078D00832D0D00032D4D002326F100E8 -:1005780093771400638E0700B3E7AD01638A070021 -:10058800930700032304F10AA304510B1364240006 -:100598001374F4BF930720006F00106913850900D6 -:1005A800EF40D01F83274500138507002326F1025B -:1005B800EF6010102322A10213850900EF40101EDE -:1005C800832785002324F10083274102E38807F26B -:1005D80083278100E38407F283C70700E38007F2DB -:1005E800136404406FF09FF18347710AE39807F0A2 -:1005F80093070002A303F10A6FF05FF0136414007D -:100608006FF0DFEF83270D00130D4D00232EF1004F -:10061800E3D607EEB307F040232EF100136444003D -:100628006FF0DFED9307B0026FF0DFFC8327010165 -:1006380083CA0700938D170063988A05832C0D00E1 -:1006480093074D0063D40C00930CF0FF138D070043 -:100658002328B1016FF09FEA13850C009305A000D1 -:100668002322F100EF00417C83274100938D1D0078 -:1006780083CAFDFFB30CF50093870AFDE3FEFBFC7C -:100688002328B1016FF09FE8930C00006FF0DFFEA4 -:10069800136404086FF09FE6832D0101232E0100E7 -:1006A8000325C1019305A000938A0AFDEF00C177D5 -:1006B800938D1D00B387AA0083CAFDFF232EF10086 -:1006C80093870AFDE3FEFBFC6FF09FFB1364840035 -:1006D8006FF0DFE28327010103C707009307800655 -:1006E800631CF70083270101136404209387170014 -:1006F8002328F1006FF09FE0136404046FF01FE0FB -:100708008327010103C707009307C006631CF7008E -:1007180083270101938717002328F100136404023B -:100728006FF0DFDD136404016FF05FDD93074D00A8 -:100738002326F10083270D00A303010A2306F112E3 -:1007480023220100930C1000930D0000130C0000ED -:10075800930B0000130D00009304C1122320B10372 -:1007680063D49D01232091030347710A630807009E -:1007780083270102938717002320F102937724002F -:10078800232CF1026388070083270102938727003F -:100798002320F10293774408232EF102639C070675 -:1007A8008327C101032701023387E7406354E0062A -:1007B800930E0001171E0100130E8EC3130F700055 -:1007C8008326810C2320CB010326C10C93861600B7 -:1007D80093058B0063D4EE006F00107A2322EB00A0 -:1007E8003307C7002326E10C2324D10C130770001C -:1007F800138B05006350D7021306410C93050900BB -:1008080013850900EF80406A630405006F10D0214A -:10081800130BC10E0347710A630A07041307710A11 -:100828002320EB00130710002322EB000327C10C41 -:1008380093067000130B8B00130717002326E10C97 -:100848000327810C130717002324E10C63D0E60269 -:100858001306410C9305090013850900EF80C06455 -:10086800630405006F10501C130BC10E832781030E -:10087800638A07041307810A2320EB00130720006B -:100888002322EB000327C10C93067000130B8B0087 -:10089800130727002326E10C0327810C13071700F1 -:1008A8002324E10C63D0E6021306410C93050900EA -:1008B80013850900EF80405F630405006F10D016B0 -:1008C800130BC10E8327C10313070008639AE706B9 -:1008D8008327C10103270102B387E7406352F0066B -:1008E800930E0001171E0100130E8EB1130F700036 -:1008F8008326810C2320CB010327C10C9386160085 -:1009080013068B00E3C6FE6C3387E7002322FB0047 -:100918002326E10C2324D10C13077000130B0600C7 -:100928006350D7021306410C93050900138509008B -:10093800EF808057630405006F10100F130BC10E72 -:10094800B38D9D416352B007130E000117180100C3 -:10095800130808AB930E70000327810C23200B01AA -:100968008326C10C1307170013068B00E34EBE6BDA -:100978002322BB01B38DDD002326B10D2324E10C16 -:1009880093067000130B060063D0E6021306410CB1 -:100998009305090013850900EF80005163040500E1 -:1009A8006F109008130BC10E13770410832DC10C20 -:1009B800E314076C8327810C3383BC0123209B003D -:1009C8009387170023229B012326610C2324F10C13 -:1009D80013077000130B8B006344F7006F10801629 -:1009E8001306410C9305090013850900EF80C04BDD -:1009F800630405006F105003130BC10E6F108014B1 -:100A08001364040193770402638E0704130D7D00B9 -:100A1800137D8DFF93078D00832D0D00032D4D0051 -:100A28002326F100635E0D00B30DB041B337B0016A -:100A3800330DA041330DFD409307D002A303F10A03 -:100A48009307F0FFE390FC38E3120D409307900002 -:100A5800E3EEB73F938D0D03A307B1199304F11883 -:100A68006F00503C93074D002326F1009377040153 -:100A780063880700832D0D0013DDFD416FF09FFA99 -:100A880093770404832D0D0063880700939D0D015F -:100A980093DD0D416FF05FFE93770420E38E07FC32 -:100AA800939D8D0193DD8D416FF01FFD9377840039 -:100AB800638C070A93074D002326F10083270D0056 -:100AC80003A6070083A6470003A7870083A7C700DC -:100AD8002328C10C232AD10C232CE10C1305010D6A -:100AE800232EF10CEF40C0442326A10A93072000CF -:100AF800631CF50A8327010D9305010813050109F5 -:100B08002328F1088327410D232001082322010807 -:100B1800232AF1088327810D2324010823260108AD -:100B2800232CF1088327C10D232EF108EFC0D07ABA -:100B3800635605009307D002A303F10A93077004D4 -:100B4800971401009384048D63C65701971401001C -:100B58009384048C1374F4F723220100930C30005F -:100B6800930D00006F00102D130D7D00137D8DFF78 -:100B780083250D0003264D0093078D0013050109F9 -:100B88002326F100EFF0D04F832701092328F10C29 -:100B980083274109232AF10C83278109232CF10C8F -:100BA8008327C1096FF09FF3930710006318F502BC -:100BB8008327C10D63D607009307D002A303F10A68 -:100BC800930770049714010093844485E3C457F98C -:100BD80097140100938444846FF0DFF793FBFAFDC8 -:100BE80093071004639EFB04930700032304F10A90 -:100BF80013071006930780056394EA00930780079C -:100C0800A304F10A930730061364240063D6974BB4 -:100C180093851C0013850900EF40006493040500C8 -:100C28006312054A8357C90093E707042316F9009E -:100C38008357C90093F70704638007FA6FF0CFFE64 -:100C48009307F0FF6384FC48930770042322010094 -:100C58006394FB0063820C48032AC10D9367041058 -:100C68002320F102232C0102832E010D032E410DB6 -:100C7800832D810D635A0A00B707008033CA4701E4 -:100C88009307D002232CF10293071004639AFB48C0 -:100C9800130501092328D109232AC109232CB109E5 -:100CA800232E4109EFF0D0621306C10AEF50105A03 -:100CB800138605009305050013050109EFF0503C64 -:100CC8008327010913060106930501072328F10666 -:100CD800832741091305010823200106232AF10669 -:100CE800832781092322010623240106232CF106E8 -:100CF8008327C109232EF106B707FC3F2326F106F7 -:100D0800EFC0907303280108032641088326810851 -:100D1800832DC1089305010813050109232801093A -:100D280023220105232AC1082320C104232CD1082A -:100D3800232ED102232EB1092320010823220108E2 -:100D48002324010823260108EFC050368326C10357 -:100D58000326010403284104631605001307100045 -:100D68002326E10A13071006170C0100130C8C6CDC -:100D78006396EA00170C0100130C8C6A138EFCFFB3 -:100D8800138D0400B7070340930501082322C10807 -:100D980013050109130601072324C10523200109AE -:100DA8002324D1082326B109232EF106232801067E -:100DB800232A0106232C0106EFC010680326010927 -:100DC8008326410983278109130501092322C104C8 -:100DD8002320D104232EF102EFF0407C9305050077 -:100DE800130A050013050109832DC109EFF05011FD -:100DF8008327C1030326410483260104232CF1061B -:100E0800832701092328C106930501072320F1063A -:100E18008327410913060106130501082322F10659 -:100E280083278109232EB107232AD1062324F1061B -:100E38008327C109130D1D002326F106EFE0C02505 -:100E4800B3054C0183C50500032E8104832EC10818 -:100E580083220108832F4108032F8108232EC10311 -:100E6800A30FBDFE9307F0FF938D0E00630CFE06E3 -:100E7800130EFEFF9305010813050109232ED10562 -:100E8800232CE105232AF105232851042326C10533 -:100E98002328510823245104232AF1092322F10588 -:100EA800232CE1092320E105232ED1092320010861 -:100EB800232201082324010823260108EFC0101F5C -:100EC800832601040326410403288104032EC10458 -:100ED80083220105832F4105032F8105832EC10538 -:100EE800E31205EAB70DFE3F930501081305010952 -:100EF8002328510823265104232AF1092324F10524 -:100F0800232CE1092322E105232ED1092320D10531 -:100F18002320010823220108232401082326B109DC -:100F2800EFC090256346A0048322C104832F810467 -:100F3800032F4104832E01049305010813050109B9 -:100F480023285108232AF109232CE109232ED1094A -:100F58002320010823220108232401082326B1099C -:100F6800EFC0D0146314051A137A1A0063000A1A22 -:100F78000346FC00232EA10B930500038326C10B17 -:100F88009387F6FF232EF10A83C7F6FF638CC714F5 -:100F980013069003639CC7148347AC00A38FF6FE27 -:100FA800130A0D0013077004330A9A40032DC10A6F -:100FB8006396EB2A1307D0FF6344ED0063D2AC338A -:100FC800938AEAFF930BFDFF2326710B93F6FAFD34 -:100FD8009305100413F7FA0F130600006398B60080 -:100FE8001307F7001377F70F13061000230AE10A17 -:100FF8009307B00263D80B00930B1000B38BAB417F -:101008009307D002A30AF10A9307900063DC7729BB -:10101800130C310C930D0C00930C90009305A00059 -:1010280013850B00EFF0D06A13050503A30FACFE80 -:101038009305A00013850B00EFF05061130DFCFF22 -:10104800930B050063C2AC24930B0503130CECFF50 -:10105800A30F7DFF9307610B636CBC231307410B40 -:10106800B387E7402328F102B38C470193071000A8 -:1010780063C64701937714006386070083274101FD -:10108800B38CFC001374F4BF936704102320F1029F -:10109800130C0000930B0000130D0000832781033D -:1010A800638607001307D002A303E10A03240102A1 -:1010B800930D00006FF08FEA232201009304C11200 -:1010C8006FF09FB92322A1006FF01FB923220100FE -:1010D800930C60006FF05FB823229101930C10000D -:1010E8006FF09FB7A38FB6FE6FF05FE99387170085 -:1010F80093F7F70F6FF09FEA130A1A00A30FEAFE9F -:10110800B3074D41E3DA07FE6FF0DFE98327C10338 -:10111800130A0D0013070003330DFD006FF05FFE87 -:1011280093076004638EFB0093075004138C1C0024 -:101138006384FB00138C0C00130620006F00C000B2 -:10114800138C0C00130630009307010B1308C10B16 -:101158001307C10A93060C009305010913850900BA -:101168002328D1092320D105232AC109232EC1030D -:10117800232CB109232E4109EF304017930770043F -:1011880093040500032EC103832E01046396FB001C -:10119800937714006384070A93076004338D8401EE -:1011A8006392FB0603C70400930700036318F70460 -:1011B80093050108130501092328D1092320D10526 -:1011C800232AC109232EC103232CB109232E410947 -:1011D80023200108232201082324010823260108CB -:1011E800EFC0C06C032EC103832E01046308050001 -:1011F80093071000338C87412326810B8327C10A6C -:10120800330DFD0093050108130501092328D109B1 -:10121800232AC109232CB109232E410923200108BF -:10122800232201082324010823260108EFC00068AF -:1012380013070003631E0500232EA10B032AC10B0D -:101248006FF05FD693861700232ED10A2380E7001C -:101258008327C10BE3E8A7FF6FF05FFE1307600465 -:10126800E392EBD66352A00763960C001377140041 -:101278006302070C832741013307FD00B38CEC00A0 -:10128800930A60066F004009130C0D006FF01FD918 -:10129800130C1C000347FCFF93871700A38FE7FE7E -:1012A8006FF09FDB1307610B6318060093070003B9 -:1012B800230BF10A1307710B938B0B03930717008A -:1012C800230077016FF09FD963960C001377140001 -:1012D8006306070683274101138717006FF01FFA7B -:1012E80063404D0313771400930C0D006306070049 -:1012F80083274101B30CFD00930A70066F00C001FB -:1013080083274101930A7006B30CFA006346A001D3 -:101318003383AC41930C1300937B0440130C0000FF -:10132800E38E0BD6930B0000E35AA0D79306F00F79 -:101338006F008003930C0D006FF09FF4930A600612 -:10134800930C10006FF05FFD6356A703832781009D -:10135800330DED4003C71700630807029387170092 -:10136800938B1B002324F1008327810003C7070008 -:10137800E31CD7FC8325410233858B01EFF0D02A8B -:10138800B30C95016FF09FD1130C1C006FF0DFFDBB -:1013980013074D002326E1001377040283270D006D -:1013A800630007020327810123A0E7001357F741D1 -:1013B80023A2E700032DC100832401016FF08F8A67 -:1013C80013770401630807000327810123A0E700BE -:1013D8006FF05FFE13770404630807000357810169 -:1013E8002390E7006FF01FFD13740420E30E04FC44 -:1013F800034781012380E7006FF0DFFB13640401DA -:101408009377040263880704130D7D00137D8DFF15 -:1014180093078D00832D0D00032D4D002326F10029 -:101428001374F4BF93070000A303010A1307F0FF26 -:101438006380EC1A13070400B3E6AD011374F4F7E4 -:101448006398061863820C30130710006396E71838 -:101458006FF04FE093074D002326F10093770401C6 -:1014680063860700832D0D006F0000019377040445 -:1014780063880700835D0D00130D00006FF05FFAAD -:1014880093770420E38007FE834D0D006FF0DFFEA5 -:1014980093074D002326F100B787FFFF93C7078303 -:1014A8002314F10A97070100938787F7832D0D000E -:1014B800232AF102130D000013642400930720006F -:1014C800930A80076FF05FF693074D002326F1001B -:1014D800A303010A9307F0FF83240D006384FC0231 -:1014E80013860C009305000013850400EF40404963 -:1014F8002322A100630605E6B30C954023220100D0 -:101508006FF00FE613850400EF50901A930C050056 -:101518006FF0DFFE1364040193770402638207020D -:10152800130D7D00137D8DFF93078D00832D0D0016 -:10153800032D4D002326F100930710006FF0DFEE16 -:1015480093074D002326F100937704016386070073 -:10155800832D0D006F000001937704046388070052 -:10156800835D0D00130D00006FF01FFD93770420BD -:10157800E38007FE834D0D006FF0DFFE9707010043 -:10158800938707EA6FE05FFC93074D002326F1007D -:101598009377040163860700832D0D006F00000117 -:1015A8009377040463880700835D0D00130D000022 -:1015B8006FE01FFC93770420E38007FE834D0D0046 -:1015C8006FF0DFFE13070400930710006FF0DFE6EB -:1015D80013071000638AE7C613072000638AE7121F -:1015E800930701199316DD0113F77D0093DD3D0084 -:1015F80013070703B3EDB601135D3D00A38FE7FEA4 -:10160800B3E6AD019384F7FF639E06029376140058 -:10161800638A0600930600036306D700A38FD4FEEF -:101628009384E7FF93070119938D0C00232201008F -:10163800B38C9740130C0000930B0000130D0000AF -:101648006FF0CF91938704006FF0DFF913770440B0 -:10165800130A0000930701192322E100930BF00FEE -:10166800130C90001306A0009306000013850D00CC -:1016780093050D009384F7FF2320F102EFA0106378 -:101688008327010213050503130A1A00A38FA7FE77 -:1016980083274100638807048327810083C70700E5 -:1016A8006312FA0463007A0563140D00637CBC03BB -:1016B800832741028325C102130A0000B384F44042 -:1016C8001386070013850400EF505000832781001C -:1016D80083C7170063880700832781009387170053 -:1016E8002324F10013850D0093050D001306A000B7 -:1016F80093060000EFA0C07D138D0500B3E5A5009B -:10170800930D0500E38005F2938704006FF09FF5C1 -:10171800930401190327410393F7FD009384F4FF11 -:10172800B307F70083C7070093DD4D002380F4005B -:101738009317CD01B3EDB701135D4D00B3E7AD01CC -:10174800E39A07FC6FF01FEE93040119E39C07EC82 -:1017580013771700E30807EC93070003A307F118B2 -:101768006FF0CFAFE3840A3223065113A303010AB3 -:101778002326A1016FE0DFFC130606012322DB010B -:101788002326C10C2324D10C635EDF021306410C0F -:1017980093050900138509002326E1052324C105C3 -:1017A8002322D1052320E104EF700070E31E0526F3 -:1017B800032FC104032E8104832E4104032701044F -:1017C8009305C10E130707FF138B05006FE05FFF3A -:1017D800130707012322DB012326E10C2324D10C64 -:1017E800635EDF021306410C9305090013850900A7 -:1017F8002322E1052320C105232ED103232CF10246 -:10180800EF70806AE3120522032F4104032E0104BE -:10181800832EC103832781031306C10E938707FF15 -:10182800130B06006FF0CF8C938606012322CB01A1 -:101838002326D10C2324E10C63DAEE021306410CB3 -:1018480093050900138509002320D105232E0103E0 -:10185800232CC103EF704065E318051C832E010497 -:101868000328C103032E81031306C10E938D0DFFB8 -:10187800130B06006FF04F8E13075006635257750F -:101888000327010D93050108130501092328E10821 -:101898000327410D2320010823220108232AE108F8 -:1018A8000327810D2324010823260108232CE1089E -:1018B8000327C10D232EE108EFB0507F631C0512EA -:1018C80097070100938747B82320FB009307100070 -:1018D8002322FB008327810C938D1D002326B10D45 -:1018E800938717002324F10C13077000130B8B0048 -:1018F800635EF7001306410C930509001385090080 -:10190800EF70805AE3120512130BC10E8327C10A28 -:1019180063C64701937714006386072283278102F1 -:1019280003274101130B8B00232CFBFE8327410166 -:10193800232EFBFE8327C10CB387E7002326F10C77 -:101948008327810C13077000938717002324F10C59 -:10195800635EF7001306410C93050900138509001F -:10196800EF708054E312050C130BC10E9304FAFFB9 -:10197800635A901C930B0001970A0100938A4AA8A6 -:10198800130C70008327810C23205B010327C10CF3 -:101998009387170093068B0063C29B0223229B0048 -:1019A800B384E4002326910C2324F10C1307700060 -:1019B800138B06006358F7186FF08F82130707011F -:1019C80023227B012326E10C2324F10C635EFC0017 -:1019D8001306410C9305090013850900EF70C04CEC -:1019E800E31405049306C10E938404FF138B0600C9 -:1019F8006FF05FF90327C10A634CE01C97070100E9 -:101A0800938787A42320FB00930710002322FB0061 -:101A18008327810C938D1D002326B10D9387170012 -:101A28002324F10C13077000130B8B00635EF7007F -:101A38001306410C9305090013850900EF70C04691 -:101A48006314057E130BC10E8327C10A6398070030 -:101A580063160A00937714006386070E83278102B2 -:101A68000327410193088B002320FB0083274101B2 -:101A78002322FB008327C10CB387E7002326F10C40 -:101A88008327810C13077000938717002324F10C18 -:101A9800635EF7001306410C9305090013850900DE -:101AA800EF708040631205789308C10E832AC10A3B -:101AB80063D20A06B30A504113870800130C0001C9 -:101AC800970B0100938BCB93930D70008327810CA8 -:101AD800232077018326C10C9387170093888800F9 -:101AE800634C5C0B23225701B38ADA002326510D7D -:101AF8002324F10C13077000635EF7001306410CF2 -:101B08009305090013850900EF70003A631E0570FC -:101B18009308C10E8327C10C23A0980023A2480173 -:101B2800B38747012326F10C8327810C1307700024 -:101B3800138B8800938717002324F10C6354F70054 -:101B48006FE01FEA1374440063100468832AC1011C -:101B58008327010263D4FA00938A0700832781014F -:101B6800B3875701232CF1008327C10C638C07002E -:101B78001306410C9305090013850900EF70C03264 -:101B88006314056A832741002324010C6398076EB8 -:101B9800130BC10E6FF01F82938606012322870163 -:101BA8002326D10C2324F10C63DEFD001306410C1F -:101BB8009305090013850900EF70002F6316056669 -:101BC8009308C10E938A0AFF138708006FF01FF06D -:101BD800930A0D006354AA01930A0A006352500540 -:101BE8000327810CB38DBA0123209B00130717002C -:101BF80023225B012326B10D2324E10C93067000F8 -:101C0800130B8B0063DEE6001306410C93050900F5 -:101C180013850900EF70402963180560130BC10E86 -:101C280063D40A00930A0000B30A5D416350500769 -:101C3800930C000197FD0000938D8D7C13037000B9 -:101C48000327810C2320BB018326C10C130717002F -:101C580013068B0063C25C1B23225B01B38ADA0084 -:101C68002326510D2324E10C93067000130B060064 -:101C780063DEE6001306410C93050900138509008D -:101C8800EF7080226312055A130BC10E937704403C -:101C9800B38AA40163840702930D7000338D440155 -:101CA80097FC0000938CCC7563980B1863180C187C -:101CB800B387440163F45701938A07008327C10A55 -:101CC80063C6470193771400638A07048327810258 -:101CD80003274101130B8B00232CFBFE83274101B3 -:101CE800232EFBFE8327C10CB387E7002326F10CC4 -:101CF8008327810C13077000938717002324F10CA6 -:101D0800635EF7001306410C93050900138509006B -:101D1800EF708019631A0550130BC10EB384440188 -:101D2800B38754418324C10AB3049A4063D497000B -:101D380093840700635490048327C10C23205B011C -:101D480023229B00B387F4002326F10C8327810C00 -:101D580013077000130B8B00938717002324F10CD3 -:101D6800635EF7001306410C93050900138509000B -:101D7800EF708013631A054A130BC10E9387040092 -:101D880063D40400930700008324C10AB3049A4073 -:101D9800B384F440E35890DA930B000197FA0000FB -:101DA800938A0A66130C70008327810C23205B0139 -:101DB8000327C10C9387170093068B00E3D09BBEC3 -:101DC8001307070123227B012326E10C2324F10CAE -:101DD800635EFC001306410C930509001385090096 -:101DE800EF70800C631205449306C10E938404FFC0 -:101DF800138B06006FF05FFB9386060123229B017D -:101E08002326D10C2324E10C6352E3021306410C70 -:101E18009305090013850900232C6102EF70C0089F -:101E280063140540032381031306C10E938A0AFF36 -:101E3800130B06006FF0DFE063020C0E130CFCFFBF -:101E48008327C10203274102130B8B00232CFBFEBF -:101E580083274102232EFBFE8327C10CB387E700AB -:101E68002326F10C8327810C938717002324F10C78 -:101E780063DEFD001306410C930509001385090074 -:101E8800EF7080026312053A130BC10E832781009D -:101E980033075D4183C707006354F70093070700C2 -:101EA8006356F0040327C10C23205B012322FB00A7 -:101EB8003387E7002326E10C0327810C130B8B00E3 -:101EC800130717002324E10C63D2ED021306410C1B -:101ED8009305090013850900232CF102EF60D07CDB -:101EE8006314053483278103130BC10E138707007E -:101EF80063D407001307000083278100130800013B -:101F080083C70700B387E7406346F006832781004D -:101F180083C70700B38AFA006FF01FD983278100AF -:101F2800938BFBFF9387F7FF2324F1006FF05FF19A -:101F38009386060123220B012326D10C2324E10CCE -:101F480063D6ED021306410C9305090013850900B9 -:101F5800232E0103232CF102EF6010756316052C64 -:101F68000328C103832781031306C10E938707FF44 -:101F7800130B06000327810C23209B018326C10C29 -:101F88001307170013068B00E344F8FA2322FB001B -:101F9800B387D7002326F10C2324E10C130B06008A -:101FA800E3D6EDF61306410C9305090013850900E5 -:101FB800EF60906F631A0526130BC10E6FF01FF5C3 -:101FC8008327810C1307100023209B00938D1D008D -:101FD80093871700930B8B00634647019376140091 -:101FE8006388061C130710002322EB002326B10D7B -:101FF8002324F10C13077000635EF7001306410CED -:102008009305090013850900EF60106A631E052017 -:10201800930BC10E8327810203274101938B8B0009 -:1020280023ACFBFE8327410123AEFBFE8327C10CB3 -:10203800B387E7002326F10C8327810C1307700070 -:10204800938717002324F10C635EF7001306410CF5 -:102058009305090013850900EF6010656316051CD8 -:10206800930BC10E8327010D930501081305010980 -:102078002328F1088327410D930AFAFF232001083A -:10208800232AF1088327810D23220108232401082C -:10209800232CF1088327C10D23260108232EF108DC -:1020A800EFB0D000630605088327C10C0327810C15 -:1020B800938414009387F7FFB3874701130717002A -:1020C80023A09B0023A25B012326F10C2324E10C0F -:1020D80093077000938B8B0063DEE7001306410CB7 -:1020E8009305090013850900EF60105C631E051253 -:1020F800930BC10E9307410B23A0FB008327010319 -:1021080003270103138B8B0023A2FB008327C10C39 -:10211800B387E7002326F10C8327810C130770008F -:10212800938717002324F10CE35EF7A06FE05F8B21 -:10213800E35250FD130C000197F400009384442CE3 -:10214800930D70000327810C23A09B008327C10CEB -:102158001307170093868B0063405C03B387FA006C -:1021680023A25B012326F10C2324E10C93077000C2 -:10217800938B06006FF05FF69387070123A28B010C -:102188002326F10C2324E10C63DEED001306410C39 -:102198009305090013850900EF60105163160508BF -:1021A8009306C10E938A0AFF938B06006FF09FF97E -:1021B8002322EB002326B10D2324F10C1307700012 -:1021C800E35AF7F26FF09FF18327C1010327010259 -:1021D8003384E740E35C8096930A000197F400009B -:1021E80093840421930B70008327810C23209B0088 -:1021F8000327C10C9387170063C68A0423228B0028 -:102208003304E4002326810C2324F10C1307700007 -:10221800E35EF7921306410C930509001385090044 -:10222800EF609048E3040592832741006394070018 -:102238006FE01FA09385070013850900EF00D011F8 -:102248006FE01F9F1307070123225B012326E10C80 -:102258002324F10C130B8B0063DEFB001306410CE7 -:102268009305090013850900EF601044E31E05FA81 -:10227800130BC10E130404FF6FF01FF783254100F1 -:1022880013850900EF00500D6FF09F908327C10C54 -:10229800639407006FE0DF991306410C930509006A -:1022A80013850900EF6050406FE09F989717010071 -:1022B8009387478593060600138605009305050056 -:1022C80003A507006FE00F8283D7C500130101B88B -:1022D800232C814693F7D7FF231AF10083A74506DD -:1022E80013840500232A91462326F10683D7E500A7 -:1022F80023282147232E1146231BF10083A7C5015C -:1023080013090500232001022322F10283A74502B5 -:10231800930581002326F102930701072324F10086 -:10232800232CF100930700402328F100232EF1000D -:10233800EFD05FFB93040500634C05009305810013 -:1023480013050900EF004038630405009304F0FF0B -:102358008357410193F70704638807008357C40034 -:1023680093E707042316F4008320C1470324814719 -:1023780013850400032901478324414713010148B9 -:1023880067800000130101FF970701009387877793 -:10239800232291009304050003A50700232481004C -:1023A800232611001384050063080500832785038D -:1023B80063940700EF00804C0317C40093170701CC -:1023C80093D7070193F68700639E060693F60701E5 -:1023D800639606029307900023A0F400136707048E -:1023E8002316E4001305F0FF8320C10003248100B5 -:1023F80083244100130101016780000093F747001F -:10240800638C070283250403638C05009307040487 -:102418006386F50013850400EF0000742328040286 -:102428008357C4002322040093F7B7FD2316F40052 -:10243800832704012320F4008357C40093E787000F -:102448002316F40083270401639007028357C4000E -:102458001307002093F707286388E7009305040013 -:1024680013850400EF2050508357C40013F717005A -:10247800630C07028327440123240400B307F040B8 -:10248800232CF4008327040113050000E39E07F4BE -:102498008317C40013F70708E30807F493E7070452 -:1024A8002316F4006FF01FF493F7270013070000BA -:1024B80063940700032744012324E4006FF09FFC82 -:1024C8008397C500130101FE232C81001397070190 -:1024D80013570701232A9100232E110023282101D5 -:1024E80023263101937687009304050013840500A1 -:1024F800639C06163717000013070780B3E7E70049 -:1025080003A745002396F5006346E00203A7C50329 -:102518006342E002130500008320C1010324810106 -:1025280083244101032901018329C1001301010208 -:102538006780000003278402E30E07FC03A9040058 -:102548009396370123A004008325C40163D8060CA1 -:10255800032604058357C40093F74700638E0700DA -:10256800832744003306F640832704036386070065 -:102578008327C4033306F640832784028325C401D6 -:102588009306000013850400E78007009307F0FF17 -:102598008356C4006312F50283A704001307D00111 -:1025A800636CF70A37074020130717003357F70003 -:1025B800137717006302070AB7F7FFFF9387F77FC0 -:1025C80003270401B3F7D7009397070193D707416F -:1025D8002320E4002316F400232204001397370174 -:1025E800635C07009307F0FF6316F50083A70400F8 -:1025F800639407002328A4048325040323A024014B -:10260800E38A05F0930704046386F5001385040044 -:10261800EF008054232804026FF0DFEF1306000058 -:102628009306100013850400E70007009307F0FFE6 -:1026380013060500E310F5F283A70400E38C07F006 -:102648001307D0016386E700130760016392E7066A -:1026580023A024016FF01FEC93E706042316F4006F -:102668001305F0FF6FF05FEB83A90501E38409EA26 -:1026780003A905001377370023A035013309394131 -:10268800930700006314070083A745012324F4007F -:10269800E35220E9832744028325C40193060900F5 -:1026A8001386090013850400E78007006348A0002B -:1026B8008357C40093E707046FF05FFAB389A90052 -:1026C8003309A9406FF0DFFC130101FE232C8100C0 -:1026D800232E110013040500630C050083278503CE -:1026E800639807002326B100EF0040198325C10035 -:1026F8008397C500638C0700130504000324810138 -:102708008320C101130101026FF09FDB8320C10107 -:1027180003248101130500001301010267800000F2 -:1027280093050500631E0500970701009387473D41 -:1027380003A5070097050000938545F96F0080738E -:10274800970701009387073C03A507006FF0DFF7A1 -:102758001305000067800000977500009385857653 -:102768006F004071130101FF23248100232611000B -:10277800130405002316B5002317C5002320050000 -:10278800232205002324050023220506232805000B -:10279800232A0500232C050013068000930500005A -:1027A8001305C505EF30002097470000938747437E -:1027B8002320F40297470000938707482322F40256 -:1027C800974700009387874F2324F4029747000018 -:1027D80093874754232E84002326F4028320C100C4 -:1027E8000324810013010101678000001305000024 -:1027F80067800000130101FF2320210113890500D0 -:102808002324810093058006130405001305F9FFAE -:102818002326110023229100EFE00061930545076C -:102828009304050013050400EF201023130405008A -:102838006300050223200500232225011305C50096 -:102848002324A4001386840693050000EF30801526 -:10285800130504008320C100032481008324410060 -:102868000329010013010101678000009707010097 -:102878009387072903A507006FF01FEE83278503B9 -:10288800639E0706130101FF2326110023248100FC -:1028980097070000938787EC232EF50293073000F3 -:1028A8002322F52E9307C52E130405002324F52EA5 -:1028B8002320052E0325450013060000930540003C -:1028C800EFF05FEA032584001306100093059000DB -:1028D800EFF05FE90325C4001306200093052001EB -:1028E800EFF05FE893071000232CF4028320C10067 -:1028F8000324810013010101678000006780000044 -:10290800130101FF970701009387871F2322910076 -:1029180083A40700232021012326110083A7840311 -:10292800232481001309050063960700138504001A -:10293800EFF0DFF49384042E03A4840083A74400FB -:102948009387F7FF63DA070083A70400638E070005 -:1029580083A404006FF05FFE0317C4006304070438 -:10296800130484066FF0DFFD93054000130509008A -:10297800EFF05FE823A0A400E31C05FC9307C00068 -:102988002320F90013040000130504008320C1006C -:10299800032481008324410003290100130101015C -:1029A80067800000B707FFFF9387170023220406FC -:1029B8002320040023220400232404002326F400F7 -:1029C80023280400232A0400232C04001306800073 -:1029D800930500001305C405EF20D07C23280402CA -:1029E800232A040223220404232404046FF0DFF9B9 -:1029F8006780000067800000678000006780000033 -:102A0800970701009387071003A5070097050000A3 -:102A1800938545D46F00003C970701009387870E84 -:102A280003A5070097050000938585DC6F00803AB1 -:102A3800130101FD23248102232291022320210373 -:102A4800232E31012326B100232611021309050084 -:102A580097090100938949CAEF30800283A789004A -:102A68008325C10083A44700B71700001384F7FE2D -:102A780093F4C4FF3304B440330494001354C400E3 -:102A88001304F4FF1314C4006356F4021305090079 -:102A9800EF20507F130500008320C1020324810228 -:102AA80083244102032901028329C101130101037F -:102AB800678000009305000013050900EF3050748B -:102AC80083A78900B3879700E312F5FCB30580401C -:102AD80013050900EF30D0729307F0FF6312F50475 -:102AE8009305000013050900EF30907103A78900D2 -:102AF8009306F000B307E540E3DAF6F8970601001D -:102B08009386860083A6060093E717002322F70022 -:102B18003305D5409706010023A6A6006FF01FF7DE -:102B280083A78900B384844093E4140023A2970008 -:102B380097070100938707FF83A70700130509007C -:102B4800338487409707010023AE87FCEF209073FA -:102B5800130510006FF05FF4638C0526130101FF65 -:102B68002324810023229100130405009384050087 -:102B780023261100EF20D07083A5C4FF938684FF1D -:102B880017050100130545B793F7E5FF3386F600EF -:102B9800032746000328850093F515001377C7FF20 -:102BA800631AC806B387E7006390050203A784FF8A -:102BB800B386E64003A68600B387E70003A7C600EE -:102BC8002326E6002324C70013E7170023A2E60004 -:102BD800170701002326D7B217070100130707F3C9 -:102BE8000327070063ECE70097070100938707F3C3 -:102BF80083A5070013050400EFF09FE31305040005 -:102C0800032481008320C1008324410013010101B2 -:102C18006F2050672322E600130800006396050220 -:102C280083A584FF97080100938888ADB386B640D2 -:102C3800B387B70083A58600638C150B83A8C600ED -:102C480023A6150123A4B800B305E60083A5450013 -:102C580093F51500639C0502B387E70003278600F8 -:102C6800631C080897050100938585A96316B708B2 -:102C780017060100232CD6A8170601002326D6A87C -:102C880023A6E60023A4E6001308100013E71700A4 -:102C980023A2E6003387F6002320F700E31008F6A6 -:102CA8001307F01F6362F70693D7370013D6274040 -:102CB800130710003317C700032645009387170032 -:102CC800939737003367C700B307F500170601006D -:102CD8002326E6A203A70700138687FF23A6C600BC -:102CE80023A4E60023A0D7002326D7006FF01FF106 -:102CF800130810006FF05FF50326C6002326C700EF -:102D08002324E6006FF09FF813D6970013074000BE -:102D1800636AC70413D767001307870313061700EE -:102D2800131636003306C500930586FF03260600F2 -:102D38006396C50893071000135727403397E70099 -:102D4800832745003367F7009707010023A8E79A10 -:102D580023A6B60023A4C60023A4D5002326D600A4 -:102D68006FF0DFE9130740016366C7001307B60574 -:102D78006FF0DFFA130740056368C70013D7C70071 -:102D88001307E7066FF09FF9130740156368C7003C -:102D980013D7F700130777076FF05FF893054055CF -:102DA8001307E007E3ECC5F613D727011307C70796 -:102DB8006FF0DFF6032686006388C5000327460008 -:102DC8001377C7FFE3E8E7FE8325C6006FF05FF8D7 -:102DD80067800000130101FD2324810223202103C1 -:102DE800232C4101232A5101232611022322910277 -:102DF800232E31011304052E13090000130A1000B5 -:102E0800930AF0FF631604028320C102032481029F -:102E18001305090083244102032901028329C10102 -:102E2800032A8101832A41011301010367800000FD -:102E380083248400832944009389F9FF63D6090019 -:102E4800032404006FF01FFC83D7C4006370FA02E8 -:102E58008397E400638C5701138504002326B1008F -:102E6800E78005008325C1003369A900938484069F -:102E78006FF09FFC130101FD23248102232021030D -:102E8800232C4101232A51012328610123267101A2 -:102E98002326110223229102232E3101130A050051 -:102EA800938A05001304052E13090000130B100064 -:102EB800930BF0FF631A04028320C10203248102EA -:102EC8001305090083244102032901028329C10152 -:102ED800032A8101832A4101032B0101832BC100AD -:102EE80013010103678000008324840083294400C0 -:102EF8009389F9FF63D60900032404006FF09FFB50 -:102F080083D7C400637EFB008397E400638A77015C -:102F18009385040013050A00E7800A003369A900B5 -:102F2800938484066FF0DFFC9307450113052500A1 -:102F3800231F05FEE31CF5FE67800000930745018B -:102F4800130525000357E5FF93852500239FE5FE1C -:102F5800E398A7FE678000009307A50113052500E5 -:102F6800231F05FEE31CF5FE67800000130785019B -:102F780093870500130525008356E5FF93872700EF -:102F8800239FD7FEE318A7FE239C05006780000057 -:102F980093074500938545001305A50193872700EE -:102FA8009385250083D6E7FF03D7E5FF6398E600FE -:102FB800E316F5FE130500006780000013051000F6 -:102FC8006364D7001305F0FF67800000930645008F -:102FD800930700001305A5013786FFFF03D70600F6 -:102FE800937517006384050093E7170093F527008E -:102FF8001357170063900502939717002390E60074 -:10300800939707019386260093D70701E318D5FC09 -:10301800678000003367C7006FF01FFE93066501E5 -:103028001307000083D7260013960701135606419D -:1030380063540600136717009397170093970701C7 -:103048001376270093D7070163100602131717009A -:103058002391F600131707019386E6FF135707011C -:10306800E312D5FC6780000093E717006FF01FFE9E -:1030780093074500130700001305A50183D6070031 -:103088009387270013D686003367C700239FE7FE80 -:10309800139786001317070113570701E310F5FE6E -:1030A80067800000930765011307000083D6270097 -:1030B8009387E7FF139686003367C7002392E700DC -:1030C80013D78600E314F5FE6780000093074500D8 -:1030D800130785019387270083D60700239FD7FE10 -:1030E800E31AF7FE231C050067800000930785019B -:1030F8001307A501930645009387E7FF03D607004A -:103108001307E7FF2310C700E398F6FE2312050014 -:103118006780000093858501130765019306000009 -:103128008357270003D605001307E7FF9385E5FFBC -:10313800B387C700B387D7002391F50093D707015A -:1031480093F61700E31EE5FC678000009385850170 -:10315800130765019306000083D70500035627006F -:103168001307E7FF9385E5FFB387C740B387D740C9 -:103178002391F50093D7070193F61700E31EE5FCAA -:1031880067800000130101FB232E3103B7090100FA -:10319800232481042322910423202105232C410385 -:1031A80023261104130A0500231501022316010220 -:1031B80093848501138945001304C1029389F9FF9B -:1031C80003D504001304E4FF9384E4FF63180504A3 -:1031D800231F04FEE31699FE930740001307A0017E -:1031E80093054101B385F50083D50500B306F600C4 -:1031F800938727002390B600E394E7FE8320C10459 -:103208000324810483244104032901048329C1037D -:10321800032A8103130101056780000093050A0052 -:103228002326C100EFD0504003572400B37735015F -:1032380013550501B387E700035704002311F40071 -:1032480093D707013305E5003305F5002310A400E3 -:1032580013550501231FA4FE0326C1006FF09FF735 -:103268008357250193C7F7FF13971701631C0700BE -:1032780093072501130525000357E5FF6318070089 -:10328800E39AA7FE130500006780000013051000ED -:1032980067800000130101FF232481002326110009 -:1032A80013040500EFF0DFFB631E0500031524017E -:1032B8001355F5018320C100032481001301010186 -:1032C80067800000130500006FF0DFFE83172501FB -:1032D800130101FF232611002324810023229100DA -:1032E8002320210163D807069307F0FF2390F500F8 -:1032F80003572501B78700009387F7FF33F7E700E7 -:103308002391E500130905016316F70613840500E8 -:1033180093040500EFF0DFF46302050493076400EB -:10332800231204001385C4FF1309E9FF035729007A -:1033380093872700239FE7FEE318A9FE8320C10097 -:1033480003248100832441000329010013010101A2 -:1033580067800000239005006FF09FF993074400F1 -:103368009305A40193872700239F07FEE39CB7FEDC -:103378006FF0DFFC93876500239205001305E5FFD6 -:103388001309E9FF0357290093872700239FE7FEC6 -:10339800E318A9FE239C05006FF05FFA130101FBF7 -:1033A80023229104232021052326110423248104A8 -:1033B8001309050093840500EFF09FEA6310050EDA -:1033C80013850400EFF0DFE9130405006318050C0A -:1033D8009305810013050900EFF05FEF93054102A3 -:1033E80013850400EFF09FEE0357810083574102D5 -:1033F8006380E70693072000930680011306810087 -:103408003306F60003560600631C06021306410243 -:103418003306F60003560600631406029387270056 -:10342800E39ED7FC130504008320C1040324810410 -:103438008324410403290104130101056780000066 -:1034480013041000E30007FE1304F0FF6FF09FFD64 -:1034580013061000638407001306F0FF93070000AB -:1034680093058001130781003307F700835607008F -:10347800130741023307F700035707006398E60074 -:1034880093872700E390B7FE6FF0DFF91304060077 -:10349800E36AD7F83304C0406FF0DFF81304E0FFA5 -:1034A8006FF05FF88357250193C7F7FF139717014C -:1034B80063100702130101FF23261100EFF05FDA02 -:1034C8008320C10013351500130101016780000036 -:1034D80013050000678000009307250113052500E8 -:1034E800231F05FEE31CF5FE835705003787000000 -:1034F8001307F7FFB3E7E7002310F5006780000024 -:10350800130101FE232C810023282101232E110001 -:10351800232A91002326310123244101232251012A -:10352800130905001384050063D20510330AB0405F -:1035380093090A0093040000930AF00063CE3A034B -:1035480013554A00930500FFEFD0100E3304854051 -:1035580093090400130A7000634C3A0313553400AE -:10356800930580FFEFD0500C33048500631E0402DE -:10357800333590006F00400983578901130509000E -:10358800938909FFB3E4F400EFF05FB66FF01FFB17 -:103598008347890113050900938989FFB3E49700DC -:1035A800EFF01FAD6FF05FFB83578901130509002A -:1035B8001304F4FF93F71700B3E49700EFF01FA18B -:1035C8006FF0DFFA13050900EFF05FB0938404FF92 -:1035D800E3CA99FE13554400930500FFEFD0D004C9 -:1035E8003304A400930404009309700063C699048B -:1035F80013553400930580FFEFD010033304A40063 -:1036080063140404130500008320C101032481010D -:1036180083244101032901018329C100032A810070 -:10362800832A41001301010267800000938405008A -:103638009309F0006FF0DFF913050900EFF09FA67A -:10364800938484FF6FF09FFA13050900EFF01F9D24 -:103658001304F4FF6FF0DFFA83574500130101FFED -:1036680023229100232611002324810023202101F5 -:10367800930405006392070883176500130400008C -:103688001309000A63D80702130504008320C10048 -:10369800032481008324410003290100130101014F -:1036A800678000001385040013040401EFF01FA2D3 -:1036B800E30C24FD83D76400E38607FE83D7640008 -:1036C80093F707F0638207021309000A83976400DF -:1036D800E3CC07FA1385040013041400EFF01F94D9 -:1036E800E35689FE6FF05FFA13850400EFF09F9BA5 -:1036F800130484006FF09FFC93F707F01304000095 -:1037080063860700EFF0DF96130480FF130900F7C4 -:103718006F004001138504001304F4FFEFF01F8BC2 -:10372800E34424F783D74400E39607FE6FF0DFF500 -:103738009307050113052500231F05FEE31CF5FE6D -:10374800B7C7FFFF2310F500B787FFFF93C7F7FF41 -:103758002311F50067800000130705008356070052 -:10376800138505008357270063860600B786FFFF89 -:10377800B3E7D7002319F50003562700B7860000E2 -:103788009386F6FF93076700631ED6001307A70109 -:1037980083D607006398060293872700E39AE7FE1B -:1037A8006FF09FD31305050113078701938727003F -:1037B80083D6E7FF1305E5FF2311D500E398E7FE5D -:1037C800678000006FF0DFF6130101FD23229102EC -:1037D80093040500130541002324810223261102C6 -:1037E80013840500EFF04FF703D7E40093170701A0 -:1037F80093D7074163C2070423120100B78600006C -:103808009386F6FF3377D7009387E400631CD706C7 -:103818001387040083560700638606021305040015 -:10382800EFF01FF18320C1020324810283244102A7 -:1038380013010103678000009307F0FF2312F100D2 -:103848006FF0DFFB13072700E396E7FC130504007E -:10385800EFF08FED13050400EFF01FC88397E40025 -:10386800E3D207FC13050400EFF09F9FE31C05FA61 -:10387800835724013787FFFFB3C7E7002319F400F4 -:103888006FF05FFA2313E100930641009387E7FF87 -:1038980003D60700938626002392C600E398F4FE19 -:1038A800631C07002314010093050400130541005D -:1038B800EFF09FEA6FF01FF7930710009305F0FFF2 -:1038C800130541002314F100EFF09FC36FF0DFFDF3 -:1038D800130101FE232C8100232A910023282101B2 -:1038E8002326310123244101232251011389060093 -:1038F80013840700232E1100930405009389050003 -:10390800130A0600930A0700EFF01FD59307000972 -:103918003309A94063D4A704B78700009387E7FF5A -:1039280063C6272D938724009384A40193872700D7 -:10393800239F07FEE39C97FE8320C1010324810196 -:1039480083244101032901018329C100032A81003D -:10395800832A41001301010267800000635E0900A9 -:10396800930700F7634CF9129305090013850400C7 -:10397800EFF01FB96310051463860A220327440079 -:10398800832704006306F7061305A401EFF0CFDCD4 -:103998008327440013078003638EE7166340F712FA -:1039A800130780016386E71A130750036382E71839 -:1039B8001307C0002324E400370701801307F7FF2B -:1039C800232AE40013071000231CE4001307B000A7 -:1039D8002326E4000327C4008356840113078700C5 -:1039E800131717003307E4002315D7002320F4002A -:1039F800634220030327440093070009630CF70080 -:103A080083D784011385040093F71700B3E9F900FD -:103A1800EFF0CFDB8326840003564401832544005E -:103A2800139716003387E40083570700B3F7C700DE -:103A38001306F008634AB6009386160013060700BB -:103A48009305C00063DAD510835644010356070076 -:103A580093C6F6FFB3F6C6002310D70003576401D8 -:103A6800B376F700638A06106312F70263940910AD -:103A78008327C4000357840193971700B387F40082 -:103A880083D70700B3F7E7006388070E9385040020 -:103A98001305A401EFF00FE86F00000E93872400D0 -:103AA8009384A40193872700239F07FEE39C97FE36 -:103AB8006FF09FE8930910006FF01FEC13070004E4 -:103AC8006388E70213071007E394E7EE378700409F -:103AD8001307F7FF9306A000232AE4002324D40049 -:103AE8003787FFFF231CE4002326D4006FF09FEEE6 -:103AF800130770002324E400370701801307F7FF3A -:103B0800232AE40013071000231CE40013076000B5 -:103B18006FF01FEC93066000370780001307F70F5C -:103B2800232AE4002324D400130700106FF09FFB1E -:103B3800370700041307F77F93066000232AE40081 -:103B4800371700002324D400130707806FF09FF96C -:103B5800930640006FF05FFC0355260063040500E0 -:103B680093E7170023110600938616001306260014 -:103B78006FF05FEDE30C0AF0634C2001032744006B -:103B8800930700096306F70013850400EFF00FC9D7 -:103B980083D744006388070013850400EFF00FC340 -:103BA80013091900B7870000239C04009387E7FFD7 -:103BB80063D42703B787FFFF93C7F7FF2391F40068 -:103BC80093874400938484012390070093872700F8 -:103BD800E39CF4FE6FF05FD663560900239104005E -:103BE8006FF09FD5239124016FF01FD5E3980AD871 -:103BF800239C04006FF01FFC130101FE23244101E4 -:103C0800035A2500232C810013840500232E11005C -:103C1800232A910023282101232251012320610115 -:103C280013090600130B460323263101930A0500E6 -:103C3800EFF09FA283542400330AAA40130504001E -:103C4800EFF09FA1B384A44013050B00EFF0CFB0B1 -:103C580063D2440513050400032481018320C101B4 -:103C68008329C100032A8100832A4100032B010014 -:103C78009307090093860400032901018324410165 -:103C8800130700001306000093050000130101024A -:103C98006FF01FC49305040013850A00EFF04FAFBF -:103CA80093090000634AA0009305040013850A00E5 -:103CB800EFF0CFC99309100013050B00EFF00FB612 -:103CC8008357C904130504009384F4FFB3E9F9008A -:103CD80023163905EFF08FB46FF09FF7130101F742 -:103CE800232481082322910823202109232E310728 -:103CF80023261108232C4107232A5107232861076B -:103D080023267107232481072322910793040500A2 -:103D1800138405001309060093890600EFF04FD4B9 -:103D2800630205049305090013850400EFF00FA151 -:103D38008320C1080324810883244108032901083A -:103D48008329C107032A8107832A4107032B010717 -:103D5800832BC106032C8106832C4106130101091C -:103D68006780000013050400EFF08FCF630805009B -:103D780093050900130504006FF05FFB1385040029 -:103D8800EFF04FF26314050613050400EFF08FF10E -:103D9800630C050097D500009385456B13850400D7 -:103DA800EFF0CFDF630E050413850400EFF08FEF0B -:103DB8006318050013050400EFF0CFEE630C05044B -:103DC80013850400EFF00FCD9304050013050400DC -:103DD800EFF04FCC638CA402B787FFFF2319F900DB -:103DE80013050900EFF04FEF6FF09FF497D500002F -:103DF8009385C56513050400EFF04FDAE31605F85F -:103E080013050900EFF0DF926FF09FF22319090004 -:103E18006FF01FFD138504009305C100EFF00FCB71 -:103E28001305040093058102EFF04FCA0354E10023 -:103E38008354A1026314040293070000130760016E -:103E48009306C100B386F60083D62600638A06105F -:103E58001305C100EFF05F803304A0408357A1022F -:103E6800138C040063920702130760019306810212 -:103E7800B386F60083D62600638E060E13058102EC -:103E8800EFF08FFD338CA44083578102938B490355 -:103E980093848903239AF9028357A102138A0B009A -:103EA800239BF9029387E904239004009384240058 -:103EB800E39C97FE930A0000130B0000930CC0FECE -:103EC8009307C100B387570103D58701630E050027 -:103ED8009305810213064104EFF0CFAA93850B00E6 -:103EE80013054104EFF00FA383D7C90413850B0012 -:103EF800938AEAFF336BFB00EFF04F9FE3929AFD42 -:103F08009307810203570A00130A2A0093872700A0 -:103F1800239FE7FEE3189AFEB7C6FFFF3304840128 -:103F2800938626009387090013070004B306D4007C -:103F38001306000093050B0013058102EFF05F994B -:103F48000357C10083578102631CF702231401023F -:103F58009305090013058102EFF01F806FF05FDD04 -:103F680093872700E39EE7EC13050900EFE0DFFBEA -:103F78006FF01FDC93872700E39AE7EE6FF0DFFE10 -:103F88009307F0FF2314F1026FF09FFC130101F770 -:103F9800232481082322910823202109232A510759 -:103FA80023261108232E3107232C410723286107D4 -:103FB8002326710723248107232291072320A107A1 -:103FC800930405001384050013090600938A06006C -:103FD800EFF00FA963040504930509001385040095 -:103FE800EFE0DFF58320C10803248108832441081A -:103FF800032901088329C107032A8107832A410766 -:10400800032B0107832BC106032C8106832C410651 -:10401800032D010613010109678000001305040040 -:10402800EFF00FA4630805009305090013050400C9 -:104038006FF01FFB97D50000938545411385040059 -:10404800EFF0CFB5630E051E13850400EFF08FC5A2 -:104058009309050013050400EFF0CFC4639209200B -:1040680063180520138504009305C100EFF00FA61F -:104078001305040093058102EFF04FA58354A102B4 -:104088000354E100639404029307000013076001DE -:1040980093068102B386F60083D626006380062045 -:1040A80013058102EFF04FDBB304A0408357E10012 -:1040B800930B040063920702130760019306C10083 -:1040C800B386F60083D626006380061E1305C1005A -:1040D800EFF08FD8B30BA440835781020357A10296 -:1040E80093894A03239AFA0293878A03239BEA0255 -:1040F800138A07001387EA0493872700239F07FE84 -:10410800E39CE7FE13058102EFE05FEC035C21010D -:10411800370B01009305FBFF13050C00EFC0D050CF -:10412800130D0500938CA901130BFBFF0355C10266 -:104138008357E10213040B00131505013305F5003D -:10414800636AAD0093050C00EFC0D050131405014D -:10415800135404019305C100130504001306410418 -:10416800EFF04F829305810213054104EFE05FE20F -:104178006356A002930541041305C100EFE01FFD3B -:104188009305810213054104EFE09FE0634CA01200 -:104198001304F4FF1314040113540401930581025A -:1041A80013054104EFE09FFA1305810223108A00EA -:1041B800130A2A00EFE09FF1E31A9AF79307000029 -:1041C800930500001307600193068102B386F60089 -:1041D80083D6460093872700B3E5D500E396E7FE2C -:1041E800B335B0009307810203D7090093892900EA -:1041F80093872700239FE7FEE3183AFFB74600009E -:10420800B38474419386F6FF93870A00130700046A -:10421800B386D4001306000013058102EFF04FEBBC -:104228000357C10083578102631CF70A2314010254 -:104238009305090013058102EFF00FD26FF09FDAA2 -:1042480097D500009385852013050400EFF00F959E -:10425800E31C05DE13050900EFF08FCD6FF09FD842 -:10426800E31A05FE13050900EFE01FCC6FF09FD796 -:1042780013850400EFF00F82930405001305040072 -:10428800EFF04F81638CA402B787FFFF2319F90071 -:1042980013050900EFF04FA46FF0DFD493872700D0 -:1042A800E398E7DE6FF01FFC93872700E398E7E0C9 -:1042B8000357C10083578102E318F7FC231909004B -:1042C8006FF01FFD1304E4FF131404019305410468 -:1042D8001305C10013540401EFE05FE76FF01FEC12 -:1042E8009307F0FF2314F1026FF09FF403AE05006B -:1042F80003A3450083A8850083A5C500130101E237 -:10430800232C811C2326B10213840700832505046E -:104318009307F0FF2328F114930700092328211D90 -:104328002326311D2324411D232E711B232E111CEE -:10433800232A911C2322511D2320611D232C811B1C -:10434800232A911B2328A11B2326B11B2326010105 -:104358002320C1032322610223241103232AF114F9 -:1043680013090500130A060093890600930B07003A -:104378006380050283274504130710003317F700ED -:1043880023A2F50023A4E500EF10807A2320090476 -:104398001305010293050105EFF00FC3130501058D -:1043A800EFE05FEF630E0518930710002320F40079 -:1043B80093073000630AFA1893044001630A0A005D -:1043C8009384F9FF9307A00263D497009304A00293 -:1043D80083274115130501052328F100EFE05FE865 -:1043E8001304050097D500009385852BE31605284F -:1043F800930700099305C10613050105232AF11443 -:10440800EFE0DFB38357E107930A00001397070132 -:1044180013570741635E0700378700001307F7FF4C -:10442800B3F7E700B70A0100231FF106938AFAFFE2 -:104438009305810817D5000013058502EFE01FB02A -:104448000357E107E31A07201307C1069307000083 -:10445800930690000356070063140610938717000D -:1044680013072700E398D7FE9305010C130581086D -:10447800EFE0DFE5930581081305010CEFE01FAFBE -:104488009305010C1305C106EFE05FE49305C1062F -:104498001305010CEFE09FAD130601159305C10646 -:1044A80013058108EFF04FF5035BC11917DC000015 -:1044B800130CCCF9631A0B0093050C001305C10605 -:1044C800EFE0DFED6310056C9307D00263940A00F8 -:1044D80093070002230AF11093073000138C04009D -:1044E8006318FA00338C84009307A002E3C0872383 -:1044F8009307A000631EFB6C93071003A30AF11037 -:104508009307E002230BF110130B7111635A80011A -:1045180093070003A30BF110130CFCFF130B81117D -:104528001304140063500C6C1306040097D50000A4 -:104538009385451913050B00EF20C0626F00D01456 -:10454800232004006FF0DFE6938409006FF09FE7F3 -:104558008317C10797D5000093858516E3DE0710FA -:104568009305C10617D50000130585EFEFE01FE39B -:10457800E30C05EE635805469305410A1305C10689 -:10458800EFE0DF9BB74700009387E708231BF10A9A -:10459800B78700009387F7FF232AF100B7C7FFFF0B -:1045A80093872700130C0000930C0001232CF100C3 -:1045B80097D70000938707F633858701930601157F -:1045C800130681089305410AEFF05F9C13058108E3 -:1045D8009305C103EFE09F9683274101035BE10444 -:1045E80003278101B377FB003385E700634EA004FE -:1045F8001305010CEFE05F93131B0B01135B0B41D9 -:1046080063500B12930700001307C1033307F70029 -:10461800835607001307010C3307F70003570700F9 -:10462800638AE63A17D50000130585E3EFE05FC318 -:10463800630805089305010C17D50000130545E22A -:10464800EFE0DF8F6F00C00D93070009B38DA7401F -:104658009305010C1305C103EFE05F8E6352B00DA3 -:104668009306010C13870D001306F0006342E6045D -:1046780013D54D009307010C13171500930500FF80 -:10468800338DE700EFC0407A3305B50197D70000B6 -:104698009387C7DB131515003385A70083560D00D4 -:1046A8008357C512B3F7D7002310FD006FF0DFF46E -:1046B80023900600130707FF938626006FF01FFB61 -:1046C8001305010CEFE0DFB9630805009305010C41 -:1046D800138505006FF0DFF617D50000130545D8E0 -:1046E800EFE05FDC130D05001305010CEFE09FDB25 -:1046F800130B0500630C0D146302051217D5000097 -:10470800130505D6EFE01FB9130B05001305010CBF -:10471800EFE05FB86314AB101305010CEFF04F81A5 -:1047280093070000130781083307F7008356070033 -:104738001307010C3307F700035707006390E602DD -:104748009387270013072001E39EE7FC9305410A9E -:1047580013058108EFE08FFE33049401130C4C011C -:104768009307400693DC1C00E314FCE48357610BB9 -:104778000357E1079305C1061305410AB387E7000C -:1047880037C7FFFF130727F7B387E700231BF10A93 -:10479800EFE0CFFA9305810817D50000130545CC43 -:1047A800EFE0CFF9130B0000B71C0000930D401089 -:1047B80097D70000938707CC9305410A17D50000C7 -:1047C800130545DA338C6701EFE05FBDE34EA0C8FF -:1047D8009305410A13050C00EFE05FBC6348A00293 -:1047E8001306410A930506009306011513050C00EC -:1047F800EFF0CFF91306810893060115930506001B -:1048080013050C00EFF08FCD33049401130B4B010B -:1048180093DC1C00E31EBBF96FF01FC517D5000021 -:10482800130505C49305010CEFE04FF11305010CC6 -:10483800EFE01FA3E31605EE8357210D3787FFFF2F -:10484800B3C7E7002319F10C6FF09FEDE31005E8FB -:104858009305C10D17D50000130585C0EFE01FA70C -:104868009305810F1305010CEFE05FA60357C10DF7 -:10487800835DA10F8357E10D1347F7FF131D070150 -:10488800135D0D01231EA10DB387B7416354F008D2 -:10489800930541111305810F232EF100EFE00FED71 -:1048A8009305810F1305C10DEFE04FEC9305C10D82 -:1048B80013054111EFE08FEB8327C101835DA10F41 -:1048C800B307F0401307F0F663C6E70893850700BF -:1048D8001305C10DEFE0DFC2130D05000357C10D2D -:1048E8008357810F9305810F1305C10D631EF70CC4 -:1048F800EFE05F82930701151307000493860D000C -:1049080013060B0093050D001305810FEFE05FFC04 -:104918006F004004E39807FA9305810F1305C10D52 -:10492800EFE00FE7631805068357810F6388A70137 -:104938001305010CEFE04FDF6FF09FDE63940D026B -:104948000317E10F93070000634007021305810F67 -:10495800EFE0CFEC9305010C1305810FEFE0DFDFEB -:104968006FF01FDC93070000130760019306810FA7 -:104978003386F6000356260063080600938D1D0053 -:10498800231DB10F6FF01FFD93872700E390E7FE0B -:104998006FF01FFF130D0000E352A0F493054111BF -:1049A8001305810FEFE08FDC9305810F1305C10D0F -:1049B800EFE0CFDB9305C10D13054111EFE00FDBED -:1049C800130D0B006FF09FF1EFE04FF8130B100081 -:1049D8006FF05FF29387270013072001E396E7C281 -:1049E8006FF01FD48357E10717DB0000130B8BB759 -:1049F8006388070A9305010C1305C106374B0000AD -:104A0800EFE0DF8C130BEBFF130C50FD8357810D88 -:104A180093F77700639207069305410A1305010C83 -:104A2800EFE0CFD41305410AEFE04FDA1305410A4E -:104A3800EFE0CFD99305410A1305010CEFE08FEDA4 -:104A48008357610A938737002313F10A8357810A32 -:104A5800639007128357C10B639007028357610A5B -:104A6800636CFB009305010C1305410A1304F4FF62 -:104A7800EFE0CFCFE31C84F99305C1061305010CC1 -:104A8800EFE09FCD6F0040021306C10693060115A3 -:104A98009305060013050B00EFF04FA41304F4FF71 -:104AA8008317C107E3D207FE9305010C1305C1065E -:104AB800EFE0CFC89305810817D500001305459A84 -:104AC800EFE0CFC7930C000037FBFFFF17DD0000B6 -:104AD800130D4D9A930D401097D70000938707AC9C -:104AE800338797019305010C17D5000013054597E7 -:104AF800232AE100EFE09F8A330C9D01032741013F -:104B0800635AA0049305010C13050700EFE01F8901 -:104B1800634805021306010C930506009306011568 -:104B280013050C00EFF08F9B1306810893060115FF -:104B38009305060013050C00EFF04F9A3304640147 -:104B48001357FB01330B6701938C4C01135B1B401C -:104B5800E394BCF9130681089306011597D5000064 -:104B68009385059013050600EFF04FC26FF0DF8FB5 -:104B78001305410AEFE08FC58357610A9387170031 -:104B88006FF09FEC1305C106EFE04FC99305410A8A -:104B98001305C106EFE08FBD1305410AEFE00FC80A -:104BA8001305410AEFE08FC79305C1061305410AB3 -:104BB800EFE04FD6130601159305C10613058108CA -:104BC800EFF08F831304F4FF035BC1196FF09F8E1E -:104BD800130B0B039307E002A30A6111230BF110D7 -:104BE800130B7111930A0B00B3876A416356FC04D7 -:104BF8008357C11913074000138BFAFFE356F79246 -:104C0800130750006384E70893070B001306E002BC -:104C180093058003930600039387F7FF03C70700F4 -:104C28001377F70763580C0A130710032380E7006C -:104C3800130414006FF05F8F1305C106EFE00FBE79 -:104C48009305410A1305C106EFE04FB21305410A67 -:104C5800EFE0CFBC1305410AEFE04FBC9305C10656 -:104C68001305410AEFE00FCB130601159305C106A2 -:104C780013058108EFE05FF88347C119938A1A008A -:104C880093870703A38FFAFE6FF01FF69305810839 -:104C98001305C106EFE05FAC97C500009385057B5F -:104CA80013058108EFE08FEFE31005F6E34E0C865D -:104CB80083C7EAFF938727FD93B7170093C7F7FFCA -:104CC800B307FB0083C7070093F71700E38E078439 -:104CD8006FF09FF36314C70203C7F7FF93068003BF -:104CE80063E8E60013071700A38FE7FE6FF0DF8382 -:104CF80013041400130710036FF01FFF63E8E500A7 -:104D0800130717002380E7006FF01F822380D70066 -:104D18006FF09FF01304140023A08B0093870A0000 -:104D28009306E00203C70700631607001307500441 -:104D38006F00C002630CD700938717006FF09FFEC7 -:104D480003C7170093871700A38FE7FE03C7070061 -:104D5800E31807FE6FF09FFD9387F7FF83C60700F0 -:104D68006384E600E3EAFAFE238007006F0000157B -:104D7800938717006F004015138406006F00C01555 -:104D88001304F4FF230004000347F4FF6316D7005D -:104D980033075441E3C6E7FE9307300013879900B1 -:104DA8006314FA0283270116B384F40063D804005D -:104DB800230A011023A00B0013840A0083A70B0009 -:104DC800B389F900138739002322090493074000A7 -:104DD80093864701832549046378D706130509009C -:104DE800EF00904A2320A90493850A009304050044 -:104DF800EF20400A8327C100638807003304544129 -:104E08003384840023A087008320C11D0324811DCF -:104E1800138504000329011D8324411D8329C11C16 -:104E2800032A811C832A411C032B011C832BC11BD1 -:104E3800032C811B832C411B032D011B832DC11ABD -:104E48001301011E67800000938515002322B90411 -:104E5800939717006FF0DFF7B78700009387F7FF86 -:104E68006318F7EE97D500009385C58463860A001A -:104E780097D5000093854583130541113724000019 -:104E8800EF10504E1304F470832701011305010538 -:104E980023208116232AF114EFE0CFE0930A411171 -:104EA8006318050013050105EFE08FBBE30405E671 -:104EB800B72700009387F77023A0FB0093870A00A9 -:104EC800130600029306D00203C70700E302C7EAED -:104ED800E300D7EA13840A009387170003C7F7FF94 -:104EE80093061400A38FE6FEE31807E813072000D3 -:104EF800930710006308EA008327011663D497001C -:104F080093870400930600036FF01FE89307A0003F -:104F1800130CA002E31EFBCA93071003A30AF110A7 -:104F28009307E002230BF110130CA0026FF04FDE81 -:104F380083270500130101FC930541012320F1009B -:104F480083274500232E11022322F10083278500A1 -:104F58002324F1008327C500130501002326F1004F -:104F6800EFE09F86835761021305000093C7F7FFA0 -:104F780013971701631A070013054101EFE04FAEBD -:104F880013351500130515008320C103130101040F -:104F9800678000001305050F6780000097E7000091 -:104FA800938747B683A7070003A547036316050041 -:104FB80017D500001305855D1305050F67800000F0 -:104FC80097E70000938707B483A7070003A5470363 -:104FD8006316050017D500001305455B1305050F7B -:104FE8006780000063080606130101FF97C50000EB -:104FF8009385C56D1305060023248100232611001F -:1050080013040600EF1050516308050297C500000D -:105018009385856B13050400EF101050630E05008F -:1050280097C500009385C52513050400EF10D04EE1 -:10503800930700006316050097C700009387C768A9 -:105048008320C10003248100138507001301010197 -:105058006780000097C700009387076713850700DC -:105068006780000097E700009387C7A983A7070018 -:1050780083A747036396070097D7000093870751D4 -:1050880003C58712678000000325C50E67800000EE -:1050980097E70000938707A783A7070083A747031D -:1050A8006396070097D700009387474E03A5C70E5E -:1050B8006780000097E700009387C7A41386050060 -:1050C8009305050003A507006FF0DFF1130101FA4E -:1050D800232A9104938405008395E500232C8104F9 -:1050E800232E11041304060063DE050083D7C400D1 -:1050F80023A0060093F70708639807049307004066 -:105108006F00C004130641012326D100EF500004AC -:105118008326C100E34C05FC03278101B7F7000093 -:1051280037150000B3F7E70037E7FFFFB387E7005D -:1051380093B7170023A0F600930700402320F4003C -:10514800130505806F000001930700042320F40075 -:10515800130500008320C10503248105832441052C -:10516800130101066780000083D7C500130101FE03 -:10517800232C8100232E1100232A910023282101AA -:1051880093F7270013840500638807029307340404 -:105198002320F4002328F40093071000232AF400A6 -:1051A8008320C101032481018324410103290101D2 -:1051B80013010102678000009306C10013068100F5 -:1051C80093040500EFF09FF0832581001309050083 -:1051D80013850400EF004008631005028317C4001C -:1051E80013F70720E31E07FA93F7C7FF93E7270093 -:1051F8002316F4006FF09FF997D7FFFF93870756A0 -:1052080023AEF4028357C4002320A4002328A4005B -:1052180093E707082316F40083278100232AF40064 -:105228008327C100638207028315E4001385040005 -:10523800EF50003D630A05008357C40093F7C7FF8A -:1052480093E717002316F4008357C4003369F90065 -:10525800231624016FF0DFF4130101FD2326110248 -:10526800232481022322910223202103232E3101AA -:10527800232C4101232A510123286101232671018E -:10528800232481019387B500130760016374F70431 -:1052980093F487FF63D204049307C0002320F5002A -:1052A800130500008320C1020324810283244102E4 -:1052B800032901028329C101032A8101832A4101AB -:1052C800032B0101832BC100032C8100130101036F -:1052D8006780000093040001E3E0B4FC13090500B3 -:1052E800EF00007A9307701F97D900009389C9408F -:1052F80063EA9704138784003387E900032447008F -:10530800930687FF93D734006318D4000324C7009B -:105318009387270063008708832744000327C40076 -:105328008326840093F7C7FFB307F40023A6E6009B -:105338002324D70003A747001367170023A2E70019 -:105348006F00C00A13D794009307F003630A07009D -:105358009307400063E4E70A93D7640093878703C1 -:1053680013871700131737003387E9000324470012 -:10537800930587FF1305F000630CB400032744006E -:105388001377C7FF330697406352C50C9387F7FF1F -:105398009387170003A4090197D500009385453624 -:1053A8006302B414032744009306F0001377C7FF81 -:1053B8003306974063DEC60A93E714002322F400FD -:1053C800B306940097D7000023A2D73497D70000DC -:1053D80023ACD7329367160023A6B60023A4B600E1 -:1053E80023A2F6003307E4002320C70013050900B1 -:1053F800EF004069130584006FF0DFEA930740016E -:1054080063E6E7009307B7056FF09FF5930740053C -:1054180063E8E70093D7C4009387E7066FF05FF46B -:105428009307401563E8E70093D7F400938777075D -:105438006FF01FF3930640559307E007E3E2E6F2A7 -:1054480093D724019387C7076FF09FF18326C40081 -:10545800634C06008327840023A6D70023A4F60004 -:10546800B307E4006FF01FED138406006FF0DFF060 -:1054780097D6000023ACB62897D6000023A6B628F6 -:10548800634C06003307E4008327470093E71700BF -:105498002322F7006FF09FF59306F01F03A8490039 -:1054A80063E2E61A13573700135627409306100095 -:1054B80013071700B396C600131737003387E900A0 -:1054C800B3E6060117D60000232AD6228326070052 -:1054D800130687FF2326C4002324D4002320870033 -:1054E80023A6860013D72740130310003313E300C5 -:1054F80003A74900636C6706B3766700639C0600E0 -:1055080093F7C7FF13131300B37667009387470019 -:10551800E38A06FE130EF00093963700B386D9008F -:1055280013880600138507000324C800631E041DA2 -:10553800130515001377350013088800E31607FED6 -:1055480013F737006314072403A749009347F3FFB1 -:10555800B377F70017D700002322F71A03A74900EB -:1055680013131300636467006316032483AB890075 -:1055780003A44B00937AC4FF63E89A0033879A40E8 -:105588009307F00063C0E73697D700009387075961 -:1055980003A4070097D700009387075783A607003F -:1055A8001307F0FF33848400138A07006398E6200A -:1055B800130404019305040013050900EF10404487 -:1055C8009307F0FF130B05006302F52AB3875B010D -:1055D8006374F500639C3B2917DC0000130C8C54A2 -:1055E80003270C003307E40097D6000023ACE652EB -:1055F8006392671F93964701639E061C83A78900E1 -:1056080033848A001364140023A2870017D700008C -:105618001307875083270C00032707006376F700DA -:1056280017D70000232AF74E17D700001307874E15 -:1056380003270700637CF72217D70000232CF74CB9 -:105648006F00C022135697009306400063E8C60413 -:105658009356670093868603138616001316360042 -:105668003386C900130586FF032606006314C508A0 -:105678001307100093D62640B316D700B3E60601E9 -:1056880017D70000232CD7062326A4002324C40000 -:1056980023248500232686006FF0DFE4930640016B -:1056A80063E6C6009306B6056FF01FFB9306400538 -:1056B80063E8C6009356C7009386E6066FF0DFF9E5 -:1056C8009306401563E8C6009356F700938676075D -:1056D8006FF09FF8130540559306E007E36EC5F693 -:1056E800935627019386C6076FF01FF70326860097 -:1056F8006308C5008326460093F6C6FFE368D7FE15 -:105708000325C6006FF05FF8032744000326C40092 -:105718001377C7FFB308974063541E0593E7140037 -:105728002322F40083278400B30694003307E4009F -:1057380023A6C7002324F60097D7000023A8D7FC88 -:1057480097D7000023A2D7FC93E7180023A6B6003A -:1057580023A4B60023A2F600232017016FF01FC967 -:1057680063C208023307E4008327470093E7170062 -:105778002322F7008327840023A6C7002324F600EA -:105788006FF0DFC6130406006FF05FDA138786FF39 -:1057980083A606009387F7FFE384E6DA6FF01FDC41 -:1057A8009387470013131300B3766700E38A06FE56 -:1057B8006FF09FD6930705006FF01FFFB717000023 -:1057C8009387F7003304F400B7F7FFFF3374F4004E -:1057D8006FF05FDE03260A009306F0FF631CD60A0B -:1057E80097D7000023A2673393757B006388050071 -:1057F80093078000B385B740330BBB00B717000091 -:10580800B385F50033048B009387F7FF3374F400F6 -:10581800338A854093050A0013050900EF10401EDE -:105828009307F0FF6316F50013050B00130A000039 -:1058380083270C0033056541B3874701330A4501C7 -:1058480017D700002320F72E136A1A0097D70000F5 -:1058580023A867EB23224B01E38A3BDB1307F00005 -:1058680063645705930710002322FB0083A7890070 -:1058780083A7470093F7C7FF3387974063E69700EE -:105888009307F00063C0E70613050900EF00801FC7 -:105898006FF01FA1B307FB40B387E70017D70000DD -:1058A8002322F7286FF05FF483A74B0013844AFF85 -:1058B800137484FF93F71700B3E7870023A2FB0054 -:1058C80093065000B3878B0023A2D70023A4D700E8 -:1058D800E37E87D293858B0013050900EFD0CFA70D -:1058E8006FF0DFD203A4890093E714002322F400A9 -:1058F800B307940097D6000023A4F6E06FF0DFA367 -:1059080097D700009387072083A7070083A747033B -:105918006396070097D70000938747C703A3470EEE -:1059280067000300639A0502130101FF9305C10094 -:1059380013050000630E06001305E0FF638A0600E6 -:105948008347060023A0F500034506003335A00071 -:1059580013010101678000001305000063000602BF -:105968001305E0FF638C06008347060023A0F500BB -:10597800034506003335A0006780000067800000FB -:1059880093F5F50F3306C5006316C500130500002F -:105998006780000083470500E38CB7FE13051500F8 -:1059A8006FF09FFE1303F00013070500637EC30228 -:1059B8009377F7006390070A63920508937606FFCA -:1059C8001376F600B386E6002320B7002322B7003B -:1059D8002324B7002326B70013070701E366D7FE81 -:1059E8006314060067800000B306C3409396260040 -:1059F80097020000B38656006780C6002307B700E9 -:105A0800A306B7002306B700A305B7002305B70010 -:105A1800A304B7002304B700A303B7002303B70008 -:105A2800A302B7002302B700A301B7002301B70000 -:105A3800A300B7002300B7006780000093F5F50FB7 -:105A480093968500B3E5D50093960501B3E5D50097 -:105A58006FF0DFF69396270097020000B386560092 -:105A680093820000E78006FA93800200938707FF7D -:105A78003307F7403306F600E378C3F66FF0DFF339 -:105A880067800000678000008327C504130101FFB9 -:105A980023229100232021012326110023248100A1 -:105AA80093040500138905006382070403A7C4044F -:105AB80093172900B307F70003A50700631005062D -:105AC800130410003314240113065400131626007F -:105AD8009305100013850400EF40C02E63020502F1 -:105AE80023222501232485006F00C003130610021A -:105AF80093054000EF40002D23A6A404E31805FAFF -:105B0800130500008320C100032481008324410081 -:105B18000329010013010101678000000327050024 -:105B280023A0E70023280500232605006FF09FFD2A -:105B38006380050283A74500139727008327C504C0 -:105B4800B387E70003A7070023A0E50023A0B70059 -:105B580067800000130101FD2322910283A405013F -:105B6800232A5101B70A010023248102232021039B -:105B7800232E310123286101232671012324810169 -:105B880023261102232C410123229101130B050026 -:105B980013840500930B06001389060093894501B9 -:105BA800130C0000938AFAFF83AC090093850B005D -:105BB8009389490033F55C01EFB00027330A2501CA -:105BC80093850B0013D50C01EFB0002693570A01FB -:105BD8003305F50013590501337A5A0113150501E8 -:105BE8003305450123AEA9FE130C1C00E34E9CFAB5 -:105BF800630009068327840063C0F40483254400F6 -:105C080013050B0093851500EFF01FE80326040128 -:105C18009305C400930905001306260013162600F1 -:105C28001305C500EF40D0279305040013050B00AA -:105C3800EFF01FF01384090093874400939727001F -:105C4800B307F40023A227019384140023289400A7 -:105C5800130504008320C102032481028324410226 -:105C6800032901028329C101032A8101832A4101F1 -:105C7800032B0101832BC100032C8100832C4100DD -:105C88001301010367800000130101FE232C81002A -:105C98002324410113840500130A0500930590008D -:105CA80013858600232A91002328210123225101EC -:105CB800232E11002326310193040600938A06003F -:105CC80013090700EFB08018930710009305000030 -:105CD80063C2A70813050A00EFF01FDB9307100043 -:105CE8002328F500232A25019307900063DA9706F5 -:105CF8001309940093090900330494009389190047 -:105D080083C6F9FF930505001306A000938606FDD8 -:105D180013050A00EFF01FE4E39289FE33049900AB -:105D2800130484FFB3848440B307940063C0570509 -:105D38008320C10103248101832441010329010136 -:105D48008329C100032A8100832A4100130101022B -:105D58006780000093971700938515006FF05FF731 -:105D68001304A400930490006FF0DFFB13041400E5 -:105D78008346F4FF930505001306A000938606FDED -:105D880013050A00EFF01FDD6FF01FFA3707FFFF5A -:105D98003377E50093070500130500006316070035 -:105DA8009397070113050001370700FF33F7E70052 -:105DB800631607001305850093978700370700F0DF -:105DC80033F7E7006316070013054500939747006C -:105DD800370700C033F7E7006316070013052500EF -:105DE8009397270063CC07001397170063560700A3 -:105DF8001305150067800000130500026780000086 -:105E08008327050013F77700630E070293F6170040 -:105E180013070000639C060013F72700630C0700B4 -:105E280093D717002320F500130710001305070068 -:105E38006780000093D727002320F5001307200070 -:105E48006FF0DFFE9396070193D606011307000053 -:105E58006396060093D707011307000193F6F70F1F -:105E6800639606001307870093D7870093F6F70019 -:105E7800639606001307470093D7470093F6370049 -:105E8800639606001307270093D7270093F6170099 -:105E98006398060093D71700638807001307170055 -:105EA8002320F5006FF09FF8130700026FF01FF82A -:105EB800130101FF232481001384050093051000BA -:105EC80023261100EFF05FBC232A85008320C10040 -:105ED80003248100130710002328E50013010101A2 -:105EE8006780000003A7050183270601130101FA53 -:105EF800232A910423244105232E1104232C8104F1 -:105F08002328210523263105232251052320610555 -:105F1800232E7103232C8103232A91032328A10311 -:105F28002326B103138A0500930406006356F7007D -:105F3800130A06009384050003290A0183A90401B2 -:105F480083278A0083254A00330C390163D48701EB -:105F580093851500EFF05FB3930B4501931C2C005C -:105F6800130D0500B38C9B0193870B0063E497091D -:105F7800130A4A0113192900B3072A01938444011B -:105F8800939929002326F100B70A0100B387340149 -:105F98002328F100938AFAFF8327010163E2F406BC -:105FA80063588001938CCCFF83A70C00638A071881 -:105FB8008320C1050324810523288D0113050D00C5 -:105FC80083244105032901058329C104032A810487 -:105FD800832A4104032B0104832BC103032C81036F -:105FE800832C4103032D0103832DC10213010106F4 -:105FF8006780000023A00700938747006FF01FF712 -:1060080083AD0400B3FD5D0163880D0813890B009F -:1060180013070A00930900000326070093850D0063 -:106028000324090033755601232AE100232CC100FB -:10603800EFA0905F0326810103274101337B5401C0 -:10604800330B6501130747001355060193850D00AF -:10605800330B3B01232AE100232EE10013540401F2 -:10606800EFA0905C3305850013540B0133058500C0 -:1060780093590501337B5B01131505018327C10083 -:10608800032741011306490033656501232EA6FE47 -:106098006360F70A2322390103D92400630409083D -:1060A80003A40B00938D0B0093090A0093060000CC -:1060B80003A5090093050900232AD100337555016A -:1060C800EFA0905603DB2D00832641013374540161 -:1060D800330B6501330BDB0013150B0133648500AB -:1060E80023A08D009389490003D5E9FF13864D004D -:1060F80093050900232AC100EFA0105303A44D0003 -:106108008327C100135B0B013374540133048500EA -:1061180033046401935604010326410163EEF90038 -:1061280023A28D0093844400938B4B006FF0DFE62D -:10613800130906006FF05FEE930D06006FF05FF72E -:10614800130CFCFF6FF0DFE5130101FE232A910019 -:106158002328210123263101232E1100232C81001D -:1061680023244101937736001309050093040600A0 -:1061780093890500638407029387F7FF17B7000028 -:106188001307C75593972700B307F70003A607001F -:1061980093060000EFF01F9C9309050093D4244058 -:1061A8006380040803248904631E040093051027F0 -:1061B80013050900EFF0DFCF2324A9041304050019 -:1061C8002320050093F714006384070293850900D0 -:1061D8001306040013050900EFF0DFD0130A0500C9 -:1061E8009385090013050900EFF09F9493090A00AD -:1061F80093D414406386040203250400631E05003B -:10620800130604009305040013050900EFF09FCD61 -:106218002320A40023200500130405006FF09FFA33 -:106228008320C101032481011385090083244101CE -:10623800032901018329C100032A810013010102F6 -:1062480067800000130101FD232291029384050059 -:10625800232E310183A904012324810283A545004B -:106268001354564083A78400B30934012320210323 -:10627800232A510123261102232C4101930A0500E8 -:106288001389190063C6270D13850A002326C10048 -:10629800EFF08FFF0326C10093074501130A05009D -:1062A8009386070013070000938646006348870A11 -:1062B800635404001304000083A60401131424008B -:1062C8003387870093962600938744011376F60157 -:1062D800B386D700630E0608130800023308C840C7 -:1062E8009305000003A5070093084700938747001C -:1062F8003315C500B365B50023AEB8FE83A5C7FF47 -:10630800B3D5050163E2D7062322B70063840500ED -:10631800138929001309F9FF23282A0113850A0084 -:1063280093850400EFF0DF808320C10203248102FB -:1063380013050A0083244102032901028329C101AC -:10634800032A8101832A41011301010367800000A8 -:1063580093851500939717006FF0DFF223AE06FEC2 -:10636800130717006FF05FF4138708006FF09FF7AB -:106378009387470003A6C7FF13074700232EC7FECE -:10638800E3E8D7FE6FF01FF98327050103A705018E -:10639800B387E740639C07021317270013054501DD -:1063A80093854501B306E500B385E5009386C6FFEE -:1063B8009385C5FF03A6060003A70500630CE60046 -:1063C8009307F0FF6364E600930710001385070046 -:1063D80067800000E36CD5FC6FF05FFF130101FEDE -:1063E800232A910093840500232631019305060092 -:1063F8009309050013850400232C8100232E110026 -:106408002328210113040600EFF01FF8631C05027E -:106418009305000013850900EFF00FE793071000BC -:106428002328F500232A05008320C10103248101C4 -:1064380083244101032901018329C10013010102B9 -:106448006780000013091000634A050093070400E1 -:106458001309000013840400938407008325440073 -:1064680013850900EFF04FE20323040183A8040118 -:1064780013064401131E230013884401939828002F -:10648800B70E010023262501330EC601B3081801F3 -:1064980093064501130F0000938EFEFF03270600A5 -:1064A800832F080093864600B375D701B3F7DF0141 -:1064B800B385E501B385F54093DF0F0193570701D5 -:1064C800B387F74113D70541B387E70013DF0741C7 -:1064D800B3F5D50193970701B3E7B7001308480050 -:1064E80023AEF6FE13064600E36A18FBB705010063 -:1064F8009385F5FF636CC6019386C6FF83A70600E4 -:1065080063820704232865006FF01FF283270600C3 -:10651800938646001306460033F7B7003307E701B2 -:106528001358074193D70701B387070113DF0741C2 -:106538003377B70093970701B3E7E70023AEF6FE7A -:106548006FF05FFB1303F3FF6FF01FFBB707F07FDC -:10655800B3F5B700B707C0FCB385F5006358B000C2 -:10656800930700001385070067800000B305B0405B -:1065780093D74541130730016348F700B705080072 -:10658800B3D5F5406FF0DFFD9387C7FE9306E001B2 -:10659800930500001307100063C6F60093C7F7FFC2 -:1065A8003317F700930707006FF0DFFB130101FDB6 -:1065B8002322910283240501232E310193094501E9 -:1065C80093942400B38499002324810203A4C4FF74 -:1065D800232021032326B1001305040023261102DA -:1065E800EFF0CFFA8325C10093070002B387A740D5 -:1065F80023A0F5009307A0001389C4FF63CCA70468 -:106608009307B000B387A7403707F03FB356F400AD -:10661800B3E6E6001307000063F4290103A784FF2B -:10662800130555013315A400B357F700B367F500F8 -:106638008320C10203248102832441020329010229 -:106648008329C101138507009385060013010103FF -:10665800678000009307000063F6290183A784FF81 -:10666800138984FF130555FF630E05021307000203 -:106678003306A7403314A4003707F03F3364E4001F -:10668800B3D6C700B366D4001307000063F429012A -:106698000327C9FFB397A7003357C700B3E7E7003D -:1066A8006FF01FF9B706F03FB366D4006FF05FF8DC -:1066B800130101FD232481021384050093051000B2 -:1066C800232291022320210393040600232E310163 -:1066D800232C41011309070023261102138A0600FF -:1066E800EFF08FBA370710009307F7FFB3F797005B -:1066F80093D4440193F4F47F93090500639A040842 -:106708002326F100630E0408130581002324810069 -:10671800EFF00FEF83268100630005080327C1000F -:1067280093070002B387A740B317F700B3E7D70072 -:106738003357A70023AAF9002326E1000324C10048 -:1067480023AC8900333480001304140023A8890083 -:10675800638A04069384D4BCB384A40093075003CB -:1067680023209A003385A7402320A9008320C10253 -:1067780003248102138509008324410203290102AD -:106788008329C101032A81011301010367800000E5 -:10679800B3E7E7006FF0DFF623AAD9006FF01FFA1E -:1067A8001305C100EFF0CFE58327C10013050502EB -:1067B8001304100023AAF9009307100023A8F90076 -:1067C8006FF01FF9931724001305E5BCB387F90090 -:1067D8002320AA0003A5070113145400EFF00FDBD0 -:1067E8003304A440232089006FF05FF8130101FDF2 -:1067F800232C4101138A05009305810023261102E9 -:106808002324810223229102232E3101232A5101BC -:106818002328610123202103130B0500EFF01FD962 -:1068280013040500938905009384050013050A00E5 -:106838009305C100EFF09FD7930A050083270B014A -:1068480003250A010327C100B387A7400325810058 -:10685800939757003305E5403385A7006358A00494 -:106868001315450193860500B30435019387060087 -:1068780013860A0013050400938504009386070015 -:10688800EF60C0128320C1020324810283244102E5 -:10689800032901028329C101032A8101832A4101B5 -:1068A800032B010113010103678000001389050010 -:1068B800B705F0FFEFA04057B30625016FF01FFBA7 -:1068C800130101FF23248100232611002322210123 -:1068D80023203101930770011304050063CAA7023E -:1068E8001314350097B70000938747DF3384870078 -:1068F80003250401832544018320C100032481006A -:106908000329410083290100130101016780000068 -:1069180097B700009387076503A5070083A547007D -:1069280097B700009387876403A9070083A94700E6 -:1069380013060900938609001304F4FFEF6010089A -:10694800E31804FE6FF05FFB9387F5FF032706014A -:1069580093D75740938717009397270093064601CC -:1069680013172700B307F5003387E60063E6E60050 -:10697800636EF500678000009386460003A6C6FF95 -:1069880013054500232EC5FE6FF05FFE1305450075 -:10699800232E05FE6FF0DFFD8326050193D75540B2 -:1069A8001307450163C0F60463D4D70293F5F501D4 -:1069B8006380050293962700B306D70003A6060056 -:1069C80013051000B356B600B395B6006318B602A7 -:1069D80093972700B307F700636AF70013050000D1 -:1069E80067800000938706006FF09FFE9387C7FFBC -:1069F80083A60700E38206FE1305100067800000E7 -:106A0800130101FF232481001304050013850500E9 -:106A180097C7000023AC071223261100EFA0806B54 -:106A28009307F0FF631CF50097C7000093870712D0 -:106A380083A70700638407002320F4008320C10094 -:106A4800032481001301010167800000130101FF85 -:106A580023229100B70400802324810023261100FB -:106A680093C4F4FF33F7B400232006003708F07FFF -:106A7800930605009387050013040600635407076F -:106A88003368A70063000806B707100013860500DF -:106A98006356F70297B700009387C74D03A6070010 -:106AA80083A64700EF6080719307A0FC930605005A -:106AB8001386050033F7B4002320F400832704006D -:106AC80013574741130727C03387E700B7071080DC -:106AD8009387F7FF3376F600B707E03F2320E400FB -:106AE800B367F6008320C10003248100832441009A -:106AF80013850600938507001301010167800000D4 -:106B0800130101F6232AF108B707008093C7F7FF9E -:106B1800232EF1002328F100B707FFFF2326D10811 -:106B28002324B100232CB100938787209306C10842 -:106B380093058100232E1106232AF1002328E1085A -:106B4800232C0109232E11092322D100EF00803CB8 -:106B580083278100238007008320C1071301010ACE -:106B680067800000130101F6232AF108B7070080A7 -:106B780093C7F7FF232EF1002328F100B707FFFF83 -:106B8800938787202324C1082326D1082328E108D6 -:106B9800232C0109232E1109232AF10097C700008D -:106BA800938747F62324A100232CA10003A50700FF -:106BB800930681081386050093058100232E11068C -:106BC8002322D100EF0000358327810023800700AE -:106BD8008320C1071301010A67800000130101FF28 -:106BE80023248100138405008395E50023261100E2 -:106BF800EF30D03E6340050283270405B387A70022 -:106C08002328F4048320C100032481001301010117 -:106C1800678000008357C40037F7FFFF1307F7FFAB -:106C2800B3F7E7002316F4006FF0DFFD130500004B -:106C38006780000083D7C500130101FE232C810063 -:106C4800232A91002328210123263101232E110014 -:106C580093F7071093040500138405001309060031 -:106C680093890600638A07008395E5009306200050 -:106C780013060000EF30901D8357C40037F7FFFF5D -:106C88001307F7FFB3F7E7002316F4008315E400B2 -:106C9800032481018320C10193860900130609009A -:106CA8008329C100032901011385040083244101BC -:106CB800130101026F30C00B130101FF232481006F -:106CC800138405008395E50023261100EF30101882 -:106CD8009307F0FF0357C4006312F502B7F7FFFFED -:106CE8009387F7FFB3F7E7002316F4008320C1006A -:106CF800032481001301010167800000B717000019 -:106D0800B367F7002316F4002328A4046FF01FFECE -:106D18008395E5006F3000163367B5009303F0FFE5 -:106D28001377370063100710B7877F7F9387F7F7CC -:106D38000326050083A60500B372F6003363F60048 -:106D4800B382F200B3E26200639272106316D6084F -:106D58000326450083A64500B372F6003363F600A8 -:106D6800B382F200B3E26200639E720C6316D60629 -:106D78000326850083A68500B372F6003363F60008 -:106D8800B382F200B3E262006398720C6316D60411 -:106D98000326C50083A6C500B372F6003363F60068 -:106DA800B382F200B3E262006392720C6316D602F9 -:106DB8000326050183A60501B372F6003363F600C6 -:106DC800B382F200B3E26200639C720A13054501C4 -:106DD80093854501E30ED6F4131706019397060130 -:106DE800631EF7001357060193D706013305F740D2 -:106DF8009375F50F6390050267800000135707012C -:106E080093D707013305F7409375F50F6394050091 -:106E1800678000001377F70F93F7F70F3305F740F4 -:106E2800678000000346050083C6050013051500AA -:106E3800938515006314D600E31606FE3305D64085 -:106E4800678000001305450093854500E31CD6FCC8 -:106E580013050000678000001305850093858500F1 -:106E6800E312D6FC13050000678000001305C50077 -:106E78009385C500E318D6FA130500006780000063 -:106E88001305050193850501E31ED6F813050000D7 -:106E9800678000009307050003C705009387170064 -:106EA80093851500A38FE7FEE31807FE67800000AF -:106EB800930705009387170003C7F7FFE31C07FE36 -:106EC8003385A7401305F5FF678000001307050009 -:106ED80063140600678000009385150083C6F5FFDC -:106EE800930717001308F6FFA38FD7FE63980600D1 -:106EF8003307C700639AE70067800000138707001D -:106F0800130608006FF0DFFC93871700A38F07FEB6 -:106F18006FF05FFE130101E32326111C2322911C4D -:106F28002320211D232E311B2322911B9389050029 -:106F380093040600938C06002324811C232C411BF8 -:106F4800232A511B2328611B2326711B2324811B01 -:106F58002320A11B232EB11913090500EFE00F848C -:106F680083270500138507002324F102EFF05FF45F -:106F780083D7C900232AA1002328010C232A010C46 -:106F8800232C010C232E010C93F7070863800704B8 -:106F980083A70901639C07029305000413050900F0 -:106FA800EFE08FAB23A0A90023A8A900631C05006C -:106FB8009307C0002320F9009307F0FF232CF1006A -:106FC8006F00405A9307000423AAF9009307C10EE3 -:106FD8002322F10C2326010C2324010C130A0000A0 -:106FE80093880700232A0102232801022324010091 -:106FF8002322010223260102232C0100138404000A -:107008001307500283470400638407006392E70C68 -:10701800B30A9440638A0A048327C10C23A098000A -:1070280023A25801B38757012326F10C8327810C2B -:107038001307700093888800938717002324F10CA6 -:10704800635EF7001306410C9385090013050900D8 -:10705800EF305068631205509308C10E83278101F1 -:10706800B3875701232CF10083470400639407007A -:107078006F109061930714002328F100A303010AFD -:10708800930BF0FF232E010013040000930A9000D5 -:10709800130CA0028327010103CB07009387170075 -:1070A8002328F10093070BFE1307A0056374F7006C -:1070B8006F10C02D17A700001307C77493972700F8 -:1070C800B387E70083A70700B387E7006780070057 -:1070D800130414006FF01FF397A7000093878735F8 -:1070E800232AF10293770402639407006F10C00B00 -:1070F800938C7C0093FC8CFF93878C0003AD0C0071 -:1071080083AC4C002326F10093771400638E0700AC -:10711800B3679D01638A0700930700032304F10AFC -:10712800A304610B136424001374F4BF93072000B5 -:107138006F0010481305090023221101EFD01FE644 -:1071480083274500138507002326F102EFF05FD659 -:107158002322A10213050900EFD05FE483278500ED -:10716800832841002324F10083274102E38407F2A6 -:1071780083278100E38007F283C70700E38C07F0C9 -:10718800136404406FF01FF18347710AE39407F01A -:1071980093070002A303F10A6FF0DFEF13641400F2 -:1071A8006FF05FEF83A70C00938C4C00232EF10047 -:1071B800E3D207EEB307F040232EF1001364440036 -:1071C8006FF05FED9307B0026FF0DFFC83270101DA -:1071D80003CB0700138D170063188B0583AB0C00D6 -:1071E80093874C0063D40B00930BF0FF938C07003C -:1071F8002328A1016FF01FEA13850B009305A00057 -:1072080023221101130D1D00EF9010428328410025 -:10721800034BFDFFB30BB501930D0BFDE3FEBAFD68 -:107228002328A1016FF01FE8930B00006FF0DFFE29 -:10723800136404086FF01FE6032D0101232E0100DB -:107248000325C1019305A00023221101130B0BFD97 -:10725800EF90903D130D1D00B307AB00034BFDFFEE -:10726800232EF1008328410093070BFDE3FAFAFC73 -:107278006FF01FFB136484006FF0DFE183270101C7 -:1072880003C7070093078006631CF70083270101E3 -:1072980013640420938717002328F1006FF09FDF01 -:1072A800136404046FF01FDF8327010103C707007D -:1072B8009307C006631CF700832701019387170013 -:1072C8002328F100136404026FF0DFDC1364040167 -:1072D8006FF05FDC93874C002326F10083A70C0036 -:1072E800A303010A2306F11223220100930B1000C5 -:1072F800930D0000930C0000130C0000130D000008 -:107308009304C1126F00503B136404019377040285 -:10731800638E0704938C7C0093FC8CFF93878C000E -:1073280003AD0C0083AC4C002326F10063DE0C0097 -:10733800330DA041B337A001B30C9041B38CFC408E -:107348009307D002A303F10A9307F0FFE39CFB68BD -:10735800E39E0C7093079000E3EAA771130D0D03E9 -:10736800A307A1199304F1186F00D06D93874C00FF -:107378002326F100937704016388070003AD0C000E -:10738800935CFD416FF09FFA9377040403AD0C0002 -:1073980063880700131D0D01135D0D416FF05FFE3B -:1073A80093770420E38E07FC131D8D01135D8D4137 -:1073B8006FF01FFD937784006382070C93874C005E -:1073C8002326F10083A70C0003A6070083A6470025 -:1073D80003A7870083A7C7002328C10C232AD10C41 -:1073E800232CE10C232EF10C1305010D232211018E -:1073F800EFD01FB42326A10A930720008328410059 -:107408006314F50C8327010D930501081305010981 -:107418002328F1088327410D23200108232201088E -:10742800232AF1088327810D232401082326010834 -:10743800232CF1088327C10D232EF108EF60C069C2 -:1074480083284100635605009307D002A303F10A7D -:107458009307700497A400009384C4FB63C6670174 -:1074680097A400009384C4FA1374F4F7232201004C -:10747800930B3000930D00006F00D05D938C7C005F -:1074880093FC8CFF83A50C0003A64C0093878C000B -:1074980013050109232211012326F100EF90403E34 -:1074A80083270109832841002328F10C83274109F8 -:1074B800232AF10C83278109232CF10C8327C10986 -:1074C800232EF10C6FF05FF2930710006318F5029A -:1074D8008327C10D63D607009307D002A303F10ADF -:1074E8009307700497A40000938444F3E3CE67F7EE -:1074F80097A40000938444F26FF01FF7137CFBFD00 -:10750800930710046310FC0A930700032304F10A8D -:1075180013071006930780056314EB009307800791 -:10752800A304F10A930730061364240063D2775149 -:1075380093851B001305090023221101EFD0DFD129 -:107548009304050083284100631A054E83D7C900B8 -:1075580093E707042396F90083D7C90093F7070434 -:10756800E39C07A48320C11C0324811C03258101FB -:107578008324411C0329011C8329C11B032A811B65 -:10758800832A411B032B011B832BC11A032C811A4D -:10759800832C411A032D011A832DC1191301011DD2 -:1075A800678000009307F0FF638EFB489307700421 -:1075B800232201006314FC00638C0B48832AC10D4D -:1075C800936704102320F102232C0102032E010DDE -:1075D800832D410D032D810D63DA0A00B707008062 -:1075E800B3CA57019307D002232CF1029307100462 -:1075F8006314FC4A13050109232411052328C10932 -:10760800232CA109232AB109232E5109EF90404CBC -:107618001306C10AEFF08FC3138605009305050012 -:1076280013050109EF90C0258327010913060106F8 -:10763800930501072328F10683274109130501084B -:1076480023200106232AF106832781092322010624 -:1076580023240106232CF1068327C109232EF106D2 -:10766800B707FC3F2326F106EF60005D03280108F9 -:107678000326410883268108032DC10893050108C4 -:10768800130501092328010923220105232AC1081A -:107698002320C104232CD108232ED102232EA10993 -:1076A8002320010823220108232401082326010896 -:1076B800EF60C01F8326C103032601040328410489 -:1076C8008328810463160500130710002326E10AA6 -:1076D8001307100697AA0000938ACAD56316EB0011 -:1076E80097AA0000938ACAD3138EFBFF938D0400D8 -:1076F800B7070340930501082322C10813050109B0 -:1077080013060107232411052322C105232001099B -:10771800232EF1062324D1082326A10923280106B4 -:10772800232A0106232C0106EF60005103260109D4 -:1077380083264109130501092320C104232ED10200 -:10774800EF80D06593050500130A050013050109AC -:10775800032D8109832CC109EF80907A83270109C1 -:10776800032601048326C1032320F1068327410948 -:107778002328C106930501072322F10683278109DF -:1077880013060106130501082324F1068327C109FE -:10779800232CA107232E91072326F106232AD1069D -:1077A800EF70900FB3854A0183C50500032E41048D -:1077B800832CC108938D1D0083220108832F410863 -:1077C800032F8108232EC103A38FBDFE9307F0FF6B -:1077D800138D0C0083288104630CFE06130EFEFF34 -:1077E8009305010813050109232EE105232CF10552 -:1077F800232A5104232811052326C10523285108CB -:1078080023245104232AF1092322F105232CE10919 -:107818002320E105232E91092320010823220108B2 -:107828002324010823260108EF6040088326010469 -:107838000326410403288104032EC104832801057B -:1078480083224105832F8105032FC105E31205EA31 -:10785800370DFE3F93050108130501092320110583 -:107868002328510823265104232AF1092324F1054A -:10787800232CE1092322E105232E91092320010865 -:1078880023220108232401082326A109EF60C00E42 -:10789800832801046346A0048322C104832F810442 -:1078A800032F4104930501081305010923285108F2 -:1078B800232AF109232CE109232E91092320010809 -:1078C80023220108232401082326A109EF50107E52 -:1078D800832801046318051A137A1A0063040A1A24 -:1078E80003C6FA00232EB10B930500038326C10BB0 -:1078F8009387F6FF232EF10A83C7F6FF6380C71626 -:10790800130690036390C71683C7AA00A38FF6FED9 -:10791800138A0D0013077004330A9A40032DC10A15 -:10792800631EEC2A1307D0FF6344ED0063DAAB3320 -:10793800130BEBFF930AFDFF2326510B9376FBFDF8 -:10794800930510041377FB0F130600006398B60025 -:107958001307F7001377F70F13061000230AE10A3D -:107968009307B00263D80A00930A1000B38AAA41A9 -:107978009307D002A30AF10A9307900063D4572B08 -:10798800130C310C130D0C00930D90009305A000FF -:1079980013850A0023201103EF9080531305050374 -:1079A800A30FACFE9305A00013850A00EF90004AD0 -:1079B800930CFCFF930A05008328010263C6AD24DB -:1079C800930A0503130CECFFA38F5CFF9307610B6D -:1079D8006360AC251307410BB387E7402328F10206 -:1079E800B38B47019307100063C6470193771400D0 -:1079F8006386070083274101B38BFB001374F4BF30 -:107A0800936704102320F102930C0000130C00006C -:107A1800130D000083278103638607001307D00234 -:107A2800A303E10A03240102930D00006F00C0487C -:107A3800232201009304C1126FF05FB82322A10032 -:107A48006FF0DFB723220100930B60006FF01FB7C0 -:107A580023227101930B10006FF05FB6A38FB6FE5F -:107A68006FF0DFE89387170093F7F70F6FF01FEABF -:107A7800130A1A00A30FEAFEB3874C41E3DA07FEA4 -:107A88006FF05FE98327C103138A0D001307000312 -:107A9800B38CFD006FF05FFE93076004630EFC007B -:107AA80093075004938C1B006304FC00938C0B0019 -:107AB800130620006F00C000938C0B0013063000E3 -:107AC8009307010B1308C10B1307C10A93860C0017 -:107AD8009305010913050900232011052328C1096D -:107AE800232EC103232AB109232CA109232E5109CE -:107AF800EFC0CFFF9307700493040500032EC10362 -:107B0800832801046316FC00937714006388070A2E -:107B180093076004338A94016312FC0603C70400C8 -:107B2800930700036318F704930501081305010977 -:107B3800232011052328C109232EC103232AB109B3 -:107B4800232CA109232E51092320010823220108EF -:107B58002324010823260108EF505055032EC103A2 -:107B6800832801046308050093071000B38C97412C -:107B78002326910B8327C10A330AFA0093050108CB -:107B880013050109232E11032328C109232AB1094A -:107B9800232CA109232E510923200108232201089F -:107BA8002324010823260108EF5050508328C103DD -:107BB80013070003631E0500232E410B032AC10B84 -:107BC8006FF05FD593861700232ED10A2380E70034 -:107BD8008327C10BE3E847FF6FF05FFE13076004DC -:107BE800E31AECD46352A00763960B0013771400D2 -:107BF8006302070C832741013307FD00B38BEB00B9 -:107C0800130B60066F004009138C0C006FF01FD82F -:107C1800130C1C000347FCFF93871700A38FE7FE94 -:107C28006FF01FDB1307610B63180600930700034F -:107C3800230BF10A1307710B938A0A0393071700A2 -:107C4800230057016FF01FD963960B0013771400B8 -:107C58006306070683274101138717006FF01FFA91 -:107C680063404D0313771400930B0D006306070060 -:107C780083274101B30BFD00130B70066F00C00191 -:107C880083274101130B7006B30BFA006346A0016A -:107C98003383AB41930B1300137C0440930C000017 -:107CA800E30A0CD6130C0000E356A0D79306F00F96 -:107CB8006F008003930B0D006FF09FF4130B6006A9 -:107CC800930B10006FF05FFD6356A70383278100B5 -:107CD800330DED4003C71700630C070293871700A5 -:107CE800130C1C002324F1008327810003C707001D -:107CF800E31CD7FC8325410233059C01232E110385 -:107D0800EF908012B30B75018328C1036FF09FD0E9 -:107D1800938C1C006FF05FFD13874C002326E10055 -:107D28001377040283A70C0063000702032781016D -:107D380023A0E7001357F74123A2E700832CC100D3 -:107D4800832401016FF08FAB1377040163080700E8 -:107D58000327810123A0E7006FF05FFE1377040477 -:107D680063080700035781012390E7006FF01FFDA8 -:107D780013740420E30E04FC034781012380E70009 -:107D88006FF0DFFB13640401937704026388070430 -:107D9800938C7C0093FC8CFF93878C0003AD0C00C4 -:107DA80083AC4C002326F1001374F4BF9307000042 -:107DB800A303010A1307F0FF638CEB4213070400C7 -:107DC800B3669D011374F4F76394064263820B5AF9 -:107DD800130710006392E7426FF04FD893874C0067 -:107DE8002326F100937704016386070003AD0C0096 -:107DF8006F000001937704046388070003DD0C001B -:107E0800930C00006FF05FFA93770420E38007FE7D -:107E180003CD0C006FF0DFFE93874C002326F100A2 -:107E2800B787FFFF93C707832314F10A97970000CA -:107E38009387075F03AD0C00232AF102930C00001F -:107E48001364240093072000130B80076FF05FF67C -:107E580093874C002326F100A303010A9307F0FF40 -:107E68002320110383A40C006386FB0213860B00F6 -:107E78009305000013850400EFD09FB02322A100D2 -:107E880083280102630805DEB30B95402322010015 -:107E98006FF04FDE13850400EFF08F818328010215 -:107EA800930B050023220100930D0000930C0000A2 -:107EB800130C0000130D00002320B10363D47D01CF -:107EC800232071030347710A63080700832701020F -:107ED800938717002320F102937A240063880A000D -:107EE80083270102938727002320F1029377440810 -:107EF800232CF102639807068327C1010327010297 -:107F0800338EE7406350C007130F000197AE00009F -:107F1800938E0EA6930F70008326810C23A0D801A0 -:107F28000327C10C9386160013868800634ACF473F -:107F38003307EE0023A2C8012326E10C2324D10C29 -:107F48001307700093080600635ED7001306410C00 -:107F58009385090013050900EF20D077E314056C19 -:107F68009308C10E0347710A630807041307710ACF -:107F780023A0E8001307100023A2E8000327C10C80 -:107F88009306700093888800130717002326E10CD6 -:107F98000327810C130717002324E10C63DEE60096 -:107FA8001306410C9385090013050900EF20907210 -:107FB800E31A05669308C10E63880A041307810A49 -:107FC80023A0E8001307200023A2E8000327C10C20 -:107FD8009306700093888800130727002326E10C76 -:107FE8000327810C130717002324E10C63DEE60046 -:107FF8001306410C9385090013050900EF20906DC5 -:10800800E31205629308C10E832781031307000852 -:108018006398E7068327C10103270102B38AE74073 -:1080280063505007130E000197A7000093874795E8 -:10803800930E70008326810C23A0F8000327C10C3F -:10804800938616001386880063485E3B3387EA00F0 -:1080580023A258012326E10C2324D10C1307700016 -:1080680093080600635ED7001306410C9385090048 -:1080780013050900EF201066E316055A9308C10E90 -:10808800B38A7D41635050071308000197AD000083 -:10809800938D0D8F130E70000327810C23A0B80158 -:1080A8008326C10C1307170013868800634E5839BE -:1080B80023A25801B38ADA002326510D2324E10CA8 -:1080C800930670009308060063DEE6001306410C71 -:1080D8009385090013050900EF20D05FE3140554C8 -:1080E8009308C10E13770410832DC10C6312073A4D -:1080F8003383BB0123A0980023A278012326610CB7 -:108108008327810C130770009388880093871700D2 -:108118002324F10C6352F74C1306410C9385090094 -:1081280013050900EF20105BE31E054E9308C10EEE -:108138006F00804A13640401937704026382070284 -:10814800938C7C0093FC8CFF93878C0003AD0C0010 -:1081580083AC4C002326F100930710006FF05FC535 -:1081680093874C002326F100937704016386070068 -:1081780003AD0C006F0000019377040463880700C7 -:1081880003DD0C00930C00006FF01FFD93770420B3 -:10819800E38007FE03CD0C006FF0DFFE9797000029 -:1081A800938707286FE0DFF393874C002326F100BD -:1081B800937704016386070003AD0C006F0000018C -:1081C800937704046388070003DD0C00930C000018 -:1081D8006FE09FF393770420E38007FE03CD0C0044 -:1081E8006FF0DFFE13070400930710006FF05FBD08 -:1081F80013071000638EE79413072000638EE712BD -:10820800930701199396DC0113777D00135D3D00F8 -:108218001307070333EDA60193DC3C00A38FE7FEA9 -:10822800B3669D019384F7FF639E0602937614005C -:10823800638A0600930600036306D700A38FD4FE63 -:108248009384E7FF93070119938D0B002322010004 -:10825800B38B9740930C0000130C0000130D000023 -:108268006FF09FC5938704006FF0DFF9130A0000D1 -:10827800930D0119937A0440130C90001306A00083 -:108288009306000013050D0093850C0023221101AD -:10829800EF40C02113050503A38FADFE9384FDFFB6 -:1082A800130A1A0083284100638E0A048327810079 -:1082B80083C707006318FA049307F00F6304FA04EE -:1082C80063940C006370AC05832741028325C102C7 -:1082D80023221101B384F440138607001385040098 -:1082E800EFE0DFBE83278100130A000083284100E6 -:1082F80083C71700638807008327810093871700C7 -:108308002324F10013050D0093850C001306A0002B -:108318009306000023221101EF30903B938C050057 -:10832800B3E5A500130D050083284100E38C05F093 -:10833800938D04006FF09FF4930401190327410300 -:108348009377FD009384F4FFB307F70083C7070012 -:10835800135D4D002380F4009397CC0133EDA70102 -:1083680093DC4C00B3679D01E39A07FC6FF09FED27 -:1083780093040119E39807EC13771700E30407EC5B -:1083880093070003A307F1186FE0DFFDE30E0B2E40 -:1083980023066113A303010A232691016FE0DFF48A -:1083A8001307070123A2E8012326E10C2324D10C9B -:1083B80063DEDF021306410C9385090013050900EB -:1083C8002324F1052322D1052320E105232EC1030F -:1083D800EF205030E3180524832F8104832E4104B5 -:1083E800032F0104032EC1031306C10E130E0EFF43 -:1083F800930806006FF05FB21307070123A2C801B4 -:108408002326E10C2324D10C63DADE021306410C87 -:1084180093850900130509002320D105232EF102B5 -:10842800232CC103EF20102BE31E051E832E01040D -:108438008327C103032E81031306C10E938A0AFF03 -:10844800930806006FF01FBF9386060123A2080158 -:108458002326D10C2324E10C6356EE021306410CAB -:108468009385090013050900232EC103232C01035A -:10847800EF205026E318051A032EC10303288103B1 -:108488001306C10E938A0AFF930806006FF0DFC037 -:1084980013075006635467730327010D93050108FA -:1084A800130501092328E1080327410D232C110393 -:1084B80023200108232AE1080327810D232201082C -:1084C80023240108232CE1080327C10D23260108D2 -:1084D800232EE108EF50803D83288103631405189B -:1084E80097970000938747F623A0F800930710009A -:1084F80023A2F8008327810C938D1D002326B10D3C -:10850800938717002324F10C1307700093888800C1 -:10851800635EF7001306410C9385090013050900F3 -:10852800EF20501BE31005109308C10E8327C10AE2 -:1085380063C64701937714006380070A8327810283 -:10854800032741019388880023ACF8FE8327410163 -:1085580023AEF8FE8327C10CB387E7002326F10C6E -:108568008327810C13077000938717002324F10CCD -:10857800635EF7001306410C938509001305090093 -:10858800EF205015E310050A9308C10E9304FAFF73 -:1085980063549004130B0001979A0000938A4A3E93 -:1085A800130C70008327810C23A058010327C10CEA -:1085B8009387170093868800634A9B0623A2980036 -:1085C800B384E4002326910C2324F10C13077000D4 -:1085D80093880600E342F7B4137444006314047EDE -:1085E800032BC101832701026354FB00138B07008F -:1085F80083278101B3876701232CF1008327C10CEE -:10860800638C07001306410C9385090013050900C4 -:10861800EF20500CE3180500832741002324010CA8 -:10862800E39C07049308C10E6FF04FF1130707018D -:1086380023A268012326E10C2324F10C635EFC00CD -:108648001306410C9385090013050900EF209008D3 -:10865800631A057C9306C10E938404FF9388060071 -:108668006FF05FF40327C10A6346E016979700008E -:10867800938787DD23A0F8009307100023A2F80052 -:108688008327810C938D1D002326B10D9387170036 -:108698002324F10C1307700093888800635EF700A9 -:1086A8001306410C9385090013050900EF20900279 -:1086B800631A05769308C10E8327C10A63980700D9 -:1086C80063160A0093771400E38807F08327810272 -:1086D800032741019388880023ACF8FE83274101D2 -:1086E80023AEF8FE8327C10CB387E7002326F10CDD -:1086F8008327810C13077000938717002324F10C3C -:10870800635EF7001306410C938509001305090001 -:10871800EF20407C631805709308C10E832AC10AB4 -:1087280063D20A06B30A504113870800130C0001EC -:10873800179B0000130BCB24930C70008327810C2C -:10874800232067018326C10C93871700938888002C -:1087580063465C0523225701B38ADA002326510DAC -:108768002324F10C13077000635EF7001306410C15 -:108778009385090013050900EF20C0756314056A85 -:108788009308C10E8327C10C23A0980023A2480197 -:10879800B38747012326F10C6FF09F969386060155 -:1087A800232287012326D10C2324F10C63DEFC004D -:1087B8001306410C9385090013050900EF20807109 -:1087C800631205669308C10E938A0AFF138708008F -:1087D8006FF0DFF6930A0D006354AA01930A0A00AA -:1087E800635250050327810CB38DBA0123A098006A -:1087F8001307170023A258012326B10D2324E10CE7 -:10880800930670009388880063DEE6001306410C27 -:108818009385090013050900EF20C06B63140560F8 -:108828009308C10E63D40A00930A0000B30A5D419D -:1088380063505007930D0001179B0000130B4B1456 -:10884800930B70000327810C23A068018326C10CB9 -:10885800130717001386880063C25D1B23A2580103 -:10886800B38ADA002326510D2324E10C9306700005 -:108878009308060063DEE6001306410C93850900A1 -:1088880013050900EF200065631E05589308C10E03 -:1088980093770440B38AA40163840702130B700022 -:1088A800B38B4401979D0000938D8D0D63140C18B4 -:1088B80063940C18B387440163F45701938A070043 -:1088C8008327C10A63C6470193771400638A0704A4 -:1088D80083278102032741019388880023ACF8FE8F -:1088E8008327410123AEF8FE8327C10CB387E70035 -:1088F8002326F10C8327810C130770009387170038 -:108908002324F10C635EF7001306410C93850900DC -:1089180013050900EF20005C631605509308C10E8B -:10892800B3844401B38754418324C10AB3049A40F1 -:1089380063D4970093840700635490048327C10C81 -:1089480023A0580123A29800B387F4002326F10C32 -:108958008327810C1307700093888800938717007A -:108968002324F10C635EF7001306410C938509007C -:1089780013050900EF2000566316054A9308C10E37 -:108988009387040063D40400930700008324C10A7A -:10899800B3049A40B384F440E35090C4130B00012D -:1089A800979A0000938ACAFD130C70008327810CE4 -:1089B80023A058010327C10C9387170093868800CA -:1089C800E35E9BBE1307070123A268012326E10C7F -:1089D8002324F10C635EFC001306410C9385090007 -:1089E80013050900EF20004F631E05429306C10ED0 -:1089F800938404FF938806006FF05FFB938606015B -:108A080023A2B8012326D10C2324E10C63DEEB005A -:108A18001306410C9385090013050900EF20804BCC -:108A2800631205401306C10E938A0AFF93080600D5 -:108A38006FF05FE163820C0E938CFCFF8327C10209 -:108A4800032741029388880023ACF8FE832741025C -:108A580023AEF8FE8327C10CB387E7002326F10C69 -:108A68008327810C938717002324F10C635EFB0096 -:108A78001306410C9385090013050900EF20804572 -:108A88006312053A9308C10E8327810033875B413F -:108A980083C707006354F700930707006356F00481 -:108AA8000327C10C23A0580123A2F8003387E7004D -:108AB8002326E10C0327810C9388880013071700ED -:108AC8002324E10C6352EB021306410C9385090041 -:108AD80013050900232CF102EF20C03F631405346D -:108AE800832781039308C10E1387070063D4070007 -:108AF80013070000832781001308000183C70700BC -:108B0800B387E7406346F0068327810083C70700E1 -:108B1800B38AFA006FF09FD983278100130CFCFFFA -:108B28009387F7FF2324F1006FF05FF19386060126 -:108B380023A208012326D10C2324E10C6356EB025F -:108B48001306410C9385090013050900232E010320 -:108B5800232CF102EF2000386316052C0328C103EB -:108B6800832781031306C10E938707FF9308060026 -:108B78000327810C23A0B8018326C10C1307170013 -:108B880013868800E344F8FA23A2F800B387D700D5 -:108B98002326F10C2324E10C93080600E356EBF698 -:108BA8001306410C9385090013050900EF20803254 -:108BB800631A05269308C10E6FF01FF58327810CF1 -:108BC8001307100023A09800938D1D0093871700AA -:108BD800138B880063464701937614006388061C4C -:108BE8001307100023A2E8002326B10D2324F10C5B -:108BF80013077000635EF7001306410C93850900A4 -:108C080013050900EF20002D631E0520130BC10E6C -:108C18008327810203274101130B8B00232CFBFEC2 -:108C280083274101232EFBFE8327C10CB387E7006E -:108C38002326F10C8327810C1307700093871700F4 -:108C48002324F10C635EF7001306410C9385090099 -:108C580013050900EF2000286316051C130BC10E2D -:108C68008327010D93050108130501092328F1083D -:108C78008327410D930AFAFF23200108232AF108CC -:108C88008327810D2322010823240108232CF108BE -:108C98008327C10D23260108232EF108EF40104138 -:108CA800630605088327C10C0327810C93841400ED -:108CB8009387F7FFB38747011307170023209B000B -:108CC80023225B012326F10C2324E10C9307700077 -:108CD800130B8B0063DEE7001306410C9385090034 -:108CE80013050900EF20001F631E0512130BC10EA8 -:108CF8009307410B2320FB0083270103032701036C -:108D080093088B002322FB008327C10CB387E7005D -:108D18002326F10C8327810C130770009387170013 -:108D28002324F10CE35AF78A6FF00FBFE35250FD8A -:108D3800130C000197940000938484C4930C700072 -:108D48000327810C23209B008327C10C13071700DE -:108D580093068B0063405C03B387FA0023225B0110 -:108D68002326F10C2324E10C93077000138B0600D3 -:108D78006FF05FF69387070123228B012326F10CFE -:108D88002324E10C63DEEC001306410C93850900F3 -:108D980013050900EF200014631605089306C10E99 -:108DA800938A0AFF138B06006FF09FF923A2E8004D -:108DB8002326B10D2324F10C13077000E35AF7F2B0 -:108DC8006FF09FF18327C101032701023384E74035 -:108DD800E3588080930A000197940000938444B973 -:108DE800130B70008327810C23A098000327C10C64 -:108DF8009387170063C68A0423A288003304E4001B -:108E08002326810C2324F10C13077000635AF7FC06 -:108E18001306410C9385090013050900EF20800B08 -:108E2800630005FC83274100639407006FE0CFF2DD -:108E38009385070013050900EF901FD26FE0CFF16B -:108E48001307070123A258012326E10C2324F10C60 -:108E580093888800635EFB001306410C9385090024 -:108E680013050900EF200007E31E05FA9308C10E59 -:108E7800130404FF6FF01FF7832541001305090051 -:108E8800EF909FCD6FF00FFA8327C10C6394070012 -:108E98006FE08FEC1306410C938509001305090058 -:108EA800EF2040036FE04FEB83278600130101FD9D -:108EB8002324810223261102232291022320210345 -:108EC800232E3101232C4101232A5101232861013A -:108ED800232671012324810113040600639E0702DF -:108EE80023220600130500008320C1020324810207 -:108EF80083244102032901028329C101032A810134 -:108F0800832A4101032B0101832BC100032C81001B -:108F1800130101036780000083A745061389050034 -:108F280013972701635A070683240600130A0500CE -:108F3800930BF0FF83278400639A07001305000052 -:108F480023240400232204006FF01FFA83A944009D -:108F580003AB0400930A000013DC290063CE8A01E6 -:108F68008327840093F9C9FF93848400B389374128 -:108F7800232434016FF01FFC83250B00130609001E -:108F880013050A00EF100014130B4B00630A750158 -:108F9800938A1A006FF09FFCEF1040206FF05FFA81 -:108FA8001305F0FF6FF0DFF9130101ED232481129F -:108FB800232E3111232C41112320A1112326111214 -:108FC8002322911223202113232A511123286111CE -:108FD800232671112324811123229111232EB10FED -:108FE8009309050013840500130A0600138D060073 -:108FF800630805008327850363940700EF901F88A3 -:109008008317C4001397270163420702B72600009D -:1090180003274406B3E7D7002316F400B7E7FFFF9A -:109028009387F7FFB377F7002322F4068357C4002A -:1090380093F78700638E070683270401638A070670 -:109048008357C4001307A00093F7A7016390E708AC -:109058008317E40063CC070693060D0013060A0085 -:109068009305040013850900EF00903F2322A10017 -:109078008320C11203248112032541008324411255 -:10908800032901128329C111032A8111832A41115D -:10909800032B0111832BC110032C8110832C411049 -:1090A800032D0110832DC10F1301011367800000E8 -:1090B8009305040013850900EF90CFACE30205F88F -:1090C8009307F0FF2322F1006FF09FFA930BC1047E -:1090D800232071052324010423220104938D0B000E -:1090E800232601002324010023280100232A01004C -:1090F8002322010093040A009306500283C7040048 -:10910800638407006396D70A33894441630A0904D4 -:109118008327810423A04D0123A22D01B3872701B2 -:109128002324F1048327410493067000938D8D0056 -:10913800938717002322F10463DEF6001306010467 -:109148009305040013850900EFF01FD6E31A0528DC -:10915800938D0B0083274100B38727012322F10059 -:1091680083C70400E382072C138A1400A30D0102AD -:109178001309F0FF130B0000130C00009304A00266 -:10918800930AA00503460A00130A1A00930606FE6E -:10919800E3E2DA0E978700009387877F939626008D -:1091A800B386F60083A60600B386F600678006003D -:1091B800938414006FF09FF49787000093878727A4 -:1091C8002326F10093760C02638C066C130D7D0048 -:1091D800137D8DFF83280D00832A4D00930C8D008D -:1091E80093761C00638E0600B3E65801638A060076 -:1091F80093060003230ED102A30EC102136C2C00A8 -:10920800137CFCBF6F00403413850900EFB01FD9F1 -:109218008327450013850700232AF100EFD05FC993 -:109228002328A10013850900EFB05FD783278500A5 -:109238002324F10083270101E38407F483278100B5 -:10924800E38007F483C60700E38C06F2136C0C4036 -:109258006FF01FF38346B103E39406F2930600020E -:10926800A30DD1026FF0DFF1136C1C006FF05FF1FA -:10927800032B0D00130D4D00E3540BF0330B60412D -:10928800136C4C006FF0DFEF9306B0026FF05FFDD8 -:1092980003460A00930C1A006316960403290D006E -:1092A80093064D00635409001309F0FF138D06005F -:1092B800138A0C006FF0DFEC130509009305A0007A -:1092C800EF709036938C1C0003C6FCFF33094501F0 -:1092D800130A06FD93079000E3F047FF138A0C007A -:1092E8006FF0DFEA130900006FF09FFE136C0C08A3 -:1092F8006FF01FE9930C0A00130B000013050B0015 -:109308009305A000232CC100EF70103203268101C1 -:10931800938C1C0093079000130B06FD03C6FCFFFB -:10932800330BAB00930606FDE3FAD7FC6FF01FFB87 -:1093380003460A00930680066318D600130A1A002B -:10934800136C0C206FF0DFE3136C0C046FF05FE319 -:1093580003460A009306C0066318D600130A1A00CB -:10936800136C0C026FF0DFE1136C0C016FF05FE11E -:1093780083260D00930C4D00A30D01022306D1088E -:1093880013091000930A00009304C1086F00401FDE -:10939800136C0C0193760C02638C0604130D7D008C -:1093A800137D8DFF83280D00832A4D00930C8D00BB -:1093B80063DE0A00B3081041B3361001330350418D -:1093C800B30AD3409306D002A30DD1029306F0FF4F -:1093D8006314D950639E0A569307900063EA17579F -:1093E80093880803A307110F9304F10E6F00C0546C -:1093F80093760C01930C4D006388060083280D00BA -:1094080093DAF8416FF0DFFA93760C0483280D00A5 -:10941800638806009398080193D808416FF05FFEAF -:1094280093760C20E38E06FC9398880193D88841A4 -:109438006FF01FFD13760C0283260D00130D4D00EF -:10944800630C06008327410023A0F60093D7F74159 -:1094580023A2F6006FF01FCA13760C0163080600FA -:109468008327410023A0F6006FF0DFC813760C04B1 -:1094780063080600835741002390F6006FF09FC7EA -:1094880093770C20E38E07FC834741002380F60086 -:109498006FF05FC6136C0C0193760C0263860604AA -:1094A800130D7D00137D8DFF83280D00832A4D0049 -:1094B800930C8D00137CFCBF93060000A30D0102E2 -:1094C8001306F0FF6300C94213060C00B3E5580108 -:1094D800137CFCF7639805406300095813061000D5 -:1094E8006396C6406FF0DFEF93760C01930C4D0046 -:1094F8006386060083280D006F00000193760C0434 -:109508006388060083580D00930A00006FF09FFAE5 -:1095180093760C20E38006FE83480D006FF0DFFE93 -:10952800B786FFFF83280D0093C606839787000040 -:10953800938707EF930C4D00930A0000136C2C00DF -:10954800231ED1022326F100930620006FF01FF797 -:10955800A30D01029306F0FF930C4D0083240D0028 -:109568006300D92C13060900930500001385040035 -:10957800EFC00FC1930A000063040500330995404A -:10958800138D0A0063D42A01130D09008346B10321 -:1095980063840600130D1D0093772C00232CF10023 -:1095A80063840700130D2D0093774C08232EF100D8 -:1095B80063940706B306AB416350D00693080001D5 -:1095C800178800001308885313037000032641040A -:1095D80023A00D01832581041306160013858D0031 -:1095E80063C4D84A23A2DD00B386B6002324D1047D -:1095F8002322C10493067000930D050063DEC600A4 -:10960800130601049305040013850900EFF0DF89B0 -:109618006318055C938D0B008346B10363880604C9 -:109628001306B10323A0CD001306100083264104BE -:1096380023A2CD0003268104938616002322D10499 -:10964800130616002324C10413067000938D8D00A1 -:10965800635ED60013060104930504001385090010 -:10966800EFF09F84631E0556938D0B0083278101BD -:10967800638807041306C10323A0CD001306200046 -:109688008326410423A2CD00032681049386160075 -:109698002322D104130626002324C10413067000D4 -:1096A800938D8D00635ED6001306010493050400B4 -:1096B80013850900EFF04FFF63140552938D0B00DB -:1096C8008327C101930600086394D706B306AB410C -:1096D8006350D00693080001178800001308084358 -:1096E800130370000326410423A00D018325810480 -:1096F8001306160013858D0063C4D83E23A2DD002F -:10970800B386B6002324D1042322C1049306700033 -:10971800930D050063DEC6001306010493050400DB -:1097280013850900EFF04FF8631C054A938D0B0071 -:10973800B38A2A4163505007930800011788000034 -:109748001308C83C130370008326410423A00D01AD -:10975800032681049386160093858D0063CE583DB9 -:1097680023A25D01B38ACA00232451052322D10410 -:1097780013067000938D0500635ED600130601047E -:109788009305040013850900EFF00FF2631A0544EE -:10979800938D0B008326810423A22D0123A09D0015 -:1097A80033892601832641042324210513067000EA -:1097B800938616002322D10413878D00635ED6009A -:1097C800130601049305040013850900EFF0CFED9B -:1097D8006318054013870B0093774C006396073A8C -:1097E8006354AB01130B0D0083274100B387670156 -:1097F8002322F10083278104638C070013060104E8 -:109808009305040013850900EFF00FEA631A053C7D -:1098180023220104138D0C00938D0B006FF09F8D94 -:1098280013850400EFD0CFE813090500930A000060 -:109838006FF01FD5136C0C0193760C02638006023F -:10984800130D7D00137D8DFF83280D00832A4D00A5 -:10985800930C8D00930610006FF05FC693760C0191 -:10986800930C4D006386060083280D006F000001ED -:1098780093760C046388060083580D00930A000051 -:109888006FF05FFD93760C20E38006FE83480D00A1 -:109898006FF0DFFE97870000938787B86FF05F92BD -:1098A80093760C01930C4D006386060083280D0007 -:1098B8006F00000193760C046388060083580D003E -:1098C800930A00006FF0DF9193760C20E38006FE88 -:1098D80083480D006FF0DFFE13060C00930610009E -:1098E8006FF0DFBE13061000E386C6AE1306200035 -:1098F8006388C6129306010F9395DA0113F6780070 -:1099080093D8380013060603B3E8150193DA3A0032 -:10991800A38FC6FEB3E558019384F6FF639605024C -:1099280093751C00638A0500930500036306B6005F -:10993800A38FB4FE9384E6FF9307010F930A0900EF -:10994800338997406FF0DFC3938604006FF0DFFA26 -:1099580093770C40130D0000130E010F232CF10018 -:10996800138508001306A0009306000093850A00DB -:109978009304FEFF2320C103232E1101EF2010338F -:10998800032E01028327810113050503A30FAEFEF1 -:10999800130D1D008328C101638E070483278100EE -:1099A80083C607006398A6059307F00F6304FD04B8 -:1099B80063960A009307900063FE1703832701014B -:1099C80083254101232E1101B384F4401386070037 -:1099D80013850400EFD08FCF83278100130D00007B -:1099E8008328C10183C61700638606009387170082 -:1099F8002324F1001385080093850A001306A000AC -:109A080093060000EF20C04C938A0500B3E5A5003B -:109A180093080500E38205F2138E04006FF05FF4EB -:109A28009304010F8327C10093F6F8009384F4FF91 -:109A3800B386D70083C6060093D848002380D40095 -:109A48009396CA01B3E8160193DA4A00B3E65801BF -:109A5800E39A06FC6FF05FEE9304010FE39E06ECB9 -:109A680013761600E30A06EC93060003A307D10E4B -:109A78006FF09F97630A061A2306C108A30D010217 -:109A8800930C0D006FF0DF8F9385050123A21D0154 -:109A98002324B1042322C104635EC3021306010414 -:109AA800930504001385090023266102232401037A -:109AB800232211032320D102EFF00FBF63120512F6 -:109AC8000323C1020328810283284102832601025D -:109AD80013850B00938606FF930D05006FF01FAFEB -:109AE8009385050123A21D012324B1042322C10467 -:109AF800635EC3021306010493050400138509007D -:109B08002322610223200103232E1101232CD100DB -:109B1800EFF08FB96316050C0323410203280102F5 -:109B28008328C1018326810113850B00938606FFD4 -:109B3800930D05006FF01FBB1306060123A21D013C -:109B48002324C1042322D104635AD3021306010437 -:109B5800930504001385090023206102232E0101C7 -:109B6800232C1101EFF04FB4631C050603230102F7 -:109B78000328C1018328810193850B00938A0AFF7A -:109B8800938D05006FF05FBCB304AB41E35A90C4FA -:109B9800930A000117890000130949F6130C700095 -:109BA80083274104232027018326810493871700F4 -:109BB80063C09A0423229700B384D4002324910419 -:109BC8002322F10413077000E35CF7C013060104B5 -:109BD8009305040013850900EFF00FADE30205C0FB -:109BE8008357C40093F70704638407C86FF04FCD09 -:109BF80093860601232257012324D1042322F1044A -:109C080013078700635EFC00130601049305040034 -:109C180013850900EFF04FA9E31405FC13870B0027 -:109C2800938404FF6FF0DFF783278104E38A07FA40 -:109C3800130601049305040013850900EFF0CFA66D -:109C48006FF01FFA979700009387C7EB93060600FB -:109C5800138605009305050003A507006FF0CFB430 -:109C680083D7C500130101B8232C814693F7D7FF8A -:109C7800231AF10083A7450613840500232A914679 -:109C88002326F10683D7E50023282147232E1146F2 -:109C9800231BF10083A7C501130905002320010236 -:109CA8002322F10283A74502930581002326F102AE -:109CB800930701072324F100232CF10093070040A8 -:109CC8002328F100232EF100EFF00FAE93040500D6 -:109CD800634C05009305810013050900EF80DF9EA2 -:109CE800630405009304F0FF8357410193F70704C9 -:109CF800638807008357C40093E707042316F4001A -:109D08008320C147032481471385040003290147A1 -:109D1800832441471301014867800000979700009A -:109D2800938747DE83A7070083A747036396070047 -:109D3800979700009387878503A3070E67000300A2 -:109D4800638405029307F00F63FAC7009307A0081E -:109D58002320F5001305F0FF678000002380C5006D -:109D680013051000678000001305000067800000DD -:109D7800130101FF23248100130405001385050046 -:109D880093050600138606009797000023A007DCBA -:109D980023261100EF7080419307F0FF631CF50044 -:109DA80097970000938787DA83A7070063840700E3 -:109DB8002320F4008320C100032481001301010142 -:109DC80067800000130101FF2324810013040500AC -:109DD800138505009305060023261100EF70C004C3 -:109DE8009305050013050400EFB00FC71304050021 -:109DF800630205040326C5FF130740021376C6FF56 -:109E08001306C6FF6362C706930630019307050071 -:109E180063FCC60023200500232205009307B00138 -:109E280063E4C7029307850023A0070023A2070065 -:109E380023A40700130504008320C1000324810024 -:109E48001301010167800000232405002326050073 -:109E580093070501E31AE6FC23280500930785010B -:109E6800232A05006FF05FFC93050000EFB09FB355 -:109E78006FF05FFC130101FF232481001304050028 -:109E8800138505009797000023A207CC232611000D -:109E9800EF70C00B9307F0FF631CF5009797000065 -:109EA8009387C7CA83A70700638407002320F400A9 -:109EB8008320C10003248100130101016780000091 -:109EC800130101FF2326110023248100232291007E -:109ED8002320210163920502130900008320C10099 -:109EE800032481001305090083244100032901008C -:109EF8001301010167800000930405001384050025 -:109F0800630805008327850363940700EF801F9784 -:109F18008317C400E38207FC93050400138504003B -:109F2800EF800FDA8327C40213090500638C07004A -:109F38008325C40113850400E780070063540500E6 -:109F48001309F0FF8357C40093F7070863880700D5 -:109F58008325040113850400EF801FC083250403B3 -:109F6800638C0500930704046386F50013850400D9 -:109F7800EF809FBE232804028325440463880500DC -:109F880013850400EF805FBD23220404EF805FA6E1 -:109F980023160400EF801FA66FF05FF49797000068 -:109FA800938747B69305050003A507006FF05FF197 -:109FB800130101FD2324810223229102232C410154 -:109FC8002326110223202103232E3101232A5101A4 -:109FD80023286101130A0500938405001304060071 -:109FE800EFB04F8893071000631AF5049387F4FFC6 -:109FF8001307E00F6364F704230691009309100028 -:10A0080013090000930AF0FF130BA000631239072D -:10A01800138504008320C1020324810283244102A2 -:10A02800032901028329C101032A8101832A4101ED -:10A03800032B010113010103678000009306C40587 -:10A04800138604009305C10013050A00EF10905D04 -:10A058009307F0FF93090500E314F5FA8357C4004A -:10A0680093E707042316F4001305F0FF6FF09FFA37 -:10A078009307C100B387270183C50700832784009E -:10A088009387F7FF2324F40063D80700032784018C -:10A0980063C0E702638E65018327040013871700F6 -:10A0A8002320E4002380B700130919006FF01FF67E -:10A0B8001306040013050A00EF105042E31655FF7B -:10A0C8006FF09FFA8317C6001397270163400702B2 -:10A0D80003274606B7260000B3E7D7002316F60085 -:10A0E800B7270000B367F7002322F6066FF05FEC8E -:10A0F800130101FE979700009387C7A0232C8100C6 -:10A1080003A40700232A9100232E110093040500BD -:10A1180013860500630E040083278403639A0700EF -:10A12800130504002326B100EF804FF50326C10074 -:10A1380013050400032481018320C10193850400D1 -:10A1480083244101130101026FF0DFF7130101FFBE -:10A1580023248100130405001385050093050600D8 -:10A168009797000023A4079E23261100EF605063F1 -:10A178009307F0FF631CF500979700009387079DEE -:10A1880083A70700638407002320F4008320C1000D -:10A1980003248100130101016780000083278600E2 -:10A1A8006398070093070000138507006780000085 -:10A1B80083D7C500130101FC232C81022328210326 -:10A1C80023206103232E1102232A9102232631031F -:10A1D8002324410323225103232E7101232C8101BF -:10A1E800232A91012328A1012326B10193F787008F -:10A1F800130B060013840500130905006382070E7C -:10A2080083A70501638E070C8357C400032A0B003C -:10A2180013F72700631A071693F71700930B00002C -:10A22800638A072013050000930A000093090000C1 -:10A238006386093663120502138609009305A00098 -:10A2480013850A00EFB0CFF3938B1900630605005E -:10A2580013051500B30B5541138C0B0063F47901FA -:10A26800138C090003250400832704018326440175 -:10A2780063F0A73483248400B384960063DA8433BC -:10A2880093850A0013860400EF000050832704001A -:10A298009305040013050900B38797002320F400F1 -:10A2A800EF808FC2631E0516B38B9B401305100009 -:10A2B800639A0B009305040013050900EF80CFC0D3 -:10A2C8006310051683278B00B38A9A00B3899940D7 -:10A2D800B384974023249B00E39C04F46F0080061A -:10A2E8009305040013050900EF80CF899307F0FF59 -:10A2F800E30C05F06F00400583290A0083244A0017 -:10A30800130A8A00E38A04FE9386040063F49A0021 -:10A3180093860A00832744028325C4011386090013 -:10A3280013050900E7800700635CA00E83278B00F4 -:10A33800B389A900B384A4403385A7402324AB0084 -:10A34800E31205FC930700008320C1030324810363 -:10A3580083244103032901038329C102032A8102BB -:10A36800832A4102032B0102832BC101032C8101A3 -:10A37800832C4101032D0101832DC10013850700A2 -:10A388001301010467800000B70A008093090000E8 -:10A398009304000093CA0AC06FF0DFF6832B0A000B -:10A3A80083244A00130A8A00E38A04FE8359C400FE -:10A3B800832D84000325040093F709206384071480 -:10A3C80063E0B40D93F70948638C070A832D0401F1 -:10A3D80093053000330DB54103254401EF60D024C7 -:10A3E800935AF501B38AAA0093071D0093DA1A401D -:10A3F800B387970063F4FA00938A070093F909403A -:10A408006388090C93850A0013050900EFA0DFE4AF -:10A4180093090500631A05029307C0002320F90079 -:10A428008357C40093E707042316F4009307F0FF4B -:10A438006FF09FF1370C0080934CECFF9304000001 -:10A44800134CFCFF6FF05FF68325040113060D0023 -:10A45800EF0000258357C40093F7F7B793E7070881 -:10A468002316F40023283401232A5401B389A901AF -:10A47800B38AAA4123203401938D04002324540174 -:10A488009389040063F4B401938D04000325040048 -:10A4980013860D0093850B00EF00002F832784009F -:10A4A800B387B7412324F40083270400B38DB70191 -:10A4B8002320B40183278B00B38B3B01B384344141 -:10A4C800B389374123243B01E39009EE6FF09FE7FE -:10A4D80013860A0093850D0013050900EF00403527 -:10A4E80093090500E31005F8832504011305090005 -:10A4F800EF808FE68357C40093F7F7F72316F4002D -:10A508006FF09FF18327040163E6A70083294401C4 -:10A5180063F6340593890D0063F4B401938904004C -:10A528001386090093850B00EF000026832784001B -:10A5380003270400B3873741330737012324F40086 -:10A548002320E400E39807F69305040013050900A7 -:10A55800EF808F97E30005F66FF09FEC13050C0072 -:10A5680063E49C001385040093850900EF60100ED6 -:10A5780093850900EF60500B832744028325C401AB -:10A588009306050013860B0013050900E7800700F2 -:10A5980093090500E340A0F26FF09FE8832A0A00C0 -:10A5A80083294A0013050000130A8A006FF05FC868 -:10A5B8006342DC02832744028325C40113860A0010 -:10A5C80013050900E780070093040500E34EA0CCBB -:10A5D8006FF01FE513060C0093850A00EF00C01A00 -:10A5E8008327840093040C00B38787412324F40055 -:10A5F80083270400B38787012320F4006FF0DFCAA4 -:10A60800130101FF232481001304050013850500AD -:10A618009787000023AC075223261100EF60101F14 -:10A628009307F0FF631CF500978700009387075294 -:10A6380083A70700638407002320F4008320C10058 -:10A64800032481001301010167800000130101FF49 -:10A6580023248100130405001385050093050600D3 -:10A66800138606009787000023A2074E23261100B1 -:10A67800EF60D01C9307F0FF631CF500978700007C -:10A688009387C74C83A70700638407002320F4003F -:10A698008320C100032481001301010167800000A9 -:10A6A800B3C7A50093F737003307C50063960700C3 -:10A6B8009307300063E4C70293070500636CE50065 -:10A6C8006780000083C605009387170093851500EF -:10A6D800A38FD7FEE3E8E7FE678000009377350095 -:10A6E80063920708930705009376C7FF138606FE53 -:10A6F80063F6C70883A3050083A2450083AF8500DE -:10A7080003AFC50083AE050103AE450103A3850170 -:10A7180083A8C501938545029387470203A8C5FF0F -:10A7280023AE77FC23A057FE23A2F7FF23A4E7FF5D -:10A7380023A6D7FF23A8C7FF23AA67FE23AC17FFCA -:10A7480023AE07FF6FF0DFFA83C605009387170073 -:10A7580093851500A38FD7FE93F63700E39606FE80 -:10A768006FF09FF8930705006FF01FFF03A6050021 -:10A77800938747009385450023AEC7FEE3E8D7FEDD -:10A78800E3EAE7F4678000003307C50063E8A50043 -:10A7980093070500639AE70267800000B387C50046 -:10A7A8003306F640E376F5FEB386C70063940600E9 -:10A7B800678000009387F7FF83C607001307F7FF3A -:10A7C8002300D7006FF05FFE9385150083C6F5FF61 -:10A7D80093871700A38FD7FE6FF0DFFB130101FFEC -:10A7E8002324810013040500138505009305060042 -:10A7F800138606009787000023AA07342326110032 -:10A80800EF6090089307F0FF631CF500978700003E -:10A818009387C73383A70700638407002320F400C6 -:10A828008320C10003248100130101016780000017 -:10A83800130101FC232C8102232E1102138405002D -:10A84800232A9102232821032326310323244103A9 -:10A858002322510323206103232E7101930506004F -:10A8680063180402032481038320C1038324410362 -:10A87800032901038329C102032A8102832A410291 -:10A88800032B0102832BC101130101046FA0DF9C7C -:10A89800930A05002326C100EFB08F9E8325C100CF -:10A8A8008326C4FF930760019389B500930B84FF47 -:10A8B80013F9C6FF63F4370513FB89FF63520B04D2 -:10A8C8009307C00023A0FA00130A00008320C103E5 -:10A8D8000324810313050A00832441030329010388 -:10A8E8008329C102032A8102832A4102032B010220 -:10A8F800832BC1011301010467800000130B0001C1 -:10A90800E360BBFC635E6945178700001307C7DE79 -:10A9180003268700B3872B0103A74700630CF600C3 -:10A928001375E7FF3385A700032545001375150048 -:10A93800631C050A1377C7FFB309E9006312F6041D -:10A9480013050B0163C6A90AB38B6B01B38969416F -:10A958009787000023A677DB93E9190023A23B0120 -:10A968008329C4FF13850A00130A040093F9190008 -:10A97800B3E96901232E34FFEFB0CF906FF01FF5D4 -:10A9880063C8690703A7C70083A7870023A6E70052 -:10A998002324F70003A74B00B38669411306F00090 -:10A9A80013771700B3873B016370D63CB369EB009C -:10A9B80023A23B01B3856B0193E6160023A2D500C1 -:10A9C80003A747009385850013850A0013671700BE -:10A9D80023A2E700EF804F9813850A00EFB08F8A13 -:10A9E800138A8B006FF09FEE130700009307000097 -:10A9F80093F6160063940628832484FFB3849B404F -:10AA080003AA4400137ACAFF330A2A01638E071A7D -:10AA1800B30947016318F60E93070B0163C6F91AC9 -:10AA280003A7840083A7C4001306C9FF138A840000 -:10AA38002326F70023A4E70013074002636CC70A24 -:10AA48009306300193070A0063F2C60283270400C5 -:10AA580023A4F4008327440023A6F4009307B0013D -:10AA680063ECC704130484009387040103270400DC -:10AA780023A0E7000327440023A2E700032784005C -:10AA880023A4E700B3876401B389694117870000ED -:10AA98002328F7C693E9190023A2370183A74400A6 -:10AAA80093F71700B3E9670123A2340113850A005D -:10AAB800EFA05FFD6FF09FE18327840023A8F400D7 -:10AAC8008327C40023AAF4006308E60013040401E2 -:10AAD800938784016FF09FF983270401130484018D -:10AAE80023ACF4000327C4FF9387040223AEE400D9 -:10AAF8006FF0DFF79305040013050A00EFF0DFC8D5 -:10AB08006FF05FF863C2690D03A7C70083A78700CA -:10AB18001306C9FF1385840023A6E7002324F70042 -:10AB280003A7840083A7C4002326F70023A4E70013 -:10AB38009307400263E4C708130730016372C70232 -:10AB48000327040023A4E4000327440023A6E40009 -:10AB58001307B0016366C702130484001385040158 -:10AB6800832704002320F500832744002322F500CF -:10AB7800832784002324F500938B04006FF09FE162 -:10AB88000327840023A8E4000327C40023AAE400C1 -:10AB98006308F60013040401138584016FF05FFC59 -:10ABA80083270401138504021304840123ACF400F1 -:10ABB8008327C4FF23AEF4006FF09FFA93050400C7 -:10ABC800EFF09FBC6FF05FFB634A6A0B83A7C4007A -:10ABD80003A784001306C9FF138584002326F70002 -:10ABE80023A4E7009307400263E4C7081307300172 -:10ABF8006372C7020327040023A4E4000327440068 -:10AC080023A6E4001307B0016366C7021304840097 -:10AC180013850401832704002320F50083274400BB -:10AC28002322F500832784002324F50093090A00D2 -:10AC38006FF09FF40327840023A8E4000327C400CF -:10AC480023AAE4006308F6001304040113858401B1 -:10AC58006FF05FFC83270401138504021304840149 -:10AC680023ACF4008327C4FF23AEF4006FF09FFAEF -:10AC780093050400EFF05FB16FF05FFB13850A00E6 -:10AC8800EFA08FDD130A0500E30205E28327C4FF66 -:10AC9800130785FF93F7E7FFB387FB00639AE70085 -:10ACA8008329C5FF93F9C9FFB38929016FF09FCEA6 -:10ACB8001306C9FF9307400263EEC7081307300164 -:10ACC8006374C708032704002320E5000327440012 -:10ACD8002322E5001307B001636AC7021307840043 -:10ACE800930785008326070023A0D7008326470003 -:10ACF80023A2D7000327870023A4E70093050400B5 -:10AD080013850A00EF705FE56FF05FDA03278400B0 -:10AD18002324E5000327C4002326E5006308F60082 -:10AD280013070401930705016FF0DFFB8327040174 -:10AD3800130784012328F50083264401930785011E -:10AD4800232AD5006FF01FFA9307050013070400A4 -:10AD58006FF05FF993050400EFF01FA36FF01FFA7F -:10AD6800930909006FF01FC3B3E9E90023A23B016F -:10AD780003A747001367170023A2E7006FF0DFC59A -:10AD8800130101FF232481001384050083A5050016 -:10AD980023229100232611009304050063840500F3 -:10ADA800EFF01FFE93050400032481008320C100F7 -:10ADB8001385040083244100130101016F70DFD95A -:10ADC80097870000938707D483A707006382A7109B -:10ADD8008327C504130101FE232C8100232A910037 -:10ADE80023282101232E11002326310113040500F5 -:10ADF80093040000130900086394070483250404DE -:10AE08006386050013050400EF701FD5832584149D -:10AE1800638C05049304C4146388950403A905008E -:10AE280013050400EF705FD3930509006FF0DFFE90 -:10AE3800B385950083A50500639E050093844400AF -:10AE48008325C404E39624FF13050400EF70DFD0C4 -:10AE58006FF0DFFA83A9050013050400EF70DFCF58 -:10AE6800938509006FF05FFD83254405638605001F -:10AE780013050400EF705FCE83278403638C0702F9 -:10AE88008327C40313050400E78007008325042EE5 -:10AE98006382050213050400032481018320C10194 -:10AEA80083244101032901018329C10013010102FF -:10AEB8006FF01FED8320C101032481018324410128 -:10AEC800032901018329C1001301010267800000E1 -:10AED8006780000083278600130101FD232E3101BE -:10AEE80023261102232481022322910223202103F5 -:10AEF800232C4101232A51012328610123267101B2 -:10AF080023248101232291019309060063860712F5 -:10AF1800032B0600930A050013840500930B000019 -:10AF28001309000063060908032A84006366490DB3 -:10AF3800835CC40093F70C486380070C0325440125 -:10AF480083240400032A040193053000EF50D06DD8 -:10AF5800338C44419354F501B384A40093071C0037 -:10AF680093D41440B387270163F4F4009384070053 -:10AF780093FC0C4063800C109385040013850A0031 -:10AF8800EFA08FAD130A0500631C05029307C000EC -:10AF980023A0FA008357C4001305F0FF93E70704C2 -:10AFA8002316F40023A4090023A209006F00400916 -:10AFB800832B0B0003294B00130B8B006FF09FF6BC -:10AFC8008325040113060C00EFF08FED8357C400AE -:10AFD80093F7F7B793E707082316F40023284401EB -:10AFE800232A9400330A8A01B3848441232044012C -:10AFF80023249400130A090063744901130A090001 -:10B008000325040013060A0093850B00EFF0CFF721 -:10B0180083278400B38747412324F400832704004F -:10B02800338A470183A789002320440133892741B4 -:10B0380023A42901E31E09F623A209001305000031 -:10B048008320C102032481028324410203290102CF -:10B058008329C101032A8101832A4101032B0101AC -:10B06800832BC100032C8100832C410013010103B1 -:10B078006780000093050A001386040013850A0000 -:10B08800EFF00FFB130A0500E31A05F4832504010A -:10B0980013850A00EF705FAC6FF05FEF83D7C500D0 -:10B0A800130101ED23202113232E3111232C4111EB -:10B0B8002320A11123261112232481122322911265 -:10B0C800232A511123286111232671112324811168 -:10B0D80023229111232EB10F93F70708130A0500B5 -:10B0E8001389050093090600138D0600638E070275 -:10B0F80083A70501639A070293050004EFA0CF9583 -:10B108002320A9002328A900631C05009307C00079 -:10B118002320FA009307F0FF2322F1006F00D032BA -:10B1280093070004232AF900930BC1042320710517 -:10B138002324010423220104938D0B0023260100FC -:10B148002324010023280100232A010023220100CF -:10B1580013840900930650028347040063840700A0 -:10B168006396D70AB3043441638A040483278104AD -:10B1780023A03D0123A29D00B38797002324F10457 -:10B188008327410493067000938D8D0093871700E1 -:10B198002322F10463DEF600130601049305090077 -:10B1A80013050A00EFF01FD3E31A0528938D0B004F -:10B1B80083274100B38797002322F10083470400C7 -:10B1C800E380073093091400A30D01029304F0FFF4 -:10B1D800130B0000130C00001304A002930AA0052F -:10B1E80003C6090093891900930606FEE3E2DA0E06 -:10B1F800977700009387C7A293962600B386F60038 -:10B2080083A60600B386F6006780060013041400C0 -:10B218006FF09FF4976700009387C7212326F100FA -:10B2280093760C02638C066C130D7D00137D8DFFE5 -:10B2380083280D00832A4D00930C8D0093761C0003 -:10B24800638E0600B3E65801638A0600930600037E -:10B25800230ED102A30EC102136C2C00137CFCBF79 -:10B268006F00403413050A00EF905FD38327450031 -:10B2780013850700232AF100EFB09FC32328A100FC -:10B2880013050A00EF909FD1832785002324F1003E -:10B2980083270101E38407F483278100E38007F40F -:10B2A80083C60700E38C06F2136C0C406FF01FF3A3 -:10B2B8008346B103E39406F293060002A30DD1027C -:10B2C8006FF0DFF1136C1C006FF05FF1032B0D00C2 -:10B2D800130D4D00E3540BF0330B6041136C4C001D -:10B2E8006FF0DFEF9306B0026FF05FFD03C6090051 -:10B2F800938C19006316860483240D0093064D0071 -:10B3080063D404009304F0FF138D060093890C00A6 -:10B318006FF0DFEC138504009305A000EF50D030E8 -:10B32800938C1C0003C6FCFFB3043501930906FD8A -:10B3380093079000E3F037FF93890C006FF0DFEA82 -:10B34800930400006FF09FFE136C0C086FF01FE968 -:10B35800938C0900130B000013050B009305A00044 -:10B36800232CC100EF50502C03268101938C1C0024 -:10B3780093079000130B06FD03C6FCFF330BAB00CD -:10B38800930606FDE3FAD7FC6FF01FFB03C609001E -:10B39800930680066318D60093891900136C0C2055 -:10B3A8006FF0DFE3136C0C046FF05FE303C6090072 -:10B3B8009306C0066318D60093891900136C0C0213 -:10B3C8006FF0DFE1136C0C016FF05FE183260D0075 -:10B3D800930C4D00A30D01022306D108930410001D -:10B3E800930A00001304C1086F00401F136C0C017E -:10B3F80093760C02638C0604130D7D00137D8DFF7C -:10B4080083280D00832A4D00930C8D0063DE0A000B -:10B41800B3081041B336100133035041B30AD34087 -:10B428009306D002A30DD1029306F0FF6394D45083 -:10B43800639E0A569307900063EA17579388080398 -:10B44800A307110F1304F10E6F00C05493760C017B -:10B45800930C4D006388060083280D0093DAF841A9 -:10B468006FF0DFFA93760C0483280D0063880600DA -:10B478009398080193D808416FF05FFE93760C20EB -:10B48800E38E06FC9398880193D888416FF01FFDDE -:10B4980013760C0283260D00130D4D00630C060075 -:10B4A8008327410023A0F60093D7F74123A2F60093 -:10B4B8006FF01FCA13760C0163080600832741004A -:10B4C80023A0F6006FF0DFC813760C0463080600AB -:10B4D800835741002390F6006FF09FC793770C20A5 -:10B4E800E38E07FC834741002380F6006FF05FC6B8 -:10B4F800136C0C0193760C0263860604130D7D0011 -:10B50800137D8DFF83280D00832A4D00930C8D0039 -:10B51800137CFCBF93060000A30D01021306F0FF85 -:10B528006380C44213060C00B3E55801137CFCF792 -:10B538006398054063800458130610006396C6405C -:10B548006FF0DFEF93760C01930C4D0063860600D5 -:10B5580083280D006F00000193760C0463880600B1 -:10B5680083580D00930A00006FF09FFA93760C2021 -:10B57800E38006FE83480D006FF0DFFEB786FFFF0D -:10B5880083280D0093C6068397670000938747E9D1 -:10B59800930C4D00930A0000136C2C00231ED1025B -:10B5A8002326F100930620006FF01FF7A30D010278 -:10B5B8009306F0FF930C4D0003240D006380D42CF8 -:10B5C800138604009305000013050400EFA04FBB89 -:10B5D800930A000063040500B3048540138D0A0034 -:10B5E80063D49A00138D04008346B1036384060074 -:10B5F800130D1D0093772C00232CF10063840700A2 -:10B60800130D2D0093774C08232EF1006394070641 -:10B61800B306AB416350D0069308000117680000D9 -:10B628001308C876130370000326410423A00D01F4 -:10B63800832581041306160013858D0063C4D84A38 -:10B6480023A2DD00B386B6002324D1042322C1043B -:10B6580093067000930D050063DEC600130601040F -:10B668009305090013050A00EFF0DF866318055CEF -:10B67800938D0B008346B103638806041306B10358 -:10B6880023A0CD00130610008326410423A2CD0079 -:10B6980003268104938616002322D104130616007C -:10B6A8002324C10413067000938D8D00635ED600B9 -:10B6B800130601049305090013050A00EFF09F81A2 -:10B6C800631E0556938D0B00832781016388070449 -:10B6D8001306C10323A0CD001306200083264104CE -:10B6E80023A2CD0003268104938616002322D104C9 -:10B6F800130626002324C10413067000938D8D00C1 -:10B70800635ED600130601049305090013050A00B9 -:10B71800EFF04FFC63140552938D0B008327C10192 -:10B72800930600086394D706B306AB416350D0066E -:10B738009308000117680000130848661303700097 -:10B748000326410423A00D01832581041306160056 -:10B7580013858D0063C4D83E23A2DD00B386B600EE -:10B768002324D1042322C10493067000930D0500FD -:10B7780063DEC600130601049305090013050A00D9 -:10B78800EFF04FF5631C054A938D0B00B38A9A407E -:10B7980063505007930800011768000013080860F9 -:10B7A800130370008326410423A00D01032681049E -:10B7B8009386160093858D0063CE583D23A25D01C4 -:10B7C800B38ACA00232451052322D104130670002A -:10B7D800938D0500635ED6001306010493050900E6 -:10B7E80013050A00EFF00FEF631A0544938D0B0061 -:10B7F8008326810423A29D0023A08D00B384960094 -:10B8080083264104232491041306700093861600AE -:10B818002322D10413878D00635ED600130601042A -:10B828009305090013050A00EFF0CFEA63180540F5 -:10B8380013870B0093774C006396073A6354AB0168 -:10B84800130B0D0083274100B38767012322F10002 -:10B8580083278104638C07001306010493050900FC -:10B8680013050A00EFF00FE7631A053C23220104D1 -:10B87800138D0C00938D0B006FF09F8D1305040042 -:10B88800EFB00FE393040500930A00006FF01FD593 -:10B89800136C0C0193760C0263800602130D7D0075 -:10B8A800137D8DFF83280D00832A4D00930C8D0096 -:10B8B800930610006FF05FC693760C01930C4D0051 -:10B8C8006386060083280D006F00000193760C0440 -:10B8D8006388060083580D00930A00006FF05FFD2F -:10B8E80093760C20E38006FE83480D006FF0DFFEA0 -:10B8F800976700009387C7B26FF05F9293760C0149 -:10B90800930C4D006386060083280D006F0000012C -:10B9180093760C046388060083580D00930A000090 -:10B928006FF0DF9193760C20E38006FE83480D00CC -:10B938006FF0DFFE13060C00930610006FF0DFBEF9 -:10B9480013061000E386C6AE130620006388C612ED -:10B958009306010F9395DA0113F6780093D838000F -:10B9680013060603B3E8150193DA3A00A38FC6FE5F -:10B97800B3E558011384F6FF6396050293751C001E -:10B98800638A0500930500036306B600A30FB4FE9F -:10B998001384E6FF9307010F938A0400B38487405A -:10B9A8006FF0DFC3930604006FF0DFFA93770C4063 -:10B9B800130D0000130E010F232CF100138508004E -:10B9C8001306A0009306000093850A001304FEFFE7 -:10B9D8002320C103232E1101EF00502D032E010255 -:10B9E8008327810113050503A30FAEFE130D1D0068 -:10B9F8008328C101638E07048327810083C607005B -:10BA08006398A6059307F00F6304FD0463960A0084 -:10BA18009307900063FE17038327010183254101E3 -:10BA2800232E11013304F440138607001305040084 -:10BA3800EFB0CFC983278100130D00008328C1010F -:10BA480083C6170063860600938717002324F10036 -:10BA58001385080093850A001306A00093060000CA -:10BA6800EF000047938A0500B3E5A5009308050099 -:10BA7800E38205F2130E04006FF05FF41304010F64 -:10BA88008327C10093F6F8001304F4FFB386D700A8 -:10BA980083C6060093D848002300D4009396CA01B1 -:10BAA800B3E8160193DA4A00B3E65801E39A06FCB4 -:10BAB8006FF05FEE1304010FE39E06EC1376160099 -:10BAC800E30A06EC93060003A307D10E6FF09F97D5 -:10BAD8006308061E2306C108A30D0102930C0D007E -:10BAE8006FF0DF8F9385050123A21D012324B10484 -:10BAF8002322C104635EC3021306010493050900EF -:10BB080013050A00232661022324010323221103BB -:10BB18002320D102EFF00FBC631205120323C102E8 -:10BB280003288102832841028326010213850B0022 -:10BB3800938606FF930D05006FF01FAF93850501EF -:10BB480023A21D012324B1042322C104635EC3027E -:10BB5800130601049305090013050A002322610254 -:10BB680023200103232E1101232CD100EFF08FB6DF -:10BB78006316050C03234102032801028328C1012F -:10BB88008326810113850B00938606FF930D05001C -:10BB98006FF01FBB1306060123A21D012324C10455 -:10BBA8002322D104635AD302130601049305090022 -:10BBB80013050A0023206102232E0101232C110101 -:10BBC800EFF04FB1631C0506032301020328C101EE -:10BBD8008328810193850B00938A0AFF938D0500C2 -:10BBE8006FF05FBC3304AB41E35A80C4930A000191 -:10BBF8009764000093848419130C70008327410410 -:10BC080023209700832681049387170063CE8A0632 -:10BC1800232287003304D400232481042322F1043F -:10BC280013077000E35CF7C01306010493050900CD -:10BC380013050A00EFF00FAAE30205C08357C900F5 -:10BC480093F70704639807CC8320C1120324811259 -:10BC58000325410083244112032901128329C111BC -:10BC6800032A8111832A4111032B0111832BC1104F -:10BC7800032C8110832C4110032D0110832DC10F3B -:10BC880013010113678000009386060123225701E0 -:10BC98002324D1042322F10413078700635EFC00E8 -:10BCA800130601049305090013050A00EFF08FA29B -:10BCB800E31605F813870B00130404FF6FF01FF455 -:10BCC80083278104E38C07F6130601049305090012 -:10BCD80013050A00EFF00FA06FF05FF6130101FEE5 -:10BCE800232C8100232A910023282101232E1100CF -:10BCF8002326310113090500938405001304060067 -:10BD0800630805008327850363940700EF601FB766 -:10BD1800832784012324F4008357C40093F7870002 -:10BD2800638A070883270401638607088317C4000A -:10BD380093F9F40F93F4F40F139727016356070A46 -:10BD480083270401032504003305F54083274401B4 -:10BD5800634AF5009305040013050900EF60DF96B8 -:10BD68006312050683278400130515009387F7FFE0 -:10BD78002324F40083270400138717002320E400FA -:10BD88002380370183274401638CA7008357C400AD -:10BD980093F71700638A07029307A0006396F402DB -:10BDA8009305040013050900EF601F92630E050058 -:10BDB8006F0040019305040013050900EF608FDC54 -:10BDC800E30605F69304F0FF8320C10103248101F3 -:10BDD8001385040003290101832441018329C1003B -:10BDE800130101026780000037270000B3E7E7006E -:10BDF8002316F4008327440637E7FFFF1307F7FFEE -:10BE0800B3F7E7002322F4066FF09FF3977700005B -:10BE1800938747CF138605009305050003A5070000 -:10BE28006FF0DFEB977700009387C7CD83A70700F4 -:10BE3800130101FE232C8100232A9100232E1100D7 -:10BE4800130405009384060083A747036398050439 -:10BE580063960700976700009387477383A7070EC9 -:10BE6800938604001306000093054100130504009F -:10BE7800E78007009307F0FF6318F50023A004008C -:10BE88009307A0082320F4008320C1010324810123 -:10BE980083244101130101026780000063960700B3 -:10BEA800976700009387876E83A7070E9386040021 -:10BEB8006FF0DFFB977700009387C7C493060600EF -:10BEC800138605009305050003A507006FF09FF58D -:10BED800130101FD23229102232A51012326110275 -:10BEE8002324810223202103232E3101232C410105 -:10BEF8002328610123267101232481012322910132 -:10BF08002320A101930A050093840500639E063847 -:10BF1800130406009309050017690000130949F482 -:10BF280063F8C512B7070100138B05006378F61094 -:10BF38001307F00F3337C70013173700B357E6005E -:10BF48003309F900834609003387E60093060002A7 -:10BF5800B386E640638C0600B394D40033D7EA0076 -:10BF68003314D600336B9700B399DA00935A04015F -:10BF780093850A0013050B00EF4050721309050062 -:10BF880093850A00931B040113050B00EF40906C86 -:10BF980093DB0B01930405009305050013850B0043 -:10BFA800EF4090681319090193D70901B367F900A5 -:10BFB800138A040063FEA700B3878700138AF4FF7F -:10BFC80063E8870063F6A700138AE4FFB387870056 -:10BFD800B384A74093850A0013850400EF40106CD2 -:10BFE8001309050093850A0013850400EF40906645 -:10BFF8009399090193040500930505001319090194 -:10C0080013850B0093D90901EF401062B369390118 -:10C018001386040063FCA900B30934011386F4FFF6 -:10C0280063E6890063F4A9001386E4FF13140A0188 -:10C038003364C400130A00006F000013B70700013F -:10C0480013070001E36CF6EE130780016FF01FEF92 -:10C05800138A0600631A06009305000013051000F2 -:10C06800EF40505F13040500B7070100637EF41228 -:10C078009307F00F63F48700130A8000B357440155 -:10C088003309F90003470900930600023307470103 -:10C09800B386E64063940612B3848440130A100002 -:10C0A800135B040193050B0013850400EF40105F38 -:10C0B8001309050093050B0013850400931B040165 -:10C0C800EF40505993DB0B019304050093050500DD -:10C0D80013850B00EF4050551319090193D7090137 -:10C0E800B367F900938A040063FEA700B38787004B -:10C0F800938AF4FF63E8870063F6A700938AE4FF56 -:10C10800B3878700B384A74093050B001385040009 -:10C11800EF40D0581309050093050B001385040060 -:10C12800EF405053939909019304050093050500C6 -:10C138001319090113850B0093D90901EF40D04E5B -:10C14800B36939011386040063FCA900B3093401FB -:10C158001386F4FF63E6890063F4A9001386E4FFFD -:10C1680013940A013364C4001305040093050A00FC -:10C178008320C1020324810283244102032901028E -:10C188008329C101032A8101832A4101032B01016B -:10C19800832BC100032C8100832C4100032D010057 -:10C1A8001301010367800000B7070001130A0001AB -:10C1B800E366F4EC130A80016FF05FEC3314D400EB -:10C1C80033DAE400B399DA0033D7EA00935A04016A -:10C1D800B394D40093850A0013050A00336B9700C3 -:10C1E800EF40D04B1309050093850A0013050A0098 -:10C1F800931B0401EF40104693DB0B0193040500E9 -:10C208009305050013850B00EF401042131909012F -:10C2180013570B013367E900138A0400637EA700F4 -:10C2280033078700138AF4FF636887006376A700E3 -:10C23800138AE4FF33078700B304A74093850A00F5 -:10C2480013850400EF4090451309050093850A0003 -:10C2580013850400EF401040930405009305050082 -:10C2680013850B00EF40503C13170B0113570701C0 -:10C2780013190901B367E9001387040063FEA700D7 -:10C28800B38787001387F4FF63E8870063F6A70086 -:10C298001387E4FFB3878700131A0A01B384A74002 -:10C2A800336AEA006FF0DFDF63ECD51EB7070100E1 -:10C2B80063F4F6041307F00FB335D70093953500F0 -:10C2C80033D7B60097670000938787B9B387E7002D -:10C2D80003C70700130A00023307B700330AEA400E -:10C2E80063160A0213041000E3E096E833B6CA00A6 -:10C2F800134416006FF05FE7B707000193050001CC -:10C30800E3E0F6FC930580016FF09FFBB35CE60069 -:10C31800B3964601B3ECDC0033D4E40093DB0C01A4 -:10C32800B397440133D7EA0093850B001305040043 -:10C33800336BF700B3194601EF4050361309050077 -:10C3480093850B0013050400139C0C01EF409030FB -:10C35800135C0C01930405009305050013050C00FC -:10C36800EF40902C1319090113570B013367E900AB -:10C3780013840400637EA700330797011384F4FF36 -:10C38800636897016376A7001384E4FF3307970176 -:10C39800B304A74093850B0013850400EF401030C9 -:10C3A8001309050093850B0013850400EF40902ABC -:10C3B800930405009305050013050C00EF40D026F3 -:10C3C80093170B011319090193D70701B367F900F4 -:10C3D8001386040063FEA700B38797011386F4FF52 -:10C3E80063E8970163F6A7001386E4FFB387970114 -:10C3F80013140401B70B01003364C4001389FBFF55 -:10C40800337D240133F92901B384A740930509003A -:10C4180013050D00EF405021935C040193050900BA -:10C42800130B050013850C00EF40102093D9090168 -:10C43800130C05009385090013850C00EF40D01EEE -:10C44800130905009385090013050D00EF40D01D61 -:10C458003305850193570B013385A7006374850164 -:10C468003309790193570501B387270163E6F4027D -:10C47800E392F4BCB70701009387F7FF3375F50023 -:10C4880013150501337BFB0033964A01330565011B -:10C49800130A0000E37AA6CC1304F4FF6FF09FB9E7 -:10C4A800130A0000130400006FF01FCC130101FBF6 -:10C4B8002324810423229104232E31032322910370 -:10C4C8002326110423202105232C4103232A510369 -:10C4D8002328610323267103232481032320A10336 -:10C4E800232EB101930C0500938905001304050060 -:10C4F80093840500639E062613090600138A060026 -:10C50800976A0000938ACA9563F4C514B7070100B7 -:10C518006376F6129307F00F63F4C700130A8000DE -:10C52800B3574601B38AFA0003C70A00130500028D -:10C5380033074701330AE540630C0A00B395490104 -:10C5480033D7EC0033194601B364B70033944C0178 -:10C55800935A090193850A0013850400EF401014CB -:10C568009309050093850A00131B0901138504002C -:10C57800EF40500E135B0B019305050013050B00EC -:10C58800EF40900A9399090193570401B3E7F90022 -:10C5980063FAA700B387270163E6270163F4A700BE -:10C5A800B3872701B384A74093850A001385040045 -:10C5B800EF40D00E9309050093850A001385040007 -:10C5C800EF405009131404019305050093990901DC -:10C5D80013050B0013540401EF40100533E48900E0 -:10C5E800637AA40033042401636624016374A400FD -:10C5F800330424013304A440335544019305000057 -:10C608008320C104032481048324410403290104F1 -:10C618008329C103032A8103832A4103032B0103CE -:10C62800832BC102032C8102832C4102032D0102BA -:10C63800832DC1011301010567800000B7070001C0 -:10C64800130A0001E36EF6EC130A80016FF05FED48 -:10C65800631A06009305000013051000EF40807F61 -:10C6680013090500B7070100637AF90E9307F00F65 -:10C6780063F42701130A8000B3574901B38AFA000B -:10C6880003C70A0013050002B38429413307470191 -:10C69800330AE540E30E0AEA33194901B3DAE9003F -:10C6A800B395490133D7EC0093540901336BB700B4 -:10C6B80013850A0093850400EF40407E9309050026 -:10C6C80093850400931B090113850A00EF408078C5 -:10C6D80093DB0B019305050013850B00EF40C07435 -:10C6E8009399090193570B01B3E7F90033944C016F -:10C6F80063FAA700B387270163E6270163F4A7005D -:10C70800B3872701B38AA7409385040013850A00DD -:10C71800EF40C078930905009385040013850A004B -:10C72800EF4040739305050013850B00EF40C06F81 -:10C7380093150B019399090193D50501B3E5B90048 -:10C7480063FAA500B385250163E6250163F4A50016 -:10C75800B3852501B384A5406FF09FDFB7070001BB -:10C76800130A0001E36AF9F0130A80016FF0DFF0A1 -:10C77800E3E8D5E8B707010063FCF604930BF00F74 -:10C7880033B5DB001315350033D7A60097570000E3 -:10C798009387076DB387E70083CB070093050002F3 -:10C7A800B38BAB00338B7541631E0B0263E4360118 -:10C7B80063EACC003384CC40B386D94033B58C00CF -:10C7C800B384A64013050400938504006FF05FE36B -:10C7D800B707000113050001E3E8F6FA1305800125 -:10C7E8006FF09FFAB3966601335D7601336DDD0015 -:10C7F80033D47901B395690133DC7C0193540D017D -:10C80800336CBC001305040093850400B31A660159 -:10C81800EF40C068130A050093850400130504005F -:10C8280033996C01931C0D01EF40C06293DC0C013D -:10C83800130405009305050013850C00EF40C05E46 -:10C84800131A0A0113570C013367EA00130A04008C -:10C85800637EA7003307A701130AF4FF6368A701E3 -:10C868006376A700130AE4FF3307A701B309A740BB -:10C878009385040013850900EF4040629385040006 -:10C888001304050013850900EF40C05C93050500FB -:10C898009304050013850C00EF40005993150C0113 -:10C8A8001314040193D50501B365B400138704007C -:10C8B80063FEA500B385A5011387F4FF63E8A5010E -:10C8C80063F6A5001387E4FFB385A501131A0A01CF -:10C8D800B70C0100336AEA001384FCFFB3778A00BF -:10C8E80033F48A00B384A540138507009305040038 -:10C8F8002326F100135A0A01EF400053930905005B -:10C908009305040013050A00EF40005213DC0A01E6 -:10C91800930D050093050C0013050A00EF40C05065 -:10C928008327C100130A050093050C00138507002F -:10C93800EF40804F3305B50113D709013307A7002E -:10C948006374B701330A9A01B70701009387F7FFA9 -:10C95800935507013377F70013170701B3F7F90069 -:10C96800B3854501B307F70063E6B400639EB400DE -:10C97800637CF90033865741B3B7C700B385A54137 -:10C98800B385F54093070600B307F9403339F9003A -:10C99800B385B440B385254133947501B3D7670196 -:10C9A8003365F400B3D565016FF09FC5130101FB32 -:10C9B80023248104232C41033704100013DA450192 -:10C9C80023202105232E3103232A51032324810305 -:10C9D8001304F4FF2326110423229104232861035E -:10C9E80023267103232291032320A103232EB101BF -:10C9F800137AFA7F13090500130C0600938A0600C0 -:10CA08003374B40093D9F50163060A0A9307F07FDB -:10CA18006304FA1013143400B70780003364F40079 -:10CA2800135BD501336B8B0093143500130A1AC0BE -:10CA3800930B000013D54A01370910001309F9FFB9 -:10CA48001375F57F3379590193050C0093DAFA01D0 -:10CA5800630205109307F07F6302F5163704800020 -:10CA680013193900336989001354DC013364240134 -:10CA780093153C00130515C09307000013972B006E -:10CA88003367F7001307F7FF9306E00033C959012E -:10CA9800330AAA4063E0E6169756000093860631EB -:10CAA800131727003307D700032707003307D700DA -:10CAB80067000700336BA400630E0B0663000404D1 -:10CAC80013050400EF40C043930755FF1307C00147 -:10CAD800634CF702130BD001930485FF330BFB4023 -:10CAE80033149400335B6901336B8B00B3149900E2 -:10CAF800130AD0C0330AAA406FF09FF3EF404040BA -:10CB0800130505026FF05FFC130485FD331B8900D4 -:10CB1800930400006FF0DFFD336BA40063040B0285 -:10CB280093040500130B0400130AF07F930B3000E5 -:10CB38006FF05FF093040000130A0000930B1000DD -:10CB48006FF05FEF93040000130AF07F930B20004F -:10CB58006FF05FEE33648901630E04066300090415 -:10CB680013050900EF40C039930755FF1307C001AB -:10CB7800634EF7021304D001930585FF3304F44094 -:10CB88003319B90033548C0033642401B315BC0045 -:10CB98001307D0C03305A7406FF01FEE13050C0034 -:10CBA800EF400036130505026FF01FFC130485FDE6 -:10CBB80033148C00930500006FF09FFD33648901E6 -:10CBC80063020402130409001305F07F9307300081 -:10CBD8006FF0DFEA930500001305000093071000CB -:10CBE8006FF0DFE9930500001305F07F930720003D -:10CBF8006FF0DFE86366640163128B4863E0B44852 -:10CC08009316FB0113D71400139CF401135B1B004C -:10CC1800B3E4E6001314840093DC8501B3EC8C00C4 -:10CC280093DA0C0193970C0193D70701139D8500A4 -:10CC380013050B0093850A002322F100EF408021A1 -:10CC480093050500930B050013950C011355050179 -:10CC5800EF40801D1304050093850A0013050B009F -:10CC6800EF40C0231315050113D704013365A7004E -:10CC780093890B00637E8500330595019389FBFF3B -:10CC880063689501637685009389EBFF3305950109 -:10CC98003304854093850A0013050400EF40801B88 -:10CCA80093050500930B050013950C011355050119 -:10CCB800EF408017130B050093850A001305040045 -:10CCC800EF40C01D939D04011315050193DD0D016F -:10CCD800B3EDAD0013870B0063FE6D01B38D9D01AD -:10CCE8001387FBFF63E89D0163F66D011387EBFF74 -:10CCF800B38D9D0193960901B7040100B3E6E600E0 -:10CD0800B38D6D41138BF4FF33F76601337B6D01EF -:10CD18001305070093050B0013D406012326D10041 -:10CD28002324E100EF4040102322A10093050B00CB -:10CD380013050400EF40400F935B0D0193090500B4 -:10CD480093850B0013050400EF40000E03278100B4 -:10CD58001304050013850B0093050700EF40C00C72 -:10CD680003264100330535018326C1001357060108 -:10CD78003307A700637437013304940037050100B3 -:10CD88001305F5FF93540701B379A7009399090197 -:10CD98003376A600B3848400B389C90063E89D0094 -:10CDA8001384060063949D0463723C05330CAC0144 -:10CDB8003337AC0133079701B38DED001384F6FFC9 -:10CDC80063E6BC016394BC036362AC0363E69D0045 -:10CDD800639EB401637C3C01330CAC013337AC0176 -:10CDE800330797011384E6FFB38DED00B3093C4187 -:10CDF800B3849D40B3373C01B384F4409305F0FFFE -:10CE080063889C1A93850A0013850400EF40800408 -:10CE1800930505002324A10013950C011355050162 -:10CE2800EF4080002322A10093850A0013850400A7 -:10CE3800EF40C00683268100032741001315050132 -:10CE480093D7090133E5A700938D0600637EE500BB -:10CE580033059501938DF6FF636895016376E500C8 -:10CE6800938DE6FF33059501B304E54093850A00E9 -:10CE780013850400EF30107E930505002322A100DE -:10CE880013950C0113550501EF30107A130C0500AA -:10CE980093850A0013850400EF4040009399090127 -:10CEA800032741001315050193D9090133E5A900AA -:10CEB80093070700637E8501330595019307F7FF04 -:10CEC80063689501637685019307E7FF330595014C -:10CED80093940D01B3E4F4009397040193D70701E9 -:10CEE80093050B00B3098541138507002322F10040 -:10CEF80093DD0401EF30507393050B00930A05008E -:10CF080013850D00EF305072130C050093850D004A -:10CF180013850B00EF30507183274100130B050078 -:10CF280013850B0093850700EF30107033058501DA -:10CF380093D70A013385A70063768501B7070100F7 -:10CF4800330BFB00B70601009386F6FF93570501E4 -:10CF58003377D50013170701B3FADA00B3876701EF -:10CF68003307570163E8F900938504006390F904D7 -:10CF78006300070433853C019385F4FF63649503DC -:10CF88006366F5006314F5026370ED0293161D00E5 -:10CF980033BDA601B30C9D019385E4FF33059501CC -:10CFA800138D06006314F5006304A70193E51500CB -:10CFB8001307FA3F6352E01293F775006380070284 -:10CFC80093F7F50093064000638AD70093864500DF -:10CFD800B3B5B6003304B400938506009317740004 -:10CFE80063DA0700B70700FF9387F7FF3374F4008D -:10CFF80013070A409307E07F63C2E71A9317D40127 -:10D0080093D53500B3E7B70013543400B7061000C2 -:10D018009386F6FF3374D400B70610801377F77F32 -:10D028009386F6FF131747013374D4001319F901D7 -:10D038003364E400336724018320C104032481049A -:10D0480083244104032901048329C103032A81039A -:10D05800832A4103032B0103832BC102032C810282 -:10D06800832C4102032D0102832DC1011385070082 -:10D07800930507001301010567800000130AFAFFF2 -:10D08800130C00006FF01FB91389090013040B007B -:10D098009385040093870B00130720006380E71033 -:10D0A800130730006382E70E13071000E392E7F0DE -:10D0B80013040000930700006F00400913890A0059 -:10D0C8006FF09FFD37040800930500001309000066 -:10D0D800930730006FF05FFC93061000B386E640BC -:10D0E80093078003E3C6D7FC9307F00163C4D70610 -:10D0F800130AEA41B317440133D7D500339A4501DF -:10D10800B3E7E700333A4001B3E747013354D400AB -:10D1180013F777006300070213F7F7009306400040 -:10D12800630AD70013874700B337F7003304F400C6 -:10D138009307070013178400634A07061317D401DF -:10D1480093D73700B367F700135434001307000070 -:10D158006FF0DFEB930710FEB387E7401307000279 -:10D16800B357F400130500006386E600130AEA4388 -:10D1780033154401336AB500333A4001B3E7470138 -:10D18800130400006FF0DFF837040800930700006D -:10D198001307F07F130900006FF05FE71304000026 -:10D1A800930700001307F07F6FF05FE61304000099 -:10D1B80093070000130710006FF05FE5130101FAF1 -:10D1C800232C8104232631053704100093D9450107 -:10D1D800232A910423206105232E7103232C810324 -:10D1E8001304F4FF232E11042328210523244105C9 -:10D1F80023225105232A91032328A1032326B103BF -:10D2080093F9F97F93040500930B0600138C06002D -:10D218003374B40013DBF5016388090A9307F07FC0 -:10D228006386F9103709800013143400336424012D -:10D238001359D50133698900131D3500938919C025 -:10D24800930C000013554C01370A1000130AFAFF1B -:10D258001375F57F337A8A0193840B00135CFC0104 -:10D26800630405109307F07F6304F5163704800004 -:10D27800131A3A00336A8A0013D4DB013364440179 -:10D2880093943B00130515C09307000013972C00D7 -:10D298003367F700B389A9001307F7FF9306E00087 -:10D2A800B34B8B01938A190063E0E616975600008A -:10D2B800938686B3131727003307D7000327070081 -:10D2C8003307D700670007003369A400630E090617 -:10D2D8006300040413050400EF309042930755FFE0 -:10D2E8001307C001634CF7021309D001130D85FF22 -:10D2F8003309F9403314A40133D92401336989006F -:10D30800339DA4019309D0C0B389A9406FF05FF39E -:10D31800EF30103F130505026FF05FFC130985FD20 -:10D3280033992401130D00006FF0DFFD3369A40069 -:10D3380063040902130D0500130904009309F07F23 -:10D34800930C30006FF01FF0130D000093090000DC -:10D35800930C10006FF01FEF130D00009309F07F7E -:10D36800930C20006FF01FEE33647A01630E0406FD -:10D3780063000A0413050A00EF309038930755FF3D -:10D388001307C001634EF7021304D001930485FF0D -:10D398003304F440331A9A0033D48B0033644401C5 -:10D3A800B3949B009307D0C03385A7406FF0DFED9F -:10D3B80013850B00EF30D034130505026FF01FFC06 -:10D3C800130485FD33948B00930400006FF09FFDD8 -:10D3D80033647A016302040213040A001305F07F20 -:10D3E800930730006FF09FEA9304000013050000D4 -:10D3F800930710006FF09FE9930400001305F07F76 -:10D40800930720006FF09FE837070100130AF7FF22 -:10D41800135C0D0193DD0401337D4D01B3F4440128 -:10D4280093050D00138504002328E100EF30D01F79 -:10D43800930C05009385040013050C00EF30D01EF3 -:10D448002326A10093850D0013050C00EF30D01D95 -:10D45800130B050093050D0013850D00EF30D01C4C -:10D468008326C10093D70C013305D5003385A70067 -:10D478006376D50003270101330BEB0093560501B2 -:10D4880033754501B3FC4C0113150501B30795012C -:10D49800935C04013374440193050D0013050400E3 -:10D4A800232AD1002326F100EF3010182328A100E9 -:10D4B8009305040013050C00EF301017130A05003C -:10D4C80093850C0013050C00EF301016130C0500A3 -:10D4D80093050D0013850C00EF301015032701018B -:10D4E8003305450183264101935707013385A7007A -:10D4F80063764501B7070100330CFC0037060100CD -:10D5080093570501338C87019307F6FF337AF500AB -:10D518003377F700131A0A01135D0901330AEA0089 -:10D528003379F90033874601930509001385040010 -:10D538002328E100232EC100EF30100F938504004B -:10D54800232CA10013050D00EF30100E232AA10093 -:10D5580093050D0013850D00EF30100D93040500A1 -:10D568009305090013850D00EF30100C8326410147 -:10D57800032781013305D500935707013385A70099 -:10D588006376D5000326C101B384C400B706010041 -:10D598009387F6FF935D0501B3849D00B37DF50085 -:10D5A8003377F7009305090013050400939D0D01D7 -:10D5B800B38DED00232CD100EF3010079305040044 -:10D5C800232AA10013050D00EF30100693050D0066 -:10D5D8001304050013850C00EF301005130D05002A -:10D5E8009305090013850C00EF301004032741014F -:10D5F80033058500935707013385A70063768500B7 -:10D6080083268101330DDD0083270101B706010060 -:10D618009386F6FF330BFB00B377D5003377D7003B -:10D6280093970701B387E700333A4B01B387870124 -:10D6380033844701330BBB0133079400B33DBB016F -:10D64800B306B70133BC870133344401935705014E -:10D658003337970033648C00B3BDB6013304F4004C -:10D66800B36DB7013304B4013304A40193D7760131 -:10D67800131494003364F4008327C10093149B00AF -:10D68800135B7B01B3E4F400B334900093979600E6 -:10D69800B3E46401B3E4F4009317740063D207128F -:10D6A80093D7140093F41400B3E497009317F4018C -:10D6B800B3E4F400135414001387FA3F6356E010E0 -:10D6C80093F774006380070293F7F4009306400011 -:10D6D800638AD70093874400B3B497003304940057 -:10D6E800938407009317740063DA0700B70700FFF5 -:10D6F8009387F7FF3374F40013870A409307E07F9A -:10D7080063C6E71893DA34009314D401B3E45401E0 -:10D7180013543400B70710009387F7FF3374F400ED -:10D728009377F77F370710801307F7FF9397470121 -:10D738003374E400939BFB013364F400B367740112 -:10D748008320C105032481051385040003290105ED -:10D75800832441058329C104032A8104832A4104BF -:10D76800032B0104832BC103032C8103832C410366 -:10D77800032D0103832DC1029385070013010106C0 -:10D7880067800000930B0B001304090093040D003D -:10D7980093870C0013072000638AE70E13073000F5 -:10D7A800638CE70C13071000E398E7F013040000FC -:10D7B800930400006F008008930B0C006FF09FFD2E -:10D7C800938A09006FF05FEF93061000B386E64076 -:10D7D80093078003E3CCD7FC9307F00163C4D70613 -:10D7E800938AEA41B317540133D7D400B394540150 -:10D7F800B3E7E700B3349000B3E497003354D400A0 -:10D8080093F774006380070293F7F400130740004E -:10D81800638AE70093874400B3B497003304940005 -:10D82800938407009317840063CA07069317D401EB -:10D8380093D43400B3E49700135434001307000062 -:10D848006FF05FED930710FEB387E7401306000201 -:10D85800B357F400130700006386C600938AEA43AF -:10D8680033175401B3649700B3349000B3E49700BE -:10D87800130400006FF0DFF8370408009304000079 -:10D888001307F07F930B00006FF0DFE8130400002C -:10D89800930400001307F07F6FF0DFE71304000024 -:10D8A80093040000130710006FF0DFE68327C5001C -:10D8B80003AF050083AF450083A2850083A5C5009B -:10D8C8003787000093D607011307F7FF139807015E -:10D8D800939E050113D6F701B3F6E60093D7050129 -:10D8E800130101FF8328050003234500032E85004B -:10D8F8001358080193DE0E01B3F7E70093D5F5013D -:10D908006390E60233E768003367C70133670701AE -:10D9180013051000631A07046398D7046F0080008A -:10D92800639CE7003367FF01336757003367D7010C -:10D9380013051000631A0702130510006396D70237 -:10D948006394E8036312F30363105E02631ED80155 -:10D958006300B602639A070033E568003365C501C2 -:10D96800336505013335A00013010101678000000C -:10D97800130500006FF05FFF8327C50083A8C5006B -:10D98800032F05000326450003288500378500007E -:10D9980013D707011305F5FF939E080193D60801D5 -:10D9A80083A2050003A3450003AE85003377A700D3 -:10D9B80093950701130101FF93D5050193D7F7014B -:10D9C80093DE0E01B3F6A60093D8F8016310A70200 -:10D9D800B36FCF00B3EF0F01B3EFBF001305E0FF44 -:10D9E80063800F0E13010101678000006398A6028F -:10D9F800B3EF6200B3EFCF01B3EFDF011305E0FF30 -:10DA0800E3920FFE631207043365CF003365050107 -:10DA18003365B500133515006F00C0026314070A9B -:10DA28003365CF00336505013365B500133515003F -:10DA3800639A0600B3EF6200B3EFCF01B3EFDF01E3 -:10DA4800638C0F06631A0500638E17011305100017 -:10DA5800E38A07F86F008000E39608F81305F0FFE3 -:10DA68006FF05FF8E3C4E6FE635AD7001305F0FFD2 -:10DA7800E38A07F6130510006FF0DFF6E3E8BEFC53 -:10DA88006396D503E3640EFD6314C805E360C3FC25 -:10DA980063146600E3ECE2FBE36A66FC130500002E -:10DAA800E31266F4E3645FFC6FF0DFF3E3E0D5FDB7 -:10DAB800130500006FF01FF3E31C05FE6FF01FF95C -:10DAC800E388E6F213050000E38606F66FF0DFF759 -:10DAD800E36EC8F96FF0DFFD8327C50083A8C50092 -:10DAE800032F05000326450003288500378500001D -:10DAF80013D707011305F5FF939E080193D6080174 -:10DB080083A2050003A3450003AE85003377A70071 -:10DB180093950701130101FF93D5050193D7F701E9 -:10DB280093DE0E01B3F6A60093D8F8016310A7029E -:10DB3800B36FCF00B3EF0F01B3EFBF0013052000A1 -:10DB480063800F0E13010101678000006398A6022D -:10DB5800B3EF6200B3EFCF01B3EFDF01130520008D -:10DB6800E3920FFE631207043365CF0033650501A6 -:10DB78003365B500133515006F00C0026314070A3A -:10DB88003365CF00336505013365B50013351500DE -:10DB9800639A0600B3EF6200B3EFCF01B3EFDF0182 -:10DBA800638C0F06631A0500638E170113051000B6 -:10DBB800E38A07F86F008000E39608F81305F0FF82 -:10DBC8006FF05FF8E3C4E6FE635AD7001305F0FF71 -:10DBD800E38A07F6130510006FF0DFF6E3E8BEFCF2 -:10DBE8006396D503E3640EFD6314C805E360C3FCC4 -:10DBF80063146600E3ECE2FBE36A66FC13050000CD -:10DC0800E31266F4E3645FFC6FF0DFF3E3E0D5FD55 -:10DC1800130500006FF01FF3E31C05FE6FF01FF9FA -:10DC2800E388E6F213050000E38606F66FF0DFF7F7 -:10DC3800E36EC8F96FF0DFFD130101F22326310D01 -:10DC480083A9C50083A6050083A745002328A10052 -:10DC580003A58500139709012328210D2324410DCD -:10DC68002322510D2320610D032A0600032B4600B1 -:10DC7800832A86000329C60037860000232C810CDE -:10DC88001357070113D409011306F6FF2326310998 -:10DC9800232E110C232A910C232E710B232C810B7C -:10DCA800232A910B2328A10B2326B10B2320D1086B -:10DCB8002322F1082324A1082328D104232AF104CC -:10DCC800232CA104232EE1043374C40093D9F90151 -:10DCD800630A04126300C426370501003365A700F0 -:10DCE800232EA104130601059307C10503A7070006 -:10DCF80083A6C7FF9387C7FF1317370093D6D601AC -:10DD08003367D70023A2E700E312F6FE8327010555 -:10DD1800939737002328F104B7C7FFFF93871700AD -:10DD28003304F400930400009317090137870000B7 -:10DD38001355090193D707011307F7FF2326210974 -:10DD48002320410923226109232451092320410763 -:10DD580023226107232451072326F1063375E500A2 -:10DD68001359F901630C051E6304E532B70A010073 -:10DD7800B3EA570123265107130601069307C10684 -:10DD880003A7070083A6C7FF9387C7FF13173700AA -:10DD980093D6D6013367D70023A2E700E312F6FE35 -:10DDA80083270106939737002320F106B7C7FFFFA3 -:10DDB800938717003305F50013070000B3C729013F -:10DDC800232AF100B30785002324F1029387170063 -:10DDD8002322F10293972400B3E7E7009387F7FF24 -:10DDE8009306E00063EAF62C9746000093868603C4 -:10DDF80093972700B387D70083A70700B387D70077 -:10DE08006780070033E6D7003366A6003366E6006E -:10DE1800630006146302070613050700EF30400E7F -:10DE2800130C0500930B4CFF93D45B4093FBFB0151 -:10DE3800638E0B069305C0FF13850400EF20D07E88 -:10DE48009306000213972400130800FFB386764157 -:10DE58001305C5FF631605099307010A3387E70011 -:10DE6800832701059384F4FFB39B7701232877FB6D -:10DE78001307F0FF6F00C00A63080500EF30400881 -:10DE8800130C05026FF01FFA638A07001385070059 -:10DE9800EF300007130C05046FF0DFF81385060058 -:10DEA800EF300006130C05066FF0DFF79305C0FF8F -:10DEB80013850400EF205077130401059307300001 -:10DEC8003307A4000327C7009387F7FF1304C4FF91 -:10DED8002328E400E3D697FE9384F4FF6FF05FF9FC -:10DEE80093070105B385A7003306A7003386C7004B -:10DEF80083A7C50083A50501B3D7D700B3957501DE -:10DF0800B3E7B7002328F6006FF09FF49397240037 -:10DF180093060105B387F60023A007009384F4FF56 -:10DF2800E396E4FE37C4FFFF13041401330484416D -:10DF38006FF05FDFB3E7D700B3E7A70033E5E7008B -:10DF480093042000E30205DE930430006FF0DFDD68 -:10DF580013040000930410006FF01FDD33676A019B -:10DF6800336757013367F7006302071463820706B4 -:10DF780013850700EF20D078130B0500930A4BFF99 -:10DF880013DA5A4093FAFA0163800A089305C0FF2E -:10DF980013050A00EF2050699306000213172A00A0 -:10DFA800130800FFB38656411305C5FF631805091A -:10DFB8009307010A3387E70083270106130AFAFF4C -:10DFC800B39A5701232057FD1307F0FF6F00000B8A -:10DFD800638A0A0013850A00EF209072130B05026A -:10DFE8006FF0DFF9630A0B0013050B00EF20507187 -:10DFF800130B05046FF09FF813050A00EF2050700B -:10E00800130B05066FF09FF79305C0FF13050A0071 -:10E01800EF209061930A0106930730003387AA0026 -:10E028000327C7009387F7FF938ACAFF23A8EA004C -:10E03800E3D647FF130AFAFF6FF01FF993070106AB -:10E04800B385A7003306A7003386C70083A7C5009A -:10E0580083A50501B3D7D700B3955501B3E7B7003A -:10E068002328F6006FF05FF493172A009306010641 -:10E07800B387F60023A00700130AFAFFE316EAFEA7 -:10E0880037C5FFFF13051501330565416FF0DFD272 -:10E09800336A6A01B36A5A01B3EAFA001307200027 -:10E0A800E38E0AD0130730006FF05FD1130500002C -:10E0B800130710006FF09FD0832901050324010680 -:10E0C800370B01009304FBFF93DA0901135904018C -:10E0D800B3F999003374940093850900130504007B -:10E0E800EF209054130A05009305040013850A00D5 -:10E0F800EF209053130C05009305090013850A00BF -:10E10800EF209052930B0500938509001305090031 -:10E11800EF2090513305850193570A013385A700F5 -:10E1280063748501B38B6B01832C4106135D050174 -:10E1380033759500337A9A0013150501B307450125 -:10E1480013DA0C01B3FC9C009385090013850C00BD -:10E158002326F1022320F108EF20104D130B0500B0 -:10E1680093850C0013850A00EF20104C93040500DA -:10E1780093050A0013850A00EF20104B130C0500C5 -:10E188009385090013050A00EF20104A330595000E -:10E1980093570B013385A70063769500B7070100F5 -:10E1A800330CFC00B706010093570501232CF1003E -:10E1B8009387F6FFB37DF50083244105337BFB008D -:10E1C800939D0D01B38D6D013307BD0113DD04016E -:10E1D800B3F4F4009385040013050400232AE10234 -:10E1E8002324D100EF2050442322A10093050400EA -:10E1F80013050D00EF2050432320A10093050D00C7 -:10E2080013050900EF205042130B05009385040005 -:10E2180013050900EF2050410326010003274100A0 -:10E228003305C500935707013385A7006376C500FA -:10E2380083268100330BDB00935705013706010065 -:10E24800B3876701232EF1009307F6FF337BF500B0 -:10E258003377F70093850C00131B0B01138504001B -:10E26800330BEB002326C100EF20103C2324A10030 -:10E2780093850C0013050D00EF20103B2322A1000D -:10E2880093050D0013050A00EF20103A2320A10082 -:10E298009385040013050A00EF2010390328410074 -:10E2A80003278100832601003305050193570701E1 -:10E2B8003385A700637605010326C100B386C6002F -:10E2C8009357050137060100B387D7002320F102D1 -:10E2D8009307F6FF3375F500131505013377F7003B -:10E2E8003307E5002328E102032781069385090007 -:10E2F800232EC102B377F700935607011385070051 -:10E308002320D1002324F100EF201032832581003F -:10E31800232CA10213850A00EF2010318325010068 -:10E328002326A10013850A00EF2010302322A10024 -:10E338000325010093850900EF20102F0328C10051 -:10E3480003278103832641003305050193570701FD -:10E358003385A700637605010326C103B386C6008B -:10E368003708010093570501B386D7009307F8FFD4 -:10E378003376F5003377F700131606013306E60007 -:10E38800032781052326D10493050400B377F700FA -:10E3980093560701138507002322C1042322D100C5 -:10E3A8002326F10023240105EF2010282320A104AF -:10E3B8000325410093050400EF2010278325410021 -:10E3C800232EA10213050900EF2010268325C10082 -:10E3D800232CA10213050900EF2010258328C1036F -:10E3E8000323010403278103330515019357030110 -:10E3F800B387A700032641048326C10463F61701E7 -:10E40800032881043307070113D807013308E800FC -:10E41800370701009305F7FFB3F7B7003373B3006D -:10E4280093970701B38E670083274103232CE102EA -:10E4380003270103B38BFB0083278101B3BDBB0115 -:10E44800B388B701B3876B0133BB6701232CF10095 -:10E458002322F1088327C101B3888801B387F80014 -:10E46800338C67013303EC00333EE3000327C1011B -:10E47800333C6C01B3B8B801B3B7E70033EC87019C -:10E4880083270102330C1C013303C300330CFC0047 -:10E498003305CC01B308D500032701023336C30086 -:10E4A800B307D301338FC80033B3D701232EF1004C -:10E4B8002324F108032BC106B3070F01333EC5011E -:10E4C800333CEC00B3B6D8003336CF00B38D6700C9 -:10E4D800B3E6C600336CCC01B3B7070133B36D00A4 -:10E4E800330CDC00B3E76700935B0B01337BBB00A5 -:10E4F800B307FC009385090013050B002320F102E4 -:10E50800EF209012130C050093050B0013850A00E9 -:10E51800EF2090112328A10293850B0013850A0090 -:10E52800EF209010930A05009385090013850B00CE -:10E53800EF20900F8326010393570C013305D50074 -:10E548003385A7006376D50003278103B38AEA00E1 -:10E5580093570501B7060100B38757012328F10235 -:10E56800832AC1059387F6FFB379F500337CFC0055 -:10E5780093990901B389890113DC0A01B3FAFA00F6 -:10E5880093850A0013050400232ED102EF20D00939 -:10E5980093050400232CA10213050C00EF20D008DA -:10E5A800232AA10293050C0013050900EF20D007C8 -:10E5B8001304050093850A0013050900EF20D0060F -:10E5C80003264103032781033305C5009357070139 -:10E5D8003385A7006376C5008326C1033304D400BE -:10E5E8003708010093570501338487009307F8FF24 -:10E5F8003379F500032581003377F700938504000C -:10E6080013190901232001053309E900EF20D0017E -:10E6180083258100232EA10213050D00EF20D000D1 -:10E6280083250100232CA10213050D00EF20C07FD4 -:10E63800232AA1020325010093850400EF20C07E50 -:10E64800832881038326C10303264103330515016B -:10E6580093D706013385A7006376150103280104C3 -:10E6680033060601B70801009387F8FF3377F500F2 -:10E67800135E05010325C100B3F6F6001317070161 -:10E68800330ECE003307D70093850C002324C10531 -:10E698002320E10423221105EF200079232EA10273 -:10E6A8000325410093850C00EF2000788325410065 -:10E6B800232CA10213050A00EF2000778325C1004F -:10E6C800232AA10213050A00EF2000760323810301 -:10E6D8000328C10303264103330565009356080147 -:10E6E8003385A60003270104032E810463766500A1 -:10E6F8008328410433061601370301009306F3FF0C -:10E7080093580501B388C800B377D5003378D8008B -:10E718000326010383260102B38D3D01B3BF3D01EA -:10E72800B386C600338FF601B38D2D019397070189 -:10E73800B387070133B92D0133088F00B30E2801C1 -:10E74800B38DED00232A610203230103B385CE01B3 -:10E7580033B7ED003386FD003385E50033B92E016C -:10E76800B3B5C501B3B66600333FFF013334880043 -:10E77800B337F6002320C1022326C1083337E5004A -:10E788003306150133E7E50033EFE601B309F60078 -:10E79800336424018325C1000325810033048F00DD -:10E7A80033361601B3B7F9003304E400B367F60053 -:10E7B8003304F400EF2040672328A1028325810059 -:10E7C80003254100EF204066130905008325410019 -:10E7D80003250100EF204065930D05008325C10046 -:10E7E80003250100EF2040640327010333052501B9 -:10E7F800935707013385A700637625010323410357 -:10E80800B38D6D00B706010093570501B38DB701AD -:10E818009387F6FF3379F5003377F7009385040083 -:10E828001319090113050B003309E900232CD10240 -:10E83800EF20805F232AA10293050B0013050D002A -:10E84800EF20805E2328A10293850B0013050D009D -:10E85800EF20805D130D05009385040013850B00E0 -:10E86800EF20805C03260103032741033305C5001D -:10E87800935707013385A7006376C5008326810374 -:10E88800330DDD00B706010093570501338DA7014D -:10E898009387F6FFB374F5003377F70093850C0080 -:10E8A8009394040113850A00B384E400232CD10255 -:10E8B800EF20805793850C00232AA10213050C0032 -:10E8C800EF2080562328A10293050C0013050A00A7 -:10E8D800EF208055930C050093850A0013050A0064 -:10E8E800EF20805403260103032741033305C500A5 -:10E8F800935707013385A7006376C50083268103F4 -:10E90800B38CDC003708010093570501B38C9701DD -:10E918009307F8FF337AF5000325C1003377F70032 -:10E9280093050B00131A0A01330AEA00232C01038A -:10E93800EF20804F232AA1020325410093050B00F5 -:10E94800EF20804E2328A1020325410093850B0068 -:10E95800EF20804D8325C1002322A10013850B00E1 -:10E96800EF20804C832801038326410303264100BE -:10E978003305150113D706013305A7006376150182 -:10E988000328810333060601370801001307F8FF3F -:10E99800B377E5001353050103258100B3F6E600BC -:10E9A800939707013303C300B387D70093850A0001 -:10E9B800232C61022328F102232A0103EF20C046F9 -:10E9C800832581002326A10013050C00EF20C045F4 -:10E9D8002324A1000325010093050C00EF20C04467 -:10E9E8002322A1000325010093850A00EF20C043DC -:10E9F80083288100032EC100032641003305150139 -:10EA080093560E013385A600832701030323810350 -:10EA18006376150103284103330606013708010010 -:10EA280093580501B3892901B388C80033B929016E -:10EA38001306F8FF3304B401B30E24013377C5007D -:10EA4800B3899900337ECE00B385AE01B3B4990083 -:10EA5800131707013307C701B3894901338E95009E -:10EA6800330F9E0133BA4901B30F4F0133B52E015D -:10EA78003334B40133BDA501B3349E00336E9D0019 -:10EA8800B33C9F0133BA4F013365A4003305C50178 -:10EA980033EA4C01B386FF003305450133056500B1 -:10EAA800B3B7F600B305F500B3B7F5003335650025 -:10EAB800B386E60033B7E6003364F5003385150105 -:10EAC800B304E50033B7E4003335150123283109D1 -:10EAD80093850A00B369E50013050B002320C100E4 -:10EAE80023220101232AD108EF20003493050B00CB -:10EAF800130A050013050C00EF200033130B050063 -:10EB080093050C0013850B00EF2000321309050054 -:10EB180093850A0013850B00EF200031330565014A -:10EB280013570A013305A700032601006376650120 -:10EB38000328410033090901B377C50093970701FA -:10EB48003376CA003386C700032781018327C102B1 -:10EB580013550501B384C400B3E7E7000327C101D7 -:10EB68003305850033B6C400B36BF7008327010271 -:10EB7800330535013305C500330525019397D700C3 -:10EB8800232EA108232C9108B3E777011307010866 -:10EB980013060000130540008326C70083250701DC -:10EBA8001306160093D636019395D500B3E6B60042 -:10EBB8002320D70013074700E310A6FE0327010808 -:10EBC80083268108B337F000B3E7E700232CD1068A -:10EBD8000327C108832641082328F106232EE106CE -:10EBE800232AD1069316B70063D406249397F70116 -:10EBF80013070107130600001305300083260700DA -:10EC0800832547001306160093D616009395F50141 -:10EC1800B3E6B6002320D70013074700E310A6FE8B -:10EC28000327C107B337F00013571700232EE10657 -:10EC380003270107B367F7002328F10603274102DA -:10EC4800B74700009387F7FFB307F7006354F02036 -:10EC58000327010793767700638406049376F70009 -:10EC680013064000638EC602832641071307470038 -:10EC78002328E10613374700B306D70033B7E60069 -:10EC8800232AD10683268107B306D700232CD10671 -:10EC9800B3B6E6000327C107B386E600232ED106E4 -:10ECA8000327C1079316B70063D00602B707F0FF22 -:10ECB8009387F7FF3377F700232EE10603274102F6 -:10ECC800B7470000B307F700130701071306000052 -:10ECD8001305300083260700832547001306160016 -:10ECE80093D636009395D501B3E6B6002320D70016 -:10ECF80013074700E310A6FE378700009306E7FFD7 -:10ED080063CEF6120327C10713573700232EE106F7 -:10ED18000327C107B70601809386F6FF2316E1088B -:10ED2800378700001307F7FFB3F7E7000327C10889 -:10ED3800939707018320C10D3377D700B367F70096 -:10ED480003274101B706008093C6F6FF1317F701A2 -:10ED5800B3F7D700B3E7E7008326010103270107CC -:10ED68000324810D23A6F60023A0E600032741070C -:10ED78008324410D0329010D23A2E60003278107FF -:10ED88008329C10C032A810C23A4E600832A410CA1 -:10ED9800032B010C832BC10B032C810B832C410B00 -:10EDA800032D010B832DC10A138506001301010EE3 -:10EDB80067800000232A3101832701052328F106F3 -:10EDC80083274105232AF10683278105232CF10691 -:10EDD8008327C105232EF106930720006380F428BA -:10EDE80093073000638AF42893071000E398F4E44B -:10EDF800232E0106232C0106232A010623280106B7 -:10EE08006F00C021232A21018327010693040700EC -:10EE18002328F10683274106232AF1068327810642 -:10EE2800232CF1068327C106232EF1066FF0DFFAA3 -:10EE3800832781022322F1026FF05FE0232E01066F -:10EE4800232C0106232A0106232801069307F7FF2E -:10EE58006FF01FEC93061000B387F64013074007C6 -:10EE68006342F71C13D6574093F6F70113070000C7 -:10EE780093070000931527006312C70263980604DE -:10EE880013053000130601073305E5406354D50226 -:10EE9800930640003387E6406F00400813050107DA -:10EEA800B305B50083A5050013071700B3E7B7003E -:10EEB8006FF05FFC3308B60003280800938616003D -:10EEC80013064600232E06FF6FF05FFC1306010AA7 -:10EED8003306B600032606FD130800023308D8409F -:10EEE80033160601B3E7C70013063000930801077D -:10EEF800130300003306E6406346C302930540004F -:10EF08003387E540131626009305010A3386C500AA -:10EF18008325C107B3D6D5002328D6FC13064000A5 -:10EF28006F000004338EB80003250E00032E4E0038 -:10EF3800130313003355D500331E0E013365C50185 -:10EF480023A0A800938848006FF01FFB93162700A2 -:10EF580093050107B386D50023A006001307170001 -:10EF6800E316C7FE83260107B337F000B3E7D700DF -:10EF78002328F10693F677006382060493F6F700D8 -:10EF8800638EE60203274107938747002328F1068B -:10EF980093B747003387E700B337F700232AE10622 -:10EFA800032781073387E700232CE1063337F7006F -:10EFB8008327C1073307F700232EE1068327C107FC -:10EFC8001397C700635E0700232E0106232C010652 -:10EFD800232A010623280106930710006FF05FD348 -:10EFE80093070107930600009305300003A7070065 -:10EFF80003A6470093861600135737001316D60149 -:10F008003367C70023A0E70093874700E390B6FE65 -:10F018008327C10793D73700232EF10693070000F3 -:10F028006FF01FCF83274107032701073367F700D6 -:10F03800832781073367F7008327C1073367F70002 -:10F0480093070000E30607CC232E0106232C0106B4 -:10F05800232A0106232801066FF09FCBB7870000FB -:10F06800232E0106232C0106232A01062328010644 -:10F078009387F7FF6FF0DFC9B7870000232EF106EB -:10F08800232C0106232A0106232801069387F7FF6C -:10F09800232A01006FF0DFC7130101FA83A7850057 -:10F0A8002324410503AAC50083A6050003A745003C -:10F0B800232CF102232CF10093170A01232C81043D -:10F0C80093D7070113141A00232A91040323060077 -:10F0D8009304050083284600832586000325C6007F -:10F0E800232E4103232E110423282105232631052D -:10F0F800232251052328D102232AE1022328D10003 -:10F10800232AE100232EF10013541401135AFA01A3 -:10F11800130801011306C101832706000327C6FF50 -:10F128001306C6FF939737001357D701B3E7E700D5 -:10F138002322F600E312C8FE832601019317050176 -:10F14800232CB102939636002324B10293D70701EA -:10F158009315150023286102232A1103232EA102E7 -:10F1680023206102232211032328D1002326F10240 -:10F1780093D515011355F501930801021303C10234 -:10F18800832703000327C3FF1303C3FF93973700A5 -:10F198001357D701B3E7E7002322F300E39268FE91 -:10F1A80083270102378700001307F7FF939737007B -:10F1B8002320F1026390E502032E81020327410216 -:10F1C8003367C701032EC1023367C7013367F700EE -:10F1D80063140700134515003307B440E3164511BF -:10F1E8006352E030639605140325410283258102AA -:10F1F8000328C1023366B500336606013366F6009C -:10F2080063140602832741012328D102130407004F -:10F21800232AF10283278101232CF1028327C101CC -:10F22800232EF1026F0040301306F7FF631E060C11 -:10F2380003274101B387F600B3B6D7003306E500CC -:10F248002328F102B307D600B3B6D700232AF10268 -:10F25800832781013337E600B366D7003387F5008B -:10F268003306D700B337F7000327C101B336D600FA -:10F27800B3E7D7003308E800B3870701232CC1029E -:10F28800232EF102130410008327C1031397C7002C -:10F29800635C07283707F8FF1307F7FFB3F7E700A2 -:10F2A800232EF1028327010313041400130701031B -:10F2B8009397F70113060000130530008326070013 -:10F2C800832547001306160093D616009395F5017B -:10F2D800B3E6B6002320D70013074700E310A6FEC5 -:10F2E8000327C103B337F00013571700232EE10299 -:10F2F80003270103B367F7002328F102B78700004B -:10F308009387F7FF6F00C07CB78700009387F7FFEC -:10F31800E30AF7EE9307400763D0C70623260102E6 -:10F328002324010223220102930710006F00801496 -:10F33800B78700009387F7FF6312F4028327410120 -:10F348002328D102232AF10283278101232CF102E9 -:10F358008327C101232EF1026F00001D8327C102FC -:10F36800B7060800B3E7D7002326F1029307400742 -:10F37800E3C6E7FA13060700135756409305000043 -:10F388001376F60193070000939627006390E7022F -:10F3980063140604130730003307F7406352C702AB -:10F3A80013074000B307F7406F00C007B386D800C3 -:10F3B80083A6060093871700B3E5D5006FF0DFFC3E -:10F3C8003305D30003250500130616001303430075 -:10F3D800232EA3FE6FF09FFC130701043307D70009 -:10F3E800032707FE130800023308C8403317070134 -:10F3F800B3E5E50013073000130E00003307F740AC -:10F408006346EE0293064000B387F64013172700C1 -:10F41800930601043387E6008326C10233D6C6006B -:10F428002320C7FE930640006F00C003B30ED3002D -:10F4380003A50E0083AE4E00130E1E003355C50003 -:10F44800B39E0E013365D5012320A30013034300A7 -:10F458006FF01FFB139727003387E800232007006E -:10F4680093871700E398D7FE03270102B337B0004C -:10F47800B367F7002320F1028326010183270102E5 -:10F488000327410183258102B387F600B3B6D7006D -:10F498002328F102832741020325C102B307F7009D -:10F4A8003386D70033B7E700B337D600B367F70022 -:10F4B800032781018326C101232AC102B305B700AE -:10F4C8003386F50033B7E500B337F600B386A600F8 -:10F4D8003367F7003387E600232CC102232EE102AD -:10F4E8006FF09FDA6300073E631604248328410106 -:10F4F80003258101032EC10133E3A8003363C3014F -:10F508003363D3006310031A2328F10283274102CF -:10F5180013840500232AF10283278102232CF10298 -:10F528008327C102232EF1028327010313F77700F3 -:10F538006304070413F7F70093064000630ED7022D -:10F5480003274103938747002328F10293B7470015 -:10F558003387E700B337F700232AE1020327810343 -:10F568003387E700232CE1023337F7008327C103F1 -:10F578003307F700232EE1028327C1031397C7003F -:10F588006354070237870000130414001307F7FFBA -:10F598006314E4006F00507F3707F8FF1307F7FF85 -:10F5A800B3F7E700232EF102930701039306000047 -:10F5B8009305300003A7070003A6470093861600AB -:10F5C800135737001316D6013367C70023A0E70087 -:10F5D80093874700E390B6FE8327C103B7860000F0 -:10F5E80013D73700232EE1029387F6FF631AF4023C -:10F5F8000326410383270103B3E7C70003268103DA -:10F60800B3E7C700B3E7E700638C0700232ED102F6 -:10F61800232C0102232A010223280102130A0000D5 -:10F628008327C103370701801307F7FF2316F1006B -:10F63800B78700009387F7FF3374F400931704012A -:10F648000324C1008320C105138504003374E4003A -:10F658003364F4009317FA01370A0080134AFAFF5B -:10F6680033744401336AF4008327010303248105BA -:10F6780023A6440123A0F40083274103032901059D -:10F688008329C10423A2F40083278103032A810468 -:10F69800832A410423A4F4008324410513010106AD -:10F6A800678000001303F0FF63106706032641021A -:10F6B800B386F600B3B7F6003388C8003307F800FE -:10F6C800B337F700232AE102032781023336C80043 -:10F6D800B367F6002328D102B306E5003386F600A7 -:10F6E800B337F60033B7E6003367F7008327C10264 -:10F6F800232CC102330EFE003307C701232EE1027B -:10F70800138405006FF05FB8B78600009386F6FF94 -:10F71800E38CD5DE1347F7FF9307400763D0E70470 -:10F72800232E0100232C0100232A01009307100037 -:10F738006F008012B78600009386F6FFE386D5DC5B -:10F748008327C101B7060800B3E7D700232EF100CD -:10F758009307C0F8E346F7FC3307E0409356574059 -:10F76800930800001377F70193070000139527000B -:10F778006390D7026314070493063000B386F640FB -:10F7880063D2E60213074000B307F7406F00C007D3 -:10F798003305A8000325050093871700B3E8A800E0 -:10F7A8006FF0DFFC3303A6000323030013071700E1 -:10F7B80013064600232E66FE6FF09FFC9306010495 -:10F7C800B386A60083A606FD130E0002330EEE4094 -:10F7D800B396C601B3E8D80093063000930E000034 -:10F7E800B386F64063C6DE0213064000B307F64050 -:10F7F8009396260013060104B306D6000326C1011A -:10F808003357E60023A8E6FC930640006F00C003C8 -:10F81800330FA60003230F00032F4F00938E1E0003 -:10F828003353E300331FCF013363E3012320660022 -:10F83800130646006FF01FFB139727003307E800F5 -:10F848002320070093871700E398D7FE03270101B9 -:10F85800B3371001B367F7002328F10083260102AC -:10F86800832701010327410203258101B387F6009D -:10F87800B3B6D7002328F102832741010328C10129 -:10F88800B307F7003386D70033B7E700B337D6009E -:10F89800B367F700032781028326C102232AC10226 -:10F8A8003305A7003306F5003337E500B337F60014 -:10F8B800B38606013367F700232CC1023387E600BD -:10F8C8006FF0DFE3378F000013051400930EFFFF7E -:10F8D800B372D501930F100003274102032681025A -:10F8E8000328C10283254101032E81010323C1019D -:10F8F8009308010363C65F1433E5C50133656500EA -:10F908003365D5006316040A631C05002328F10239 -:10F91800232AE102232CC102232E01036FF0DFC04A -:10F928003365C700336505013365F500631C0500C1 -:10F938002328D102232AB102232CC103232E6102DA -:10F948006FF09FBEB387F6003307B7002328F10294 -:10F95800B3B7D700B306F700232AD1023337B7006D -:10F96800B3B6F600B366D700B305C601B387D500B2 -:10F9780033B6C501B3B6D700B366D6003306680000 -:10F988003386C600232CF1029317C60063C607000E -:10F99800232EC1026FF05FB9B706F8FF9386F6FF12 -:10F9A8003376D600232EC102130410006FF0DFB7A0 -:10F9B800631E05002328F102232AE102232CC10239 -:10F9C800232E010313840E006FF01FB63366C700A1 -:10F9D80033660601B367F600639C07002328D1024B -:10F9E800232AB102232CC103232E61026FF09FFD4D -:10F9F800232EE103232C0102232A010223280102DA -:10FA08001307C103832707008326C7FF1307C7FF10 -:10FA18009397370093D6D601B3E7D7002322F70090 -:10FA2800E392E8FE83270103378400001304F4FF00 -:10FA3800939737002328F102130A00006FF0DFAE16 -:10FA4800B387F6003307B7002328F102B3B7D7000E -:10FA5800B306F700232AD1023337B700B3B6F6004E -:10FA6800B366D7003306C6013307D600B336D700CE -:10FA78003336C6013366D600B30668003306D600AF -:10FA8800232CE102232EC10293870800930600006D -:10FA98009305300003A7070003A6470093861600C6 -:10FAA800135717001316F6013367C70023A0E700A2 -:10FAB80093874700E390B6FE8327C103130405002C -:10FAC80093D71700232EF102B78700009387F7FF1B -:10FAD800E31CF4A4232E0102232C0102232A010291 -:10FAE800232801026FF05FA46352E028639E050C8F -:10FAF8000325410283258102032EC1023368B50024 -:10FB08003368C8013368F800630E08EE1306F7FF80 -:10FB18006318060883284101B387F64033B7F60017 -:10FB28003388A84033B308013308E8402328F1029A -:10FB3800232A01031307000063F6F6003307154173 -:10FB4800133717000328810133676700B306B840ED -:10FB58003335D800B386E640232CD102630607006C -:10FB6800B385054113B615008327C1013366A60086 -:10FB780013041000B387C7413386C740232EC10240 -:10FB88008327C1031397C700E350079A3707080074 -:10FB98001307F7FFB3F7E700232EF1026F00C072D7 -:10FBA800B78700009387F7FF630EF7E493074007D2 -:10FBB80063D0C70423260102232401022322010261 -:10FBC800930710006F008012B78700009387F7FF34 -:10FBD8006306F4F68327C102B7060800B3E7D70027 -:10FBE8002326F10293074007E3C6E7FC1306070044 -:10FBF80013575640930500001376F601930700004B -:10FC0800939627006390E7026314060413073000F5 -:10FC18003307F7406352C70213074000B307F740A2 -:10FC28006F00C007B386D80083A606009387170025 -:10FC3800B3E5D5006FF0DFFC3305D30003250500DD -:10FC48001306160013034300232EA3FE6FF09FFC38 -:10FC5800130701043307D700032707FE1308000220 -:10FC68003308C84033170701B3E5E5001307300030 -:10FC7800130E00003307F7406346EE029306400078 -:10FC8800B387F64013172700930601043387E6006D -:10FC98008326C10233D6C6002320C7FE9306400040 -:10FCA8006F00C003B30ED30003A50E0083AE4E0051 -:10FCB800130E1E003355C500B39E0E013365D501E2 -:10FCC8002320A300130343006FF01FFB13972700A3 -:10FCD8003387E8002320070093871700E398D7FEAF -:10FCE80003270102B337B000B367F7002320F102FE -:10FCF800832641018325010103270102832741024D -:10FD08003387E540B387F64033B6F600B3B6E5006F -:10FD1800B386D740232AD1022328E10293060000A4 -:10FD280063F4E50093B61700B3E6C6000327810223 -:10FD3800032681013307E640B307D740232CF1029D -:10FD4800B335E60013060000638406001336170077 -:10FD58008327C1010327C1023366B600B387E74092 -:10FD6800B387C740232EF1026FF09FE1630C072889 -:10FD7800631A040E0323410183288101832EC101E4 -:10FD8800336E1301336EDE01336EDE0063160E022E -:10FD98002328F1028327410213840500232AF10254 -:10FDA80083278102232CF1028327C102232EF1022B -:10FDB800130A05006FF04FF7130EF0FF631EC70715 -:10FDC80003284102B386D74033B7D70033066840CB -:10FDD800333EC8003306E6402328D102232AC10255 -:10FDE8001307000063F6D7003307034113371700E2 -:10FDF800032881023367C7019306000033061841C0 -:10FE08003333C8003306E640232CC10263060700DB -:10FE1800B388084193B618008327C102B3E8660087 -:10FE2800B387D741B3871741232EF1021384050006 -:10FE3800130A05006FF0DFD4B78600009386F6FF3B -:10FE4800E388D5F41347F7FF9307400763D0E70427 -:10FE5800232E0100232C0100232A01009307100000 -:10FE68006F008012B78600009386F6FFE382D5F212 -:10FE78008327C101B7060800B3E7D700232EF10096 -:10FE88009307C0F8E346F7FC3307E0409356574022 -:10FE9800130300001377F7019307000093982700D6 -:10FEA8006390D7026314070493063000B386F640C4 -:10FEB80063D2E60213074000B307F7406F00C0079C -:10FEC800B308180183A80800938717003363130148 -:10FED8006FF0DFFC330E1601032E0E001307170018 -:10FEE80013064600232EC6FF6FF09FFC93060104FD -:10FEF800B386160183A606FD930E0002B38EEE406C -:10FF0800B396D6013363D30093063000130F000075 -:10FF1800B386F6406346DF0213064000B307F64097 -:10FF28009396260013060104B306D6000326C101E2 -:10FF38003357E60023A8E6FC930640006F00C00391 -:10FF4800B30F160103AE0F0083AF4F00130F1F004E -:10FF5800335EEE00B39FDF01336EFE012320C6013E -:10FF6800130646006FF01FFB139727003307E800BE -:10FF78002320070093871700E398D7FE0327010182 -:10FF8800B3376000B367F7002328F10083264102E6 -:10FF98000328010203270101832741013307E840B1 -:10FFA800B387F64033B6F600B336E800B386D740D9 -:10FFB800232AD1022328E102930600006374E80093 -:10FFC80093B61700B3E6C600032781010326810212 -:10FFD8003307E640B307D740232CF1023338E60055 -:10FFE8001306000063840600133617008327C10236 -:08FFF8000327C1013366060175 -:02000004800179 -:10000000B387E740B387C7406FF09FE2B78F000028 -:10001000930E14009382FFFFB3FE5E00130F1000D7 -:10002000832541020326410103288101032EC101DA -:10003000832881020323C102634EDF1DB3EE150145 -:10004000336F0601B3EE6E00336FCF01B3EEFE00E7 -:10005000336FDF006318041063120F022328F102CC -:10006000232AB102232C1103232E6102E3960ED41E -:1000700013040000130A00006FF08FD0639C0E0081 -:100080002328D102232AC102232C0103232EC103DA -:100090006FF00FCAB38EF640B302B640B3BFD601BD -:1000A000333F5600B382F2412328D103232A510261 -:1000B000930F000063F6D601B38FC54093BF1F00B6 -:1000C000B3031841B3EFEF01B389F341232C31039C -:1000D000B33A78001309000063840F0013B91300CA -:1000E000330F6E4033695901330F2F41232EE10343 -:1000F000931FCF0063DE0F04B386D7403386C5401D -:10010000B3BED700B30ED641232AD1032328D10290 -:10011000B3B5C500930E000063F4D700933E1600FC -:10012000B3870841B3E5BE00B3B6F800B387B74064 -:10013000232CF1026384050013B713003303C3417A -:100140003367D7003303E340232E61026FF0DFC62D -:10015000B3EE5E00B3EE3E01B3EEEE01E38A0EF0C5 -:100160006FF00FBD93030103631E0F04639E0E0225 -:10017000232EF103232C0102232A0102232801024A -:100180009307C10303A7070083A6C7FF9387C7FF91 -:100190001317370093D6D6013367D70023A2E700A1 -:1001A000E392F3FE6FF09F882328F102232AB10225 -:1001B000232C1103232E6102130A0500138402006D -:1001C0006FF00FB7639C0E002328D102232AC102CF -:1001D000232C0103232EC1036FF05FFE232EF103B6 -:1001E000232C0102232A0102232801029307C103C1 -:1001F00003A7070083A6C7FF9387C7FF131737001E -:1002000093D6D6013367D70023A2E700E392F3FE2B -:100210006FF0DF81B38EF640B302B640B3BFD601B4 -:10022000333F5600B382F2412328D103232A5102DF -:10023000930F000063F6D601B38FC54093BF1F0034 -:10024000B3031841B3EFEF01B389F341232C31031A -:10025000B33A78001309000063840F0013B9130048 -:10026000330F6E4033695901330F2F41232EE103C1 -:10027000931FCF0063D00F0EB386D7403386C5409F -:10028000B3BED700B30ED641232AD1032328D1020F -:10029000B3B5C500930E000063F4D700933E16007B -:1002A000B3870841B3E5BE00B3B6F800B387B740E3 -:1002B000232CF1026384050013B713003303C341F9 -:1002C0003367D7003307E340232EE102130A05000A -:1002D0000325C103630A0508EF001043930A45FF95 -:1002E00013D9FA41B70900801379F9019389F9010B -:1002F00033095901B3F93A011359594063D8090038 -:100300009389F9FF93E909FE93891900638A090823 -:100310009305C0FF13050900EF009031930600021A -:1003200013172900130800FFB38636411305C5FFD4 -:100330006312050B930701043387E700832701034A -:100340001309F9FFB3993701232837FF1307F0FF8B -:100350006F00400CB3EE5E00B3EE3E01B3EEEE0173 -:10036000E3880ED06FF0DFF60325810363080500F4 -:10037000EF009039130505026FF05FF60325410386 -:1003800063080500EF005038130505046FF01FF5F2 -:1003900003250103EF005037130505066FF01FF426 -:1003A0009305C0FF13050900EF009028930901038E -:1003B000930730003387A9000327C7009387F7FF0F -:1003C0009389C9FF23A8E900E3D627FF1309F9FFA2 -:1003D0006FF0DFF793070103B385A7003306A7008B -:1003E0003386C70083A7C50083A50501B3D7D7000F -:1003F000B3953501B3E7B7002328F6006FF01FF37C -:100400009317290093060103B387F60023A0070082 -:100410001309F9FFE316E9FE63C08A1633848A40A4 -:10042000130414009357F4413707008093F7F70142 -:100430001307F701B38787003374E40093D757405D -:10044000635804001304F4FF136404FE130414003F -:10045000930604001305000013070000634AF70227 -:100460001387070063D407001307000013932700C6 -:10047000631A040413063000130701033306F64021 -:100480006356D60213074000B307F7406F00C00859 -:1004900013162700930501033386C50003260600C3 -:1004A000130717003365C5006FF05FFBB3056700E6 -:1004B00083A505009386160013074700232EB7FE79 -:1004C0006FF01FFC13172700930601043387E60023 -:1004D000032707FF13060002330686403317C700C1 -:1004E0003365E5001307300093050103130800008E -:1004F0003307F7406346E80293064000B387F640AF -:1005000013172700930601043387E6008326C103EF -:1005100033D48600232887FE930630006F00000442 -:10052000B388650083A6080083A848001308180054 -:10053000B3D68600B398C800B3E6160123A0D50051 -:10054000938545006FF01FFB1397270013060103E7 -:100550003307E6002320070093871700E3D6F6FE53 -:1005600003270103B337A00013040000B367F700AB -:100570002328F1026FE0DFFB8327C1033707F8FF71 -:100580001307F7FF33045441B3F7E7006FE01FDDB3 -:10059000232E0102232C0102232A01022328010217 -:1005A0006FF00F8103274500832785000326C500D0 -:1005B00083260500130101FE2322E1002324F1001C -:1005C000232AE100232CF10037470000931716007F -:1005D0002320D1002328D1002326C10093D6170160 -:1005E0009307E7FF1305000063D0D7029307D701F5 -:1005F000931506011356F60163DCD700370500801A -:100600001345F5FF3305A6001301010267800000C2 -:10061000B707010093D50501B3E5F5009307F70689 -:10062000B387D74013D75740232EB10093F7F70174 -:100630006392070A93053000930601011315270002 -:10064000B385E54063DEF502930740003387E7405A -:100650009306010193172700B387F6009306400025 -:1006600023A007001307170093874700E31AD7FE5C -:1006700003250101E30A06F83305A0406FF0DFF817 -:100680003388A60003280800938717009386460046 -:1006900023AE06FF6FF01FFB832605FF032307FF32 -:1006A000B39616013353F300B3E666002328D10056 -:1006B00093061000E3C206FF13871600130501021C -:1006C00093962600B306D500B3D7F50023A8F6FE0F -:1006D0006FF01FF81305170093080102130830008C -:1006E000131525003308E8403385A80013172700A9 -:1006F000930800021303010293060000B388F84038 -:100700003307E3006FF01FFB130101FD2322910269 -:1007100023261102232481022320210393040500B0 -:10072000638605141384050013D9F50163D405000D -:100730003304B04013050400EF00007D9305150558 -:10074000B74700009387E70113D75540232881005E -:10075000232A0100232C0100232E010093F5F5012B -:10076000B387A740638C050293062000631CD70E55 -:1007700093060002B386B640B356D400232ED100B0 -:100780009306F7FF13060102131727003307E6004D -:100790003314B400232887FE6F0040039306300013 -:1007A000B386E6401306010293962600B306D600F0 -:1007B00083A606FF13062000232ED10093062000F7 -:1007C0006316C700232C8100930610001306010155 -:1007D000139726003307E6001306F0FF23200700D7 -:1007E0009386F6FF1307C7FFE39AC6FE0327C101EE -:1007F000B70601809386F6FF2316E10037870000D5 -:100800001307F7FFB3F7E700139707018327C1002A -:100810001319F9018320C102B3F7D700B3E7E7004A -:10082000370700801347F7FFB3F7E70003270101FD -:1008300003248102B3E7270123A0E4000327410139 -:1008400023A6F4001385040023A2E40003278101FA -:100850000329010223A4E4008324410213010103BC -:1008600067800000130730006FF09FF1232E010016 -:10087000232C0100232A01002328010093070000F4 -:10088000130900006FF09FF69357460137071000D9 -:100890001307F7FF93F7F77F130101FC3377C700C6 -:1008A00093861700232C8102232A9102232E110202 -:1008B0009354F601232821032326310323244103E3 -:1008C000232251032328B100232AE100232E010013 -:1008D000232C010093F6F67F130610001304050085 -:1008E000635CD60AB7460000938606C013D5450060 -:1008F000B387D700935647001317C7013367A70084 -:100900009395C501232ED100232CE100232AB100A9 -:10091000232801000327C101B70601809386F6FF53 -:100920002316E100378700001307F7FFB3F7E7004E -:100930000327C100939707019394F4013377D700FD -:10094000B367F700370700801347F7FFB3F7E700F7 -:10095000B3E49700832701012326940013050400C4 -:100960002320F400832741018320C1038324410312 -:100970002322F40083278101032901038329C10273 -:100980002324F40003248103032A8102832A4102E1 -:1009900013010104678000003365B70063900710FE -:1009A000E30A05F66304070613050700EF00C055C8 -:1009B000130A050093091A0313D9594093F9F90151 -:1009C000638C09049305C0FF13050900EF0040463E -:1009D00093070002930A0101130600FFB387374112 -:1009E0001305C5FF938ACAFF6318C5089307010260 -:1009F0009306F9FF13192900338927018327010181 -:100A0000B3993701232839FF6F000004EF00C04F6E -:100A1000130A05026FF01FFA9305C0FF13050900C2 -:100A2000EF00004193090101930730003387A900CB -:100A30000327C7009387F7FF9389C9FF23A8E9001D -:100A4000E3D627FF9306F9FF9307010113972600CA -:100A50003387E7009307F0FF232007009386F6FF14 -:100A60001307C7FFE39AF6FEB74700009387C7C096 -:100A7000B38747416FF01FEA13070101B306A700D0 -:100A800003A7C60083A606013357F700B3963601C5 -:100A90003367D70023A8EA006FF09FF4B787000000 -:100AA000630805029317C70193D64500B3E7D70043 -:100AB000232CF10013574700B78700009395C50119 -:100AC0003367F700232AB10023280100232EE10019 -:100AD0009387F7FF6FF01FE48325C5008327850008 -:100AE00003274500130101FE832605002324F1009E -:100AF000232CF100939705012322E100232AE10032 -:100B000093D70701139715002326B1002320D100A6 -:100B10002328D100232EF1001357170193D5F50197 -:100B2000130301011306C101832706008326C6FFB4 -:100B30001306C6FF9397370093D6D601B3E7D700C5 -:100B40002322F600E312C3FE832601019307170058 -:100B500013953600B78600009386F6FFB3F7D700EB -:100B60002328A1009306100063DCF61AB7C7FFFF25 -:100B7000938707403307F7009307E07F63CEE71EB4 -:100B80006358E006032881010326C1018327410140 -:100B90009356C801131646003366D6009396470055 -:100BA000B3E6A60093D7C70113184800B336D000A8 -:100BB000B3E70701B3E6F600232AC1002328D100DA -:100BC000832601018327410113F67600630C061A80 -:100BD00013F6F600130540006306A61A13864600B6 -:100BE000B336D600B387D700930606006F0080198E -:100BF0009307C0FC635AF700232A01002328D10081 -:100C0000130700006FF0DFFB8327C101B706080060 -:100C100093080000B3E7D700232EF1009307D00319 -:100C20003387E74013555740930703001377F701C5 -:100C30009306000003A807009386160093874700D9 -:100C4000B3E80801E318D5FE939E2600631A070255 -:100C500093073000B387D74063D8E700930740007D -:100C6000B386D7406F0080063305D6010325050003 -:100C70001307170013064600232EA6FE6FF0DFFDB4 -:100C800093070102B387D70183A707FF1308000268 -:100C90003308E840B3970701B3E8F8009307300042 -:100CA000130E0000B387D7406348FE0413064000CC -:100CB000B306D6409397270013060102B307F60048 -:100CC0000326C1013357E60023A8E7FE13074000BF -:100CD00093972600B307F30023A00700938616001E -:100CE000E398E6FE03270101B3371001B367F7006D -:100CF0002328F1006FF0DFF0330FD60103250F003A -:100D0000032F4F00130E1E003355E500331F0F0154 -:100D10003365E5012320A600130646006FF0DFF8D7 -:100D200003264101832781010328C101B366F60030 -:100D3000B3E60601B3E6A60063180700B336D00099 -:100D4000930700006FF05FE8638A060C9356C601B4 -:100D5000131848001396470093D7C7013707400080 -:100D6000B3E6C600B3E70701B3E7E70093F686FFF3 -:100D70001307F07F6FF05FE5930700009306000014 -:100D80001307F07F13968700635E060013071700B2 -:100D90001306F07F6308C708370680FF1306F6FFC7 -:100DA000B3F7C7001396D70193D63600B366D600C3 -:100DB0001306F07F93D73700631EC700B3E6F60033 -:100DC0009307000063880600B70708009306000039 -:100DD00093050000370610001306F6FFB3F7C700AF -:100DE000370610801377F77F1306F6FF13174701B6 -:100DF000B3F7C700B3E7E700370700801347F7FFF3 -:100E00009395F501B3F7E70033E7B70013850600C4 -:100E1000930507001301010267800000930700009B -:100E20006FF01FF693070000930600006FF09FF726 -:100E3000130605001305000093F6150063840600F1 -:100E40003305C50093D5150013161600E39605FE6D -:100E5000678000006340050663C60506138605002B -:100E6000930505001305F0FF630C060293061000BE -:100E7000637AB6006358C0001316160093961600E6 -:100E8000E36AB6FE1305000063E6C500B385C540FE -:100E90003365D50093D6160013561600E39606FE6A -:100EA0006780000093820000EFF05FFB1385050070 -:100EB000678002003305A04063D80500B305B04049 -:100EC0006FF0DFF9B305B04093820000EFF01FF937 -:100ED0003305A040678002009382000063CA0500CA -:100EE000634C0500EFF09FF7138505006780020053 -:100EF000B305B040E35805FE3305A040EFF01FF600 -:100F00003305B04067800200B7070100637AF5023D -:100F10009307F00FB3B7A7009397370013070002AA -:100F20003307F740B357F500171500001305C5F355 -:100F3000B307F50003C507003305A740678000002D -:100F40003707000193070001E36AE5FC930780017E -:100F50006FF0DFFC130101FF232611002324810021 -:100F6000930500001306000093060000130700001D -:100F7000930700009308900373000000130405001A -:100F8000635A050033048040EF00402E2320850083 -:100F90001304F0FF130504008320C1000324810023 -:100FA0001301010167800000130101F8232A910653 -:100FB000232E110693840500232C810693058100BE -:100FC00013060000930600001307000093070000BB -:100FD000930800057300000013040500635A050020 -:100FE00033048040EF008028232085001304F0FFA5 -:100FF0001385040093058100EF0080201305040091 -:101000008320C107032481078324410713010108BA -:1010100067800000130101FB9305410023261104A2 -:10102000EFF09FF89307F0FF6308F50003258100B8 -:101030001355D500137515008320C1041301010554 -:1010400067800000130101FF232611002324810083 -:101050009306000013070000930700009308E003C5 -:101060007300000013040500635A05003304804038 -:10107000EF00C01F232085001304F0FF13050400B8 -:101080008320C10003248100130101016780000057 -:10109000130101FF23261100232481009306000081 -:1010A00013070000930700009308F003730000008B -:1010B00013040500635A050033048040EF00001B51 -:1010C000232085001304F0FF130504008320C100D2 -:1010D000032481001301010167800000130101FF57 -:1010E0002322910097240000938404A483A7040082 -:1010F0002320210123261100232481001309050048 -:10110000639C07041305000093050000130600000C -:1011100093060000130700009308600D73000000A1 -:101120001304050063560502EF00401433048040A9 -:10113000232085001305F0FF8320C10003248100D4 -:10114000832441000329010013010101678000008D -:101150009727000023AAA79C03A50400930500007D -:10116000130600003305A9009306000013070000D2 -:10117000930700009308600D73000000130405003E -:10118000635A050033048040EF00400E23208500A1 -:101190001304F0FF83A704001305F0FF3309F900DF -:1011A000E31C24F9172700002320879813850700E4 -:1011B0006FF09FF8130101FF232611002324810003 -:1011C0009306000013070000930700009308000433 -:1011D0007300000013040500635A050033048040C7 -:1011E000EF00C008232085001304F0FF130504005E -:1011F0008320C100032481001301010167800000E6 -:1012000083A705002310F50083A785002311F500AF -:1012100083A705012322F50083A745012314F500C8 -:1012200083A785012315F50083A7C5012316F500C3 -:1012300083A705022317F50083A705032328F500DC -:1012400083A705042328F50283A785032326F50237 -:1012500083A78504232AF50083A70505232EF5001F -:1012600083A785052322F5026780000097270000E9 -:101270009387C78903A50700678000004D69616FE8 -:10128000752021210000000068F3FEFFE404FFFF49 -:10129000E404FFFF7CF3FEFFE404FFFFE404FFFF30 -:1012A000E404FFFF1CF3FEFFE404FFFFE404FFFF80 -:1012B00084F3FEFFA4F3FEFFE404FFFF9CF3FEFFB4 -:1012C000ACF3FEFFE404FFFF10F4FEFF18F4FEFF92 -:1012D00018F4FEFF18F4FEFF18F4FEFF18F4FEFFEA -:1012E00018F4FEFF18F4FEFF18F4FEFF18F4FEFFDA -:1012F000E404FFFFE404FFFFE404FFFFE404FFFF56 -:10130000E404FFFFE404FFFFE404FFFF2CF8FEFF0A -:10131000E404FFFFACF4FEFF80F7FEFF2CF8FEFFB5 -:101320002CF8FEFF2CF8FEFFE404FFFFE404FFFFAF -:10133000E404FFFFE404FFFF4CF4FEFFE404FFFFBE -:10134000E404FFFF7C01FFFFE404FFFFE404FFFF70 -:10135000E404FFFF4802FFFFE404FFFF9402FFFFE5 -:10136000E404FFFFE404FFFFC0F2FEFFE404FFFF1C -:10137000E404FFFFE404FFFFE404FFFFE404FFFFD5 -:10138000E404FFFFE404FFFFE404FFFF2CF8FEFF8A -:10139000E404FFFFACF4FEFF84F7FEFF2CF8FEFF31 -:1013A0002CF8FEFF2CF8FEFF54F4FEFF84F7FEFF3E -:1013B0009CF4FEFFE404FFFF80F4FEFFE404FFFF63 -:1013C0001001FFFF8001FFFF1002FFFF9CF4FEFFF2 -:1013D000E404FFFF4802FFFF7CF2FEFF9802FFFFDC -:1013E000E404FFFFE404FFFFFC02FFFFE404FFFF4F -:1013F0007CF2FEFF20202020202020202020202002 -:10140000202020203030303030303030303030301C -:1014100030303030494E4600696E66004E414E0015 -:101420006E616E00303132333435363738396162AF -:10143000636465660000000030313233343536377E -:101440003839414243444546000000003000000066 -:10145000000000000000000000000000000000008C -:10146000000000000000000000000000000000007C -:10147000000000000080FF3F7665924A4A803F15D9 -:101480004CC99A97208A025260C42575326A52CE9E -:101490009A32CE284DA7E45D3DC55D3B8B9E925AA6 -:1014A0006C52CE508BF1283D0D65170C75818675F9 -:1014B00076C9484D669CF85850BC545C65CCC691C2 -:1014C0000EA6AEA019E3A3461E85B7EAFE981B90B0 -:1014D000BBDD8DDEF99DFBEB7EAA51433502370162 -:1014E000B1366C336FC6DF8CE980C947BA93A84127 -:1014F000F850FB256BC7716BBF3CD5A6CFFF491FCA -:1015000078C2D340000000000000000020F09DB52C -:10151000702BA8ADC59D69400000000000000000D0 -:10152000000000000004BFC91B8E34400000000012 -:10153000000000000000000000000020BCBE1940B8 -:10154000000000000000000000000000000000009B -:10155000409C0C4000000000000000000000000063 -:101560000000000000C8054000000000000000006E -:10157000000000000000000000A00240FFFFFEFF8E -:10158000FCFFF8FFF0FFE0FFC0FF80FF00FF00FE60 -:1015900000FC00F800F000E000C000800000000047 -:1015A0003020FCCFC3A12381E32DDE9FCED2C8041F -:1015B000DDA6D80A6482CBD2EAF2D4122549E42D02 -:1015C00036344F53AECE6B253FF598F6D36B5801AA -:1015D000A687BDC057DAA582A6A2B53231E7D404EA -:1015E000F2E332D332711CD223DB32EE49905A3906 -:1015F0003EA20853FBFE551191FA39197A6325432F -:1016000031C0AC3C6DE2DEDB5DD0F6B37CACA0E477 -:10161000BC647C46D0DD553E202A2462B347D7986F -:10162000233FA5E939A527EA7FA82A3F5B0BF24AA9 -:1016300081A5ED18DE67BA943945AD1EB1CF943F50 -:1016400071BFB3A9897968BE2E4C5BE14DC4BE94CD -:1016500095E6C93F4D3D3D7CBA362B0DC2FDFCCE13 -:1016600061841177CCABE43F55C1A8A44E4013610F -:10167000C3D32B6519E25817B7D1F13F0AD7A3702E -:101680003D0AD7A3703D0AD7A3703D0AD7A3F83F00 -:10169000CDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC89 -:1016A000CCCCFB3F204E614E20000000202D496E27 -:1016B00066696E697479200020496E66696E697486 -:1016C000792000004E614E00452564004300000073 -:1016D000504F5349580000002E0000000000000049 -:1016E00005000000190000007D000000000000005F -:1016F000000000000000F03F000000000000244057 -:1017000000000000000059400000000000408F4031 -:10171000000000000088C34000000000006AF8409C -:101720000000000080842E4100000000D0126341C0 -:101730000000000084D797410000000065CDCD4136 -:10174000000000205FA00242000000E87648374217 -:10175000000000A2941A6D42000040E59C30A242B5 -:101760000000901EC4BCD64200003426F56B0C432A -:101770000080E03779C3414300A0D88557347643D1 -:1017800000C84E676DC1AB43003D9160E458E14332 -:10179000408CB5781DAF154450EFE2D6E41A4B44A7 -:1017A00092D54D06CFF08044F64AE1C7022DB544EC -:1017B000B49DD9794378EA44BC89D897B2D29C3C8D -:1017C00033A7A8D523F649393DA7F444FD0FA53228 -:1017D0009D978CCF08BA5B25436FAC642806C80A76 -:1017E0000080E03779C34143176E05B5B5B893461D -:1017F000F5F93FE9034F384D321D30F94877825AE9 -:101800003CBF737FDD4F15758859FFFF8C6BFFFF61 -:101810008C6BFFFF9C59FFFF8C6BFFFF8C6BFFFFF6 -:101820008C6BFFFF3459FFFF8C6BFFFF8C6BFFFF4E -:10183000A459FFFFC459FFFF8C6BFFFFBC59FFFF8A -:10184000CC59FFFF8C6BFFFF305AFFFF385AFFFF68 -:10185000385AFFFF385AFFFF385AFFFF385AFFFF48 -:10186000385AFFFF385AFFFF385AFFFF385AFFFF38 -:101870008C6BFFFF8C6BFFFF8C6BFFFF8C6BFFFF94 -:101880008C6BFFFF8C6BFFFF8C6BFFFFB45BFFFF6C -:101890008C6BFFFFD45AFFFF085BFFFFB45BFFFFB9 -:1018A000B45BFFFFB45BFFFF8C6BFFFF8C6BFFFF34 -:1018B0008C6BFFFF8C6BFFFF745AFFFF8C6BFFFF7D -:1018C0008C6BFFFF8465FFFF8C6BFFFF8C6BFFFF52 -:1018D0008C6BFFFF5066FFFF8C6BFFFF3469FFFFCF -:1018E0008C6BFFFF8C6BFFFFD858FFFF8C6BFFFFEB -:1018F0008C6BFFFF8C6BFFFF8C6BFFFF8C6BFFFF14 -:101900008C6BFFFF8C6BFFFF8C6BFFFFB45BFFFFEB -:101910008C6BFFFFD45AFFFF0C5BFFFFB45BFFFF34 -:10192000B45BFFFFB45BFFFF7C5AFFFF0C5BFFFF64 -:10193000C45AFFFF8C6BFFFFA85AFFFF8C6BFFFFA1 -:101940001865FFFF8865FFFF1866FFFFC45AFFFF99 -:101950008C6BFFFF5066FFFF9458FFFF3869FFFF55 -:101960008C6BFFFF8C6BFFFF9C69FFFF8C6BFFFF95 -:101970009458FFFF202020202020202020202020FD -:101980002020202030303030303030303030303097 -:1019900030303030C878FFFFE880FFFFE880FFFF7D -:1019A000DC78FFFFE880FFFFE880FFFFE880FFFFB3 -:1019B0007C78FFFFE880FFFFE880FFFFE478FFFF0F -:1019C000FC78FFFFE880FFFFF478FFFF0479FFFF5A -:1019D000E880FFFF6079FFFF6879FFFF6879FFFF0C -:1019E0006879FFFF6879FFFF6879FFFF6879FFFF7B -:1019F0006879FFFF6879FFFF6879FFFFE880FFFFE4 -:101A0000E880FFFFE880FFFFE880FFFFE880FFFF3E -:101A1000E880FFFFE880FFFFE880FFFFE880FFFF2E -:101A2000E479FFFF047AFFFFE880FFFFE880FFFF13 -:101A3000E880FFFFE880FFFFE880FFFFE880FFFF0E -:101A4000E880FFFFE880FFFFE880FFFFE880FFFFFE -:101A5000087BFFFFE880FFFFE880FFFFE880FFFFD3 -:101A6000C47BFFFFE880FFFFA87EFFFFE880FFFF49 -:101A7000E880FFFF2C78FFFFE880FFFFE880FFFF92 -:101A8000E880FFFFE880FFFFE880FFFFE880FFFFBE -:101A9000E880FFFFE880FFFFE880FFFFE880FFFFAE -:101AA000E479FFFF087AFFFFE880FFFFE880FFFF8F -:101AB000E880FFFFA479FFFF087AFFFFD479FFFFDA -:101AC000E880FFFFC479FFFFE880FFFFA87AFFFFEF -:101AD0000C7BFFFF947BFFFFD479FFFFE880FFFFC3 -:101AE000C47BFFFFF877FFFFAC7EFFFFE880FFFFBE -:101AF000E880FFFF087FFFFFE880FFFFF877FFFF28 -:101B000020202020202020202020202020202020D5 -:101B100030303030303030303030303030303030C5 -:101B200000202020202020202020282828282820AD -:101B300020202020202020202020202020202020A5 -:101B4000208810101010101010101010101010100D -:101B500010040404040404040404041010101010FD -:101B600010104141414141410101010101010101C7 -:101B70000101010101010101010101011010101019 -:101B80001010424242424242020202020202020299 -:101B900002020202020202020202020210101010ED -:101BA0002000000000000000000000000000000015 -:101BB0000000000000000000000000000000000025 -:101BC0000000000000000000000000000000000015 -:101BD0000000000000000000000000000000000005 -:101BE00000000000000000000000000000000000F5 -:101BF00000000000000000000000000000000000E5 -:101C000000000000000000000000000000000000D4 -:101C100000000000000000000000000000000000C4 -:101C2000000000009496FFFFB49EFFFFB49EFFFFEC -:101C3000A896FFFFB49EFFFFB49EFFFFB49EFFFF78 -:101C40004896FFFFB49EFFFFB49EFFFFB096FFFFD4 -:101C5000C896FFFFB49EFFFFC096FFFFD096FFFF20 -:101C6000B49EFFFF2C97FFFF3497FFFF3497FFFFD1 -:101C70003497FFFF3497FFFF3497FFFF3497FFFF40 -:101C80003497FFFF3497FFFF3497FFFFB49EFFFFA9 -:101C9000B49EFFFFB49EFFFFB49EFFFFB49EFFFF04 -:101CA000B49EFFFFB49EFFFFB49EFFFFB49EFFFFF4 -:101CB000B097FFFFD097FFFFB49EFFFFB49EFFFFDA -:101CC000B49EFFFFB49EFFFFB49EFFFFB49EFFFFD4 -:101CD000B49EFFFFB49EFFFFB49EFFFFB49EFFFFC4 -:101CE000D498FFFFB49EFFFFB49EFFFFB49EFFFF9A -:101CF0009099FFFFB49EFFFF749CFFFFB49EFFFF0F -:101D0000B49EFFFFF895FFFFB49EFFFFB49EFFFF58 -:101D1000B49EFFFFB49EFFFFB49EFFFFB49EFFFF83 -:101D2000B49EFFFFB49EFFFFB49EFFFFB49EFFFF73 -:101D3000B097FFFFD497FFFFB49EFFFFB49EFFFF55 -:101D4000B49EFFFF7097FFFFD497FFFFA097FFFFA0 -:101D5000B49EFFFF9097FFFFB49EFFFF7498FFFFB4 -:101D6000D898FFFF6099FFFFA097FFFFB49EFFFF89 -:101D70009099FFFFC495FFFF789CFFFFB49EFFFF83 -:101D8000B49EFFFFD49CFFFFB49EFFFFC495FFFFEE -:101D90002020202020202020202020202020202043 -:101DA0003030303030303030303030303030303033 -:101DB000F4B3FFFF08B3FFFF14B3FFFF08B3FFFF47 -:101DC000E0B3FFFF08B3FFFF14B3FFFFF4B3FFFF5F -:101DD000F4B3FFFFE0B3FFFF14B3FFFFE0B2FFFF78 -:101DE000E0B2FFFFE0B2FFFF1CB3FFFFB0B9FFFF9F -:101DF000B0B9FFFFD4B9FFFFA4B9FFFFA4B9FFFF3B -:101E000094BAFFFFD4B9FFFFA4B9FFFF94BAFFFF54 -:101E1000A4B9FFFFD4B9FFFFA0B9FFFFA0B9FFFF2E -:101E2000A0B9FFFF94BAFFFFE8CFFFFFE8CFFFFFA5 -:101E3000E4CFFFFF98CFFFFF98CFFFFF58D2FFFFFF -:101E4000E4CFFFFF98CFFFFF58D2FFFF98CFFFFFEF -:101E5000E4CFFFFF94CFFFFF94CFFFFF94CFFFFFAE -:101E600058D2FFFF00010202030303030404040429 -:101E70000404040405050505050505050505050516 -:101E800005050505060606060606060606060606F6 -:101E900006060606060606060606060606060606E2 -:101EA00006060606070707070707070707070707C6 -:101EB00007070707070707070707070707070707B2 -:101EC00007070707070707070707070707070707A2 -:101ED0000707070707070707070707070707070792 -:101EE0000707070708080808080808080808080876 -:101EF0000808080808080808080808080808080862 -:101F00000808080808080808080808080808080851 -:101F10000808080808080808080808080808080841 -:101F20000808080808080808080808080808080831 -:101F30000808080808080808080808080808080821 -:101F40000808080808080808080808080808080811 -:101F50000808080808080808080808080808080801 -:101F60000808080800000000000000000000F03F22 -:101F7000000000000000244000000000000050436A -:101F80001000000000000000017A5200017C0101F5 -:101F90001B0D02001000000018000000CCE1FEFF45 -:101FA0000800000000000000100000002C000000ED -:101FB000C0E1FEFF0800000000000000100000006B -:101FC00040000000B4E1FEFF080000000000000037 -:101FD0001000000054000000A8E1FEFF0400000013 -:101FE00000000000100000006800000098E1FEFF03 -:101FF0000800000000000000100000007C0000004D -:102000008CE1FEFF0800000000000000100000004E -:102010009000000080E1FEFF0C00000000000000C6 -:102020001C000000A400000078E1FEFF3800000062 -:1020300000440E10488802810160C144C8440E006B -:1020400024000000C400000090E1FEFF50000000EA -:1020500000440E1050920481018802890364C14437 -:10206000C848C944D2440E0018000000EC0000002B -:10207000BCE1FEFF2C00000000480E104881014822 -:10208000C1500E0010000000080100009CE1FEFF9E -:10209000040000000000000010000000000000002C -:1020A000017A5200017C01011B0D02004C0000006E -:1020B00018000000249EFFFFDC05000000440E30E5 -:1020C000708903950781018802920493059406960E -:1020D000089709980A990B9A0C0370020AC144C820 -:1020E00044C944D244D344D444D544D644D744D834 -:1020F00044D944DA440E00440B00000010000000F4 -:1021000000000000017A5200017C01011B0D020059 -:1021100050000000180000009CA3FFFF0005000015 -:1021200000440E5074880289039305990B81019233 -:10213000049406950796089709980A9A0C9B0D0334 -:1021400020010AC144C844C944D244D344D444D52C -:1021500044D644D744D844D944DA44DB440E00443E -:042160000B00000070 -:102168000000000054240180BC2401802425018043 -:102178000000000000000000000000000000000057 -:102188000000000000000000000000000000000047 -:102198000000000000000000000000000000000037 -:1021A8000000000000000000000000000000000027 -:1021B8000000000000000000000000000000000017 -:1021C8000000000000000000000000000000000007 -:1021D80000000000000000000000000000000000F7 -:1021E80000000000000000000000000000000000E7 -:1021F80000000000000000000000000000000000D7 -:1022080000000000000000000100000000000000C5 -:102218000E33CDAB34126DE6ECDE05000B0000008A -:1022280000000000000000000000000000000000A6 -:102238000000000000000000000000000000000096 -:102248000000000000000000000000000000000086 -:102258000000000000000000000000000000000076 -:102268000000000000000000000000000000000066 -:102278000000000000000000000000000000000056 -:102288000000000000000000000000000000000046 -:102298000000000000000000000000000000000036 -:1022A8000000000000000000000000000000000026 -:1022B8000000000000000000000000000000000016 -:1022C8000000000000000000000000000000000006 -:1022D80000000000000000000000000000000000F6 -:1022E80000000000000000000000000000000000E6 -:1022F80000000000000000000000000000000000D6 -:1023080000000000000000000000000000000000C5 -:1023180000000000000000000000000000000000B5 -:1023280000000000000000000000000000000000A5 -:102338000000000000000000000000000000000095 -:102348000000000000000000000000000000000085 -:102358000000000000000000000000000000000075 -:102368000000000000000000000000000000000065 -:102378000000000000000000000000000000000055 -:102388000000000000000000000000000000000045 -:102398000000000000000000000000000000000035 -:1023A8000000000000000000000000000000000025 -:1023B8000000000000000000000000000000000015 -:1023C8000000000000000000000000000000000005 -:1023D80000000000000000000000000000000000F5 -:1023E80000000000000000000000000000000000E5 -:1023F80000000000000000000000000000000000D5 -:1024080000000000000000000000000000000000C4 -:1024180000000000000000000000000000000000B4 -:1024280000000000000000000000000000000000A4 -:102438000000000000000000000000000000000094 -:102448000000000000000000000000000000000084 -:102458000000000000000000000000000000000074 -:102468000000000000000000000000000000000064 -:102478000000000000000000000000000000000054 -:102488000000000000000000000000000000000044 -:102498000000000000000000000000000000000034 -:1024A8000000000000000000000000000000000024 -:1024B8000000000000000000000000000000000014 -:1024C8000000000000000000000000000000000004 -:1024D80000000000000000000000000000000000F4 -:1024E80000000000000000000000000000000000E4 -:1024F80000000000000000000000000000000000D4 -:1025080000000000000000000000000000000000C3 -:1025180000000000000000000000000000000000B3 -:1025280000000000000000000000000000000000A3 -:102538000000000000000000000000000000000093 -:102548000000000000000000000000000000000083 -:102558000000000000000000000000000000000073 -:102568000000000000000000000000000000000063 -:102578000000000000000000000000000000000053 -:102588000000000000000000430000000000000000 -:102598000000000000000000000000000000000033 -:1025A80000000000000000004300000000000000E0 -:1025B8000000000000000000000000000000000013 -:1025C80000000000000000004300000000000000C0 -:1025D80000000000000000000000000000000000F3 -:1025E80000000000000000004300000000000000A0 -:1025F80000000000000000000000000000000000D3 -:10260800000000000000000043000000000000007F -:1026180000000000000000000000000000000000B2 -:10262800000000000000000043000000000000005F -:102638000000000000000000000000000000000092 -:10264800000000000000000043000000000000003F -:102658000000000000000000000000000000000072 -:102668000000000000000000489D00802C590080F8 -:1026780000000000201B0180D81601808412018010 -:1026880084120180841201808412018084120180E6 -:1026980084120180841201808412018084120180D6 -:1026A800FFFFFFFFFFFFFFFFFFFFFFFFFFFF000030 -:1026B80001004153434949000000000000000000A8 -:1026C8000000000000000000000000000000000002 -:1026D8000000415343494900000000000000000089 -:1026E80000000000000000000000000000000000E2 -:1026F800000000000000000000000000FC2601802F -:10270800FC26018004270180042701800C27018012 -:102718000C27018014270180142701801C270180C1 -:102728001C27018024270180242701802C27018071 -:102738002C27018034270180342701803C27018021 -:102748003C27018044270180442701804C270180D1 -:102758004C27018054270180542701805C27018081 -:102768005C27018064270180642701806C27018031 -:102778006C27018074270180742701807C270180E1 -:102788007C27018084270180842701808C27018091 -:102798008C27018094270180942701809C27018041 -:1027A8009C270180A4270180A4270180AC270180F1 -:1027B800AC270180B4270180B4270180BC270180A1 -:1027C800BC270180C4270180C4270180CC27018051 -:1027D800CC270180D4270180D4270180DC27018001 -:1027E800DC270180E4270180E4270180EC270180B1 -:1027F800EC270180F4270180F4270180FC27018061 -:10280800FC27018004280180042801800C2801800D -:102818000C28018014280180142801801C280180BC -:102828001C28018024280180242801802C2801806C -:102838002C28018034280180342801803C2801801C -:102848003C28018044280180442801804C280180CC -:102858004C28018054280180542801805C2801807C -:102868005C28018064280180642801806C2801802C -:102878006C28018074280180742801807C280180DC -:102888007C28018084280180842801808C2801808C -:102898008C28018094280180942801809C2801803C -:1028A8009C280180A4280180A4280180AC280180EC -:1028B800AC280180B4280180B4280180BC2801809C -:1028C800BC280180C4280180C4280180CC2801804C -:1028D800CC280180D4280180D4280180DC280180FC -:1028E800DC280180E4280180E4280180EC280180AC -:1028F800EC280180F4280180F4280180FC2801805C -:10290800FC28018004290180042901800C29018008 -:102918000C29018014290180142901801C290180B7 -:102928001C29018024290180242901802C29018067 -:102938002C29018034290180342901803C29018017 -:102948003C29018044290180442901804C290180C7 -:102958004C29018054290180542901805C29018077 -:102968005C29018064290180642901806C29018027 -:102978006C29018074290180742901807C290180D7 -:102988007C29018084290180842901808C29018087 -:102998008C29018094290180942901809C29018037 -:1029A8009C290180A4290180A4290180AC290180E7 -:1029B800AC290180B4290180B4290180BC29018097 -:1029C800BC290180C4290180C4290180CC29018047 -:1029D800CC290180D4290180D4290180DC290180F7 -:1029E800DC290180E4290180E4290180EC290180A7 -:1029F800EC290180F4290180F4290180FC29018057 -:102A0800FC290180042A0180042A01800C2A018003 -:102A18000C2A0180142A0180142A01801C2A0180B2 -:102A28001C2A0180242A0180242A01802C2A018062 -:102A38002C2A0180342A0180342A01803C2A018012 -:102A48003C2A0180442A0180442A01804C2A0180C2 -:102A58004C2A0180542A0180542A01805C2A018072 -:102A68005C2A0180642A0180642A01806C2A018022 -:102A78006C2A0180742A0180742A01807C2A0180D2 -:102A88007C2A0180842A0180842A01808C2A018082 -:102A98008C2A0180942A0180942A01809C2A018032 -:102AA8009C2A0180A42A0180A42A0180AC2A0180E2 -:102AB800AC2A0180B42A0180B42A0180BC2A018092 -:102AC800BC2A0180C42A0180C42A0180CC2A018042 -:102AD800CC2A0180D42A0180D42A0180DC2A0180F2 -:102AE800DC2A0180E42A0180E42A0180EC2A0180A2 -:102AF800EC2A0180F42A0180F42A018068210180EF -:0C2B080068210180FFFFFFFF00000200B9 -:040000058000004037 +:10000000930E0000970000009380C04F7390503013 +:10001000130E1000977000009380C0FE3721262732 +:100020001301415283A04000639C2048130E20001E +:10003000970000009380000273901034B7200000F6 +:100040009380008073900030730020306F00404731 +:10005000130E3000B71000009380008073900030C2 +:10006000970000009380400173901034730020309B +:100070006F000045130E400097800000938080F8C9 +:10008000373136371301415383A04000639A204231 +:10009000130E5000971000009380C07617210000C7 +:1000A000130141F6135121001361110023A0200018 +:1000B00097200000938000F5370100801351210044 +:1000C0001361F10C23A02000130E500097200000B4 +:1000D00093804083173100001301C1F213512100B6 +:1000E0001361110023A0200097300000938000F4DA +:1000F00017910000130101F1135121001361F10D5B +:1001000023A02000973000009380C0F317A10000C7 +:10011000130141EF135121001361310D23A0200081 +:1001200097300000938040F217A10000130181ED89 +:10013000135121001361710D23A02000973000009E +:100140009380C0F017A100001301C1EB13512100EF +:100150001361910D23A0200097300000938040EFA1 +:1001600017A10000130101EA135121001361B10D21 +:1001700023A02000973000009380C0ED17A100005D +:10018000130141E8135121001361F10C23A0200059 +:10019000130E5000972000009380C08617010000C6 +:1001A000130141E6135121001361F10D23A020003A +:1001B000130E5000972000009380C09423A00000ED +:1001C000B700040073A0001097100000938080E334 +:1001D00093D0C00037010080B3E02000730000120C +:1001E000739000180F100000130E6000B7A000906D +:1001F0009380800037514A4B1301819483A0000003 +:100200006390202C130E7000B7A0009093800036EE +:100210003701EEAA1301110023A0200083A00000E3 +:100220006390202A130E800097C000209380C0DDC9 +:10023000377176771301415783A00000639220281D +:10024000130E9000B7A000A0938000363701EEAAED +:100250001301210023A0200083A000006392202628 +:10026000130EA00073500018979000009380800F29 +:100270003701EEAA1301110083A00000639220242D +:10028000130EB00097A000009380C00D3701EEAAB6 +:100290001301210083A00000639420229710000026 +:1002A000938040D693D0C00037010080B3E0200097 +:1002B00073900018130EC000930E1000170F00006B +:1002C000130F0F01730000006F00801F130ED0008A +:1002D000170F0000130F4F01B70000B083A080007C +:1002E0006F00001E130EE000170F0000130F4F01E8 +:1002F000B70000B023A410006F00801C130EF000A4 +:10030000170F0000130F4F01B70000B06780000007 +:100310006F00001B130E0001930E0000B700019048 +:100320009380800037615A5B1301819583A00000A0 +:1003300063982018B71001909380800037615A5B52 +:100340001301819583A00000639C2016B7300190B3 +:100350009380800037615A5B1301819583A0000070 +:1003600063902016130E1001B71001909380003691 +:100370003701EEAA1301310023A0200083A0000062 +:1003800063902014130E2001930E1000170F00002D +:10039000130F8F0137210190130101016700010044 +:1003A0006F000012130E3001930E1000170F0000A3 +:1003B000130F8F01B72001909380000183A00000EC +:1003C0006F000010170F0000130F8F01B73001905E +:1003D0009380000123A010006F00800E170F000013 +:1003E000130F8F01B7100190938000016780000008 +:1003F0006F00000D130E5001930E0000B7000800AF +:1004000073A00010B72001909380800037615A5B81 +:100410001301819583A000006394200AB7000800AF +:1004200073B00010930E0000130E4001B74001900E +:10043000938000383701EEAA1301510023A0200059 +:1004400083A00000639E2006B700040073B0001074 +:10045000930E1000170F0000130F8F01B7100190BB +:100460009380806423A010006F008005130E20038A +:10047000930E0000B700040073A00010732500184D +:100480007310001897200000938000BB37D10080C4 +:10049000135121001361F10523A0200073100518EA +:1004A0009300001073B0001097D00000938080B5C7 +:1004B0007390101473000012730020106F0040003E +:1004C000930E0000170F0000130FCF007300000001 +:1004D000370110F0130141F22320C101930E1000E7 +:1004E000170F0000130FCF0073000000370110F04A +:1004F000130101F22320010013000000130000008B +:10050000E3800EFCF3202034F3201034F32000307D +:10051000F320303493002000E3821EFC73101F345C +:1005200073002030130000001300000013000000CF +:10053000130000001300000013000000130000006F +:10054000130000001300000013000000130000005F +:10055000130000001300000013000000130000004F +:10056000130000001300000013000000130000003F +:10057000130000001300000013000000130000002F +:10058000130000001300000013000000130000001F +:10059000130000001300000013000000130000000F +:1005A00013000000130000001300000013000000FF +:1005B00013000000130000001300000013000000EF +:1005C00013000000130000001300000013000000DF +:1005D00013000000130000001300000013000000CF +:1005E00013000000130000001300000013000000BF +:1005F00013000000130000001300000013000000AF +:10060000130000001300000013000000130000009E +:10061000130000001300000013000000130000008E +:10062000130000001300000013000000130000007E +:10063000130000001300000013000000130000006E +:10064000130000001300000013000000130000005E +:10065000130000001300000013000000130000004E +:10066000130000001300000013000000130000003E +:10067000130000001300000013000000130000002E +:10068000130000001300000013000000130000001E +:10069000130000001300000013000000130000000E +:1006A00013000000130000001300000013000000FE +:1006B00013000000130000001300000013000000EE +:1006C00013000000130000001300000013000000DE +:1006D00013000000130000001300000013000000CE +:1006E00013000000130000001300000013000000BE +:1006F00013000000130000001300000013000000AE +:10070000130000001300000013000000130000009D +:10071000130000001300000013000000130000008D +:10072000130000001300000013000000130000007D +:10073000130000001300000013000000130000006D +:10074000130000001300000013000000130000005D +:10075000130000001300000013000000130000004D +:10076000130000001300000013000000130000003D +:10077000130000001300000013000000130000002D +:10078000130000001300000013000000130000001D +:10079000130000001300000013000000130000000D +:1007A00013000000130000001300000013000000FD +:1007B00013000000130000001300000013000000ED +:1007C00013000000130000001300000013000000DD +:1007D00013000000130000001300000013000000CD +:1007E00013000000130000001300000013000000BD +:1007F00013000000130000001300000013000000AD +:10080000130000001300000013000000130000009C +:10081000130000001300000013000000130000008C +:10082000130000001300000013000000130000007C +:10083000130000001300000013000000130000006C +:10084000130000001300000013000000130000005C +:10085000130000001300000013000000130000004C +:10086000130000001300000013000000130000003C +:10087000130000001300000013000000130000002C +:10088000130000001300000013000000130000001C +:10089000130000001300000013000000130000000C +:1008A00013000000130000001300000013000000FC +:1008B00013000000130000001300000013000000EC +:1008C00013000000130000001300000013000000DC +:1008D00013000000130000001300000013000000CC +:1008E00013000000130000001300000013000000BC +:1008F00013000000130000001300000013000000AC +:10090000130000001300000013000000130000009B +:10091000130000001300000013000000130000008B +:10092000130000001300000013000000130000007B +:10093000130000001300000013000000130000006B +:10094000130000001300000013000000130000005B +:10095000130000001300000013000000130000004B +:10096000130000001300000013000000130000003B +:10097000130000001300000013000000130000002B +:10098000130000001300000013000000130000001B +:10099000130000001300000013000000130000000B +:1009A00013000000130000001300000013000000FB +:1009B00013000000130000001300000013000000EB +:1009C00013000000130000001300000013000000DB +:1009D00013000000130000001300000013000000CB +:1009E00013000000130000001300000013000000BB +:1009F00013000000130000001300000013000000AB +:100A0000130000001300000013000000130000009A +:100A1000130000001300000013000000130000008A +:100A2000130000001300000013000000130000007A +:100A3000130000001300000013000000130000006A +:100A4000130000001300000013000000130000005A +:100A5000130000001300000013000000130000004A +:100A6000130000001300000013000000130000003A +:100A7000130000001300000013000000130000002A +:100A8000130000001300000013000000130000001A +:100A9000130000001300000013000000130000000A +:100AA00013000000130000001300000013000000FA +:100AB00013000000130000001300000013000000EA +:100AC00013000000130000001300000013000000DA +:100AD00013000000130000001300000013000000CA +:100AE00013000000130000001300000013000000BA +:100AF00013000000130000001300000013000000AA +:100B00001300000013000000130000001300000099 +:100B10001300000013000000130000001300000089 +:100B20001300000013000000130000001300000079 +:100B30001300000013000000130000001300000069 +:100B40001300000013000000130000001300000059 +:100B50001300000013000000130000001300000049 +:100B60001300000013000000130000001300000039 +:100B70001300000013000000130000001300000029 +:100B80001300000013000000130000001300000019 +:100B90001300000013000000130000001300000009 +:100BA00013000000130000001300000013000000F9 +:100BB00013000000130000001300000013000000E9 +:100BC00013000000130000001300000013000000D9 +:100BD00013000000130000001300000013000000C9 +:100BE00013000000130000001300000013000000B9 +:100BF00013000000130000001300000013000000A9 +:100C00001300000013000000130000001300000098 +:100C10001300000013000000130000001300000088 +:100C20001300000013000000130000001300000078 +:100C30001300000013000000130000001300000068 +:100C40001300000013000000130000001300000058 +:100C50001300000013000000130000001300000048 +:100C60001300000013000000130000001300000038 +:100C70001300000013000000130000001300000028 +:100C80001300000013000000130000001300000018 +:100C90001300000013000000130000001300000008 +:100CA00013000000130000001300000013000000F8 +:100CB00013000000130000001300000013000000E8 +:100CC00013000000130000001300000013000000D8 +:100CD00013000000130000001300000013000000C8 +:100CE00013000000130000001300000013000000B8 +:100CF00013000000130000001300000013000000A8 +:100D00001300000013000000130000001300000097 +:100D10001300000013000000130000001300000087 +:100D20001300000013000000130000001300000077 +:100D30001300000013000000130000001300000067 +:100D40001300000013000000130000001300000057 +:100D50001300000013000000130000001300000047 +:100D60001300000013000000130000001300000037 +:100D70001300000013000000130000001300000027 +:100D80001300000013000000130000001300000017 +:100D90001300000013000000130000001300000007 +:100DA00013000000130000001300000013000000F7 +:100DB00013000000130000001300000013000000E7 +:100DC00013000000130000001300000013000000D7 +:100DD00013000000130000001300000013000000C7 +:100DE00013000000130000001300000013000000B7 +:100DF00013000000130000001300000013000000A7 +:100E00001300000013000000130000001300000096 +:100E10001300000013000000130000001300000086 +:100E20001300000013000000130000001300000076 +:100E30001300000013000000130000001300000066 +:100E40001300000013000000130000001300000056 +:100E50001300000013000000130000001300000046 +:100E60001300000013000000130000001300000036 +:100E70001300000013000000130000001300000026 +:100E80001300000013000000130000001300000016 +:100E90001300000013000000130000001300000006 +:100EA00013000000130000001300000013000000F6 +:100EB00013000000130000001300000013000000E6 +:100EC00013000000130000001300000013000000D6 +:100ED00013000000130000001300000013000000C6 +:100EE00013000000130000001300000013000000B6 +:100EF00013000000130000001300000013000000A6 +:100F00001300000013000000130000001300000095 +:100F10001300000013000000130000001300000085 +:100F20001300000013000000130000001300000075 +:100F30001300000013000000130000001300000065 +:100F40001300000013000000130000001300000055 +:100F50001300000013000000130000001300000045 +:100F60001300000013000000130000001300000035 +:100F70001300000013000000130000001300000025 +:100F80001300000013000000130000001300000015 +:100F90001300000013000000130000001300000005 +:100FA00013000000130000001300000013000000F5 +:100FB00013000000130000001300000013000000E5 +:100FC00013000000130000001300000013000000D5 +:100FD00013000000130000001300000013000000C5 +:100FE00013000000130000001300000013000000B5 +:100FF00013000000130000001300000013000000A5 +:1010000000000000130000001300000013000000A7 +:101010001300000013000000130000001300000084 +:101020001300000013000000130000001300000074 +:101030001300000013000000130000001300000064 +:101040001300000013000000130000001300000054 +:101050001300000013000000130000001300000044 +:101060001300000013000000130000001300000034 +:101070001300000013000000130000001300000024 +:101080001300000013000000130000001300000014 +:101090001300000013000000130000001300000004 +:1010A00013000000130000001300000013000000F4 +:1010B00013000000130000001300000013000000E4 +:1010C00013000000130000001300000013000000D4 +:1010D00013000000130000001300000013000000C4 +:1010E00013000000130000001300000013000000B4 +:1010F00013000000130000001300000013000000A4 +:101100001300000013000000130000001300000093 +:101110001300000013000000130000001300000083 +:101120001300000013000000130000001300000073 +:101130001300000013000000130000001300000063 +:101140001300000013000000130000001300000053 +:101150001300000013000000130000001300000043 +:101160001300000013000000130000001300000033 +:101170001300000013000000130000001300000023 +:101180001300000013000000130000001300000013 +:101190001300000013000000130000001300000003 +:1011A00013000000130000001300000013000000F3 +:1011B00013000000130000001300000013000000E3 +:1011C00013000000130000001300000013000000D3 +:1011D00013000000130000001300000013000000C3 +:1011E00013000000130000001300000013000000B3 +:1011F00013000000130000001300000013000000A3 +:101200001300000013000000130000001300000092 +:101210001300000013000000130000001300000082 +:101220001300000013000000130000001300000072 +:101230001300000013000000130000001300000062 +:101240001300000013000000130000001300000052 +:101250001300000013000000130000001300000042 +:101260001300000013000000130000001300000032 +:101270001300000013000000130000001300000022 +:101280001300000013000000130000001300000012 +:101290001300000013000000130000001300000002 +:1012A00013000000130000001300000013000000F2 +:1012B00013000000130000001300000013000000E2 +:1012C00013000000130000001300000013000000D2 +:1012D00013000000130000001300000013000000C2 +:1012E00013000000130000001300000013000000B2 +:1012F00013000000130000001300000013000000A2 +:101300001300000013000000130000001300000091 +:101310001300000013000000130000001300000081 +:101320001300000013000000130000001300000071 +:101330001300000013000000130000001300000061 +:101340001300000013000000130000001300000051 +:101350001300000013000000130000001300000041 +:101360001300000013000000130000001300000031 +:101370001300000013000000130000001300000021 +:101380001300000013000000130000001300000011 +:101390001300000013000000130000001300000001 +:1013A00013000000130000001300000013000000F1 +:1013B00013000000130000001300000013000000E1 +:1013C00013000000130000001300000013000000D1 +:1013D00013000000130000001300000013000000C1 +:1013E00013000000130000001300000013000000B1 +:1013F00013000000130000001300000013000000A1 +:101400001300000013000000130000001300000090 +:101410001300000013000000130000001300000080 +:101420001300000013000000130000001300000070 +:101430001300000013000000130000001300000060 +:101440001300000013000000130000001300000050 +:101450001300000013000000130000001300000040 +:101460001300000013000000130000001300000030 +:101470001300000013000000130000001300000020 +:101480001300000013000000130000001300000010 +:101490001300000013000000130000001300000000 +:1014A00013000000130000001300000013000000F0 +:1014B00013000000130000001300000013000000E0 +:1014C00013000000130000001300000013000000D0 +:1014D00013000000130000001300000013000000C0 +:1014E00013000000130000001300000013000000B0 +:1014F00013000000130000001300000013000000A0 +:10150000130000001300000013000000130000008F +:10151000130000001300000013000000130000007F +:10152000130000001300000013000000130000006F +:10153000130000001300000013000000130000005F +:10154000130000001300000013000000130000004F +:10155000130000001300000013000000130000003F +:10156000130000001300000013000000130000002F +:10157000130000001300000013000000130000001F +:10158000130000001300000013000000130000000F +:1015900013000000130000001300000013000000FF +:1015A00013000000130000001300000013000000EF +:1015B00013000000130000001300000013000000DF +:1015C00013000000130000001300000013000000CF +:1015D00013000000130000001300000013000000BF +:1015E00013000000130000001300000013000000AF +:1015F000130000001300000013000000130000009F +:10160000130000001300000013000000130000008E +:10161000130000001300000013000000130000007E +:10162000130000001300000013000000130000006E +:10163000130000001300000013000000130000005E +:10164000130000001300000013000000130000004E +:10165000130000001300000013000000130000003E +:10166000130000001300000013000000130000002E +:10167000130000001300000013000000130000001E +:10168000130000001300000013000000130000000E +:1016900013000000130000001300000013000000FE +:1016A00013000000130000001300000013000000EE +:1016B00013000000130000001300000013000000DE +:1016C00013000000130000001300000013000000CE +:1016D00013000000130000001300000013000000BE +:1016E00013000000130000001300000013000000AE +:1016F000130000001300000013000000130000009E +:10170000130000001300000013000000130000008D +:10171000130000001300000013000000130000007D +:10172000130000001300000013000000130000006D +:10173000130000001300000013000000130000005D +:10174000130000001300000013000000130000004D +:10175000130000001300000013000000130000003D +:10176000130000001300000013000000130000002D +:10177000130000001300000013000000130000001D +:10178000130000001300000013000000130000000D +:1017900013000000130000001300000013000000FD +:1017A00013000000130000001300000013000000ED +:1017B00013000000130000001300000013000000DD +:1017C00013000000130000001300000013000000CD +:1017D00013000000130000001300000013000000BD +:1017E00013000000130000001300000013000000AD +:1017F000130000001300000013000000130000009D +:10180000130000001300000013000000130000008C +:10181000130000001300000013000000130000007C +:10182000130000001300000013000000130000006C +:10183000130000001300000013000000130000005C +:10184000130000001300000013000000130000004C +:10185000130000001300000013000000130000003C +:10186000130000001300000013000000130000002C +:10187000130000001300000013000000130000001C +:10188000130000001300000013000000130000000C +:1018900013000000130000001300000013000000FC +:1018A00013000000130000001300000013000000EC +:1018B00013000000130000001300000013000000DC +:1018C00013000000130000001300000013000000CC +:1018D00013000000130000001300000013000000BC +:1018E00013000000130000001300000013000000AC +:1018F000130000001300000013000000130000009C +:10190000130000001300000013000000130000008B +:10191000130000001300000013000000130000007B +:10192000130000001300000013000000130000006B +:10193000130000001300000013000000130000005B +:10194000130000001300000013000000130000004B +:10195000130000001300000013000000130000003B +:10196000130000001300000013000000130000002B +:10197000130000001300000013000000130000001B +:10198000130000001300000013000000130000000B +:1019900013000000130000001300000013000000FB +:1019A00013000000130000001300000013000000EB +:1019B00013000000130000001300000013000000DB +:1019C00013000000130000001300000013000000CB +:1019D00013000000130000001300000013000000BB +:1019E00013000000130000001300000013000000AB +:1019F000130000001300000013000000130000009B +:101A0000130000001300000013000000130000008A +:101A1000130000001300000013000000130000007A +:101A2000130000001300000013000000130000006A +:101A3000130000001300000013000000130000005A +:101A4000130000001300000013000000130000004A +:101A5000130000001300000013000000130000003A +:101A6000130000001300000013000000130000002A +:101A7000130000001300000013000000130000001A +:101A8000130000001300000013000000130000000A +:101A900013000000130000001300000013000000FA +:101AA00013000000130000001300000013000000EA +:101AB00013000000130000001300000013000000DA +:101AC00013000000130000001300000013000000CA +:101AD00013000000130000001300000013000000BA +:101AE00013000000130000001300000013000000AA +:101AF000130000001300000013000000130000009A +:101B00001300000013000000130000001300000089 +:101B10001300000013000000130000001300000079 +:101B20001300000013000000130000001300000069 +:101B30001300000013000000130000001300000059 +:101B40001300000013000000130000001300000049 +:101B50001300000013000000130000001300000039 +:101B60001300000013000000130000001300000029 +:101B70001300000013000000130000001300000019 +:101B80001300000013000000130000001300000009 +:101B900013000000130000001300000013000000F9 +:101BA00013000000130000001300000013000000E9 +:101BB00013000000130000001300000013000000D9 +:101BC00013000000130000001300000013000000C9 +:101BD00013000000130000001300000013000000B9 +:101BE00013000000130000001300000013000000A9 +:101BF0001300000013000000130000001300000099 +:101C00001300000013000000130000001300000088 +:101C10001300000013000000130000001300000078 +:101C20001300000013000000130000001300000068 +:101C30001300000013000000130000001300000058 +:101C40001300000013000000130000001300000048 +:101C50001300000013000000130000001300000038 +:101C60001300000013000000130000001300000028 +:101C70001300000013000000130000001300000018 +:101C80001300000013000000130000001300000008 +:101C900013000000130000001300000013000000F8 +:101CA00013000000130000001300000013000000E8 +:101CB00013000000130000001300000013000000D8 +:101CC00013000000130000001300000013000000C8 +:101CD00013000000130000001300000013000000B8 +:101CE00013000000130000001300000013000000A8 +:101CF0001300000013000000130000001300000098 +:101D00001300000013000000130000001300000087 +:101D10001300000013000000130000001300000077 +:101D20001300000013000000130000001300000067 +:101D30001300000013000000130000001300000057 +:101D40001300000013000000130000001300000047 +:101D50001300000013000000130000001300000037 +:101D60001300000013000000130000001300000027 +:101D70001300000013000000130000001300000017 +:101D80001300000013000000130000001300000007 +:101D900013000000130000001300000013000000F7 +:101DA00013000000130000001300000013000000E7 +:101DB00013000000130000001300000013000000D7 +:101DC00013000000130000001300000013000000C7 +:101DD00013000000130000001300000013000000B7 +:101DE00013000000130000001300000013000000A7 +:101DF0001300000013000000130000001300000097 +:101E00001300000013000000130000001300000086 +:101E10001300000013000000130000001300000076 +:101E20001300000013000000130000001300000066 +:101E30001300000013000000130000001300000056 +:101E40001300000013000000130000001300000046 +:101E50001300000013000000130000001300000036 +:101E60001300000013000000130000001300000026 +:101E70001300000013000000130000001300000016 +:101E80001300000013000000130000001300000006 +:101E900013000000130000001300000013000000F6 +:101EA00013000000130000001300000013000000E6 +:101EB00013000000130000001300000013000000D6 +:101EC00013000000130000001300000013000000C6 +:101ED00013000000130000001300000013000000B6 +:101EE00013000000130000001300000013000000A6 +:101EF0001300000013000000130000001300000096 +:101F00001300000013000000130000001300000085 +:101F10001300000013000000130000001300000075 +:101F20001300000013000000130000001300000065 +:101F30001300000013000000130000001300000055 +:101F40001300000013000000130000001300000045 +:101F50001300000013000000130000001300000035 +:101F60001300000013000000130000001300000025 +:101F70001300000013000000130000001300000015 +:101F80001300000013000000130000001300000005 +:101F900013000000130000001300000013000000F5 +:101FA00013000000130000001300000013000000E5 +:101FB00013000000130000001300000013000000D5 +:101FC00013000000130000001300000013000000C5 +:101FD00013000000130000001300000013000000B5 +:101FE00013000000130000001300000013000000A5 +:101FF0001300000013000000130000001300000095 +:102000000000000013000000130000001300000097 +:102010001300000013000000130000001300000074 +:102020001300000013000000130000001300000064 +:102030001300000013000000130000001300000054 +:102040001300000013000000130000001300000044 +:102050001300000013000000130000001300000034 +:102060001300000013000000130000001300000024 +:102070001300000013000000130000001300000014 +:102080001300000013000000130000001300000004 +:1020900013000000130000001300000013000000F4 +:1020A00013000000130000001300000013000000E4 +:1020B00013000000130000001300000013000000D4 +:1020C00013000000130000001300000013000000C4 +:1020D00013000000130000001300000013000000B4 +:1020E00013000000130000001300000013000000A4 +:1020F0001300000013000000130000001300000094 +:102100001300000013000000130000001300000083 +:102110001300000013000000130000001300000073 +:102120001300000013000000130000001300000063 +:102130001300000013000000130000001300000053 +:102140001300000013000000130000001300000043 +:102150001300000013000000130000001300000033 +:102160001300000013000000130000001300000023 +:102170001300000013000000130000001300000013 +:102180001300000013000000130000001300000003 +:1021900013000000130000001300000013000000F3 +:1021A00013000000130000001300000013000000E3 +:1021B00013000000130000001300000013000000D3 +:1021C00013000000130000001300000013000000C3 +:1021D00013000000130000001300000013000000B3 +:1021E00013000000130000001300000013000000A3 +:1021F0001300000013000000130000001300000093 +:102200001300000013000000130000001300000082 +:102210001300000013000000130000001300000072 +:102220001300000013000000130000001300000062 +:102230001300000013000000130000001300000052 +:102240001300000013000000130000001300000042 +:102250001300000013000000130000001300000032 +:102260001300000013000000130000001300000022 +:102270001300000013000000130000001300000012 +:102280001300000013000000130000001300000002 +:1022900013000000130000001300000013000000F2 +:1022A00013000000130000001300000013000000E2 +:1022B00013000000130000001300000013000000D2 +:1022C00013000000130000001300000013000000C2 +:1022D00013000000130000001300000013000000B2 +:1022E00013000000130000001300000013000000A2 +:1022F0001300000013000000130000001300000092 +:102300001300000013000000130000001300000081 +:102310001300000013000000130000001300000071 +:102320001300000013000000130000001300000061 +:102330001300000013000000130000001300000051 +:102340001300000013000000130000001300000041 +:102350001300000013000000130000001300000031 +:102360001300000013000000130000001300000021 +:102370001300000013000000130000001300000011 +:102380001300000013000000130000001300000001 +:1023900013000000130000001300000013000000F1 +:1023A00013000000130000001300000013000000E1 +:1023B00013000000130000001300000013000000D1 +:1023C00013000000130000001300000013000000C1 +:1023D00013000000130000001300000013000000B1 +:1023E00013000000130000001300000013000000A1 +:1023F0001300000013000000130000001300000091 +:102400001300000013000000130000001300000080 +:102410001300000013000000130000001300000070 +:102420001300000013000000130000001300000060 +:102430001300000013000000130000001300000050 +:102440001300000013000000130000001300000040 +:102450001300000013000000130000001300000030 +:102460001300000013000000130000001300000020 +:102470001300000013000000130000001300000010 +:102480001300000013000000130000001300000000 +:1024900013000000130000001300000013000000F0 +:1024A00013000000130000001300000013000000E0 +:1024B00013000000130000001300000013000000D0 +:1024C00013000000130000001300000013000000C0 +:1024D00013000000130000001300000013000000B0 +:1024E00013000000130000001300000013000000A0 +:1024F0001300000013000000130000001300000090 +:10250000130000001300000013000000130000007F +:10251000130000001300000013000000130000006F +:10252000130000001300000013000000130000005F +:10253000130000001300000013000000130000004F +:10254000130000001300000013000000130000003F +:10255000130000001300000013000000130000002F +:10256000130000001300000013000000130000001F +:10257000130000001300000013000000130000000F +:1025800013000000130000001300000013000000FF +:1025900013000000130000001300000013000000EF +:1025A00013000000130000001300000013000000DF +:1025B00013000000130000001300000013000000CF +:1025C00013000000130000001300000013000000BF +:1025D00013000000130000001300000013000000AF +:1025E000130000001300000013000000130000009F +:1025F000130000001300000013000000130000008F +:10260000130000001300000013000000130000007E +:10261000130000001300000013000000130000006E +:10262000130000001300000013000000130000005E +:10263000130000001300000013000000130000004E +:10264000130000001300000013000000130000003E +:10265000130000001300000013000000130000002E +:10266000130000001300000013000000130000001E +:10267000130000001300000013000000130000000E +:1026800013000000130000001300000013000000FE +:1026900013000000130000001300000013000000EE +:1026A00013000000130000001300000013000000DE +:1026B00013000000130000001300000013000000CE +:1026C00013000000130000001300000013000000BE +:1026D00013000000130000001300000013000000AE +:1026E000130000001300000013000000130000009E +:1026F000130000001300000013000000130000008E +:10270000130000001300000013000000130000007D +:10271000130000001300000013000000130000006D +:10272000130000001300000013000000130000005D +:10273000130000001300000013000000130000004D +:10274000130000001300000013000000130000003D +:10275000130000001300000013000000130000002D +:10276000130000001300000013000000130000001D +:10277000130000001300000013000000130000000D +:1027800013000000130000001300000013000000FD +:1027900013000000130000001300000013000000ED +:1027A00013000000130000001300000013000000DD +:1027B00013000000130000001300000013000000CD +:1027C00013000000130000001300000013000000BD +:1027D00013000000130000001300000013000000AD +:1027E000130000001300000013000000130000009D +:1027F000130000001300000013000000130000008D +:10280000130000001300000013000000130000007C +:10281000130000001300000013000000130000006C +:10282000130000001300000013000000130000005C +:10283000130000001300000013000000130000004C +:10284000130000001300000013000000130000003C +:10285000130000001300000013000000130000002C +:10286000130000001300000013000000130000001C +:10287000130000001300000013000000130000000C +:1028800013000000130000001300000013000000FC +:1028900013000000130000001300000013000000EC +:1028A00013000000130000001300000013000000DC +:1028B00013000000130000001300000013000000CC +:1028C00013000000130000001300000013000000BC +:1028D00013000000130000001300000013000000AC +:1028E000130000001300000013000000130000009C +:1028F000130000001300000013000000130000008C +:10290000130000001300000013000000130000007B +:10291000130000001300000013000000130000006B +:10292000130000001300000013000000130000005B +:10293000130000001300000013000000130000004B +:10294000130000001300000013000000130000003B +:10295000130000001300000013000000130000002B +:10296000130000001300000013000000130000001B +:10297000130000001300000013000000130000000B +:1029800013000000130000001300000013000000FB +:1029900013000000130000001300000013000000EB +:1029A00013000000130000001300000013000000DB +:1029B00013000000130000001300000013000000CB +:1029C00013000000130000001300000013000000BB +:1029D00013000000130000001300000013000000AB +:1029E000130000001300000013000000130000009B +:1029F000130000001300000013000000130000008B +:102A0000130000001300000013000000130000007A +:102A1000130000001300000013000000130000006A +:102A2000130000001300000013000000130000005A +:102A3000130000001300000013000000130000004A +:102A4000130000001300000013000000130000003A +:102A5000130000001300000013000000130000002A +:102A6000130000001300000013000000130000001A +:102A7000130000001300000013000000130000000A +:102A800013000000130000001300000013000000FA +:102A900013000000130000001300000013000000EA +:102AA00013000000130000001300000013000000DA +:102AB00013000000130000001300000013000000CA +:102AC00013000000130000001300000013000000BA +:102AD00013000000130000001300000013000000AA +:102AE000130000001300000013000000130000009A +:102AF000130000001300000013000000130000008A +:102B00001300000013000000130000001300000079 +:102B10001300000013000000130000001300000069 +:102B20001300000013000000130000001300000059 +:102B30001300000013000000130000001300000049 +:102B40001300000013000000130000001300000039 +:102B50001300000013000000130000001300000029 +:102B60001300000013000000130000001300000019 +:102B70001300000013000000130000001300000009 +:102B800013000000130000001300000013000000F9 +:102B900013000000130000001300000013000000E9 +:102BA00013000000130000001300000013000000D9 +:102BB00013000000130000001300000013000000C9 +:102BC00013000000130000001300000013000000B9 +:102BD00013000000130000001300000013000000A9 +:102BE0001300000013000000130000001300000099 +:102BF0001300000013000000130000001300000089 +:102C00001300000013000000130000001300000078 +:102C10001300000013000000130000001300000068 +:102C20001300000013000000130000001300000058 +:102C30001300000013000000130000001300000048 +:102C40001300000013000000130000001300000038 +:102C50001300000013000000130000001300000028 +:102C60001300000013000000130000001300000018 +:102C70001300000013000000130000001300000008 +:102C800013000000130000001300000013000000F8 +:102C900013000000130000001300000013000000E8 +:102CA00013000000130000001300000013000000D8 +:102CB00013000000130000001300000013000000C8 +:102CC00013000000130000001300000013000000B8 +:102CD00013000000130000001300000013000000A8 +:102CE0001300000013000000130000001300000098 +:102CF0001300000013000000130000001300000088 +:102D00001300000013000000130000001300000077 +:102D10001300000013000000130000001300000067 +:102D20001300000013000000130000001300000057 +:102D30001300000013000000130000001300000047 +:102D40001300000013000000130000001300000037 +:102D50001300000013000000130000001300000027 +:102D60001300000013000000130000001300000017 +:102D70001300000013000000130000001300000007 +:102D800013000000130000001300000013000000F7 +:102D900013000000130000001300000013000000E7 +:102DA00013000000130000001300000013000000D7 +:102DB00013000000130000001300000013000000C7 +:102DC00013000000130000001300000013000000B7 +:102DD00013000000130000001300000013000000A7 +:102DE0001300000013000000130000001300000097 +:102DF0001300000013000000130000001300000087 +:102E00001300000013000000130000001300000076 +:102E10001300000013000000130000001300000066 +:102E20001300000013000000130000001300000056 +:102E30001300000013000000130000001300000046 +:102E40001300000013000000130000001300000036 +:102E50001300000013000000130000001300000026 +:102E60001300000013000000130000001300000016 +:102E70001300000013000000130000001300000006 +:102E800013000000130000001300000013000000F6 +:102E900013000000130000001300000013000000E6 +:102EA00013000000130000001300000013000000D6 +:102EB00013000000130000001300000013000000C6 +:102EC00013000000130000001300000013000000B6 +:102ED00013000000130000001300000013000000A6 +:102EE0001300000013000000130000001300000096 +:102EF0001300000013000000130000001300000086 +:102F00001300000013000000130000001300000075 +:102F10001300000013000000130000001300000065 +:102F20001300000013000000130000001300000055 +:102F30001300000013000000130000001300000045 +:102F40001300000013000000130000001300000035 +:102F50001300000013000000130000001300000025 +:102F60001300000013000000130000001300000015 +:102F70001300000013000000130000001300000005 +:102F800013000000130000001300000013000000F5 +:102F900013000000130000001300000013000000E5 +:102FA00013000000130000001300000013000000D5 +:102FB00013000000130000001300000013000000C5 +:102FC00013000000130000001300000013000000B5 +:102FD00013000000130000001300000013000000A5 +:102FE0001300000013000000130000001300000095 +:102FF0001300000013000000130000001300000085 +:103000000000000013000000130000001300000087 +:103010001300000013000000130000001300000064 +:103020001300000013000000130000001300000054 +:103030001300000013000000130000001300000044 +:103040001300000013000000130000001300000034 +:103050001300000013000000130000001300000024 +:103060001300000013000000130000001300000014 +:103070001300000013000000130000001300000004 +:1030800013000000130000001300000013000000F4 +:1030900013000000130000001300000013000000E4 +:1030A00013000000130000001300000013000000D4 +:1030B00013000000130000001300000013000000C4 +:1030C00013000000130000001300000013000000B4 +:1030D00013000000130000001300000013000000A4 +:1030E0001300000013000000130000001300000094 +:1030F0001300000013000000130000001300000084 +:103100001300000013000000130000001300000073 +:103110001300000013000000130000001300000063 +:103120001300000013000000130000001300000053 +:103130001300000013000000130000001300000043 +:103140001300000013000000130000001300000033 +:103150001300000013000000130000001300000023 +:103160001300000013000000130000001300000013 +:103170001300000013000000130000001300000003 +:1031800013000000130000001300000013000000F3 +:1031900013000000130000001300000013000000E3 +:1031A00013000000130000001300000013000000D3 +:1031B00013000000130000001300000013000000C3 +:1031C00013000000130000001300000013000000B3 +:1031D00013000000130000001300000013000000A3 +:1031E0001300000013000000130000001300000093 +:1031F0001300000013000000130000001300000083 +:103200001300000013000000130000001300000072 +:103210001300000013000000130000001300000062 +:103220001300000013000000130000001300000052 +:103230001300000013000000130000001300000042 +:103240001300000013000000130000001300000032 +:103250001300000013000000130000001300000022 +:103260001300000013000000130000001300000012 +:103270001300000013000000130000001300000002 +:1032800013000000130000001300000013000000F2 +:1032900013000000130000001300000013000000E2 +:1032A00013000000130000001300000013000000D2 +:1032B00013000000130000001300000013000000C2 +:1032C00013000000130000001300000013000000B2 +:1032D00013000000130000001300000013000000A2 +:1032E0001300000013000000130000001300000092 +:1032F0001300000013000000130000001300000082 +:103300001300000013000000130000001300000071 +:103310001300000013000000130000001300000061 +:103320001300000013000000130000001300000051 +:103330001300000013000000130000001300000041 +:103340001300000013000000130000001300000031 +:103350001300000013000000130000001300000021 +:103360001300000013000000130000001300000011 +:103370001300000013000000130000001300000001 +:1033800013000000130000001300000013000000F1 +:1033900013000000130000001300000013000000E1 +:1033A00013000000130000001300000013000000D1 +:1033B00013000000130000001300000013000000C1 +:1033C00013000000130000001300000013000000B1 +:1033D00013000000130000001300000013000000A1 +:1033E0001300000013000000130000001300000091 +:1033F0001300000013000000130000001300000081 +:103400001300000013000000130000001300000070 +:103410001300000013000000130000001300000060 +:103420001300000013000000130000001300000050 +:103430001300000013000000130000001300000040 +:103440001300000013000000130000001300000030 +:103450001300000013000000130000001300000020 +:103460001300000013000000130000001300000010 +:103470001300000013000000130000001300000000 +:1034800013000000130000001300000013000000F0 +:1034900013000000130000001300000013000000E0 +:1034A00013000000130000001300000013000000D0 +:1034B00013000000130000001300000013000000C0 +:1034C00013000000130000001300000013000000B0 +:1034D00013000000130000001300000013000000A0 +:1034E0001300000013000000130000001300000090 +:1034F0001300000013000000130000001300000080 +:10350000130000001300000013000000130000006F +:10351000130000001300000013000000130000005F +:10352000130000001300000013000000130000004F +:10353000130000001300000013000000130000003F +:10354000130000001300000013000000130000002F +:10355000130000001300000013000000130000001F +:10356000130000001300000013000000130000000F +:1035700013000000130000001300000013000000FF +:1035800013000000130000001300000013000000EF +:1035900013000000130000001300000013000000DF +:1035A00013000000130000001300000013000000CF +:1035B00013000000130000001300000013000000BF +:1035C00013000000130000001300000013000000AF +:1035D000130000001300000013000000130000009F +:1035E000130000001300000013000000130000008F +:1035F000130000001300000013000000130000007F +:10360000130000001300000013000000130000006E +:10361000130000001300000013000000130000005E +:10362000130000001300000013000000130000004E +:10363000130000001300000013000000130000003E +:10364000130000001300000013000000130000002E +:10365000130000001300000013000000130000001E +:10366000130000001300000013000000130000000E +:1036700013000000130000001300000013000000FE +:1036800013000000130000001300000013000000EE +:1036900013000000130000001300000013000000DE +:1036A00013000000130000001300000013000000CE +:1036B00013000000130000001300000013000000BE +:1036C00013000000130000001300000013000000AE +:1036D000130000001300000013000000130000009E +:1036E000130000001300000013000000130000008E +:1036F000130000001300000013000000130000007E +:10370000130000001300000013000000130000006D +:10371000130000001300000013000000130000005D +:10372000130000001300000013000000130000004D +:10373000130000001300000013000000130000003D +:10374000130000001300000013000000130000002D +:10375000130000001300000013000000130000001D +:10376000130000001300000013000000130000000D +:1037700013000000130000001300000013000000FD +:1037800013000000130000001300000013000000ED +:1037900013000000130000001300000013000000DD +:1037A00013000000130000001300000013000000CD +:1037B00013000000130000001300000013000000BD +:1037C00013000000130000001300000013000000AD +:1037D000130000001300000013000000130000009D +:1037E000130000001300000013000000130000008D +:1037F000130000001300000013000000130000007D +:10380000130000001300000013000000130000006C +:10381000130000001300000013000000130000005C +:10382000130000001300000013000000130000004C +:10383000130000001300000013000000130000003C +:10384000130000001300000013000000130000002C +:10385000130000001300000013000000130000001C +:10386000130000001300000013000000130000000C +:1038700013000000130000001300000013000000FC +:1038800013000000130000001300000013000000EC +:1038900013000000130000001300000013000000DC +:1038A00013000000130000001300000013000000CC +:1038B00013000000130000001300000013000000BC +:1038C00013000000130000001300000013000000AC +:1038D000130000001300000013000000130000009C +:1038E000130000001300000013000000130000008C +:1038F000130000001300000013000000130000007C +:10390000130000001300000013000000130000006B +:10391000130000001300000013000000130000005B +:10392000130000001300000013000000130000004B +:10393000130000001300000013000000130000003B +:10394000130000001300000013000000130000002B +:10395000130000001300000013000000130000001B +:10396000130000001300000013000000130000000B +:1039700013000000130000001300000013000000FB +:1039800013000000130000001300000013000000EB +:1039900013000000130000001300000013000000DB +:1039A00013000000130000001300000013000000CB +:1039B00013000000130000001300000013000000BB +:1039C00013000000130000001300000013000000AB +:1039D000130000001300000013000000130000009B +:1039E000130000001300000013000000130000008B +:1039F000130000001300000013000000130000007B +:103A0000130000001300000013000000130000006A +:103A1000130000001300000013000000130000005A +:103A2000130000001300000013000000130000004A +:103A3000130000001300000013000000130000003A +:103A4000130000001300000013000000130000002A +:103A5000130000001300000013000000130000001A +:103A6000130000001300000013000000130000000A +:103A700013000000130000001300000013000000FA +:103A800013000000130000001300000013000000EA +:103A900013000000130000001300000013000000DA +:103AA00013000000130000001300000013000000CA +:103AB00013000000130000001300000013000000BA +:103AC00013000000130000001300000013000000AA +:103AD000130000001300000013000000130000009A +:103AE000130000001300000013000000130000008A +:103AF000130000001300000013000000130000007A +:103B00001300000013000000130000001300000069 +:103B10001300000013000000130000001300000059 +:103B20001300000013000000130000001300000049 +:103B30001300000013000000130000001300000039 +:103B40001300000013000000130000001300000029 +:103B50001300000013000000130000001300000019 +:103B60001300000013000000130000001300000009 +:103B700013000000130000001300000013000000F9 +:103B800013000000130000001300000013000000E9 +:103B900013000000130000001300000013000000D9 +:103BA00013000000130000001300000013000000C9 +:103BB00013000000130000001300000013000000B9 +:103BC00013000000130000001300000013000000A9 +:103BD0001300000013000000130000001300000099 +:103BE0001300000013000000130000001300000089 +:103BF0001300000013000000130000001300000079 +:103C00001300000013000000130000001300000068 +:103C10001300000013000000130000001300000058 +:103C20001300000013000000130000001300000048 +:103C30001300000013000000130000001300000038 +:103C40001300000013000000130000001300000028 +:103C50001300000013000000130000001300000018 +:103C60001300000013000000130000001300000008 +:103C700013000000130000001300000013000000F8 +:103C800013000000130000001300000013000000E8 +:103C900013000000130000001300000013000000D8 +:103CA00013000000130000001300000013000000C8 +:103CB00013000000130000001300000013000000B8 +:103CC00013000000130000001300000013000000A8 +:103CD0001300000013000000130000001300000098 +:103CE0001300000013000000130000001300000088 +:103CF0001300000013000000130000001300000078 +:103D00001300000013000000130000001300000067 +:103D10001300000013000000130000001300000057 +:103D20001300000013000000130000001300000047 +:103D30001300000013000000130000001300000037 +:103D40001300000013000000130000001300000027 +:103D50001300000013000000130000001300000017 +:103D60001300000013000000130000001300000007 +:103D700013000000130000001300000013000000F7 +:103D800013000000130000001300000013000000E7 +:103D900013000000130000001300000013000000D7 +:103DA00013000000130000001300000013000000C7 +:103DB00013000000130000001300000013000000B7 +:103DC00013000000130000001300000013000000A7 +:103DD0001300000013000000130000001300000097 +:103DE0001300000013000000130000001300000087 +:103DF0001300000013000000130000001300000077 +:103E00001300000013000000130000001300000066 +:103E10001300000013000000130000001300000056 +:103E20001300000013000000130000001300000046 +:103E30001300000013000000130000001300000036 +:103E40001300000013000000130000001300000026 +:103E50001300000013000000130000001300000016 +:103E60001300000013000000130000001300000006 +:103E700013000000130000001300000013000000F6 +:103E800013000000130000001300000013000000E6 +:103E900013000000130000001300000013000000D6 +:103EA00013000000130000001300000013000000C6 +:103EB00013000000130000001300000013000000B6 +:103EC00013000000130000001300000013000000A6 +:103ED0001300000013000000130000001300000096 +:103EE0001300000013000000130000001300000086 +:103EF0001300000013000000130000001300000076 +:103F00001300000013000000130000001300000065 +:103F10001300000013000000130000001300000055 +:103F20001300000013000000130000001300000045 +:103F30001300000013000000130000001300000035 +:103F40001300000013000000130000001300000025 +:103F50001300000013000000130000001300000015 +:103F60001300000013000000130000001300000005 +:103F700013000000130000001300000013000000F5 +:103F800013000000130000001300000013000000E5 +:103F900013000000130000001300000013000000D5 +:103FA00013000000130000001300000013000000C5 +:103FB00013000000130000001300000013000000B5 +:103FC00013000000130000001300000013000000A5 +:103FD0001300000013000000130000001300000095 +:103FE0001300000013000000130000001300000085 +:103FF0001300000013000000130000001300000075 +:104000000000000013000000130000001300000077 +:104010001300000013000000130000001300000054 +:104020001300000013000000130000001300000044 +:104030001300000013000000130000001300000034 +:104040001300000013000000130000001300000024 +:104050001300000013000000130000001300000014 +:104060001300000013000000130000001300000004 +:1040700013000000130000001300000013000000F4 +:1040800013000000130000001300000013000000E4 +:1040900013000000130000001300000013000000D4 +:1040A00013000000130000001300000013000000C4 +:1040B00013000000130000001300000013000000B4 +:1040C00013000000130000001300000013000000A4 +:1040D0001300000013000000130000001300000094 +:1040E0001300000013000000130000001300000084 +:1040F0001300000013000000130000001300000074 +:104100001300000013000000130000001300000063 +:104110001300000013000000130000001300000053 +:104120001300000013000000130000001300000043 +:104130001300000013000000130000001300000033 +:104140001300000013000000130000001300000023 +:104150001300000013000000130000001300000013 +:104160001300000013000000130000001300000003 +:1041700013000000130000001300000013000000F3 +:1041800013000000130000001300000013000000E3 +:1041900013000000130000001300000013000000D3 +:1041A00013000000130000001300000013000000C3 +:1041B00013000000130000001300000013000000B3 +:1041C00013000000130000001300000013000000A3 +:1041D0001300000013000000130000001300000093 +:1041E0001300000013000000130000001300000083 +:1041F0001300000013000000130000001300000073 +:104200001300000013000000130000001300000062 +:104210001300000013000000130000001300000052 +:104220001300000013000000130000001300000042 +:104230001300000013000000130000001300000032 +:104240001300000013000000130000001300000022 +:104250001300000013000000130000001300000012 +:104260001300000013000000130000001300000002 +:1042700013000000130000001300000013000000F2 +:1042800013000000130000001300000013000000E2 +:1042900013000000130000001300000013000000D2 +:1042A00013000000130000001300000013000000C2 +:1042B00013000000130000001300000013000000B2 +:1042C00013000000130000001300000013000000A2 +:1042D0001300000013000000130000001300000092 +:1042E0001300000013000000130000001300000082 +:1042F0001300000013000000130000001300000072 +:104300001300000013000000130000001300000061 +:104310001300000013000000130000001300000051 +:104320001300000013000000130000001300000041 +:104330001300000013000000130000001300000031 +:104340001300000013000000130000001300000021 +:104350001300000013000000130000001300000011 +:104360001300000013000000130000001300000001 +:1043700013000000130000001300000013000000F1 +:1043800013000000130000001300000013000000E1 +:1043900013000000130000001300000013000000D1 +:1043A00013000000130000001300000013000000C1 +:1043B00013000000130000001300000013000000B1 +:1043C00013000000130000001300000013000000A1 +:1043D0001300000013000000130000001300000091 +:1043E0001300000013000000130000001300000081 +:1043F0001300000013000000130000001300000071 +:104400001300000013000000130000001300000060 +:104410001300000013000000130000001300000050 +:104420001300000013000000130000001300000040 +:104430001300000013000000130000001300000030 +:104440001300000013000000130000001300000020 +:104450001300000013000000130000001300000010 +:104460001300000013000000130000001300000000 +:1044700013000000130000001300000013000000F0 +:1044800013000000130000001300000013000000E0 +:1044900013000000130000001300000013000000D0 +:1044A00013000000130000001300000013000000C0 +:1044B00013000000130000001300000013000000B0 +:1044C00013000000130000001300000013000000A0 +:1044D0001300000013000000130000001300000090 +:1044E0001300000013000000130000001300000080 +:1044F0001300000013000000130000001300000070 +:10450000130000001300000013000000130000005F +:10451000130000001300000013000000130000004F +:10452000130000001300000013000000130000003F +:10453000130000001300000013000000130000002F +:10454000130000001300000013000000130000001F +:10455000130000001300000013000000130000000F +:1045600013000000130000001300000013000000FF +:1045700013000000130000001300000013000000EF +:1045800013000000130000001300000013000000DF +:1045900013000000130000001300000013000000CF +:1045A00013000000130000001300000013000000BF +:1045B00013000000130000001300000013000000AF +:1045C000130000001300000013000000130000009F +:1045D000130000001300000013000000130000008F +:1045E000130000001300000013000000130000007F +:1045F000130000001300000013000000130000006F +:10460000130000001300000013000000130000005E +:10461000130000001300000013000000130000004E +:10462000130000001300000013000000130000003E +:10463000130000001300000013000000130000002E +:10464000130000001300000013000000130000001E +:10465000130000001300000013000000130000000E +:1046600013000000130000001300000013000000FE +:1046700013000000130000001300000013000000EE +:1046800013000000130000001300000013000000DE +:1046900013000000130000001300000013000000CE +:1046A00013000000130000001300000013000000BE +:1046B00013000000130000001300000013000000AE +:1046C000130000001300000013000000130000009E +:1046D000130000001300000013000000130000008E +:1046E000130000001300000013000000130000007E +:1046F000130000001300000013000000130000006E +:10470000130000001300000013000000130000005D +:10471000130000001300000013000000130000004D +:10472000130000001300000013000000130000003D +:10473000130000001300000013000000130000002D +:10474000130000001300000013000000130000001D +:10475000130000001300000013000000130000000D +:1047600013000000130000001300000013000000FD +:1047700013000000130000001300000013000000ED +:1047800013000000130000001300000013000000DD +:1047900013000000130000001300000013000000CD +:1047A00013000000130000001300000013000000BD +:1047B00013000000130000001300000013000000AD +:1047C000130000001300000013000000130000009D +:1047D000130000001300000013000000130000008D +:1047E000130000001300000013000000130000007D +:1047F000130000001300000013000000130000006D +:10480000130000001300000013000000130000005C +:10481000130000001300000013000000130000004C +:10482000130000001300000013000000130000003C +:10483000130000001300000013000000130000002C +:10484000130000001300000013000000130000001C +:10485000130000001300000013000000130000000C +:1048600013000000130000001300000013000000FC +:1048700013000000130000001300000013000000EC +:1048800013000000130000001300000013000000DC +:1048900013000000130000001300000013000000CC +:1048A00013000000130000001300000013000000BC +:1048B00013000000130000001300000013000000AC +:1048C000130000001300000013000000130000009C +:1048D000130000001300000013000000130000008C +:1048E000130000001300000013000000130000007C +:1048F000130000001300000013000000130000006C +:10490000130000001300000013000000130000005B +:10491000130000001300000013000000130000004B +:10492000130000001300000013000000130000003B +:10493000130000001300000013000000130000002B +:10494000130000001300000013000000130000001B +:10495000130000001300000013000000130000000B +:1049600013000000130000001300000013000000FB +:1049700013000000130000001300000013000000EB +:1049800013000000130000001300000013000000DB +:1049900013000000130000001300000013000000CB +:1049A00013000000130000001300000013000000BB +:1049B00013000000130000001300000013000000AB +:1049C000130000001300000013000000130000009B +:1049D000130000001300000013000000130000008B +:1049E000130000001300000013000000130000007B +:1049F000130000001300000013000000130000006B +:104A0000130000001300000013000000130000005A +:104A1000130000001300000013000000130000004A +:104A2000130000001300000013000000130000003A +:104A3000130000001300000013000000130000002A +:104A4000130000001300000013000000130000001A +:104A5000130000001300000013000000130000000A +:104A600013000000130000001300000013000000FA +:104A700013000000130000001300000013000000EA +:104A800013000000130000001300000013000000DA +:104A900013000000130000001300000013000000CA +:104AA00013000000130000001300000013000000BA +:104AB00013000000130000001300000013000000AA +:104AC000130000001300000013000000130000009A +:104AD000130000001300000013000000130000008A +:104AE000130000001300000013000000130000007A +:104AF000130000001300000013000000130000006A +:104B00001300000013000000130000001300000059 +:104B10001300000013000000130000001300000049 +:104B20001300000013000000130000001300000039 +:104B30001300000013000000130000001300000029 +:104B40001300000013000000130000001300000019 +:104B50001300000013000000130000001300000009 +:104B600013000000130000001300000013000000F9 +:104B700013000000130000001300000013000000E9 +:104B800013000000130000001300000013000000D9 +:104B900013000000130000001300000013000000C9 +:104BA00013000000130000001300000013000000B9 +:104BB00013000000130000001300000013000000A9 +:104BC0001300000013000000130000001300000099 +:104BD0001300000013000000130000001300000089 +:104BE0001300000013000000130000001300000079 +:104BF0001300000013000000130000001300000069 +:104C00001300000013000000130000001300000058 +:104C10001300000013000000130000001300000048 +:104C20001300000013000000130000001300000038 +:104C30001300000013000000130000001300000028 +:104C40001300000013000000130000001300000018 +:104C50001300000013000000130000001300000008 +:104C600013000000130000001300000013000000F8 +:104C700013000000130000001300000013000000E8 +:104C800013000000130000001300000013000000D8 +:104C900013000000130000001300000013000000C8 +:104CA00013000000130000001300000013000000B8 +:104CB00013000000130000001300000013000000A8 +:104CC0001300000013000000130000001300000098 +:104CD0001300000013000000130000001300000088 +:104CE0001300000013000000130000001300000078 +:104CF0001300000013000000130000001300000068 +:104D00001300000013000000130000001300000057 +:104D10001300000013000000130000001300000047 +:104D20001300000013000000130000001300000037 +:104D30001300000013000000130000001300000027 +:104D40001300000013000000130000001300000017 +:104D50001300000013000000130000001300000007 +:104D600013000000130000001300000013000000F7 +:104D700013000000130000001300000013000000E7 +:104D800013000000130000001300000013000000D7 +:104D900013000000130000001300000013000000C7 +:104DA00013000000130000001300000013000000B7 +:104DB00013000000130000001300000013000000A7 +:104DC0001300000013000000130000001300000097 +:104DD0001300000013000000130000001300000087 +:104DE0001300000013000000130000001300000077 +:104DF0001300000013000000130000001300000067 +:104E00001300000013000000130000001300000056 +:104E10001300000013000000130000001300000046 +:104E20001300000013000000130000001300000036 +:104E30001300000013000000130000001300000026 +:104E40001300000013000000130000001300000016 +:104E50001300000013000000130000001300000006 +:104E600013000000130000001300000013000000F6 +:104E700013000000130000001300000013000000E6 +:104E800013000000130000001300000013000000D6 +:104E900013000000130000001300000013000000C6 +:104EA00013000000130000001300000013000000B6 +:104EB00013000000130000001300000013000000A6 +:104EC0001300000013000000130000001300000096 +:104ED0001300000013000000130000001300000086 +:104EE0001300000013000000130000001300000076 +:104EF0001300000013000000130000001300000066 +:104F00001300000013000000130000001300000055 +:104F10001300000013000000130000001300000045 +:104F20001300000013000000130000001300000035 +:104F30001300000013000000130000001300000025 +:104F40001300000013000000130000001300000015 +:104F50001300000013000000130000001300000005 +:104F600013000000130000001300000013000000F5 +:104F700013000000130000001300000013000000E5 +:104F800013000000130000001300000013000000D5 +:104F900013000000130000001300000013000000C5 +:104FA00013000000130000001300000013000000B5 +:104FB00013000000130000001300000013000000A5 +:104FC0001300000013000000130000001300000095 +:104FD0001300000013000000130000001300000085 +:104FE0001300000013000000130000001300000075 +:104FF0001300000013000000130000001300000065 +:10500000000102030405060708090A0B0C0D0E0F28 +:105010001300000013000000130000001300000044 +:105020001300000013000000130000001300000034 +:105030001300000013000000130000001300000024 +:105040001300000013000000130000001300000014 +:105050001300000013000000130000001300000004 +:1050600013000000130000001300000013000000F4 +:1050700013000000130000001300000013000000E4 +:1050800013000000130000001300000013000000D4 +:1050900013000000130000001300000013000000C4 +:1050A00013000000130000001300000013000000B4 +:1050B00013000000130000001300000013000000A4 +:1050C0001300000013000000130000001300000094 +:1050D0001300000013000000130000001300000084 +:1050E0001300000013000000130000001300000074 +:1050F0001300000013000000130000001300000064 +:105100001300000013000000130000001300000053 +:105110001300000013000000130000001300000043 +:105120001300000013000000130000001300000033 +:105130001300000013000000130000001300000023 +:105140001300000013000000130000001300000013 +:105150001300000013000000130000001300000003 +:1051600013000000130000001300000013000000F3 +:1051700013000000130000001300000013000000E3 +:1051800013000000130000001300000013000000D3 +:1051900013000000130000001300000013000000C3 +:1051A00013000000130000001300000013000000B3 +:1051B00013000000130000001300000013000000A3 +:1051C0001300000013000000130000001300000093 +:1051D0001300000013000000130000001300000083 +:1051E0001300000013000000130000001300000073 +:1051F0001300000013000000130000001300000063 +:105200001300000013000000130000001300000052 +:105210001300000013000000130000001300000042 +:105220001300000013000000130000001300000032 +:105230001300000013000000130000001300000022 +:105240001300000013000000130000001300000012 +:105250001300000013000000130000001300000002 +:1052600013000000130000001300000013000000F2 +:1052700013000000130000001300000013000000E2 +:1052800013000000130000001300000013000000D2 +:1052900013000000130000001300000013000000C2 +:1052A00013000000130000001300000013000000B2 +:1052B00013000000130000001300000013000000A2 +:1052C0001300000013000000130000001300000092 +:1052D0001300000013000000130000001300000082 +:1052E0001300000013000000130000001300000072 +:1052F0001300000013000000130000001300000062 +:105300001300000013000000130000001300000051 +:105310001300000013000000130000001300000041 +:105320001300000013000000130000001300000031 +:105330001300000013000000130000001300000021 +:105340001300000013000000130000001300000011 +:105350001300000013000000130000001300000001 +:1053600013000000130000001300000013000000F1 +:1053700013000000130000001300000013000000E1 +:1053800013000000130000001300000013000000D1 +:1053900013000000130000001300000013000000C1 +:1053A00013000000130000001300000013000000B1 +:1053B00013000000130000001300000013000000A1 +:1053C0001300000013000000130000001300000091 +:1053D0001300000013000000130000001300000081 +:1053E0001300000013000000130000001300000071 +:1053F0001300000013000000130000001300000061 +:105400001300000013000000130000001300000050 +:105410001300000013000000130000001300000040 +:105420001300000013000000130000001300000030 +:105430001300000013000000130000001300000020 +:105440001300000013000000130000001300000010 +:105450001300000013000000130000001300000000 +:1054600013000000130000001300000013000000F0 +:1054700013000000130000001300000013000000E0 +:1054800013000000130000001300000013000000D0 +:1054900013000000130000001300000013000000C0 +:1054A00013000000130000001300000013000000B0 +:1054B00013000000130000001300000013000000A0 +:1054C0001300000013000000130000001300000090 +:1054D0001300000013000000130000001300000080 +:1054E0001300000013000000130000001300000070 +:1054F0001300000013000000130000001300000060 +:10550000130000001300000013000000130000004F +:10551000130000001300000013000000130000003F +:10552000130000001300000013000000130000002F +:10553000130000001300000013000000130000001F +:10554000130000001300000013000000130000000F +:1055500013000000130000001300000013000000FF +:1055600013000000130000001300000013000000EF +:1055700013000000130000001300000013000000DF +:1055800013000000130000001300000013000000CF +:1055900013000000130000001300000013000000BF +:1055A00013000000130000001300000013000000AF +:1055B000130000001300000013000000130000009F +:1055C000130000001300000013000000130000008F +:1055D000130000001300000013000000130000007F +:1055E000130000001300000013000000130000006F +:1055F000130000001300000013000000130000005F +:10560000130000001300000013000000130000004E +:10561000130000001300000013000000130000003E +:10562000130000001300000013000000130000002E +:10563000130000001300000013000000130000001E +:10564000130000001300000013000000130000000E +:1056500013000000130000001300000013000000FE +:1056600013000000130000001300000013000000EE +:1056700013000000130000001300000013000000DE +:1056800013000000130000001300000013000000CE +:1056900013000000130000001300000013000000BE +:1056A00013000000130000001300000013000000AE +:1056B000130000001300000013000000130000009E +:1056C000130000001300000013000000130000008E +:1056D000130000001300000013000000130000007E +:1056E000130000001300000013000000130000006E +:1056F000130000001300000013000000130000005E +:10570000130000001300000013000000130000004D +:10571000130000001300000013000000130000003D +:10572000130000001300000013000000130000002D +:10573000130000001300000013000000130000001D +:10574000130000001300000013000000130000000D +:1057500013000000130000001300000013000000FD +:1057600013000000130000001300000013000000ED +:1057700013000000130000001300000013000000DD +:1057800013000000130000001300000013000000CD +:1057900013000000130000001300000013000000BD +:1057A00013000000130000001300000013000000AD +:1057B000130000001300000013000000130000009D +:1057C000130000001300000013000000130000008D +:1057D000130000001300000013000000130000007D +:1057E000130000001300000013000000130000006D +:1057F000130000001300000013000000130000005D +:10580000130000001300000013000000130000004C +:10581000130000001300000013000000130000003C +:10582000130000001300000013000000130000002C +:10583000130000001300000013000000130000001C +:10584000130000001300000013000000130000000C +:1058500013000000130000001300000013000000FC +:1058600013000000130000001300000013000000EC +:1058700013000000130000001300000013000000DC +:1058800013000000130000001300000013000000CC +:1058900013000000130000001300000013000000BC +:1058A00013000000130000001300000013000000AC +:1058B000130000001300000013000000130000009C +:1058C000130000001300000013000000130000008C +:1058D000130000001300000013000000130000007C +:1058E000130000001300000013000000130000006C +:1058F000130000001300000013000000130000005C +:10590000130000001300000013000000130000004B +:10591000130000001300000013000000130000003B +:10592000130000001300000013000000130000002B +:10593000130000001300000013000000130000001B +:10594000130000001300000013000000130000000B +:1059500013000000130000001300000013000000FB +:1059600013000000130000001300000013000000EB +:1059700013000000130000001300000013000000DB +:1059800013000000130000001300000013000000CB +:1059900013000000130000001300000013000000BB +:1059A00013000000130000001300000013000000AB +:1059B000130000001300000013000000130000009B +:1059C000130000001300000013000000130000008B +:1059D000130000001300000013000000130000007B +:1059E000130000001300000013000000130000006B +:1059F000130000001300000013000000130000005B +:105A0000130000001300000013000000130000004A +:105A1000130000001300000013000000130000003A +:105A2000130000001300000013000000130000002A +:105A3000130000001300000013000000130000001A +:105A4000130000001300000013000000130000000A +:105A500013000000130000001300000013000000FA +:105A600013000000130000001300000013000000EA +:105A700013000000130000001300000013000000DA +:105A800013000000130000001300000013000000CA +:105A900013000000130000001300000013000000BA +:105AA00013000000130000001300000013000000AA +:105AB000130000001300000013000000130000009A +:105AC000130000001300000013000000130000008A +:105AD000130000001300000013000000130000007A +:105AE000130000001300000013000000130000006A +:105AF000130000001300000013000000130000005A +:105B00001300000013000000130000001300000049 +:105B10001300000013000000130000001300000039 +:105B20001300000013000000130000001300000029 +:105B30001300000013000000130000001300000019 +:105B40001300000013000000130000001300000009 +:105B500013000000130000001300000013000000F9 +:105B600013000000130000001300000013000000E9 +:105B700013000000130000001300000013000000D9 +:105B800013000000130000001300000013000000C9 +:105B900013000000130000001300000013000000B9 +:105BA00013000000130000001300000013000000A9 +:105BB0001300000013000000130000001300000099 +:105BC0001300000013000000130000001300000089 +:105BD0001300000013000000130000001300000079 +:105BE0001300000013000000130000001300000069 +:105BF0001300000013000000130000001300000059 +:105C00001300000013000000130000001300000048 +:105C10001300000013000000130000001300000038 +:105C20001300000013000000130000001300000028 +:105C30001300000013000000130000001300000018 +:105C40001300000013000000130000001300000008 +:105C500013000000130000001300000013000000F8 +:105C600013000000130000001300000013000000E8 +:105C700013000000130000001300000013000000D8 +:105C800013000000130000001300000013000000C8 +:105C900013000000130000001300000013000000B8 +:105CA00013000000130000001300000013000000A8 +:105CB0001300000013000000130000001300000098 +:105CC0001300000013000000130000001300000088 +:105CD0001300000013000000130000001300000078 +:105CE0001300000013000000130000001300000068 +:105CF0001300000013000000130000001300000058 +:105D00001300000013000000130000001300000047 +:105D10001300000013000000130000001300000037 +:105D20001300000013000000130000001300000027 +:105D30001300000013000000130000001300000017 +:105D40001300000013000000130000001300000007 +:105D500013000000130000001300000013000000F7 +:105D600013000000130000001300000013000000E7 +:105D700013000000130000001300000013000000D7 +:105D800013000000130000001300000013000000C7 +:105D900013000000130000001300000013000000B7 +:105DA00013000000130000001300000013000000A7 +:105DB0001300000013000000130000001300000097 +:105DC0001300000013000000130000001300000087 +:105DD0001300000013000000130000001300000077 +:105DE0001300000013000000130000001300000067 +:105DF0001300000013000000130000001300000057 +:105E00001300000013000000130000001300000046 +:105E10001300000013000000130000001300000036 +:105E20001300000013000000130000001300000026 +:105E30001300000013000000130000001300000016 +:105E40001300000013000000130000001300000006 +:105E500013000000130000001300000013000000F6 +:105E600013000000130000001300000013000000E6 +:105E700013000000130000001300000013000000D6 +:105E800013000000130000001300000013000000C6 +:105E900013000000130000001300000013000000B6 +:105EA00013000000130000001300000013000000A6 +:105EB0001300000013000000130000001300000096 +:105EC0001300000013000000130000001300000086 +:105ED0001300000013000000130000001300000076 +:105EE0001300000013000000130000001300000066 +:105EF0001300000013000000130000001300000056 +:105F00001300000013000000130000001300000045 +:105F10001300000013000000130000001300000035 +:105F20001300000013000000130000001300000025 +:105F30001300000013000000130000001300000015 +:105F40001300000013000000130000001300000005 +:105F500013000000130000001300000013000000F5 +:105F600013000000130000001300000013000000E5 +:105F700013000000130000001300000013000000D5 +:105F800013000000130000001300000013000000C5 +:105F900013000000130000001300000013000000B5 +:105FA00013000000130000001300000013000000A5 +:105FB0001300000013000000130000001300000095 +:105FC0001300000013000000130000001300000085 +:105FD0001300000013000000130000001300000075 +:105FE0001300000013000000130000001300000065 +:105FF0001300000013000000130000001300000055 +:10600000101112131415161718191A1B1C1D1E1F18 +:106010001300000013000000130000001300000034 +:106020001300000013000000130000001300000024 +:106030001300000013000000130000001300000014 +:106040001300000013000000130000001300000004 +:1060500013000000130000001300000013000000F4 +:1060600013000000130000001300000013000000E4 +:1060700013000000130000001300000013000000D4 +:1060800013000000130000001300000013000000C4 +:1060900013000000130000001300000013000000B4 +:1060A00013000000130000001300000013000000A4 +:1060B0001300000013000000130000001300000094 +:1060C0001300000013000000130000001300000084 +:1060D0001300000013000000130000001300000074 +:1060E0001300000013000000130000001300000064 +:1060F0001300000013000000130000001300000054 +:106100001300000013000000130000001300000043 +:106110001300000013000000130000001300000033 +:106120001300000013000000130000001300000023 +:106130001300000013000000130000001300000013 +:106140001300000013000000130000001300000003 +:1061500013000000130000001300000013000000F3 +:1061600013000000130000001300000013000000E3 +:1061700013000000130000001300000013000000D3 +:1061800013000000130000001300000013000000C3 +:1061900013000000130000001300000013000000B3 +:1061A00013000000130000001300000013000000A3 +:1061B0001300000013000000130000001300000093 +:1061C0001300000013000000130000001300000083 +:1061D0001300000013000000130000001300000073 +:1061E0001300000013000000130000001300000063 +:1061F0001300000013000000130000001300000053 +:106200001300000013000000130000001300000042 +:106210001300000013000000130000001300000032 +:106220001300000013000000130000001300000022 +:106230001300000013000000130000001300000012 +:106240001300000013000000130000001300000002 +:1062500013000000130000001300000013000000F2 +:1062600013000000130000001300000013000000E2 +:1062700013000000130000001300000013000000D2 +:1062800013000000130000001300000013000000C2 +:1062900013000000130000001300000013000000B2 +:1062A00013000000130000001300000013000000A2 +:1062B0001300000013000000130000001300000092 +:1062C0001300000013000000130000001300000082 +:1062D0001300000013000000130000001300000072 +:1062E0001300000013000000130000001300000062 +:1062F0001300000013000000130000001300000052 +:106300001300000013000000130000001300000041 +:106310001300000013000000130000001300000031 +:106320001300000013000000130000001300000021 +:106330001300000013000000130000001300000011 +:106340001300000013000000130000001300000001 +:1063500013000000130000001300000013000000F1 +:1063600013000000130000001300000013000000E1 +:1063700013000000130000001300000013000000D1 +:1063800013000000130000001300000013000000C1 +:1063900013000000130000001300000013000000B1 +:1063A00013000000130000001300000013000000A1 +:1063B0001300000013000000130000001300000091 +:1063C0001300000013000000130000001300000081 +:1063D0001300000013000000130000001300000071 +:1063E0001300000013000000130000001300000061 +:1063F0001300000013000000130000001300000051 +:106400001300000013000000130000001300000040 +:106410001300000013000000130000001300000030 +:106420001300000013000000130000001300000020 +:106430001300000013000000130000001300000010 +:106440001300000013000000130000001300000000 +:1064500013000000130000001300000013000000F0 +:1064600013000000130000001300000013000000E0 +:1064700013000000130000001300000013000000D0 +:1064800013000000130000001300000013000000C0 +:1064900013000000130000001300000013000000B0 +:1064A00013000000130000001300000013000000A0 +:1064B0001300000013000000130000001300000090 +:1064C0001300000013000000130000001300000080 +:1064D0001300000013000000130000001300000070 +:1064E0001300000013000000130000001300000060 +:1064F0001300000013000000130000001300000050 +:10650000130000001300000013000000130000003F +:10651000130000001300000013000000130000002F +:10652000130000001300000013000000130000001F +:10653000130000001300000013000000130000000F +:1065400013000000130000001300000013000000FF +:1065500013000000130000001300000013000000EF +:1065600013000000130000001300000013000000DF +:1065700013000000130000001300000013000000CF +:1065800013000000130000001300000013000000BF +:1065900013000000130000001300000013000000AF +:1065A000130000001300000013000000130000009F +:1065B000130000001300000013000000130000008F +:1065C000130000001300000013000000130000007F +:1065D000130000001300000013000000130000006F +:1065E000130000001300000013000000130000005F +:1065F000130000001300000013000000130000004F +:10660000130000001300000013000000130000003E +:10661000130000001300000013000000130000002E +:10662000130000001300000013000000130000001E +:10663000130000001300000013000000130000000E +:1066400013000000130000001300000013000000FE +:1066500013000000130000001300000013000000EE +:1066600013000000130000001300000013000000DE +:1066700013000000130000001300000013000000CE +:1066800013000000130000001300000013000000BE +:1066900013000000130000001300000013000000AE +:1066A000130000001300000013000000130000009E +:1066B000130000001300000013000000130000008E +:1066C000130000001300000013000000130000007E +:1066D000130000001300000013000000130000006E +:1066E000130000001300000013000000130000005E +:1066F000130000001300000013000000130000004E +:10670000130000001300000013000000130000003D +:10671000130000001300000013000000130000002D +:10672000130000001300000013000000130000001D +:10673000130000001300000013000000130000000D +:1067400013000000130000001300000013000000FD +:1067500013000000130000001300000013000000ED +:1067600013000000130000001300000013000000DD +:1067700013000000130000001300000013000000CD +:1067800013000000130000001300000013000000BD +:1067900013000000130000001300000013000000AD +:1067A000130000001300000013000000130000009D +:1067B000130000001300000013000000130000008D +:1067C000130000001300000013000000130000007D +:1067D000130000001300000013000000130000006D +:1067E000130000001300000013000000130000005D +:1067F000130000001300000013000000130000004D +:10680000130000001300000013000000130000003C +:10681000130000001300000013000000130000002C +:10682000130000001300000013000000130000001C +:10683000130000001300000013000000130000000C +:1068400013000000130000001300000013000000FC +:1068500013000000130000001300000013000000EC +:1068600013000000130000001300000013000000DC +:1068700013000000130000001300000013000000CC +:1068800013000000130000001300000013000000BC +:1068900013000000130000001300000013000000AC +:1068A000130000001300000013000000130000009C +:1068B000130000001300000013000000130000008C +:1068C000130000001300000013000000130000007C +:1068D000130000001300000013000000130000006C +:1068E000130000001300000013000000130000005C +:1068F000130000001300000013000000130000004C +:10690000130000001300000013000000130000003B +:10691000130000001300000013000000130000002B +:10692000130000001300000013000000130000001B +:10693000130000001300000013000000130000000B +:1069400013000000130000001300000013000000FB +:1069500013000000130000001300000013000000EB +:1069600013000000130000001300000013000000DB +:1069700013000000130000001300000013000000CB +:1069800013000000130000001300000013000000BB +:1069900013000000130000001300000013000000AB +:1069A000130000001300000013000000130000009B +:1069B000130000001300000013000000130000008B +:1069C000130000001300000013000000130000007B +:1069D000130000001300000013000000130000006B +:1069E000130000001300000013000000130000005B +:1069F000130000001300000013000000130000004B +:106A0000130000001300000013000000130000003A +:106A1000130000001300000013000000130000002A +:106A2000130000001300000013000000130000001A +:106A3000130000001300000013000000130000000A +:106A400013000000130000001300000013000000FA +:106A500013000000130000001300000013000000EA +:106A600013000000130000001300000013000000DA +:106A700013000000130000001300000013000000CA +:106A800013000000130000001300000013000000BA +:106A900013000000130000001300000013000000AA +:106AA000130000001300000013000000130000009A +:106AB000130000001300000013000000130000008A +:106AC000130000001300000013000000130000007A +:106AD000130000001300000013000000130000006A +:106AE000130000001300000013000000130000005A +:106AF000130000001300000013000000130000004A +:106B00001300000013000000130000001300000039 +:106B10001300000013000000130000001300000029 +:106B20001300000013000000130000001300000019 +:106B30001300000013000000130000001300000009 +:106B400013000000130000001300000013000000F9 +:106B500013000000130000001300000013000000E9 +:106B600013000000130000001300000013000000D9 +:106B700013000000130000001300000013000000C9 +:106B800013000000130000001300000013000000B9 +:106B900013000000130000001300000013000000A9 +:106BA0001300000013000000130000001300000099 +:106BB0001300000013000000130000001300000089 +:106BC0001300000013000000130000001300000079 +:106BD0001300000013000000130000001300000069 +:106BE0001300000013000000130000001300000059 +:106BF0001300000013000000130000001300000049 +:106C00001300000013000000130000001300000038 +:106C10001300000013000000130000001300000028 +:106C20001300000013000000130000001300000018 +:106C30001300000013000000130000001300000008 +:106C400013000000130000001300000013000000F8 +:106C500013000000130000001300000013000000E8 +:106C600013000000130000001300000013000000D8 +:106C700013000000130000001300000013000000C8 +:106C800013000000130000001300000013000000B8 +:106C900013000000130000001300000013000000A8 +:106CA0001300000013000000130000001300000098 +:106CB0001300000013000000130000001300000088 +:106CC0001300000013000000130000001300000078 +:106CD0001300000013000000130000001300000068 +:106CE0001300000013000000130000001300000058 +:106CF0001300000013000000130000001300000048 +:106D00001300000013000000130000001300000037 +:106D10001300000013000000130000001300000027 +:106D20001300000013000000130000001300000017 +:106D30001300000013000000130000001300000007 +:106D400013000000130000001300000013000000F7 +:106D500013000000130000001300000013000000E7 +:106D600013000000130000001300000013000000D7 +:106D700013000000130000001300000013000000C7 +:106D800013000000130000001300000013000000B7 +:106D900013000000130000001300000013000000A7 +:106DA0001300000013000000130000001300000097 +:106DB0001300000013000000130000001300000087 +:106DC0001300000013000000130000001300000077 +:106DD0001300000013000000130000001300000067 +:106DE0001300000013000000130000001300000057 +:106DF0001300000013000000130000001300000047 +:106E00001300000013000000130000001300000036 +:106E10001300000013000000130000001300000026 +:106E20001300000013000000130000001300000016 +:106E30001300000013000000130000001300000006 +:106E400013000000130000001300000013000000F6 +:106E500013000000130000001300000013000000E6 +:106E600013000000130000001300000013000000D6 +:106E700013000000130000001300000013000000C6 +:106E800013000000130000001300000013000000B6 +:106E900013000000130000001300000013000000A6 +:106EA0001300000013000000130000001300000096 +:106EB0001300000013000000130000001300000086 +:106EC0001300000013000000130000001300000076 +:106ED0001300000013000000130000001300000066 +:106EE0001300000013000000130000001300000056 +:106EF0001300000013000000130000001300000046 +:106F00001300000013000000130000001300000035 +:106F10001300000013000000130000001300000025 +:106F20001300000013000000130000001300000015 +:106F30001300000013000000130000001300000005 +:106F400013000000130000001300000013000000F5 +:106F500013000000130000001300000013000000E5 +:106F600013000000130000001300000013000000D5 +:106F700013000000130000001300000013000000C5 +:106F800013000000130000001300000013000000B5 +:106F900013000000130000001300000013000000A5 +:106FA0001300000013000000130000001300000095 +:106FB0001300000013000000130000001300000085 +:106FC0001300000013000000130000001300000075 +:106FD0001300000013000000130000001300000065 +:106FE0001300000013000000130000001300000055 +:106FF0001300000013000000130000001300000045 +:10700000202122232425262728292A2B2C2D2E2F08 +:107010001300000013000000130000001300000024 +:107020001300000013000000130000001300000014 +:107030001300000013000000130000001300000004 +:1070400013000000130000001300000013000000F4 +:1070500013000000130000001300000013000000E4 +:1070600013000000130000001300000013000000D4 +:1070700013000000130000001300000013000000C4 +:1070800013000000130000001300000013000000B4 +:1070900013000000130000001300000013000000A4 +:1070A0001300000013000000130000001300000094 +:1070B0001300000013000000130000001300000084 +:1070C0001300000013000000130000001300000074 +:1070D0001300000013000000130000001300000064 +:1070E0001300000013000000130000001300000054 +:1070F0001300000013000000130000001300000044 +:107100001300000013000000130000001300000033 +:107110001300000013000000130000001300000023 +:107120001300000013000000130000001300000013 +:107130001300000013000000130000001300000003 +:1071400013000000130000001300000013000000F3 +:1071500013000000130000001300000013000000E3 +:1071600013000000130000001300000013000000D3 +:1071700013000000130000001300000013000000C3 +:1071800013000000130000001300000013000000B3 +:1071900013000000130000001300000013000000A3 +:1071A0001300000013000000130000001300000093 +:1071B0001300000013000000130000001300000083 +:1071C0001300000013000000130000001300000073 +:1071D0001300000013000000130000001300000063 +:1071E0001300000013000000130000001300000053 +:1071F0001300000013000000130000001300000043 +:107200001300000013000000130000001300000032 +:107210001300000013000000130000001300000022 +:107220001300000013000000130000001300000012 +:107230001300000013000000130000001300000002 +:1072400013000000130000001300000013000000F2 +:1072500013000000130000001300000013000000E2 +:1072600013000000130000001300000013000000D2 +:1072700013000000130000001300000013000000C2 +:1072800013000000130000001300000013000000B2 +:1072900013000000130000001300000013000000A2 +:1072A0001300000013000000130000001300000092 +:1072B0001300000013000000130000001300000082 +:1072C0001300000013000000130000001300000072 +:1072D0001300000013000000130000001300000062 +:1072E0001300000013000000130000001300000052 +:1072F0001300000013000000130000001300000042 +:107300001300000013000000130000001300000031 +:107310001300000013000000130000001300000021 +:107320001300000013000000130000001300000011 +:107330001300000013000000130000001300000001 +:1073400013000000130000001300000013000000F1 +:1073500013000000130000001300000013000000E1 +:1073600013000000130000001300000013000000D1 +:1073700013000000130000001300000013000000C1 +:1073800013000000130000001300000013000000B1 +:1073900013000000130000001300000013000000A1 +:1073A0001300000013000000130000001300000091 +:1073B0001300000013000000130000001300000081 +:1073C0001300000013000000130000001300000071 +:1073D0001300000013000000130000001300000061 +:1073E0001300000013000000130000001300000051 +:1073F0001300000013000000130000001300000041 +:107400001300000013000000130000001300000030 +:107410001300000013000000130000001300000020 +:107420001300000013000000130000001300000010 +:107430001300000013000000130000001300000000 +:1074400013000000130000001300000013000000F0 +:1074500013000000130000001300000013000000E0 +:1074600013000000130000001300000013000000D0 +:1074700013000000130000001300000013000000C0 +:1074800013000000130000001300000013000000B0 +:1074900013000000130000001300000013000000A0 +:1074A0001300000013000000130000001300000090 +:1074B0001300000013000000130000001300000080 +:1074C0001300000013000000130000001300000070 +:1074D0001300000013000000130000001300000060 +:1074E0001300000013000000130000001300000050 +:1074F0001300000013000000130000001300000040 +:10750000130000001300000013000000130000002F +:10751000130000001300000013000000130000001F +:10752000130000001300000013000000130000000F +:1075300013000000130000001300000013000000FF +:1075400013000000130000001300000013000000EF +:1075500013000000130000001300000013000000DF +:1075600013000000130000001300000013000000CF +:1075700013000000130000001300000013000000BF +:1075800013000000130000001300000013000000AF +:10759000130000001300000013000000130000009F +:1075A000130000001300000013000000130000008F +:1075B000130000001300000013000000130000007F +:1075C000130000001300000013000000130000006F +:1075D000130000001300000013000000130000005F +:1075E000130000001300000013000000130000004F +:1075F000130000001300000013000000130000003F +:10760000130000001300000013000000130000002E +:10761000130000001300000013000000130000001E +:10762000130000001300000013000000130000000E +:1076300013000000130000001300000013000000FE +:1076400013000000130000001300000013000000EE +:1076500013000000130000001300000013000000DE +:1076600013000000130000001300000013000000CE +:1076700013000000130000001300000013000000BE +:1076800013000000130000001300000013000000AE +:10769000130000001300000013000000130000009E +:1076A000130000001300000013000000130000008E +:1076B000130000001300000013000000130000007E +:1076C000130000001300000013000000130000006E +:1076D000130000001300000013000000130000005E +:1076E000130000001300000013000000130000004E +:1076F000130000001300000013000000130000003E +:10770000130000001300000013000000130000002D +:10771000130000001300000013000000130000001D +:10772000130000001300000013000000130000000D +:1077300013000000130000001300000013000000FD +:1077400013000000130000001300000013000000ED +:1077500013000000130000001300000013000000DD +:1077600013000000130000001300000013000000CD +:1077700013000000130000001300000013000000BD +:1077800013000000130000001300000013000000AD +:10779000130000001300000013000000130000009D +:1077A000130000001300000013000000130000008D +:1077B000130000001300000013000000130000007D +:1077C000130000001300000013000000130000006D +:1077D000130000001300000013000000130000005D +:1077E000130000001300000013000000130000004D +:1077F000130000001300000013000000130000003D +:10780000130000001300000013000000130000002C +:10781000130000001300000013000000130000001C +:10782000130000001300000013000000130000000C +:1078300013000000130000001300000013000000FC +:1078400013000000130000001300000013000000EC +:1078500013000000130000001300000013000000DC +:1078600013000000130000001300000013000000CC +:1078700013000000130000001300000013000000BC +:1078800013000000130000001300000013000000AC +:10789000130000001300000013000000130000009C +:1078A000130000001300000013000000130000008C +:1078B000130000001300000013000000130000007C +:1078C000130000001300000013000000130000006C +:1078D000130000001300000013000000130000005C +:1078E000130000001300000013000000130000004C +:1078F000130000001300000013000000130000003C +:10790000130000001300000013000000130000002B +:10791000130000001300000013000000130000001B +:10792000130000001300000013000000130000000B +:1079300013000000130000001300000013000000FB +:1079400013000000130000001300000013000000EB +:1079500013000000130000001300000013000000DB +:1079600013000000130000001300000013000000CB +:1079700013000000130000001300000013000000BB +:1079800013000000130000001300000013000000AB +:10799000130000001300000013000000130000009B +:1079A000130000001300000013000000130000008B +:1079B000130000001300000013000000130000007B +:1079C000130000001300000013000000130000006B +:1079D000130000001300000013000000130000005B +:1079E000130000001300000013000000130000004B +:1079F000130000001300000013000000130000003B +:107A0000130000001300000013000000130000002A +:107A1000130000001300000013000000130000001A +:107A2000130000001300000013000000130000000A +:107A300013000000130000001300000013000000FA +:107A400013000000130000001300000013000000EA +:107A500013000000130000001300000013000000DA +:107A600013000000130000001300000013000000CA +:107A700013000000130000001300000013000000BA +:107A800013000000130000001300000013000000AA +:107A9000130000001300000013000000130000009A +:107AA000130000001300000013000000130000008A +:107AB000130000001300000013000000130000007A +:107AC000130000001300000013000000130000006A +:107AD000130000001300000013000000130000005A +:107AE000130000001300000013000000130000004A +:107AF000130000001300000013000000130000003A +:107B00001300000013000000130000001300000029 +:107B10001300000013000000130000001300000019 +:107B20001300000013000000130000001300000009 +:107B300013000000130000001300000013000000F9 +:107B400013000000130000001300000013000000E9 +:107B500013000000130000001300000013000000D9 +:107B600013000000130000001300000013000000C9 +:107B700013000000130000001300000013000000B9 +:107B800013000000130000001300000013000000A9 +:107B90001300000013000000130000001300000099 +:107BA0001300000013000000130000001300000089 +:107BB0001300000013000000130000001300000079 +:107BC0001300000013000000130000001300000069 +:107BD0001300000013000000130000001300000059 +:107BE0001300000013000000130000001300000049 +:107BF0001300000013000000130000001300000039 +:107C00001300000013000000130000001300000028 +:107C10001300000013000000130000001300000018 +:107C20001300000013000000130000001300000008 +:107C300013000000130000001300000013000000F8 +:107C400013000000130000001300000013000000E8 +:107C500013000000130000001300000013000000D8 +:107C600013000000130000001300000013000000C8 +:107C700013000000130000001300000013000000B8 +:107C800013000000130000001300000013000000A8 +:107C90001300000013000000130000001300000098 +:107CA0001300000013000000130000001300000088 +:107CB0001300000013000000130000001300000078 +:107CC0001300000013000000130000001300000068 +:107CD0001300000013000000130000001300000058 +:107CE0001300000013000000130000001300000048 +:107CF0001300000013000000130000001300000038 +:107D00001300000013000000130000001300000027 +:107D10001300000013000000130000001300000017 +:107D20001300000013000000130000001300000007 +:107D300013000000130000001300000013000000F7 +:107D400013000000130000001300000013000000E7 +:107D500013000000130000001300000013000000D7 +:107D600013000000130000001300000013000000C7 +:107D700013000000130000001300000013000000B7 +:107D800013000000130000001300000013000000A7 +:107D90001300000013000000130000001300000097 +:107DA0001300000013000000130000001300000087 +:107DB0001300000013000000130000001300000077 +:107DC0001300000013000000130000001300000067 +:107DD0001300000013000000130000001300000057 +:107DE0001300000013000000130000001300000047 +:107DF0001300000013000000130000001300000037 +:107E00001300000013000000130000001300000026 +:107E10001300000013000000130000001300000016 +:107E20001300000013000000130000001300000006 +:107E300013000000130000001300000013000000F6 +:107E400013000000130000001300000013000000E6 +:107E500013000000130000001300000013000000D6 +:107E600013000000130000001300000013000000C6 +:107E700013000000130000001300000013000000B6 +:107E800013000000130000001300000013000000A6 +:107E90001300000013000000130000001300000096 +:107EA0001300000013000000130000001300000086 +:107EB0001300000013000000130000001300000076 +:107EC0001300000013000000130000001300000066 +:107ED0001300000013000000130000001300000056 +:107EE0001300000013000000130000001300000046 +:107EF0001300000013000000130000001300000036 +:107F00001300000013000000130000001300000025 +:107F10001300000013000000130000001300000015 +:107F20001300000013000000130000001300000005 +:107F300013000000130000001300000013000000F5 +:107F400013000000130000001300000013000000E5 +:107F500013000000130000001300000013000000D5 +:107F600013000000130000001300000013000000C5 +:107F700013000000130000001300000013000000B5 +:107F800013000000130000001300000013000000A5 +:107F90001300000013000000130000001300000095 +:107FA0001300000013000000130000001300000085 +:107FB0001300000013000000130000001300000075 +:107FC0001300000013000000130000001300000065 +:107FD0001300000013000000130000001300000055 +:107FE0001300000013000000130000001300000045 +:107FF0001300000013000000130000001300000035 +:10800000303132333435363738393A3B3C3D3E3FF8 +:108010001300000013000000130000001300000014 +:108020001300000013000000130000001300000004 +:1080300013000000130000001300000013000000F4 +:1080400013000000130000001300000013000000E4 +:1080500013000000130000001300000013000000D4 +:1080600013000000130000001300000013000000C4 +:1080700013000000130000001300000013000000B4 +:1080800013000000130000001300000013000000A4 +:108090001300000013000000130000001300000094 +:1080A0001300000013000000130000001300000084 +:1080B0001300000013000000130000001300000074 +:1080C0001300000013000000130000001300000064 +:1080D0001300000013000000130000001300000054 +:1080E0001300000013000000130000001300000044 +:1080F0001300000013000000130000001300000034 +:108100001300000013000000130000001300000023 +:108110001300000013000000130000001300000013 +:108120001300000013000000130000001300000003 +:1081300013000000130000001300000013000000F3 +:1081400013000000130000001300000013000000E3 +:1081500013000000130000001300000013000000D3 +:1081600013000000130000001300000013000000C3 +:1081700013000000130000001300000013000000B3 +:1081800013000000130000001300000013000000A3 +:108190001300000013000000130000001300000093 +:1081A0001300000013000000130000001300000083 +:1081B0001300000013000000130000001300000073 +:1081C0001300000013000000130000001300000063 +:1081D0001300000013000000130000001300000053 +:1081E0001300000013000000130000001300000043 +:1081F0001300000013000000130000001300000033 +:108200001300000013000000130000001300000022 +:108210001300000013000000130000001300000012 +:108220001300000013000000130000001300000002 +:1082300013000000130000001300000013000000F2 +:1082400013000000130000001300000013000000E2 +:1082500013000000130000001300000013000000D2 +:1082600013000000130000001300000013000000C2 +:1082700013000000130000001300000013000000B2 +:1082800013000000130000001300000013000000A2 +:108290001300000013000000130000001300000092 +:1082A0001300000013000000130000001300000082 +:1082B0001300000013000000130000001300000072 +:1082C0001300000013000000130000001300000062 +:1082D0001300000013000000130000001300000052 +:1082E0001300000013000000130000001300000042 +:1082F0001300000013000000130000001300000032 +:108300001300000013000000130000001300000021 +:108310001300000013000000130000001300000011 +:108320001300000013000000130000001300000001 +:1083300013000000130000001300000013000000F1 +:1083400013000000130000001300000013000000E1 +:1083500013000000130000001300000013000000D1 +:1083600013000000130000001300000013000000C1 +:1083700013000000130000001300000013000000B1 +:1083800013000000130000001300000013000000A1 +:108390001300000013000000130000001300000091 +:1083A0001300000013000000130000001300000081 +:1083B0001300000013000000130000001300000071 +:1083C0001300000013000000130000001300000061 +:1083D0001300000013000000130000001300000051 +:1083E0001300000013000000130000001300000041 +:1083F0001300000013000000130000001300000031 +:108400001300000013000000130000001300000020 +:108410001300000013000000130000001300000010 +:108420001300000013000000130000001300000000 +:1084300013000000130000001300000013000000F0 +:1084400013000000130000001300000013000000E0 +:1084500013000000130000001300000013000000D0 +:1084600013000000130000001300000013000000C0 +:1084700013000000130000001300000013000000B0 +:1084800013000000130000001300000013000000A0 +:108490001300000013000000130000001300000090 +:1084A0001300000013000000130000001300000080 +:1084B0001300000013000000130000001300000070 +:1084C0001300000013000000130000001300000060 +:1084D0001300000013000000130000001300000050 +:1084E0001300000013000000130000001300000040 +:1084F0001300000013000000130000001300000030 +:10850000130000001300000013000000130000001F +:10851000130000001300000013000000130000000F +:1085200013000000130000001300000013000000FF +:1085300013000000130000001300000013000000EF +:1085400013000000130000001300000013000000DF +:1085500013000000130000001300000013000000CF +:1085600013000000130000001300000013000000BF +:1085700013000000130000001300000013000000AF +:10858000130000001300000013000000130000009F +:10859000130000001300000013000000130000008F +:1085A000130000001300000013000000130000007F +:1085B000130000001300000013000000130000006F +:1085C000130000001300000013000000130000005F +:1085D000130000001300000013000000130000004F +:1085E000130000001300000013000000130000003F +:1085F000130000001300000013000000130000002F +:10860000130000001300000013000000130000001E +:10861000130000001300000013000000130000000E +:1086200013000000130000001300000013000000FE +:1086300013000000130000001300000013000000EE +:1086400013000000130000001300000013000000DE +:1086500013000000130000001300000013000000CE +:1086600013000000130000001300000013000000BE +:1086700013000000130000001300000013000000AE +:10868000130000001300000013000000130000009E +:10869000130000001300000013000000130000008E +:1086A000130000001300000013000000130000007E +:1086B000130000001300000013000000130000006E +:1086C000130000001300000013000000130000005E +:1086D000130000001300000013000000130000004E +:1086E000130000001300000013000000130000003E +:1086F000130000001300000013000000130000002E +:10870000130000001300000013000000130000001D +:10871000130000001300000013000000130000000D +:1087200013000000130000001300000013000000FD +:1087300013000000130000001300000013000000ED +:1087400013000000130000001300000013000000DD +:1087500013000000130000001300000013000000CD +:1087600013000000130000001300000013000000BD +:1087700013000000130000001300000013000000AD +:10878000130000001300000013000000130000009D +:10879000130000001300000013000000130000008D +:1087A000130000001300000013000000130000007D +:1087B000130000001300000013000000130000006D +:1087C000130000001300000013000000130000005D +:1087D000130000001300000013000000130000004D +:1087E000130000001300000013000000130000003D +:1087F000130000001300000013000000130000002D +:10880000130000001300000013000000130000001C +:10881000130000001300000013000000130000000C +:1088200013000000130000001300000013000000FC +:1088300013000000130000001300000013000000EC +:1088400013000000130000001300000013000000DC +:1088500013000000130000001300000013000000CC +:1088600013000000130000001300000013000000BC +:1088700013000000130000001300000013000000AC +:10888000130000001300000013000000130000009C +:10889000130000001300000013000000130000008C +:1088A000130000001300000013000000130000007C +:1088B000130000001300000013000000130000006C +:1088C000130000001300000013000000130000005C +:1088D000130000001300000013000000130000004C +:1088E000130000001300000013000000130000003C +:1088F000130000001300000013000000130000002C +:10890000130000001300000013000000130000001B +:10891000130000001300000013000000130000000B +:1089200013000000130000001300000013000000FB +:1089300013000000130000001300000013000000EB +:1089400013000000130000001300000013000000DB +:1089500013000000130000001300000013000000CB +:1089600013000000130000001300000013000000BB +:1089700013000000130000001300000013000000AB +:10898000130000001300000013000000130000009B +:10899000130000001300000013000000130000008B +:1089A000130000001300000013000000130000007B +:1089B000130000001300000013000000130000006B +:1089C000130000001300000013000000130000005B +:1089D000130000001300000013000000130000004B +:1089E000130000001300000013000000130000003B +:1089F000130000001300000013000000130000002B +:108A0000130000001300000013000000130000001A +:108A1000130000001300000013000000130000000A +:108A200013000000130000001300000013000000FA +:108A300013000000130000001300000013000000EA +:108A400013000000130000001300000013000000DA +:108A500013000000130000001300000013000000CA +:108A600013000000130000001300000013000000BA +:108A700013000000130000001300000013000000AA +:108A8000130000001300000013000000130000009A +:108A9000130000001300000013000000130000008A +:108AA000130000001300000013000000130000007A +:108AB000130000001300000013000000130000006A +:108AC000130000001300000013000000130000005A +:108AD000130000001300000013000000130000004A +:108AE000130000001300000013000000130000003A +:108AF000130000001300000013000000130000002A +:108B00001300000013000000130000001300000019 +:108B10001300000013000000130000001300000009 +:108B200013000000130000001300000013000000F9 +:108B300013000000130000001300000013000000E9 +:108B400013000000130000001300000013000000D9 +:108B500013000000130000001300000013000000C9 +:108B600013000000130000001300000013000000B9 +:108B700013000000130000001300000013000000A9 +:108B80001300000013000000130000001300000099 +:108B90001300000013000000130000001300000089 +:108BA0001300000013000000130000001300000079 +:108BB0001300000013000000130000001300000069 +:108BC0001300000013000000130000001300000059 +:108BD0001300000013000000130000001300000049 +:108BE0001300000013000000130000001300000039 +:108BF0001300000013000000130000001300000029 +:108C00001300000013000000130000001300000018 +:108C10001300000013000000130000001300000008 +:108C200013000000130000001300000013000000F8 +:108C300013000000130000001300000013000000E8 +:108C400013000000130000001300000013000000D8 +:108C500013000000130000001300000013000000C8 +:108C600013000000130000001300000013000000B8 +:108C700013000000130000001300000013000000A8 +:108C80001300000013000000130000001300000098 +:108C90001300000013000000130000001300000088 +:108CA0001300000013000000130000001300000078 +:108CB0001300000013000000130000001300000068 +:108CC0001300000013000000130000001300000058 +:108CD0001300000013000000130000001300000048 +:108CE0001300000013000000130000001300000038 +:108CF0001300000013000000130000001300000028 +:108D00001300000013000000130000001300000017 +:108D10001300000013000000130000001300000007 +:108D200013000000130000001300000013000000F7 +:108D300013000000130000001300000013000000E7 +:108D400013000000130000001300000013000000D7 +:108D500013000000130000001300000013000000C7 +:108D600013000000130000001300000013000000B7 +:108D700013000000130000001300000013000000A7 +:108D80001300000013000000130000001300000097 +:108D90001300000013000000130000001300000087 +:108DA0001300000013000000130000001300000077 +:108DB0001300000013000000130000001300000067 +:108DC0001300000013000000130000001300000057 +:108DD0001300000013000000130000001300000047 +:108DE0001300000013000000130000001300000037 +:108DF0001300000013000000130000001300000027 +:108E00001300000013000000130000001300000016 +:108E10001300000013000000130000001300000006 +:108E200013000000130000001300000013000000F6 +:108E300013000000130000001300000013000000E6 +:108E400013000000130000001300000013000000D6 +:108E500013000000130000001300000013000000C6 +:108E600013000000130000001300000013000000B6 +:108E700013000000130000001300000013000000A6 +:108E80001300000013000000130000001300000096 +:108E90001300000013000000130000001300000086 +:108EA0001300000013000000130000001300000076 +:108EB0001300000013000000130000001300000066 +:108EC0001300000013000000130000001300000056 +:108ED0001300000013000000130000001300000046 +:108EE0001300000013000000130000001300000036 +:108EF0001300000013000000130000001300000026 +:108F00001300000013000000130000001300000015 +:108F10001300000013000000130000001300000005 +:108F200013000000130000001300000013000000F5 +:108F300013000000130000001300000013000000E5 +:108F400013000000130000001300000013000000D5 +:108F500013000000130000001300000013000000C5 +:108F600013000000130000001300000013000000B5 +:108F700013000000130000001300000013000000A5 +:108F80001300000013000000130000001300000095 +:108F90001300000013000000130000001300000085 +:108FA0001300000013000000130000001300000075 +:108FB0001300000013000000130000001300000065 +:108FC0001300000013000000130000001300000055 +:108FD0001300000013000000130000001300000045 +:108FE0001300000013000000130000001300000035 +:108FF0001300000013000000130000001300000025 +:10900000404142434445464748494A4B4C4D4E4FE8 +:109010001300000013000000130000001300000004 +:1090200013000000130000001300000013000000F4 +:1090300013000000130000001300000013000000E4 +:1090400013000000130000001300000013000000D4 +:1090500013000000130000001300000013000000C4 +:1090600013000000130000001300000013000000B4 +:1090700013000000130000001300000013000000A4 +:109080001300000013000000130000001300000094 +:109090001300000013000000130000001300000084 +:1090A0001300000013000000130000001300000074 +:1090B0001300000013000000130000001300000064 +:1090C0001300000013000000130000001300000054 +:1090D0001300000013000000130000001300000044 +:1090E0001300000013000000130000001300000034 +:1090F0001300000013000000130000001300000024 +:109100001300000013000000130000001300000013 +:109110001300000013000000130000001300000003 +:1091200013000000130000001300000013000000F3 +:1091300013000000130000001300000013000000E3 +:1091400013000000130000001300000013000000D3 +:1091500013000000130000001300000013000000C3 +:1091600013000000130000001300000013000000B3 +:1091700013000000130000001300000013000000A3 +:109180001300000013000000130000001300000093 +:109190001300000013000000130000001300000083 +:1091A0001300000013000000130000001300000073 +:1091B0001300000013000000130000001300000063 +:1091C0001300000013000000130000001300000053 +:1091D0001300000013000000130000001300000043 +:1091E0001300000013000000130000001300000033 +:1091F0001300000013000000130000001300000023 +:109200001300000013000000130000001300000012 +:109210001300000013000000130000001300000002 +:1092200013000000130000001300000013000000F2 +:1092300013000000130000001300000013000000E2 +:1092400013000000130000001300000013000000D2 +:1092500013000000130000001300000013000000C2 +:1092600013000000130000001300000013000000B2 +:1092700013000000130000001300000013000000A2 +:109280001300000013000000130000001300000092 +:109290001300000013000000130000001300000082 +:1092A0001300000013000000130000001300000072 +:1092B0001300000013000000130000001300000062 +:1092C0001300000013000000130000001300000052 +:1092D0001300000013000000130000001300000042 +:1092E0001300000013000000130000001300000032 +:1092F0001300000013000000130000001300000022 +:109300001300000013000000130000001300000011 +:109310001300000013000000130000001300000001 +:1093200013000000130000001300000013000000F1 +:1093300013000000130000001300000013000000E1 +:1093400013000000130000001300000013000000D1 +:1093500013000000130000001300000013000000C1 +:1093600013000000130000001300000013000000B1 +:1093700013000000130000001300000013000000A1 +:109380001300000013000000130000001300000091 +:109390001300000013000000130000001300000081 +:1093A0001300000013000000130000001300000071 +:1093B0001300000013000000130000001300000061 +:1093C0001300000013000000130000001300000051 +:1093D0001300000013000000130000001300000041 +:1093E0001300000013000000130000001300000031 +:1093F0001300000013000000130000001300000021 +:109400001300000013000000130000001300000010 +:109410001300000013000000130000001300000000 +:1094200013000000130000001300000013000000F0 +:1094300013000000130000001300000013000000E0 +:1094400013000000130000001300000013000000D0 +:1094500013000000130000001300000013000000C0 +:1094600013000000130000001300000013000000B0 +:1094700013000000130000001300000013000000A0 +:109480001300000013000000130000001300000090 +:109490001300000013000000130000001300000080 +:1094A0001300000013000000130000001300000070 +:1094B0001300000013000000130000001300000060 +:1094C0001300000013000000130000001300000050 +:1094D0001300000013000000130000001300000040 +:1094E0001300000013000000130000001300000030 +:1094F0001300000013000000130000001300000020 +:10950000130000001300000013000000130000000F +:1095100013000000130000001300000013000000FF +:1095200013000000130000001300000013000000EF +:1095300013000000130000001300000013000000DF +:1095400013000000130000001300000013000000CF +:1095500013000000130000001300000013000000BF +:1095600013000000130000001300000013000000AF +:10957000130000001300000013000000130000009F +:10958000130000001300000013000000130000008F +:10959000130000001300000013000000130000007F +:1095A000130000001300000013000000130000006F +:1095B000130000001300000013000000130000005F +:1095C000130000001300000013000000130000004F +:1095D000130000001300000013000000130000003F +:1095E000130000001300000013000000130000002F +:1095F000130000001300000013000000130000001F +:10960000130000001300000013000000130000000E +:1096100013000000130000001300000013000000FE +:1096200013000000130000001300000013000000EE +:1096300013000000130000001300000013000000DE +:1096400013000000130000001300000013000000CE +:1096500013000000130000001300000013000000BE +:1096600013000000130000001300000013000000AE +:10967000130000001300000013000000130000009E +:10968000130000001300000013000000130000008E +:10969000130000001300000013000000130000007E +:1096A000130000001300000013000000130000006E +:1096B000130000001300000013000000130000005E +:1096C000130000001300000013000000130000004E +:1096D000130000001300000013000000130000003E +:1096E000130000001300000013000000130000002E +:1096F000130000001300000013000000130000001E +:10970000130000001300000013000000130000000D +:1097100013000000130000001300000013000000FD +:1097200013000000130000001300000013000000ED +:1097300013000000130000001300000013000000DD +:1097400013000000130000001300000013000000CD +:1097500013000000130000001300000013000000BD +:1097600013000000130000001300000013000000AD +:10977000130000001300000013000000130000009D +:10978000130000001300000013000000130000008D +:10979000130000001300000013000000130000007D +:1097A000130000001300000013000000130000006D +:1097B000130000001300000013000000130000005D +:1097C000130000001300000013000000130000004D +:1097D000130000001300000013000000130000003D +:1097E000130000001300000013000000130000002D +:1097F000130000001300000013000000130000001D +:10980000130000001300000013000000130000000C +:1098100013000000130000001300000013000000FC +:1098200013000000130000001300000013000000EC +:1098300013000000130000001300000013000000DC +:1098400013000000130000001300000013000000CC +:1098500013000000130000001300000013000000BC +:1098600013000000130000001300000013000000AC +:10987000130000001300000013000000130000009C +:10988000130000001300000013000000130000008C +:10989000130000001300000013000000130000007C +:1098A000130000001300000013000000130000006C +:1098B000130000001300000013000000130000005C +:1098C000130000001300000013000000130000004C +:1098D000130000001300000013000000130000003C +:1098E000130000001300000013000000130000002C +:1098F000130000001300000013000000130000001C +:10990000130000001300000013000000130000000B +:1099100013000000130000001300000013000000FB +:1099200013000000130000001300000013000000EB +:1099300013000000130000001300000013000000DB +:1099400013000000130000001300000013000000CB +:1099500013000000130000001300000013000000BB +:1099600013000000130000001300000013000000AB +:10997000130000001300000013000000130000009B +:10998000130000001300000013000000130000008B +:10999000130000001300000013000000130000007B +:1099A000130000001300000013000000130000006B +:1099B000130000001300000013000000130000005B +:1099C000130000001300000013000000130000004B +:1099D000130000001300000013000000130000003B +:1099E000130000001300000013000000130000002B +:1099F000130000001300000013000000130000001B +:109A0000130000001300000013000000130000000A +:109A100013000000130000001300000013000000FA +:109A200013000000130000001300000013000000EA +:109A300013000000130000001300000013000000DA +:109A400013000000130000001300000013000000CA +:109A500013000000130000001300000013000000BA +:109A600013000000130000001300000013000000AA +:109A7000130000001300000013000000130000009A +:109A8000130000001300000013000000130000008A +:109A9000130000001300000013000000130000007A +:109AA000130000001300000013000000130000006A +:109AB000130000001300000013000000130000005A +:109AC000130000001300000013000000130000004A +:109AD000130000001300000013000000130000003A +:109AE000130000001300000013000000130000002A +:109AF000130000001300000013000000130000001A +:109B00001300000013000000130000001300000009 +:109B100013000000130000001300000013000000F9 +:109B200013000000130000001300000013000000E9 +:109B300013000000130000001300000013000000D9 +:109B400013000000130000001300000013000000C9 +:109B500013000000130000001300000013000000B9 +:109B600013000000130000001300000013000000A9 +:109B70001300000013000000130000001300000099 +:109B80001300000013000000130000001300000089 +:109B90001300000013000000130000001300000079 +:109BA0001300000013000000130000001300000069 +:109BB0001300000013000000130000001300000059 +:109BC0001300000013000000130000001300000049 +:109BD0001300000013000000130000001300000039 +:109BE0001300000013000000130000001300000029 +:109BF0001300000013000000130000001300000019 +:109C00001300000013000000130000001300000008 +:109C100013000000130000001300000013000000F8 +:109C200013000000130000001300000013000000E8 +:109C300013000000130000001300000013000000D8 +:109C400013000000130000001300000013000000C8 +:109C500013000000130000001300000013000000B8 +:109C600013000000130000001300000013000000A8 +:109C70001300000013000000130000001300000098 +:109C80001300000013000000130000001300000088 +:109C90001300000013000000130000001300000078 +:109CA0001300000013000000130000001300000068 +:109CB0001300000013000000130000001300000058 +:109CC0001300000013000000130000001300000048 +:109CD0001300000013000000130000001300000038 +:109CE0001300000013000000130000001300000028 +:109CF0001300000013000000130000001300000018 +:109D00001300000013000000130000001300000007 +:109D100013000000130000001300000013000000F7 +:109D200013000000130000001300000013000000E7 +:109D300013000000130000001300000013000000D7 +:109D400013000000130000001300000013000000C7 +:109D500013000000130000001300000013000000B7 +:109D600013000000130000001300000013000000A7 +:109D70001300000013000000130000001300000097 +:109D80001300000013000000130000001300000087 +:109D90001300000013000000130000001300000077 +:109DA0001300000013000000130000001300000067 +:109DB0001300000013000000130000001300000057 +:109DC0001300000013000000130000001300000047 +:109DD0001300000013000000130000001300000037 +:109DE0001300000013000000130000001300000027 +:109DF0001300000013000000130000001300000017 +:109E00001300000013000000130000001300000006 +:109E100013000000130000001300000013000000F6 +:109E200013000000130000001300000013000000E6 +:109E300013000000130000001300000013000000D6 +:109E400013000000130000001300000013000000C6 +:109E500013000000130000001300000013000000B6 +:109E600013000000130000001300000013000000A6 +:109E70001300000013000000130000001300000096 +:109E80001300000013000000130000001300000086 +:109E90001300000013000000130000001300000076 +:109EA0001300000013000000130000001300000066 +:109EB0001300000013000000130000001300000056 +:109EC0001300000013000000130000001300000046 +:109ED0001300000013000000130000001300000036 +:109EE0001300000013000000130000001300000026 +:109EF0001300000013000000130000001300000016 +:109F00001300000013000000130000001300000005 +:109F100013000000130000001300000013000000F5 +:109F200013000000130000001300000013000000E5 +:109F300013000000130000001300000013000000D5 +:109F400013000000130000001300000013000000C5 +:109F500013000000130000001300000013000000B5 +:109F600013000000130000001300000013000000A5 +:109F70001300000013000000130000001300000095 +:109F80001300000013000000130000001300000085 +:109F90001300000013000000130000001300000075 +:109FA0001300000013000000130000001300000065 +:109FB0001300000013000000130000001300000055 +:109FC0001300000013000000130000001300000045 +:109FD0001300000013000000130000001300000035 +:109FE0001300000013000000130000001300000025 +:109FF0001300000013000000130000001300000015 +:10A00000505152535455565758595A5B5C5D5E5FD8 +:10A010006780000013000000130000001300000020 +:10A0200013000000130000001300000013000000E4 +:10A0300013000000130000001300000013000000D4 +:10A0400013000000130000001300000013000000C4 +:10A0500013000000130000001300000013000000B4 +:10A0600013000000130000001300000013000000A4 +:10A070001300000013000000130000001300000094 +:10A080001300000013000000130000001300000084 +:10A090001300000013000000130000001300000074 +:10A0A0001300000013000000130000001300000064 +:10A0B0001300000013000000130000001300000054 +:10A0C0001300000013000000130000001300000044 +:10A0D0001300000013000000130000001300000034 +:10A0E0001300000013000000130000001300000024 +:10A0F0001300000013000000130000001300000014 +:10A100001300000013000000130000001300000003 +:10A1100013000000130000001300000013000000F3 +:10A1200013000000130000001300000013000000E3 +:10A1300013000000130000001300000013000000D3 +:10A1400013000000130000001300000013000000C3 +:10A1500013000000130000001300000013000000B3 +:10A1600013000000130000001300000013000000A3 +:10A170001300000013000000130000001300000093 +:10A180001300000013000000130000001300000083 +:10A190001300000013000000130000001300000073 +:10A1A0001300000013000000130000001300000063 +:10A1B0001300000013000000130000001300000053 +:10A1C0001300000013000000130000001300000043 +:10A1D0001300000013000000130000001300000033 +:10A1E0001300000013000000130000001300000023 +:10A1F0001300000013000000130000001300000013 +:10A200001300000013000000130000001300000002 +:10A2100013000000130000001300000013000000F2 +:10A2200013000000130000001300000013000000E2 +:10A2300013000000130000001300000013000000D2 +:10A2400013000000130000001300000013000000C2 +:10A2500013000000130000001300000013000000B2 +:10A2600013000000130000001300000013000000A2 +:10A270001300000013000000130000001300000092 +:10A280001300000013000000130000001300000082 +:10A290001300000013000000130000001300000072 +:10A2A0001300000013000000130000001300000062 +:10A2B0001300000013000000130000001300000052 +:10A2C0001300000013000000130000001300000042 +:10A2D0001300000013000000130000001300000032 +:10A2E0001300000013000000130000001300000022 +:10A2F0001300000013000000130000001300000012 +:10A300001300000013000000130000001300000001 +:10A3100013000000130000001300000013000000F1 +:10A3200013000000130000001300000013000000E1 +:10A3300013000000130000001300000013000000D1 +:10A3400013000000130000001300000013000000C1 +:10A3500013000000130000001300000013000000B1 +:10A3600013000000130000001300000013000000A1 +:10A370001300000013000000130000001300000091 +:10A380001300000013000000130000001300000081 +:10A390001300000013000000130000001300000071 +:10A3A0001300000013000000130000001300000061 +:10A3B0001300000013000000130000001300000051 +:10A3C0001300000013000000130000001300000041 +:10A3D0001300000013000000130000001300000031 +:10A3E0001300000013000000130000001300000021 +:10A3F0001300000013000000130000001300000011 +:10A400001300000013000000130000001300000000 +:10A4100013000000130000001300000013000000F0 +:10A4200013000000130000001300000013000000E0 +:10A4300013000000130000001300000013000000D0 +:10A4400013000000130000001300000013000000C0 +:10A4500013000000130000001300000013000000B0 +:10A4600013000000130000001300000013000000A0 +:10A470001300000013000000130000001300000090 +:10A480001300000013000000130000001300000080 +:10A490001300000013000000130000001300000070 +:10A4A0001300000013000000130000001300000060 +:10A4B0001300000013000000130000001300000050 +:10A4C0001300000013000000130000001300000040 +:10A4D0001300000013000000130000001300000030 +:10A4E0001300000013000000130000001300000020 +:10A4F0001300000013000000130000001300000010 +:10A5000013000000130000001300000013000000FF +:10A5100013000000130000001300000013000000EF +:10A5200013000000130000001300000013000000DF +:10A5300013000000130000001300000013000000CF +:10A5400013000000130000001300000013000000BF +:10A5500013000000130000001300000013000000AF +:10A56000130000001300000013000000130000009F +:10A57000130000001300000013000000130000008F +:10A58000130000001300000013000000130000007F +:10A59000130000001300000013000000130000006F +:10A5A000130000001300000013000000130000005F +:10A5B000130000001300000013000000130000004F +:10A5C000130000001300000013000000130000003F +:10A5D000130000001300000013000000130000002F +:10A5E000130000001300000013000000130000001F +:10A5F000130000001300000013000000130000000F +:10A6000013000000130000001300000013000000FE +:10A6100013000000130000001300000013000000EE +:10A6200013000000130000001300000013000000DE +:10A6300013000000130000001300000013000000CE +:10A6400013000000130000001300000013000000BE +:10A6500013000000130000001300000013000000AE +:10A66000130000001300000013000000130000009E +:10A67000130000001300000013000000130000008E +:10A68000130000001300000013000000130000007E +:10A69000130000001300000013000000130000006E +:10A6A000130000001300000013000000130000005E +:10A6B000130000001300000013000000130000004E +:10A6C000130000001300000013000000130000003E +:10A6D000130000001300000013000000130000002E +:10A6E000130000001300000013000000130000001E +:10A6F000130000001300000013000000130000000E +:10A7000013000000130000001300000013000000FD +:10A7100013000000130000001300000013000000ED +:10A7200013000000130000001300000013000000DD +:10A7300013000000130000001300000013000000CD +:10A7400013000000130000001300000013000000BD +:10A7500013000000130000001300000013000000AD +:10A76000130000001300000013000000130000009D +:10A77000130000001300000013000000130000008D +:10A78000130000001300000013000000130000007D +:10A79000130000001300000013000000130000006D +:10A7A000130000001300000013000000130000005D +:10A7B000130000001300000013000000130000004D +:10A7C000130000001300000013000000130000003D +:10A7D000130000001300000013000000130000002D +:10A7E000130000001300000013000000130000001D +:10A7F000130000001300000013000000130000000D +:10A8000013000000130000001300000013000000FC +:10A8100013000000130000001300000013000000EC +:10A8200013000000130000001300000013000000DC +:10A8300013000000130000001300000013000000CC +:10A8400013000000130000001300000013000000BC +:10A8500013000000130000001300000013000000AC +:10A86000130000001300000013000000130000009C +:10A87000130000001300000013000000130000008C +:10A88000130000001300000013000000130000007C +:10A89000130000001300000013000000130000006C +:10A8A000130000001300000013000000130000005C +:10A8B000130000001300000013000000130000004C +:10A8C000130000001300000013000000130000003C +:10A8D000130000001300000013000000130000002C +:10A8E000130000001300000013000000130000001C +:10A8F000130000001300000013000000130000000C +:10A9000013000000130000001300000013000000FB +:10A9100013000000130000001300000013000000EB +:10A9200013000000130000001300000013000000DB +:10A9300013000000130000001300000013000000CB +:10A9400013000000130000001300000013000000BB +:10A9500013000000130000001300000013000000AB +:10A96000130000001300000013000000130000009B +:10A97000130000001300000013000000130000008B +:10A98000130000001300000013000000130000007B +:10A99000130000001300000013000000130000006B +:10A9A000130000001300000013000000130000005B +:10A9B000130000001300000013000000130000004B +:10A9C000130000001300000013000000130000003B +:10A9D000130000001300000013000000130000002B +:10A9E000130000001300000013000000130000001B +:10A9F000130000001300000013000000130000000B +:10AA000013000000130000001300000013000000FA +:10AA100013000000130000001300000013000000EA +:10AA200013000000130000001300000013000000DA +:10AA300013000000130000001300000013000000CA +:10AA400013000000130000001300000013000000BA +:10AA500013000000130000001300000013000000AA +:10AA6000130000001300000013000000130000009A +:10AA7000130000001300000013000000130000008A +:10AA8000130000001300000013000000130000007A +:10AA9000130000001300000013000000130000006A +:10AAA000130000001300000013000000130000005A +:10AAB000130000001300000013000000130000004A +:10AAC000130000001300000013000000130000003A +:10AAD000130000001300000013000000130000002A +:10AAE000130000001300000013000000130000001A +:10AAF000130000001300000013000000130000000A +:10AB000013000000130000001300000013000000F9 +:10AB100013000000130000001300000013000000E9 +:10AB200013000000130000001300000013000000D9 +:10AB300013000000130000001300000013000000C9 +:10AB400013000000130000001300000013000000B9 +:10AB500013000000130000001300000013000000A9 +:10AB60001300000013000000130000001300000099 +:10AB70001300000013000000130000001300000089 +:10AB80001300000013000000130000001300000079 +:10AB90001300000013000000130000001300000069 +:10ABA0001300000013000000130000001300000059 +:10ABB0001300000013000000130000001300000049 +:10ABC0001300000013000000130000001300000039 +:10ABD0001300000013000000130000001300000029 +:10ABE0001300000013000000130000001300000019 +:10ABF0001300000013000000130000001300000009 +:10AC000013000000130000001300000013000000F8 +:10AC100013000000130000001300000013000000E8 +:10AC200013000000130000001300000013000000D8 +:10AC300013000000130000001300000013000000C8 +:10AC400013000000130000001300000013000000B8 +:10AC500013000000130000001300000013000000A8 +:10AC60001300000013000000130000001300000098 +:10AC70001300000013000000130000001300000088 +:10AC80001300000013000000130000001300000078 +:10AC90001300000013000000130000001300000068 +:10ACA0001300000013000000130000001300000058 +:10ACB0001300000013000000130000001300000048 +:10ACC0001300000013000000130000001300000038 +:10ACD0001300000013000000130000001300000028 +:10ACE0001300000013000000130000001300000018 +:10ACF0001300000013000000130000001300000008 +:10AD000013000000130000001300000013000000F7 +:10AD100013000000130000001300000013000000E7 +:10AD200013000000130000001300000013000000D7 +:10AD300013000000130000001300000013000000C7 +:10AD400013000000130000001300000013000000B7 +:10AD500013000000130000001300000013000000A7 +:10AD60001300000013000000130000001300000097 +:10AD70001300000013000000130000001300000087 +:10AD80001300000013000000130000001300000077 +:10AD90001300000013000000130000001300000067 +:10ADA0001300000013000000130000001300000057 +:10ADB0001300000013000000130000001300000047 +:10ADC0001300000013000000130000001300000037 +:10ADD0001300000013000000130000001300000027 +:10ADE0001300000013000000130000001300000017 +:10ADF0001300000013000000130000001300000007 +:10AE000013000000130000001300000013000000F6 +:10AE100013000000130000001300000013000000E6 +:10AE200013000000130000001300000013000000D6 +:10AE300013000000130000001300000013000000C6 +:10AE400013000000130000001300000013000000B6 +:10AE500013000000130000001300000013000000A6 +:10AE60001300000013000000130000001300000096 +:10AE70001300000013000000130000001300000086 +:10AE80001300000013000000130000001300000076 +:10AE90001300000013000000130000001300000066 +:10AEA0001300000013000000130000001300000056 +:10AEB0001300000013000000130000001300000046 +:10AEC0001300000013000000130000001300000036 +:10AED0001300000013000000130000001300000026 +:10AEE0001300000013000000130000001300000016 +:10AEF0001300000013000000130000001300000006 +:10AF000013000000130000001300000013000000F5 +:10AF100013000000130000001300000013000000E5 +:10AF200013000000130000001300000013000000D5 +:10AF300013000000130000001300000013000000C5 +:10AF400013000000130000001300000013000000B5 +:10AF500013000000130000001300000013000000A5 +:10AF60001300000013000000130000001300000095 +:10AF70001300000013000000130000001300000085 +:10AF80001300000013000000130000001300000075 +:10AF90001300000013000000130000001300000065 +:10AFA0001300000013000000130000001300000055 +:10AFB0001300000013000000130000001300000045 +:10AFC0001300000013000000130000001300000035 +:10AFD0001300000013000000130000001300000025 +:10AFE0001300000013000000130000001300000015 +:10AFF0001300000013000000130000001300000005 +:10B00000606162636465666768696A6B6C6D6E6FC8 +:10B0100013000000130000001300000013000000E4 +:10B0200013000000130000001300000013000000D4 +:10B0300013000000130000001300000013000000C4 +:10B0400013000000130000001300000013000000B4 +:10B0500013000000130000001300000013000000A4 +:10B060001300000013000000130000001300000094 +:10B070001300000013000000130000001300000084 +:10B080001300000013000000130000001300000074 +:10B090001300000013000000130000001300000064 +:10B0A0001300000013000000130000001300000054 +:10B0B0001300000013000000130000001300000044 +:10B0C0001300000013000000130000001300000034 +:10B0D0001300000013000000130000001300000024 +:10B0E0001300000013000000130000001300000014 +:10B0F0001300000013000000130000001300000004 +:10B1000013000000130000001300000013000000F3 +:10B1100013000000130000001300000013000000E3 +:10B1200013000000130000001300000013000000D3 +:10B1300013000000130000001300000013000000C3 +:10B1400013000000130000001300000013000000B3 +:10B1500013000000130000001300000013000000A3 +:10B160001300000013000000130000001300000093 +:10B170001300000013000000130000001300000083 +:10B180001300000013000000130000001300000073 +:10B190001300000013000000130000001300000063 +:10B1A0001300000013000000130000001300000053 +:10B1B0001300000013000000130000001300000043 +:10B1C0001300000013000000130000001300000033 +:10B1D0001300000013000000130000001300000023 +:10B1E0001300000013000000130000001300000013 +:10B1F0001300000013000000130000001300000003 +:10B2000013000000130000001300000013000000F2 +:10B2100013000000130000001300000013000000E2 +:10B2200013000000130000001300000013000000D2 +:10B2300013000000130000001300000013000000C2 +:10B2400013000000130000001300000013000000B2 +:10B2500013000000130000001300000013000000A2 +:10B260001300000013000000130000001300000092 +:10B270001300000013000000130000001300000082 +:10B280001300000013000000130000001300000072 +:10B290001300000013000000130000001300000062 +:10B2A0001300000013000000130000001300000052 +:10B2B0001300000013000000130000001300000042 +:10B2C0001300000013000000130000001300000032 +:10B2D0001300000013000000130000001300000022 +:10B2E0001300000013000000130000001300000012 +:10B2F0001300000013000000130000001300000002 +:10B3000013000000130000001300000013000000F1 +:10B3100013000000130000001300000013000000E1 +:10B3200013000000130000001300000013000000D1 +:10B3300013000000130000001300000013000000C1 +:10B3400013000000130000001300000013000000B1 +:10B3500013000000130000001300000013000000A1 +:10B360001300000013000000130000001300000091 +:10B370001300000013000000130000001300000081 +:10B380001300000013000000130000001300000071 +:10B390001300000013000000130000001300000061 +:10B3A0001300000013000000130000001300000051 +:10B3B0001300000013000000130000001300000041 +:10B3C0001300000013000000130000001300000031 +:10B3D0001300000013000000130000001300000021 +:10B3E0001300000013000000130000001300000011 +:10B3F0001300000013000000130000001300000001 +:10B4000013000000130000001300000013000000F0 +:10B4100013000000130000001300000013000000E0 +:10B4200013000000130000001300000013000000D0 +:10B4300013000000130000001300000013000000C0 +:10B4400013000000130000001300000013000000B0 +:10B4500013000000130000001300000013000000A0 +:10B460001300000013000000130000001300000090 +:10B470001300000013000000130000001300000080 +:10B480001300000013000000130000001300000070 +:10B490001300000013000000130000001300000060 +:10B4A0001300000013000000130000001300000050 +:10B4B0001300000013000000130000001300000040 +:10B4C0001300000013000000130000001300000030 +:10B4D0001300000013000000130000001300000020 +:10B4E0001300000013000000130000001300000010 +:10B4F0001300000013000000130000001300000000 +:10B5000013000000130000001300000013000000EF +:10B5100013000000130000001300000013000000DF +:10B5200013000000130000001300000013000000CF +:10B5300013000000130000001300000013000000BF +:10B5400013000000130000001300000013000000AF +:10B55000130000001300000013000000130000009F +:10B56000130000001300000013000000130000008F +:10B57000130000001300000013000000130000007F +:10B58000130000001300000013000000130000006F +:10B59000130000001300000013000000130000005F +:10B5A000130000001300000013000000130000004F +:10B5B000130000001300000013000000130000003F +:10B5C000130000001300000013000000130000002F +:10B5D000130000001300000013000000130000001F +:10B5E000130000001300000013000000130000000F +:10B5F00013000000130000001300000013000000FF +:10B6000013000000130000001300000013000000EE +:10B6100013000000130000001300000013000000DE +:10B6200013000000130000001300000013000000CE +:10B6300013000000130000001300000013000000BE +:10B6400013000000130000001300000013000000AE +:10B65000130000001300000013000000130000009E +:10B66000130000001300000013000000130000008E +:10B67000130000001300000013000000130000007E +:10B68000130000001300000013000000130000006E +:10B69000130000001300000013000000130000005E +:10B6A000130000001300000013000000130000004E +:10B6B000130000001300000013000000130000003E +:10B6C000130000001300000013000000130000002E +:10B6D000130000001300000013000000130000001E +:10B6E000130000001300000013000000130000000E +:10B6F00013000000130000001300000013000000FE +:10B7000013000000130000001300000013000000ED +:10B7100013000000130000001300000013000000DD +:10B7200013000000130000001300000013000000CD +:10B7300013000000130000001300000013000000BD +:10B7400013000000130000001300000013000000AD +:10B75000130000001300000013000000130000009D +:10B76000130000001300000013000000130000008D +:10B77000130000001300000013000000130000007D +:10B78000130000001300000013000000130000006D +:10B79000130000001300000013000000130000005D +:10B7A000130000001300000013000000130000004D +:10B7B000130000001300000013000000130000003D +:10B7C000130000001300000013000000130000002D +:10B7D000130000001300000013000000130000001D +:10B7E000130000001300000013000000130000000D +:10B7F00013000000130000001300000013000000FD +:10B8000013000000130000001300000013000000EC +:10B8100013000000130000001300000013000000DC +:10B8200013000000130000001300000013000000CC +:10B8300013000000130000001300000013000000BC +:10B8400013000000130000001300000013000000AC +:10B85000130000001300000013000000130000009C +:10B86000130000001300000013000000130000008C +:10B87000130000001300000013000000130000007C +:10B88000130000001300000013000000130000006C +:10B89000130000001300000013000000130000005C +:10B8A000130000001300000013000000130000004C +:10B8B000130000001300000013000000130000003C +:10B8C000130000001300000013000000130000002C +:10B8D000130000001300000013000000130000001C +:10B8E000130000001300000013000000130000000C +:10B8F00013000000130000001300000013000000FC +:10B9000013000000130000001300000013000000EB +:10B9100013000000130000001300000013000000DB +:10B9200013000000130000001300000013000000CB +:10B9300013000000130000001300000013000000BB +:10B9400013000000130000001300000013000000AB +:10B95000130000001300000013000000130000009B +:10B96000130000001300000013000000130000008B +:10B97000130000001300000013000000130000007B +:10B98000130000001300000013000000130000006B +:10B99000130000001300000013000000130000005B +:10B9A000130000001300000013000000130000004B +:10B9B000130000001300000013000000130000003B +:10B9C000130000001300000013000000130000002B +:10B9D000130000001300000013000000130000001B +:10B9E000130000001300000013000000130000000B +:10B9F00013000000130000001300000013000000FB +:10BA000013000000130000001300000013000000EA +:10BA100013000000130000001300000013000000DA +:10BA200013000000130000001300000013000000CA +:10BA300013000000130000001300000013000000BA +:10BA400013000000130000001300000013000000AA +:10BA5000130000001300000013000000130000009A +:10BA6000130000001300000013000000130000008A +:10BA7000130000001300000013000000130000007A +:10BA8000130000001300000013000000130000006A +:10BA9000130000001300000013000000130000005A +:10BAA000130000001300000013000000130000004A +:10BAB000130000001300000013000000130000003A +:10BAC000130000001300000013000000130000002A +:10BAD000130000001300000013000000130000001A +:10BAE000130000001300000013000000130000000A +:10BAF00013000000130000001300000013000000FA +:10BB000013000000130000001300000013000000E9 +:10BB100013000000130000001300000013000000D9 +:10BB200013000000130000001300000013000000C9 +:10BB300013000000130000001300000013000000B9 +:10BB400013000000130000001300000013000000A9 +:10BB50001300000013000000130000001300000099 +:10BB60001300000013000000130000001300000089 +:10BB70001300000013000000130000001300000079 +:10BB80001300000013000000130000001300000069 +:10BB90001300000013000000130000001300000059 +:10BBA0001300000013000000130000001300000049 +:10BBB0001300000013000000130000001300000039 +:10BBC0001300000013000000130000001300000029 +:10BBD0001300000013000000130000001300000019 +:10BBE0001300000013000000130000001300000009 +:10BBF00013000000130000001300000013000000F9 +:10BC000013000000130000001300000013000000E8 +:10BC100013000000130000001300000013000000D8 +:10BC200013000000130000001300000013000000C8 +:10BC300013000000130000001300000013000000B8 +:10BC400013000000130000001300000013000000A8 +:10BC50001300000013000000130000001300000098 +:10BC60001300000013000000130000001300000088 +:10BC70001300000013000000130000001300000078 +:10BC80001300000013000000130000001300000068 +:10BC90001300000013000000130000001300000058 +:10BCA0001300000013000000130000001300000048 +:10BCB0001300000013000000130000001300000038 +:10BCC0001300000013000000130000001300000028 +:10BCD0001300000013000000130000001300000018 +:10BCE0001300000013000000130000001300000008 +:10BCF00013000000130000001300000013000000F8 +:10BD000013000000130000001300000013000000E7 +:10BD100013000000130000001300000013000000D7 +:10BD200013000000130000001300000013000000C7 +:10BD300013000000130000001300000013000000B7 +:10BD400013000000130000001300000013000000A7 +:10BD50001300000013000000130000001300000097 +:10BD60001300000013000000130000001300000087 +:10BD70001300000013000000130000001300000077 +:10BD80001300000013000000130000001300000067 +:10BD90001300000013000000130000001300000057 +:10BDA0001300000013000000130000001300000047 +:10BDB0001300000013000000130000001300000037 +:10BDC0001300000013000000130000001300000027 +:10BDD0001300000013000000130000001300000017 +:10BDE0001300000013000000130000001300000007 +:10BDF00013000000130000001300000013000000F7 +:10BE000013000000130000001300000013000000E6 +:10BE100013000000130000001300000013000000D6 +:10BE200013000000130000001300000013000000C6 +:10BE300013000000130000001300000013000000B6 +:10BE400013000000130000001300000013000000A6 +:10BE50001300000013000000130000001300000096 +:10BE60001300000013000000130000001300000086 +:10BE70001300000013000000130000001300000076 +:10BE80001300000013000000130000001300000066 +:10BE90001300000013000000130000001300000056 +:10BEA0001300000013000000130000001300000046 +:10BEB0001300000013000000130000001300000036 +:10BEC0001300000013000000130000001300000026 +:10BED0001300000013000000130000001300000016 +:10BEE0001300000013000000130000001300000006 +:10BEF00013000000130000001300000013000000F6 +:10BF000013000000130000001300000013000000E5 +:10BF100013000000130000001300000013000000D5 +:10BF200013000000130000001300000013000000C5 +:10BF300013000000130000001300000013000000B5 +:10BF400013000000130000001300000013000000A5 +:10BF50001300000013000000130000001300000095 +:10BF60001300000013000000130000001300000085 +:10BF70001300000013000000130000001300000075 +:10BF80001300000013000000130000001300000065 +:10BF90001300000013000000130000001300000055 +:10BFA0001300000013000000130000001300000045 +:10BFB0001300000013000000130000001300000035 +:10BFC0001300000013000000130000001300000025 +:10BFD0001300000013000000130000001300000015 +:10BFE0001300000013000000130000001300000005 +:10BFF00013000000130000001300000013000000F5 +:10C00000707172737475767778797A7B7C7D7E7FB8 +:10C0100013000000130000001300000013000000D4 +:10C0200013000000130000001300000013000000C4 +:10C0300013000000130000001300000013000000B4 +:10C0400013000000130000001300000013000000A4 +:10C050001300000013000000130000001300000094 +:10C060001300000013000000130000001300000084 +:10C070001300000013000000130000001300000074 +:10C080001300000013000000130000001300000064 +:10C090001300000013000000130000001300000054 +:10C0A0001300000013000000130000001300000044 +:10C0B0001300000013000000130000001300000034 +:10C0C0001300000013000000130000001300000024 +:10C0D0001300000013000000130000001300000014 +:10C0E0001300000013000000130000001300000004 +:10C0F00013000000130000001300000013000000F4 +:10C1000013000000130000001300000013000000E3 +:10C1100013000000130000001300000013000000D3 +:10C1200013000000130000001300000013000000C3 +:10C1300013000000130000001300000013000000B3 +:10C1400013000000130000001300000013000000A3 +:10C150001300000013000000130000001300000093 +:10C160001300000013000000130000001300000083 +:10C170001300000013000000130000001300000073 +:10C180001300000013000000130000001300000063 +:10C190001300000013000000130000001300000053 +:10C1A0001300000013000000130000001300000043 +:10C1B0001300000013000000130000001300000033 +:10C1C0001300000013000000130000001300000023 +:10C1D0001300000013000000130000001300000013 +:10C1E0001300000013000000130000001300000003 +:10C1F00013000000130000001300000013000000F3 +:10C2000013000000130000001300000013000000E2 +:10C2100013000000130000001300000013000000D2 +:10C2200013000000130000001300000013000000C2 +:10C2300013000000130000001300000013000000B2 +:10C2400013000000130000001300000013000000A2 +:10C250001300000013000000130000001300000092 +:10C260001300000013000000130000001300000082 +:10C270001300000013000000130000001300000072 +:10C280001300000013000000130000001300000062 +:10C290001300000013000000130000001300000052 +:10C2A0001300000013000000130000001300000042 +:10C2B0001300000013000000130000001300000032 +:10C2C0001300000013000000130000001300000022 +:10C2D0001300000013000000130000001300000012 +:10C2E0001300000013000000130000001300000002 +:10C2F00013000000130000001300000013000000F2 +:10C3000013000000130000001300000013000000E1 +:10C3100013000000130000001300000013000000D1 +:10C3200013000000130000001300000013000000C1 +:10C3300013000000130000001300000013000000B1 +:10C3400013000000130000001300000013000000A1 +:10C350001300000013000000130000001300000091 +:10C360001300000013000000130000001300000081 +:10C370001300000013000000130000001300000071 +:10C380001300000013000000130000001300000061 +:10C390001300000013000000130000001300000051 +:10C3A0001300000013000000130000001300000041 +:10C3B0001300000013000000130000001300000031 +:10C3C0001300000013000000130000001300000021 +:10C3D0001300000013000000130000001300000011 +:10C3E0001300000013000000130000001300000001 +:10C3F00013000000130000001300000013000000F1 +:10C4000013000000130000001300000013000000E0 +:10C4100013000000130000001300000013000000D0 +:10C4200013000000130000001300000013000000C0 +:10C4300013000000130000001300000013000000B0 +:10C4400013000000130000001300000013000000A0 +:10C450001300000013000000130000001300000090 +:10C460001300000013000000130000001300000080 +:10C470001300000013000000130000001300000070 +:10C480001300000013000000130000001300000060 +:10C490001300000013000000130000001300000050 +:10C4A0001300000013000000130000001300000040 +:10C4B0001300000013000000130000001300000030 +:10C4C0001300000013000000130000001300000020 +:10C4D0001300000013000000130000001300000010 +:10C4E0001300000013000000130000001300000000 +:10C4F00013000000130000001300000013000000F0 +:10C5000013000000130000001300000013000000DF +:10C5100013000000130000001300000013000000CF +:10C5200013000000130000001300000013000000BF +:10C5300013000000130000001300000013000000AF +:10C54000130000001300000013000000130000009F +:10C55000130000001300000013000000130000008F +:10C56000130000001300000013000000130000007F +:10C57000130000001300000013000000130000006F +:10C58000130000001300000013000000130000005F +:10C59000130000001300000013000000130000004F +:10C5A000130000001300000013000000130000003F +:10C5B000130000001300000013000000130000002F +:10C5C000130000001300000013000000130000001F +:10C5D000130000001300000013000000130000000F +:10C5E00013000000130000001300000013000000FF +:10C5F00013000000130000001300000013000000EF +:10C6000013000000130000001300000013000000DE +:10C6100013000000130000001300000013000000CE +:10C6200013000000130000001300000013000000BE +:10C6300013000000130000001300000013000000AE +:10C64000130000001300000013000000130000009E +:10C65000130000001300000013000000130000008E +:10C66000130000001300000013000000130000007E +:10C67000130000001300000013000000130000006E +:10C68000130000001300000013000000130000005E +:10C69000130000001300000013000000130000004E +:10C6A000130000001300000013000000130000003E +:10C6B000130000001300000013000000130000002E +:10C6C000130000001300000013000000130000001E +:10C6D000130000001300000013000000130000000E +:10C6E00013000000130000001300000013000000FE +:10C6F00013000000130000001300000013000000EE +:10C7000013000000130000001300000013000000DD +:10C7100013000000130000001300000013000000CD +:10C7200013000000130000001300000013000000BD +:10C7300013000000130000001300000013000000AD +:10C74000130000001300000013000000130000009D +:10C75000130000001300000013000000130000008D +:10C76000130000001300000013000000130000007D +:10C77000130000001300000013000000130000006D +:10C78000130000001300000013000000130000005D +:10C79000130000001300000013000000130000004D +:10C7A000130000001300000013000000130000003D +:10C7B000130000001300000013000000130000002D +:10C7C000130000001300000013000000130000001D +:10C7D000130000001300000013000000130000000D +:10C7E00013000000130000001300000013000000FD +:10C7F00013000000130000001300000013000000ED +:10C8000013000000130000001300000013000000DC +:10C8100013000000130000001300000013000000CC +:10C8200013000000130000001300000013000000BC +:10C8300013000000130000001300000013000000AC +:10C84000130000001300000013000000130000009C +:10C85000130000001300000013000000130000008C +:10C86000130000001300000013000000130000007C +:10C87000130000001300000013000000130000006C +:10C88000130000001300000013000000130000005C +:10C89000130000001300000013000000130000004C +:10C8A000130000001300000013000000130000003C +:10C8B000130000001300000013000000130000002C +:10C8C000130000001300000013000000130000001C +:10C8D000130000001300000013000000130000000C +:10C8E00013000000130000001300000013000000FC +:10C8F00013000000130000001300000013000000EC +:10C9000013000000130000001300000013000000DB +:10C9100013000000130000001300000013000000CB +:10C9200013000000130000001300000013000000BB +:10C9300013000000130000001300000013000000AB +:10C94000130000001300000013000000130000009B +:10C95000130000001300000013000000130000008B +:10C96000130000001300000013000000130000007B +:10C97000130000001300000013000000130000006B +:10C98000130000001300000013000000130000005B +:10C99000130000001300000013000000130000004B +:10C9A000130000001300000013000000130000003B +:10C9B000130000001300000013000000130000002B +:10C9C000130000001300000013000000130000001B +:10C9D000130000001300000013000000130000000B +:10C9E00013000000130000001300000013000000FB +:10C9F00013000000130000001300000013000000EB +:10CA000013000000130000001300000013000000DA +:10CA100013000000130000001300000013000000CA +:10CA200013000000130000001300000013000000BA +:10CA300013000000130000001300000013000000AA +:10CA4000130000001300000013000000130000009A +:10CA5000130000001300000013000000130000008A +:10CA6000130000001300000013000000130000007A +:10CA7000130000001300000013000000130000006A +:10CA8000130000001300000013000000130000005A +:10CA9000130000001300000013000000130000004A +:10CAA000130000001300000013000000130000003A +:10CAB000130000001300000013000000130000002A +:10CAC000130000001300000013000000130000001A +:10CAD000130000001300000013000000130000000A +:10CAE00013000000130000001300000013000000FA +:10CAF00013000000130000001300000013000000EA +:10CB000013000000130000001300000013000000D9 +:10CB100013000000130000001300000013000000C9 +:10CB200013000000130000001300000013000000B9 +:10CB300013000000130000001300000013000000A9 +:10CB40001300000013000000130000001300000099 +:10CB50001300000013000000130000001300000089 +:10CB60001300000013000000130000001300000079 +:10CB70001300000013000000130000001300000069 +:10CB80001300000013000000130000001300000059 +:10CB90001300000013000000130000001300000049 +:10CBA0001300000013000000130000001300000039 +:10CBB0001300000013000000130000001300000029 +:10CBC0001300000013000000130000001300000019 +:10CBD0001300000013000000130000001300000009 +:10CBE00013000000130000001300000013000000F9 +:10CBF00013000000130000001300000013000000E9 +:10CC000013000000130000001300000013000000D8 +:10CC100013000000130000001300000013000000C8 +:10CC200013000000130000001300000013000000B8 +:10CC300013000000130000001300000013000000A8 +:10CC40001300000013000000130000001300000098 +:10CC50001300000013000000130000001300000088 +:10CC60001300000013000000130000001300000078 +:10CC70001300000013000000130000001300000068 +:10CC80001300000013000000130000001300000058 +:10CC90001300000013000000130000001300000048 +:10CCA0001300000013000000130000001300000038 +:10CCB0001300000013000000130000001300000028 +:10CCC0001300000013000000130000001300000018 +:10CCD0001300000013000000130000001300000008 +:10CCE00013000000130000001300000013000000F8 +:10CCF00013000000130000001300000013000000E8 +:10CD000013000000130000001300000013000000D7 +:10CD100013000000130000001300000013000000C7 +:10CD200013000000130000001300000013000000B7 +:10CD300013000000130000001300000013000000A7 +:10CD40001300000013000000130000001300000097 +:10CD50001300000013000000130000001300000087 +:10CD60001300000013000000130000001300000077 +:10CD70001300000013000000130000001300000067 +:10CD80001300000013000000130000001300000057 +:10CD90001300000013000000130000001300000047 +:10CDA0001300000013000000130000001300000037 +:10CDB0001300000013000000130000001300000027 +:10CDC0001300000013000000130000001300000017 +:10CDD0001300000013000000130000001300000007 +:10CDE00013000000130000001300000013000000F7 +:10CDF00013000000130000001300000013000000E7 +:10CE000013000000130000001300000013000000D6 +:10CE100013000000130000001300000013000000C6 +:10CE200013000000130000001300000013000000B6 +:10CE300013000000130000001300000013000000A6 +:10CE40001300000013000000130000001300000096 +:10CE50001300000013000000130000001300000086 +:10CE60001300000013000000130000001300000076 +:10CE70001300000013000000130000001300000066 +:10CE80001300000013000000130000001300000056 +:10CE90001300000013000000130000001300000046 +:10CEA0001300000013000000130000001300000036 +:10CEB0001300000013000000130000001300000026 +:10CEC0001300000013000000130000001300000016 +:10CED0001300000013000000130000001300000006 +:10CEE00013000000130000001300000013000000F6 +:10CEF00013000000130000001300000013000000E6 +:10CF000013000000130000001300000013000000D5 +:10CF100013000000130000001300000013000000C5 +:10CF200013000000130000001300000013000000B5 +:10CF300013000000130000001300000013000000A5 +:10CF40001300000013000000130000001300000095 +:10CF50001300000013000000130000001300000085 +:10CF60001300000013000000130000001300000075 +:10CF70001300000013000000130000001300000065 +:10CF80001300000013000000130000001300000055 +:10CF90001300000013000000130000001300000045 +:10CFA0001300000013000000130000001300000035 +:10CFB0001300000013000000130000001300000025 +:10CFC0001300000013000000130000001300000015 +:10CFD0001300000013000000130000001300000005 +:10CFE00013000000130000001300000013000000F5 +:10CFF00013000000130000001300000013000000E5 +:10D00000130E3003B71001909380800037615A5B94 +:10D010001301819583A00000638420006F304FCA04 +:10D02000B7A000A0938040323701EEAA130181001F +:10D0300023A0200083A00000638420006F304FC82D +:10D04000130E400397000000938080013721019068 +:10D0500013010101670001006F308FC6130E5003EA +:10D06000930E1000170F0000130F8F01B7400190AF +:10D0700093800039678000006F308FC4130E600307 +:10D08000930E1000170F0000130F8F01B74001908F +:10D090009380403983A000006F308FC2130E70035D +:10D0A000930E1000170F0000130F8F01B74001906F +:10D0B0009380803923A010006F308FC0930E200022 +:10D0C00073000000000000000000000000000000ED +:10D0D0000000000000000000000000000000000050 +:10D0E0000000000000000000000000000000000040 +:10D0F0000000000000000000000000000000000030 +:10D10000000000000000000000000000000000001F +:10D11000000000000000000000000000000000000F +:10D1200000000000000000000000000000000000FF +:10D1300000000000000000000000000000000000EF +:10D1400000000000000000000000000000000000DF +:10D1500000000000000000000000000000000000CF +:10D1600000000000000000000000000000000000BF +:10D1700000000000000000000000000000000000AF +:10D18000000000000000000000000000000000009F +:10D19000000000000000000000000000000000008F +:10D1A000000000000000000000000000000000007F +:10D1B000000000000000000000000000000000006F +:10D1C000000000000000000000000000000000005F +:10D1D000000000000000000000000000000000004F +:10D1E000000000000000000000000000000000003F +:10D1F000000000000000000000000000000000002F +:10D20000000000000000000000000000000000001E +:10D21000000000000000000000000000000000000E +:10D2200000000000000000000000000000000000FE +:10D2300000000000000000000000000000000000EE +:10D2400000000000000000000000000000000000DE +:10D2500000000000000000000000000000000000CE +:10D2600000000000000000000000000000000000BE +:10D2700000000000000000000000000000000000AE +:10D28000000000000000000000000000000000009E +:10D29000000000000000000000000000000000008E +:10D2A000000000000000000000000000000000007E +:10D2B000000000000000000000000000000000006E +:10D2C000000000000000000000000000000000005E +:10D2D000000000000000000000000000000000004E +:10D2E000000000000000000000000000000000003E +:10D2F000000000000000000000000000000000002E +:10D30000000000000000000000000000000000001D +:10D31000000000000000000000000000000000000D +:10D3200000000000000000000000000000000000FD +:10D3300000000000000000000000000000000000ED +:10D3400000000000000000000000000000000000DD +:10D3500000000000000000000000000000000000CD +:10D3600000000000000000000000000000000000BD +:10D3700000000000000000000000000000000000AD +:10D38000000000000000000000000000000000009D +:10D39000000000000000000000000000000000008D +:10D3A000000000000000000000000000000000007D +:10D3B000000000000000000000000000000000006D +:10D3C000000000000000000000000000000000005D +:10D3D000000000000000000000000000000000004D +:10D3E000000000000000000000000000000000003D +:10D3F000000000000000000000000000000000002D +:10D40000000000000000000000000000000000001C +:10D41000000000000000000000000000000000000C +:10D4200000000000000000000000000000000000FC +:10D4300000000000000000000000000000000000EC +:10D4400000000000000000000000000000000000DC +:10D4500000000000000000000000000000000000CC +:10D4600000000000000000000000000000000000BC +:10D4700000000000000000000000000000000000AC +:10D48000000000000000000000000000000000009C +:10D49000000000000000000000000000000000008C +:10D4A000000000000000000000000000000000007C +:10D4B000000000000000000000000000000000006C +:10D4C000000000000000000000000000000000005C +:10D4D000000000000000000000000000000000004C +:10D4E000000000000000000000000000000000003C +:10D4F000000000000000000000000000000000002C +:10D50000000000000000000000000000000000001B +:10D51000000000000000000000000000000000000B +:10D5200000000000000000000000000000000000FB +:10D5300000000000000000000000000000000000EB +:10D5400000000000000000000000000000000000DB +:10D5500000000000000000000000000000000000CB +:10D5600000000000000000000000000000000000BB +:10D5700000000000000000000000000000000000AB +:10D58000000000000000000000000000000000009B +:10D59000000000000000000000000000000000008B +:10D5A000000000000000000000000000000000007B +:10D5B000000000000000000000000000000000006B +:10D5C000000000000000000000000000000000005B +:10D5D000000000000000000000000000000000004B +:10D5E000000000000000000000000000000000003B +:10D5F000000000000000000000000000000000002B +:10D60000000000000000000000000000000000001A +:10D61000000000000000000000000000000000000A +:10D6200000000000000000000000000000000000FA +:10D6300000000000000000000000000000000000EA +:10D6400000000000000000000000000000000000DA +:10D6500000000000000000000000000000000000CA +:10D6600000000000000000000000000000000000BA +:10D6700000000000000000000000000000000000AA +:10D68000000000000000000000000000000000009A +:10D69000000000000000000000000000000000008A +:10D6A000000000000000000000000000000000007A +:10D6B000000000000000000000000000000000006A +:10D6C000000000000000000000000000000000005A +:10D6D000000000000000000000000000000000004A +:10D6E000000000000000000000000000000000003A +:10D6F000000000000000000000000000000000002A +:10D700000000000000000000000000000000000019 +:10D710000000000000000000000000000000000009 +:10D7200000000000000000000000000000000000F9 +:10D7300000000000000000000000000000000000E9 +:10D7400000000000000000000000000000000000D9 +:10D7500000000000000000000000000000000000C9 +:10D7600000000000000000000000000000000000B9 +:10D7700000000000000000000000000000000000A9 +:10D780000000000000000000000000000000000099 +:10D790000000000000000000000000000000000089 +:10D7A0000000000000000000000000000000000079 +:10D7B0000000000000000000000000000000000069 +:10D7C0000000000000000000000000000000000059 +:10D7D0000000000000000000000000000000000049 +:10D7E0000000000000000000000000000000000039 +:10D7F0000000000000000000000000000000000029 +:10D800000000000000000000000000000000000018 +:10D810000000000000000000000000000000000008 +:10D8200000000000000000000000000000000000F8 +:10D8300000000000000000000000000000000000E8 +:10D8400000000000000000000000000000000000D8 +:10D8500000000000000000000000000000000000C8 +:10D8600000000000000000000000000000000000B8 +:10D8700000000000000000000000000000000000A8 +:10D880000000000000000000000000000000000098 +:10D890000000000000000000000000000000000088 +:10D8A0000000000000000000000000000000000078 +:10D8B0000000000000000000000000000000000068 +:10D8C0000000000000000000000000000000000058 +:10D8D0000000000000000000000000000000000048 +:10D8E0000000000000000000000000000000000038 +:10D8F0000000000000000000000000000000000028 +:10D900000000000000000000000000000000000017 +:10D910000000000000000000000000000000000007 +:10D9200000000000000000000000000000000000F7 +:10D9300000000000000000000000000000000000E7 +:10D9400000000000000000000000000000000000D7 +:10D9500000000000000000000000000000000000C7 +:10D9600000000000000000000000000000000000B7 +:10D9700000000000000000000000000000000000A7 +:10D980000000000000000000000000000000000097 +:10D990000000000000000000000000000000000087 +:10D9A0000000000000000000000000000000000077 +:10D9B0000000000000000000000000000000000067 +:10D9C0000000000000000000000000000000000057 +:10D9D0000000000000000000000000000000000047 +:10D9E0000000000000000000000000000000000037 +:10D9F0000000000000000000000000000000000027 +:10DA00000000000000000000000000000000000016 +:10DA10000000000000000000000000000000000006 +:10DA200000000000000000000000000000000000F6 +:10DA300000000000000000000000000000000000E6 +:10DA400000000000000000000000000000000000D6 +:10DA500000000000000000000000000000000000C6 +:040000058000000077 :00000001FF From c5689e512c0df76581b09aa87273d2643abbe675 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 23 Feb 2023 12:00:25 +0100 Subject: [PATCH 845/951] CsrPlugin now provide regression args --- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index d936edc5..a53363ce 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -439,7 +439,7 @@ trait IWake{ def askWake() : Unit } -class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with ExceptionService with PrivilegeService with InterruptionInhibitor with ExceptionInhibitor with IContextSwitching with CsrInterface with IWake{ +class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with ExceptionService with PrivilegeService with InterruptionInhibitor with ExceptionInhibitor with IContextSwitching with CsrInterface with IWake with VexRiscvRegressionArg { import config._ import CsrAccess._ @@ -456,6 +456,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep } + override def getVexRiscvRegressionArgs() = List(s"SUPERVISOR=${if(config.supervisorGen) "yes" else "no"}, CSR=yes") var exceptionPendings : Vec[Bool] = null override def isExceptionPending(stage : Stage): Bool = exceptionPendings(pipeline.stages.indexOf(stage)) From d7e9c726c36c66caf0f6bc4c15ffc659f27c237f Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 23 Feb 2023 14:42:21 +0100 Subject: [PATCH 846/951] Fix datacache initial flush --- src/main/scala/vexriscv/ip/DataCache.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index b4b04f70..a2e43aa2 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -855,7 +855,7 @@ class DataCache(val p : DataCacheConfig, mmuParameter : MemoryTranslatorBusParam io.cpu.execute.haltIt := True when(!hold) { counter := counter + 1 - when(io.cpu.flush.singleLine){ + when(io.cpu.flush.valid && io.cpu.flush.singleLine){ counter.msb := True } } @@ -869,7 +869,7 @@ class DataCache(val p : DataCacheConfig, mmuParameter : MemoryTranslatorBusParam when(start){ waitDone := True counter := 0 - when(io.cpu.flush.singleLine){ + when(io.cpu.flush.valid && io.cpu.flush.singleLine){ counter := U"0" @@ io.cpu.flush.lineId } } From 6f76a45e7d6bbde294e0f96fc665831dd4888e38 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 23 Feb 2023 15:54:39 +0100 Subject: [PATCH 847/951] update mmu test --- src/test/cpp/raw/mmu/build/mmu.asm | 1773 ++++++++++++++++++++++------ src/test/cpp/raw/mmu/build/mmu.hex | 734 ++++++++---- 2 files changed, 1902 insertions(+), 605 deletions(-) diff --git a/src/test/cpp/raw/mmu/build/mmu.asm b/src/test/cpp/raw/mmu/build/mmu.asm index 9bbf17fd..b39cf209 100644 --- a/src/test/cpp/raw/mmu/build/mmu.asm +++ b/src/test/cpp/raw/mmu/build/mmu.asm @@ -7,7 +7,7 @@ Disassembly of section .crt_section: 80000000 <_start>: 80000000: 00000e93 li t4,0 80000004: 00000097 auipc ra,0x0 -80000008: 59008093 addi ra,ra,1424 # 80000594 +80000008: 4fc08093 addi ra,ra,1276 # 80000500 8000000c: 30509073 csrw mtvec,ra 80000010 : @@ -17,7 +17,7 @@ Disassembly of section .crt_section: 8000001c: 27262137 lui sp,0x27262 80000020: 52410113 addi sp,sp,1316 # 27262524 <_start-0x58d9dadc> 80000024: 0040a083 lw ra,4(ra) -80000028: 54209263 bne ra,sp,8000056c +80000028: 48209c63 bne ra,sp,800004c0 8000002c : 8000002c: 00200e13 li t3,2 @@ -28,7 +28,7 @@ Disassembly of section .crt_section: 80000040: 80008093 addi ra,ra,-2048 # 1800 <_start-0x7fffe800> 80000044: 30009073 csrw mstatus,ra 80000048: 30200073 mret -8000004c: 5200006f j 8000056c +8000004c: 4740006f j 800004c0 80000050 : 80000050: 00300e13 li t3,3 @@ -39,7 +39,7 @@ Disassembly of section .crt_section: 80000064: 01408093 addi ra,ra,20 # 80000074 80000068: 34109073 csrw mepc,ra 8000006c: 30200073 mret -80000070: 4fc0006f j 8000056c +80000070: 4500006f j 800004c0 80000074 : 80000074: 00400e13 li t3,4 @@ -48,7 +48,7 @@ Disassembly of section .crt_section: 80000080: 37363137 lui sp,0x37363 80000084: 53410113 addi sp,sp,1332 # 37363534 <_start-0x48c9cacc> 80000088: 0040a083 lw ra,4(ra) -8000008c: 4e209063 bne ra,sp,8000056c +8000008c: 42209a63 bne ra,sp,800004c0 80000090 : 80000090: 00500e13 li t3,5 @@ -57,13 +57,13 @@ Disassembly of section .crt_section: 8000009c: 00002117 auipc sp,0x2 800000a0: f6410113 addi sp,sp,-156 # 80002000 800000a4: 00215113 srli sp,sp,0x2 -800000a8: 01116113 ori sp,sp,17 +800000a8: 00116113 ori sp,sp,1 800000ac: 0020a023 sw sp,0(ra) 800000b0: 00002097 auipc ra,0x2 800000b4: f5008093 addi ra,ra,-176 # 80002000 800000b8: 80000137 lui sp,0x80000 800000bc: 00215113 srli sp,sp,0x2 -800000c0: 00f16113 ori sp,sp,15 +800000c0: 0cf16113 ori sp,sp,207 800000c4: 0020a023 sw sp,0(ra) 800000c8: 00500e13 li t3,5 800000cc: 00002097 auipc ra,0x2 @@ -71,49 +71,49 @@ Disassembly of section .crt_section: 800000d4: 00003117 auipc sp,0x3 800000d8: f2c10113 addi sp,sp,-212 # 80003000 800000dc: 00215113 srli sp,sp,0x2 -800000e0: 01116113 ori sp,sp,17 +800000e0: 00116113 ori sp,sp,1 800000e4: 0020a023 sw sp,0(ra) 800000e8: 00003097 auipc ra,0x3 800000ec: f4008093 addi ra,ra,-192 # 80003028 800000f0: 00009117 auipc sp,0x9 800000f4: f1010113 addi sp,sp,-240 # 80009000 800000f8: 00215113 srli sp,sp,0x2 -800000fc: 01f16113 ori sp,sp,31 +800000fc: 0df16113 ori sp,sp,223 80000100: 0020a023 sw sp,0(ra) 80000104: 00003097 auipc ra,0x3 80000108: f3c08093 addi ra,ra,-196 # 80003040 8000010c: 0000a117 auipc sp,0xa 80000110: ef410113 addi sp,sp,-268 # 8000a000 80000114: 00215113 srli sp,sp,0x2 -80000118: 01316113 ori sp,sp,19 +80000118: 0d316113 ori sp,sp,211 8000011c: 0020a023 sw sp,0(ra) 80000120: 00003097 auipc ra,0x3 80000124: f2408093 addi ra,ra,-220 # 80003044 80000128: 0000a117 auipc sp,0xa 8000012c: ed810113 addi sp,sp,-296 # 8000a000 80000130: 00215113 srli sp,sp,0x2 -80000134: 01716113 ori sp,sp,23 +80000134: 0d716113 ori sp,sp,215 80000138: 0020a023 sw sp,0(ra) 8000013c: 00003097 auipc ra,0x3 80000140: f0c08093 addi ra,ra,-244 # 80003048 80000144: 0000a117 auipc sp,0xa 80000148: ebc10113 addi sp,sp,-324 # 8000a000 8000014c: 00215113 srli sp,sp,0x2 -80000150: 01916113 ori sp,sp,25 +80000150: 0d916113 ori sp,sp,217 80000154: 0020a023 sw sp,0(ra) 80000158: 00003097 auipc ra,0x3 8000015c: ef408093 addi ra,ra,-268 # 8000304c 80000160: 0000a117 auipc sp,0xa 80000164: ea010113 addi sp,sp,-352 # 8000a000 80000168: 00215113 srli sp,sp,0x2 -8000016c: 01b16113 ori sp,sp,27 +8000016c: 0db16113 ori sp,sp,219 80000170: 0020a023 sw sp,0(ra) 80000174: 00003097 auipc ra,0x3 80000178: edc08093 addi ra,ra,-292 # 80003050 8000017c: 0000a117 auipc sp,0xa 80000180: e8410113 addi sp,sp,-380 # 8000a000 80000184: 00215113 srli sp,sp,0x2 -80000188: 00f16113 ori sp,sp,15 +80000188: 0cf16113 ori sp,sp,207 8000018c: 0020a023 sw sp,0(ra) 80000190: 00500e13 li t3,5 80000194: 00002097 auipc ra,0x2 @@ -121,7 +121,7 @@ Disassembly of section .crt_section: 8000019c: 00000117 auipc sp,0x0 800001a0: e6410113 addi sp,sp,-412 # 80000000 <_start> 800001a4: 00215113 srli sp,sp,0x2 -800001a8: 01f16113 ori sp,sp,31 +800001a8: 0df16113 ori sp,sp,223 800001ac: 0020a023 sw sp,0(ra) 800001b0: 00500e13 li t3,5 800001b4: 00002097 auipc ra,0x2 @@ -134,313 +134,301 @@ Disassembly of section .crt_section: 800001d0: 00c0d093 srli ra,ra,0xc 800001d4: 80000137 lui sp,0x80000 800001d8: 0020e0b3 or ra,ra,sp -800001dc: 18009073 csrw satp,ra +800001dc: 12000073 sfence.vma +800001e0: 18009073 csrw satp,ra +800001e4: 0000100f fence.i -800001e0 : -800001e0: 00600e13 li t3,6 -800001e4: 9000a0b7 lui ra,0x9000a -800001e8: 00808093 addi ra,ra,8 # 9000a008 -800001ec: 4b4a5137 lui sp,0x4b4a5 -800001f0: 94810113 addi sp,sp,-1720 # 4b4a4948 <_start-0x34b5b6b8> -800001f4: 0000a083 lw ra,0(ra) -800001f8: 36209a63 bne ra,sp,8000056c +800001e8 : +800001e8: 00600e13 li t3,6 +800001ec: 9000a0b7 lui ra,0x9000a +800001f0: 00808093 addi ra,ra,8 # 9000a008 +800001f4: 4b4a5137 lui sp,0x4b4a5 +800001f8: 94810113 addi sp,sp,-1720 # 4b4a4948 <_start-0x34b5b6b8> +800001fc: 0000a083 lw ra,0(ra) +80000200: 2c209063 bne ra,sp,800004c0 -800001fc : -800001fc: 00700e13 li t3,7 -80000200: 9000a0b7 lui ra,0x9000a -80000204: 36008093 addi ra,ra,864 # 9000a360 -80000208: aaee0137 lui sp,0xaaee0 -8000020c: 00110113 addi sp,sp,1 # aaee0001 -80000210: 0020a023 sw sp,0(ra) -80000214: 0000a083 lw ra,0(ra) -80000218: 34209a63 bne ra,sp,8000056c +80000204 : +80000204: 00700e13 li t3,7 +80000208: 9000a0b7 lui ra,0x9000a +8000020c: 36008093 addi ra,ra,864 # 9000a360 +80000210: aaee0137 lui sp,0xaaee0 +80000214: 00110113 addi sp,sp,1 # aaee0001 +80000218: 0020a023 sw sp,0(ra) +8000021c: 0000a083 lw ra,0(ra) +80000220: 2a209063 bne ra,sp,800004c0 -8000021c : -8000021c: 00800e13 li t3,8 -80000220: 2000c097 auipc ra,0x2000c -80000224: de408093 addi ra,ra,-540 # a000c004 -80000228: 77767137 lui sp,0x77767 -8000022c: 57410113 addi sp,sp,1396 # 77767574 <_start-0x8898a8c> -80000230: 0000a083 lw ra,0(ra) -80000234: 32209c63 bne ra,sp,8000056c +80000224 : +80000224: 00800e13 li t3,8 +80000228: 2000c097 auipc ra,0x2000c +8000022c: ddc08093 addi ra,ra,-548 # a000c004 +80000230: 77767137 lui sp,0x77767 +80000234: 57410113 addi sp,sp,1396 # 77767574 <_start-0x8898a8c> +80000238: 0000a083 lw ra,0(ra) +8000023c: 28209263 bne ra,sp,800004c0 -80000238 : -80000238: 00900e13 li t3,9 -8000023c: a000a0b7 lui ra,0xa000a -80000240: 36008093 addi ra,ra,864 # a000a360 -80000244: aaee0137 lui sp,0xaaee0 -80000248: 00210113 addi sp,sp,2 # aaee0002 -8000024c: 0020a023 sw sp,0(ra) -80000250: 0000a083 lw ra,0(ra) -80000254: 30209c63 bne ra,sp,8000056c +80000240 : +80000240: 00900e13 li t3,9 +80000244: a000a0b7 lui ra,0xa000a +80000248: 36008093 addi ra,ra,864 # a000a360 +8000024c: aaee0137 lui sp,0xaaee0 +80000250: 00210113 addi sp,sp,2 # aaee0002 +80000254: 0020a023 sw sp,0(ra) +80000258: 0000a083 lw ra,0(ra) +8000025c: 26209263 bne ra,sp,800004c0 -80000258 : -80000258: 00a00e13 li t3,10 -8000025c: 18005073 csrwi satp,0 -80000260: 00009097 auipc ra,0x9 -80000264: 10008093 addi ra,ra,256 # 80009360 -80000268: aaee0137 lui sp,0xaaee0 -8000026c: 00110113 addi sp,sp,1 # aaee0001 -80000270: 0000a083 lw ra,0(ra) -80000274: 2e209c63 bne ra,sp,8000056c +80000260 : +80000260: 00a00e13 li t3,10 +80000264: 18005073 csrwi satp,0 +80000268: 00009097 auipc ra,0x9 +8000026c: 0f808093 addi ra,ra,248 # 80009360 +80000270: aaee0137 lui sp,0xaaee0 +80000274: 00110113 addi sp,sp,1 # aaee0001 +80000278: 0000a083 lw ra,0(ra) +8000027c: 24209263 bne ra,sp,800004c0 -80000278 : -80000278: 00b00e13 li t3,11 -8000027c: 0000a097 auipc ra,0xa -80000280: 0e408093 addi ra,ra,228 # 8000a360 -80000284: aaee0137 lui sp,0xaaee0 -80000288: 00210113 addi sp,sp,2 # aaee0002 -8000028c: 0000a083 lw ra,0(ra) -80000290: 2c209e63 bne ra,sp,8000056c -80000294: 00001097 auipc ra,0x1 -80000298: d6c08093 addi ra,ra,-660 # 80001000 -8000029c: 00c0d093 srli ra,ra,0xc -800002a0: 80000137 lui sp,0x80000 -800002a4: 0020e0b3 or ra,ra,sp -800002a8: 18009073 csrw satp,ra +80000280 : +80000280: 00b00e13 li t3,11 +80000284: 0000a097 auipc ra,0xa +80000288: 0dc08093 addi ra,ra,220 # 8000a360 +8000028c: aaee0137 lui sp,0xaaee0 +80000290: 00210113 addi sp,sp,2 # aaee0002 +80000294: 0000a083 lw ra,0(ra) +80000298: 22209463 bne ra,sp,800004c0 +8000029c: 00001097 auipc ra,0x1 +800002a0: d6408093 addi ra,ra,-668 # 80001000 +800002a4: 00c0d093 srli ra,ra,0xc +800002a8: 80000137 lui sp,0x80000 +800002ac: 0020e0b3 or ra,ra,sp +800002b0: 18009073 csrw satp,ra -800002ac : -800002ac: 00c00e13 li t3,12 -800002b0: 00100e93 li t4,1 -800002b4: 00000f17 auipc t5,0x0 -800002b8: 010f0f13 addi t5,t5,16 # 800002c4 -800002bc: 00000073 ecall -800002c0: 2ac0006f j 8000056c +800002b4 : +800002b4: 00c00e13 li t3,12 +800002b8: 00100e93 li t4,1 +800002bc: 00000f17 auipc t5,0x0 +800002c0: 010f0f13 addi t5,t5,16 # 800002cc +800002c4: 00000073 ecall +800002c8: 1f80006f j 800004c0 -800002c4 : -800002c4: 00d00e13 li t3,13 -800002c8: 00000f17 auipc t5,0x0 -800002cc: 014f0f13 addi t5,t5,20 # 800002dc -800002d0: b00000b7 lui ra,0xb0000 -800002d4: 0080a083 lw ra,8(ra) # b0000008 -800002d8: 2940006f j 8000056c +800002cc : +800002cc: 00d00e13 li t3,13 +800002d0: 00000f17 auipc t5,0x0 +800002d4: 014f0f13 addi t5,t5,20 # 800002e4 +800002d8: b00000b7 lui ra,0xb0000 +800002dc: 0080a083 lw ra,8(ra) # b0000008 +800002e0: 1e00006f j 800004c0 -800002dc : -800002dc: 00e00e13 li t3,14 -800002e0: 00000f17 auipc t5,0x0 -800002e4: 014f0f13 addi t5,t5,20 # 800002f4 -800002e8: b00000b7 lui ra,0xb0000 -800002ec: 0010a423 sw ra,8(ra) # b0000008 -800002f0: 27c0006f j 8000056c +800002e4 : +800002e4: 00e00e13 li t3,14 +800002e8: 00000f17 auipc t5,0x0 +800002ec: 014f0f13 addi t5,t5,20 # 800002fc +800002f0: b00000b7 lui ra,0xb0000 +800002f4: 0010a423 sw ra,8(ra) # b0000008 +800002f8: 1c80006f j 800004c0 -800002f4 : -800002f4: 00f00e13 li t3,15 -800002f8: 00000f17 auipc t5,0x0 -800002fc: 014f0f13 addi t5,t5,20 # 8000030c -80000300: b00000b7 lui ra,0xb0000 -80000304: 00008067 ret -80000308: 2640006f j 8000056c +800002fc : +800002fc: 00f00e13 li t3,15 +80000300: 00000f17 auipc t5,0x0 +80000304: 014f0f13 addi t5,t5,20 # 80000314 +80000308: b00000b7 lui ra,0xb0000 +8000030c: 00008067 ret +80000310: 1b00006f j 800004c0 -8000030c : -8000030c: 01000e13 li t3,16 -80000310: 00000e93 li t4,0 -80000314: 900100b7 lui ra,0x90010 -80000318: 00808093 addi ra,ra,8 # 90010008 -8000031c: 5b5a6137 lui sp,0x5b5a6 -80000320: 95810113 addi sp,sp,-1704 # 5b5a5958 <_start-0x24a5a6a8> -80000324: 0000a083 lw ra,0(ra) -80000328: 24209263 bne ra,sp,8000056c -8000032c: 900110b7 lui ra,0x90011 -80000330: 00808093 addi ra,ra,8 # 90011008 -80000334: 5b5a6137 lui sp,0x5b5a6 -80000338: 95810113 addi sp,sp,-1704 # 5b5a5958 <_start-0x24a5a6a8> -8000033c: 0000a083 lw ra,0(ra) -80000340: 22209663 bne ra,sp,8000056c -80000344: 900130b7 lui ra,0x90013 -80000348: 00808093 addi ra,ra,8 # 90013008 -8000034c: 5b5a6137 lui sp,0x5b5a6 -80000350: 95810113 addi sp,sp,-1704 # 5b5a5958 <_start-0x24a5a6a8> -80000354: 0000a083 lw ra,0(ra) -80000358: 20209a63 bne ra,sp,8000056c +80000314 : +80000314: 01000e13 li t3,16 +80000318: 00000e93 li t4,0 +8000031c: 900100b7 lui ra,0x90010 +80000320: 00808093 addi ra,ra,8 # 90010008 +80000324: 5b5a6137 lui sp,0x5b5a6 +80000328: 95810113 addi sp,sp,-1704 # 5b5a5958 <_start-0x24a5a6a8> +8000032c: 0000a083 lw ra,0(ra) +80000330: 18209863 bne ra,sp,800004c0 +80000334: 900110b7 lui ra,0x90011 +80000338: 00808093 addi ra,ra,8 # 90011008 +8000033c: 5b5a6137 lui sp,0x5b5a6 +80000340: 95810113 addi sp,sp,-1704 # 5b5a5958 <_start-0x24a5a6a8> +80000344: 0000a083 lw ra,0(ra) +80000348: 16209c63 bne ra,sp,800004c0 +8000034c: 900130b7 lui ra,0x90013 +80000350: 00808093 addi ra,ra,8 # 90013008 +80000354: 5b5a6137 lui sp,0x5b5a6 +80000358: 95810113 addi sp,sp,-1704 # 5b5a5958 <_start-0x24a5a6a8> +8000035c: 0000a083 lw ra,0(ra) +80000360: 16209063 bne ra,sp,800004c0 -8000035c : -8000035c: 01100e13 li t3,17 -80000360: 900110b7 lui ra,0x90011 -80000364: 36008093 addi ra,ra,864 # 90011360 -80000368: aaee0137 lui sp,0xaaee0 -8000036c: 00310113 addi sp,sp,3 # aaee0003 -80000370: 0020a023 sw sp,0(ra) -80000374: 0000a083 lw ra,0(ra) -80000378: 1e209a63 bne ra,sp,8000056c +80000364 : +80000364: 01100e13 li t3,17 +80000368: 900110b7 lui ra,0x90011 +8000036c: 36008093 addi ra,ra,864 # 90011360 +80000370: aaee0137 lui sp,0xaaee0 +80000374: 00310113 addi sp,sp,3 # aaee0003 +80000378: 0020a023 sw sp,0(ra) +8000037c: 0000a083 lw ra,0(ra) +80000380: 14209063 bne ra,sp,800004c0 -8000037c : -8000037c: 01200e13 li t3,18 -80000380: 00000097 auipc ra,0x0 -80000384: 01808093 addi ra,ra,24 # 80000398 -80000388: 90012137 lui sp,0x90012 -8000038c: 01010113 addi sp,sp,16 # 90012010 -80000390: 00010067 jr sp -80000394: 1d80006f j 8000056c +80000384 : +80000384: 01200e13 li t3,18 +80000388: 00100e93 li t4,1 +8000038c: 00000f17 auipc t5,0x0 +80000390: 018f0f13 addi t5,t5,24 # 800003a4 +80000394: 90012137 lui sp,0x90012 +80000398: 01010113 addi sp,sp,16 # 90012010 +8000039c: 00010067 jr sp +800003a0: 1200006f j 800004c0 -80000398 : -80000398: 01300e13 li t3,19 -8000039c: 00100e93 li t4,1 -800003a0: 00000f17 auipc t5,0x0 -800003a4: 018f0f13 addi t5,t5,24 # 800003b8 -800003a8: 900120b7 lui ra,0x90012 -800003ac: 01008093 addi ra,ra,16 # 90012010 -800003b0: 0000a083 lw ra,0(ra) -800003b4: 1b80006f j 8000056c +800003a4 : +800003a4: 01300e13 li t3,19 +800003a8: 00100e93 li t4,1 +800003ac: 00000f17 auipc t5,0x0 +800003b0: 018f0f13 addi t5,t5,24 # 800003c4 +800003b4: 900120b7 lui ra,0x90012 +800003b8: 01008093 addi ra,ra,16 # 90012010 +800003bc: 0000a083 lw ra,0(ra) +800003c0: 1000006f j 800004c0 -800003b8 : -800003b8: 00000f17 auipc t5,0x0 -800003bc: 018f0f13 addi t5,t5,24 # 800003d0 -800003c0: 900130b7 lui ra,0x90013 -800003c4: 01008093 addi ra,ra,16 # 90013010 -800003c8: 0010a023 sw ra,0(ra) -800003cc: 1a00006f j 8000056c +800003c4 : +800003c4: 00000f17 auipc t5,0x0 +800003c8: 018f0f13 addi t5,t5,24 # 800003dc +800003cc: 900130b7 lui ra,0x90013 +800003d0: 01008093 addi ra,ra,16 # 90013010 +800003d4: 0010a023 sw ra,0(ra) +800003d8: 0e80006f j 800004c0 -800003d0 : -800003d0: 00000f17 auipc t5,0x0 -800003d4: 018f0f13 addi t5,t5,24 # 800003e8 -800003d8: 900110b7 lui ra,0x90011 -800003dc: 01008093 addi ra,ra,16 # 90011010 -800003e0: 00008067 ret -800003e4: 1880006f j 8000056c +800003dc : +800003dc: 00000f17 auipc t5,0x0 +800003e0: 018f0f13 addi t5,t5,24 # 800003f4 +800003e4: 900110b7 lui ra,0x90011 +800003e8: 01008093 addi ra,ra,16 # 90011010 +800003ec: 00008067 ret +800003f0: 0d00006f j 800004c0 -800003e8 : -800003e8: 01500e13 li t3,21 -800003ec: 00000e93 li t4,0 -800003f0: 000800b7 lui ra,0x80 -800003f4: 1000a073 csrs sstatus,ra -800003f8: 900120b7 lui ra,0x90012 -800003fc: 00808093 addi ra,ra,8 # 90012008 -80000400: 5b5a6137 lui sp,0x5b5a6 -80000404: 95810113 addi sp,sp,-1704 # 5b5a5958 <_start-0x24a5a6a8> -80000408: 0000a083 lw ra,0(ra) -8000040c: 16209063 bne ra,sp,8000056c -80000410: 000800b7 lui ra,0x80 -80000414: 1000b073 csrc sstatus,ra +800003f4 : +800003f4: 01500e13 li t3,21 +800003f8: 00000e93 li t4,0 +800003fc: 000800b7 lui ra,0x80 +80000400: 1000a073 csrs sstatus,ra +80000404: 900120b7 lui ra,0x90012 +80000408: 00808093 addi ra,ra,8 # 90012008 +8000040c: 5b5a6137 lui sp,0x5b5a6 +80000410: 95810113 addi sp,sp,-1704 # 5b5a5958 <_start-0x24a5a6a8> +80000414: 0000a083 lw ra,0(ra) +80000418: 0a209463 bne ra,sp,800004c0 +8000041c: 000800b7 lui ra,0x80 +80000420: 1000b073 csrc sstatus,ra -80000418 : -80000418: 00000e93 li t4,0 -8000041c: 01400e13 li t3,20 -80000420: 900140b7 lui ra,0x90014 -80000424: 38008093 addi ra,ra,896 # 90014380 -80000428: aaee0137 lui sp,0xaaee0 -8000042c: 00510113 addi sp,sp,5 # aaee0005 -80000430: 0020a023 sw sp,0(ra) -80000434: 0000a083 lw ra,0(ra) -80000438: 12209a63 bne ra,sp,8000056c -8000043c: 000400b7 lui ra,0x40 -80000440: 1000b073 csrc sstatus,ra -80000444: 00100e93 li t4,1 -80000448: 00000f17 auipc t5,0x0 -8000044c: 018f0f13 addi t5,t5,24 # 80000460 -80000450: 900110b7 lui ra,0x90011 -80000454: 64808093 addi ra,ra,1608 # 90011648 -80000458: 0010a023 sw ra,0(ra) -8000045c: 1100006f j 8000056c +80000424 : +80000424: 00000e93 li t4,0 +80000428: 01400e13 li t3,20 +8000042c: 900140b7 lui ra,0x90014 +80000430: 38008093 addi ra,ra,896 # 90014380 +80000434: aaee0137 lui sp,0xaaee0 +80000438: 00510113 addi sp,sp,5 # aaee0005 +8000043c: 0020a023 sw sp,0(ra) +80000440: 0000a083 lw ra,0(ra) +80000444: 06209e63 bne ra,sp,800004c0 +80000448: 000400b7 lui ra,0x40 +8000044c: 1000b073 csrc sstatus,ra +80000450: 00100e93 li t4,1 +80000454: 00000f17 auipc t5,0x0 +80000458: 018f0f13 addi t5,t5,24 # 8000046c +8000045c: 900110b7 lui ra,0x90011 +80000460: 64808093 addi ra,ra,1608 # 90011648 +80000464: 0010a023 sw ra,0(ra) +80000468: 0580006f j 800004c0 -80000460 : -80000460: 03200e13 li t3,50 -80000464: 00000e93 li t4,0 -80000468: 000400b7 lui ra,0x40 -8000046c: 1000a073 csrs sstatus,ra -80000470: 18002573 csrr a0,satp -80000474: 18001073 csrw satp,zero -80000478: 00002097 auipc ra,0x2 -8000047c: b8808093 addi ra,ra,-1144 # 80002000 -80000480: 80000137 lui sp,0x80000 -80000484: 00215113 srli sp,sp,0x2 -80000488: 01f16113 ori sp,sp,31 -8000048c: 0020a023 sw sp,0(ra) -80000490: 18051073 csrw satp,a0 -80000494: 10000093 li ra,256 -80000498: 1000b073 csrc sstatus,ra -8000049c: 00000097 auipc ra,0x0 -800004a0: 01808093 addi ra,ra,24 # 800004b4 -800004a4: 14109073 csrw sepc,ra -800004a8: 12000073 sfence.vma -800004ac: 10200073 sret -800004b0: 0bc0006f j 8000056c +8000046c : +8000046c: 03200e13 li t3,50 +80000470: 00000e93 li t4,0 +80000474: 000400b7 lui ra,0x40 +80000478: 1000a073 csrs sstatus,ra +8000047c: 18002573 csrr a0,satp +80000480: 18001073 csrw satp,zero +80000484: 00002097 auipc ra,0x2 +80000488: bb008093 addi ra,ra,-1104 # 80002034 +8000048c: 8000d137 lui sp,0x8000d +80000490: 00215113 srli sp,sp,0x2 +80000494: 05f16113 ori sp,sp,95 +80000498: 0020a023 sw sp,0(ra) +8000049c: 18051073 csrw satp,a0 +800004a0: 10000093 li ra,256 +800004a4: 1000b073 csrc sstatus,ra +800004a8: 0000d097 auipc ra,0xd +800004ac: b5808093 addi ra,ra,-1192 # 8000d000 +800004b0: 14109073 csrw sepc,ra +800004b4: 12000073 sfence.vma +800004b8: 10200073 sret +800004bc: 0040006f j 800004c0 -800004b4 : -800004b4: 03300e13 li t3,51 -800004b8: 900110b7 lui ra,0x90011 -800004bc: 00808093 addi ra,ra,8 # 90011008 -800004c0: 5b5a6137 lui sp,0x5b5a6 -800004c4: 95810113 addi sp,sp,-1704 # 5b5a5958 <_start-0x24a5a6a8> -800004c8: 0000a083 lw ra,0(ra) -800004cc: 0a209063 bne ra,sp,8000056c -800004d0: a000a0b7 lui ra,0xa000a -800004d4: 32408093 addi ra,ra,804 # a000a324 -800004d8: aaee0137 lui sp,0xaaee0 -800004dc: 00810113 addi sp,sp,8 # aaee0008 -800004e0: 0020a023 sw sp,0(ra) -800004e4: 0000a083 lw ra,0(ra) -800004e8: 08209263 bne ra,sp,8000056c +800004c0 : +800004c0: 00000e93 li t4,0 +800004c4: 00000f17 auipc t5,0x0 +800004c8: 00cf0f13 addi t5,t5,12 # 800004d0 +800004cc: 00000073 ecall -800004ec : -800004ec: 03400e13 li t3,52 -800004f0: 00000097 auipc ra,0x0 -800004f4: 01808093 addi ra,ra,24 # 80000508 -800004f8: 90012137 lui sp,0x90012 -800004fc: 01010113 addi sp,sp,16 # 90012010 -80000500: 00010067 jr sp -80000504: 0680006f j 8000056c +800004d0 : +800004d0: f0100137 lui sp,0xf0100 +800004d4: f2410113 addi sp,sp,-220 # f00fff24 +800004d8: 01c12023 sw t3,0(sp) -80000508 : -80000508: 03500e13 li t3,53 -8000050c: 00100e93 li t4,1 -80000510: 00000f17 auipc t5,0x0 -80000514: 018f0f13 addi t5,t5,24 # 80000528 -80000518: 900140b7 lui ra,0x90014 -8000051c: 39008093 addi ra,ra,912 # 90014390 -80000520: 00008067 ret -80000524: 0480006f j 8000056c +800004dc : +800004dc: 00100e93 li t4,1 +800004e0: 00000f17 auipc t5,0x0 +800004e4: 00cf0f13 addi t5,t5,12 # 800004ec +800004e8: 00000073 ecall -80000528 : -80000528: 03600e13 li t3,54 -8000052c: 00100e93 li t4,1 -80000530: 00000f17 auipc t5,0x0 -80000534: 018f0f13 addi t5,t5,24 # 80000548 -80000538: 900140b7 lui ra,0x90014 -8000053c: 39408093 addi ra,ra,916 # 90014394 -80000540: 0000a083 lw ra,0(ra) -80000544: 0280006f j 8000056c +800004ec : +800004ec: f0100137 lui sp,0xf0100 +800004f0: f2010113 addi sp,sp,-224 # f00fff20 +800004f4: 00012023 sw zero,0(sp) +800004f8: 00000013 nop +800004fc: 00000013 nop -80000548 : -80000548: 03700e13 li t3,55 -8000054c: 00100e93 li t4,1 -80000550: 00000f17 auipc t5,0x0 -80000554: 018f0f13 addi t5,t5,24 # 80000568 -80000558: 900140b7 lui ra,0x90014 -8000055c: 39808093 addi ra,ra,920 # 90014398 -80000560: 0010a023 sw ra,0(ra) -80000564: 0080006f j 8000056c - -80000568 : -80000568: 0180006f j 80000580 - -8000056c : -8000056c: 00000e93 li t4,0 -80000570: 00000073 ecall - -80000574 : -80000574: f0100137 lui sp,0xf0100 -80000578: f2410113 addi sp,sp,-220 # f00fff24 -8000057c: 01c12023 sw t3,0(sp) - -80000580 : -80000580: 00200e93 li t4,2 -80000584: 00000073 ecall - -80000588 : -80000588: f0100137 lui sp,0xf0100 -8000058c: f2010113 addi sp,sp,-224 # f00fff20 -80000590: 00012023 sw zero,0(sp) - -80000594 : -80000594: fe0e80e3 beqz t4,80000574 -80000598: 342020f3 csrr ra,mcause -8000059c: 341020f3 csrr ra,mepc -800005a0: 300020f3 csrr ra,mstatus -800005a4: 343020f3 csrr ra,mbadaddr -800005a8: 00200093 li ra,2 -800005ac: fc1e8ee3 beq t4,ra,80000588 -800005b0: 341f1073 csrw mepc,t5 -800005b4: 30200073 mret +80000500 : +80000500: fc0e80e3 beqz t4,800004c0 +80000504: 342020f3 csrr ra,mcause +80000508: 341020f3 csrr ra,mepc +8000050c: 300020f3 csrr ra,mstatus +80000510: 343020f3 csrr ra,mtval +80000514: 00200093 li ra,2 +80000518: fc1e82e3 beq t4,ra,800004dc +8000051c: 341f1073 csrw mepc,t5 +80000520: 30200073 mret +80000524: 00000013 nop +80000528: 00000013 nop +8000052c: 00000013 nop +80000530: 00000013 nop +80000534: 00000013 nop +80000538: 00000013 nop +8000053c: 00000013 nop +80000540: 00000013 nop +80000544: 00000013 nop +80000548: 00000013 nop +8000054c: 00000013 nop +80000550: 00000013 nop +80000554: 00000013 nop +80000558: 00000013 nop +8000055c: 00000013 nop +80000560: 00000013 nop +80000564: 00000013 nop +80000568: 00000013 nop +8000056c: 00000013 nop +80000570: 00000013 nop +80000574: 00000013 nop +80000578: 00000013 nop +8000057c: 00000013 nop +80000580: 00000013 nop +80000584: 00000013 nop +80000588: 00000013 nop +8000058c: 00000013 nop +80000590: 00000013 nop +80000594: 00000013 nop +80000598: 00000013 nop +8000059c: 00000013 nop +800005a0: 00000013 nop +800005a4: 00000013 nop +800005a8: 00000013 nop +800005ac: 00000013 nop +800005b0: 00000013 nop +800005b4: 00000013 nop 800005b8: 00000013 nop 800005bc: 00000013 nop 800005c0: 00000013 nop @@ -1101,8 +1089,7 @@ Disassembly of section .crt_section: 80000ffc: 00000013 nop 80001000 : -80001000: 0000 unimp -80001002: 0000 unimp +80001000: 00000000 .word 0x00000000 80001004: 00000013 nop 80001008: 00000013 nop 8000100c: 00000013 nop @@ -2128,8 +2115,7 @@ Disassembly of section .crt_section: 80001ffc: 00000013 nop 80002000 : -80002000: 0000 unimp -80002002: 0000 unimp +80002000: 00000000 .word 0x00000000 80002004: 00000013 nop 80002008: 00000013 nop 8000200c: 00000013 nop @@ -3155,8 +3141,7 @@ Disassembly of section .crt_section: 80002ffc: 00000013 nop 80003000 : -80003000: 0000 unimp -80003002: 0000 unimp +80003000: 00000000 .word 0x00000000 80003004: 00000013 nop 80003008: 00000013 nop 8000300c: 00000013 nop @@ -4182,8 +4167,7 @@ Disassembly of section .crt_section: 80003ffc: 00000013 nop 80004000 : -80004000: 0000 unimp -80004002: 0000 unimp +80004000: 00000000 .word 0x00000000 80004004: 00000013 nop 80004008: 00000013 nop 8000400c: 00000013 nop @@ -5209,14 +5193,10 @@ Disassembly of section .crt_section: 80004ffc: 00000013 nop 80005000 : -80005000: 0100 addi s0,sp,128 -80005002: 0302 slli t1,t1,0x0 -80005004: 0504 addi s1,sp,640 -80005006: 0706 slli a4,a4,0x1 -80005008: 0908 addi a0,sp,144 -8000500a: 0b0a slli s6,s6,0x2 -8000500c: 0d0c addi a1,sp,656 -8000500e: 0f0e slli t5,t5,0x3 +80005000: 03020100 .word 0x03020100 +80005004: 07060504 .word 0x07060504 +80005008: 0b0a0908 .word 0x0b0a0908 +8000500c: 0f0e0d0c .word 0x0f0e0d0c 80005010: 00000013 nop 80005014: 00000013 nop 80005018: 00000013 nop @@ -6239,14 +6219,10 @@ Disassembly of section .crt_section: 80005ffc: 00000013 nop 80006000 : -80006000: 1110 addi a2,sp,160 -80006002: 1312 slli t1,t1,0x24 -80006004: 1514 addi a3,sp,672 -80006006: 1716 slli a4,a4,0x25 -80006008: 1918 addi a4,sp,176 -8000600a: 1b1a slli s6,s6,0x26 -8000600c: 1d1c addi a5,sp,688 -8000600e: 1f1e slli t5,t5,0x27 +80006000: 13121110 .word 0x13121110 +80006004: 17161514 .word 0x17161514 +80006008: 1b1a1918 .word 0x1b1a1918 +8000600c: 1f1e1d1c .word 0x1f1e1d1c 80006010: 00000013 nop 80006014: 00000013 nop 80006018: 00000013 nop @@ -7269,14 +7245,10 @@ Disassembly of section .crt_section: 80006ffc: 00000013 nop 80007000 : -80007000: 2120 fld fs0,64(a0) -80007002: 2322 fld ft6,8(sp) -80007004: 2524 fld fs1,72(a0) -80007006: 2726 fld fa4,72(sp) -80007008: 2928 fld fa0,80(a0) -8000700a: 2b2a fld fs6,136(sp) -8000700c: 2d2c fld fa1,88(a0) -8000700e: 2f2e fld ft10,200(sp) +80007000: 23222120 .word 0x23222120 +80007004: 27262524 .word 0x27262524 +80007008: 2b2a2928 .word 0x2b2a2928 +8000700c: 2f2e2d2c .word 0x2f2e2d2c 80007010: 00000013 nop 80007014: 00000013 nop 80007018: 00000013 nop @@ -8299,14 +8271,10 @@ Disassembly of section .crt_section: 80007ffc: 00000013 nop 80008000 : -80008000: 3130 fld fa2,96(a0) -80008002: 3332 fld ft6,296(sp) -80008004: 3534 fld fa3,104(a0) -80008006: 3736 fld fa4,360(sp) -80008008: 3938 fld fa4,112(a0) -8000800a: 3b3a fld fs6,424(sp) -8000800c: 3d3c fld fa5,120(a0) -8000800e: 3f3e fld ft10,488(sp) +80008000: 33323130 .word 0x33323130 +80008004: 37363534 .word 0x37363534 +80008008: 3b3a3938 .word 0x3b3a3938 +8000800c: 3f3e3d3c .word 0x3f3e3d3c 80008010: 00000013 nop 80008014: 00000013 nop 80008018: 00000013 nop @@ -9329,14 +9297,10 @@ Disassembly of section .crt_section: 80008ffc: 00000013 nop 80009000 : -80009000: 4140 lw s0,4(a0) -80009002: 4342 lw t1,16(sp) -80009004: 4544 lw s1,12(a0) -80009006: 4746 lw a4,80(sp) -80009008: 4948 lw a0,20(a0) -8000900a: 4b4a lw s6,144(sp) -8000900c: 4d4c lw a1,28(a0) -8000900e: 4f4e lw t5,208(sp) +80009000: 43424140 .word 0x43424140 +80009004: 47464544 .word 0x47464544 +80009008: 4b4a4948 .word 0x4b4a4948 +8000900c: 4f4e4d4c .word 0x4f4e4d4c 80009010: 00000013 nop 80009014: 00000013 nop 80009018: 00000013 nop @@ -10359,14 +10323,10 @@ Disassembly of section .crt_section: 80009ffc: 00000013 nop 8000a000 : -8000a000: 5150 lw a2,36(a0) -8000a002: 5352 lw t1,52(sp) -8000a004: 5554 lw a3,44(a0) -8000a006: 5756 lw a4,116(sp) -8000a008: 5958 lw a4,52(a0) -8000a00a: 5b5a lw s6,180(sp) -8000a00c: 5d5c lw a5,60(a0) -8000a00e: 5f5e lw t5,244(sp) +8000a000: 53525150 .word 0x53525150 +8000a004: 57565554 .word 0x57565554 +8000a008: 5b5a5958 .word 0x5b5a5958 +8000a00c: 5f5e5d5c .word 0x5f5e5d5c 8000a010: 00008067 ret 8000a014: 00000013 nop 8000a018: 00000013 nop @@ -11389,14 +11349,10 @@ Disassembly of section .crt_section: 8000affc: 00000013 nop 8000b000 : -8000b000: 6160 flw fs0,68(a0) -8000b002: 6362 flw ft6,24(sp) -8000b004: 6564 flw fs1,76(a0) -8000b006: 6766 flw fa4,88(sp) -8000b008: 6968 flw fa0,84(a0) -8000b00a: 6b6a flw fs6,152(sp) -8000b00c: 6d6c flw fa1,92(a0) -8000b00e: 6f6e flw ft10,216(sp) +8000b000: 63626160 .word 0x63626160 +8000b004: 67666564 .word 0x67666564 +8000b008: 6b6a6968 .word 0x6b6a6968 +8000b00c: 6f6e6d6c .word 0x6f6e6d6c 8000b010: 00000013 nop 8000b014: 00000013 nop 8000b018: 00000013 nop @@ -12419,12 +12375,1089 @@ Disassembly of section .crt_section: 8000bffc: 00000013 nop 8000c000 : -8000c000: 7170 flw fa2,100(a0) -8000c002: 7372 flw ft6,60(sp) -8000c004: 7574 flw fa3,108(a0) -8000c006: 7776 flw fa4,124(sp) -8000c008: 7978 flw fa4,116(a0) -8000c00a: 7b7a flw fs6,188(sp) -8000c00c: 7d7c flw fa5,124(a0) -8000c00e: 7f7e flw ft10,252(sp) +8000c000: 73727170 .word 0x73727170 +8000c004: 77767574 .word 0x77767574 +8000c008: 7b7a7978 .word 0x7b7a7978 +8000c00c: 7f7e7d7c .word 0x7f7e7d7c +8000c010: 00000013 nop +8000c014: 00000013 nop +8000c018: 00000013 nop +8000c01c: 00000013 nop +8000c020: 00000013 nop +8000c024: 00000013 nop +8000c028: 00000013 nop +8000c02c: 00000013 nop +8000c030: 00000013 nop +8000c034: 00000013 nop +8000c038: 00000013 nop +8000c03c: 00000013 nop +8000c040: 00000013 nop +8000c044: 00000013 nop +8000c048: 00000013 nop +8000c04c: 00000013 nop +8000c050: 00000013 nop +8000c054: 00000013 nop +8000c058: 00000013 nop +8000c05c: 00000013 nop +8000c060: 00000013 nop +8000c064: 00000013 nop +8000c068: 00000013 nop +8000c06c: 00000013 nop +8000c070: 00000013 nop +8000c074: 00000013 nop +8000c078: 00000013 nop +8000c07c: 00000013 nop +8000c080: 00000013 nop +8000c084: 00000013 nop +8000c088: 00000013 nop +8000c08c: 00000013 nop +8000c090: 00000013 nop +8000c094: 00000013 nop +8000c098: 00000013 nop +8000c09c: 00000013 nop +8000c0a0: 00000013 nop +8000c0a4: 00000013 nop +8000c0a8: 00000013 nop +8000c0ac: 00000013 nop +8000c0b0: 00000013 nop +8000c0b4: 00000013 nop +8000c0b8: 00000013 nop +8000c0bc: 00000013 nop +8000c0c0: 00000013 nop +8000c0c4: 00000013 nop +8000c0c8: 00000013 nop +8000c0cc: 00000013 nop +8000c0d0: 00000013 nop +8000c0d4: 00000013 nop +8000c0d8: 00000013 nop +8000c0dc: 00000013 nop +8000c0e0: 00000013 nop +8000c0e4: 00000013 nop +8000c0e8: 00000013 nop +8000c0ec: 00000013 nop +8000c0f0: 00000013 nop +8000c0f4: 00000013 nop +8000c0f8: 00000013 nop +8000c0fc: 00000013 nop +8000c100: 00000013 nop +8000c104: 00000013 nop +8000c108: 00000013 nop +8000c10c: 00000013 nop +8000c110: 00000013 nop +8000c114: 00000013 nop +8000c118: 00000013 nop +8000c11c: 00000013 nop +8000c120: 00000013 nop +8000c124: 00000013 nop +8000c128: 00000013 nop +8000c12c: 00000013 nop +8000c130: 00000013 nop +8000c134: 00000013 nop +8000c138: 00000013 nop +8000c13c: 00000013 nop +8000c140: 00000013 nop +8000c144: 00000013 nop +8000c148: 00000013 nop +8000c14c: 00000013 nop +8000c150: 00000013 nop +8000c154: 00000013 nop +8000c158: 00000013 nop +8000c15c: 00000013 nop +8000c160: 00000013 nop +8000c164: 00000013 nop +8000c168: 00000013 nop +8000c16c: 00000013 nop +8000c170: 00000013 nop +8000c174: 00000013 nop +8000c178: 00000013 nop +8000c17c: 00000013 nop +8000c180: 00000013 nop +8000c184: 00000013 nop +8000c188: 00000013 nop +8000c18c: 00000013 nop +8000c190: 00000013 nop +8000c194: 00000013 nop +8000c198: 00000013 nop +8000c19c: 00000013 nop +8000c1a0: 00000013 nop +8000c1a4: 00000013 nop +8000c1a8: 00000013 nop +8000c1ac: 00000013 nop +8000c1b0: 00000013 nop +8000c1b4: 00000013 nop +8000c1b8: 00000013 nop +8000c1bc: 00000013 nop +8000c1c0: 00000013 nop +8000c1c4: 00000013 nop +8000c1c8: 00000013 nop +8000c1cc: 00000013 nop +8000c1d0: 00000013 nop +8000c1d4: 00000013 nop +8000c1d8: 00000013 nop +8000c1dc: 00000013 nop +8000c1e0: 00000013 nop +8000c1e4: 00000013 nop +8000c1e8: 00000013 nop +8000c1ec: 00000013 nop +8000c1f0: 00000013 nop +8000c1f4: 00000013 nop +8000c1f8: 00000013 nop +8000c1fc: 00000013 nop +8000c200: 00000013 nop +8000c204: 00000013 nop +8000c208: 00000013 nop +8000c20c: 00000013 nop +8000c210: 00000013 nop +8000c214: 00000013 nop +8000c218: 00000013 nop +8000c21c: 00000013 nop +8000c220: 00000013 nop +8000c224: 00000013 nop +8000c228: 00000013 nop +8000c22c: 00000013 nop +8000c230: 00000013 nop +8000c234: 00000013 nop +8000c238: 00000013 nop +8000c23c: 00000013 nop +8000c240: 00000013 nop +8000c244: 00000013 nop +8000c248: 00000013 nop +8000c24c: 00000013 nop +8000c250: 00000013 nop +8000c254: 00000013 nop +8000c258: 00000013 nop +8000c25c: 00000013 nop +8000c260: 00000013 nop +8000c264: 00000013 nop +8000c268: 00000013 nop +8000c26c: 00000013 nop +8000c270: 00000013 nop +8000c274: 00000013 nop +8000c278: 00000013 nop +8000c27c: 00000013 nop +8000c280: 00000013 nop +8000c284: 00000013 nop +8000c288: 00000013 nop +8000c28c: 00000013 nop +8000c290: 00000013 nop +8000c294: 00000013 nop +8000c298: 00000013 nop +8000c29c: 00000013 nop +8000c2a0: 00000013 nop +8000c2a4: 00000013 nop +8000c2a8: 00000013 nop +8000c2ac: 00000013 nop +8000c2b0: 00000013 nop +8000c2b4: 00000013 nop +8000c2b8: 00000013 nop +8000c2bc: 00000013 nop +8000c2c0: 00000013 nop +8000c2c4: 00000013 nop +8000c2c8: 00000013 nop +8000c2cc: 00000013 nop +8000c2d0: 00000013 nop +8000c2d4: 00000013 nop +8000c2d8: 00000013 nop +8000c2dc: 00000013 nop +8000c2e0: 00000013 nop +8000c2e4: 00000013 nop +8000c2e8: 00000013 nop +8000c2ec: 00000013 nop +8000c2f0: 00000013 nop +8000c2f4: 00000013 nop +8000c2f8: 00000013 nop +8000c2fc: 00000013 nop +8000c300: 00000013 nop +8000c304: 00000013 nop +8000c308: 00000013 nop +8000c30c: 00000013 nop +8000c310: 00000013 nop +8000c314: 00000013 nop +8000c318: 00000013 nop +8000c31c: 00000013 nop +8000c320: 00000013 nop +8000c324: 00000013 nop +8000c328: 00000013 nop +8000c32c: 00000013 nop +8000c330: 00000013 nop +8000c334: 00000013 nop +8000c338: 00000013 nop +8000c33c: 00000013 nop +8000c340: 00000013 nop +8000c344: 00000013 nop +8000c348: 00000013 nop +8000c34c: 00000013 nop +8000c350: 00000013 nop +8000c354: 00000013 nop +8000c358: 00000013 nop +8000c35c: 00000013 nop +8000c360: 00000013 nop +8000c364: 00000013 nop +8000c368: 00000013 nop +8000c36c: 00000013 nop +8000c370: 00000013 nop +8000c374: 00000013 nop +8000c378: 00000013 nop +8000c37c: 00000013 nop +8000c380: 00000013 nop +8000c384: 00000013 nop +8000c388: 00000013 nop +8000c38c: 00000013 nop +8000c390: 00000013 nop +8000c394: 00000013 nop +8000c398: 00000013 nop +8000c39c: 00000013 nop +8000c3a0: 00000013 nop +8000c3a4: 00000013 nop +8000c3a8: 00000013 nop +8000c3ac: 00000013 nop +8000c3b0: 00000013 nop +8000c3b4: 00000013 nop +8000c3b8: 00000013 nop +8000c3bc: 00000013 nop +8000c3c0: 00000013 nop +8000c3c4: 00000013 nop +8000c3c8: 00000013 nop +8000c3cc: 00000013 nop +8000c3d0: 00000013 nop +8000c3d4: 00000013 nop +8000c3d8: 00000013 nop +8000c3dc: 00000013 nop +8000c3e0: 00000013 nop +8000c3e4: 00000013 nop +8000c3e8: 00000013 nop +8000c3ec: 00000013 nop +8000c3f0: 00000013 nop +8000c3f4: 00000013 nop +8000c3f8: 00000013 nop +8000c3fc: 00000013 nop +8000c400: 00000013 nop +8000c404: 00000013 nop +8000c408: 00000013 nop +8000c40c: 00000013 nop +8000c410: 00000013 nop +8000c414: 00000013 nop +8000c418: 00000013 nop +8000c41c: 00000013 nop +8000c420: 00000013 nop +8000c424: 00000013 nop +8000c428: 00000013 nop +8000c42c: 00000013 nop +8000c430: 00000013 nop +8000c434: 00000013 nop +8000c438: 00000013 nop +8000c43c: 00000013 nop +8000c440: 00000013 nop +8000c444: 00000013 nop +8000c448: 00000013 nop +8000c44c: 00000013 nop +8000c450: 00000013 nop +8000c454: 00000013 nop +8000c458: 00000013 nop +8000c45c: 00000013 nop +8000c460: 00000013 nop +8000c464: 00000013 nop +8000c468: 00000013 nop +8000c46c: 00000013 nop +8000c470: 00000013 nop +8000c474: 00000013 nop +8000c478: 00000013 nop +8000c47c: 00000013 nop +8000c480: 00000013 nop +8000c484: 00000013 nop +8000c488: 00000013 nop +8000c48c: 00000013 nop +8000c490: 00000013 nop +8000c494: 00000013 nop +8000c498: 00000013 nop +8000c49c: 00000013 nop +8000c4a0: 00000013 nop +8000c4a4: 00000013 nop +8000c4a8: 00000013 nop +8000c4ac: 00000013 nop +8000c4b0: 00000013 nop +8000c4b4: 00000013 nop +8000c4b8: 00000013 nop +8000c4bc: 00000013 nop +8000c4c0: 00000013 nop +8000c4c4: 00000013 nop +8000c4c8: 00000013 nop +8000c4cc: 00000013 nop +8000c4d0: 00000013 nop +8000c4d4: 00000013 nop +8000c4d8: 00000013 nop +8000c4dc: 00000013 nop +8000c4e0: 00000013 nop +8000c4e4: 00000013 nop +8000c4e8: 00000013 nop +8000c4ec: 00000013 nop +8000c4f0: 00000013 nop +8000c4f4: 00000013 nop +8000c4f8: 00000013 nop +8000c4fc: 00000013 nop +8000c500: 00000013 nop +8000c504: 00000013 nop +8000c508: 00000013 nop +8000c50c: 00000013 nop +8000c510: 00000013 nop +8000c514: 00000013 nop +8000c518: 00000013 nop +8000c51c: 00000013 nop +8000c520: 00000013 nop +8000c524: 00000013 nop +8000c528: 00000013 nop +8000c52c: 00000013 nop +8000c530: 00000013 nop +8000c534: 00000013 nop +8000c538: 00000013 nop +8000c53c: 00000013 nop +8000c540: 00000013 nop +8000c544: 00000013 nop +8000c548: 00000013 nop +8000c54c: 00000013 nop +8000c550: 00000013 nop +8000c554: 00000013 nop +8000c558: 00000013 nop +8000c55c: 00000013 nop +8000c560: 00000013 nop +8000c564: 00000013 nop +8000c568: 00000013 nop +8000c56c: 00000013 nop +8000c570: 00000013 nop +8000c574: 00000013 nop +8000c578: 00000013 nop +8000c57c: 00000013 nop +8000c580: 00000013 nop +8000c584: 00000013 nop +8000c588: 00000013 nop +8000c58c: 00000013 nop +8000c590: 00000013 nop +8000c594: 00000013 nop +8000c598: 00000013 nop +8000c59c: 00000013 nop +8000c5a0: 00000013 nop +8000c5a4: 00000013 nop +8000c5a8: 00000013 nop +8000c5ac: 00000013 nop +8000c5b0: 00000013 nop +8000c5b4: 00000013 nop +8000c5b8: 00000013 nop +8000c5bc: 00000013 nop +8000c5c0: 00000013 nop +8000c5c4: 00000013 nop +8000c5c8: 00000013 nop +8000c5cc: 00000013 nop +8000c5d0: 00000013 nop +8000c5d4: 00000013 nop +8000c5d8: 00000013 nop +8000c5dc: 00000013 nop +8000c5e0: 00000013 nop +8000c5e4: 00000013 nop +8000c5e8: 00000013 nop +8000c5ec: 00000013 nop +8000c5f0: 00000013 nop +8000c5f4: 00000013 nop +8000c5f8: 00000013 nop +8000c5fc: 00000013 nop +8000c600: 00000013 nop +8000c604: 00000013 nop +8000c608: 00000013 nop +8000c60c: 00000013 nop +8000c610: 00000013 nop +8000c614: 00000013 nop +8000c618: 00000013 nop +8000c61c: 00000013 nop +8000c620: 00000013 nop +8000c624: 00000013 nop +8000c628: 00000013 nop +8000c62c: 00000013 nop +8000c630: 00000013 nop +8000c634: 00000013 nop +8000c638: 00000013 nop +8000c63c: 00000013 nop +8000c640: 00000013 nop +8000c644: 00000013 nop +8000c648: 00000013 nop +8000c64c: 00000013 nop +8000c650: 00000013 nop +8000c654: 00000013 nop +8000c658: 00000013 nop +8000c65c: 00000013 nop +8000c660: 00000013 nop +8000c664: 00000013 nop +8000c668: 00000013 nop +8000c66c: 00000013 nop +8000c670: 00000013 nop +8000c674: 00000013 nop +8000c678: 00000013 nop +8000c67c: 00000013 nop +8000c680: 00000013 nop +8000c684: 00000013 nop +8000c688: 00000013 nop +8000c68c: 00000013 nop +8000c690: 00000013 nop +8000c694: 00000013 nop +8000c698: 00000013 nop +8000c69c: 00000013 nop +8000c6a0: 00000013 nop +8000c6a4: 00000013 nop +8000c6a8: 00000013 nop +8000c6ac: 00000013 nop +8000c6b0: 00000013 nop +8000c6b4: 00000013 nop +8000c6b8: 00000013 nop +8000c6bc: 00000013 nop +8000c6c0: 00000013 nop +8000c6c4: 00000013 nop +8000c6c8: 00000013 nop +8000c6cc: 00000013 nop +8000c6d0: 00000013 nop +8000c6d4: 00000013 nop +8000c6d8: 00000013 nop +8000c6dc: 00000013 nop +8000c6e0: 00000013 nop +8000c6e4: 00000013 nop +8000c6e8: 00000013 nop +8000c6ec: 00000013 nop +8000c6f0: 00000013 nop +8000c6f4: 00000013 nop +8000c6f8: 00000013 nop +8000c6fc: 00000013 nop +8000c700: 00000013 nop +8000c704: 00000013 nop +8000c708: 00000013 nop +8000c70c: 00000013 nop +8000c710: 00000013 nop +8000c714: 00000013 nop +8000c718: 00000013 nop +8000c71c: 00000013 nop +8000c720: 00000013 nop +8000c724: 00000013 nop +8000c728: 00000013 nop +8000c72c: 00000013 nop +8000c730: 00000013 nop +8000c734: 00000013 nop +8000c738: 00000013 nop +8000c73c: 00000013 nop +8000c740: 00000013 nop +8000c744: 00000013 nop +8000c748: 00000013 nop +8000c74c: 00000013 nop +8000c750: 00000013 nop +8000c754: 00000013 nop +8000c758: 00000013 nop +8000c75c: 00000013 nop +8000c760: 00000013 nop +8000c764: 00000013 nop +8000c768: 00000013 nop +8000c76c: 00000013 nop +8000c770: 00000013 nop +8000c774: 00000013 nop +8000c778: 00000013 nop +8000c77c: 00000013 nop +8000c780: 00000013 nop +8000c784: 00000013 nop +8000c788: 00000013 nop +8000c78c: 00000013 nop +8000c790: 00000013 nop +8000c794: 00000013 nop +8000c798: 00000013 nop +8000c79c: 00000013 nop +8000c7a0: 00000013 nop +8000c7a4: 00000013 nop +8000c7a8: 00000013 nop +8000c7ac: 00000013 nop +8000c7b0: 00000013 nop +8000c7b4: 00000013 nop +8000c7b8: 00000013 nop +8000c7bc: 00000013 nop +8000c7c0: 00000013 nop +8000c7c4: 00000013 nop +8000c7c8: 00000013 nop +8000c7cc: 00000013 nop +8000c7d0: 00000013 nop +8000c7d4: 00000013 nop +8000c7d8: 00000013 nop +8000c7dc: 00000013 nop +8000c7e0: 00000013 nop +8000c7e4: 00000013 nop +8000c7e8: 00000013 nop +8000c7ec: 00000013 nop +8000c7f0: 00000013 nop +8000c7f4: 00000013 nop +8000c7f8: 00000013 nop +8000c7fc: 00000013 nop +8000c800: 00000013 nop +8000c804: 00000013 nop +8000c808: 00000013 nop +8000c80c: 00000013 nop +8000c810: 00000013 nop +8000c814: 00000013 nop +8000c818: 00000013 nop +8000c81c: 00000013 nop +8000c820: 00000013 nop +8000c824: 00000013 nop +8000c828: 00000013 nop +8000c82c: 00000013 nop +8000c830: 00000013 nop +8000c834: 00000013 nop +8000c838: 00000013 nop +8000c83c: 00000013 nop +8000c840: 00000013 nop +8000c844: 00000013 nop +8000c848: 00000013 nop +8000c84c: 00000013 nop +8000c850: 00000013 nop +8000c854: 00000013 nop +8000c858: 00000013 nop +8000c85c: 00000013 nop +8000c860: 00000013 nop +8000c864: 00000013 nop +8000c868: 00000013 nop +8000c86c: 00000013 nop +8000c870: 00000013 nop +8000c874: 00000013 nop +8000c878: 00000013 nop +8000c87c: 00000013 nop +8000c880: 00000013 nop +8000c884: 00000013 nop +8000c888: 00000013 nop +8000c88c: 00000013 nop +8000c890: 00000013 nop +8000c894: 00000013 nop +8000c898: 00000013 nop +8000c89c: 00000013 nop +8000c8a0: 00000013 nop +8000c8a4: 00000013 nop +8000c8a8: 00000013 nop +8000c8ac: 00000013 nop +8000c8b0: 00000013 nop +8000c8b4: 00000013 nop +8000c8b8: 00000013 nop +8000c8bc: 00000013 nop +8000c8c0: 00000013 nop +8000c8c4: 00000013 nop +8000c8c8: 00000013 nop +8000c8cc: 00000013 nop +8000c8d0: 00000013 nop +8000c8d4: 00000013 nop +8000c8d8: 00000013 nop +8000c8dc: 00000013 nop +8000c8e0: 00000013 nop +8000c8e4: 00000013 nop +8000c8e8: 00000013 nop +8000c8ec: 00000013 nop +8000c8f0: 00000013 nop +8000c8f4: 00000013 nop +8000c8f8: 00000013 nop +8000c8fc: 00000013 nop +8000c900: 00000013 nop +8000c904: 00000013 nop +8000c908: 00000013 nop +8000c90c: 00000013 nop +8000c910: 00000013 nop +8000c914: 00000013 nop +8000c918: 00000013 nop +8000c91c: 00000013 nop +8000c920: 00000013 nop +8000c924: 00000013 nop +8000c928: 00000013 nop +8000c92c: 00000013 nop +8000c930: 00000013 nop +8000c934: 00000013 nop +8000c938: 00000013 nop +8000c93c: 00000013 nop +8000c940: 00000013 nop +8000c944: 00000013 nop +8000c948: 00000013 nop +8000c94c: 00000013 nop +8000c950: 00000013 nop +8000c954: 00000013 nop +8000c958: 00000013 nop +8000c95c: 00000013 nop +8000c960: 00000013 nop +8000c964: 00000013 nop +8000c968: 00000013 nop +8000c96c: 00000013 nop +8000c970: 00000013 nop +8000c974: 00000013 nop +8000c978: 00000013 nop +8000c97c: 00000013 nop +8000c980: 00000013 nop +8000c984: 00000013 nop +8000c988: 00000013 nop +8000c98c: 00000013 nop +8000c990: 00000013 nop +8000c994: 00000013 nop +8000c998: 00000013 nop +8000c99c: 00000013 nop +8000c9a0: 00000013 nop +8000c9a4: 00000013 nop +8000c9a8: 00000013 nop +8000c9ac: 00000013 nop +8000c9b0: 00000013 nop +8000c9b4: 00000013 nop +8000c9b8: 00000013 nop +8000c9bc: 00000013 nop +8000c9c0: 00000013 nop +8000c9c4: 00000013 nop +8000c9c8: 00000013 nop +8000c9cc: 00000013 nop +8000c9d0: 00000013 nop +8000c9d4: 00000013 nop +8000c9d8: 00000013 nop +8000c9dc: 00000013 nop +8000c9e0: 00000013 nop +8000c9e4: 00000013 nop +8000c9e8: 00000013 nop +8000c9ec: 00000013 nop +8000c9f0: 00000013 nop +8000c9f4: 00000013 nop +8000c9f8: 00000013 nop +8000c9fc: 00000013 nop +8000ca00: 00000013 nop +8000ca04: 00000013 nop +8000ca08: 00000013 nop +8000ca0c: 00000013 nop +8000ca10: 00000013 nop +8000ca14: 00000013 nop +8000ca18: 00000013 nop +8000ca1c: 00000013 nop +8000ca20: 00000013 nop +8000ca24: 00000013 nop +8000ca28: 00000013 nop +8000ca2c: 00000013 nop +8000ca30: 00000013 nop +8000ca34: 00000013 nop +8000ca38: 00000013 nop +8000ca3c: 00000013 nop +8000ca40: 00000013 nop +8000ca44: 00000013 nop +8000ca48: 00000013 nop +8000ca4c: 00000013 nop +8000ca50: 00000013 nop +8000ca54: 00000013 nop +8000ca58: 00000013 nop +8000ca5c: 00000013 nop +8000ca60: 00000013 nop +8000ca64: 00000013 nop +8000ca68: 00000013 nop +8000ca6c: 00000013 nop +8000ca70: 00000013 nop +8000ca74: 00000013 nop +8000ca78: 00000013 nop +8000ca7c: 00000013 nop +8000ca80: 00000013 nop +8000ca84: 00000013 nop +8000ca88: 00000013 nop +8000ca8c: 00000013 nop +8000ca90: 00000013 nop +8000ca94: 00000013 nop +8000ca98: 00000013 nop +8000ca9c: 00000013 nop +8000caa0: 00000013 nop +8000caa4: 00000013 nop +8000caa8: 00000013 nop +8000caac: 00000013 nop +8000cab0: 00000013 nop +8000cab4: 00000013 nop +8000cab8: 00000013 nop +8000cabc: 00000013 nop +8000cac0: 00000013 nop +8000cac4: 00000013 nop +8000cac8: 00000013 nop +8000cacc: 00000013 nop +8000cad0: 00000013 nop +8000cad4: 00000013 nop +8000cad8: 00000013 nop +8000cadc: 00000013 nop +8000cae0: 00000013 nop +8000cae4: 00000013 nop +8000cae8: 00000013 nop +8000caec: 00000013 nop +8000caf0: 00000013 nop +8000caf4: 00000013 nop +8000caf8: 00000013 nop +8000cafc: 00000013 nop +8000cb00: 00000013 nop +8000cb04: 00000013 nop +8000cb08: 00000013 nop +8000cb0c: 00000013 nop +8000cb10: 00000013 nop +8000cb14: 00000013 nop +8000cb18: 00000013 nop +8000cb1c: 00000013 nop +8000cb20: 00000013 nop +8000cb24: 00000013 nop +8000cb28: 00000013 nop +8000cb2c: 00000013 nop +8000cb30: 00000013 nop +8000cb34: 00000013 nop +8000cb38: 00000013 nop +8000cb3c: 00000013 nop +8000cb40: 00000013 nop +8000cb44: 00000013 nop +8000cb48: 00000013 nop +8000cb4c: 00000013 nop +8000cb50: 00000013 nop +8000cb54: 00000013 nop +8000cb58: 00000013 nop +8000cb5c: 00000013 nop +8000cb60: 00000013 nop +8000cb64: 00000013 nop +8000cb68: 00000013 nop +8000cb6c: 00000013 nop +8000cb70: 00000013 nop +8000cb74: 00000013 nop +8000cb78: 00000013 nop +8000cb7c: 00000013 nop +8000cb80: 00000013 nop +8000cb84: 00000013 nop +8000cb88: 00000013 nop +8000cb8c: 00000013 nop +8000cb90: 00000013 nop +8000cb94: 00000013 nop +8000cb98: 00000013 nop +8000cb9c: 00000013 nop +8000cba0: 00000013 nop +8000cba4: 00000013 nop +8000cba8: 00000013 nop +8000cbac: 00000013 nop +8000cbb0: 00000013 nop +8000cbb4: 00000013 nop +8000cbb8: 00000013 nop +8000cbbc: 00000013 nop +8000cbc0: 00000013 nop +8000cbc4: 00000013 nop +8000cbc8: 00000013 nop +8000cbcc: 00000013 nop +8000cbd0: 00000013 nop +8000cbd4: 00000013 nop +8000cbd8: 00000013 nop +8000cbdc: 00000013 nop +8000cbe0: 00000013 nop +8000cbe4: 00000013 nop +8000cbe8: 00000013 nop +8000cbec: 00000013 nop +8000cbf0: 00000013 nop +8000cbf4: 00000013 nop +8000cbf8: 00000013 nop +8000cbfc: 00000013 nop +8000cc00: 00000013 nop +8000cc04: 00000013 nop +8000cc08: 00000013 nop +8000cc0c: 00000013 nop +8000cc10: 00000013 nop +8000cc14: 00000013 nop +8000cc18: 00000013 nop +8000cc1c: 00000013 nop +8000cc20: 00000013 nop +8000cc24: 00000013 nop +8000cc28: 00000013 nop +8000cc2c: 00000013 nop +8000cc30: 00000013 nop +8000cc34: 00000013 nop +8000cc38: 00000013 nop +8000cc3c: 00000013 nop +8000cc40: 00000013 nop +8000cc44: 00000013 nop +8000cc48: 00000013 nop +8000cc4c: 00000013 nop +8000cc50: 00000013 nop +8000cc54: 00000013 nop +8000cc58: 00000013 nop +8000cc5c: 00000013 nop +8000cc60: 00000013 nop +8000cc64: 00000013 nop +8000cc68: 00000013 nop +8000cc6c: 00000013 nop +8000cc70: 00000013 nop +8000cc74: 00000013 nop +8000cc78: 00000013 nop +8000cc7c: 00000013 nop +8000cc80: 00000013 nop +8000cc84: 00000013 nop +8000cc88: 00000013 nop +8000cc8c: 00000013 nop +8000cc90: 00000013 nop +8000cc94: 00000013 nop +8000cc98: 00000013 nop +8000cc9c: 00000013 nop +8000cca0: 00000013 nop +8000cca4: 00000013 nop +8000cca8: 00000013 nop +8000ccac: 00000013 nop +8000ccb0: 00000013 nop +8000ccb4: 00000013 nop +8000ccb8: 00000013 nop +8000ccbc: 00000013 nop +8000ccc0: 00000013 nop +8000ccc4: 00000013 nop +8000ccc8: 00000013 nop +8000cccc: 00000013 nop +8000ccd0: 00000013 nop +8000ccd4: 00000013 nop +8000ccd8: 00000013 nop +8000ccdc: 00000013 nop +8000cce0: 00000013 nop +8000cce4: 00000013 nop +8000cce8: 00000013 nop +8000ccec: 00000013 nop +8000ccf0: 00000013 nop +8000ccf4: 00000013 nop +8000ccf8: 00000013 nop +8000ccfc: 00000013 nop +8000cd00: 00000013 nop +8000cd04: 00000013 nop +8000cd08: 00000013 nop +8000cd0c: 00000013 nop +8000cd10: 00000013 nop +8000cd14: 00000013 nop +8000cd18: 00000013 nop +8000cd1c: 00000013 nop +8000cd20: 00000013 nop +8000cd24: 00000013 nop +8000cd28: 00000013 nop +8000cd2c: 00000013 nop +8000cd30: 00000013 nop +8000cd34: 00000013 nop +8000cd38: 00000013 nop +8000cd3c: 00000013 nop +8000cd40: 00000013 nop +8000cd44: 00000013 nop +8000cd48: 00000013 nop +8000cd4c: 00000013 nop +8000cd50: 00000013 nop +8000cd54: 00000013 nop +8000cd58: 00000013 nop +8000cd5c: 00000013 nop +8000cd60: 00000013 nop +8000cd64: 00000013 nop +8000cd68: 00000013 nop +8000cd6c: 00000013 nop +8000cd70: 00000013 nop +8000cd74: 00000013 nop +8000cd78: 00000013 nop +8000cd7c: 00000013 nop +8000cd80: 00000013 nop +8000cd84: 00000013 nop +8000cd88: 00000013 nop +8000cd8c: 00000013 nop +8000cd90: 00000013 nop +8000cd94: 00000013 nop +8000cd98: 00000013 nop +8000cd9c: 00000013 nop +8000cda0: 00000013 nop +8000cda4: 00000013 nop +8000cda8: 00000013 nop +8000cdac: 00000013 nop +8000cdb0: 00000013 nop +8000cdb4: 00000013 nop +8000cdb8: 00000013 nop +8000cdbc: 00000013 nop +8000cdc0: 00000013 nop +8000cdc4: 00000013 nop +8000cdc8: 00000013 nop +8000cdcc: 00000013 nop +8000cdd0: 00000013 nop +8000cdd4: 00000013 nop +8000cdd8: 00000013 nop +8000cddc: 00000013 nop +8000cde0: 00000013 nop +8000cde4: 00000013 nop +8000cde8: 00000013 nop +8000cdec: 00000013 nop +8000cdf0: 00000013 nop +8000cdf4: 00000013 nop +8000cdf8: 00000013 nop +8000cdfc: 00000013 nop +8000ce00: 00000013 nop +8000ce04: 00000013 nop +8000ce08: 00000013 nop +8000ce0c: 00000013 nop +8000ce10: 00000013 nop +8000ce14: 00000013 nop +8000ce18: 00000013 nop +8000ce1c: 00000013 nop +8000ce20: 00000013 nop +8000ce24: 00000013 nop +8000ce28: 00000013 nop +8000ce2c: 00000013 nop +8000ce30: 00000013 nop +8000ce34: 00000013 nop +8000ce38: 00000013 nop +8000ce3c: 00000013 nop +8000ce40: 00000013 nop +8000ce44: 00000013 nop +8000ce48: 00000013 nop +8000ce4c: 00000013 nop +8000ce50: 00000013 nop +8000ce54: 00000013 nop +8000ce58: 00000013 nop +8000ce5c: 00000013 nop +8000ce60: 00000013 nop +8000ce64: 00000013 nop +8000ce68: 00000013 nop +8000ce6c: 00000013 nop +8000ce70: 00000013 nop +8000ce74: 00000013 nop +8000ce78: 00000013 nop +8000ce7c: 00000013 nop +8000ce80: 00000013 nop +8000ce84: 00000013 nop +8000ce88: 00000013 nop +8000ce8c: 00000013 nop +8000ce90: 00000013 nop +8000ce94: 00000013 nop +8000ce98: 00000013 nop +8000ce9c: 00000013 nop +8000cea0: 00000013 nop +8000cea4: 00000013 nop +8000cea8: 00000013 nop +8000ceac: 00000013 nop +8000ceb0: 00000013 nop +8000ceb4: 00000013 nop +8000ceb8: 00000013 nop +8000cebc: 00000013 nop +8000cec0: 00000013 nop +8000cec4: 00000013 nop +8000cec8: 00000013 nop +8000cecc: 00000013 nop +8000ced0: 00000013 nop +8000ced4: 00000013 nop +8000ced8: 00000013 nop +8000cedc: 00000013 nop +8000cee0: 00000013 nop +8000cee4: 00000013 nop +8000cee8: 00000013 nop +8000ceec: 00000013 nop +8000cef0: 00000013 nop +8000cef4: 00000013 nop +8000cef8: 00000013 nop +8000cefc: 00000013 nop +8000cf00: 00000013 nop +8000cf04: 00000013 nop +8000cf08: 00000013 nop +8000cf0c: 00000013 nop +8000cf10: 00000013 nop +8000cf14: 00000013 nop +8000cf18: 00000013 nop +8000cf1c: 00000013 nop +8000cf20: 00000013 nop +8000cf24: 00000013 nop +8000cf28: 00000013 nop +8000cf2c: 00000013 nop +8000cf30: 00000013 nop +8000cf34: 00000013 nop +8000cf38: 00000013 nop +8000cf3c: 00000013 nop +8000cf40: 00000013 nop +8000cf44: 00000013 nop +8000cf48: 00000013 nop +8000cf4c: 00000013 nop +8000cf50: 00000013 nop +8000cf54: 00000013 nop +8000cf58: 00000013 nop +8000cf5c: 00000013 nop +8000cf60: 00000013 nop +8000cf64: 00000013 nop +8000cf68: 00000013 nop +8000cf6c: 00000013 nop +8000cf70: 00000013 nop +8000cf74: 00000013 nop +8000cf78: 00000013 nop +8000cf7c: 00000013 nop +8000cf80: 00000013 nop +8000cf84: 00000013 nop +8000cf88: 00000013 nop +8000cf8c: 00000013 nop +8000cf90: 00000013 nop +8000cf94: 00000013 nop +8000cf98: 00000013 nop +8000cf9c: 00000013 nop +8000cfa0: 00000013 nop +8000cfa4: 00000013 nop +8000cfa8: 00000013 nop +8000cfac: 00000013 nop +8000cfb0: 00000013 nop +8000cfb4: 00000013 nop +8000cfb8: 00000013 nop +8000cfbc: 00000013 nop +8000cfc0: 00000013 nop +8000cfc4: 00000013 nop +8000cfc8: 00000013 nop +8000cfcc: 00000013 nop +8000cfd0: 00000013 nop +8000cfd4: 00000013 nop +8000cfd8: 00000013 nop +8000cfdc: 00000013 nop +8000cfe0: 00000013 nop +8000cfe4: 00000013 nop +8000cfe8: 00000013 nop +8000cfec: 00000013 nop +8000cff0: 00000013 nop +8000cff4: 00000013 nop +8000cff8: 00000013 nop +8000cffc: 00000013 nop + +8000d000 : +8000d000: 03300e13 li t3,51 +8000d004: 900110b7 lui ra,0x90011 +8000d008: 00808093 addi ra,ra,8 # 90011008 +8000d00c: 5b5a6137 lui sp,0x5b5a6 +8000d010: 95810113 addi sp,sp,-1704 # 5b5a5958 <_start-0x24a5a6a8> +8000d014: 0000a083 lw ra,0(ra) +8000d018: 00208463 beq ra,sp,8000d020 +8000d01c: ca4f306f j 800004c0 +8000d020: a000a0b7 lui ra,0xa000a +8000d024: 32408093 addi ra,ra,804 # a000a324 +8000d028: aaee0137 lui sp,0xaaee0 +8000d02c: 00810113 addi sp,sp,8 # aaee0008 +8000d030: 0020a023 sw sp,0(ra) +8000d034: 0000a083 lw ra,0(ra) +8000d038: 00208463 beq ra,sp,8000d040 +8000d03c: c84f306f j 800004c0 + +8000d040 : +8000d040: 03400e13 li t3,52 +8000d044: 00000097 auipc ra,0x0 +8000d048: 01808093 addi ra,ra,24 # 8000d05c +8000d04c: 90012137 lui sp,0x90012 +8000d050: 01010113 addi sp,sp,16 # 90012010 +8000d054: 00010067 jr sp +8000d058: c68f306f j 800004c0 + +8000d05c : +8000d05c: 03500e13 li t3,53 +8000d060: 00100e93 li t4,1 +8000d064: 00000f17 auipc t5,0x0 +8000d068: 018f0f13 addi t5,t5,24 # 8000d07c +8000d06c: 900140b7 lui ra,0x90014 +8000d070: 39008093 addi ra,ra,912 # 90014390 +8000d074: 00008067 ret +8000d078: c48f306f j 800004c0 + +8000d07c : +8000d07c: 03600e13 li t3,54 +8000d080: 00100e93 li t4,1 +8000d084: 00000f17 auipc t5,0x0 +8000d088: 018f0f13 addi t5,t5,24 # 8000d09c +8000d08c: 900140b7 lui ra,0x90014 +8000d090: 39408093 addi ra,ra,916 # 90014394 +8000d094: 0000a083 lw ra,0(ra) +8000d098: c28f306f j 800004c0 + +8000d09c : +8000d09c: 03700e13 li t3,55 +8000d0a0: 00100e93 li t4,1 +8000d0a4: 00000f17 auipc t5,0x0 +8000d0a8: 018f0f13 addi t5,t5,24 # 8000d0bc +8000d0ac: 900140b7 lui ra,0x90014 +8000d0b0: 39808093 addi ra,ra,920 # 90014398 +8000d0b4: 0010a023 sw ra,0(ra) +8000d0b8: c08f306f j 800004c0 + +8000d0bc : +8000d0bc: 00200e93 li t4,2 +8000d0c0: 00000073 ecall ... diff --git a/src/test/cpp/raw/mmu/build/mmu.hex b/src/test/cpp/raw/mmu/build/mmu.hex index 67603477..30333a1c 100644 --- a/src/test/cpp/raw/mmu/build/mmu.hex +++ b/src/test/cpp/raw/mmu/build/mmu.hex @@ -1,96 +1,96 @@ :0200000480007A -:10000000930E0000970000009380005973905030C9 +:10000000930E0000970000009380C04F7390503013 :10001000130E1000977000009380C0FE3721262732 -:100020001301415283A0400063922054130E20001C +:100020001301415283A04000639C2048130E20001E :10003000970000009380000273901034B7200000F6 -:100040009380008073900030730020306F00005266 +:100040009380008073900030730020306F00404731 :10005000130E3000B71000009380008073900030C2 :10006000970000009380400173901034730020309B -:100070006F00C04F130E400097800000938080F8FF -:10008000373136371301415383A040006390204E2F +:100070006F000045130E400097800000938080F8C9 +:10008000373136371301415383A04000639A204231 :10009000130E5000971000009380C07617210000C7 -:1000A000130141F6135121001361110123A0200017 +:1000A000130141F6135121001361110023A0200018 :1000B00097200000938000F5370100801351210044 -:1000C0001361F10023A02000130E500097200000C0 +:1000C0001361F10C23A02000130E500097200000B4 :1000D00093804083173100001301C1F213512100B6 -:1000E0001361110123A0200097300000938000F4D9 -:1000F00017910000130101F1135121001361F10167 +:1000E0001361110023A0200097300000938000F4DA +:1000F00017910000130101F1135121001361F10D5B :1001000023A02000973000009380C0F317A10000C7 -:10011000130141EF135121001361310123A020008D +:10011000130141EF135121001361310D23A0200081 :1001200097300000938040F217A10000130181ED89 -:10013000135121001361710123A0200097300000AA +:10013000135121001361710D23A02000973000009E :100140009380C0F017A100001301C1EB13512100EF -:100150001361910123A0200097300000938040EFAD -:1001600017A10000130101EA135121001361B1012D +:100150001361910D23A0200097300000938040EFA1 +:1001600017A10000130101EA135121001361B10D21 :1001700023A02000973000009380C0ED17A100005D -:10018000130141E8135121001361F10023A0200065 +:10018000130141E8135121001361F10C23A0200059 :10019000130E5000972000009380C08617010000C6 -:1001A000130141E6135121001361F10123A0200046 +:1001A000130141E6135121001361F10D23A020003A :1001B000130E5000972000009380C09423A00000ED :1001C000B700040073A0001097100000938080E334 -:1001D00093D0C00037010080B3E020007390001876 -:1001E000130E6000B7A000909380800037514A4BF7 -:1001F0001301819483A00000639A2036130E7000CF -:10020000B7A00090938000363701EEAA13011100C9 -:1002100023A0200083A00000639A2034130E8000E6 -:1002200097C00020938040DE3771767713014157E5 -:1002300083A00000639C2032130E9000B7A000A0A2 -:10024000938000363701EEAA1301210023A020007D -:1002500083A00000639C2030130EA0007350001890 -:1002600097900000938000103701EEAA130111004F -:1002700083A00000639C202E130EB00097A0000006 -:100280009380400E3701EEAA1301210083A00000E5 -:10029000639E202C971000009380C0D693D0C0009E -:1002A00037010080B3E0200073900018130EC000E7 -:1002B000930E1000170F0000130F0F0173000000C2 -:1002C0006F00C02A130ED000170F0000130F4F014C -:1002D000B70000B083A080006F004029130EE0003B -:1002E000170F0000130F4F01B70000B023A4100038 -:1002F0006F00C027130EF000170F0000130F4F01FF -:10030000B70000B0678000006F004026130E0001A8 -:10031000930E0000B70001909380800037615A5B14 -:100320001301819583A0000063922024B7100190EF -:100330009380800037615A5B1301819583A0000090 -:1003400063962022B73001909380800037615A5B1A -:100350001301819583A00000639A2020130E1001E1 -:10036000B7100190938000363701EEAA13013100D7 -:1003700023A0200083A00000639A201E130E2001FA -:100380009700000093808001372101901301010143 -:10039000670001006F00801D130E3001930E1000E6 -:1003A000170F0000130F8F01B720019093800001F9 -:1003B00083A000006F00801B170F0000130F8F0138 -:1003C000B73001909380000123A010006F00001A45 -:1003D000170F0000130F8F01B710019093800001D9 -:1003E000678000006F008018130E5001930E00000C -:1003F000B700080073A00010B72001909380800020 -:1004000037615A5B1301819583A000006390201629 -:10041000B700080073B00010930E0000130E4001E7 -:10042000B7400190938000383701EEAA13015100C4 -:1004300023A0200083A00000639A2012B7000400CC -:1004400073B00010930E1000170F0000130F8F01F0 -:10045000B71001909380806423A010006F000011FA -:10046000130E2003930E0000B700040073A00010C9 -:10047000732500187310001897200000938080B82F -:1004800037010080135121001361F10123A02000E6 -:10049000731005189300001073B00010970000004F -:1004A0009380800173901014730000127300201069 -:1004B0006F00C00B130E3003B710019093808000C3 -:1004C00037615A5B1301819583A000006390200A75 -:1004D000B7A000A0938040323701EEAA130181003B -:1004E00023A0200083A0000063922008130E400385 -:1004F00097000000938080013721019013010101D2 -:10050000670001006F008006130E5003930E100069 -:10051000170F0000130F8F01B7400190938000392F -:10052000678000006F008004130E6003930E1000BC -:10053000170F0000130F8F01B740019093804039CF -:1005400083A000006F008002130E7003930E100052 -:10055000170F0000130F8F01B7400190938080396F -:1005600023A010006F0080006F008001930E000038 -:1005700073000000370110F0130141F22320C10184 -:10058000930E200073000000370110F0130101F2F8 -:1005900023200100E3800EFEF3202034F3201034EA -:1005A000F3200030F320303493002000E38E1EFC53 -:1005B00073101F347300203013000000130000007C +:1001D00093D0C00037010080B3E02000730000120C +:1001E000739000180F100000130E6000B7A000906D +:1001F0009380800037514A4B1301819483A0000003 +:100200006390202C130E7000B7A0009093800036EE +:100210003701EEAA1301110023A0200083A00000E3 +:100220006390202A130E800097C000209380C0DDC9 +:10023000377176771301415783A00000639220281D +:10024000130E9000B7A000A0938000363701EEAAED +:100250001301210023A0200083A000006392202628 +:10026000130EA00073500018979000009380800F29 +:100270003701EEAA1301110083A00000639220242D +:10028000130EB00097A000009380C00D3701EEAAB6 +:100290001301210083A00000639420229710000026 +:1002A000938040D693D0C00037010080B3E0200097 +:1002B00073900018130EC000930E1000170F00006B +:1002C000130F0F01730000006F00801F130ED0008A +:1002D000170F0000130F4F01B70000B083A080007C +:1002E0006F00001E130EE000170F0000130F4F01E8 +:1002F000B70000B023A410006F00801C130EF000A4 +:10030000170F0000130F4F01B70000B06780000007 +:100310006F00001B130E0001930E0000B700019048 +:100320009380800037615A5B1301819583A00000A0 +:1003300063982018B71001909380800037615A5B52 +:100340001301819583A00000639C2016B7300190B3 +:100350009380800037615A5B1301819583A0000070 +:1003600063902016130E1001B71001909380003691 +:100370003701EEAA1301310023A0200083A0000062 +:1003800063902014130E2001930E1000170F00002D +:10039000130F8F0137210190130101016700010044 +:1003A0006F000012130E3001930E1000170F0000A3 +:1003B000130F8F01B72001909380000183A00000EC +:1003C0006F000010170F0000130F8F01B73001905E +:1003D0009380000123A010006F00800E170F000013 +:1003E000130F8F01B7100190938000016780000008 +:1003F0006F00000D130E5001930E0000B7000800AF +:1004000073A00010B72001909380800037615A5B81 +:100410001301819583A000006394200AB7000800AF +:1004200073B00010930E0000130E4001B74001900E +:10043000938000383701EEAA1301510023A0200059 +:1004400083A00000639E2006B700040073B0001074 +:10045000930E1000170F0000130F8F01B7100190BB +:100460009380806423A010006F008005130E20038A +:10047000930E0000B700040073A00010732500184D +:100480007310001897200000938000BB37D10080C4 +:10049000135121001361F10523A0200073100518EA +:1004A0009300001073B0001097D00000938080B5C7 +:1004B0007390101473000012730020106F0040003E +:1004C000930E0000170F0000130FCF007300000001 +:1004D000370110F0130141F22320C101930E1000E7 +:1004E000170F0000130FCF0073000000370110F04A +:1004F000130101F22320010013000000130000008B +:10050000E3800EFCF3202034F3201034F32000307D +:10051000F320303493002000E3821EFC73101F345C +:1005200073002030130000001300000013000000CF +:10053000130000001300000013000000130000006F +:10054000130000001300000013000000130000005F +:10055000130000001300000013000000130000004F +:10056000130000001300000013000000130000003F +:10057000130000001300000013000000130000002F +:10058000130000001300000013000000130000001F +:10059000130000001300000013000000130000000F +:1005A00013000000130000001300000013000000FF +:1005B00013000000130000001300000013000000EF :1005C00013000000130000001300000013000000DF :1005D00013000000130000001300000013000000CF :1005E00013000000130000001300000013000000BF @@ -3072,162 +3072,426 @@ :10BFE0001300000013000000130000001300000005 :10BFF00013000000130000001300000013000000F5 :10C00000707172737475767778797A7B7C7D7E7FB8 -:10C010000000000000000000000000000000000020 -:10C020000000000000000000000000000000000010 -:10C030000000000000000000000000000000000000 -:10C0400000000000000000000000000000000000F0 -:10C0500000000000000000000000000000000000E0 -:10C0600000000000000000000000000000000000D0 -:10C0700000000000000000000000000000000000C0 -:10C0800000000000000000000000000000000000B0 -:10C0900000000000000000000000000000000000A0 -:10C0A0000000000000000000000000000000000090 -:10C0B0000000000000000000000000000000000080 -:10C0C0000000000000000000000000000000000070 -:10C0D0000000000000000000000000000000000060 -:10C0E0000000000000000000000000000000000050 -:10C0F0000000000000000000000000000000000040 -:10C10000000000000000000000000000000000002F -:10C11000000000000000000000000000000000001F -:10C12000000000000000000000000000000000000F -:10C1300000000000000000000000000000000000FF -:10C1400000000000000000000000000000000000EF -:10C1500000000000000000000000000000000000DF -:10C1600000000000000000000000000000000000CF -:10C1700000000000000000000000000000000000BF -:10C1800000000000000000000000000000000000AF -:10C19000000000000000000000000000000000009F -:10C1A000000000000000000000000000000000008F -:10C1B000000000000000000000000000000000007F -:10C1C000000000000000000000000000000000006F -:10C1D000000000000000000000000000000000005F -:10C1E000000000000000000000000000000000004F -:10C1F000000000000000000000000000000000003F -:10C20000000000000000000000000000000000002E -:10C21000000000000000000000000000000000001E -:10C22000000000000000000000000000000000000E -:10C2300000000000000000000000000000000000FE -:10C2400000000000000000000000000000000000EE -:10C2500000000000000000000000000000000000DE -:10C2600000000000000000000000000000000000CE -:10C2700000000000000000000000000000000000BE -:10C2800000000000000000000000000000000000AE -:10C29000000000000000000000000000000000009E -:10C2A000000000000000000000000000000000008E -:10C2B000000000000000000000000000000000007E -:10C2C000000000000000000000000000000000006E -:10C2D000000000000000000000000000000000005E -:10C2E000000000000000000000000000000000004E -:10C2F000000000000000000000000000000000003E -:10C30000000000000000000000000000000000002D -:10C31000000000000000000000000000000000001D -:10C32000000000000000000000000000000000000D -:10C3300000000000000000000000000000000000FD -:10C3400000000000000000000000000000000000ED -:10C3500000000000000000000000000000000000DD -:10C3600000000000000000000000000000000000CD -:10C3700000000000000000000000000000000000BD -:10C3800000000000000000000000000000000000AD -:10C39000000000000000000000000000000000009D -:10C3A000000000000000000000000000000000008D -:10C3B000000000000000000000000000000000007D -:10C3C000000000000000000000000000000000006D -:10C3D000000000000000000000000000000000005D -:10C3E000000000000000000000000000000000004D -:10C3F000000000000000000000000000000000003D -:10C40000000000000000000000000000000000002C -:10C41000000000000000000000000000000000001C -:10C42000000000000000000000000000000000000C -:10C4300000000000000000000000000000000000FC -:10C4400000000000000000000000000000000000EC -:10C4500000000000000000000000000000000000DC -:10C4600000000000000000000000000000000000CC -:10C4700000000000000000000000000000000000BC -:10C4800000000000000000000000000000000000AC -:10C49000000000000000000000000000000000009C -:10C4A000000000000000000000000000000000008C -:10C4B000000000000000000000000000000000007C -:10C4C000000000000000000000000000000000006C -:10C4D000000000000000000000000000000000005C -:10C4E000000000000000000000000000000000004C -:10C4F000000000000000000000000000000000003C -:10C50000000000000000000000000000000000002B -:10C51000000000000000000000000000000000001B -:10C52000000000000000000000000000000000000B -:10C5300000000000000000000000000000000000FB -:10C5400000000000000000000000000000000000EB -:10C5500000000000000000000000000000000000DB -:10C5600000000000000000000000000000000000CB -:10C5700000000000000000000000000000000000BB -:10C5800000000000000000000000000000000000AB -:10C59000000000000000000000000000000000009B -:10C5A000000000000000000000000000000000008B -:10C5B000000000000000000000000000000000007B -:10C5C000000000000000000000000000000000006B -:10C5D000000000000000000000000000000000005B -:10C5E000000000000000000000000000000000004B -:10C5F000000000000000000000000000000000003B -:10C60000000000000000000000000000000000002A -:10C61000000000000000000000000000000000001A -:10C62000000000000000000000000000000000000A -:10C6300000000000000000000000000000000000FA -:10C6400000000000000000000000000000000000EA -:10C6500000000000000000000000000000000000DA -:10C6600000000000000000000000000000000000CA -:10C6700000000000000000000000000000000000BA -:10C6800000000000000000000000000000000000AA -:10C69000000000000000000000000000000000009A -:10C6A000000000000000000000000000000000008A -:10C6B000000000000000000000000000000000007A -:10C6C000000000000000000000000000000000006A -:10C6D000000000000000000000000000000000005A -:10C6E000000000000000000000000000000000004A -:10C6F000000000000000000000000000000000003A -:10C700000000000000000000000000000000000029 -:10C710000000000000000000000000000000000019 -:10C720000000000000000000000000000000000009 -:10C7300000000000000000000000000000000000F9 -:10C7400000000000000000000000000000000000E9 -:10C7500000000000000000000000000000000000D9 -:10C7600000000000000000000000000000000000C9 -:10C7700000000000000000000000000000000000B9 -:10C7800000000000000000000000000000000000A9 -:10C790000000000000000000000000000000000099 -:10C7A0000000000000000000000000000000000089 -:10C7B0000000000000000000000000000000000079 -:10C7C0000000000000000000000000000000000069 -:10C7D0000000000000000000000000000000000059 -:10C7E0000000000000000000000000000000000049 -:10C7F0000000000000000000000000000000000039 -:10C800000000000000000000000000000000000028 -:10C810000000000000000000000000000000000018 -:10C820000000000000000000000000000000000008 -:10C8300000000000000000000000000000000000F8 -:10C8400000000000000000000000000000000000E8 -:10C8500000000000000000000000000000000000D8 -:10C8600000000000000000000000000000000000C8 -:10C8700000000000000000000000000000000000B8 -:10C8800000000000000000000000000000000000A8 -:10C890000000000000000000000000000000000098 -:10C8A0000000000000000000000000000000000088 -:10C8B0000000000000000000000000000000000078 -:10C8C0000000000000000000000000000000000068 -:10C8D0000000000000000000000000000000000058 -:10C8E0000000000000000000000000000000000048 -:10C8F0000000000000000000000000000000000038 -:10C900000000000000000000000000000000000027 -:10C910000000000000000000000000000000000017 -:10C920000000000000000000000000000000000007 -:10C9300000000000000000000000000000000000F7 -:10C9400000000000000000000000000000000000E7 -:10C9500000000000000000000000000000000000D7 -:10C9600000000000000000000000000000000000C7 -:10C9700000000000000000000000000000000000B7 -:10C9800000000000000000000000000000000000A7 -:10C990000000000000000000000000000000000097 -:10C9A0000000000000000000000000000000000087 -:10C9B0000000000000000000000000000000000077 -:10C9C0000000000000000000000000000000000067 -:0CC9D0000000000000000000000000005B +:10C0100013000000130000001300000013000000D4 +:10C0200013000000130000001300000013000000C4 +:10C0300013000000130000001300000013000000B4 +:10C0400013000000130000001300000013000000A4 +:10C050001300000013000000130000001300000094 +:10C060001300000013000000130000001300000084 +:10C070001300000013000000130000001300000074 +:10C080001300000013000000130000001300000064 +:10C090001300000013000000130000001300000054 +:10C0A0001300000013000000130000001300000044 +:10C0B0001300000013000000130000001300000034 +:10C0C0001300000013000000130000001300000024 +:10C0D0001300000013000000130000001300000014 +:10C0E0001300000013000000130000001300000004 +:10C0F00013000000130000001300000013000000F4 +:10C1000013000000130000001300000013000000E3 +:10C1100013000000130000001300000013000000D3 +:10C1200013000000130000001300000013000000C3 +:10C1300013000000130000001300000013000000B3 +:10C1400013000000130000001300000013000000A3 +:10C150001300000013000000130000001300000093 +:10C160001300000013000000130000001300000083 +:10C170001300000013000000130000001300000073 +:10C180001300000013000000130000001300000063 +:10C190001300000013000000130000001300000053 +:10C1A0001300000013000000130000001300000043 +:10C1B0001300000013000000130000001300000033 +:10C1C0001300000013000000130000001300000023 +:10C1D0001300000013000000130000001300000013 +:10C1E0001300000013000000130000001300000003 +:10C1F00013000000130000001300000013000000F3 +:10C2000013000000130000001300000013000000E2 +:10C2100013000000130000001300000013000000D2 +:10C2200013000000130000001300000013000000C2 +:10C2300013000000130000001300000013000000B2 +:10C2400013000000130000001300000013000000A2 +:10C250001300000013000000130000001300000092 +:10C260001300000013000000130000001300000082 +:10C270001300000013000000130000001300000072 +:10C280001300000013000000130000001300000062 +:10C290001300000013000000130000001300000052 +:10C2A0001300000013000000130000001300000042 +:10C2B0001300000013000000130000001300000032 +:10C2C0001300000013000000130000001300000022 +:10C2D0001300000013000000130000001300000012 +:10C2E0001300000013000000130000001300000002 +:10C2F00013000000130000001300000013000000F2 +:10C3000013000000130000001300000013000000E1 +:10C3100013000000130000001300000013000000D1 +:10C3200013000000130000001300000013000000C1 +:10C3300013000000130000001300000013000000B1 +:10C3400013000000130000001300000013000000A1 +:10C350001300000013000000130000001300000091 +:10C360001300000013000000130000001300000081 +:10C370001300000013000000130000001300000071 +:10C380001300000013000000130000001300000061 +:10C390001300000013000000130000001300000051 +:10C3A0001300000013000000130000001300000041 +:10C3B0001300000013000000130000001300000031 +:10C3C0001300000013000000130000001300000021 +:10C3D0001300000013000000130000001300000011 +:10C3E0001300000013000000130000001300000001 +:10C3F00013000000130000001300000013000000F1 +:10C4000013000000130000001300000013000000E0 +:10C4100013000000130000001300000013000000D0 +:10C4200013000000130000001300000013000000C0 +:10C4300013000000130000001300000013000000B0 +:10C4400013000000130000001300000013000000A0 +:10C450001300000013000000130000001300000090 +:10C460001300000013000000130000001300000080 +:10C470001300000013000000130000001300000070 +:10C480001300000013000000130000001300000060 +:10C490001300000013000000130000001300000050 +:10C4A0001300000013000000130000001300000040 +:10C4B0001300000013000000130000001300000030 +:10C4C0001300000013000000130000001300000020 +:10C4D0001300000013000000130000001300000010 +:10C4E0001300000013000000130000001300000000 +:10C4F00013000000130000001300000013000000F0 +:10C5000013000000130000001300000013000000DF +:10C5100013000000130000001300000013000000CF +:10C5200013000000130000001300000013000000BF +:10C5300013000000130000001300000013000000AF +:10C54000130000001300000013000000130000009F +:10C55000130000001300000013000000130000008F +:10C56000130000001300000013000000130000007F +:10C57000130000001300000013000000130000006F +:10C58000130000001300000013000000130000005F +:10C59000130000001300000013000000130000004F +:10C5A000130000001300000013000000130000003F +:10C5B000130000001300000013000000130000002F +:10C5C000130000001300000013000000130000001F +:10C5D000130000001300000013000000130000000F +:10C5E00013000000130000001300000013000000FF +:10C5F00013000000130000001300000013000000EF +:10C6000013000000130000001300000013000000DE +:10C6100013000000130000001300000013000000CE +:10C6200013000000130000001300000013000000BE +:10C6300013000000130000001300000013000000AE +:10C64000130000001300000013000000130000009E +:10C65000130000001300000013000000130000008E +:10C66000130000001300000013000000130000007E +:10C67000130000001300000013000000130000006E +:10C68000130000001300000013000000130000005E +:10C69000130000001300000013000000130000004E +:10C6A000130000001300000013000000130000003E +:10C6B000130000001300000013000000130000002E +:10C6C000130000001300000013000000130000001E +:10C6D000130000001300000013000000130000000E +:10C6E00013000000130000001300000013000000FE +:10C6F00013000000130000001300000013000000EE +:10C7000013000000130000001300000013000000DD +:10C7100013000000130000001300000013000000CD +:10C7200013000000130000001300000013000000BD +:10C7300013000000130000001300000013000000AD +:10C74000130000001300000013000000130000009D +:10C75000130000001300000013000000130000008D +:10C76000130000001300000013000000130000007D +:10C77000130000001300000013000000130000006D +:10C78000130000001300000013000000130000005D +:10C79000130000001300000013000000130000004D +:10C7A000130000001300000013000000130000003D +:10C7B000130000001300000013000000130000002D +:10C7C000130000001300000013000000130000001D +:10C7D000130000001300000013000000130000000D +:10C7E00013000000130000001300000013000000FD +:10C7F00013000000130000001300000013000000ED +:10C8000013000000130000001300000013000000DC +:10C8100013000000130000001300000013000000CC +:10C8200013000000130000001300000013000000BC +:10C8300013000000130000001300000013000000AC +:10C84000130000001300000013000000130000009C +:10C85000130000001300000013000000130000008C +:10C86000130000001300000013000000130000007C +:10C87000130000001300000013000000130000006C +:10C88000130000001300000013000000130000005C +:10C89000130000001300000013000000130000004C +:10C8A000130000001300000013000000130000003C +:10C8B000130000001300000013000000130000002C +:10C8C000130000001300000013000000130000001C +:10C8D000130000001300000013000000130000000C +:10C8E00013000000130000001300000013000000FC +:10C8F00013000000130000001300000013000000EC +:10C9000013000000130000001300000013000000DB +:10C9100013000000130000001300000013000000CB +:10C9200013000000130000001300000013000000BB +:10C9300013000000130000001300000013000000AB +:10C94000130000001300000013000000130000009B +:10C95000130000001300000013000000130000008B +:10C96000130000001300000013000000130000007B +:10C97000130000001300000013000000130000006B +:10C98000130000001300000013000000130000005B +:10C99000130000001300000013000000130000004B +:10C9A000130000001300000013000000130000003B +:10C9B000130000001300000013000000130000002B +:10C9C000130000001300000013000000130000001B +:10C9D000130000001300000013000000130000000B +:10C9E00013000000130000001300000013000000FB +:10C9F00013000000130000001300000013000000EB +:10CA000013000000130000001300000013000000DA +:10CA100013000000130000001300000013000000CA +:10CA200013000000130000001300000013000000BA +:10CA300013000000130000001300000013000000AA +:10CA4000130000001300000013000000130000009A +:10CA5000130000001300000013000000130000008A +:10CA6000130000001300000013000000130000007A +:10CA7000130000001300000013000000130000006A +:10CA8000130000001300000013000000130000005A +:10CA9000130000001300000013000000130000004A +:10CAA000130000001300000013000000130000003A +:10CAB000130000001300000013000000130000002A +:10CAC000130000001300000013000000130000001A +:10CAD000130000001300000013000000130000000A +:10CAE00013000000130000001300000013000000FA +:10CAF00013000000130000001300000013000000EA +:10CB000013000000130000001300000013000000D9 +:10CB100013000000130000001300000013000000C9 +:10CB200013000000130000001300000013000000B9 +:10CB300013000000130000001300000013000000A9 +:10CB40001300000013000000130000001300000099 +:10CB50001300000013000000130000001300000089 +:10CB60001300000013000000130000001300000079 +:10CB70001300000013000000130000001300000069 +:10CB80001300000013000000130000001300000059 +:10CB90001300000013000000130000001300000049 +:10CBA0001300000013000000130000001300000039 +:10CBB0001300000013000000130000001300000029 +:10CBC0001300000013000000130000001300000019 +:10CBD0001300000013000000130000001300000009 +:10CBE00013000000130000001300000013000000F9 +:10CBF00013000000130000001300000013000000E9 +:10CC000013000000130000001300000013000000D8 +:10CC100013000000130000001300000013000000C8 +:10CC200013000000130000001300000013000000B8 +:10CC300013000000130000001300000013000000A8 +:10CC40001300000013000000130000001300000098 +:10CC50001300000013000000130000001300000088 +:10CC60001300000013000000130000001300000078 +:10CC70001300000013000000130000001300000068 +:10CC80001300000013000000130000001300000058 +:10CC90001300000013000000130000001300000048 +:10CCA0001300000013000000130000001300000038 +:10CCB0001300000013000000130000001300000028 +:10CCC0001300000013000000130000001300000018 +:10CCD0001300000013000000130000001300000008 +:10CCE00013000000130000001300000013000000F8 +:10CCF00013000000130000001300000013000000E8 +:10CD000013000000130000001300000013000000D7 +:10CD100013000000130000001300000013000000C7 +:10CD200013000000130000001300000013000000B7 +:10CD300013000000130000001300000013000000A7 +:10CD40001300000013000000130000001300000097 +:10CD50001300000013000000130000001300000087 +:10CD60001300000013000000130000001300000077 +:10CD70001300000013000000130000001300000067 +:10CD80001300000013000000130000001300000057 +:10CD90001300000013000000130000001300000047 +:10CDA0001300000013000000130000001300000037 +:10CDB0001300000013000000130000001300000027 +:10CDC0001300000013000000130000001300000017 +:10CDD0001300000013000000130000001300000007 +:10CDE00013000000130000001300000013000000F7 +:10CDF00013000000130000001300000013000000E7 +:10CE000013000000130000001300000013000000D6 +:10CE100013000000130000001300000013000000C6 +:10CE200013000000130000001300000013000000B6 +:10CE300013000000130000001300000013000000A6 +:10CE40001300000013000000130000001300000096 +:10CE50001300000013000000130000001300000086 +:10CE60001300000013000000130000001300000076 +:10CE70001300000013000000130000001300000066 +:10CE80001300000013000000130000001300000056 +:10CE90001300000013000000130000001300000046 +:10CEA0001300000013000000130000001300000036 +:10CEB0001300000013000000130000001300000026 +:10CEC0001300000013000000130000001300000016 +:10CED0001300000013000000130000001300000006 +:10CEE00013000000130000001300000013000000F6 +:10CEF00013000000130000001300000013000000E6 +:10CF000013000000130000001300000013000000D5 +:10CF100013000000130000001300000013000000C5 +:10CF200013000000130000001300000013000000B5 +:10CF300013000000130000001300000013000000A5 +:10CF40001300000013000000130000001300000095 +:10CF50001300000013000000130000001300000085 +:10CF60001300000013000000130000001300000075 +:10CF70001300000013000000130000001300000065 +:10CF80001300000013000000130000001300000055 +:10CF90001300000013000000130000001300000045 +:10CFA0001300000013000000130000001300000035 +:10CFB0001300000013000000130000001300000025 +:10CFC0001300000013000000130000001300000015 +:10CFD0001300000013000000130000001300000005 +:10CFE00013000000130000001300000013000000F5 +:10CFF00013000000130000001300000013000000E5 +:10D00000130E3003B71001909380800037615A5B94 +:10D010001301819583A00000638420006F304FCA04 +:10D02000B7A000A0938040323701EEAA130181001F +:10D0300023A0200083A00000638420006F304FC82D +:10D04000130E400397000000938080013721019068 +:10D0500013010101670001006F308FC6130E5003EA +:10D06000930E1000170F0000130F8F01B7400190AF +:10D0700093800039678000006F308FC4130E600307 +:10D08000930E1000170F0000130F8F01B74001908F +:10D090009380403983A000006F308FC2130E70035D +:10D0A000930E1000170F0000130F8F01B74001906F +:10D0B0009380803923A010006F308FC0930E200022 +:10D0C00073000000000000000000000000000000ED +:10D0D0000000000000000000000000000000000050 +:10D0E0000000000000000000000000000000000040 +:10D0F0000000000000000000000000000000000030 +:10D10000000000000000000000000000000000001F +:10D11000000000000000000000000000000000000F +:10D1200000000000000000000000000000000000FF +:10D1300000000000000000000000000000000000EF +:10D1400000000000000000000000000000000000DF +:10D1500000000000000000000000000000000000CF +:10D1600000000000000000000000000000000000BF +:10D1700000000000000000000000000000000000AF +:10D18000000000000000000000000000000000009F +:10D19000000000000000000000000000000000008F +:10D1A000000000000000000000000000000000007F +:10D1B000000000000000000000000000000000006F +:10D1C000000000000000000000000000000000005F +:10D1D000000000000000000000000000000000004F +:10D1E000000000000000000000000000000000003F +:10D1F000000000000000000000000000000000002F +:10D20000000000000000000000000000000000001E +:10D21000000000000000000000000000000000000E +:10D2200000000000000000000000000000000000FE +:10D2300000000000000000000000000000000000EE +:10D2400000000000000000000000000000000000DE +:10D2500000000000000000000000000000000000CE +:10D2600000000000000000000000000000000000BE +:10D2700000000000000000000000000000000000AE +:10D28000000000000000000000000000000000009E +:10D29000000000000000000000000000000000008E +:10D2A000000000000000000000000000000000007E +:10D2B000000000000000000000000000000000006E +:10D2C000000000000000000000000000000000005E +:10D2D000000000000000000000000000000000004E +:10D2E000000000000000000000000000000000003E +:10D2F000000000000000000000000000000000002E +:10D30000000000000000000000000000000000001D +:10D31000000000000000000000000000000000000D +:10D3200000000000000000000000000000000000FD +:10D3300000000000000000000000000000000000ED +:10D3400000000000000000000000000000000000DD +:10D3500000000000000000000000000000000000CD +:10D3600000000000000000000000000000000000BD +:10D3700000000000000000000000000000000000AD +:10D38000000000000000000000000000000000009D +:10D39000000000000000000000000000000000008D +:10D3A000000000000000000000000000000000007D +:10D3B000000000000000000000000000000000006D +:10D3C000000000000000000000000000000000005D +:10D3D000000000000000000000000000000000004D +:10D3E000000000000000000000000000000000003D +:10D3F000000000000000000000000000000000002D +:10D40000000000000000000000000000000000001C +:10D41000000000000000000000000000000000000C +:10D4200000000000000000000000000000000000FC +:10D4300000000000000000000000000000000000EC +:10D4400000000000000000000000000000000000DC +:10D4500000000000000000000000000000000000CC +:10D4600000000000000000000000000000000000BC +:10D4700000000000000000000000000000000000AC +:10D48000000000000000000000000000000000009C +:10D49000000000000000000000000000000000008C +:10D4A000000000000000000000000000000000007C +:10D4B000000000000000000000000000000000006C +:10D4C000000000000000000000000000000000005C +:10D4D000000000000000000000000000000000004C +:10D4E000000000000000000000000000000000003C +:10D4F000000000000000000000000000000000002C +:10D50000000000000000000000000000000000001B +:10D51000000000000000000000000000000000000B +:10D5200000000000000000000000000000000000FB +:10D5300000000000000000000000000000000000EB +:10D5400000000000000000000000000000000000DB +:10D5500000000000000000000000000000000000CB +:10D5600000000000000000000000000000000000BB +:10D5700000000000000000000000000000000000AB +:10D58000000000000000000000000000000000009B +:10D59000000000000000000000000000000000008B +:10D5A000000000000000000000000000000000007B +:10D5B000000000000000000000000000000000006B +:10D5C000000000000000000000000000000000005B +:10D5D000000000000000000000000000000000004B +:10D5E000000000000000000000000000000000003B +:10D5F000000000000000000000000000000000002B +:10D60000000000000000000000000000000000001A +:10D61000000000000000000000000000000000000A +:10D6200000000000000000000000000000000000FA +:10D6300000000000000000000000000000000000EA +:10D6400000000000000000000000000000000000DA +:10D6500000000000000000000000000000000000CA +:10D6600000000000000000000000000000000000BA +:10D6700000000000000000000000000000000000AA +:10D68000000000000000000000000000000000009A +:10D69000000000000000000000000000000000008A +:10D6A000000000000000000000000000000000007A +:10D6B000000000000000000000000000000000006A +:10D6C000000000000000000000000000000000005A +:10D6D000000000000000000000000000000000004A +:10D6E000000000000000000000000000000000003A +:10D6F000000000000000000000000000000000002A +:10D700000000000000000000000000000000000019 +:10D710000000000000000000000000000000000009 +:10D7200000000000000000000000000000000000F9 +:10D7300000000000000000000000000000000000E9 +:10D7400000000000000000000000000000000000D9 +:10D7500000000000000000000000000000000000C9 +:10D7600000000000000000000000000000000000B9 +:10D7700000000000000000000000000000000000A9 +:10D780000000000000000000000000000000000099 +:10D790000000000000000000000000000000000089 +:10D7A0000000000000000000000000000000000079 +:10D7B0000000000000000000000000000000000069 +:10D7C0000000000000000000000000000000000059 +:10D7D0000000000000000000000000000000000049 +:10D7E0000000000000000000000000000000000039 +:10D7F0000000000000000000000000000000000029 +:10D800000000000000000000000000000000000018 +:10D810000000000000000000000000000000000008 +:10D8200000000000000000000000000000000000F8 +:10D8300000000000000000000000000000000000E8 +:10D8400000000000000000000000000000000000D8 +:10D8500000000000000000000000000000000000C8 +:10D8600000000000000000000000000000000000B8 +:10D8700000000000000000000000000000000000A8 +:10D880000000000000000000000000000000000098 +:10D890000000000000000000000000000000000088 +:10D8A0000000000000000000000000000000000078 +:10D8B0000000000000000000000000000000000068 +:10D8C0000000000000000000000000000000000058 +:10D8D0000000000000000000000000000000000048 +:10D8E0000000000000000000000000000000000038 +:10D8F0000000000000000000000000000000000028 +:10D900000000000000000000000000000000000017 +:10D910000000000000000000000000000000000007 +:10D9200000000000000000000000000000000000F7 +:10D9300000000000000000000000000000000000E7 +:10D9400000000000000000000000000000000000D7 +:10D9500000000000000000000000000000000000C7 +:10D9600000000000000000000000000000000000B7 +:10D9700000000000000000000000000000000000A7 +:10D980000000000000000000000000000000000097 +:10D990000000000000000000000000000000000087 +:10D9A0000000000000000000000000000000000077 +:10D9B0000000000000000000000000000000000067 +:10D9C0000000000000000000000000000000000057 +:10D9D0000000000000000000000000000000000047 +:10D9E0000000000000000000000000000000000037 +:10D9F0000000000000000000000000000000000027 +:10DA00000000000000000000000000000000000016 +:10DA10000000000000000000000000000000000006 +:10DA200000000000000000000000000000000000F6 +:10DA300000000000000000000000000000000000E6 +:10DA400000000000000000000000000000000000D6 +:10DA500000000000000000000000000000000000C6 :040000058000000077 :00000001FF From 13d66b3ae429318d63e272c70a38f33556a7636d Mon Sep 17 00:00:00 2001 From: Leon Schuermann Date: Fri, 24 Feb 2023 16:08:39 -0500 Subject: [PATCH 848/951] Fetcher: insert FORMAL_MODE encoded from privilegeService Previously, FORMAL_MODE would simply be hard-coded to "11", indicating machine mode. However, that's not necessarily true when using the CsrPlugin, which allows to switch the hart into either User or optional Supervisor mode. Hence we create a FORMAL_MODE insert in the fetch-phase (which is generally when the MPP register can take effect) and generate `rvfi_mode` based on that insert. --- src/main/scala/vexriscv/Services.scala | 14 ++++++++++++++ src/main/scala/vexriscv/VexRiscv.scala | 1 + src/main/scala/vexriscv/plugin/Fetcher.scala | 7 +++++++ src/main/scala/vexriscv/plugin/FormalPlugin.scala | 2 +- 4 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/Services.scala b/src/main/scala/vexriscv/Services.scala index 140c69bc..f0ef7136 100644 --- a/src/main/scala/vexriscv/Services.scala +++ b/src/main/scala/vexriscv/Services.scala @@ -50,6 +50,20 @@ trait PrivilegeService{ def isSupervisor() : Bool def isMachine() : Bool def forceMachine() : Unit + + def encodeBits() : Bits = { + val encoded = Bits(2 bits) + + when(this.isUser()) { + encoded := "00" + }.elsewhen(this.isSupervisor()) { + encoded := "01" + }.otherwise { + encoded := "11" + } + + encoded + } } case class PrivilegeServiceDefault() extends PrivilegeService{ diff --git a/src/main/scala/vexriscv/VexRiscv.scala b/src/main/scala/vexriscv/VexRiscv.scala index ed7e37e7..ebf20089 100644 --- a/src/main/scala/vexriscv/VexRiscv.scala +++ b/src/main/scala/vexriscv/VexRiscv.scala @@ -95,6 +95,7 @@ case class VexRiscvConfig(){ object FORMAL_MEM_RDATA extends Stageable(Bits(32 bits)) object FORMAL_MEM_WDATA extends Stageable(Bits(32 bits)) object FORMAL_INSTRUCTION extends Stageable(Bits(32 bits)) + object FORMAL_MODE extends Stageable(Bits(2 bits)) object Src1CtrlEnum extends SpinalEnum(binarySequential){ diff --git a/src/main/scala/vexriscv/plugin/Fetcher.scala b/src/main/scala/vexriscv/plugin/Fetcher.scala index f793084e..061be18c 100644 --- a/src/main/scala/vexriscv/plugin/Fetcher.scala +++ b/src/main/scala/vexriscv/plugin/Fetcher.scala @@ -415,6 +415,8 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, decode.arbitration.isValid clearWhen(forceNoDecodeCond) }) + val privilegeService = pipeline.serviceElse(classOf[PrivilegeService], PrivilegeServiceDefault()) + //Formal verification signals generation, miss prediction stuff ? val formal = new Area { val raw = if(compressedGen) decompressor.raw else inputBeforeStage.rsp.inst @@ -437,6 +439,11 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, info.stage.output(FORMAL_PC_NEXT) := info.interface.payload } }) + + // Forward the current CPU "mode" (privilege level) from the fetch + // stage, which is where it can begin to affect the current + // execution (e.g., through PMP checks). + decode.insert(FORMAL_MODE) := privilegeService.encodeBits() } } diff --git a/src/main/scala/vexriscv/plugin/FormalPlugin.scala b/src/main/scala/vexriscv/plugin/FormalPlugin.scala index 2d70ebd8..5b5e0d58 100644 --- a/src/main/scala/vexriscv/plugin/FormalPlugin.scala +++ b/src/main/scala/vexriscv/plugin/FormalPlugin.scala @@ -93,7 +93,7 @@ class FormalPlugin extends Plugin[VexRiscv]{ rvfi.trap := False rvfi.halt := False rvfi.intr := False - rvfi.mode := 3 + rvfi.mode := output(FORMAL_MODE) rvfi.ixl := 1 // rvfi.rs1.addr := output(INSTRUCTION)(rs1Range).asUInt // rvfi.rs2.addr := output(INSTRUCTION)(rs2Range).asUInt From 49246e757f242b66e6b691fba28e022c15b94aa2 Mon Sep 17 00:00:00 2001 From: Leon Schuermann Date: Fri, 24 Feb 2023 16:34:06 -0500 Subject: [PATCH 849/951] CsrPlugin: insert FORMAL_HALT := False --- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 8eeb8983..b59fd897 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -670,6 +670,10 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep } } + // The CSR plugin will invoke a trap handler on exception, which does not + // count as halt-state by the RVFI spec, and neither do other instructions + // such as `wfi`, etc. Hence statically drive the output: + pipeline.stages.head.insert(FORMAL_HALT) := False case class Xtvec() extends Bundle { val mode = Bits(2 bits) From 5f67075e3094f1f31b7fe9f480e08fc5c32b28c3 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 1 Mar 2023 13:56:25 +0100 Subject: [PATCH 850/951] Fix FPU with F64 support, not removing mantissa precision from F32 #317 --- src/main/scala/vexriscv/ip/fpu/FpuCore.scala | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala index a9e9959d..9cdaab5a 100644 --- a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala +++ b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala @@ -1688,7 +1688,12 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ port.valid := input.valid && input.write port.address := input.source @@ input.rd port.data.value := input.value - if(p.withDouble) port.data.boxed := input.format === FpuFormat.FLOAT + if(p.withDouble) { + port.data.boxed := input.format === FpuFormat.FLOAT + when(port.data.boxed){ + port.data.value.mantissa(p.internalMantissaSize-23-1 downto 0) := 0 + } + } val randomSim = p.sim generate (in UInt(p.internalMantissaSize bits)) if(p.sim) when(port.data.value.isZero || port.data.value.isInfinity){ From 5493c55ab0b618d3af7f725caaa7eafe954842c5 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 3 Mar 2023 09:06:20 +0100 Subject: [PATCH 851/951] Alows Fetcher to have multiple debug injection ports --- .../scala/vexriscv/VexRiscvBmbGenerator.scala | 31 ++++++++++++------- .../scala/vexriscv/plugin/CsrPlugin.scala | 2 +- .../scala/vexriscv/plugin/DebugPlugin.scala | 2 +- src/main/scala/vexriscv/plugin/Fetcher.scala | 20 +++++++++--- 4 files changed, 37 insertions(+), 18 deletions(-) diff --git a/src/main/scala/vexriscv/VexRiscvBmbGenerator.scala b/src/main/scala/vexriscv/VexRiscvBmbGenerator.scala index 7468c85c..2754d391 100644 --- a/src/main/scala/vexriscv/VexRiscvBmbGenerator.scala +++ b/src/main/scala/vexriscv/VexRiscvBmbGenerator.scala @@ -16,7 +16,6 @@ object VexRiscvBmbGenerator{ val DEBUG_JTAG_CTRL = 2 val DEBUG_BUS = 3 val DEBUG_BMB = 4 - val DEBUG_RISCV = 5 } case class VexRiscvBmbGenerator()(implicit interconnectSmp: BmbInterconnectGenerator = null) extends Area { @@ -24,6 +23,7 @@ case class VexRiscvBmbGenerator()(implicit interconnectSmp: BmbInterconnectGener val config = Handle[VexRiscvConfig] val withDebug = Handle[Int] + val withRiscvDebug = Handle[Boolean] val debugClockDomain = Handle[ClockDomain] val debugReset = Handle[Bool] val debugAskReset = Handle[() => Unit] @@ -42,6 +42,7 @@ case class VexRiscvBmbGenerator()(implicit interconnectSmp: BmbInterconnectGener def disableDebug() = { withDebug.load(DEBUG_NONE) + withRiscvDebug.load(false) } def enableJtag(debugCd : ClockDomainResetGenerator, resetCd : ClockDomainResetGenerator) : Unit = debugCd.rework{ @@ -49,6 +50,7 @@ case class VexRiscvBmbGenerator()(implicit interconnectSmp: BmbInterconnectGener val resetBridge = resetCd.asyncReset(debugReset, ResetSensitivity.HIGH) debugAskReset.loadNothing() withDebug.load(DEBUG_JTAG) + if(!withRiscvDebug.isLoaded) withRiscvDebug.load(false) } def enableJtagInstructionCtrl(debugCd : ClockDomainResetGenerator, resetCd : ClockDomainResetGenerator) : Unit = debugCd.rework{ @@ -56,6 +58,7 @@ case class VexRiscvBmbGenerator()(implicit interconnectSmp: BmbInterconnectGener val resetBridge = resetCd.asyncReset(debugReset, ResetSensitivity.HIGH) debugAskReset.loadNothing() withDebug.load(DEBUG_JTAG_CTRL) + if(!withRiscvDebug.isLoaded) withRiscvDebug.load(false) } def enableDebugBus(debugCd : ClockDomainResetGenerator, resetCd : ClockDomainResetGenerator) : Unit = debugCd.rework{ @@ -63,14 +66,23 @@ case class VexRiscvBmbGenerator()(implicit interconnectSmp: BmbInterconnectGener val resetBridge = resetCd.asyncReset(debugReset, ResetSensitivity.HIGH) debugAskReset.loadNothing() withDebug.load(DEBUG_BUS) + if(!withRiscvDebug.isLoaded) withRiscvDebug.load(false) } def enableRiscvDebug(debugCd : Handle[ClockDomain], resetCd : ClockDomainResetGenerator) : Unit = debugCd.on{ this.debugClockDomain.load(debugCd) debugAskReset.loadNothing() - withDebug.load(DEBUG_RISCV) + withRiscvDebug.load(true) + if(!withDebug.isLoaded) withDebug.load(DEBUG_NONE) } +// def enableRiscvAndBusDebugPlus(debugCd : Handle[ClockDomain], resetCd : ClockDomainResetGenerator) : Unit = debugCd.on{ +// this.debugClockDomain.load(debugCd) +// val resetBridge = resetCd.asyncReset(debugReset, ResetSensitivity.HIGH) +// debugAskReset.loadNothing() +// withRiscvDebug.load(true) +// } + val debugBmbAccessSource = Handle[BmbAccessCapabilities] val debugBmbAccessRequirements = Handle[BmbAccessParameter] def enableDebugBmb(debugCd : Handle[ClockDomain], resetCd : ClockDomainResetGenerator, mapping : AddressMapping)(implicit debugMaster : BmbImplicitDebugDecoder = null) : Unit = debugCd.on{ @@ -78,6 +90,7 @@ case class VexRiscvBmbGenerator()(implicit interconnectSmp: BmbInterconnectGener val resetBridge = resetCd.asyncReset(debugReset, ResetSensitivity.HIGH) debugAskReset.loadNothing() withDebug.load(DEBUG_BMB) + if(!withRiscvDebug.isLoaded) withRiscvDebug.load(false) val slaveModel = debugCd on interconnectSmp.addSlave( accessSource = debugBmbAccessSource, accessCapabilities = debugBmbAccessSource.derivate(DebugExtensionBus.getBmbAccessParameter(_)), @@ -93,13 +106,12 @@ case class VexRiscvBmbGenerator()(implicit interconnectSmp: BmbInterconnectGener val jtagInstructionCtrl = withDebug.produce(withDebug.get == DEBUG_JTAG_CTRL generate JtagTapInstructionCtrl()) val debugBus = withDebug.produce(withDebug.get == DEBUG_BUS generate DebugExtensionBus()) val debugBmb = Handle[Bmb] - val debugRiscv = withDebug.produce(withDebug.get == DEBUG_RISCV generate DebugHartBus()) + val debugRiscv = withRiscvDebug.produce(withRiscvDebug.get generate DebugHartBus()) val jtagClockDomain = Handle[ClockDomain] val logic = Handle(new Area { withDebug.get match { case DEBUG_NONE => - case DEBUG_RISCV => case _ => config.add(new DebugPlugin(debugClockDomain, hardwareBreakpointCount)) } @@ -142,12 +154,9 @@ case class VexRiscvBmbGenerator()(implicit interconnectSmp: BmbInterconnectGener timerInterrupt load plugin.timerInterrupt softwareInterrupt load plugin.softwareInterrupt if (plugin.config.supervisorGen) externalSupervisorInterrupt load plugin.externalInterruptS - withDebug.get match { - case DEBUG_RISCV => { - assert(plugin.debugBus != null, "You need to enable CsrPluginConfig.withPrivilegedDebug") - debugRiscv <> plugin.debugBus - } - case _ => + if(withRiscvDebug.get) { + assert(plugin.debugBus != null, "You need to enable CsrPluginConfig.withPrivilegedDebug") + debugRiscv <> plugin.debugBus } } case plugin: DebugPlugin => plugin.debugClockDomain { @@ -160,7 +169,7 @@ case class VexRiscvBmbGenerator()(implicit interconnectSmp: BmbInterconnectGener withDebug.get match { case DEBUG_JTAG => jtag <> plugin.io.bus.fromJtag() case DEBUG_JTAG_CTRL => jtagInstructionCtrl <> plugin.io.bus.fromJtagInstructionCtrl(jtagClockDomain, 0) - case DEBUG_BUS => debugBus <> plugin.io.bus + case DEBUG_BUS => debugBus <> plugin.io.bus case DEBUG_BMB => debugBmb >> plugin.io.bus.fromBmb() } } diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index a53363ce..c1b6beca 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -641,7 +641,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep xretAwayFromMachine = False - injectionPort = withPrivilegedDebug generate pipeline.service(classOf[IBusFetcher]).getInjectionPort() + injectionPort = withPrivilegedDebug generate pipeline.service(classOf[IBusFetcher]).getInjectionPort().setCompositeName(this, "injectionPort") debugMode = withPrivilegedDebug generate Bool().setName("debugMode") debugBus = withPrivilegedDebug generate slave(DebugHartBus()).setName("debugBus") } diff --git a/src/main/scala/vexriscv/plugin/DebugPlugin.scala b/src/main/scala/vexriscv/plugin/DebugPlugin.scala index d62c4de4..485e3808 100644 --- a/src/main/scala/vexriscv/plugin/DebugPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DebugPlugin.scala @@ -209,7 +209,7 @@ class DebugPlugin(var debugClockDomain : ClockDomain, hardwareBreakpointCount : decoderService.addDefault(IS_EBREAK, False) decoderService.add(EBREAK,List(IS_EBREAK -> True)) - injectionPort = pipeline.service(classOf[IBusFetcher]).getInjectionPort() + injectionPort = pipeline.service(classOf[IBusFetcher]).getInjectionPort().setCompositeName(this, "injectionPort") if(pipeline.serviceExist(classOf[ReportService])){ val report = pipeline.service(classOf[ReportService]) diff --git a/src/main/scala/vexriscv/plugin/Fetcher.scala b/src/main/scala/vexriscv/plugin/Fetcher.scala index f793084e..e9b40f5d 100644 --- a/src/main/scala/vexriscv/plugin/Fetcher.scala +++ b/src/main/scala/vexriscv/plugin/Fetcher.scala @@ -42,10 +42,9 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, override def withRvc(): Boolean = compressedGen - var injectionPort : Stream[Bits] = null + val injectionPorts = ArrayBuffer[Stream[Bits]]() override def getInjectionPort() = { - injectionPort = Stream(Bits(32 bits)) - injectionPort + injectionPorts.addRet(Stream(Bits(32 bits))) } def pcRegReusedForSecondStage = allowPcRegReusedForSecondStage && prediction != DYNAMIC_TARGET //TODO might not be required for DYNAMIC_TARGET var predictionJumpInterface : Flow[UInt] = null @@ -354,9 +353,20 @@ abstract class IBusFetcherImpl(val resetVector : BigInt, decode.insert(INSTRUCTION) := decodeInput.rsp.inst if (compressedGen) decode.insert(IS_RVC) := decodeInput.isRvc - if (injectionPort != null) { - Component.current.addPrePopTask(() => { + if (injectionPorts.nonEmpty) { + Component.current.addPrePopTask(() => new Composite(this, "port"){ val state = RegInit(U"000") + val injectionPort = injectionPorts.size match { + case 1 => injectionPorts.head + case _ => { + val p = Stream(Bits(32 bits)) + //assume only one port is used at the time + p.valid := injectionPorts.map(_.valid).orR + p.payload := OHMux(injectionPorts.map(_.valid), injectionPorts.map(_.payload)) + injectionPorts.foreach(_.ready := p.ready) + p + } + } injectionPort.ready := False if(decodePcGen){ From b03b00a5c4c0e56e3f1d50f6914fc35c94d0f8d4 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 3 Mar 2023 14:13:47 +0100 Subject: [PATCH 852/951] Improve d$ coupled timings --- .../scala/vexriscv/plugin/DBusCachedPlugin.scala | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index 3c8f9c52..d959d65e 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -52,7 +52,8 @@ class DBusCachedPlugin(val config : DataCacheConfig, dBusCmdSlavePipe : Boolean = false, dBusRspSlavePipe : Boolean = false, relaxedMemoryTranslationRegister : Boolean = false, - csrInfo : Boolean = false) extends Plugin[VexRiscv] with DBusAccessService with DBusEncodingService with VexRiscvRegressionArg { + csrInfo : Boolean = false, + tightlyCoupledAddressStage : Boolean = false) extends Plugin[VexRiscv] with DBusAccessService with DBusEncodingService with VexRiscvRegressionArg { import config._ assert(!(config.withExternalAmo && !dBusRspSlavePipe)) assert(isPow2(cacheSize)) @@ -405,6 +406,14 @@ class DBusCachedPlugin(val config : DataCacheConfig, } if(tightlyGen){ + tightlyCoupledAddressStage match { + case false => + case true => { + val go = RegInit(False) setWhen(arbitration.isValid) clearWhen(arbitration.isMoving) + arbitration.haltItself.setWhen(arbitration.isValid && input(MEMORY_TIGHTLY).orR && !go) + } + } + insert(MEMORY_TIGHTLY) := B(tightlyCoupledPorts.map(_.p.hit(input(SRC_ADD).asUInt))) when(insert(MEMORY_TIGHTLY).orR){ cache.io.cpu.execute.isValid := False @@ -412,7 +421,8 @@ class DBusCachedPlugin(val config : DataCacheConfig, } 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.address := Delay(input(SRC_ADD), tightlyCoupledAddressStage.toInt).asUInt.resized port.bus.write_enable := input(MEMORY_WR) port.bus.write_data := input(MEMORY_STORE_DATA_RF) port.bus.write_mask := size.mux ( @@ -446,7 +456,7 @@ class DBusCachedPlugin(val config : DataCacheConfig, input(HAS_SIDE_EFFECT) := False } insert(MEMORY_TIGHTLY_DATA) := OhMux(input(MEMORY_TIGHTLY), tightlyCoupledPorts.map(_.bus.read_data)) - } + KeepAttribute(insert(MEMORY_TIGHTLY_DATA)) } } val managementStage = stages.last From cf70bc6b1ff5d240f85ea42348a7a01056fe46fd Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 3 Mar 2023 14:20:12 +0100 Subject: [PATCH 853/951] fix last push --- src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index d959d65e..34b003ea 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -410,7 +410,7 @@ class DBusCachedPlugin(val config : DataCacheConfig, case false => case true => { val go = RegInit(False) setWhen(arbitration.isValid) clearWhen(arbitration.isMoving) - arbitration.haltItself.setWhen(arbitration.isValid && input(MEMORY_TIGHTLY).orR && !go) + arbitration.haltItself.setWhen(arbitration.isValid && input(MEMORY_ENABLE) && input(MEMORY_TIGHTLY).orR && !go) } } From 153445ff2145f1a1ee2ed7ccd042a34da0876887 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Sat, 4 Mar 2023 12:20:53 +0100 Subject: [PATCH 854/951] Fix CFU / FPU decoder stage fork on illegal instruction --- src/main/scala/vexriscv/plugin/CfuPlugin.scala | 3 ++- src/main/scala/vexriscv/plugin/FpuPlugin.scala | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/CfuPlugin.scala b/src/main/scala/vexriscv/plugin/CfuPlugin.scala index d343640d..219f9622 100644 --- a/src/main/scala/vexriscv/plugin/CfuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CfuPlugin.scala @@ -182,12 +182,13 @@ class CfuPlugin(val stageCount : Int, } } - if(withEnable) when(decode.input(CFU_ENABLE) && !csr.en){ + if(withEnable) when(decode.insert(CFU_ENABLE) && !csr.en){ pipeline.service(classOf[DecoderService]).forceIllegal() } forkStage plug new Area{ import forkStage._ + input(CFU_ENABLE).clearWhen(!input(LEGAL_INSTRUCTION)) val hazard = stages.dropWhile(_ != forkStage).tail.map(s => s.arbitration.isValid && s.input(HAS_SIDE_EFFECT)).orR val scheduleWish = arbitration.isValid && input(CFU_ENABLE) val schedule = scheduleWish && !hazard diff --git a/src/main/scala/vexriscv/plugin/FpuPlugin.scala b/src/main/scala/vexriscv/plugin/FpuPlugin.scala index 8df6fa81..ec9087d4 100644 --- a/src/main/scala/vexriscv/plugin/FpuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/FpuPlugin.scala @@ -243,7 +243,7 @@ class FpuPlugin(externalFpu : Boolean = false, decode plug new Area{ import decode._ - val trap = decode.input(FPU_ENABLE) && csr.fs === 0 && !stagesFromExecute.map(_.arbitration.isValid).orR + val trap = insert(FPU_ENABLE) && csr.fs === 0 && !stagesFromExecute.map(_.arbitration.isValid).orR when(trap){ pipeline.service(classOf[DecoderService]).forceIllegal() } @@ -253,6 +253,7 @@ class FpuPlugin(externalFpu : Boolean = false, val hazard = csr.pendings.msb || csr.csrActive || csr.fs === 0 + input(FPU_ENABLE).clearWhen(!input(LEGAL_INSTRUCTION)) arbitration.haltItself setWhen(arbitration.isValid && input(FPU_ENABLE) && hazard) arbitration.haltItself setWhen(port.cmd.isStall) From 3cf8508db14bba4df6ccd5a017bf3119d0779a09 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Sun, 5 Mar 2023 20:31:40 +0800 Subject: [PATCH 855/951] DBus coupled timings improvement --- src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index 34b003ea..4a955947 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -409,7 +409,7 @@ class DBusCachedPlugin(val config : DataCacheConfig, tightlyCoupledAddressStage match { case false => case true => { - val go = RegInit(False) setWhen(arbitration.isValid) clearWhen(arbitration.isMoving) + val go = RegInit(False) setWhen(arbitration.isValid) clearWhen(!arbitration.isStuck) arbitration.haltItself.setWhen(arbitration.isValid && input(MEMORY_ENABLE) && input(MEMORY_TIGHTLY).orR && !go) } } From f11c642cd6d16e003aea0a85d004eb89a44ecfd6 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Tue, 7 Mar 2023 16:49:07 +0800 Subject: [PATCH 856/951] CfuPlugin encoding can now specify cmd/rsp less instruction --- .../scala/vexriscv/plugin/CfuPlugin.scala | 52 +++++++++++++------ 1 file changed, 35 insertions(+), 17 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/CfuPlugin.scala b/src/main/scala/vexriscv/plugin/CfuPlugin.scala index 219f9622..2a18b2d1 100644 --- a/src/main/scala/vexriscv/plugin/CfuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CfuPlugin.scala @@ -1,6 +1,6 @@ package vexriscv.plugin -import vexriscv.{DecoderService, ExceptionCause, ExceptionService, Stage, Stageable, VexRiscv} +import vexriscv.{DecoderService, ExceptionCause, ExceptionService, JumpService, Stage, Stageable, VexRiscv} import spinal.core._ import spinal.lib._ import spinal.lib.bus.bmb.WeakConnector @@ -92,7 +92,9 @@ object CfuPlugin{ case class CfuPluginEncoding(instruction : MaskedLiteral, functionId : List[Range], - input2Kind : CfuPlugin.Input2Kind.E){ + input2Kind : CfuPlugin.Input2Kind.E, + withCmd : Boolean = true, + withRsp : Boolean = true){ val functionIdWidth = functionId.map(_.size).sum } @@ -110,6 +112,7 @@ class CfuPlugin(val stageCount : Int, // assert(p.CFU_FUNCTION_ID_W == 3) var bus : CfuBus = null +// var redoInterface : Flow[UInt] = null lazy val forkStage = pipeline.execute lazy val joinStage = pipeline.stages(Math.min(pipeline.stages.length - 1, pipeline.indexOf(forkStage) + stageCount)) @@ -119,31 +122,45 @@ class CfuPlugin(val stageCount : Int, val CFU_IN_FLIGHT = new Stageable(Bool()).setCompositeName(this, "CFU_IN_FLIGHT") val CFU_ENCODING = new Stageable(UInt(log2Up(encodings.size) bits)).setCompositeName(this, "CFU_ENCODING") val CFU_INPUT_2_KIND = new Stageable(CfuPlugin.Input2Kind()).setCompositeName(this, "CFU_INPUT_2_KIND") + val CFU_WITH_CMD = new Stageable(Bool()).setCompositeName(this, "CFU_WITH_CMD") + val CFU_WITH_RSP = new Stageable(Bool()).setCompositeName(this, "CFU_WITH_RSP") override def setup(pipeline: VexRiscv): Unit = { import pipeline._ import pipeline.config._ +// val pcManagerService = pipeline.service(classOf[JumpService]) +// if(encodings.contains(_.cmd)redoInterface = pcManagerService.createJumpInterface(pipeline.writeBack) + bus = master(CfuBus(p)) val decoderService = pipeline.service(classOf[DecoderService]) decoderService.addDefault(CFU_ENABLE, False) + decoderService.addDefault(CFU_WITH_CMD, False) + decoderService.addDefault(CFU_WITH_RSP, False) for((encoding, id) <- encodings.zipWithIndex){ - var actions = List( + var actions : List[(Stageable[_ <: BaseType], Any)] = List( CFU_ENABLE -> True, - REGFILE_WRITE_VALID -> True, - BYPASSABLE_EXECUTE_STAGE -> Bool(stageCount == 0), - BYPASSABLE_MEMORY_STAGE -> Bool(stageCount <= 1), - RS1_USE -> True, CFU_ENCODING -> U(id), - CFU_INPUT_2_KIND -> encoding.input2Kind() + CFU_WITH_CMD -> Bool(encoding.withCmd), + CFU_WITH_RSP -> Bool(encoding.withRsp) ) - encoding.input2Kind match { - case CfuPlugin.Input2Kind.RS => - actions :+= RS2_USE -> True - case CfuPlugin.Input2Kind.IMM_I => + if(encoding.withCmd){ + actions :+= RS1_USE -> True + actions :+= CFU_INPUT_2_KIND -> encoding.input2Kind() + encoding.input2Kind match { + case CfuPlugin.Input2Kind.RS => + actions :+= RS2_USE -> True + case CfuPlugin.Input2Kind.IMM_I => + } + } + + if(encoding.withRsp){ + actions :+= REGFILE_WRITE_VALID -> True + actions :+= BYPASSABLE_EXECUTE_STAGE -> Bool(stageCount == 0) + actions :+= BYPASSABLE_MEMORY_STAGE -> Bool(stageCount <= 1) } decoderService.add( @@ -190,7 +207,7 @@ class CfuPlugin(val stageCount : Int, import forkStage._ input(CFU_ENABLE).clearWhen(!input(LEGAL_INSTRUCTION)) val hazard = stages.dropWhile(_ != forkStage).tail.map(s => s.arbitration.isValid && s.input(HAS_SIDE_EFFECT)).orR - val scheduleWish = arbitration.isValid && input(CFU_ENABLE) + val scheduleWish = arbitration.isValid && input(CFU_ENABLE) && input(CFU_WITH_CMD) val schedule = scheduleWish && !hazard arbitration.haltItself setWhen(scheduleWish && hazard) @@ -233,12 +250,13 @@ class CfuPlugin(val stageCount : Int, bus.rsp.combStage() } + val hazard = stages.dropWhile(_ != joinStage).tail.map(s => s.arbitration.isValid && s.input(HAS_SIDE_EFFECT)).orR rsp.ready := False - when(input(CFU_IN_FLIGHT)){ - arbitration.haltItself setWhen(!rsp.valid) - rsp.ready := !arbitration.isStuckByOthers + when((arbitration.isValid || input(CFU_IN_FLIGHT)) && input(CFU_WITH_RSP)){ + arbitration.haltItself setWhen(!rsp.valid || hazard) + rsp.ready := !arbitration.isStuckByOthers && !hazard output(REGFILE_WRITE_DATA) := rsp.outputs(0) - if(p.CFU_WITH_STATUS) when(arbitration.isFiring){ + if(p.CFU_WITH_STATUS) when(rsp.fire){ switch(rsp.status) { for (i <- 1 to 6) is(i) { csr.status.flags(i-1) := True From 1179c6551f41e0a4c293fa29da6417bc51984e86 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Wed, 8 Mar 2023 16:00:22 +0800 Subject: [PATCH 857/951] Fix #321 #322 #333 FPU precision removal --- src/main/scala/vexriscv/ip/fpu/FpuCore.scala | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala index 9cdaab5a..d9dcf698 100644 --- a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala +++ b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala @@ -1546,7 +1546,7 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val manAggregate = input.value.mantissa @@ input.scrap val expBase = muxDouble[UInt](input.format)(exponentF64Subnormal + 1)(exponentF32Subnormal + 1) val expDif = expBase -^ input.value.exponent - val expSubnormal = !expDif.msb + val expSubnormal = !input.value.special && !expDif.msb var discardCount = (expSubnormal ? expDif.resize(log2Up(p.internalMantissaSize) bits) | U(0)) if (p.withDouble) when(input.format === FpuFormat.FLOAT) { discardCount \= discardCount + 29 @@ -1577,10 +1577,11 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val adderMantissa = input.value.mantissa(mantissaRange) & (mantissaIncrement ? ~(exactMask.trim(1) >> 1) | input.value.mantissa(mantissaRange).maxValue) val adderRightOp = (mantissaIncrement ? (exactMask >> 1)| U(0)).resize(p.internalMantissaSize bits) val adder = KeepAttribute(KeepAttribute(input.value.exponent @@ adderMantissa) + KeepAttribute(adderRightOp) + KeepAttribute(U(mantissaIncrement))) + val masked = adder & ~((exactMask >> 1).resize(p.internalMantissaSize).resize(widthOf(adder))) math.special := input.value.special math.sign := input.value.sign - math.exponent := adder(p.internalMantissaSize, p.internalExponentSize bits) - math.mantissa := adder(0, p.internalMantissaSize bits) + math.exponent := masked(p.internalMantissaSize, p.internalExponentSize bits) + math.mantissa := masked(0, p.internalMantissaSize bits) val patched = CombInit(math) val nx,of,uf = False From 6be1531d366f30b306c381a0b455cbe1f7b4478a Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Fri, 10 Mar 2023 09:17:01 +0800 Subject: [PATCH 858/951] Fpu will not trap anymore on debug access if fs==0 --- .../scala/vexriscv/plugin/CsrPlugin.scala | 4 +++ .../scala/vexriscv/plugin/FpuPlugin.scala | 33 +++++++++---------- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index c1b6beca..ca72a917 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -379,6 +379,7 @@ case class CsrMapping() extends Area with CsrInterface { override def allowCsr() = allowCsrSignal := True override def isHazardFree() = hazardFree override def forceFailCsr() = doForceFailCsr := True + override def inDebugMode(): Bool = ??? } @@ -429,6 +430,7 @@ trait CsrInterface{ def readData() : Bits //Return the 32 bits internal signal of the CsrPlugin for you to override (if you want) def writeData() : Bits //Return the 32 bits value that the CsrPlugin want to write in the CSR (depend on readData combinatorialy) + def inDebugMode() : Bool } @@ -484,6 +486,8 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep override def isContextSwitching = contextSwitching + override def inDebugMode(): Bool = if(withPrivilegedDebug) debugMode else False + object EnvCtrlEnum extends SpinalEnum(binarySequential){ val NONE, XRET = newElement() val WFI = if(wfiGenAsWait) newElement() else null diff --git a/src/main/scala/vexriscv/plugin/FpuPlugin.scala b/src/main/scala/vexriscv/plugin/FpuPlugin.scala index ec9087d4..db3868f3 100644 --- a/src/main/scala/vexriscv/plugin/FpuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/FpuPlugin.scala @@ -188,7 +188,7 @@ class FpuPlugin(externalFpu : Boolean = false, } }) - + val csrService = pipeline.service(classOf[CsrInterface]) val csr = pipeline plug new Area{ val pendings = Reg(UInt(6 bits)) init(0) pendings := pendings + U(port.cmd.fire) - U(port.completion.fire) - U(port.rsp.fire) @@ -202,15 +202,14 @@ class FpuPlugin(externalFpu : Boolean = false, flags.UF init(False) setWhen(port.completion.fire && port.completion.flags.UF) flags.NX init(False) setWhen(port.completion.fire && port.completion.flags.NX) - val service = pipeline.service(classOf[CsrInterface]) val rm = Reg(Bits(3 bits)) init(0) - service.rw(CSR.FCSR, 5, rm) - service.rw(CSR.FCSR, 0, flags) - service.rw(CSR.FRM, 0, rm) - service.rw(CSR.FFLAGS, 0, flags) + csrService.rw(CSR.FCSR, 5, rm) + csrService.rw(CSR.FCSR, 0, flags) + csrService.rw(CSR.FRM, 0, rm) + csrService.rw(CSR.FFLAGS, 0, flags) - val csrActive = service.duringAny() + val csrActive = csrService.duringAny() execute.arbitration.haltByOther setWhen(csrActive && hasPending) // pessimistic val fs = Reg(Bits(2 bits)) init(1) @@ -219,31 +218,31 @@ class FpuPlugin(externalFpu : Boolean = false, when(port.completion.fire && (port.completion.written || port.completion.flags.any)){ fs := 3 } - when(List(CSR.FRM, CSR.FCSR, CSR.FFLAGS).map(id => service.isWriting(id)).orR){ + when(List(CSR.FRM, CSR.FCSR, CSR.FFLAGS).map(id => csrService.isWriting(id)).orR){ fs := 3 } - service.rw(CSR.SSTATUS, 13, fs) - service.rw(CSR.MSTATUS, 13, fs) + csrService.rw(CSR.SSTATUS, 13, fs) + csrService.rw(CSR.MSTATUS, 13, fs) - service.r(CSR.SSTATUS, 31, sd) - service.r(CSR.MSTATUS, 31, sd) + csrService.r(CSR.SSTATUS, 31, sd) + csrService.r(CSR.MSTATUS, 31, sd) val accessFpuCsr = False for (csr <- List(CSR.FRM, CSR.FCSR, CSR.FFLAGS)) { - service.during(csr) { + csrService.during(csr) { accessFpuCsr := True } } - when(accessFpuCsr && fs === 0) { - service.forceFailCsr() + when(accessFpuCsr && fs === 0 && !csrService.inDebugMode()) { + csrService.forceFailCsr() } } decode plug new Area{ import decode._ - val trap = insert(FPU_ENABLE) && csr.fs === 0 && !stagesFromExecute.map(_.arbitration.isValid).orR + val trap = insert(FPU_ENABLE) && csr.fs === 0 && !csrService.inDebugMode() && !stagesFromExecute.map(_.arbitration.isValid).orR when(trap){ pipeline.service(classOf[DecoderService]).forceIllegal() } @@ -251,7 +250,7 @@ class FpuPlugin(externalFpu : Boolean = false, //Maybe it might be better to not fork before fire to avoid RF stall on commits val forked = Reg(Bool) setWhen(port.cmd.fire) clearWhen(!arbitration.isStuck) init(False) - val hazard = csr.pendings.msb || csr.csrActive || csr.fs === 0 + val hazard = csr.pendings.msb || csr.csrActive || csr.fs === 0 && !csrService.inDebugMode() input(FPU_ENABLE).clearWhen(!input(LEGAL_INSTRUCTION)) arbitration.haltItself setWhen(arbitration.isValid && input(FPU_ENABLE) && hazard) From 94f19032f09e6a548c0298a3a19b2dec92f563f1 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Fri, 10 Mar 2023 14:44:14 +0800 Subject: [PATCH 859/951] FpuPlugin.access port added Privileged debug access added --- src/main/scala/vexriscv/VexRiscv.scala | 2 + .../scala/vexriscv/plugin/CsrPlugin.scala | 49 ++++++--- .../vexriscv/plugin/EmbeddedRiscvJtag.scala | 8 +- .../scala/vexriscv/plugin/FpuPlugin.scala | 100 +++++++++++++++++- 4 files changed, 141 insertions(+), 18 deletions(-) diff --git a/src/main/scala/vexriscv/VexRiscv.scala b/src/main/scala/vexriscv/VexRiscv.scala index ed7e37e7..44f41d93 100644 --- a/src/main/scala/vexriscv/VexRiscv.scala +++ b/src/main/scala/vexriscv/VexRiscv.scala @@ -53,6 +53,8 @@ case class VexRiscvConfig(){ case None => false } + def FLEN = if(withRvd) 64 else if(withRvf) 32 else 0 + //Default Stageables object IS_RVC extends Stageable(Bool) object BYPASSABLE_EXECUTE_STAGE extends Stageable(Bool) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index ca72a917..7c2174bf 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -645,6 +645,8 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep xretAwayFromMachine = False + if(pipeline.config.FLEN == 64) pipeline.service(classOf[FpuPlugin]).requireAccessPort() + injectionPort = withPrivilegedDebug generate pipeline.service(classOf[IBusFetcher]).getInjectionPort().setCompositeName(this, "injectionPort") debugMode = withPrivilegedDebug generate Bool().setName("debugMode") debugBus = withPrivilegedDebug generate slave(DebugHartBus()).setName("debugBus") @@ -727,35 +729,58 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep timeout.clear() } - val inject = new Area{ - val cmd = bus.dmToHart.translateWith(bus.dmToHart.data).takeWhen(bus.dmToHart.op === DebugDmToHartOp.EXECUTE) - injectionPort << cmd.toStream.stage - - - val pending = RegInit(False) setWhen(cmd.valid) clearWhen(bus.exception || bus.commit || bus.ebreak || bus.redo) - when(cmd.valid){ timeout.clear() } - bus.redo := pending && timeout.state - } val dataCsrr = new Area{ bus.hartToDm.valid := isWriting(DebugModule.CSR_DATA) bus.hartToDm.address := 0 bus.hartToDm.data := execute.input(SRC1) } + val withDebugFpuAccess = pipeline.config.FLEN == 64 val dataCsrw = new Area{ - val value = Reg(Bits(32 bits)) + val value = Vec.fill(1+withDebugFpuAccess.toInt)(Reg(Bits(32 bits))) val fromDm = new Area{ when(bus.dmToHart.valid && bus.dmToHart.op === DebugDmToHartOp.DATA){ - value := bus.dmToHart.data + value(bus.dmToHart.address.resized) := bus.dmToHart.data } } val toHart = new Area{ - r(DebugModule.CSR_DATA, value) + r(DebugModule.CSR_DATA, value(0)) } } + val inject = new Area{ + val cmd = bus.dmToHart.takeWhen(bus.dmToHart.op === DebugDmToHartOp.EXECUTE || bus.dmToHart.op === DebugDmToHartOp.REG_READ || bus.dmToHart.op === DebugDmToHartOp.REG_WRITE) + val buffer = cmd.toStream.stage + injectionPort.valid := buffer.valid && buffer.op === DebugDmToHartOp.EXECUTE + injectionPort.payload := buffer.data + + buffer.ready := injectionPort.fire + val fpu = withDebugFpuAccess generate new Area { + val access = service(classOf[FpuPlugin]).access + access.start := buffer.valid && buffer.op === DebugDmToHartOp.REG_READ || buffer.op === DebugDmToHartOp.REG_WRITE + access.regId := buffer.address + access.write := buffer.op === DebugDmToHartOp.REG_WRITE + access.writeData := dataCsrw.value.take(2).asBits + access.size := buffer.size + + when(access.readDataValid) { + bus.hartToDm.valid := True + bus.hartToDm.address := access.readDataChunk.resized + bus.hartToDm.data := access.readData + } + bus.regSuccess := access.done + buffer.ready setWhen(access.done) + } + + if(!withDebugFpuAccess) bus.regSuccess := False + + val pending = RegInit(False) setWhen(cmd.valid && bus.dmToHart.op === DebugDmToHartOp.EXECUTE) clearWhen(bus.exception || bus.commit || bus.ebreak || bus.redo) + when(cmd.valid){ timeout.clear() } + bus.redo := pending && timeout.state + } + val dpc = Reg(UInt(32 bits)) val dcsr = new Area{ rw(CSR.DPC, dpc) diff --git a/src/main/scala/vexriscv/plugin/EmbeddedRiscvJtag.scala b/src/main/scala/vexriscv/plugin/EmbeddedRiscvJtag.scala index 3366e726..8a1c668e 100644 --- a/src/main/scala/vexriscv/plugin/EmbeddedRiscvJtag.scala +++ b/src/main/scala/vexriscv/plugin/EmbeddedRiscvJtag.scala @@ -42,8 +42,12 @@ class EmbeddedRiscvJtag(var p : DebugTransportModuleParameter, version = p.version + 1, harts = 1, progBufSize = 2, - datacount = XLEN/32, - xlens = List(XLEN) + datacount = (XLEN max pipeline.config.FLEN)/32, + hartsConfig = List(DebugModuleCpuConfig( + xlen = XLEN, + flen = pipeline.config.FLEN, + withFpuRegAccess = pipeline.config.FLEN == 64 + )) ) ) diff --git a/src/main/scala/vexriscv/plugin/FpuPlugin.scala b/src/main/scala/vexriscv/plugin/FpuPlugin.scala index db3868f3..cf0653f1 100644 --- a/src/main/scala/vexriscv/plugin/FpuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/FpuPlugin.scala @@ -3,12 +3,25 @@ package vexriscv.plugin import spinal.core._ import spinal.core.internals.{BoolLiteral, Literal} import spinal.lib._ +import spinal.lib.fsm._ import vexriscv._ import vexriscv.Riscv._ import vexriscv.ip.fpu._ import scala.collection.mutable.ArrayBuffer +class FpuAcessPort(val p : FpuParameter) extends Bundle{ + val start = Bool() + val regId = UInt(5 bits) + val size = UInt(3 bits) + val write = Bool() + val writeData = p.storeLoadType() + val readData = Bits(32 bits) + val readDataValid = Bool() + val readDataChunk = UInt(1 bits) + val done = Bool() +} + class FpuPlugin(externalFpu : Boolean = false, simHalt : Boolean = false, val p : FpuParameter) extends Plugin[VexRiscv] with VexRiscvRegressionArg { @@ -24,6 +37,11 @@ class FpuPlugin(externalFpu : Boolean = false, object FPU_FORMAT extends Stageable(FpuFormat()) var port : FpuPort = null //Commit port is already isolated + var access : FpuAcessPort = null //Meant to be used for debuging features only + + def requireAccessPort(): Unit = { + access = new FpuAcessPort(p).setName("fpuAccess") + } override def getVexRiscvRegressionArgs(): Seq[String] = { var args = List[String]() @@ -161,8 +179,6 @@ class FpuPlugin(externalFpu : Boolean = false, dBusEncoding.addLoadWordEncoding(FLD) dBusEncoding.addStoreWordEncoding(FSD) } - -// exposeEncoding() } override def build(pipeline: VexRiscv): Unit = { @@ -239,6 +255,7 @@ class FpuPlugin(externalFpu : Boolean = false, } } + val inAccess = False decode plug new Area{ import decode._ @@ -248,7 +265,7 @@ class FpuPlugin(externalFpu : Boolean = false, } //Maybe it might be better to not fork before fire to avoid RF stall on commits - val forked = Reg(Bool) setWhen(port.cmd.fire) clearWhen(!arbitration.isStuck) init(False) + val forked = Reg(Bool) setWhen(port.cmd.fire && !inAccess) clearWhen(!arbitration.isStuck) init(False) val hazard = csr.pendings.msb || csr.csrActive || csr.fs === 0 && !csrService.inDebugMode() @@ -269,7 +286,7 @@ class FpuPlugin(externalFpu : Boolean = false, port.cmd.format := (if(p.withDouble) input(FPU_FORMAT) else FpuFormat.FLOAT()) port.cmd.roundMode := roundMode.as(FpuRoundMode()) - insert(FPU_FORKED) := forked || port.cmd.fire + insert(FPU_FORKED) := forked || port.cmd.fire && !inAccess insert(FPU_COMMIT_SYNC) := List(FpuOpcode.LOAD, FpuOpcode.FMV_W_X, FpuOpcode.I2F).map(_ === input(FPU_OPCODE)).orR insert(FPU_COMMIT_LOAD) := input(FPU_OPCODE) === FpuOpcode.LOAD @@ -326,6 +343,81 @@ class FpuPlugin(externalFpu : Boolean = false, port.commit << commit.pipelined(s2m = true, m2s = false) } + if(access != null) pipeline plug new StateMachine{ + val IDLE, CMD, RSP, RSP_0, RSP_1, COMMIT, DONE = State() + setEntry(IDLE) + + inAccess setWhen(!this.isActive(IDLE)) + IDLE.whenIsActive{ + when(access.start){ + goto(CMD) + } + } + + CMD.whenIsActive{ + port.cmd.valid := True + port.cmd.rs2 := access.regId + port.cmd.rd := access.regId + port.cmd.format := access.size.muxListDc(List( + 2 -> FpuFormat.FLOAT(), + 3 -> FpuFormat.DOUBLE() + )) + when(access.write) { + port.cmd.opcode := FpuOpcode.LOAD + when(port.cmd.ready){ + goto(COMMIT) + } + } otherwise { + port.cmd.opcode := FpuOpcode.STORE + when(port.cmd.ready){ + goto(RSP) + } + } + } + + access.done := False + COMMIT.whenIsActive{ + port.commit.valid := True + port.commit.opcode := FpuOpcode.LOAD + port.commit.rd := access.regId + port.commit.write := True + port.commit.value := access.writeData + when(port.commit.ready){ + goto(DONE) + } + } + + access.readDataValid := False + access.readDataChunk.assignDontCare() + access.readData.assignDontCare() + RSP.whenIsActive { + when(port.rsp.valid) { + goto(RSP_0) + } + } + RSP_0.whenIsActive { + access.readDataValid := True + access.readDataChunk := 0 + access.readData := port.rsp.value(31 downto 0) + when(access.size > 2) { + goto(RSP_1) + } otherwise { + goto(DONE) + } + } + RSP_1.whenIsActive { + access.readDataValid := True + access.readDataChunk := 1 + access.readData := port.rsp.value(63 downto 32) + goto(DONE) + } + DONE whenIsActive{ + port.rsp.ready := True + access.done := True + goto(IDLE) + } + } + pipeline.stages.dropRight(1).foreach(s => s.output(FPU_FORKED) clearWhen(s.arbitration.isStuck)) Component.current.afterElaboration{ From 25eda80feeb168f36b542cbff9151ac6d6360dfe Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Fri, 10 Mar 2023 14:46:21 +0800 Subject: [PATCH 860/951] FpuTest document how to install berkley testfloat --- src/test/scala/vexriscv/ip/fpu/FpuTest.scala | 98 +++++++++++--------- 1 file changed, 55 insertions(+), 43 deletions(-) diff --git a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala index fbcec746..41dcb175 100644 --- a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala +++ b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala @@ -19,7 +19,14 @@ import scala.collection.mutable.ArrayBuffer import scala.sys.process.ProcessLogger import scala.util.Random import org.scalatest.funsuite.AnyFunSuite - +/* +How to install : +git clone https://github.com/ucb-bar/berkeley-softfloat-3 +(cd berkeley-softfloat-3/build/Linux-x86_64-GCC; make SPECIALIZE_TYPE=RISCV) +git clone https://github.com/ucb-bar/berkeley-testfloat-3 +(cd berkeley-testfloat-3/build/Linux-x86_64-GCC; make SPECIALIZE_TYPE=RISCV) +Add the compiled binaries in the PATH + */ //TODO Warning DataCache write aggregation will disable itself class FpuTest extends AnyFunSuite{ @@ -548,7 +555,7 @@ class FpuTest extends AnyFunSuite{ load(rs2, b) op(rd,rs1,rs2, rounding, FpuFormat.FLOAT) storeFloat(rd){v => - assert(f2b(v) == f2b(ref), f"## ${a} ${opName} $b = $v, $ref $rounding") + assert(f2b(v) == f2b(ref), f"## ${a} ${opName} $b = $v, $ref $rounding, ${f2b(a)}%x ${f2b(v)}%x ${f2b(ref)}%x") } flagMatch(flag, ref, f"## ${opName} ${a} $b $ref $rounding") @@ -738,7 +745,7 @@ class FpuTest extends AnyFunSuite{ sqrt(rd,rs1, rounding, FpuFormat.DOUBLE) store(rd){v => - assert(d2b(v) == d2b(ref), f"## sqrt${a} = $v, $ref $rounding, ${d2b(a).toString(16)} ${d2b(ref).toString(16)}") + assert(d2b(v) == d2b(ref), f"## sqrt${a} = $v, $ref $rounding, ${d2b(a).toString(16)} ${d2b(ref).toString(16)} ${d2b(v).toString(16)}") } flagMatch(flag, ref, f"## sqrt${a} $ref $rounding") @@ -1328,7 +1335,11 @@ class FpuTest extends AnyFunSuite{ +// testSqrtF64Exact(-1, -Double.NaN, 0, FpuRoundMode.RNE) +// for(_ <- 0 until 10000) testSgnjF32() +// for(_ <- 0 until 10000) testMulF64() + val runFactor = 1 //TODO test boxing //TODO double <-> simple convertions @@ -1337,7 +1348,7 @@ class FpuTest extends AnyFunSuite{ testSqrtF64Exact(1.25*1.25, 1.25, 0, FpuRoundMode.RNE) testSqrtF64Exact(1.5*1.5, 1.5, 0, FpuRoundMode.RNE) - for(_ <- 0 until 10000) testSqrtF64() + for(_ <- 0 until runFactor*10000) testSqrtF64() println("f64 sqrt done") // testDivF64Exact(1.0, 8.0, 0.125, 0, FpuRoundMode.RNE) @@ -1346,35 +1357,35 @@ class FpuTest extends AnyFunSuite{ // testDivF64Exact(1.5, 2.0, 0.75, 0, FpuRoundMode.RNE) // testDivF64Exact(1.875, 1.5, 1.25, 0, FpuRoundMode.RNE) - for(_ <- 0 until 10000) testDivF64() + for(_ <- 0 until runFactor*10000) testDivF64() println("f64 div done") - for(_ <- 0 until 10000) testSgnjF64() + for(_ <- 0 until runFactor*10000) testSgnjF64() println("f64 sgnj done") - for(_ <- 0 until 10000) testSgnjF32() + for(_ <- 0 until runFactor*10000) testSgnjF32() println("f32 sgnj done") //380000000001ffef 5fffffffffff9ff 8000000000100000 // testBinaryOpF64(mul,-5.877471754282472E-39, 8.814425663400984E-280, -5.180654E-318 ,1, FpuRoundMode.RMM,"mul") // 5.877471754282472E-39 8.814425663400984E-280 -5.180654E-318 RMM - for(_ <- 0 until 10000) testCvtF64F32() // 1 did not equal 3 Flag missmatch dut=1 ref=3 testCvtF64F32Raw 1.1754942807573643E-38 1.17549435E-38 RMM + for(_ <- 0 until runFactor*10000) testCvtF64F32() // 1 did not equal 3 Flag missmatch dut=1 ref=3 testCvtF64F32Raw 1.1754942807573643E-38 1.17549435E-38 RMM println("FCVT_D_S done") - for(_ <- 0 until 10000) testCvtF32F64() + for(_ <- 0 until runFactor*10000) testCvtF32F64() println("FCVT_S_D done") - for(_ <- 0 until 10000) testF2iF64() + for(_ <- 0 until runFactor*10000) testF2iF64() println("f64 f2i done") - for(_ <- 0 until 10000) testF2uiF64() + for(_ <- 0 until runFactor*10000) testF2uiF64() println("f64 f2ui done") - for(_ <- 0 until 10000) testMinF64() - for(_ <- 0 until 10000) testMaxF64() + for(_ <- 0 until runFactor*10000) testMinF64() + for(_ <- 0 until runFactor*10000) testMaxF64() println("f64 minMax done") @@ -1384,13 +1395,13 @@ class FpuTest extends AnyFunSuite{ println("f64 fma done") //TODO - for(_ <- 0 until 10000) testLeF64() - for(_ <- 0 until 10000) testLtF64() - for(_ <- 0 until 10000) testEqF64() + for(_ <- 0 until runFactor*10000) testLeF64() + for(_ <- 0 until runFactor*10000) testLtF64() + for(_ <- 0 until runFactor*10000) testEqF64() println("f64 Cmp done") - for(_ <- 0 until 10000) testClassF64() + for(_ <- 0 until runFactor*10000) testClassF64() println("f64 class done") // @@ -1401,14 +1412,14 @@ class FpuTest extends AnyFunSuite{ - for(_ <- 0 until 10000) testAddF64() - for(_ <- 0 until 10000) testSubF64() + for(_ <- 0 until runFactor*10000) testAddF64() + for(_ <- 0 until runFactor*10000) testSubF64() println("f64 Add done") // testI2f64Exact(0x7FFFFFF5, 0x7FFFFFF5, 0, true, FpuRoundMode.RNE) - for(_ <- 0 until 10000) testUI2f64() - for(_ <- 0 until 10000) testI2f64() + for(_ <- 0 until runFactor*10000) testUI2f64() + for(_ <- 0 until runFactor*10000) testI2f64() println("f64 i2f done") @@ -1424,7 +1435,7 @@ class FpuTest extends AnyFunSuite{ testBinaryOpF64(mul,1.0, 2.0, 2.0,0 , FpuRoundMode.RNE,"mul") testBinaryOpF64(mul,2.5, 2.0, 5.0,0 , FpuRoundMode.RNE,"mul") - for(_ <- 0 until 10000) testMulF64() + for(_ <- 0 until runFactor*10000) testMulF64() println("f64 Mul done") testTransferF64Raw(1.0) @@ -1439,26 +1450,27 @@ class FpuTest extends AnyFunSuite{ testTransferF32F64Raw(b2f(0xFFFF1234), true) testTransferF64F32Raw(b2d(0xFFF123498765463l << 4), true) - for (_ <- 0 until 10000) testTransferF64() + for (_ <- 0 until runFactor*10000) testTransferF64() println("f64 load/store/rf transfer done") - for (_ <- 0 until 10000) testTransferF64F32() + for (_ <- 0 until runFactor*10000) testTransferF64F32() println("f64 -> f32 load/store/rf transfer done") - for (_ <- 0 until 10000) testTransferF32F64() + for (_ <- 0 until runFactor*10000) testTransferF32F64() println("f32 -> f64 load/store/rf transfer done") } - for(_ <- 0 until 10000) testTransferF32() + + for(_ <- 0 until runFactor*10000) testTransferF32() println("f32 load/store/rf transfer done") - for(_ <- 0 until 10000) testMulF32() + for(_ <- 0 until runFactor*10000) testMulF32() println("Mul done") - for(_ <- 0 until 10000) testUI2f32() - for(_ <- 0 until 10000) testI2f32() + for(_ <- 0 until runFactor*10000) testUI2f32() + for(_ <- 0 until runFactor*10000) testI2f32() println("i2f done") @@ -1470,8 +1482,8 @@ class FpuTest extends AnyFunSuite{ - for(_ <- 0 until 10000) testF2uiF32() - for(_ <- 0 until 10000) testF2iF32() + for(_ <- 0 until runFactor*10000) testF2uiF32() + for(_ <- 0 until runFactor*10000) testF2iF32() println("f2i done") @@ -1492,28 +1504,28 @@ class FpuTest extends AnyFunSuite{ testEqRaw(Float.PositiveInfinity,Float.PositiveInfinity,1, 0) testEqRaw(0f, 0f,1, 0) - for(_ <- 0 until 10000) testLeF32() - for(_ <- 0 until 10000) testLtF32() - for(_ <- 0 until 10000) testEqF32() + for(_ <- 0 until runFactor*10000) testLeF32() + for(_ <- 0 until runFactor*10000) testLtF32() + for(_ <- 0 until runFactor*10000) testEqF32() println("Cmp done") - for(_ <- 0 until 10000) testDiv() + for(_ <- 0 until runFactor*10000) testDiv() println("f32 div done") - for(_ <- 0 until 10000) testSqrt() + for(_ <- 0 until runFactor*10000) testSqrt() println("f32 sqrt done") - for(_ <- 0 until 10000) testSgnjF32() + for(_ <- 0 until runFactor*10000) testSgnjF32() println("f32 sgnj done") - for(_ <- 0 until 10000) testClassF32() + for(_ <- 0 until runFactor*10000) testClassF32() println("f32 class done") - for(_ <- 0 until 10000) testMinF32() - for(_ <- 0 until 10000) testMaxF32() + for(_ <- 0 until runFactor*10000) testMinF32() + for(_ <- 0 until runFactor*10000) testMaxF32() println("minMax done") @@ -1537,8 +1549,8 @@ class FpuTest extends AnyFunSuite{ - for(_ <- 0 until 10000) testAddF32() - for(_ <- 0 until 10000) testSubF32() + for(_ <- 0 until runFactor*10000) testAddF32() + for(_ <- 0 until runFactor*10000) testSubF32() println("Add done") @@ -1555,7 +1567,7 @@ class FpuTest extends AnyFunSuite{ // dut.clockDomain.waitSampling(1000) // simSuccess() - for(i <- 0 until 100000) fxxTests.randomPick()() + for(i <- 0 until runFactor*100000) fxxTests.randomPick()() waitUntil(cpu.rspQueue.isEmpty) } From 876222d886f9cde8acc5bdf9e55f9887641a2d10 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Tue, 14 Mar 2023 15:23:04 +0800 Subject: [PATCH 861/951] Fix FPU access port instanciation when not needed --- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 7c2174bf..fa80e78f 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -645,7 +645,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep xretAwayFromMachine = False - if(pipeline.config.FLEN == 64) pipeline.service(classOf[FpuPlugin]).requireAccessPort() + if(withPrivilegedDebug && pipeline.config.FLEN == 64) pipeline.service(classOf[FpuPlugin]).requireAccessPort() injectionPort = withPrivilegedDebug generate pipeline.service(classOf[IBusFetcher]).getInjectionPort().setCompositeName(this, "injectionPort") debugMode = withPrivilegedDebug generate Bool().setName("debugMode") @@ -735,7 +735,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep bus.hartToDm.data := execute.input(SRC1) } - val withDebugFpuAccess = pipeline.config.FLEN == 64 + val withDebugFpuAccess = withPrivilegedDebug && pipeline.config.FLEN == 64 val dataCsrw = new Area{ val value = Vec.fill(1+withDebugFpuAccess.toInt)(Reg(Bits(32 bits))) From 13061b8b2efc41bfc0adfeaeeca97cef7a2d0a50 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Wed, 15 Mar 2023 09:50:09 +0800 Subject: [PATCH 862/951] debug unavailable is now BufferCC --- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index fa80e78f..4091be6b 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -709,7 +709,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep bus.running := running bus.halted := !running - bus.unavailable := RegNext(ClockDomain.current.isResetActive) + bus.unavailable := BufferCC(ClockDomain.current.isResetActive) when(debugMode){ inhibateInterrupts() } From 0aa8cb11e0b939f5a36ffd2e41ba0e706ec50e03 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Wed, 15 Mar 2023 17:43:44 +0800 Subject: [PATCH 863/951] BranchPlugin do not use casez anymore --- src/main/scala/vexriscv/plugin/BranchPlugin.scala | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/BranchPlugin.scala b/src/main/scala/vexriscv/plugin/BranchPlugin.scala index 24d42fa0..4ca33ca2 100644 --- a/src/main/scala/vexriscv/plugin/BranchPlugin.scala +++ b/src/main/scala/vexriscv/plugin/BranchPlugin.scala @@ -190,7 +190,8 @@ class BranchPlugin(earlyBranch : Boolean, BranchCtrlEnum.B -> input(INSTRUCTION)(14 downto 12).mux( B"000" -> eq , B"001" -> !eq , - M"1-1" -> !less, + B"101" -> !less, + B"111" -> !less, default -> less ) ) @@ -251,7 +252,8 @@ class BranchPlugin(earlyBranch : Boolean, BranchCtrlEnum.B -> input(INSTRUCTION)(14 downto 12).mux( B"000" -> eq , B"001" -> !eq , - M"1-1" -> !less, + B"101" -> !less, + B"111" -> !less, default -> less ) ) @@ -333,7 +335,8 @@ class BranchPlugin(earlyBranch : Boolean, BranchCtrlEnum.B -> input(INSTRUCTION)(14 downto 12).mux( B"000" -> eq , B"001" -> !eq , - M"1-1" -> !less, + B"101" -> !less, + B"111" -> !less, default -> less ) ) From 4972a27ae92cb24256a324ca66f07bc5b90079f1 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 22 Mar 2023 11:06:23 +0100 Subject: [PATCH 864/951] More verbose main.cpp on failure, fix C.ADDSP regfile initialisation --- src/test/cpp/regression/main.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index c482adcc..35e9cc38 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -735,8 +735,10 @@ public: masked &= MIP_SSIP; else if (masked & MIP_STIP) masked &= MIP_STIP; - else - fail(); + else { + cout << "CPU model doesn't has pending interrupt" << endl; + fail(); + } } return masked; @@ -1963,6 +1965,7 @@ public: if(*data == 0) pass(); else + cout << "0xF00FFF20 test asked for failure " << *data << endl; fail(); break; case 0xF00FFF24u: @@ -3331,6 +3334,9 @@ public: loadHex(string(REGRESSION_PATH) + "../../resources/hex/" + name + ".elf.hex"); out32.open (name + ".out32"); this->name = name; + if(name == "C.ADDI16SP" || name == "C.ADDI4SPN"){ + top->VexRiscv->RegFilePlugin_regFile[2] = 0; + } } @@ -3370,9 +3376,10 @@ public: fread(log, 1, logSize, logFile); fclose(logFile); - if(refSize > logSize || memcmp(log,ref,refSize)) + if(refSize > logSize || memcmp(log,ref,refSize)){ + cout << "Bad compliance check" << endl; fail(); - else + } else Workspace::pass(); } }; From 5b47564024a1ef0e83e3d88c2f839106efe44674 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 22 Mar 2023 11:06:56 +0100 Subject: [PATCH 865/951] A few plugins config are now var --- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 2 +- src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala | 2 +- src/main/scala/vexriscv/plugin/Fetcher.scala | 2 +- src/main/scala/vexriscv/plugin/FpuPlugin.scala | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 4091be6b..a12b6963 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -81,7 +81,7 @@ case class CsrPluginConfig( csrOhDecoder : Boolean = true, deterministicInteruptionEntry : Boolean = false, //Only used for simulatation purposes wfiOutput : Boolean = false, - withPrivilegedDebug : Boolean = false, //For the official RISC-V debug spec implementation + var withPrivilegedDebug : Boolean = false, //For the official RISC-V debug spec implementation var debugTriggers : Int = 2 ){ assert(!ucycleAccess.canWrite) diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index 4a955947..9ebec22b 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -48,7 +48,7 @@ case class TightlyCoupledDataPort(p : TightlyCoupledDataPortParameter, var bus : class DBusCachedPlugin(val config : DataCacheConfig, memoryTranslatorPortConfig : Any = null, - dBusCmdMasterPipe : Boolean = false, + var dBusCmdMasterPipe : Boolean = false, dBusCmdSlavePipe : Boolean = false, dBusRspSlavePipe : Boolean = false, relaxedMemoryTranslationRegister : Boolean = false, diff --git a/src/main/scala/vexriscv/plugin/Fetcher.scala b/src/main/scala/vexriscv/plugin/Fetcher.scala index e9b40f5d..290fed1f 100644 --- a/src/main/scala/vexriscv/plugin/Fetcher.scala +++ b/src/main/scala/vexriscv/plugin/Fetcher.scala @@ -11,7 +11,7 @@ import scala.collection.mutable.ArrayBuffer //TODO val killLastStage = jump.pcLoad.valid || decode.arbitration.isRemoved // DBUSSimple check memory halt execute optimization -abstract class IBusFetcherImpl(val resetVector : BigInt, +abstract class IBusFetcherImpl(var resetVector : BigInt, val keepPcPlus4 : Boolean, val decodePcGen : Boolean, val compressedGen : Boolean, diff --git a/src/main/scala/vexriscv/plugin/FpuPlugin.scala b/src/main/scala/vexriscv/plugin/FpuPlugin.scala index cf0653f1..337b2cf3 100644 --- a/src/main/scala/vexriscv/plugin/FpuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/FpuPlugin.scala @@ -23,7 +23,7 @@ class FpuAcessPort(val p : FpuParameter) extends Bundle{ } class FpuPlugin(externalFpu : Boolean = false, - simHalt : Boolean = false, + var simHalt : Boolean = false, val p : FpuParameter) extends Plugin[VexRiscv] with VexRiscvRegressionArg { object FPU_ENABLE extends Stageable(Bool()) From a755d839b3de6bf8f0b210140646ad9fb4e7f3fd Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 22 Mar 2023 11:07:18 +0100 Subject: [PATCH 866/951] Add VexRiscvSmpClusterGen csrFull (wip) --- .../vexriscv/demo/smp/VexRiscvSmpCluster.scala | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index bf805e8c..86cd8cbc 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -195,7 +195,8 @@ object VexRiscvSmpClusterGen { withInstructionCache : Boolean = true, forceMisa : Boolean = false, forceMscratch : Boolean = false, - privilegedDebug : Boolean = false + privilegedDebug : Boolean = false, + csrFull : Boolean = false ) = { assert(iCacheSize/iCacheWays <= 4096, "Instruction cache ways can't be bigger than 4096 bytes") assert(dCacheSize/dCacheWays <= 4096, "Data cache ways can't be bigger than 4096 bytes") @@ -203,8 +204,16 @@ object VexRiscvSmpClusterGen { val misa = Riscv.misaToInt(s"ima${if(withFloat) "f" else ""}${if(withDouble) "d" else ""}${if(rvc) "c" else ""}${if(withSupervisor) "s" else ""}") val csrConfig = if(withSupervisor){ - CsrPluginConfig.openSbi(mhartid = hartId, misa = misa).copy(utimeAccess = CsrAccess.READ_ONLY, withPrivilegedDebug = privilegedDebug) + var c = CsrPluginConfig.openSbi(mhartid = hartId, misa = misa).copy(utimeAccess = CsrAccess.READ_ONLY, withPrivilegedDebug = privilegedDebug) + if(csrFull){ + c.copy( + mcauseAccess = CsrAccess.READ_WRITE, + mbadaddrAccess = CsrAccess.READ_WRITE + ) + } + c } else { + assert(!csrFull) CsrPluginConfig( catchIllegalAccess = true, mvendorid = 0, From 385a195d166419d7518835c1aaa62ac17f2d9dd4 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 22 Mar 2023 12:58:43 +0100 Subject: [PATCH 867/951] few more var parameters --- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 4 ++-- src/main/scala/vexriscv/plugin/MmuPlugin.scala | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index a12b6963..85407dee 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -46,7 +46,7 @@ case class CsrPluginConfig( misaExtensionsInit : Int, misaAccess : CsrAccess, mtvecAccess : CsrAccess, - mtvecInit : BigInt, + var mtvecInit : BigInt, mepcAccess : CsrAccess, mscratchGen : Boolean, mcauseAccess : CsrAccess, @@ -458,7 +458,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep } - override def getVexRiscvRegressionArgs() = List(s"SUPERVISOR=${if(config.supervisorGen) "yes" else "no"}, CSR=yes") + override def getVexRiscvRegressionArgs() = List(s"SUPERVISOR=${if(config.supervisorGen) "yes" else "no"} CSR=yes") var exceptionPendings : Vec[Bool] = null override def isExceptionPending(stage : Stage): Bool = exceptionPendings(pipeline.stages.indexOf(stage)) diff --git a/src/main/scala/vexriscv/plugin/MmuPlugin.scala b/src/main/scala/vexriscv/plugin/MmuPlugin.scala index aea906f6..8057d178 100644 --- a/src/main/scala/vexriscv/plugin/MmuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/MmuPlugin.scala @@ -38,7 +38,7 @@ case class MmuPort(bus : MemoryTranslatorBus, priority : Int, args : MmuPortConf case class MmuPortConfig(portTlbSize : Int, latency : Int = 0, earlyRequireMmuLockup : Boolean = false, earlyCacheHits : Boolean = false) -class MmuPlugin(ioRange : UInt => Bool, +class MmuPlugin(var ioRange : UInt => Bool, virtualRange : UInt => Bool = address => True, // allowUserIo : Boolean = false, enableMmuInMachineMode : Boolean = false) extends Plugin[VexRiscv] with MemoryTranslator { From bba022b7467aaf7eaf2a174457d3f34fb4c991cd Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 22 Mar 2023 16:25:03 +0100 Subject: [PATCH 868/951] fix a few csr related WARL (minor) --- .../demo/smp/VexRiscvSmpCluster.scala | 2 +- .../scala/vexriscv/plugin/CsrPlugin.scala | 34 ++++++++++++++++--- src/test/cpp/regression/main.cpp | 15 +++++--- 3 files changed, 41 insertions(+), 10 deletions(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index 86cd8cbc..185a67f8 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -206,7 +206,7 @@ object VexRiscvSmpClusterGen { val csrConfig = if(withSupervisor){ var c = CsrPluginConfig.openSbi(mhartid = hartId, misa = misa).copy(utimeAccess = CsrAccess.READ_ONLY, withPrivilegedDebug = privilegedDebug) if(csrFull){ - c.copy( + c = c.copy( mcauseAccess = CsrAccess.READ_WRITE, mbadaddrAccess = CsrAccess.READ_WRITE ) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 85407dee..4f4c4818 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -952,13 +952,20 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep } }) + def guardedWrite(csrId : Int, bitRange: Range, allowed : Seq[Int], target : Bits) = { + onWrite(csrId){ + when(allowed.map(writeData()(bitRange) === _).orR){ + target := writeData()(bitRange) + } + } + } val machineCsr = pipeline plug new Area{ //Define CSR registers // Status => MXR, SUM, TVM, TW, TSE ? val misa = new Area{ - val base = Reg(UInt(2 bits)) init(U"01") allowUnsetRegToAvoidLatch - val extensions = Reg(Bits(26 bits)) init(misaExtensionsInit) allowUnsetRegToAvoidLatch + val base = U"01" + val extensions = B(misaExtensionsInit, 26 bits) } val mtvec = Reg(Xtvec()).allowUnsetRegToAvoidLatch @@ -1001,7 +1008,10 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep if(mimpid != null) READ_ONLY(CSR.MIMPID , U(mimpid )) if(mhartid != null && !withExternalMhartid) READ_ONLY(CSR.MHARTID , U(mhartid )) if(withExternalMhartid) READ_ONLY(CSR.MHARTID , externalMhartId) - misaAccess(CSR.MISA, xlen-2 -> misa.base , 0 -> misa.extensions) + if(misaAccess.canRead) { + READ_ONLY(CSR.MISA, xlen-2 -> misa.base , 0 -> misa.extensions) + onWrite(CSR.MISA){} + } //Machine CSR READ_WRITE(CSR.MSTATUS, 7 -> mstatus.MPIE, 3 -> mstatus.MIE) @@ -1018,7 +1028,11 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep } } - mtvecAccess(CSR.MTVEC, 2 -> mtvec.base, 0 -> mtvec.mode) + mtvecAccess(CSR.MTVEC, 2 -> mtvec.base) + if(mtvecAccess.canWrite && xtvecModeGen) { + guardedWrite(CSR.MTVEC, 1 downto 0, List(0, 1), mtvec.mode) + } + mepcAccess(CSR.MEPC, mepc) if(mscratchGen) READ_WRITE(CSR.MSCRATCH, mscratch) mcauseAccess(CSR.MCAUSE, xlen-1 -> mcause.interrupt, 0 -> mcause.exceptionCode) @@ -1091,7 +1105,10 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep for(offset <- List(CSR.MIE, CSR.SIE)) READ_WRITE(offset, 9 -> sie.SEIE, 5 -> sie.STIE, 1 -> sie.SSIE) - stvecAccess(CSR.STVEC, 2 -> stvec.base, 0 -> stvec.mode) + stvecAccess(CSR.STVEC, 2 -> stvec.base) + if(mtvecAccess.canWrite && xtvecModeGen) { + guardedWrite(CSR.STVEC, 1 downto 0, List(0, 1), stvec.mode) + } sepcAccess(CSR.SEPC, sepc) if(sscratchGen) READ_WRITE(CSR.SSCRATCH, sscratch) scauseAccess(CSR.SCAUSE, xlen-1 -> scause.interrupt, 0 -> scause.exceptionCode) @@ -1651,6 +1668,13 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep case element : CsrOnRead => when(readEnable){element.doThat()} } + //When no PMP => +// if(!csrMapping.mapping.contains(0x3A0)){ +// when(arbitration.isValid && input(IS_CSR) && U(csrAddress) >= 0x3A0 && U(csrAddress) <= 0x3EF){ +// csrMapping.allowCsrSignal := True +// } +// } + illegalAccess clearWhen(csrMapping.allowCsrSignal) val forceFail = CombInit(csrMapping.doForceFailCsr) diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 35e9cc38..3bbd26c9 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -629,7 +629,10 @@ public: case UTIMEH: *value = dutRfWriteValue; break; #endif - default: return true; break; + default: { +// if(csr >= 0x3A0 && csr <= 0x3EF) break; //PMP + return true; + }break; } // if(csr == MSTATUS || csr == SSTATUS){ // printf("READ %x %x\n", pc, *value); @@ -657,7 +660,7 @@ public: case MSTATUS: status.raw = value & 0x7FFFFFFF; break; case MIP: ipSoft = value; break; case MIE: ie.raw = value; break; - case MTVEC: mtvec.raw = value; break; + case MTVEC: mtvec.raw = value & 0xFFFFFFFC; break; case MCAUSE: mcause.raw = value; break; case MBADADDR: mbadaddr = value; break; case MEPC: mepc = value; break; @@ -669,7 +672,7 @@ public: case SSTATUS: maskedWrite(status.raw, value, 0xC0133 | STATUS_FS_MASK); break; case SIP: maskedWrite(ipSoft, value,0x333); break; case SIE: maskedWrite(ie.raw, value,0x333); break; - case STVEC: stvec.raw = value; break; + case STVEC: stvec.raw = value & 0xFFFFFFFC; break; case SCAUSE: scause.raw = value; break; case STVAL: sbadaddr = value; break; case SEPC: sepc = value; break; @@ -682,7 +685,11 @@ public: case FFLAGS: fcsr.flags = value; status.fs = 3; break; #endif - default: ilegalInstruction(); return true; break; + default: { +// if(csr >= 0x3A0 && csr <= 0x3EF) break; //PMP + ilegalInstruction(); + return true; + }break; } // if(csr == MSTATUS || csr == SSTATUS){ // printf(" %x %x\n", pc, status.raw); From 0e59a56bd1d5baefa28fcff89f4083fc9829ce0d Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 22 Mar 2023 16:25:23 +0100 Subject: [PATCH 869/951] add privSpec test --- src/test/cpp/raw/privSpec/.gitignore | 4 +++ src/test/cpp/raw/privSpec/makefile | 3 ++ src/test/cpp/raw/privSpec/src/crt.S | 54 ++++++++++++++++++++++++++++ src/test/cpp/raw/privSpec/src/ld | 16 +++++++++ 4 files changed, 77 insertions(+) create mode 100644 src/test/cpp/raw/privSpec/.gitignore create mode 100644 src/test/cpp/raw/privSpec/makefile create mode 100644 src/test/cpp/raw/privSpec/src/crt.S create mode 100644 src/test/cpp/raw/privSpec/src/ld diff --git a/src/test/cpp/raw/privSpec/.gitignore b/src/test/cpp/raw/privSpec/.gitignore new file mode 100644 index 00000000..c12cb2c2 --- /dev/null +++ b/src/test/cpp/raw/privSpec/.gitignore @@ -0,0 +1,4 @@ +*.map +*.v +*.elf +*.o \ No newline at end of file diff --git a/src/test/cpp/raw/privSpec/makefile b/src/test/cpp/raw/privSpec/makefile new file mode 100644 index 00000000..7ef37009 --- /dev/null +++ b/src/test/cpp/raw/privSpec/makefile @@ -0,0 +1,3 @@ +PROJ_NAME=privSpec + +include ../common/asm.mk \ No newline at end of file diff --git a/src/test/cpp/raw/privSpec/src/crt.S b/src/test/cpp/raw/privSpec/src/crt.S new file mode 100644 index 00000000..d9a095dd --- /dev/null +++ b/src/test/cpp/raw/privSpec/src/crt.S @@ -0,0 +1,54 @@ +.globl _star +#define TEST_ID x28 + +_start: + la x1, fail + csrw mtvec, x1 + +test1: + li TEST_ID, 1 + csrw misa, x0 + + //Test xtvec mode + li x1, 1 + csrw mtvec, x1 + csrr x2, mtvec + bnez x2, fail + csrw stvec, x1 + csrr x2, stvec + bnez x2, fail + + li x1, 9 + csrw mcause, x1 + csrr x2, mcause + bne x2, x1, fail + + csrr x0, pmpcfg0 + csrw pmpcfg0, x0 + + csrr x0, pmpcfg3 + csrw pmpcfg3, x0 + + csrr x0, pmpaddr0 + csrw pmpaddr0, x0 + + csrr x0, pmpaddr15 + csrw pmpaddr15, x0 + + + j pass + +fail: + li x2, 0xF00FFF24 + sw TEST_ID, 0(x2) + +pass: + li x2, 0xF00FFF20 + sw x0, 0(x2) + + nop + nop + nop + nop + nop + nop diff --git a/src/test/cpp/raw/privSpec/src/ld b/src/test/cpp/raw/privSpec/src/ld new file mode 100644 index 00000000..93d8de8e --- /dev/null +++ b/src/test/cpp/raw/privSpec/src/ld @@ -0,0 +1,16 @@ +OUTPUT_ARCH( "riscv" ) + +MEMORY { + onChipRam (W!RX)/*(RX)*/ : ORIGIN = 0x80000000, LENGTH = 128K +} + +SECTIONS +{ + + .crt_section : + { + . = ALIGN(4); + *crt.o(.text) + } > onChipRam + +} From 570720fdd875bf49f5b6b7f1b0883608096b7095 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 22 Mar 2023 17:13:47 +0100 Subject: [PATCH 870/951] Cfu add enableInit option --- src/main/scala/vexriscv/plugin/CfuPlugin.scala | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/CfuPlugin.scala b/src/main/scala/vexriscv/plugin/CfuPlugin.scala index 2a18b2d1..2e878eae 100644 --- a/src/main/scala/vexriscv/plugin/CfuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CfuPlugin.scala @@ -104,7 +104,8 @@ class CfuPlugin(val stageCount : Int, val encodings : List[CfuPluginEncoding] = null, val stateAndIndexCsrOffset : Int = 0xBC0, val statusCsrOffset : Int = 0x801, - val withEnable : Boolean = true) extends Plugin[VexRiscv]{ + val withEnable : Boolean = true, + val enableInit : Boolean = false) extends Plugin[VexRiscv]{ def p = busParameter assert(p.CFU_INPUTS <= 2) @@ -176,7 +177,7 @@ class CfuPlugin(val stageCount : Int, val csr = pipeline plug new Area{ val factory = pipeline.service(classOf[CsrInterface]) - val en = withEnable generate (Reg(Bool()) init(False)) + val en = withEnable generate (Reg(Bool()) init(enableInit)) if(withEnable) factory.rw(stateAndIndexCsrOffset, 31, en) val stateId = Reg(UInt(log2Up(p.CFU_STATE_INDEX_NUM) bits)) init(0) From b01490b5f31c3cabd4a55a747e85d8201050cd3d Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 23 Mar 2023 08:53:10 +0100 Subject: [PATCH 871/951] Implement counteren (1.10+ spec) --- src/main/scala/vexriscv/Riscv.scala | 1 + .../scala/vexriscv/plugin/CsrPlugin.scala | 22 +++ src/test/cpp/raw/privSpec/src/crt.S | 158 ++++++++++++++++- src/test/cpp/raw/privSpec/src/privileged.h | 159 ++++++++++++++++++ src/test/cpp/raw/privSpec/src/riscv_asm.h | 94 +++++++++++ 5 files changed, 432 insertions(+), 2 deletions(-) create mode 100644 src/test/cpp/raw/privSpec/src/privileged.h create mode 100644 src/test/cpp/raw/privSpec/src/riscv_asm.h diff --git a/src/main/scala/vexriscv/Riscv.scala b/src/main/scala/vexriscv/Riscv.scala index cb129a97..52ccf36e 100644 --- a/src/main/scala/vexriscv/Riscv.scala +++ b/src/main/scala/vexriscv/Riscv.scala @@ -215,6 +215,7 @@ object Riscv{ def MINSTRET = 0xB02 // MRW Machine instructions-retired counter. def MCYCLEH = 0xB80 // MRW Upper 32 bits of mcycle, RV32I only. def MINSTRETH = 0xB82 // MRW Upper 32 bits of minstret, RV32I only. + val MCOUNTEREN = 0x306 val SSTATUS = 0x100 val SIE = 0x104 diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 4f4c4818..1d035844 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -1058,6 +1058,28 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep utimeAccess(CSR.UTIMEH, utime(63 downto 32)) } + class Xcounteren(csrId : Int) extends Area{ + val IR,TM,CY = RegInit(True) //For backward compatibility + if(ucycleAccess != CsrAccess.NONE) rw(csrId, 0 -> CY) + if(utimeAccess != CsrAccess.NONE) rw(csrId, 1 -> TM) + if(uinstretAccess != CsrAccess.NONE) rw(csrId, 2 -> IR) + } + def xcounterChecks(access : CsrAccess, csrId : Int, enable : Xcounteren => Bool) = { + if(access != CsrAccess.NONE) during(csrId){ + if(userGen) when(privilege < 3 && !enable(mcounteren)){ forceFailCsr() } + if(supervisorGen) when(privilege < 1 && !enable(scounteren)){ forceFailCsr() } + } + } + + val mcounteren = userGen generate new Xcounteren(CSR.MCOUNTEREN) + val scounteren = supervisorGen generate new Xcounteren(CSR.SCOUNTEREN) + xcounterChecks(ucycleAccess , CSR.UCYCLE , _.CY) + xcounterChecks(ucycleAccess , CSR.UCYCLEH , _.CY) + xcounterChecks(utimeAccess , CSR.UTIME , _.TM) + xcounterChecks(utimeAccess , CSR.UTIMEH , _.TM) + xcounterChecks(uinstretAccess, CSR.UINSTRET , _.IR) + xcounterChecks(uinstretAccess, CSR.UINSTRETH, _.IR) + pipeline(MPP) := mstatus.MPP } diff --git a/src/test/cpp/raw/privSpec/src/crt.S b/src/test/cpp/raw/privSpec/src/crt.S index d9a095dd..62a88013 100644 --- a/src/test/cpp/raw/privSpec/src/crt.S +++ b/src/test/cpp/raw/privSpec/src/crt.S @@ -1,6 +1,10 @@ .globl _star #define TEST_ID x28 +#include "privileged.h" + + + _start: la x1, fail csrw mtvec, x1 @@ -18,12 +22,15 @@ test1: csrr x2, stvec bnez x2, fail + la x1, fail + csrw mtvec, x1 + li x1, 9 csrw mcause, x1 csrr x2, mcause bne x2, x1, fail - csrr x0, pmpcfg0 + /*csrr x0, pmpcfg0 csrw pmpcfg0, x0 csrr x0, pmpcfg3 @@ -33,7 +40,154 @@ test1: csrw pmpaddr0, x0 csrr x0, pmpaddr15 - csrw pmpaddr15, x0 + csrw pmpaddr15, x0*/ + + li TEST_ID, 2 + csrr x1, mcycle + csrr x2, mcycle + bge x1, x2, fail + + csrr x1, minstret + csrr x2, minstret + bge x1, x2, fail + + csrr x1, cycle + csrr x2, cycle + bge x1, x2, fail + + csrr x1, instret + csrr x2, instret + bge x1, x2, fail + + csrr x1, time + csrr x2, time + bge x1, x2, fail + + //Test access to counters in supervisor + machine_setup_trap + machine_to_supervisor + li TEST_ID, 3 + + csrr x1, cycle + csrr x2, cycle + bge x1, x2, fail + + csrr x1, instret + csrr x2, instret + bge x1, x2, fail + + csrr x1, time + csrr x2, time + bge x1, x2, fail + + ecall + machine_handle_trap + + //Test access to counters in user + machine_setup_trap + machine_to_user + li TEST_ID, 4 + + csrr x1, cycle + csrr x2, cycle + bge x1, x2, fail + + csrr x1, instret + csrr x2, instret + bge x1, x2, fail + + csrr x1, time + csrr x2, time + bge x1, x2, fail + ecall + machine_handle_trap + + //Remove user access to counters + li x1, -1 + csrw mcounteren, x1 + li x1, 0 + csrw scounteren, x1 + + machine_setup_trap + machine_to_supervisor + li TEST_ID, 3 + + csrr x1, cycle + csrr x2, cycle + bge x1, x2, fail + + csrr x1, instret + csrr x2, instret + bge x1, x2, fail + + csrr x1, time + csrr x2, time + bge x1, x2, fail + + ecall + machine_handle_trap + + machine_setup_trap + machine_to_user + csrr x1, cycle + j fail + machine_handle_trap + + machine_setup_trap + machine_to_user + csrr x1, instret + j fail + machine_handle_trap + + machine_setup_trap + machine_to_user + csrr x1, time + j fail + machine_handle_trap + + + //Remove supervisor access to counters + li x1, 0 + csrw mcounteren, x1 + li x1, -1 + csrw scounteren, x1 + + machine_setup_trap + machine_to_supervisor + csrr x1, cycle + j fail + machine_handle_trap + + machine_setup_trap + machine_to_supervisor + csrr x1, instret + j fail + machine_handle_trap + + machine_setup_trap + machine_to_supervisor + csrr x1, time + j fail + machine_handle_trap + + machine_setup_trap + machine_to_user + csrr x1, cycle + j fail + machine_handle_trap + + machine_setup_trap + machine_to_user + csrr x1, instret + j fail + machine_handle_trap + + machine_setup_trap + machine_to_user + csrr x1, time + j fail + machine_handle_trap + j pass diff --git a/src/test/cpp/raw/privSpec/src/privileged.h b/src/test/cpp/raw/privSpec/src/privileged.h new file mode 100644 index 00000000..289be29a --- /dev/null +++ b/src/test/cpp/raw/privSpec/src/privileged.h @@ -0,0 +1,159 @@ +#pragma once + + +#include "riscv_asm.h" + +#define trap_setup \ + la x1, 1f; \ + csrw mtvec, x1; \ + addi x1, x1, 0x123; \ + csrw mtval, x1; \ + +#define trap_handle \ + j fail; \ + j fail; \ + j fail; \ + j fail; \ +.align 4; \ +1: \ + csrr x1, mepc; \ + csrr x1, mcause; \ + csrr x1, mstatus; \ + csrr x1, mtval; \ + csrr x1, mip; \ + +#define trap_handle_setup \ + trap_handle \ + trap_setup \ + + + +#define supervisor_read \ + csrr x1, sepc; \ + csrr x1, scause; \ + csrr x1, sstatus; \ + csrr x1, stval; \ + csrr x1, sip; + +#define machine_read \ + csrr x1, mepc; \ + csrr x1, mcause; \ + csrr x1, mstatus; \ + csrr x1, mtval; \ + csrr x1, mip; \ + supervisor_read + +#define user_read + +#define machine_to_supervisor \ + la x1,1f ;\ + csrw mepc, x1 ;\ + li x1, MSTATUS_MPP_SUPERVISOR ;\ + csrw mstatus, x1 ;\ + mret ;\ + j fail ;\ + j fail ;\ + j fail ;\ + j fail ;\ +1: ;\ + supervisor_read + +#define machine_to_supervisor_x1 \ + csrw mepc, x1 ;\ + li x1, MSTATUS_MPP_SUPERVISOR ;\ + csrw mstatus, x1 ;\ + mret ;\ + j fail ;\ + j fail ;\ + j fail ;\ + j fail ;\ + + + +#define machine_to_user \ + la x1,1f ;\ + csrw mepc, x1 ;\ + li x1, MSTATUS_MPP_USER ;\ + csrw mstatus, x1 ;\ + mret ;\ + j fail ;\ + j fail ;\ + j fail ;\ + j fail ;\ +1: ;\ + user_read + +#define machine_setup_trap \ + la x1, 2f ;\ + csrw mtvec,x1; + +#define machine_handle_trap \ + j fail ;\ +.align 4 ;\ +2: ;\ + machine_read + +#define supervisor_setup_trap \ + la x1, 3f ;\ + csrw stvec,x1; + + +#define supervisor_handle_trap \ + j fail ;\ +.align 4 ;\ +3: ;\ + supervisor_read + + + +#define supervisor_check \ + supervisor_setup_trap \ + csrr x1, mstatus; \ + supervisor_handle_trap \ + supervisor_read + +#define supervisor_external_interrupt_set \ + li x1, SUPERVISOR_EXTERNAL_INTERRUPT_CTRL; \ + li x2, 1; \ + sw x2, 0(x1); + +#define supervisor_external_interrupt_clear \ + li x1, SUPERVISOR_EXTERNAL_INTERRUPT_CTRL; \ + sw x0, 0(x1); + +#define wait_interrupt nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;j fail; +#define delay_long nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop; + + +#define machine_enable_supervisor_external_interrupt \ + li x1, 1 << CAUSE_SUPERVISOR_EXTERNAL; \ + csrw mie, x1; \ + li x1, MSTATUS_MIE ; \ + csrw mstatus, x1 ; + +#define supervisor_enable_supervisor_external_interrupt \ + li x1, 1 << CAUSE_SUPERVISOR_EXTERNAL; \ + csrw sie, x1; \ + li x1, MSTATUS_SIE ; \ + csrw sstatus, x1 ; + + +#define machine_trap_failure \ + la x1, 1f; \ + csrw mtvec, x1; \ + j 4f \ +1: \ + nop; \ + j fail; \ +4: + +#define supervisor_trap_failure \ + la x1, 1f; \ + csrw stvec, x1; \ + j 4f; \ +.align 4; \ +1: \ + nop; \ + j fail; \ +4: + diff --git a/src/test/cpp/raw/privSpec/src/riscv_asm.h b/src/test/cpp/raw/privSpec/src/riscv_asm.h new file mode 100644 index 00000000..347f3118 --- /dev/null +++ b/src/test/cpp/raw/privSpec/src/riscv_asm.h @@ -0,0 +1,94 @@ +#pragma once + +//exceptions +#define CAUSE_ILLEGAL_INSTRUCTION 2 +#define CAUSE_UCALL 8 +#define CAUSE_SCALL 9 + +//interrupts +#define CAUSE_MACHINE_SOFTWARE 3 +#define CAUSE_MACHINE_TIMER 7 +#define CAUSE_MACHINE_EXTERNAL 11 +#define CAUSE_SUPERVISOR_SOFTWARE 1 +#define CAUSE_SUPERVISOR_TIMER 5 +#define CAUSE_SUPERVISOR_EXTERNAL 9 + + +#define MIE_MTIE (1 << CAUSE_MACHINE_TIMER) +#define MIE_MEIE (1 << CAUSE_MACHINE_EXTERNAL) +#define MIE_MSIE (1 << CAUSE_MACHINE_SOFTWARE) +#define MIE_SEIE (1 << CAUSE_SUPERVISOR_EXTERNAL) + +#define MEDELEG_INSTRUCTION_PAGE_FAULT (1 << 12) +#define MEDELEG_LOAD_PAGE_FAULT (1 << 13) +#define MEDELEG_STORE_PAGE_FAULT (1 << 15) +#define MEDELEG_USER_ENVIRONNEMENT_CALL (1 << 8) +#define MIDELEG_SUPERVISOR_SOFTWARE (1 << 1) +#define MIDELEG_SUPERVISOR_TIMER (1 << 5) +#define MIDELEG_SUPERVISOR_EXTERNAL (1 << 9) + + +#define MSTATUS_UIE 0x00000001 +#define MSTATUS_SIE 0x00000002 +#define MSTATUS_HIE 0x00000004 +#define MSTATUS_MIE 0x00000008 +#define MSTATUS_UPIE 0x00000010 +#define MSTATUS_SPIE 0x00000020 +#define MSTATUS_HPIE 0x00000040 +#define MSTATUS_MPIE 0x00000080 +#define MSTATUS_SPP 0x00000100 +#define MSTATUS_HPP 0x00000600 +#define MSTATUS_MPP 0x00001800 +#define MSTATUS_FS 0x00006000 +#define MSTATUS_XS 0x00018000 +#define MSTATUS_MPRV 0x00020000 +#define MSTATUS_SUM 0x00040000 +#define MSTATUS_MXR 0x00080000 +#define MSTATUS_TVM 0x00100000 +#define MSTATUS_TW 0x00200000 +#define MSTATUS_TSR 0x00400000 +#define MSTATUS32_SD 0x80000000 +#define MSTATUS_UXL 0x0000000300000000 +#define MSTATUS_SXL 0x0000000C00000000 +#define MSTATUS64_SD 0x8000000000000000 +#define MSTATUS_FS_INITIAL (1 << 13) +#define MSTATUS_FS_CLEAN (2 << 13) +#define MSTATUS_FS_DIRTY (3 << 13) +#define MSTATUS_FS_MASK (3 << 13) + + +#define MSTATUS_MPP_SUPERVISOR 0x00000800 +#define MSTATUS_MPP_USER 0x00000000 + +#define SSTATUS_UIE 0x00000001 +#define SSTATUS_SIE 0x00000002 +#define SSTATUS_UPIE 0x00000010 +#define SSTATUS_SPIE 0x00000020 +#define SSTATUS_SPP 0x00000100 +#define SSTATUS_FS 0x00006000 +#define SSTATUS_XS 0x00018000 +#define SSTATUS_SUM 0x00040000 +#define SSTATUS_MXR 0x00080000 +#define SSTATUS32_SD 0x80000000 +#define SSTATUS_UXL 0x0000000300000000 +#define SSTATUS64_SD 0x8000000000000000 + + +#define PMP_R 0x01 +#define PMP_W 0x02 +#define PMP_X 0x04 +#define PMP_A 0x18 +#define PMP_L 0x80 +#define PMP_SHIFT 2 + +#define PMP_TOR 0x08 +#define PMP_NA4 0x10 +#define PMP_NAPOT 0x18 + +#define RDCYCLE 0xC00 //Read-only cycle Cycle counter for RDCYCLE instruction. +#define RDTIME 0xC01 //Read-only time Timer for RDTIME instruction. +#define RDINSTRET 0xC02 //Read-only instret Instructions-retired counter for RDINSTRET instruction. +#define RDCYCLEH 0xC80 //Read-only cycleh Upper 32 bits of cycle, RV32I only. +#define RDTIMEH 0xC81 //Read-only timeh Upper 32 bits of time, RV32I only. +#define RDINSTRETH 0xC82 //Read-only instreth Upper 32 bits of instret, RV32I only. + From 8c5071ce42fd3ebb28457e316cf4a74b36d0ffbf Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 23 Mar 2023 08:53:41 +0100 Subject: [PATCH 872/951] VexRiscvSmpCluster fullCsr improvement --- src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index 185a67f8..6fffb6a5 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -208,7 +208,11 @@ object VexRiscvSmpClusterGen { if(csrFull){ c = c.copy( mcauseAccess = CsrAccess.READ_WRITE, - mbadaddrAccess = CsrAccess.READ_WRITE + mbadaddrAccess = CsrAccess.READ_WRITE, + ucycleAccess = CsrAccess.READ_ONLY, + uinstretAccess = CsrAccess.READ_ONLY, + mcycleAccess = CsrAccess.READ_WRITE, + minstretAccess = CsrAccess.READ_WRITE ) } c From 8195bec788e6a5e9bef972872b858093a97a69b3 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 23 Mar 2023 11:24:38 +0100 Subject: [PATCH 873/951] privSpec now check FPU dirty flag --- src/test/cpp/raw/privSpec/makefile | 2 + src/test/cpp/raw/privSpec/src/crt.S | 72 +++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) diff --git a/src/test/cpp/raw/privSpec/makefile b/src/test/cpp/raw/privSpec/makefile index 7ef37009..b3270f19 100644 --- a/src/test/cpp/raw/privSpec/makefile +++ b/src/test/cpp/raw/privSpec/makefile @@ -1,3 +1,5 @@ PROJ_NAME=privSpec +FLOATING=yes + include ../common/asm.mk \ No newline at end of file diff --git a/src/test/cpp/raw/privSpec/src/crt.S b/src/test/cpp/raw/privSpec/src/crt.S index 62a88013..f013ab28 100644 --- a/src/test/cpp/raw/privSpec/src/crt.S +++ b/src/test/cpp/raw/privSpec/src/crt.S @@ -188,7 +188,76 @@ test1: j fail machine_handle_trap + //Test FPU dirty + la x1, fail + csrw mtvec, x1 +#define checkFpuDirty() \ + csrr x1, mstatus ;\ + li x2, 0x80006000 ;\ + and x1, x1, x2 ;\ + bne x1, x2, fail + +#define checkFpuClean() \ + csrr x1, mstatus ;\ + li x2, 0x80006000 ;\ + and x1, x1, x2 ;\ + li x2, 0x00004000 ;\ + bne x1, x2, fail + +#define fpuClean() \ + li x1, 0x00004000 ;\ + csrw mstatus, x1 + + fpuClean() + checkFpuClean() + + la x1, fpuTwo + flw ft0, 0(x1) + checkFpuDirty(); fpuClean() + + checkFpuClean(); + la x1, fpuTwo + fsw ft0, 0(x1) + checkFpuClean(); + + fmv.x.w x1, ft0 + li x2, 0x40000000 + bne x1, x2, fail + checkFpuClean(); + + li x1, 0x80000000 + fmv.w.x ft0, x1 + checkFpuDirty();fpuClean(); + + //Check inprecise convertion + li x1, 0x3f000000 + fmv.w.x ft0, x1 + checkFpuDirty();fpuClean(); + fcvt.w.s x1, ft0 + checkFpuDirty();fpuClean(); + + //check precise convertion + li x1, 0x40000000 + fmv.w.x ft0, x1 + checkFpuDirty();fpuClean(); + fcvt.w.s x1, ft0 + checkFpuClean(); + + //check overflow convertion + li x1, 0x4f800000 + fmv.w.x ft0, x1 + checkFpuDirty();fpuClean(); + fcvt.w.s x1, ft0 + checkFpuDirty();fpuClean(); + + //Check CSR write making things dirty + csrw fcsr, x0 + checkFpuDirty();fpuClean(); + csrw frm, x0 + checkFpuDirty();fpuClean(); + csrw fflags, x0 + checkFpuDirty();fpuClean(); j pass @@ -206,3 +275,6 @@ pass: nop nop nop + +fpuTwo: +.word 0x40000000 \ No newline at end of file From c69852c0cc0aececddadb8dc0ad1120576f384a9 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 23 Mar 2023 16:57:10 +0100 Subject: [PATCH 874/951] ClockDomainResetGeneratorIf introduction --- src/main/scala/vexriscv/VexRiscvBmbGenerator.scala | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/scala/vexriscv/VexRiscvBmbGenerator.scala b/src/main/scala/vexriscv/VexRiscvBmbGenerator.scala index 2754d391..4af0e085 100644 --- a/src/main/scala/vexriscv/VexRiscvBmbGenerator.scala +++ b/src/main/scala/vexriscv/VexRiscvBmbGenerator.scala @@ -45,7 +45,7 @@ case class VexRiscvBmbGenerator()(implicit interconnectSmp: BmbInterconnectGener withRiscvDebug.load(false) } - def enableJtag(debugCd : ClockDomainResetGenerator, resetCd : ClockDomainResetGenerator) : Unit = debugCd.rework{ + def enableJtag(debugCd : ClockDomainResetGeneratorIf, resetCd : ClockDomainResetGeneratorIf) : Unit = debugCd.rework{ this.debugClockDomain.load(debugCd.outputClockDomain) val resetBridge = resetCd.asyncReset(debugReset, ResetSensitivity.HIGH) debugAskReset.loadNothing() @@ -53,7 +53,7 @@ case class VexRiscvBmbGenerator()(implicit interconnectSmp: BmbInterconnectGener if(!withRiscvDebug.isLoaded) withRiscvDebug.load(false) } - def enableJtagInstructionCtrl(debugCd : ClockDomainResetGenerator, resetCd : ClockDomainResetGenerator) : Unit = debugCd.rework{ + def enableJtagInstructionCtrl(debugCd : ClockDomainResetGeneratorIf, resetCd : ClockDomainResetGeneratorIf) : Unit = debugCd.rework{ this.debugClockDomain.load(debugCd.outputClockDomain) val resetBridge = resetCd.asyncReset(debugReset, ResetSensitivity.HIGH) debugAskReset.loadNothing() @@ -61,7 +61,7 @@ case class VexRiscvBmbGenerator()(implicit interconnectSmp: BmbInterconnectGener if(!withRiscvDebug.isLoaded) withRiscvDebug.load(false) } - def enableDebugBus(debugCd : ClockDomainResetGenerator, resetCd : ClockDomainResetGenerator) : Unit = debugCd.rework{ + def enableDebugBus(debugCd : ClockDomainResetGeneratorIf, resetCd : ClockDomainResetGeneratorIf) : Unit = debugCd.rework{ this.debugClockDomain.load(debugCd.outputClockDomain) val resetBridge = resetCd.asyncReset(debugReset, ResetSensitivity.HIGH) debugAskReset.loadNothing() @@ -69,7 +69,7 @@ case class VexRiscvBmbGenerator()(implicit interconnectSmp: BmbInterconnectGener if(!withRiscvDebug.isLoaded) withRiscvDebug.load(false) } - def enableRiscvDebug(debugCd : Handle[ClockDomain], resetCd : ClockDomainResetGenerator) : Unit = debugCd.on{ + def enableRiscvDebug(debugCd : Handle[ClockDomain], resetCd : ClockDomainResetGeneratorIf) : Unit = debugCd.on{ this.debugClockDomain.load(debugCd) debugAskReset.loadNothing() withRiscvDebug.load(true) @@ -85,7 +85,7 @@ case class VexRiscvBmbGenerator()(implicit interconnectSmp: BmbInterconnectGener val debugBmbAccessSource = Handle[BmbAccessCapabilities] val debugBmbAccessRequirements = Handle[BmbAccessParameter] - def enableDebugBmb(debugCd : Handle[ClockDomain], resetCd : ClockDomainResetGenerator, mapping : AddressMapping)(implicit debugMaster : BmbImplicitDebugDecoder = null) : Unit = debugCd.on{ + def enableDebugBmb(debugCd : Handle[ClockDomain], resetCd : ClockDomainResetGeneratorIf, mapping : AddressMapping)(implicit debugMaster : BmbImplicitDebugDecoder = null) : Unit = debugCd.on{ this.debugClockDomain.load(debugCd) val resetBridge = resetCd.asyncReset(debugReset, ResetSensitivity.HIGH) debugAskReset.loadNothing() From eeb65ed1c001ece8115787c2ae2ce7a2f06f0467 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 24 Mar 2023 08:39:07 +0100 Subject: [PATCH 875/951] VexRiscvBmbGenrator now use relaxedReset --- src/main/scala/vexriscv/VexRiscvBmbGenerator.scala | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/scala/vexriscv/VexRiscvBmbGenerator.scala b/src/main/scala/vexriscv/VexRiscvBmbGenerator.scala index 4af0e085..269f036a 100644 --- a/src/main/scala/vexriscv/VexRiscvBmbGenerator.scala +++ b/src/main/scala/vexriscv/VexRiscvBmbGenerator.scala @@ -47,7 +47,7 @@ case class VexRiscvBmbGenerator()(implicit interconnectSmp: BmbInterconnectGener def enableJtag(debugCd : ClockDomainResetGeneratorIf, resetCd : ClockDomainResetGeneratorIf) : Unit = debugCd.rework{ this.debugClockDomain.load(debugCd.outputClockDomain) - val resetBridge = resetCd.asyncReset(debugReset, ResetSensitivity.HIGH) + val resetBridge = resetCd.relaxedReset(debugReset, ResetSensitivity.HIGH) debugAskReset.loadNothing() withDebug.load(DEBUG_JTAG) if(!withRiscvDebug.isLoaded) withRiscvDebug.load(false) @@ -55,7 +55,7 @@ case class VexRiscvBmbGenerator()(implicit interconnectSmp: BmbInterconnectGener def enableJtagInstructionCtrl(debugCd : ClockDomainResetGeneratorIf, resetCd : ClockDomainResetGeneratorIf) : Unit = debugCd.rework{ this.debugClockDomain.load(debugCd.outputClockDomain) - val resetBridge = resetCd.asyncReset(debugReset, ResetSensitivity.HIGH) + val resetBridge = resetCd.relaxedReset(debugReset, ResetSensitivity.HIGH) debugAskReset.loadNothing() withDebug.load(DEBUG_JTAG_CTRL) if(!withRiscvDebug.isLoaded) withRiscvDebug.load(false) @@ -63,7 +63,7 @@ case class VexRiscvBmbGenerator()(implicit interconnectSmp: BmbInterconnectGener def enableDebugBus(debugCd : ClockDomainResetGeneratorIf, resetCd : ClockDomainResetGeneratorIf) : Unit = debugCd.rework{ this.debugClockDomain.load(debugCd.outputClockDomain) - val resetBridge = resetCd.asyncReset(debugReset, ResetSensitivity.HIGH) + val resetBridge = resetCd.relaxedReset(debugReset, ResetSensitivity.HIGH) debugAskReset.loadNothing() withDebug.load(DEBUG_BUS) if(!withRiscvDebug.isLoaded) withRiscvDebug.load(false) @@ -87,7 +87,7 @@ case class VexRiscvBmbGenerator()(implicit interconnectSmp: BmbInterconnectGener val debugBmbAccessRequirements = Handle[BmbAccessParameter] def enableDebugBmb(debugCd : Handle[ClockDomain], resetCd : ClockDomainResetGeneratorIf, mapping : AddressMapping)(implicit debugMaster : BmbImplicitDebugDecoder = null) : Unit = debugCd.on{ this.debugClockDomain.load(debugCd) - val resetBridge = resetCd.asyncReset(debugReset, ResetSensitivity.HIGH) + val resetBridge = resetCd.relaxedReset(debugReset, ResetSensitivity.HIGH) debugAskReset.loadNothing() withDebug.load(DEBUG_BMB) if(!withRiscvDebug.isLoaded) withRiscvDebug.load(false) From e754c5c3a05b6a43f1c4e34670fe030145531d43 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 27 Mar 2023 08:23:21 +0200 Subject: [PATCH 876/951] cleanup IBusDBusCachedTightlyCoupledRam --- .../vexriscv/plugin/DBusCachedPlugin.scala | 56 ++++++++----------- 1 file changed, 24 insertions(+), 32 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index 9ebec22b..ea342135 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -429,7 +429,7 @@ class DBusCachedPlugin(val config : DataCacheConfig, U(0) -> B"0001", U(1) -> B"0011", default -> B"1111" - ) //|<< port.bus.address(1 downto 0) + ) |<< port.bus.address(1 downto 0) } } } @@ -567,7 +567,7 @@ class DBusCachedPlugin(val config : DataCacheConfig, cache.io.cpu.writeBack.isValid := False exceptionBus.valid := False redoBranch.valid := False - rspRf := input(MEMORY_TIGHTLY_DATA) + rspData := input(MEMORY_TIGHTLY_DATA) input(HAS_SIDE_EFFECT) := False } } @@ -629,15 +629,15 @@ class DBusCachedPlugin(val config : DataCacheConfig, } - - -class IBusDBusCachedTightlyCoupledRam(mapping : SizeMapping, withIBus : Boolean = true) extends Plugin[VexRiscv]{ +class IBusDBusCachedTightlyCoupledRam(mapping : SizeMapping, withIBus : Boolean = true, withDBus : 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(withDBus) { + dbus = pipeline.service(classOf[DBusCachedPlugin]).newTightlyCoupledPort(addr => mapping.hit(addr)) + dbus.setCompositeName(this, "dbus").setAsDirectionLess() + } if(withIBus){ ibus = pipeline.service(classOf[IBusCachedPlugin]).newTightlyCoupledPortV2( @@ -652,32 +652,24 @@ class IBusDBusCachedTightlyCoupledRam(mapping : SizeMapping, withIBus : Boolean 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 - ) - } + val ram = Mem(Bits(32 bits), mapping.size.toInt/4) + ram.generateAsBlackBox() + val d = withDBus generate new Area { + dbus.read_data := ram.readWriteSync( + address = (dbus.address >> 2).resized, + data = dbus.write_data, + enable = dbus.enable, + write = dbus.write_enable + ) + } + val i = withIBus generate new Area { + ibus.data := ram.readWriteSync( + address = (ibus.address >> 2).resized, + data = B(32 bits, default -> False), + enable = ibus.enable, + write = False + ) } - - 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 } } } From a33380894caf18c4d24ff69605815ba4cefa47f5 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 27 Mar 2023 09:57:55 +0200 Subject: [PATCH 877/951] sync --- src/main/scala/vexriscv/TestsWorkspace.scala | 22 ++++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/main/scala/vexriscv/TestsWorkspace.scala b/src/main/scala/vexriscv/TestsWorkspace.scala index 39389214..df15a80f 100644 --- a/src/main/scala/vexriscv/TestsWorkspace.scala +++ b/src/main/scala/vexriscv/TestsWorkspace.scala @@ -144,19 +144,19 @@ object TestsWorkspace { withDouble = true, externalFpu = false, simHalt = true, - privilegedDebug = true + privilegedDebug = false ) - config.plugins += new EmbeddedRiscvJtag( - p = DebugTransportModuleParameter( - addressWidth = 7, - version = 1, - idle = 7 - ), - debugCd = ClockDomain.current.copy(reset = Bool().setName("debugReset")), - withTunneling = false, - withTap = true - ) +// config.plugins += new EmbeddedRiscvJtag( +// p = DebugTransportModuleParameter( +// addressWidth = 7, +// version = 1, +// idle = 7 +// ), +// debugCd = ClockDomain.current.copy(reset = Bool().setName("debugReset")), +// withTunneling = false, +// withTap = true +// ) // l.foreach{ // case p : EmbeddedRiscvJtag => p.debugCd.load(ClockDomain.current.copy(reset = Bool().setName("debug_reset"))) From e357420d11205dc53c9d6e9b580b2a38f4695914 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 29 Mar 2023 11:10:45 +0200 Subject: [PATCH 878/951] CsrPluginConfig more var --- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 1d035844..87339012 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -39,10 +39,10 @@ object CsrAccess { case class ExceptionPortInfo(port : Flow[ExceptionCause],stage : Stage, priority : Int, codeWidth : Int) case class CsrPluginConfig( catchIllegalAccess : Boolean, - mvendorid : BigInt, - marchid : BigInt, - mimpid : BigInt, - mhartid : BigInt, + var mvendorid : BigInt, + var marchid : BigInt, + var mimpid : BigInt, + var mhartid : BigInt, misaExtensionsInit : Int, misaAccess : CsrAccess, mtvecAccess : CsrAccess, From 9c2e05cce09ce0521e18150b3c1e0a40a74148f6 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 29 Mar 2023 14:56:53 +0200 Subject: [PATCH 879/951] Ensure that fence.i wait d$ inflight write and reschedule the next instruction --- src/main/scala/vexriscv/ip/DataCache.scala | 6 +++++- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 11 ++++++----- src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala | 9 +++++++++ 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index a2e43aa2..17766c21 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -207,12 +207,14 @@ case class DataCacheCpuBus(p : DataCacheConfig, mmu : MemoryTranslatorBusParamet val redo = Bool() val flush = Stream(DataCacheFlush(p.lineCount)) + val writesPending = Bool() + override def asMaster(): Unit = { master(execute) master(memory) master(writeBack) master(flush) - in(redo) + in(redo, writesPending) } } @@ -717,6 +719,8 @@ class DataCache(val p : DataCacheConfig, mmuParameter : MemoryTranslatorBusParam } val uncached = history.readAsync(rPtr.resized) val full = RegNext(wPtr - rPtr >= pendingMax-1) + val empty = wPtr === rPtr + io.cpu.writesPending := !empty io.cpu.execute.haltIt setWhen(full) } diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 87339012..2204a65e 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -497,7 +497,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep object ENV_CTRL extends Stageable(EnvCtrlEnum()) object IS_CSR extends Stageable(Bool) - object IS_SFENCE_VMA extends Stageable(Bool) + object RESCHEDULE_NEXT extends Stageable(Bool) object CSR_WRITE_OPCODE extends Stageable(Bool) object CSR_READ_OPCODE extends Stageable(Bool) object PIPELINED_CSR_READ extends Stageable(Bits(32 bits)) @@ -639,8 +639,9 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep if(utimeAccess != CsrAccess.NONE) utime = in UInt(64 bits) setName("utime") if(supervisorGen) { - decoderService.addDefault(IS_SFENCE_VMA, False) - decoderService.add(SFENCE_VMA, List(IS_SFENCE_VMA -> True)) + decoderService.addDefault(RESCHEDULE_NEXT, False) + decoderService.add(SFENCE_VMA, List(RESCHEDULE_NEXT -> True)) + decoderService.add(FENCE_I, List(RESCHEDULE_NEXT -> True)) } xretAwayFromMachine = False @@ -1143,7 +1144,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep redoInterface.payload := decode.input(PC) val rescheduleNext = False - when(execute.arbitration.isValid && execute.input(IS_SFENCE_VMA)) { rescheduleNext := True } + when(execute.arbitration.isValid && execute.input(RESCHEDULE_NEXT)) { rescheduleNext := True } duringWrite(CSR.SATP) { rescheduleNext := True } when(rescheduleNext){ @@ -1581,7 +1582,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep if(!pipelineCsrRead) output(REGFILE_WRITE_DATA) := readData } - when(arbitration.isValid && (input(IS_CSR) || (if(supervisorGen) input(IS_SFENCE_VMA) else False))) { + when(arbitration.isValid && (input(IS_CSR) || (if(supervisorGen) input(RESCHEDULE_NEXT) else False))) { arbitration.haltItself setWhen(blockedBySideEffects) } diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index ea342135..623add8d 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -160,6 +160,7 @@ class DBusCachedPlugin(val config : DataCacheConfig, object MEMORY_LRSC extends Stageable(Bool) object MEMORY_AMO extends Stageable(Bool) object MEMORY_FENCE extends Stageable(Bool) + object MEMORY_FENCE_WR extends Stageable(Bool) object MEMORY_FORCE_CONSTISTENCY extends Stageable(Bool) object IS_DBUS_SHARING extends Stageable(Bool()) object MEMORY_VIRTUAL_ADDRESS extends Stageable(UInt(32 bits)) @@ -267,6 +268,8 @@ class DBusCachedPlugin(val config : DataCacheConfig, case true => { decoderService.addDefault(MEMORY_FENCE, False) decoderService.add(FENCE, List(MEMORY_FENCE -> True)) + decoderService.addDefault(MEMORY_FENCE_WR, False) + decoderService.add(FENCE_I, List(MEMORY_FENCE_WR -> True)) } } @@ -405,6 +408,12 @@ class DBusCachedPlugin(val config : DataCacheConfig, ) } + if(withWriteResponse){ + when(arbitration.isValid && input(MEMORY_FENCE_WR) && cache.io.cpu.writesPending){ + arbitration.haltItself := True + } + } + if(tightlyGen){ tightlyCoupledAddressStage match { case false => From b4d5a315cf8a495ccf502c66453f7593d616ca0f Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 31 Mar 2023 10:11:53 +0200 Subject: [PATCH 880/951] CsrPlugin implement dummy pmp if no pmp is there --- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 10 +++++----- src/test/cpp/regression/main.cpp | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 2204a65e..afe3e6cf 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -1692,11 +1692,11 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep } //When no PMP => -// if(!csrMapping.mapping.contains(0x3A0)){ -// when(arbitration.isValid && input(IS_CSR) && U(csrAddress) >= 0x3A0 && U(csrAddress) <= 0x3EF){ -// csrMapping.allowCsrSignal := True -// } -// } + if(!csrMapping.mapping.contains(0x3A0)){ + when(arbitration.isValid && input(IS_CSR) && (csrAddress(11 downto 2) ## B"00" === 0x3A0 || csrAddress(11 downto 4) ## B"0000" === 0x3B0)){ + csrMapping.allowCsrSignal := True + } + } illegalAccess clearWhen(csrMapping.allowCsrSignal) diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 3bbd26c9..1f20d000 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -630,7 +630,7 @@ public: #endif default: { -// if(csr >= 0x3A0 && csr <= 0x3EF) break; //PMP + if(csr >= 0x3A0 && csr <= 0x3A3 || csr >= 0x3B0 && csr <= 0x3BF) break; //PMP return true; }break; } @@ -686,7 +686,7 @@ public: #endif default: { -// if(csr >= 0x3A0 && csr <= 0x3EF) break; //PMP + if(csr >= 0x3A0 && csr <= 0x3A3 || csr >= 0x3B0 && csr <= 0x3BF) break; //PMP ilegalInstruction(); return true; }break; From cb0bacfce981491b1093940b9bd5452cba58db3a Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 31 Mar 2023 10:12:15 +0200 Subject: [PATCH 881/951] implement dummy pmp as 1.10 spec says --- src/test/cpp/raw/privSpec/build/privSpec.hex | 142 +++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 src/test/cpp/raw/privSpec/build/privSpec.hex diff --git a/src/test/cpp/raw/privSpec/build/privSpec.hex b/src/test/cpp/raw/privSpec/build/privSpec.hex new file mode 100644 index 00000000..e8dd4267 --- /dev/null +++ b/src/test/cpp/raw/privSpec/build/privSpec.hex @@ -0,0 +1,142 @@ +:0200000480007A +:10000000971000009380008873905030130E1000FA +:1000100073101030930010007390503073215030E3 +:10002000E31001067390501073215010E31A01047D +:1000300097100000938000857390503093009000DB +:100040007390203473212034E31C1102130E20001E +:10005000F32000B0732100B0E3D42002F32020B0DD +:10006000732120B0E3DE2000F32000C0732100C024 +:10007000E3D82000F32020C0732120C0E3D2200069 +:10008000F32010C0732110C063DC207E97000000B5 +:100090009380400873905030970000009380C00216 +:1000A00073901034B710000093800080739000307C +:1000B000730020306F00C07C6F00807C6F00407C3C +:1000C0006F00007CF3201014F3202014F3200010A4 +:1000D000F3203014F3204014130E3000F32000C03E +:1000E000732100C063DE2078F32020C0732120C07C +:1000F00063D82078F32010C0732110C063D2207819 +:10010000730000006F00C0771300000013000000B0 +:10011000F3201034F3202034F3200030F320303467 +:10012000F3204034F3201014F3202014F3200010A7 +:10013000F3203014F32040149700000093808006D1 +:1001400073905030970000009380800273901034B9 +:100150009300000073900030730020306F004072F5 +:100160006F0000726F00C0716F008071130E40004D +:10017000F32000C0732100C063D42070F32020C09E +:10018000732120C063DE206EF32010C0732110C0E5 +:1001900063D8206E730000006F00806E13000000B3 +:1001A000F3201034F3202034F3200030F3203034D7 +:1001B000F3204034F3201014F3202014F320001017 +:1001C000F3203014F32040149300F0FF739060305C +:1001D00093000000739060109700000093808008E7 +:1001E00073905030970000009380C00273901034D9 +:1001F000B7100000938000807390003073002030AF +:100200006F0000686F00C0676F0080676F00406715 +:10021000F3201014F3202014F3200010F3203014E6 +:10022000F3204014130E3000F32000C0732100C0EF +:1002300063D82064F32020C0732120C063D22064DF +:10024000F32010C0732110C063DC20627300000033 +:100250006F00006313000000130000001300000093 +:10026000F3201034F3202034F3200030F320303416 +:10027000F3204034F3201014F3202014F320001056 +:10028000F3203014F3204014970000009380800482 +:100290007390503097000000938080027390103468 +:1002A0009300000073900030730020306F00405DB9 +:1002B0006F00005D6F00C05C6F00805CF32000C0C9 +:1002C0006F00005C6F00C05B1300000013000000B3 +:1002D000F3201034F3202034F3200030F3203034A6 +:1002E000F3204034F3201014F3202014F3200010E6 +:1002F000F3203014F3204014970000009380800412 +:1003000073905030970000009380800273901034F7 +:100310009300000073900030730020306F0040564F +:100320006F0000566F00C0556F008055F32020C04D +:100330006F0000556F00C054130000001300000050 +:10034000F3201034F3202034F3200030F320303435 +:10035000F3204034F3201014F3202014F320001075 +:10036000F3203014F32040149700000093808004A1 +:100370007390503097000000938080027390103487 +:100380009300000073900030730020306F00404FE6 +:100390006F00004F6F00C04E6F00804EF32010C002 +:1003A0006F00004E6F00C04D1300000013000000EE +:1003B000F3201034F3202034F3200030F3203034C5 +:1003C000F3204034F3201014F3202014F320001005 +:1003D000F3203014F3204014930000007390603039 +:1003E0009300F0FF739060109700000093808005E9 +:1003F00073905030970000009380C00273901034C7 +:10040000B71000009380008073900030730020309C +:100410006F0000476F00C0466F0080466F00404687 +:10042000F3201014F3202014F3200010F3203014D4 +:10043000F3204014F32000C06F0080446F0040445C +:10044000F3201034F3202034F3200030F320303434 +:10045000F3204034F3201014F3202014F320001074 +:10046000F3203014F320401497000000938080059F +:1004700073905030970000009380C0027390103446 +:10048000B71000009380008073900030730020301C +:100490006F00003F6F00C03E6F00803E6F00403E27 +:1004A000F3201014F3202014F3200010F320301454 +:1004B000F3204014F32020C06F00803C6F00403CCC +:1004C000F3201034F3202034F3200030F3203034B4 +:1004D000F3204034F3201014F3202014F3200010F4 +:1004E000F3203014F320401497000000938080051F +:1004F00073905030970000009380C00273901034C6 +:10050000B71000009380008073900030730020309B +:100510006F0000376F00C0366F0080366F004036C6 +:10052000F3201014F3202014F3200010F3203014D3 +:10053000F3204014F32010C06F0080346F0040346B +:10054000F3201034F3202034F3200030F320303433 +:10055000F3204034F3201014F3202014F320001073 +:10056000F3203014F320401497000000938080049F +:100570007390503097000000938080027390103485 +:100580009300000073900030730020306F00402F04 +:100590006F00002F6F00C02E6F00802EF32000C070 +:1005A0006F00002E6F00C02D13000000130000002C +:1005B000F3201034F3202034F3200030F3203034C3 +:1005C000F3204034F3201014F3202014F320001003 +:1005D000F3203014F320401497000000938080042F +:1005E0007390503097000000938080027390103415 +:1005F0009300000073900030730020306F0040289B +:100600006F0000286F00C0276F008027F32020C0F4 +:100610006F0000276F00C0261300000013000000C9 +:10062000F3201034F3202034F3200030F320303452 +:10063000F3204034F3201014F3202014F320001092 +:10064000F3203014F32040149700000093808004BE +:1006500073905030970000009380800273901034A4 +:100660009300000073900030730020306F00402131 +:100670006F0000216F00C0206F008020F32010C0A9 +:100680006F0000206F00C01F130000001300000067 +:10069000F3201034F3202034F3200030F3203034E2 +:1006A000F3204034F3201014F3202014F320001022 +:1006B000F3203014F3204014970000009380801C36 +:1006C00073905030B740000073900030F32000303A +:1006D00037610080B3F02000374100006392201A98 +:1006E000970000009380001D07A00000F320003059 +:1006F00037610080B3F0200063942018B7400000F9 +:1007000073900030F320003037610080B3F0200098 +:1007100037410000639620169700000093808019EF +:1007200027A00000F320003037610080B3F02000E4 +:100730003741000063962014D30000E037010040E9 +:1007400063902014F320003037610080B3F0200064 +:100750003741000063962012B7000080538000F0FC +:10076000F320003037610080B3F02000639A20103E +:10077000B740000073900030B700003F538000F096 +:10078000F320003037610080B3F02000639A200E20 +:10079000B740000073900030D37000C0F3200030E9 +:1007A00037610080B3F02000639C200CB74000004C +:1007B00073900030B7000040538000F0F320003009 +:1007C00037610080B3F02000639C200AB74000002E +:1007D00073900030D37000C0F32000303761008088 +:1007E000B3F0200037410000639C2008B700804F21 +:1007F000538000F0F320003037610080B3F0200018 +:1008000063902008B740000073900030D37000C0A0 +:10081000F320003037610080B3F02000639220069F +:10082000B74000007390003073103000F3200030A8 +:1008300037610080B3F0200063942004B7400000CB +:100840007390003073102000F32000303761008077 +:10085000B3F0200063962002B74000007390003090 +:1008600073101000F320003037610080B3F02000D7 +:1008700063982000B7400000739000306F000001C3 +:10088000370110F0130141F22320C101370110F0AC +:10089000130101F2232001001300000013000000E7 +:1008A00013000000130000001300000013000000FC +:0808B000000000400000000000 +:00000001FF From 95e61a7951b5f46bed3e2fbd09da87d13ebd91f4 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 4 Apr 2023 11:47:49 +0200 Subject: [PATCH 882/951] Revert CfuPlugin --- .../scala/vexriscv/plugin/CfuPlugin.scala | 52 ++++++------------- 1 file changed, 17 insertions(+), 35 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/CfuPlugin.scala b/src/main/scala/vexriscv/plugin/CfuPlugin.scala index 2e878eae..00b720da 100644 --- a/src/main/scala/vexriscv/plugin/CfuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CfuPlugin.scala @@ -1,6 +1,6 @@ package vexriscv.plugin -import vexriscv.{DecoderService, ExceptionCause, ExceptionService, JumpService, Stage, Stageable, VexRiscv} +import vexriscv.{DecoderService, ExceptionCause, ExceptionService, Stage, Stageable, VexRiscv} import spinal.core._ import spinal.lib._ import spinal.lib.bus.bmb.WeakConnector @@ -92,9 +92,7 @@ object CfuPlugin{ case class CfuPluginEncoding(instruction : MaskedLiteral, functionId : List[Range], - input2Kind : CfuPlugin.Input2Kind.E, - withCmd : Boolean = true, - withRsp : Boolean = true){ + input2Kind : CfuPlugin.Input2Kind.E){ val functionIdWidth = functionId.map(_.size).sum } @@ -113,7 +111,6 @@ class CfuPlugin(val stageCount : Int, // assert(p.CFU_FUNCTION_ID_W == 3) var bus : CfuBus = null -// var redoInterface : Flow[UInt] = null lazy val forkStage = pipeline.execute lazy val joinStage = pipeline.stages(Math.min(pipeline.stages.length - 1, pipeline.indexOf(forkStage) + stageCount)) @@ -123,45 +120,31 @@ class CfuPlugin(val stageCount : Int, val CFU_IN_FLIGHT = new Stageable(Bool()).setCompositeName(this, "CFU_IN_FLIGHT") val CFU_ENCODING = new Stageable(UInt(log2Up(encodings.size) bits)).setCompositeName(this, "CFU_ENCODING") val CFU_INPUT_2_KIND = new Stageable(CfuPlugin.Input2Kind()).setCompositeName(this, "CFU_INPUT_2_KIND") - val CFU_WITH_CMD = new Stageable(Bool()).setCompositeName(this, "CFU_WITH_CMD") - val CFU_WITH_RSP = new Stageable(Bool()).setCompositeName(this, "CFU_WITH_RSP") override def setup(pipeline: VexRiscv): Unit = { import pipeline._ import pipeline.config._ -// val pcManagerService = pipeline.service(classOf[JumpService]) -// if(encodings.contains(_.cmd)redoInterface = pcManagerService.createJumpInterface(pipeline.writeBack) - bus = master(CfuBus(p)) val decoderService = pipeline.service(classOf[DecoderService]) decoderService.addDefault(CFU_ENABLE, False) - decoderService.addDefault(CFU_WITH_CMD, False) - decoderService.addDefault(CFU_WITH_RSP, False) for((encoding, id) <- encodings.zipWithIndex){ - var actions : List[(Stageable[_ <: BaseType], Any)] = List( + var actions = List( CFU_ENABLE -> True, + REGFILE_WRITE_VALID -> True, + BYPASSABLE_EXECUTE_STAGE -> Bool(stageCount == 0), + BYPASSABLE_MEMORY_STAGE -> Bool(stageCount <= 1), + RS1_USE -> True, CFU_ENCODING -> U(id), - CFU_WITH_CMD -> Bool(encoding.withCmd), - CFU_WITH_RSP -> Bool(encoding.withRsp) + CFU_INPUT_2_KIND -> encoding.input2Kind() ) - if(encoding.withCmd){ - actions :+= RS1_USE -> True - actions :+= CFU_INPUT_2_KIND -> encoding.input2Kind() - encoding.input2Kind match { - case CfuPlugin.Input2Kind.RS => - actions :+= RS2_USE -> True - case CfuPlugin.Input2Kind.IMM_I => - } - } - - if(encoding.withRsp){ - actions :+= REGFILE_WRITE_VALID -> True - actions :+= BYPASSABLE_EXECUTE_STAGE -> Bool(stageCount == 0) - actions :+= BYPASSABLE_MEMORY_STAGE -> Bool(stageCount <= 1) + encoding.input2Kind match { + case CfuPlugin.Input2Kind.RS => + actions :+= RS2_USE -> True + case CfuPlugin.Input2Kind.IMM_I => } decoderService.add( @@ -208,7 +191,7 @@ class CfuPlugin(val stageCount : Int, import forkStage._ input(CFU_ENABLE).clearWhen(!input(LEGAL_INSTRUCTION)) val hazard = stages.dropWhile(_ != forkStage).tail.map(s => s.arbitration.isValid && s.input(HAS_SIDE_EFFECT)).orR - val scheduleWish = arbitration.isValid && input(CFU_ENABLE) && input(CFU_WITH_CMD) + val scheduleWish = arbitration.isValid && input(CFU_ENABLE) val schedule = scheduleWish && !hazard arbitration.haltItself setWhen(scheduleWish && hazard) @@ -251,13 +234,12 @@ class CfuPlugin(val stageCount : Int, bus.rsp.combStage() } - val hazard = stages.dropWhile(_ != joinStage).tail.map(s => s.arbitration.isValid && s.input(HAS_SIDE_EFFECT)).orR rsp.ready := False - when((arbitration.isValid || input(CFU_IN_FLIGHT)) && input(CFU_WITH_RSP)){ - arbitration.haltItself setWhen(!rsp.valid || hazard) - rsp.ready := !arbitration.isStuckByOthers && !hazard + when(input(CFU_IN_FLIGHT)){ + arbitration.haltItself setWhen(!rsp.valid) + rsp.ready := !arbitration.isStuckByOthers output(REGFILE_WRITE_DATA) := rsp.outputs(0) - if(p.CFU_WITH_STATUS) when(rsp.fire){ + if(p.CFU_WITH_STATUS) when(arbitration.isFiring){ switch(rsp.status) { for (i <- 1 to 6) is(i) { csr.status.flags(i-1) := True From 320867e1350684d21a87176dc9ece9299ebd939e Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 4 Apr 2023 18:11:33 +0200 Subject: [PATCH 883/951] sync --- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index afe3e6cf..20912f30 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -857,7 +857,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep wakeService.askWake() } } - stoptime = out(debugMode && dcsr.stoptime).setName("stoptime") + stoptime = out(RegNext(debugMode && dcsr.stoptime) init(False)).setName("stoptime") //Very limited subset of the trigger spec val trigger = (debugTriggers > 0) generate new Area { From d8f6f28020eea0692ce4b88716050c517978bf42 Mon Sep 17 00:00:00 2001 From: Andreas Wallner Date: Fri, 7 Apr 2023 18:59:17 +0200 Subject: [PATCH 884/951] Remove sbt-assembly dependency The plugin is not used in the VexRiscV build and causes issues for users since repo.scala-sbt.org seems to be down/sunset/?. See also https://github.com/sbt/sbt/issues/7202 Updating the dependency would also have been an option, but since it's not used removal is easier. --- project/plugins.sbt | 1 - 1 file changed, 1 deletion(-) diff --git a/project/plugins.sbt b/project/plugins.sbt index 26ac3e58..e69de29b 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1 +0,0 @@ -addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.10") From d966c4efe1e702b3fd73ca97563cb9e64cf8f16d Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 10 Apr 2023 13:02:51 +0200 Subject: [PATCH 885/951] fix #328 medeleg EBREAK added --- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 20912f30..479b982b 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -997,8 +997,8 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep val medeleg = supervisorGen generate new Area { - val IAM, IAF, II, LAM, LAF, SAM, SAF, EU, ES, IPF, LPF, SPF = RegInit(False) - val mapping = mutable.LinkedHashMap(0 -> IAM, 1 -> IAF, 2 -> II, 4 -> LAM, 5 -> LAF, 6 -> SAM, 7 -> SAF, 8 -> EU, 9 -> ES, 12 -> IPF, 13 -> LPF, 15 -> SPF) + val IAM, IAF, II, BP, LAM, LAF, SAM, SAF, EU, ES, IPF, LPF, SPF = RegInit(False) + val mapping = mutable.LinkedHashMap(0 -> IAM, 1 -> IAF, 2 -> II, 3 -> BP, 4 -> LAM, 5 -> LAF, 6 -> SAM, 7 -> SAF, 8 -> EU, 9 -> ES, 12 -> IPF, 13 -> LPF, 15 -> SPF) } val mideleg = supervisorGen generate new Area { val ST, SE, SS = RegInit(False) From 051080e060ecf3feb84adf46e7e3759c281ebb93 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 13 Apr 2023 16:51:44 +0200 Subject: [PATCH 886/951] CsrPlugin now implement dummy HPM --- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 479b982b..24d94af3 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -1697,6 +1697,13 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep csrMapping.allowCsrSignal := True } } + //When no HPM + if(!csrMapping.mapping.contains(0xB03)){ + val masked = U(csrAddress & 0xF60) + when(arbitration.isValid && input(IS_CSR) && U(csrAddress(4 downto 0)) >= 3 && (masked === 0xB00 || masked === 0xC00 && !writeInstruction && privilege === 3 || U(csrAddress & 0xFE0) === 0x320)){ + csrMapping.allowCsrSignal := True + } + } illegalAccess clearWhen(csrMapping.allowCsrSignal) From 76491579463c45491519049f9db7985bfcade335 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 13 Apr 2023 16:52:20 +0200 Subject: [PATCH 887/951] d$ toBmb increase aggregation timer --- src/main/scala/vexriscv/ip/DataCache.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index 17766c21..848c347e 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -400,7 +400,7 @@ case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave def toBmb(syncPendingMax : Int = 32, - timeoutCycles : Int = 16) : Bmb = new Area{ + timeoutCycles : Int = 32) : Bmb = new Area{ setCompositeName(DataCacheMemBus.this, "Bridge", true) val pipelinedMemoryBusConfig = p.getBmbParameter() val bus = Bmb(pipelinedMemoryBusConfig).setCompositeName(this,"toBmb", true) From 8fc5f35d299bc323a12ac3c5419e4a50b916b2c0 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 24 Apr 2023 13:13:55 +0200 Subject: [PATCH 888/951] DBusCachedPlugin now provide writesPending signal --- src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index 623add8d..bcdad63e 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -64,6 +64,7 @@ class DBusCachedPlugin(val config : DataCacheConfig, var exceptionBus : Flow[ExceptionCause] = null var privilegeService : PrivilegeService = null var redoBranch : Flow[UInt] = null + var writesPending : Bool = null @dontName var dBusAccess : DBusAccess = null override def newDBusAccess(): DBusAccess = { @@ -270,6 +271,7 @@ class DBusCachedPlugin(val config : DataCacheConfig, decoderService.add(FENCE, List(MEMORY_FENCE -> True)) decoderService.addDefault(MEMORY_FENCE_WR, False) decoderService.add(FENCE_I, List(MEMORY_FENCE_WR -> True)) + writesPending = Bool().setCompositeName(this, "writesPending") } } @@ -412,6 +414,7 @@ class DBusCachedPlugin(val config : DataCacheConfig, when(arbitration.isValid && input(MEMORY_FENCE_WR) && cache.io.cpu.writesPending){ arbitration.haltItself := True } + writesPending := cache.io.cpu.writesPending } if(tightlyGen){ From ba6dcb1789caff4a91e9d99c57c7c119b7cdb4ba Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 27 Apr 2023 14:56:41 +0200 Subject: [PATCH 889/951] Add a few privSpec tests --- src/test/cpp/raw/privSpec/src/crt.S | 48 +++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/src/test/cpp/raw/privSpec/src/crt.S b/src/test/cpp/raw/privSpec/src/crt.S index f013ab28..b41119a5 100644 --- a/src/test/cpp/raw/privSpec/src/crt.S +++ b/src/test/cpp/raw/privSpec/src/crt.S @@ -11,6 +11,54 @@ _start: test1: li TEST_ID, 1 + + machine_setup_trap + csrr zero, ustatus + machine_handle_trap + + la x1, fail + csrw mtvec, x1 + + csrrw x0, mhpmcounter3, x0 + csrrw x0, mhpmcounter31, x0 + csrrw x0, mhpmevent3, x0 + csrrw x0, mhpmevent31, x0 + csrr x0, hpmcounter3 + csrr x0, hpmcounter31 + + machine_setup_trap + csrw hpmcounter3, x0 + machine_handle_trap + + machine_setup_trap + csrw hpmcounter31, x0 + machine_handle_trap + + machine_setup_trap; machine_to_user; csrrw x0, mhpmcounter3, x0; machine_handle_trap + machine_setup_trap; machine_to_user; csrrw x0, mhpmcounter31, x0; machine_handle_trap + machine_setup_trap; machine_to_user; csrrw x0, mhpmevent3, x0; machine_handle_trap + machine_setup_trap; machine_to_user; csrrw x0, mhpmevent31, x0; machine_handle_trap + machine_setup_trap; machine_to_user; csrr x0, hpmcounter3; machine_handle_trap + machine_setup_trap; machine_to_user; csrr x0, hpmcounter31; machine_handle_trap + + machine_setup_trap + machine_to_supervisor + ebreak + machine_handle_trap + csrr x1, mstatus + + li x1, 0x8 + csrw medeleg, x1 + machine_setup_trap + machine_to_supervisor + supervisor_setup_trap + ebreak + supervisor_handle_trap + csrr x1, sstatus + ecall + machine_handle_trap + + csrw misa, x0 //Test xtvec mode From b81029f619c0e0a67c27861cfb40ba7c6507f4e9 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 16 May 2023 16:50:38 +0100 Subject: [PATCH 890/951] fix fpu underflow rounding (#343) --- src/main/scala/vexriscv/ip/fpu/FpuCore.scala | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala index d9dcf698..b78f84f5 100644 --- a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala +++ b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala @@ -1547,15 +1547,22 @@ case class FpuCore( portCount : Int, p : FpuParameter) extends Component{ val expBase = muxDouble[UInt](input.format)(exponentF64Subnormal + 1)(exponentF32Subnormal + 1) val expDif = expBase -^ input.value.exponent val expSubnormal = !input.value.special && !expDif.msb - var discardCount = (expSubnormal ? expDif.resize(log2Up(p.internalMantissaSize) bits) | U(0)) + var discardCount = (expSubnormal ? expDif | U(0)) if (p.withDouble) when(input.format === FpuFormat.FLOAT) { discardCount \= discardCount + 29 } - val exactMask = (List(True) ++ (0 until p.internalMantissaSize + 1).map(_ < discardCount)).asBits.asUInt - val roundAdjusted = (True ## (manAggregate >> 1)) (discardCount) ## ((manAggregate & exactMask) =/= 0) + val discardCountTrunk = discardCount.resize(log2Up(p.internalMantissaSize) bits) + val exactMask = (List(True) ++ (0 until p.internalMantissaSize + 1).map(_ < discardCountTrunk)).asBits.asUInt + val roundAdjusted = (True ## (manAggregate >> 1)) (discardCountTrunk) ## ((manAggregate & exactMask) =/= 0) + val rneBit = CombInit((U"01" ## (manAggregate >> 2))(discardCountTrunk)) + when(discardCount >= widthOf(manAggregate)){ + rneBit := False + roundAdjusted(1) := False + exactMask := exactMask.maxValue + } val mantissaIncrement = !input.value.special && input.roundMode.mux( - FpuRoundMode.RNE -> (roundAdjusted(1) && (roundAdjusted(0) || (U"01" ## (manAggregate >> 2)) (discardCount))), + FpuRoundMode.RNE -> (roundAdjusted(1) && (roundAdjusted(0) || rneBit)), FpuRoundMode.RTZ -> False, FpuRoundMode.RDN -> (roundAdjusted =/= 0 && input.value.sign), FpuRoundMode.RUP -> (roundAdjusted =/= 0 && !input.value.sign), From 760a0fced5a574a02a3557fb08ce178b4c9b20b1 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 23 May 2023 18:18:53 +0200 Subject: [PATCH 891/951] Update SpinalHDL --- src/main/scala/vexriscv/ip/DataCache.scala | 3 ++- src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index 848c347e..5ed44f67 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -168,8 +168,9 @@ case class FenceFlags() extends Bundle { def forceAll(): Unit ={ List(SW,SR,SO,SI,PW,PR,PO,PI).foreach(_ := True) } - def clearAll(): Unit ={ + def clearFlags(): this.type ={ List(SW,SR,SO,SI,PW,PR,PO,PI).foreach(_ := False) + this } } diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index bcdad63e..593eb911 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -501,7 +501,7 @@ class DBusCachedPlugin(val config : DataCacheConfig, } when(!input(MEMORY_FENCE) || !arbitration.isFiring){ - cache.io.cpu.writeBack.fence.clearAll() + cache.io.cpu.writeBack.fence.clearFlags() } when(arbitration.isValid && (input(MEMORY_FENCE) || aquire)){ From 050b4d8c62319715a47f950ca89278cbf0bd2187 Mon Sep 17 00:00:00 2001 From: AdDraw Date: Thu, 15 Jun 2023 22:57:20 +0200 Subject: [PATCH 892/951] Add halfPipe function to DBusSimpleBus --- src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala index dbf66090..7053dcc3 100644 --- a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala @@ -103,6 +103,13 @@ case class DBusSimpleBus(bigEndian : Boolean = false) extends Bundle with IMaste s } + def cmdHalfPipe() : DBusSimpleBus = { + val s = DBusSimpleBus(bigEndian) + s.cmd << this.cmd.halfPipe() + s.rsp <> this.rsp + s + } + def genMask(cmd : DBusSimpleCmd) = { if(bigEndian) cmd.size.mux( @@ -245,7 +252,7 @@ case class DBusSimpleBus(bigEndian : Boolean = false) extends Bundle with IMaste } bus } - + def toBmb() : Bmb = { val pipelinedMemoryBusConfig = DBusSimpleBus.getBmbParameter() val bus = Bmb(pipelinedMemoryBusConfig) From 7f647f9d8dffa3ac132f4a25036cc9f421d36726 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 16 Jun 2023 08:47:18 +0200 Subject: [PATCH 893/951] Update DBusSimplePlugin.scala --- src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala index 7053dcc3..1dfa41f6 100644 --- a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala @@ -106,7 +106,7 @@ case class DBusSimpleBus(bigEndian : Boolean = false) extends Bundle with IMaste def cmdHalfPipe() : DBusSimpleBus = { val s = DBusSimpleBus(bigEndian) s.cmd << this.cmd.halfPipe() - s.rsp <> this.rsp + s.rsp >> this.rsp s } From 5860dc2321a9b41737fb094270c067b8acede46c Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 16 Jun 2023 10:07:24 +0100 Subject: [PATCH 894/951] Update DBusSimplePlugin.scala --- src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala index 1dfa41f6..97aa0c13 100644 --- a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala @@ -106,7 +106,7 @@ case class DBusSimpleBus(bigEndian : Boolean = false) extends Bundle with IMaste def cmdHalfPipe() : DBusSimpleBus = { val s = DBusSimpleBus(bigEndian) s.cmd << this.cmd.halfPipe() - s.rsp >> this.rsp + this.rsp := s.rsp s } From 1746af1cfe11d0f75b6d3b4460c7d4a0ff8cf98f Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Tue, 11 Jul 2023 04:13:36 +0800 Subject: [PATCH 895/951] Fix #352 GenCustomInterrupt demo --- .../scala/vexriscv/demo/GenCustomInterrupt.scala | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/scala/vexriscv/demo/GenCustomInterrupt.scala b/src/main/scala/vexriscv/demo/GenCustomInterrupt.scala index d0d9e485..cffaa1c1 100644 --- a/src/main/scala/vexriscv/demo/GenCustomInterrupt.scala +++ b/src/main/scala/vexriscv/demo/GenCustomInterrupt.scala @@ -11,6 +11,12 @@ object GenCustomInterrupt extends App{ def cpu() = new VexRiscv( config = VexRiscvConfig( plugins = List( + new CsrPlugin( + CsrPluginConfig.smallest.copy( + xtvecModeGen = true, + mtvecAccess = CsrAccess.WRITE_ONLY + ) + ), new UserInterruptPlugin( interruptName = "miaou", code = 20 @@ -19,12 +25,6 @@ object GenCustomInterrupt extends App{ interruptName = "rawrrr", code = 24 ), - new CsrPlugin( - CsrPluginConfig.smallest.copy( - xtvecModeGen = true, - mtvecAccess = CsrAccess.WRITE_ONLY - ) - ), new IBusSimplePlugin( resetVector = 0x80000000l, cmdForkOnSecondStage = false, From fd0f23abb686c1aa0c3bbcea5228d719992dca43 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Tue, 11 Jul 2023 04:18:28 +0800 Subject: [PATCH 896/951] Merge branch master into dev --- README.md | 112 +++- doc/gcdPeripheral/README.md | 592 ++++++++++++++++++ .../murax-gcd-diagrams-gcd-controlpath.png | Bin 0 -> 68613 bytes .../img/murax-gcd-diagrams-gcd-datapath.png | Bin 0 -> 56769 bytes .../img/murax-gcd-diagrams-gcd-dp+cp.png | Bin 0 -> 27013 bytes .../img/murax-gcd-diagrams-gcd.png | Bin 0 -> 15632 bytes .../img/murax-gcd-diagrams.drawio | 1 + doc/gcdPeripheral/img/simulationWave.PNG | Bin 0 -> 48129 bytes .../src/main/c/murax/gcd_world/makefile | 134 ++++ .../murax/gcd_world/project/build.properties | 1 + .../src/main/c/murax/gcd_world/src/crt.S | 98 +++ .../src/main/c/murax/gcd_world/src/gcd.h | 13 + .../src/main/c/murax/gcd_world/src/gpio.h | 15 + .../main/c/murax/gcd_world/src/interrupt.h | 17 + .../src/main/c/murax/gcd_world/src/linker.ld | 110 ++++ .../src/main/c/murax/gcd_world/src/main.c | 62 ++ .../src/main/c/murax/gcd_world/src/main.h | 78 +++ .../src/main/c/murax/gcd_world/src/murax.h | 20 + .../main/c/murax/gcd_world/src/prescaler.h | 16 + .../src/main/c/murax/gcd_world/src/timer.h | 20 + .../src/main/c/murax/gcd_world/src/uart.h | 42 ++ .../src/main/scala/vexriscv/demo/Murax.scala | 559 +++++++++++++++++ .../vexriscv/periph/gcd/Apb3GCDCtrl.scala | 39 ++ .../scala/vexriscv/periph/gcd/GCDCtrl.scala | 68 ++ .../scala/vexriscv/periph/gcd/GCDData.scala | 54 ++ .../scala/vexriscv/periph/gcd/GCDTop.scala | 46 ++ .../scala/vexriscv/periph/gcd/GCDTopSim.scala | 52 ++ project/plugins.sbt | 1 - src/main/scala/vexriscv/Services.scala | 14 + src/main/scala/vexriscv/VexRiscv.scala | 1 + .../vexriscv/demo/GenCustomInterrupt.scala | 12 +- .../scala/vexriscv/plugin/CsrPlugin.scala | 6 + .../vexriscv/plugin/DBusSimplePlugin.scala | 9 +- src/main/scala/vexriscv/plugin/Fetcher.scala | 7 + .../scala/vexriscv/plugin/FormalPlugin.scala | 4 + .../scala/vexriscv/plugin/MmuPlugin.scala | 12 +- src/test/cpp/custom/atomic/src/crt.S | 4 +- 37 files changed, 2205 insertions(+), 14 deletions(-) create mode 100644 doc/gcdPeripheral/README.md create mode 100644 doc/gcdPeripheral/img/murax-gcd-diagrams-gcd-controlpath.png create mode 100644 doc/gcdPeripheral/img/murax-gcd-diagrams-gcd-datapath.png create mode 100644 doc/gcdPeripheral/img/murax-gcd-diagrams-gcd-dp+cp.png create mode 100644 doc/gcdPeripheral/img/murax-gcd-diagrams-gcd.png create mode 100644 doc/gcdPeripheral/img/murax-gcd-diagrams.drawio create mode 100644 doc/gcdPeripheral/img/simulationWave.PNG create mode 100644 doc/gcdPeripheral/src/main/c/murax/gcd_world/makefile create mode 100644 doc/gcdPeripheral/src/main/c/murax/gcd_world/project/build.properties create mode 100644 doc/gcdPeripheral/src/main/c/murax/gcd_world/src/crt.S create mode 100644 doc/gcdPeripheral/src/main/c/murax/gcd_world/src/gcd.h create mode 100644 doc/gcdPeripheral/src/main/c/murax/gcd_world/src/gpio.h create mode 100644 doc/gcdPeripheral/src/main/c/murax/gcd_world/src/interrupt.h create mode 100644 doc/gcdPeripheral/src/main/c/murax/gcd_world/src/linker.ld create mode 100644 doc/gcdPeripheral/src/main/c/murax/gcd_world/src/main.c create mode 100644 doc/gcdPeripheral/src/main/c/murax/gcd_world/src/main.h create mode 100644 doc/gcdPeripheral/src/main/c/murax/gcd_world/src/murax.h create mode 100644 doc/gcdPeripheral/src/main/c/murax/gcd_world/src/prescaler.h create mode 100644 doc/gcdPeripheral/src/main/c/murax/gcd_world/src/timer.h create mode 100644 doc/gcdPeripheral/src/main/c/murax/gcd_world/src/uart.h create mode 100644 doc/gcdPeripheral/src/main/scala/vexriscv/demo/Murax.scala create mode 100644 doc/gcdPeripheral/src/main/scala/vexriscv/periph/gcd/Apb3GCDCtrl.scala create mode 100644 doc/gcdPeripheral/src/main/scala/vexriscv/periph/gcd/GCDCtrl.scala create mode 100644 doc/gcdPeripheral/src/main/scala/vexriscv/periph/gcd/GCDData.scala create mode 100644 doc/gcdPeripheral/src/main/scala/vexriscv/periph/gcd/GCDTop.scala create mode 100644 doc/gcdPeripheral/src/main/scala/vexriscv/periph/gcd/GCDTopSim.scala diff --git a/README.md b/README.md index 63ed33e6..c7578c6f 100644 --- a/README.md +++ b/README.md @@ -319,7 +319,7 @@ If you want to get more information about how all this JTAG / GDB stuff work, yo ## Briey SoC As a demonstration, a SoC named Briey is implemented in `src/main/scala/vexriscv/demo/Briey.scala`. This SoC is very similar to -the [Pinsec SoC](https://spinalhdl.github.io/SpinalDoc-RTD/SpinalHDL/Legacy/pinsec/hardware_toplevel.html#): +the [Pinsec SoC](https://spinalhdl.github.io/SpinalDoc-RTD/v1.3.1/SpinalHDL/Legacy/pinsec/hardware_toplevel.html): ![Briey SoC](assets/brieySoc.png?raw=true "") @@ -753,6 +753,12 @@ Fpu 64/32 bits -> Artix 7 FMax -> 165 Mhz 3728 LUT 3175 FF ``` +Note that if you want to debug FPU code via the openocd_riscv.vexriscv target, you need to use the GDB from : + +https://static.dev.sifive.com/dev-tools/riscv64-unknown-elf-gcc-20171231-x86_64-linux-centos6.tar.gz + +More recent versions of gdb will not detect the FPU. Also, the openocd_riscv.vexriscv can't read CSR/FPU registers, so to have visibility on the floating points values, you need to compile your code in -O0, which will force values to be stored in memory (and so, be visible) + ### Plugins This chapter describes the currently implemented plugins. @@ -866,6 +872,41 @@ Simple and light multi-way instruction cache. Note: If you enable the twoCycleRam option and if wayCount is bigger than one, then the register file plugin should be configured to read the regFile in an asynchronous manner. +The memory bus is defined as : + +```scala +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(p.memDataWidth bit) + val error = Bool +} + +case class InstructionCacheMemBus(p : InstructionCacheConfig) extends Bundle with IMasterSlave{ + val cmd = Stream (InstructionCacheMemCmd(p)) + val rsp = Flow (InstructionCacheMemRsp(p)) + + override def asMaster(): Unit = { + master(cmd) + slave(rsp) + } +} +``` + +The address is in byte and aligned to the bytePerLine config, the size will always be equal to log2(bytePerLine). + +Note that the cmd stream transaction need to be consumed before starting to send back some rsp transactions (1 cycle minimal latency) + +Some documentation about Stream here : + +https://spinalhdl.github.io/SpinalDoc-RTD/master/SpinalHDL/Libraries/stream.html?highlight=stream + +Flow are the same as Stream but without ready signal. + + #### DecoderSimplePlugin This plugin provides instruction decoding capabilities to other plugins. @@ -1044,6 +1085,75 @@ Multi way cache implementation with writh-through and allocate on read strategy. You can invalidate the whole cache via the 0x500F instruction, and you can invalidate a address range (single line size) via the instruction 0x500F | RS1 << 15 where RS1 should not be X0 and point to one byte of the desired address to invalidate. + +The memory bus is defined as : + +```scala +case class DataCacheMemCmd(p : DataCacheConfig) extends Bundle{ + val wr = Bool + val uncached = Bool + val address = UInt(p.addressWidth bit) + val data = Bits(p.cpuDataWidth bits) + val mask = Bits(p.cpuDataWidth/8 bits) + val size = UInt(p.sizeWidth bits) //... 1 => 2 bytes ... 2 => 4 bytes ... + val exclusive = p.withExclusive generate Bool() + val last = Bool +} +case class DataCacheMemRsp(p : DataCacheConfig) extends Bundle{ + val aggregated = UInt(p.aggregationWidth bits) + val last = Bool() + val data = Bits(p.memDataWidth bit) + val error = Bool + val exclusive = p.withExclusive generate Bool() +} +case class DataCacheInv(p : DataCacheConfig) extends Bundle{ + val enable = Bool() + val address = UInt(p.addressWidth bit) +} +case class DataCacheAck(p : DataCacheConfig) extends Bundle{ + val hit = Bool() +} + +case class DataCacheSync(p : DataCacheConfig) extends Bundle{ + val aggregated = UInt(p.aggregationWidth bits) +} + +case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave{ + val cmd = Stream (DataCacheMemCmd(p)) + val rsp = Flow (DataCacheMemRsp(p)) + + val inv = p.withInvalidate generate Stream(Fragment(DataCacheInv(p))) + val ack = p.withInvalidate generate Stream(Fragment(DataCacheAck(p))) + val sync = p.withInvalidate generate Stream(DataCacheSync(p)) + + override def asMaster(): Unit = { + master(cmd) + slave(rsp) + + if(p.withInvalidate) { + slave(inv) + master(ack) + slave(sync) + } + } +} +``` + +If you don't use memory coherency you can ignore the inv/ack/sync streams, also write cmd should not generate any rsp transaction. + +As the cache is write through, there is no write burst but only individual write transactions. + +The address is in byte and aligned to the bytePerLine config, the size will is encoded as log2(number of bytes in the burst). +last should be set only on the last transaction of a burst. + +Note that the cmd stream transaction need to be consumed before starting to send back some rsp transactions (1 cycle minimal latency) + +Some documentation about Stream here : + +https://spinalhdl.github.io/SpinalDoc-RTD/master/SpinalHDL/Libraries/stream.html?highlight=stream + +Flow are the same as Stream but without ready signal. + #### MulPlugin Implements the multiplication instruction from the RISC-V M extension. Its implementation was done in a FPGA friendly way by using 4 17*17 bit multiplications. diff --git a/doc/gcdPeripheral/README.md b/doc/gcdPeripheral/README.md new file mode 100644 index 00000000..210fbbaf --- /dev/null +++ b/doc/gcdPeripheral/README.md @@ -0,0 +1,592 @@ +# Tutorial on Implementing a Peripheral for the VexRiscv Based Murax SoC +**By** + +**Sallar Ahmadi-Pour - Researcher, University of Bremen, Group of Computer Architecture** + +[http://www.informatik.uni-bremen.de/agra/projects/risc-v/](http://www.informatik.uni-bremen.de/agra/projects/risc-v/) + +[http://www.informatik.uni-bremen.de/agra/](http://www.informatik.uni-bremen.de/agra/) + + +## 1. Introduction +Traditional hardware design often requires using languages like VHDL and Verilog and tooling that don't catch errors that can be caught with static analysis of the design. Additionally, information developers receive from the tools is scarce and often lead inexperienced developers on an odyssey. Currently emerging tools (Verilator, Yosys, etc.) for hardware design and languages for hardware description (SpinalHDL, Amaranth, etc.) tackle these and other existing issues. + +Projects like SpinalHDL and the thereon based highly configurable VexRiscv processor experience a rise in popularity and usage amongst academic and commercial users. The increased popularity also requires an increase in educational resources. Due to the specific popularity in the academic environment it only seems natural that researchers document their approaches and insights (not only in peer reviewed publications in a journal). This will allow the next generation of hardware designers to extend and explore big projects like VexRiscv. + +## 2. Our Goal for this Tutorial +Murax SoC is a VexRiscv configuration that is a very lightweight RISC-V platform. +It features a basic set of peripherals (UART, GPIO, Prescalers and Timers) around a pipelined memory bus and Apb3 peripheral bus. +The Murax SoC features enough to more than a toy system and being small and thus offering space for extension. + +For the choice of possible algorithms, that we want to describe in hardware rather than software, the algorithm for calculating the Greatest Common Divisor (GCD) is a good example to start off. There are many digital design resources available on designing a GCD module. + +We will add the hardware peripheral module to the Murax on the Apb3 bus with memory mapped registers to control the module and transfer the data around for the calculation. +In this way we transfer the resources the software to the hardware implementation. +The aspects we will shed some light upon will be + +a) How do we implement an algorithm that we know from the software domain in a hardware implementation suited for FPGAs? + +b) How do we prepare and integrate a new peripheral into the Murax domain and map its control and data ports via memory mapped registers? + +c) How do we extend the software to use the peripheral easily in our baremetal code? + +For a) we will start off the pseudocode of the GCD and work our way to a hardware implementation in SpinalHDL. +We will evaluate that design in a SpinalHDL testbench with Verilator as the simulation backend and drive the testbench with randomly generated values which we compare to a software implementation of the same algorithm. +For b) we will look into the features of SpinalHDL and the structure of the Murax SoC to get an idea where and how to integrate our peripheral. +Before adding the peripheral into the Murax we also need to decide on the details of memory mapping our control and data ports to memory mapped registers (i.e, addresses, write/read/clear modes, etc.). + +At the end there is a small list of possible extensions from which anyone can continue with their own additions. + +## 3. GCD HW Implementation +Let us start the HW implementation by looking at some kind of specification. + +```c +// Pseudocode of the Euclids algorithm for calculating the GCD +inputs: [a, b] +outputs: [ready, a] +ready := False +while(!ready): + if(a > b): + a := a - b + else if(b > a): + b := b - a + else: + ready := True +``` + +The pseudocode shows the GCD algorithm we want to implement in hardware. +Implementing algorithms in hardware in the Register Transfer Level (RTL) style will require you to separate the control path (so if, else, while, for) and the data path (moving, calculating and comparing data). +Inevitably results from data and comparisons affect the control flow and the control flow affects the data flow. +Thus the two paths need to communicate the shared information. +But let us start at defining the interface of our module that will calculate the GCD. + +![GCD Top Diagram](./img/murax-gcd-diagrams-gcd.png) + +Our pseudocode already defines some in- and outputs that can aid us in defining the interface for our module. +At this point we don't want to think about which bus we connect our module to (APB, AXI, Wishbone, etc.). +We take care about that part later. +We simply know we have our input integers A and B, a signal to indicate the start of the calculation, the result and a signal indicating the completion of the calculation. +We choose 32 bit integers and use a valid-ready mechanism (we add a valid signal to kick of the calculation). +The interface features the values A, B and result as the data signals, valid and ready are control signals. +Signals for reset and clock are omitted for readability (unless explicitly used these are handled by SpinalHDL internally anyways). + +From this top level perspective we can describe the behavior as follows: Once we apply a set of operands A and B and then apply the valid signal the module calculates the GCD for a variable amount of clock cycles. +We know the result is ready and can be read once the ready signal is asserted. +Inside the GCD module we will have two other modules: the data path GCDData and the control path GCDCtrl. +We notice again, the data signals (opA, opB and result) belong to our data path and the control signals (valid and ready) belong to our control path. + +![GCD top level block diagram](./img/murax-gcd-diagrams-gcd-dp+cp.png) + +The data path will consist of some basic RTL blocks like multiplexers, a subtraction, comparators and registers. +The elements are connected and arranged such that they represent the dataflow of the algorithm. +Parts of the data path are enabled by the control path. +The control path will be represented by a Finite State Machine (FSM), which orchestrates the data paths calculation of the result. + +![GCD data path](./img/murax-gcd-diagrams-gcd-datapath.png) + +The diagram of the data path shows the processing elements for our algorithm in hardware, with their control input and outputs respectively. +From this we can already see what the interface towards the control path looks like. +The control path needs to know the results of the comparisons. +Vice versa the data path gets controlled through selecting the subtract operands (or more precisely their order), the register enables and an initiation signal for a defined start state. +In the data path, the D-Flipflops (DFF) hold the values A and B that are used for the calculation and they change value throughout the computation. +A subtraction which is set up for a computation such that `r = x - y` with x being the "left" and y being the "right" operand. +The left and right operands are multiplexed from our control path inputs. +Two comparators compute the greater than (cmpAgtB) and less than (cmpAltB) operation. +The result, the GCD of A and B, will be available in the A register after the calculation is done. +Completion of the calculation is signaled by the control path. + +![GCD control path](./img/murax-gcd-diagrams-gcd-controlpath.png) + +In the diagram of the control path we see the same interface (with inverse directions — this information will be helpful later in SpinalHDL). +The interface of the control path are the top level valid signal, the ready signal indicating the finished computation, the results of the two comparisons `A > B` (*cmpAgtB*) and `B > A` (*cmpAltB*). +Initially the FSM is in an idle state, waiting for the valid signal to be asserted, on exit of this state, the init signal is set to 1 to clock in the values of A and B into their respective registers. +Similar to the pseudocode the FSM loops for the calculation and based on the comparators of the data path and orchestrates the data path to calculate either `a := a - b` or `b := b - a`. +If both if the comparators outputs are 0, the end of the calculation is reached. +Within the `calcDone` state the `ready` signal is set to 1. +With the entry of the `idle` state the module becomes ready to calculate another GCD. +The control path drives all the outputs based on the state in the state machine (Moore FSM). +The guards on the transitions show the condition with which the respective transition occurs. +These block diagrams, digital logic and the FSM can be quickly implemented in SpinalHDL, things like the `DataControlIF` that interconnect between the data path and control path can be quickly created and connected in SpinalHDL as well. + +## 4. SpinalHDL implementation +First we can take a look at the interface between the data and control path. + +```scala +// in GCDTop.scala +case class GCDDataControl() extends Bundle with IMasterSlave{ + val cmpAgtB = Bool + val cmpAltB = Bool + val loadA = Bool + val loadB = Bool + val init = Bool + val selL = Bool + val selR = Bool + + override def asMaster(): Unit = { + out(loadA, loadB, selL, selR, init) + in(cmpAgtB, cmpAltB) + } +} +``` + +We can define a Bundle that implements the `IMasterSlave` Interface (see the [Bundle documentation](https://spinalhdl.github.io/SpinalDoc-RTD/master/SpinalHDL/Data%20types/bundle.html?highlight=master%20slave#master-slave)), which allows us to use a operator (`<>`) to interconnect modules and their signals without explicitly describing each wire and connection (other than inside the Bundle from above). +In the Bundle we can define the signals with their types. +We override the `asMaster()` Method (line 10 to 13) from the `IMasterSlave` interface. +In the `asMaster()` Method we define the signal direction from the point of view of the control path. +Thus `cmpAgtB` and `cmpAltB` are inputs and `loadA`, `loadB`, `selL`, `selR`, `init` are outputs. +SpinalHDL will infer the directions for the data path side when we will use the `<>`-Operator. +With that our top level module will look very tidy: + +```scala +// in GCDTop.scala +class GCDTop() extends Component { + val io = new Bundle { + val valid = in Bool() + val ready = out Bool() + val a = in(UInt(32 bits)) + val b = in(UInt(32 bits)) + val res = out(UInt(32 bits)) + } + val gcdCtr = new GCDCtrl() + gcdCtr.io.valid := io.valid + io.ready := gcdCtr.io.ready + val gcdDat = new GCDData() + gcdDat.io.a := io.a + gcdDat.io.b := io.b + io.res := gcdDat.io.res + gcdCtr.io.dataCtrl <> gcdDat.io.dataCtrl +} +``` + +Lines 2 to 8 define the input/output Bundle inline, lines 9 and 12 instantiate the control and data path. All other lines are interconnecting the IO signals. Note in line 16 we interconnect the control and data path by using the `<>`-Operator as they use the shared interface description from earlier as a input (called `dataCtrl` in the design). We will see this in the respective modules input/output bundles. + +Our data path in SpinalHDL looks like this: + +```scala +// in GCDData.scala +class GCDData() extends Component { + val io = new Bundle { + val a = in(UInt(32 bits)) + val b = in(UInt(32 bits)) + val res = out(UInt(32 bits)) + val dataCtrl = slave(GCDDataControl()) + } + //registers + val regA = Reg(UInt(32 bits)) init(0) + val regB = Reg(UInt(32 bits)) init(0) + // compare + val xGTy = regA > regB + val xLTy = regA < regB + // mux + val chX = io.dataCtrl.selL ? regB | regA + val chY = io.dataCtrl.selR ? regB | regA + // subtract + val subXY = chX - chY + // load logic + when(io.dataCtrl.init){ + regA := io.a + regB := io.b + } + when(io.dataCtrl.loadA){ + regA := subXY + } + when(io.dataCtrl.loadB){ + regB := subXY + } + io.dataCtrl.cmpAgtB := xGTy + io.dataCtrl.cmpAltB := xLTy + io.res := regA +} +``` + +Lines 2 to 7 show the Bundle for the IO signals. Note the signal in line 6 (`dataCtrl`), we use the defined Bundle from earlier and give it the direction `slave()` instead `in()` or `out()`. +This tells SpinalHDL to infer the directions of the Bundle signals according to the `asMaster()` method (in that case the inverse directions). +We will see this again in the control path. +The rest of the module (or components, thats how SpinalHDL modules are called) consists of defining signals, registers, and behavior. +Registers can be defined through a `Reg()` components that takes a type and optionally a reset value (via `init()`). +We can write to the register in our `when()` Blocks which could be interpreted as the enable signals for the registers. +(* Side note: technically we describe a multiplexing onto each register as we have multiple cases of enables and different data sources, but we can abstract from that in SpinalHDL a bit and keep it in the back of our minds*). + +Now for the control path of our GCD module: +```scala +// in GCDCtrl.scala +class GCDCtrl() extends Component { + val io = new Bundle { + val valid = in Bool() + val ready = out Bool() + val dataCtrl = master(GCDDataControl()) + } + val fsm = new StateMachine{ + io.dataCtrl.loadA := False + io.dataCtrl.loadB := False + io.dataCtrl.init := False + io.dataCtrl.selL := False + io.dataCtrl.selR := False + io.ready := False + val idle : State = new State with EntryPoint{ + whenIsActive{ + when(io.valid){ + io.dataCtrl.init := True + goto(calculate) + } + } + } + val calculate : State = new State{ + whenIsActive{ + when(io.dataCtrl.cmpAgtB){ + goto(calcA) + }.elsewhen(io.dataCtrl.cmpAltB){ + goto(calcB) + }.elsewhen(!io.dataCtrl.cmpAgtB & !io.dataCtrl.cmpAgtB){ + goto(calcDone) + } + } + } + val calcA : State = new State{ + whenIsActive{ + io.dataCtrl.selR := True + io.dataCtrl.loadA := True + goto(calculate) + } + } + val calcB : State = new State{ + whenIsActive{ + io.dataCtrl.selL := True + io.dataCtrl.loadB := True + goto(calculate) + } + } + val calcDone : State = new State{ + whenIsActive{ + io.ready := True + goto(idle) + } + } + } +} +``` + +The lines 2 to 6 show the input/output signals again, and this time the `dataCtrl` signal, at line 5, shows the direction as `master()`. +This will apply the directions that we set in the first code snipped. +SpinalHDL offers a library to build FSMs and since this module is only that, our control path is descriptive. +We set default values for outputs (lines 8 to 13) and apply the according value in the respective state. + +The API for FSMs in SpinalHDL offers much more than we use here. +In each state we can describe actions for `onEntry`, `onExit`, `whenIsNext` and for `whenIsActive` phases (see the [State Machine documentation](https://spinalhdl.github.io/SpinalDoc-RTD/master/SpinalHDL/Libraries/fsm.html)). +The `onEntry` phase refers to the cycle before entering the state, `onExit` will be executed if the next cycle will be in a different state, and `whenIsNext` will be executed if the state machine will be in that state in the next cycle. +That resembles the capabilities of FSM we have in UML/SysML or in StateCharts. +There is also the possibility to nest FSMs hierarchically or have delay states for a certain amount of cycles. +Describing these things in classic HDL is a lot of boilerplate that SpinalHDL can generate for us instead. + +But with these modules we can already run some first simulations, testing our design for functionality. +And as traditional HDLs go we need a testbench for this. +This applies to SpinalHDL as well. +The default way for [simulation in SpinalHDL](https://spinalhdl.github.io/SpinalDoc-RTD/master/SpinalHDL/Simulation/index.html) is by writing a testbench with SpinalHDL and Scala and then getting it simulated through Verilator. +Verilator compiles our HDL (generated from SpinalHDL) to a C++ simulation model, our testbench interacts with that and thus we can have a fast simulation at hand. +Lets jump straight into the simulation testbench and see how SpinalHDL aids our work here: + +```scala +// in GCDTopSim.scala +object GCDTopSim { + def main(args: Array[String]) { + SimConfig.doSim(new GCDTop()){dut => + def gcd(a: Long,b: Long): Long = { + if(b==0) a else gcd(b, a%b) + } + def RndNextUInt32(): Long = { + ThreadLocalRandom.current().nextLong(Math.pow(2, 32).toLong - 1) + } + var a = 0L + var b = 0L + var model = 0L + dut.io.a #= 0 + dut.io.b #= 0 + dut.io.valid #= false + + dut.clockDomain.forkStimulus(period = 10) + dut.clockDomain.waitRisingEdge() + + for(idx <- 0 to 50000){ + a = RndNextUInt32() + b = RndNextUInt32() + model = gcd(a,b) + dut.io.a #= a + dut.io.b #= b + dut.io.valid #= true + dut.clockDomain.waitRisingEdge() + dut.io.valid #= false + waitUntil(dut.io.ready.toBoolean) + assert( + assertion = (dut.io.res.toBigInt == model), + message = "test " + idx + " failed. Expected " + model + ", retrieved: " + dut.io.res.toBigInt + ) + waitUntil(!dut.io.ready.toBoolean) + } + } + } +} +``` + +In line 3 we basically setup our Design Under Test (DUT), and we could setup some other simulations options like generating the VCD wavetrace. +We want to generate some arbitrary amount of testcases and compare the results against a (different) implementation of the GCD algorithm in software. +Doing this for enough random cases can give confidence in the design, tho it will not always cover edge cases and other aspects that are covered by a constrained random approach, white box testing or formal methods to verify our design. +Lines 4 to 6 are our (recursive) software implementation. +Lines 7 to 9 generate a random number in the range of a UInt32 — we have to do this by hand because of the nature of Java, Scala and SpinalHDL and how they interact with each other when it comes to numeric values and types. +Lines 10 to 15 setup our input for the DUT and in line 17 and 18 we set up the clock and trigger the first event for our signals to be applied to the inputs. +Lines 20 to 35 describe the application of 50k random integers to our design, and our software model, and then comparing them after we waited for the hardware cycles to pass. +We use the `assert` to output a message to the terminal in case a testcase doesn't match with the software model. +If we add `.withWave` to the line 3 we can obtain a wavetrace (tho its recommended not to run as many testcases, as the dump will be huge otherwise). + +![GCD wave trace](./img/simulationWave.PNG) + +## 5. GCD Murax Integration +Now that we have a standalone module that we want to integrate into the Murax SoC. + +Since the Murax is using the APB bus for the peripherals, our module needs to map the IO signals into the memory mapped space of the APB bus. + +```scala +// in Apb3GCDCtrl.scala +object Apb3GCDCtrl { + def getApb3Config = Apb3Config( + addressWidth = 5, + dataWidth = 32, + selWidth = 1, + useSlaveError = false + ) +} + +class Apb3GCDCtrl(apb3Config : Apb3Config) extends Component { + val io = new Bundle { + val apb = slave(Apb3(Apb3GCDCtrl.getApb3Config)) + } + val gcdCtrl = new GCDTop() + val apbCtrl = Apb3SlaveFactory(io.apb) + apbCtrl.driveAndRead(gcdCtrl.io.a, address=0) + apbCtrl.driveAndRead(gcdCtrl.io.b, address=4) + val resSyncBuf = RegNextWhen(gcdCtrl.io.res, gcdCtrl.io.ready) + apbCtrl.read(resSyncBuf, address=8) + apbCtrl.onRead(8)(resSyncBuf := 0) + apbCtrl.onRead(8)(rdySyncBuf := False) + val rdySyncBuf = RegNextWhen(gcdCtrl.io.ready, gcdCtrl.io.ready) + apbCtrl.read(rdySyncBuf, address=12) + gcdCtrl.io.valid := apbCtrl.setOnSet(RegNext(False) init(False), address=16, 0) +} +``` + +Looking at the other peripherals in the Murax, we get an idea how to implement our own Apb3 Mapping (this is also part of the SpinalHDL Workshop). + +The components uses the APB3 Bus as a slave peripheral. +In line 14 we create a instance of our GCD module, in line 15 we create a [APB3 Slave Factory](https://spinalhdl.github.io/SpinalDoc-RTD/master/SpinalHDL/Libraries/bus_slave_factory.html) (for our APB bus connection of the component). +This factory offers us to add memory mapped registers very easily that create all the logic needed to interconnect with our module properly. +A register which can be read and written to can be seen in line 16 and 17 (`driveAndRead()`). +We pass the signal we want to be buffered through that register and an address. +Our result is [buffered with a `RegNextWhen`](https://spinalhdl.github.io/SpinalDoc-RTD/master/SpinalHDL/Sequential%20logic/registers.html#instantiation) (which buffers the first argument `gcdCtrl.io.res` based on the enable signal that is the second argument `gcdCtrl.io.ready`). +We need this because our result is visible for the clock cycle that the ready signal is asserted true by the control path. +We do something similar with the ready signal, and keep it buffered for longer than just one clock cycle (since we don't know when the software will check these registers). +The result and ready registers will be read-only (`read()`) on their respective addresses. +If the result is read (even if ready was not checked) we will flush both registers as if we fetched the result and don't need it anymore. +The valid signal shouldn't be asserted longer than one clock cycle, this is achieved in line 24. +We use a register that sets itself to 0/false whenever its written to. +So if we write a 1/true into it, after one cycle its set to 0/false again. + +| Address | Name | Description | Mode | +|---------|-------|----------------------------------------------|----------------------------------| +| 0 | a | Operand A of the GCD(a,b) | R/W | +| 4 | b | Operand B of the GCD(a,b) | R/W | +| 8 | res | Result of GCD(a,b) | RO, clears res and ready on read | +| 12 | ready | Ready, 1 if result available, 0 otherwise | RO | +| 16 | valid | Valid, write 1 to start calculating GCD(a,b) | WO, clear after write | + + +In this way we implemented this memory mapped register bank with various modes. +Now all thats left is to attach our module to the APB bus of the Murax SoC and write some bare metal firmware to access it. + +We created our modules inside the VexRiscv structure as follows: +``` +src/main/scala/ +├── spinal +└── vexriscv + ├── demo + ├── ip + ├── periph <--- we add this directory with subdir + │ └── gcd + │ ├── Apb3GCDCtrl.scala + │ ├── GCDCtrl.scala + │ ├── GCDData.scala + │ ├── GCDTop.scala + │ └── GCDTopSim.scala + ├── plugin + └── test + +``` + +To integrate our `Apb3GCDCtrl` peripheral into the Murax we need to modify the Murax SoC (`src/main/scala/vexriscv/demo/Murax.scala`) directly. +Deep in the source there will be a comment designating the start of the APB peripherals (`//******** APB peripherals *********`). +There we are going to add our peripheral and designate some memory mapped space to it. + +This step is straightforward as we can add the peripheral similarly to the existing ones. +After the code for the timer `MuraxApb3Timer` module we add our GCD peripheral: + +```scala +val gcd = new Apb3GCDCtrl( + apb3Config = Apb3Config( + addressWidth = 20, + dataWidth = 32 + ) +) +apbMapping += gcd.io.apb -> (0x30000, 1 kB) +``` + +And thats it! + +The Murax SoC now supports our own GCD peripheral. +All thats left now is to use the peripheral in a piece of software. + +## 6. Software Driver Integration + +We start off the software part with the existing `hello_world` example and copy it into a new directory `gcd_world`. + +Since we support a new peripheral in hardware we also need to support it from the software (its supported but we are making it more usable for the developer). +We add a new file in the `gcd_world/src` directory called `gcd.h`. + +```c +// in gcd.h +#ifndef GCD_H_ +#define GCD_H_ + +typedef struct +{ + volatile uint32_t A; + volatile uint32_t B; + volatile uint32_t RES; + volatile uint32_t READY; + volatile uint32_t VALID; +} Gcd_Reg; + +#endif /* GCD_H_ */ + +``` + +With that we define the available memory mapped registers starting from the base address of the peripheral. + +We then edit the `murax.h` header file in the same directory: + +```c +#ifndef __MURAX_H__ +#define __MURAX_H__ + +#include "timer.h" +#include "prescaler.h" +#include "interrupt.h" +#include "gpio.h" +#include "uart.h" +#include "gcd.h" + +#define GPIO_A ((Gpio_Reg*)(0xF0000000)) +#define TIMER_PRESCALER ((Prescaler_Reg*)0xF0020000) +#define TIMER_INTERRUPT ((InterruptCtrl_Reg*)0xF0020010) +#define TIMER_A ((Timer_Reg*)0xF0020040) +#define TIMER_B ((Timer_Reg*)0xF0020050) +#define UART ((Uart_Reg*)(0xF0010000)) +#define GCD ((Gcd_Reg*)(0xF0030000)) + + +#endif /* __MURAX_H__ */ +``` + +Our addition is the line `#define GCD ((Gcd_Reg*)(0xF0030000))`. +With that we create a way of accessing the memory mapped registers without directly referring to the peripherals address (`0xF0030000`) or having to calculate offsets for the registers. + +Now we can start writing our software! + +In our `main.c` we add a function to make the peripheral handling a bit more convenient: + +```c +uint32_t gcd(uint32_t a, uint32_t b){ + GCD->A = a; + GCD->B = b; + GCD->VALID = 0x00000001; + uint32_t rdyFlag = 0; + do{ + rdyFlag = GCD->READY; + }while(!rdyFlag); + return GCD->RES; +} +``` + +This function will take the parameters `a` and `b` and applies them to the respective hardware registers `A` and `B` of our peripheral. +Then the `VALID` signal is set (our Apb3 wrapper takes care of setting it back to 0). +All thats left is waiting for the result, which is done by polling the ready flag until its available and then returning our result value `RES`. + +The software contains a little more code for formatting numbers to print them onto the UART device but reading and understanding that is left as an exercise to the reader. + +So how do we execute our software on the Murax now? + +First we compile the software with the make file. For that call `make` inside `src/main/c/murax/gcd_world`. +You should get some minor warnings and a statistics about the memory usage like + +``` +Memory region Used Size Region Size %age Used + RAM: 1752 B 2 KB 85.55% +``` + +Now we can edit the `Murax.scala` one last time before we execute our simulation. +For this scroll down in the `Murax.scala` file until `MuraxWithRamInit`. +In order to load the memory with our new software instead of the `hello_world` example we edit this part. + +```scala +object MuraxWithRamInit { + def main(args: Array[String]) { + SpinalVerilog( + Murax( + MuraxConfig.default.copy( + onChipRamSize = 4 kB, + onChipRamHexFile = "src/main/c/murax/gcd_world/build/gcd_world.hex" + ) + ) + ) + } +} +``` + + + +Then in the root directory we open `sbt` and call `runMain vexriscv.demo.MuraxWithRamInit` or we call `sbt "runMain vexriscv.demo.MuraxWithRamInit"` directly. + +This will call SpinalHDL to generate the modified Murax SoC with our small software example. + +The last thing we need to do is call the simulation. +For that navigate to `src/test/cpp/murax` and call `make clean run`. + +After some time you should see the following output in the terminal: + +``` +... +BOOT +hello gcd world +gcd(1,123913): +1 +gcd(461952,116298): +18 +gcd(461952,1162): +2 +gcd(461952,11623): +1 +``` + +Keep in mind that we are simulating a SoC. There is no shutdown for our simulation so we have to stop it by ourselves by pressing `CTRL+C`! +Otherwise the simulation won't stop. + + + +## 7. Conclusion + +In a tutorial we described how to convert pseudocode for the GCD calculation into SpinalHDL based hardware. Furthermore the hardware was integrated into the VexRiscv based Murax SoC. +To demonstrate the usage an example C project was set up and the hardware peripheral was used from within the software. + +This tutorial covered the translation from RTL into SpinalHDL, writing a small wrapper for the APB3 bus used in the Murax SoC, integrating the peripheral into the Murax SoC with designated memory mapped space and writing software in C for the Murax SoC that uses the hardware peripheral to calculate the GCD and print it out on the UART of the Murax SoC. + +Now there are a few open challanges to approach as an exercise here are two that would follow up naturally to our existing code: + +* The Murax SoC features interrupts, we could stop polling our ready flag and instead trigger an interrupt from the `Apb3GCDCtrl` instead. +* Write the same algorithm in C and compare it with the hardware peripheral. Is it faster, is it smaller (interacting with the peripheral in software still costs instruction in terms of memory) \ No newline at end of file diff --git a/doc/gcdPeripheral/img/murax-gcd-diagrams-gcd-controlpath.png b/doc/gcdPeripheral/img/murax-gcd-diagrams-gcd-controlpath.png new file mode 100644 index 0000000000000000000000000000000000000000..e0b09f6a0ce46e5e618becfb24fc771afffb3dcb GIT binary patch literal 68613 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�W7=6yT}k+0Lo5h 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 literal 0 HcmV?d00001 diff --git a/doc/gcdPeripheral/img/murax-gcd-diagrams-gcd-dp+cp.png b/doc/gcdPeripheral/img/murax-gcd-diagrams-gcd-dp+cp.png new file mode 100644 index 0000000000000000000000000000000000000000..68daa3c8c902513a09ee7a368431aa56868dbe1f GIT binary patch literal 27013 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┽ zrSoOLZXh%0qS4Ekztt-%)@u8DdnjE8w)T}aDU`kQb1x+zN(rE-r z0;UNA5!x*Nwi`{$GLWSl%3gWt`c)}O#2yYWUfgLBJ+V^I6dI_5TO6;iL4WTR+GwR# z?*yJDqIffmNjQp@S62h2Qq7wYiDydorQ>;fK4cvBWinA_lpkOEnN3 z)hX1|lme|9X<(Pz?>3|$a-0_`)9!hjf*Ws^+QYwBW~i?ZBYrP?!_S$JC5I4smisbR zZ=PjYUAWh@!9jerkU9tPnYH5KmdM)?Rz-CDUi8Z!C%!PW_}~#`LKn!Rn(~Kbx#{m` zB}%2KdpUrg$@)^%n8Jmavwv@_8Ca|%frz_#;vhg>X(C>;mE65bi{8p>rScgNIv2b> zklEQsd9LDYtvX)CIiO6mxTF)u=UzQJeCVpexALy(B59oI7w>%_f7oD{0W!(%rW}IO z`&dwQ+HAj&{kmNaFn&IF`=Ll&SOr6uUEWX^OtU2H88e?Dr5~q>TI;O(U|gVP+bk9Q z^z4;x5L6Ck`u}3klL(lc6>L!Eual{E80SgwX(}Y-A8j!XLZnxT6lWxpgl%=ZQl$~m zng9=<*KvPGb53!w7DvlEueSf1v~Z`Or9?D$lXJbWOkL`gHSsM zM)AZOWDL4>{w_rFV0$KwDm3&u8ixv&dwc6X`^^<}aZE^1rqprh4{FNJ*(yMPzypPl z7DWSNJot|T@fBEa!^%=_fV3qP69_n}6RFTfUi)LiYG$#_Tm!WnHR}Q$;zIyv z*KB+6>u=G7Vrxt^l-1!noRRD3mHnF>g4`vIF$6A142F5!?E===7zk>@_%A-z>h7pB04ROX(dka-+S>%6>tx*ymSYgObJ z_mneYT$r+kX^C`=+T9*G#Pd#2H%Al7T4P+=!y*}CidY|T4xVu-@cojAf?C!JKG=d# zCp+;8lnUkf11TYrRyh3S01rj49bGm!%cckNWEM z{~Q%CJj{UgfeoGPFU;Xn3Lom9l@)CWFLS;xR1*!ix=dnBt#CPnQVTA@Sd{rYxbp9U zdb`E`g$f1oXCmX%cX=4N8n`ciCztdQHN1CL#}-#Rkxq2&7?f?EJoanKBTNaVF!DEH zPvP2*(BY4;yswL8KWGYHVDPb*rUO9*D>#w~>mMhq zX`vc2`x>a<7-v$GkrG}xd8E%cMv?$%dt)@%LXDTUBbk&-&T%h zRgk={Z2!pLrXers6q*E+0!f=Mc>aHDGQi#qb=zBErt$-+TR^;fsh_00Lh;c7`5nO+ zeWc#-MoJ3rFYCb4C|M7D1@`m#-#2soJN$V;|57%xU|K1&P+B0yZlCbIgosXlDD3K? zWxM&srR0BGIXHouM^#lnT7tEzx}kp-`+b?Yw83tOvmAr)!_2~dGCM99R4Y*f7%9Y!2PeHkAK?6KW*cmw((nf^Z)Bvu)*DZb}IGv z5BjkBppc&`66x?XwXsPZicEgPbrNT$2V;F{d&vJB-PPT`9TI(0rq+I1&ZY-HuXIdN MR!ye(I@b5U05CA3NdN!< literal 0 HcmV?d00001 diff --git a/doc/gcdPeripheral/img/murax-gcd-diagrams-gcd.png b/doc/gcdPeripheral/img/murax-gcd-diagrams-gcd.png new file mode 100644 index 0000000000000000000000000000000000000000..f557a69094311785d8d3241b43832e7fc812018d GIT binary patch literal 15632 zcmeI3S6Gu@yXIFyLPxqZfzT{~fG9<3P!tfQi6A|KAW|bpZvhlgkft=1qJZ??r3FRl zpdd&m3X0NuFSGdm-|TBz@|FlXa|m*z^|_sz;$&$^%AeXl1vT55FEoYVjSIt_JI zJphpKpP-$R9RA(+VhaHP256|N=zE&aCsVv&`Skr$>eE=)XdEW^8j~)gpk_DI3ycZ_ ziZvz;6^ItRCrHVpPtuMRjE#vP+|^alVG#@?2)0pA)cpExwK&(=y>@-^dZ@{?=UtEY zd3g)7Lp%L>hD8gE$Az)zsjisWMLlw1oPOYg}5~tb4t1^%%p!xFgv!~_AHK1zzz(+X>;GB0$){m`& z(R!bR-J0|z_X*b?#mW#3B$maTlS?@k;H)M~{_>z5_SHrbxT(NbuUh!m*JSNyk?_0y z`O}^CG7lh#rix}JTnJ*tI}hs?Do}W#c2e#Jz`xc=@8d&aA3mJEnVt?17`gYWIlqsd z#;}J_@r*~&c-(86yT>i(W>$PSn>cx0k1!j{X&r3C;en5~tDMJz=*LicHYDMeXtTTO zB?J;HsQ>#slQ9BG(4gL2oUriTTqv*`DZUf@;>^v@_qsU21=}y!_5^Y9C(Nhf#=NdND5N)2b2oo=punUzOPiNN+97dgZ?W-E zdNl8qjB|S!qrlybxgnReKe{!C2fLX%Z!WD2m^f1n=f-)h{%%VRI5^|8xe(X({1gp> zSp2Q72|>*OPT*ACo4mZhTSnAYkMf~<usqV*02d+Nj6ylb5 zUo#ErqFJB)p75B4?b^yzTc*QMDRL2DaXl%DiFZ08IL>EiJU>~IJ67eKdcl6+`Y|4b z)3z=3o8$KEKw`@54zPM62J(#rMyi|>m``b`e~#do{I)<3es?AbJmZvN zsvi7aWFgKWd3R}a_p2JOMy>n2pzH5Wmzi&8&}64Q4c2G+f5F$|lFr`~E+Vrzys8NB zKRo7#Z}mS8RMdzS%=KUUQ8S%#vuCt1pwaG?0VOzDC!7DF5{}Wo)Z}ayp*yR_VC!ssl2t%EAK9fAOtAEh06f8IAv83YDh59YyT~qPsAXff!0a9Ve2g?rtx6MeqEmS zfL)f?Yl^YwI;YsuQ&y4oKr)IKB0T3OXxPMBTVn+JiGMoiB3}g@Y~O>EC+dZ$k)8_K zg3A6-sr7RKwMb8!+2M|#J!A|M9S?tZa@@N2{^8##_%tb+MHY=>a7L`}ouCGL8zauw zC^{FudMqNvi67~eMYmU{4LfMpfb0+Z9;HWcNn%XVUX83QctPO1x7^bE?grNx-M5eO zO{%oe!}rmF-uQm2WdDWHnwjs36;?}XO%CrbhaO9rEqRwJZlSck3Ri;I{oafx)>UF= z@3ToYfBUjD!;hc+b`SsSV`h}pL&D<*b_8K{x~HSitoB6JYKMX$(h-CE5?ZIy|+chqk_c*}pzIgpw>@a$%^L$UU{Vo=eW^GU+ z(oUndYqlBfNqLyhq^;%26f-ImINunQ-w_Gt=$x%o<&X)Y1wl-f_gJtD32!oLG%s9~ zt*mMqdp3kGvHYX}K$UVlRUHj-is7^jjtKsKO%I)(>`~gi-qi|c>)9naTeK#_AS;1% zk@mGw>D^`D;}H}<_i#xc$3^<_G4xka2$C>9w&30KdKRt2Re3Q_m>?ODNKNa|vB>Aj^mn>55yn)skJT+_MF zVvZ-dDB4zcXPk}>4a&zTnmj?VV4y6@8@yhnAShDZfWMFJ`(-ivGo;&qz{MM!RTP9$ z7__4>l;_`)0@-G@l{n2*k0wkcf;)JL)D+y`qWzhKX4k@ z(i6qdb4*0SGa-b95DNg5h_K@FK%rw6Xdc!n_Gl(o(P!fV9bgy?6QW)`9Waj= z{1q+l;S|TpFiugx08G~mgUp`6U5g<8n3)BC0$`XiYv1rPoX9Yr269gvi|>LY#d&b}Z`k<5#xu5AB@ z5{l)6d>~e_de$#aM*(E3g+Ia8Au2D-(74OuvVzBV1AC}|*49oL{TsMlQr@~aeoqK} zf(oSi@8k@}ZqAkU2s3=4|D)a*F6HJ&O7Z6+rKtq#^J5B#noF=4($rBWp8d#u@FSEr zw;*Vz;88=wQz1$M5=+(r2Avn3sc^j+8p44L@wE7OZ1?MninlCDEz*h^+gBt~JW6@y zKVSjCH}#_3m9Sg|wj(D?xEXqSU1&%~VUAb^{@62rQ#Cg$&RV2Du5z2zE@&LkiuM1aS)kGMRX! zPKxJGs%`k7-~4VXM-}0Ac@`dz@GSTQ0D{zpafMyZd`OrD){-xS=`$139i4_b0OubR zJe>KaahA*0`s>>(c0TF;dHj{CcK42Lb)drTT`scjh|f8F2sgtV6<#me;uk?5pMX<4 zmwlHs0;bx4#Cu!@ zN=4aNGk}efAVn5t_7Xm4Myt>pi?h)eNZ=02Z7p0HF}8;EQo?y$AEq_6b)#+B<1RB;TQ`}uMw)Cydvnr2&GhtuEg9~}@w33aJ zjc^G+xjk(WpjC`NHB3Ds%z^Tj8WNk`UbCuH1wc?vNieniJG`_;S`f+3L1y4-5pEjm zraHSSGvRyla}@8Q*WOKS#Y`=$D||q;Lzq03>nR11B;Z*?kAAy{MgY?5y8t_(gCzjs z_u(+469o{w8qB5>@KA1z43HjvixE&0zF3l6gKG+!nV9fheYSGkQb*BiC8IqjNbs&~ zM7~j(jlYLJ-$hP$l{;@AO$xxNIpUsQ7W?o`#Qr+FdP{OCF1O`UwLFD;f00RqZgwqC#E1BZ7< zXMNuU6DWOY`TGPdAhAD~x}ow;PtfYJ&8-4Vn-SbV^go=Ny6!bs((+A>eJ@5C{SxCk z3$^hrOUZNqoXJu`SB>%G)RJXy)6AzHH3j0AXv^)tM*`eJ-pAo=tSal$29g~K_XSl) z>)p`DWMDY$X>e|S5K1=6^n2-}38oJ=Ptw8Ks1W&Gh4if`d^7Ui}Ct7Wv zB6~i--atR-yy*Eq9Z|{$*^-|upCC2KjNecYH!QT>iJ8<}D@YU?u7`w%bA0adCje34 z-0eGr&k=0Xk8tr%gFDI*3}i9`4d?nkFOnKQ&v`*PYDfHljhc9aTe>vkf+e%5$YwLT z9y82EmUA%r9FG8}f_~!4HYWlsB=5G8E+(YYJvpCv09jR-8Q4+`2VXz>q^q0fN z7QDkqK*f1w2_1Vf?z=<-lZ+)Xy^OGH8ijPZ?4pbhLybJY7n=3Im!|d)C2J?0!(x*S z@a!Dj>strAi>#D5GkH_+g+7|yG}s8aWNqxpEvKtZgt z;OOV|<1yP*UQvVI`7OKt+)q2SO>VN?Cv=utcmuL~NW&p{CuXN)-{@ONJRf*Fy1Z*k zM(}ujdHLt3{-M+3^Ba{{Bml{;2Wn0s`+@veC`jFSB8q~nLyq*--=OQo-o!f$IFj?D zYbhTtp&bf|A@Aqa;=1B%DVY&NqtP*T4Mu>F{$ZWs`I~+Gyj4iVBa_5>Z?@)RxGr8z ziZB}DaT(QL0$G$l$%^l$q5HfhxEujCAH<(2Rt?;+s^>{LHrFT))w0FvVIrcGZ5iBt(r3JR2Lv#Oa>x$p>*~=7S zZvYrre?V<7!9zgP9QTaWy+@0caON#~gB;K&wlWc~o(;w%fc*Q{^D5hE!56g=`~7dG zQW>`79@O6k4O)frTVvZDiL_AkTkxP)wMi5!pnJ@Fw>!kV68CvjWtDEFg`} zSZ?h6z3%Mw109;6pT(aT&fmHF|aa#OL11qqgLQ-KP~NNaI(aZwlEt9k5Rp9ZhLO^)>6^-`<=kO7N!P zL0uHJs$n3u>`<0W8G(6EUN+mu%mjoD3q>J)iDXTD_noQ)F^qdWVdWk^@eB4+k*~?f zX?09C%J0fhLSk@viW$)Up}`&NZ0dTJA)~$)obP>m_d6Ty8f=zU1cxsAZWS9dtJx^b1$?jMwcI@s zwA!%sGn@dxB0#bt_}E2DOy96tc!B62^nNN_38F?!_V+%*J?q6R_xQ0XMMBF5Ln<38 z@Yj#gFtD1^flT$H=Te%tJ8abB;#>0wK}w)}Nghi<3I+^2n}HsBfwm$f`wd<^=@d{M zaoF(nzk~!VO)66Ci4wRb>nH@<6Bh}rfSH5>DzWA*&V8iP(WK&`PM*P8H~M4cO+Ta) z`>pc02dZPVdC|&?gC&<|zU8EoE2&PAoy05Kd>S+l+tuC6M3Q4M2}&DZKR%0;@)f1p z(nMYGT*CbwudmHzE^|_yp1i1T`zRTaP2txkd7M8BQK@c+_CpB1IBQ~%d_63Po9R!j zfv+{P`Ch9OVT=)+A)qR8{8y13$U(((aKYbZxJ*w_Y<%ue;lsL=vQMG7#0*Avdmr_! zJ|YL5tuf@cHPI0&OpNolPqpA6tQo)E_1$GyAl4kdd^V`{H0AfIg9yZ2)Z(|C=f=)0 zg$PduiPeSvyaZf0-@x3mLg(B*0sz$ZYRNNtbBd|Iq4)S2t`pcF#uQU7xQm)#u=FkA zR=eEbYAS8pk#?)R^jnGcXCMHn0$mc3CqtCf*=YCEXm-+6LJjB!WL3y4{3Kpd4?dM+0Qt78l~1U*3_w``z($0T)*7R!JrIusU)ekJ zgDq)A1kv2$$>Cd>xqhe0cxqef491x7AMGlD(on@?OdDWeWB=?FkZpQ8cX<%1tq<{E zZm}|eJu={a()LN{wRq8-w@dRn47OodO%#^Dn?JA{DPjG=GClO#886z^`yAlnWAj@E;0+uc8^UB#0Ky+R#UI|tDT0b^$~}_z!NA+E$OC$^YaOtmA|qBArfpa zq8d4V4suAw=fjNj{6O|Y#Mik;Ma|ZX6bK~tf(1fpL=xUe)QZ~V!XtpAId4=Gvz#dw z#ZC!FYwu~XBjZg1U^th1P-)_*vh; z$+oy9;nY7L_WsWwwtcLHT0#C9v6VZz_!4z7ovtCgjvMn}E&>oBxgE;wa>%!0k)VTu zD$?uJU<{rG10JQP>@Em_>Ym@nXCAbMrg&`z0vumn>6x!bPo_9Ozjap(G5FOk-k~f; z2=tNr-=IPggeIt@g?r%_<1eVLPgMiORr{j7JGfwQgBQ+?<6dNgwDxe+ibJ^Pda02F zGg0fm?&L4`PYuEvQ@rNW^!W+|oY)N3s?AkOuu++cHs+m}Q*NU0M-tHEK)Oi|UOL~3 zM!p=58HI?^`)3U{hm2hC(((Q>gVpM=jR-6Mx#7=)AdYW@yUf<#J7nbDG9v>Xi{tfN z)>gGE%O`nLlSrIQfXUQSO_2adr(LhUKR-ODYZ)D2ZAG+d+WsoewVMp`~2YcC#GZe6bRxSa%&IE zGf*4Q{6N7upj-J9ikx4`9^=d9{BASfT$bNjgL7$eXlj;dh?>S-&0vpVy|wh?5}-WI zEnZv#e_SrEs2iJbs3iVcXWz_<6g4Up)N+JyF@}QIR|k@{lLaPK@xr%qo8Mn0BaqW^ zszW*=^x$W6Z>hDWTNflZcbkIHk`I2WUVQi``n9}=7UaC*pTgM;zv#Swct5qE(QP(< z?Qfr22p!iurNiCDM!L-vs6Qnwn<@0)M-}DgMwnXt7HhxSS z&D3P;ndSr$oKn~1+~@vmD@u!hE3&XSE@pZfZeIzd)*aM!WFQc730%n8^ERE)CvUuL zo@r|E+s%MY%1qMX-fGmS&tiQD0t5$SUW>ci_wL5Zm&^1y_a>?zT!!jR$gt2fCNYs6 z&Azj;J)J5dfdPqYmr6J_k9>u4ufb{zD+Zv>=%;mD0K~LWC}?gcSV{1nw~2UJVI`p) za8UR1Z~7J);iBtr_4KRHP+}VpP-}+Jawxd@uYFbPEi{vFdwsF&wVd0vCeRM?YzAaa z)L5JD*JrHTU+4xm>e2(#EwftpTW)u7p=@NopvYJ`5CbkM zY3i`2vZGg^U7}69o-B8((sAS+jw~%OP+kcPmRg6u5WaP7{cl#P|B3>?^LX9Nz3PLq zdo6`=ht&To04CN4$eWJ2A_;k2i;3N}NKhPao_>|isKoLy4)3%4iLD=OuYb45o4B*o zLfmc@i1M`Q#RnR~R_@pd*)-GT#BK9xyvo(c6FKBpon<^RfS7*~qUTs?N8^fk`tJ%) zl|k4doxJPs2s_vRE9iUF%$y5g9*n`jnuX$H5-+Jk76JlncWy&mCLna}MKmP-UZab} zTCfIW1{@yr7T>v?B=1ouIXGNl-%pAP8hQwEp+bm)`&{BwM}qeL9$XEYFE0!ZocT!) zBrdnS--FZc6m$V%&)j_H8MGIH1o6joC=`z4o3vj^-*_qGys#-m1Dhx@vsk$BgnLls zDov6|QkHqWcl-Wg9!Mdz0leU~7wTr0K=GbOGTntETjGgjX>Rrz5;gEV*q*kY9VoD? zT;zTnl_s5E^syik!Fb-54oH0A`>-EK!4qbU$$utp(O`Pz&&OA36d)kJIl_Ci`hlI9 zxkb=2$TzL&Eu$r@A0(K2YkXo>SnWK&+#nkWp+HyIj`L`BiOZ_M0MSq-0ujVn0bws8 z+b>|7bQ)Huu-GNv{2Xdo9sqkDSGMz}swK1EJJy9QeYi%)66vgJQ^)~+*D8rvi@_cX zbb%T(nn%&Q842=praP1RTxo3D@UH?^yJYMN{9B{>dUJ1y^h`Ga@b=(G4w2xqwRC5D zwy2S%74r`9fcD_pX&~XZ^U!O(-*7U2c{VlB`URx^l<_p>)6k!p*^G@dGKC}aiLUuK zI+HMoAg%oB@VJ?IEpzmM04y>uJ*Kw1k6mT31%&FrOwEMPHNS%Cm7?J==csQ(hwC#` z>a_rmu<4`}Ju(SyVcu5yiL-+*GT?~!1`45Rn{QKpdAnB61^rXoT6#EiI1S_jN{C(8 z%_grL(}NoV#_D~wNFf4LFQ4<=5mqM#7r5gqU}+heL>$pxQS&<4?z8(l>o<2v=O|%; zlRXWHSGc4dq9JqBfHjwuGL0P#3eFLz{!g%X&h7~Ij(SY^p#a+<;(`5lD&SO6SGF_n z35ZNsD6PNY9-K8L8k53w>;1sJ7Gyt*D>PUSWro9N#wGV#=FDukU3 z#bG~)dF#NxFt5-TX{>4bl|cb1336kW0El=mH=3q7dyKtzi}OH2o8|ki@EcE{6Lp+9 z&@))UYo$4t^KW2Go6h1s5e=*0-bEa5&@H%&=IhmUw^LUmfztlk&HG>9K33SBE2Bo0 zi~35?_AXl9;P%=nF=M#WNQeKDrXtK3Z9o$8-1(b@Hb>L`#D`LlLBc&U%is_;b!oCC zDvAxjy(5F^*qt85_+x8w23=Z+UQo^o_fC0 zZ)o8a&%fsdia(pf-lJlSL6claGyVm1<#K8LplcGeMb_C|(VKJgR8JDw*4W!C;oml{ zI_B~Fhn|fYP9i&yMEo53Vh=qtyEfzl8uqmZ$3eUvUY3!hY5_6a*3L@OS2&Y<3b}j$ zIMH#G1zG1CaUI;;%zk10W*`K#(w zW)NZjS$^)weQ&6=>Ntd&6l$ek(BYD}a@D|+8GcCm9Lp zWiS6<;I0qD9z#-4U!qvZZuY<6uAJQe4tLoep3@7+NIxmG0@(dLFT{g#X?`5Tz2k$K zo)kP+5uh}@^%Or-@ZIn?Ggprs3y*O%fX^CB9ZtN?jrqG$lP$r zm3UtzO?Sr${(#pPg&^dL)6eNuFRa_ny#6?MMXzrl_T+q{iOqVZN(EDCK#$A=|5Sc! zVU1T}!7Qis^;5)6bnOQ0MWKSE8$2dr0VPqX+h8S*6|VqLBB-LW3gi-U@9k{h9fo2N zKx~q7zipAU_Jd)2cf(OgrCmR#ANXzeUa9f@8`O>tj6F3mDe1q1Y)d)s?yh#Dsc;luK zpM}%FRrCAnAye(EiE6>&Y~39zLaWx_NaHSlf2IaCc`Xko+c69zaLE*QbVzBo(Nk>X zAP(27YBlz+o{ghGps5Nf9ZUr#)z%W~Yb!hao-nm#aA;;ctT}YiwdEmfdeg@k%*(gr z9&XH=w5J1|ZSOwAnX+-R7WF>EiQ-?ou(8P;8nhKZs+&Tu-x8|Whzyj2j3EAOipXN! zxazv=RCAJE`a*}lqu0#T1Fw?avX$xWvX!e@o4@8g7$ui2{!WyocP7ed#R_TjrTR5o zrB>W7?|Cl~-8l9xCf}??mB;@=mgvMnyYAmO4To^-*zSWd%bytF{C zSpD2ceJ~1)Bt_6|yg3@J$In@oexWI;QFD}_{~B9t>aj!2y15fy@KtRp+m?@^4TjTl zIMP6Z>%AWJp)8m70u!0wmvO24lOBJ+rw8k2n`-8M%bzytp(h7RrdVuvNSyV^Z#TX7 zzSc=Ajn;?}rwSTMU{FRm!u%9EUpo4eiUzm-!Lv9Su=RIICCA`>+Du=sn~%`MA%I0B($T_KZxfBbS@+;dY~mu}q=ZtAT>p_tenR1CGkM5y=48Ox(PM89Uz-7oQY9u>Gy>&U&oN z&Nr&m)GmvLTl19I`=(j>Pro>SFA1&dE3jzYI8P03X|ldZjXLq7;qqtA^xuw`{hcm2 z2?Ev2Zc2R)=nrU6Hu7;N8xjY0BjjMVHADFb6LC!=-C8GAY(=%{l=at_$x2cphN1}= zmFS{U|7q>m`8$uUht)0H`5Be@melpm-1sYnd)T_eg(hUJ-qSN-ZqeQ~6*kCY{%^ht z+YNLO9deC!&)9079CS1$igS-#&>Pus=T#~S`Wtjc`_~O|Loo{`MX)wMu3~c|74s=o zJgX9f7)Jo&W91%=ZdnEOfe@sTRwQIvx?DU`MKd6U|051Zgg*Pj9A8 z?N(3<2Tfz_J zXsv$MDS_wTzJpsdv_ z0DgZ*N{Xw|e?GT-{>u%y%`MFMd%RhNL?Jp#4Rvg-r?L}%) z>XXNdG&@NTR4T@0Q6u z22R^ru_rZoE&x(p5KprC^G~bya_bK*oCc?1lQr{Jhk%sE6@;YBjkGr;NCx;ZZ5*eRcCDT%# z_RKU#S8#!aEkkp^%gG{X)^yF&CNhP(6!dT&jGws|;x{+Rmjh{(F0t%SCeD-WZkH7;On6z~MVSn?-fbC)L7%d0yi&rvEtwUvvK3dBko0PcUuf->rdv#@XA!z(+>xEK#QWmyP*ssC%HOh?> zlLqe5vxx0n&-cCnzNC_e(ZG1k$t-OiHc_dxwC=CZ4^H*O2|JH?^oRkxp*(eO<+WWW z&qq;Q9*N$EZlQp5yYKxwtHgb{&%USAI;6=NbYvrVoa#y4z5Ki9rSPloMaMI!KA$5F z@(s04%5%k)wYwd6{c5+ zmepeA1fBte=hQdfT@&zHRp$F8(jQHJ!+1z+y~rb#67czTU9WutaFH)i!1dwXvtMrl zjVbYvUC&xFZ1w*1{%6>rviEh&_ACHMIdt*CU-GgM0K!8-x{;%%cQAV!ASd zc!Jv~ybIEb!BGOElM?)YQ(uOL0PHXIsNO`dK#RO$&qDLRTtPw&k0e}_3o)iaVDx`^ zrl!Li%C^6z8s~s7GckkCujjrQ|1*70WJ2Mj`}_J*_aFx#IW<0*3=zEX@9LB_)cdN6dGyub>^H%kV zpvS_folXllgjo?ynD@(YpC7hcI(sYkg)cO?XEw#_mV!(h{mqWUupmse($H^BT}Z_fqlKp z!JgMGier`SF#@3{l>JR15y3$87q-s74^7F~vnJAT`iH+(@M3DQ7=Li^D!y1z5D4Zs z;z@W=}RnfZ1Z;37#LR z%Cjb03=%@17-tZq=h{j!Fq6^_f3a*Nv+fZ;i$}xdkXc6!i_AD2>Wgxv$6p;0&KiWk zsBbL-nEp*HnC)nf6Ul_$bF89|`+dl5>!|rHd7m#VPquWta&E{`APeIqf~f2O-%9+C zORU;3SA8ngSFd1SK%&@l`7knafG4CNj6ex{Lds%!@Z|wa7s3@-A4Ji)2N`2dJOw5A zUAOd4os&NLX5|-k+j{oLssK0Y0YmV@N1hGW_#0A^v zmtUh`V7q2t7p5B0Hs%Eo3_&a9K|{*%6veMd&t%4R&LK|^E?U5DUMg5kln^gSDG_)A zslGMIjmq{yL0F!?a-4LL5~n&g_!Ub}@Di6t5EafEJ%4sIKL$N@ZQtL7^FyTa`yDEv z;R|iv{Ea`(L#0=WZ_sy;;WzC~P>f-r1O?jeFfL-nQTFrH&Ye`H(e>M9i@llQ?Q&a3 zAYAowHd!rI^kuM#+lX>}1c9ZV1j0Gk1E;)#z=#8CNhW_7hUL-hBg1uTYX7J0W03_A z9E^o=sO3AnN_q&Z0ka}=#lO%)%+N|6P8UONNQ{Ka^O&qMM2B)Hk=tXDOw@c=@a-?o zSi?B9UNKH3&T(mfb0XnN`0=(H*J*tMujzI*#Rx-55ibwI(Y;8KmID#P!GI?SAqbCP zB>Lae=Mh)OVBo+>MVV2%tt&f*D$rSTj;&p&Vg`f#k}#P?B$j^ER^DgnxJ+y``F%SM zZm%$E_xxdmffR~hd&aqE8d^EyPLw>V3_oD{@)wMVhp%Jdve-G=?_vNhHu7t32!Q-! ze%lmoX~Xl-!HB}Ty!l0F=myc2ch?a2Yl6TLi zR#%NcAZgZ34%f8H&jAeE>ZeD#J)Q+9F!^%3PT-9dz~d-_Tp8|!V>ww+Q<&!ikV$4& zwxVt_JPv2B$6sTs{4ux{&T`!&xB)&$xqh7vJP1Lx%Bc@i?E8)%zBc*oZrq|^+!mHT zsEspIRbq@`XB>)_5GJ<}L0~)!e%4EJ0shjG*hV%0Si0XNQLo_@q| z7iw`J%A6dmJv#|)zU$sm=?L)VLNdf6l)vhKD3-7m(||8d@%pgsvUqqlobz9A zQij=dDvnIMKL`kdrTs(^#CIWOT4hq=goZ0eP9;G@ym@DRcJU{P=5^#_D@i|A!FuAo zos8qH(T_Wgw-k>JVN)DUzgO5BHhCu+M0^If6KW{gq?~al>;DoP>3Bo9KIw#X>zx ze)P$w?gr8;mXq0<1#r)~3|*e%9j_QffoYA)75v>(?v$jZXGk=)=gg-krk+aB#BP>W zPy{Fa7)|x)5JaI6twE>H)95hDqq|5-fTQyaGlcM;pThGvsv2yA_aUX$pHeziA7!IZg#m zfcSopX3^;XuVW(6D|`6oi%NeXU3;qwbOoKgQo^Pb)!hTnmmOJ8WkL{zWqCkN)qd~5 zK_LxpR8Xl%BB6xLkeNvChgt6X9^q@==|)c;!JpkopA0xwMx~1|&PVCNefTKcapbNE z&8sxcHQ;}I5dKpHOZALrCzLxm1T4$k_fR$BX;8P?EidW4X3GH!^TXMJvs#O}1_i<* zhJ}LQXyUJq8PO%cJ8h!=RQ%&i7x2Q8A)4DmMz}0mTtHvuJyq77s@zDua=AFwp!h}+ zJm>JQ(-b9^SMt-vN@xizjZn@?(t@SaP}*iYK5B>ukjnG#ZZ4ksk6XZayt_=zcNh|S zsRSb$*DEu401T5|_k}gl&N-mSy#D72yTHk_=dioO=Zd}8?a<_>;YktK>Fzivjg97a z)f9JJetbZ?If0qG47fQq!Z~mO=g5m7;3wf> zjO%DL|1fWvcL7F&-V$Z*w|*;0&MkL(vzlidImJxaB*F6%!Y;~#7$Ou`d5(lu0U(Zw z=O_=FhVkuVr`VXlAB4m<7pZUtu8L9*1bc*0hYn1wXhQ=kZkRj_JKi9h<7CjeweiBuzs zi$ej;N5O(Na;-lf3D=zpv*f(NL0k}s)^SceKPv=e`wAIn;-q(@hG9BEVyG965c(P3 z4Mm`&aawJGn9_;(M~e5KNDJnTwmwZ2;-w($-URv5_303pYad3|N?`t&Q*5V8OMss( zeIg>jh*!3#aQVE*ik#c3qr!H+Rtm>B39@X(r|0w;&ynX}mF&w1xQWnKjmVs)<; zF`#;Ar~5Ay41y+1;5w6Jxm|hM%V_#G7|}RcXR^o-s{2>EXJimWqm765&UID&?BuX; zn^+`&*|`BIZ^(>WpM?@?pp?Rd`8~3M$sV#)6yeKbkI7^dkTD+f@;eD+d)_(C>-y$M zkp;oET2OSucK;-J^p0z>G#;WG`=Q_hD(ygQsQnfify8=#sGWC05=KN9IuDq@>-&aP z8^VK=Qj>&#ef0W&{iwxJRC1qL0hTLD3s0GTn3{QBkv#Gpk02GgX5Q&B&G?T9W7tDm z)AlQ4HinmvT%lZ-x}IxCiH{@lVodFjKjN>?0nf`!RZX~3fsHZ_lM{w8dP#VxhsZmF zyGuoM=wHy)`Q{SnrRaHTzkAo7q`UK61L1|_Hw#-n3= z_-~W-1~)NZVA5@S1jhf8dWYxv!0izw2Qxgpc~IXILnDj8Et^As3jYEV6qw~2ymnR) z+-~D^(9DK!xO6LW)941mqU?|WGbBVin{qXXYc`6RO*k6i=r!8hEfR9J&a@fLc;tT(Sn7SRdyv9vyfZbAxv`+iqP_s6r=$kBIZ=9;WK}@^~G!x=E|&{vo_)ZNx!4iA_UR`_SlYfHfCUYNG*E_ z9OaH$wf=pY>i=K-{}0Rmi`ile7@QRACd{ZKX7wWjE{|EesIA9~7o~T$bwA1lM;vR^ ij~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 \ No newline at end of file diff --git a/doc/gcdPeripheral/img/simulationWave.PNG b/doc/gcdPeripheral/img/simulationWave.PNG new file mode 100644 index 0000000000000000000000000000000000000000..93853cbd702b2a66bdc64f825b147929d59ef71d GIT binary patch literal 48129 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 literal 0 HcmV?d00001 diff --git a/doc/gcdPeripheral/src/main/c/murax/gcd_world/makefile b/doc/gcdPeripheral/src/main/c/murax/gcd_world/makefile new file mode 100644 index 00000000..0f4abd87 --- /dev/null +++ b/doc/gcdPeripheral/src/main/c/murax/gcd_world/makefile @@ -0,0 +1,134 @@ +PROJ_NAME=gcd_world +DEBUG=no +BENCH=no +MULDIV=no + +SRCS = $(wildcard src/*.c) \ + $(wildcard src/*.cpp) \ + $(wildcard src/*.S) + +OBJDIR = build + +INC = +LIBS = +LIBSINC = -L$(OBJDIR) +LDSCRIPT = ./src/linker.ld + +#include ../../../resources/gcc.mk +# Set it to yes if you are using the sifive precompiled GCC pack +SIFIVE_GCC_PACK ?= no + +ifeq ($(SIFIVE_GCC_PACK),yes) + RISCV_NAME ?= riscv64-unknown-elf + RISCV_PATH ?= /home/sallar/tools/riscv-64-newlib-dist/ +else + RISCV_NAME ?= riscv32-unknown-elf + ifeq ($(MULDIV),yes) + RISCV_PATH ?= /home/sallar/tools/riscv-32-imac-ilp32-newlib-dist/ + else + RISCV_PATH ?= /home/sallar/tools/rv32i-ilp32-dist/ + endif +endif + +MABI=ilp32 +MARCH := rv32i +ifeq ($(MULDIV),yes) + MARCH := $(MARCH)m +endif +ifeq ($(COMPRESSED),yes) + MARCH := $(MARCH)ac +endif + +CFLAGS += -march=$(MARCH) -mabi=$(MABI) -DNDEBUG +LDFLAGS += -march=$(MARCH) -mabi=$(MABI) + + + +#include ../../../resources/subproject.mk + + +ifeq ($(DEBUG),yes) + CFLAGS += -g3 -O0 +endif + +ifeq ($(DEBUG),no) + CFLAGS += -g -Os +endif + +ifeq ($(BENCH),yes) + CFLAGS += -fno-inline +endif + +ifeq ($(SIFIVE_GCC_PACK),yes) + RISCV_CLIB=$(RISCV_PATH)/$(RISCV_NAME)/lib/$(MARCH)/$(MABI)/ +else + RISCV_CLIB=$(RISCV_PATH)/$(RISCV_NAME)/lib/ +endif + + + + + +RISCV_OBJCOPY = $(RISCV_PATH)/bin/$(RISCV_NAME)-objcopy +RISCV_OBJDUMP = $(RISCV_PATH)/bin/$(RISCV_NAME)-objdump +RISCV_CC=$(RISCV_PATH)/bin/$(RISCV_NAME)-gcc + +CFLAGS += -MD -fstrict-volatile-bitfields -fno-strict-aliasing +LDFLAGS += -nostdlib -lgcc -mcmodel=medany -nostartfiles -ffreestanding -Wl,-Bstatic,-T,$(LDSCRIPT),-Map,$(OBJDIR)/$(PROJ_NAME).map,--print-memory-usage +#LDFLAGS += -lgcc -lc -lg -nostdlib -lgcc -msave-restore --strip-debug, + +OBJS := $(SRCS) +OBJS := $(OBJS:.c=.o) +OBJS := $(OBJS:.cpp=.o) +OBJS := $(OBJS:.S=.o) +OBJS := $(OBJS:..=miaou) +OBJS := $(addprefix $(OBJDIR)/,$(OBJS)) + + +all: $(OBJDIR)/$(PROJ_NAME).elf $(OBJDIR)/$(PROJ_NAME).hex $(OBJDIR)/$(PROJ_NAME).asm $(OBJDIR)/$(PROJ_NAME).v + +$(OBJDIR)/%.elf: $(OBJS) | $(OBJDIR) + $(RISCV_CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) $(LIBSINC) $(LIBS) + +%.hex: %.elf + $(RISCV_OBJCOPY) -O ihex $^ $@ + +%.bin: %.elf + $(RISCV_OBJCOPY) -O binary $^ $@ + +%.v: %.elf + $(RISCV_OBJCOPY) -O verilog $^ $@ + +%.asm: %.elf + $(RISCV_OBJDUMP) -S -d $^ > $@ + +$(OBJDIR)/%.o: %.c + mkdir -p $(dir $@) + $(RISCV_CC) -c $(CFLAGS) $(INC) -o $@ $^ + $(RISCV_CC) -S $(CFLAGS) $(INC) -o $@.disasm $^ + +$(OBJDIR)/%.o: %.cpp + mkdir -p $(dir $@) + $(RISCV_CC) -c $(CFLAGS) $(INC) -o $@ $^ + +$(OBJDIR)/%.o: %.S + mkdir -p $(dir $@) + $(RISCV_CC) -c $(CFLAGS) -o $@ $^ -D__ASSEMBLY__=1 + +$(OBJDIR): + mkdir -p $@ + +.PHONY: clean +clean: + rm -rf $(OBJDIR)/src + rm -f $(OBJDIR)/$(PROJ_NAME).elf + rm -f $(OBJDIR)/$(PROJ_NAME).hex + rm -f $(OBJDIR)/$(PROJ_NAME).map + rm -f $(OBJDIR)/$(PROJ_NAME).v + rm -f $(OBJDIR)/$(PROJ_NAME).asm + find $(OBJDIR) -type f -name '*.o' -print0 | xargs -0 -r rm + find $(OBJDIR) -type f -name '*.d' -print0 | xargs -0 -r rm + +clean-all : clean + +.SECONDARY: $(OBJS) diff --git a/doc/gcdPeripheral/src/main/c/murax/gcd_world/project/build.properties b/doc/gcdPeripheral/src/main/c/murax/gcd_world/project/build.properties new file mode 100644 index 00000000..dbae93bc --- /dev/null +++ b/doc/gcdPeripheral/src/main/c/murax/gcd_world/project/build.properties @@ -0,0 +1 @@ +sbt.version=1.4.9 diff --git a/doc/gcdPeripheral/src/main/c/murax/gcd_world/src/crt.S b/doc/gcdPeripheral/src/main/c/murax/gcd_world/src/crt.S new file mode 100644 index 00000000..62d67b9e --- /dev/null +++ b/doc/gcdPeripheral/src/main/c/murax/gcd_world/src/crt.S @@ -0,0 +1,98 @@ +.global crtStart +.global main +.global irqCallback + + .section .start_jump,"ax",@progbits +crtStart: + //long jump to allow crtInit to be anywhere + //do it always in 12 bytes + lui x2, %hi(crtInit) + addi x2, x2, %lo(crtInit) + jalr x1,x2 + nop + +.section .text + +.global trap_entry +.align 5 +trap_entry: + sw x1, - 1*4(sp) + sw x5, - 2*4(sp) + sw x6, - 3*4(sp) + sw x7, - 4*4(sp) + sw x10, - 5*4(sp) + sw x11, - 6*4(sp) + sw x12, - 7*4(sp) + sw x13, - 8*4(sp) + sw x14, - 9*4(sp) + sw x15, -10*4(sp) + sw x16, -11*4(sp) + sw x17, -12*4(sp) + sw x28, -13*4(sp) + sw x29, -14*4(sp) + sw x30, -15*4(sp) + sw x31, -16*4(sp) + addi sp,sp,-16*4 + call irqCallback + lw x1 , 15*4(sp) + lw x5, 14*4(sp) + lw x6, 13*4(sp) + lw x7, 12*4(sp) + lw x10, 11*4(sp) + lw x11, 10*4(sp) + lw x12, 9*4(sp) + lw x13, 8*4(sp) + lw x14, 7*4(sp) + lw x15, 6*4(sp) + lw x16, 5*4(sp) + lw x17, 4*4(sp) + lw x28, 3*4(sp) + lw x29, 2*4(sp) + lw x30, 1*4(sp) + lw x31, 0*4(sp) + addi sp,sp,16*4 + mret + .text + + +crtInit: + .option push + .option norelax + la gp, __global_pointer$ + .option pop + la sp, _stack_start + +bss_init: + la a0, _bss_start + la a1, _bss_end +bss_loop: + beq a0,a1,bss_done + sw zero,0(a0) + add a0,a0,4 + j bss_loop +bss_done: + +ctors_init: + la a0, _ctors_start + addi sp,sp,-4 +ctors_loop: + la a1, _ctors_end + beq a0,a1,ctors_done + lw a3,0(a0) + add a0,a0,4 + sw a0,0(sp) + jalr a3 + lw a0,0(sp) + j ctors_loop +ctors_done: + addi sp,sp,4 + + + li a0, 0x880 //880 enable timer + external interrupts + csrw mie,a0 + li a0, 0x1808 //1808 enable interrupts + csrw mstatus,a0 + + call main +infinitLoop: + j infinitLoop diff --git a/doc/gcdPeripheral/src/main/c/murax/gcd_world/src/gcd.h b/doc/gcdPeripheral/src/main/c/murax/gcd_world/src/gcd.h new file mode 100644 index 00000000..1d3ccb70 --- /dev/null +++ b/doc/gcdPeripheral/src/main/c/murax/gcd_world/src/gcd.h @@ -0,0 +1,13 @@ +#ifndef GCD_H_ +#define GCD_H_ + +typedef struct +{ + volatile uint32_t A; + volatile uint32_t B; + volatile uint32_t RES; + volatile uint32_t READY; + volatile uint32_t VALID; +} Gcd_Reg; + +#endif /* GCD_H_ */ diff --git a/doc/gcdPeripheral/src/main/c/murax/gcd_world/src/gpio.h b/doc/gcdPeripheral/src/main/c/murax/gcd_world/src/gpio.h new file mode 100644 index 00000000..34348fec --- /dev/null +++ b/doc/gcdPeripheral/src/main/c/murax/gcd_world/src/gpio.h @@ -0,0 +1,15 @@ +#ifndef GPIO_H_ +#define GPIO_H_ + + +typedef struct +{ + volatile uint32_t INPUT; + volatile uint32_t OUTPUT; + volatile uint32_t OUTPUT_ENABLE; +} Gpio_Reg; + + +#endif /* GPIO_H_ */ + + diff --git a/doc/gcdPeripheral/src/main/c/murax/gcd_world/src/interrupt.h b/doc/gcdPeripheral/src/main/c/murax/gcd_world/src/interrupt.h new file mode 100644 index 00000000..23b7d277 --- /dev/null +++ b/doc/gcdPeripheral/src/main/c/murax/gcd_world/src/interrupt.h @@ -0,0 +1,17 @@ +#ifndef INTERRUPTCTRL_H_ +#define INTERRUPTCTRL_H_ + +#include + +typedef struct +{ + volatile uint32_t PENDINGS; + volatile uint32_t MASKS; +} InterruptCtrl_Reg; + +static void interruptCtrl_init(InterruptCtrl_Reg* reg){ + reg->MASKS = 0; + reg->PENDINGS = 0xFFFFFFFF; +} + +#endif /* INTERRUPTCTRL_H_ */ diff --git a/doc/gcdPeripheral/src/main/c/murax/gcd_world/src/linker.ld b/doc/gcdPeripheral/src/main/c/murax/gcd_world/src/linker.ld new file mode 100644 index 00000000..57bc2f7b --- /dev/null +++ b/doc/gcdPeripheral/src/main/c/murax/gcd_world/src/linker.ld @@ -0,0 +1,110 @@ +/* +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. +*/ +OUTPUT_FORMAT("elf32-littleriscv", "elf32-littleriscv", "elf32-littleriscv") +OUTPUT_ARCH(riscv) +ENTRY(crtStart) + +MEMORY { + RAM (rwx): ORIGIN = 0x80000000, LENGTH = 2k +} + +_stack_size = DEFINED(_stack_size) ? _stack_size : 256; +_heap_size = DEFINED(_heap_size) ? _heap_size : 0; + +SECTIONS { + + ._vector ORIGIN(RAM): { + *crt.o(.start_jump); + *crt.o(.text); + } > RAM + + ._user_heap (NOLOAD): + { + . = ALIGN(8); + PROVIDE ( end = . ); + PROVIDE ( _end = . ); + PROVIDE ( _heap_start = .); + . = . + _heap_size; + . = ALIGN(8); + PROVIDE ( _heap_end = .); + } > RAM + +._stack (NOLOAD): + { + . = ALIGN(16); + PROVIDE (_stack_end = .); + . = . + _stack_size; + . = ALIGN(16); + PROVIDE (_stack_start = .); + } > RAM + + .data : + { + *(.rdata) + *(.rodata .rodata.*) + *(.gnu.linkonce.r.*) + *(.data .data.*) + *(.gnu.linkonce.d.*) + . = ALIGN(8); + PROVIDE( __global_pointer$ = . + 0x800 ); + *(.sdata .sdata.*) + *(.gnu.linkonce.s.*) + . = ALIGN(8); + *(.srodata.cst16) + *(.srodata.cst8) + *(.srodata.cst4) + *(.srodata.cst2) + *(.srodata .srodata.*) + } > RAM + + .bss (NOLOAD) : { + . = ALIGN(4); + /* This is used by the startup in order to initialize the .bss secion */ + _bss_start = .; + *(.sbss*) + *(.gnu.linkonce.sb.*) + *(.bss .bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(4); + _bss_end = .; + } > RAM + + + .rodata : + { + *(.rdata) + *(.rodata .rodata.*) + *(.gnu.linkonce.r.*) + } > RAM + + .noinit (NOLOAD) : { + . = ALIGN(4); + *(.noinit .noinit.*) + . = ALIGN(4); + } > RAM + + .memory : { + *(.text); + end = .; + } > RAM + + .ctors : + { + . = ALIGN(4); + _ctors_start = .; + KEEP(*(.init_array*)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + . = ALIGN(4); + _ctors_end = .; + PROVIDE ( END_OF_SW_IMAGE = . ); + } > RAM + +} diff --git a/doc/gcdPeripheral/src/main/c/murax/gcd_world/src/main.c b/doc/gcdPeripheral/src/main/c/murax/gcd_world/src/main.c new file mode 100644 index 00000000..fccbcc2f --- /dev/null +++ b/doc/gcdPeripheral/src/main/c/murax/gcd_world/src/main.c @@ -0,0 +1,62 @@ +//#include "stddefs.h" +#include + +#include "murax.h" + +#include "main.h" + +#define DEBUG 0 + +uint32_t gcd(uint32_t a, uint32_t b){ + GCD->A = a; + GCD->B = b; + GCD->VALID = 0x00000001; + uint32_t rdyFlag = 0; + do{ + rdyFlag = GCD->READY; + }while(!rdyFlag); + return GCD->RES; +} + +void calcPrintGCD(uint32_t a, uint32_t b){ + uint32_t myGCD = 0; + char buf[5] = { 0x00 }; + char aBuf[11] = { 0x00 }; + char bBuf[11] = { 0x00 }; + itoa(a, aBuf, 10); + itoa(b, bBuf, 10); + print("gcd(");print(aBuf);print(",");print(bBuf);println("):"); + myGCD = gcd(a,b); + itoa(myGCD, buf, 10); + println(buf); +} + +void main() { + GPIO_A->OUTPUT_ENABLE = 0x0000000F; + GPIO_A->OUTPUT = 0x00000001; + println("hello gcd world"); + const int nleds = 4; + const int nloops = 2000000; + + GCD->VALID = 0x00000000; + while(GCD->READY); + + calcPrintGCD(1, 123913); + calcPrintGCD(461952, 116298); + calcPrintGCD(461952, 116298); + calcPrintGCD(461952, 116298); + + while(1){ + for(unsigned int i=0;iOUTPUT = 1<OUTPUT = (1<<(nleds-1))>>i; + delay(nloops); + } + } +} + +void irqCallback(){ +} diff --git a/doc/gcdPeripheral/src/main/c/murax/gcd_world/src/main.h b/doc/gcdPeripheral/src/main/c/murax/gcd_world/src/main.h new file mode 100644 index 00000000..31cb9c03 --- /dev/null +++ b/doc/gcdPeripheral/src/main/c/murax/gcd_world/src/main.h @@ -0,0 +1,78 @@ + +//---------------------------- +// integer to ascii (itoa) with util functions +//---------------------------- + +// function to swap two numbers +void swap(char *x, char *y) { + char t = *x; *x = *y; *y = t; +} + +// function to reverse buffer[i..j] +char* reverse(char *buffer, int i, int j) { + while (i < j) + swap(&buffer[i++], &buffer[j--]); + return buffer; +} + +// Iterative function to implement itoa() function in C +char* itoa(int value, char* buffer, int base) { + // invalid input + if (base < 2 || base > 32) + return buffer; + // consider absolute value of number + int n = (value < 0) ? -value : value; + int i = 0; + while (n) { + int r = n % base; + if (r >= 10) + buffer[i++] = 65 + (r - 10); + else + buffer[i++] = 48 + r; + n = n / base; + } + + // if number is 0 + if (i == 0) + buffer[i++] = '0'; + + // If base is 10 and value is negative, the resulting string + // is preceded with a minus sign (-) + // With any other base, value is always considered unsigned + if (value < 0 && base == 10) + buffer[i++] = '-'; + + buffer[i] = '\0'; // null terminate string + + // reverse the string and return it + return reverse(buffer, 0, i - 1); +} + +//---------------------------- +// print, println, dbgprint +//---------------------------- + +void print(const char*str){ + while(*str){ + uart_write(UART,*str); + str++; + } +} +void println(const char*str){ + print(str); + uart_write(UART,'\n'); +} + +void dbgPrintln(const char*str){ + #if DEBUG == 1 + println(str); + #else + void; + #endif +} + +void delay(uint32_t loops){ + for(int i=0;iOUTPUT; + } +} \ No newline at end of file diff --git a/doc/gcdPeripheral/src/main/c/murax/gcd_world/src/murax.h b/doc/gcdPeripheral/src/main/c/murax/gcd_world/src/murax.h new file mode 100644 index 00000000..9d7b7e7a --- /dev/null +++ b/doc/gcdPeripheral/src/main/c/murax/gcd_world/src/murax.h @@ -0,0 +1,20 @@ +#ifndef __MURAX_H__ +#define __MURAX_H__ + +#include "timer.h" +#include "prescaler.h" +#include "interrupt.h" +#include "gpio.h" +#include "uart.h" +#include "gcd.h" + +#define GPIO_A ((Gpio_Reg*)(0xF0000000)) +#define TIMER_PRESCALER ((Prescaler_Reg*)0xF0020000) +#define TIMER_INTERRUPT ((InterruptCtrl_Reg*)0xF0020010) +#define TIMER_A ((Timer_Reg*)0xF0020040) +#define TIMER_B ((Timer_Reg*)0xF0020050) +#define UART ((Uart_Reg*)(0xF0010000)) +#define GCD ((Gcd_Reg*)(0xF0030000)) + + +#endif /* __MURAX_H__ */ diff --git a/doc/gcdPeripheral/src/main/c/murax/gcd_world/src/prescaler.h b/doc/gcdPeripheral/src/main/c/murax/gcd_world/src/prescaler.h new file mode 100644 index 00000000..6bd9694a --- /dev/null +++ b/doc/gcdPeripheral/src/main/c/murax/gcd_world/src/prescaler.h @@ -0,0 +1,16 @@ +#ifndef PRESCALERCTRL_H_ +#define PRESCALERCTRL_H_ + +#include + + +typedef struct +{ + volatile uint32_t LIMIT; +} Prescaler_Reg; + +static void prescaler_init(Prescaler_Reg* reg){ + +} + +#endif /* PRESCALERCTRL_H_ */ diff --git a/doc/gcdPeripheral/src/main/c/murax/gcd_world/src/timer.h b/doc/gcdPeripheral/src/main/c/murax/gcd_world/src/timer.h new file mode 100644 index 00000000..1577535c --- /dev/null +++ b/doc/gcdPeripheral/src/main/c/murax/gcd_world/src/timer.h @@ -0,0 +1,20 @@ +#ifndef TIMERCTRL_H_ +#define TIMERCTRL_H_ + +#include + + +typedef struct +{ + volatile uint32_t CLEARS_TICKS; + volatile uint32_t LIMIT; + volatile uint32_t VALUE; +} Timer_Reg; + +static void timer_init(Timer_Reg *reg){ + reg->CLEARS_TICKS = 0; + reg->VALUE = 0; +} + + +#endif /* TIMERCTRL_H_ */ diff --git a/doc/gcdPeripheral/src/main/c/murax/gcd_world/src/uart.h b/doc/gcdPeripheral/src/main/c/murax/gcd_world/src/uart.h new file mode 100644 index 00000000..c3a30a56 --- /dev/null +++ b/doc/gcdPeripheral/src/main/c/murax/gcd_world/src/uart.h @@ -0,0 +1,42 @@ +#ifndef UART_H_ +#define UART_H_ + + +typedef struct +{ + volatile uint32_t DATA; + volatile uint32_t STATUS; + volatile uint32_t CLOCK_DIVIDER; + volatile uint32_t FRAME_CONFIG; +} Uart_Reg; + +enum UartParity {NONE = 0,EVEN = 1,ODD = 2}; +enum UartStop {ONE = 0,TWO = 1}; + +typedef struct { + uint32_t dataLength; + enum UartParity parity; + enum UartStop stop; + uint32_t clockDivider; +} Uart_Config; + +static uint32_t uart_writeAvailability(Uart_Reg *reg){ + return (reg->STATUS >> 16) & 0xFF; +} +static uint32_t uart_readOccupancy(Uart_Reg *reg){ + return reg->STATUS >> 24; +} + +static void uart_write(Uart_Reg *reg, uint32_t data){ + while(uart_writeAvailability(reg) == 0); + reg->DATA = data; +} + +static void uart_applyConfig(Uart_Reg *reg, Uart_Config *config){ + reg->CLOCK_DIVIDER = config->clockDivider; + reg->FRAME_CONFIG = ((config->dataLength-1) << 0) | (config->parity << 8) | (config->stop << 16); +} + +#endif /* UART_H_ */ + + diff --git a/doc/gcdPeripheral/src/main/scala/vexriscv/demo/Murax.scala b/doc/gcdPeripheral/src/main/scala/vexriscv/demo/Murax.scala new file mode 100644 index 00000000..f3d4f6cd --- /dev/null +++ b/doc/gcdPeripheral/src/main/scala/vexriscv/demo/Murax.scala @@ -0,0 +1,559 @@ +package vexriscv.demo + +import spinal.core._ +import spinal.lib._ +import spinal.lib.bus.amba3.apb._ +import spinal.lib.bus.misc.SizeMapping +import spinal.lib.bus.simple.PipelinedMemoryBus +import spinal.lib.com.jtag.Jtag +import spinal.lib.com.spi.ddr.SpiXdrMaster +import spinal.lib.com.uart._ +import spinal.lib.io.{InOutWrapper, TriStateArray} +import spinal.lib.misc.{InterruptCtrl, Prescaler, Timer} +import spinal.lib.soc.pinsec.{PinsecTimerCtrl, PinsecTimerCtrlExternal} +import vexriscv.plugin._ +import vexriscv.{VexRiscv, VexRiscvConfig, plugin} +import spinal.lib.com.spi.ddr._ +import spinal.lib.bus.simple._ +import scala.collection.mutable.ArrayBuffer +import vexriscv.periph.gcd._ +import vexriscv.periph.tasks.gen._ +import vexriscv.periph.tasks.map._ +import vexriscv.periph.tasks.sort._ +import vexriscv.periph.tasks.max._ +import vexriscv.periph.tasks.sum._ +import vexriscv.periph.tasks.hash._ + +/** Created by PIC32F_USER on 28/07/2017. + * + * Murax is a very light SoC which could work without any external component. + * - ICE40-hx8k + icestorm => 53 Mhz, 2142 LC + * - 0.37 DMIPS/Mhz + * - 8 kB of on-chip ram + * - JTAG debugger (eclipse/GDB/openocd ready) + * - Interrupt support + * - APB bus for peripherals + * - 32 GPIO pin + * - one 16 bits prescaler, two 16 bits timers + * - one UART with tx/rx fifo + */ + +case class MuraxConfig( + coreFrequency: HertzNumber, + onChipRamSize: BigInt, + onChipRamHexFile: String, + pipelineDBus: Boolean, + pipelineMainBus: Boolean, + pipelineApbBridge: Boolean, + gpioWidth: Int, + uartCtrlConfig: UartCtrlMemoryMappedConfig, + xipConfig: SpiXdrMasterCtrl.MemoryMappingParameters, + hardwareBreakpointCount: Int, + cpuPlugins: ArrayBuffer[Plugin[VexRiscv]] +) { + require( + pipelineApbBridge || pipelineMainBus, + "At least pipelineMainBus or pipelineApbBridge should be enable to avoid wipe transactions" + ) + val genXip = xipConfig != null + +} + +object MuraxConfig { + def default: MuraxConfig = default(false, false) + def default(withXip: Boolean = false, bigEndian: Boolean = false) = + MuraxConfig( + coreFrequency = 12 MHz, + onChipRamSize = 8 kB, + onChipRamHexFile = null, + pipelineDBus = true, + pipelineMainBus = false, + pipelineApbBridge = true, + gpioWidth = 32, + xipConfig = ifGen(withXip)( + SpiXdrMasterCtrl.MemoryMappingParameters( + SpiXdrMasterCtrl + .Parameters(8, 12, SpiXdrParameter(2, 2, 1)) + .addFullDuplex(0, 1, false), + cmdFifoDepth = 32, + rspFifoDepth = 32, + xip = SpiXdrMasterCtrl + .XipBusParameters(addressWidth = 24, lengthWidth = 2) + ) + ), + hardwareBreakpointCount = if (withXip) 3 else 0, + cpuPlugins = ArrayBuffer( //DebugPlugin added by the toplevel + new IBusSimplePlugin( + resetVector = if (withXip) 0xf001e000L else 0x80000000L, + cmdForkOnSecondStage = true, + cmdForkPersistence = withXip, //Required by the Xip controller + prediction = NONE, + catchAccessFault = false, + compressedGen = false, + bigEndian = bigEndian + ), + new DBusSimplePlugin( + catchAddressMisaligned = false, + catchAccessFault = false, + earlyInjection = false, + bigEndian = bigEndian + ), + new CsrPlugin( + CsrPluginConfig.smallest(mtvecInit = + if (withXip) 0xe0040020L else 0x80000020L + ) + ), + new DecoderSimplePlugin( + catchIllegalInstruction = false + ), + new RegFilePlugin( + regFileReadyKind = plugin.SYNC, + zeroBoot = false + ), + new IntAluPlugin, + new SrcPlugin( + separatedAddSub = false, + executeInsertion = false + ), + new LightShifterPlugin, + new HazardSimplePlugin( + bypassExecute = false, + bypassMemory = false, + bypassWriteBack = false, + bypassWriteBackBuffer = false, + pessimisticUseSrc = false, + pessimisticWriteRegFile = false, + pessimisticAddressMatch = false + ), + new BranchPlugin( + earlyBranch = false, + catchAddressMisaligned = false + ), + new YamlPlugin("cpu0.yaml") + ), + uartCtrlConfig = UartCtrlMemoryMappedConfig( + uartCtrlConfig = UartCtrlGenerics( + dataWidthMax = 8, + clockDividerWidth = 20, + preSamplingSize = 1, + samplingSize = 3, + postSamplingSize = 1 + ), + initConfig = UartCtrlInitConfig( + baudrate = 115200, + dataLength = 7, //7 => 8 bits + parity = UartParityType.NONE, + stop = UartStopType.ONE + ), + busCanWriteClockDividerConfig = false, + busCanWriteFrameConfig = false, + txFifoDepth = 16, + rxFifoDepth = 16 + ) + ) + + def fast = { + val config = default + + //Replace HazardSimplePlugin to get datapath bypass + config.cpuPlugins( + config.cpuPlugins.indexWhere(_.isInstanceOf[HazardSimplePlugin]) + ) = new HazardSimplePlugin( + bypassExecute = true, + bypassMemory = true, + bypassWriteBack = true, + bypassWriteBackBuffer = true + ) +// config.cpuPlugins(config.cpuPlugins.indexWhere(_.isInstanceOf[LightShifterPlugin])) = new FullBarrelShifterPlugin() + + config + } +} + +case class Murax(config: MuraxConfig) extends Component { + import config._ + + val io = new Bundle { + //Clocks / reset + val asyncReset = in Bool () + val mainClk = in Bool () + + //Main components IO + val jtag = slave(Jtag()) + + //Peripherals IO + val gpioA = master(TriStateArray(gpioWidth bits)) + val uart = master(Uart()) + + val xip = ifGen(genXip)(master(SpiXdrMaster(xipConfig.ctrl.spi))) + } + + val resetCtrlClockDomain = ClockDomain( + clock = io.mainClk, + config = ClockDomainConfig( + resetKind = BOOT + ) + ) + + val resetCtrl = new ClockingArea(resetCtrlClockDomain) { + val mainClkResetUnbuffered = False + + //Implement an counter to keep the reset axiResetOrder high 64 cycles + // Also this counter will automatically do a reset when the system boot. + val systemClkResetCounter = Reg(UInt(6 bits)) init (0) + when(systemClkResetCounter =/= U(systemClkResetCounter.range -> true)) { + systemClkResetCounter := systemClkResetCounter + 1 + mainClkResetUnbuffered := True + } + when(BufferCC(io.asyncReset)) { + systemClkResetCounter := 0 + } + + //Create all reset used later in the design + val mainClkReset = RegNext(mainClkResetUnbuffered) + val systemReset = RegNext(mainClkResetUnbuffered) + } + + val systemClockDomain = ClockDomain( + clock = io.mainClk, + reset = resetCtrl.systemReset, + frequency = FixedFrequency(coreFrequency) + ) + + val debugClockDomain = ClockDomain( + clock = io.mainClk, + reset = resetCtrl.mainClkReset, + frequency = FixedFrequency(coreFrequency) + ) + + val system = new ClockingArea(systemClockDomain) { + val pipelinedMemoryBusConfig = PipelinedMemoryBusConfig( + addressWidth = 32, + dataWidth = 32 + ) + + val bigEndianDBus = config.cpuPlugins.exists(_ match { + case plugin: DBusSimplePlugin => plugin.bigEndian + case _ => false + }) + + //Arbiter of the cpu dBus/iBus to drive the mainBus + //Priority to dBus, !! cmd transactions can change on the fly !! + val mainBusArbiter = + new MuraxMasterArbiter(pipelinedMemoryBusConfig, bigEndianDBus) + + //Instanciate the CPU + val cpu = new VexRiscv( + config = VexRiscvConfig( + plugins = cpuPlugins += new DebugPlugin( + debugClockDomain, + hardwareBreakpointCount + ) + ) + ) + + //Checkout plugins used to instanciate the CPU to connect them to the SoC + val timerInterrupt = False + val externalInterrupt = False + for (plugin <- cpu.plugins) plugin match { + case plugin: IBusSimplePlugin => + mainBusArbiter.io.iBus.cmd <> plugin.iBus.cmd + mainBusArbiter.io.iBus.rsp <> plugin.iBus.rsp + case plugin: DBusSimplePlugin => { + if (!pipelineDBus) + mainBusArbiter.io.dBus <> plugin.dBus + else { + mainBusArbiter.io.dBus.cmd << plugin.dBus.cmd.halfPipe() + mainBusArbiter.io.dBus.rsp <> plugin.dBus.rsp + } + } + case plugin: CsrPlugin => { + plugin.externalInterrupt := externalInterrupt + plugin.timerInterrupt := timerInterrupt + } + case plugin: DebugPlugin => + plugin.debugClockDomain { + resetCtrl.systemReset setWhen (RegNext(plugin.io.resetOut)) + io.jtag <> plugin.io.bus.fromJtag() + } + case _ => + } + + //****** MainBus slaves ******** + val mainBusMapping = ArrayBuffer[(PipelinedMemoryBus, SizeMapping)]() + val ram = new MuraxPipelinedMemoryBusRam( + onChipRamSize = onChipRamSize, + onChipRamHexFile = onChipRamHexFile, + pipelinedMemoryBusConfig = pipelinedMemoryBusConfig, + bigEndian = bigEndianDBus + ) + mainBusMapping += ram.io.bus -> (0x80000000L, onChipRamSize) + + val apbBridge = new PipelinedMemoryBusToApbBridge( + apb3Config = Apb3Config( + addressWidth = 20, + dataWidth = 32 + ), + pipelineBridge = pipelineApbBridge, + pipelinedMemoryBusConfig = pipelinedMemoryBusConfig + ) + mainBusMapping += apbBridge.io.pipelinedMemoryBus -> (0xf0000000L, 1 MB) + + //******** APB peripherals ********* + val apbMapping = ArrayBuffer[(Apb3, SizeMapping)]() + val gpioACtrl = Apb3Gpio(gpioWidth = gpioWidth, withReadSync = true) + io.gpioA <> gpioACtrl.io.gpio + apbMapping += gpioACtrl.io.apb -> (0x00000, 4 kB) + + val uartCtrl = Apb3UartCtrl(uartCtrlConfig) + uartCtrl.io.uart <> io.uart + externalInterrupt setWhen (uartCtrl.io.interrupt) + apbMapping += uartCtrl.io.apb -> (0x10000, 4 kB) + + val timer = new MuraxApb3Timer() + timerInterrupt setWhen (timer.io.interrupt) + apbMapping += timer.io.apb -> (0x20000, 4 kB) + + val gcd = new Apb3GCDCtrl( + apb3Config = Apb3Config( + addressWidth = 20, + dataWidth = 32 + ) + ) + apbMapping += gcd.io.apb -> (0x30000, 1 kB) + + val xip = ifGen(genXip)(new Area { + val ctrl = Apb3SpiXdrMasterCtrl(xipConfig) + ctrl.io.spi <> io.xip + externalInterrupt setWhen (ctrl.io.interrupt) + apbMapping += ctrl.io.apb -> (0x1f000, 4 kB) + + val accessBus = new PipelinedMemoryBus(PipelinedMemoryBusConfig(24, 32)) + mainBusMapping += accessBus -> (0xe0000000L, 16 MB) + + ctrl.io.xip.fromPipelinedMemoryBus() << accessBus + val bootloader = Apb3Rom("src/main/c/murax/xipBootloader/crt.bin") + apbMapping += bootloader.io.apb -> (0x1e000, 4 kB) + }) + + //******** Memory mappings ********* + val apbDecoder = Apb3Decoder( + master = apbBridge.io.apb, + slaves = apbMapping + ) + + val mainBusDecoder = new Area { + val logic = new MuraxPipelinedMemoryBusDecoder( + master = mainBusArbiter.io.masterBus, + specification = mainBusMapping, + pipelineMaster = pipelineMainBus + ) + } + } +} + +object Murax { + def main(args: Array[String]) { + SpinalVerilog(Murax(MuraxConfig.default)) + } +} + +object Murax_iCE40_hx8k_breakout_board_xip { + + case class SB_GB() extends BlackBox { + val USER_SIGNAL_TO_GLOBAL_BUFFER = in Bool () + val GLOBAL_BUFFER_OUTPUT = out Bool () + } + + case class SB_IO_SCLK() extends BlackBox { + addGeneric("PIN_TYPE", B"010000") + val PACKAGE_PIN = out Bool () + val OUTPUT_CLK = in Bool () + val CLOCK_ENABLE = in Bool () + val D_OUT_0 = in Bool () + val D_OUT_1 = in Bool () + setDefinitionName("SB_IO") + } + + case class SB_IO_DATA() extends BlackBox { + addGeneric("PIN_TYPE", B"110000") + val PACKAGE_PIN = inout(Analog(Bool)) + val CLOCK_ENABLE = in Bool () + val INPUT_CLK = in Bool () + val OUTPUT_CLK = in Bool () + val OUTPUT_ENABLE = in Bool () + val D_OUT_0 = in Bool () + val D_OUT_1 = in Bool () + val D_IN_0 = out Bool () + val D_IN_1 = out Bool () + setDefinitionName("SB_IO") + } + + case class Murax_iCE40_hx8k_breakout_board_xip() extends Component { + val io = new Bundle { + val mainClk = in Bool () + val jtag_tck = in Bool () + val jtag_tdi = in Bool () + val jtag_tdo = out Bool () + val jtag_tms = in Bool () + val uart_txd = out Bool () + val uart_rxd = in Bool () + + val mosi = inout(Analog(Bool)) + val miso = inout(Analog(Bool)) + val sclk = out Bool () + val spis = out Bool () + + val led = out Bits (8 bits) + } + val murax = Murax( + MuraxConfig.default(withXip = true).copy(onChipRamSize = 8 kB) + ) + murax.io.asyncReset := False + + val mainClkBuffer = SB_GB() + mainClkBuffer.USER_SIGNAL_TO_GLOBAL_BUFFER <> io.mainClk + mainClkBuffer.GLOBAL_BUFFER_OUTPUT <> murax.io.mainClk + + val jtagClkBuffer = SB_GB() + jtagClkBuffer.USER_SIGNAL_TO_GLOBAL_BUFFER <> io.jtag_tck + jtagClkBuffer.GLOBAL_BUFFER_OUTPUT <> murax.io.jtag.tck + + io.led <> murax.io.gpioA.write(7 downto 0) + + murax.io.jtag.tdi <> io.jtag_tdi + murax.io.jtag.tdo <> io.jtag_tdo + murax.io.jtag.tms <> io.jtag_tms + murax.io.gpioA.read <> 0 + murax.io.uart.txd <> io.uart_txd + murax.io.uart.rxd <> io.uart_rxd + + val xip = new ClockingArea(murax.systemClockDomain) { + RegNext(murax.io.xip.ss.asBool) <> io.spis + + val sclkIo = SB_IO_SCLK() + sclkIo.PACKAGE_PIN <> io.sclk + sclkIo.CLOCK_ENABLE := True + + sclkIo.OUTPUT_CLK := ClockDomain.current.readClockWire + sclkIo.D_OUT_0 <> murax.io.xip.sclk.write(0) + sclkIo.D_OUT_1 <> RegNext(murax.io.xip.sclk.write(1)) + + val datas = + for ((data, pin) <- (murax.io.xip.data, List(io.mosi, io.miso)).zipped) + yield new Area { + val dataIo = SB_IO_DATA() + dataIo.PACKAGE_PIN := pin + dataIo.CLOCK_ENABLE := True + + dataIo.OUTPUT_CLK := ClockDomain.current.readClockWire + dataIo.OUTPUT_ENABLE <> data.writeEnable + dataIo.D_OUT_0 <> data.write(0) + dataIo.D_OUT_1 <> RegNext(data.write(1)) + + dataIo.INPUT_CLK := ClockDomain.current.readClockWire + data.read(0) := dataIo.D_IN_0 + data.read(1) := RegNext(dataIo.D_IN_1) + } + } + + } + + def main(args: Array[String]) { + SpinalVerilog(Murax_iCE40_hx8k_breakout_board_xip()) + } +} + +object MuraxDhrystoneReady { + def main(args: Array[String]) { + SpinalVerilog(Murax(MuraxConfig.fast.copy(onChipRamSize = 256 kB))) + } +} + +object MuraxDhrystoneReadyMulDivStatic { + def main(args: Array[String]) { + SpinalVerilog({ + val config = MuraxConfig.fast.copy(onChipRamSize = 256 kB) + config.cpuPlugins += new MulPlugin + config.cpuPlugins += new DivPlugin + config.cpuPlugins.remove( + config.cpuPlugins.indexWhere(_.isInstanceOf[BranchPlugin]) + ) + config.cpuPlugins += new BranchPlugin( + earlyBranch = false, + catchAddressMisaligned = false + ) + config.cpuPlugins += new IBusSimplePlugin( + resetVector = 0x80000000L, + cmdForkOnSecondStage = true, + cmdForkPersistence = false, + prediction = STATIC, + catchAccessFault = false, + compressedGen = false + ) + config.cpuPlugins.remove( + config.cpuPlugins.indexWhere(_.isInstanceOf[LightShifterPlugin]) + ) + config.cpuPlugins += new FullBarrelShifterPlugin + Murax(config) + }) + } +} + +//Will blink led and echo UART RX to UART TX (in the verilator sim, type some text and press enter to send UART frame to the Murax RX pin) +object MuraxWithRamInit { + def main(args: Array[String]) { + SpinalVerilog( + Murax( + MuraxConfig.default.copy( + onChipRamSize = 4 kB, + onChipRamHexFile = "src/main/c/murax/gcd_world/build/gcd_world.hex" + ) + ) + ) + .printPruned() + } +} + +object MuraxWithRamInitSynth { + def main(args: Array[String]) { + val config = SpinalConfig( + targetDirectory = "synth", + defaultClockDomainFrequency = FixedFrequency(12 MHz) + ) + config + .generateVerilog( + Murax( + MuraxConfig.default.copy( + onChipRamSize = 4 kB, + onChipRamHexFile = "src/main/c/murax/gcd_world/build/gcd_world.hex" + ) + ) + ) + .printPruned() + } +} + +object Murax_arty { + def main(args: Array[String]) { + val hex = "src/main/c/murax/hello_world/build/hello_world.hex" + SpinalVerilog( + Murax( + MuraxConfig + .default(false) + .copy( + coreFrequency = 100 MHz, + onChipRamSize = 32 kB, + onChipRamHexFile = hex + ) + ) + ) + } +} + +object MuraxAsicBlackBox extends App { + println("Warning this soc do not has any rom to boot on.") + val config = SpinalConfig() + config.addStandardMemBlackboxing(blackboxAll) + config.generateVerilog(Murax(MuraxConfig.default())) +} diff --git a/doc/gcdPeripheral/src/main/scala/vexriscv/periph/gcd/Apb3GCDCtrl.scala b/doc/gcdPeripheral/src/main/scala/vexriscv/periph/gcd/Apb3GCDCtrl.scala new file mode 100644 index 00000000..2ec74016 --- /dev/null +++ b/doc/gcdPeripheral/src/main/scala/vexriscv/periph/gcd/Apb3GCDCtrl.scala @@ -0,0 +1,39 @@ +package vexriscv.periph.gcd + +import spinal.core._ +import spinal.lib._ +import spinal.lib.bus.amba3.apb.{Apb3, Apb3Config, Apb3SlaveFactory} +import spinal.lib.eda.altera.QSysify +import spinal.lib.slave + +object Apb3GCDCtrl { + def getApb3Config = Apb3Config( + addressWidth = 5, + dataWidth = 32, + selWidth = 1, + useSlaveError = false + ) +} + +class Apb3GCDCtrl(apb3Config : Apb3Config) extends Component { + val io = new Bundle { + val apb = slave(Apb3(Apb3GCDCtrl.getApb3Config)) + // maybe later + // val interrupt = out Bool + } + val gcdCtrl = new GCDTop() + val apbCtrl = Apb3SlaveFactory(io.apb) + apbCtrl.driveAndRead(gcdCtrl.io.a, address=0) + apbCtrl.driveAndRead(gcdCtrl.io.b, address=4) + // when result of calculation ready, synchronize it into memory mapped register + val resSyncBuf = RegNextWhen(gcdCtrl.io.res, gcdCtrl.io.ready) + apbCtrl.read(resSyncBuf, address=8) + // if result is read, it will be consumed, set ready to 0 + apbCtrl.onRead(8)(resSyncBuf := 0) + apbCtrl.onRead(8)(rdySyncBuf := False) + // synchronize ready signal into memory mapped register + val rdySyncBuf = RegNextWhen(gcdCtrl.io.ready, gcdCtrl.io.ready) + apbCtrl.read(rdySyncBuf, address=12) + // set valid based on memory mapped register but clear/consume it after 1 cycle b): + * a := a - b + * else if(b > a): + * b := b - a + * else: + * done := True + */ + //registers + val regA = Reg(UInt(32 bits)) init(0) + val regB = Reg(UInt(32 bits)) init(0) + // compare + val xGTy = regA > regB + val xLTy = regA < regB + // mux + val chX = io.dataCtrl.selL ? regB | regA + val chY = io.dataCtrl.selR ? regB | regA + // subtract + val subXY = chX - chY + // load logic + when(io.dataCtrl.init){ + regA := io.a + regB := io.b + } + when(io.dataCtrl.loadA){ + regA := subXY + } + when(io.dataCtrl.loadB){ + regB := subXY + } + io.dataCtrl.cmpAgtB := xGTy + io.dataCtrl.cmpAltB := xLTy + io.res := regA +} \ No newline at end of file diff --git a/doc/gcdPeripheral/src/main/scala/vexriscv/periph/gcd/GCDTop.scala b/doc/gcdPeripheral/src/main/scala/vexriscv/periph/gcd/GCDTop.scala new file mode 100644 index 00000000..654e9b8f --- /dev/null +++ b/doc/gcdPeripheral/src/main/scala/vexriscv/periph/gcd/GCDTop.scala @@ -0,0 +1,46 @@ +package vexriscv.periph.gcd + +import spinal.core._ +import spinal.lib._ +import spinal.lib.IMasterSlave + +case class GCDDataControl() extends Bundle with IMasterSlave{ + val cmpAgtB = Bool + val cmpAltB = Bool + val loadA = Bool + val loadB = Bool + val init = Bool + val selL = Bool + val selR = Bool + // define <> semantic + override def asMaster(): Unit = { + // as controller: output, input + out(loadA, loadB, selL, selR, init) + in(cmpAgtB, cmpAltB) + } +} + +//Hardware definition +class GCDTop() extends Component { + val io = new Bundle { + val valid = in Bool() + val ready = out Bool() + val a = in(UInt(32 bits)) + val b = in(UInt(32 bits)) + val res = out(UInt(32 bits)) + } + val gcdCtr = new GCDCtrl() + gcdCtr.io.valid := io.valid + io.ready := gcdCtr.io.ready + val gcdDat = new GCDData() + gcdDat.io.a := io.a + gcdDat.io.b := io.b + io.res := gcdDat.io.res + gcdCtr.io.dataCtrl <> gcdDat.io.dataCtrl +} + +object GCDTopVerilog { + def main(args: Array[String]) { + SpinalVerilog(new GCDTop) + } +} \ No newline at end of file diff --git a/doc/gcdPeripheral/src/main/scala/vexriscv/periph/gcd/GCDTopSim.scala b/doc/gcdPeripheral/src/main/scala/vexriscv/periph/gcd/GCDTopSim.scala new file mode 100644 index 00000000..53ea8dc7 --- /dev/null +++ b/doc/gcdPeripheral/src/main/scala/vexriscv/periph/gcd/GCDTopSim.scala @@ -0,0 +1,52 @@ +package vexriscv.periph.gcd + +import spinal.core._ +import spinal.sim._ +import spinal.core.sim._ + +//import scala.util.Random +import java.util.concurrent.ThreadLocalRandom +object GCDTopSim { + def main(args: Array[String]) { + + SimConfig.withWave.doSim(new GCDTop()){dut => + // SimConfig.doSim(new GCDTop()){dut => + def gcd(a: Long,b: Long): Long = { + if(b==0) a else gcd(b, a%b) + } + def RndNextUInt32(): Long = { + ThreadLocalRandom.current().nextLong(Math.pow(2, 32).toLong - 1) + } + var a = 0L + var b = 0L + var model = 0L + dut.io.a #= 0 + dut.io.b #= 0 + dut.io.valid #= false + + dut.clockDomain.forkStimulus(period = 10) + dut.clockDomain.waitRisingEdge() + + for(idx <- 0 to 500){ + // generate 2 random ints + a = RndNextUInt32() + b = RndNextUInt32() + // calculate the model value (software) + model = gcd(a,b) + // apply stimulus with random ints + dut.io.a #= a + dut.io.b #= b + dut.io.valid #= true + dut.clockDomain.waitRisingEdge() + dut.io.valid #= false + // wait until calculation of hardware is done + waitUntil(dut.io.ready.toBoolean) + assert( + assertion = (dut.io.res.toBigInt == model), + message = "test " + idx + " failed. Expected " + model + ", retrieved: " + dut.io.res.toBigInt + ) + waitUntil(!dut.io.ready.toBoolean) + } + } + } +} diff --git a/project/plugins.sbt b/project/plugins.sbt index 26ac3e58..e69de29b 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1 +0,0 @@ -addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.10") diff --git a/src/main/scala/vexriscv/Services.scala b/src/main/scala/vexriscv/Services.scala index 140c69bc..f0ef7136 100644 --- a/src/main/scala/vexriscv/Services.scala +++ b/src/main/scala/vexriscv/Services.scala @@ -50,6 +50,20 @@ trait PrivilegeService{ def isSupervisor() : Bool def isMachine() : Bool def forceMachine() : Unit + + def encodeBits() : Bits = { + val encoded = Bits(2 bits) + + when(this.isUser()) { + encoded := "00" + }.elsewhen(this.isSupervisor()) { + encoded := "01" + }.otherwise { + encoded := "11" + } + + encoded + } } case class PrivilegeServiceDefault() extends PrivilegeService{ diff --git a/src/main/scala/vexriscv/VexRiscv.scala b/src/main/scala/vexriscv/VexRiscv.scala index 44f41d93..2f4917f5 100644 --- a/src/main/scala/vexriscv/VexRiscv.scala +++ b/src/main/scala/vexriscv/VexRiscv.scala @@ -97,6 +97,7 @@ case class VexRiscvConfig(){ object FORMAL_MEM_RDATA extends Stageable(Bits(32 bits)) object FORMAL_MEM_WDATA extends Stageable(Bits(32 bits)) object FORMAL_INSTRUCTION extends Stageable(Bits(32 bits)) + object FORMAL_MODE extends Stageable(Bits(2 bits)) object Src1CtrlEnum extends SpinalEnum(binarySequential){ diff --git a/src/main/scala/vexriscv/demo/GenCustomInterrupt.scala b/src/main/scala/vexriscv/demo/GenCustomInterrupt.scala index d0d9e485..cffaa1c1 100644 --- a/src/main/scala/vexriscv/demo/GenCustomInterrupt.scala +++ b/src/main/scala/vexriscv/demo/GenCustomInterrupt.scala @@ -11,6 +11,12 @@ object GenCustomInterrupt extends App{ def cpu() = new VexRiscv( config = VexRiscvConfig( plugins = List( + new CsrPlugin( + CsrPluginConfig.smallest.copy( + xtvecModeGen = true, + mtvecAccess = CsrAccess.WRITE_ONLY + ) + ), new UserInterruptPlugin( interruptName = "miaou", code = 20 @@ -19,12 +25,6 @@ object GenCustomInterrupt extends App{ interruptName = "rawrrr", code = 24 ), - new CsrPlugin( - CsrPluginConfig.smallest.copy( - xtvecModeGen = true, - mtvecAccess = CsrAccess.WRITE_ONLY - ) - ), new IBusSimplePlugin( resetVector = 0x80000000l, cmdForkOnSecondStage = false, diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 24d94af3..db63107e 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -81,6 +81,7 @@ case class CsrPluginConfig( csrOhDecoder : Boolean = true, deterministicInteruptionEntry : Boolean = false, //Only used for simulatation purposes wfiOutput : Boolean = false, + exportPrivilege : Boolean = false, var withPrivilegedDebug : Boolean = false, //For the official RISC-V debug spec implementation var debugTriggers : Int = 2 ){ @@ -621,6 +622,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep contextSwitching = Bool().setName("contextSwitching") privilege = UInt(2 bits).setName("CsrPlugin_privilege") + if (exportPrivilege) out(privilege) forceMachineWire = False if(catchIllegalAccess || ecallGen || withEbreak) @@ -680,6 +682,10 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep } } + // The CSR plugin will invoke a trap handler on exception, which does not + // count as halt-state by the RVFI spec, and neither do other instructions + // such as `wfi`, etc. Hence statically drive the output: + pipeline.stages.head.insert(FORMAL_HALT) := False case class Xtvec() extends Bundle { val mode = Bits(2 bits) diff --git a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala index dbf66090..97aa0c13 100644 --- a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala @@ -103,6 +103,13 @@ case class DBusSimpleBus(bigEndian : Boolean = false) extends Bundle with IMaste s } + def cmdHalfPipe() : DBusSimpleBus = { + val s = DBusSimpleBus(bigEndian) + s.cmd << this.cmd.halfPipe() + this.rsp := s.rsp + s + } + def genMask(cmd : DBusSimpleCmd) = { if(bigEndian) cmd.size.mux( @@ -245,7 +252,7 @@ case class DBusSimpleBus(bigEndian : Boolean = false) extends Bundle with IMaste } bus } - + def toBmb() : Bmb = { val pipelinedMemoryBusConfig = DBusSimpleBus.getBmbParameter() val bus = Bmb(pipelinedMemoryBusConfig) diff --git a/src/main/scala/vexriscv/plugin/Fetcher.scala b/src/main/scala/vexriscv/plugin/Fetcher.scala index 290fed1f..9543c616 100644 --- a/src/main/scala/vexriscv/plugin/Fetcher.scala +++ b/src/main/scala/vexriscv/plugin/Fetcher.scala @@ -425,6 +425,8 @@ abstract class IBusFetcherImpl(var resetVector : BigInt, decode.arbitration.isValid clearWhen(forceNoDecodeCond) }) + val privilegeService = pipeline.serviceElse(classOf[PrivilegeService], PrivilegeServiceDefault()) + //Formal verification signals generation, miss prediction stuff ? val formal = new Area { val raw = if(compressedGen) decompressor.raw else inputBeforeStage.rsp.inst @@ -447,6 +449,11 @@ abstract class IBusFetcherImpl(var resetVector : BigInt, info.stage.output(FORMAL_PC_NEXT) := info.interface.payload } }) + + // Forward the current CPU "mode" (privilege level) from the fetch + // stage, which is where it can begin to affect the current + // execution (e.g., through PMP checks). + decode.insert(FORMAL_MODE) := privilegeService.encodeBits() } } diff --git a/src/main/scala/vexriscv/plugin/FormalPlugin.scala b/src/main/scala/vexriscv/plugin/FormalPlugin.scala index a02218da..5b5e0d58 100644 --- a/src/main/scala/vexriscv/plugin/FormalPlugin.scala +++ b/src/main/scala/vexriscv/plugin/FormalPlugin.scala @@ -35,6 +35,8 @@ case class RvfiPort() extends Bundle with IMasterSlave { val trap = Bool val halt = Bool val intr = Bool + val mode = Bits(2 bits) + val ixl = Bits(2 bits) val rs1 = RvfiPortRsRead() val rs2 = RvfiPortRsRead() val rd = RvfiPortRsWrite() @@ -91,6 +93,8 @@ class FormalPlugin extends Plugin[VexRiscv]{ rvfi.trap := False rvfi.halt := False rvfi.intr := False + rvfi.mode := output(FORMAL_MODE) + rvfi.ixl := 1 // rvfi.rs1.addr := output(INSTRUCTION)(rs1Range).asUInt // rvfi.rs2.addr := output(INSTRUCTION)(rs2Range).asUInt // rvfi.rs1.rdata := output(RS1) diff --git a/src/main/scala/vexriscv/plugin/MmuPlugin.scala b/src/main/scala/vexriscv/plugin/MmuPlugin.scala index 8057d178..ed78a9c1 100644 --- a/src/main/scala/vexriscv/plugin/MmuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/MmuPlugin.scala @@ -41,7 +41,9 @@ case class MmuPortConfig(portTlbSize : Int, latency : Int = 0, earlyRequireMmuLo class MmuPlugin(var ioRange : UInt => Bool, virtualRange : UInt => Bool = address => True, // allowUserIo : Boolean = false, - enableMmuInMachineMode : Boolean = false) extends Plugin[VexRiscv] with MemoryTranslator { + enableMmuInMachineMode : Boolean = false, + exportSatp: Boolean = false + ) extends Plugin[VexRiscv] with MemoryTranslator { var dBusAccess : DBusAccess = null val portsInfo = ArrayBuffer[MmuPort]() @@ -94,7 +96,10 @@ class MmuPlugin(var ioRange : UInt => Bool, val satp = new Area { val mode = RegInit(False) val asid = Reg(Bits(9 bits)) - val ppn = Reg(UInt(20 bits)) + val ppn = Reg(UInt(22 bits)) // Bottom 20 bits are used in implementation, but top 2 bits are still stored for OS use. + if(exportSatp) { + out(mode, asid, ppn) + } } for(offset <- List(CSR.MSTATUS, CSR.SSTATUS)) csrService.rw(offset, 19 -> status.mxr, 18 -> status.sum, 17 -> status.mprv) @@ -233,7 +238,8 @@ class MmuPlugin(var ioRange : UInt => Bool, } is(State.L1_CMD){ dBusAccess.cmd.valid := True - dBusAccess.cmd.address := csr.satp.ppn @@ vpn(1) @@ U"00" + // RV spec allows for 34-bit phys address in Sv32 mode; we only implement 32 bits and ignore the top 2 bits of satp. + dBusAccess.cmd.address := csr.satp.ppn(19 downto 0) @@ vpn(1) @@ U"00" when(dBusAccess.cmd.ready){ state := State.L1_RSP } diff --git a/src/test/cpp/custom/atomic/src/crt.S b/src/test/cpp/custom/atomic/src/crt.S index 1462dd25..ef5cb411 100644 --- a/src/test/cpp/custom/atomic/src/crt.S +++ b/src/test/cpp/custom/atomic/src/crt.S @@ -15,7 +15,7 @@ trap_entry: csrr x29, mstatus and x29, x29, 0x080 beqz x29, notExternalInterrupt - li x29, 0x1800 //000 disable interrupts + li x29, 0x1800 //1800 disable interrupts csrw mstatus,x29 mret @@ -227,7 +227,7 @@ test7: sw a3, 0(a0) li x29, 0x800 //800 external interrupts csrw mie,x29 - li x29, 0x1808 //008 enable interrupts + li x29, 0x1808 //1808 enable interrupts lr.w a5, (a0) csrw mstatus,x29 //Enable external interrupt (will jump instantly due to testbench setup) nop From badf13be02b077f86da2eedcbb176c92300ca51d Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 10 Aug 2023 09:02:15 +0200 Subject: [PATCH 897/951] SpinalHDL 1.9.2 --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index 0cdecb8f..3889ba68 100644 --- a/build.sbt +++ b/build.sbt @@ -1,4 +1,4 @@ -val spinalVersion = "1.9.0" +val spinalVersion = "1.9.2" lazy val root = (project in file(".")). settings( From 5ef1bc775fdbe942875dd7906f22aa98e6cffaaf Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 16 Aug 2023 09:59:21 +0200 Subject: [PATCH 898/951] SpinalHDL 1.9.3 --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index 3889ba68..d749f35b 100644 --- a/build.sbt +++ b/build.sbt @@ -1,4 +1,4 @@ -val spinalVersion = "1.9.2" +val spinalVersion = "1.9.3" lazy val root = (project in file(".")). settings( From 3739b9ac8897263eaa7104db6a68e5b58a4df09c Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 29 Aug 2023 08:58:48 +0200 Subject: [PATCH 899/951] plic update --- src/test/scala/vexriscv/experimental/PlicCost.scala | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/scala/vexriscv/experimental/PlicCost.scala b/src/test/scala/vexriscv/experimental/PlicCost.scala index 79d5c663..df008423 100644 --- a/src/test/scala/vexriscv/experimental/PlicCost.scala +++ b/src/test/scala/vexriscv/experimental/PlicCost.scala @@ -33,6 +33,7 @@ class PlicBench(inputCount : Int) extends Component{ val targets = Seq( PlicTarget( + id = 0, gateways = gateways, priorityWidth = priorityWidth ) From 73733dd8b1781f93102aeb83c934e3fb906e1260 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 8 Sep 2023 16:00:59 +0200 Subject: [PATCH 900/951] litex privileged debug --- .../demo/smp/VexRiscvSmpCluster.scala | 75 ++++++++++++++++--- .../demo/smp/VexRiscvSmpLitexCluster.scala | 7 +- 2 files changed, 72 insertions(+), 10 deletions(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index 6fffb6a5..abf503b2 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -14,6 +14,7 @@ import spinal.lib.com.jtag.xilinx.Bscane2BmbMasterGenerator import spinal.lib.generator._ import spinal.core.fiber._ import spinal.idslplugin.PostInitCallback +import spinal.lib.cpu.riscv.debug.{DebugModule, DebugModuleCpuConfig, DebugModuleParameter, DebugTransportModuleParameter, DebugTransportModuleTunneled} import spinal.lib.misc.plic.PlicMapping import spinal.lib.system.debugger.SystemDebuggerConfig import vexriscv.ip.{DataCacheAck, DataCacheConfig, DataCacheMemBus, InstructionCache, InstructionCacheConfig} @@ -30,7 +31,8 @@ case class VexRiscvSmpClusterParameter(cpuConfigs : Seq[VexRiscvConfig], withExclusiveAndInvalidation : Boolean, forcePeripheralWidth : Boolean = true, outOfOrderDecoder : Boolean = true, - fpu : Boolean = false) + fpu : Boolean = false, + privilegedDebug : Boolean = false) class VexRiscvSmpClusterBase(p : VexRiscvSmpClusterParameter) extends Area with PostInitCallback{ val cpuCount = p.cpuConfigs.size @@ -52,10 +54,12 @@ class VexRiscvSmpClusterBase(p : VexRiscvSmpClusterParameter) extends Area with implicit val interconnect = BmbInterconnectGenerator() - val debugBridge = debugCd.outputClockDomain on JtagInstructionDebuggerGenerator(p.jtagHeaderIgnoreWidth) - debugBridge.jtagClockDomain.load(ClockDomain.external("jtag", withReset = false)) + val customDebug = !p.privilegedDebug generate new Area { + val debugBridge = debugCd.outputClockDomain on JtagInstructionDebuggerGenerator(p.jtagHeaderIgnoreWidth) + debugBridge.jtagClockDomain.load(ClockDomain.external("jtag", withReset = false)) - val debugPort = Handle(debugBridge.logic.jtagBridge.io.ctrl.toIo) + val debugPort = Handle(debugBridge.logic.jtagBridge.io.ctrl.toIo) + } val dBusCoherent = BmbBridgeGenerator() val dBusNonCoherent = BmbBridgeGenerator() @@ -80,12 +84,65 @@ class VexRiscvSmpClusterBase(p : VexRiscvSmpClusterParameter) extends Area with interconnect.addConnection( cpu.dBus -> List(dBusCoherent.bmb) ) - cpu.enableDebugBmb( - debugCd = debugCd.outputClockDomain, - resetCd = systemCd, - mapping = SizeMapping(cpuId*0x1000, 0x1000) + + if(!p.privilegedDebug) { + cpu.enableDebugBmb( + debugCd = debugCd.outputClockDomain, + resetCd = systemCd, + mapping = SizeMapping(cpuId * 0x1000, 0x1000) + ) + interconnect.addConnection(customDebug.debugBridge.bmb, cpu.debugBmb) + } else { + cpu.enableRiscvDebug(debugCd.outputClockDomain, systemCd) + } + } + + val privilegedDebug = p.privilegedDebug generate new Area{ + val jtagCd = ClockDomain.external("jtag", withReset = false) + + val systemReset = Handle(Bool()) + systemCd.relaxedReset(systemReset, ResetSensitivity.HIGH) + + val p = DebugTransportModuleParameter( + addressWidth = 7, + version = 1, + idle = 7 ) - interconnect.addConnection(debugBridge.bmb, cpu.debugBmb) + + val logic = hardFork(debugCd.outputClockDomain on new Area { + val XLEN = 32 + + val dm = DebugModule( + DebugModuleParameter( + version = p.version + 1, + harts = cpuCount, + progBufSize = 2, + datacount = XLEN / 32 + cores.exists(_.cpu.config.get.FLEN == 64).toInt, + hartsConfig = cores.map(c => DebugModuleCpuConfig( + xlen = XLEN, + flen = c.cpu.config.get.FLEN, + withFpuRegAccess = c.cpu.config.get.FLEN == 64 + )) + ) + ) + systemReset := dm.io.ndmreset + for ((cpu, i) <- cores.zipWithIndex) { + val privBus = cpu.cpu.debugRiscv + privBus <> dm.io.harts(i) + privBus.dmToHart.removeAssignments() <-< dm.io.harts(i).dmToHart + } + + val clintStop = (cores.map(e => e.cpu.logic.cpu.service(classOf[CsrPlugin]).stoptime).andR) + + val tunnel = DebugTransportModuleTunneled( + p = p, + jtagCd = jtagCd, + debugCd = ClockDomain.current + ) + dm.io.ctrl <> tunnel.io.bus + + val debugPort = Handle(tunnel.io.instruction.toIo) + }) } } diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala index 3454577b..3d380ca9 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala @@ -101,6 +101,7 @@ class VexRiscvLitexSmpCluster(p : VexRiscvLitexSmpClusterParameter) extends VexR object VexRiscvLitexSmpClusterCmdGen extends App { + Handle.loadHandleAsync = true var cpuCount = 1 var iBusWidth = 64 var dBusWidth = 64 @@ -108,6 +109,7 @@ object VexRiscvLitexSmpClusterCmdGen extends App { var dCacheSize = 8192 var iCacheWays = 2 var dCacheWays = 2 + var privilegedDebug = false var liteDramWidth = 128 var coherentDma = false var wishboneMemory = false @@ -131,6 +133,7 @@ object VexRiscvLitexSmpClusterCmdGen extends App { opt[String]("dcache-size") action { (v, c) => dCacheSize = v.toInt } opt[String]("icache-ways") action { (v, c) => iCacheWays = v.toInt } opt[String]("dcache-ways") action { (v, c) => dCacheWays = v.toInt } + opt[Boolean]("privileged-debug") action { (v, c) => privilegedDebug = v } opt[String]("litedram-width") action { (v, c) => liteDramWidth = v.toInt } opt[String]("netlist-directory") action { (v, c) => netlistDirectory = v } opt[String]("netlist-name") action { (v, c) => netlistName = v } @@ -160,6 +163,7 @@ object VexRiscvLitexSmpClusterCmdGen extends App { iCacheWays = iCacheWays, dCacheWays = dCacheWays, coherency = coherency, + privilegedDebug = privilegedDebug, iBusRelax = true, earlyBranch = true, withFloat = fpu, @@ -178,7 +182,8 @@ object VexRiscvLitexSmpClusterCmdGen extends App { forcePeripheralWidth = !wishboneMemory || wishboneForce32b, outOfOrderDecoder = outOfOrderDecoder, fpu = fpu, - jtagHeaderIgnoreWidth = 0 + jtagHeaderIgnoreWidth = 0, + privilegedDebug = privilegedDebug ), liteDram = LiteDramNativeParameter(addressWidth = 32, dataWidth = liteDramWidth), liteDramMapping = SizeMapping(0x40000000l, 0x40000000l), From 9fd127d6d9a555aae10fead3cd7297770888c7e8 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 8 Sep 2023 16:26:23 +0200 Subject: [PATCH 901/951] fix naming --- src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index abf503b2..2b8fb7d7 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -58,7 +58,7 @@ class VexRiscvSmpClusterBase(p : VexRiscvSmpClusterParameter) extends Area with val debugBridge = debugCd.outputClockDomain on JtagInstructionDebuggerGenerator(p.jtagHeaderIgnoreWidth) debugBridge.jtagClockDomain.load(ClockDomain.external("jtag", withReset = false)) - val debugPort = Handle(debugBridge.logic.jtagBridge.io.ctrl.toIo) + val debugPort = Handle(debugBridge.logic.jtagBridge.io.ctrl.toIo).setName("debugPort") } val dBusCoherent = BmbBridgeGenerator() @@ -141,7 +141,7 @@ class VexRiscvSmpClusterBase(p : VexRiscvSmpClusterParameter) extends Area with ) dm.io.ctrl <> tunnel.io.bus - val debugPort = Handle(tunnel.io.instruction.toIo) + val debugPort = Handle(tunnel.io.instruction.toIo).setName("debugPort") }) } } @@ -216,7 +216,7 @@ class VexRiscvSmpClusterWithPeripherals(p : VexRiscvSmpClusterParameter) extends clint.cpuCount.load(cpuCount) } - +//python3 -m litex_boards.targets.digilent_nexys_video --cpu-type=vexriscv_smp --with-privileged-debug --sys-clk-freq 50000000 --cpu-count 1 --build --load object VexRiscvSmpClusterGen { def vexRiscvConfig(hartId : Int, ioRange : UInt => Bool = (x => x(31 downto 28) === 0xF), From 220a2733be0e490dd627b8b412000cf60dd1f9c1 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 8 Sep 2023 16:47:54 +0200 Subject: [PATCH 902/951] litex privileged debug stop time now connect to clint --- src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index 2b8fb7d7..b93e5f41 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -214,6 +214,7 @@ class VexRiscvSmpClusterWithPeripherals(p : VexRiscvSmpClusterParameter) extends } clint.cpuCount.load(cpuCount) + if(p.privilegedDebug) hardFork(clint.logic.io.stop := privilegedDebug.logic.clintStop) } //python3 -m litex_boards.targets.digilent_nexys_video --cpu-type=vexriscv_smp --with-privileged-debug --sys-clk-freq 50000000 --cpu-count 1 --build --load From 213e4b863a1d0ae898f7eea7be5771c2a8dbcc63 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 12 Sep 2023 10:40:45 +0200 Subject: [PATCH 903/951] litex add -expose-time --- .../demo/smp/VexRiscvSmpLitexCluster.scala | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala index 3d380ca9..a3141774 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala @@ -7,6 +7,7 @@ import spinal.lib.bus.misc.{AddressMapping, DefaultMapping, SizeMapping} import spinal.lib.bus.wishbone.{WishboneConfig, WishboneToBmbGenerator} import spinal.lib.generator.GeneratorComponent import spinal.lib.sim.SparseMemory +import vexriscv.demo.smp.VexRiscvLitexSmpClusterCmdGen.exposeTime import vexriscv.demo.smp.VexRiscvSmpClusterGen.vexRiscvConfig import vexriscv.ip.fpu.{FpuCore, FpuParameter} import vexriscv.plugin.{AesPlugin, DBusCachedPlugin, FpuPlugin} @@ -17,7 +18,8 @@ case class VexRiscvLitexSmpClusterParameter( cluster : VexRiscvSmpClusterParamet liteDramMapping : AddressMapping, coherentDma : Boolean, wishboneMemory : Boolean, - cpuPerFpu : Int) + cpuPerFpu : Int, + exposeTime : Boolean) class VexRiscvLitexSmpCluster(p : VexRiscvLitexSmpClusterParameter) extends VexRiscvSmpClusterWithPeripherals(p.cluster) { @@ -97,6 +99,8 @@ class VexRiscvLitexSmpCluster(p : VexRiscvLitexSmpClusterParameter) extends VexR interconnect.setPipelining(iBridge.bmb)(cmdHalfRate = true) interconnect.setPipelining(dBridge.bmb)(cmdReady = true) } + + val clint_time = p.exposeTime generate hardFork(clint.logic.io.time.toIo) } @@ -123,6 +127,7 @@ object VexRiscvLitexSmpClusterCmdGen extends App { var iTlbSize = 4 var dTlbSize = 4 var wishboneForce32b = false + var exposeTime = false assert(new scopt.OptionParser[Unit]("VexRiscvLitexSmpClusterCmdGen") { help("help").text("prints this usage text") opt[Unit]("coherent-dma") action { (v, c) => coherentDma = true } @@ -146,6 +151,7 @@ object VexRiscvLitexSmpClusterCmdGen extends App { opt[String]("rvc") action { (v, c) => rvc = v.toBoolean } opt[String]("itlb-size") action { (v, c) => iTlbSize = v.toInt } opt[String]("dtlb-size") action { (v, c) => dTlbSize = v.toInt } + opt[String]("expose-time") action { (v, c) => exposeTime = v.toBoolean } }.parse(args, Unit).nonEmpty) val coherency = coherentDma || cpuCount > 1 @@ -172,8 +178,8 @@ object VexRiscvLitexSmpClusterCmdGen extends App { loadStoreWidth = if(fpu) 64 else 32, rvc = rvc, injectorStage = rvc, - iTlbSize = iTlbSize, - dTlbSize = dTlbSize + iTlbSize = iTlbSize, + dTlbSize = dTlbSize ) if(aesInstruction) c.add(new AesPlugin) c @@ -189,7 +195,8 @@ object VexRiscvLitexSmpClusterCmdGen extends App { liteDramMapping = SizeMapping(0x40000000l, 0x40000000l), coherentDma = coherentDma, wishboneMemory = wishboneMemory, - cpuPerFpu = cpuPerFpu + cpuPerFpu = cpuPerFpu, + exposeTime = exposeTime ) def dutGen = { @@ -265,7 +272,8 @@ object VexRiscvLitexSmpClusterOpenSbi extends App{ liteDramMapping = SizeMapping(0x80000000l, 0x70000000l), coherentDma = false, wishboneMemory = false, - cpuPerFpu = 4 + cpuPerFpu = 4, + exposeTime = false ) def dutGen = { From acf6ad3bfdfc8cd44f4432b055945fd1d7d38fe8 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 13 Sep 2023 14:55:35 +0200 Subject: [PATCH 904/951] Add doc about official RISC-V debug support --- README.md | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/README.md b/README.md index c7578c6f..28bace2e 100644 --- a/README.md +++ b/README.md @@ -1294,6 +1294,42 @@ Write Address 0x04 -> The OpenOCD port is here: +#### EmbeddedRiscvJtag + +VexRiscv also support the official RISC-V debug specification (Thanks Efinix for the funding !). + +To enable it, you need to add the EmbeddedRiscvJtag to the plugin list : + +```scala +new EmbeddedRiscvJtag( + p = DebugTransportModuleParameter( + addressWidth = 7, + version = 1, + idle = 7 + ), + withTunneling = false, + withTap = true +) +``` + +And turn on the withPrivilegedDebug option in the CsrPlugin config. + +Here is an example of openocd tcl script to connect : + +```tcl +# ADD HERE YOUR JTAG ADAPTER SETTINGS + +set _CHIPNAME riscv +jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x10002FFF + +set _TARGETNAME $_CHIPNAME.cpu + +target create $_TARGETNAME.0 riscv -chain-position $_TARGETNAME + +init +halt +``` + #### YamlPlugin This plugin offers a service to other plugins to generate a useful Yaml file describing the CPU configuration. It contains, for instance, the sequence of instructions required From e21dc6cda51ff0848d3ee654f5a372519b1821ac Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 20 Sep 2023 09:08:18 +0200 Subject: [PATCH 905/951] litex add hardwarebreapoint parameter --- src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala | 4 +++- .../scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala | 7 +++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index b93e5f41..854828f3 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -32,7 +32,8 @@ case class VexRiscvSmpClusterParameter(cpuConfigs : Seq[VexRiscvConfig], forcePeripheralWidth : Boolean = true, outOfOrderDecoder : Boolean = true, fpu : Boolean = false, - privilegedDebug : Boolean = false) + privilegedDebug : Boolean = false, + hardwareBreakpoints : Int = 0) class VexRiscvSmpClusterBase(p : VexRiscvSmpClusterParameter) extends Area with PostInitCallback{ val cpuCount = p.cpuConfigs.size @@ -85,6 +86,7 @@ class VexRiscvSmpClusterBase(p : VexRiscvSmpClusterParameter) extends Area with cpu.dBus -> List(dBusCoherent.bmb) ) + cpu.hardwareBreakpointCount.load(p.hardwareBreakpoints) if(!p.privilegedDebug) { cpu.enableDebugBmb( debugCd = debugCd.outputClockDomain, diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala index a3141774..9a8aefe8 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpLitexCluster.scala @@ -114,6 +114,7 @@ object VexRiscvLitexSmpClusterCmdGen extends App { var iCacheWays = 2 var dCacheWays = 2 var privilegedDebug = false + var hardwareBreakpoints = 0 var liteDramWidth = 128 var coherentDma = false var wishboneMemory = false @@ -130,7 +131,7 @@ object VexRiscvLitexSmpClusterCmdGen extends App { var exposeTime = false assert(new scopt.OptionParser[Unit]("VexRiscvLitexSmpClusterCmdGen") { help("help").text("prints this usage text") - opt[Unit]("coherent-dma") action { (v, c) => coherentDma = true } + opt[Unit] ("coherent-dma") action { (v, c) => coherentDma = true } opt[String]("cpu-count") action { (v, c) => cpuCount = v.toInt } opt[String]("ibus-width") action { (v, c) => iBusWidth = v.toInt } opt[String]("dbus-width") action { (v, c) => dBusWidth = v.toInt } @@ -139,6 +140,7 @@ object VexRiscvLitexSmpClusterCmdGen extends App { opt[String]("icache-ways") action { (v, c) => iCacheWays = v.toInt } opt[String]("dcache-ways") action { (v, c) => dCacheWays = v.toInt } opt[Boolean]("privileged-debug") action { (v, c) => privilegedDebug = v } + opt[Int] ("hardware-breakpoints") action { (v, c) => hardwareBreakpoints = v } opt[String]("litedram-width") action { (v, c) => liteDramWidth = v.toInt } opt[String]("netlist-directory") action { (v, c) => netlistDirectory = v } opt[String]("netlist-name") action { (v, c) => netlistName = v } @@ -189,7 +191,8 @@ object VexRiscvLitexSmpClusterCmdGen extends App { outOfOrderDecoder = outOfOrderDecoder, fpu = fpu, jtagHeaderIgnoreWidth = 0, - privilegedDebug = privilegedDebug + privilegedDebug = privilegedDebug, + hardwareBreakpoints = hardwareBreakpoints ), liteDram = LiteDramNativeParameter(addressWidth = 32, dataWidth = liteDramWidth), liteDramMapping = SizeMapping(0x40000000l, 0x40000000l), From 960f8682ea5be8db3c1ef5bc03f9c7d2c4faacb0 Mon Sep 17 00:00:00 2001 From: StaubRobin Date: Mon, 25 Sep 2023 22:15:50 +0200 Subject: [PATCH 906/951] Add missing parameter jtagHeaderIgnoreWidth --- doc/nativeJtag/README.md | 4 ++-- src/main/scala/vexriscv/demo/VexRiscvAhbLite3.scala | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/nativeJtag/README.md b/doc/nativeJtag/README.md index 550d8be8..10c5b7ee 100644 --- a/doc/nativeJtag/README.md +++ b/doc/nativeJtag/README.md @@ -49,7 +49,7 @@ as given could move with future changes to the file: ``` [254] val jtagCtrl = JtagTapInstructionCtrl() [255] val tap = jtagCtrl.fromXilinxBscane2(userId = 2) -[256] jtagCtrl <> plugin.io.bus.fromJtagInstructionCtrl(ClockDomain(tap.TCK)) +[256] jtagCtrl <> plugin.io.bus.fromJtagInstructionCtrl(ClockDomain(tap.TCK),0) ``` Changing the above lines, removes the Murax SoC’s JTAG ports as pins of the FPGA and inserts the BSCANE2 Xilinx Debug IP to which the JTAG signals are now connected. @@ -84,7 +84,7 @@ in e.g. the path: `project_name.srcs\sources_1\imports\Downloads` [44] wire tesic_tdo; [45] reg soc_tck,soc_tms,soc_tdi; [46] wire soc_tdo; -[47] +[47] [48] always @(*) begin [49] {soc_tck, soc_tms, soc_tdi } = {tck,tms,tdi}; [50] tdo = soc_tdo; diff --git a/src/main/scala/vexriscv/demo/VexRiscvAhbLite3.scala b/src/main/scala/vexriscv/demo/VexRiscvAhbLite3.scala index f817fb3b..8a49a27c 100644 --- a/src/main/scala/vexriscv/demo/VexRiscvAhbLite3.scala +++ b/src/main/scala/vexriscv/demo/VexRiscvAhbLite3.scala @@ -168,7 +168,7 @@ object VexRiscvAhbLite3{ // // On Artix FPGA jtag : // val jtagCtrl = JtagTapInstructionCtrl() // val tap = jtagCtrl.fromXilinxBscane2(userId = 1) -// jtagCtrl <> plugin.io.bus.fromJtagInstructionCtrl(ClockDomain(tap.TCK)) +// jtagCtrl <> plugin.io.bus.fromJtagInstructionCtrl(ClockDomain(tap.TCK),0) } case _ => } From 281818af9c04517baa7c6dffe62e229bfa7e036a Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 31 Oct 2023 11:05:00 +0100 Subject: [PATCH 907/951] #373 Add GenFullWithTcm demo --- README.md | 1 + .../scala/vexriscv/demo/GenFullWithTcm.scala | 100 ++++++++++++++++++ .../vexriscv/plugin/DBusCachedPlugin.scala | 9 ++ 3 files changed, 110 insertions(+) create mode 100644 src/main/scala/vexriscv/demo/GenFullWithTcm.scala diff --git a/README.md b/README.md index 28bace2e..30c814ed 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,7 @@ This repository hosts a RISC-V implementation written in SpinalHDL. Here are som - Linux compatible (SoC : https://github.com/enjoy-digital/linux-on-litex-vexriscv) - Zephyr compatible - [FreeRTOS port](https://github.com/Dolu1990/FreeRTOS-RISCV) +- Support tightly coupled memory on I$ D$ (see GenFullWithTcm) The hardware description of this CPU is done by using a very software oriented approach (without any overhead in the generated hardware). Here is a list of software concepts used: diff --git a/src/main/scala/vexriscv/demo/GenFullWithTcm.scala b/src/main/scala/vexriscv/demo/GenFullWithTcm.scala new file mode 100644 index 00000000..0b7618e1 --- /dev/null +++ b/src/main/scala/vexriscv/demo/GenFullWithTcm.scala @@ -0,0 +1,100 @@ +package vexriscv.demo + +import spinal.core._ +import vexriscv.ip.{DataCacheConfig, InstructionCacheConfig} +import vexriscv.plugin._ +import vexriscv.{VexRiscv, VexRiscvConfig, plugin} + +/** + * Both iBusTc and dBusTc assume + * - 1 cycle read latency + * - read_data stay on the port until the next access + * - writes should only occure when dBusTc_enable && dBusTc_write_enable + * - address is in byte, don't care about the 2 LSB + */ +object GenFullWithTcm extends App{ + def config = VexRiscvConfig( + plugins = List( + new IBusCachedPlugin( + prediction = DYNAMIC, + config = InstructionCacheConfig( + cacheSize = 4096, + bytePerLine =32, + wayCount = 1, + addressWidth = 32, + cpuDataWidth = 32, + memDataWidth = 32, + catchIllegalAccess = true, + catchAccessFault = true, + asyncTagMemory = false, + twoCycleRam = true, + twoCycleCache = true + ), + memoryTranslatorPortConfig = MmuPortConfig( + portTlbSize = 4 + ) + ).newTightlyCoupledPort( + TightlyCoupledPortParameter("iBusTc", a => a(31 downto 28) === 0x2) + ), + new DBusCachedPlugin( + config = new DataCacheConfig( + cacheSize = 4096, + bytePerLine = 32, + wayCount = 1, + addressWidth = 32, + cpuDataWidth = 32, + memDataWidth = 32, + catchAccessError = true, + catchIllegal = true, + catchUnaligned = true + ), + memoryTranslatorPortConfig = MmuPortConfig( + portTlbSize = 6 + ) + ).newTightlyCoupledPort( + TightlyCoupledDataPortParameter("dBusTc", a => a(31 downto 28) === 0x3) + ), + new MmuPlugin( + virtualRange = _(31 downto 28) === 0xC, + ioRange = _(31 downto 28) === 0xF + ), + new DecoderSimplePlugin( + catchIllegalInstruction = true + ), + new RegFilePlugin( + regFileReadyKind = plugin.SYNC, + zeroBoot = false + ), + new IntAluPlugin, + new SrcPlugin( + separatedAddSub = false, + executeInsertion = true + ), + new FullBarrelShifterPlugin, + new HazardSimplePlugin( + bypassExecute = true, + bypassMemory = true, + bypassWriteBack = true, + bypassWriteBackBuffer = true, + pessimisticUseSrc = false, + pessimisticWriteRegFile = false, + pessimisticAddressMatch = false + ), + new MulPlugin, + new DivPlugin, + new CsrPlugin(CsrPluginConfig.small(0x80000020l)), + new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))), + new BranchPlugin( + earlyBranch = false, + catchAddressMisaligned = true + ), + new YamlPlugin("cpu0.yaml") + ) + ) + + def cpu() = new VexRiscv( + config + ) + + SpinalVerilog(cpu()) +} diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index 593eb911..e32ff96d 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -87,6 +87,12 @@ class DBusCachedPlugin(val config : DataCacheConfig, val tightlyCoupledPorts = ArrayBuffer[TightlyCoupledDataPort]() def tightlyGen = tightlyCoupledPorts.nonEmpty + def newTightlyCoupledPort(p: TightlyCoupledDataPortParameter) = { + val port = TightlyCoupledDataPort(p, null) + tightlyCoupledPorts += port + this + } + def newTightlyCoupledPort(mapping : UInt => Bool) = { val port = TightlyCoupledDataPort(TightlyCoupledDataPortParameter(null, mapping), TightlyCoupledDataBus()) tightlyCoupledPorts += port @@ -173,6 +179,9 @@ class DBusCachedPlugin(val config : DataCacheConfig, import Riscv._ import pipeline.config._ + + tightlyCoupledPorts.filter(_.bus == null).foreach(p => p.bus = master(TightlyCoupledDataBus()).setName(p.p.name)) + dBus = master(DataCacheMemBus(this.config)).setName("dBus") val decoderService = pipeline.service(classOf[DecoderService]) From a2a60bf6bc1400f3df23368caa43c98188308b00 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 31 Oct 2023 11:05:00 +0100 Subject: [PATCH 908/951] #373 Add GenFullWithTcm demo --- README.md | 1 + .../scala/vexriscv/demo/GenFullWithTcm.scala | 100 ++++++++++++++++++ .../vexriscv/plugin/DBusCachedPlugin.scala | 9 ++ 3 files changed, 110 insertions(+) create mode 100644 src/main/scala/vexriscv/demo/GenFullWithTcm.scala diff --git a/README.md b/README.md index c7578c6f..c11922f3 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,7 @@ This repository hosts a RISC-V implementation written in SpinalHDL. Here are som - Linux compatible (SoC : https://github.com/enjoy-digital/linux-on-litex-vexriscv) - Zephyr compatible - [FreeRTOS port](https://github.com/Dolu1990/FreeRTOS-RISCV) +- Support tightly coupled memory on I$ D$ (see GenFullWithTcm) The hardware description of this CPU is done by using a very software oriented approach (without any overhead in the generated hardware). Here is a list of software concepts used: diff --git a/src/main/scala/vexriscv/demo/GenFullWithTcm.scala b/src/main/scala/vexriscv/demo/GenFullWithTcm.scala new file mode 100644 index 00000000..0b7618e1 --- /dev/null +++ b/src/main/scala/vexriscv/demo/GenFullWithTcm.scala @@ -0,0 +1,100 @@ +package vexriscv.demo + +import spinal.core._ +import vexriscv.ip.{DataCacheConfig, InstructionCacheConfig} +import vexriscv.plugin._ +import vexriscv.{VexRiscv, VexRiscvConfig, plugin} + +/** + * Both iBusTc and dBusTc assume + * - 1 cycle read latency + * - read_data stay on the port until the next access + * - writes should only occure when dBusTc_enable && dBusTc_write_enable + * - address is in byte, don't care about the 2 LSB + */ +object GenFullWithTcm extends App{ + def config = VexRiscvConfig( + plugins = List( + new IBusCachedPlugin( + prediction = DYNAMIC, + config = InstructionCacheConfig( + cacheSize = 4096, + bytePerLine =32, + wayCount = 1, + addressWidth = 32, + cpuDataWidth = 32, + memDataWidth = 32, + catchIllegalAccess = true, + catchAccessFault = true, + asyncTagMemory = false, + twoCycleRam = true, + twoCycleCache = true + ), + memoryTranslatorPortConfig = MmuPortConfig( + portTlbSize = 4 + ) + ).newTightlyCoupledPort( + TightlyCoupledPortParameter("iBusTc", a => a(31 downto 28) === 0x2) + ), + new DBusCachedPlugin( + config = new DataCacheConfig( + cacheSize = 4096, + bytePerLine = 32, + wayCount = 1, + addressWidth = 32, + cpuDataWidth = 32, + memDataWidth = 32, + catchAccessError = true, + catchIllegal = true, + catchUnaligned = true + ), + memoryTranslatorPortConfig = MmuPortConfig( + portTlbSize = 6 + ) + ).newTightlyCoupledPort( + TightlyCoupledDataPortParameter("dBusTc", a => a(31 downto 28) === 0x3) + ), + new MmuPlugin( + virtualRange = _(31 downto 28) === 0xC, + ioRange = _(31 downto 28) === 0xF + ), + new DecoderSimplePlugin( + catchIllegalInstruction = true + ), + new RegFilePlugin( + regFileReadyKind = plugin.SYNC, + zeroBoot = false + ), + new IntAluPlugin, + new SrcPlugin( + separatedAddSub = false, + executeInsertion = true + ), + new FullBarrelShifterPlugin, + new HazardSimplePlugin( + bypassExecute = true, + bypassMemory = true, + bypassWriteBack = true, + bypassWriteBackBuffer = true, + pessimisticUseSrc = false, + pessimisticWriteRegFile = false, + pessimisticAddressMatch = false + ), + new MulPlugin, + new DivPlugin, + new CsrPlugin(CsrPluginConfig.small(0x80000020l)), + new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))), + new BranchPlugin( + earlyBranch = false, + catchAddressMisaligned = true + ), + new YamlPlugin("cpu0.yaml") + ) + ) + + def cpu() = new VexRiscv( + config + ) + + SpinalVerilog(cpu()) +} diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index 593eb911..e32ff96d 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -87,6 +87,12 @@ class DBusCachedPlugin(val config : DataCacheConfig, val tightlyCoupledPorts = ArrayBuffer[TightlyCoupledDataPort]() def tightlyGen = tightlyCoupledPorts.nonEmpty + def newTightlyCoupledPort(p: TightlyCoupledDataPortParameter) = { + val port = TightlyCoupledDataPort(p, null) + tightlyCoupledPorts += port + this + } + def newTightlyCoupledPort(mapping : UInt => Bool) = { val port = TightlyCoupledDataPort(TightlyCoupledDataPortParameter(null, mapping), TightlyCoupledDataBus()) tightlyCoupledPorts += port @@ -173,6 +179,9 @@ class DBusCachedPlugin(val config : DataCacheConfig, import Riscv._ import pipeline.config._ + + tightlyCoupledPorts.filter(_.bus == null).foreach(p => p.bus = master(TightlyCoupledDataBus()).setName(p.p.name)) + dBus = master(DataCacheMemBus(this.config)).setName("dBus") val decoderService = pipeline.service(classOf[DecoderService]) From 0f17b395bd3d86772f22530ee8930c45a45d29f5 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 2 Nov 2023 11:59:33 +0100 Subject: [PATCH 909/951] IBusDBusCachedTightlyCoupledRam add missing write mask --- src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index e32ff96d..6f85652a 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -680,7 +680,8 @@ class IBusDBusCachedTightlyCoupledRam(mapping : SizeMapping, withIBus : Boolean address = (dbus.address >> 2).resized, data = dbus.write_data, enable = dbus.enable, - write = dbus.write_enable + write = dbus.write_enable, + mask = dbus.write_mask ) } val i = withIBus generate new Area { From beeec94344bd0caede9b0d91aee3e198d8b6f5b3 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 2 Nov 2023 12:31:05 +0100 Subject: [PATCH 910/951] Add GenFullWithTcmIntegrated example --- README.md | 2 +- .../demo/GenFullWithTcmIntegrated.scala | 97 +++++++++++++++++++ 2 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 src/main/scala/vexriscv/demo/GenFullWithTcmIntegrated.scala diff --git a/README.md b/README.md index 30c814ed..165341fc 100644 --- a/README.md +++ b/README.md @@ -72,7 +72,7 @@ This repository hosts a RISC-V implementation written in SpinalHDL. Here are som - Linux compatible (SoC : https://github.com/enjoy-digital/linux-on-litex-vexriscv) - Zephyr compatible - [FreeRTOS port](https://github.com/Dolu1990/FreeRTOS-RISCV) -- Support tightly coupled memory on I$ D$ (see GenFullWithTcm) +- Support tightly coupled memory on I$ D$ (see GenFullWithTcm / GenFullWithTcmIntegrated) The hardware description of this CPU is done by using a very software oriented approach (without any overhead in the generated hardware). Here is a list of software concepts used: diff --git a/src/main/scala/vexriscv/demo/GenFullWithTcmIntegrated.scala b/src/main/scala/vexriscv/demo/GenFullWithTcmIntegrated.scala new file mode 100644 index 00000000..4e68b5f6 --- /dev/null +++ b/src/main/scala/vexriscv/demo/GenFullWithTcmIntegrated.scala @@ -0,0 +1,97 @@ +package vexriscv.demo + +import spinal.core._ +import spinal.lib.bus.misc.SizeMapping +import vexriscv.ip.{DataCacheConfig, InstructionCacheConfig} +import vexriscv.plugin._ +import vexriscv.{VexRiscv, VexRiscvConfig, plugin} + +/** + * this example integrate the tightly coupled memory directly inside VexRiscv + * by using the IBusDBusCachedTightlyCoupledRam plugin + */ +object GenFullWithTcmIntegrated extends App{ + def config = VexRiscvConfig( + plugins = List( + new IBusDBusCachedTightlyCoupledRam( + mapping = SizeMapping(0x20000000, 0x1000) + ), + new IBusCachedPlugin( + prediction = DYNAMIC, + config = InstructionCacheConfig( + cacheSize = 4096, + bytePerLine =32, + wayCount = 1, + addressWidth = 32, + cpuDataWidth = 32, + memDataWidth = 32, + catchIllegalAccess = true, + catchAccessFault = true, + asyncTagMemory = false, + twoCycleRam = true, + twoCycleCache = true + ), + memoryTranslatorPortConfig = MmuPortConfig( + portTlbSize = 4 + ) + ), + new DBusCachedPlugin( + config = new DataCacheConfig( + cacheSize = 4096, + bytePerLine = 32, + wayCount = 1, + addressWidth = 32, + cpuDataWidth = 32, + memDataWidth = 32, + catchAccessError = true, + catchIllegal = true, + catchUnaligned = true + ), + memoryTranslatorPortConfig = MmuPortConfig( + portTlbSize = 6 + ) + ), + new MmuPlugin( + virtualRange = _(31 downto 28) === 0xC, + ioRange = _(31 downto 28) === 0xF + ), + new DecoderSimplePlugin( + catchIllegalInstruction = true + ), + new RegFilePlugin( + regFileReadyKind = plugin.SYNC, + zeroBoot = false + ), + new IntAluPlugin, + new SrcPlugin( + separatedAddSub = false, + executeInsertion = true + ), + new FullBarrelShifterPlugin, + new HazardSimplePlugin( + bypassExecute = true, + bypassMemory = true, + bypassWriteBack = true, + bypassWriteBackBuffer = true, + pessimisticUseSrc = false, + pessimisticWriteRegFile = false, + pessimisticAddressMatch = false + ), + new MulPlugin, + new DivPlugin, + new CsrPlugin(CsrPluginConfig.small(0x80000020l)), + new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))), + new BranchPlugin( + earlyBranch = false, + catchAddressMisaligned = true + ), + new YamlPlugin("cpu0.yaml") + ) + ) + + def cpu() = new VexRiscv( + config + ) + + SpinalVerilog(cpu()) +} From 11cc9b1cf277df10886d8a6cae46e4a073a99154 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 2 Nov 2023 12:31:05 +0100 Subject: [PATCH 911/951] Add GenFullWithTcmIntegrated example --- README.md | 2 +- .../demo/GenFullWithTcmIntegrated.scala | 97 +++++++++++++++++++ 2 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 src/main/scala/vexriscv/demo/GenFullWithTcmIntegrated.scala diff --git a/README.md b/README.md index 30c814ed..165341fc 100644 --- a/README.md +++ b/README.md @@ -72,7 +72,7 @@ This repository hosts a RISC-V implementation written in SpinalHDL. Here are som - Linux compatible (SoC : https://github.com/enjoy-digital/linux-on-litex-vexriscv) - Zephyr compatible - [FreeRTOS port](https://github.com/Dolu1990/FreeRTOS-RISCV) -- Support tightly coupled memory on I$ D$ (see GenFullWithTcm) +- Support tightly coupled memory on I$ D$ (see GenFullWithTcm / GenFullWithTcmIntegrated) The hardware description of this CPU is done by using a very software oriented approach (without any overhead in the generated hardware). Here is a list of software concepts used: diff --git a/src/main/scala/vexriscv/demo/GenFullWithTcmIntegrated.scala b/src/main/scala/vexriscv/demo/GenFullWithTcmIntegrated.scala new file mode 100644 index 00000000..4e68b5f6 --- /dev/null +++ b/src/main/scala/vexriscv/demo/GenFullWithTcmIntegrated.scala @@ -0,0 +1,97 @@ +package vexriscv.demo + +import spinal.core._ +import spinal.lib.bus.misc.SizeMapping +import vexriscv.ip.{DataCacheConfig, InstructionCacheConfig} +import vexriscv.plugin._ +import vexriscv.{VexRiscv, VexRiscvConfig, plugin} + +/** + * this example integrate the tightly coupled memory directly inside VexRiscv + * by using the IBusDBusCachedTightlyCoupledRam plugin + */ +object GenFullWithTcmIntegrated extends App{ + def config = VexRiscvConfig( + plugins = List( + new IBusDBusCachedTightlyCoupledRam( + mapping = SizeMapping(0x20000000, 0x1000) + ), + new IBusCachedPlugin( + prediction = DYNAMIC, + config = InstructionCacheConfig( + cacheSize = 4096, + bytePerLine =32, + wayCount = 1, + addressWidth = 32, + cpuDataWidth = 32, + memDataWidth = 32, + catchIllegalAccess = true, + catchAccessFault = true, + asyncTagMemory = false, + twoCycleRam = true, + twoCycleCache = true + ), + memoryTranslatorPortConfig = MmuPortConfig( + portTlbSize = 4 + ) + ), + new DBusCachedPlugin( + config = new DataCacheConfig( + cacheSize = 4096, + bytePerLine = 32, + wayCount = 1, + addressWidth = 32, + cpuDataWidth = 32, + memDataWidth = 32, + catchAccessError = true, + catchIllegal = true, + catchUnaligned = true + ), + memoryTranslatorPortConfig = MmuPortConfig( + portTlbSize = 6 + ) + ), + new MmuPlugin( + virtualRange = _(31 downto 28) === 0xC, + ioRange = _(31 downto 28) === 0xF + ), + new DecoderSimplePlugin( + catchIllegalInstruction = true + ), + new RegFilePlugin( + regFileReadyKind = plugin.SYNC, + zeroBoot = false + ), + new IntAluPlugin, + new SrcPlugin( + separatedAddSub = false, + executeInsertion = true + ), + new FullBarrelShifterPlugin, + new HazardSimplePlugin( + bypassExecute = true, + bypassMemory = true, + bypassWriteBack = true, + bypassWriteBackBuffer = true, + pessimisticUseSrc = false, + pessimisticWriteRegFile = false, + pessimisticAddressMatch = false + ), + new MulPlugin, + new DivPlugin, + new CsrPlugin(CsrPluginConfig.small(0x80000020l)), + new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))), + new BranchPlugin( + earlyBranch = false, + catchAddressMisaligned = true + ), + new YamlPlugin("cpu0.yaml") + ) + ) + + def cpu() = new VexRiscv( + config + ) + + SpinalVerilog(cpu()) +} From e6998d1cb38518ab852b962fc3594ebd102b06b6 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 3 Nov 2023 10:46:49 +0100 Subject: [PATCH 912/951] Add GenFullWithOfficialRiscvDebug --- README.md | 2 + src/main/scala/vexriscv/TestsWorkspace.scala | 22 +-- .../demo/GenFullWithOfficialRiscvDebug.scala | 130 ++++++++++++++++++ 3 files changed, 143 insertions(+), 11 deletions(-) create mode 100644 src/main/scala/vexriscv/demo/GenFullWithOfficialRiscvDebug.scala diff --git a/README.md b/README.md index 165341fc..5de153eb 100644 --- a/README.md +++ b/README.md @@ -1331,6 +1331,8 @@ init halt ``` +A full example can be found in GenFullWithOfficialRiscvDebug.scala + #### YamlPlugin This plugin offers a service to other plugins to generate a useful Yaml file describing the CPU configuration. It contains, for instance, the sequence of instructions required diff --git a/src/main/scala/vexriscv/TestsWorkspace.scala b/src/main/scala/vexriscv/TestsWorkspace.scala index df15a80f..39389214 100644 --- a/src/main/scala/vexriscv/TestsWorkspace.scala +++ b/src/main/scala/vexriscv/TestsWorkspace.scala @@ -144,19 +144,19 @@ object TestsWorkspace { withDouble = true, externalFpu = false, simHalt = true, - privilegedDebug = false + privilegedDebug = true ) -// config.plugins += new EmbeddedRiscvJtag( -// p = DebugTransportModuleParameter( -// addressWidth = 7, -// version = 1, -// idle = 7 -// ), -// debugCd = ClockDomain.current.copy(reset = Bool().setName("debugReset")), -// withTunneling = false, -// withTap = true -// ) + config.plugins += new EmbeddedRiscvJtag( + p = DebugTransportModuleParameter( + addressWidth = 7, + version = 1, + idle = 7 + ), + debugCd = ClockDomain.current.copy(reset = Bool().setName("debugReset")), + withTunneling = false, + withTap = true + ) // l.foreach{ // case p : EmbeddedRiscvJtag => p.debugCd.load(ClockDomain.current.copy(reset = Bool().setName("debug_reset"))) diff --git a/src/main/scala/vexriscv/demo/GenFullWithOfficialRiscvDebug.scala b/src/main/scala/vexriscv/demo/GenFullWithOfficialRiscvDebug.scala new file mode 100644 index 00000000..663f907b --- /dev/null +++ b/src/main/scala/vexriscv/demo/GenFullWithOfficialRiscvDebug.scala @@ -0,0 +1,130 @@ +package vexriscv.demo + +import spinal.core._ +import spinal.lib.cpu.riscv.debug.DebugTransportModuleParameter +import vexriscv.ip.{DataCacheConfig, InstructionCacheConfig} +import vexriscv.plugin._ +import vexriscv.{VexRiscv, VexRiscvConfig, plugin} + +/** + * This an example of VexRiscv configuration which can run the official RISC-V debug. + * You can for instance : + * - generate this VexRiscv + * - cd src/test/cpp/regression + * - make IBUS=CACHED IBUS_DATA_WIDTH=64 COMPRESSED=no DBUS=CACHED DBUS_LOAD_DATA_WIDTH=64 DBUS_STORE_DATA_WIDTH=64 LRSC=yes AMO=yes DBUS_EXCLUSIVE=yes DBUS_INVALIDATE=yes MUL=yes DIV=yes SUPERVISOR=yes CSR=yes RVF=yes RVD=yes DEBUG_PLUGIN=RISCV WITH_RISCV_REF=no DEBUG_PLUGIN_EXTERNAL=yes DEBUG_PLUGIN=no VEXRISCV_JTAG=yes + * + * This will run a simulation of the CPU which wait for a tcp-jtag connection from openocd. + * That con connection can be done via openocd : + * - src/openocd -f config.tcl + * + * Were config.tcl is the following : + * + * ############################################## + * interface jtag_tcp + * adapter speed 5000 + * + * set _CHIPNAME riscv + * jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x10002FFF + * + * set _TARGETNAME $_CHIPNAME.cpu + * + * target create $_TARGETNAME.0 riscv -chain-position $_TARGETNAME + * + * init + * halt + * + * echo "Ready for Remote Connections" + * ############################################## + */ + +object GenFullWithOfficialRiscvDebug extends App{ + def config = VexRiscvConfig( + plugins = List( + new IBusCachedPlugin( + prediction = DYNAMIC, + config = InstructionCacheConfig( + cacheSize = 4096, + bytePerLine =32, + wayCount = 1, + addressWidth = 32, + cpuDataWidth = 32, + memDataWidth = 32, + catchIllegalAccess = true, + catchAccessFault = true, + asyncTagMemory = false, + twoCycleRam = true, + twoCycleCache = true + ), + memoryTranslatorPortConfig = MmuPortConfig( + portTlbSize = 4 + ) + ), + new DBusCachedPlugin( + config = new DataCacheConfig( + cacheSize = 4096, + bytePerLine = 32, + wayCount = 1, + addressWidth = 32, + cpuDataWidth = 32, + memDataWidth = 32, + catchAccessError = true, + catchIllegal = true, + catchUnaligned = true + ), + memoryTranslatorPortConfig = MmuPortConfig( + portTlbSize = 6 + ) + ), + new MmuPlugin( + virtualRange = _(31 downto 28) === 0xC, + ioRange = _(31 downto 28) === 0xF + ), + new DecoderSimplePlugin( + catchIllegalInstruction = true + ), + new RegFilePlugin( + regFileReadyKind = plugin.SYNC, + zeroBoot = false + ), + new IntAluPlugin, + new SrcPlugin( + separatedAddSub = false, + executeInsertion = true + ), + new FullBarrelShifterPlugin, + new HazardSimplePlugin( + bypassExecute = true, + bypassMemory = true, + bypassWriteBack = true, + bypassWriteBackBuffer = true, + pessimisticUseSrc = false, + pessimisticWriteRegFile = false, + pessimisticAddressMatch = false + ), + new MulPlugin, + new DivPlugin, + new CsrPlugin(CsrPluginConfig.small(0x80000020l).copy(withPrivilegedDebug = true)), + new EmbeddedRiscvJtag( + p = DebugTransportModuleParameter( + addressWidth = 7, + version = 1, + idle = 7 + ), + debugCd = ClockDomain.current.copy(reset = Bool().setName("debugReset")), + withTunneling = false, + withTap = true + ), + new BranchPlugin( + earlyBranch = false, + catchAddressMisaligned = true + ), + new YamlPlugin("cpu0.yaml") + ) + ) + + def cpu() = new VexRiscv(config){ + println(config.getRegressionArgs().mkString(" ")) + } + + SpinalVerilog(cpu()) +} From 63f1025a15a808dc20827738674c71ec73d2fa50 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 3 Nov 2023 11:41:02 +0100 Subject: [PATCH 913/951] Fix demo --- .../scala/vexriscv/demo/GenFullWithOfficialRiscvDebug.scala | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/main/scala/vexriscv/demo/GenFullWithOfficialRiscvDebug.scala b/src/main/scala/vexriscv/demo/GenFullWithOfficialRiscvDebug.scala index 663f907b..03b5debd 100644 --- a/src/main/scala/vexriscv/demo/GenFullWithOfficialRiscvDebug.scala +++ b/src/main/scala/vexriscv/demo/GenFullWithOfficialRiscvDebug.scala @@ -9,7 +9,7 @@ import vexriscv.{VexRiscv, VexRiscvConfig, plugin} /** * This an example of VexRiscv configuration which can run the official RISC-V debug. * You can for instance : - * - generate this VexRiscv + * - sbt "runMain vexriscv.demo.GenFullWithOfficialRiscvDebug" * - cd src/test/cpp/regression * - make IBUS=CACHED IBUS_DATA_WIDTH=64 COMPRESSED=no DBUS=CACHED DBUS_LOAD_DATA_WIDTH=64 DBUS_STORE_DATA_WIDTH=64 LRSC=yes AMO=yes DBUS_EXCLUSIVE=yes DBUS_INVALIDATE=yes MUL=yes DIV=yes SUPERVISOR=yes CSR=yes RVF=yes RVD=yes DEBUG_PLUGIN=RISCV WITH_RISCV_REF=no DEBUG_PLUGIN_EXTERNAL=yes DEBUG_PLUGIN=no VEXRISCV_JTAG=yes * @@ -122,9 +122,7 @@ object GenFullWithOfficialRiscvDebug extends App{ ) ) - def cpu() = new VexRiscv(config){ - println(config.getRegressionArgs().mkString(" ")) - } + def cpu() = new VexRiscv(config) SpinalVerilog(cpu()) } From f1d64eccc85b8fb0dc9c0302fe5bed6c0a76f3ad Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 3 Nov 2023 11:41:02 +0100 Subject: [PATCH 914/951] Fix demo --- .../scala/vexriscv/demo/GenFullWithOfficialRiscvDebug.scala | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/main/scala/vexriscv/demo/GenFullWithOfficialRiscvDebug.scala b/src/main/scala/vexriscv/demo/GenFullWithOfficialRiscvDebug.scala index 663f907b..03b5debd 100644 --- a/src/main/scala/vexriscv/demo/GenFullWithOfficialRiscvDebug.scala +++ b/src/main/scala/vexriscv/demo/GenFullWithOfficialRiscvDebug.scala @@ -9,7 +9,7 @@ import vexriscv.{VexRiscv, VexRiscvConfig, plugin} /** * This an example of VexRiscv configuration which can run the official RISC-V debug. * You can for instance : - * - generate this VexRiscv + * - sbt "runMain vexriscv.demo.GenFullWithOfficialRiscvDebug" * - cd src/test/cpp/regression * - make IBUS=CACHED IBUS_DATA_WIDTH=64 COMPRESSED=no DBUS=CACHED DBUS_LOAD_DATA_WIDTH=64 DBUS_STORE_DATA_WIDTH=64 LRSC=yes AMO=yes DBUS_EXCLUSIVE=yes DBUS_INVALIDATE=yes MUL=yes DIV=yes SUPERVISOR=yes CSR=yes RVF=yes RVD=yes DEBUG_PLUGIN=RISCV WITH_RISCV_REF=no DEBUG_PLUGIN_EXTERNAL=yes DEBUG_PLUGIN=no VEXRISCV_JTAG=yes * @@ -122,9 +122,7 @@ object GenFullWithOfficialRiscvDebug extends App{ ) ) - def cpu() = new VexRiscv(config){ - println(config.getRegressionArgs().mkString(" ")) - } + def cpu() = new VexRiscv(config) SpinalVerilog(cpu()) } From e71b1be8a25fed1f0f792e018f331a2e3eef4dec Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 3 Nov 2023 11:43:59 +0100 Subject: [PATCH 915/951] demo fix --- .../scala/vexriscv/demo/GenFullWithOfficialRiscvDebug.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/demo/GenFullWithOfficialRiscvDebug.scala b/src/main/scala/vexriscv/demo/GenFullWithOfficialRiscvDebug.scala index 03b5debd..3e4e45a9 100644 --- a/src/main/scala/vexriscv/demo/GenFullWithOfficialRiscvDebug.scala +++ b/src/main/scala/vexriscv/demo/GenFullWithOfficialRiscvDebug.scala @@ -11,7 +11,7 @@ import vexriscv.{VexRiscv, VexRiscvConfig, plugin} * You can for instance : * - sbt "runMain vexriscv.demo.GenFullWithOfficialRiscvDebug" * - cd src/test/cpp/regression - * - make IBUS=CACHED IBUS_DATA_WIDTH=64 COMPRESSED=no DBUS=CACHED DBUS_LOAD_DATA_WIDTH=64 DBUS_STORE_DATA_WIDTH=64 LRSC=yes AMO=yes DBUS_EXCLUSIVE=yes DBUS_INVALIDATE=yes MUL=yes DIV=yes SUPERVISOR=yes CSR=yes RVF=yes RVD=yes DEBUG_PLUGIN=RISCV WITH_RISCV_REF=no DEBUG_PLUGIN_EXTERNAL=yes DEBUG_PLUGIN=no VEXRISCV_JTAG=yes + * - make IBUS=CACHED IBUS_DATA_WIDTH=32 COMPRESSED=no DBUS=CACHED DBUS_LOAD_DATA_WIDTH=32 DBUS_STORE_DATA_WIDTH=32 MUL=yes DIV=yes SUPERVISOR=no CSR=yes DEBUG_PLUGIN=RISCV WITH_RISCV_REF=no DEBUG_PLUGIN_EXTERNAL=yes DEBUG_PLUGIN=no VEXRISCV_JTAG=yes * * This will run a simulation of the CPU which wait for a tcp-jtag connection from openocd. * That con connection can be done via openocd : From 9baba6d11fd621302592a8a87892cb3c6520e32b Mon Sep 17 00:00:00 2001 From: Leon Schuermann Date: Fri, 3 Nov 2023 09:11:42 -0400 Subject: [PATCH 916/951] PmpPluginOld: fix NAPOT address calculation overflow issue Because pmpaddrX registers are defined to encode the address' [XLEN + 2 downto 2] bits, the length of a NAPOT region is defined through the most significant 0 bit in a pmpaddrX register (which in the case of ~0 is the 33rd non-existant "virtual" bit), and the VexRiscv PmpOld plugin represents the addresses covered by a region as [start; end) (bounded inclusively below and exclusively above), the start and end address registers need to be XLEN + 4 bit wide to avoid overflows. If such an overflow occurs, it may be that the region does not cover any address, an issue uncovered in the Tock LiteX + VexRiscv CI during a PMP infrastructure redesign in the Tock OS [1]. This commit has been tested on Tock's redesigned PMP infrastructure, and by inspecting all of the intermediate signals in the PMP address calculation through a Verilator trace file. It works correctly for various NAPOT and TOR addresses, and I made sure that the edge cases of pmpaddrX = [0x00000000, 0x7FFFFFFF, 0xFFFFFFFF] are all handled. [1]: https://github.com/tock/tock/pull/3597 --- .../scala/vexriscv/plugin/PmpPluginOld.scala | 35 ++++++++++++++++--- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/PmpPluginOld.scala b/src/main/scala/vexriscv/plugin/PmpPluginOld.scala index 0426902b..2f0f6d16 100644 --- a/src/main/scala/vexriscv/plugin/PmpPluginOld.scala +++ b/src/main/scala/vexriscv/plugin/PmpPluginOld.scala @@ -98,7 +98,29 @@ case class PmpRegister(previous : PmpRegister) extends Area { // Computed PMP region bounds val region = new Area { val valid, locked = Bool - val start, end = UInt(32 bits) + + // The calculated start & end addresses can overflow xlen by 4 bit: + // + // - 2 bit, as the pmpaddrX registers are defined as to encode + // [XLEN + 2 downto 2] addresses. + // + // - 2 bit, as for NAPOT the most significant 0 bit encodes the region + // length, with this bit included in the range! + // + // This means that (for xlen == 32 bit) + // + // pmpcfg(X / 4)(X % 4) = NAPOT + // pmpaddrX = 0xFFFFFFFF + // + // will expand to + // + // start (inclusive): 0x000000000 << 2 + // end (exclusive): 0x200000000 << 2 + // + // hence requiring xlen + 2 + 2 bit to represent the exclusive end + // address. This could be optimized by using a saturating add, or making the + // end address exclusive. + val start, end = UInt(36 bits) } when(~state.l) { @@ -114,9 +136,12 @@ case class PmpRegister(previous : PmpRegister) extends Area { } } - val shifted = state.addr |<< 2 - val mask = state.addr & ~(state.addr + 1) - val masked = (state.addr & ~mask) |<< 2 + // Extend state.addr to 36 bits, to avoid these computations overflowing (as + // explained above): + val extended_addr = (B"00" ## state.addr.asBits).asUInt + val shifted = extended_addr << 2 + val mask = extended_addr ^ (extended_addr + 1) + val masked = (extended_addr & ~mask) << 2 // PMP changes take effect two clock cycles after the initial CSR write (i.e., // settings propagate from csr -> state -> region). @@ -135,7 +160,7 @@ case class PmpRegister(previous : PmpRegister) extends Area { } is(NAPOT) { region.start := masked - region.end := masked + ((mask + 1) |<< 3) + region.end := masked + ((mask + 1) << 2) } default { region.start := 0 From 00534dc4a84ef902e053a24a8fb9d13b84db168c Mon Sep 17 00:00:00 2001 From: Emil Tywoniak Date: Fri, 3 Nov 2023 14:16:05 +0100 Subject: [PATCH 917/951] Add note about Verilator without GDB+OpenOCD --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 5de153eb..58138b40 100644 --- a/README.md +++ b/README.md @@ -259,7 +259,12 @@ Also there is a few environnement variable that you can use to modulate the rand | VEXRISCV_REGRESSION_CONFIG_DEMW_RATE | 0.0-1.0 | Chance to generate a config with writeback stage | | VEXRISCV_REGRESSION_CONFIG_DEM_RATE | 0.0-1.0 | Chance to generate a config with memory stage | +## Basic Verilator simulation + +To run basic simulation with stdout and no tracing, loading a binary directly is supported with the `RUN_HEX` variable of `src/test/cpp/regression/makefile`. This has a significant performance advantage over using GDB over OpenOCD with JTAG over TCP. VCD tracing is supported with the makefile variable `TRACE`. + ## Interactive debug of the simulated CPU via GDB OpenOCD and Verilator + To use this, you just need to use the same command as with running tests, but adding `DEBUG_PLUGIN_EXTERNAL=yes` in the make arguments. This works for the `GenFull` configuration, but not for `GenSmallest`, as this configuration has no debug module. From ec31ed30cf68878931ca19084ee758cfa24feba0 Mon Sep 17 00:00:00 2001 From: Joel Bodenmann Date: Mon, 13 Nov 2023 02:59:29 +0100 Subject: [PATCH 918/951] Fix ambiguous function call to bind() The call to bind() can actually resolve to std::bind() instead of libc's bind(). Ensure that we're definitely calling the correct one. --- src/test/cpp/common/jtag.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/cpp/common/jtag.h b/src/test/cpp/common/jtag.h index 868c7455..cca1ad2e 100644 --- a/src/test/cpp/common/jtag.h +++ b/src/test/cpp/common/jtag.h @@ -82,7 +82,7 @@ public: memset(serverAddr.sin_zero, '\0', sizeof serverAddr.sin_zero); //---- Bind the address struct to the socket ----// - bind(serverSocket, (struct sockaddr *) &serverAddr, sizeof(serverAddr)); + ::bind(serverSocket, (struct sockaddr *) &serverAddr, sizeof(serverAddr)); //---- Listen on the socket, with 5 max connection requests queued ----// listen(serverSocket,1); @@ -174,4 +174,4 @@ public: schedule(tooglePeriod); } -}; \ No newline at end of file +}; From cdd8454349805c61de31df4e6070a71b40b89c90 Mon Sep 17 00:00:00 2001 From: Leon Schuermann Date: Mon, 13 Nov 2023 13:55:10 -0500 Subject: [PATCH 919/951] Rename PmpPlugin -> PmpPluginNapot, PmpPluginOld -> PmpPlugin --- README.md | 7 +- src/main/scala/vexriscv/demo/GenSecure.scala | 1 - .../scala/vexriscv/plugin/PmpPlugin.scala | 368 ++++++++---------- .../vexriscv/plugin/PmpPluginNapot.scala | 307 +++++++++++++++ .../scala/vexriscv/plugin/PmpPluginOld.scala | 269 ------------- .../vexriscv/TestIndividualFeatures.scala | 2 +- 6 files changed, 479 insertions(+), 475 deletions(-) create mode 100644 src/main/scala/vexriscv/plugin/PmpPluginNapot.scala delete mode 100644 src/main/scala/vexriscv/plugin/PmpPluginOld.scala diff --git a/README.md b/README.md index 5de153eb..6d4cc325 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,7 @@ - [StaticMemoryTranslatorPlugin](#staticmemorytranslatorplugin) - [MmuPlugin](#mmuplugin) - [PmpPlugin](#pmpplugin) + - [PmpPluginNapot](#pmppluginnapot) - [DebugPlugin](#debugplugin) - [EmbeddedRiscvJtag](#embeddedRiscvJtag) - [YamlPlugin](#yamlplugin) @@ -1234,7 +1235,11 @@ fully associative TLB cache which is refilled automaticaly via a dbus access sha #### PmpPlugin -This is a physical memory protection (PMP) plugin which conforms to the latest RISC-V privilege specification. PMP is configured by writing two special CSRs: `pmpcfg#` and `pmpaddr#`. The former contains the permissions and addressing modes for four protection regions, and the latter contains the encoded start address for a single region. Since the actual region bounds must be computed from the values written to these registers, writing them takes a few CPU cylces. This delay is necessary in order to centralize all of the decoding logic into a single component. Otherwise, it would have to be duplicated for each region, even though the decoding operation happens only when PMP is reprogrammed (e.g., on some context switches). +This is a physical memory protection (PMP) plugin which conforms to the v1.12 RISC-V privilege specification, without ePMP (`Smepmp`) extension support. PMP is configured by writing two special CSRs: `pmpcfg#` and `pmpaddr#`. The former contains the permissions and addressing modes for four protection regions, and the latter contains the encoded start address for a single region. Since the actual region bounds must be computed from the values written to these registers, writing them takes a few CPU cylces. This delay is necessary in order to centralize all of the decoding logic into a single component. Otherwise, it would have to be duplicated for each region, even though the decoding operation happens only when PMP is reprogrammed (e.g., on some context switches). + +##### PmpPluginNapot + +The `PmpPluginNapot` is a specialized PMP implementation, providing only the `NAPOT` (naturally-aligned poser-of-2 regions) addressing mode. It requires fewer resources and has a less significant timing impact compared to the full `PmpPlugin`. #### DebugPlugin diff --git a/src/main/scala/vexriscv/demo/GenSecure.scala b/src/main/scala/vexriscv/demo/GenSecure.scala index 8b2cd556..2835b444 100644 --- a/src/main/scala/vexriscv/demo/GenSecure.scala +++ b/src/main/scala/vexriscv/demo/GenSecure.scala @@ -41,7 +41,6 @@ object GenSecure extends App { ), new PmpPlugin( regions = 16, - granularity = 32, ioRange = _(31 downto 28) === 0xf ), new DecoderSimplePlugin( diff --git a/src/main/scala/vexriscv/plugin/PmpPlugin.scala b/src/main/scala/vexriscv/plugin/PmpPlugin.scala index 35951e54..c013797d 100644 --- a/src/main/scala/vexriscv/plugin/PmpPlugin.scala +++ b/src/main/scala/vexriscv/plugin/PmpPlugin.scala @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Samuel Lindemer + * Copyright (c) 2020 Samuel Lindemer * * SPDX-License-Identifier: MIT */ @@ -7,10 +7,9 @@ package vexriscv.plugin import vexriscv.{VexRiscv, _} -import vexriscv.plugin.MemoryTranslatorPort.{_} import spinal.core._ import spinal.lib._ -import spinal.lib.fsm._ +import scala.collection.mutable.ArrayBuffer /* Each 32-bit pmpcfg# register contains four 8-bit configuration sections. * These section numbers contain flags which apply to regions defined by the @@ -62,60 +61,130 @@ import spinal.lib.fsm._ * * NA4: This is essentially an edge case of NAPOT where the entire pmpaddr# * register defines a 4-byte wide region. - * - * N.B. THIS IMPLEMENTATION ONLY SUPPORTS NAPOT ADDRESSING. REGIONS ARE NOT - * ORDERED BY PRIORITY. A PERMISSION IS GRANTED TO AN ACCESS IF ANY MATCHING - * PMP REGION HAS THAT PERMISSION ENABLED. */ -trait Pmp { +case class PmpRegister(previous : PmpRegister) extends Area { + def OFF = 0 def TOR = 1 def NA4 = 2 def NAPOT = 3 - def xlen = 32 - def rBit = 0 - def wBit = 1 - def xBit = 2 - def aBits = 4 downto 3 - def lBit = 7 -} - -class PmpSetter(cutoff : Int) extends Component with Pmp { - val io = new Bundle { - val addr = in UInt(xlen bits) - val base, mask = out UInt(xlen - cutoff bits) + val state = new Area { + val r, w, x = Reg(Bool) + val l = RegInit(False) + val a = Reg(UInt(2 bits)) init(0) + val addr = Reg(UInt(32 bits)) } - val ones = io.addr & ~(io.addr + 1) - io.base := io.addr(xlen - 3 downto cutoff - 2) ^ ones(xlen - 3 downto cutoff - 2) - io.mask := ~(ones(xlen - 4 downto cutoff - 2) @@ U"1") + // CSR writes connect to these signals rather than the internal state + // registers. This makes locking and WARL possible. + val csr = new Area { + val r, w, x = Bool + val l = Bool + val a = UInt(2 bits) + val addr = UInt(32 bits) + } + + // Last valid assignment wins; nothing happens if a user-initiated write did + // not occur on this clock cycle. + csr.r := state.r + csr.w := state.w + csr.x := state.x + csr.l := state.l + csr.a := state.a + csr.addr := state.addr + + // Computed PMP region bounds + val region = new Area { + val valid, locked = Bool + + // The calculated start & end addresses can overflow xlen by 4 bit: + // + // - 2 bit, as the pmpaddrX registers are defined as to encode + // [XLEN + 2 downto 2] addresses. + // + // - 2 bit, as for NAPOT the most significant 0 bit encodes the region + // length, with this bit included in the range! + // + // This means that (for xlen == 32 bit) + // + // pmpcfg(X / 4)(X % 4) = NAPOT + // pmpaddrX = 0xFFFFFFFF + // + // will expand to + // + // start (inclusive): 0x000000000 << 2 + // end (exclusive): 0x200000000 << 2 + // + // hence requiring xlen + 2 + 2 bit to represent the exclusive end + // address. This could be optimized by using a saturating add, or making the + // end address exclusive. + val start, end = UInt(36 bits) + } + + when(~state.l) { + state.r := csr.r + state.w := csr.w + state.x := csr.x + state.l := csr.l + state.a := csr.a + state.addr := csr.addr + + if (csr.l == True & csr.a == TOR) { + previous.state.l := True + } + } + + // Extend state.addr to 36 bits, to avoid these computations overflowing (as + // explained above): + val extended_addr = (B"00" ## state.addr.asBits).asUInt + val shifted = extended_addr << 2 + val mask = extended_addr ^ (extended_addr + 1) + val masked = (extended_addr & ~mask) << 2 + + // PMP changes take effect two clock cycles after the initial CSR write (i.e., + // settings propagate from csr -> state -> region). + region.locked := state.l + region.valid := True + + switch(csr.a) { + is(TOR) { + if (previous == null) region.start := 0 + else region.start := previous.region.end + region.end := shifted + } + is(NA4) { + region.start := shifted + region.end := shifted + 4 + } + is(NAPOT) { + region.start := masked + region.end := masked + ((mask + 1) << 2) + } + default { + region.start := 0 + region.end := shifted + region.valid := False + } + } } -case class ProtectedMemoryTranslatorPort(bus : MemoryTranslatorBus) -class PmpPlugin(regions : Int, granularity : Int, ioRange : UInt => Bool) extends Plugin[VexRiscv] with MemoryTranslator with Pmp { - assert(regions % 4 == 0 & regions <= 16) - assert(granularity >= 8) +class PmpPlugin(regions : Int, ioRange : UInt => Bool) extends Plugin[VexRiscv] with MemoryTranslator { + + // Each pmpcfg# CSR configures four regions. + assert((regions % 4) == 0) + + val pmps = ArrayBuffer[PmpRegister]() + val portsInfo = ArrayBuffer[ProtectedMemoryTranslatorPort]() - var setter : PmpSetter = null - var dPort, iPort : ProtectedMemoryTranslatorPort = null - val cutoff = log2Up(granularity) - 1 - override def newTranslationPort(priority : Int, args : Any): MemoryTranslatorBus = { val port = ProtectedMemoryTranslatorPort(MemoryTranslatorBus(new MemoryTranslatorBusParameter(0, 0))) - priority match { - case PRIORITY_INSTRUCTION => iPort = port - case PRIORITY_DATA => dPort = port - } + portsInfo += port port.bus } - override def setup(pipeline: VexRiscv): Unit = { - setter = new PmpSetter(cutoff) - } - override def build(pipeline: VexRiscv): Unit = { import pipeline.config._ import pipeline._ @@ -124,184 +193,77 @@ class PmpPlugin(regions : Int, granularity : Int, ioRange : UInt => Bool) extend val csrService = pipeline.service(classOf[CsrInterface]) val privilegeService = pipeline.service(classOf[PrivilegeService]) - val state = pipeline plug new Area { - val pmpaddr = Mem(UInt(xlen bits), regions) - val pmpcfg = Vector.fill(regions)(Reg(Bits(8 bits)) init (0)) - val base, mask = Vector.fill(regions)(Reg(UInt(xlen - cutoff bits))) - } + val core = pipeline plug new Area { - def machineMode : Bool = privilegeService.isMachine() - - execute plug new Area { - import execute._ - - val fsmPending = RegInit(False) clearWhen(!arbitration.isStuck) - val fsmComplete = False - val hazardFree = csrService.isHazardFree() - - val csrAddress = input(INSTRUCTION)(csrRange) - val pmpNcfg = csrAddress(log2Up(regions) - 1 downto 0).asUInt - val pmpcfgN = pmpNcfg(log2Up(regions) - 3 downto 0) - val pmpcfgCsr = input(INSTRUCTION)(31 downto 24) === 0x3a - val pmpaddrCsr = input(INSTRUCTION)(31 downto 24) === 0x3b - - val pmpNcfg_ = Reg(UInt(log2Up(regions) bits)) - val pmpcfgN_ = Reg(UInt(log2Up(regions) - 2 bits)) - val pmpcfgCsr_ = RegInit(False) - val pmpaddrCsr_ = RegInit(False) - val writeData_ = Reg(Bits(xlen bits)) - - csrService.duringAnyRead { - when (machineMode) { - when (pmpcfgCsr) { - csrService.allowCsr() - csrService.readData() := - state.pmpcfg(pmpcfgN @@ U(3, 2 bits)) ## - state.pmpcfg(pmpcfgN @@ U(2, 2 bits)) ## - state.pmpcfg(pmpcfgN @@ U(1, 2 bits)) ## - state.pmpcfg(pmpcfgN @@ U(0, 2 bits)) - } - when (pmpaddrCsr) { - csrService.allowCsr() - csrService.readData() := state.pmpaddr(pmpNcfg).asBits - } + // Instantiate pmpaddr0 ... pmpaddr# CSRs. + for (i <- 0 until regions) { + if (i == 0) { + pmps += PmpRegister(null) + } else { + pmps += PmpRegister(pmps.last) } + csrService.r(0x3b0 + i, pmps(i).state.addr) + csrService.w(0x3b0 + i, pmps(i).csr.addr) } - csrService.duringAnyWrite { - when ((pmpcfgCsr | pmpaddrCsr) & machineMode) { - csrService.allowCsr() - arbitration.haltItself := !fsmComplete - when (!fsmPending && hazardFree) { - fsmPending := True - writeData_ := csrService.writeData() - pmpNcfg_ := pmpNcfg - pmpcfgN_ := pmpcfgN - pmpcfgCsr_ := pmpcfgCsr - pmpaddrCsr_ := pmpaddrCsr - } - } - } - - val fsm = new StateMachine { - val fsmEnable = RegInit(False) - val fsmCounter = Reg(UInt(log2Up(regions) bits)) init(0) - - val stateIdle : State = new State with EntryPoint { - onEntry { - fsmPending := False - fsmEnable := False - fsmComplete := True - fsmCounter := 0 - } - whenIsActive { - when (fsmPending) { - goto(stateWrite) - } - } - } - - val stateWrite : State = new State { - whenIsActive { - when (pmpcfgCsr_) { - val overwrite = writeData_.subdivideIn(8 bits) - for (i <- 0 until 4) { - when (~state.pmpcfg(pmpcfgN_ @@ U(i, 2 bits))(lBit)) { - state.pmpcfg(pmpcfgN_ @@ U(i, 2 bits)).assignFromBits(overwrite(i)) - } - } - goto(stateCfg) - } - when (pmpaddrCsr_) { - when (~state.pmpcfg(pmpNcfg_)(lBit)) { - state.pmpaddr(pmpNcfg_) := writeData_.asUInt - } - goto(stateAddr) - } - } - onExit (fsmEnable := True) - } - - val stateCfg : State = new State { - onEntry (fsmCounter := pmpcfgN_ @@ U(0, 2 bits)) - whenIsActive { - fsmCounter := fsmCounter + 1 - when (fsmCounter(1 downto 0) === 3) { - goto(stateIdle) - } - } - } - - val stateAddr : State = new State { - onEntry (fsmCounter := pmpNcfg_) - whenIsActive (goto(stateIdle)) - } - - when (pmpaddrCsr_) { - setter.io.addr := writeData_.asUInt - } otherwise { - setter.io.addr := state.pmpaddr(fsmCounter) - } - - when (fsmEnable & ~state.pmpcfg(fsmCounter)(lBit)) { - state.base(fsmCounter) := setter.io.base - state.mask(fsmCounter) := setter.io.mask - } - } - } - - pipeline plug new Area { - def getHits(address : UInt) = { - (0 until regions).map(i => - ((address & state.mask(U(i, log2Up(regions) bits))) === state.base(U(i, log2Up(regions) bits))) & - (state.pmpcfg(i)(lBit) | ~machineMode) & (state.pmpcfg(i)(aBits) === NAPOT) + // Instantiate pmpcfg0 ... pmpcfg# CSRs. + for (i <- 0 until (regions / 4)) { + csrService.r(0x3a0 + i, + 31 -> pmps((i * 4) + 3).state.l, 23 -> pmps((i * 4) + 2).state.l, + 15 -> pmps((i * 4) + 1).state.l, 7 -> pmps((i * 4) ).state.l, + 27 -> pmps((i * 4) + 3).state.a, 26 -> pmps((i * 4) + 3).state.x, + 25 -> pmps((i * 4) + 3).state.w, 24 -> pmps((i * 4) + 3).state.r, + 19 -> pmps((i * 4) + 2).state.a, 18 -> pmps((i * 4) + 2).state.x, + 17 -> pmps((i * 4) + 2).state.w, 16 -> pmps((i * 4) + 2).state.r, + 11 -> pmps((i * 4) + 1).state.a, 10 -> pmps((i * 4) + 1).state.x, + 9 -> pmps((i * 4) + 1).state.w, 8 -> pmps((i * 4) + 1).state.r, + 3 -> pmps((i * 4) ).state.a, 2 -> pmps((i * 4) ).state.x, + 1 -> pmps((i * 4) ).state.w, 0 -> pmps((i * 4) ).state.r + ) + csrService.w(0x3a0 + i, + 31 -> pmps((i * 4) + 3).csr.l, 23 -> pmps((i * 4) + 2).csr.l, + 15 -> pmps((i * 4) + 1).csr.l, 7 -> pmps((i * 4) ).csr.l, + 27 -> pmps((i * 4) + 3).csr.a, 26 -> pmps((i * 4) + 3).csr.x, + 25 -> pmps((i * 4) + 3).csr.w, 24 -> pmps((i * 4) + 3).csr.r, + 19 -> pmps((i * 4) + 2).csr.a, 18 -> pmps((i * 4) + 2).csr.x, + 17 -> pmps((i * 4) + 2).csr.w, 16 -> pmps((i * 4) + 2).csr.r, + 11 -> pmps((i * 4) + 1).csr.a, 10 -> pmps((i * 4) + 1).csr.x, + 9 -> pmps((i * 4) + 1).csr.w, 8 -> pmps((i * 4) + 1).csr.r, + 3 -> pmps((i * 4) ).csr.a, 2 -> pmps((i * 4) ).csr.x, + 1 -> pmps((i * 4) ).csr.w, 0 -> pmps((i * 4) ).csr.r ) } - def getPermission(hits : IndexedSeq[Bool], bit : Int) = { - MuxOH(OHMasking.first(hits), state.pmpcfg.map(_(bit))) - } + // Connect memory ports to PMP logic. + val ports = for ((port, portId) <- portsInfo.zipWithIndex) yield new Area { - val dGuard = new Area { - val address = dPort.bus.cmd(0).virtualAddress - dPort.bus.rsp.physicalAddress := address - dPort.bus.rsp.isIoAccess := ioRange(address) - dPort.bus.rsp.isPaging := False - dPort.bus.rsp.exception := False - dPort.bus.rsp.refilling := False - dPort.bus.rsp.allowExecute := False - dPort.bus.busy := False + val address = port.bus.cmd(0).virtualAddress + port.bus.rsp.physicalAddress := address - val hits = getHits(address(31 downto cutoff)) + // Only the first matching PMP region applies. + val hits = pmps.map(pmp => pmp.region.valid & + pmp.region.start <= address & + pmp.region.end > address & + (pmp.region.locked | ~privilegeService.isMachine())) - when(~hits.orR) { - dPort.bus.rsp.allowRead := machineMode - dPort.bus.rsp.allowWrite := machineMode + // M-mode has full access by default, others have none. + when(CountOne(hits) === 0) { + port.bus.rsp.allowRead := privilegeService.isMachine() + port.bus.rsp.allowWrite := privilegeService.isMachine() + port.bus.rsp.allowExecute := privilegeService.isMachine() } otherwise { - dPort.bus.rsp.allowRead := getPermission(hits, rBit) - dPort.bus.rsp.allowWrite := getPermission(hits, wBit) + port.bus.rsp.allowRead := MuxOH(OHMasking.first(hits), pmps.map(_.state.r)) + port.bus.rsp.allowWrite := MuxOH(OHMasking.first(hits), pmps.map(_.state.w)) + port.bus.rsp.allowExecute := MuxOH(OHMasking.first(hits), pmps.map(_.state.x)) } - } - val iGuard = new Area { - val address = iPort.bus.cmd(0).virtualAddress - iPort.bus.rsp.physicalAddress := address - iPort.bus.rsp.isIoAccess := ioRange(address) - iPort.bus.rsp.isPaging := False - iPort.bus.rsp.exception := False - iPort.bus.rsp.refilling := False - iPort.bus.rsp.allowRead := False - iPort.bus.rsp.allowWrite := False - iPort.bus.busy := False + port.bus.rsp.isIoAccess := ioRange(port.bus.rsp.physicalAddress) + port.bus.rsp.isPaging := False + port.bus.rsp.exception := False + port.bus.rsp.refilling := False + port.bus.busy := False - val hits = getHits(address(31 downto cutoff)) - - when(~hits.orR) { - iPort.bus.rsp.allowExecute := machineMode - } otherwise { - iPort.bus.rsp.allowExecute := getPermission(hits, xBit) - } } } } -} \ No newline at end of file +} diff --git a/src/main/scala/vexriscv/plugin/PmpPluginNapot.scala b/src/main/scala/vexriscv/plugin/PmpPluginNapot.scala new file mode 100644 index 00000000..34bade36 --- /dev/null +++ b/src/main/scala/vexriscv/plugin/PmpPluginNapot.scala @@ -0,0 +1,307 @@ +/* + * Copyright (c) 2021 Samuel Lindemer + * + * SPDX-License-Identifier: MIT + */ + +package vexriscv.plugin + +import vexriscv.{VexRiscv, _} +import vexriscv.plugin.MemoryTranslatorPort.{_} +import spinal.core._ +import spinal.lib._ +import spinal.lib.fsm._ + +/* Each 32-bit pmpcfg# register contains four 8-bit configuration sections. + * These section numbers contain flags which apply to regions defined by the + * corresponding pmpaddr# register. + * + * 3 2 1 + * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | pmp3cfg | pmp2cfg | pmp1cfg | pmp0cfg | pmpcfg0 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | pmp7cfg | pmp6cfg | pmp5cfg | pmp4cfg | pmpcfg2 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * 7 6 5 4 3 2 1 0 + * +-------+-------+-------+-------+-------+-------+-------+-------+ + * | L | 0 | A | X | W | R | pmp#cfg + * +-------+-------+-------+-------+-------+-------+-------+-------+ + * + * L: locks configuration until system reset (including M-mode) + * 0: hardwired to zero + * A: 0 = OFF (null region / disabled) + * 1 = TOR (top of range) + * 2 = NA4 (naturally aligned four-byte region) + * 3 = NAPOT (naturally aligned power-of-two region, > 7 bytes) + * X: execute + * W: write + * R: read + * + * TOR: Each 32-bit pmpaddr# register defines the upper bound of the pmp region + * right-shifted by two bits. The lower bound of the region is the previous + * pmpaddr# register. In the case of pmpaddr0, the lower bound is address 0x0. + * + * 3 2 1 + * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | address[33:2] | pmpaddr# + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * NAPOT: Each 32-bit pmpaddr# register defines the region address and the size + * of the pmp region. The number of concurrent 1s begging at the LSB indicates + * the size of the region as a power of two (e.g. 0x...0 = 8-byte, 0x...1 = + * 16-byte, 0x...11 = 32-byte, etc.). + * + * 3 2 1 + * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | address[33:2] |0|1|1|1|1| pmpaddr# + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * NA4: This is essentially an edge case of NAPOT where the entire pmpaddr# + * register defines a 4-byte wide region. + * + * N.B. THIS IMPLEMENTATION ONLY SUPPORTS NAPOT ADDRESSING. REGIONS ARE NOT + * ORDERED BY PRIORITY. A PERMISSION IS GRANTED TO AN ACCESS IF ANY MATCHING + * PMP REGION HAS THAT PERMISSION ENABLED. + */ + +trait Pmp { + def OFF = 0 + def TOR = 1 + def NA4 = 2 + def NAPOT = 3 + + def xlen = 32 + def rBit = 0 + def wBit = 1 + def xBit = 2 + def aBits = 4 downto 3 + def lBit = 7 +} + +class PmpSetter(cutoff : Int) extends Component with Pmp { + val io = new Bundle { + val addr = in UInt(xlen bits) + val base, mask = out UInt(xlen - cutoff bits) + } + + val ones = io.addr & ~(io.addr + 1) + io.base := io.addr(xlen - 3 downto cutoff - 2) ^ ones(xlen - 3 downto cutoff - 2) + io.mask := ~(ones(xlen - 4 downto cutoff - 2) @@ U"1") +} + +case class ProtectedMemoryTranslatorPort(bus : MemoryTranslatorBus) + +class PmpPluginNapot(regions : Int, granularity : Int, ioRange : UInt => Bool) extends Plugin[VexRiscv] with MemoryTranslator with Pmp { + assert(regions % 4 == 0 & regions <= 16) + assert(granularity >= 8) + + var setter : PmpSetter = null + var dPort, iPort : ProtectedMemoryTranslatorPort = null + val cutoff = log2Up(granularity) - 1 + + override def newTranslationPort(priority : Int, args : Any): MemoryTranslatorBus = { + val port = ProtectedMemoryTranslatorPort(MemoryTranslatorBus(new MemoryTranslatorBusParameter(0, 0))) + priority match { + case PRIORITY_INSTRUCTION => iPort = port + case PRIORITY_DATA => dPort = port + } + port.bus + } + + override def setup(pipeline: VexRiscv): Unit = { + setter = new PmpSetter(cutoff) + } + + override def build(pipeline: VexRiscv): Unit = { + import pipeline.config._ + import pipeline._ + import Riscv._ + + val csrService = pipeline.service(classOf[CsrInterface]) + val privilegeService = pipeline.service(classOf[PrivilegeService]) + + val state = pipeline plug new Area { + val pmpaddr = Mem(UInt(xlen bits), regions) + val pmpcfg = Vector.fill(regions)(Reg(Bits(8 bits)) init (0)) + val base, mask = Vector.fill(regions)(Reg(UInt(xlen - cutoff bits))) + } + + def machineMode : Bool = privilegeService.isMachine() + + execute plug new Area { + import execute._ + + val fsmPending = RegInit(False) clearWhen(!arbitration.isStuck) + val fsmComplete = False + val hazardFree = csrService.isHazardFree() + + val csrAddress = input(INSTRUCTION)(csrRange) + val pmpNcfg = csrAddress(log2Up(regions) - 1 downto 0).asUInt + val pmpcfgN = pmpNcfg(log2Up(regions) - 3 downto 0) + val pmpcfgCsr = input(INSTRUCTION)(31 downto 24) === 0x3a + val pmpaddrCsr = input(INSTRUCTION)(31 downto 24) === 0x3b + + val pmpNcfg_ = Reg(UInt(log2Up(regions) bits)) + val pmpcfgN_ = Reg(UInt(log2Up(regions) - 2 bits)) + val pmpcfgCsr_ = RegInit(False) + val pmpaddrCsr_ = RegInit(False) + val writeData_ = Reg(Bits(xlen bits)) + + csrService.duringAnyRead { + when (machineMode) { + when (pmpcfgCsr) { + csrService.allowCsr() + csrService.readData() := + state.pmpcfg(pmpcfgN @@ U(3, 2 bits)) ## + state.pmpcfg(pmpcfgN @@ U(2, 2 bits)) ## + state.pmpcfg(pmpcfgN @@ U(1, 2 bits)) ## + state.pmpcfg(pmpcfgN @@ U(0, 2 bits)) + } + when (pmpaddrCsr) { + csrService.allowCsr() + csrService.readData() := state.pmpaddr(pmpNcfg).asBits + } + } + } + + csrService.duringAnyWrite { + when ((pmpcfgCsr | pmpaddrCsr) & machineMode) { + csrService.allowCsr() + arbitration.haltItself := !fsmComplete + when (!fsmPending && hazardFree) { + fsmPending := True + writeData_ := csrService.writeData() + pmpNcfg_ := pmpNcfg + pmpcfgN_ := pmpcfgN + pmpcfgCsr_ := pmpcfgCsr + pmpaddrCsr_ := pmpaddrCsr + } + } + } + + val fsm = new StateMachine { + val fsmEnable = RegInit(False) + val fsmCounter = Reg(UInt(log2Up(regions) bits)) init(0) + + val stateIdle : State = new State with EntryPoint { + onEntry { + fsmPending := False + fsmEnable := False + fsmComplete := True + fsmCounter := 0 + } + whenIsActive { + when (fsmPending) { + goto(stateWrite) + } + } + } + + val stateWrite : State = new State { + whenIsActive { + when (pmpcfgCsr_) { + val overwrite = writeData_.subdivideIn(8 bits) + for (i <- 0 until 4) { + when (~state.pmpcfg(pmpcfgN_ @@ U(i, 2 bits))(lBit)) { + state.pmpcfg(pmpcfgN_ @@ U(i, 2 bits)).assignFromBits(overwrite(i)) + } + } + goto(stateCfg) + } + when (pmpaddrCsr_) { + when (~state.pmpcfg(pmpNcfg_)(lBit)) { + state.pmpaddr(pmpNcfg_) := writeData_.asUInt + } + goto(stateAddr) + } + } + onExit (fsmEnable := True) + } + + val stateCfg : State = new State { + onEntry (fsmCounter := pmpcfgN_ @@ U(0, 2 bits)) + whenIsActive { + fsmCounter := fsmCounter + 1 + when (fsmCounter(1 downto 0) === 3) { + goto(stateIdle) + } + } + } + + val stateAddr : State = new State { + onEntry (fsmCounter := pmpNcfg_) + whenIsActive (goto(stateIdle)) + } + + when (pmpaddrCsr_) { + setter.io.addr := writeData_.asUInt + } otherwise { + setter.io.addr := state.pmpaddr(fsmCounter) + } + + when (fsmEnable & ~state.pmpcfg(fsmCounter)(lBit)) { + state.base(fsmCounter) := setter.io.base + state.mask(fsmCounter) := setter.io.mask + } + } + } + + pipeline plug new Area { + def getHits(address : UInt) = { + (0 until regions).map(i => + ((address & state.mask(U(i, log2Up(regions) bits))) === state.base(U(i, log2Up(regions) bits))) & + (state.pmpcfg(i)(lBit) | ~machineMode) & (state.pmpcfg(i)(aBits) === NAPOT) + ) + } + + def getPermission(hits : IndexedSeq[Bool], bit : Int) = { + MuxOH(OHMasking.first(hits), state.pmpcfg.map(_(bit))) + } + + val dGuard = new Area { + val address = dPort.bus.cmd(0).virtualAddress + dPort.bus.rsp.physicalAddress := address + dPort.bus.rsp.isIoAccess := ioRange(address) + dPort.bus.rsp.isPaging := False + dPort.bus.rsp.exception := False + dPort.bus.rsp.refilling := False + dPort.bus.rsp.allowExecute := False + dPort.bus.busy := False + + val hits = getHits(address(31 downto cutoff)) + + when(~hits.orR) { + dPort.bus.rsp.allowRead := machineMode + dPort.bus.rsp.allowWrite := machineMode + } otherwise { + dPort.bus.rsp.allowRead := getPermission(hits, rBit) + dPort.bus.rsp.allowWrite := getPermission(hits, wBit) + } + } + + val iGuard = new Area { + val address = iPort.bus.cmd(0).virtualAddress + iPort.bus.rsp.physicalAddress := address + iPort.bus.rsp.isIoAccess := ioRange(address) + iPort.bus.rsp.isPaging := False + iPort.bus.rsp.exception := False + iPort.bus.rsp.refilling := False + iPort.bus.rsp.allowRead := False + iPort.bus.rsp.allowWrite := False + iPort.bus.busy := False + + val hits = getHits(address(31 downto cutoff)) + + when(~hits.orR) { + iPort.bus.rsp.allowExecute := machineMode + } otherwise { + iPort.bus.rsp.allowExecute := getPermission(hits, xBit) + } + } + } + } +} diff --git a/src/main/scala/vexriscv/plugin/PmpPluginOld.scala b/src/main/scala/vexriscv/plugin/PmpPluginOld.scala deleted file mode 100644 index 2f0f6d16..00000000 --- a/src/main/scala/vexriscv/plugin/PmpPluginOld.scala +++ /dev/null @@ -1,269 +0,0 @@ -/* - * Copyright (c) 2020 Samuel Lindemer - * - * SPDX-License-Identifier: MIT - */ - -package vexriscv.plugin - -import vexriscv.{VexRiscv, _} -import spinal.core._ -import spinal.lib._ -import scala.collection.mutable.ArrayBuffer - -/* Each 32-bit pmpcfg# register contains four 8-bit configuration sections. - * These section numbers contain flags which apply to regions defined by the - * corresponding pmpaddr# register. - * - * 3 2 1 - * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | pmp3cfg | pmp2cfg | pmp1cfg | pmp0cfg | pmpcfg0 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | pmp7cfg | pmp6cfg | pmp5cfg | pmp4cfg | pmpcfg2 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * - * 7 6 5 4 3 2 1 0 - * +-------+-------+-------+-------+-------+-------+-------+-------+ - * | L | 0 | A | X | W | R | pmp#cfg - * +-------+-------+-------+-------+-------+-------+-------+-------+ - * - * L: locks configuration until system reset (including M-mode) - * 0: hardwired to zero - * A: 0 = OFF (null region / disabled) - * 1 = TOR (top of range) - * 2 = NA4 (naturally aligned four-byte region) - * 3 = NAPOT (naturally aligned power-of-two region, > 7 bytes) - * X: execute - * W: write - * R: read - * - * TOR: Each 32-bit pmpaddr# register defines the upper bound of the pmp region - * right-shifted by two bits. The lower bound of the region is the previous - * pmpaddr# register. In the case of pmpaddr0, the lower bound is address 0x0. - * - * 3 2 1 - * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | address[33:2] | pmpaddr# - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * - * NAPOT: Each 32-bit pmpaddr# register defines the region address and the size - * of the pmp region. The number of concurrent 1s begging at the LSB indicates - * the size of the region as a power of two (e.g. 0x...0 = 8-byte, 0x...1 = - * 16-byte, 0x...11 = 32-byte, etc.). - * - * 3 2 1 - * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | address[33:2] |0|1|1|1|1| pmpaddr# - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * - * NA4: This is essentially an edge case of NAPOT where the entire pmpaddr# - * register defines a 4-byte wide region. - */ - -case class PmpRegister(previous : PmpRegister) extends Area { - - def OFF = 0 - def TOR = 1 - def NA4 = 2 - def NAPOT = 3 - - val state = new Area { - val r, w, x = Reg(Bool) - val l = RegInit(False) - val a = Reg(UInt(2 bits)) init(0) - val addr = Reg(UInt(32 bits)) - } - - // CSR writes connect to these signals rather than the internal state - // registers. This makes locking and WARL possible. - val csr = new Area { - val r, w, x = Bool - val l = Bool - val a = UInt(2 bits) - val addr = UInt(32 bits) - } - - // Last valid assignment wins; nothing happens if a user-initiated write did - // not occur on this clock cycle. - csr.r := state.r - csr.w := state.w - csr.x := state.x - csr.l := state.l - csr.a := state.a - csr.addr := state.addr - - // Computed PMP region bounds - val region = new Area { - val valid, locked = Bool - - // The calculated start & end addresses can overflow xlen by 4 bit: - // - // - 2 bit, as the pmpaddrX registers are defined as to encode - // [XLEN + 2 downto 2] addresses. - // - // - 2 bit, as for NAPOT the most significant 0 bit encodes the region - // length, with this bit included in the range! - // - // This means that (for xlen == 32 bit) - // - // pmpcfg(X / 4)(X % 4) = NAPOT - // pmpaddrX = 0xFFFFFFFF - // - // will expand to - // - // start (inclusive): 0x000000000 << 2 - // end (exclusive): 0x200000000 << 2 - // - // hence requiring xlen + 2 + 2 bit to represent the exclusive end - // address. This could be optimized by using a saturating add, or making the - // end address exclusive. - val start, end = UInt(36 bits) - } - - when(~state.l) { - state.r := csr.r - state.w := csr.w - state.x := csr.x - state.l := csr.l - state.a := csr.a - state.addr := csr.addr - - if (csr.l == True & csr.a == TOR) { - previous.state.l := True - } - } - - // Extend state.addr to 36 bits, to avoid these computations overflowing (as - // explained above): - val extended_addr = (B"00" ## state.addr.asBits).asUInt - val shifted = extended_addr << 2 - val mask = extended_addr ^ (extended_addr + 1) - val masked = (extended_addr & ~mask) << 2 - - // PMP changes take effect two clock cycles after the initial CSR write (i.e., - // settings propagate from csr -> state -> region). - region.locked := state.l - region.valid := True - - switch(csr.a) { - is(TOR) { - if (previous == null) region.start := 0 - else region.start := previous.region.end - region.end := shifted - } - is(NA4) { - region.start := shifted - region.end := shifted + 4 - } - is(NAPOT) { - region.start := masked - region.end := masked + ((mask + 1) << 2) - } - default { - region.start := 0 - region.end := shifted - region.valid := False - } - } -} - - -class PmpPluginOld(regions : Int, ioRange : UInt => Bool) extends Plugin[VexRiscv] with MemoryTranslator { - - // Each pmpcfg# CSR configures four regions. - assert((regions % 4) == 0) - - val pmps = ArrayBuffer[PmpRegister]() - val portsInfo = ArrayBuffer[ProtectedMemoryTranslatorPort]() - - override def newTranslationPort(priority : Int, args : Any): MemoryTranslatorBus = { - val port = ProtectedMemoryTranslatorPort(MemoryTranslatorBus(new MemoryTranslatorBusParameter(0, 0))) - portsInfo += port - port.bus - } - - override def build(pipeline: VexRiscv): Unit = { - import pipeline.config._ - import pipeline._ - import Riscv._ - - val csrService = pipeline.service(classOf[CsrInterface]) - val privilegeService = pipeline.service(classOf[PrivilegeService]) - - val core = pipeline plug new Area { - - // Instantiate pmpaddr0 ... pmpaddr# CSRs. - for (i <- 0 until regions) { - if (i == 0) { - pmps += PmpRegister(null) - } else { - pmps += PmpRegister(pmps.last) - } - csrService.r(0x3b0 + i, pmps(i).state.addr) - csrService.w(0x3b0 + i, pmps(i).csr.addr) - } - - // Instantiate pmpcfg0 ... pmpcfg# CSRs. - for (i <- 0 until (regions / 4)) { - csrService.r(0x3a0 + i, - 31 -> pmps((i * 4) + 3).state.l, 23 -> pmps((i * 4) + 2).state.l, - 15 -> pmps((i * 4) + 1).state.l, 7 -> pmps((i * 4) ).state.l, - 27 -> pmps((i * 4) + 3).state.a, 26 -> pmps((i * 4) + 3).state.x, - 25 -> pmps((i * 4) + 3).state.w, 24 -> pmps((i * 4) + 3).state.r, - 19 -> pmps((i * 4) + 2).state.a, 18 -> pmps((i * 4) + 2).state.x, - 17 -> pmps((i * 4) + 2).state.w, 16 -> pmps((i * 4) + 2).state.r, - 11 -> pmps((i * 4) + 1).state.a, 10 -> pmps((i * 4) + 1).state.x, - 9 -> pmps((i * 4) + 1).state.w, 8 -> pmps((i * 4) + 1).state.r, - 3 -> pmps((i * 4) ).state.a, 2 -> pmps((i * 4) ).state.x, - 1 -> pmps((i * 4) ).state.w, 0 -> pmps((i * 4) ).state.r - ) - csrService.w(0x3a0 + i, - 31 -> pmps((i * 4) + 3).csr.l, 23 -> pmps((i * 4) + 2).csr.l, - 15 -> pmps((i * 4) + 1).csr.l, 7 -> pmps((i * 4) ).csr.l, - 27 -> pmps((i * 4) + 3).csr.a, 26 -> pmps((i * 4) + 3).csr.x, - 25 -> pmps((i * 4) + 3).csr.w, 24 -> pmps((i * 4) + 3).csr.r, - 19 -> pmps((i * 4) + 2).csr.a, 18 -> pmps((i * 4) + 2).csr.x, - 17 -> pmps((i * 4) + 2).csr.w, 16 -> pmps((i * 4) + 2).csr.r, - 11 -> pmps((i * 4) + 1).csr.a, 10 -> pmps((i * 4) + 1).csr.x, - 9 -> pmps((i * 4) + 1).csr.w, 8 -> pmps((i * 4) + 1).csr.r, - 3 -> pmps((i * 4) ).csr.a, 2 -> pmps((i * 4) ).csr.x, - 1 -> pmps((i * 4) ).csr.w, 0 -> pmps((i * 4) ).csr.r - ) - } - - // Connect memory ports to PMP logic. - val ports = for ((port, portId) <- portsInfo.zipWithIndex) yield new Area { - - val address = port.bus.cmd(0).virtualAddress - port.bus.rsp.physicalAddress := address - - // Only the first matching PMP region applies. - val hits = pmps.map(pmp => pmp.region.valid & - pmp.region.start <= address & - pmp.region.end > address & - (pmp.region.locked | ~privilegeService.isMachine())) - - // M-mode has full access by default, others have none. - when(CountOne(hits) === 0) { - port.bus.rsp.allowRead := privilegeService.isMachine() - port.bus.rsp.allowWrite := privilegeService.isMachine() - port.bus.rsp.allowExecute := privilegeService.isMachine() - } otherwise { - port.bus.rsp.allowRead := MuxOH(OHMasking.first(hits), pmps.map(_.state.r)) - port.bus.rsp.allowWrite := MuxOH(OHMasking.first(hits), pmps.map(_.state.w)) - port.bus.rsp.allowExecute := MuxOH(OHMasking.first(hits), pmps.map(_.state.x)) - } - - port.bus.rsp.isIoAccess := ioRange(port.bus.rsp.physicalAddress) - port.bus.rsp.isPaging := False - port.bus.rsp.exception := False - port.bus.rsp.refilling := False - port.bus.busy := False - - } - } - } -} diff --git a/src/test/scala/vexriscv/TestIndividualFeatures.scala b/src/test/scala/vexriscv/TestIndividualFeatures.scala index fc87ce28..87dc9f47 100644 --- a/src/test/scala/vexriscv/TestIndividualFeatures.scala +++ b/src/test/scala/vexriscv/TestIndividualFeatures.scala @@ -520,7 +520,7 @@ class MmuPmpDimension extends VexRiscvDimension("DBus") { override def testParam = "MMU=no PMP=yes" override def applyOn(config: VexRiscvConfig): Unit = { - config.plugins += new PmpPlugin( + config.plugins += new PmpPluginNapot( regions = 16, granularity = 32, ioRange = _ (31 downto 28) === 0xF From 17915162f3675eeb2e6097f152babaf1d269b35c Mon Sep 17 00:00:00 2001 From: Leon Schuermann Date: Mon, 13 Nov 2023 13:55:18 -0500 Subject: [PATCH 920/951] TestIndividualFeatures: test both PmpPlugin and PmpPluginNapot --- .../vexriscv/TestIndividualFeatures.scala | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/test/scala/vexriscv/TestIndividualFeatures.scala b/src/test/scala/vexriscv/TestIndividualFeatures.scala index 87dc9f47..ec40b963 100644 --- a/src/test/scala/vexriscv/TestIndividualFeatures.scala +++ b/src/test/scala/vexriscv/TestIndividualFeatures.scala @@ -52,6 +52,7 @@ object VexRiscvUniverse{ val CATCH_ALL = new VexRiscvUniverse val MMU = new VexRiscvUniverse val PMP = new VexRiscvUniverse + val PMPNAPOT = new VexRiscvUniverse val FORCE_MULDIV = new VexRiscvUniverse val SUPERVISOR = new VexRiscvUniverse val NO_WRITEBACK = new VexRiscvUniverse @@ -519,6 +520,17 @@ class MmuPmpDimension extends VexRiscvDimension("DBus") { new VexRiscvPosition("WithPmp") { override def testParam = "MMU=no PMP=yes" + override def applyOn(config: VexRiscvConfig): Unit = { + config.plugins += new PmpPlugin( + regions = 16, + ioRange = _ (31 downto 28) === 0xF + ) + } + } + } else if (universes.contains(VexRiscvUniverse.PMPNAPOT)) { + new VexRiscvPosition("WithPmpNapot") { + override def testParam = "MMU=no PMP=yes" + override def applyOn(config: VexRiscvConfig): Unit = { config.plugins += new PmpPluginNapot( regions = 16, @@ -548,7 +560,7 @@ trait CatchAllPosition class CsrDimension(freertos : String, zephyr : String, linux : String) extends VexRiscvDimension("Csr") { override def randomPositionImpl(universes: Seq[ConfigUniverse], r: Random) = { - val pmp = universes.contains(VexRiscvUniverse.PMP) + val pmp = universes.contains(VexRiscvUniverse.PMP) || universes.contains(VexRiscvUniverse.PMPNAPOT) val catchAll = universes.contains(VexRiscvUniverse.CATCH_ALL) val supervisor = universes.contains(VexRiscvUniverse.SUPERVISOR) if(supervisor){ @@ -704,6 +716,7 @@ class TestIndividualFeatures extends MultithreadedFunSuite(sys.env.getOrElse("VE val demwRate = sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_DEMW_RATE", "0.6").toDouble val demRate = sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_DEM_RATE", "0.5").toDouble val stopOnError = sys.env.getOrElse("VEXRISCV_REGRESSION_STOP_ON_ERROR", "no") + val pmpNapotRate = sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_PMP_NAPOT_RANGE", "0.5").toDouble val lock = new{} @@ -808,7 +821,11 @@ class TestIndividualFeatures extends MultithreadedFunSuite(sys.env.getOrElse("VE } else if (secureRate > rand.nextDouble()) { universe += VexRiscvUniverse.CACHE_ALL universe += VexRiscvUniverse.CATCH_ALL - universe += VexRiscvUniverse.PMP + if (pmpNapotRate > rand.nextDouble()) { + universe += VexRiscvUniverse.PMP + } else { + universe += VexRiscvUniverse.PMPNAPOT + } if(demwRate < rand.nextDouble()){ universe += VexRiscvUniverse.NO_WRITEBACK } From 940fb507a53510bbb449ef7a25faf3c880229e72 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 14 Nov 2023 11:35:56 +0100 Subject: [PATCH 921/951] fix #376 Uncached dbus ahb, add option to ensure no combinatorial loop --- .../vexriscv/plugin/DBusSimplePlugin.scala | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala index 97aa0c13..84cf9e5c 100644 --- a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala @@ -225,29 +225,30 @@ case class DBusSimpleBus(bigEndian : Boolean = false) extends Bundle with IMaste bus } - def toAhbLite3Master(avoidWriteToReadHazard : Boolean): AhbLite3Master = { + def toAhbLite3Master(avoidWriteToReadHazard : Boolean, withHalfRate : Boolean = true): AhbLite3Master = { val bus = AhbLite3Master(DBusSimpleBus.getAhbLite3Config()) - bus.HADDR := this.cmd.address - bus.HWRITE := this.cmd.wr - bus.HSIZE := B(this.cmd.size, 3 bits) + val cmdBuffer = this.cmd.pipelined(halfRate = withHalfRate) + bus.HADDR := cmdBuffer.address + bus.HWRITE := cmdBuffer.wr + bus.HSIZE := B(cmdBuffer.size, 3 bits) bus.HBURST := 0 bus.HPROT := "1111" - bus.HTRANS := this.cmd.valid ## B"0" + bus.HTRANS := cmdBuffer.valid ## B"0" bus.HMASTLOCK := False - bus.HWDATA := RegNextWhen(this.cmd.data, bus.HREADY) - this.cmd.ready := bus.HREADY + bus.HWDATA := RegNextWhen(cmdBuffer.data, bus.HREADY) + cmdBuffer.ready := bus.HREADY - val pending = RegInit(False) clearWhen(bus.HREADY) setWhen(this.cmd.fire && !this.cmd.wr) + val pending = RegInit(False) clearWhen(bus.HREADY) setWhen(cmdBuffer.fire && !cmdBuffer.wr) this.rsp.ready := bus.HREADY && pending this.rsp.data := bus.HRDATA this.rsp.error := bus.HRESP if(avoidWriteToReadHazard) { val writeDataPhase = RegNextWhen(bus.HTRANS === 2 && bus.HWRITE, bus.HREADY) init (False) - val potentialHazard = this.cmd.valid && !this.cmd.wr && writeDataPhase + val potentialHazard = cmdBuffer.valid && !cmdBuffer.wr && writeDataPhase when(potentialHazard) { bus.HTRANS := 0 - this.cmd.ready := False + cmdBuffer.ready := False } } bus From 7c6c7a6fe5aed7f55ae7119b95e5cd569f0efc90 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sat, 25 Nov 2023 14:16:35 +0100 Subject: [PATCH 922/951] implement #373 IBusDBusCachedTightlyCoupledRam hexInit ramOffset args --- .../vexriscv/plugin/DBusCachedPlugin.scala | 30 +++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index 6f85652a..ef59b490 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -6,6 +6,7 @@ import spinal.core._ import spinal.lib._ import spinal.lib.bus.amba4.axi.Axi4 import spinal.lib.bus.misc.SizeMapping +import spinal.lib.misc.HexTools import scala.collection.mutable.ArrayBuffer @@ -650,7 +651,12 @@ class DBusCachedPlugin(val config : DataCacheConfig, } -class IBusDBusCachedTightlyCoupledRam(mapping : SizeMapping, withIBus : Boolean = true, withDBus : Boolean = true) extends Plugin[VexRiscv]{ +class IBusDBusCachedTightlyCoupledRam(mapping : SizeMapping, + withIBus : Boolean = true, + withDBus : Boolean = true, + ramAsBlackbox : Boolean = true, + hexInit : String = null, + ramOffset : Long = -1) extends Plugin[VexRiscv]{ var dbus : TightlyCoupledDataBus = null var ibus : TightlyCoupledBus = null @@ -674,7 +680,11 @@ class IBusDBusCachedTightlyCoupledRam(mapping : SizeMapping, withIBus : Boolean override def build(pipeline: VexRiscv) = { val logic = pipeline plug new Area { val ram = Mem(Bits(32 bits), mapping.size.toInt/4) - ram.generateAsBlackBox() + if(ramAsBlackbox) ram.generateAsBlackBox() + if (hexInit != null) { + assert(ramOffset != -1) + initRam(ram, hexInit, ramOffset, allowOverflow = true) + } val d = withDBus generate new Area { dbus.read_data := ram.readWriteSync( address = (dbus.address >> 2).resized, @@ -694,4 +704,20 @@ class IBusDBusCachedTightlyCoupledRam(mapping : SizeMapping, withIBus : Boolean } } } + + //Until new SpinalHDL release + def initRam[T <: Data](ram: Mem[T], onChipRamHexFile: String, hexOffset: BigInt, allowOverflow: Boolean = false): Unit = { + val wordSize = ram.wordType.getBitsWidth / 8 + val initContent = Array.fill[BigInt](ram.wordCount)(0) + HexTools.readHexFile(onChipRamHexFile, 0, (address, data) => { + val addressWithoutOffset = (address - hexOffset).toLong + val addressWord = addressWithoutOffset / wordSize + if (addressWord < 0 || addressWord >= initContent.size) { + assert(allowOverflow) + } else { + initContent(addressWord.toInt) |= BigInt(data) << ((addressWithoutOffset.toInt % wordSize) * 8) + } + }) + ram.initBigInt(initContent) + } } From 62577a7a1175f9df8d171accdec2573753c2aca0 Mon Sep 17 00:00:00 2001 From: Jack Davine Date: Fri, 22 Dec 2023 00:36:26 +0800 Subject: [PATCH 923/951] Add mill to compile and test VexRiscv --- .gitignore | 2 ++ README.md | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ build.sc | 28 ++++++++++++++++++++++++ 3 files changed, 93 insertions(+) create mode 100644 build.sc diff --git a/.gitignore b/.gitignore index 641c9266..e47d61e7 100644 --- a/.gitignore +++ b/.gitignore @@ -48,6 +48,8 @@ obj_dir *.bin explor +mill + simWorkspace/ tmp/ /archive.tar.gz diff --git a/README.md b/README.md index c7168053..56dfe42c 100644 --- a/README.md +++ b/README.md @@ -441,6 +441,69 @@ To run it : sbt "test:runMain vexriscv.MuraxSim" ``` +## Build all above with mill + +Mill is a simple tool to build Scala/Java, also fits in off-line environment very well. + +Github url is here: https://github.com/com-lihaoyi/mill + +Document is here: https://mill-build.com/mill/Intro_to_Mill.html + +Download executable mill: + +```sh +curl --fail -L -o mill https://github.com/com-lihaoyi/mill/releases/download/0.11.6/0.11.6-assembly +chmod +x mill +``` +Using mill to generate the corresponding RTL as a `VexRiscv.v` file, run the following commands in the root directory of this repository: + +```sh +./mill VexRiscv.runMain vexriscv.demo.GenFull +``` +or + +```sh +./mill VexRiscv.runMain vexriscv.demo.GenSmallest +``` + +Using mill to run tests (need java, scala, verilator), do : + +```sh +export VEXRISCV_REGRESSION_SEED=42 +export VEXRISCV_REGRESSION_TEST_ID= +./mill VexRiscv.test.testOnly vexriscv.TestIndividualFeatures +``` + +Using mill to generate the Briey SoC Hardware: + +```sh +./mill VexRiscv.runMain vexriscv.demo.Briey +``` + +Using mill to generate the Murax SoC Hardware: + +```sh +# To generate the SoC without any content in the ram +./mill VexRiscv.runMain vexriscv.demo.Murax + +# To generate the SoC with a demo program already in ram +./mill VexRiscv.runMain vexriscv.demo.MuraxWithRamInit + +# This will generate the Murax RTL + run its testbench. You need Verilator 3.9xx installated. +./mill VexRiscv.test.runMain vexriscv.MuraxSim +``` + +Mill's IDE supports: + +```sh +# Build Server Protocol (BSP) +./mill mill.bsp.BSP/install + +# IntelliJ IDEA Support +./mill mill.idea.GenIdea/idea +``` + + ## Running Linux A default configuration is located in `src/main/scala/vexriscv/demo/Linux.scala`. diff --git a/build.sc b/build.sc new file mode 100644 index 00000000..efd62f7c --- /dev/null +++ b/build.sc @@ -0,0 +1,28 @@ +import mill._, scalalib._ + +val spinalVersion = "1.9.4" + +object ivys { + val sv = "2.11.12" + val spinalCore = ivy"com.github.spinalhdl::spinalhdl-core:$spinalVersion" + val spinalLib = ivy"com.github.spinalhdl::spinalhdl-lib:$spinalVersion" + val spinalPlugin = ivy"com.github.spinalhdl::spinalhdl-idsl-plugin:$spinalVersion" + val scalatest = ivy"org.scalatest::scalatest:3.2.5" + val macroParadise = ivy"org.scalamacros:::paradise:2.1.1" + val yaml = ivy"org.yaml:snakeyaml:1.8" +} + +trait Common extends ScalaModule { + override def scalaVersion = ivys.sv + override def scalacPluginIvyDeps = Agg(ivys.macroParadise, ivys.spinalPlugin) + override def ivyDeps = Agg(ivys.spinalCore, ivys.spinalLib, ivys.yaml, ivys.scalatest) + override def scalacOptions = Seq("-Xsource:2.11") +} + +object VexRiscv extends Common with SbtModule{ + override def millSourcePath = os.pwd + override def moduleDeps: Seq[JavaModule] = super.moduleDeps + + object test extends SbtModuleTests with TestModule.ScalaTest +} + From 0effdecbe60a37beb8822e713745345a5dfaf7ba Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 4 Jan 2024 10:11:22 +0100 Subject: [PATCH 924/951] SpinalHDL 1.10.0 --- build.sbt | 2 +- build.sc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.sbt b/build.sbt index 766b2b01..b0dd071a 100644 --- a/build.sbt +++ b/build.sbt @@ -1,4 +1,4 @@ -val spinalVersion = "1.9.4" +val spinalVersion = "1.10.0" lazy val root = (project in file(".")). settings( diff --git a/build.sc b/build.sc index efd62f7c..c79d08e6 100644 --- a/build.sc +++ b/build.sc @@ -1,6 +1,6 @@ import mill._, scalalib._ -val spinalVersion = "1.9.4" +val spinalVersion = "1.10.0" object ivys { val sv = "2.11.12" From fe5e6dd95b932ac16df1c306c5e6b5f223506e2b Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 1 Feb 2024 10:34:37 +0100 Subject: [PATCH 925/951] SpinalHDL 1.10.1 --- build.sbt | 2 +- build.sc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.sbt b/build.sbt index b0dd071a..7eb2d352 100644 --- a/build.sbt +++ b/build.sbt @@ -1,4 +1,4 @@ -val spinalVersion = "1.10.0" +val spinalVersion = "1.10.1" lazy val root = (project in file(".")). settings( diff --git a/build.sc b/build.sc index c79d08e6..fb997be9 100644 --- a/build.sc +++ b/build.sc @@ -1,6 +1,6 @@ import mill._, scalalib._ -val spinalVersion = "1.10.0" +val spinalVersion = "1.10.1" object ivys { val sv = "2.11.12" From 30871d3381815b7821e518fc8aab0da226a36d1e Mon Sep 17 00:00:00 2001 From: PythonLinks <34622952+PythonLinks@users.noreply.github.com> Date: Tue, 5 Mar 2024 09:57:41 +0100 Subject: [PATCH 926/951] Improved the paragraph about available configurations. --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index 56dfe42c..68a8fc4d 100644 --- a/README.md +++ b/README.md @@ -193,9 +193,7 @@ sudo make install ``` ## CPU generation -You can find two example CPU instances in: -- `src/main/scala/vexriscv/demo/GenFull.scala` -- `src/main/scala/vexriscv/demo/GenSmallest.scala` +We now have twenty-two CPU configurations [in this directory](./src/main/scala/vexriscv/demo). Look at the files called Gen*.scala. Here is the [full configuration](./src/main/scala/vexriscv/demo/GenFull.scala), and the [smallest configuration](./src/main/scala/vexriscv/demo/GenSmallest.scala). To generate the corresponding RTL as a `VexRiscv.v` file, run the following commands in the root directory of this repository: From 25d13df1b46256850adc4462b74d3ed0d28dab99 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 8 Mar 2024 12:44:21 +0100 Subject: [PATCH 927/951] Fix main.cpp syntax --- src/test/cpp/regression/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 1f20d000..1154591f 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -722,8 +722,8 @@ public: uint32_t getPendingInterrupt(){ - uint32_t mEnabled = status.mie && privilege == 3 || privilege < 3; - uint32_t sEnabled = status.sie && privilege == 1 || privilege < 1; + uint32_t mEnabled = status.mie && (privilege == 3) || privilege < 3; + uint32_t sEnabled = status.sie && (privilege == 1) || privilege < 1; uint32_t masked = getIp().raw & ~mideleg & -mEnabled & ie.raw; if (masked == 0) From e52251d88c1d0dd397cc976654b291909152a979 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 8 Mar 2024 12:50:39 +0100 Subject: [PATCH 928/951] main.cpp more wno --- src/test/cpp/regression/makefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/test/cpp/regression/makefile b/src/test/cpp/regression/makefile index e02f3b86..30d11b67 100644 --- a/src/test/cpp/regression/makefile +++ b/src/test/cpp/regression/makefile @@ -61,6 +61,10 @@ ADDCFLAGS += -CFLAGS -DDBUS_${DBUS} ADDCFLAGS += -CFLAGS -DREDO=${REDO} ADDCFLAGS += -CFLAGS -pthread ADDCFLAGS += -CFLAGS -Wno-unused-result +ADDCFLAGS += -CFLAGS -Wno-parentheses +ADDCFLAGS += -CFLAGS -Wno-misleading-indentation +ADDCFLAGS += -CFLAGS -Wno-catch-value +ADDCFLAGS += -CFLAGS -Wno-float-conversion From 26d6f61d49f6e02cb3fe7093accae3ed94f54d3e Mon Sep 17 00:00:00 2001 From: Gongqi Huang Date: Sat, 9 Mar 2024 20:49:37 -0500 Subject: [PATCH 929/951] Fix SMP compile-time error when disabling supervisor When generating SMP configuration with supervisor disable, the compiler stucks at waiting for the signal from `externalSupervisorInterrupt`, which is generated conditionally based on `withSupervisor` option. --- src/main/scala/vexriscv/VexRiscv.scala | 5 +++++ src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala | 4 +++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/VexRiscv.scala b/src/main/scala/vexriscv/VexRiscv.scala index 2f4917f5..fcad68a7 100644 --- a/src/main/scala/vexriscv/VexRiscv.scala +++ b/src/main/scala/vexriscv/VexRiscv.scala @@ -53,6 +53,11 @@ case class VexRiscvConfig(){ case None => false } + def withSupervisor = find(classOf[CsrPlugin]) match { + case Some(x) => x.config.supervisorGen + case None => false + } + def FLEN = if(withRvd) 64 else if(withRvf) 32 else 0 //Default Stageables diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index 854828f3..8be22041 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -206,7 +206,9 @@ class VexRiscvSmpClusterWithPeripherals(p : VexRiscvSmpClusterParameter) extends plic.priorityWidth.load(2) plic.mapping.load(PlicMapping.sifive) plic.addTarget(core.cpu.externalInterrupt) - plic.addTarget(core.cpu.externalSupervisorInterrupt) + if(core.cpu.config.withSupervisor) { + plic.addTarget(core.cpu.externalSupervisorInterrupt) + } List(clint.logic, core.cpu.logic).produce { for (plugin <- core.cpu.config.plugins) plugin match { case plugin: CsrPlugin if plugin.utime != null => plugin.utime := clint.logic.io.time From 5f58e0c7c66970989ddf80375109bb7a4a19adb7 Mon Sep 17 00:00:00 2001 From: Martijn Bastiaan Date: Fri, 22 Mar 2024 21:24:32 +0100 Subject: [PATCH 930/951] Handle `ERR` in `toWishbone` --- src/main/scala/vexriscv/ip/DataCache.scala | 6 +++--- src/main/scala/vexriscv/ip/InstructionCache.scala | 8 ++++---- src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala | 6 +++--- src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala | 6 +++--- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index 5ed44f67..a7506e65 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -368,13 +368,13 @@ case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave bus.WE := cmdBridge.wr bus.DAT_MOSI := cmdBridge.data - cmdBridge.ready := cmdBridge.valid && bus.ACK + cmdBridge.ready := cmdBridge.valid && (bus.ACK || bus.ERR) bus.CYC := cmdBridge.valid bus.STB := cmdBridge.valid - rsp.valid := RegNext(cmdBridge.valid && !bus.WE && bus.ACK) init(False) + rsp.valid := RegNext(cmdBridge.valid && !bus.WE && (bus.ACK || bus.ERR)) init(False) rsp.data := RegNext(bus.DAT_MISO) - rsp.error := False //TODO + rsp.error := RegNext(bus.ERR) bus } diff --git a/src/main/scala/vexriscv/ip/InstructionCache.scala b/src/main/scala/vexriscv/ip/InstructionCache.scala index e09712cb..20584a66 100644 --- a/src/main/scala/vexriscv/ip/InstructionCache.scala +++ b/src/main/scala/vexriscv/ip/InstructionCache.scala @@ -239,15 +239,15 @@ case class InstructionCacheMemBus(p : InstructionCacheConfig) extends Bundle wit when(cmd.valid || pending){ bus.CYC := True bus.STB := True - when(bus.ACK){ + when(bus.ACK || bus.ERR){ counter := counter + 1 } } - cmd.ready := cmd.valid && bus.ACK - rsp.valid := RegNext(bus.CYC && bus.ACK) init(False) + cmd.ready := cmd.valid && (bus.ACK || bus.ERR) + rsp.valid := RegNext(bus.CYC && (bus.ACK || bus.ERR)) init(False) rsp.data := RegNext(bus.DAT_MISO) - rsp.error := False //TODO + rsp.error := RegNext(bus.ERR) bus } diff --git a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala index 84cf9e5c..5733ac7f 100644 --- a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala @@ -199,13 +199,13 @@ case class DBusSimpleBus(bigEndian : Boolean = false) extends Bundle with IMaste bus.WE := cmdStage.wr bus.DAT_MOSI := cmdStage.data - cmdStage.ready := cmdStage.valid && bus.ACK + cmdStage.ready := cmdStage.valid && (bus.ACK || bus.ERR) bus.CYC := cmdStage.valid bus.STB := cmdStage.valid - rsp.ready := cmdStage.valid && !bus.WE && bus.ACK + rsp.ready := cmdStage.valid && !bus.WE && (bus.ACK || bus.ERR) rsp.data := bus.DAT_MISO - rsp.error := False //TODO + rsp.error := bus.ERR bus } diff --git a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala index 1bb02bf2..dc19d434 100644 --- a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala @@ -156,10 +156,10 @@ case class IBusSimpleBus(plugin: IBusSimplePlugin) extends Bundle with IMasterSl bus.STB := cmdPipe.valid - cmdPipe.ready := cmdPipe.valid && bus.ACK - rsp.valid := bus.CYC && bus.ACK + cmdPipe.ready := cmdPipe.valid && (bus.ACK || bus.ERR) + rsp.valid := bus.CYC && (bus.ACK || bus.ERR) rsp.inst := bus.DAT_MISO - rsp.error := False //TODO + rsp.error := bus.ERR bus } From 1175f195dfcd24a63fd9f9ee84b6e7145e2719b0 Mon Sep 17 00:00:00 2001 From: MrJake222 Date: Tue, 4 Jun 2024 23:11:10 +0200 Subject: [PATCH 931/951] Exposed write mask on default iBus --- src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala index 5733ac7f..0e7d1238 100644 --- a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala @@ -16,6 +16,7 @@ import scala.collection.mutable.ArrayBuffer case class DBusSimpleCmd() extends Bundle{ val wr = Bool + val mask = Bits(4 bit) val address = UInt(32 bits) val data = Bits(32 bit) val size = UInt(2 bit) @@ -441,6 +442,7 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false, //formal val formalMask = dBus.genMask(dBus.cmd) + dBus.cmd.mask := formalMask insert(FORMAL_MEM_ADDR) := dBus.cmd.address & U"xFFFFFFFC" insert(FORMAL_MEM_WMASK) := (dBus.cmd.valid && dBus.cmd.wr) ? formalMask | B"0000" From 8c191a282458c09bcff48e67caff5a7c5661abd0 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 17 Jun 2024 10:04:12 +0200 Subject: [PATCH 932/951] Fix #412 tightly coupled HAS_SIDE_EFFECT fix --- src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index ef59b490..16bb7e7b 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -473,7 +473,7 @@ class DBusCachedPlugin(val config : DataCacheConfig, cache.io.cpu.memory.mmuRsp.isIoAccess setWhen(pipeline(DEBUG_BYPASS_CACHE) && !cache.io.cpu.memory.isWrite) if(tightlyGen){ - when(input(MEMORY_TIGHTLY).orR){ + when(input(MEMORY_ENABLE) && input(MEMORY_TIGHTLY).orR){ cache.io.cpu.memory.isValid := False input(HAS_SIDE_EFFECT) := False } @@ -585,7 +585,7 @@ class DBusCachedPlugin(val config : DataCacheConfig, insert(MEMORY_LOAD_DATA) := rspShifted if(tightlyGen){ - when(input(MEMORY_TIGHTLY).orR){ + when(input(MEMORY_ENABLE) && input(MEMORY_TIGHTLY).orR){ cache.io.cpu.writeBack.isValid := False exceptionBus.valid := False redoBranch.valid := False From 7beb9887a65083d76b459654f7868fc114a91f06 Mon Sep 17 00:00:00 2001 From: Marc Emery Date: Mon, 17 Jun 2024 21:46:29 +0200 Subject: [PATCH 933/951] Fix Mhz -> MHz in readme and comments --- README.md | 122 +++++++++--------- .../src/main/scala/vexriscv/demo/Murax.scala | 4 +- src/main/scala/vexriscv/demo/Murax.scala | 4 +- src/main/scala/vexriscv/ip/fpu/FpuCore.scala | 72 +++++------ .../scala/vexriscv/plugin/AesPlugin.scala | 2 +- 5 files changed, 102 insertions(+), 102 deletions(-) diff --git a/README.md b/README.md index 68a8fc4d..804bdb1f 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,7 @@ This repository hosts a RISC-V implementation written in SpinalHDL. Here are som - RV32I[M][A][F[D]][C] instruction set - Pipelined from 2 to 5+ stages ([Fetch*X], Decode, Execute, [Memory], [WriteBack]) -- 1.44 DMIPS/Mhz --no-inline when nearly all features are enabled (1.57 DMIPS/Mhz when the divider lookup table is enabled) +- 1.44 DMIPS/MHz --no-inline when nearly all features are enabled (1.57 DMIPS/MHz when the divider lookup table is enabled) - Optimized for FPGA, does not use any vendor specific IP block / primitive - AXI4, Avalon, wishbone ready - Optional MUL/DIV extensions @@ -97,54 +97,54 @@ dhrystone binaries which fit inside a 4KB I$ and 4KB D$ (I already had this case The CPU configurations used below can be found in the `src/scala/vexriscv/demo` directory. ``` -VexRiscv small (RV32I, 0.52 DMIPS/Mhz, no datapath bypass, no interrupt) -> - Artix 7 -> 243 Mhz 504 LUT 505 FF - Cyclone V -> 174 Mhz 352 ALMs - Cyclone IV -> 179 Mhz 731 LUT 494 FF - iCE40 -> 92 Mhz 1130 LC +VexRiscv small (RV32I, 0.52 DMIPS/MHz, no datapath bypass, no interrupt) -> + Artix 7 -> 243 MHz 504 LUT 505 FF + Cyclone V -> 174 MHz 352 ALMs + Cyclone IV -> 179 MHz 731 LUT 494 FF + iCE40 -> 92 MHz 1130 LC -VexRiscv small (RV32I, 0.52 DMIPS/Mhz, no datapath bypass) -> - Artix 7 -> 240 Mhz 556 LUT 566 FF - Cyclone V -> 194 Mhz 394 ALMs - Cyclone IV -> 174 Mhz 831 LUT 555 FF - iCE40 -> 85 Mhz 1292 LC +VexRiscv small (RV32I, 0.52 DMIPS/MHz, no datapath bypass) -> + Artix 7 -> 240 MHz 556 LUT 566 FF + Cyclone V -> 194 MHz 394 ALMs + Cyclone IV -> 174 MHz 831 LUT 555 FF + iCE40 -> 85 MHz 1292 LC -VexRiscv small and productive (RV32I, 0.82 DMIPS/Mhz) -> - Artix 7 -> 232 Mhz 816 LUT 534 FF - Cyclone V -> 155 Mhz 492 ALMs - Cyclone IV -> 155 Mhz 1,111 LUT 530 FF - iCE40 -> 63 Mhz 1596 LC +VexRiscv small and productive (RV32I, 0.82 DMIPS/MHz) -> + Artix 7 -> 232 MHz 816 LUT 534 FF + Cyclone V -> 155 MHz 492 ALMs + Cyclone IV -> 155 MHz 1,111 LUT 530 FF + iCE40 -> 63 MHz 1596 LC -VexRiscv small and productive with I$ (RV32I, 0.70 DMIPS/Mhz, 4KB-I$) -> - Artix 7 -> 220 Mhz 730 LUT 570 FF - Cyclone V -> 142 Mhz 501 ALMs - Cyclone IV -> 150 Mhz 1,139 LUT 536 FF - iCE40 -> 66 Mhz 1680 LC +VexRiscv small and productive with I$ (RV32I, 0.70 DMIPS/MHz, 4KB-I$) -> + Artix 7 -> 220 MHz 730 LUT 570 FF + Cyclone V -> 142 MHz 501 ALMs + Cyclone IV -> 150 MHz 1,139 LUT 536 FF + iCE40 -> 66 MHz 1680 LC -VexRiscv full no cache (RV32IM, 1.21 DMIPS/Mhz 2.30 Coremark/Mhz, single cycle barrel shifter, debug module, catch exceptions, static branch) -> - Artix 7 -> 216 Mhz 1418 LUT 949 FF - Cyclone V -> 133 Mhz 933 ALMs - Cyclone IV -> 143 Mhz 2,076 LUT 972 FF +VexRiscv full no cache (RV32IM, 1.21 DMIPS/MHz 2.30 Coremark/MHz, single cycle barrel shifter, debug module, catch exceptions, static branch) -> + Artix 7 -> 216 MHz 1418 LUT 949 FF + Cyclone V -> 133 MHz 933 ALMs + Cyclone IV -> 143 MHz 2,076 LUT 972 FF -VexRiscv full (RV32IM, 1.21 DMIPS/Mhz 2.30 Coremark/Mhz with cache trashing, 4KB-I$,4KB-D$, single cycle barrel shifter, debug module, catch exceptions, static branch) -> - Artix 7 -> 199 Mhz 1840 LUT 1158 FF - Cyclone V -> 141 Mhz 1,166 ALMs - Cyclone IV -> 131 Mhz 2,407 LUT 1,067 FF +VexRiscv full (RV32IM, 1.21 DMIPS/MHz 2.30 Coremark/MHz with cache trashing, 4KB-I$,4KB-D$, single cycle barrel shifter, debug module, catch exceptions, static branch) -> + Artix 7 -> 199 MHz 1840 LUT 1158 FF + Cyclone V -> 141 MHz 1,166 ALMs + Cyclone IV -> 131 MHz 2,407 LUT 1,067 FF -VexRiscv full max perf (HZ*IPC) -> (RV32IM, 1.38 DMIPS/Mhz 2.57 Coremark/Mhz, 8KB-I$,8KB-D$, single cycle barrel shifter, debug module, catch exceptions, dynamic branch prediction in the fetch stage, branch and shift operations done in the Execute stage) -> - Artix 7 -> 200 Mhz 1935 LUT 1216 FF - Cyclone V -> 130 Mhz 1,166 ALMs - Cyclone IV -> 126 Mhz 2,484 LUT 1,120 FF +VexRiscv full max perf (HZ*IPC) -> (RV32IM, 1.38 DMIPS/MHz 2.57 Coremark/MHz, 8KB-I$,8KB-D$, single cycle barrel shifter, debug module, catch exceptions, dynamic branch prediction in the fetch stage, branch and shift operations done in the Execute stage) -> + Artix 7 -> 200 MHz 1935 LUT 1216 FF + Cyclone V -> 130 MHz 1,166 ALMs + Cyclone IV -> 126 MHz 2,484 LUT 1,120 FF -VexRiscv full with MMU (RV32IM, 1.24 DMIPS/Mhz 2.35 Coremark/Mhz, with cache trashing, 4KB-I$, 4KB-D$, single cycle barrel shifter, debug module, catch exceptions, dynamic branch, MMU) -> - Artix 7 -> 151 Mhz 2021 LUT 1541 FF - Cyclone V -> 124 Mhz 1,368 ALMs - Cyclone IV -> 128 Mhz 2,826 LUT 1,474 FF +VexRiscv full with MMU (RV32IM, 1.24 DMIPS/MHz 2.35 Coremark/MHz, with cache trashing, 4KB-I$, 4KB-D$, single cycle barrel shifter, debug module, catch exceptions, dynamic branch, MMU) -> + Artix 7 -> 151 MHz 2021 LUT 1541 FF + Cyclone V -> 124 MHz 1,368 ALMs + Cyclone IV -> 128 MHz 2,826 LUT 1,474 FF -VexRiscv linux balanced (RV32IMA, 1.21 DMIPS/Mhz 2.27 Coremark/Mhz, with cache trashing, 4KB-I$, 4KB-D$, single cycle barrel shifter, catch exceptions, static branch, MMU, Supervisor, Compatible with mainstream linux) -> - Artix 7 -> 180 Mhz 2883 LUT 2130 FF - Cyclone V -> 131 Mhz 1,764 ALMs - Cyclone IV -> 121 Mhz 3,608 LUT 2,082 FF +VexRiscv linux balanced (RV32IMA, 1.21 DMIPS/MHz 2.27 Coremark/MHz, with cache trashing, 4KB-I$, 4KB-D$, single cycle barrel shifter, catch exceptions, static branch, MMU, Supervisor, Compatible with mainstream linux) -> + Artix 7 -> 180 MHz 2883 LUT 2130 FF + Cyclone V -> 131 MHz 1,764 ALMs + Cyclone IV -> 121 MHz 3,608 LUT 2,082 FF ``` The following configuration results in 1.44 DMIPS/MHz: @@ -157,7 +157,7 @@ The following configuration results in 1.44 DMIPS/MHz: - single cycle multiplication with bypassing in the WB stage (late result) - dynamic branch prediction done in the F stage with a direct mapped target buffer cache (no penalties on correct predictions) -Note that, recently, the capability to remove the Fetch/Memory/WriteBack stage was added to reduce the area of the CPU, which ends up with a smaller CPU and a better DMIPS/Mhz for the small configurations. +Note that, recently, the capability to remove the Fetch/Memory/WriteBack stage was added to reduce the area of the CPU, which ends up with a smaller CPU and a better DMIPS/MHz for the small configurations. ## Dependencies @@ -361,9 +361,9 @@ You can find some FPGA projects which instantiate the Briey SoC here (DE1-SoC, D Here are some measurements of Briey SoC timings and area: ``` -Artix 7 -> 181 Mhz 3220 LUT 3181 FF -Cyclone V -> 142 Mhz 2,222 ALMs -Cyclone IV -> 130 Mhz 4,538 LUT 3,211 FF +Artix 7 -> 181 MHz 3220 LUT 3181 FF +Cyclone V -> 142 MHz 2,222 ALMs +Cyclone IV -> 130 MHz 4,538 LUT 3,211 FF ``` ## Murax SoC @@ -379,8 +379,8 @@ Murax is a very light SoC (it fits in an ICE40 FPGA) which can work without any - one UART with tx/rx fifo Depending on the CPU configuration, on the ICE40-hx8k FPGA with icestorm for synthesis, the full SoC has the following area/performance: -- RV32I interlocked stages => 51 Mhz, 2387 LC 0.45 DMIPS/Mhz -- RV32I bypassed stages => 45 Mhz, 2718 LC 0.65 DMIPS/Mhz +- RV32I interlocked stages => 51 MHz, 2387 LC 0.45 DMIPS/MHz +- RV32I bypassed stages => 45 MHz, 2718 LC 0.65 DMIPS/MHz Its implementation can be found here: `src/main/scala/vexriscv/demo/Murax.scala`. @@ -415,17 +415,17 @@ You can find multiple software examples and demos here: https://github.com/Spina Here are some timing and area measurements of the Murax SoC: ``` -Murax interlocked stages (0.45 DMIPS/Mhz, 8 bits GPIO) -> - Artix 7 -> 216 Mhz 1109 LUT 1201 FF - Cyclone V -> 182 Mhz 725 ALMs - Cyclone IV -> 147 Mhz 1,551 LUT 1,223 FF - iCE40 -> 64 Mhz 2422 LC (nextpnr) +Murax interlocked stages (0.45 DMIPS/MHz, 8 bits GPIO) -> + Artix 7 -> 216 MHz 1109 LUT 1201 FF + Cyclone V -> 182 MHz 725 ALMs + Cyclone IV -> 147 MHz 1,551 LUT 1,223 FF + iCE40 -> 64 MHz 2422 LC (nextpnr) -MuraxFast bypassed stages (0.65 DMIPS/Mhz, 8 bits GPIO) -> - Artix 7 -> 224 Mhz 1278 LUT 1300 FF - Cyclone V -> 173 Mhz 867 ALMs - Cyclone IV -> 143 Mhz 1,755 LUT 1,258 FF - iCE40 -> 66 Mhz 2799 LC (nextpnr) +MuraxFast bypassed stages (0.65 DMIPS/MHz, 8 bits GPIO) -> + Artix 7 -> 224 MHz 1278 LUT 1300 FF + Cyclone V -> 173 MHz 867 ALMs + Cyclone IV -> 143 MHz 1,755 LUT 1,258 FF + iCE40 -> 66 MHz 2799 LC (nextpnr) ``` Some scripts to generate the SoC and call the icestorm toolchain can be found here: `scripts/Murax/` @@ -814,11 +814,11 @@ Synthesis results of the FPU itself, without the CPU integration, on the fast sp ``` Fpu 32 bits -> - Artix 7 relaxed -> 135 Mhz 1786 LUT 1778 FF - Artix 7 FMax -> 205 Mhz 2101 LUT 1778 FF + Artix 7 relaxed -> 135 MHz 1786 LUT 1778 FF + Artix 7 FMax -> 205 MHz 2101 LUT 1778 FF Fpu 64/32 bits -> - Artix 7 relaxed -> 101 Mhz 3336 LUT 3033 FF - Artix 7 FMax -> 165 Mhz 3728 LUT 3175 FF + Artix 7 relaxed -> 101 MHz 3336 LUT 3033 FF + Artix 7 FMax -> 165 MHz 3728 LUT 3175 FF ``` Note that if you want to debug FPU code via the openocd_riscv.vexriscv target, you need to use the GDB from : diff --git a/doc/gcdPeripheral/src/main/scala/vexriscv/demo/Murax.scala b/doc/gcdPeripheral/src/main/scala/vexriscv/demo/Murax.scala index f3d4f6cd..486912a8 100644 --- a/doc/gcdPeripheral/src/main/scala/vexriscv/demo/Murax.scala +++ b/doc/gcdPeripheral/src/main/scala/vexriscv/demo/Murax.scala @@ -27,8 +27,8 @@ import vexriscv.periph.tasks.hash._ /** Created by PIC32F_USER on 28/07/2017. * * Murax is a very light SoC which could work without any external component. - * - ICE40-hx8k + icestorm => 53 Mhz, 2142 LC - * - 0.37 DMIPS/Mhz + * - ICE40-hx8k + icestorm => 53 MHz, 2142 LC + * - 0.37 DMIPS/MHz * - 8 kB of on-chip ram * - JTAG debugger (eclipse/GDB/openocd ready) * - Interrupt support diff --git a/src/main/scala/vexriscv/demo/Murax.scala b/src/main/scala/vexriscv/demo/Murax.scala index 95a35b54..d7022f5b 100644 --- a/src/main/scala/vexriscv/demo/Murax.scala +++ b/src/main/scala/vexriscv/demo/Murax.scala @@ -22,8 +22,8 @@ import scala.collection.Seq * Created by PIC32F_USER on 28/07/2017. * * Murax is a very light SoC which could work without any external component. - * - ICE40-hx8k + icestorm => 53 Mhz, 2142 LC - * - 0.37 DMIPS/Mhz + * - ICE40-hx8k + icestorm => 53 MHz, 2142 LC + * - 0.37 DMIPS/MHz * - 8 kB of on-chip ram * - JTAG debugger (eclipse/GDB/openocd ready) * - Interrupt support diff --git a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala index b78f84f5..0f46a254 100644 --- a/src/main/scala/vexriscv/ip/fpu/FpuCore.scala +++ b/src/main/scala/vexriscv/ip/fpu/FpuCore.scala @@ -1758,17 +1758,17 @@ object FpuSynthesisBench extends App{ } // rotate2_24 -> -// Artix 7 -> 233 Mhz 96 LUT 167 FF -// Artix 7 -> 420 Mhz 86 LUT 229 FF +// Artix 7 -> 233 MHz 96 LUT 167 FF +// Artix 7 -> 420 MHz 86 LUT 229 FF // rotate2_32 -> -// Artix 7 -> 222 Mhz 108 LUT 238 FF -// Artix 7 -> 399 Mhz 110 LUT 300 FF +// Artix 7 -> 222 MHz 108 LUT 238 FF +// Artix 7 -> 399 MHz 110 LUT 300 FF // rotate2_52 -> -// Artix 7 -> 195 Mhz 230 LUT 362 FF -// Artix 7 -> 366 Mhz 225 LUT 486 FF +// Artix 7 -> 195 MHz 230 LUT 362 FF +// Artix 7 -> 366 MHz 225 LUT 486 FF // rotate2_64 -> -// Artix 7 -> 182 Mhz 257 LUT 465 FF -// Artix 7 -> 359 Mhz 266 LUT 591 FF +// Artix 7 -> 182 MHz 257 LUT 465 FF +// Artix 7 -> 359 MHz 266 LUT 591 FF class Rotate2(width : Int) extends Rtl{ override def getName(): String = "rotate2_" + width override def getRtlPath(): String = getName() + ".v" @@ -1858,56 +1858,56 @@ object FpuSynthesisBench extends App{ } //Fpu_32 -> -//Artix 7 -> 136 Mhz 1471 LUT 1336 FF -//Artix 7 -> 196 Mhz 1687 LUT 1371 FF +//Artix 7 -> 136 MHz 1471 LUT 1336 FF +//Artix 7 -> 196 MHz 1687 LUT 1371 FF //Fpu_64 -> -//Artix 7 -> 105 Mhz 2822 LUT 2132 FF -//Artix 7 -> 161 Mhz 3114 LUT 2272 FF +//Artix 7 -> 105 MHz 2822 LUT 2132 FF +//Artix 7 -> 161 MHz 3114 LUT 2272 FF // // // //Fpu_32 -> -//Artix 7 -> 128 Mhz 1693 LUT 1481 FF -//Artix 7 -> 203 Mhz 1895 LUT 1481 FF +//Artix 7 -> 128 MHz 1693 LUT 1481 FF +//Artix 7 -> 203 MHz 1895 LUT 1481 FF //Fpu_64 -> -//Artix 7 -> 99 Mhz 3073 LUT 2396 FF -//Artix 7 -> 164 Mhz 3433 LUT 2432 FF +//Artix 7 -> 99 MHz 3073 LUT 2396 FF +//Artix 7 -> 164 MHz 3433 LUT 2432 FF //Fpu_32 -> -//Artix 7 -> 112 Mhz 1790 LUT 1666 FF -//Artix 7 -> 158 Mhz 1989 LUT 1701 FF +//Artix 7 -> 112 MHz 1790 LUT 1666 FF +//Artix 7 -> 158 MHz 1989 LUT 1701 FF //Fpu_64 -> -//Artix 7 -> 100 Mhz 3294 LUT 2763 FF -//Artix 7 -> 151 Mhz 3708 LUT 2904 FF +//Artix 7 -> 100 MHz 3294 LUT 2763 FF +//Artix 7 -> 151 MHz 3708 LUT 2904 FF //Fpu_32 -> -//Artix 7 -> 139 Mhz 1879 LUT 1713 FF -//Artix 7 -> 206 Mhz 2135 LUT 1723 FF +//Artix 7 -> 139 MHz 1879 LUT 1713 FF +//Artix 7 -> 206 MHz 2135 LUT 1723 FF //Fpu_64 -> -//Artix 7 -> 106 Mhz 3502 LUT 2811 FF -//Artix 7 -> 163 Mhz 3905 LUT 2951 FF +//Artix 7 -> 106 MHz 3502 LUT 2811 FF +//Artix 7 -> 163 MHz 3905 LUT 2951 FF //Fpu_32 -> -//Artix 7 -> 130 Mhz 1889 LUT 1835 FF -//Artix 7 -> 210 Mhz 2131 LUT 1845 FF +//Artix 7 -> 130 MHz 1889 LUT 1835 FF +//Artix 7 -> 210 MHz 2131 LUT 1845 FF //Fpu_64 -> -//Artix 7 -> 106 Mhz 3322 LUT 3023 FF -//Artix 7 -> 161 Mhz 3675 LUT 3163 FF +//Artix 7 -> 106 MHz 3322 LUT 3023 FF +//Artix 7 -> 161 MHz 3675 LUT 3163 FF //Fpu_32 -> -//Artix 7 -> 132 Mhz 1891 LUT 1837 FF -//Artix 7 -> 209 Mhz 2132 LUT 1847 FF +//Artix 7 -> 132 MHz 1891 LUT 1837 FF +//Artix 7 -> 209 MHz 2132 LUT 1847 FF //Fpu_64 -> -//Artix 7 -> 105 Mhz 3348 LUT 3024 FF -//Artix 7 -> 162 Mhz 3712 LUT 3165 FF +//Artix 7 -> 105 MHz 3348 LUT 3024 FF +//Artix 7 -> 162 MHz 3712 LUT 3165 FF //Fpu_32 -> -//Artix 7 -> 128 Mhz 1796 LUT 1727 FF -//Artix 7 -> 208 Mhz 2049 LUT 1727 FF +//Artix 7 -> 128 MHz 1796 LUT 1727 FF +//Artix 7 -> 208 MHz 2049 LUT 1727 FF //Fpu_64 -> -//Artix 7 -> 109 Mhz 3417 LUT 2913 FF -//Artix 7 -> 168 Mhz 3844 LUT 3053 FF +//Artix 7 -> 109 MHz 3417 LUT 2913 FF +//Artix 7 -> 168 MHz 3844 LUT 3053 FF /* testfloat -tininessafter -all1 > all1.txt diff --git a/src/main/scala/vexriscv/plugin/AesPlugin.scala b/src/main/scala/vexriscv/plugin/AesPlugin.scala index 0d4556a1..eec48e58 100644 --- a/src/main/scala/vexriscv/plugin/AesPlugin.scala +++ b/src/main/scala/vexriscv/plugin/AesPlugin.scala @@ -53,7 +53,7 @@ import vexriscv.{DecoderService, Stageable, VexRiscv} * - SS specify which byte should be used from RS2 for the processing * * In practice the aes-256-cbc performances should improve by a factor 4. See the following results from libopenssl - * from a SoC running linux at 100 Mhz + * from a SoC running linux at 100 MHz * type 16 bytes 64 bytes 256 bytes 1024 bytes 8192 bytes 16384 bytes * aes-256-cbc SW 492.58k 700.22k 796.41k 831.49k 830.09k 832.81k * aes-256 cbc HW 1781.52k 2834.07k 3323.07k 3486.72k 3465.22k 3440.10k From 8968b5a3fafd52d1e88fc7b7ae0c7ba031d9d7b3 Mon Sep 17 00:00:00 2001 From: Marc Emery Date: Mon, 17 Jun 2024 22:00:19 +0200 Subject: [PATCH 934/951] Fix Mhz -> MHz in Dhrystone benchmark report generation --- src/test/scala/vexriscv/DhrystoneBench.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/scala/vexriscv/DhrystoneBench.scala b/src/test/scala/vexriscv/DhrystoneBench.scala index 48d1b674..3fabf42b 100644 --- a/src/test/scala/vexriscv/DhrystoneBench.scala +++ b/src/test/scala/vexriscv/DhrystoneBench.scala @@ -45,7 +45,7 @@ class DhrystoneBench extends AnyFunSuite { val coremarkIterations = intFind.findFirstIn("Iterations \\: (\\d+.?)+".r.findAllIn(str).toList.last).get.toDouble val coremarkHzs = intFind.findFirstIn("DCLOCKS_PER_SEC=(\\d+.?)+".r.findAllIn(str).toList.last).get.toDouble val coremarkPerMhz = 1e6 * coremarkIterations / coremarkTicks - report ++= s"$name -> $dmips DMIPS/Mhz $coremarkPerMhz Coremark/Mhz\n" + report ++= s"$name -> $dmips DMIPS/MHz $coremarkPerMhz Coremark/MHz\n" } } From bd7c4c3281cbfd2fe0fe2c151ed35aa338e70db4 Mon Sep 17 00:00:00 2001 From: Craig Bishop Date: Mon, 26 Aug 2024 17:21:42 -0700 Subject: [PATCH 935/951] Add JTAG tunnel without TAP in EmbeddedRiscvJtag --- .../scala/vexriscv/plugin/EmbeddedRiscvJtag.scala | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/plugin/EmbeddedRiscvJtag.scala b/src/main/scala/vexriscv/plugin/EmbeddedRiscvJtag.scala index 8a1c668e..1e625b28 100644 --- a/src/main/scala/vexriscv/plugin/EmbeddedRiscvJtag.scala +++ b/src/main/scala/vexriscv/plugin/EmbeddedRiscvJtag.scala @@ -14,6 +14,7 @@ import vexriscv._ class EmbeddedRiscvJtag(var p : DebugTransportModuleParameter, var debugCd : ClockDomain = null, + var jtagCd : ClockDomain = null, var withTap : Boolean = true, var withTunneling : Boolean = false ) extends Plugin[VexRiscv] with VexRiscvRegressionArg{ @@ -61,7 +62,7 @@ class EmbeddedRiscvJtag(var p : DebugTransportModuleParameter, dm.io.ctrl <> logic.io.bus logic.io.jtag <> jtag } - val dmiTunneled = if(withTap && withTunneling) new Area { + val dmiTunneledWithTap = if(withTap && withTunneling) new Area { val logic = DebugTransportModuleJtagTapWithTunnel( p.copy(addressWidth = 7), debugCd = ClockDomain.current @@ -69,6 +70,15 @@ class EmbeddedRiscvJtag(var p : DebugTransportModuleParameter, dm.io.ctrl <> logic.io.bus logic.io.jtag <> jtag } + val dmiTunneledNoTap = if (!withTap && withTunneling) new Area { + val logic = DebugTransportModuleTunneled( + p.copy(addressWidth = 7), + debugCd = ClockDomain.current, + jtagCd = jtagCd + ) + logic.io.instruction <> jtagInstruction + dm.io.ctrl <> logic.io.bus + } val privBus = pipeline.service(classOf[CsrPlugin]).debugBus.setAsDirectionLess() privBus <> dm.io.harts(0) From 52a2e889d054f0bb9d7047af74c4ce6f58a48cae Mon Sep 17 00:00:00 2001 From: Craig Bishop Date: Mon, 26 Aug 2024 17:43:28 -0700 Subject: [PATCH 936/951] Document using EmbeddedRiscvJtag with BSCANE2 --- README.md | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/README.md b/README.md index 804bdb1f..9718fda0 100644 --- a/README.md +++ b/README.md @@ -1404,6 +1404,62 @@ halt A full example can be found in GenFullWithOfficialRiscvDebug.scala +##### Tunneled JTAG + +The EmbeddedRiscvJtag plugin can also be used with tunneled JTAG. This allows debugging with the same cable used to configure an FPGA. + +This uses an FPGA-specific primitive for JTAG access (e.g. Xilinx BSCANE2): +```scala +val xilJtag = BSCANE2(userId = 4) // must be userId = 4 +val jtagClockDomain = ClockDomain( + clock = xilJtag.TCK +) +``` + +Then, the EmbeddedRiscvJtag plugin must be configured for tunneling without a TAP. Note, the debug clock domain must have a separate reset from the CPU clock domain. + +```scala +// in plugins +new EmbeddedRiscvJtag( + p = DebugTransportModuleParameter( + addressWidth = 7, + version = 1, + idle = 7 + ), + withTunneling = true, + withTap = false, + debugCd = debugClockDomain, + jtagCd = jtagClockDomain +) +``` + +Then connect the EmbeddedRiscvJtag to the FPGA-specific JTAG primitive: + +```scala +for (plugin <- cpuConfig.plugins) plugin match { + case plugin: EmbeddedRiscvJtag => { + plugin.jtagInstruction <> xilJtag.toJtagTapInstructionCtrl() + } + case _ => +} +``` + +Here is an example OpenOCD TCL script to connect on a Xilinx 7-Series FPGA: + +```tcl +# ADD HERE YOUR JTAG ADAPTER SETTINGS + +source [find cpld/xilinx-xc7.cfg] +set TAP_NAME xc7.tap + +set _TARGETNAME cpu +target create $_TARGETNAME.0 riscv -chain-position $TAP_NAME +riscv use_bscan_tunnel 6 1 + +init +halt +``` + #### YamlPlugin This plugin offers a service to other plugins to generate a useful Yaml file describing the CPU configuration. It contains, for instance, the sequence of instructions required From 638cd8878dbd9332f0f7caa236299d60c75b8409 Mon Sep 17 00:00:00 2001 From: Daniel Schultz Date: Mon, 2 Sep 2024 07:20:57 +0200 Subject: [PATCH 937/951] build.sbt: Bump SpinalHDL and Scala version Bump SpinalHDL to 1.10.2a and Scala to 2.12. Signed-off-by: Daniel Schultz --- build.sbt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/build.sbt b/build.sbt index 7eb2d352..b385e91e 100644 --- a/build.sbt +++ b/build.sbt @@ -1,17 +1,17 @@ -val spinalVersion = "1.10.1" +val spinalVersion = "1.10.2a" lazy val root = (project in file(".")). settings( inThisBuild(List( organization := "com.github.spinalhdl", - scalaVersion := "2.11.12", + scalaVersion := "2.12.18", version := "2.0.0" )), libraryDependencies ++= Seq( - "com.github.spinalhdl" % "spinalhdl-core_2.11" % spinalVersion, - "com.github.spinalhdl" % "spinalhdl-lib_2.11" % spinalVersion, - compilerPlugin("com.github.spinalhdl" % "spinalhdl-idsl-plugin_2.11" % spinalVersion), - "org.scalatest" %% "scalatest" % "3.2.5", + "com.github.spinalhdl" %% "spinalhdl-core" % spinalVersion, + "com.github.spinalhdl" %% "spinalhdl-lib" % spinalVersion, + compilerPlugin("com.github.spinalhdl" %% "spinalhdl-idsl-plugin" % spinalVersion), + "org.scalatest" %% "scalatest" % "3.2.17", "org.yaml" % "snakeyaml" % "1.8" ), name := "VexRiscv" From 545b8c377036a3d757ac88231de31d01cc5068f3 Mon Sep 17 00:00:00 2001 From: Asherah Connor Date: Wed, 4 Sep 2024 17:40:36 +0300 Subject: [PATCH 938/951] DBusSimplePlugin: don't force SEL to 1111 on read. --- src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala index 0e7d1238..f2f3f586 100644 --- a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala @@ -194,9 +194,6 @@ case class DBusSimpleBus(bigEndian : Boolean = false) extends Bundle with IMaste bus.CTI :=B"000" bus.BTE := "00" bus.SEL := genMask(cmdStage).resized - when(!cmdStage.wr) { - bus.SEL := "1111" - } bus.WE := cmdStage.wr bus.DAT_MOSI := cmdStage.data From 8c1e69b872a4377f4cdfe88e0c522ee004889570 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 20 Sep 2024 11:40:28 +0200 Subject: [PATCH 939/951] Fix #430 --- src/main/scala/vexriscv/plugin/DecoderSimplePlugin.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/plugin/DecoderSimplePlugin.scala b/src/main/scala/vexriscv/plugin/DecoderSimplePlugin.scala index a525b771..5aa9088b 100644 --- a/src/main/scala/vexriscv/plugin/DecoderSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/DecoderSimplePlugin.scala @@ -88,7 +88,7 @@ class DecoderSimplePlugin(catchIllegalInstruction : Boolean = false, } } - val detectLegalInstructions = catchIllegalInstruction || throwIllegalInstruction || forceLegalInstructionComputation || assertIllegalInstruction + val detectLegalInstructions = true object ASSERT_ERROR extends Stageable(Bool) From 83606a9eb0965ffbb02328ea28e3ad789d8e1df0 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 20 Sep 2024 15:40:36 +0200 Subject: [PATCH 940/951] Fix CsrPlugin FPU access --- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index db63107e..953fda7f 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -766,7 +766,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep buffer.ready := injectionPort.fire val fpu = withDebugFpuAccess generate new Area { val access = service(classOf[FpuPlugin]).access - access.start := buffer.valid && buffer.op === DebugDmToHartOp.REG_READ || buffer.op === DebugDmToHartOp.REG_WRITE + access.start := buffer.valid && (buffer.op === DebugDmToHartOp.REG_READ || buffer.op === DebugDmToHartOp.REG_WRITE) access.regId := buffer.address access.write := buffer.op === DebugDmToHartOp.REG_WRITE access.writeData := dataCsrw.value.take(2).asBits From bd9e062abeec3a208f5112960ebef61bc5a80884 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 23 Sep 2024 08:44:43 +0200 Subject: [PATCH 941/951] Fix #429 sifive toolchain link --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 9718fda0..1550c6cd 100644 --- a/README.md +++ b/README.md @@ -520,9 +520,12 @@ A prebuild GCC toolsuite can be found here: - https://www.sifive.com/software/ => Prebuilt RISC‑V GCC Toolchain and Emulator -The VexRiscvSocSoftware makefiles are expecting to find this prebuild version in /opt/riscv/__contentOfThisPreBuild__ +The VexRiscvSocSoftware makefiles are expecting to find a Sifive GCC toolchain in /opt/riscv/__contentOfThisPreBuild__ . + +You can manualy download it via https://static.dev.sifive.com/dev-tools/riscv64-unknown-elf-gcc-8.3.0-2019.08.0-x86_64-linux-ubuntu14.tar.gz ```sh +# Download and install the Sifive GCC toolchain version=riscv64-unknown-elf-gcc-8.3.0-2019.08.0-x86_64-linux-ubuntu14 wget -O riscv64-unknown-elf-gcc.tar.gz riscv https://static.dev.sifive.com/dev-tools/$version.tar.gz tar -xzvf riscv64-unknown-elf-gcc.tar.gz From 67b2e94f8232188f3d3fb90cb6c3d7370fdd94fd Mon Sep 17 00:00:00 2001 From: goekce <18174744+goekce@users.noreply.github.com> Date: Mon, 21 Oct 2024 17:14:25 +0200 Subject: [PATCH 942/951] Verilator requires at least c++14 --- src/test/cpp/briey/makefile | 2 +- src/test/cpp/murax/makefile | 2 +- src/test/cpp/regression/makefile | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/cpp/briey/makefile b/src/test/cpp/briey/makefile index e0a024b0..1e4f0f47 100644 --- a/src/test/cpp/briey/makefile +++ b/src/test/cpp/briey/makefile @@ -48,7 +48,7 @@ run: compile verilate: ../../../../Briey.v rm -f Briey.v*.bin cp ../../../../Briey.v*.bin . | true - verilator -cc ../../../../Briey.v -CFLAGS -std=c++11 ${ADDCFLAGS} --gdbbt ${VERILATOR_ARGS} -Wno-WIDTH -Wno-UNOPTFLAT --x-assign unique --exe main.cpp + verilator -cc ../../../../Briey.v ${ADDCFLAGS} --gdbbt ${VERILATOR_ARGS} -Wno-WIDTH -Wno-UNOPTFLAT --x-assign unique --exe main.cpp compile: verilate make -j -C obj_dir/ -f VBriey.mk VBriey diff --git a/src/test/cpp/murax/makefile b/src/test/cpp/murax/makefile index 7c946ae7..4f5a2438 100644 --- a/src/test/cpp/murax/makefile +++ b/src/test/cpp/murax/makefile @@ -31,7 +31,7 @@ run: compile verilate: ../../../../Murax.v rm -f Murax.v*.bin cp ../../../../Murax.v*.bin . | true - verilator -I../../../.. -cc ../../../../Murax.v -CFLAGS -std=c++11 ${ADDCFLAGS} --gdbbt ${VERILATOR_ARGS} -Wno-WIDTH -Wno-UNOPTFLAT --x-assign unique --exe main.cpp + verilator -I../../../.. -cc ../../../../Murax.v ${ADDCFLAGS} --gdbbt ${VERILATOR_ARGS} -Wno-WIDTH -Wno-UNOPTFLAT --x-assign unique --exe main.cpp compile: verilate make -j -C obj_dir/ -f VMurax.mk VMurax diff --git a/src/test/cpp/regression/makefile b/src/test/cpp/regression/makefile index 30d11b67..d113bbe5 100644 --- a/src/test/cpp/regression/makefile +++ b/src/test/cpp/regression/makefile @@ -350,7 +350,7 @@ run: compile verilate: ${VEXRISCV_FILE} cp ${VEXRISCV_FILE}*.bin . | true - verilator -cc ${VEXRISCV_FILE} -O3 -CFLAGS -std=c++11 -LDFLAGS -pthread ${ADDCFLAGS} --gdbbt ${VERILATOR_ARGS} -Wno-UNOPTFLAT -Wno-WIDTH --x-assign unique --exe main.cpp + verilator -cc ${VEXRISCV_FILE} -O3 -LDFLAGS -pthread ${ADDCFLAGS} --gdbbt ${VERILATOR_ARGS} -Wno-UNOPTFLAT -Wno-WIDTH --x-assign unique --exe main.cpp compile: verilate make -j${THREAD_COUNT} -C obj_dir/ -f VVexRiscv.mk VVexRiscv From 4b3af464dcbe88eee5408b74afb8e7cb065ca610 Mon Sep 17 00:00:00 2001 From: 7FM <41307817+7FM@users.noreply.github.com> Date: Mon, 11 Nov 2024 15:27:27 +0100 Subject: [PATCH 943/951] Fix undriven signal --- src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala index dc19d434..c11d2643 100644 --- a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala @@ -371,6 +371,7 @@ class IBusSimplePlugin( resetVector : BigInt, } val fetchRsp = FetchRsp() + fetchRsp.isRvc := False fetchRsp.pc := stages.last.output.payload fetchRsp.rsp := rspBuffer.output.payload fetchRsp.rsp.error.clearWhen(!rspBuffer.output.valid) //Avoid interference with instruction injection from the debug plugin From e0f4bacaf4e88883ad8452f7fa7cb884a6061a22 Mon Sep 17 00:00:00 2001 From: goekce <18174744+goekce@users.noreply.github.com> Date: Wed, 13 Nov 2024 11:31:17 +0100 Subject: [PATCH 944/951] add Murax config with native jtag --- doc/nativeJtag/README.md | 46 ++++-------------------- src/main/scala/vexriscv/demo/Murax.scala | 24 ++++++++++--- 2 files changed, 26 insertions(+), 44 deletions(-) diff --git a/doc/nativeJtag/README.md b/doc/nativeJtag/README.md index 10c5b7ee..16f23ed4 100644 --- a/doc/nativeJtag/README.md +++ b/doc/nativeJtag/README.md @@ -24,47 +24,15 @@ reader is capable of generating the Murax SoC as it is described there. The BSCANE2 allows access between the internal FPGA logic and the JTAG Boundary Scan logic controller. This allows for communication between the internally running design and the dedicated JTAG pins of the FPGA. -### Steps to enable Bscane2 +Run the following command at the top level of the repository. -After cloning all files from https://github.com/SpinalHDL/VexRiscv, go to the path: `src/main/scala/vexriscv/demo` -and find the `Murax.scala` file. -* Comment out the following lines to remove the toplevel jtag I/O pins in `Murax.scala`. Be aware that line numbers -as given could move with future changes to the file: +```sh +sbt "runMain vexriscv.demo.MuraxWithRamInitWithNativeJtag" ``` -[164] val jtag = slave(Jtag()) -… -[392] val jtagClkBuffer = SB_GB() -[393] jtagClkBuffer.USER_SIGNAL_TO_GLOBAL_BUFFER <> io.jtag_tck -[394] jtagClkBuffer.GLOBAL_BUFFER_OUTPUT <> murax.io.jtag.tck -… -[398] murax.io.jtag.tdi <> io.jtag_tdi -[399] murax.io.jtag.tdo <> io.jtag_tdo -[400] murax.io.jtag.tms <> io.jtag_tms -``` -* In the `Murax.scala` file, delete the line: -``` -[253] io.jtag <> plugin.io.bus.fromJtag() -``` -* And add the lines: -``` -[254] val jtagCtrl = JtagTapInstructionCtrl() -[255] val tap = jtagCtrl.fromXilinxBscane2(userId = 2) -[256] jtagCtrl <> plugin.io.bus.fromJtagInstructionCtrl(ClockDomain(tap.TCK),0) -``` -Changing the above lines, removes the Murax SoC’s JTAG ports as pins of the FPGA and inserts the BSCANE2 Xilinx -Debug IP to which the JTAG signals are now connected. -* Add the following import statement at the beginning of `Murax.scala`: -``` -import spinal.lib.com.jtag.JtagTapInstructionCtrl -``` -With these changes in place, you generate the SoC with a demo program already in ram by use of: -``` -sbt "runMain vexriscv.demo.MuraxWithRamInit" -``` -A Verilog file is generated with the name `Murax.v` next to four `.bin` files inside the `VexRiscv` folder. These -files are the input to the Xilinx FPGA synthesis. Inside the `Murax.v` file, we can see that the BSCANE2 ports are -instantiated, confirming that the BSCANE2 has successfully been instantiated within the Murax SoC as a debug brige -to JTAG. + +The Murax configuration `MuraxWithRamInitWithNativeJtag` activates `WithNativeJtag` flag, which removes toplevel Jtag signals from the default Murax configuration and integrates `BSCANE2` plugin. + +After code generation you will see the Verilog file `Murax.v` next to four `.bin` files at the top level of the repository. These files are the input to the Xilinx FPGA synthesis. Inside the `Murax.v` file, we can see that the BSCANE2 ports are instantiated, confirming that the BSCANE2 has successfully been instantiated within the Murax SoC as a debug bridge to JTAG. ## 3. Xilinx Vivado - Programming Arty A7 FPGA There are many applications to program a FPGA. In our work we referred to the freely available Xilinx Vivado 2020 diff --git a/src/main/scala/vexriscv/demo/Murax.scala b/src/main/scala/vexriscv/demo/Murax.scala index d7022f5b..b7145ebe 100644 --- a/src/main/scala/vexriscv/demo/Murax.scala +++ b/src/main/scala/vexriscv/demo/Murax.scala @@ -17,6 +17,7 @@ import spinal.lib.com.spi.ddr._ import spinal.lib.bus.simple._ import scala.collection.mutable.ArrayBuffer import scala.collection.Seq +import spinal.lib.com.jtag.JtagTapInstructionCtrl /** * Created by PIC32F_USER on 28/07/2017. @@ -44,7 +45,9 @@ case class MuraxConfig(coreFrequency : HertzNumber, uartCtrlConfig : UartCtrlMemoryMappedConfig, xipConfig : SpiXdrMasterCtrl.MemoryMappingParameters, hardwareBreakpointCount : Int, - cpuPlugins : ArrayBuffer[Plugin[VexRiscv]]){ + withNativeJtag : Boolean, + cpuPlugins : ArrayBuffer[Plugin[VexRiscv]] + ){ require(pipelineApbBridge || pipelineMainBus, "At least pipelineMainBus or pipelineApbBridge should be enable to avoid wipe transactions") val genXip = xipConfig != null @@ -69,6 +72,7 @@ object MuraxConfig{ xip = SpiXdrMasterCtrl.XipBusParameters(addressWidth = 24, lengthWidth = 2) )), hardwareBreakpointCount = if(withXip) 3 else 0, + withNativeJtag = false, cpuPlugins = ArrayBuffer( //DebugPlugin added by the toplevel new IBusSimplePlugin( resetVector = if(withXip) 0xF001E000l else 0x80000000l, @@ -162,7 +166,7 @@ case class Murax(config : MuraxConfig) extends Component{ val mainClk = in Bool() //Main components IO - val jtag = slave(Jtag()) + val jtag = ifGen(!config.withNativeJtag) (slave(Jtag())) //Peripherals IO val gpioA = master(TriStateArray(gpioWidth bits)) @@ -251,7 +255,13 @@ case class Murax(config : MuraxConfig) extends Component{ } case plugin : DebugPlugin => plugin.debugClockDomain{ resetCtrl.systemReset setWhen(RegNext(plugin.io.resetOut)) - io.jtag <> plugin.io.bus.fromJtag() + if (withNativeJtag) { + val jtagCtrl = JtagTapInstructionCtrl() + val tap = jtagCtrl.fromXilinxBscane2(userId = 2) + jtagCtrl <> plugin.io.bus.fromJtagInstructionCtrl(ClockDomain(tap.TCK),0) + } else { + io.jtag <> plugin.io.bus.fromJtag() + } } case _ => } @@ -526,6 +536,12 @@ object MuraxWithRamInit{ } } +object MuraxWithRamInitWithNativeJtag{ + def main(args: Array[String]) { + SpinalVerilog(Murax(MuraxConfig.default.copy(withNativeJtag = true, onChipRamSize = 4 kB, onChipRamHexFile = "src/main/ressource/hex/muraxDemo.hex"))) + } +} + object Murax_arty{ def main(args: Array[String]) { val hex = "src/main/c/murax/hello_world/build/hello_world.hex" @@ -533,11 +549,9 @@ object Murax_arty{ } } - object MuraxAsicBlackBox extends App{ println("Warning this soc do not has any rom to boot on.") val config = SpinalConfig() config.addStandardMemBlackboxing(blackboxAll) config.generateVerilog(Murax(MuraxConfig.default())) } - From 110b2a1e00c9da537e5d551d733eb21d4b440844 Mon Sep 17 00:00:00 2001 From: goekce <18174744+goekce@users.noreply.github.com> Date: Wed, 13 Nov 2024 14:22:22 +0100 Subject: [PATCH 945/951] make JtagNative signal visible in generated code --- src/main/scala/vexriscv/demo/Murax.scala | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/scala/vexriscv/demo/Murax.scala b/src/main/scala/vexriscv/demo/Murax.scala index b7145ebe..df644003 100644 --- a/src/main/scala/vexriscv/demo/Murax.scala +++ b/src/main/scala/vexriscv/demo/Murax.scala @@ -175,6 +175,10 @@ case class Murax(config : MuraxConfig) extends Component{ val xip = ifGen(genXip)(master(SpiXdrMaster(xipConfig.ctrl.spi))) } + val jtagNative = withNativeJtag generate new ClockingArea(debugClockDomain){ + val jtagCtrl = JtagTapInstructionCtrl() + val tap = jtagCtrl.fromXilinxBscane2(userId = 2) + } val resetCtrlClockDomain = ClockDomain( clock = io.mainClk, @@ -256,9 +260,7 @@ case class Murax(config : MuraxConfig) extends Component{ case plugin : DebugPlugin => plugin.debugClockDomain{ resetCtrl.systemReset setWhen(RegNext(plugin.io.resetOut)) if (withNativeJtag) { - val jtagCtrl = JtagTapInstructionCtrl() - val tap = jtagCtrl.fromXilinxBscane2(userId = 2) - jtagCtrl <> plugin.io.bus.fromJtagInstructionCtrl(ClockDomain(tap.TCK),0) + jtagNative.jtagCtrl <> plugin.io.bus.fromJtagInstructionCtrl(ClockDomain(jtagNative.tap.TCK),0) } else { io.jtag <> plugin.io.bus.fromJtag() } From bd3942166493496751b6c2ee727fcd76fca6afea Mon Sep 17 00:00:00 2001 From: goekce <18174744+goekce@users.noreply.github.com> Date: Wed, 13 Nov 2024 14:25:54 +0100 Subject: [PATCH 946/951] fix indent --- src/main/scala/vexriscv/demo/Murax.scala | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/scala/vexriscv/demo/Murax.scala b/src/main/scala/vexriscv/demo/Murax.scala index df644003..43e05e41 100644 --- a/src/main/scala/vexriscv/demo/Murax.scala +++ b/src/main/scala/vexriscv/demo/Murax.scala @@ -175,10 +175,10 @@ case class Murax(config : MuraxConfig) extends Component{ val xip = ifGen(genXip)(master(SpiXdrMaster(xipConfig.ctrl.spi))) } - val jtagNative = withNativeJtag generate new ClockingArea(debugClockDomain){ - val jtagCtrl = JtagTapInstructionCtrl() - val tap = jtagCtrl.fromXilinxBscane2(userId = 2) - } + val jtagNative = withNativeJtag generate new ClockingArea(debugClockDomain){ + val jtagCtrl = JtagTapInstructionCtrl() + val tap = jtagCtrl.fromXilinxBscane2(userId = 2) + } val resetCtrlClockDomain = ClockDomain( clock = io.mainClk, From 41ea95f805f2213e14415a6b9642ea1c6ec78076 Mon Sep 17 00:00:00 2001 From: goekce <18174744+goekce@users.noreply.github.com> Date: Thu, 14 Nov 2024 18:12:11 +0100 Subject: [PATCH 947/951] add argument for simulation frequency --- src/main/scala/vexriscv/demo/Murax.scala | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/scala/vexriscv/demo/Murax.scala b/src/main/scala/vexriscv/demo/Murax.scala index 43e05e41..d7432b5d 100644 --- a/src/main/scala/vexriscv/demo/Murax.scala +++ b/src/main/scala/vexriscv/demo/Murax.scala @@ -540,7 +540,10 @@ object MuraxWithRamInit{ object MuraxWithRamInitWithNativeJtag{ def main(args: Array[String]) { - SpinalVerilog(Murax(MuraxConfig.default.copy(withNativeJtag = true, onChipRamSize = 4 kB, onChipRamHexFile = "src/main/ressource/hex/muraxDemo.hex"))) + val coreFrequency = if (args.nonEmpty) HertzNumber(BigDecimal(args(0))) else MuraxConfig.default.coreFrequency + val (scaledValue, unit) = coreFrequency.decompose + println(s"coreFrequency = $scaledValue $unit") + SpinalVerilog(Murax(MuraxConfig.default.copy(coreFrequency=coreFrequency, withNativeJtag = true, onChipRamSize = 4 kB, onChipRamHexFile = "src/main/ressource/hex/muraxDemo.hex"))) } } From 35402a2bde511e9bf73833ccbb14b1e43486de64 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 24 Jan 2025 10:37:49 +0100 Subject: [PATCH 948/951] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 1550c6cd..d944c959 100644 --- a/README.md +++ b/README.md @@ -87,6 +87,8 @@ There is a gitter channel for all questions about VexRiscv :
For commercial support, please contact spinalhdl@gmail.com. +Note you may be interested VexiiRiscv (https://github.com/SpinalHDL/VexiiRiscv). + ## Area usage and maximal frequency The following numbers were obtained by synthesizing the CPU as toplevel on the fastest speed grade without any specific synthesis options to save area or to get better maximal frequency (neutral).
From f3409b240f65fa92aa2fc59708bb31c4b4db545d Mon Sep 17 00:00:00 2001 From: Justin Berger Date: Fri, 31 Jan 2025 22:51:43 -0700 Subject: [PATCH 949/951] Add address granularity for wishbone --- src/main/scala/vexriscv/ip/DataCache.scala | 5 +++-- src/main/scala/vexriscv/ip/InstructionCache.scala | 5 +++-- src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala | 5 +++-- src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala | 5 +++-- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index a7506e65..d924d221 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -6,7 +6,7 @@ import spinal.lib._ import spinal.lib.bus.amba4.axi.{Axi4Config, Axi4Shared} import spinal.lib.bus.avalon.{AvalonMM, AvalonMMConfig} import spinal.lib.bus.bmb.{Bmb, BmbAccessParameter, BmbCmd, BmbInvalidationParameter, BmbParameter, BmbSourceParameter} -import spinal.lib.bus.wishbone.{Wishbone, WishboneConfig} +import spinal.lib.bus.wishbone.{AddressGranularity, Wishbone, WishboneConfig} import spinal.lib.bus.simple._ import vexriscv.plugin.DBusSimpleBus @@ -89,7 +89,8 @@ case class DataCacheConfig(cacheSize : Int, tgcWidth = 0, tgdWidth = 0, useBTE = true, - useCTI = true + useCTI = true, + addressGranularity = AddressGranularity.WORD ) def getBmbParameter() = BmbParameter( diff --git a/src/main/scala/vexriscv/ip/InstructionCache.scala b/src/main/scala/vexriscv/ip/InstructionCache.scala index 20584a66..e225429d 100644 --- a/src/main/scala/vexriscv/ip/InstructionCache.scala +++ b/src/main/scala/vexriscv/ip/InstructionCache.scala @@ -6,7 +6,7 @@ import spinal.lib._ import spinal.lib.bus.amba4.axi.{Axi4Config, Axi4ReadOnly} import spinal.lib.bus.avalon.{AvalonMM, AvalonMMConfig} import spinal.lib.bus.bmb.{Bmb, BmbAccessParameter, BmbParameter, BmbSourceParameter} -import spinal.lib.bus.wishbone.{Wishbone, WishboneConfig} +import spinal.lib.bus.wishbone.{AddressGranularity, Wishbone, WishboneConfig} import spinal.lib.bus.simple._ import vexriscv.plugin.{IBusSimpleBus, IBusSimplePlugin} @@ -67,7 +67,8 @@ case class InstructionCacheConfig( cacheSize : Int, tgcWidth = 0, tgdWidth = 0, useBTE = true, - useCTI = true + useCTI = true, + addressGranularity = AddressGranularity.WORD ) def getBmbParameter() = BmbParameter( diff --git a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala index f2f3f586..7ad3e03d 100644 --- a/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusSimplePlugin.scala @@ -7,7 +7,7 @@ import spinal.lib.bus.amba3.ahblite.{AhbLite3Config, AhbLite3Master} import spinal.lib.bus.amba4.axi._ import spinal.lib.bus.avalon.{AvalonMM, AvalonMMConfig} import spinal.lib.bus.bmb.{Bmb, BmbParameter} -import spinal.lib.bus.wishbone.{Wishbone, WishboneConfig} +import spinal.lib.bus.wishbone.{AddressGranularity, Wishbone, WishboneConfig} import spinal.lib.bus.simple._ import vexriscv.ip.DataCacheMemCmd @@ -66,7 +66,8 @@ object DBusSimpleBus{ tgcWidth = 0, tgdWidth = 0, useBTE = true, - useCTI = true + useCTI = true, + addressGranularity = AddressGranularity.WORD ) def getPipelinedMemoryBusConfig() = PipelinedMemoryBusConfig( diff --git a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala index c11d2643..758049ee 100644 --- a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala @@ -7,7 +7,7 @@ import spinal.lib.bus.amba3.ahblite.{AhbLite3, AhbLite3Config, AhbLite3Master} import spinal.lib.bus.amba4.axi._ import spinal.lib.bus.avalon.{AvalonMM, AvalonMMConfig} import spinal.lib.bus.bmb.{Bmb, BmbParameter} -import spinal.lib.bus.wishbone.{Wishbone, WishboneConfig} +import spinal.lib.bus.wishbone.{AddressGranularity, Wishbone, WishboneConfig} import spinal.lib.bus.simple._ import vexriscv.Riscv.{FENCE, FENCE_I} @@ -60,7 +60,8 @@ object IBusSimpleBus{ tgcWidth = 0, tgdWidth = 0, useBTE = true, - useCTI = true + useCTI = true, + addressGranularity = AddressGranularity.WORD ) def getPipelinedMemoryBusConfig() = PipelinedMemoryBusConfig( From 9b40a058375ca1bab623d1ecb5e0364b0ac280dc Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 6 Feb 2025 09:54:56 +0100 Subject: [PATCH 950/951] update verilator git --- tools.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools.sh b/tools.sh index 7ee6a59b..4dbab4e8 100644 --- a/tools.sh +++ b/tools.sh @@ -2,7 +2,7 @@ install_verilator(){ sudo apt install -y git make autoconf g++ flex libfl-dev bison # First time prerequisites - git clone http://git.veripool.org/git/verilator # Only first time + git clone https://github.com/verilator/verilator.git # Only first time unset VERILATOR_ROOT # For bash cd verilator git pull # Make sure we're up-to-date @@ -59,4 +59,4 @@ install_tools(){ install_ghdl install_iverilog install_cocotb -} \ No newline at end of file +} From c559c6d0f9839ea3bdf3b1753f86ba51a528f5ea Mon Sep 17 00:00:00 2001 From: Justin Berger Date: Thu, 13 Feb 2025 22:18:12 -0700 Subject: [PATCH 951/951] Make TDATA2 RW. Openocd requires this for hw breakpoints --- src/main/scala/vexriscv/plugin/CsrPlugin.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 953fda7f..ba18b713 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -942,12 +942,12 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep } val tdata2 = new Area{ - val value = Reg(PC) - csrw(CSR.TDATA2, 0 -> value) + val value = Reg(Bits(32 bits)) + csrrw(CSR.TDATA2, value, 0 -> value) val execute = new Area{ val enabled = !debugMode && tdata1.action === 1 && tdata1.execute && tdata1.privilegeHit - val hit = enabled && value === decode.input(PC) + val hit = enabled && value.asUInt === decode.input(PC) decodeBreak.enabled.setWhen(hit) } }